@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,213 @@
|
|
|
1
|
+
import { CallableRequest } from "./CallableRequest.mjs";
|
|
2
|
+
import { Any } from "./Callable.mjs";
|
|
3
|
+
import { Context, Effect, Schema } from "effect";
|
|
4
|
+
import { unhandled } from "effect/Types";
|
|
5
|
+
declare namespace CallableMiddleware_d_exports {
|
|
6
|
+
export { AnyId, AnyKey, ApplyServices, CallableMiddleware, Error, ErrorConstraint, ErrorSchema, Options, Provides, Requires, Service, ServiceClass };
|
|
7
|
+
}
|
|
8
|
+
declare const TypeId = "~@visiolab/effect-firebase/functions/CallableMiddleware";
|
|
9
|
+
/**
|
|
10
|
+
* The errors a middleware can fail with: one schema or an array.
|
|
11
|
+
*
|
|
12
|
+
* @stability unstable
|
|
13
|
+
* @category models
|
|
14
|
+
* @since 0.3.0
|
|
15
|
+
*/
|
|
16
|
+
export type ErrorConstraint = Schema.Top | ReadonlyArray<Schema.Top>;
|
|
17
|
+
type ErrorSchemaFromConstraint<E> = E extends ReadonlyArray<Schema.Top> ? E[number] : E extends Schema.Top ? E : never;
|
|
18
|
+
/**
|
|
19
|
+
* What a middleware's implementation is told about the call it wraps.
|
|
20
|
+
*
|
|
21
|
+
* @stability unstable
|
|
22
|
+
* @category models
|
|
23
|
+
* @since 0.3.0
|
|
24
|
+
*/
|
|
25
|
+
export interface Options {
|
|
26
|
+
/** The Callable being called. */
|
|
27
|
+
readonly callable: Any;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The implementation of a middleware: a function that wraps the rest of the
|
|
31
|
+
* call.
|
|
32
|
+
*
|
|
33
|
+
* **Details**
|
|
34
|
+
*
|
|
35
|
+
* `effect` is the rest of the call: the middleware inside this one, the
|
|
36
|
+
* Payload's decoding and the handler. It needs what this middleware
|
|
37
|
+
* `Provides`. The implementation may run it, fail instead, or catch what it
|
|
38
|
+
* fails with. It may require what middleware outside it provides, and always
|
|
39
|
+
* the {@link CallableRequest.CallableRequest}.
|
|
40
|
+
*
|
|
41
|
+
* A Payload that doesn't decode fails `effect` too. An implementation that
|
|
42
|
+
* catches every failure catches that one as well, and the caller then no
|
|
43
|
+
* longer gets `invalid-argument`. Catch only the errors you mean to.
|
|
44
|
+
*
|
|
45
|
+
* @stability unstable
|
|
46
|
+
* @category models
|
|
47
|
+
* @since 0.3.0
|
|
48
|
+
*/
|
|
49
|
+
export type CallableMiddleware<Provides, E extends ErrorConstraint, Requires> = (effect: Effect.Effect<unknown, unhandled, Provides>, options: Options) => Effect.Effect<unknown, unhandled | ErrorSchemaFromConstraint<E>["Type"], Requires | CallableRequest>;
|
|
50
|
+
/**
|
|
51
|
+
* Any middleware, as the type of its service class's instances: what it
|
|
52
|
+
* provides, requires and fails with.
|
|
53
|
+
*
|
|
54
|
+
* @stability unstable
|
|
55
|
+
* @category models
|
|
56
|
+
* @since 0.3.0
|
|
57
|
+
*/
|
|
58
|
+
export interface AnyId {
|
|
59
|
+
readonly [TypeId]: {
|
|
60
|
+
readonly provides: any;
|
|
61
|
+
readonly requires: any;
|
|
62
|
+
readonly error: ErrorConstraint;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Any middleware's service key, as `.middleware` takes it.
|
|
67
|
+
*
|
|
68
|
+
* @stability unstable
|
|
69
|
+
* @category models
|
|
70
|
+
* @since 0.3.0
|
|
71
|
+
*/
|
|
72
|
+
export interface AnyKey extends Context.Key<any, any> {
|
|
73
|
+
readonly [TypeId]: typeof TypeId;
|
|
74
|
+
/** The schemas of the errors the middleware can fail with. */
|
|
75
|
+
readonly error: ReadonlySet<Schema.Top>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The services a middleware provides to what it wraps.
|
|
79
|
+
*
|
|
80
|
+
* @stability unstable
|
|
81
|
+
* @category type-level
|
|
82
|
+
* @since 0.3.0
|
|
83
|
+
*/
|
|
84
|
+
export type Provides<A> = A extends {
|
|
85
|
+
readonly [TypeId]: {
|
|
86
|
+
readonly provides: infer P;
|
|
87
|
+
};
|
|
88
|
+
} ? P : never;
|
|
89
|
+
/**
|
|
90
|
+
* The services a middleware requires from the middleware outside it.
|
|
91
|
+
*
|
|
92
|
+
* @stability unstable
|
|
93
|
+
* @category type-level
|
|
94
|
+
* @since 0.3.0
|
|
95
|
+
*/
|
|
96
|
+
export type Requires<A> = A extends {
|
|
97
|
+
readonly [TypeId]: {
|
|
98
|
+
readonly requires: infer R;
|
|
99
|
+
};
|
|
100
|
+
} ? R : never;
|
|
101
|
+
/**
|
|
102
|
+
* The services still required after wrapping `R` in the middleware `A`: `A`'s
|
|
103
|
+
* `provides` are removed and its `requires` added.
|
|
104
|
+
*
|
|
105
|
+
* @stability unstable
|
|
106
|
+
* @category type-level
|
|
107
|
+
* @since 0.3.0
|
|
108
|
+
*/
|
|
109
|
+
export type ApplyServices<A extends AnyId, R> = Exclude<R, Provides<A>> | Requires<A>;
|
|
110
|
+
/**
|
|
111
|
+
* The union of the error schemas of a middleware.
|
|
112
|
+
*
|
|
113
|
+
* @stability unstable
|
|
114
|
+
* @category type-level
|
|
115
|
+
* @since 0.3.0
|
|
116
|
+
*/
|
|
117
|
+
export type ErrorSchema<A> = A extends {
|
|
118
|
+
readonly [TypeId]: {
|
|
119
|
+
readonly error: infer E;
|
|
120
|
+
};
|
|
121
|
+
} ? ErrorSchemaFromConstraint<E> : never;
|
|
122
|
+
/**
|
|
123
|
+
* The errors a middleware can fail with.
|
|
124
|
+
*
|
|
125
|
+
* @stability unstable
|
|
126
|
+
* @category type-level
|
|
127
|
+
* @since 0.3.0
|
|
128
|
+
*/
|
|
129
|
+
export type Error<A> = ErrorSchema<A>["Type"];
|
|
130
|
+
/**
|
|
131
|
+
* The class {@link Service} returns: a service key whose instances carry the
|
|
132
|
+
* middleware's types.
|
|
133
|
+
*
|
|
134
|
+
* @stability unstable
|
|
135
|
+
* @category models
|
|
136
|
+
* @since 0.3.0
|
|
137
|
+
*/
|
|
138
|
+
export type ServiceClass<Self, Id extends string, Config extends {
|
|
139
|
+
requires: any;
|
|
140
|
+
provides: any;
|
|
141
|
+
error: ErrorConstraint;
|
|
142
|
+
}> = Context.Service<Self, CallableMiddleware<Config["provides"], Config["error"], Config["requires"]>> & {
|
|
143
|
+
new (_: never): Context.ServiceClass.Shape<Id, CallableMiddleware<Config["provides"], Config["error"], Config["requires"]>> & {
|
|
144
|
+
readonly [TypeId]: {
|
|
145
|
+
readonly error: Config["error"];
|
|
146
|
+
readonly requires: Config["requires"];
|
|
147
|
+
readonly provides: Config["provides"];
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
readonly [TypeId]: typeof TypeId;
|
|
151
|
+
/** The schemas of the errors the middleware can fail with. */
|
|
152
|
+
readonly error: ReadonlySet<Schema.Top>;
|
|
153
|
+
};
|
|
154
|
+
/**
|
|
155
|
+
* Declares a Callable Middleware as a class.
|
|
156
|
+
*
|
|
157
|
+
* **When to use**
|
|
158
|
+
*
|
|
159
|
+
* Use to state a requirement of a Callable, such as "the caller is a member of
|
|
160
|
+
* a tenant", as part of its contract. For "the caller is signed in", use the
|
|
161
|
+
* built-in `Caller.Authenticated`.
|
|
162
|
+
*
|
|
163
|
+
* **Details**
|
|
164
|
+
*
|
|
165
|
+
* `provides` is what the middleware gives the handler: the handler's Layer no
|
|
166
|
+
* longer needs it. `requires` is what it needs from middleware outside it; a
|
|
167
|
+
* `requires` that nothing outside provides is left for the Layers where the
|
|
168
|
+
* chain runs. The {@link CallableRequest.CallableRequest} is always there and
|
|
169
|
+
* is never listed.
|
|
170
|
+
*
|
|
171
|
+
* `error` is one schema or an array. A middleware's errors join the error
|
|
172
|
+
* union of every Callable it is attached to. They are sent like the
|
|
173
|
+
* Callable's declared errors, and the client decodes them back.
|
|
174
|
+
*
|
|
175
|
+
* The middleware runs before the Payload is decoded, so a call it rejects
|
|
176
|
+
* learns nothing from the Payload's decoding. The decoding runs inside the
|
|
177
|
+
* chain, so an implementation that catches every failure also catches a
|
|
178
|
+
* Payload that doesn't decode.
|
|
179
|
+
*
|
|
180
|
+
* @example Declaring a middleware
|
|
181
|
+
* ```ts
|
|
182
|
+
* import { Context } from "effect";
|
|
183
|
+
* import { CallableError, CallableMiddleware } from "@visiolab/effect-firebase/functions";
|
|
184
|
+
*
|
|
185
|
+
* class Tenant extends Context.Service<Tenant, { readonly id: string }>()("Tenant") {}
|
|
186
|
+
*
|
|
187
|
+
* class WithTenant extends CallableMiddleware.Service<WithTenant, { provides: Tenant }>()(
|
|
188
|
+
* "WithTenant",
|
|
189
|
+
* { error: CallableError.PermissionDenied },
|
|
190
|
+
* ) {}
|
|
191
|
+
* ```
|
|
192
|
+
*
|
|
193
|
+
* @see {@link Callable.Callable.middleware} for attaching it to a Callable
|
|
194
|
+
* @see {@link Caller.Authenticated} for the built-in middleware
|
|
195
|
+
*
|
|
196
|
+
* @stability unstable
|
|
197
|
+
* @category constructors
|
|
198
|
+
* @since 0.3.0
|
|
199
|
+
*/
|
|
200
|
+
export declare const Service: <Self, Config extends {
|
|
201
|
+
requires?: any;
|
|
202
|
+
provides?: any;
|
|
203
|
+
} = {
|
|
204
|
+
requires: never;
|
|
205
|
+
provides: never;
|
|
206
|
+
}>() => <const Id extends string, const Error extends ErrorConstraint = never>(id: Id, options?: {
|
|
207
|
+
readonly error?: Error | undefined;
|
|
208
|
+
}) => ServiceClass<Self, Id, {
|
|
209
|
+
requires: "requires" extends keyof Config ? Config["requires"] : never;
|
|
210
|
+
provides: "provides" extends keyof Config ? Config["provides"] : never;
|
|
211
|
+
error: Error;
|
|
212
|
+
}>;
|
|
213
|
+
export { CallableMiddleware_d_exports };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { Service as Service$1 } from "./internal/callableMiddleware.mjs";
|
|
3
|
+
// src/functions/CallableMiddleware.ts
|
|
4
|
+
var CallableMiddleware_exports = /* @__PURE__ */ __exportAll({ Service: () => Service });
|
|
5
|
+
/**
|
|
6
|
+
* Declares a Callable Middleware as a class.
|
|
7
|
+
*
|
|
8
|
+
* **When to use**
|
|
9
|
+
*
|
|
10
|
+
* Use to state a requirement of a Callable, such as "the caller is a member of
|
|
11
|
+
* a tenant", as part of its contract. For "the caller is signed in", use the
|
|
12
|
+
* built-in `Caller.Authenticated`.
|
|
13
|
+
*
|
|
14
|
+
* **Details**
|
|
15
|
+
*
|
|
16
|
+
* `provides` is what the middleware gives the handler: the handler's Layer no
|
|
17
|
+
* longer needs it. `requires` is what it needs from middleware outside it; a
|
|
18
|
+
* `requires` that nothing outside provides is left for the Layers where the
|
|
19
|
+
* chain runs. The {@link CallableRequest.CallableRequest} is always there and
|
|
20
|
+
* is never listed.
|
|
21
|
+
*
|
|
22
|
+
* `error` is one schema or an array. A middleware's errors join the error
|
|
23
|
+
* union of every Callable it is attached to. They are sent like the
|
|
24
|
+
* Callable's declared errors, and the client decodes them back.
|
|
25
|
+
*
|
|
26
|
+
* The middleware runs before the Payload is decoded, so a call it rejects
|
|
27
|
+
* learns nothing from the Payload's decoding. The decoding runs inside the
|
|
28
|
+
* chain, so an implementation that catches every failure also catches a
|
|
29
|
+
* Payload that doesn't decode.
|
|
30
|
+
*
|
|
31
|
+
* @example Declaring a middleware
|
|
32
|
+
* ```ts
|
|
33
|
+
* import { Context } from "effect";
|
|
34
|
+
* import { CallableError, CallableMiddleware } from "@visiolab/effect-firebase/functions";
|
|
35
|
+
*
|
|
36
|
+
* class Tenant extends Context.Service<Tenant, { readonly id: string }>()("Tenant") {}
|
|
37
|
+
*
|
|
38
|
+
* class WithTenant extends CallableMiddleware.Service<WithTenant, { provides: Tenant }>()(
|
|
39
|
+
* "WithTenant",
|
|
40
|
+
* { error: CallableError.PermissionDenied },
|
|
41
|
+
* ) {}
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @see {@link Callable.Callable.middleware} for attaching it to a Callable
|
|
45
|
+
* @see {@link Caller.Authenticated} for the built-in middleware
|
|
46
|
+
*
|
|
47
|
+
* @stability unstable
|
|
48
|
+
* @category constructors
|
|
49
|
+
* @since 0.3.0
|
|
50
|
+
*/
|
|
51
|
+
const Service = () => (id, options) => Service$1(id, options);
|
|
52
|
+
export { CallableMiddleware_exports, Service };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
3
|
+
declare namespace CallableRequest_d_exports {
|
|
4
|
+
export { App, Auth, CallableRequest, Input };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Who made a call: the signed-in user's uid, the claims of their ID token and
|
|
8
|
+
* the raw ID token.
|
|
9
|
+
*
|
|
10
|
+
* @stability unstable
|
|
11
|
+
* @category models
|
|
12
|
+
* @since 0.3.0
|
|
13
|
+
*/
|
|
14
|
+
export interface Auth {
|
|
15
|
+
/** The signed-in user's uid. */
|
|
16
|
+
readonly uid: string;
|
|
17
|
+
/** The decoded claims of the user's ID token. */
|
|
18
|
+
readonly token: Readonly<Record<string, unknown>>;
|
|
19
|
+
/** The ID token as the client sent it. */
|
|
20
|
+
readonly rawToken: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The app a call came from, as App Check attested it.
|
|
24
|
+
*
|
|
25
|
+
* @stability unstable
|
|
26
|
+
* @category models
|
|
27
|
+
* @since 0.3.0
|
|
28
|
+
*/
|
|
29
|
+
export interface App {
|
|
30
|
+
/** The app ID of the attested Firebase app. */
|
|
31
|
+
readonly appId: string;
|
|
32
|
+
/** The decoded claims of the App Check token. */
|
|
33
|
+
readonly token: Readonly<Record<string, unknown>>;
|
|
34
|
+
/** Whether the App Check token was already used, when replay protection is on. */
|
|
35
|
+
readonly alreadyConsumed?: boolean | undefined;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The call a Callable is answering.
|
|
39
|
+
*
|
|
40
|
+
* **Details**
|
|
41
|
+
*
|
|
42
|
+
* `data` is the raw Payload, the `Schema.toCodecJson` output the client sent.
|
|
43
|
+
* Callable Middleware runs before the Payload is decoded, so it sees only
|
|
44
|
+
* `data`.
|
|
45
|
+
*
|
|
46
|
+
* `rawRequest` is the HTTP request the call came in, as Effect's
|
|
47
|
+
* `HttpServerRequest`. `Functions` builds it from Firebase's request,
|
|
48
|
+
* streaming its body without copying the bytes, and `Callable.handler` takes
|
|
49
|
+
* it from {@link Input.rawRequest}.
|
|
50
|
+
*
|
|
51
|
+
* @stability unstable
|
|
52
|
+
* @category models
|
|
53
|
+
* @since 0.3.0
|
|
54
|
+
*/
|
|
55
|
+
export interface CallableRequest {
|
|
56
|
+
/** The signed-in caller, absent for a signed-out call. */
|
|
57
|
+
readonly auth?: Auth | undefined;
|
|
58
|
+
/** The app the call came from, absent without App Check. */
|
|
59
|
+
readonly app?: App | undefined;
|
|
60
|
+
/** An unverified Firebase Instance ID token, if the client sent one. */
|
|
61
|
+
readonly instanceIdToken?: string | undefined;
|
|
62
|
+
/** The raw Payload, before it is decoded. */
|
|
63
|
+
readonly data: unknown;
|
|
64
|
+
/**
|
|
65
|
+
* The HTTP request the call came in: its headers, method, URL, body and the
|
|
66
|
+
* caller's `remoteAddress`.
|
|
67
|
+
*
|
|
68
|
+
* **Details**
|
|
69
|
+
*
|
|
70
|
+
* The Firebase web SDK's `httpsCallable` can't send custom headers, so a
|
|
71
|
+
* header of your own comes only from callers that don't use it, such as
|
|
72
|
+
* another server. Headers the browser or the SDK sets, such as `user-agent`
|
|
73
|
+
* and `accept-language`, are there for every caller.
|
|
74
|
+
*
|
|
75
|
+
* `remoteAddress` is the caller's IP address as the platform reports it,
|
|
76
|
+
* `Option.none()` when it is unknown.
|
|
77
|
+
*/
|
|
78
|
+
readonly rawRequest: HttpServerRequest.HttpServerRequest;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* The service key of the {@link CallableRequest}.
|
|
82
|
+
*
|
|
83
|
+
* **Details**
|
|
84
|
+
*
|
|
85
|
+
* Every call provides it, so Callable Middleware may read it without listing
|
|
86
|
+
* it in `requires`.
|
|
87
|
+
*
|
|
88
|
+
* @stability unstable
|
|
89
|
+
* @category services
|
|
90
|
+
* @since 0.3.0
|
|
91
|
+
*/
|
|
92
|
+
export declare const CallableRequest: Context.Service<CallableRequest, CallableRequest>;
|
|
93
|
+
/**
|
|
94
|
+
* What `Callable.handler` takes about a call: who makes it, from which app and
|
|
95
|
+
* over which HTTP request. `Callable.handler` fills `data` by encoding the
|
|
96
|
+
* Payload.
|
|
97
|
+
*
|
|
98
|
+
* **Details**
|
|
99
|
+
*
|
|
100
|
+
* Pass `{}` for a signed-out call and `{ auth: { uid, token } }` for a
|
|
101
|
+
* signed-in one. `rawToken` defaults to an empty string, since a call made in
|
|
102
|
+
* process has no real ID token.
|
|
103
|
+
*
|
|
104
|
+
* @stability unstable
|
|
105
|
+
* @category models
|
|
106
|
+
* @since 0.3.0
|
|
107
|
+
*/
|
|
108
|
+
export interface Input {
|
|
109
|
+
/** The signed-in caller, absent for a signed-out call. */
|
|
110
|
+
readonly auth?: {
|
|
111
|
+
readonly uid: string;
|
|
112
|
+
readonly token: Readonly<Record<string, unknown>>;
|
|
113
|
+
readonly rawToken?: string | undefined;
|
|
114
|
+
} | undefined;
|
|
115
|
+
/** The app the call came from. */
|
|
116
|
+
readonly app?: App | undefined;
|
|
117
|
+
/** A Firebase Instance ID token. */
|
|
118
|
+
readonly instanceIdToken?: string | undefined;
|
|
119
|
+
/**
|
|
120
|
+
* The HTTP request the call comes in, for middleware that reads headers or
|
|
121
|
+
* the caller's address.
|
|
122
|
+
*
|
|
123
|
+
* **Details**
|
|
124
|
+
*
|
|
125
|
+
* Left out, it is a `POST` of the encoded Payload as JSON to
|
|
126
|
+
* `http://localhost/<deployed name>`, with `content-type:
|
|
127
|
+
* application/json`, no other headers and no `remoteAddress`. Build one with
|
|
128
|
+
* `HttpServerRequest.fromWeb` from `effect/http/HttpServerRequest`, and set
|
|
129
|
+
* `remoteAddress` with its `modify`.
|
|
130
|
+
*
|
|
131
|
+
* @example Calling with a request of your own
|
|
132
|
+
* ```ts
|
|
133
|
+
* import { Effect, Layer, Option } from "effect";
|
|
134
|
+
* import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
135
|
+
* import { Callable, CallableMiddleware, CallableRequest } from "@visiolab/effect-firebase/functions";
|
|
136
|
+
*
|
|
137
|
+
* class LogLocale extends CallableMiddleware.Service<LogLocale>()("LogLocale") {}
|
|
138
|
+
*
|
|
139
|
+
* const Ping = Callable.make("ping").middleware(LogLocale);
|
|
140
|
+
*
|
|
141
|
+
* const program = Effect.gen(function* () {
|
|
142
|
+
* const ping = yield* Callable.handler(Ping);
|
|
143
|
+
* const rawRequest = HttpServerRequest.fromWeb(
|
|
144
|
+
* new Request("https://example.com/ping", {
|
|
145
|
+
* method: "POST",
|
|
146
|
+
* headers: { "accept-language": "de-CH" },
|
|
147
|
+
* }),
|
|
148
|
+
* ).modify({ remoteAddress: Option.some("203.0.113.7") });
|
|
149
|
+
* yield* ping(undefined, { rawRequest });
|
|
150
|
+
* }).pipe(
|
|
151
|
+
* Effect.provide(
|
|
152
|
+
* Layer.mergeAll(
|
|
153
|
+
* Callable.toLayer(Ping, () => Effect.void),
|
|
154
|
+
* Layer.succeed(LogLocale, (effect) =>
|
|
155
|
+
* Effect.flatMap(Effect.service(CallableRequest.CallableRequest), ({ rawRequest }) =>
|
|
156
|
+
* Effect.andThen(Effect.logInfo("Locale", rawRequest.headers["accept-language"]), effect),
|
|
157
|
+
* ),
|
|
158
|
+
* ),
|
|
159
|
+
* ),
|
|
160
|
+
* ),
|
|
161
|
+
* );
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
readonly rawRequest?: HttpServerRequest.HttpServerRequest | undefined;
|
|
165
|
+
}
|
|
166
|
+
export { CallableRequest_d_exports };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { CallableRequest as CallableRequest$1 } from "./internal/callableRequest.mjs";
|
|
3
|
+
// src/functions/CallableRequest.ts
|
|
4
|
+
var CallableRequest_exports = /* @__PURE__ */ __exportAll({ CallableRequest: () => CallableRequest });
|
|
5
|
+
/**
|
|
6
|
+
* The service key of the {@link CallableRequest}.
|
|
7
|
+
*
|
|
8
|
+
* **Details**
|
|
9
|
+
*
|
|
10
|
+
* Every call provides it, so Callable Middleware may read it without listing
|
|
11
|
+
* it in `requires`.
|
|
12
|
+
*
|
|
13
|
+
* @stability unstable
|
|
14
|
+
* @category services
|
|
15
|
+
* @since 0.3.0
|
|
16
|
+
*/
|
|
17
|
+
const CallableRequest = CallableRequest$1;
|
|
18
|
+
export { CallableRequest, CallableRequest_exports };
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Unauthenticated } from "./CallableError.mjs";
|
|
2
|
+
import { ServiceClass } from "./CallableMiddleware.mjs";
|
|
3
|
+
import { Context, Layer } from "effect";
|
|
4
|
+
declare namespace Caller_d_exports {
|
|
5
|
+
export { Authenticated, Caller };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The signed-in user making a call.
|
|
9
|
+
*
|
|
10
|
+
* **Details**
|
|
11
|
+
*
|
|
12
|
+
* A portable shape, not `firebase-admin`'s `DecodedIdToken`. There is no
|
|
13
|
+
* constructor: {@link Authenticated} provides it from the request, and a test
|
|
14
|
+
* provides a fake one from a stub middleware Layer.
|
|
15
|
+
*
|
|
16
|
+
* @stability unstable
|
|
17
|
+
* @category models
|
|
18
|
+
* @since 0.3.0
|
|
19
|
+
*/
|
|
20
|
+
export interface Caller {
|
|
21
|
+
/** The user's uid. */
|
|
22
|
+
readonly uid: string;
|
|
23
|
+
/** The decoded claims of the user's ID token. */
|
|
24
|
+
readonly token: Readonly<Record<string, unknown>>;
|
|
25
|
+
/** The ID token as the client sent it. */
|
|
26
|
+
readonly rawToken: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The service key of the {@link Caller}.
|
|
30
|
+
*
|
|
31
|
+
* @stability unstable
|
|
32
|
+
* @category services
|
|
33
|
+
* @since 0.3.0
|
|
34
|
+
*/
|
|
35
|
+
export declare const Caller: Context.Service<Caller, Caller>;
|
|
36
|
+
declare const Authenticated_base: ServiceClass<Authenticated, "@visiolab/effect-firebase/functions/Caller/Authenticated", {
|
|
37
|
+
requires: never;
|
|
38
|
+
provides: Caller;
|
|
39
|
+
error: typeof Unauthenticated;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* The built-in middleware that requires a signed-in caller and provides the
|
|
43
|
+
* {@link Caller}.
|
|
44
|
+
*
|
|
45
|
+
* **When to use**
|
|
46
|
+
*
|
|
47
|
+
* Use on every Callable that only a signed-in user may call. Write a
|
|
48
|
+
* middleware of your own with {@link CallableMiddleware.Service} for other
|
|
49
|
+
* requirements, such as a custom claim.
|
|
50
|
+
*
|
|
51
|
+
* **Details**
|
|
52
|
+
*
|
|
53
|
+
* A call without auth fails with `CallableError.Unauthenticated`, before its
|
|
54
|
+
* Payload is decoded. Provide {@link Authenticated.layer} where the chain
|
|
55
|
+
* runs, or a stub Layer that provides a fake Caller in tests.
|
|
56
|
+
*
|
|
57
|
+
* @example Stubbing the Caller in process
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { Effect, Layer, Schema } from "effect";
|
|
60
|
+
* import { Callable, Caller } from "@visiolab/effect-firebase/functions";
|
|
61
|
+
*
|
|
62
|
+
* const WhoAmI = Callable.make("whoAmI", { success: Schema.String }).middleware(
|
|
63
|
+
* Caller.Authenticated,
|
|
64
|
+
* );
|
|
65
|
+
*
|
|
66
|
+
* const WhoAmILive = Callable.toLayer(WhoAmI, () =>
|
|
67
|
+
* Effect.map(Effect.service(Caller.Caller), ({ uid }) => uid),
|
|
68
|
+
* );
|
|
69
|
+
*
|
|
70
|
+
* const AsAda = Layer.succeed(Caller.Authenticated, (effect) =>
|
|
71
|
+
* Effect.provideService(effect, Caller.Caller, { uid: "ada", token: {}, rawToken: "" }),
|
|
72
|
+
* );
|
|
73
|
+
*
|
|
74
|
+
* const program = Effect.gen(function* () {
|
|
75
|
+
* const whoAmI = yield* Callable.handler(WhoAmI);
|
|
76
|
+
* return yield* whoAmI(undefined, {});
|
|
77
|
+
* }).pipe(Effect.provide(Layer.merge(WhoAmILive, AsAda)));
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @see {@link Caller} for what it provides
|
|
81
|
+
* @see {@link CallableMiddleware.Service} for declaring a middleware of your own
|
|
82
|
+
*
|
|
83
|
+
* @stability unstable
|
|
84
|
+
* @category middleware
|
|
85
|
+
* @since 0.3.0
|
|
86
|
+
*/
|
|
87
|
+
export declare class Authenticated extends Authenticated_base {
|
|
88
|
+
/**
|
|
89
|
+
* The implementation of {@link Authenticated}: provides the {@link Caller}
|
|
90
|
+
* from the request's auth, and fails with `CallableError.Unauthenticated`
|
|
91
|
+
* when there is none.
|
|
92
|
+
*
|
|
93
|
+
* **When to use**
|
|
94
|
+
*
|
|
95
|
+
* Use where the chain runs, in production and in process alike.
|
|
96
|
+
*
|
|
97
|
+
* @stability unstable
|
|
98
|
+
* @category layers
|
|
99
|
+
* @since 0.3.0
|
|
100
|
+
*/
|
|
101
|
+
static readonly layer: Layer.Layer<Authenticated>;
|
|
102
|
+
}
|
|
103
|
+
export { Caller_d_exports };
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { Unauthenticated } from "./CallableError.mjs";
|
|
3
|
+
import { Service } from "./CallableMiddleware.mjs";
|
|
4
|
+
import { CallableRequest } from "./CallableRequest.mjs";
|
|
5
|
+
import { Context, Effect, Layer } from "effect";
|
|
6
|
+
// src/functions/Caller.ts
|
|
7
|
+
/**
|
|
8
|
+
* The Caller: the signed-in user making a call, and the built-in
|
|
9
|
+
* `Authenticated` middleware that provides it.
|
|
10
|
+
*
|
|
11
|
+
* A Callable that requires a signed-in caller attaches {@link Authenticated}.
|
|
12
|
+
* Its handler then reads the {@link Caller} instead of the raw request, and a
|
|
13
|
+
* signed-out call fails with `CallableError.Unauthenticated` before its
|
|
14
|
+
* Payload is decoded.
|
|
15
|
+
*
|
|
16
|
+
* @example Reading the Caller in a handler
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Effect, Schema } from "effect";
|
|
19
|
+
* import { Callable, Caller } from "@visiolab/effect-firebase/functions";
|
|
20
|
+
*
|
|
21
|
+
* const WhoAmI = Callable.make("whoAmI", { success: Schema.String }).middleware(
|
|
22
|
+
* Caller.Authenticated,
|
|
23
|
+
* );
|
|
24
|
+
*
|
|
25
|
+
* const WhoAmILive = Callable.toLayer(WhoAmI, () =>
|
|
26
|
+
* Effect.map(Effect.service(Caller.Caller), ({ uid }) => uid),
|
|
27
|
+
* );
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @stability unstable
|
|
31
|
+
* @since 0.3.0
|
|
32
|
+
*/
|
|
33
|
+
var Caller_exports = /* @__PURE__ */ __exportAll({
|
|
34
|
+
Authenticated: () => Authenticated,
|
|
35
|
+
Caller: () => Caller
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* The service key of the {@link Caller}.
|
|
39
|
+
*
|
|
40
|
+
* @stability unstable
|
|
41
|
+
* @category services
|
|
42
|
+
* @since 0.3.0
|
|
43
|
+
*/
|
|
44
|
+
const Caller = Context.Service("@visiolab/effect-firebase/functions/Caller");
|
|
45
|
+
/**
|
|
46
|
+
* The built-in middleware that requires a signed-in caller and provides the
|
|
47
|
+
* {@link Caller}.
|
|
48
|
+
*
|
|
49
|
+
* **When to use**
|
|
50
|
+
*
|
|
51
|
+
* Use on every Callable that only a signed-in user may call. Write a
|
|
52
|
+
* middleware of your own with {@link CallableMiddleware.Service} for other
|
|
53
|
+
* requirements, such as a custom claim.
|
|
54
|
+
*
|
|
55
|
+
* **Details**
|
|
56
|
+
*
|
|
57
|
+
* A call without auth fails with `CallableError.Unauthenticated`, before its
|
|
58
|
+
* Payload is decoded. Provide {@link Authenticated.layer} where the chain
|
|
59
|
+
* runs, or a stub Layer that provides a fake Caller in tests.
|
|
60
|
+
*
|
|
61
|
+
* @example Stubbing the Caller in process
|
|
62
|
+
* ```ts
|
|
63
|
+
* import { Effect, Layer, Schema } from "effect";
|
|
64
|
+
* import { Callable, Caller } from "@visiolab/effect-firebase/functions";
|
|
65
|
+
*
|
|
66
|
+
* const WhoAmI = Callable.make("whoAmI", { success: Schema.String }).middleware(
|
|
67
|
+
* Caller.Authenticated,
|
|
68
|
+
* );
|
|
69
|
+
*
|
|
70
|
+
* const WhoAmILive = Callable.toLayer(WhoAmI, () =>
|
|
71
|
+
* Effect.map(Effect.service(Caller.Caller), ({ uid }) => uid),
|
|
72
|
+
* );
|
|
73
|
+
*
|
|
74
|
+
* const AsAda = Layer.succeed(Caller.Authenticated, (effect) =>
|
|
75
|
+
* Effect.provideService(effect, Caller.Caller, { uid: "ada", token: {}, rawToken: "" }),
|
|
76
|
+
* );
|
|
77
|
+
*
|
|
78
|
+
* const program = Effect.gen(function* () {
|
|
79
|
+
* const whoAmI = yield* Callable.handler(WhoAmI);
|
|
80
|
+
* return yield* whoAmI(undefined, {});
|
|
81
|
+
* }).pipe(Effect.provide(Layer.merge(WhoAmILive, AsAda)));
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* @see {@link Caller} for what it provides
|
|
85
|
+
* @see {@link CallableMiddleware.Service} for declaring a middleware of your own
|
|
86
|
+
*
|
|
87
|
+
* @stability unstable
|
|
88
|
+
* @category middleware
|
|
89
|
+
* @since 0.3.0
|
|
90
|
+
*/
|
|
91
|
+
var Authenticated = class extends Service()("@visiolab/effect-firebase/functions/Caller/Authenticated", { error: Unauthenticated }) {
|
|
92
|
+
/**
|
|
93
|
+
* The implementation of {@link Authenticated}: provides the {@link Caller}
|
|
94
|
+
* from the request's auth, and fails with `CallableError.Unauthenticated`
|
|
95
|
+
* when there is none.
|
|
96
|
+
*
|
|
97
|
+
* **When to use**
|
|
98
|
+
*
|
|
99
|
+
* Use where the chain runs, in production and in process alike.
|
|
100
|
+
*
|
|
101
|
+
* @stability unstable
|
|
102
|
+
* @category layers
|
|
103
|
+
* @since 0.3.0
|
|
104
|
+
*/
|
|
105
|
+
static layer = Layer.succeed(this, (effect) => Effect.gen(function* () {
|
|
106
|
+
const { auth } = yield* Effect.service(CallableRequest);
|
|
107
|
+
if (auth === void 0) return yield* new Unauthenticated();
|
|
108
|
+
return yield* Effect.provideService(effect, Caller, {
|
|
109
|
+
uid: auth.uid,
|
|
110
|
+
token: auth.token,
|
|
111
|
+
rawToken: auth.rawToken
|
|
112
|
+
});
|
|
113
|
+
}));
|
|
114
|
+
};
|
|
115
|
+
export { Authenticated, Caller, Caller_exports };
|