@visiolab/effect-firebase-client 0.0.0-stage → 0.3.0

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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -2
  3. package/dist/_virtual/_rolldown/runtime.mjs +12 -0
  4. package/dist/app/App.d.mts +117 -0
  5. package/dist/app/App.mjs +149 -0
  6. package/dist/app/App.mjs.map +1 -0
  7. package/dist/app/index.d.mts +2 -0
  8. package/dist/app/index.mjs +1 -0
  9. package/dist/app/internal/app.mjs +20 -0
  10. package/dist/app/internal/app.mjs.map +1 -0
  11. package/dist/firestore/ClientDocumentSnapshot.d.mts +106 -0
  12. package/dist/firestore/ClientDocumentSnapshot.mjs +86 -0
  13. package/dist/firestore/ClientDocumentSnapshot.mjs.map +1 -0
  14. package/dist/firestore/ClientFirestore.d.mts +331 -0
  15. package/dist/firestore/ClientFirestore.mjs +146 -0
  16. package/dist/firestore/ClientFirestore.mjs.map +1 -0
  17. package/dist/firestore/ClientFirestoreValue.d.mts +61 -0
  18. package/dist/firestore/ClientFirestoreValue.mjs +62 -0
  19. package/dist/firestore/ClientFirestoreValue.mjs.map +1 -0
  20. package/dist/firestore/ClientQuerySnapshot.d.mts +52 -0
  21. package/dist/firestore/ClientQuerySnapshot.mjs +58 -0
  22. package/dist/firestore/ClientQuerySnapshot.mjs.map +1 -0
  23. package/dist/firestore/index.d.mts +5 -0
  24. package/dist/firestore/index.mjs +5 -0
  25. package/dist/firestore/internal/firestore.mjs +158 -0
  26. package/dist/firestore/internal/firestore.mjs.map +1 -0
  27. package/dist/firestore/internal/firestoreValue.mjs +43 -0
  28. package/dist/firestore/internal/firestoreValue.mjs.map +1 -0
  29. package/dist/firestore/internal/snapshotMetadata.mjs +15 -0
  30. package/dist/firestore/internal/snapshotMetadata.mjs.map +1 -0
  31. package/dist/functions/CallableClient.d.mts +139 -0
  32. package/dist/functions/CallableClient.mjs +215 -0
  33. package/dist/functions/CallableClient.mjs.map +1 -0
  34. package/dist/functions/ClientFunctions.d.mts +112 -0
  35. package/dist/functions/ClientFunctions.mjs +105 -0
  36. package/dist/functions/ClientFunctions.mjs.map +1 -0
  37. package/dist/functions/index.d.mts +3 -0
  38. package/dist/functions/index.mjs +3 -0
  39. package/package.json +63 -3
  40. package/src/app/App.ts +163 -0
  41. package/src/app/index.ts +7 -0
  42. package/src/app/internal/app.ts +35 -0
  43. package/src/firestore/ClientDocumentSnapshot.ts +156 -0
  44. package/src/firestore/ClientFirestore.ts +410 -0
  45. package/src/firestore/ClientFirestoreValue.ts +94 -0
  46. package/src/firestore/ClientQuerySnapshot.ts +93 -0
  47. package/src/firestore/index.ts +30 -0
  48. package/src/firestore/internal/firestore.ts +264 -0
  49. package/src/firestore/internal/firestoreValue.ts +58 -0
  50. package/src/firestore/internal/snapshotMetadata.ts +14 -0
  51. package/src/functions/CallableClient.ts +296 -0
  52. package/src/functions/ClientFunctions.ts +149 -0
  53. package/src/functions/index.ts +15 -0
@@ -0,0 +1,215 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
2
+ import { ClientFunctions } from "./ClientFunctions.mjs";
3
+ import { Effect, Schema } from "effect";
4
+ import * as Callable from "@visiolab/effect-firebase/functions/Callable";
5
+ import * as CallableError from "@visiolab/effect-firebase/functions/CallableError";
6
+ import * as FunctionGroup from "@visiolab/effect-firebase/functions/FunctionGroup";
7
+ import * as Sdk from "firebase/functions";
8
+ // src/functions/CallableClient.ts
9
+ /**
10
+ * Callable Clients: call the Callables a server serves, with the Payload, the
11
+ * success value and the errors typed by their contract.
12
+ *
13
+ * A client calls through the {@link ClientFunctions.ClientFunctions} in
14
+ * context, so the region and the emulator are set once, where that is
15
+ * provided.
16
+ *
17
+ * @example Calling a Callable
18
+ * ```ts
19
+ * import { Effect, Layer, Schema } from "effect";
20
+ * import { Callable } from "@visiolab/effect-firebase/functions";
21
+ * import { App } from "@visiolab/effect-firebase-client/app";
22
+ * import { CallableClient, ClientFunctions } from "@visiolab/effect-firebase-client/functions";
23
+ *
24
+ * const Greet = Callable.make("greet", {
25
+ * payload: { name: Schema.String },
26
+ * success: Schema.String,
27
+ * });
28
+ *
29
+ * const program = Effect.gen(function* () {
30
+ * const { greet } = yield* CallableClient.make(Greet);
31
+ * const message = yield* greet({ name: "Ada" });
32
+ * yield* Effect.log(message);
33
+ * });
34
+ *
35
+ * const FunctionsLive = ClientFunctions.layer().pipe(
36
+ * Layer.provide(App.layer({ apiKey: "<api key>", projectId: "my-project", appId: "<app id>" })),
37
+ * );
38
+ *
39
+ * program.pipe(Effect.provide(FunctionsLive));
40
+ * ```
41
+ *
42
+ * @stability unstable
43
+ * @since 0.3.0
44
+ */
45
+ var CallableClient_exports = /* @__PURE__ */ __exportAll({ make: () => make });
46
+ /** The ` [<status>]` the SDK appends to the message of an error built from an answer. */
47
+ const statusSuffix = / \[(\d+)\]$/;
48
+ /**
49
+ * The messages of the SDK's errors for an answer it can't read: not a JSON
50
+ * object, or one without `data` or `error`.
51
+ */
52
+ const malformedAnswer = /Response is (?:not valid JSON object|missing data field)\.$/;
53
+ /**
54
+ * The client function of `callable`, served as `deployment`. `errors` are the
55
+ * schemas of every error it can be answered with, its middleware's included.
56
+ */
57
+ const method = (functions, callable, deployment, errors) => {
58
+ const deployedName = deployment.name;
59
+ const span = {
60
+ kind: "client",
61
+ attributes: deployment.attributes
62
+ };
63
+ const call = Sdk.httpsCallable(functions, deployedName);
64
+ const encode = Schema.encodeUnknownEffect(Schema.toCodecJson(callable.payload));
65
+ const decode = Schema.decodeUnknownEffect(Schema.toCodecJson(callable.success));
66
+ const fail = (reason) => new CallableError.CallableError({
67
+ callable: deployedName,
68
+ reason
69
+ });
70
+ const run = Effect.fn(`CallableClient.${deployedName}`, span)(function* (payload) {
71
+ const data = yield* encode(payload).pipe(Effect.mapError((cause) => fail(new CallableError.EncodeError({ cause }))));
72
+ const result = yield* Effect.tryPromise({
73
+ try: () => call(data),
74
+ catch: (error) => error
75
+ }).pipe(Effect.catch(decodeFailure));
76
+ return yield* decode(result.data).pipe(Effect.mapError((cause) => fail(new CallableError.DecodeError({ cause }))));
77
+ });
78
+ /**
79
+ * Turns what the SDK threw into the declared error it carries, or into a
80
+ * `CallableError`.
81
+ */
82
+ const decodeFailure = (error) => {
83
+ if (!(error instanceof Sdk.FunctionsError)) return Effect.fail(fail(new CallableError.TransportError({ cause: error })));
84
+ const status = statusSuffix.exec(error.message)?.[1];
85
+ if (status === void 0 || status === "0") {
86
+ if (malformedAnswer.test(error.message)) return Effect.fail(fail(new CallableError.DecodeError({ cause: error })));
87
+ return Effect.fail(fail(new CallableError.TransportError({ cause: error })));
88
+ }
89
+ const code = error.code.replace(/^functions\//, "");
90
+ const candidates = errors.filter((schema) => Callable.getErrorCode(schema) === code);
91
+ if (candidates.length === 0 || error.details === void 0) return Effect.fail(fail(new CallableError.ResponseError({
92
+ code,
93
+ message: error.message.replace(statusSuffix, ""),
94
+ details: error.details
95
+ })));
96
+ return Schema.decodeUnknownEffect(Schema.toCodecJson(Schema.Union(candidates)))(error.details).pipe(Effect.mapError((cause) => fail(new CallableError.DecodeError({ cause }))), Effect.flatMap(Effect.fail));
97
+ };
98
+ return run;
99
+ };
100
+ /**
101
+ * Builds the client of a Callable in no group, or of every Callable member of
102
+ * a Function Group.
103
+ *
104
+ * **When to use**
105
+ *
106
+ * Use to call Callables from the browser or any other client SDK program.
107
+ *
108
+ * **Details**
109
+ *
110
+ * Returns a record keyed by Callable name: `const { greet } = yield*
111
+ * CallableClient.make(Greet)` for a Callable in no group, and
112
+ * `const users = yield* CallableClient.make(Users)` for a group, where
113
+ * `users.create` calls `users-create`. A group's members of other kinds, which
114
+ * no client calls, are left out. The region of the
115
+ * {@link ClientFunctions.ClientFunctions} in context is bound once, here.
116
+ *
117
+ * Build a member's client from its group. A client built from the member on
118
+ * its own calls the name without the group's prefix, which the server doesn't
119
+ * export, and fails with `not-found`. Nothing checks this at runtime.
120
+ *
121
+ * Each call encodes the Payload with `Schema.toCodecJson`, sends it as is
122
+ * through the SDK's `httpsCallable`, and decodes the answer the same way.
123
+ *
124
+ * When the server answers with an error, the client strips the `functions/`
125
+ * prefix from its code and decodes its `details` against the declared errors
126
+ * that carry that code. It fails with the decoded error, so `Effect.catchTag`
127
+ * recovers from it. Every other failure is a
128
+ * {@link CallableError.CallableError}:
129
+ *
130
+ * - `EncodeError` when the Payload doesn't encode. Nothing is sent.
131
+ * - `DecodeError` when the success value doesn't decode, the `details` of
132
+ * an error don't decode against the declared errors with its code, as after
133
+ * the server and the client drift apart, or the answer isn't one the SDK
134
+ * can read: not a JSON object, or one without `data`.
135
+ * - `ResponseError` when the server answers with a code no declared error
136
+ * carries, or without details, as on a defect. `not-found` usually means a
137
+ * wrong region, or a name the server doesn't export, such as a group's
138
+ * member called without its group. A `deadline-exceeded` the server sends
139
+ * is a `ResponseError` too.
140
+ * - `TransportError` when no answer arrived: a network failure, the SDK's
141
+ * own timeout (`deadline-exceeded`), a cancelled call, or a deleted
142
+ * Functions instance. The SDK appends the HTTP status of an answer to its
143
+ * error's message as ` [<status>]`, and status 0 to a network failure. The
144
+ * client treats an error without that suffix, or with status 0, as no
145
+ * answer.
146
+ *
147
+ * Each call runs in a `kind: "client"` span named `CallableClient.<deployed
148
+ * name>`, such as `CallableClient.users-create`, with the attributes
149
+ * `rpc.system: "firebase_callable"`, `rpc.method` (the Callable's name),
150
+ * `rpc.service` (the group, for a member) and `faas.name` (the deployed name).
151
+ * The span isn't linked to the server's span of the same call: the two land in
152
+ * separate traces. It carries no uid; add one with `Effect.annotateCurrentSpan`
153
+ * around the call when you want it.
154
+ *
155
+ * @example Injecting a client as a service
156
+ * ```ts
157
+ * import { Context, Layer, Schema } from "effect";
158
+ * import { Callable } from "@visiolab/effect-firebase/functions";
159
+ * import { CallableClient } from "@visiolab/effect-firebase-client/functions";
160
+ *
161
+ * const Greet = Callable.make("greet", {
162
+ * payload: { name: Schema.String },
163
+ * success: Schema.String,
164
+ * });
165
+ *
166
+ * class GreetClient extends Context.Service<GreetClient, CallableClient.Client<typeof Greet>>()(
167
+ * "app/GreetClient",
168
+ * ) {
169
+ * static readonly layer = Layer.effect(GreetClient, CallableClient.make(Greet));
170
+ * }
171
+ * ```
172
+ *
173
+ * @example Calling the members of a group
174
+ * ```ts
175
+ * import { Effect, Schema } from "effect";
176
+ * import { Callable, FunctionGroup } from "@visiolab/effect-firebase/functions";
177
+ * import { CallableClient } from "@visiolab/effect-firebase-client/functions";
178
+ *
179
+ * const CreateUser = Callable.make("create", {
180
+ * payload: { name: Schema.String },
181
+ * success: Schema.String,
182
+ * });
183
+ *
184
+ * class Users extends FunctionGroup.make("users").add(CreateUser) {}
185
+ *
186
+ * const program = Effect.gen(function* () {
187
+ * const users = yield* CallableClient.make(Users);
188
+ * // Calls `users-create`.
189
+ * return yield* users.create({ name: "Ada" });
190
+ * });
191
+ * ```
192
+ *
193
+ * @see {@link ClientFunctions.ClientFunctions} for the region and emulator it calls
194
+ * @see {@link Functions.make} for serving a Callable in no group
195
+ * @see {@link Functions.group} for serving the members of a group
196
+ *
197
+ * @stability unstable
198
+ * @category constructors
199
+ * @since 0.3.0
200
+ */
201
+ const make = (target) => Effect.map(Effect.service(ClientFunctions), ({ instance }) => {
202
+ if (!FunctionGroup.isFunctionGroup(target)) {
203
+ const callable = target;
204
+ return { [callable.name]: method(instance, callable, Callable.deployment(callable), Callable.errorSchemas(callable)) };
205
+ }
206
+ const client = {};
207
+ for (const [name, member] of Object.entries(target.functions)) {
208
+ if (member.kind !== "Callable") continue;
209
+ client[name] = method(instance, member, Callable.deployment(target, name), Callable.errorSchemas(target, name));
210
+ }
211
+ return client;
212
+ });
213
+ export { CallableClient_exports, make };
214
+
215
+ //# sourceMappingURL=CallableClient.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CallableClient.mjs","names":["ClientFunctions.ClientFunctions"],"sources":["../../src/functions/CallableClient.ts"],"sourcesContent":["/**\n * Callable Clients: call the Callables a server serves, with the Payload, the\n * success value and the errors typed by their contract.\n *\n * A client calls through the {@link ClientFunctions.ClientFunctions} in\n * context, so the region and the emulator are set once, where that is\n * provided.\n *\n * @example Calling a Callable\n * ```ts\n * import { Effect, Layer, Schema } from \"effect\";\n * import { Callable } from \"@visiolab/effect-firebase/functions\";\n * import { App } from \"@visiolab/effect-firebase-client/app\";\n * import { CallableClient, ClientFunctions } from \"@visiolab/effect-firebase-client/functions\";\n *\n * const Greet = Callable.make(\"greet\", {\n * payload: { name: Schema.String },\n * success: Schema.String,\n * });\n *\n * const program = Effect.gen(function* () {\n * const { greet } = yield* CallableClient.make(Greet);\n * const message = yield* greet({ name: \"Ada\" });\n * yield* Effect.log(message);\n * });\n *\n * const FunctionsLive = ClientFunctions.layer().pipe(\n * Layer.provide(App.layer({ apiKey: \"<api key>\", projectId: \"my-project\", appId: \"<app id>\" })),\n * );\n *\n * program.pipe(Effect.provide(FunctionsLive));\n * ```\n *\n * @stability unstable\n * @since 0.3.0\n */\nimport { Effect, Schema } from \"effect\";\nimport * as Callable from \"@visiolab/effect-firebase/functions/Callable\";\nimport * as CallableError from \"@visiolab/effect-firebase/functions/CallableError\";\nimport * as FunctionGroup from \"@visiolab/effect-firebase/functions/FunctionGroup\";\nimport * as Sdk from \"firebase/functions\";\nimport * as ClientFunctions from \"./ClientFunctions.ts\";\n\n/**\n * A client of one Callable: a function from its Payload to an Effect of its\n * success value, failing with its declared errors or a `CallableError`.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport type Method<C extends Callable.Any> = (\n payload: Callable.Payload<C>,\n) => Effect.Effect<Callable.Success<C>, Callable.Error<C> | CallableError.CallableError>;\n\n/**\n * What {@link make} returns: one {@link Method} per Callable, keyed by the\n * Callable's name. For a Function Group, one per Callable member.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport type Client<T extends Callable.Any | FunctionGroup.Any> = {\n readonly [C in Members<T> as C[\"name\"]]: Method<C>;\n};\n\n/**\n * The Callables a client of `T` calls: the Callable members of a Function\n * Group, or the Callable itself. Members of other kinds are left out.\n *\n * @stability unstable\n * @category type-level\n * @since 0.3.0\n */\nexport type Members<T extends Callable.Any | FunctionGroup.Any> = T extends FunctionGroup.Any\n ? FunctionGroup.Members<T, Callable.Any>\n : T;\n\n/** The ` [<status>]` the SDK appends to the message of an error built from an answer. */\nconst statusSuffix = / \\[(\\d+)\\]$/;\n\n/**\n * The messages of the SDK's errors for an answer it can't read: not a JSON\n * object, or one without `data` or `error`.\n */\nconst malformedAnswer = /Response is (?:not valid JSON object|missing data field)\\.$/;\n\n/**\n * The client function of `callable`, served as `deployment`. `errors` are the\n * schemas of every error it can be answered with, its middleware's included.\n */\nconst method = (\n functions: Sdk.Functions,\n callable: Callable.Any,\n deployment: Callable.Deployment,\n errors: ReadonlyArray<Schema.Top>,\n) => {\n const deployedName = deployment.name;\n const span = { kind: \"client\", attributes: deployment.attributes } as const;\n const call = Sdk.httpsCallable(functions, deployedName);\n const encode = Schema.encodeUnknownEffect(\n Schema.toCodecJson(callable.payload as Schema.Codec<unknown>),\n );\n const decode = Schema.decodeUnknownEffect(\n Schema.toCodecJson(callable.success as Schema.Codec<unknown>),\n );\n const fail = (reason: CallableError.Reason) =>\n new CallableError.CallableError({ callable: deployedName, reason });\n const run = Effect.fn(\n `CallableClient.${deployedName}`,\n span,\n )(function* (payload: unknown) {\n const data = yield* encode(payload).pipe(\n Effect.mapError((cause) => fail(new CallableError.EncodeError({ cause }))),\n );\n const result = yield* Effect.tryPromise({\n try: () => call(data),\n catch: (error) => error,\n }).pipe(Effect.catch(decodeFailure));\n return yield* decode(result.data).pipe(\n Effect.mapError((cause) => fail(new CallableError.DecodeError({ cause }))),\n );\n });\n\n /**\n * Turns what the SDK threw into the declared error it carries, or into a\n * `CallableError`.\n */\n const decodeFailure = (error: unknown): Effect.Effect<never, unknown> => {\n if (!(error instanceof Sdk.FunctionsError)) {\n return Effect.fail(fail(new CallableError.TransportError({ cause: error })));\n }\n // The SDK appends the HTTP status to the message of an error built from\n // an answer, and status 0 to a network failure. The errors it makes\n // itself, such as its timeout or a cancellation, carry no status.\n const status = statusSuffix.exec(error.message)?.[1];\n if (status === undefined || status === \"0\") {\n // An answer arrived, but not one the SDK could read.\n if (malformedAnswer.test(error.message)) {\n return Effect.fail(fail(new CallableError.DecodeError({ cause: error })));\n }\n return Effect.fail(fail(new CallableError.TransportError({ cause: error })));\n }\n const code = error.code.replace(/^functions\\//, \"\") as CallableError.ErrorCode;\n const candidates = errors.filter((schema) => Callable.getErrorCode(schema) === code);\n if (candidates.length === 0 || error.details === undefined) {\n return Effect.fail(\n fail(\n new CallableError.ResponseError({\n code,\n message: error.message.replace(statusSuffix, \"\"),\n details: error.details,\n }),\n ),\n );\n }\n return Schema.decodeUnknownEffect(\n Schema.toCodecJson(Schema.Union(candidates) as unknown as Schema.Codec<unknown>),\n )(error.details).pipe(\n Effect.mapError((cause) => fail(new CallableError.DecodeError({ cause }))),\n Effect.flatMap(Effect.fail),\n );\n };\n return run;\n};\n\n/**\n * Builds the client of a Callable in no group, or of every Callable member of\n * a Function Group.\n *\n * **When to use**\n *\n * Use to call Callables from the browser or any other client SDK program.\n *\n * **Details**\n *\n * Returns a record keyed by Callable name: `const { greet } = yield*\n * CallableClient.make(Greet)` for a Callable in no group, and\n * `const users = yield* CallableClient.make(Users)` for a group, where\n * `users.create` calls `users-create`. A group's members of other kinds, which\n * no client calls, are left out. The region of the\n * {@link ClientFunctions.ClientFunctions} in context is bound once, here.\n *\n * Build a member's client from its group. A client built from the member on\n * its own calls the name without the group's prefix, which the server doesn't\n * export, and fails with `not-found`. Nothing checks this at runtime.\n *\n * Each call encodes the Payload with `Schema.toCodecJson`, sends it as is\n * through the SDK's `httpsCallable`, and decodes the answer the same way.\n *\n * When the server answers with an error, the client strips the `functions/`\n * prefix from its code and decodes its `details` against the declared errors\n * that carry that code. It fails with the decoded error, so `Effect.catchTag`\n * recovers from it. Every other failure is a\n * {@link CallableError.CallableError}:\n *\n * - `EncodeError` when the Payload doesn't encode. Nothing is sent.\n * - `DecodeError` when the success value doesn't decode, the `details` of\n * an error don't decode against the declared errors with its code, as after\n * the server and the client drift apart, or the answer isn't one the SDK\n * can read: not a JSON object, or one without `data`.\n * - `ResponseError` when the server answers with a code no declared error\n * carries, or without details, as on a defect. `not-found` usually means a\n * wrong region, or a name the server doesn't export, such as a group's\n * member called without its group. A `deadline-exceeded` the server sends\n * is a `ResponseError` too.\n * - `TransportError` when no answer arrived: a network failure, the SDK's\n * own timeout (`deadline-exceeded`), a cancelled call, or a deleted\n * Functions instance. The SDK appends the HTTP status of an answer to its\n * error's message as ` [<status>]`, and status 0 to a network failure. The\n * client treats an error without that suffix, or with status 0, as no\n * answer.\n *\n * Each call runs in a `kind: \"client\"` span named `CallableClient.<deployed\n * name>`, such as `CallableClient.users-create`, with the attributes\n * `rpc.system: \"firebase_callable\"`, `rpc.method` (the Callable's name),\n * `rpc.service` (the group, for a member) and `faas.name` (the deployed name).\n * The span isn't linked to the server's span of the same call: the two land in\n * separate traces. It carries no uid; add one with `Effect.annotateCurrentSpan`\n * around the call when you want it.\n *\n * @example Injecting a client as a service\n * ```ts\n * import { Context, Layer, Schema } from \"effect\";\n * import { Callable } from \"@visiolab/effect-firebase/functions\";\n * import { CallableClient } from \"@visiolab/effect-firebase-client/functions\";\n *\n * const Greet = Callable.make(\"greet\", {\n * payload: { name: Schema.String },\n * success: Schema.String,\n * });\n *\n * class GreetClient extends Context.Service<GreetClient, CallableClient.Client<typeof Greet>>()(\n * \"app/GreetClient\",\n * ) {\n * static readonly layer = Layer.effect(GreetClient, CallableClient.make(Greet));\n * }\n * ```\n *\n * @example Calling the members of a group\n * ```ts\n * import { Effect, Schema } from \"effect\";\n * import { Callable, FunctionGroup } from \"@visiolab/effect-firebase/functions\";\n * import { CallableClient } from \"@visiolab/effect-firebase-client/functions\";\n *\n * const CreateUser = Callable.make(\"create\", {\n * payload: { name: Schema.String },\n * success: Schema.String,\n * });\n *\n * class Users extends FunctionGroup.make(\"users\").add(CreateUser) {}\n *\n * const program = Effect.gen(function* () {\n * const users = yield* CallableClient.make(Users);\n * // Calls `users-create`.\n * return yield* users.create({ name: \"Ada\" });\n * });\n * ```\n *\n * @see {@link ClientFunctions.ClientFunctions} for the region and emulator it calls\n * @see {@link Functions.make} for serving a Callable in no group\n * @see {@link Functions.group} for serving the members of a group\n *\n * @stability unstable\n * @category constructors\n * @since 0.3.0\n */\nexport const make = <T extends Callable.Any | FunctionGroup.Any>(\n target: T,\n): Effect.Effect<Client<T>, never, ClientFunctions.ClientFunctions> =>\n Effect.map(Effect.service(ClientFunctions.ClientFunctions), ({ instance }) => {\n if (!FunctionGroup.isFunctionGroup(target)) {\n const callable = target as Callable.Any;\n return {\n [callable.name]: method(\n instance,\n callable,\n Callable.deployment(callable),\n Callable.errorSchemas(callable),\n ),\n } as Client<T>;\n }\n const client: Record<string, ReturnType<typeof method>> = {};\n for (const [name, member] of Object.entries(target.functions)) {\n // Only Callables are called by a client.\n if (member.kind !== \"Callable\") continue;\n client[name] = method(\n instance,\n member as Callable.Any,\n Callable.deployment(target, name),\n Callable.errorSchemas(target, name),\n );\n }\n return client as Client<T>;\n });\n"],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ import { App } from "../app/App.mjs";
2
+ import { Context, Effect, Layer } from "effect";
3
+ import * as Client from "firebase/functions";
4
+ declare namespace ClientFunctions_d_exports {
5
+ export { ClientFunctions, Emulator, Options, layer, make };
6
+ }
7
+ /**
8
+ * The client SDK's `Functions` instance for one region.
9
+ *
10
+ * @stability unstable
11
+ * @category models
12
+ * @since 0.3.0
13
+ */
14
+ export interface ClientFunctions {
15
+ /** The SDK's own `Functions` instance, for what this package doesn't wrap. */
16
+ readonly instance: Client.Functions;
17
+ }
18
+ /**
19
+ * Service key for {@link ClientFunctions}.
20
+ *
21
+ * **When to use**
22
+ *
23
+ * Use to give every Callable Client one region and emulator setting. Provide
24
+ * it with {@link layer}. A {@link CallableClient.make} client reads it once,
25
+ * when it is built.
26
+ *
27
+ * @see {@link layer} for providing it
28
+ * @see {@link CallableClient.make} for the clients that call through it
29
+ *
30
+ * @stability unstable
31
+ * @category services
32
+ * @since 0.3.0
33
+ */
34
+ export declare const ClientFunctions: Context.Service<ClientFunctions, ClientFunctions>;
35
+ /**
36
+ * Where the Functions emulator runs.
37
+ *
38
+ * @stability unstable
39
+ * @category models
40
+ * @since 0.3.0
41
+ */
42
+ export interface Emulator {
43
+ readonly host: string;
44
+ readonly port: number;
45
+ }
46
+ /**
47
+ * Options for {@link make} and {@link layer}.
48
+ *
49
+ * @stability unstable
50
+ * @category models
51
+ * @since 0.3.0
52
+ */
53
+ export interface Options {
54
+ /**
55
+ * The region the functions are deployed to, such as `europe-west1`, or a
56
+ * custom domain that serves them. Defaults to the SDK's, `us-central1`. A
57
+ * function called in a region it isn't deployed to fails with `not-found`.
58
+ */
59
+ readonly regionOrCustomDomain?: string | undefined;
60
+ /** Calls the Functions emulator at this address instead of the deployed functions. */
61
+ readonly emulator?: Emulator | undefined;
62
+ }
63
+ /**
64
+ * Gets the client SDK's `Functions` instance of the {@link App.App} in
65
+ * context, for one region.
66
+ *
67
+ * **When to use**
68
+ *
69
+ * Use to build the service inside an effect of your own. Most programs provide
70
+ * it with {@link layer} instead.
71
+ *
72
+ * **Details**
73
+ *
74
+ * Wraps `getFunctions(app, regionOrCustomDomain)`, and connects the emulator
75
+ * when `emulator` is given. For a second region, build a second service.
76
+ *
77
+ * @see {@link layer} for the same as a layer
78
+ *
79
+ * @stability unstable
80
+ * @category constructors
81
+ * @since 0.3.0
82
+ */
83
+ export declare const make: (options?: Options) => Effect.Effect<ClientFunctions, never, App>;
84
+ /**
85
+ * A layer that provides {@link ClientFunctions} for the {@link App.App} in
86
+ * context.
87
+ *
88
+ * **When to use**
89
+ *
90
+ * Use to set the region and the emulator once, for every Callable Client built
91
+ * on it.
92
+ *
93
+ * @example Calling the Functions emulator
94
+ * ```ts
95
+ * import { Layer } from "effect";
96
+ * import { App } from "@visiolab/effect-firebase-client/app";
97
+ * import { ClientFunctions } from "@visiolab/effect-firebase-client/functions";
98
+ *
99
+ * const FunctionsLive = ClientFunctions.layer({
100
+ * emulator: { host: "127.0.0.1", port: 5001 },
101
+ * }).pipe(Layer.provide(App.layer({ projectId: "demo-project" })));
102
+ * ```
103
+ *
104
+ * @see {@link make} for what it wraps
105
+ *
106
+ * @stability unstable
107
+ * @category layers
108
+ * @since 0.3.0
109
+ */
110
+ export declare const layer: (options?: Options) => Layer.Layer<ClientFunctions, never, App>;
111
+ export { ClientFunctions_d_exports };
112
+ //# sourceMappingURL=ClientFunctions.d.mts.map
@@ -0,0 +1,105 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.mjs";
2
+ import { App } from "../app/App.mjs";
3
+ import { Context, Effect, Layer } from "effect";
4
+ import * as Client from "firebase/functions";
5
+ // src/functions/ClientFunctions.ts
6
+ /**
7
+ * Cloud Functions for Firebase on the client SDK: the `Functions` instance
8
+ * that a Callable Client calls through, for one region.
9
+ *
10
+ * A call that fails with `not-found` usually went to the wrong region, or to a
11
+ * name the server doesn't export: build the client of a Function Group's
12
+ * member from its group, so it calls `<group>-<name>`.
13
+ *
14
+ * @example Pointing the client at a region
15
+ * ```ts
16
+ * import { Layer } from "effect";
17
+ * import { App } from "@visiolab/effect-firebase-client/app";
18
+ * import { ClientFunctions } from "@visiolab/effect-firebase-client/functions";
19
+ *
20
+ * const FunctionsLive = ClientFunctions.layer({ regionOrCustomDomain: "europe-west1" }).pipe(
21
+ * Layer.provide(App.layer({ apiKey: "<api key>", projectId: "my-project", appId: "<app id>" })),
22
+ * );
23
+ * ```
24
+ *
25
+ * @stability unstable
26
+ * @since 0.3.0
27
+ */
28
+ var ClientFunctions_exports = /* @__PURE__ */ __exportAll({
29
+ ClientFunctions: () => ClientFunctions,
30
+ layer: () => layer,
31
+ make: () => make
32
+ });
33
+ /**
34
+ * Service key for {@link ClientFunctions}.
35
+ *
36
+ * **When to use**
37
+ *
38
+ * Use to give every Callable Client one region and emulator setting. Provide
39
+ * it with {@link layer}. A {@link CallableClient.make} client reads it once,
40
+ * when it is built.
41
+ *
42
+ * @see {@link layer} for providing it
43
+ * @see {@link CallableClient.make} for the clients that call through it
44
+ *
45
+ * @stability unstable
46
+ * @category services
47
+ * @since 0.3.0
48
+ */
49
+ const ClientFunctions = Context.Service("@visiolab/effect-firebase-client/functions/ClientFunctions");
50
+ /**
51
+ * Gets the client SDK's `Functions` instance of the {@link App.App} in
52
+ * context, for one region.
53
+ *
54
+ * **When to use**
55
+ *
56
+ * Use to build the service inside an effect of your own. Most programs provide
57
+ * it with {@link layer} instead.
58
+ *
59
+ * **Details**
60
+ *
61
+ * Wraps `getFunctions(app, regionOrCustomDomain)`, and connects the emulator
62
+ * when `emulator` is given. For a second region, build a second service.
63
+ *
64
+ * @see {@link layer} for the same as a layer
65
+ *
66
+ * @stability unstable
67
+ * @category constructors
68
+ * @since 0.3.0
69
+ */
70
+ const make = Effect.fn("ClientFunctions.make")(function* (options) {
71
+ const app = yield* App;
72
+ const instance = Client.getFunctions(app, options?.regionOrCustomDomain);
73
+ if (options?.emulator !== void 0) Client.connectFunctionsEmulator(instance, options.emulator.host, options.emulator.port);
74
+ return { instance };
75
+ });
76
+ /**
77
+ * A layer that provides {@link ClientFunctions} for the {@link App.App} in
78
+ * context.
79
+ *
80
+ * **When to use**
81
+ *
82
+ * Use to set the region and the emulator once, for every Callable Client built
83
+ * on it.
84
+ *
85
+ * @example Calling the Functions emulator
86
+ * ```ts
87
+ * import { Layer } from "effect";
88
+ * import { App } from "@visiolab/effect-firebase-client/app";
89
+ * import { ClientFunctions } from "@visiolab/effect-firebase-client/functions";
90
+ *
91
+ * const FunctionsLive = ClientFunctions.layer({
92
+ * emulator: { host: "127.0.0.1", port: 5001 },
93
+ * }).pipe(Layer.provide(App.layer({ projectId: "demo-project" })));
94
+ * ```
95
+ *
96
+ * @see {@link make} for what it wraps
97
+ *
98
+ * @stability unstable
99
+ * @category layers
100
+ * @since 0.3.0
101
+ */
102
+ const layer = (options) => Layer.effect(ClientFunctions, make(options));
103
+ export { ClientFunctions, ClientFunctions_exports, layer, make };
104
+
105
+ //# sourceMappingURL=ClientFunctions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ClientFunctions.mjs","names":["App.App"],"sources":["../../src/functions/ClientFunctions.ts"],"sourcesContent":["/**\n * Cloud Functions for Firebase on the client SDK: the `Functions` instance\n * that a Callable Client calls through, for one region.\n *\n * A call that fails with `not-found` usually went to the wrong region, or to a\n * name the server doesn't export: build the client of a Function Group's\n * member from its group, so it calls `<group>-<name>`.\n *\n * @example Pointing the client at a region\n * ```ts\n * import { Layer } from \"effect\";\n * import { App } from \"@visiolab/effect-firebase-client/app\";\n * import { ClientFunctions } from \"@visiolab/effect-firebase-client/functions\";\n *\n * const FunctionsLive = ClientFunctions.layer({ regionOrCustomDomain: \"europe-west1\" }).pipe(\n * Layer.provide(App.layer({ apiKey: \"<api key>\", projectId: \"my-project\", appId: \"<app id>\" })),\n * );\n * ```\n *\n * @stability unstable\n * @since 0.3.0\n */\nimport { Context, Effect, Layer } from \"effect\";\nimport * as Client from \"firebase/functions\";\nimport * as App from \"../app/App.ts\";\n// Only the documentation links to it.\n// oxlint-disable-next-line no-unused-vars\nimport type * as CallableClient from \"./CallableClient.ts\";\n\n/**\n * The client SDK's `Functions` instance for one region.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport interface ClientFunctions {\n /** The SDK's own `Functions` instance, for what this package doesn't wrap. */\n readonly instance: Client.Functions;\n}\n\n/**\n * Service key for {@link ClientFunctions}.\n *\n * **When to use**\n *\n * Use to give every Callable Client one region and emulator setting. Provide\n * it with {@link layer}. A {@link CallableClient.make} client reads it once,\n * when it is built.\n *\n * @see {@link layer} for providing it\n * @see {@link CallableClient.make} for the clients that call through it\n *\n * @stability unstable\n * @category services\n * @since 0.3.0\n */\nexport const ClientFunctions = Context.Service<ClientFunctions>(\n \"@visiolab/effect-firebase-client/functions/ClientFunctions\",\n);\n\n/**\n * Where the Functions emulator runs.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport interface Emulator {\n readonly host: string;\n readonly port: number;\n}\n\n/**\n * Options for {@link make} and {@link layer}.\n *\n * @stability unstable\n * @category models\n * @since 0.3.0\n */\nexport interface Options {\n /**\n * The region the functions are deployed to, such as `europe-west1`, or a\n * custom domain that serves them. Defaults to the SDK's, `us-central1`. A\n * function called in a region it isn't deployed to fails with `not-found`.\n */\n readonly regionOrCustomDomain?: string | undefined;\n /** Calls the Functions emulator at this address instead of the deployed functions. */\n readonly emulator?: Emulator | undefined;\n}\n\n/**\n * Gets the client SDK's `Functions` instance of the {@link App.App} in\n * context, for one region.\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 * Wraps `getFunctions(app, regionOrCustomDomain)`, and connects the emulator\n * when `emulator` is given. For a second region, build a second service.\n *\n * @see {@link layer} for the same as a layer\n *\n * @stability unstable\n * @category constructors\n * @since 0.3.0\n */\nexport const make: (options?: Options) => Effect.Effect<ClientFunctions, never, App.App> =\n Effect.fn(\"ClientFunctions.make\")(function* (options?: Options) {\n const app = yield* App.App;\n const instance = Client.getFunctions(app, options?.regionOrCustomDomain);\n if (options?.emulator !== undefined) {\n Client.connectFunctionsEmulator(instance, options.emulator.host, options.emulator.port);\n }\n return { instance };\n });\n\n/**\n * A layer that provides {@link ClientFunctions} for the {@link App.App} in\n * context.\n *\n * **When to use**\n *\n * Use to set the region and the emulator once, for every Callable Client built\n * on it.\n *\n * @example Calling the Functions emulator\n * ```ts\n * import { Layer } from \"effect\";\n * import { App } from \"@visiolab/effect-firebase-client/app\";\n * import { ClientFunctions } from \"@visiolab/effect-firebase-client/functions\";\n *\n * const FunctionsLive = ClientFunctions.layer({\n * emulator: { host: \"127.0.0.1\", port: 5001 },\n * }).pipe(Layer.provide(App.layer({ projectId: \"demo-project\" })));\n * ```\n *\n * @see {@link make} for what it wraps\n *\n * @stability unstable\n * @category layers\n * @since 0.3.0\n */\nexport const layer = (options?: Options): Layer.Layer<ClientFunctions, never, App.App> =>\n Layer.effect(ClientFunctions, make(options));\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyDA,MAAa,kBAAkB,QAAQ,QACrC,4DACF;;;;;;;;;;;;;;;;;;;;;AAoDA,MAAa,OACX,OAAO,GAAG,sBAAsB,CAAC,CAAC,WAAW,SAAmB;CAC9D,MAAM,MAAM,OAAOA;CACnB,MAAM,WAAW,OAAO,aAAa,KAAK,SAAS,oBAAoB;CACvE,IAAI,SAAS,aAAa,KAAA,GACxB,OAAO,yBAAyB,UAAU,QAAQ,SAAS,MAAM,QAAQ,SAAS,IAAI;CAExF,OAAO,EAAE,SAAS;AACpB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BH,MAAa,SAAS,YACpB,MAAM,OAAO,iBAAiB,KAAK,OAAO,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { ClientFunctions_d_exports } from "./ClientFunctions.mjs";
2
+ import { CallableClient_d_exports } from "./CallableClient.mjs";
3
+ export { CallableClient_d_exports as CallableClient, ClientFunctions_d_exports as ClientFunctions };
@@ -0,0 +1,3 @@
1
+ import { ClientFunctions_exports } from "./ClientFunctions.mjs";
2
+ import { CallableClient_exports } from "./CallableClient.mjs";
3
+ export { CallableClient_exports as CallableClient, ClientFunctions_exports as ClientFunctions };
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "@visiolab/effect-firebase-client",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.3.0",
4
+ "description": "Firebase client SDK implementation of the @visiolab/effect-firebase services.",
5
+ "keywords": [
6
+ "effect",
7
+ "firebase",
8
+ "typescript"
9
+ ],
10
+ "homepage": "https://github.com/VisioLab/effect-firebase",
11
+ "bugs": {
12
+ "url": "https://github.com/VisioLab/effect-firebase/issues"
13
+ },
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/VisioLab/effect-firebase.git",
18
+ "directory": "packages/client"
19
+ },
20
+ "files": [
21
+ "src/**/*.ts",
22
+ "dist/**/*.mjs",
23
+ "dist/**/*.mjs.map",
24
+ "dist/**/*.d.mts",
25
+ "dist/**/*.d.mts.map"
26
+ ],
27
+ "type": "module",
28
+ "sideEffects": [],
29
+ "exports": {
30
+ "./app": "./dist/app/index.mjs",
31
+ "./app/App": "./dist/app/App.mjs",
32
+ "./firestore": "./dist/firestore/index.mjs",
33
+ "./firestore/ClientDocumentSnapshot": "./dist/firestore/ClientDocumentSnapshot.mjs",
34
+ "./firestore/ClientFirestore": "./dist/firestore/ClientFirestore.mjs",
35
+ "./firestore/ClientFirestoreValue": "./dist/firestore/ClientFirestoreValue.mjs",
36
+ "./firestore/ClientQuerySnapshot": "./dist/firestore/ClientQuerySnapshot.mjs",
37
+ "./functions": "./dist/functions/index.mjs",
38
+ "./functions/CallableClient": "./dist/functions/CallableClient.mjs",
39
+ "./functions/ClientFunctions": "./dist/functions/ClientFunctions.mjs",
40
+ "./package.json": "./package.json"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "devDependencies": {
46
+ "@effect/vitest": "^4.1.0",
47
+ "effect": "4.1.0",
48
+ "firebase": "^13.0.0",
49
+ "typescript": "^7.0.2",
50
+ "vite": "npm:@voidzero-dev/vite-plus-core@1.4.0",
51
+ "vite-plus": "1.4.0",
52
+ "vitest": "5.0.5",
53
+ "@visiolab/effect-firebase": "^0.3.0"
54
+ },
55
+ "peerDependencies": {
56
+ "effect": "~4.1.0",
57
+ "firebase": "^13.0.0",
58
+ "@visiolab/effect-firebase": "^0.3.0"
59
+ },
60
+ "scripts": {
61
+ "build": "vp pack",
62
+ "dev": "vp pack --watch",
63
+ "test": "vp test",
64
+ "check": "vp check"
65
+ }
6
66
  }