@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,175 @@
|
|
|
1
|
+
import { Any as Any$1, Handler } from "./FirebaseFunction.mjs";
|
|
2
|
+
import { Pipeable } from "effect";
|
|
3
|
+
declare namespace FunctionGroup_d_exports {
|
|
4
|
+
export { Any, FunctionGroup, Handlers, Member, Members, Names, isFunctionGroup, make };
|
|
5
|
+
}
|
|
6
|
+
declare const TypeId = "~@visiolab/effect-firebase/functions/FunctionGroup";
|
|
7
|
+
/**
|
|
8
|
+
* A Function Group: a name and the Functions it deploys under that name.
|
|
9
|
+
*
|
|
10
|
+
* **Details**
|
|
11
|
+
*
|
|
12
|
+
* A group is a class, so `class Users extends FunctionGroup.make("users")`
|
|
13
|
+
* gives it a name of its own in types and in hovers. Its name is
|
|
14
|
+
* `identifier`, since a class already has a `name` of its own.
|
|
15
|
+
*
|
|
16
|
+
* A group holds Functions of any kind, so a group can follow a domain, such
|
|
17
|
+
* as `posts`, rather than a kind. A Function's name is unique within its
|
|
18
|
+
* group. `.add` checks this when the module loads; the types don't. A
|
|
19
|
+
* Function can be in more than one group, and each group serves and
|
|
20
|
+
* implements it separately. Groups don't nest.
|
|
21
|
+
*
|
|
22
|
+
* A group is only a name and its members. It carries no middleware: attach a
|
|
23
|
+
* Callable Middleware to each Callable that needs it with
|
|
24
|
+
* {@link Callable.Callable.middleware}.
|
|
25
|
+
*
|
|
26
|
+
* @stability unstable
|
|
27
|
+
* @category models
|
|
28
|
+
* @since 0.3.0
|
|
29
|
+
*/
|
|
30
|
+
export interface FunctionGroup<out Identifier extends string, in out Functions extends Any$1 = never> extends Pipeable.Pipeable {
|
|
31
|
+
new (_: never): {};
|
|
32
|
+
readonly [TypeId]: typeof TypeId;
|
|
33
|
+
/** The group's name: the prefix its members deploy under. */
|
|
34
|
+
readonly identifier: Identifier;
|
|
35
|
+
/** The group's members, keyed by their names. */
|
|
36
|
+
readonly functions: { readonly [F in Functions as F["name"]]: F; };
|
|
37
|
+
/**
|
|
38
|
+
* Adds Functions of any kind to the group.
|
|
39
|
+
*
|
|
40
|
+
* **Details**
|
|
41
|
+
*
|
|
42
|
+
* Returns a new group. Throws when a Function's name is already taken in
|
|
43
|
+
* the group, so a clash fails when the module loads, before anything
|
|
44
|
+
* deploys. The types don't catch a clash.
|
|
45
|
+
*/
|
|
46
|
+
add<const A extends ReadonlyArray<Any$1>>(...functions: A): FunctionGroup<Identifier, Functions | A[number]>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Any {@link FunctionGroup}, whatever its name and members.
|
|
50
|
+
*
|
|
51
|
+
* @stability unstable
|
|
52
|
+
* @category models
|
|
53
|
+
* @since 0.3.0
|
|
54
|
+
*/
|
|
55
|
+
export interface Any {
|
|
56
|
+
readonly [TypeId]: typeof TypeId;
|
|
57
|
+
readonly identifier: string;
|
|
58
|
+
readonly functions: {
|
|
59
|
+
readonly [name: string]: Any$1;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The members of a {@link FunctionGroup}, as a union of Functions.
|
|
64
|
+
*
|
|
65
|
+
* **When to use**
|
|
66
|
+
*
|
|
67
|
+
* Use to read every member of a group. Pass the `Any` of a kind as `K`, such
|
|
68
|
+
* as `Members<typeof Users, Callable.Any>`, to keep only the members of that
|
|
69
|
+
* kind.
|
|
70
|
+
*
|
|
71
|
+
* @see {@link Names} for the names of the members
|
|
72
|
+
* @see {@link Member} for the member of one name
|
|
73
|
+
*
|
|
74
|
+
* @stability unstable
|
|
75
|
+
* @category type-level
|
|
76
|
+
* @since 0.3.0
|
|
77
|
+
*/
|
|
78
|
+
export type Members<G, K extends Any$1 = Any$1> = G extends {
|
|
79
|
+
readonly functions: infer Record;
|
|
80
|
+
} ? Extract<Record[keyof Record], K> : never;
|
|
81
|
+
/**
|
|
82
|
+
* The names of the members of a {@link FunctionGroup}.
|
|
83
|
+
*
|
|
84
|
+
* **When to use**
|
|
85
|
+
*
|
|
86
|
+
* Use to key something on a group's members. Pass the `Any` of a kind as `K`
|
|
87
|
+
* to keep only the names of the members of that kind.
|
|
88
|
+
*
|
|
89
|
+
* @see {@link Members} for the members themselves
|
|
90
|
+
*
|
|
91
|
+
* @stability unstable
|
|
92
|
+
* @category type-level
|
|
93
|
+
* @since 0.3.0
|
|
94
|
+
*/
|
|
95
|
+
export type Names<G, K extends Any$1 = Any$1> = Members<G, K>["name"];
|
|
96
|
+
/**
|
|
97
|
+
* The member of a {@link FunctionGroup} named `Name`.
|
|
98
|
+
*
|
|
99
|
+
* **When to use**
|
|
100
|
+
*
|
|
101
|
+
* Use to read one member's type by its name. Pass the `Any` of a kind as `K`
|
|
102
|
+
* to get `never` unless the member is of that kind.
|
|
103
|
+
*
|
|
104
|
+
* @see {@link Members} for every member
|
|
105
|
+
*
|
|
106
|
+
* @stability unstable
|
|
107
|
+
* @category type-level
|
|
108
|
+
* @since 0.3.0
|
|
109
|
+
*/
|
|
110
|
+
export type Member<G, Name extends string, K extends Any$1 = Any$1> = Extract<Members<G, K>, {
|
|
111
|
+
readonly name: Name;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* The {@link FirebaseFunction.Handler}s that serving a {@link FunctionGroup}
|
|
115
|
+
* needs: one per member, keyed by the group.
|
|
116
|
+
*
|
|
117
|
+
* @stability unstable
|
|
118
|
+
* @category type-level
|
|
119
|
+
* @since 0.3.0
|
|
120
|
+
*/
|
|
121
|
+
export type Handlers<G extends Any> = Names<G> extends (infer Name) ? Name extends string ? Handler<G["identifier"], Name> : never : never;
|
|
122
|
+
/**
|
|
123
|
+
* Checks whether a value is a {@link FunctionGroup}. A building block for the
|
|
124
|
+
* functions and client packages, which take a Function or a group. Most apps
|
|
125
|
+
* don't need it.
|
|
126
|
+
*
|
|
127
|
+
* @stability unstable
|
|
128
|
+
* @category guards
|
|
129
|
+
* @since 0.3.0
|
|
130
|
+
*/
|
|
131
|
+
export declare const isFunctionGroup: (u: unknown) => u is Any;
|
|
132
|
+
/**
|
|
133
|
+
* Starts a Function Group with no members.
|
|
134
|
+
*
|
|
135
|
+
* **When to use**
|
|
136
|
+
*
|
|
137
|
+
* Use to collect related Functions, of any kind, under one prefix, and to
|
|
138
|
+
* deploy them as one. A Function that stands alone needs no group.
|
|
139
|
+
*
|
|
140
|
+
* **Details**
|
|
141
|
+
*
|
|
142
|
+
* Add members with `.add`. Extend the result as a class, so the group has a
|
|
143
|
+
* name of its own. Each member deploys as `<identifier>-<name>`.
|
|
144
|
+
*
|
|
145
|
+
* A client built from a Callable on its own, rather than from its group,
|
|
146
|
+
* calls the name without the prefix and fails with `not-found`. Nothing
|
|
147
|
+
* checks this at runtime.
|
|
148
|
+
*
|
|
149
|
+
* @example Serving one Callable in two groups
|
|
150
|
+
* ```ts
|
|
151
|
+
* import { Schema } from "effect";
|
|
152
|
+
* import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
|
|
153
|
+
*
|
|
154
|
+
* const GetUser = Callable.make("get", {
|
|
155
|
+
* payload: { id: Schema.String },
|
|
156
|
+
* success: Schema.String,
|
|
157
|
+
* });
|
|
158
|
+
*
|
|
159
|
+
* // Deploys as `users-get` and `admins-get`, each with a handler of its own.
|
|
160
|
+
* class Users extends FunctionGroup.make("users").add(GetUser) {}
|
|
161
|
+
* class Admins extends FunctionGroup.make("admins").add(GetUser) {}
|
|
162
|
+
* ```
|
|
163
|
+
*
|
|
164
|
+
* @see {@link Callable.make} for declaring a Callable member
|
|
165
|
+
* @see {@link Callable.toLayer} for implementing a Callable member
|
|
166
|
+
* @see {@link DocumentTrigger.created} for declaring a Document Trigger member
|
|
167
|
+
* @see {@link DocumentTrigger.toLayer} for implementing a Document Trigger member
|
|
168
|
+
* @see {@link Functions.group} for deploying the group
|
|
169
|
+
*
|
|
170
|
+
* @stability unstable
|
|
171
|
+
* @category constructors
|
|
172
|
+
* @since 0.3.0
|
|
173
|
+
*/
|
|
174
|
+
export declare const make: <const Identifier extends string>(identifier: Identifier) => FunctionGroup<Identifier>;
|
|
175
|
+
export { FunctionGroup_d_exports };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { isFunctionGroup as isFunctionGroup$1, make as make$1 } from "./internal/functionGroup.mjs";
|
|
3
|
+
// src/functions/FunctionGroup.ts
|
|
4
|
+
var FunctionGroup_exports = /* @__PURE__ */ __exportAll({
|
|
5
|
+
isFunctionGroup: () => isFunctionGroup,
|
|
6
|
+
make: () => make
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Checks whether a value is a {@link FunctionGroup}. A building block for the
|
|
10
|
+
* functions and client packages, which take a Function or a group. Most apps
|
|
11
|
+
* don't need it.
|
|
12
|
+
*
|
|
13
|
+
* @stability unstable
|
|
14
|
+
* @category guards
|
|
15
|
+
* @since 0.3.0
|
|
16
|
+
*/
|
|
17
|
+
const isFunctionGroup = isFunctionGroup$1;
|
|
18
|
+
/**
|
|
19
|
+
* Starts a Function Group with no members.
|
|
20
|
+
*
|
|
21
|
+
* **When to use**
|
|
22
|
+
*
|
|
23
|
+
* Use to collect related Functions, of any kind, under one prefix, and to
|
|
24
|
+
* deploy them as one. A Function that stands alone needs no group.
|
|
25
|
+
*
|
|
26
|
+
* **Details**
|
|
27
|
+
*
|
|
28
|
+
* Add members with `.add`. Extend the result as a class, so the group has a
|
|
29
|
+
* name of its own. Each member deploys as `<identifier>-<name>`.
|
|
30
|
+
*
|
|
31
|
+
* A client built from a Callable on its own, rather than from its group,
|
|
32
|
+
* calls the name without the prefix and fails with `not-found`. Nothing
|
|
33
|
+
* checks this at runtime.
|
|
34
|
+
*
|
|
35
|
+
* @example Serving one Callable in two groups
|
|
36
|
+
* ```ts
|
|
37
|
+
* import { Schema } from "effect";
|
|
38
|
+
* import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
|
|
39
|
+
*
|
|
40
|
+
* const GetUser = Callable.make("get", {
|
|
41
|
+
* payload: { id: Schema.String },
|
|
42
|
+
* success: Schema.String,
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* // Deploys as `users-get` and `admins-get`, each with a handler of its own.
|
|
46
|
+
* class Users extends FunctionGroup.make("users").add(GetUser) {}
|
|
47
|
+
* class Admins extends FunctionGroup.make("admins").add(GetUser) {}
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* @see {@link Callable.make} for declaring a Callable member
|
|
51
|
+
* @see {@link Callable.toLayer} for implementing a Callable member
|
|
52
|
+
* @see {@link DocumentTrigger.created} for declaring a Document Trigger member
|
|
53
|
+
* @see {@link DocumentTrigger.toLayer} for implementing a Document Trigger member
|
|
54
|
+
* @see {@link Functions.group} for deploying the group
|
|
55
|
+
*
|
|
56
|
+
* @stability unstable
|
|
57
|
+
* @category constructors
|
|
58
|
+
* @since 0.3.0
|
|
59
|
+
*/
|
|
60
|
+
const make = (identifier) => make$1({
|
|
61
|
+
identifier,
|
|
62
|
+
functions: {}
|
|
63
|
+
});
|
|
64
|
+
export { FunctionGroup_exports, isFunctionGroup, make };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CallableError_d_exports } from "./CallableError.mjs";
|
|
2
|
+
import { CallableRequest_d_exports } from "./CallableRequest.mjs";
|
|
3
|
+
import { CallableMiddleware_d_exports } from "./CallableMiddleware.mjs";
|
|
4
|
+
import { FirebaseFunction_d_exports } from "./FirebaseFunction.mjs";
|
|
5
|
+
import { FunctionGroup_d_exports } from "./FunctionGroup.mjs";
|
|
6
|
+
import { Callable_d_exports } from "./Callable.mjs";
|
|
7
|
+
import { Caller_d_exports } from "./Caller.mjs";
|
|
8
|
+
import { DocumentTrigger_d_exports } from "./DocumentTrigger.mjs";
|
|
9
|
+
export { Callable_d_exports as Callable, CallableError_d_exports as CallableError, CallableMiddleware_d_exports as CallableMiddleware, CallableRequest_d_exports as CallableRequest, Caller_d_exports as Caller, DocumentTrigger_d_exports as DocumentTrigger, FirebaseFunction_d_exports as FirebaseFunction, FunctionGroup_d_exports as FunctionGroup };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CallableError_exports } from "./CallableError.mjs";
|
|
2
|
+
import { Callable_exports } from "./Callable.mjs";
|
|
3
|
+
import { CallableMiddleware_exports } from "./CallableMiddleware.mjs";
|
|
4
|
+
import { CallableRequest_exports } from "./CallableRequest.mjs";
|
|
5
|
+
import { Caller_exports } from "./Caller.mjs";
|
|
6
|
+
import { DocumentTrigger_exports } from "./DocumentTrigger.mjs";
|
|
7
|
+
import { FirebaseFunction_exports } from "./FirebaseFunction.mjs";
|
|
8
|
+
import { FunctionGroup_exports } from "./FunctionGroup.mjs";
|
|
9
|
+
export { Callable_exports as Callable, CallableError_exports as CallableError, CallableMiddleware_exports as CallableMiddleware, CallableRequest_exports as CallableRequest, Caller_exports as Caller, DocumentTrigger_exports as DocumentTrigger, FirebaseFunction_exports as FirebaseFunction, FunctionGroup_exports as FunctionGroup };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { CallableError, ResponseError } from "../CallableError.mjs";
|
|
2
|
+
import { CallableRequest } from "./callableRequest.mjs";
|
|
3
|
+
import { deployedName as deployedName$1, handlerKey as handlerKey$1 } from "./firebaseFunction.mjs";
|
|
4
|
+
import { Context, Effect, Layer, Pipeable, Schema } from "effect";
|
|
5
|
+
import * as HttpServerRequest from "effect/http/HttpServerRequest";
|
|
6
|
+
// src/functions/internal/callable.ts
|
|
7
|
+
/** @internal */
|
|
8
|
+
/** @internal */
|
|
9
|
+
const TypeId = "~@visiolab/effect-firebase/functions/Callable";
|
|
10
|
+
/** @internal */
|
|
11
|
+
const kind = "Callable";
|
|
12
|
+
const Proto = {
|
|
13
|
+
[TypeId]: TypeId,
|
|
14
|
+
middleware(middleware) {
|
|
15
|
+
return make({
|
|
16
|
+
kind,
|
|
17
|
+
name: this.name,
|
|
18
|
+
payload: this.payload,
|
|
19
|
+
success: this.success,
|
|
20
|
+
error: this.error,
|
|
21
|
+
middlewares: /* @__PURE__ */ new Set([...this.middlewares, middleware])
|
|
22
|
+
});
|
|
23
|
+
},
|
|
24
|
+
pipe() {
|
|
25
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
/** @internal */
|
|
29
|
+
const make = (fields) => Object.assign(Object.create(Proto), fields);
|
|
30
|
+
/**
|
|
31
|
+
* The key of the handler of the Callable `name` in `group`, or in no group.
|
|
32
|
+
*
|
|
33
|
+
* @internal
|
|
34
|
+
*/
|
|
35
|
+
const handlerKey = (group, name) => handlerKey$1(group, name);
|
|
36
|
+
/** @internal */
|
|
37
|
+
const toLayer = (group, name, handler) => Layer.effect(handlerKey(group, name), Effect.gen(function* () {
|
|
38
|
+
const run = Effect.isEffect(handler) ? yield* handler : handler;
|
|
39
|
+
const built = yield* Effect.context();
|
|
40
|
+
return (payload) => Effect.updateContext(run(payload), (call) => Context.merge(built, call));
|
|
41
|
+
}));
|
|
42
|
+
/**
|
|
43
|
+
* Schemas with their services erased: a Callable's codecs need none that the
|
|
44
|
+
* types track, and `Schema.Top` leaves them `unknown`.
|
|
45
|
+
*/
|
|
46
|
+
const codec = (schema) => Schema.toCodecJson(schema);
|
|
47
|
+
/** @internal */
|
|
48
|
+
const getErrorCode = (schema) => Schema.resolveAnnotations(schema)?.callableErrorCode ?? "internal";
|
|
49
|
+
/**
|
|
50
|
+
* The name `callable` is deployed under: its own in no group, or
|
|
51
|
+
* `<group>-<name>` in `group`. The server exports it under this name, and the
|
|
52
|
+
* client calls it.
|
|
53
|
+
*
|
|
54
|
+
* @internal
|
|
55
|
+
*/
|
|
56
|
+
const deployedName = deployedName$1;
|
|
57
|
+
/**
|
|
58
|
+
* The attributes of the server's and the client's span of a call to
|
|
59
|
+
* `callable` in `group`, or in no group.
|
|
60
|
+
*
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
const spanAttributes = (group, callable) => ({
|
|
64
|
+
"rpc.system": "firebase_callable",
|
|
65
|
+
"rpc.method": callable.name,
|
|
66
|
+
...group === void 0 ? {} : { "rpc.service": group.identifier },
|
|
67
|
+
"faas.name": deployedName(group, callable)
|
|
68
|
+
});
|
|
69
|
+
/**
|
|
70
|
+
* The schemas of every error a call to `callable` can be answered with: its
|
|
71
|
+
* declared errors, then those of its middleware.
|
|
72
|
+
*
|
|
73
|
+
* @internal
|
|
74
|
+
*/
|
|
75
|
+
const errorSchemas = (callable) => [...callable.error, ...[...callable.middlewares].flatMap((middleware) => [...middleware.error])];
|
|
76
|
+
/**
|
|
77
|
+
* Turns a failure of the call into the answer that carries it: the code of
|
|
78
|
+
* the error schema it matches, a readable message, and the encoded error. A
|
|
79
|
+
* failure no schema matches, or one that doesn't encode, is a defect.
|
|
80
|
+
*/
|
|
81
|
+
const encodeFailure = (schemas, error) => Effect.gen(function* () {
|
|
82
|
+
for (const schema of schemas) {
|
|
83
|
+
if (!Schema.is(schema)(error)) continue;
|
|
84
|
+
const code = getErrorCode(schema);
|
|
85
|
+
const details = yield* Effect.orDie(Schema.encodeUnknownEffect(codec(schema))(error));
|
|
86
|
+
const fields = error;
|
|
87
|
+
const message = typeof fields.message === "string" && fields.message !== "" ? fields.message : typeof fields._tag === "string" ? fields._tag : code;
|
|
88
|
+
return new ResponseError({
|
|
89
|
+
code,
|
|
90
|
+
message,
|
|
91
|
+
details
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
return yield* Effect.die(error);
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* The failure of a raw Payload that doesn't decode, as it leaves the chain.
|
|
98
|
+
* Middleware sees it like any other failure.
|
|
99
|
+
*/
|
|
100
|
+
var PayloadDecodeError = class {
|
|
101
|
+
cause;
|
|
102
|
+
constructor(cause) {
|
|
103
|
+
this.cause = cause;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* The middleware chain of `callable` in `group`, or in no group, around the
|
|
108
|
+
* Payload's decoding and the handler. `serve`, which `Functions` runs,
|
|
109
|
+
* and `handler` both run this one chain.
|
|
110
|
+
*
|
|
111
|
+
* The middleware implementations are read from the context once. The context
|
|
112
|
+
* the chain was read in sits under that of each call, and the call's request
|
|
113
|
+
* on top of both.
|
|
114
|
+
*
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
const chain = (group, callable) => Effect.gen(function* () {
|
|
118
|
+
const handler = yield* Effect.service(handlerKey(group?.identifier, callable.name));
|
|
119
|
+
const context = yield* Effect.context();
|
|
120
|
+
const implementations = [...callable.middlewares].map((key) => Context.getUnsafe(context, key));
|
|
121
|
+
const decode = Schema.decodeUnknownEffect(codec(callable.payload));
|
|
122
|
+
return (request) => {
|
|
123
|
+
let effect = decode(request.data).pipe(Effect.mapError((cause) => new PayloadDecodeError(cause)), Effect.flatMap(handler));
|
|
124
|
+
for (const implementation of implementations) effect = implementation(effect, { callable });
|
|
125
|
+
return effect.pipe(Effect.provideService(CallableRequest, request), Effect.updateContext((call) => Context.merge(context, call)));
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
/** @internal */
|
|
129
|
+
const serve = (group, callable) => Effect.map(chain(group, callable), (run) => {
|
|
130
|
+
const encode = Schema.encodeUnknownEffect(codec(callable.success));
|
|
131
|
+
const schemas = errorSchemas(callable);
|
|
132
|
+
const fail = (reason) => new CallableError({
|
|
133
|
+
callable: deployedName(group, callable),
|
|
134
|
+
reason
|
|
135
|
+
});
|
|
136
|
+
return (request) => run(request).pipe(Effect.catch((error) => error instanceof PayloadDecodeError ? Effect.logDebug("The Payload of a Callable didn't decode", error.cause).pipe(Effect.andThen(Effect.fail(fail(new ResponseError({
|
|
137
|
+
code: "invalid-argument",
|
|
138
|
+
message: "The Payload didn't decode",
|
|
139
|
+
details: void 0
|
|
140
|
+
}))))) : Effect.flatMap(encodeFailure(schemas, error), (reason) => Effect.fail(fail(reason)))), Effect.flatMap((value) => Effect.orDie(encode(value))));
|
|
141
|
+
});
|
|
142
|
+
/**
|
|
143
|
+
* The HTTP request of a call `handler` runs with no request given: a JSON
|
|
144
|
+
* `POST` of the encoded Payload to the deployed name.
|
|
145
|
+
*/
|
|
146
|
+
const syntheticRequest = (name, data) => HttpServerRequest.fromWeb(new Request(`http://localhost/${name}`, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: { "content-type": "application/json" },
|
|
149
|
+
body: JSON.stringify(data)
|
|
150
|
+
}));
|
|
151
|
+
/** @internal */
|
|
152
|
+
const handler = (group, callable) => Effect.map(chain(group, callable), (run) => {
|
|
153
|
+
const encode = Schema.encodeUnknownEffect(codec(callable.payload));
|
|
154
|
+
const name = deployedName(group, callable);
|
|
155
|
+
return (payload, input) => encode(payload).pipe(Effect.orDie, Effect.flatMap((data) => run({
|
|
156
|
+
auth: input.auth === void 0 ? void 0 : {
|
|
157
|
+
uid: input.auth.uid,
|
|
158
|
+
token: input.auth.token,
|
|
159
|
+
rawToken: input.auth.rawToken ?? ""
|
|
160
|
+
},
|
|
161
|
+
app: input.app,
|
|
162
|
+
instanceIdToken: input.instanceIdToken,
|
|
163
|
+
data,
|
|
164
|
+
rawRequest: input.rawRequest ?? syntheticRequest(name, data)
|
|
165
|
+
})), Effect.catchIf((error) => error instanceof PayloadDecodeError, (error) => Effect.die(error.cause)));
|
|
166
|
+
});
|
|
167
|
+
export { TypeId, chain, deployedName, errorSchemas, getErrorCode, handler, handlerKey, kind, make, serve, spanAttributes, toLayer };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Context, Effect, Schema } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* The middleware attached to a Callable, as a union, from its phantom
|
|
4
|
+
* `~Middleware` field.
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export type Attached<X> = X extends {
|
|
9
|
+
readonly "~Middleware": infer M;
|
|
10
|
+
} ? M : never;
|
|
11
|
+
/**
|
|
12
|
+
* What the middleware attached to a Callable still requires, from its phantom
|
|
13
|
+
* `~MiddlewareServices` field.
|
|
14
|
+
*
|
|
15
|
+
* @internal
|
|
16
|
+
*/
|
|
17
|
+
export type AttachedServices<X> = X extends {
|
|
18
|
+
readonly "~MiddlewareServices": infer R;
|
|
19
|
+
} ? R : never;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
// src/functions/internal/callableMiddleware.ts
|
|
3
|
+
/** @internal */
|
|
4
|
+
/** @internal */
|
|
5
|
+
const TypeId = "~@visiolab/effect-firebase/functions/CallableMiddleware";
|
|
6
|
+
/** @internal */
|
|
7
|
+
const Service = (id, options) => {
|
|
8
|
+
class Service extends Context.Service()(id) {}
|
|
9
|
+
const self = Service;
|
|
10
|
+
self[TypeId] = TypeId;
|
|
11
|
+
const error = options?.error;
|
|
12
|
+
self.error = new Set(error === void 0 ? [] : Array.isArray(error) ? error : [error]);
|
|
13
|
+
return self;
|
|
14
|
+
};
|
|
15
|
+
export { Service, TypeId };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "../../firestore/DocumentSnapshot.mjs";
|
|
2
|
+
import "../../firestore/Collection.mjs";
|
|
3
|
+
import "./firebaseFunction.mjs";
|
|
4
|
+
import { Context, Effect, Layer } from "effect";
|
|
5
|
+
/**
|
|
6
|
+
* The changes to a document a trigger can listen to.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export type EventKind = "created" | "deleted" | "updated" | "written";
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { deployedName, handlerKey as handlerKey$1 } from "./firebaseFunction.mjs";
|
|
2
|
+
import { Context, Effect, Layer, Pipeable } from "effect";
|
|
3
|
+
// src/functions/internal/documentTrigger.ts
|
|
4
|
+
/** @internal */
|
|
5
|
+
/** @internal */
|
|
6
|
+
const TypeId = "~@visiolab/effect-firebase/functions/DocumentTrigger";
|
|
7
|
+
/** @internal */
|
|
8
|
+
const kind = "DocumentTrigger";
|
|
9
|
+
const Proto = {
|
|
10
|
+
[TypeId]: TypeId,
|
|
11
|
+
pipe() {
|
|
12
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/** @internal */
|
|
16
|
+
const make = (fields) => Object.assign(Object.create(Proto), fields);
|
|
17
|
+
/**
|
|
18
|
+
* The key of the handler of the Document Trigger `name` in `group`, or in no
|
|
19
|
+
* group.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
const handlerKey = (group, name) => handlerKey$1(group, name);
|
|
24
|
+
/** @internal */
|
|
25
|
+
const toLayer = (group, name, handler) => Layer.effect(handlerKey(group, name), Effect.gen(function* () {
|
|
26
|
+
const run = Effect.isEffect(handler) ? yield* handler : handler;
|
|
27
|
+
const built = yield* Effect.context();
|
|
28
|
+
return (event) => Effect.updateContext(run(event), (call) => Context.merge(built, call));
|
|
29
|
+
}));
|
|
30
|
+
/** @internal */
|
|
31
|
+
const serve = (group, trigger) => Effect.service(handlerKey(group?.identifier, trigger.name));
|
|
32
|
+
/**
|
|
33
|
+
* The path pattern of the documents of `collection`, with a wildcard of its
|
|
34
|
+
* own for each ancestor id and for the document id:
|
|
35
|
+
* `users/{id0}/posts/{id1}`. The wildcards are only ever read back through
|
|
36
|
+
* the event's document path, so their names are free.
|
|
37
|
+
*
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
const documentPattern = (collection) => collection.path.map((segment, i) => `${segment}/{id${i}}`).join("/");
|
|
41
|
+
/** @internal */
|
|
42
|
+
const deployment = (group, trigger) => ({
|
|
43
|
+
name: deployedName(group, trigger),
|
|
44
|
+
document: documentPattern(trigger.collection)
|
|
45
|
+
});
|
|
46
|
+
/** @internal */
|
|
47
|
+
const createdEvent = (input) => ({
|
|
48
|
+
id: input.id,
|
|
49
|
+
time: input.time,
|
|
50
|
+
ref: input.snapshot.ref,
|
|
51
|
+
snapshot: input.snapshot
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* A `deleted` event has the shape of a `created` one, with the document as it
|
|
55
|
+
* was just before it was deleted.
|
|
56
|
+
*
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
const deletedEvent = createdEvent;
|
|
60
|
+
/**
|
|
61
|
+
* The event of a change with a document on each side. Both sides are at the
|
|
62
|
+
* same reference; `ref` is taken from `after`.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
const changeEvent = (input) => ({
|
|
67
|
+
id: input.id,
|
|
68
|
+
time: input.time,
|
|
69
|
+
ref: input.after.ref,
|
|
70
|
+
before: input.before,
|
|
71
|
+
after: input.after
|
|
72
|
+
});
|
|
73
|
+
export { TypeId, changeEvent, createdEvent, deletedEvent, deployment, documentPattern, handlerKey, kind, make, serve, toLayer };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
/** @internal */
|
|
3
|
+
export declare const NoGroupTypeId = "~@visiolab/effect-firebase/functions/FirebaseFunction/NoGroup";
|
|
4
|
+
/** @internal */
|
|
5
|
+
export declare const HandlerTypeId = "~@visiolab/effect-firebase/functions/FirebaseFunction/Handler";
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Context } from "effect";
|
|
2
|
+
// src/functions/internal/firebaseFunction.ts
|
|
3
|
+
/** @internal */
|
|
4
|
+
/**
|
|
5
|
+
* The key of the handler of the Function `name` in `group`, or in no group,
|
|
6
|
+
* whatever its kind. A kind decides what it holds.
|
|
7
|
+
*
|
|
8
|
+
* Context keys are compared by their string, so every call with the same group
|
|
9
|
+
* and name reaches the same service. Deployed names can't contain `/`, so the
|
|
10
|
+
* two forms can't collide. Names are unique within a group, and a Function in
|
|
11
|
+
* no group is deployed under its name, so two kinds never share a key they
|
|
12
|
+
* could both be served under.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
const handlerKey = (group, name) => Context.Service(group === void 0 ? `@visiolab/effect-firebase/functions/Handler/${name}` : `@visiolab/effect-firebase/functions/Handler/${group}/${name}`);
|
|
17
|
+
/**
|
|
18
|
+
* The name `fn` is deployed under: its own in no group, or `<group>-<name>`
|
|
19
|
+
* in `group`.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
const deployedName = (group, fn) => group === void 0 ? fn.name : `${group.identifier}-${fn.name}`;
|
|
24
|
+
export { deployedName, handlerKey };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Pipeable } from "effect";
|
|
2
|
+
// src/functions/internal/functionGroup.ts
|
|
3
|
+
/** @internal */
|
|
4
|
+
/** @internal */
|
|
5
|
+
const TypeId = "~@visiolab/effect-firebase/functions/FunctionGroup";
|
|
6
|
+
/** @internal */
|
|
7
|
+
const isFunctionGroup = (u) => (typeof u === "function" || typeof u === "object" && u !== null) && "~@visiolab/effect-firebase/functions/FunctionGroup" in u;
|
|
8
|
+
const Proto = {
|
|
9
|
+
[TypeId]: TypeId,
|
|
10
|
+
add(...toAdd) {
|
|
11
|
+
const functions = { ...this.functions };
|
|
12
|
+
for (const fn of toAdd) {
|
|
13
|
+
if (Object.hasOwn(functions, fn.name)) throw new Error(`The Function Group "${this.identifier}" already has a Function named "${fn.name}"`);
|
|
14
|
+
functions[fn.name] = fn;
|
|
15
|
+
}
|
|
16
|
+
return make({
|
|
17
|
+
identifier: this.identifier,
|
|
18
|
+
functions
|
|
19
|
+
});
|
|
20
|
+
},
|
|
21
|
+
pipe() {
|
|
22
|
+
return Pipeable.pipeArguments(this, arguments);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* A function, so that a group can be the base of a class. Its `name` is the
|
|
27
|
+
* function's own, so the group's name is its `identifier`.
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
const make = (fields) => {
|
|
32
|
+
function FunctionGroup() {}
|
|
33
|
+
Object.setPrototypeOf(FunctionGroup, Proto);
|
|
34
|
+
return Object.assign(FunctionGroup, fields);
|
|
35
|
+
};
|
|
36
|
+
export { TypeId, isFunctionGroup, make };
|