@flowerforce/flowerbase-client 0.1.1-beta.2
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/CHANGELOG.md +0 -0
- package/LICENSE +3 -0
- package/README.md +198 -0
- package/dist/app.d.ts +40 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +186 -0
- package/dist/bson.d.ts +8 -0
- package/dist/bson.d.ts.map +1 -0
- package/dist/bson.js +10 -0
- package/dist/credentials.d.ts +7 -0
- package/dist/credentials.d.ts.map +1 -0
- package/dist/credentials.js +24 -0
- package/dist/functions.d.ts +3 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +30 -0
- package/dist/http.d.ts +15 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +74 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/mongo.d.ts +4 -0
- package/dist/mongo.d.ts.map +1 -0
- package/dist/mongo.js +61 -0
- package/dist/session.d.ts +12 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +53 -0
- package/dist/session.native.d.ts +14 -0
- package/dist/session.native.d.ts.map +1 -0
- package/dist/session.native.js +81 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/user.d.ts +17 -0
- package/dist/user.d.ts.map +1 -0
- package/dist/user.js +30 -0
- package/dist/watch.d.ts +3 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +138 -0
- package/jest.config.ts +13 -0
- package/package.json +30 -0
- package/project.json +11 -0
- package/rollup.config.js +17 -0
- package/src/__tests__/auth.test.ts +164 -0
- package/src/__tests__/compat.test.ts +12 -0
- package/src/__tests__/functions.test.ts +76 -0
- package/src/__tests__/mongo.test.ts +48 -0
- package/src/__tests__/session.test.ts +103 -0
- package/src/__tests__/watch.test.ts +138 -0
- package/src/app.ts +235 -0
- package/src/bson.ts +6 -0
- package/src/credentials.ts +24 -0
- package/src/functions.ts +32 -0
- package/src/http.ts +92 -0
- package/src/index.ts +14 -0
- package/src/mongo.ts +63 -0
- package/src/session.native.ts +98 -0
- package/src/session.ts +59 -0
- package/src/types.ts +84 -0
- package/src/user.ts +39 -0
- package/src/watch.ts +150 -0
- package/tsconfig.json +34 -0
- package/tsconfig.spec.json +13 -0
package/dist/mongo.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createMongoClient = void 0;
|
|
4
|
+
const bson_1 = require("./bson");
|
|
5
|
+
const watch_1 = require("./watch");
|
|
6
|
+
const serialize = (value) => bson_1.EJSON.serialize(value, { relaxed: false });
|
|
7
|
+
const deserialize = (value) => {
|
|
8
|
+
if (!value || typeof value !== 'object')
|
|
9
|
+
return value;
|
|
10
|
+
return bson_1.EJSON.deserialize(value);
|
|
11
|
+
};
|
|
12
|
+
const mapResult = (value) => {
|
|
13
|
+
if (typeof value === 'string') {
|
|
14
|
+
try {
|
|
15
|
+
return deserialize(JSON.parse(value));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return deserialize(value);
|
|
22
|
+
};
|
|
23
|
+
const createMongoClient = (app) => ({
|
|
24
|
+
db: (database) => ({
|
|
25
|
+
collection: (collection) => {
|
|
26
|
+
const callService = async (name, args) => {
|
|
27
|
+
const result = await app.callService(name, [
|
|
28
|
+
{
|
|
29
|
+
database,
|
|
30
|
+
collection,
|
|
31
|
+
...serialize(args[0] ?? {}),
|
|
32
|
+
...(args[1] !== undefined ? { options: serialize(args[1]) } : {})
|
|
33
|
+
}
|
|
34
|
+
]);
|
|
35
|
+
return mapResult(result);
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
find: (query = {}, options = {}) => callService('find', [{ query, options }]),
|
|
39
|
+
findOne: (query = {}, options = {}) => callService('findOne', [{ query, options }]),
|
|
40
|
+
insertOne: (document, options = {}) => callService('insertOne', [{ document, options }]),
|
|
41
|
+
updateOne: (filter, update, options = {}) => callService('updateOne', [{ filter, update, options }]),
|
|
42
|
+
updateMany: (filter, update, options = {}) => callService('updateMany', [{ filter, update, options }]),
|
|
43
|
+
deleteOne: (filter, options = {}) => callService('deleteOne', [{ query: filter, options }]),
|
|
44
|
+
watch: (pipeline = [], options = {}) => {
|
|
45
|
+
const session = app.getSessionOrThrow();
|
|
46
|
+
return (0, watch_1.createWatchIterator)({
|
|
47
|
+
appId: app.id,
|
|
48
|
+
baseUrl: app.baseUrl,
|
|
49
|
+
accessToken: session.accessToken,
|
|
50
|
+
database,
|
|
51
|
+
collection,
|
|
52
|
+
pipeline,
|
|
53
|
+
options,
|
|
54
|
+
timeout: app.timeout
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
});
|
|
61
|
+
exports.createMongoClient = createMongoClient;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SessionData } from './types';
|
|
2
|
+
export declare class SessionManager {
|
|
3
|
+
private readonly key;
|
|
4
|
+
private readonly storage;
|
|
5
|
+
private session;
|
|
6
|
+
constructor(appId: string);
|
|
7
|
+
load(): SessionData | null;
|
|
8
|
+
get(): SessionData | null;
|
|
9
|
+
set(session: SessionData): void;
|
|
10
|
+
clear(): void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAwBrC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,KAAK,EAAE,MAAM;IAKzB,IAAI,IAAI,WAAW,GAAG,IAAI;IAW1B,GAAG;IAIH,GAAG,CAAC,OAAO,EAAE,WAAW;IAKxB,KAAK;CAIN"}
|
package/dist/session.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionManager = void 0;
|
|
4
|
+
const memoryStore = new Map();
|
|
5
|
+
const getStorage = () => {
|
|
6
|
+
if (typeof localStorage !== 'undefined') {
|
|
7
|
+
return {
|
|
8
|
+
getItem: (key) => localStorage.getItem(key),
|
|
9
|
+
setItem: (key, value) => localStorage.setItem(key, value),
|
|
10
|
+
removeItem: (key) => localStorage.removeItem(key)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
getItem: (key) => memoryStore.get(key) ?? null,
|
|
15
|
+
setItem: (key, value) => {
|
|
16
|
+
memoryStore.set(key, value);
|
|
17
|
+
},
|
|
18
|
+
removeItem: (key) => {
|
|
19
|
+
memoryStore.delete(key);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
class SessionManager {
|
|
24
|
+
constructor(appId) {
|
|
25
|
+
this.storage = getStorage();
|
|
26
|
+
this.session = null;
|
|
27
|
+
this.key = `flowerbase:${appId}:session`;
|
|
28
|
+
this.session = this.load();
|
|
29
|
+
}
|
|
30
|
+
load() {
|
|
31
|
+
const raw = this.storage.getItem(this.key);
|
|
32
|
+
if (!raw)
|
|
33
|
+
return null;
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
get() {
|
|
42
|
+
return this.session;
|
|
43
|
+
}
|
|
44
|
+
set(session) {
|
|
45
|
+
this.session = session;
|
|
46
|
+
this.storage.setItem(this.key, JSON.stringify(session));
|
|
47
|
+
}
|
|
48
|
+
clear() {
|
|
49
|
+
this.session = null;
|
|
50
|
+
this.storage.removeItem(this.key);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
exports.SessionManager = SessionManager;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SessionData } from './types';
|
|
2
|
+
export declare class SessionManager {
|
|
3
|
+
private readonly key;
|
|
4
|
+
private session;
|
|
5
|
+
private readonly asyncStorage;
|
|
6
|
+
private hydrationPromise;
|
|
7
|
+
constructor(appId: string);
|
|
8
|
+
private hydrateFromAsyncStorage;
|
|
9
|
+
load(): SessionData | null;
|
|
10
|
+
get(): SessionData | null;
|
|
11
|
+
set(session: SessionData): void;
|
|
12
|
+
clear(): void;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=session.native.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.native.d.ts","sourceRoot":"","sources":["../src/session.native.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AA+BrC,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,gBAAgB,CAA6B;gBAEzC,KAAK,EAAE,MAAM;IAMzB,OAAO,CAAC,uBAAuB;IAwB/B,IAAI,IAAI,WAAW,GAAG,IAAI;IAI1B,GAAG;IAIH,GAAG,CAAC,OAAO,EAAE,WAAW;IAYxB,KAAK;CAUN"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionManager = void 0;
|
|
4
|
+
const memoryStore = new Map();
|
|
5
|
+
const getAsyncStorage = () => {
|
|
6
|
+
try {
|
|
7
|
+
const req = (0, eval)('require');
|
|
8
|
+
const asyncStorageModule = req('@react-native-async-storage/async-storage');
|
|
9
|
+
return asyncStorageModule?.default ?? null;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
const parseSession = (raw) => {
|
|
16
|
+
if (!raw)
|
|
17
|
+
return null;
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(raw);
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
class SessionManager {
|
|
26
|
+
constructor(appId) {
|
|
27
|
+
this.session = null;
|
|
28
|
+
this.asyncStorage = getAsyncStorage();
|
|
29
|
+
this.hydrationPromise = null;
|
|
30
|
+
this.key = `flowerbase:${appId}:session`;
|
|
31
|
+
this.session = this.load();
|
|
32
|
+
void this.hydrateFromAsyncStorage();
|
|
33
|
+
}
|
|
34
|
+
hydrateFromAsyncStorage() {
|
|
35
|
+
if (!this.asyncStorage) {
|
|
36
|
+
return Promise.resolve();
|
|
37
|
+
}
|
|
38
|
+
if (this.hydrationPromise) {
|
|
39
|
+
return this.hydrationPromise;
|
|
40
|
+
}
|
|
41
|
+
this.hydrationPromise = this.asyncStorage
|
|
42
|
+
.getItem(this.key)
|
|
43
|
+
.then((raw) => {
|
|
44
|
+
const parsed = parseSession(raw);
|
|
45
|
+
if (!parsed)
|
|
46
|
+
return;
|
|
47
|
+
this.session = parsed;
|
|
48
|
+
memoryStore.set(this.key, JSON.stringify(parsed));
|
|
49
|
+
})
|
|
50
|
+
.catch(() => {
|
|
51
|
+
// Ignore storage read failures and keep memory fallback.
|
|
52
|
+
});
|
|
53
|
+
return this.hydrationPromise;
|
|
54
|
+
}
|
|
55
|
+
load() {
|
|
56
|
+
return parseSession(memoryStore.get(this.key) ?? null);
|
|
57
|
+
}
|
|
58
|
+
get() {
|
|
59
|
+
return this.session;
|
|
60
|
+
}
|
|
61
|
+
set(session) {
|
|
62
|
+
this.session = session;
|
|
63
|
+
const raw = JSON.stringify(session);
|
|
64
|
+
memoryStore.set(this.key, raw);
|
|
65
|
+
if (this.asyncStorage) {
|
|
66
|
+
void this.asyncStorage.setItem(this.key, raw).catch(() => {
|
|
67
|
+
// Ignore write failures and keep memory fallback.
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
clear() {
|
|
72
|
+
this.session = null;
|
|
73
|
+
memoryStore.delete(this.key);
|
|
74
|
+
if (this.asyncStorage) {
|
|
75
|
+
void this.asyncStorage.removeItem(this.key).catch(() => {
|
|
76
|
+
// Ignore delete failures and keep memory fallback.
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.SessionManager = SessionManager;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export type AppConfig = {
|
|
2
|
+
id: string;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
};
|
|
6
|
+
export type CredentialsLike = {
|
|
7
|
+
provider: 'local-userpass';
|
|
8
|
+
email: string;
|
|
9
|
+
password: string;
|
|
10
|
+
} | {
|
|
11
|
+
provider: 'anon-user';
|
|
12
|
+
} | {
|
|
13
|
+
provider: 'custom-function';
|
|
14
|
+
payload: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
export type SessionData = {
|
|
17
|
+
accessToken: string;
|
|
18
|
+
refreshToken: string;
|
|
19
|
+
userId: string;
|
|
20
|
+
};
|
|
21
|
+
export type ProfileData = {
|
|
22
|
+
_id?: string;
|
|
23
|
+
identities?: unknown[];
|
|
24
|
+
type?: string;
|
|
25
|
+
custom_data?: Record<string, unknown>;
|
|
26
|
+
data?: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
export type FunctionCallPayload = {
|
|
29
|
+
name: string;
|
|
30
|
+
arguments: unknown[];
|
|
31
|
+
service?: string;
|
|
32
|
+
};
|
|
33
|
+
export type WatchConfig = {
|
|
34
|
+
appId: string;
|
|
35
|
+
baseUrl: string;
|
|
36
|
+
accessToken: string;
|
|
37
|
+
database: string;
|
|
38
|
+
collection: string;
|
|
39
|
+
pipeline?: unknown[];
|
|
40
|
+
options?: Record<string, unknown>;
|
|
41
|
+
timeout?: number;
|
|
42
|
+
};
|
|
43
|
+
export type WatchAsyncIterator<TChange = unknown> = AsyncIterableIterator<TChange> & {
|
|
44
|
+
close: () => void;
|
|
45
|
+
};
|
|
46
|
+
export interface CollectionLike {
|
|
47
|
+
find: (query?: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
48
|
+
findOne: (query?: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
49
|
+
insertOne: (document: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
50
|
+
updateOne: (filter: Record<string, unknown>, update: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
51
|
+
updateMany: (filter: Record<string, unknown>, update: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
52
|
+
deleteOne: (filter: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>;
|
|
53
|
+
watch: (pipeline?: unknown[], options?: Record<string, unknown>) => WatchAsyncIterator<unknown>;
|
|
54
|
+
}
|
|
55
|
+
export interface MongoDbLike {
|
|
56
|
+
collection: (name: string) => CollectionLike;
|
|
57
|
+
}
|
|
58
|
+
export interface MongoClientLike {
|
|
59
|
+
db: (name: string) => MongoDbLike;
|
|
60
|
+
}
|
|
61
|
+
export interface UserLike {
|
|
62
|
+
id: string;
|
|
63
|
+
profile?: {
|
|
64
|
+
email?: string;
|
|
65
|
+
[key: string]: unknown;
|
|
66
|
+
};
|
|
67
|
+
functions: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
68
|
+
logOut: () => Promise<void>;
|
|
69
|
+
refreshAccessToken: () => Promise<string>;
|
|
70
|
+
refreshCustomData: () => Promise<ProfileData>;
|
|
71
|
+
mongoClient: (serviceName: string) => MongoClientLike;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
package/dist/user.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { App } from './app';
|
|
2
|
+
import { MongoClientLike, ProfileData, UserLike } from './types';
|
|
3
|
+
export declare class User implements UserLike {
|
|
4
|
+
id: string;
|
|
5
|
+
profile?: {
|
|
6
|
+
email?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
};
|
|
9
|
+
private readonly app;
|
|
10
|
+
functions: Record<string, (...args: unknown[]) => Promise<unknown>>;
|
|
11
|
+
constructor(app: App, id: string);
|
|
12
|
+
logOut(): Promise<void>;
|
|
13
|
+
refreshAccessToken(): Promise<string>;
|
|
14
|
+
refreshCustomData(): Promise<ProfileData>;
|
|
15
|
+
mongoClient(serviceName: string): MongoClientLike;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=user.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAGhC,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAEhE,qBAAa,IAAK,YAAW,QAAQ;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAA,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAA;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IAEzB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;gBAEvD,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM;IAM1B,MAAM;IAIN,kBAAkB;IAIlB,iBAAiB,IAAI,OAAO,CAAC,WAAW,CAAC;IAM/C,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe;CAMlD"}
|
package/dist/user.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.User = void 0;
|
|
4
|
+
const functions_1 = require("./functions");
|
|
5
|
+
const mongo_1 = require("./mongo");
|
|
6
|
+
class User {
|
|
7
|
+
constructor(app, id) {
|
|
8
|
+
this.app = app;
|
|
9
|
+
this.id = id;
|
|
10
|
+
this.functions = (0, functions_1.createFunctionsProxy)((name, args) => this.app.callFunction(name, args));
|
|
11
|
+
}
|
|
12
|
+
async logOut() {
|
|
13
|
+
await this.app.logoutUser();
|
|
14
|
+
}
|
|
15
|
+
async refreshAccessToken() {
|
|
16
|
+
return this.app.refreshAccessToken();
|
|
17
|
+
}
|
|
18
|
+
async refreshCustomData() {
|
|
19
|
+
const profile = await this.app.getProfile();
|
|
20
|
+
this.profile = profile.data;
|
|
21
|
+
return profile.custom_data || {};
|
|
22
|
+
}
|
|
23
|
+
mongoClient(serviceName) {
|
|
24
|
+
if (serviceName !== 'mongodb-atlas') {
|
|
25
|
+
throw new Error(`Unsupported service "${serviceName}"`);
|
|
26
|
+
}
|
|
27
|
+
return (0, mongo_1.createMongoClient)(this.app);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.User = User;
|
package/dist/watch.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAoCzD,eAAO,MAAM,mBAAmB,WAAY,WAAW,KAAG,mBAAmB,OAAO,CAiHnF,CAAA"}
|
package/dist/watch.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createWatchIterator = void 0;
|
|
4
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
5
|
+
const createWatchRequest = ({ database, collection, pipeline = [], options = {} }) => ({
|
|
6
|
+
name: 'watch',
|
|
7
|
+
service: 'mongodb-atlas',
|
|
8
|
+
arguments: [
|
|
9
|
+
{
|
|
10
|
+
database,
|
|
11
|
+
collection,
|
|
12
|
+
pipeline,
|
|
13
|
+
options
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
});
|
|
17
|
+
const toBase64 = (input) => {
|
|
18
|
+
if (typeof btoa === 'function') {
|
|
19
|
+
return btoa(input);
|
|
20
|
+
}
|
|
21
|
+
throw new Error('Base64 encoder not available in current runtime');
|
|
22
|
+
};
|
|
23
|
+
const parseSsePayload = (line) => {
|
|
24
|
+
if (!line.startsWith('data:'))
|
|
25
|
+
return null;
|
|
26
|
+
const raw = line.slice(5).trim();
|
|
27
|
+
if (!raw)
|
|
28
|
+
return null;
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return raw;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const createWatchIterator = (config) => {
|
|
37
|
+
let closed = false;
|
|
38
|
+
let activeController = null;
|
|
39
|
+
const queue = [];
|
|
40
|
+
const waiters = [];
|
|
41
|
+
const enqueue = (value) => {
|
|
42
|
+
const waiter = waiters.shift();
|
|
43
|
+
if (waiter) {
|
|
44
|
+
waiter({ done: false, value });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
queue.push(value);
|
|
48
|
+
};
|
|
49
|
+
const close = () => {
|
|
50
|
+
if (closed)
|
|
51
|
+
return;
|
|
52
|
+
closed = true;
|
|
53
|
+
activeController?.abort();
|
|
54
|
+
while (waiters.length > 0) {
|
|
55
|
+
const resolve = waiters.shift();
|
|
56
|
+
resolve?.({ done: true, value: undefined });
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const run = async () => {
|
|
60
|
+
let attempts = 0;
|
|
61
|
+
while (!closed) {
|
|
62
|
+
const controller = new AbortController();
|
|
63
|
+
activeController = controller;
|
|
64
|
+
const request = createWatchRequest(config);
|
|
65
|
+
const encoded = toBase64(JSON.stringify(request));
|
|
66
|
+
const url = `${config.baseUrl}/api/client/v2.0/app/${config.appId}/functions/call?baas_request=${encodeURIComponent(encoded)}`;
|
|
67
|
+
try {
|
|
68
|
+
const response = await fetch(url, {
|
|
69
|
+
method: 'GET',
|
|
70
|
+
headers: {
|
|
71
|
+
Authorization: `Bearer ${config.accessToken}`,
|
|
72
|
+
Accept: 'text/event-stream'
|
|
73
|
+
},
|
|
74
|
+
signal: controller.signal
|
|
75
|
+
});
|
|
76
|
+
if (!response.ok || !response.body) {
|
|
77
|
+
throw new Error(`Watch request failed (${response.status})`);
|
|
78
|
+
}
|
|
79
|
+
attempts = 0;
|
|
80
|
+
const reader = response.body.getReader();
|
|
81
|
+
const decoder = new TextDecoder();
|
|
82
|
+
let buffer = '';
|
|
83
|
+
while (!closed) {
|
|
84
|
+
const { done, value } = await reader.read();
|
|
85
|
+
if (done)
|
|
86
|
+
break;
|
|
87
|
+
buffer += decoder.decode(value, { stream: true });
|
|
88
|
+
const lines = buffer.split('\n');
|
|
89
|
+
buffer = lines.pop() ?? '';
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
const parsed = parseSsePayload(line);
|
|
92
|
+
if (parsed !== null) {
|
|
93
|
+
enqueue(parsed);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
if (closed) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (closed) {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
attempts += 1;
|
|
107
|
+
const backoff = Math.min(5000, 250 * 2 ** (attempts - 1));
|
|
108
|
+
await sleep(backoff);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
void run();
|
|
112
|
+
return {
|
|
113
|
+
[Symbol.asyncIterator]() {
|
|
114
|
+
return this;
|
|
115
|
+
},
|
|
116
|
+
next() {
|
|
117
|
+
if (queue.length > 0) {
|
|
118
|
+
return Promise.resolve({ done: false, value: queue.shift() });
|
|
119
|
+
}
|
|
120
|
+
if (closed) {
|
|
121
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
122
|
+
}
|
|
123
|
+
return new Promise((resolve) => {
|
|
124
|
+
waiters.push(resolve);
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
return() {
|
|
128
|
+
close();
|
|
129
|
+
return Promise.resolve({ done: true, value: undefined });
|
|
130
|
+
},
|
|
131
|
+
throw(error) {
|
|
132
|
+
close();
|
|
133
|
+
return Promise.reject(error);
|
|
134
|
+
},
|
|
135
|
+
close
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
exports.createWatchIterator = createWatchIterator;
|
package/jest.config.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowerforce/flowerbase-client",
|
|
3
|
+
"version": "0.1.1-beta.2",
|
|
4
|
+
"description": "Client for Flowerbase",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"keywords": [],
|
|
8
|
+
"author": "",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/flowerforce/flowerbase.git"
|
|
16
|
+
},
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "npx jest",
|
|
25
|
+
"build": "rm -rf dist/ && tsc"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"bson": "^6.10.4"
|
|
29
|
+
}
|
|
30
|
+
}
|
package/project.json
ADDED
package/rollup.config.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const { withNx } = require('@nx/rollup/with-nx')
|
|
2
|
+
|
|
3
|
+
module.exports = withNx(
|
|
4
|
+
{
|
|
5
|
+
main: './src/index.ts',
|
|
6
|
+
outputPath: './dist',
|
|
7
|
+
tsConfig: './tsconfig.lib.json',
|
|
8
|
+
compiler: 'tsc',
|
|
9
|
+
format: ['cjs', 'esm'],
|
|
10
|
+
generateExportsField: true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
// Provide additional rollup configuration here. See: https://rollupjs.org/configuration-options
|
|
14
|
+
// e.g.
|
|
15
|
+
// output: { sourcemap: true },
|
|
16
|
+
}
|
|
17
|
+
)
|