@flowerforce/flowerbase-client 0.1.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/src/http.ts ADDED
@@ -0,0 +1,221 @@
1
+ type ParsedPayloadError = {
2
+ message?: string
3
+ error?: string
4
+ errorCode?: string
5
+ link?: string
6
+ }
7
+
8
+ const parsePayloadError = (payload: unknown): ParsedPayloadError => {
9
+ if (!payload || typeof payload !== 'object') return {}
10
+
11
+ const message = 'message' in payload && typeof payload.message === 'string' ? payload.message : undefined
12
+ const error = 'error' in payload && typeof payload.error === 'string' ? payload.error : undefined
13
+ const errorCode =
14
+ 'error_code' in payload && typeof payload.error_code === 'string'
15
+ ? payload.error_code
16
+ : 'errorCode' in payload && typeof payload.errorCode === 'string'
17
+ ? payload.errorCode
18
+ : undefined
19
+ const link = 'link' in payload && typeof payload.link === 'string' ? payload.link : undefined
20
+
21
+ if (error) {
22
+ try {
23
+ const parsed = JSON.parse(error)
24
+ if (parsed && typeof parsed === 'object') {
25
+ const nestedMessage = 'message' in parsed && typeof parsed.message === 'string' ? parsed.message : undefined
26
+ const nestedErrorCode =
27
+ 'error_code' in parsed && typeof parsed.error_code === 'string'
28
+ ? parsed.error_code
29
+ : 'errorCode' in parsed && typeof parsed.errorCode === 'string'
30
+ ? parsed.errorCode
31
+ : undefined
32
+ return {
33
+ message: nestedMessage ?? message ?? error,
34
+ error,
35
+ errorCode: nestedErrorCode ?? errorCode,
36
+ link
37
+ }
38
+ }
39
+ } catch {
40
+ // Keep original error text if it isn't JSON.
41
+ }
42
+ }
43
+
44
+ return {
45
+ message: message ?? error,
46
+ error,
47
+ errorCode,
48
+ link
49
+ }
50
+ }
51
+
52
+ export class MongoDBRealmError extends Error {
53
+ readonly method: string
54
+ readonly url: string
55
+ readonly statusCode: number
56
+ readonly statusText: string
57
+ readonly error: string | undefined
58
+ readonly errorCode: string | undefined
59
+ readonly link: string | undefined
60
+ readonly payload?: unknown
61
+
62
+ constructor(params: {
63
+ method: string
64
+ url: string
65
+ statusCode: number
66
+ statusText: string
67
+ error?: string
68
+ errorCode?: string
69
+ link?: string
70
+ payload?: unknown
71
+ }) {
72
+ super(params.error || `${params.statusCode} ${params.statusText}`.trim())
73
+ this.name = 'MongoDBRealmError'
74
+ this.method = params.method
75
+ this.url = params.url
76
+ this.statusCode = params.statusCode
77
+ this.statusText = params.statusText
78
+ this.error = params.error
79
+ this.errorCode = params.errorCode
80
+ this.link = params.link
81
+ this.payload = params.payload
82
+ }
83
+ }
84
+
85
+ export class FlowerbaseHttpError extends MongoDBRealmError {
86
+ readonly status: number
87
+
88
+ constructor(params: ConstructorParameters<typeof MongoDBRealmError>[0]) {
89
+ super(params)
90
+ this.name = 'FlowerbaseHttpError'
91
+ this.status = params.statusCode
92
+ }
93
+ }
94
+
95
+ type RequestParams = {
96
+ url: string
97
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
98
+ body?: unknown
99
+ bearerToken?: string
100
+ timeout?: number
101
+ }
102
+
103
+ const parseBody = async (response: Response) => {
104
+ const text = await response.text()
105
+ if (!text) return null
106
+
107
+ try {
108
+ return JSON.parse(text)
109
+ } catch {
110
+ return text
111
+ }
112
+ }
113
+
114
+ const timeoutSignal = (timeout = 10000) => {
115
+ const controller = new AbortController()
116
+ const timer = setTimeout(() => controller.abort(), timeout)
117
+ return {
118
+ signal: controller.signal,
119
+ clear: () => clearTimeout(timer)
120
+ }
121
+ }
122
+
123
+ export const requestJson = async <T = unknown>({
124
+ url,
125
+ method = 'GET',
126
+ body,
127
+ bearerToken,
128
+ timeout
129
+ }: RequestParams): Promise<T> => {
130
+ const { signal, clear } = timeoutSignal(timeout)
131
+
132
+ try {
133
+ const response = await fetch(url, {
134
+ method,
135
+ headers: {
136
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
137
+ ...(bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {})
138
+ },
139
+ body: body !== undefined ? JSON.stringify(body) : undefined,
140
+ signal
141
+ })
142
+
143
+ const payload = await parseBody(response)
144
+
145
+ if (!response.ok) {
146
+ const parsedError = parsePayloadError(payload)
147
+ throw new FlowerbaseHttpError({
148
+ method,
149
+ url,
150
+ statusCode: response.status,
151
+ statusText: response.statusText,
152
+ error: parsedError.message ?? `HTTP ${response.status}`,
153
+ errorCode: parsedError.errorCode,
154
+ link: parsedError.link,
155
+ payload
156
+ })
157
+ }
158
+
159
+ return payload as T
160
+ } finally {
161
+ clear()
162
+ }
163
+ }
164
+
165
+ export const requestStream = async ({
166
+ url,
167
+ method = 'GET',
168
+ body,
169
+ bearerToken,
170
+ timeout
171
+ }: RequestParams): Promise<AsyncIterable<Uint8Array>> => {
172
+ const { signal, clear } = timeoutSignal(timeout)
173
+
174
+ try {
175
+ const response = await fetch(url, {
176
+ method,
177
+ headers: {
178
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
179
+ ...(bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {})
180
+ },
181
+ body: body !== undefined ? JSON.stringify(body) : undefined,
182
+ signal
183
+ })
184
+
185
+ if (!response.ok) {
186
+ const payload = await parseBody(response)
187
+ const parsedError = parsePayloadError(payload)
188
+ throw new FlowerbaseHttpError({
189
+ method,
190
+ url,
191
+ statusCode: response.status,
192
+ statusText: response.statusText,
193
+ error: parsedError.message ?? `HTTP ${response.status}`,
194
+ errorCode: parsedError.errorCode,
195
+ link: parsedError.link,
196
+ payload
197
+ })
198
+ }
199
+
200
+ if (!response.body) {
201
+ throw new Error('Response stream body is missing')
202
+ }
203
+
204
+ const reader = response.body.getReader()
205
+ return {
206
+ async *[Symbol.asyncIterator]() {
207
+ try {
208
+ while (true) {
209
+ const { done, value } = await reader.read()
210
+ if (done) break
211
+ if (value) yield value
212
+ }
213
+ } finally {
214
+ reader.releaseLock()
215
+ }
216
+ }
217
+ }
218
+ } finally {
219
+ clear()
220
+ }
221
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { BSON, EJSON, ObjectId, ObjectID } from './bson'
2
+
3
+ export { App } from './app'
4
+ export { User } from './user'
5
+ export { Credentials } from './credentials'
6
+ export { MongoDBRealmError } from './http'
7
+ export { BSON, EJSON, ObjectId, ObjectID }
8
+ export type {
9
+ AppConfig,
10
+ CredentialsLike,
11
+ UserLike,
12
+ MongoClientLike,
13
+ CollectionLike,
14
+ WatchAsyncIterator
15
+ } from './types'
package/src/mongo.ts ADDED
@@ -0,0 +1,112 @@
1
+ import type { App } from './app'
2
+ import { EJSON } from './bson'
3
+ import { CollectionLike, MongoClientLike } from './types'
4
+ import { createWatchIterator } from './watch'
5
+
6
+ const serialize = (value: unknown) => EJSON.serialize(value, { relaxed: false })
7
+ const deserialize = <T>(value: T): T => {
8
+ if (!value || typeof value !== 'object') return value
9
+ return EJSON.deserialize(value as Record<string, unknown>) as T
10
+ }
11
+
12
+ const mapResult = (value: unknown) => {
13
+ if (typeof value === 'string') {
14
+ try {
15
+ return deserialize(JSON.parse(value))
16
+ } catch {
17
+ return value
18
+ }
19
+ }
20
+ return deserialize(value)
21
+ }
22
+
23
+ export const createMongoClient = (app: App, serviceName: string, userId: string): MongoClientLike => ({
24
+ db: (database: string) => ({
25
+ collection: (collection: string): CollectionLike => {
26
+ const callService = async (name: string, args: unknown[]) => {
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
+ ], serviceName, userId)
35
+ return mapResult(result)
36
+ }
37
+
38
+ const normalizeWatchInput = (input?: unknown) => {
39
+ if (typeof input === 'undefined') {
40
+ return { filter: undefined, ids: undefined }
41
+ }
42
+ if (Array.isArray(input)) {
43
+ throw new Error('watch accepts only an options object with "filter" or "ids"')
44
+ }
45
+ if (!input || typeof input !== 'object') {
46
+ throw new Error('watch options must be an object')
47
+ }
48
+
49
+ const typed = input as { ids?: unknown[]; filter?: Record<string, unknown>; [key: string]: unknown }
50
+ const keys = Object.keys(typed)
51
+ const hasOnlyAllowedKeys = keys.every((key) => key === 'ids' || key === 'filter')
52
+ if (!hasOnlyAllowedKeys) {
53
+ throw new Error('watch options support only "filter" or "ids"')
54
+ }
55
+ if (typed.ids || typed.filter) {
56
+ if (typed.ids && typed.filter) {
57
+ throw new Error('watch options cannot include both "ids" and "filter"')
58
+ }
59
+ const { ids, filter } = typed
60
+ if (filter && typeof filter === 'object' && '$match' in filter) {
61
+ throw new Error('watch filter must be a query object, not a $match stage')
62
+ }
63
+ if (ids) {
64
+ if (!Array.isArray(ids)) {
65
+ throw new Error('watch ids must be an array')
66
+ }
67
+ return { filter: undefined, ids }
68
+ }
69
+ if (filter) {
70
+ return { filter, ids: undefined }
71
+ }
72
+ return { filter: undefined, ids: undefined }
73
+ }
74
+ throw new Error('watch options must include "filter" or "ids"')
75
+ }
76
+
77
+ return {
78
+ find: (query = {}, options = {}) => callService('find', [{ query, options }]),
79
+ findOne: (query = {}, options = {}) => callService('findOne', [{ query, options }]),
80
+ findOneAndUpdate: (filter, update, options = {}) =>
81
+ callService('findOneAndUpdate', [{ filter, update, options }]),
82
+ findOneAndReplace: (filter, replacement, options = {}) =>
83
+ callService('findOneAndReplace', [{ filter, replacement, options }]),
84
+ findOneAndDelete: (filter, options = {}) => callService('findOneAndDelete', [{ filter, options }]),
85
+ aggregate: (pipeline) => callService('aggregate', [{ pipeline }]),
86
+ count: (query = {}, options = {}) => callService('count', [{ query, options }]),
87
+ insertOne: (document, options = {}) => callService('insertOne', [{ document, options }]),
88
+ insertMany: (documents, options = {}) => callService('insertMany', [{ documents, options }]),
89
+ updateOne: (filter, update, options = {}) =>
90
+ callService('updateOne', [{ filter, update, options }]),
91
+ updateMany: (filter, update, options = {}) =>
92
+ callService('updateMany', [{ filter, update, options }]),
93
+ deleteOne: (filter, options = {}) => callService('deleteOne', [{ query: filter, options }]),
94
+ deleteMany: (filter, options = {}) => callService('deleteMany', [{ query: filter, options }]),
95
+ watch: (options) => {
96
+ const { filter, ids } = normalizeWatchInput(options)
97
+ const session = app.getSessionOrThrow(userId)
98
+ return createWatchIterator({
99
+ appId: app.id,
100
+ baseUrl: app.baseUrl,
101
+ accessToken: session.accessToken,
102
+ database,
103
+ collection,
104
+ filter,
105
+ ids,
106
+ timeout: app.timeout
107
+ })
108
+ }
109
+ }
110
+ }
111
+ })
112
+ })
@@ -0,0 +1,89 @@
1
+ import { SessionData } from './types'
2
+ import AsyncStorage from '@react-native-async-storage/async-storage'
3
+
4
+ type StorageLike = {
5
+ getItem: (key: string) => Promise<string | null>
6
+ setItem: (key: string, value: string) => Promise<void>
7
+ removeItem: (key: string) => Promise<void>
8
+ }
9
+
10
+ const memoryStore = new Map<string, string>()
11
+
12
+ const getAsyncStorage = (): StorageLike => AsyncStorage
13
+
14
+ const parseSession = (raw: string | null): SessionData | null => {
15
+ if (!raw) return null
16
+ try {
17
+ return JSON.parse(raw) as SessionData
18
+ } catch {
19
+ return null
20
+ }
21
+ }
22
+
23
+ export class SessionManager {
24
+ private readonly key: string
25
+ private session: SessionData | null = null
26
+ private readonly asyncStorage = getAsyncStorage()
27
+ private hydrationPromise: Promise<void> | null = null
28
+
29
+ constructor(appId: string) {
30
+ this.key = `flowerbase:${appId}:session`
31
+ this.session = this.load()
32
+ void this.hydrateFromAsyncStorage()
33
+ }
34
+
35
+ private hydrateFromAsyncStorage() {
36
+ if (!this.asyncStorage) {
37
+ return Promise.resolve()
38
+ }
39
+
40
+ if (this.hydrationPromise) {
41
+ return this.hydrationPromise
42
+ }
43
+
44
+ this.hydrationPromise = this.asyncStorage
45
+ .getItem(this.key)
46
+ .then((raw) => {
47
+ const parsed = parseSession(raw)
48
+ if (!parsed) return
49
+ this.session = parsed
50
+ memoryStore.set(this.key, JSON.stringify(parsed))
51
+ })
52
+ .catch(() => {
53
+ // Ignore storage read failures and keep memory fallback.
54
+ })
55
+
56
+ return this.hydrationPromise
57
+ }
58
+
59
+ load(): SessionData | null {
60
+ return parseSession(memoryStore.get(this.key) ?? null)
61
+ }
62
+
63
+ get() {
64
+ return this.session
65
+ }
66
+
67
+ set(session: SessionData) {
68
+ this.session = session
69
+ const raw = JSON.stringify(session)
70
+ memoryStore.set(this.key, raw)
71
+
72
+ if (this.asyncStorage) {
73
+ void this.asyncStorage.setItem(this.key, raw).catch(() => {
74
+ // Ignore write failures and keep memory fallback.
75
+ })
76
+ }
77
+ }
78
+
79
+ clear() {
80
+ this.session = null
81
+ memoryStore.delete(this.key)
82
+
83
+ if (this.asyncStorage) {
84
+ void this.asyncStorage.removeItem(this.key).catch(() => {
85
+ // Ignore delete failures and keep memory fallback.
86
+ })
87
+ }
88
+ }
89
+ }
package/src/session.ts ADDED
@@ -0,0 +1,114 @@
1
+ import { SessionData } from './types'
2
+
3
+ const memoryStore = new Map<string, string>()
4
+
5
+ const getStorage = () => {
6
+ if (typeof localStorage !== 'undefined') {
7
+ return {
8
+ getItem: (key: string) => localStorage.getItem(key),
9
+ setItem: (key: string, value: string) => localStorage.setItem(key, value),
10
+ removeItem: (key: string) => localStorage.removeItem(key)
11
+ }
12
+ }
13
+
14
+ return {
15
+ getItem: (key: string) => memoryStore.get(key) ?? null,
16
+ setItem: (key: string, value: string) => {
17
+ memoryStore.set(key, value)
18
+ },
19
+ removeItem: (key: string) => {
20
+ memoryStore.delete(key)
21
+ }
22
+ }
23
+ }
24
+
25
+ export class SessionManager {
26
+ private readonly key: string
27
+ private readonly usersKey: string
28
+ private readonly sessionsKey: string
29
+ private readonly storage = getStorage()
30
+ private session: SessionData | null = null
31
+
32
+ constructor(appId: string) {
33
+ this.key = `flowerbase:${appId}:session`
34
+ this.usersKey = `flowerbase:${appId}:users`
35
+ this.sessionsKey = `flowerbase:${appId}:sessions`
36
+ this.session = this.load()
37
+ }
38
+
39
+ load(): SessionData | null {
40
+ const raw = this.storage.getItem(this.key)
41
+ if (!raw) return null
42
+
43
+ try {
44
+ return JSON.parse(raw) as SessionData
45
+ } catch {
46
+ return null
47
+ }
48
+ }
49
+
50
+ get() {
51
+ return this.session
52
+ }
53
+
54
+ set(session: SessionData) {
55
+ this.session = session
56
+ this.storage.setItem(this.key, JSON.stringify(session))
57
+ }
58
+
59
+ clear() {
60
+ this.session = null
61
+ this.storage.removeItem(this.key)
62
+ }
63
+
64
+ getUsersOrder() {
65
+ const raw = this.storage.getItem(this.usersKey)
66
+ if (!raw) return []
67
+ try {
68
+ const parsed = JSON.parse(raw)
69
+ if (!Array.isArray(parsed)) return []
70
+ return parsed.filter((item): item is string => typeof item === 'string')
71
+ } catch {
72
+ return []
73
+ }
74
+ }
75
+
76
+ setUsersOrder(order: string[]) {
77
+ if (order.length === 0) {
78
+ this.storage.removeItem(this.usersKey)
79
+ return
80
+ }
81
+ this.storage.setItem(this.usersKey, JSON.stringify(order))
82
+ }
83
+
84
+ getSessionsByUser() {
85
+ const raw = this.storage.getItem(this.sessionsKey)
86
+ if (!raw) return {} as Record<string, SessionData>
87
+ try {
88
+ const parsed = JSON.parse(raw) as Record<string, SessionData>
89
+ const normalized: Record<string, SessionData> = {}
90
+ for (const [userId, session] of Object.entries(parsed)) {
91
+ if (
92
+ session &&
93
+ typeof session === 'object' &&
94
+ typeof session.accessToken === 'string' &&
95
+ typeof session.refreshToken === 'string' &&
96
+ typeof session.userId === 'string'
97
+ ) {
98
+ normalized[userId] = session
99
+ }
100
+ }
101
+ return normalized
102
+ } catch {
103
+ return {} as Record<string, SessionData>
104
+ }
105
+ }
106
+
107
+ setSessionsByUser(sessionsByUser: Record<string, SessionData>) {
108
+ if (Object.keys(sessionsByUser).length === 0) {
109
+ this.storage.removeItem(this.sessionsKey)
110
+ return
111
+ }
112
+ this.storage.setItem(this.sessionsKey, JSON.stringify(sessionsByUser))
113
+ }
114
+ }
package/src/types.ts ADDED
@@ -0,0 +1,114 @@
1
+ export type AppConfig = {
2
+ id: string
3
+ baseUrl?: string
4
+ timeout?: number
5
+ }
6
+
7
+ export type CredentialsLike =
8
+ | { provider: 'local-userpass'; email: string; password: string }
9
+ | { provider: 'anon-user' }
10
+ | { provider: 'custom-function'; payload: Record<string, unknown> }
11
+ | { provider: 'custom-token'; token: string }
12
+
13
+ export type SessionData = {
14
+ accessToken: string
15
+ refreshToken: string
16
+ userId: string
17
+ }
18
+
19
+ export type ProfileData = {
20
+ _id?: string
21
+ identities?: unknown[]
22
+ type?: string
23
+ custom_data?: Record<string, unknown>
24
+ data?: Record<string, unknown>
25
+ }
26
+
27
+ export type FunctionCallPayload = {
28
+ name: string
29
+ arguments: unknown[]
30
+ service?: string
31
+ }
32
+
33
+ export type WatchConfig = {
34
+ appId: string
35
+ baseUrl: string
36
+ accessToken: string
37
+ database: string
38
+ collection: string
39
+ filter?: Record<string, unknown>
40
+ ids?: unknown[]
41
+ timeout?: number
42
+ }
43
+
44
+ export type WatchAsyncIterator<TChange = unknown> = AsyncIterableIterator<TChange> & {
45
+ close: () => void
46
+ }
47
+
48
+ export interface CollectionLike {
49
+ find: (query?: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
50
+ findOne: (query?: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
51
+ findOneAndUpdate: (
52
+ filter: Record<string, unknown>,
53
+ update: Record<string, unknown>,
54
+ options?: Record<string, unknown>
55
+ ) => Promise<unknown>
56
+ findOneAndReplace: (
57
+ filter: Record<string, unknown>,
58
+ replacement: Record<string, unknown>,
59
+ options?: Record<string, unknown>
60
+ ) => Promise<unknown>
61
+ findOneAndDelete: (filter: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
62
+ aggregate: (pipeline: Record<string, unknown>[]) => Promise<unknown>
63
+ count: (filter?: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
64
+ insertOne: (document: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
65
+ insertMany: (documents: Record<string, unknown>[], options?: Record<string, unknown>) => Promise<unknown>
66
+ updateOne: (
67
+ filter: Record<string, unknown>,
68
+ update: Record<string, unknown>,
69
+ options?: Record<string, unknown>
70
+ ) => Promise<unknown>
71
+ updateMany: (
72
+ filter: Record<string, unknown>,
73
+ update: Record<string, unknown>,
74
+ options?: Record<string, unknown>
75
+ ) => Promise<unknown>
76
+ deleteOne: (filter: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
77
+ deleteMany: (filter: Record<string, unknown>, options?: Record<string, unknown>) => Promise<unknown>
78
+ watch: (options?: unknown) => WatchAsyncIterator<unknown>
79
+ }
80
+
81
+ export interface MongoDbLike {
82
+ collection: (name: string) => CollectionLike
83
+ }
84
+
85
+ export interface MongoClientLike {
86
+ db: (name: string) => MongoDbLike
87
+ }
88
+
89
+ export interface UserLike {
90
+ id: string
91
+ state: 'active' | 'logged-out' | 'removed'
92
+ isLoggedIn: boolean
93
+ accessToken: string | null
94
+ refreshToken: string | null
95
+ providerType: string | null
96
+ identities: unknown[]
97
+ customData: Record<string, unknown>
98
+ profile?: {
99
+ email?: string
100
+ [key: string]: unknown
101
+ }
102
+ functions: Record<string, (...args: unknown[]) => Promise<unknown>> & {
103
+ callFunction: (name: string, ...args: unknown[]) => Promise<unknown>
104
+ callFunctionStreaming: (name: string, ...args: unknown[]) => Promise<AsyncIterable<Uint8Array>>
105
+ }
106
+ logOut: () => Promise<void>
107
+ callFunction: (name: string, ...args: unknown[]) => Promise<unknown>
108
+ refreshAccessToken: () => Promise<string>
109
+ refreshCustomData: () => Promise<Record<string, unknown>>
110
+ mongoClient: (serviceName: string) => MongoClientLike
111
+ addListener: (callback: () => void) => void
112
+ removeListener: (callback: () => void) => void
113
+ removeAllListeners: () => void
114
+ }