@visiolab/effect-firebase 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 +81 -2
- package/dist/_virtual/_rolldown/runtime.mjs +12 -0
- package/dist/app/App.d.mts +27 -0
- package/dist/app/App.mjs +27 -0
- package/dist/app/index.d.mts +2 -0
- package/dist/app/index.mjs +1 -0
- package/dist/firestore/Collection.d.mts +423 -0
- package/dist/firestore/Collection.mjs +133 -0
- package/dist/firestore/CollectionGroup.d.mts +164 -0
- package/dist/firestore/CollectionGroup.mjs +84 -0
- package/dist/firestore/DocumentPath.d.mts +95 -0
- package/dist/firestore/DocumentPath.mjs +71 -0
- package/dist/firestore/DocumentSnapshot.d.mts +239 -0
- package/dist/firestore/DocumentSnapshot.mjs +134 -0
- package/dist/firestore/FieldValue.d.mts +332 -0
- package/dist/firestore/FieldValue.mjs +256 -0
- package/dist/firestore/Firestore.d.mts +1165 -0
- package/dist/firestore/Firestore.mjs +274 -0
- package/dist/firestore/FirestoreModel.d.mts +1232 -0
- package/dist/firestore/FirestoreModel.mjs +586 -0
- package/dist/firestore/FirestoreSchema.d.mts +567 -0
- package/dist/firestore/FirestoreSchema.mjs +419 -0
- package/dist/firestore/FirestoreValue.d.mts +145 -0
- package/dist/firestore/FirestoreValue.mjs +87 -0
- package/dist/firestore/GeoPoint.d.mts +90 -0
- package/dist/firestore/GeoPoint.mjs +75 -0
- package/dist/firestore/Patch.d.mts +73 -0
- package/dist/firestore/Patch.mjs +57 -0
- package/dist/firestore/QuerySnapshot.d.mts +107 -0
- package/dist/firestore/QuerySnapshot.mjs +43 -0
- package/dist/firestore/Timestamp.d.mts +273 -0
- package/dist/firestore/Timestamp.mjs +255 -0
- package/dist/firestore/index.d.mts +14 -0
- package/dist/firestore/index.mjs +14 -0
- package/dist/firestore/internal/collection.mjs +156 -0
- package/dist/firestore/internal/collectionGroup.mjs +64 -0
- package/dist/firestore/internal/documentPath.d.mts +4 -0
- package/dist/firestore/internal/documentPath.mjs +42 -0
- package/dist/firestore/internal/documentSnapshot.mjs +63 -0
- package/dist/firestore/internal/fieldValue.d.mts +11 -0
- package/dist/firestore/internal/fieldValue.mjs +88 -0
- package/dist/firestore/internal/firestore.mjs +145 -0
- package/dist/firestore/internal/firestoreError.d.mts +29 -0
- package/dist/firestore/internal/firestoreError.mjs +30 -0
- package/dist/firestore/internal/firestoreModel.mjs +719 -0
- package/dist/firestore/internal/firestoreSchema.mjs +123 -0
- package/dist/firestore/internal/firestoreValue.mjs +108 -0
- package/dist/firestore/internal/firestoreValueWalk.d.mts +58 -0
- package/dist/firestore/internal/firestoreValueWalk.mjs +223 -0
- package/dist/firestore/internal/geoPoint.d.mts +4 -0
- package/dist/firestore/internal/geoPoint.mjs +39 -0
- package/dist/firestore/internal/patch.mjs +19 -0
- package/dist/firestore/internal/querySnapshot.mjs +24 -0
- package/dist/firestore/internal/schemaAST.mjs +35 -0
- package/dist/firestore/internal/snapshotExtra.mjs +35 -0
- package/dist/firestore/internal/streamFromListener.mjs +12 -0
- package/dist/firestore/internal/timestamp.d.mts +4 -0
- package/dist/firestore/internal/timestamp.mjs +66 -0
- package/dist/firestore/internal/timestampSchema.mjs +31 -0
- package/dist/firestore/internal/transactionFromCallback.mjs +66 -0
- package/dist/functions/Callable.d.mts +654 -0
- package/dist/functions/Callable.mjs +450 -0
- package/dist/functions/CallableError.d.mts +297 -0
- package/dist/functions/CallableError.mjs +256 -0
- package/dist/functions/CallableMiddleware.d.mts +213 -0
- package/dist/functions/CallableMiddleware.mjs +52 -0
- package/dist/functions/CallableRequest.d.mts +166 -0
- package/dist/functions/CallableRequest.mjs +18 -0
- package/dist/functions/Caller.d.mts +103 -0
- package/dist/functions/Caller.mjs +115 -0
- package/dist/functions/DocumentTrigger.d.mts +795 -0
- package/dist/functions/DocumentTrigger.mjs +566 -0
- package/dist/functions/FirebaseFunction.d.mts +79 -0
- package/dist/functions/FirebaseFunction.mjs +4 -0
- package/dist/functions/FunctionGroup.d.mts +175 -0
- package/dist/functions/FunctionGroup.mjs +64 -0
- package/dist/functions/index.d.mts +9 -0
- package/dist/functions/index.mjs +9 -0
- package/dist/functions/internal/callable.mjs +167 -0
- package/dist/functions/internal/callableMiddleware.d.mts +19 -0
- package/dist/functions/internal/callableMiddleware.mjs +15 -0
- package/dist/functions/internal/callableRequest.mjs +6 -0
- package/dist/functions/internal/documentTrigger.d.mts +10 -0
- package/dist/functions/internal/documentTrigger.mjs +73 -0
- package/dist/functions/internal/firebaseFunction.d.mts +5 -0
- package/dist/functions/internal/firebaseFunction.mjs +24 -0
- package/dist/functions/internal/functionGroup.mjs +36 -0
- package/package.json +72 -3
- package/src/app/App.ts +24 -0
- package/src/app/index.ts +7 -0
- package/src/firestore/Collection.ts +520 -0
- package/src/firestore/CollectionGroup.ts +245 -0
- package/src/firestore/DocumentPath.ts +114 -0
- package/src/firestore/DocumentSnapshot.ts +308 -0
- package/src/firestore/FieldValue.ts +375 -0
- package/src/firestore/Firestore.ts +1432 -0
- package/src/firestore/FirestoreModel.ts +1884 -0
- package/src/firestore/FirestoreSchema.ts +643 -0
- package/src/firestore/FirestoreValue.ts +207 -0
- package/src/firestore/GeoPoint.ts +105 -0
- package/src/firestore/Patch.ts +117 -0
- package/src/firestore/QuerySnapshot.ts +150 -0
- package/src/firestore/Timestamp.ts +302 -0
- package/src/firestore/index.ts +67 -0
- package/src/firestore/internal/collection.ts +246 -0
- package/src/firestore/internal/collectionGroup.ts +81 -0
- package/src/firestore/internal/documentPath.ts +53 -0
- package/src/firestore/internal/documentSnapshot.ts +117 -0
- package/src/firestore/internal/fieldValue.ts +119 -0
- package/src/firestore/internal/firestore.ts +322 -0
- package/src/firestore/internal/firestoreError.ts +36 -0
- package/src/firestore/internal/firestoreModel.ts +1242 -0
- package/src/firestore/internal/firestoreSchema.ts +218 -0
- package/src/firestore/internal/firestoreValue.ts +202 -0
- package/src/firestore/internal/firestoreValueWalk.ts +349 -0
- package/src/firestore/internal/geoPoint.ts +59 -0
- package/src/firestore/internal/patch.ts +21 -0
- package/src/firestore/internal/querySnapshot.ts +39 -0
- package/src/firestore/internal/schemaAST.ts +83 -0
- package/src/firestore/internal/snapshotExtra.ts +47 -0
- package/src/firestore/internal/streamFromListener.ts +27 -0
- package/src/firestore/internal/timestamp.ts +119 -0
- package/src/firestore/internal/timestampSchema.ts +42 -0
- package/src/firestore/internal/transactionFromCallback.ts +106 -0
- package/src/functions/Callable.ts +855 -0
- package/src/functions/CallableError.ts +348 -0
- package/src/functions/CallableMiddleware.ts +279 -0
- package/src/functions/CallableRequest.ts +207 -0
- package/src/functions/Caller.ts +141 -0
- package/src/functions/DocumentTrigger.ts +927 -0
- package/src/functions/FirebaseFunction.ts +96 -0
- package/src/functions/FunctionGroup.ts +225 -0
- package/src/functions/index.ts +62 -0
- package/src/functions/internal/callable.ts +272 -0
- package/src/functions/internal/callableMiddleware.ts +54 -0
- package/src/functions/internal/callableRequest.ts +8 -0
- package/src/functions/internal/documentTrigger.ts +143 -0
- package/src/functions/internal/firebaseFunction.ts +58 -0
- package/src/functions/internal/functionGroup.ts +47 -0
|
@@ -0,0 +1,855 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callables: server functions the client calls by name, declared once and
|
|
3
|
+
* shared by the server and the client.
|
|
4
|
+
*
|
|
5
|
+
* A {@link Callable} is a contract: its name, its Payload and what it succeeds
|
|
6
|
+
* with. The server implements it with {@link toLayer} and serves it with
|
|
7
|
+
* `Functions.make` from `@visiolab/effect-firebase-functions`. The client
|
|
8
|
+
* calls it with `CallableClient` from `@visiolab/effect-firebase-client`. This
|
|
9
|
+
* module imports neither SDK, so the contract can live in code shared with the
|
|
10
|
+
* browser.
|
|
11
|
+
*
|
|
12
|
+
* Values cross the wire as `Schema.toCodecJson` output, on both sides, so a
|
|
13
|
+
* `Date` or a `bigint` arrives as itself.
|
|
14
|
+
*
|
|
15
|
+
* @example Declaring a Callable and implementing it
|
|
16
|
+
* ```ts
|
|
17
|
+
* import { Effect, Schema } from "effect";
|
|
18
|
+
* import { Callable } from "@visiolab/effect-firebase/functions";
|
|
19
|
+
*
|
|
20
|
+
* const Greet = Callable.make("greet", {
|
|
21
|
+
* payload: { name: Schema.String },
|
|
22
|
+
* success: Schema.String,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* const GreetLive = Callable.toLayer(Greet, ({ name }) => Effect.succeed(`Hello, ${name}!`));
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @stability unstable
|
|
29
|
+
* @since 0.3.0
|
|
30
|
+
*/
|
|
31
|
+
import { type Context, type Effect, type Layer, type Pipeable, Schema } from "effect";
|
|
32
|
+
import type * as CallableError from "./CallableError.ts";
|
|
33
|
+
import type * as CallableMiddleware from "./CallableMiddleware.ts";
|
|
34
|
+
import type * as CallableRequest from "./CallableRequest.ts";
|
|
35
|
+
import type * as FirebaseFunction from "./FirebaseFunction.ts";
|
|
36
|
+
import type * as FunctionGroup from "./FunctionGroup.ts";
|
|
37
|
+
import * as internal from "./internal/callable.ts";
|
|
38
|
+
import type * as internalGroup from "./internal/functionGroup.ts";
|
|
39
|
+
import { isFunctionGroup } from "./internal/functionGroup.ts";
|
|
40
|
+
import type * as internalMiddleware from "./internal/callableMiddleware.ts";
|
|
41
|
+
|
|
42
|
+
const TypeId = internal.TypeId;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The group and the Callable that the arguments of an overload taking
|
|
46
|
+
* `(callable, ...)` or `(group, name, ...)` name.
|
|
47
|
+
*/
|
|
48
|
+
const target = (
|
|
49
|
+
args: ReadonlyArray<unknown>,
|
|
50
|
+
): readonly [internalGroup.Fields | undefined, internal.Fields] =>
|
|
51
|
+
isFunctionGroup(args[0])
|
|
52
|
+
? [args[0], args[0].functions[args[1] as string] as internal.Fields]
|
|
53
|
+
: [undefined, args[0] as internal.Fields];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* A Callable: a server function's name, its Payload and what it succeeds with.
|
|
57
|
+
*
|
|
58
|
+
* **Details**
|
|
59
|
+
*
|
|
60
|
+
* A Callable is the kind of {@link FirebaseFunction.FirebaseFunction} the
|
|
61
|
+
* client calls by name, and its `kind` is `"Callable"`.
|
|
62
|
+
*
|
|
63
|
+
* The name is the Callable's identity. A Callable in no group is deployed
|
|
64
|
+
* under its name, so it is a literal type that the server's exports and the
|
|
65
|
+
* client's functions are keyed on.
|
|
66
|
+
*
|
|
67
|
+
* @see {@link DocumentTrigger.DocumentTrigger} for a Function a change to a document runs
|
|
68
|
+
*
|
|
69
|
+
* @stability unstable
|
|
70
|
+
* @category models
|
|
71
|
+
* @since 0.3.0
|
|
72
|
+
*/
|
|
73
|
+
export interface Callable<
|
|
74
|
+
out Name extends string,
|
|
75
|
+
out Payload extends Schema.Top = Schema.Void,
|
|
76
|
+
out Success extends Schema.Top = Schema.Void,
|
|
77
|
+
out Error extends Schema.Top = never,
|
|
78
|
+
out Middleware = never,
|
|
79
|
+
out MiddlewareServices = never,
|
|
80
|
+
>
|
|
81
|
+
extends FirebaseFunction.FirebaseFunction<"Callable", Name>, Pipeable.Pipeable {
|
|
82
|
+
readonly [TypeId]: typeof TypeId;
|
|
83
|
+
/** The Callable's name, which a Callable in no group is deployed under. */
|
|
84
|
+
readonly name: Name;
|
|
85
|
+
/** The schema of what the client sends. */
|
|
86
|
+
readonly payload: Payload;
|
|
87
|
+
/** The schema of what the handler succeeds with. */
|
|
88
|
+
readonly success: Success;
|
|
89
|
+
/** The schemas of the errors the handler can fail with. */
|
|
90
|
+
readonly error: ReadonlySet<Error>;
|
|
91
|
+
/** The Callable's own middleware, in the order it was attached. */
|
|
92
|
+
readonly middlewares: ReadonlySet<CallableMiddleware.AnyKey>;
|
|
93
|
+
/** The middleware attached to the Callable, as a union. Types only. */
|
|
94
|
+
readonly "~Middleware": Middleware;
|
|
95
|
+
/** What the middleware chain still requires. Types only. */
|
|
96
|
+
readonly "~MiddlewareServices": MiddlewareServices;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Attaches a Callable Middleware to the Callable.
|
|
100
|
+
*
|
|
101
|
+
* **Details**
|
|
102
|
+
*
|
|
103
|
+
* Returns a new Callable. The middleware runs around every call, before
|
|
104
|
+
* the Payload is decoded. A middleware attached later wraps the ones
|
|
105
|
+
* attached before it, so it can provide what they require. A Function
|
|
106
|
+
* Group carries no middleware, so a member of a group runs only its own.
|
|
107
|
+
*
|
|
108
|
+
* Its `provides` are removed from what the handler's Layer requires, and
|
|
109
|
+
* its errors join the Callable's error union. Its implementation is
|
|
110
|
+
* required where the chain runs: by `Functions` and by
|
|
111
|
+
* {@link handler}.
|
|
112
|
+
*
|
|
113
|
+
* The Payload is decoded inside the chain, so a middleware that catches
|
|
114
|
+
* every failure also catches a Payload that doesn't decode, and the caller
|
|
115
|
+
* then no longer gets `invalid-argument`.
|
|
116
|
+
*
|
|
117
|
+
* @see {@link CallableMiddleware.Service} for declaring a middleware
|
|
118
|
+
*/
|
|
119
|
+
middleware<I extends CallableMiddleware.AnyId, S>(
|
|
120
|
+
middleware: Context.Key<I, S>,
|
|
121
|
+
): Callable<
|
|
122
|
+
Name,
|
|
123
|
+
Payload,
|
|
124
|
+
Success,
|
|
125
|
+
Error,
|
|
126
|
+
Middleware | I,
|
|
127
|
+
CallableMiddleware.ApplyServices<I, MiddlewareServices>
|
|
128
|
+
>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Any {@link Callable}, whatever its name, schemas and middleware.
|
|
133
|
+
*
|
|
134
|
+
* @stability unstable
|
|
135
|
+
* @category models
|
|
136
|
+
* @since 0.3.0
|
|
137
|
+
*/
|
|
138
|
+
export interface Any extends FirebaseFunction.FirebaseFunction<"Callable", string> {
|
|
139
|
+
readonly [TypeId]: typeof TypeId;
|
|
140
|
+
readonly payload: Schema.Top;
|
|
141
|
+
readonly success: Schema.Top;
|
|
142
|
+
readonly error: ReadonlySet<Schema.Top>;
|
|
143
|
+
readonly middlewares: ReadonlySet<CallableMiddleware.AnyKey>;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The middleware attached to a {@link Callable}, as a union of the middleware
|
|
148
|
+
* service types.
|
|
149
|
+
*
|
|
150
|
+
* @stability unstable
|
|
151
|
+
* @category type-level
|
|
152
|
+
* @since 0.3.0
|
|
153
|
+
*/
|
|
154
|
+
export type Middleware<C> = internalMiddleware.Attached<C>;
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* What the middleware chain of a {@link Callable} still requires: the
|
|
158
|
+
* `requires` of each middleware that no middleware outside it provides.
|
|
159
|
+
*
|
|
160
|
+
* @stability unstable
|
|
161
|
+
* @category type-level
|
|
162
|
+
* @since 0.3.0
|
|
163
|
+
*/
|
|
164
|
+
export type MiddlewareServices<C> = Exclude<
|
|
165
|
+
internalMiddleware.AttachedServices<C>,
|
|
166
|
+
CallableRequest.CallableRequest
|
|
167
|
+
>;
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* What the middleware of a {@link Callable} provides to its handler.
|
|
171
|
+
*
|
|
172
|
+
* @stability unstable
|
|
173
|
+
* @category type-level
|
|
174
|
+
* @since 0.3.0
|
|
175
|
+
*/
|
|
176
|
+
export type MiddlewareProvides<C> = CallableMiddleware.Provides<Middleware<C>>;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The Payload type of a {@link Callable}: what its handler receives.
|
|
180
|
+
*
|
|
181
|
+
* @stability unstable
|
|
182
|
+
* @category type-level
|
|
183
|
+
* @since 0.3.0
|
|
184
|
+
*/
|
|
185
|
+
export type Payload<C extends Any> = C["payload"]["Type"];
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The success type of a {@link Callable}: what its handler succeeds with.
|
|
189
|
+
*
|
|
190
|
+
* @stability unstable
|
|
191
|
+
* @category type-level
|
|
192
|
+
* @since 0.3.0
|
|
193
|
+
*/
|
|
194
|
+
export type Success<C extends Any> = C["success"]["Type"];
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* The union of the error schemas of a {@link Callable}.
|
|
198
|
+
*
|
|
199
|
+
* @stability unstable
|
|
200
|
+
* @category type-level
|
|
201
|
+
* @since 0.3.0
|
|
202
|
+
*/
|
|
203
|
+
export type ErrorSchema<C extends Any> =
|
|
204
|
+
| (C["error"] extends ReadonlySet<infer S extends Schema.Top> ? S : never)
|
|
205
|
+
| CallableMiddleware.ErrorSchema<Middleware<C>>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* The error type of a {@link Callable}: what its handler can fail with, and
|
|
209
|
+
* what its client decodes back. It includes the errors of its middleware.
|
|
210
|
+
*
|
|
211
|
+
* @stability unstable
|
|
212
|
+
* @category type-level
|
|
213
|
+
* @since 0.3.0
|
|
214
|
+
*/
|
|
215
|
+
export type Error<C extends Any> = ErrorSchema<C>["Type"];
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Options for {@link make}.
|
|
219
|
+
*
|
|
220
|
+
* @stability unstable
|
|
221
|
+
* @category models
|
|
222
|
+
* @since 0.3.0
|
|
223
|
+
*/
|
|
224
|
+
export interface MakeOptions<
|
|
225
|
+
Payload extends Schema.Top | Schema.Struct.Fields,
|
|
226
|
+
Success extends Schema.Top,
|
|
227
|
+
Error extends Schema.Top | ReadonlyArray<Schema.Top> = never,
|
|
228
|
+
> {
|
|
229
|
+
/**
|
|
230
|
+
* What the client sends: a schema, or the fields of a struct. Leave it out
|
|
231
|
+
* for a Callable that takes nothing.
|
|
232
|
+
*/
|
|
233
|
+
readonly payload?: Payload | undefined;
|
|
234
|
+
/**
|
|
235
|
+
* What the handler succeeds with. Leave it out for a Callable that answers
|
|
236
|
+
* with nothing.
|
|
237
|
+
*/
|
|
238
|
+
readonly success?: Success | undefined;
|
|
239
|
+
/**
|
|
240
|
+
* The errors the handler can fail with: one schema or an array. Leave it
|
|
241
|
+
* out for a Callable that never fails with an error of its own.
|
|
242
|
+
*/
|
|
243
|
+
readonly error?: Error | undefined;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Declares a Callable.
|
|
248
|
+
*
|
|
249
|
+
* **When to use**
|
|
250
|
+
*
|
|
251
|
+
* Use to declare a server function once, in code that the server and the
|
|
252
|
+
* client share.
|
|
253
|
+
*
|
|
254
|
+
* **Details**
|
|
255
|
+
*
|
|
256
|
+
* `payload` takes a schema or the fields of a struct, and defaults to
|
|
257
|
+
* `Schema.Void`. `success` defaults to `Schema.Void`. `error` takes one
|
|
258
|
+
* schema or an array; without it the Callable never fails with an error of
|
|
259
|
+
* its own, and its client fails only with `CallableError`.
|
|
260
|
+
*
|
|
261
|
+
* All of them are sent through `Schema.toCodecJson`, so they must round-trip
|
|
262
|
+
* through JSON. `Schema.Unknown` is the safe choice for "any JSON".
|
|
263
|
+
* `Schema.Any` skips every check and is an escape hatch. A schema that can't
|
|
264
|
+
* round-trip fails at runtime, not at compile time.
|
|
265
|
+
*
|
|
266
|
+
* An error is sent with the Firebase error code of its schema, `internal`
|
|
267
|
+
* unless {@link errorCode} or its `callableErrorCode` annotation sets one.
|
|
268
|
+
*
|
|
269
|
+
* @example Declaring a Callable with a Payload and a success value
|
|
270
|
+
* ```ts
|
|
271
|
+
* import { Schema } from "effect";
|
|
272
|
+
* import { Callable } from "@visiolab/effect-firebase/functions";
|
|
273
|
+
*
|
|
274
|
+
* const Greet = Callable.make("greet", {
|
|
275
|
+
* payload: { name: Schema.String, at: Schema.Date },
|
|
276
|
+
* success: Schema.Struct({ message: Schema.String }),
|
|
277
|
+
* });
|
|
278
|
+
* ```
|
|
279
|
+
*
|
|
280
|
+
* @example Declaring the errors a Callable can fail with
|
|
281
|
+
* ```ts
|
|
282
|
+
* import { Schema } from "effect";
|
|
283
|
+
* import { Callable, CallableError } from "@visiolab/effect-firebase/functions";
|
|
284
|
+
*
|
|
285
|
+
* class NameTaken extends Schema.TaggedError<NameTaken>()(
|
|
286
|
+
* "NameTaken",
|
|
287
|
+
* { name: Schema.String },
|
|
288
|
+
* { callableErrorCode: "already-exists" },
|
|
289
|
+
* ) {}
|
|
290
|
+
*
|
|
291
|
+
* const Register = Callable.make("register", {
|
|
292
|
+
* payload: { name: Schema.String },
|
|
293
|
+
* error: [NameTaken, CallableError.PermissionDenied],
|
|
294
|
+
* });
|
|
295
|
+
* ```
|
|
296
|
+
*
|
|
297
|
+
* @see {@link toLayer} for implementing the Callable on the server
|
|
298
|
+
* @see {@link errorCode} for giving an error schema its code
|
|
299
|
+
* @see {@link FunctionGroup.make} for collecting Functions under one prefix
|
|
300
|
+
* @see {@link DocumentTrigger.created} for declaring a Function a change to a document runs
|
|
301
|
+
*
|
|
302
|
+
* @stability unstable
|
|
303
|
+
* @category constructors
|
|
304
|
+
* @since 0.3.0
|
|
305
|
+
*/
|
|
306
|
+
export const make = <
|
|
307
|
+
const Name extends string,
|
|
308
|
+
Payload extends Schema.Top | Schema.Struct.Fields = Schema.Void,
|
|
309
|
+
Success extends Schema.Top = Schema.Void,
|
|
310
|
+
const Error extends Schema.Top | ReadonlyArray<Schema.Top> = never,
|
|
311
|
+
>(
|
|
312
|
+
name: Name,
|
|
313
|
+
options?: MakeOptions<Payload, Success, Error>,
|
|
314
|
+
): Callable<
|
|
315
|
+
Name,
|
|
316
|
+
Payload extends Schema.Top
|
|
317
|
+
? Payload
|
|
318
|
+
: Payload extends Schema.Struct.Fields
|
|
319
|
+
? Schema.Struct<Payload>
|
|
320
|
+
: never,
|
|
321
|
+
Success,
|
|
322
|
+
Error extends ReadonlyArray<Schema.Top> ? Error[number] : Error
|
|
323
|
+
> => {
|
|
324
|
+
const payload = options?.payload;
|
|
325
|
+
const error: Schema.Top | ReadonlyArray<Schema.Top> | undefined = options?.error;
|
|
326
|
+
return internal.make({
|
|
327
|
+
kind: internal.kind,
|
|
328
|
+
error: new Set(error === undefined ? [] : Schema.isSchema(error) ? [error] : error),
|
|
329
|
+
middlewares: new Set(),
|
|
330
|
+
name,
|
|
331
|
+
payload:
|
|
332
|
+
payload === undefined
|
|
333
|
+
? Schema.Void
|
|
334
|
+
: Schema.isSchema(payload)
|
|
335
|
+
? payload
|
|
336
|
+
: Schema.Struct(payload as Schema.Struct.Fields),
|
|
337
|
+
success: options?.success ?? Schema.Void,
|
|
338
|
+
}) as never;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Marks the {@link Handler} of a Callable in no group. The same marker as
|
|
343
|
+
* {@link FirebaseFunction.NoGroup}, which every kind of Function shares.
|
|
344
|
+
*
|
|
345
|
+
* @stability unstable
|
|
346
|
+
* @category models
|
|
347
|
+
* @since 0.3.0
|
|
348
|
+
*/
|
|
349
|
+
export type NoGroup = FirebaseFunction.NoGroup;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* The service a {@link toLayer} Layer provides: the Callable Handler of the
|
|
353
|
+
* Callable `Name`, as served in `Group`.
|
|
354
|
+
*
|
|
355
|
+
* **Details**
|
|
356
|
+
*
|
|
357
|
+
* A handler is keyed by its group and its name, so the handler of `greet` in
|
|
358
|
+
* no group is `Handler<NoGroup, "greet">`. A Layer that serves a Callable must
|
|
359
|
+
* provide the handler under exactly that key. It is the
|
|
360
|
+
* {@link FirebaseFunction.Handler} every kind of Function is served by.
|
|
361
|
+
*
|
|
362
|
+
* @stability unstable
|
|
363
|
+
* @category models
|
|
364
|
+
* @since 0.3.0
|
|
365
|
+
*/
|
|
366
|
+
export type Handler<Group, Name extends string> = FirebaseFunction.Handler<Group, Name>;
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* The {@link Handler} of a Callable in no group.
|
|
370
|
+
*
|
|
371
|
+
* @stability unstable
|
|
372
|
+
* @category type-level
|
|
373
|
+
* @since 0.3.0
|
|
374
|
+
*/
|
|
375
|
+
export type HandlerFor<C extends Any> = FirebaseFunction.HandlerFor<C>;
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* What implements a Callable: a function from the decoded Payload to an
|
|
379
|
+
* Effect of the success value, failing only with the Callable's declared
|
|
380
|
+
* errors.
|
|
381
|
+
*
|
|
382
|
+
* @stability unstable
|
|
383
|
+
* @category models
|
|
384
|
+
* @since 0.3.0
|
|
385
|
+
*/
|
|
386
|
+
export type HandlerFunction<C extends Any, R> = (
|
|
387
|
+
payload: Payload<C>,
|
|
388
|
+
) => Effect.Effect<Success<C>, Error<C>, R>;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* What a handler that requires `R` leaves for its {@link toLayer} Layer to
|
|
392
|
+
* require: `R` without what the Callable's middleware provides and without
|
|
393
|
+
* the {@link CallableRequest.CallableRequest}, which every call provides.
|
|
394
|
+
*
|
|
395
|
+
* @stability unstable
|
|
396
|
+
* @category type-level
|
|
397
|
+
* @since 0.3.0
|
|
398
|
+
*/
|
|
399
|
+
export type HandlerServices<C, R> = Exclude<
|
|
400
|
+
R,
|
|
401
|
+
MiddlewareProvides<C> | CallableRequest.CallableRequest
|
|
402
|
+
>;
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* What {@link handler} yields: the Callable's handler behind its middleware
|
|
406
|
+
* chain, run in process.
|
|
407
|
+
*
|
|
408
|
+
* @stability unstable
|
|
409
|
+
* @category models
|
|
410
|
+
* @since 0.3.0
|
|
411
|
+
*/
|
|
412
|
+
export type HandlerCall<C extends Any> = (
|
|
413
|
+
payload: Payload<C>,
|
|
414
|
+
request: CallableRequest.Input,
|
|
415
|
+
) => Effect.Effect<Success<C>, Error<C>>;
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* What running the middleware chain of a {@link Callable} requires: its
|
|
419
|
+
* handler, each middleware implementation, and what the chain still
|
|
420
|
+
* requires.
|
|
421
|
+
*
|
|
422
|
+
* @stability unstable
|
|
423
|
+
* @category type-level
|
|
424
|
+
* @since 0.3.0
|
|
425
|
+
*/
|
|
426
|
+
export type ChainServices<C extends Any, H> = H | Middleware<C> | MiddlewareServices<C>;
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Implements a Callable as a Layer.
|
|
430
|
+
*
|
|
431
|
+
* **When to use**
|
|
432
|
+
*
|
|
433
|
+
* Use to write the server side of a Callable. The Layer is what
|
|
434
|
+
* `Functions.make` or `Functions.group` from
|
|
435
|
+
* `@visiolab/effect-firebase-functions` serves.
|
|
436
|
+
*
|
|
437
|
+
* **Details**
|
|
438
|
+
*
|
|
439
|
+
* Pass the Callable for a Callable in no group. Pass its group and its name
|
|
440
|
+
* for a Callable member of a {@link FunctionGroup.FunctionGroup}: the Layer then
|
|
441
|
+
* provides `Handler<"users", "create">`, which serves the member in that group
|
|
442
|
+
* only. A Layer from the Callable on its own doesn't serve it in a group, and
|
|
443
|
+
* a Callable in two groups needs a Layer for each.
|
|
444
|
+
*
|
|
445
|
+
* Takes the handler itself, or an Effect that builds it. The Effect runs once,
|
|
446
|
+
* when the Layer is built, so do per-instance setup there.
|
|
447
|
+
*
|
|
448
|
+
* The Layer requires what the handler needs on each call and what building it
|
|
449
|
+
* needs. Both are provided where the Layer is built: services built with the
|
|
450
|
+
* Layer are shared by every call. What the Callable's middleware provides,
|
|
451
|
+
* such as the `Caller`, and the {@link CallableRequest.CallableRequest} are
|
|
452
|
+
* provided per call instead, so the Layer doesn't require them. Nor does it
|
|
453
|
+
* require the middleware's implementations: those are required where the
|
|
454
|
+
* chain runs.
|
|
455
|
+
*
|
|
456
|
+
* @example Implementing a Callable
|
|
457
|
+
* ```ts
|
|
458
|
+
* import { Effect, Schema } from "effect";
|
|
459
|
+
* import { Callable } from "@visiolab/effect-firebase/functions";
|
|
460
|
+
*
|
|
461
|
+
* const Greet = Callable.make("greet", {
|
|
462
|
+
* payload: { name: Schema.String },
|
|
463
|
+
* success: Schema.String,
|
|
464
|
+
* });
|
|
465
|
+
*
|
|
466
|
+
* const GreetLive = Callable.toLayer(Greet, ({ name }) => Effect.succeed(`Hello, ${name}!`));
|
|
467
|
+
* ```
|
|
468
|
+
*
|
|
469
|
+
* @example Building the handler once per instance
|
|
470
|
+
* ```ts
|
|
471
|
+
* import { Effect, Schema } from "effect";
|
|
472
|
+
* import { Callable } from "@visiolab/effect-firebase/functions";
|
|
473
|
+
*
|
|
474
|
+
* const Greet = Callable.make("greet", {
|
|
475
|
+
* payload: { name: Schema.String },
|
|
476
|
+
* success: Schema.String,
|
|
477
|
+
* });
|
|
478
|
+
*
|
|
479
|
+
* const GreetLive = Callable.toLayer(
|
|
480
|
+
* Greet,
|
|
481
|
+
* Effect.gen(function* () {
|
|
482
|
+
* const greeting = yield* Effect.succeed("Hello");
|
|
483
|
+
* return ({ name }) => Effect.succeed(`${greeting}, ${name}!`);
|
|
484
|
+
* }),
|
|
485
|
+
* );
|
|
486
|
+
* ```
|
|
487
|
+
*
|
|
488
|
+
* @example Implementing a member of a group
|
|
489
|
+
* ```ts
|
|
490
|
+
* import { Effect, Schema } from "effect";
|
|
491
|
+
* import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
|
|
492
|
+
*
|
|
493
|
+
* const CreateUser = Callable.make("create", {
|
|
494
|
+
* payload: { name: Schema.String },
|
|
495
|
+
* success: Schema.String,
|
|
496
|
+
* });
|
|
497
|
+
*
|
|
498
|
+
* class Users extends FunctionGroup.make("users").add(CreateUser) {}
|
|
499
|
+
*
|
|
500
|
+
* const CreateUserLive = Callable.toLayer(Users, "create", ({ name }) => Effect.succeed(name));
|
|
501
|
+
* ```
|
|
502
|
+
*
|
|
503
|
+
* @see {@link make} for declaring the Callable
|
|
504
|
+
* @see {@link serve} for running a call against the handler
|
|
505
|
+
* @see {@link DocumentTrigger.toLayer} for implementing a Document Trigger
|
|
506
|
+
* @see {@link FunctionGroup.make} for collecting Functions under one prefix
|
|
507
|
+
*
|
|
508
|
+
* @stability unstable
|
|
509
|
+
* @category constructors
|
|
510
|
+
* @since 0.3.0
|
|
511
|
+
*/
|
|
512
|
+
export const toLayer: {
|
|
513
|
+
<C extends Any, R = never, EB = never, RB = never>(
|
|
514
|
+
callable: C,
|
|
515
|
+
handler: HandlerFunction<C, R> | Effect.Effect<HandlerFunction<C, R>, EB, RB>,
|
|
516
|
+
): Layer.Layer<HandlerFor<C>, EB, HandlerServices<C, R> | RB>;
|
|
517
|
+
<
|
|
518
|
+
G extends FunctionGroup.Any,
|
|
519
|
+
const Name extends FunctionGroup.Names<G, Any>,
|
|
520
|
+
R = never,
|
|
521
|
+
EB = never,
|
|
522
|
+
RB = never,
|
|
523
|
+
>(
|
|
524
|
+
group: G,
|
|
525
|
+
name: Name,
|
|
526
|
+
handler:
|
|
527
|
+
| HandlerFunction<FunctionGroup.Member<G, Name, Any>, R>
|
|
528
|
+
| Effect.Effect<HandlerFunction<FunctionGroup.Member<G, Name, Any>, R>, EB, RB>,
|
|
529
|
+
): Layer.Layer<
|
|
530
|
+
Handler<G["identifier"], Name>,
|
|
531
|
+
EB,
|
|
532
|
+
HandlerServices<FunctionGroup.Member<G, Name, Any>, R> | RB
|
|
533
|
+
>;
|
|
534
|
+
} = ((...args: ReadonlyArray<unknown>) => {
|
|
535
|
+
const [group, callable] = target(args);
|
|
536
|
+
// The handler's requirements are checked by the signatures, and provided
|
|
537
|
+
// where the Layer is built.
|
|
538
|
+
return internal.toLayer(
|
|
539
|
+
group?.identifier,
|
|
540
|
+
callable.name,
|
|
541
|
+
args[group === undefined ? 1 : 2] as internal.HandlerInput,
|
|
542
|
+
);
|
|
543
|
+
}) as never;
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Runs one call to a Callable, as it arrives on the wire. A building block for
|
|
547
|
+
* the functions package. Most apps don't need it.
|
|
548
|
+
*
|
|
549
|
+
* **When to use**
|
|
550
|
+
*
|
|
551
|
+
* Use to serve Callables from a transport of your own. `Functions`
|
|
552
|
+
* from `@visiolab/effect-firebase-functions` serves them through
|
|
553
|
+
* `firebase-functions`.
|
|
554
|
+
*
|
|
555
|
+
* **Details**
|
|
556
|
+
*
|
|
557
|
+
* Pass the Callable for a Callable in no group, or its group and its name for
|
|
558
|
+
* a Callable member of a {@link FunctionGroup.FunctionGroup}.
|
|
559
|
+
*
|
|
560
|
+
* Returns a function of the call's {@link CallableRequest.CallableRequest}. It
|
|
561
|
+
* runs the middleware chain, the same one {@link handler} runs. Inside it, it
|
|
562
|
+
* decodes the raw `data` with the Payload's `Schema.toCodecJson` and runs the
|
|
563
|
+
* handler. It then encodes the success value with the success schema's
|
|
564
|
+
* `Schema.toCodecJson`, so its result is plain JSON. The request is provided
|
|
565
|
+
* to the chain. Give it a `rawRequest` built from your transport's HTTP
|
|
566
|
+
* request, with `HttpServerRequest.fromWeb` from `effect/http/HttpServerRequest`.
|
|
567
|
+
*
|
|
568
|
+
* Requires the handler, every middleware implementation, and what the chain
|
|
569
|
+
* still requires. They are read once, so a call needs nothing else.
|
|
570
|
+
*
|
|
571
|
+
* Every failure is a `CallableError` whose `ResponseError` reason is what to
|
|
572
|
+
* answer with:
|
|
573
|
+
*
|
|
574
|
+
* - A declared error, or an error of a middleware, is sent with its schema's
|
|
575
|
+
* code, the error's `message` if it is a non-empty string, else its `_tag`,
|
|
576
|
+
* and the error encoded with its schema's `Schema.toCodecJson` as
|
|
577
|
+
* `details`.
|
|
578
|
+
* - A raw Payload that doesn't decode is sent as `invalid-argument` with a
|
|
579
|
+
* generic message and no details. The `Schema.SchemaError` is logged at
|
|
580
|
+
* Debug.
|
|
581
|
+
*
|
|
582
|
+
* A defect, or a success or error value that doesn't encode, is a defect.
|
|
583
|
+
* Answer it with a bare `internal`, so nothing of it reaches the caller.
|
|
584
|
+
*
|
|
585
|
+
* The `CallableError`'s `callable` is the deployed name: the Callable's name,
|
|
586
|
+
* or `<group>-<name>` for a member of a group.
|
|
587
|
+
*
|
|
588
|
+
* @see {@link toLayer} for providing the handler
|
|
589
|
+
* @see {@link handler} for running the handler in process, with typed values
|
|
590
|
+
* @see {@link Functions.make} for serving through `firebase-functions`
|
|
591
|
+
* @see {@link deployment} for the name and span attributes a transport uses
|
|
592
|
+
* @see {@link DocumentTrigger.serve} for running an event of a Document Trigger
|
|
593
|
+
*
|
|
594
|
+
* @stability unstable
|
|
595
|
+
* @category serving
|
|
596
|
+
* @since 0.3.0
|
|
597
|
+
*/
|
|
598
|
+
export const serve: {
|
|
599
|
+
<C extends Any>(
|
|
600
|
+
callable: C,
|
|
601
|
+
): Effect.Effect<
|
|
602
|
+
(
|
|
603
|
+
request: CallableRequest.CallableRequest,
|
|
604
|
+
) => Effect.Effect<unknown, CallableError.CallableError>,
|
|
605
|
+
never,
|
|
606
|
+
ChainServices<C, HandlerFor<C>>
|
|
607
|
+
>;
|
|
608
|
+
<G extends FunctionGroup.Any, const Name extends FunctionGroup.Names<G, Any>>(
|
|
609
|
+
group: G,
|
|
610
|
+
name: Name,
|
|
611
|
+
): Effect.Effect<
|
|
612
|
+
(
|
|
613
|
+
request: CallableRequest.CallableRequest,
|
|
614
|
+
) => Effect.Effect<unknown, CallableError.CallableError>,
|
|
615
|
+
never,
|
|
616
|
+
ChainServices<FunctionGroup.Member<G, Name, Any>, Handler<G["identifier"], Name>>
|
|
617
|
+
>;
|
|
618
|
+
} = ((...args: ReadonlyArray<unknown>) => internal.serve(...target(args))) as never;
|
|
619
|
+
|
|
620
|
+
/**
|
|
621
|
+
* Runs a Callable's handler in process, behind its middleware chain.
|
|
622
|
+
*
|
|
623
|
+
* **When to use**
|
|
624
|
+
*
|
|
625
|
+
* Use to test a handler and its middleware without the emulator and without
|
|
626
|
+
* `firebase-functions`. Provide the same Layers you serve it with, or stub a
|
|
627
|
+
* middleware with a Layer of your own.
|
|
628
|
+
*
|
|
629
|
+
* **Details**
|
|
630
|
+
*
|
|
631
|
+
* Pass the Callable for a Callable in no group, or its group and its name for
|
|
632
|
+
* a Callable member of a {@link FunctionGroup.FunctionGroup}.
|
|
633
|
+
*
|
|
634
|
+
* Requires the handler, every middleware implementation, and what the chain
|
|
635
|
+
* still requires. A middleware whose
|
|
636
|
+
* `requires` no middleware outside it provides leaves that requirement here,
|
|
637
|
+
* so a chain in the wrong order is a type error where the Layers are
|
|
638
|
+
* provided.
|
|
639
|
+
*
|
|
640
|
+
* Yields a function of the Payload and a {@link CallableRequest.Input}: `{}`
|
|
641
|
+
* for a signed-out call, `{ auth: { uid, token } }` for a signed-in one. It
|
|
642
|
+
* encodes the Payload with `Schema.toCodecJson` as the request's raw `data`,
|
|
643
|
+
* so middleware sees what it would see on the wire. The request's
|
|
644
|
+
* `rawRequest` is the input's, or else a JSON `POST` of the encoded Payload to
|
|
645
|
+
* `http://localhost/<deployed name>` (see
|
|
646
|
+
* {@link CallableRequest.Input.rawRequest}). It runs the chain that
|
|
647
|
+
* `Functions` runs, and fails with the Callable's declared errors and
|
|
648
|
+
* those of its middleware. The success value is the handler's, not encoded.
|
|
649
|
+
*
|
|
650
|
+
* @example Running a handler behind Authenticated
|
|
651
|
+
* ```ts
|
|
652
|
+
* import { Effect, Layer, Schema } from "effect";
|
|
653
|
+
* import { Callable, Caller } from "@visiolab/effect-firebase/functions";
|
|
654
|
+
*
|
|
655
|
+
* const WhoAmI = Callable.make("whoAmI", { success: Schema.String }).middleware(
|
|
656
|
+
* Caller.Authenticated,
|
|
657
|
+
* );
|
|
658
|
+
*
|
|
659
|
+
* const WhoAmILive = Callable.toLayer(WhoAmI, () =>
|
|
660
|
+
* Effect.map(Effect.service(Caller.Caller), ({ uid }) => uid),
|
|
661
|
+
* );
|
|
662
|
+
*
|
|
663
|
+
* const program = Effect.gen(function* () {
|
|
664
|
+
* const whoAmI = yield* Callable.handler(WhoAmI);
|
|
665
|
+
* // "ada"
|
|
666
|
+
* return yield* whoAmI(undefined, { auth: { uid: "ada", token: {} } });
|
|
667
|
+
* }).pipe(Effect.provide(Layer.merge(WhoAmILive, Caller.Authenticated.layer)));
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
670
|
+
* @see {@link serve} for running a call as it arrives on the wire
|
|
671
|
+
* @see {@link toLayer} for providing the handler
|
|
672
|
+
* @see {@link Functions.make} for serving the same chain through `firebase-functions`
|
|
673
|
+
*
|
|
674
|
+
* @stability unstable
|
|
675
|
+
* @category serving
|
|
676
|
+
* @since 0.3.0
|
|
677
|
+
*/
|
|
678
|
+
export const handler: {
|
|
679
|
+
<C extends Any>(
|
|
680
|
+
callable: C,
|
|
681
|
+
): Effect.Effect<HandlerCall<C>, never, ChainServices<C, HandlerFor<C>>>;
|
|
682
|
+
<G extends FunctionGroup.Any, const Name extends FunctionGroup.Names<G, Any>>(
|
|
683
|
+
group: G,
|
|
684
|
+
name: Name,
|
|
685
|
+
): Effect.Effect<
|
|
686
|
+
HandlerCall<FunctionGroup.Member<G, Name, Any>>,
|
|
687
|
+
never,
|
|
688
|
+
ChainServices<FunctionGroup.Member<G, Name, Any>, Handler<G["identifier"], Name>>
|
|
689
|
+
>;
|
|
690
|
+
} = ((...args: ReadonlyArray<unknown>) => internal.handler(...target(args))) as never;
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Sets the Firebase error code a Callable answers with when it fails with
|
|
694
|
+
* errors of this schema.
|
|
695
|
+
*
|
|
696
|
+
* **When to use**
|
|
697
|
+
*
|
|
698
|
+
* Use to give a code to an error schema you don't own. For an error class of
|
|
699
|
+
* your own, set `callableErrorCode` in its annotations instead, so every
|
|
700
|
+
* Callable that lists it uses the same code.
|
|
701
|
+
*
|
|
702
|
+
* **Details**
|
|
703
|
+
*
|
|
704
|
+
* An error schema without a code is sent as `internal`. The client reads the
|
|
705
|
+
* code to find the declared errors to decode the answer against, so the code
|
|
706
|
+
* is part of the contract.
|
|
707
|
+
*
|
|
708
|
+
* @example Giving codes to error schemas
|
|
709
|
+
* ```ts
|
|
710
|
+
* import { Schema } from "effect";
|
|
711
|
+
* import { Callable } from "@visiolab/effect-firebase/functions";
|
|
712
|
+
*
|
|
713
|
+
* class NameTaken extends Schema.TaggedError<NameTaken>()(
|
|
714
|
+
* "NameTaken",
|
|
715
|
+
* { name: Schema.String },
|
|
716
|
+
* { callableErrorCode: "already-exists" },
|
|
717
|
+
* ) {}
|
|
718
|
+
*
|
|
719
|
+
* class Banned extends Schema.TaggedError<Banned>()("Banned", {}) {}
|
|
720
|
+
*
|
|
721
|
+
* const Register = Callable.make("register", {
|
|
722
|
+
* payload: { name: Schema.String },
|
|
723
|
+
* error: [NameTaken, Banned.pipe(Callable.errorCode("permission-denied"))],
|
|
724
|
+
* });
|
|
725
|
+
* ```
|
|
726
|
+
*
|
|
727
|
+
* @see {@link getErrorCode} for reading the code back
|
|
728
|
+
* @see {@link make} for declaring the errors a Callable fails with
|
|
729
|
+
*
|
|
730
|
+
* @stability unstable
|
|
731
|
+
* @category errors
|
|
732
|
+
* @since 0.3.0
|
|
733
|
+
*/
|
|
734
|
+
export const errorCode =
|
|
735
|
+
(code: CallableError.ErrorCode) =>
|
|
736
|
+
<S extends Schema.Top>(self: S): S["Rebuild"] =>
|
|
737
|
+
self.annotate({ callableErrorCode: code });
|
|
738
|
+
|
|
739
|
+
/**
|
|
740
|
+
* Reads the Firebase error code of an error schema: what {@link errorCode} or
|
|
741
|
+
* its `callableErrorCode` annotation set, else `internal`. A building block
|
|
742
|
+
* for the functions and client packages. Most apps don't need it.
|
|
743
|
+
*
|
|
744
|
+
* **When to use**
|
|
745
|
+
*
|
|
746
|
+
* Use when serving or calling Callables from a transport of your own.
|
|
747
|
+
*
|
|
748
|
+
* @see {@link errorCode} for setting the code
|
|
749
|
+
* @see {@link errorSchemas} for the schemas a call can be answered with
|
|
750
|
+
*
|
|
751
|
+
* @stability unstable
|
|
752
|
+
* @category errors
|
|
753
|
+
* @since 0.3.0
|
|
754
|
+
*/
|
|
755
|
+
export const getErrorCode: (schema: Schema.Top) => CallableError.ErrorCode = internal.getErrorCode;
|
|
756
|
+
|
|
757
|
+
/**
|
|
758
|
+
* The schemas of every error a call can be answered with: the Callable's
|
|
759
|
+
* declared errors, then those of its middleware. A building block for the
|
|
760
|
+
* client package. Most apps don't need it.
|
|
761
|
+
*
|
|
762
|
+
* **When to use**
|
|
763
|
+
*
|
|
764
|
+
* Use when calling Callables from a transport of your own, to decode an
|
|
765
|
+
* error's `details` against the schemas that carry its code.
|
|
766
|
+
*
|
|
767
|
+
* **Details**
|
|
768
|
+
*
|
|
769
|
+
* Pass the Callable for a Callable in no group, or its group and its name for
|
|
770
|
+
* a Callable member of a {@link FunctionGroup.FunctionGroup}.
|
|
771
|
+
*
|
|
772
|
+
* @see {@link getErrorCode} for the code of each schema
|
|
773
|
+
* @see {@link deployment} for the name a transport calls
|
|
774
|
+
*
|
|
775
|
+
* @stability unstable
|
|
776
|
+
* @category errors
|
|
777
|
+
* @since 0.3.0
|
|
778
|
+
*/
|
|
779
|
+
export const errorSchemas: {
|
|
780
|
+
(callable: Any): ReadonlyArray<Schema.Top>;
|
|
781
|
+
<G extends FunctionGroup.Any>(
|
|
782
|
+
group: G,
|
|
783
|
+
name: FunctionGroup.Names<G, Any>,
|
|
784
|
+
): ReadonlyArray<Schema.Top>;
|
|
785
|
+
} = ((...args: ReadonlyArray<unknown>) => internal.errorSchemas(target(args)[1])) as never;
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Where a Callable is served: the name it is deployed under and the
|
|
789
|
+
* attributes of each call's spans.
|
|
790
|
+
*
|
|
791
|
+
* @stability unstable
|
|
792
|
+
* @category models
|
|
793
|
+
* @since 0.3.0
|
|
794
|
+
*/
|
|
795
|
+
export interface Deployment {
|
|
796
|
+
/**
|
|
797
|
+
* The name the Callable Function is exported under and the client calls:
|
|
798
|
+
* the Callable's name, or `<group>-<name>` for a member of a group.
|
|
799
|
+
*/
|
|
800
|
+
readonly name: string;
|
|
801
|
+
/**
|
|
802
|
+
* The attributes of the server's and the client's span of a call:
|
|
803
|
+
* `rpc.system: "firebase_callable"`, `rpc.method` (the Callable's name),
|
|
804
|
+
* `rpc.service` (the group, for a member) and `faas.name` (the deployed
|
|
805
|
+
* name).
|
|
806
|
+
*/
|
|
807
|
+
readonly attributes: Readonly<Record<string, string>>;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/**
|
|
811
|
+
* Returns the {@link Deployment} of a Callable: its deployed name and its span
|
|
812
|
+
* attributes. A building block of the functions and client packages, which
|
|
813
|
+
* agree on both through it. Most apps don't need it.
|
|
814
|
+
*
|
|
815
|
+
* **When to use**
|
|
816
|
+
*
|
|
817
|
+
* Use when serving or calling Callables from a transport of your own.
|
|
818
|
+
* `Functions` and `CallableClient` already use it.
|
|
819
|
+
*
|
|
820
|
+
* **Details**
|
|
821
|
+
*
|
|
822
|
+
* Pass the Callable for a Callable in no group, or its group and its name for
|
|
823
|
+
* a Callable member of a {@link FunctionGroup.FunctionGroup}.
|
|
824
|
+
*
|
|
825
|
+
* @example Reading the deployed name of a member
|
|
826
|
+
* ```ts
|
|
827
|
+
* import { Schema } from "effect";
|
|
828
|
+
* import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
|
|
829
|
+
*
|
|
830
|
+
* const CreateUser = Callable.make("create", { payload: { name: Schema.String } });
|
|
831
|
+
*
|
|
832
|
+
* class Users extends FunctionGroup.make("users").add(CreateUser) {}
|
|
833
|
+
*
|
|
834
|
+
* // "users-create"
|
|
835
|
+
* const { name } = Callable.deployment(Users, "create");
|
|
836
|
+
* ```
|
|
837
|
+
*
|
|
838
|
+
* @see {@link serve} for running a call on the server
|
|
839
|
+
* @see {@link errorSchemas} for the errors a call can be answered with
|
|
840
|
+
* @see {@link DocumentTrigger.deployment} for where a Document Trigger is deployed
|
|
841
|
+
*
|
|
842
|
+
* @stability unstable
|
|
843
|
+
* @category serving
|
|
844
|
+
* @since 0.3.0
|
|
845
|
+
*/
|
|
846
|
+
export const deployment: {
|
|
847
|
+
(callable: Any): Deployment;
|
|
848
|
+
<G extends FunctionGroup.Any>(group: G, name: FunctionGroup.Names<G, Any>): Deployment;
|
|
849
|
+
} = ((...args: ReadonlyArray<unknown>) => {
|
|
850
|
+
const [group, callable] = target(args);
|
|
851
|
+
return {
|
|
852
|
+
name: internal.deployedName(group, callable),
|
|
853
|
+
attributes: internal.spanAttributes(group, callable),
|
|
854
|
+
};
|
|
855
|
+
}) as never;
|