@visiolab/effect-firebase-admin 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 +73 -2
- package/dist/_virtual/_rolldown/runtime.mjs +12 -0
- package/dist/app/App.d.mts +115 -0
- package/dist/app/App.mjs +145 -0
- package/dist/app/App.mjs.map +1 -0
- package/dist/app/index.d.mts +2 -0
- package/dist/app/index.mjs +1 -0
- package/dist/app/internal/app.mjs +20 -0
- package/dist/app/internal/app.mjs.map +1 -0
- package/dist/auth/Auth.d.mts +167 -0
- package/dist/auth/Auth.mjs +131 -0
- package/dist/auth/Auth.mjs.map +1 -0
- package/dist/auth/index.d.mts +2 -0
- package/dist/auth/index.mjs +1 -0
- package/dist/firestore/AdminFirestore.d.mts +241 -0
- package/dist/firestore/AdminFirestore.mjs +133 -0
- package/dist/firestore/AdminFirestore.mjs.map +1 -0
- package/dist/firestore/AdminFirestoreValue.d.mts +61 -0
- package/dist/firestore/AdminFirestoreValue.mjs +62 -0
- package/dist/firestore/AdminFirestoreValue.mjs.map +1 -0
- package/dist/firestore/index.d.mts +3 -0
- package/dist/firestore/index.mjs +3 -0
- package/dist/firestore/internal/firestore.mjs +135 -0
- package/dist/firestore/internal/firestore.mjs.map +1 -0
- package/dist/firestore/internal/firestoreValue.mjs +56 -0
- package/dist/firestore/internal/firestoreValue.mjs.map +1 -0
- package/package.json +61 -3
- package/src/app/App.ts +158 -0
- package/src/app/index.ts +7 -0
- package/src/app/internal/app.ts +35 -0
- package/src/auth/Auth.ts +258 -0
- package/src/auth/index.ts +7 -0
- package/src/firestore/AdminFirestore.ts +303 -0
- package/src/firestore/AdminFirestoreValue.ts +93 -0
- package/src/firestore/index.ts +14 -0
- package/src/firestore/internal/firestore.ts +238 -0
- package/src/firestore/internal/firestoreValue.ts +85 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { App } from "../app/App.mjs";
|
|
3
|
+
import { Context, Effect, Layer, Schema } from "effect";
|
|
4
|
+
import { FirebaseError } from "firebase-admin/app";
|
|
5
|
+
import * as Admin from "firebase-admin/auth";
|
|
6
|
+
// src/auth/Auth.ts
|
|
7
|
+
/**
|
|
8
|
+
* Firebase Authentication on the Admin SDK, as an Effect service.
|
|
9
|
+
*
|
|
10
|
+
* {@link Auth} wraps the calls server code uses most, such as verifying ID
|
|
11
|
+
* tokens and managing users. Every call fails with an {@link AuthError}, and
|
|
12
|
+
* {@link Auth.use} reaches the rest of the Admin SDK.
|
|
13
|
+
*
|
|
14
|
+
* @example Verifying an ID token
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { Effect, Layer } from "effect";
|
|
17
|
+
* import { App } from "@visiolab/effect-firebase-admin/app";
|
|
18
|
+
* import { Auth } from "@visiolab/effect-firebase-admin/auth";
|
|
19
|
+
*
|
|
20
|
+
* const uidOf = (idToken: string) =>
|
|
21
|
+
* Effect.gen(function* () {
|
|
22
|
+
* const auth = yield* Auth.Auth;
|
|
23
|
+
* const token = yield* auth.verifyIdToken(idToken, true);
|
|
24
|
+
* return token.uid;
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* const AuthLive = Auth.layer.pipe(Layer.provide(App.layer()));
|
|
28
|
+
*
|
|
29
|
+
* uidOf("<id token>").pipe(Effect.provide(AuthLive));
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @stability unstable
|
|
33
|
+
* @since 0.1.0
|
|
34
|
+
*/
|
|
35
|
+
var Auth_exports = /* @__PURE__ */ __exportAll({
|
|
36
|
+
Auth: () => Auth,
|
|
37
|
+
AuthError: () => AuthError,
|
|
38
|
+
layer: () => layer,
|
|
39
|
+
make: () => make
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Fails a call on {@link Auth} when the Admin SDK rejects it, with what it
|
|
43
|
+
* threw as the `cause`.
|
|
44
|
+
*
|
|
45
|
+
* Match on `code` to tell failures apart, such as `auth/user-not-found` or
|
|
46
|
+
* `auth/id-token-revoked`.
|
|
47
|
+
*
|
|
48
|
+
* @stability unstable
|
|
49
|
+
* @category errors
|
|
50
|
+
* @since 0.1.0
|
|
51
|
+
*/
|
|
52
|
+
var AuthError = class extends Schema.TaggedError()("AuthError", {
|
|
53
|
+
message: Schema.String,
|
|
54
|
+
/** The `service/string-code` the Admin SDK reported, such as `auth/user-not-found`. */
|
|
55
|
+
code: Schema.optional(Schema.String),
|
|
56
|
+
cause: Schema.optional(Schema.Defect())
|
|
57
|
+
}) {};
|
|
58
|
+
const authError = (message) => (cause) => new AuthError({
|
|
59
|
+
message,
|
|
60
|
+
code: cause instanceof FirebaseError ? cause.code : void 0,
|
|
61
|
+
cause
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* Service key for Firebase Authentication.
|
|
65
|
+
*
|
|
66
|
+
* @stability unstable
|
|
67
|
+
* @category services
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
*/
|
|
70
|
+
const Auth = Context.Service("@visiolab/effect-firebase-admin/auth/Auth");
|
|
71
|
+
/**
|
|
72
|
+
* Builds {@link Auth} on the {@link App.App} in context.
|
|
73
|
+
*
|
|
74
|
+
* **When to use**
|
|
75
|
+
*
|
|
76
|
+
* Use to build the service inside an effect of your own. Most programs provide
|
|
77
|
+
* it with {@link layer} instead.
|
|
78
|
+
*
|
|
79
|
+
* **Details**
|
|
80
|
+
*
|
|
81
|
+
* Building the service cannot fail. `getAuth` only throws for an app that was
|
|
82
|
+
* already deleted or is not an app at all. Both are wiring mistakes, so they
|
|
83
|
+
* are defects, and {@link AuthError} only ever means that a call failed.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link layer} for the same as a layer
|
|
86
|
+
*
|
|
87
|
+
* @stability unstable
|
|
88
|
+
* @category constructors
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
const make = Effect.gen(function* () {
|
|
92
|
+
const app = yield* App;
|
|
93
|
+
const auth = Admin.getAuth(app);
|
|
94
|
+
const call = (span, message, f) => Effect.tryPromise({
|
|
95
|
+
try: () => Promise.resolve(f(auth)),
|
|
96
|
+
catch: authError(message)
|
|
97
|
+
}).pipe(Effect.withSpan(`Auth.${span}`));
|
|
98
|
+
return Auth.of({
|
|
99
|
+
use: (f) => call("use", "A Firebase Authentication call failed", f),
|
|
100
|
+
verifyIdToken: (idToken, checkRevoked) => call("verifyIdToken", "Failed to verify the ID token", (auth) => auth.verifyIdToken(idToken, checkRevoked)),
|
|
101
|
+
createCustomToken: (uid, developerClaims) => call("createCustomToken", `Failed to create a custom token for "${uid}"`, (auth) => auth.createCustomToken(uid, developerClaims)),
|
|
102
|
+
getUser: (uid) => call("getUser", `Failed to get the user "${uid}"`, (auth) => auth.getUser(uid)),
|
|
103
|
+
getUserByEmail: (email) => call("getUserByEmail", `Failed to get the user with the email "${email}"`, (auth) => auth.getUserByEmail(email)),
|
|
104
|
+
createUser: (properties) => call("createUser", "Failed to create the user", (auth) => auth.createUser(properties)),
|
|
105
|
+
updateUser: (uid, properties) => call("updateUser", `Failed to update the user "${uid}"`, (auth) => auth.updateUser(uid, properties)),
|
|
106
|
+
deleteUser: (uid) => call("deleteUser", `Failed to delete the user "${uid}"`, (auth) => auth.deleteUser(uid))
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
/**
|
|
110
|
+
* A layer that provides {@link Auth} for the {@link App.App} in context.
|
|
111
|
+
*
|
|
112
|
+
* @example Providing Auth
|
|
113
|
+
* ```ts
|
|
114
|
+
* import { Layer } from "effect";
|
|
115
|
+
* import { App } from "@visiolab/effect-firebase-admin/app";
|
|
116
|
+
* import { Auth } from "@visiolab/effect-firebase-admin/auth";
|
|
117
|
+
*
|
|
118
|
+
* const AuthLive = Auth.layer.pipe(Layer.provide(App.layer()));
|
|
119
|
+
* ```
|
|
120
|
+
*
|
|
121
|
+
* @see {@link make} for why building the service cannot fail
|
|
122
|
+
* @see {@link App.layer} for the app it needs
|
|
123
|
+
*
|
|
124
|
+
* @stability unstable
|
|
125
|
+
* @category layers
|
|
126
|
+
* @since 0.1.0
|
|
127
|
+
*/
|
|
128
|
+
const layer = Layer.effect(Auth, make);
|
|
129
|
+
export { Auth, AuthError, Auth_exports, layer, make };
|
|
130
|
+
|
|
131
|
+
//# sourceMappingURL=Auth.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Auth.mjs","names":["App.App"],"sources":["../../src/auth/Auth.ts"],"sourcesContent":["/**\n * Firebase Authentication on the Admin SDK, as an Effect service.\n *\n * {@link Auth} wraps the calls server code uses most, such as verifying ID\n * tokens and managing users. Every call fails with an {@link AuthError}, and\n * {@link Auth.use} reaches the rest of the Admin SDK.\n *\n * @example Verifying an ID token\n * ```ts\n * import { Effect, Layer } from \"effect\";\n * import { App } from \"@visiolab/effect-firebase-admin/app\";\n * import { Auth } from \"@visiolab/effect-firebase-admin/auth\";\n *\n * const uidOf = (idToken: string) =>\n * Effect.gen(function* () {\n * const auth = yield* Auth.Auth;\n * const token = yield* auth.verifyIdToken(idToken, true);\n * return token.uid;\n * });\n *\n * const AuthLive = Auth.layer.pipe(Layer.provide(App.layer()));\n *\n * uidOf(\"<id token>\").pipe(Effect.provide(AuthLive));\n * ```\n *\n * @stability unstable\n * @since 0.1.0\n */\nimport { Context, Effect, Layer, Schema } from \"effect\";\nimport { FirebaseError } from \"firebase-admin/app\";\nimport * as Admin from \"firebase-admin/auth\";\nimport * as App from \"../app/App.ts\";\n\n/**\n * Fails a call on {@link Auth} when the Admin SDK rejects it, with what it\n * threw as the `cause`.\n *\n * Match on `code` to tell failures apart, such as `auth/user-not-found` or\n * `auth/id-token-revoked`.\n *\n * @stability unstable\n * @category errors\n * @since 0.1.0\n */\nexport class AuthError extends Schema.TaggedError<AuthError, { readonly brand: unique symbol }>()(\n \"AuthError\",\n {\n message: Schema.String,\n /** The `service/string-code` the Admin SDK reported, such as `auth/user-not-found`. */\n code: Schema.optional(Schema.String),\n cause: Schema.optional(Schema.Defect()),\n },\n) {}\n\nconst authError = (message: string) => (cause: unknown) =>\n new AuthError({\n message,\n code: cause instanceof FirebaseError ? cause.code : undefined,\n cause,\n });\n\n/**\n * Firebase Authentication for a single app.\n *\n * Each call is the Admin SDK's method of the same name, with the same\n * arguments, failing with an {@link AuthError} and traced as a span named\n * `Auth.<method>`. Use {@link Auth.use} for anything else the Admin SDK offers.\n *\n * The Admin SDK cannot abort a request in flight, so interrupting a call does\n * not stop it: the request still runs to completion.\n *\n * @stability unstable\n * @category models\n * @since 0.1.0\n */\nexport interface Auth {\n /**\n * Runs `f` against the Admin SDK's own `Auth`, failing with an\n * {@link AuthError} when it throws or rejects.\n *\n * **When to use**\n *\n * Use for the Admin SDK calls this service does not wrap, such as\n * `setCustomUserClaims` or `listUsers`. Prefer the wrapped methods where one\n * exists: they name the failure in the error's message.\n *\n * @example Setting custom claims\n * ```ts\n * import { Effect } from \"effect\";\n * import { Auth } from \"@visiolab/effect-firebase-admin/auth\";\n *\n * const makeAdmin = (uid: string) =>\n * Effect.gen(function* () {\n * const auth = yield* Auth.Auth;\n * yield* auth.use((sdk) => sdk.setCustomUserClaims(uid, { admin: true }));\n * });\n * ```\n */\n readonly use: <A>(f: (auth: Admin.Auth) => PromiseLike<A> | A) => Effect.Effect<A, AuthError>;\n /**\n * Verifies a Firebase ID token and decodes it.\n *\n * With `checkRevoked`, it also fails for a token whose session was revoked or\n * whose user is disabled, at the cost of a request to the Auth backend.\n *\n * @see {@link Auth.createCustomToken} for minting a token a client signs in with\n */\n readonly verifyIdToken: (\n idToken: string,\n checkRevoked?: boolean,\n ) => Effect.Effect<Admin.DecodedIdToken, AuthError>;\n /**\n * Mints a custom token for `uid`, which a client signs in with through\n * `signInWithCustomToken`.\n *\n * `developerClaims` end up in the ID tokens of that session.\n *\n * @see {@link Auth.verifyIdToken} for checking the ID token a client sends back\n */\n readonly createCustomToken: (\n uid: string,\n developerClaims?: object,\n ) => Effect.Effect<string, AuthError>;\n /**\n * Reads the user with `uid`.\n *\n * Fails with `auth/user-not-found` when there is none.\n *\n * @see {@link Auth.getUserByEmail} for looking a user up by email\n */\n readonly getUser: (uid: string) => Effect.Effect<Admin.UserRecord, AuthError>;\n /**\n * Reads the user with `email`.\n *\n * Fails with `auth/user-not-found` when there is none.\n *\n * @see {@link Auth.getUser} for looking a user up by uid\n */\n readonly getUserByEmail: (email: string) => Effect.Effect<Admin.UserRecord, AuthError>;\n /**\n * Creates a user, under the `uid` in `properties` or one the Auth backend\n * picks.\n *\n * @see {@link Auth.updateUser} for changing a user that exists\n */\n readonly createUser: (\n properties: Admin.CreateRequest,\n ) => Effect.Effect<Admin.UserRecord, AuthError>;\n /**\n * Changes the properties of the user with `uid`.\n *\n * @see {@link Auth.createUser} for creating one\n */\n readonly updateUser: (\n uid: string,\n properties: Admin.UpdateRequest,\n ) => Effect.Effect<Admin.UserRecord, AuthError>;\n /**\n * Deletes the user with `uid`.\n */\n readonly deleteUser: (uid: string) => Effect.Effect<void, AuthError>;\n}\n\n/**\n * Service key for Firebase Authentication.\n *\n * @stability unstable\n * @category services\n * @since 0.1.0\n */\nexport const Auth = Context.Service<Auth>(\"@visiolab/effect-firebase-admin/auth/Auth\");\n\n/**\n * Builds {@link Auth} on the {@link App.App} in context.\n *\n * **When to use**\n *\n * Use to build the service inside an effect of your own. Most programs provide\n * it with {@link layer} instead.\n *\n * **Details**\n *\n * Building the service cannot fail. `getAuth` only throws for an app that was\n * already deleted or is not an app at all. Both are wiring mistakes, so they\n * are defects, and {@link AuthError} only ever means that a call failed.\n *\n * @see {@link layer} for the same as a layer\n *\n * @stability unstable\n * @category constructors\n * @since 0.1.0\n */\nexport const make = Effect.gen(function* () {\n const app = yield* App.App;\n\n // `getAuth` memoizes the service on the app itself, so there is nothing to\n // release here.\n const auth = Admin.getAuth(app);\n\n const call = <A>(\n span: string,\n message: string,\n f: (auth: Admin.Auth) => PromiseLike<A> | A,\n ): Effect.Effect<A, AuthError> =>\n Effect.tryPromise({\n // `Promise.resolve` covers the calls that hand back a plain value, and\n // keeps a synchronous throw on the `catch` path rather than the die one.\n try: () => Promise.resolve(f(auth)),\n catch: authError(message),\n }).pipe(Effect.withSpan(`Auth.${span}`));\n\n return Auth.of({\n use: (f) => call(\"use\", \"A Firebase Authentication call failed\", f),\n verifyIdToken: (idToken, checkRevoked) =>\n call(\"verifyIdToken\", \"Failed to verify the ID token\", (auth) =>\n auth.verifyIdToken(idToken, checkRevoked),\n ),\n createCustomToken: (uid, developerClaims) =>\n call(\"createCustomToken\", `Failed to create a custom token for \"${uid}\"`, (auth) =>\n auth.createCustomToken(uid, developerClaims),\n ),\n getUser: (uid) =>\n call(\"getUser\", `Failed to get the user \"${uid}\"`, (auth) => auth.getUser(uid)),\n getUserByEmail: (email) =>\n call(\"getUserByEmail\", `Failed to get the user with the email \"${email}\"`, (auth) =>\n auth.getUserByEmail(email),\n ),\n createUser: (properties) =>\n call(\"createUser\", \"Failed to create the user\", (auth) => auth.createUser(properties)),\n updateUser: (uid, properties) =>\n call(\"updateUser\", `Failed to update the user \"${uid}\"`, (auth) =>\n auth.updateUser(uid, properties),\n ),\n deleteUser: (uid) =>\n call(\"deleteUser\", `Failed to delete the user \"${uid}\"`, (auth) => auth.deleteUser(uid)),\n });\n});\n\n/**\n * A layer that provides {@link Auth} for the {@link App.App} in context.\n *\n * @example Providing Auth\n * ```ts\n * import { Layer } from \"effect\";\n * import { App } from \"@visiolab/effect-firebase-admin/app\";\n * import { Auth } from \"@visiolab/effect-firebase-admin/auth\";\n *\n * const AuthLive = Auth.layer.pipe(Layer.provide(App.layer()));\n * ```\n *\n * @see {@link make} for why building the service cannot fail\n * @see {@link App.layer} for the app it needs\n *\n * @stability unstable\n * @category layers\n * @since 0.1.0\n */\nexport const layer: Layer.Layer<Auth, never, App.App> = Layer.effect(Auth, make);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4CA,IAAa,YAAb,cAA+B,OAAO,YAA0D,CAAC,CAC/F,aACA;CACE,SAAS,OAAO;;CAEhB,MAAM,OAAO,SAAS,OAAO,MAAM;CACnC,OAAO,OAAO,SAAS,OAAO,OAAO,CAAC;AACxC,CACF,CAAC,CAAC,CAAC;AAEH,MAAM,aAAa,aAAqB,UACtC,IAAI,UAAU;CACZ;CACA,MAAM,iBAAiB,gBAAgB,MAAM,OAAO,KAAA;CACpD;AACF,CAAC;;;;;;;;AA+GH,MAAa,OAAO,QAAQ,QAAc,2CAA2C;;;;;;;;;;;;;;;;;;;;;AAsBrF,MAAa,OAAO,OAAO,IAAI,aAAa;CAC1C,MAAM,MAAM,OAAOA;CAInB,MAAM,OAAO,MAAM,QAAQ,GAAG;CAE9B,MAAM,QACJ,MACA,SACA,MAEA,OAAO,WAAW;EAGhB,WAAW,QAAQ,QAAQ,EAAE,IAAI,CAAC;EAClC,OAAO,UAAU,OAAO;CAC1B,CAAC,CAAC,CAAC,KAAK,OAAO,SAAS,QAAQ,MAAM,CAAC;CAEzC,OAAO,KAAK,GAAG;EACb,MAAM,MAAM,KAAK,OAAO,yCAAyC,CAAC;EAClE,gBAAgB,SAAS,iBACvB,KAAK,iBAAiB,kCAAkC,SACtD,KAAK,cAAc,SAAS,YAAY,CAC1C;EACF,oBAAoB,KAAK,oBACvB,KAAK,qBAAqB,wCAAwC,IAAI,KAAK,SACzE,KAAK,kBAAkB,KAAK,eAAe,CAC7C;EACF,UAAU,QACR,KAAK,WAAW,2BAA2B,IAAI,KAAK,SAAS,KAAK,QAAQ,GAAG,CAAC;EAChF,iBAAiB,UACf,KAAK,kBAAkB,0CAA0C,MAAM,KAAK,SAC1E,KAAK,eAAe,KAAK,CAC3B;EACF,aAAa,eACX,KAAK,cAAc,8BAA8B,SAAS,KAAK,WAAW,UAAU,CAAC;EACvF,aAAa,KAAK,eAChB,KAAK,cAAc,8BAA8B,IAAI,KAAK,SACxD,KAAK,WAAW,KAAK,UAAU,CACjC;EACF,aAAa,QACX,KAAK,cAAc,8BAA8B,IAAI,KAAK,SAAS,KAAK,WAAW,GAAG,CAAC;CAC3F,CAAC;AACH,CAAC;;;;;;;;;;;;;;;;;;;;AAqBD,MAAa,QAA2C,MAAM,OAAO,MAAM,IAAI"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Auth_exports as Auth } from "./Auth.mjs";
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import { App } from "../app/App.mjs";
|
|
2
|
+
import { Context, Effect, Layer } from "effect";
|
|
3
|
+
import { Firestore, Transaction, TransactionBase, With } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
4
|
+
import * as Admin from "firebase-admin/firestore";
|
|
5
|
+
declare namespace AdminFirestore_d_exports {
|
|
6
|
+
export { AdminFirestore, AdminTransaction, Options, layer, make };
|
|
7
|
+
}
|
|
8
|
+
declare const TypeId = "~@visiolab/effect-firebase-admin/firestore/AdminFirestore";
|
|
9
|
+
declare const TransactionTypeId = "~@visiolab/effect-firebase-admin/firestore/AdminFirestore/AdminTransaction";
|
|
10
|
+
/**
|
|
11
|
+
* The portable {@link Firestore}, plus what only the Admin SDK can do.
|
|
12
|
+
*
|
|
13
|
+
* **When to use**
|
|
14
|
+
*
|
|
15
|
+
* Ask for it where code needs the Admin SDK: {@link AdminTransaction} reads of
|
|
16
|
+
* many documents, or the SDK itself through {@link AdminFirestore.instance}.
|
|
17
|
+
* Everywhere else ask for {@link Firestore}, so the code also runs on the
|
|
18
|
+
* client SDK.
|
|
19
|
+
*
|
|
20
|
+
* **Details**
|
|
21
|
+
*
|
|
22
|
+
* The service its key holds is also a {@link Firestore}, so it can be handed to
|
|
23
|
+
* portable code as it is. The type itself only extends {@link Firestore.With},
|
|
24
|
+
* so providing a {@link Firestore} alone, such as an in-memory fake, does not
|
|
25
|
+
* satisfy code that asks for it. A {@link Firestore.With.runTransaction} body
|
|
26
|
+
* finds its transaction both
|
|
27
|
+
* as {@link AdminTransaction} and as the portable
|
|
28
|
+
* {@link Firestore.Transaction}. They are the same transaction, so portable
|
|
29
|
+
* helpers and Admin-only ones can run in the same body.
|
|
30
|
+
*
|
|
31
|
+
* The Admin SDK cannot abort a request in flight, so interrupting a call does
|
|
32
|
+
* not stop it: the request still runs to completion.
|
|
33
|
+
*
|
|
34
|
+
* @see {@link Firestore.With} for each read and write it offers
|
|
35
|
+
*
|
|
36
|
+
* @stability unstable
|
|
37
|
+
* @category models
|
|
38
|
+
* @since 0.2.0
|
|
39
|
+
*/
|
|
40
|
+
export interface AdminFirestore extends With<never, never, {}, AdminTransaction> {
|
|
41
|
+
readonly [TypeId]: typeof TypeId;
|
|
42
|
+
/**
|
|
43
|
+
* The Admin SDK's own `Firestore`, for the database the service was opened
|
|
44
|
+
* on.
|
|
45
|
+
*
|
|
46
|
+
* **When to use**
|
|
47
|
+
*
|
|
48
|
+
* Use for what this service does not wrap, such as queries, batched writes
|
|
49
|
+
* or `recursiveDelete`. Prefer the service's own methods where one exists.
|
|
50
|
+
*
|
|
51
|
+
* **Details**
|
|
52
|
+
*
|
|
53
|
+
* Calls through it skip the collection's model, take and return the SDK's
|
|
54
|
+
* own values, and throw the SDK's own errors. To write a model through it,
|
|
55
|
+
* encode with {@link FirestoreValue.toCodecFirestore} and map with
|
|
56
|
+
* {@link AdminFirestoreValue.toAdmin}.
|
|
57
|
+
*
|
|
58
|
+
* @see {@link AdminFirestoreValue} for mapping between the SDK's values and Firestore Values
|
|
59
|
+
*/
|
|
60
|
+
readonly instance: Admin.Firestore;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* A {@link Firestore.Transaction} that can also read every document in a
|
|
64
|
+
* collection or a Collection Group, which only the Admin SDK's transactions
|
|
65
|
+
* can.
|
|
66
|
+
*
|
|
67
|
+
* **When to use**
|
|
68
|
+
*
|
|
69
|
+
* Ask for it in a transaction body that reads many documents. A body that only
|
|
70
|
+
* reads single documents should ask for the portable
|
|
71
|
+
* {@link Firestore.Transaction}, so it also runs on the client SDK.
|
|
72
|
+
*
|
|
73
|
+
* **Details**
|
|
74
|
+
*
|
|
75
|
+
* A body run through {@link AdminFirestore} finds it next to
|
|
76
|
+
* {@link Firestore.Transaction}; they are the same transaction. The type
|
|
77
|
+
* extends {@link Firestore.TransactionBase}, not {@link Firestore.Transaction},
|
|
78
|
+
* and its key holds an `AdminTransaction & Transaction`. A body that asks for
|
|
79
|
+
* it and runs
|
|
80
|
+
* through the portable {@link Firestore} still needs it provided, so the
|
|
81
|
+
* compiler catches Admin-only code handed to portable code.
|
|
82
|
+
*
|
|
83
|
+
* The same rules hold as for {@link Firestore.Transaction}: a read of many is a
|
|
84
|
+
* read, so it comes before every write.
|
|
85
|
+
*
|
|
86
|
+
* @example Reading a collection in a transaction
|
|
87
|
+
* ```ts
|
|
88
|
+
* import { Effect, Schema } from "effect";
|
|
89
|
+
* import { Collection, FirestoreModel } from "@visiolab/effect-firebase/firestore";
|
|
90
|
+
* import { AdminFirestore } from "@visiolab/effect-firebase-admin/firestore";
|
|
91
|
+
*
|
|
92
|
+
* class Seat extends FirestoreModel.Class<Seat>("Seat")({
|
|
93
|
+
* taken: Schema.Boolean,
|
|
94
|
+
* }) {}
|
|
95
|
+
*
|
|
96
|
+
* const Seats = Collection.make("seats", Seat);
|
|
97
|
+
*
|
|
98
|
+
* const takeAnySeat = Effect.gen(function* () {
|
|
99
|
+
* const firestore = yield* AdminFirestore.AdminFirestore;
|
|
100
|
+
* return yield* firestore.runTransaction(
|
|
101
|
+
* Effect.gen(function* () {
|
|
102
|
+
* const tx = yield* AdminFirestore.AdminTransaction;
|
|
103
|
+
* const { docs } = yield* tx.getDocs(Seats.collection());
|
|
104
|
+
* for (const seat of docs) {
|
|
105
|
+
* if (!(yield* seat.data).taken) {
|
|
106
|
+
* yield* tx.updateDoc(seat.ref, { taken: true });
|
|
107
|
+
* return seat.id;
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
* return undefined;
|
|
111
|
+
* }),
|
|
112
|
+
* );
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*
|
|
116
|
+
* @see {@link Firestore.Transaction} for the portable transaction, which reads one document at a time
|
|
117
|
+
*
|
|
118
|
+
* @stability unstable
|
|
119
|
+
* @category models
|
|
120
|
+
* @since 0.2.0
|
|
121
|
+
*/
|
|
122
|
+
export interface AdminTransaction extends TransactionBase {
|
|
123
|
+
readonly [TransactionTypeId]: typeof TransactionTypeId;
|
|
124
|
+
/**
|
|
125
|
+
* Reads every document in a collection or a Collection Group as part of the
|
|
126
|
+
* transaction, as {@link Firestore.With.getDocs} does outside one.
|
|
127
|
+
*
|
|
128
|
+
* Every document it returns is locked for the rest of the transaction, so
|
|
129
|
+
* another write to one of them makes the transaction run again. A group
|
|
130
|
+
* read that fails with an {@link Firestore.UndefinedCollectionError} fails
|
|
131
|
+
* the body, which rolls the transaction back without running it again.
|
|
132
|
+
*/
|
|
133
|
+
readonly getDocs: Firestore["getDocs"];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Service key for {@link AdminTransaction}. The transaction it holds is a
|
|
137
|
+
* {@link Firestore.Transaction} too.
|
|
138
|
+
*
|
|
139
|
+
* @stability unstable
|
|
140
|
+
* @category services
|
|
141
|
+
* @since 0.2.0
|
|
142
|
+
*/
|
|
143
|
+
export declare const AdminTransaction: Context.Service<AdminTransaction, AdminTransaction & Transaction>;
|
|
144
|
+
/**
|
|
145
|
+
* Service key for {@link AdminFirestore}.
|
|
146
|
+
*
|
|
147
|
+
* @see {@link Firestore} for the portable key, which {@link layer} provides the same service under
|
|
148
|
+
*
|
|
149
|
+
* @stability unstable
|
|
150
|
+
* @category services
|
|
151
|
+
* @since 0.2.0
|
|
152
|
+
*/
|
|
153
|
+
export declare const AdminFirestore: Context.Service<AdminFirestore, AdminFirestore & Firestore>;
|
|
154
|
+
/**
|
|
155
|
+
* How {@link layer} opens a database. Both are fixed once the database is open.
|
|
156
|
+
*
|
|
157
|
+
* There is no emulator option. The Admin SDK reads the emulator from the
|
|
158
|
+
* `FIRESTORE_EMULATOR_HOST` environment variable, which must be set before the
|
|
159
|
+
* database is opened and applies to every app in the process.
|
|
160
|
+
*
|
|
161
|
+
* @see {@link ClientFirestore.Options} for the client SDK's, which take the emulator per database
|
|
162
|
+
*
|
|
163
|
+
* @stability unstable
|
|
164
|
+
* @category models
|
|
165
|
+
* @since 0.2.0
|
|
166
|
+
*/
|
|
167
|
+
export interface Options {
|
|
168
|
+
/**
|
|
169
|
+
* The database to open, where the project has more than its default one.
|
|
170
|
+
* Leave it out for the default database.
|
|
171
|
+
*/
|
|
172
|
+
readonly databaseId?: string | undefined;
|
|
173
|
+
/**
|
|
174
|
+
* Talk HTTP/1.1 instead of gRPC until something needs gRPC.
|
|
175
|
+
*
|
|
176
|
+
* Use it where a process handles a request or two and exits, such as a
|
|
177
|
+
* function: it saves loading the gRPC libraries and opening a channel.
|
|
178
|
+
* Listening is the one thing that needs gRPC; the first listen loads it and
|
|
179
|
+
* the SDK stays on it.
|
|
180
|
+
*/
|
|
181
|
+
readonly preferRest?: boolean | undefined;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Builds {@link AdminFirestore} on the {@link App.App} in context.
|
|
185
|
+
*
|
|
186
|
+
* **When to use**
|
|
187
|
+
*
|
|
188
|
+
* Use to build the service inside an effect of your own. Most programs provide
|
|
189
|
+
* it with {@link layer} instead, which also provides it as {@link Firestore}.
|
|
190
|
+
*
|
|
191
|
+
* **Details**
|
|
192
|
+
*
|
|
193
|
+
* Building the service cannot fail. Opening a database only throws for an app
|
|
194
|
+
* that was already deleted, something that is not an app, or a database already
|
|
195
|
+
* opened with other settings. All three are wiring mistakes, so they are
|
|
196
|
+
* defects, and a {@link Firestore.FirestoreError} only ever means that a call
|
|
197
|
+
* failed.
|
|
198
|
+
*
|
|
199
|
+
* @see {@link layer} for the same as a layer
|
|
200
|
+
*
|
|
201
|
+
* @stability unstable
|
|
202
|
+
* @category constructors
|
|
203
|
+
* @since 0.2.0
|
|
204
|
+
*/
|
|
205
|
+
export declare const make: (options?: Options) => Effect.Effect<AdminFirestore & Firestore, never, App>;
|
|
206
|
+
/**
|
|
207
|
+
* A layer that provides {@link AdminFirestore} for the {@link App.App} in
|
|
208
|
+
* context, and the same service as the portable {@link Firestore}.
|
|
209
|
+
*
|
|
210
|
+
* **When to use**
|
|
211
|
+
*
|
|
212
|
+
* Use on a server, or anywhere the Admin SDK runs. In a browser, use
|
|
213
|
+
* {@link ClientFirestore.layer} instead.
|
|
214
|
+
*
|
|
215
|
+
* **Details**
|
|
216
|
+
*
|
|
217
|
+
* With no options it opens the project's default database with the SDK's
|
|
218
|
+
* defaults.
|
|
219
|
+
*
|
|
220
|
+
* @example Providing Firestore against the emulator
|
|
221
|
+
* ```ts
|
|
222
|
+
* import { Layer } from "effect";
|
|
223
|
+
* import { App } from "@visiolab/effect-firebase-admin/app";
|
|
224
|
+
* import { AdminFirestore } from "@visiolab/effect-firebase-admin/firestore";
|
|
225
|
+
*
|
|
226
|
+
* // The Admin SDK reads FIRESTORE_EMULATOR_HOST, such as "127.0.0.1:8080".
|
|
227
|
+
* const FirestoreLive = AdminFirestore.layer({ preferRest: true }).pipe(
|
|
228
|
+
* Layer.provide(App.layer({ projectId: "demo-project" })),
|
|
229
|
+
* );
|
|
230
|
+
* ```
|
|
231
|
+
*
|
|
232
|
+
* @see {@link make} for why building the service cannot fail
|
|
233
|
+
* @see {@link ClientFirestore.layer} for the client SDK's layer, for browsers
|
|
234
|
+
*
|
|
235
|
+
* @stability unstable
|
|
236
|
+
* @category layers
|
|
237
|
+
* @since 0.2.0
|
|
238
|
+
*/
|
|
239
|
+
export declare const layer: (options?: Options) => Layer.Layer<AdminFirestore | Firestore, never, App>;
|
|
240
|
+
export { AdminFirestore_d_exports };
|
|
241
|
+
//# sourceMappingURL=AdminFirestore.d.mts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
|
|
2
|
+
import { fromDatabase, openDatabase } from "./internal/firestore.mjs";
|
|
3
|
+
import { Context, Effect, Layer } from "effect";
|
|
4
|
+
import { Firestore } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
5
|
+
// src/firestore/AdminFirestore.ts
|
|
6
|
+
/**
|
|
7
|
+
* Firestore on the Firebase Admin SDK, for servers.
|
|
8
|
+
*
|
|
9
|
+
* {@link layer} provides one service under two keys: the portable
|
|
10
|
+
* {@link Firestore}, which code that runs on either SDK asks for, and
|
|
11
|
+
* {@link AdminFirestore}, which adds what only the Admin SDK can do. Both reach
|
|
12
|
+
* the same database.
|
|
13
|
+
*
|
|
14
|
+
* @example Reading and writing a document
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { Effect, Layer, Schema } from "effect";
|
|
17
|
+
* import { Collection, Firestore, FirestoreModel } from "@visiolab/effect-firebase/firestore";
|
|
18
|
+
* import { App } from "@visiolab/effect-firebase-admin/app";
|
|
19
|
+
* import { AdminFirestore } from "@visiolab/effect-firebase-admin/firestore";
|
|
20
|
+
*
|
|
21
|
+
* class Post extends FirestoreModel.Class<Post>("Post")({
|
|
22
|
+
* title: Schema.String,
|
|
23
|
+
* }) {}
|
|
24
|
+
*
|
|
25
|
+
* const Posts = Collection.make("posts", Post);
|
|
26
|
+
* const hello = Posts.doc(Posts.id.make("hello"));
|
|
27
|
+
*
|
|
28
|
+
* const program = Effect.gen(function* () {
|
|
29
|
+
* const firestore = yield* Firestore.Firestore;
|
|
30
|
+
* yield* firestore.setDoc(hello, { title: "Hello" });
|
|
31
|
+
* return yield* firestore.getDoc(hello);
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* const FirestoreLive = AdminFirestore.layer().pipe(Layer.provide(App.layer()));
|
|
35
|
+
*
|
|
36
|
+
* program.pipe(Effect.provide(FirestoreLive));
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @see {@link ClientFirestore} for the same service on the client SDK, for browsers
|
|
40
|
+
*
|
|
41
|
+
* @stability unstable
|
|
42
|
+
* @since 0.2.0
|
|
43
|
+
*/
|
|
44
|
+
var AdminFirestore_exports = /* @__PURE__ */ __exportAll({
|
|
45
|
+
AdminFirestore: () => AdminFirestore,
|
|
46
|
+
AdminTransaction: () => AdminTransaction,
|
|
47
|
+
layer: () => layer,
|
|
48
|
+
make: () => make
|
|
49
|
+
});
|
|
50
|
+
/**
|
|
51
|
+
* Service key for {@link AdminTransaction}. The transaction it holds is a
|
|
52
|
+
* {@link Firestore.Transaction} too.
|
|
53
|
+
*
|
|
54
|
+
* @stability unstable
|
|
55
|
+
* @category services
|
|
56
|
+
* @since 0.2.0
|
|
57
|
+
*/
|
|
58
|
+
const AdminTransaction = Context.Service("@visiolab/effect-firebase-admin/firestore/AdminFirestore/AdminTransaction");
|
|
59
|
+
/**
|
|
60
|
+
* Service key for {@link AdminFirestore}.
|
|
61
|
+
*
|
|
62
|
+
* @see {@link Firestore} for the portable key, which {@link layer} provides the same service under
|
|
63
|
+
*
|
|
64
|
+
* @stability unstable
|
|
65
|
+
* @category services
|
|
66
|
+
* @since 0.2.0
|
|
67
|
+
*/
|
|
68
|
+
const AdminFirestore = Context.Service("@visiolab/effect-firebase-admin/firestore/AdminFirestore");
|
|
69
|
+
/**
|
|
70
|
+
* Builds {@link AdminFirestore} on the {@link App.App} in context.
|
|
71
|
+
*
|
|
72
|
+
* **When to use**
|
|
73
|
+
*
|
|
74
|
+
* Use to build the service inside an effect of your own. Most programs provide
|
|
75
|
+
* it with {@link layer} instead, which also provides it as {@link Firestore}.
|
|
76
|
+
*
|
|
77
|
+
* **Details**
|
|
78
|
+
*
|
|
79
|
+
* Building the service cannot fail. Opening a database only throws for an app
|
|
80
|
+
* that was already deleted, something that is not an app, or a database already
|
|
81
|
+
* opened with other settings. All three are wiring mistakes, so they are
|
|
82
|
+
* defects, and a {@link Firestore.FirestoreError} only ever means that a call
|
|
83
|
+
* failed.
|
|
84
|
+
*
|
|
85
|
+
* @see {@link layer} for the same as a layer
|
|
86
|
+
*
|
|
87
|
+
* @stability unstable
|
|
88
|
+
* @category constructors
|
|
89
|
+
* @since 0.2.0
|
|
90
|
+
*/
|
|
91
|
+
const make = Effect.fn("AdminFirestore.make")(function* (options) {
|
|
92
|
+
const firestore = yield* openDatabase(options);
|
|
93
|
+
return fromDatabase(firestore, AdminTransaction);
|
|
94
|
+
});
|
|
95
|
+
/** The one service, under both its own tag and the portable one. */
|
|
96
|
+
const both = (service) => Context.make(AdminFirestore, service).pipe(Context.add(Firestore, service));
|
|
97
|
+
/**
|
|
98
|
+
* A layer that provides {@link AdminFirestore} for the {@link App.App} in
|
|
99
|
+
* context, and the same service as the portable {@link Firestore}.
|
|
100
|
+
*
|
|
101
|
+
* **When to use**
|
|
102
|
+
*
|
|
103
|
+
* Use on a server, or anywhere the Admin SDK runs. In a browser, use
|
|
104
|
+
* {@link ClientFirestore.layer} instead.
|
|
105
|
+
*
|
|
106
|
+
* **Details**
|
|
107
|
+
*
|
|
108
|
+
* With no options it opens the project's default database with the SDK's
|
|
109
|
+
* defaults.
|
|
110
|
+
*
|
|
111
|
+
* @example Providing Firestore against the emulator
|
|
112
|
+
* ```ts
|
|
113
|
+
* import { Layer } from "effect";
|
|
114
|
+
* import { App } from "@visiolab/effect-firebase-admin/app";
|
|
115
|
+
* import { AdminFirestore } from "@visiolab/effect-firebase-admin/firestore";
|
|
116
|
+
*
|
|
117
|
+
* // The Admin SDK reads FIRESTORE_EMULATOR_HOST, such as "127.0.0.1:8080".
|
|
118
|
+
* const FirestoreLive = AdminFirestore.layer({ preferRest: true }).pipe(
|
|
119
|
+
* Layer.provide(App.layer({ projectId: "demo-project" })),
|
|
120
|
+
* );
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @see {@link make} for why building the service cannot fail
|
|
124
|
+
* @see {@link ClientFirestore.layer} for the client SDK's layer, for browsers
|
|
125
|
+
*
|
|
126
|
+
* @stability unstable
|
|
127
|
+
* @category layers
|
|
128
|
+
* @since 0.2.0
|
|
129
|
+
*/
|
|
130
|
+
const layer = (options) => Layer.effectContext(Effect.map(make(options), both));
|
|
131
|
+
export { AdminFirestore, AdminFirestore_exports, AdminTransaction, layer, make };
|
|
132
|
+
|
|
133
|
+
//# sourceMappingURL=AdminFirestore.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminFirestore.mjs","names":["internalFirestore.openDatabase","internalFirestore.fromDatabase"],"sources":["../../src/firestore/AdminFirestore.ts"],"sourcesContent":["/**\n * Firestore on the Firebase Admin SDK, for servers.\n *\n * {@link layer} provides one service under two keys: the portable\n * {@link Firestore}, which code that runs on either SDK asks for, and\n * {@link AdminFirestore}, which adds what only the Admin SDK can do. Both reach\n * the same database.\n *\n * @example Reading and writing a document\n * ```ts\n * import { Effect, Layer, Schema } from \"effect\";\n * import { Collection, Firestore, FirestoreModel } from \"@visiolab/effect-firebase/firestore\";\n * import { App } from \"@visiolab/effect-firebase-admin/app\";\n * import { AdminFirestore } from \"@visiolab/effect-firebase-admin/firestore\";\n *\n * class Post extends FirestoreModel.Class<Post>(\"Post\")({\n * title: Schema.String,\n * }) {}\n *\n * const Posts = Collection.make(\"posts\", Post);\n * const hello = Posts.doc(Posts.id.make(\"hello\"));\n *\n * const program = Effect.gen(function* () {\n * const firestore = yield* Firestore.Firestore;\n * yield* firestore.setDoc(hello, { title: \"Hello\" });\n * return yield* firestore.getDoc(hello);\n * });\n *\n * const FirestoreLive = AdminFirestore.layer().pipe(Layer.provide(App.layer()));\n *\n * program.pipe(Effect.provide(FirestoreLive));\n * ```\n *\n * @see {@link ClientFirestore} for the same service on the client SDK, for browsers\n *\n * @stability unstable\n * @since 0.2.0\n */\nimport { Context, Effect, Layer } from \"effect\";\nimport { Firestore, type With } from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport type { Transaction, TransactionBase } from \"@visiolab/effect-firebase/firestore/Firestore\";\nimport type * as Admin from \"firebase-admin/firestore\";\nimport type * as App from \"../app/App.ts\";\nimport * as internalFirestore from \"./internal/firestore.ts\";\n\nconst TypeId = internalFirestore.TypeId;\n\nconst TransactionTypeId = internalFirestore.TransactionTypeId;\n\n/**\n * The portable {@link Firestore}, plus what only the Admin SDK can do.\n *\n * **When to use**\n *\n * Ask for it where code needs the Admin SDK: {@link AdminTransaction} reads of\n * many documents, or the SDK itself through {@link AdminFirestore.instance}.\n * Everywhere else ask for {@link Firestore}, so the code also runs on the\n * client SDK.\n *\n * **Details**\n *\n * The service its key holds is also a {@link Firestore}, so it can be handed to\n * portable code as it is. The type itself only extends {@link Firestore.With},\n * so providing a {@link Firestore} alone, such as an in-memory fake, does not\n * satisfy code that asks for it. A {@link Firestore.With.runTransaction} body\n * finds its transaction both\n * as {@link AdminTransaction} and as the portable\n * {@link Firestore.Transaction}. They are the same transaction, so portable\n * helpers and Admin-only ones can run in the same body.\n *\n * The Admin SDK cannot abort a request in flight, so interrupting a call does\n * not stop it: the request still runs to completion.\n *\n * @see {@link Firestore.With} for each read and write it offers\n *\n * @stability unstable\n * @category models\n * @since 0.2.0\n */\nexport interface AdminFirestore extends With<never, never, {}, AdminTransaction> {\n readonly [TypeId]: typeof TypeId;\n\n /**\n * The Admin SDK's own `Firestore`, for the database the service was opened\n * on.\n *\n * **When to use**\n *\n * Use for what this service does not wrap, such as queries, batched writes\n * or `recursiveDelete`. Prefer the service's own methods where one exists.\n *\n * **Details**\n *\n * Calls through it skip the collection's model, take and return the SDK's\n * own values, and throw the SDK's own errors. To write a model through it,\n * encode with {@link FirestoreValue.toCodecFirestore} and map with\n * {@link AdminFirestoreValue.toAdmin}.\n *\n * @see {@link AdminFirestoreValue} for mapping between the SDK's values and Firestore Values\n */\n readonly instance: Admin.Firestore;\n}\n\n/**\n * A {@link Firestore.Transaction} that can also read every document in a\n * collection or a Collection Group, which only the Admin SDK's transactions\n * can.\n *\n * **When to use**\n *\n * Ask for it in a transaction body that reads many documents. A body that only\n * reads single documents should ask for the portable\n * {@link Firestore.Transaction}, so it also runs on the client SDK.\n *\n * **Details**\n *\n * A body run through {@link AdminFirestore} finds it next to\n * {@link Firestore.Transaction}; they are the same transaction. The type\n * extends {@link Firestore.TransactionBase}, not {@link Firestore.Transaction},\n * and its key holds an `AdminTransaction & Transaction`. A body that asks for\n * it and runs\n * through the portable {@link Firestore} still needs it provided, so the\n * compiler catches Admin-only code handed to portable code.\n *\n * The same rules hold as for {@link Firestore.Transaction}: a read of many is a\n * read, so it comes before every write.\n *\n * @example Reading a collection in a transaction\n * ```ts\n * import { Effect, Schema } from \"effect\";\n * import { Collection, FirestoreModel } from \"@visiolab/effect-firebase/firestore\";\n * import { AdminFirestore } from \"@visiolab/effect-firebase-admin/firestore\";\n *\n * class Seat extends FirestoreModel.Class<Seat>(\"Seat\")({\n * taken: Schema.Boolean,\n * }) {}\n *\n * const Seats = Collection.make(\"seats\", Seat);\n *\n * const takeAnySeat = Effect.gen(function* () {\n * const firestore = yield* AdminFirestore.AdminFirestore;\n * return yield* firestore.runTransaction(\n * Effect.gen(function* () {\n * const tx = yield* AdminFirestore.AdminTransaction;\n * const { docs } = yield* tx.getDocs(Seats.collection());\n * for (const seat of docs) {\n * if (!(yield* seat.data).taken) {\n * yield* tx.updateDoc(seat.ref, { taken: true });\n * return seat.id;\n * }\n * }\n * return undefined;\n * }),\n * );\n * });\n * ```\n *\n * @see {@link Firestore.Transaction} for the portable transaction, which reads one document at a time\n *\n * @stability unstable\n * @category models\n * @since 0.2.0\n */\nexport interface AdminTransaction extends TransactionBase {\n readonly [TransactionTypeId]: typeof TransactionTypeId;\n\n /**\n * Reads every document in a collection or a Collection Group as part of the\n * transaction, as {@link Firestore.With.getDocs} does outside one.\n *\n * Every document it returns is locked for the rest of the transaction, so\n * another write to one of them makes the transaction run again. A group\n * read that fails with an {@link Firestore.UndefinedCollectionError} fails\n * the body, which rolls the transaction back without running it again.\n */\n readonly getDocs: Firestore[\"getDocs\"];\n}\n\n/**\n * Service key for {@link AdminTransaction}. The transaction it holds is a\n * {@link Firestore.Transaction} too.\n *\n * @stability unstable\n * @category services\n * @since 0.2.0\n */\nexport const AdminTransaction = Context.Service<AdminTransaction, AdminTransaction & Transaction>(\n \"@visiolab/effect-firebase-admin/firestore/AdminFirestore/AdminTransaction\",\n);\n\n/**\n * Service key for {@link AdminFirestore}.\n *\n * @see {@link Firestore} for the portable key, which {@link layer} provides the same service under\n *\n * @stability unstable\n * @category services\n * @since 0.2.0\n */\nexport const AdminFirestore = Context.Service<AdminFirestore, AdminFirestore & Firestore>(\n \"@visiolab/effect-firebase-admin/firestore/AdminFirestore\",\n);\n\n/**\n * How {@link layer} opens a database. Both are fixed once the database is open.\n *\n * There is no emulator option. The Admin SDK reads the emulator from the\n * `FIRESTORE_EMULATOR_HOST` environment variable, which must be set before the\n * database is opened and applies to every app in the process.\n *\n * @see {@link ClientFirestore.Options} for the client SDK's, which take the emulator per database\n *\n * @stability unstable\n * @category models\n * @since 0.2.0\n */\nexport interface Options {\n /**\n * The database to open, where the project has more than its default one.\n * Leave it out for the default database.\n */\n readonly databaseId?: string | undefined;\n /**\n * Talk HTTP/1.1 instead of gRPC until something needs gRPC.\n *\n * Use it where a process handles a request or two and exits, such as a\n * function: it saves loading the gRPC libraries and opening a channel.\n * Listening is the one thing that needs gRPC; the first listen loads it and\n * the SDK stays on it.\n */\n readonly preferRest?: boolean | undefined;\n}\n\n/**\n * Builds {@link AdminFirestore} on the {@link App.App} in context.\n *\n * **When to use**\n *\n * Use to build the service inside an effect of your own. Most programs provide\n * it with {@link layer} instead, which also provides it as {@link Firestore}.\n *\n * **Details**\n *\n * Building the service cannot fail. Opening a database only throws for an app\n * that was already deleted, something that is not an app, or a database already\n * opened with other settings. All three are wiring mistakes, so they are\n * defects, and a {@link Firestore.FirestoreError} only ever means that a call\n * failed.\n *\n * @see {@link layer} for the same as a layer\n *\n * @stability unstable\n * @category constructors\n * @since 0.2.0\n */\nexport const make: (\n options?: Options,\n) => Effect.Effect<AdminFirestore & Firestore, never, App.App> = Effect.fn(\"AdminFirestore.make\")(\n function* (options?: Options) {\n const firestore = yield* internalFirestore.openDatabase(options);\n return internalFirestore.fromDatabase(firestore, AdminTransaction);\n },\n);\n\n/** The one service, under both its own tag and the portable one. */\nconst both = (service: AdminFirestore & Firestore) =>\n Context.make(AdminFirestore, service).pipe(Context.add(Firestore, service));\n\n/**\n * A layer that provides {@link AdminFirestore} for the {@link App.App} in\n * context, and the same service as the portable {@link Firestore}.\n *\n * **When to use**\n *\n * Use on a server, or anywhere the Admin SDK runs. In a browser, use\n * {@link ClientFirestore.layer} instead.\n *\n * **Details**\n *\n * With no options it opens the project's default database with the SDK's\n * defaults.\n *\n * @example Providing Firestore against the emulator\n * ```ts\n * import { Layer } from \"effect\";\n * import { App } from \"@visiolab/effect-firebase-admin/app\";\n * import { AdminFirestore } from \"@visiolab/effect-firebase-admin/firestore\";\n *\n * // The Admin SDK reads FIRESTORE_EMULATOR_HOST, such as \"127.0.0.1:8080\".\n * const FirestoreLive = AdminFirestore.layer({ preferRest: true }).pipe(\n * Layer.provide(App.layer({ projectId: \"demo-project\" })),\n * );\n * ```\n *\n * @see {@link make} for why building the service cannot fail\n * @see {@link ClientFirestore.layer} for the client SDK's layer, for browsers\n *\n * @stability unstable\n * @category layers\n * @since 0.2.0\n */\nexport const layer = (options?: Options): Layer.Layer<AdminFirestore | Firestore, never, App.App> =>\n Layer.effectContext(Effect.map(make(options), both));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0LA,MAAa,mBAAmB,QAAQ,QACtC,2EACF;;;;;;;;;;AAWA,MAAa,iBAAiB,QAAQ,QACpC,0DACF;;;;;;;;;;;;;;;;;;;;;;;AAsDA,MAAa,OAEoD,OAAO,GAAG,qBAAqB,CAAC,CAC/F,WAAW,SAAmB;CAC5B,MAAM,YAAY,OAAOA,aAA+B,OAAO;CAC/D,OAAOC,aAA+B,WAAW,gBAAgB;AACnE,CACF;;AAGA,MAAM,QAAQ,YACZ,QAAQ,KAAK,gBAAgB,OAAO,CAAC,CAAC,KAAK,QAAQ,IAAI,WAAW,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmC5E,MAAa,SAAS,YACpB,MAAM,cAAc,OAAO,IAAI,KAAK,OAAO,GAAG,IAAI,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Result } from "effect";
|
|
2
|
+
import { FirestoreError } from "@visiolab/effect-firebase/firestore/Firestore";
|
|
3
|
+
import { Firestore as Firestore$1 } from "firebase-admin/firestore";
|
|
4
|
+
import { FirestoreValue } from "@visiolab/effect-firebase/firestore/FirestoreValue";
|
|
5
|
+
declare namespace AdminFirestoreValue_d_exports {
|
|
6
|
+
export { fromAdmin, toAdmin };
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Turns a Firestore Value into the value the Admin SDK writes into
|
|
10
|
+
* `firestore`.
|
|
11
|
+
*
|
|
12
|
+
* **When to use**
|
|
13
|
+
*
|
|
14
|
+
* Use to write what a model encodes to through the Admin SDK itself.
|
|
15
|
+
*
|
|
16
|
+
* **Details**
|
|
17
|
+
*
|
|
18
|
+
* The portable `Timestamp`, `GeoPoint`, bytes and sentinels become the Admin
|
|
19
|
+
* SDK's own. A `DocumentPath` becomes `firestore.doc(path)`, so it points into
|
|
20
|
+
* that database. Map keys are kept as they are, so the dotted field paths of an
|
|
21
|
+
* update stay field paths.
|
|
22
|
+
*
|
|
23
|
+
* It throws for anything that is not a Firestore Value, such as one of the
|
|
24
|
+
* Admin SDK's own values or a class instance cast past the type. What
|
|
25
|
+
* {@link FirestoreValue.toCodecFirestore} encodes is always a Firestore Value.
|
|
26
|
+
*
|
|
27
|
+
* @see {@link fromAdmin} for the other direction
|
|
28
|
+
*
|
|
29
|
+
* @stability unstable
|
|
30
|
+
* @category conversions
|
|
31
|
+
* @since 0.2.0
|
|
32
|
+
*/
|
|
33
|
+
export declare const toAdmin: (value: FirestoreValue, firestore: Firestore$1) => unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Turns a value the Admin SDK read into a Firestore Value.
|
|
36
|
+
*
|
|
37
|
+
* **When to use**
|
|
38
|
+
*
|
|
39
|
+
* Use to decode what the Admin SDK itself read through a model, with
|
|
40
|
+
* {@link FirestoreValue.toCodecFirestore}.
|
|
41
|
+
*
|
|
42
|
+
* **Details**
|
|
43
|
+
*
|
|
44
|
+
* The Admin SDK's `Timestamp`, `GeoPoint`, bytes and sentinels become their
|
|
45
|
+
* portable forms. A `DocumentReference` becomes the `DocumentPath` it points
|
|
46
|
+
* at, since Firestore stores nothing else of it;
|
|
47
|
+
* {@link FirestoreSchema.DocumentReference} reads that back into the collection
|
|
48
|
+
* it names.
|
|
49
|
+
*
|
|
50
|
+
* Fails with a {@link Firestore.FirestoreError} naming the field for a value
|
|
51
|
+
* that is not a Firestore Value, such as a vector.
|
|
52
|
+
*
|
|
53
|
+
* @see {@link toAdmin} for the other direction
|
|
54
|
+
*
|
|
55
|
+
* @stability unstable
|
|
56
|
+
* @category conversions
|
|
57
|
+
* @since 0.2.0
|
|
58
|
+
*/
|
|
59
|
+
export declare const fromAdmin: (value: unknown) => Result.Result<FirestoreValue, FirestoreError>;
|
|
60
|
+
export { AdminFirestoreValue_d_exports };
|
|
61
|
+
//# sourceMappingURL=AdminFirestoreValue.d.mts.map
|