@flowerforce/flowerbase-client 0.1.1-beta.0

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 (63) hide show
  1. package/CHANGELOG.md +0 -0
  2. package/LICENSE +3 -0
  3. package/README.md +209 -0
  4. package/dist/app.d.ts +85 -0
  5. package/dist/app.d.ts.map +1 -0
  6. package/dist/app.js +461 -0
  7. package/dist/bson.d.ts +8 -0
  8. package/dist/bson.d.ts.map +1 -0
  9. package/dist/bson.js +10 -0
  10. package/dist/credentials.d.ts +8 -0
  11. package/dist/credentials.d.ts.map +1 -0
  12. package/dist/credentials.js +30 -0
  13. package/dist/functions.d.ts +6 -0
  14. package/dist/functions.d.ts.map +1 -0
  15. package/dist/functions.js +47 -0
  16. package/dist/http.d.ts +35 -0
  17. package/dist/http.d.ts.map +1 -0
  18. package/dist/http.js +170 -0
  19. package/dist/index.d.ts +8 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +16 -0
  22. package/dist/mongo.d.ts +4 -0
  23. package/dist/mongo.d.ts.map +1 -0
  24. package/dist/mongo.js +106 -0
  25. package/dist/session.d.ts +18 -0
  26. package/dist/session.d.ts.map +1 -0
  27. package/dist/session.js +105 -0
  28. package/dist/session.native.d.ts +14 -0
  29. package/dist/session.native.d.ts.map +1 -0
  30. package/dist/session.native.js +76 -0
  31. package/dist/types.d.ts +97 -0
  32. package/dist/types.d.ts.map +1 -0
  33. package/dist/types.js +2 -0
  34. package/dist/user.d.ts +37 -0
  35. package/dist/user.d.ts.map +1 -0
  36. package/dist/user.js +125 -0
  37. package/dist/watch.d.ts +3 -0
  38. package/dist/watch.d.ts.map +1 -0
  39. package/dist/watch.js +139 -0
  40. package/jest.config.ts +13 -0
  41. package/package.json +41 -0
  42. package/project.json +11 -0
  43. package/rollup.config.js +17 -0
  44. package/src/__tests__/auth.test.ts +213 -0
  45. package/src/__tests__/compat.test.ts +22 -0
  46. package/src/__tests__/functions.test.ts +312 -0
  47. package/src/__tests__/mongo.test.ts +83 -0
  48. package/src/__tests__/session.test.ts +597 -0
  49. package/src/__tests__/watch.test.ts +336 -0
  50. package/src/app.ts +562 -0
  51. package/src/bson.ts +6 -0
  52. package/src/credentials.ts +31 -0
  53. package/src/functions.ts +56 -0
  54. package/src/http.ts +221 -0
  55. package/src/index.ts +15 -0
  56. package/src/mongo.ts +112 -0
  57. package/src/session.native.ts +89 -0
  58. package/src/session.ts +114 -0
  59. package/src/types.ts +114 -0
  60. package/src/user.ts +150 -0
  61. package/src/watch.ts +156 -0
  62. package/tsconfig.json +34 -0
  63. package/tsconfig.spec.json +13 -0
package/dist/app.js ADDED
@@ -0,0 +1,461 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.App = void 0;
4
+ const functions_1 = require("./functions");
5
+ const http_1 = require("./http");
6
+ const session_1 = require("./session");
7
+ const credentials_1 = require("./credentials");
8
+ const user_1 = require("./user");
9
+ const API_PREFIX = '/api/client/v2.0';
10
+ class App {
11
+ constructor(idOrConfig) {
12
+ this.usersById = new Map();
13
+ this.sessionsByUserId = new Map();
14
+ this.usersOrder = [];
15
+ this.profilesByUserId = new Map();
16
+ this.listeners = new Set();
17
+ const config = typeof idOrConfig === 'string' ? { id: idOrConfig } : idOrConfig;
18
+ this.id = config.id;
19
+ this.baseUrl = (config.baseUrl ?? '').replace(/\/$/, '');
20
+ this.timeout = config.timeout ?? 10000;
21
+ this.sessionManager = new session_1.SessionManager(this.id);
22
+ const persistedSessionsByUser = this.sessionManager.getSessionsByUser();
23
+ for (const [userId, session] of Object.entries(persistedSessionsByUser)) {
24
+ this.sessionsByUserId.set(userId, session);
25
+ }
26
+ this.usersOrder = this.sessionManager.getUsersOrder();
27
+ for (const userId of this.sessionsByUserId.keys()) {
28
+ if (!this.usersOrder.includes(userId)) {
29
+ this.usersOrder.push(userId);
30
+ }
31
+ }
32
+ for (const userId of this.usersOrder) {
33
+ this.getOrCreateUser(userId);
34
+ }
35
+ const currentSession = this.sessionManager.get();
36
+ if (currentSession?.userId) {
37
+ this.sessionsByUserId.set(currentSession.userId, currentSession);
38
+ this.getOrCreateUser(currentSession.userId);
39
+ this.touchUser(currentSession.userId);
40
+ this.persistSessionsByUser();
41
+ }
42
+ else {
43
+ this.setCurrentSessionFromOrder();
44
+ }
45
+ this.sessionBootstrapPromise = this.bootstrapSessionOnLoad();
46
+ this.emailPasswordAuth = {
47
+ registerUser: ({ email, password }) => this.postProvider('/local-userpass/register', { email, password }),
48
+ confirmUser: ({ token, tokenId }) => this.postProvider('/local-userpass/confirm', { token, tokenId }),
49
+ resendConfirmationEmail: ({ email }) => this.postProvider('/local-userpass/confirm/send', { email }),
50
+ retryCustomConfirmation: ({ email }) => this.postProvider('/local-userpass/confirm/call', { email }),
51
+ sendResetPasswordEmail: (input) => this.postProvider('/local-userpass/reset/send', {
52
+ email: typeof input === 'string' ? input : input.email
53
+ }),
54
+ callResetPasswordFunction: (input, passwordOrArg, ...args) => {
55
+ if (typeof input === 'string') {
56
+ return this.postProvider('/local-userpass/reset/call', {
57
+ email: input,
58
+ password: passwordOrArg,
59
+ arguments: args
60
+ });
61
+ }
62
+ return this.postProvider('/local-userpass/reset/call', {
63
+ email: input.email,
64
+ password: input.password,
65
+ arguments: [passwordOrArg, ...args].filter((value) => value !== undefined)
66
+ });
67
+ },
68
+ resetPassword: ({ token, tokenId, password }) => this.postProvider('/local-userpass/reset', { token, tokenId, password })
69
+ };
70
+ }
71
+ static getApp(appIdOrConfig) {
72
+ const appId = typeof appIdOrConfig === 'string' ? appIdOrConfig : appIdOrConfig.id;
73
+ if (appId in App.appCache) {
74
+ return App.appCache[appId];
75
+ }
76
+ const app = new App(appIdOrConfig);
77
+ App.appCache[appId] = app;
78
+ return app;
79
+ }
80
+ get currentUser() {
81
+ for (const userId of this.usersOrder) {
82
+ const user = this.usersById.get(userId);
83
+ if (user?.state === 'active') {
84
+ return user;
85
+ }
86
+ }
87
+ return null;
88
+ }
89
+ get allUsers() {
90
+ const activeUsers = [];
91
+ const loggedOutUsers = [];
92
+ for (const userId of this.usersOrder) {
93
+ const user = this.usersById.get(userId);
94
+ if (!user)
95
+ continue;
96
+ if (user.state === 'active') {
97
+ activeUsers.push(userId);
98
+ }
99
+ else if (user.state === 'logged-out') {
100
+ loggedOutUsers.push(userId);
101
+ }
102
+ }
103
+ const users = Object.fromEntries([...activeUsers, ...loggedOutUsers].map((userId) => [userId, this.usersById.get(userId)]));
104
+ return users;
105
+ }
106
+ persistSessionsByUser() {
107
+ this.sessionManager.setSessionsByUser(Object.fromEntries(this.sessionsByUserId.entries()));
108
+ }
109
+ persistUsersOrder() {
110
+ this.sessionManager.setUsersOrder(this.usersOrder);
111
+ }
112
+ touchUser(userId) {
113
+ this.usersOrder = [userId, ...this.usersOrder.filter((id) => id !== userId)];
114
+ this.persistUsersOrder();
115
+ }
116
+ removeUserFromOrder(userId) {
117
+ this.usersOrder = this.usersOrder.filter((id) => id !== userId);
118
+ this.persistUsersOrder();
119
+ }
120
+ setSessionForUser(session) {
121
+ this.sessionsByUserId.set(session.userId, session);
122
+ this.sessionManager.set(session);
123
+ this.persistSessionsByUser();
124
+ }
125
+ clearSessionForUser(userId) {
126
+ this.sessionsByUserId.delete(userId);
127
+ this.persistSessionsByUser();
128
+ }
129
+ setCurrentSessionFromOrder() {
130
+ for (const userId of this.usersOrder) {
131
+ const session = this.sessionsByUserId.get(userId);
132
+ if (session) {
133
+ this.sessionManager.set(session);
134
+ return;
135
+ }
136
+ }
137
+ this.sessionManager.clear();
138
+ }
139
+ notifyListeners(userId) {
140
+ for (const callback of Array.from(this.listeners)) {
141
+ try {
142
+ callback();
143
+ }
144
+ catch {
145
+ // Listener failures should not break auth/session lifecycle.
146
+ }
147
+ }
148
+ if (userId) {
149
+ this.usersById.get(userId)?.notifyListeners();
150
+ }
151
+ }
152
+ providerUrl(path) {
153
+ return `${this.baseUrl}${API_PREFIX}/app/${this.id}/auth/providers${path}`;
154
+ }
155
+ authUrl(path) {
156
+ return `${this.baseUrl}${API_PREFIX}/auth${path}`;
157
+ }
158
+ functionsUrl(path = '/call') {
159
+ return `${this.baseUrl}${API_PREFIX}/app/${this.id}/functions${path}`;
160
+ }
161
+ async createSession(refreshToken) {
162
+ return (0, http_1.requestJson)({
163
+ url: this.authUrl('/session'),
164
+ method: 'POST',
165
+ bearerToken: refreshToken,
166
+ timeout: this.timeout
167
+ });
168
+ }
169
+ async bootstrapSessionOnLoad() {
170
+ const session = this.sessionManager.get();
171
+ if (!session || typeof localStorage === 'undefined') {
172
+ return;
173
+ }
174
+ try {
175
+ const result = await this.createSession(session.refreshToken);
176
+ this.setSessionForUser({
177
+ ...session,
178
+ accessToken: result.access_token
179
+ });
180
+ }
181
+ catch {
182
+ this.clearSessionForUser(session.userId);
183
+ this.setCurrentSessionFromOrder();
184
+ }
185
+ }
186
+ async ensureSessionBootstrapped() {
187
+ await this.sessionBootstrapPromise;
188
+ }
189
+ async setLoggedInUser(data, providerType, profileEmail) {
190
+ const sessionResult = await this.createSession(data.refresh_token);
191
+ const session = {
192
+ accessToken: sessionResult.access_token,
193
+ refreshToken: data.refresh_token,
194
+ userId: data.user_id
195
+ };
196
+ this.setSessionForUser(session);
197
+ const user = this.getOrCreateUser(data.user_id);
198
+ user.setProviderType(providerType);
199
+ this.touchUser(data.user_id);
200
+ if (profileEmail) {
201
+ user.profile = { email: profileEmail };
202
+ }
203
+ this.notifyListeners(data.user_id);
204
+ return user;
205
+ }
206
+ getOrCreateUser(userId) {
207
+ const existing = this.usersById.get(userId);
208
+ if (existing) {
209
+ return existing;
210
+ }
211
+ const user = new user_1.User(this, userId);
212
+ this.usersById.set(userId, user);
213
+ return user;
214
+ }
215
+ async logIn(credentials) {
216
+ if (credentials.provider === 'local-userpass') {
217
+ const result = await this.postProvider('/local-userpass/login', {
218
+ username: credentials.email,
219
+ password: credentials.password
220
+ });
221
+ return this.setLoggedInUser(result, 'local-userpass', credentials.email);
222
+ }
223
+ if (credentials.provider === 'anon-user') {
224
+ const result = await this.postProvider('/anon-user/login', {});
225
+ return this.setLoggedInUser(result, 'anon-user');
226
+ }
227
+ if (credentials.provider === 'custom-function') {
228
+ const result = await this.postProvider('/custom-function/login', credentials.payload);
229
+ return this.setLoggedInUser(result, 'custom-function');
230
+ }
231
+ if (credentials.provider === 'custom-token') {
232
+ const result = await this.postProvider('/custom-token/login', { token: credentials.token });
233
+ return this.setLoggedInUser(result, 'custom-token');
234
+ }
235
+ const unsupportedProvider = credentials;
236
+ throw new Error(`Unsupported credentials provider: ${JSON.stringify(unsupportedProvider)}`);
237
+ }
238
+ switchUser(nextUser) {
239
+ const knownUser = this.usersById.get(nextUser.id);
240
+ if (!knownUser) {
241
+ throw new Error('The user was never logged into this app');
242
+ }
243
+ this.touchUser(nextUser.id);
244
+ const session = this.sessionsByUserId.get(nextUser.id);
245
+ if (session) {
246
+ this.sessionManager.set(session);
247
+ }
248
+ this.notifyListeners(nextUser.id);
249
+ }
250
+ async removeUser(user) {
251
+ const knownUser = this.usersById.get(user.id);
252
+ if (!knownUser) {
253
+ throw new Error('The user was never logged into this app');
254
+ }
255
+ if (this.sessionsByUserId.has(user.id)) {
256
+ await this.logoutUser(user.id);
257
+ }
258
+ this.usersById.delete(user.id);
259
+ this.removeUserFromOrder(user.id);
260
+ this.profilesByUserId.delete(user.id);
261
+ this.clearSessionForUser(user.id);
262
+ this.setCurrentSessionFromOrder();
263
+ this.notifyListeners(user.id);
264
+ }
265
+ async deleteUser(user) {
266
+ await this.requestWithAccessToken((accessToken) => (0, http_1.requestJson)({
267
+ url: this.authUrl('/delete'),
268
+ method: 'DELETE',
269
+ bearerToken: accessToken,
270
+ timeout: this.timeout
271
+ }), user.id);
272
+ await this.removeUser(user);
273
+ }
274
+ getSessionOrThrow(userId) {
275
+ const targetUserId = userId ?? this.currentUser?.id;
276
+ const session = targetUserId ? this.sessionsByUserId.get(targetUserId) : this.sessionManager.get();
277
+ if (!session) {
278
+ throw new Error('User is not authenticated');
279
+ }
280
+ return session;
281
+ }
282
+ getSession(userId) {
283
+ if (userId) {
284
+ return this.sessionsByUserId.get(userId) ?? null;
285
+ }
286
+ return this.sessionManager.get();
287
+ }
288
+ hasUser(userId) {
289
+ return this.usersById.has(userId);
290
+ }
291
+ getProfileSnapshot(userId) {
292
+ return this.profilesByUserId.get(userId);
293
+ }
294
+ async postProvider(path, body) {
295
+ return (0, http_1.requestJson)({
296
+ url: this.providerUrl(path),
297
+ method: 'POST',
298
+ body,
299
+ timeout: this.timeout
300
+ });
301
+ }
302
+ async requestWithAccessToken(operation, userId) {
303
+ const firstSession = this.getSessionOrThrow(userId);
304
+ try {
305
+ return await operation(firstSession.accessToken);
306
+ }
307
+ catch (error) {
308
+ if (!(error instanceof http_1.FlowerbaseHttpError) || error.status !== 401) {
309
+ throw error;
310
+ }
311
+ await this.refreshAccessToken(userId);
312
+ const refreshedSession = this.getSessionOrThrow(userId);
313
+ return operation(refreshedSession.accessToken);
314
+ }
315
+ }
316
+ async callFunction(name, args, userId) {
317
+ await this.ensureSessionBootstrapped();
318
+ const payload = {
319
+ name,
320
+ arguments: args
321
+ };
322
+ const result = await this.requestWithAccessToken((accessToken) => (0, http_1.requestJson)({
323
+ url: this.functionsUrl('/call'),
324
+ method: 'POST',
325
+ body: payload,
326
+ bearerToken: accessToken,
327
+ timeout: this.timeout
328
+ }), userId);
329
+ return (0, functions_1.normalizeFunctionResponse)(result);
330
+ }
331
+ async callFunctionStreaming(name, args, userId) {
332
+ await this.ensureSessionBootstrapped();
333
+ const payload = {
334
+ name,
335
+ arguments: args
336
+ };
337
+ const resolveSession = () => this.getSessionOrThrow(userId);
338
+ const refreshSession = () => this.refreshAccessToken(userId);
339
+ const timeout = this.timeout;
340
+ const url = this.functionsUrl('/call');
341
+ return {
342
+ async *[Symbol.asyncIterator]() {
343
+ let didRefresh = false;
344
+ while (true) {
345
+ const session = resolveSession();
346
+ let stream;
347
+ try {
348
+ stream = await (0, http_1.requestStream)({
349
+ url,
350
+ method: 'POST',
351
+ body: payload,
352
+ bearerToken: session.accessToken,
353
+ timeout
354
+ });
355
+ }
356
+ catch (error) {
357
+ if (!didRefresh && error instanceof http_1.FlowerbaseHttpError && error.status === 401) {
358
+ await refreshSession();
359
+ didRefresh = true;
360
+ continue;
361
+ }
362
+ throw error;
363
+ }
364
+ try {
365
+ for await (const chunk of stream) {
366
+ yield chunk;
367
+ }
368
+ return;
369
+ }
370
+ catch (error) {
371
+ if (!didRefresh && error instanceof http_1.FlowerbaseHttpError && error.status === 401) {
372
+ await refreshSession();
373
+ didRefresh = true;
374
+ continue;
375
+ }
376
+ throw error;
377
+ }
378
+ }
379
+ }
380
+ };
381
+ }
382
+ async callService(name, args, service = 'mongodb-atlas', userId) {
383
+ await this.ensureSessionBootstrapped();
384
+ const payload = {
385
+ name,
386
+ service,
387
+ arguments: args
388
+ };
389
+ return this.requestWithAccessToken((accessToken) => (0, http_1.requestJson)({
390
+ url: this.functionsUrl('/call'),
391
+ method: 'POST',
392
+ body: payload,
393
+ bearerToken: accessToken,
394
+ timeout: this.timeout
395
+ }), userId);
396
+ }
397
+ async getProfile(userId) {
398
+ await this.ensureSessionBootstrapped();
399
+ const profile = await this.requestWithAccessToken((accessToken) => (0, http_1.requestJson)({
400
+ url: this.authUrl('/profile'),
401
+ method: 'GET',
402
+ bearerToken: accessToken,
403
+ timeout: this.timeout
404
+ }), userId);
405
+ const session = this.getSessionOrThrow(userId);
406
+ this.profilesByUserId.set(session.userId, profile);
407
+ return profile;
408
+ }
409
+ async refreshAccessToken(userId) {
410
+ await this.ensureSessionBootstrapped();
411
+ const session = this.getSessionOrThrow(userId);
412
+ try {
413
+ const result = await this.createSession(session.refreshToken);
414
+ this.setSessionForUser({
415
+ ...session,
416
+ accessToken: result.access_token
417
+ });
418
+ this.touchUser(session.userId);
419
+ this.notifyListeners(session.userId);
420
+ return result.access_token;
421
+ }
422
+ catch (error) {
423
+ this.clearSessionForUser(session.userId);
424
+ this.setCurrentSessionFromOrder();
425
+ this.notifyListeners(session.userId);
426
+ throw error;
427
+ }
428
+ }
429
+ async logoutUser(userId) {
430
+ const session = this.getSession(userId ?? this.currentUser?.id);
431
+ try {
432
+ if (session) {
433
+ await (0, http_1.requestJson)({
434
+ url: this.authUrl('/session'),
435
+ method: 'DELETE',
436
+ bearerToken: session.refreshToken,
437
+ timeout: this.timeout
438
+ });
439
+ }
440
+ }
441
+ finally {
442
+ if (session) {
443
+ this.clearSessionForUser(session.userId);
444
+ this.notifyListeners(session.userId);
445
+ }
446
+ this.setCurrentSessionFromOrder();
447
+ }
448
+ }
449
+ addListener(callback) {
450
+ this.listeners.add(callback);
451
+ }
452
+ removeListener(callback) {
453
+ this.listeners.delete(callback);
454
+ }
455
+ removeAllListeners() {
456
+ this.listeners.clear();
457
+ }
458
+ }
459
+ exports.App = App;
460
+ App.appCache = {};
461
+ App.Credentials = credentials_1.Credentials;
package/dist/bson.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { EJSON, ObjectId, BSON as RawBSON } from 'bson';
2
+ declare const ObjectID: typeof ObjectId;
3
+ declare const BSON: typeof RawBSON & {
4
+ ObjectId: typeof ObjectId;
5
+ ObjectID: typeof ObjectId;
6
+ };
7
+ export { BSON, EJSON, ObjectId, ObjectID };
8
+ //# sourceMappingURL=bson.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bson.d.ts","sourceRoot":"","sources":["../src/bson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,MAAM,CAAA;AAEvD,QAAA,MAAM,QAAQ,iBAAW,CAAA;AACzB,QAAA,MAAM,IAAI;;;CAAqD,CAAA;AAE/D,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAA"}
package/dist/bson.js ADDED
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ObjectID = exports.ObjectId = exports.EJSON = exports.BSON = void 0;
4
+ const bson_1 = require("bson");
5
+ Object.defineProperty(exports, "EJSON", { enumerable: true, get: function () { return bson_1.EJSON; } });
6
+ Object.defineProperty(exports, "ObjectId", { enumerable: true, get: function () { return bson_1.ObjectId; } });
7
+ const ObjectID = bson_1.ObjectId;
8
+ exports.ObjectID = ObjectID;
9
+ const BSON = Object.assign({}, bson_1.BSON, { ObjectId: bson_1.ObjectId, ObjectID });
10
+ exports.BSON = BSON;
@@ -0,0 +1,8 @@
1
+ import { CredentialsLike } from './types';
2
+ export declare class Credentials {
3
+ static emailPassword(email: string, password: string): CredentialsLike;
4
+ static anonymous(): CredentialsLike;
5
+ static function(payload: Record<string, unknown>): CredentialsLike;
6
+ static jwt(token: string): CredentialsLike;
7
+ }
8
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAEzC,qBAAa,WAAW;IACtB,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe;IAQtE,MAAM,CAAC,SAAS,IAAI,eAAe;IAMnC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,eAAe;IAOlE,MAAM,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe;CAM3C"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Credentials = void 0;
4
+ class Credentials {
5
+ static emailPassword(email, password) {
6
+ return {
7
+ provider: 'local-userpass',
8
+ email,
9
+ password
10
+ };
11
+ }
12
+ static anonymous() {
13
+ return {
14
+ provider: 'anon-user'
15
+ };
16
+ }
17
+ static function(payload) {
18
+ return {
19
+ provider: 'custom-function',
20
+ payload
21
+ };
22
+ }
23
+ static jwt(token) {
24
+ return {
25
+ provider: 'custom-token',
26
+ token
27
+ };
28
+ }
29
+ }
30
+ exports.Credentials = Credentials;
@@ -0,0 +1,6 @@
1
+ export declare const normalizeFunctionResponse: (value: unknown) => any;
2
+ export declare const createFunctionsProxy: (callFunction: (name: string, args: unknown[]) => Promise<unknown>, callFunctionStreaming: (name: string, args: unknown[]) => Promise<AsyncIterable<Uint8Array>>) => Record<string, (...args: unknown[]) => Promise<unknown>> & {
3
+ callFunction: (name: string, ...args: unknown[]) => Promise<unknown>;
4
+ callFunctionStreaming: (name: string, ...args: unknown[]) => Promise<AsyncIterable<Uint8Array>>;
5
+ };
6
+ //# sourceMappingURL=functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,yBAAyB,UAAW,OAAO,QAWvD,CAAA;AAED,eAAO,MAAM,oBAAoB,iBACjB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,OAAO,CAAC,yBAC1C,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,cAAc,UAAU,CAAC,CAAC,KAC3F,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,OAAO,CAAC,CAAC,GAAG;IAC5D,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,OAAO,CAAC,CAAA;IACpE,qBAAqB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,QAAQ,cAAc,UAAU,CAAC,CAAC,CAAA;CAoB9F,CAAA"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createFunctionsProxy = exports.normalizeFunctionResponse = void 0;
4
+ const bson_1 = require("./bson");
5
+ const RESERVED_PROXY_KEYS = new Set([
6
+ 'toJSON',
7
+ 'then',
8
+ 'catch',
9
+ 'finally',
10
+ 'constructor',
11
+ '__proto__',
12
+ 'prototype'
13
+ ]);
14
+ const deserialize = (value) => {
15
+ if (!value || typeof value !== 'object')
16
+ return value;
17
+ return bson_1.EJSON.deserialize(value);
18
+ };
19
+ const normalizeFunctionResponse = (value) => {
20
+ if (typeof value === 'string') {
21
+ try {
22
+ const parsed = JSON.parse(value);
23
+ return deserialize(parsed);
24
+ }
25
+ catch {
26
+ return value;
27
+ }
28
+ }
29
+ return deserialize(value);
30
+ };
31
+ exports.normalizeFunctionResponse = normalizeFunctionResponse;
32
+ const createFunctionsProxy = (callFunction, callFunctionStreaming) => new Proxy({}, {
33
+ get: (_, key) => {
34
+ if (typeof key !== 'string')
35
+ return undefined;
36
+ if (RESERVED_PROXY_KEYS.has(key))
37
+ return undefined;
38
+ if (key === 'callFunction') {
39
+ return (name, ...args) => callFunction(name, args);
40
+ }
41
+ if (key === 'callFunctionStreaming') {
42
+ return (name, ...args) => callFunctionStreaming(name, args);
43
+ }
44
+ return (...args) => callFunction(key, args);
45
+ }
46
+ });
47
+ exports.createFunctionsProxy = createFunctionsProxy;
package/dist/http.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export declare class MongoDBRealmError extends Error {
2
+ readonly method: string;
3
+ readonly url: string;
4
+ readonly statusCode: number;
5
+ readonly statusText: string;
6
+ readonly error: string | undefined;
7
+ readonly errorCode: string | undefined;
8
+ readonly link: string | undefined;
9
+ readonly payload?: unknown;
10
+ constructor(params: {
11
+ method: string;
12
+ url: string;
13
+ statusCode: number;
14
+ statusText: string;
15
+ error?: string;
16
+ errorCode?: string;
17
+ link?: string;
18
+ payload?: unknown;
19
+ });
20
+ }
21
+ export declare class FlowerbaseHttpError extends MongoDBRealmError {
22
+ readonly status: number;
23
+ constructor(params: ConstructorParameters<typeof MongoDBRealmError>[0]);
24
+ }
25
+ type RequestParams = {
26
+ url: string;
27
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
28
+ body?: unknown;
29
+ bearerToken?: string;
30
+ timeout?: number;
31
+ };
32
+ export declare const requestJson: <T = unknown>({ url, method, body, bearerToken, timeout }: RequestParams) => Promise<T>;
33
+ export declare const requestStream: ({ url, method, body, bearerToken, timeout }: RequestParams) => Promise<AsyncIterable<Uint8Array>>;
34
+ export {};
35
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAmDA,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAA;gBAEd,MAAM,EAAE;QAClB,MAAM,EAAE,MAAM,CAAA;QACd,GAAG,EAAE,MAAM,CAAA;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,MAAM,CAAA;QACd,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,OAAO,CAAA;KAClB;CAYF;AAED,qBAAa,mBAAoB,SAAQ,iBAAiB;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;gBAEX,MAAM,EAAE,qBAAqB,CAAC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAC;CAKvE;AAED,KAAK,aAAa,GAAG;IACnB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;IACpD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAsBD,eAAO,MAAM,WAAW,6DAMrB,aAAa,KAAG,QAAQ,CAAC,CAkC3B,CAAA;AAED,eAAO,MAAM,aAAa,gDAMvB,aAAa,KAAG,QAAQ,cAAc,UAAU,CAAC,CAkDnD,CAAA"}