@visiolab/effect-firebase-client 0.0.0-stage → 0.3.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -2
  3. package/dist/_virtual/_rolldown/runtime.mjs +12 -0
  4. package/dist/app/App.d.mts +117 -0
  5. package/dist/app/App.mjs +149 -0
  6. package/dist/app/App.mjs.map +1 -0
  7. package/dist/app/index.d.mts +2 -0
  8. package/dist/app/index.mjs +1 -0
  9. package/dist/app/internal/app.mjs +20 -0
  10. package/dist/app/internal/app.mjs.map +1 -0
  11. package/dist/firestore/ClientDocumentSnapshot.d.mts +106 -0
  12. package/dist/firestore/ClientDocumentSnapshot.mjs +86 -0
  13. package/dist/firestore/ClientDocumentSnapshot.mjs.map +1 -0
  14. package/dist/firestore/ClientFirestore.d.mts +331 -0
  15. package/dist/firestore/ClientFirestore.mjs +146 -0
  16. package/dist/firestore/ClientFirestore.mjs.map +1 -0
  17. package/dist/firestore/ClientFirestoreValue.d.mts +61 -0
  18. package/dist/firestore/ClientFirestoreValue.mjs +62 -0
  19. package/dist/firestore/ClientFirestoreValue.mjs.map +1 -0
  20. package/dist/firestore/ClientQuerySnapshot.d.mts +52 -0
  21. package/dist/firestore/ClientQuerySnapshot.mjs +58 -0
  22. package/dist/firestore/ClientQuerySnapshot.mjs.map +1 -0
  23. package/dist/firestore/index.d.mts +5 -0
  24. package/dist/firestore/index.mjs +5 -0
  25. package/dist/firestore/internal/firestore.mjs +158 -0
  26. package/dist/firestore/internal/firestore.mjs.map +1 -0
  27. package/dist/firestore/internal/firestoreValue.mjs +43 -0
  28. package/dist/firestore/internal/firestoreValue.mjs.map +1 -0
  29. package/dist/firestore/internal/snapshotMetadata.mjs +15 -0
  30. package/dist/firestore/internal/snapshotMetadata.mjs.map +1 -0
  31. package/dist/functions/CallableClient.d.mts +139 -0
  32. package/dist/functions/CallableClient.mjs +215 -0
  33. package/dist/functions/CallableClient.mjs.map +1 -0
  34. package/dist/functions/ClientFunctions.d.mts +112 -0
  35. package/dist/functions/ClientFunctions.mjs +105 -0
  36. package/dist/functions/ClientFunctions.mjs.map +1 -0
  37. package/dist/functions/index.d.mts +3 -0
  38. package/dist/functions/index.mjs +3 -0
  39. package/package.json +63 -3
  40. package/src/app/App.ts +163 -0
  41. package/src/app/index.ts +7 -0
  42. package/src/app/internal/app.ts +35 -0
  43. package/src/firestore/ClientDocumentSnapshot.ts +156 -0
  44. package/src/firestore/ClientFirestore.ts +410 -0
  45. package/src/firestore/ClientFirestoreValue.ts +94 -0
  46. package/src/firestore/ClientQuerySnapshot.ts +93 -0
  47. package/src/firestore/index.ts +30 -0
  48. package/src/firestore/internal/firestore.ts +264 -0
  49. package/src/firestore/internal/firestoreValue.ts +58 -0
  50. package/src/firestore/internal/snapshotMetadata.ts +14 -0
  51. package/src/functions/CallableClient.ts +296 -0
  52. package/src/functions/ClientFunctions.ts +149 -0
  53. package/src/functions/index.ts +15 -0
@@ -0,0 +1,52 @@
1
+ import { Existing as Existing$1, SnapshotMetadata } from "./ClientDocumentSnapshot.mjs";
2
+ import * as QuerySnapshot from "@visiolab/effect-firebase/firestore/QuerySnapshot";
3
+ import * as Collection from "@visiolab/effect-firebase/firestore/Collection";
4
+ declare namespace ClientQuerySnapshot_d_exports {
5
+ export { ClientQuerySnapshot, Existing, make };
6
+ }
7
+ /**
8
+ * A client snapshot of a document that was there when it was read, of
9
+ * whichever of the collections in `C` it is in.
10
+ *
11
+ * @see {@link QuerySnapshot.Existing} for the portable type
12
+ *
13
+ * @stability unstable
14
+ * @category models
15
+ * @since 0.3.0
16
+ */
17
+ export type Existing<C extends Collection.Any> = C extends Collection.Any ? Existing$1<C> : never;
18
+ /**
19
+ * The documents in `C` a read of many found, with the
20
+ * {@link ClientDocumentSnapshot.SnapshotMetadata} of that read.
21
+ *
22
+ * Each of its `docs` carries its own metadata too, and is of the one
23
+ * collection in `C` it is in.
24
+ *
25
+ * @see {@link QuerySnapshot.QuerySnapshot} for the portable snapshot it extends
26
+ *
27
+ * @stability unstable
28
+ * @category models
29
+ * @since 0.1.0
30
+ */
31
+ export interface ClientQuerySnapshot<C extends Collection.Any> extends QuerySnapshot.QuerySnapshot<C, {
32
+ readonly metadata: SnapshotMetadata;
33
+ }> {
34
+ /** Where the read as a whole came from. */
35
+ readonly metadata: SnapshotMetadata;
36
+ }
37
+ /**
38
+ * Builds a snapshot of the documents a read of many found, with the
39
+ * `snapshot.metadata` the client SDK reported for the read.
40
+ *
41
+ * **When to use**
42
+ *
43
+ * Use to turn a query snapshot read through the client SDK itself into this
44
+ * library's. Build each document with {@link ClientDocumentSnapshot.existing}.
45
+ *
46
+ * @stability unstable
47
+ * @category constructors
48
+ * @since 0.1.0
49
+ */
50
+ export declare const make: <C extends Collection.Any>(docs: ReadonlyArray<Existing$1<C>>, metadata: SnapshotMetadata) => ClientQuerySnapshot<C>;
51
+ export { ClientQuerySnapshot_d_exports };
52
+ //# sourceMappingURL=ClientQuerySnapshot.d.mts.map
@@ -0,0 +1,58 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
2
+ import { extraOf } from "./internal/snapshotMetadata.mjs";
3
+ import * as QuerySnapshot from "@visiolab/effect-firebase/firestore/QuerySnapshot";
4
+ // src/firestore/ClientQuerySnapshot.ts
5
+ /**
6
+ * What a read of many documents through
7
+ * {@link ClientFirestore.ClientFirestore} returns: a portable
8
+ * {@link QuerySnapshot.QuerySnapshot} that also carries the
9
+ * {@link ClientDocumentSnapshot.SnapshotMetadata} the client SDK reported for
10
+ * the read as a whole, and whose documents carry their own.
11
+ *
12
+ * The snapshot's own metadata says where a read that found nothing came from,
13
+ * since there is no document to ask.
14
+ *
15
+ * @example Telling an empty cache from an empty collection
16
+ * ```ts
17
+ * import { Effect, Schema } from "effect";
18
+ * import { Collection, FirestoreModel } from "@visiolab/effect-firebase/firestore";
19
+ * import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
20
+ *
21
+ * class User extends FirestoreModel.Class<User>("User")({
22
+ * name: Schema.String,
23
+ * }) {}
24
+ *
25
+ * const Users = Collection.make("users", User);
26
+ *
27
+ * const program = Effect.gen(function* () {
28
+ * const firestore = yield* ClientFirestore.ClientFirestore;
29
+ * const snapshot = yield* firestore.getDocs(Users.collection());
30
+ * if (snapshot.docs.length === 0 && snapshot.metadata.fromCache) {
31
+ * // Nothing in the local cache, which says nothing of the server.
32
+ * }
33
+ * });
34
+ * ```
35
+ *
36
+ * @see {@link ClientDocumentSnapshot} for what a read of one document returns
37
+ *
38
+ * @stability unstable
39
+ * @since 0.1.0
40
+ */
41
+ var ClientQuerySnapshot_exports = /* @__PURE__ */ __exportAll({ make: () => make });
42
+ /**
43
+ * Builds a snapshot of the documents a read of many found, with the
44
+ * `snapshot.metadata` the client SDK reported for the read.
45
+ *
46
+ * **When to use**
47
+ *
48
+ * Use to turn a query snapshot read through the client SDK itself into this
49
+ * library's. Build each document with {@link ClientDocumentSnapshot.existing}.
50
+ *
51
+ * @stability unstable
52
+ * @category constructors
53
+ * @since 0.1.0
54
+ */
55
+ const make = (docs, metadata) => QuerySnapshot.make(docs, extraOf(metadata));
56
+ export { ClientQuerySnapshot_exports, make };
57
+
58
+ //# sourceMappingURL=ClientQuerySnapshot.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClientQuerySnapshot.mjs","names":["snapshotMetadata.extraOf"],"sources":["../../src/firestore/ClientQuerySnapshot.ts"],"sourcesContent":["/**\n * What a read of many documents through\n * {@link ClientFirestore.ClientFirestore} returns: a portable\n * {@link QuerySnapshot.QuerySnapshot} that also carries the\n * {@link ClientDocumentSnapshot.SnapshotMetadata} the client SDK reported for\n * the read as a whole, and whose documents carry their own.\n *\n * The snapshot's own metadata says where a read that found nothing came from,\n * since there is no document to ask.\n *\n * @example Telling an empty cache from an empty collection\n * ```ts\n * import { Effect, Schema } from \"effect\";\n * import { Collection, FirestoreModel } from \"@visiolab/effect-firebase/firestore\";\n * import { ClientFirestore } from \"@visiolab/effect-firebase-client/firestore\";\n *\n * class User extends FirestoreModel.Class<User>(\"User\")({\n * name: Schema.String,\n * }) {}\n *\n * const Users = Collection.make(\"users\", User);\n *\n * const program = Effect.gen(function* () {\n * const firestore = yield* ClientFirestore.ClientFirestore;\n * const snapshot = yield* firestore.getDocs(Users.collection());\n * if (snapshot.docs.length === 0 && snapshot.metadata.fromCache) {\n * // Nothing in the local cache, which says nothing of the server.\n * }\n * });\n * ```\n *\n * @see {@link ClientDocumentSnapshot} for what a read of one document returns\n *\n * @stability unstable\n * @since 0.1.0\n */\nimport * as QuerySnapshot from \"@visiolab/effect-firebase/firestore/QuerySnapshot\";\nimport type * as Collection from \"@visiolab/effect-firebase/firestore/Collection\";\nimport type * as ClientDocumentSnapshot from \"./ClientDocumentSnapshot.ts\";\nimport * as snapshotMetadata from \"./internal/snapshotMetadata.ts\";\n\n/**\n * A client snapshot of a document that was there when it was read, of\n * whichever of the collections in `C` it is in.\n *\n * @see {@link QuerySnapshot.Existing} for the portable type\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport type Existing<C extends Collection.Any> = C extends Collection.Any\n ? ClientDocumentSnapshot.Existing<C>\n : never;\n\n/**\n * The documents in `C` a read of many found, with the\n * {@link ClientDocumentSnapshot.SnapshotMetadata} of that read.\n *\n * Each of its `docs` carries its own metadata too, and is of the one\n * collection in `C` it is in.\n *\n * @see {@link QuerySnapshot.QuerySnapshot} for the portable snapshot it extends\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface ClientQuerySnapshot<C extends Collection.Any> extends QuerySnapshot.QuerySnapshot<\n C,\n { readonly metadata: ClientDocumentSnapshot.SnapshotMetadata }\n> {\n /** Where the read as a whole came from. */\n readonly metadata: ClientDocumentSnapshot.SnapshotMetadata;\n}\n\n/**\n * Builds a snapshot of the documents a read of many found, with the\n * `snapshot.metadata` the client SDK reported for the read.\n *\n * **When to use**\n *\n * Use to turn a query snapshot read through the client SDK itself into this\n * library's. Build each document with {@link ClientDocumentSnapshot.existing}.\n *\n * @stability unstable\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <C extends Collection.Any>(\n docs: ReadonlyArray<ClientDocumentSnapshot.Existing<C>>,\n metadata: ClientDocumentSnapshot.SnapshotMetadata,\n): ClientQuerySnapshot<C> => QuerySnapshot.make(docs, snapshotMetadata.extraOf(metadata));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyFA,MAAa,QACX,MACA,aAC2B,cAAc,KAAK,MAAMA,QAAyB,QAAQ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { ClientDocumentSnapshot_d_exports } from "./ClientDocumentSnapshot.mjs";
2
+ import { ClientFirestore_d_exports } from "./ClientFirestore.mjs";
3
+ import { ClientFirestoreValue_d_exports } from "./ClientFirestoreValue.mjs";
4
+ import { ClientQuerySnapshot_d_exports } from "./ClientQuerySnapshot.mjs";
5
+ export { ClientDocumentSnapshot_d_exports as ClientDocumentSnapshot, ClientFirestore_d_exports as ClientFirestore, ClientFirestoreValue_d_exports as ClientFirestoreValue, ClientQuerySnapshot_d_exports as ClientQuerySnapshot };
@@ -0,0 +1,5 @@
1
+ import { ClientDocumentSnapshot_exports } from "./ClientDocumentSnapshot.mjs";
2
+ import { ClientFirestore_exports } from "./ClientFirestore.mjs";
3
+ import { ClientFirestoreValue_exports } from "./ClientFirestoreValue.mjs";
4
+ import { ClientQuerySnapshot_exports } from "./ClientQuerySnapshot.mjs";
5
+ export { ClientDocumentSnapshot_exports as ClientDocumentSnapshot, ClientFirestore_exports as ClientFirestore, ClientFirestoreValue_exports as ClientFirestoreValue, ClientQuerySnapshot_exports as ClientQuerySnapshot };
@@ -0,0 +1,158 @@
1
+ import { App } from "../../app/App.mjs";
2
+ import { extraOf } from "./snapshotMetadata.mjs";
3
+ import { readDocument, toClient } from "./firestoreValue.mjs";
4
+ import { Effect, Result } from "effect";
5
+ import { FirebaseError } from "firebase/app";
6
+ import * as Firestore$2 from "@visiolab/effect-firebase/firestore/Firestore";
7
+ import * as Client from "firebase/firestore";
8
+ // src/firestore/internal/firestore.ts
9
+ /** @internal */
10
+ const TypeId = "~@visiolab/effect-firebase-client/firestore/ClientFirestore";
11
+ /**
12
+ * Opens the database the options name.
13
+ *
14
+ * Settings can only be handed over through `initializeFirestore`, which refuses
15
+ * a database already opened, so they are only passed along when there are
16
+ * some: asking for the default database twice keeps working, and asking for it
17
+ * twice with settings is the mistake it reports.
18
+ *
19
+ * The emulator is connected after, which the SDK takes as often as it is asked
20
+ * for the same one, but only before the database is first used.
21
+ */
22
+ const open = (app, options) => {
23
+ const databaseId = options?.databaseId;
24
+ const firestore = options?.localCache === void 0 ? databaseId === void 0 ? Client.getFirestore(app) : Client.getFirestore(app, databaseId) : Client.initializeFirestore(app, { localCache: options.localCache }, databaseId);
25
+ if (options?.emulator !== void 0) Client.connectFirestoreEmulator(firestore, options.emulator.host, options.emulator.port);
26
+ return firestore;
27
+ };
28
+ /**
29
+ * Opens the database the options name on the {@link App.App} in context.
30
+ *
31
+ * The SDK memoizes a database on the app itself, and deleting the app
32
+ * terminates it, so there is nothing to release here.
33
+ *
34
+ * @internal
35
+ */
36
+ const openDatabase = Effect.fnUntraced(function* (options) {
37
+ const app = yield* App;
38
+ return open(app, options);
39
+ });
40
+ const firestoreError = (message) => (cause) => new Firestore$2.FirestoreError({
41
+ message,
42
+ code: cause instanceof FirebaseError ? cause.code : void 0,
43
+ cause
44
+ });
45
+ /** Runs one call to the SDK, turning what it throws or rejects with into a `FirestoreError`. */
46
+ const call = (message, f) => Effect.tryPromise({
47
+ try: () => Promise.resolve(f()),
48
+ catch: firestoreError(message)
49
+ });
50
+ /**
51
+ * Reads a document's data as Firestore Values, with the server timestamps it
52
+ * is still waiting on estimated, rather than left `null` where a timestamp is
53
+ * expected.
54
+ *
55
+ * A document holding a value outside the Firestore Value union, such as a
56
+ * vector, fails to read: it could only ever be decoded as an untyped object.
57
+ * `data()` hands back `undefined` for a document that is not there, which is
58
+ * kept as it is.
59
+ */
60
+ const dataOf = (path, snapshot) => readDocument(path, snapshot.data({ serverTimestamps: "estimate" }));
61
+ /** A read of one document, with the metadata the SDK reported for it. */
62
+ const documentReadOf = (snapshot) => Result.map(dataOf(snapshot.ref.path, snapshot), (data) => ({
63
+ data,
64
+ extra: extraOf(snapshot.metadata)
65
+ }));
66
+ /** A read of many documents, each and as a whole with the metadata the SDK reported. */
67
+ const queryReadOf = (query) => Result.map(Result.all(query.docs.map((snapshot) => Result.map(dataOf(snapshot.ref.path, snapshot), (data) => ({
68
+ path: snapshot.ref.path,
69
+ data,
70
+ extra: extraOf(snapshot.metadata)
71
+ })))), (docs) => ({
72
+ docs,
73
+ extra: extraOf(query.metadata)
74
+ }));
75
+ /** The client SDK query `selector` names, and what it is called in a failure. */
76
+ const queryOf = (firestore, selector) => selector._tag === "CollectionGroup" ? {
77
+ query: Client.collectionGroup(firestore, selector.id),
78
+ name: `the collection group "${selector.id}"`
79
+ } : {
80
+ query: Client.collection(firestore, selector.path),
81
+ name: `the collection "${selector.path}"`
82
+ };
83
+ const reads = {
84
+ default: {
85
+ getDoc: Client.getDoc,
86
+ getDocs: Client.getDocs
87
+ },
88
+ server: {
89
+ getDoc: Client.getDocFromServer,
90
+ getDocs: Client.getDocsFromServer
91
+ },
92
+ cache: {
93
+ getDoc: Client.getDocFromCache,
94
+ getDocs: Client.getDocsFromCache
95
+ }
96
+ };
97
+ /** The SDK's reads from where `options` names, `"default"` where it names none. */
98
+ const readsFrom = (options) => reads[options?.source ?? "default"];
99
+ /**
100
+ * The SDK's listen options for `options`, leaving out what is not given rather
101
+ * than handing the SDK an `undefined` in its place.
102
+ */
103
+ const snapshotListenOptions = (options) => ({
104
+ ...options?.includeMetadataChanges === void 0 ? {} : { includeMetadataChanges: options.includeMetadataChanges },
105
+ ...options?.source === void 0 ? {} : { source: options.source }
106
+ });
107
+ /**
108
+ * The service over a database already opened.
109
+ *
110
+ * @internal
111
+ */
112
+ const fromDatabase = (firestore) => {
113
+ const docOf = (path) => Client.doc(firestore, path);
114
+ const toClient$1 = (data) => toClient(data, firestore);
115
+ const made = Firestore$2.make({
116
+ getDoc: (path, options) => Effect.flatMap(call(`Failed to read the document "${path}"`, () => readsFrom(options).getDoc(docOf(path))), (snapshot) => Effect.fromResult(documentReadOf(snapshot))),
117
+ getDocs: (selector, options) => {
118
+ const { query, name } = queryOf(firestore, selector);
119
+ return Effect.flatMap(call(`Failed to read ${name}`, () => readsFrom(options).getDocs(query)), (snapshot) => Effect.fromResult(queryReadOf(snapshot)));
120
+ },
121
+ setDoc: (path, data) => call(`Failed to write the document "${path}"`, () => Client.setDoc(docOf(path), toClient$1(data))),
122
+ updateDoc: (path, data) => call(`Failed to update the document "${path}"`, () => Client.updateDoc(docOf(path), toClient$1(data))),
123
+ addDoc: (path, data) => Effect.map(call(`Failed to add a document to "${path}"`, () => Client.addDoc(Client.collection(firestore, path), toClient$1(data))), (added) => added.id),
124
+ streamDoc: (path, options) => Firestore$2.streamFromListener({
125
+ subscribe: (onNext, onError) => Client.onSnapshot(docOf(path), snapshotListenOptions(options), onNext, onError),
126
+ onError: firestoreError(`Failed to listen to the document "${path}"`),
127
+ map: documentReadOf
128
+ }),
129
+ streamDocs: (selector, options) => {
130
+ const { query, name } = queryOf(firestore, selector);
131
+ return Firestore$2.streamFromListener({
132
+ subscribe: (onNext, onError) => Client.onSnapshot(query, snapshotListenOptions(options), onNext, onError),
133
+ onError: firestoreError(`Failed to listen to ${name}`),
134
+ map: queryReadOf
135
+ });
136
+ },
137
+ runTransaction: Firestore$2.transactionFromCallback({
138
+ run: (callback, options) => Client.runTransaction(firestore, callback, options),
139
+ operations: (tx) => ({
140
+ getDoc: (path) => Effect.flatMap(call(`Failed to read the document "${path}"`, () => tx.get(docOf(path))), (snapshot) => Effect.fromResult(Result.map(dataOf(path, snapshot), (data) => ({ data })))),
141
+ setDoc: (path, data) => call(`Failed to write the document "${path}"`, () => {
142
+ tx.set(docOf(path), toClient$1(data));
143
+ }),
144
+ updateDoc: (path, data) => call(`Failed to update the document "${path}"`, () => {
145
+ tx.update(docOf(path), toClient$1(data));
146
+ })
147
+ }),
148
+ onError: firestoreError("Failed to run a transaction")
149
+ })
150
+ });
151
+ return Object.assign(made, {
152
+ [TypeId]: TypeId,
153
+ instance: firestore
154
+ });
155
+ };
156
+ export { TypeId, fromDatabase, openDatabase };
157
+
158
+ //# sourceMappingURL=firestore.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestore.mjs","names":["App.App","Firestore","firestoreValue.readDocument","snapshotMetadata.extraOf","toClient","firestoreValue.toClient"],"sources":["../../../src/firestore/internal/firestore.ts"],"sourcesContent":["import { Effect, Result } from \"effect\";\nimport * as Firestore from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport { FirebaseError } from \"firebase/app\";\nimport * as Client from \"firebase/firestore\";\nimport * as App from \"../../app/App.ts\";\nimport type * as ClientFirestore from \"../ClientFirestore.ts\";\nimport * as firestoreValue from \"./firestoreValue.ts\";\nimport * as snapshotMetadata from \"./snapshotMetadata.ts\";\n\n/** @internal */\nexport const TypeId = \"~@visiolab/effect-firebase-client/firestore/ClientFirestore\";\n\n/**\n * Opens the database the options name.\n *\n * Settings can only be handed over through `initializeFirestore`, which refuses\n * a database already opened, so they are only passed along when there are\n * some: asking for the default database twice keeps working, and asking for it\n * twice with settings is the mistake it reports.\n *\n * The emulator is connected after, which the SDK takes as often as it is asked\n * for the same one, but only before the database is first used.\n */\nconst open = (app: App.App, options: ClientFirestore.Options | undefined): Client.Firestore => {\n const databaseId = options?.databaseId;\n const firestore =\n options?.localCache === undefined\n ? databaseId === undefined\n ? Client.getFirestore(app)\n : Client.getFirestore(app, databaseId)\n : Client.initializeFirestore(app, { localCache: options.localCache }, databaseId);\n if (options?.emulator !== undefined) {\n Client.connectFirestoreEmulator(firestore, options.emulator.host, options.emulator.port);\n }\n return firestore;\n};\n\n/**\n * Opens the database the options name on the {@link App.App} in context.\n *\n * The SDK memoizes a database on the app itself, and deleting the app\n * terminates it, so there is nothing to release here.\n *\n * @internal\n */\nexport const openDatabase = Effect.fnUntraced(function* (options?: ClientFirestore.Options) {\n const app = yield* App.App;\n return open(app, options);\n});\n\nconst firestoreError = (message: string) => (cause: unknown) =>\n new Firestore.FirestoreError({\n message,\n // The client SDK names every failure it reports, such as\n // `permission-denied`, whether it raised it itself or the database did.\n code: cause instanceof FirebaseError ? cause.code : undefined,\n cause,\n });\n\n/** Runs one call to the SDK, turning what it throws or rejects with into a `FirestoreError`. */\nconst call = <A>(\n message: string,\n f: () => PromiseLike<A> | A,\n): Effect.Effect<A, Firestore.FirestoreError> =>\n Effect.tryPromise({\n try: () => Promise.resolve(f()),\n catch: firestoreError(message),\n });\n\n/**\n * Reads a document's data as Firestore Values, with the server timestamps it\n * is still waiting on estimated, rather than left `null` where a timestamp is\n * expected.\n *\n * A document holding a value outside the Firestore Value union, such as a\n * vector, fails to read: it could only ever be decoded as an untyped object.\n * `data()` hands back `undefined` for a document that is not there, which is\n * kept as it is.\n */\nconst dataOf = (\n path: string,\n snapshot: Client.DocumentSnapshot,\n): Result.Result<Firestore.DocumentData | undefined, Firestore.FirestoreError> =>\n firestoreValue.readDocument(\n path,\n snapshot.data({ serverTimestamps: \"estimate\" }),\n ) as Result.Result<Firestore.DocumentData | undefined, Firestore.FirestoreError>;\n\n/** What the client knows about a read beyond the portable snapshot. */\ntype Extra = ReturnType<typeof snapshotMetadata.extraOf>;\n\n/** A read of one document, with the metadata the SDK reported for it. */\nconst documentReadOf = (\n snapshot: Client.DocumentSnapshot,\n): Result.Result<Firestore.DocumentRead<Extra>, Firestore.FirestoreError> =>\n Result.map(dataOf(snapshot.ref.path, snapshot), (data) => ({\n data,\n extra: snapshotMetadata.extraOf(snapshot.metadata),\n }));\n\n/** A read of many documents, each and as a whole with the metadata the SDK reported. */\nconst queryReadOf = (\n query: Client.QuerySnapshot,\n): Result.Result<Firestore.QueryRead<Extra>, Firestore.FirestoreError> =>\n Result.map(\n Result.all(\n query.docs.map((snapshot) =>\n Result.map(dataOf(snapshot.ref.path, snapshot), (data) => ({\n path: snapshot.ref.path,\n // A query only hands back documents that are there.\n data: data as Firestore.DocumentData,\n extra: snapshotMetadata.extraOf(snapshot.metadata),\n })),\n ),\n ),\n (docs) => ({ docs, extra: snapshotMetadata.extraOf(query.metadata) }),\n );\n\n/** The client SDK query `selector` names, and what it is called in a failure. */\nconst queryOf = (\n firestore: Client.Firestore,\n selector: Firestore.CollectionSelector,\n): { readonly query: Client.Query; readonly name: string } =>\n selector._tag === \"CollectionGroup\"\n ? {\n query: Client.collectionGroup(firestore, selector.id),\n name: `the collection group \"${selector.id}\"`,\n }\n : {\n query: Client.collection(firestore, selector.path),\n name: `the collection \"${selector.path}\"`,\n };\n\n/** The SDK's own reads, for one {@link ClientFirestore.ReadSource}. */\ninterface Reads {\n readonly getDoc: (ref: Client.DocumentReference) => Promise<Client.DocumentSnapshot>;\n readonly getDocs: (query: Client.Query) => Promise<Client.QuerySnapshot>;\n}\n\nconst reads: Record<ClientFirestore.ReadSource, Reads> = {\n default: { getDoc: Client.getDoc, getDocs: Client.getDocs },\n server: { getDoc: Client.getDocFromServer, getDocs: Client.getDocsFromServer },\n cache: { getDoc: Client.getDocFromCache, getDocs: Client.getDocsFromCache },\n};\n\n/** The SDK's reads from where `options` names, `\"default\"` where it names none. */\nconst readsFrom = (options: ClientFirestore.ReadOptions | undefined): Reads =>\n reads[options?.source ?? \"default\"];\n\n/**\n * The SDK's listen options for `options`, leaving out what is not given rather\n * than handing the SDK an `undefined` in its place.\n */\nconst snapshotListenOptions = (\n options: ClientFirestore.ListenOptions | undefined,\n): Client.SnapshotListenOptions => ({\n ...(options?.includeMetadataChanges === undefined\n ? {}\n : { includeMetadataChanges: options.includeMetadataChanges }),\n ...(options?.source === undefined ? {} : { source: options.source }),\n});\n\n/**\n * The service over a database already opened.\n *\n * @internal\n */\nexport const fromDatabase = (\n firestore: Client.Firestore,\n): ClientFirestore.ClientFirestore & Firestore.Firestore => {\n const docOf = (path: string) => Client.doc(firestore, path);\n const toClient = (data: Firestore.DocumentData) =>\n firestoreValue.toClient(data, firestore) as Client.DocumentData;\n\n const made = Firestore.make({\n getDoc: (path, options: ClientFirestore.ReadOptions | undefined) =>\n Effect.flatMap(\n call(`Failed to read the document \"${path}\"`, () => readsFrom(options).getDoc(docOf(path))),\n (snapshot) => Effect.fromResult(documentReadOf(snapshot)),\n ),\n\n getDocs: (selector, options: ClientFirestore.ReadOptions | undefined) => {\n const { query, name } = queryOf(firestore, selector);\n return Effect.flatMap(\n call(`Failed to read ${name}`, () => readsFrom(options).getDocs(query)),\n (snapshot) => Effect.fromResult(queryReadOf(snapshot)),\n );\n },\n\n setDoc: (path, data) =>\n call(`Failed to write the document \"${path}\"`, () =>\n Client.setDoc(docOf(path), toClient(data)),\n ),\n\n updateDoc: (path, data) =>\n call(`Failed to update the document \"${path}\"`, () =>\n Client.updateDoc(docOf(path), toClient(data)),\n ),\n\n addDoc: (path, data) =>\n Effect.map(\n call(`Failed to add a document to \"${path}\"`, () =>\n Client.addDoc(Client.collection(firestore, path), toClient(data)),\n ),\n (added) => added.id,\n ),\n\n // The client SDK hands a listener the documents as this client last wrote\n // them, before the database has taken the writes, so each write is seen\n // straight away rather than once it is acknowledged.\n streamDoc: (path, options: ClientFirestore.ListenOptions | undefined) =>\n Firestore.streamFromListener({\n subscribe: (onNext, onError) =>\n Client.onSnapshot(docOf(path), snapshotListenOptions(options), onNext, onError),\n onError: firestoreError(`Failed to listen to the document \"${path}\"`),\n map: documentReadOf,\n }),\n\n streamDocs: (selector, options: ClientFirestore.ListenOptions | undefined) => {\n const { query, name } = queryOf(firestore, selector);\n return Firestore.streamFromListener({\n subscribe: (onNext, onError) =>\n Client.onSnapshot(query, snapshotListenOptions(options), onNext, onError),\n onError: firestoreError(`Failed to listen to ${name}`),\n map: queryReadOf,\n });\n },\n\n runTransaction: Firestore.transactionFromCallback({\n run: (callback, options) => Client.runTransaction(firestore, callback, options),\n operations: (tx: Client.Transaction) => ({\n // A transaction reads from the server alone and never holds writes of\n // its own that are pending, so its metadata says nothing and is left\n // out: what it hands back is the portable snapshot.\n getDoc: (path) =>\n Effect.flatMap(\n call(`Failed to read the document \"${path}\"`, () => tx.get(docOf(path))),\n (snapshot) =>\n Effect.fromResult(Result.map(dataOf(path, snapshot), (data) => ({ data }))),\n ),\n // Writes into a transaction are queued rather than sent, so these return\n // straight away - or throw, where the transaction refuses them.\n setDoc: (path, data) =>\n call(`Failed to write the document \"${path}\"`, () => {\n tx.set(docOf(path), toClient(data));\n }),\n updateDoc: (path, data) =>\n call(`Failed to update the document \"${path}\"`, () => {\n tx.update(docOf(path), toClient(data));\n }),\n }),\n onError: firestoreError(\"Failed to run a transaction\"),\n }),\n });\n\n // `make` infers the read source and listen options its hooks are handed and\n // the metadata they read with each snapshot, so the client's interface is\n // checked against what it built here.\n const service: ClientFirestore.ClientFirestore & Firestore.Firestore = Object.assign(made, {\n [TypeId]: TypeId as typeof TypeId,\n instance: firestore,\n });\n return service;\n};\n"],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import * as Client from "firebase/firestore";
2
+ import * as DocumentPath from "@visiolab/effect-firebase/firestore/DocumentPath";
3
+ import * as FirestoreValue$1 from "@visiolab/effect-firebase/firestore/FirestoreValue";
4
+ import * as GeoPoint from "@visiolab/effect-firebase/firestore/GeoPoint";
5
+ import * as Timestamp from "@visiolab/effect-firebase/firestore/Timestamp";
6
+ // src/firestore/internal/firestoreValue.ts
7
+ /** How the client SDK writes each kind of Firestore Value into `firestore`. */
8
+ const writer = (firestore) => ({
9
+ bytes: (bytes) => Client.Bytes.fromUint8Array(bytes),
10
+ timestamp: (ts) => new Client.Timestamp(ts.seconds, ts.nanoseconds),
11
+ geoPoint: (point) => new Client.GeoPoint(point.latitude, point.longitude),
12
+ documentPath: (ref) => Client.doc(firestore, ref.path),
13
+ serverTimestamp: () => Client.serverTimestamp(),
14
+ increment: (increment) => Client.increment(increment.by),
15
+ deleteField: () => Client.deleteField(),
16
+ arrayUnion: (union, walk) => Client.arrayUnion(...union.elements.map(walk)),
17
+ arrayRemove: (remove, walk) => Client.arrayRemove(...remove.elements.map(walk))
18
+ });
19
+ /** @internal */
20
+ const toClient = (value, firestore) => FirestoreValue$1.toSdk(value, writer(firestore));
21
+ /**
22
+ * How the client SDK's own values read back as Firestore Values. Its
23
+ * sentinels are not read back: a read never hands one back, and the names it
24
+ * keeps them by are internal to it.
25
+ */
26
+ const reader = (u) => {
27
+ if (u instanceof Client.Timestamp) return Timestamp.makeUnsafe(u.seconds, u.nanoseconds);
28
+ if (u instanceof Client.GeoPoint) return GeoPoint.makeUnsafe(u.latitude, u.longitude);
29
+ if (u instanceof Client.DocumentReference) return DocumentPath.makeUnsafe(u.path);
30
+ if (u instanceof Client.Bytes) return u.toUint8Array();
31
+ };
32
+ /** @internal */
33
+ const fromClient = (value) => FirestoreValue$1.fromSdk(value, reader);
34
+ /**
35
+ * What the client SDK read for the document at `path`, as Firestore Values,
36
+ * or `undefined` for a document that is not there.
37
+ *
38
+ * @internal
39
+ */
40
+ const readDocument = (path, data) => FirestoreValue$1.readDocument(path, data, reader);
41
+ export { fromClient, readDocument, toClient };
42
+
43
+ //# sourceMappingURL=firestoreValue.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firestoreValue.mjs","names":["FirestoreValue"],"sources":["../../../src/firestore/internal/firestoreValue.ts"],"sourcesContent":["import type { Result } from \"effect\";\nimport * as DocumentPath from \"@visiolab/effect-firebase/firestore/DocumentPath\";\nimport type { FirestoreError } from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport * as FirestoreValue from \"@visiolab/effect-firebase/firestore/FirestoreValue\";\nimport * as GeoPoint from \"@visiolab/effect-firebase/firestore/GeoPoint\";\nimport * as Timestamp from \"@visiolab/effect-firebase/firestore/Timestamp\";\nimport * as Client from \"firebase/firestore\";\n\n/** How the client SDK writes each kind of Firestore Value into `firestore`. */\nconst writer = (firestore: Client.Firestore): FirestoreValue.Writer => ({\n // The client SDK refuses a raw `Uint8Array`, as a custom object.\n bytes: (bytes) => Client.Bytes.fromUint8Array(bytes),\n timestamp: (ts) => new Client.Timestamp(ts.seconds, ts.nanoseconds),\n geoPoint: (point) => new Client.GeoPoint(point.latitude, point.longitude),\n documentPath: (ref) => Client.doc(firestore, ref.path),\n serverTimestamp: () => Client.serverTimestamp(),\n increment: (increment) => Client.increment(increment.by),\n deleteField: () => Client.deleteField(),\n arrayUnion: (union, walk) => Client.arrayUnion(...union.elements.map(walk)),\n arrayRemove: (remove, walk) => Client.arrayRemove(...remove.elements.map(walk)),\n});\n\n/** @internal */\nexport const toClient = (\n value: FirestoreValue.FirestoreValue,\n firestore: Client.Firestore,\n): unknown => FirestoreValue.toSdk(value, writer(firestore));\n\n/**\n * How the client SDK's own values read back as Firestore Values. Its\n * sentinels are not read back: a read never hands one back, and the names it\n * keeps them by are internal to it.\n */\nconst reader: FirestoreValue.Reader = (u) => {\n if (u instanceof Client.Timestamp) return Timestamp.makeUnsafe(u.seconds, u.nanoseconds);\n if (u instanceof Client.GeoPoint) return GeoPoint.makeUnsafe(u.latitude, u.longitude);\n if (u instanceof Client.DocumentReference) return DocumentPath.makeUnsafe(u.path);\n if (u instanceof Client.Bytes) return u.toUint8Array();\n return undefined;\n};\n\n/** @internal */\nexport const fromClient = (\n value: unknown,\n): Result.Result<FirestoreValue.FirestoreValue, FirestoreError> =>\n FirestoreValue.fromSdk(value, reader);\n\n/**\n * What the client SDK read for the document at `path`, as Firestore Values,\n * or `undefined` for a document that is not there.\n *\n * @internal\n */\nexport const readDocument = (\n path: string,\n data: Client.DocumentData | undefined,\n): Result.Result<FirestoreValue.FirestoreValue | undefined, FirestoreError> =>\n FirestoreValue.readDocument(path, data, reader);\n"],"mappings":";;;;;;;AASA,MAAM,UAAU,eAAwD;CAEtE,QAAQ,UAAU,OAAO,MAAM,eAAe,KAAK;CACnD,YAAY,OAAO,IAAI,OAAO,UAAU,GAAG,SAAS,GAAG,WAAW;CAClE,WAAW,UAAU,IAAI,OAAO,SAAS,MAAM,UAAU,MAAM,SAAS;CACxE,eAAe,QAAQ,OAAO,IAAI,WAAW,IAAI,IAAI;CACrD,uBAAuB,OAAO,gBAAgB;CAC9C,YAAY,cAAc,OAAO,UAAU,UAAU,EAAE;CACvD,mBAAmB,OAAO,YAAY;CACtC,aAAa,OAAO,SAAS,OAAO,WAAW,GAAG,MAAM,SAAS,IAAI,IAAI,CAAC;CAC1E,cAAc,QAAQ,SAAS,OAAO,YAAY,GAAG,OAAO,SAAS,IAAI,IAAI,CAAC;AAChF;;AAGA,MAAa,YACX,OACA,cACYA,iBAAe,MAAM,OAAO,OAAO,SAAS,CAAC;;;;;;AAO3D,MAAM,UAAiC,MAAM;CAC3C,IAAI,aAAa,OAAO,WAAW,OAAO,UAAU,WAAW,EAAE,SAAS,EAAE,WAAW;CACvF,IAAI,aAAa,OAAO,UAAU,OAAO,SAAS,WAAW,EAAE,UAAU,EAAE,SAAS;CACpF,IAAI,aAAa,OAAO,mBAAmB,OAAO,aAAa,WAAW,EAAE,IAAI;CAChF,IAAI,aAAa,OAAO,OAAO,OAAO,EAAE,aAAa;AAEvD;;AAGA,MAAa,cACX,UAEAA,iBAAe,QAAQ,OAAO,MAAM;;;;;;;AAQtC,MAAa,gBACX,MACA,SAEAA,iBAAe,aAAa,MAAM,MAAM,MAAM"}
@@ -0,0 +1,15 @@
1
+ // src/firestore/internal/snapshotMetadata.ts
2
+ /**
3
+ * The extra a client snapshot is built with: its metadata, copied out of the
4
+ * SDK's own object so that the snapshot holds, and prints, only these two
5
+ * fields.
6
+ *
7
+ * @internal
8
+ */
9
+ const extraOf = (metadata) => ({ metadata: {
10
+ fromCache: metadata.fromCache,
11
+ hasPendingWrites: metadata.hasPendingWrites
12
+ } });
13
+ export { extraOf };
14
+
15
+ //# sourceMappingURL=snapshotMetadata.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshotMetadata.mjs","names":[],"sources":["../../../src/firestore/internal/snapshotMetadata.ts"],"sourcesContent":["import type * as ClientDocumentSnapshot from \"../ClientDocumentSnapshot.ts\";\n\n/**\n * The extra a client snapshot is built with: its metadata, copied out of the\n * SDK's own object so that the snapshot holds, and prints, only these two\n * fields.\n *\n * @internal\n */\nexport const extraOf = (\n metadata: ClientDocumentSnapshot.SnapshotMetadata,\n): { readonly metadata: ClientDocumentSnapshot.SnapshotMetadata } => ({\n metadata: { fromCache: metadata.fromCache, hasPendingWrites: metadata.hasPendingWrites },\n});\n"],"mappings":";;;;;;;;AASA,MAAa,WACX,cACoE,EACpE,UAAU;CAAE,WAAW,SAAS;CAAW,kBAAkB,SAAS;AAAiB,EACzF"}
@@ -0,0 +1,139 @@
1
+ import { ClientFunctions } from "./ClientFunctions.mjs";
2
+ import { Effect } from "effect";
3
+ import * as Callable from "@visiolab/effect-firebase/functions/Callable";
4
+ import * as CallableError from "@visiolab/effect-firebase/functions/CallableError";
5
+ import * as FunctionGroup from "@visiolab/effect-firebase/functions/FunctionGroup";
6
+ declare namespace CallableClient_d_exports {
7
+ export { Client, Members, Method, make };
8
+ }
9
+ /**
10
+ * A client of one Callable: a function from its Payload to an Effect of its
11
+ * success value, failing with its declared errors or a `CallableError`.
12
+ *
13
+ * @stability unstable
14
+ * @category models
15
+ * @since 0.3.0
16
+ */
17
+ export type Method<C extends Callable.Any> = (payload: Callable.Payload<C>) => Effect.Effect<Callable.Success<C>, Callable.Error<C> | CallableError.CallableError>;
18
+ /**
19
+ * What {@link make} returns: one {@link Method} per Callable, keyed by the
20
+ * Callable's name. For a Function Group, one per Callable member.
21
+ *
22
+ * @stability unstable
23
+ * @category models
24
+ * @since 0.3.0
25
+ */
26
+ export type Client<T extends Callable.Any | FunctionGroup.Any> = { readonly [C in Members<T> as C["name"]]: Method<C>; };
27
+ /**
28
+ * The Callables a client of `T` calls: the Callable members of a Function
29
+ * Group, or the Callable itself. Members of other kinds are left out.
30
+ *
31
+ * @stability unstable
32
+ * @category type-level
33
+ * @since 0.3.0
34
+ */
35
+ export type Members<T extends Callable.Any | FunctionGroup.Any> = T extends FunctionGroup.Any ? FunctionGroup.Members<T, Callable.Any> : T;
36
+ /**
37
+ * Builds the client of a Callable in no group, or of every Callable member of
38
+ * a Function Group.
39
+ *
40
+ * **When to use**
41
+ *
42
+ * Use to call Callables from the browser or any other client SDK program.
43
+ *
44
+ * **Details**
45
+ *
46
+ * Returns a record keyed by Callable name: `const { greet } = yield*
47
+ * CallableClient.make(Greet)` for a Callable in no group, and
48
+ * `const users = yield* CallableClient.make(Users)` for a group, where
49
+ * `users.create` calls `users-create`. A group's members of other kinds, which
50
+ * no client calls, are left out. The region of the
51
+ * {@link ClientFunctions.ClientFunctions} in context is bound once, here.
52
+ *
53
+ * Build a member's client from its group. A client built from the member on
54
+ * its own calls the name without the group's prefix, which the server doesn't
55
+ * export, and fails with `not-found`. Nothing checks this at runtime.
56
+ *
57
+ * Each call encodes the Payload with `Schema.toCodecJson`, sends it as is
58
+ * through the SDK's `httpsCallable`, and decodes the answer the same way.
59
+ *
60
+ * When the server answers with an error, the client strips the `functions/`
61
+ * prefix from its code and decodes its `details` against the declared errors
62
+ * that carry that code. It fails with the decoded error, so `Effect.catchTag`
63
+ * recovers from it. Every other failure is a
64
+ * {@link CallableError.CallableError}:
65
+ *
66
+ * - `EncodeError` when the Payload doesn't encode. Nothing is sent.
67
+ * - `DecodeError` when the success value doesn't decode, the `details` of
68
+ * an error don't decode against the declared errors with its code, as after
69
+ * the server and the client drift apart, or the answer isn't one the SDK
70
+ * can read: not a JSON object, or one without `data`.
71
+ * - `ResponseError` when the server answers with a code no declared error
72
+ * carries, or without details, as on a defect. `not-found` usually means a
73
+ * wrong region, or a name the server doesn't export, such as a group's
74
+ * member called without its group. A `deadline-exceeded` the server sends
75
+ * is a `ResponseError` too.
76
+ * - `TransportError` when no answer arrived: a network failure, the SDK's
77
+ * own timeout (`deadline-exceeded`), a cancelled call, or a deleted
78
+ * Functions instance. The SDK appends the HTTP status of an answer to its
79
+ * error's message as ` [<status>]`, and status 0 to a network failure. The
80
+ * client treats an error without that suffix, or with status 0, as no
81
+ * answer.
82
+ *
83
+ * Each call runs in a `kind: "client"` span named `CallableClient.<deployed
84
+ * name>`, such as `CallableClient.users-create`, with the attributes
85
+ * `rpc.system: "firebase_callable"`, `rpc.method` (the Callable's name),
86
+ * `rpc.service` (the group, for a member) and `faas.name` (the deployed name).
87
+ * The span isn't linked to the server's span of the same call: the two land in
88
+ * separate traces. It carries no uid; add one with `Effect.annotateCurrentSpan`
89
+ * around the call when you want it.
90
+ *
91
+ * @example Injecting a client as a service
92
+ * ```ts
93
+ * import { Context, Layer, Schema } from "effect";
94
+ * import { Callable } from "@visiolab/effect-firebase/functions";
95
+ * import { CallableClient } from "@visiolab/effect-firebase-client/functions";
96
+ *
97
+ * const Greet = Callable.make("greet", {
98
+ * payload: { name: Schema.String },
99
+ * success: Schema.String,
100
+ * });
101
+ *
102
+ * class GreetClient extends Context.Service<GreetClient, CallableClient.Client<typeof Greet>>()(
103
+ * "app/GreetClient",
104
+ * ) {
105
+ * static readonly layer = Layer.effect(GreetClient, CallableClient.make(Greet));
106
+ * }
107
+ * ```
108
+ *
109
+ * @example Calling the members of a group
110
+ * ```ts
111
+ * import { Effect, Schema } from "effect";
112
+ * import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
113
+ * import { CallableClient } from "@visiolab/effect-firebase-client/functions";
114
+ *
115
+ * const CreateUser = Callable.make("create", {
116
+ * payload: { name: Schema.String },
117
+ * success: Schema.String,
118
+ * });
119
+ *
120
+ * class Users extends FunctionGroup.make("users").add(CreateUser) {}
121
+ *
122
+ * const program = Effect.gen(function* () {
123
+ * const users = yield* CallableClient.make(Users);
124
+ * // Calls `users-create`.
125
+ * return yield* users.create({ name: "Ada" });
126
+ * });
127
+ * ```
128
+ *
129
+ * @see {@link ClientFunctions.ClientFunctions} for the region and emulator it calls
130
+ * @see {@link Functions.make} for serving a Callable in no group
131
+ * @see {@link Functions.group} for serving the members of a group
132
+ *
133
+ * @stability unstable
134
+ * @category constructors
135
+ * @since 0.3.0
136
+ */
137
+ export declare const make: <T extends Callable.Any | FunctionGroup.Any>(target: T) => Effect.Effect<Client<T>, never, ClientFunctions>;
138
+ export { CallableClient_d_exports };
139
+ //# sourceMappingURL=CallableClient.d.mts.map