@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.
- package/LICENSE +21 -0
- package/README.md +70 -2
- package/dist/_virtual/_rolldown/runtime.mjs +12 -0
- package/dist/app/App.d.mts +117 -0
- package/dist/app/App.mjs +149 -0
- package/dist/app/App.mjs.map +1 -0
- package/dist/app/index.d.mts +2 -0
- package/dist/app/index.mjs +1 -0
- package/dist/app/internal/app.mjs +20 -0
- package/dist/app/internal/app.mjs.map +1 -0
- package/dist/firestore/ClientDocumentSnapshot.d.mts +106 -0
- package/dist/firestore/ClientDocumentSnapshot.mjs +86 -0
- package/dist/firestore/ClientDocumentSnapshot.mjs.map +1 -0
- package/dist/firestore/ClientFirestore.d.mts +331 -0
- package/dist/firestore/ClientFirestore.mjs +146 -0
- package/dist/firestore/ClientFirestore.mjs.map +1 -0
- package/dist/firestore/ClientFirestoreValue.d.mts +61 -0
- package/dist/firestore/ClientFirestoreValue.mjs +62 -0
- package/dist/firestore/ClientFirestoreValue.mjs.map +1 -0
- package/dist/firestore/ClientQuerySnapshot.d.mts +52 -0
- package/dist/firestore/ClientQuerySnapshot.mjs +58 -0
- package/dist/firestore/ClientQuerySnapshot.mjs.map +1 -0
- package/dist/firestore/index.d.mts +5 -0
- package/dist/firestore/index.mjs +5 -0
- package/dist/firestore/internal/firestore.mjs +158 -0
- package/dist/firestore/internal/firestore.mjs.map +1 -0
- package/dist/firestore/internal/firestoreValue.mjs +43 -0
- package/dist/firestore/internal/firestoreValue.mjs.map +1 -0
- package/dist/firestore/internal/snapshotMetadata.mjs +15 -0
- package/dist/firestore/internal/snapshotMetadata.mjs.map +1 -0
- package/dist/functions/CallableClient.d.mts +139 -0
- package/dist/functions/CallableClient.mjs +215 -0
- package/dist/functions/CallableClient.mjs.map +1 -0
- package/dist/functions/ClientFunctions.d.mts +112 -0
- package/dist/functions/ClientFunctions.mjs +105 -0
- package/dist/functions/ClientFunctions.mjs.map +1 -0
- package/dist/functions/index.d.mts +3 -0
- package/dist/functions/index.mjs +3 -0
- package/package.json +63 -3
- package/src/app/App.ts +163 -0
- package/src/app/index.ts +7 -0
- package/src/app/internal/app.ts +35 -0
- package/src/firestore/ClientDocumentSnapshot.ts +156 -0
- package/src/firestore/ClientFirestore.ts +410 -0
- package/src/firestore/ClientFirestoreValue.ts +94 -0
- package/src/firestore/ClientQuerySnapshot.ts +93 -0
- package/src/firestore/index.ts +30 -0
- package/src/firestore/internal/firestore.ts +264 -0
- package/src/firestore/internal/firestoreValue.ts +58 -0
- package/src/firestore/internal/snapshotMetadata.ts +14 -0
- package/src/functions/CallableClient.ts +296 -0
- package/src/functions/ClientFunctions.ts +149 -0
- package/src/functions/index.ts +15 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import { App } from "../app/App.mjs";
|
|
2
|
+
import { SnapshotMetadata } from "./ClientDocumentSnapshot.mjs";
|
|
3
|
+
import { Context, Effect, Layer } from "effect";
|
|
4
|
+
import { Firestore, With } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
5
|
+
import { Firestore as Firestore$1, FirestoreLocalCache } from "firebase/firestore";
|
|
6
|
+
declare namespace ClientFirestore_d_exports {
|
|
7
|
+
export { ClientFirestore, Emulator, ListenOptions, Options, ReadOptions, ReadSource, layer, make };
|
|
8
|
+
}
|
|
9
|
+
declare const TypeId = "~@visiolab/effect-firebase-client/firestore/ClientFirestore";
|
|
10
|
+
/**
|
|
11
|
+
* The portable {@link Firestore}, plus what only the client SDK can do.
|
|
12
|
+
*
|
|
13
|
+
* **When to use**
|
|
14
|
+
*
|
|
15
|
+
* Ask for it where code needs the client SDK: a read from the server or the
|
|
16
|
+
* cache alone, metadata changes on a listen, a snapshot's
|
|
17
|
+
* {@link ClientDocumentSnapshot.SnapshotMetadata}, or the SDK itself through
|
|
18
|
+
* {@link ClientFirestore.instance}. Everywhere else ask for {@link Firestore},
|
|
19
|
+
* so the code also runs on the Admin SDK.
|
|
20
|
+
*
|
|
21
|
+
* **Details**
|
|
22
|
+
*
|
|
23
|
+
* Its reads take {@link ReadOptions} and its listens {@link ListenOptions}.
|
|
24
|
+
* Every document snapshot, each document of a query snapshot, and each query
|
|
25
|
+
* snapshot as a whole carries the `metadata` of its read, as a
|
|
26
|
+
* {@link ClientDocumentSnapshot.ClientDocumentSnapshot} or
|
|
27
|
+
* {@link ClientQuerySnapshot.ClientQuerySnapshot} does.
|
|
28
|
+
*
|
|
29
|
+
* The service its key holds is also a {@link Firestore}, so it can be handed
|
|
30
|
+
* to code that expects one as it is. The type itself only extends
|
|
31
|
+
* {@link Firestore.With}, so providing a {@link Firestore} alone, such as an
|
|
32
|
+
* in-memory fake, does not satisfy code that asks for it. Its
|
|
33
|
+
* transactions are the portable {@link Firestore.Transaction}: the client SDK's
|
|
34
|
+
* transactions read one document at a time.
|
|
35
|
+
*
|
|
36
|
+
* The client SDK cannot abort a request in flight, so interrupting a call does
|
|
37
|
+
* not stop it: the request still runs to completion.
|
|
38
|
+
*
|
|
39
|
+
* @see {@link Firestore.With} for each read and write it offers
|
|
40
|
+
*
|
|
41
|
+
* @stability unstable
|
|
42
|
+
* @category models
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
*/
|
|
45
|
+
export interface ClientFirestore extends With<ReadOptions, ListenOptions, {
|
|
46
|
+
readonly metadata: SnapshotMetadata;
|
|
47
|
+
}> {
|
|
48
|
+
readonly [TypeId]: typeof TypeId;
|
|
49
|
+
/**
|
|
50
|
+
* The client SDK's own `Firestore`, for the database the service was opened
|
|
51
|
+
* on.
|
|
52
|
+
*
|
|
53
|
+
* **When to use**
|
|
54
|
+
*
|
|
55
|
+
* Use for what this service does not wrap, such as queries or
|
|
56
|
+
* `disableNetwork` and `enableNetwork`. Prefer the service's own methods
|
|
57
|
+
* where one exists.
|
|
58
|
+
*
|
|
59
|
+
* **Details**
|
|
60
|
+
*
|
|
61
|
+
* Calls through it skip the collection's model, take and return the SDK's
|
|
62
|
+
* own values, and throw the SDK's own errors. To write a model through it,
|
|
63
|
+
* encode with {@link FirestoreValue.toCodecFirestore} and map with
|
|
64
|
+
* {@link ClientFirestoreValue.toClient}.
|
|
65
|
+
*
|
|
66
|
+
* @see {@link ClientFirestoreValue} for mapping between the SDK's values and Firestore Values
|
|
67
|
+
*/
|
|
68
|
+
readonly instance: Firestore$1;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* How `streamDoc` and `streamDocs` on {@link ClientFirestore} listen, named as
|
|
72
|
+
* in the client SDK's own listen options.
|
|
73
|
+
*
|
|
74
|
+
* **When to use**
|
|
75
|
+
*
|
|
76
|
+
* Use to also hear metadata changes, such as a pending write being
|
|
77
|
+
* acknowledged, or to listen to the local cache alone. Left out, a listen
|
|
78
|
+
* behaves as the SDK's does by default: it emits only when the data changes.
|
|
79
|
+
*
|
|
80
|
+
* **Details**
|
|
81
|
+
*
|
|
82
|
+
* Every snapshot a listen emits carries the
|
|
83
|
+
* {@link ClientDocumentSnapshot.SnapshotMetadata} it arrived with. The portable
|
|
84
|
+
* {@link Firestore.With.streamDoc} takes no options, because the Admin SDK's
|
|
85
|
+
* listeners take none.
|
|
86
|
+
*
|
|
87
|
+
* @example Waiting for the server to acknowledge a write
|
|
88
|
+
* ```ts
|
|
89
|
+
* import { Effect, Schema, Stream } from "effect";
|
|
90
|
+
* import { Collection, FirestoreModel } from "@visiolab/effect-firebase/firestore";
|
|
91
|
+
* import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
|
|
92
|
+
*
|
|
93
|
+
* class Post extends FirestoreModel.Class<Post>("Post")({
|
|
94
|
+
* title: Schema.String,
|
|
95
|
+
* }) {}
|
|
96
|
+
*
|
|
97
|
+
* const Posts = Collection.make("posts", Post);
|
|
98
|
+
* const hello = Posts.doc(Posts.id.make("hello"));
|
|
99
|
+
*
|
|
100
|
+
* const acknowledged = Effect.gen(function* () {
|
|
101
|
+
* const firestore = yield* ClientFirestore.ClientFirestore;
|
|
102
|
+
* yield* firestore.streamDoc(hello, { includeMetadataChanges: true }).pipe(
|
|
103
|
+
* Stream.filter((snapshot) => !snapshot.metadata.hasPendingWrites),
|
|
104
|
+
* Stream.runHead,
|
|
105
|
+
* );
|
|
106
|
+
* });
|
|
107
|
+
* ```
|
|
108
|
+
*
|
|
109
|
+
* @see {@link ReadOptions} for the options of a one-off read
|
|
110
|
+
*
|
|
111
|
+
* @stability unstable
|
|
112
|
+
* @category models
|
|
113
|
+
* @since 0.1.0
|
|
114
|
+
*/
|
|
115
|
+
export interface ListenOptions {
|
|
116
|
+
/**
|
|
117
|
+
* Whether to also emit when only the
|
|
118
|
+
* {@link ClientDocumentSnapshot.SnapshotMetadata} changes, such as when the
|
|
119
|
+
* server acknowledges a pending write or the cache catches up with the
|
|
120
|
+
* server. Without it, a listen only emits when the data changes.
|
|
121
|
+
*/
|
|
122
|
+
readonly includeMetadataChanges?: boolean | undefined;
|
|
123
|
+
/**
|
|
124
|
+
* Where to listen. `"default"` listens to the server and the local cache.
|
|
125
|
+
* `"cache"` listens to the local cache alone and never reaches the server, so
|
|
126
|
+
* it only sees what this client has written or already read.
|
|
127
|
+
*/
|
|
128
|
+
readonly source?: "default" | "cache" | undefined;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Service key for {@link ClientFirestore}.
|
|
132
|
+
*
|
|
133
|
+
* @see {@link Firestore} for the portable key, which {@link layer} provides the same service under
|
|
134
|
+
*
|
|
135
|
+
* @stability unstable
|
|
136
|
+
* @category services
|
|
137
|
+
* @since 0.1.0
|
|
138
|
+
*/
|
|
139
|
+
export declare const ClientFirestore: Context.Service<ClientFirestore, ClientFirestore & Firestore>;
|
|
140
|
+
/**
|
|
141
|
+
* Where a one-off read is served from.
|
|
142
|
+
*
|
|
143
|
+
* - `"default"`: the server when it can be reached, otherwise the local cache.
|
|
144
|
+
* What a read does when no source is given.
|
|
145
|
+
* - `"server"`: the server alone. Fails with the SDK's code when the server
|
|
146
|
+
* cannot be reached, instead of falling back to the cache.
|
|
147
|
+
* - `"cache"`: the local cache alone, without asking the server.
|
|
148
|
+
*
|
|
149
|
+
* The two reads report what the cache lacks differently, as the SDK does. A
|
|
150
|
+
* cached `getDoc` of a document the cache has never seen fails with a
|
|
151
|
+
* {@link Firestore.FirestoreError} whose code is `unavailable`, and one the
|
|
152
|
+
* cache knows was deleted reads as `Missing`. A cached `getDocs` never fails
|
|
153
|
+
* for what the cache lacks: it returns whatever the cache holds, which may be
|
|
154
|
+
* nothing, with `fromCache: true`.
|
|
155
|
+
*
|
|
156
|
+
* @see {@link ReadOptions} for passing it to a read
|
|
157
|
+
*
|
|
158
|
+
* @stability unstable
|
|
159
|
+
* @category models
|
|
160
|
+
* @since 0.1.0
|
|
161
|
+
*/
|
|
162
|
+
export type ReadSource = "default" | "server" | "cache";
|
|
163
|
+
/**
|
|
164
|
+
* How `getDoc` and `getDocs` on {@link ClientFirestore} read a document, a
|
|
165
|
+
* collection, or a Collection Group.
|
|
166
|
+
*
|
|
167
|
+
* **When to use**
|
|
168
|
+
*
|
|
169
|
+
* Use to read from the server alone, such as to confirm a value before acting
|
|
170
|
+
* on it, or from the local cache alone, such as to render at once while
|
|
171
|
+
* offline. Left out, a read behaves as the SDK's does by default.
|
|
172
|
+
*
|
|
173
|
+
* **Details**
|
|
174
|
+
*
|
|
175
|
+
* With `source: "cache"`, a `getDoc` of a document the cache has never seen
|
|
176
|
+
* fails with a {@link Firestore.FirestoreError} whose code is `unavailable`:
|
|
177
|
+
* not being cached is not the same as not existing. One the cache knows was
|
|
178
|
+
* deleted reads as `Missing`. A `getDocs` never fails for what the cache lacks:
|
|
179
|
+
* it returns whatever the cache holds, which may be nothing, with `fromCache:
|
|
180
|
+
* true`. So, unlike `getDoc`, an empty result cannot tell "nothing cached" from
|
|
181
|
+
* "nothing there".
|
|
182
|
+
*
|
|
183
|
+
* The portable {@link Firestore.With.getDoc} takes no options, because the
|
|
184
|
+
* Admin SDK's reads take none.
|
|
185
|
+
*
|
|
186
|
+
* @example Reading from the server alone
|
|
187
|
+
* ```ts
|
|
188
|
+
* import { Effect, Schema } from "effect";
|
|
189
|
+
* import { Collection, FirestoreModel } from "@visiolab/effect-firebase/firestore";
|
|
190
|
+
* import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
|
|
191
|
+
*
|
|
192
|
+
* class Post extends FirestoreModel.Class<Post>("Post")({
|
|
193
|
+
* title: Schema.String,
|
|
194
|
+
* }) {}
|
|
195
|
+
*
|
|
196
|
+
* const Posts = Collection.make("posts", Post);
|
|
197
|
+
*
|
|
198
|
+
* const fresh = Effect.gen(function* () {
|
|
199
|
+
* const firestore = yield* ClientFirestore.ClientFirestore;
|
|
200
|
+
* return yield* firestore.getDoc(Posts.doc(Posts.id.make("hello")), { source: "server" });
|
|
201
|
+
* });
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @see {@link ReadSource} for where a read can be served from
|
|
205
|
+
* @see {@link ListenOptions} for the options of a listen
|
|
206
|
+
*
|
|
207
|
+
* @stability unstable
|
|
208
|
+
* @category models
|
|
209
|
+
* @since 0.1.0
|
|
210
|
+
*/
|
|
211
|
+
export interface ReadOptions {
|
|
212
|
+
/**
|
|
213
|
+
* Where the read is served from. Left out, it is `"default"`.
|
|
214
|
+
*
|
|
215
|
+
* @see {@link ReadSource} for each source, and what a cached read does with what the cache lacks
|
|
216
|
+
*/
|
|
217
|
+
readonly source?: ReadSource | undefined;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Where the Firestore emulator listens, such as `{ host: "127.0.0.1", port:
|
|
221
|
+
* 8080 }`.
|
|
222
|
+
*
|
|
223
|
+
* @see {@link Options.emulator} for connecting to it
|
|
224
|
+
*
|
|
225
|
+
* @stability unstable
|
|
226
|
+
* @category models
|
|
227
|
+
* @since 0.1.0
|
|
228
|
+
*/
|
|
229
|
+
export interface Emulator {
|
|
230
|
+
readonly host: string;
|
|
231
|
+
readonly port: number;
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* How {@link layer} opens a database. All of them are fixed once the database
|
|
235
|
+
* is open.
|
|
236
|
+
*
|
|
237
|
+
* @see {@link AdminFirestore.Options} for the Admin SDK's, which read the emulator from the environment
|
|
238
|
+
*
|
|
239
|
+
* @stability unstable
|
|
240
|
+
* @category models
|
|
241
|
+
* @since 0.1.0
|
|
242
|
+
*/
|
|
243
|
+
export interface Options {
|
|
244
|
+
/**
|
|
245
|
+
* The database to open, where the project has more than its default one.
|
|
246
|
+
* Leave it out for the default database.
|
|
247
|
+
*/
|
|
248
|
+
readonly databaseId?: string | undefined;
|
|
249
|
+
/**
|
|
250
|
+
* The emulator to talk to instead of the project's database.
|
|
251
|
+
*
|
|
252
|
+
* Unlike the Admin SDK, the client SDK takes the emulator per database, not
|
|
253
|
+
* from the environment, and only before the database is first used.
|
|
254
|
+
*/
|
|
255
|
+
readonly emulator?: Emulator | undefined;
|
|
256
|
+
/**
|
|
257
|
+
* Where the SDK keeps the documents it has seen and the writes it has yet to
|
|
258
|
+
* send: `memoryLocalCache()`, the SDK's default, or `persistentLocalCache()`,
|
|
259
|
+
* which keeps them in IndexedDB across reloads.
|
|
260
|
+
*/
|
|
261
|
+
readonly localCache?: FirestoreLocalCache | undefined;
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Builds {@link ClientFirestore} on the {@link App.App} in context.
|
|
265
|
+
*
|
|
266
|
+
* **When to use**
|
|
267
|
+
*
|
|
268
|
+
* Use to build the service inside an effect of your own. Most programs provide
|
|
269
|
+
* it with {@link layer} instead, which also provides it as {@link Firestore}.
|
|
270
|
+
*
|
|
271
|
+
* **Details**
|
|
272
|
+
*
|
|
273
|
+
* Building the service cannot fail. Opening a database only throws for an app
|
|
274
|
+
* that was already deleted, or a database already opened or used with other
|
|
275
|
+
* settings. Both are wiring mistakes, so they are defects, and a
|
|
276
|
+
* {@link Firestore.FirestoreError} only ever means that a call failed.
|
|
277
|
+
*
|
|
278
|
+
* A write only succeeds once the server acknowledges it, so a write made
|
|
279
|
+
* offline waits for the connection. It is applied to the local cache at once
|
|
280
|
+
* and sent when it can be: interrupting the write, or timing it out, does not
|
|
281
|
+
* take it back.
|
|
282
|
+
*
|
|
283
|
+
* A server timestamp the server has not settled yet reads as the local clock's
|
|
284
|
+
* estimate, so the field decodes as a timestamp.
|
|
285
|
+
*
|
|
286
|
+
* @see {@link layer} for the same as a layer
|
|
287
|
+
*
|
|
288
|
+
* @stability unstable
|
|
289
|
+
* @category constructors
|
|
290
|
+
* @since 0.1.0
|
|
291
|
+
*/
|
|
292
|
+
export declare const make: (options?: Options) => Effect.Effect<ClientFirestore & Firestore, never, App>;
|
|
293
|
+
/**
|
|
294
|
+
* A layer that provides {@link ClientFirestore} for the {@link App.App} in
|
|
295
|
+
* context, and the same service as the portable {@link Firestore}.
|
|
296
|
+
*
|
|
297
|
+
* **When to use**
|
|
298
|
+
*
|
|
299
|
+
* Use in a browser, or anywhere the client SDK runs. On a server, use
|
|
300
|
+
* {@link AdminFirestore.layer} instead.
|
|
301
|
+
*
|
|
302
|
+
* **Details**
|
|
303
|
+
*
|
|
304
|
+
* With no options it opens the project's default database with the SDK's
|
|
305
|
+
* defaults.
|
|
306
|
+
*
|
|
307
|
+
* @example Providing Firestore with a persistent cache
|
|
308
|
+
* ```ts
|
|
309
|
+
* import { Layer } from "effect";
|
|
310
|
+
* import { persistentLocalCache } from "firebase/firestore";
|
|
311
|
+
* import { App } from "@visiolab/effect-firebase-client/app";
|
|
312
|
+
* import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
|
|
313
|
+
*
|
|
314
|
+
* const FirestoreLive = ClientFirestore.layer({
|
|
315
|
+
* localCache: persistentLocalCache(),
|
|
316
|
+
* emulator: import.meta.env.DEV ? { host: "127.0.0.1", port: 8080 } : undefined,
|
|
317
|
+
* }).pipe(
|
|
318
|
+
* Layer.provide(App.layer({ apiKey: "<api key>", projectId: "my-project", appId: "<app id>" })),
|
|
319
|
+
* );
|
|
320
|
+
* ```
|
|
321
|
+
*
|
|
322
|
+
* @see {@link make} for why building the service cannot fail
|
|
323
|
+
* @see {@link AdminFirestore.layer} for the Admin SDK's layer, for servers
|
|
324
|
+
*
|
|
325
|
+
* @stability unstable
|
|
326
|
+
* @category layers
|
|
327
|
+
* @since 0.1.0
|
|
328
|
+
*/
|
|
329
|
+
export declare const layer: (options?: Options) => Layer.Layer<ClientFirestore | Firestore, never, App>;
|
|
330
|
+
export { ClientFirestore_d_exports };
|
|
331
|
+
//# sourceMappingURL=ClientFirestore.d.mts.map
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { fromDatabase, openDatabase } from "./internal/firestore.mjs";
|
|
3
|
+
import { Context, Effect, Layer } from "effect";
|
|
4
|
+
import { Firestore } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
5
|
+
// src/firestore/ClientFirestore.ts
|
|
6
|
+
/**
|
|
7
|
+
* Firestore on the Firebase client SDK, for browsers.
|
|
8
|
+
*
|
|
9
|
+
* {@link layer} provides one service under two keys: the portable
|
|
10
|
+
* {@link Firestore}, which code that runs on either SDK asks for, and
|
|
11
|
+
* {@link ClientFirestore}, which adds what only the client SDK can do: read
|
|
12
|
+
* sources, listen options, and the
|
|
13
|
+
* {@link ClientDocumentSnapshot.SnapshotMetadata} of every read. Both reach the
|
|
14
|
+
* same database.
|
|
15
|
+
*
|
|
16
|
+
* Where it behaves differently from the Admin SDK:
|
|
17
|
+
*
|
|
18
|
+
* - The emulator is a layer option, not an environment variable.
|
|
19
|
+
* - A write only succeeds once the server acknowledges it, so a write made
|
|
20
|
+
* offline waits for the connection. It is applied to the local cache at once
|
|
21
|
+
* and sent when it can be; interrupting the write does not take it back.
|
|
22
|
+
* - A pending server timestamp reads as the local clock's estimate, not `null`,
|
|
23
|
+
* so it decodes as a timestamp before the server has settled it.
|
|
24
|
+
* - Error codes are always named, such as `permission-denied`.
|
|
25
|
+
*
|
|
26
|
+
* @example Reading a document, and where the read came from
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { Effect, Layer, Schema } from "effect";
|
|
29
|
+
* import { Collection, FirestoreModel } from "@visiolab/effect-firebase/firestore";
|
|
30
|
+
* import { App } from "@visiolab/effect-firebase-client/app";
|
|
31
|
+
* import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
|
|
32
|
+
*
|
|
33
|
+
* class Post extends FirestoreModel.Class<Post>("Post")({
|
|
34
|
+
* title: Schema.String,
|
|
35
|
+
* }) {}
|
|
36
|
+
*
|
|
37
|
+
* const Posts = Collection.make("posts", Post);
|
|
38
|
+
*
|
|
39
|
+
* const program = Effect.gen(function* () {
|
|
40
|
+
* const firestore = yield* ClientFirestore.ClientFirestore;
|
|
41
|
+
* const snapshot = yield* firestore.getDoc(Posts.doc(Posts.id.make("hello")));
|
|
42
|
+
* yield* Effect.log(snapshot.metadata.fromCache ? "from the cache" : "from the server");
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* const FirestoreLive = ClientFirestore.layer().pipe(
|
|
46
|
+
* Layer.provide(App.layer({ apiKey: "<api key>", projectId: "my-project", appId: "<app id>" })),
|
|
47
|
+
* );
|
|
48
|
+
*
|
|
49
|
+
* program.pipe(Effect.provide(FirestoreLive));
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* @see {@link AdminFirestore} for the same service on the Admin SDK, for servers
|
|
53
|
+
*
|
|
54
|
+
* @stability unstable
|
|
55
|
+
* @since 0.1.0
|
|
56
|
+
*/
|
|
57
|
+
var ClientFirestore_exports = /* @__PURE__ */ __exportAll({
|
|
58
|
+
ClientFirestore: () => ClientFirestore,
|
|
59
|
+
layer: () => layer,
|
|
60
|
+
make: () => make
|
|
61
|
+
});
|
|
62
|
+
/**
|
|
63
|
+
* Service key for {@link ClientFirestore}.
|
|
64
|
+
*
|
|
65
|
+
* @see {@link Firestore} for the portable key, which {@link layer} provides the same service under
|
|
66
|
+
*
|
|
67
|
+
* @stability unstable
|
|
68
|
+
* @category services
|
|
69
|
+
* @since 0.1.0
|
|
70
|
+
*/
|
|
71
|
+
const ClientFirestore = Context.Service("@visiolab/effect-firebase-client/firestore/ClientFirestore");
|
|
72
|
+
/**
|
|
73
|
+
* Builds {@link ClientFirestore} on the {@link App.App} in context.
|
|
74
|
+
*
|
|
75
|
+
* **When to use**
|
|
76
|
+
*
|
|
77
|
+
* Use to build the service inside an effect of your own. Most programs provide
|
|
78
|
+
* it with {@link layer} instead, which also provides it as {@link Firestore}.
|
|
79
|
+
*
|
|
80
|
+
* **Details**
|
|
81
|
+
*
|
|
82
|
+
* Building the service cannot fail. Opening a database only throws for an app
|
|
83
|
+
* that was already deleted, or a database already opened or used with other
|
|
84
|
+
* settings. Both are wiring mistakes, so they are defects, and a
|
|
85
|
+
* {@link Firestore.FirestoreError} only ever means that a call failed.
|
|
86
|
+
*
|
|
87
|
+
* A write only succeeds once the server acknowledges it, so a write made
|
|
88
|
+
* offline waits for the connection. It is applied to the local cache at once
|
|
89
|
+
* and sent when it can be: interrupting the write, or timing it out, does not
|
|
90
|
+
* take it back.
|
|
91
|
+
*
|
|
92
|
+
* A server timestamp the server has not settled yet reads as the local clock's
|
|
93
|
+
* estimate, so the field decodes as a timestamp.
|
|
94
|
+
*
|
|
95
|
+
* @see {@link layer} for the same as a layer
|
|
96
|
+
*
|
|
97
|
+
* @stability unstable
|
|
98
|
+
* @category constructors
|
|
99
|
+
* @since 0.1.0
|
|
100
|
+
*/
|
|
101
|
+
const make = Effect.fn("ClientFirestore.make")(function* (options) {
|
|
102
|
+
const firestore = yield* openDatabase(options);
|
|
103
|
+
return fromDatabase(firestore);
|
|
104
|
+
});
|
|
105
|
+
/** The one service, under both its own tag and the portable one. */
|
|
106
|
+
const both = (service) => Context.make(ClientFirestore, service).pipe(Context.add(Firestore, service));
|
|
107
|
+
/**
|
|
108
|
+
* A layer that provides {@link ClientFirestore} for the {@link App.App} in
|
|
109
|
+
* context, and the same service as the portable {@link Firestore}.
|
|
110
|
+
*
|
|
111
|
+
* **When to use**
|
|
112
|
+
*
|
|
113
|
+
* Use in a browser, or anywhere the client SDK runs. On a server, use
|
|
114
|
+
* {@link AdminFirestore.layer} instead.
|
|
115
|
+
*
|
|
116
|
+
* **Details**
|
|
117
|
+
*
|
|
118
|
+
* With no options it opens the project's default database with the SDK's
|
|
119
|
+
* defaults.
|
|
120
|
+
*
|
|
121
|
+
* @example Providing Firestore with a persistent cache
|
|
122
|
+
* ```ts
|
|
123
|
+
* import { Layer } from "effect";
|
|
124
|
+
* import { persistentLocalCache } from "firebase/firestore";
|
|
125
|
+
* import { App } from "@visiolab/effect-firebase-client/app";
|
|
126
|
+
* import { ClientFirestore } from "@visiolab/effect-firebase-client/firestore";
|
|
127
|
+
*
|
|
128
|
+
* const FirestoreLive = ClientFirestore.layer({
|
|
129
|
+
* localCache: persistentLocalCache(),
|
|
130
|
+
* emulator: import.meta.env.DEV ? { host: "127.0.0.1", port: 8080 } : undefined,
|
|
131
|
+
* }).pipe(
|
|
132
|
+
* Layer.provide(App.layer({ apiKey: "<api key>", projectId: "my-project", appId: "<app id>" })),
|
|
133
|
+
* );
|
|
134
|
+
* ```
|
|
135
|
+
*
|
|
136
|
+
* @see {@link make} for why building the service cannot fail
|
|
137
|
+
* @see {@link AdminFirestore.layer} for the Admin SDK's layer, for servers
|
|
138
|
+
*
|
|
139
|
+
* @stability unstable
|
|
140
|
+
* @category layers
|
|
141
|
+
* @since 0.1.0
|
|
142
|
+
*/
|
|
143
|
+
const layer = (options) => Layer.effectContext(Effect.map(make(options), both));
|
|
144
|
+
export { ClientFirestore, ClientFirestore_exports, layer, make };
|
|
145
|
+
|
|
146
|
+
//# sourceMappingURL=ClientFirestore.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientFirestore.mjs","names":["internalFirestore.openDatabase","internalFirestore.fromDatabase"],"sources":["../../src/firestore/ClientFirestore.ts"],"sourcesContent":["/**\n * Firestore on the Firebase client SDK, for browsers.\n *\n * {@link layer} provides one service under two keys: the portable\n * {@link Firestore}, which code that runs on either SDK asks for, and\n * {@link ClientFirestore}, which adds what only the client SDK can do: read\n * sources, listen options, and the\n * {@link ClientDocumentSnapshot.SnapshotMetadata} of every read. Both reach the\n * same database.\n *\n * Where it behaves differently from the Admin SDK:\n *\n * - The emulator is a layer option, not an environment variable.\n * - A write only succeeds once the server acknowledges it, so a write made\n * offline waits for the connection. It is applied to the local cache at once\n * and sent when it can be; interrupting the write does not take it back.\n * - A pending server timestamp reads as the local clock's estimate, not `null`,\n * so it decodes as a timestamp before the server has settled it.\n * - Error codes are always named, such as `permission-denied`.\n *\n * @example Reading a document, and where the read came from\n * ```ts\n * import { Effect, Layer, Schema } from \"effect\";\n * import { Collection, FirestoreModel } from \"@visiolab/effect-firebase/firestore\";\n * import { App } from \"@visiolab/effect-firebase-client/app\";\n * import { ClientFirestore } from \"@visiolab/effect-firebase-client/firestore\";\n *\n * class Post extends FirestoreModel.Class<Post>(\"Post\")({\n * title: Schema.String,\n * }) {}\n *\n * const Posts = Collection.make(\"posts\", Post);\n *\n * const program = Effect.gen(function* () {\n * const firestore = yield* ClientFirestore.ClientFirestore;\n * const snapshot = yield* firestore.getDoc(Posts.doc(Posts.id.make(\"hello\")));\n * yield* Effect.log(snapshot.metadata.fromCache ? \"from the cache\" : \"from the server\");\n * });\n *\n * const FirestoreLive = ClientFirestore.layer().pipe(\n * Layer.provide(App.layer({ apiKey: \"<api key>\", projectId: \"my-project\", appId: \"<app id>\" })),\n * );\n *\n * program.pipe(Effect.provide(FirestoreLive));\n * ```\n *\n * @see {@link AdminFirestore} for the same service on the Admin SDK, for servers\n *\n * @stability unstable\n * @since 0.1.0\n */\nimport { Context, Effect, Layer } from \"effect\";\nimport { Firestore, type With } from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport type { Firestore as SdkFirestore, FirestoreLocalCache } from \"firebase/firestore\";\nimport type * as App from \"../app/App.ts\";\nimport type * as ClientDocumentSnapshot from \"./ClientDocumentSnapshot.ts\";\n// Only {@link ClientFirestore}'s documentation links to it.\n// oxlint-disable-next-line no-unused-vars\nimport type * as ClientQuerySnapshot from \"./ClientQuerySnapshot.ts\";\nimport * as internalFirestore from \"./internal/firestore.ts\";\n\nconst TypeId = internalFirestore.TypeId;\n\n/**\n * The portable {@link Firestore}, plus what only the client SDK can do.\n *\n * **When to use**\n *\n * Ask for it where code needs the client SDK: a read from the server or the\n * cache alone, metadata changes on a listen, a snapshot's\n * {@link ClientDocumentSnapshot.SnapshotMetadata}, or the SDK itself through\n * {@link ClientFirestore.instance}. Everywhere else ask for {@link Firestore},\n * so the code also runs on the Admin SDK.\n *\n * **Details**\n *\n * Its reads take {@link ReadOptions} and its listens {@link ListenOptions}.\n * Every document snapshot, each document of a query snapshot, and each query\n * snapshot as a whole carries the `metadata` of its read, as a\n * {@link ClientDocumentSnapshot.ClientDocumentSnapshot} or\n * {@link ClientQuerySnapshot.ClientQuerySnapshot} does.\n *\n * The service its key holds is also a {@link Firestore}, so it can be handed\n * to code that expects one as it is. The type itself only extends\n * {@link Firestore.With}, so providing a {@link Firestore} alone, such as an\n * in-memory fake, does not satisfy code that asks for it. Its\n * transactions are the portable {@link Firestore.Transaction}: the client SDK's\n * transactions read one document at a time.\n *\n * The client SDK cannot abort a request in flight, so interrupting a call does\n * not stop it: the request still runs to completion.\n *\n * @see {@link Firestore.With} for each read and write it offers\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface ClientFirestore extends With<\n ReadOptions,\n ListenOptions,\n { readonly metadata: ClientDocumentSnapshot.SnapshotMetadata }\n> {\n readonly [TypeId]: typeof TypeId;\n\n /**\n * The client SDK's own `Firestore`, for the database the service was opened\n * on.\n *\n * **When to use**\n *\n * Use for what this service does not wrap, such as queries or\n * `disableNetwork` and `enableNetwork`. Prefer the service's own methods\n * where one exists.\n *\n * **Details**\n *\n * Calls through it skip the collection's model, take and return the SDK's\n * own values, and throw the SDK's own errors. To write a model through it,\n * encode with {@link FirestoreValue.toCodecFirestore} and map with\n * {@link ClientFirestoreValue.toClient}.\n *\n * @see {@link ClientFirestoreValue} for mapping between the SDK's values and Firestore Values\n */\n readonly instance: SdkFirestore;\n}\n\n/**\n * How `streamDoc` and `streamDocs` on {@link ClientFirestore} listen, named as\n * in the client SDK's own listen options.\n *\n * **When to use**\n *\n * Use to also hear metadata changes, such as a pending write being\n * acknowledged, or to listen to the local cache alone. Left out, a listen\n * behaves as the SDK's does by default: it emits only when the data changes.\n *\n * **Details**\n *\n * Every snapshot a listen emits carries the\n * {@link ClientDocumentSnapshot.SnapshotMetadata} it arrived with. The portable\n * {@link Firestore.With.streamDoc} takes no options, because the Admin SDK's\n * listeners take none.\n *\n * @example Waiting for the server to acknowledge a write\n * ```ts\n * import { Effect, Schema, Stream } from \"effect\";\n * import { Collection, FirestoreModel } from \"@visiolab/effect-firebase/firestore\";\n * import { ClientFirestore } from \"@visiolab/effect-firebase-client/firestore\";\n *\n * class Post extends FirestoreModel.Class<Post>(\"Post\")({\n * title: Schema.String,\n * }) {}\n *\n * const Posts = Collection.make(\"posts\", Post);\n * const hello = Posts.doc(Posts.id.make(\"hello\"));\n *\n * const acknowledged = Effect.gen(function* () {\n * const firestore = yield* ClientFirestore.ClientFirestore;\n * yield* firestore.streamDoc(hello, { includeMetadataChanges: true }).pipe(\n * Stream.filter((snapshot) => !snapshot.metadata.hasPendingWrites),\n * Stream.runHead,\n * );\n * });\n * ```\n *\n * @see {@link ReadOptions} for the options of a one-off read\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface ListenOptions {\n /**\n * Whether to also emit when only the\n * {@link ClientDocumentSnapshot.SnapshotMetadata} changes, such as when the\n * server acknowledges a pending write or the cache catches up with the\n * server. Without it, a listen only emits when the data changes.\n */\n readonly includeMetadataChanges?: boolean | undefined;\n /**\n * Where to listen. `\"default\"` listens to the server and the local cache.\n * `\"cache\"` listens to the local cache alone and never reaches the server, so\n * it only sees what this client has written or already read.\n */\n readonly source?: \"default\" | \"cache\" | undefined;\n}\n\n/**\n * Service key for {@link ClientFirestore}.\n *\n * @see {@link Firestore} for the portable key, which {@link layer} provides the same service under\n *\n * @stability unstable\n * @category services\n * @since 0.1.0\n */\nexport const ClientFirestore = Context.Service<ClientFirestore, ClientFirestore & Firestore>(\n \"@visiolab/effect-firebase-client/firestore/ClientFirestore\",\n);\n\n/**\n * Where a one-off read is served from.\n *\n * - `\"default\"`: the server when it can be reached, otherwise the local cache.\n * What a read does when no source is given.\n * - `\"server\"`: the server alone. Fails with the SDK's code when the server\n * cannot be reached, instead of falling back to the cache.\n * - `\"cache\"`: the local cache alone, without asking the server.\n *\n * The two reads report what the cache lacks differently, as the SDK does. A\n * cached `getDoc` of a document the cache has never seen fails with a\n * {@link Firestore.FirestoreError} whose code is `unavailable`, and one the\n * cache knows was deleted reads as `Missing`. A cached `getDocs` never fails\n * for what the cache lacks: it returns whatever the cache holds, which may be\n * nothing, with `fromCache: true`.\n *\n * @see {@link ReadOptions} for passing it to a read\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport type ReadSource = \"default\" | \"server\" | \"cache\";\n\n/**\n * How `getDoc` and `getDocs` on {@link ClientFirestore} read a document, a\n * collection, or a Collection Group.\n *\n * **When to use**\n *\n * Use to read from the server alone, such as to confirm a value before acting\n * on it, or from the local cache alone, such as to render at once while\n * offline. Left out, a read behaves as the SDK's does by default.\n *\n * **Details**\n *\n * With `source: \"cache\"`, a `getDoc` of a document the cache has never seen\n * fails with a {@link Firestore.FirestoreError} whose code is `unavailable`:\n * not being cached is not the same as not existing. One the cache knows was\n * deleted reads as `Missing`. A `getDocs` never fails for what the cache lacks:\n * it returns whatever the cache holds, which may be nothing, with `fromCache:\n * true`. So, unlike `getDoc`, an empty result cannot tell \"nothing cached\" from\n * \"nothing there\".\n *\n * The portable {@link Firestore.With.getDoc} takes no options, because the\n * Admin SDK's reads take none.\n *\n * @example Reading from the server alone\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 Post extends FirestoreModel.Class<Post>(\"Post\")({\n * title: Schema.String,\n * }) {}\n *\n * const Posts = Collection.make(\"posts\", Post);\n *\n * const fresh = Effect.gen(function* () {\n * const firestore = yield* ClientFirestore.ClientFirestore;\n * return yield* firestore.getDoc(Posts.doc(Posts.id.make(\"hello\")), { source: \"server\" });\n * });\n * ```\n *\n * @see {@link ReadSource} for where a read can be served from\n * @see {@link ListenOptions} for the options of a listen\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface ReadOptions {\n /**\n * Where the read is served from. Left out, it is `\"default\"`.\n *\n * @see {@link ReadSource} for each source, and what a cached read does with what the cache lacks\n */\n readonly source?: ReadSource | undefined;\n}\n\n/**\n * Where the Firestore emulator listens, such as `{ host: \"127.0.0.1\", port:\n * 8080 }`.\n *\n * @see {@link Options.emulator} for connecting to it\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface Emulator {\n readonly host: string;\n readonly port: number;\n}\n\n/**\n * How {@link layer} opens a database. All of them are fixed once the database\n * is open.\n *\n * @see {@link AdminFirestore.Options} for the Admin SDK's, which read the emulator from the environment\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface Options {\n /**\n * The database to open, where the project has more than its default one.\n * Leave it out for the default database.\n */\n readonly databaseId?: string | undefined;\n /**\n * The emulator to talk to instead of the project's database.\n *\n * Unlike the Admin SDK, the client SDK takes the emulator per database, not\n * from the environment, and only before the database is first used.\n */\n readonly emulator?: Emulator | undefined;\n /**\n * Where the SDK keeps the documents it has seen and the writes it has yet to\n * send: `memoryLocalCache()`, the SDK's default, or `persistentLocalCache()`,\n * which keeps them in IndexedDB across reloads.\n */\n readonly localCache?: FirestoreLocalCache | undefined;\n}\n\n/**\n * Builds {@link ClientFirestore} on the {@link App.App} in context.\n *\n * **When to use**\n *\n * Use to build the service inside an effect of your own. Most programs provide\n * it with {@link layer} instead, which also provides it as {@link Firestore}.\n *\n * **Details**\n *\n * Building the service cannot fail. Opening a database only throws for an app\n * that was already deleted, or a database already opened or used with other\n * settings. Both are wiring mistakes, so they are defects, and a\n * {@link Firestore.FirestoreError} only ever means that a call failed.\n *\n * A write only succeeds once the server acknowledges it, so a write made\n * offline waits for the connection. It is applied to the local cache at once\n * and sent when it can be: interrupting the write, or timing it out, does not\n * take it back.\n *\n * A server timestamp the server has not settled yet reads as the local clock's\n * estimate, so the field decodes as a timestamp.\n *\n * @see {@link layer} for the same as a layer\n *\n * @stability unstable\n * @category constructors\n * @since 0.1.0\n */\nexport const make: (\n options?: Options,\n) => Effect.Effect<ClientFirestore & Firestore, never, App.App> = Effect.fn(\"ClientFirestore.make\")(\n function* (options?: Options) {\n const firestore = yield* internalFirestore.openDatabase(options);\n return internalFirestore.fromDatabase(firestore);\n },\n);\n\n/** The one service, under both its own tag and the portable one. */\nconst both = (service: ClientFirestore & Firestore) =>\n Context.make(ClientFirestore, service).pipe(Context.add(Firestore, service));\n\n/**\n * A layer that provides {@link ClientFirestore} for the {@link App.App} in\n * context, and the same service as the portable {@link Firestore}.\n *\n * **When to use**\n *\n * Use in a browser, or anywhere the client SDK runs. On a server, use\n * {@link AdminFirestore.layer} instead.\n *\n * **Details**\n *\n * With no options it opens the project's default database with the SDK's\n * defaults.\n *\n * @example Providing Firestore with a persistent cache\n * ```ts\n * import { Layer } from \"effect\";\n * import { persistentLocalCache } from \"firebase/firestore\";\n * import { App } from \"@visiolab/effect-firebase-client/app\";\n * import { ClientFirestore } from \"@visiolab/effect-firebase-client/firestore\";\n *\n * const FirestoreLive = ClientFirestore.layer({\n * localCache: persistentLocalCache(),\n * emulator: import.meta.env.DEV ? { host: \"127.0.0.1\", port: 8080 } : undefined,\n * }).pipe(\n * Layer.provide(App.layer({ apiKey: \"<api key>\", projectId: \"my-project\", appId: \"<app id>\" })),\n * );\n * ```\n *\n * @see {@link make} for why building the service cannot fail\n * @see {@link AdminFirestore.layer} for the Admin SDK's layer, for servers\n *\n * @stability unstable\n * @category layers\n * @since 0.1.0\n */\nexport const layer = (\n options?: Options,\n): Layer.Layer<ClientFirestore | Firestore, never, App.App> =>\n Layer.effectContext(Effect.map(make(options), both));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqMA,MAAa,kBAAkB,QAAQ,QACrC,4DACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8JA,MAAa,OAEqD,OAAO,GAAG,sBAAsB,CAAC,CACjG,WAAW,SAAmB;CAC5B,MAAM,YAAY,OAAOA,aAA+B,OAAO;CAC/D,OAAOC,aAA+B,SAAS;AACjD,CACF;;AAGA,MAAM,QAAQ,YACZ,QAAQ,KAAK,iBAAiB,OAAO,CAAC,CAAC,KAAK,QAAQ,IAAI,WAAW,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsC7E,MAAa,SACX,YAEA,MAAM,cAAc,OAAO,IAAI,KAAK,OAAO,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Result } from "effect";
|
|
2
|
+
import { FirestoreError } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
3
|
+
import { Firestore as Firestore$1 } from "firebase/firestore";
|
|
4
|
+
import { FirestoreValue } from "@visiolab/effect-firebase/firestore/FirestoreValue";
|
|
5
|
+
declare namespace ClientFirestoreValue_d_exports {
|
|
6
|
+
export { fromClient, toClient };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Turns a Firestore Value into the value the client SDK writes into
|
|
10
|
+
* `firestore`.
|
|
11
|
+
*
|
|
12
|
+
* **When to use**
|
|
13
|
+
*
|
|
14
|
+
* Use to write what a model encodes to through the client SDK itself.
|
|
15
|
+
*
|
|
16
|
+
* **Details**
|
|
17
|
+
*
|
|
18
|
+
* The portable `Timestamp`, `GeoPoint` and bytes become the SDK's `Timestamp`,
|
|
19
|
+
* `GeoPoint` and `Bytes`, and the sentinels its `FieldValue`s. A `DocumentPath`
|
|
20
|
+
* becomes `doc(firestore, path)`, so it points into that database. Map keys are
|
|
21
|
+
* kept as they are, so the dotted field paths of an update stay field paths.
|
|
22
|
+
*
|
|
23
|
+
* It throws for anything that is not a Firestore Value, such as one of the
|
|
24
|
+
* client SDK's own values or a class instance cast past the type. What
|
|
25
|
+
* {@link FirestoreValue.toCodecFirestore} encodes is always a Firestore Value.
|
|
26
|
+
*
|
|
27
|
+
* @see {@link fromClient} for the other direction
|
|
28
|
+
*
|
|
29
|
+
* @stability unstable
|
|
30
|
+
* @category conversions
|
|
31
|
+
* @since 0.3.0
|
|
32
|
+
*/
|
|
33
|
+
export declare const toClient: (value: FirestoreValue, firestore: Firestore$1) => unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Turns a value the client SDK read into a Firestore Value.
|
|
36
|
+
*
|
|
37
|
+
* **When to use**
|
|
38
|
+
*
|
|
39
|
+
* Use to decode what the client SDK itself read through a model, with
|
|
40
|
+
* {@link FirestoreValue.toCodecFirestore}.
|
|
41
|
+
*
|
|
42
|
+
* **Details**
|
|
43
|
+
*
|
|
44
|
+
* The SDK's `Timestamp`, `GeoPoint` and `Bytes` become the portable
|
|
45
|
+
* `Timestamp`, `GeoPoint` and `Uint8Array`. A `DocumentReference` becomes the
|
|
46
|
+
* `DocumentPath` it points at, since Firestore stores nothing else of it;
|
|
47
|
+
* {@link FirestoreSchema.DocumentReference} reads that back into the
|
|
48
|
+
* collection it names.
|
|
49
|
+
*
|
|
50
|
+
* Fails with a {@link Firestore.FirestoreError} naming the field for a value
|
|
51
|
+
* that is not a Firestore Value, such as a vector.
|
|
52
|
+
*
|
|
53
|
+
* @see {@link toClient} for the other direction
|
|
54
|
+
*
|
|
55
|
+
* @stability unstable
|
|
56
|
+
* @category conversions
|
|
57
|
+
* @since 0.3.0
|
|
58
|
+
*/
|
|
59
|
+
export declare const fromClient: (value: unknown) => Result.Result<FirestoreValue, FirestoreError>;
|
|
60
|
+
export { ClientFirestoreValue_d_exports };
|
|
61
|
+
//# sourceMappingURL=ClientFirestoreValue.d.mts.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { fromClient as fromClient$1, toClient as toClient$1 } from "./internal/firestoreValue.mjs";
|
|
3
|
+
// src/firestore/ClientFirestoreValue.ts
|
|
4
|
+
var ClientFirestoreValue_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
fromClient: () => fromClient,
|
|
6
|
+
toClient: () => toClient
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Turns a Firestore Value into the value the client SDK writes into
|
|
10
|
+
* `firestore`.
|
|
11
|
+
*
|
|
12
|
+
* **When to use**
|
|
13
|
+
*
|
|
14
|
+
* Use to write what a model encodes to through the client SDK itself.
|
|
15
|
+
*
|
|
16
|
+
* **Details**
|
|
17
|
+
*
|
|
18
|
+
* The portable `Timestamp`, `GeoPoint` and bytes become the SDK's `Timestamp`,
|
|
19
|
+
* `GeoPoint` and `Bytes`, and the sentinels its `FieldValue`s. A `DocumentPath`
|
|
20
|
+
* becomes `doc(firestore, path)`, so it points into that database. Map keys are
|
|
21
|
+
* kept as they are, so the dotted field paths of an update stay field paths.
|
|
22
|
+
*
|
|
23
|
+
* It throws for anything that is not a Firestore Value, such as one of the
|
|
24
|
+
* client SDK's own values or a class instance cast past the type. What
|
|
25
|
+
* {@link FirestoreValue.toCodecFirestore} encodes is always a Firestore Value.
|
|
26
|
+
*
|
|
27
|
+
* @see {@link fromClient} for the other direction
|
|
28
|
+
*
|
|
29
|
+
* @stability unstable
|
|
30
|
+
* @category conversions
|
|
31
|
+
* @since 0.3.0
|
|
32
|
+
*/
|
|
33
|
+
const toClient = toClient$1;
|
|
34
|
+
/**
|
|
35
|
+
* Turns a value the client SDK read into a Firestore Value.
|
|
36
|
+
*
|
|
37
|
+
* **When to use**
|
|
38
|
+
*
|
|
39
|
+
* Use to decode what the client SDK itself read through a model, with
|
|
40
|
+
* {@link FirestoreValue.toCodecFirestore}.
|
|
41
|
+
*
|
|
42
|
+
* **Details**
|
|
43
|
+
*
|
|
44
|
+
* The SDK's `Timestamp`, `GeoPoint` and `Bytes` become the portable
|
|
45
|
+
* `Timestamp`, `GeoPoint` and `Uint8Array`. A `DocumentReference` becomes the
|
|
46
|
+
* `DocumentPath` it points at, since Firestore stores nothing else of it;
|
|
47
|
+
* {@link FirestoreSchema.DocumentReference} reads that back into the
|
|
48
|
+
* collection it names.
|
|
49
|
+
*
|
|
50
|
+
* Fails with a {@link Firestore.FirestoreError} naming the field for a value
|
|
51
|
+
* that is not a Firestore Value, such as a vector.
|
|
52
|
+
*
|
|
53
|
+
* @see {@link toClient} for the other direction
|
|
54
|
+
*
|
|
55
|
+
* @stability unstable
|
|
56
|
+
* @category conversions
|
|
57
|
+
* @since 0.3.0
|
|
58
|
+
*/
|
|
59
|
+
const fromClient = fromClient$1;
|
|
60
|
+
export { ClientFirestoreValue_exports, fromClient, toClient };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=ClientFirestoreValue.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientFirestoreValue.mjs","names":["internal.toClient","internal.fromClient"],"sources":["../../src/firestore/ClientFirestoreValue.ts"],"sourcesContent":["/**\n * Maps between Firestore Values, the portable values a model encodes to, and\n * the values the client SDK reads and writes.\n *\n * {@link ClientFirestore} applies it on every read and write. Use it directly\n * to read or write a model through the client SDK itself, such as through\n * {@link ClientFirestore.instance}.\n *\n * @example Writing a model through the client SDK\n * ```ts\n * import { Schema } from \"effect\";\n * import { FirestoreModel, FirestoreValue } from \"@visiolab/effect-firebase/firestore\";\n * import { ClientFirestoreValue } from \"@visiolab/effect-firebase-client/firestore\";\n * import { type DocumentData, doc, getFirestore, setDoc } from \"firebase/firestore\";\n *\n * class Post extends FirestoreModel.Class<Post>(\"Post\")({\n * title: Schema.String,\n * }) {}\n *\n * const firestore = getFirestore();\n * const encoded = Schema.encodeSync(FirestoreValue.toCodecFirestore(Post.create))({\n * title: \"Hello\",\n * });\n * await setDoc(\n * doc(firestore, \"posts/hello\"),\n * ClientFirestoreValue.toClient(encoded, firestore) as DocumentData,\n * );\n * ```\n *\n * @see {@link AdminFirestoreValue} for the Admin SDK's mapping\n *\n * @stability unstable\n * @since 0.3.0\n */\nimport type { Result } from \"effect\";\nimport type { FirestoreError } from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport type { FirestoreValue } from \"@visiolab/effect-firebase/firestore/FirestoreValue\";\nimport type { Firestore } from \"firebase/firestore\";\nimport * as internal from \"./internal/firestoreValue.ts\";\n\n/**\n * Turns a Firestore Value into the value the client SDK writes into\n * `firestore`.\n *\n * **When to use**\n *\n * Use to write what a model encodes to through the client SDK itself.\n *\n * **Details**\n *\n * The portable `Timestamp`, `GeoPoint` and bytes become the SDK's `Timestamp`,\n * `GeoPoint` and `Bytes`, and the sentinels its `FieldValue`s. A `DocumentPath`\n * becomes `doc(firestore, path)`, so it points into that database. Map keys are\n * kept as they are, so the dotted field paths of an update stay field paths.\n *\n * It throws for anything that is not a Firestore Value, such as one of the\n * client SDK's own values or a class instance cast past the type. What\n * {@link FirestoreValue.toCodecFirestore} encodes is always a Firestore Value.\n *\n * @see {@link fromClient} for the other direction\n *\n * @stability unstable\n * @category conversions\n * @since 0.3.0\n */\nexport const toClient: (value: FirestoreValue, firestore: Firestore) => unknown = internal.toClient;\n\n/**\n * Turns a value the client SDK read into a Firestore Value.\n *\n * **When to use**\n *\n * Use to decode what the client SDK itself read through a model, with\n * {@link FirestoreValue.toCodecFirestore}.\n *\n * **Details**\n *\n * The SDK's `Timestamp`, `GeoPoint` and `Bytes` become the portable\n * `Timestamp`, `GeoPoint` and `Uint8Array`. A `DocumentReference` becomes the\n * `DocumentPath` it points at, since Firestore stores nothing else of it;\n * {@link FirestoreSchema.DocumentReference} reads that back into the\n * collection it names.\n *\n * Fails with a {@link Firestore.FirestoreError} naming the field for a value\n * that is not a Firestore Value, such as a vector.\n *\n * @see {@link toClient} for the other direction\n *\n * @stability unstable\n * @category conversions\n * @since 0.3.0\n */\nexport const fromClient: (value: unknown) => Result.Result<FirestoreValue, FirestoreError> =\n internal.fromClient;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiEA,MAAa,WAAqEA;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BlF,MAAa,aACXC"}
|