effect-zero 0.8.0 → 0.9.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/README.md +84 -78
- package/dist/client.d.ts +38 -133
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +75 -23
- package/dist/client.js.map +1 -1
- package/dist/mutator.d.ts +117 -0
- package/dist/mutator.d.ts.map +1 -0
- package/dist/mutator.js +67 -0
- package/dist/mutator.js.map +1 -0
- package/dist/mutator.test.d.ts +2 -0
- package/dist/mutator.test.d.ts.map +1 -0
- package/dist/{client.test.js → mutator.test.js} +2 -2
- package/dist/mutator.test.js.map +1 -0
- package/dist/server.d.ts +7 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +27 -11
- package/dist/server.js.map +1 -1
- package/dist/types.test.js +114 -116
- package/dist/types.test.js.map +1 -1
- package/package.json +7 -7
- package/src/client.ts +159 -55
- package/src/mutator.ts +236 -0
- package/src/server.ts +43 -23
- package/dist/client.test.d.ts +0 -2
- package/dist/client.test.d.ts.map +0 -1
- package/dist/client.test.js.map +0 -1
- package/dist/mutators.d.ts +0 -30
- package/dist/mutators.d.ts.map +0 -1
- package/dist/mutators.js +0 -17
- package/dist/mutators.js.map +0 -1
- package/src/mutators.ts +0 -80
package/src/mutator.ts
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AnyMutatorRegistry,
|
|
3
|
+
MutateRequest as ZeroMutateRequest,
|
|
4
|
+
Schema as ZeroSchema,
|
|
5
|
+
Transaction as ZeroTransaction,
|
|
6
|
+
} from "@rocicorp/zero";
|
|
7
|
+
import * as Cause from "effect/Cause";
|
|
8
|
+
import * as Context from "effect/Context";
|
|
9
|
+
import * as Data from "effect/Data";
|
|
10
|
+
import * as Effect from "effect/Effect";
|
|
11
|
+
import type { NodeInspectSymbol } from "effect/Inspectable";
|
|
12
|
+
import * as Predicate from "effect/Predicate";
|
|
13
|
+
import * as Rec from "effect/Record";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import type * as Unify from "effect/Unify";
|
|
16
|
+
import type * as ClientTransaction from "./client-transaction.js";
|
|
17
|
+
import { ContextSymbol } from "./client-transaction.js";
|
|
18
|
+
import { prefixId } from "./internal/utils.js";
|
|
19
|
+
|
|
20
|
+
type _NodeInspectSymbol = NodeInspectSymbol;
|
|
21
|
+
type _Unify = Unify.typeSymbol | Unify.unifySymbol | Unify.ignoreSymbol;
|
|
22
|
+
|
|
23
|
+
export const RegistryTypeId = Symbol.for(prefixId("MutatorRegistry"));
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A mutator that isn't part of a registry yet, made with {@link make}. Like `defineMutator`, it gets its name
|
|
27
|
+
* from its path in the {@link registry}. `R` is the services its body requires, and `RD` the services decoding its
|
|
28
|
+
* payload requires.
|
|
29
|
+
*/
|
|
30
|
+
export interface Definition<Type, Encoded, E, R, RD = never> {
|
|
31
|
+
readonly payload: Schema.Codec<Type, Encoded, RD>;
|
|
32
|
+
readonly mutator: (args: Type) => Effect.Effect<unknown, E, R>;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
36
|
+
export type AnyDefinition = Definition<any, any, any, any, any>;
|
|
37
|
+
|
|
38
|
+
export type Definitions = { readonly [key: string]: AnyDefinition | Definitions };
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A registered mutator. Calling it encodes `args` and returns a request for `ZfxClient.mutate(zero, request)`, or
|
|
42
|
+
* for Zero's own `zero.mutate(request)`. It is also a Zero `Mutator`, so the registry can be passed to Zero.
|
|
43
|
+
*/
|
|
44
|
+
export interface Mutator<Type, Encoded, E, R, RD = never> extends Definition<Type, Encoded, E, R, RD> {
|
|
45
|
+
(args: Type): MutateRequest<Type>;
|
|
46
|
+
readonly mutatorName: string;
|
|
47
|
+
/** Runs the mutator for Zero, which calls it with the transaction and the `context` from `ZfxClient.make`. */
|
|
48
|
+
readonly fn: (options: {
|
|
49
|
+
readonly args: unknown;
|
|
50
|
+
readonly ctx: unknown;
|
|
51
|
+
readonly tx: ZeroTransaction<ZeroSchema>;
|
|
52
|
+
}) => Promise<void>;
|
|
53
|
+
readonly "~": "Mutator";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
57
|
+
export type AnyMutator = Mutator<any, any, any, any, any>;
|
|
58
|
+
|
|
59
|
+
/** A request to run a mutator, for `ZfxClient.mutate` or Zero's own `zero.mutate`. */
|
|
60
|
+
// biome-ignore lint/suspicious/noExplicitAny: compatible with any Zero instance's `zero.mutate`
|
|
61
|
+
export type MutateRequest<Type> = ZeroMutateRequest<any, any, any, any> & {
|
|
62
|
+
// biome-ignore lint/suspicious/noExplicitAny: the encoded args, errors and services don't matter to the caller
|
|
63
|
+
readonly mutator: Mutator<Type, any, any, any>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type Tree<D> = {
|
|
67
|
+
readonly [K in keyof D]: D[K] extends Definition<infer Type, infer Encoded, infer E, infer R, infer RD>
|
|
68
|
+
? Mutator<Type, Encoded, E, R, RD>
|
|
69
|
+
: Tree<D[K]>;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/** A tree of registered mutators, made with {@link registry}. Pass it to `ZfxClient.make` and the server. */
|
|
73
|
+
export type Registry<D extends Definitions, TTransaction extends AnyClientTransaction> = Tree<D> & {
|
|
74
|
+
readonly "~": AnyMutatorRegistry["~"];
|
|
75
|
+
readonly [RegistryTypeId]: { readonly transaction: TTransaction };
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
79
|
+
export type AnyRegistry = Registry<any, AnyClientTransaction>;
|
|
80
|
+
|
|
81
|
+
// biome-ignore lint/suspicious/noExplicitAny: any client transaction
|
|
82
|
+
type AnyClientTransaction = ClientTransaction.Context<any>;
|
|
83
|
+
|
|
84
|
+
type Keys<T> = Exclude<Extract<keyof T, string>, "~">;
|
|
85
|
+
|
|
86
|
+
/** The services a registry's mutators require: their bodies' and their payloads'. */
|
|
87
|
+
// biome-ignore lint/suspicious/noExplicitAny: matches any mutator
|
|
88
|
+
export type Requirements<T> = T extends Mutator<any, any, any, infer R, infer RD>
|
|
89
|
+
? R | RD
|
|
90
|
+
: { [K in Keys<T>]: Requirements<T[K]> }[Keys<T>];
|
|
91
|
+
|
|
92
|
+
/** The client transaction a registry's mutators run in. */
|
|
93
|
+
export type Transaction<T extends AnyRegistry> = T[typeof RegistryTypeId]["transaction"];
|
|
94
|
+
|
|
95
|
+
/** The Zero schema a registry's mutators run against. */
|
|
96
|
+
export type ZeroSchemaOf<T extends AnyRegistry> = Transaction<T> extends ClientTransaction.Context<infer S> ? S : never;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Defines a mutator. Its `payload` codec decodes the args on both the client and the server; it must encode without
|
|
100
|
+
* services, since calling a registered mutator encodes its args synchronously.
|
|
101
|
+
*/
|
|
102
|
+
export const make = <Type, Encoded, RD = never, A = unknown, E = never, R = never>(options: {
|
|
103
|
+
readonly payload: Schema.Codec<Type, Encoded, RD, never>;
|
|
104
|
+
readonly mutator: (args: NoInfer<Type>) => Effect.Effect<A, E, R>;
|
|
105
|
+
}): Definition<Type, Encoded, E, R, RD> => options;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Registers mutators under their path, like Zero's `defineMutators`: `{ todo: { create } }` registers
|
|
109
|
+
* `"todo.create"`. The result is also a Zero mutator registry, so it can be passed to `new Zero({ mutators })`.
|
|
110
|
+
*/
|
|
111
|
+
export const registry = <TTransaction extends AnyClientTransaction, const D extends Definitions>(
|
|
112
|
+
transaction: TTransaction,
|
|
113
|
+
definitions: D,
|
|
114
|
+
): Registry<D, TTransaction> => {
|
|
115
|
+
const register = (definitions: Definitions, path: ReadonlyArray<string>): Record<string, unknown> =>
|
|
116
|
+
Rec.map(definitions, (value, key) =>
|
|
117
|
+
isDefinition(value) ? makeMutator(transaction, [...path, key].join("."), value) : register(value, [...path, key]),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// The registry's shape is only known from `D`.
|
|
121
|
+
return Object.assign(register(definitions, []), {
|
|
122
|
+
"~": "MutatorRegistry",
|
|
123
|
+
[RegistryTypeId]: { transaction },
|
|
124
|
+
}) as unknown as Registry<D, TTransaction>;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const isDefinition = (u: unknown): u is AnyDefinition =>
|
|
128
|
+
Predicate.hasProperty(u, "payload") && Schema.isSchema(u.payload);
|
|
129
|
+
|
|
130
|
+
const makeMutator = <Type, Encoded, E, R, RD>(
|
|
131
|
+
transaction: AnyClientTransaction,
|
|
132
|
+
name: string,
|
|
133
|
+
definition: Definition<Type, Encoded, E, R, RD>,
|
|
134
|
+
): Mutator<Type, Encoded, E, R, RD> => {
|
|
135
|
+
const run = (args: unknown, tx: ZeroTransaction<ZeroSchema>) =>
|
|
136
|
+
Schema.decodeUnknownEffect(definition.payload)(args).pipe(
|
|
137
|
+
Effect.catchTag("SchemaError", (error) => new ClientArgsParseError({ cause: Cause.fail(error) })),
|
|
138
|
+
Effect.flatMap(definition.mutator),
|
|
139
|
+
Effect.withSpan("zero.mutator", {
|
|
140
|
+
attributes: {
|
|
141
|
+
"zero.mutator": name,
|
|
142
|
+
"zero.clientID": tx.clientID,
|
|
143
|
+
"zero.mutationID": tx.mutationID,
|
|
144
|
+
"zero.mutation.reason": tx.reason,
|
|
145
|
+
},
|
|
146
|
+
}),
|
|
147
|
+
Effect.provideService(transaction[ContextSymbol], tx),
|
|
148
|
+
Effect.asVoid,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
const mutator: Mutator<Type, Encoded, E, R, RD> = Object.assign(
|
|
152
|
+
(args: Type) =>
|
|
153
|
+
// A Zero `MutateRequest`, whose brand only exists at the type level.
|
|
154
|
+
({ mutator, args: Schema.encodeSync(definition.payload)(args), "~": "MutateRequest" }) as MutateRequest<Type>,
|
|
155
|
+
{
|
|
156
|
+
...definition,
|
|
157
|
+
mutatorName: name,
|
|
158
|
+
"~": "Mutator" as const,
|
|
159
|
+
fn: ({
|
|
160
|
+
args,
|
|
161
|
+
ctx,
|
|
162
|
+
tx,
|
|
163
|
+
}: {
|
|
164
|
+
readonly args: unknown;
|
|
165
|
+
readonly ctx: unknown;
|
|
166
|
+
readonly tx: ZeroTransaction<ZeroSchema>;
|
|
167
|
+
}) =>
|
|
168
|
+
Context.isContext(ctx)
|
|
169
|
+
? // `ZfxClient.make` passes the services it captured, which cover every mutator's requirements.
|
|
170
|
+
run(args, tx).pipe(Effect.runPromiseWith(ctx as Context.Context<R | RD>))
|
|
171
|
+
: Promise.reject(new MutatorContextNotFound({ mutator: name })),
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
return mutator;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type Overrides<T> = {
|
|
178
|
+
readonly [K in Keys<T>]?: T[K] extends Mutator<infer Type, infer _Encoded, infer _E, infer _R, infer _RD>
|
|
179
|
+
? // biome-ignore lint/suspicious/noExplicitAny: any server implementation
|
|
180
|
+
(args: Type) => Effect.Effect<unknown, any, any>
|
|
181
|
+
: Overrides<T[K]>;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/** The server's view of a registry, made with {@link server}. */
|
|
185
|
+
export interface ServerMutators<TRegistry extends AnyRegistry, O> {
|
|
186
|
+
readonly registry: TRegistry;
|
|
187
|
+
readonly overrides: O;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type AnyServerMutators = ServerMutators<AnyRegistry, unknown>;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The registry's mutators as the server runs them, for `ZfxServer.handleMutate`. `overrides` replaces some mutators'
|
|
194
|
+
* bodies, like Zero's `defineMutators(base, overrides)`; every other mutator runs its shared body in a server
|
|
195
|
+
* transaction, so pass `{}` if nothing differs. An override runs outside the transaction, so it can do work before
|
|
196
|
+
* and after `serverTransaction.execute`, e.g. `registry.todo.create.mutator(args).pipe(serverTransaction.execute)`.
|
|
197
|
+
*/
|
|
198
|
+
export const server = <TRegistry extends AnyRegistry, const O extends Overrides<TRegistry>>(
|
|
199
|
+
registry: TRegistry,
|
|
200
|
+
overrides: O,
|
|
201
|
+
): ServerMutators<TRegistry, O> => ({ registry, overrides });
|
|
202
|
+
|
|
203
|
+
// biome-ignore lint/suspicious/noExplicitAny: matches any mutator
|
|
204
|
+
type PayloadRequirements<T> = T extends Mutator<any, any, any, any, infer RD> ? RD : never;
|
|
205
|
+
|
|
206
|
+
type ServerTreeRequirements<T, O, ClientTransactionId> = {
|
|
207
|
+
[K in Keys<T>]: T[K] extends AnyMutator
|
|
208
|
+
? K extends keyof O
|
|
209
|
+
? O[K] extends (args: never) => Effect.Effect<infer _A, infer _E, infer R>
|
|
210
|
+
? R | PayloadRequirements<T[K]>
|
|
211
|
+
: never
|
|
212
|
+
: Exclude<Requirements<T[K]>, ClientTransactionId>
|
|
213
|
+
: ServerTreeRequirements<T[K], K extends keyof O ? O[K] : unknown, ClientTransactionId>;
|
|
214
|
+
}[Keys<T>];
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* The services the server needs to run these mutators. Mutators that aren't overridden run in a server transaction,
|
|
218
|
+
* which provides their client transaction. Every mutator's payload is decoded on the server, overridden or not.
|
|
219
|
+
*/
|
|
220
|
+
export type ServerRequirements<T extends AnyServerMutators> = T extends ServerMutators<infer TRegistry, infer O>
|
|
221
|
+
? ServerTreeRequirements<TRegistry, O, Transaction<TRegistry>[typeof ContextSymbol]["Identifier"]>
|
|
222
|
+
: never;
|
|
223
|
+
|
|
224
|
+
export class ClientArgsParseError extends Data.TaggedError("ClientArgsParseError")<{
|
|
225
|
+
readonly cause: Cause.Cause<unknown>;
|
|
226
|
+
}> {
|
|
227
|
+
override get message() {
|
|
228
|
+
const error = Cause.squash(this.cause);
|
|
229
|
+
return Predicate.isError(error) && !Schema.isSchemaError(error) ? error.message : "Internal error";
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** A mutator ran on a Zero instance that wasn't made with `ZfxClient.make`. */
|
|
234
|
+
export class MutatorContextNotFound extends Data.TaggedError("MutatorContextNotFound")<{
|
|
235
|
+
readonly mutator: string;
|
|
236
|
+
}> {}
|
package/src/server.ts
CHANGED
|
@@ -10,10 +10,8 @@ import * as Data from "effect/Data";
|
|
|
10
10
|
import * as Deferred from "effect/Deferred";
|
|
11
11
|
import * as Effect from "effect/Effect";
|
|
12
12
|
import * as Exit from "effect/Exit";
|
|
13
|
-
import * as Fn from "effect/Function";
|
|
14
13
|
import type { NodeInspectSymbol } from "effect/Inspectable";
|
|
15
14
|
import * as Layer from "effect/Layer";
|
|
16
|
-
import * as Match from "effect/Match";
|
|
17
15
|
import * as Option from "effect/Option";
|
|
18
16
|
import * as Predicate from "effect/Predicate";
|
|
19
17
|
import * as Rec from "effect/Record";
|
|
@@ -22,7 +20,7 @@ import * as Str from "effect/String";
|
|
|
22
20
|
import type * as Unify from "effect/Unify";
|
|
23
21
|
import { TransactCallbackNotInvokedError, TransactInternalError } from "./internal/server.js";
|
|
24
22
|
import * as ServerSynchronizationContext from "./internal/server-synchronization-context.js";
|
|
25
|
-
import * as
|
|
23
|
+
import type * as Mutator from "./mutator.js";
|
|
26
24
|
import { type MakeQueryResult, QueryNameSymbol, RunQuerySymbol } from "./query.js";
|
|
27
25
|
import type * as ServerTransaction from "./server-transaction.js";
|
|
28
26
|
import { DatabaseSymbol, ServerTransactionCallbackSymbol } from "./server-transaction.js";
|
|
@@ -43,10 +41,14 @@ type _Unify = Unify.typeSymbol | Unify.unifySymbol | Unify.ignoreSymbol;
|
|
|
43
41
|
type MutateUserId = Extract<Awaited<ReturnType<typeof handleMutateRequest>>, { kind: "MutateResponse" }>["userID"];
|
|
44
42
|
type QueryUserId = Extract<Awaited<ReturnType<typeof handleQueryRequest>>, { kind: "QueryResponse" }>["userID"];
|
|
45
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Handles Zero's push endpoint, running each mutation's server implementation: its override from
|
|
46
|
+
* `ZfxMutator.server`, or else its shared body in a server transaction.
|
|
47
|
+
*/
|
|
46
48
|
export const handleMutate = Effect.fn(function* <
|
|
47
49
|
TSchema extends ZeroSchema,
|
|
48
50
|
TTransaction,
|
|
49
|
-
TMutators extends
|
|
51
|
+
TMutators extends Mutator.AnyServerMutators,
|
|
50
52
|
>({
|
|
51
53
|
transaction,
|
|
52
54
|
mutators,
|
|
@@ -63,7 +65,7 @@ export const handleMutate = Effect.fn(function* <
|
|
|
63
65
|
const ctx =
|
|
64
66
|
yield* Effect.context<
|
|
65
67
|
Exclude<
|
|
66
|
-
|
|
68
|
+
Mutator.ServerRequirements<TMutators>,
|
|
67
69
|
| (typeof transaction)[typeof ServerTransactionCallbackSymbol]["Identifier"]
|
|
68
70
|
| ServerSynchronizationContext.ServerSynchronizationContext
|
|
69
71
|
>
|
|
@@ -102,14 +104,19 @@ export const handleMutate = Effect.fn(function* <
|
|
|
102
104
|
);
|
|
103
105
|
}, ServerSynchronizationContext.guard);
|
|
104
106
|
|
|
105
|
-
const exit: Exit.Exit<unknown, unknown> = yield* runMutation
|
|
106
|
-
Mutators.ExtractMutatorsRequirements<TMutators>
|
|
107
|
-
>(mutators, mutation).pipe(
|
|
107
|
+
const exit: Exit.Exit<unknown, unknown> = yield* runMutation(mutators, transaction, mutation).pipe(
|
|
108
108
|
ServerSynchronizationContext.finalize,
|
|
109
109
|
Effect.provide([
|
|
110
110
|
Layer.succeed(transaction[ServerTransactionCallbackSymbol], { transact }),
|
|
111
111
|
ServerSynchronizationContext.layer,
|
|
112
112
|
]),
|
|
113
|
+
Effect.withSpan("zero.mutation.handle", {
|
|
114
|
+
attributes: {
|
|
115
|
+
"zero.mutator": mutation.name,
|
|
116
|
+
"zero.clientID": mutation.clientID,
|
|
117
|
+
"zero.mutationID": mutation.id,
|
|
118
|
+
},
|
|
119
|
+
}),
|
|
113
120
|
Effect.exit,
|
|
114
121
|
);
|
|
115
122
|
|
|
@@ -139,28 +146,41 @@ export const handleMutate = Effect.fn(function* <
|
|
|
139
146
|
});
|
|
140
147
|
});
|
|
141
148
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
149
|
+
/**
|
|
150
|
+
* Runs a mutation: its override if it has one, or else its shared body in a server transaction. Like upstream, names
|
|
151
|
+
* are split on "." or "|" (the separator of Zero's legacy custom mutators), at any depth. Their services aren't tracked
|
|
152
|
+
* from here on: `handleMutate` already requires every implementation's.
|
|
153
|
+
*/
|
|
154
|
+
const runMutation = Effect.fn(function* <TSchema extends ZeroSchema, TTransaction>(
|
|
155
|
+
mutators: Mutator.AnyServerMutators,
|
|
156
|
+
transaction: ServerTransaction.Context<TSchema, TTransaction>,
|
|
157
|
+
mutation: Mutation,
|
|
158
|
+
) {
|
|
159
|
+
const { registry, overrides } = Rec.map(mutators, (root) =>
|
|
160
|
+
Arr.reduce(Str.split(mutation.name, /[.|]/), Option.some(root), (tree, key) =>
|
|
161
|
+
// Only an object has keys to walk into; the checks below make sure the walk ended at a mutator.
|
|
162
|
+
tree.pipe(Option.filter(Predicate.isObject), Option.flatMap(Rec.get(key))),
|
|
163
|
+
),
|
|
164
|
+
);
|
|
165
|
+
const mutator = yield* registry.pipe(
|
|
166
|
+
Option.filter(
|
|
167
|
+
(u): u is Mutator.Mutator<unknown, unknown, unknown, never> =>
|
|
168
|
+
Predicate.isFunction(u) && Predicate.hasProperty(u, "mutatorName"),
|
|
155
169
|
),
|
|
156
170
|
Effect.fromOption(() => new MutatorNotFoundError({ name: mutation.name })),
|
|
157
171
|
);
|
|
158
172
|
|
|
159
|
-
const args = yield* Schema.decodeUnknownEffect(mutator
|
|
173
|
+
const args = yield* Schema.decodeUnknownEffect(mutator.payload)(mutation.args[0]).pipe(
|
|
160
174
|
Effect.catchTag("SchemaError", (e) => Effect.fail(new ServerArgsParseError({ cause: Cause.fail(e) }))),
|
|
161
175
|
);
|
|
162
176
|
|
|
163
|
-
return yield*
|
|
177
|
+
return yield* overrides.pipe(
|
|
178
|
+
Option.filter((u): u is (args: unknown) => Effect.Effect<unknown, unknown> => Predicate.isFunction(u)),
|
|
179
|
+
Option.match({
|
|
180
|
+
onNone: () => transaction.execute(mutator.mutator(args)),
|
|
181
|
+
onSome: (run) => run(args),
|
|
182
|
+
}),
|
|
183
|
+
);
|
|
164
184
|
});
|
|
165
185
|
|
|
166
186
|
export const makeApplicationError = (cause: Cause.Cause<unknown>) => {
|
package/dist/client.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":""}
|
package/dist/client.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.test.js","sourceRoot":"","sources":["../src/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,sGAAsG;IACtG,wGAAwG;IACxG,4CAA4C;IAC5C,EAAE,CAAC,MAAM,CACP,wDAAwD,EACxD,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE;QAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtG,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO;QAElC,MAAM,KAAK,GAAG,IAAI,oBAAoB,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAE9D,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC/C,CAAC,CAAC,CACH,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/dist/mutators.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type * as Effect from "effect/Effect";
|
|
2
|
-
import * as Schema from "effect/Schema";
|
|
3
|
-
export type AnyMutatorFn<R = any, TArgs extends any[] = any[]> = (...args: TArgs) => Effect.Effect<any, any, R>;
|
|
4
|
-
export type AnyMutatorFns<R = any> = {
|
|
5
|
-
[K: string]: AnyMutatorFn<R> | {
|
|
6
|
-
[K: string]: AnyMutatorFn<R>;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
export type AnyMutatorSchema = Schema.Codec<any, any>;
|
|
10
|
-
export type AnyMutatorSchemas = Record<string, AnyMutatorSchema | Record<string, AnyMutatorSchema>>;
|
|
11
|
-
export type MutatorFns<TSchema extends AnyMutatorSchemas> = {
|
|
12
|
-
[K in keyof TSchema]: TSchema[K] extends AnyMutatorSchema ? AnyMutatorFn<unknown, [Schema.Schema.Type<TSchema[K]>]> : TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchema> ? {
|
|
13
|
-
[K in keyof TSchema]: AnyMutatorFn<unknown, [Schema.Schema.Type<TSchema[K]>]>;
|
|
14
|
-
} : never;
|
|
15
|
-
};
|
|
16
|
-
export declare const MutatorSchemaSymbol: unique symbol;
|
|
17
|
-
export type Mutator<TFunc extends AnyMutatorFn = AnyMutatorFn, TSchema extends AnyMutatorSchema = AnyMutatorSchema> = TFunc & {
|
|
18
|
-
[MutatorSchemaSymbol]: TSchema;
|
|
19
|
-
};
|
|
20
|
-
export type Mutators<TSchema extends AnyMutatorSchemas, TFns extends AnyMutatorFns> = {
|
|
21
|
-
[K in keyof TFns & keyof TSchema]: TFns[K] extends AnyMutatorFn ? TSchema[K] extends AnyMutatorSchema ? Mutator<TFns[K], TSchema[K]> : never : TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchema> ? TFns[K] extends infer TFns extends Record<string, AnyMutatorFn> ? {
|
|
22
|
-
[K in keyof TFns & keyof TSchema]: Mutator<TFns[K], TSchema[K]>;
|
|
23
|
-
} : never : never;
|
|
24
|
-
} & {};
|
|
25
|
-
export type AnyMutator<R = any, E = any> = Mutator<(...args: any[]) => Effect.Effect<any, E, R>>;
|
|
26
|
-
export type AnyMutators<R = any> = Record<string, AnyMutator<R> | Record<string, AnyMutator<R>>>;
|
|
27
|
-
export type ExtractMutatorsRequirements<TMutators extends AnyMutators> = TMutators extends AnyMutators<infer R> ? R : never;
|
|
28
|
-
export declare const schema: <TSchema extends AnyMutatorSchemas>(schema: TSchema) => TSchema;
|
|
29
|
-
export declare function make<TSchema extends AnyMutatorSchemas, TFns extends MutatorFns<TSchema>>(schema: TSchema, mutators: TFns): Mutators<TSchema, TFns>;
|
|
30
|
-
//# sourceMappingURL=mutators.d.ts.map
|
package/dist/mutators.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mutators.d.ts","sourceRoot":"","sources":["../src/mutators.ts"],"names":[],"mappings":"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"}
|
package/dist/mutators.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import * as Match from "effect/Match";
|
|
2
|
-
import * as Option from "effect/Option";
|
|
3
|
-
import * as Predicate from "effect/Predicate";
|
|
4
|
-
import * as Rec from "effect/Record";
|
|
5
|
-
import * as Schema from "effect/Schema";
|
|
6
|
-
import { prefixId } from "./internal/utils.js";
|
|
7
|
-
export const MutatorSchemaSymbol = Symbol.for(prefixId("MutatorSchema"));
|
|
8
|
-
export const schema = (schema) => schema;
|
|
9
|
-
export function make(schema, mutators) {
|
|
10
|
-
function makeMutator(schema, fn) {
|
|
11
|
-
return Object.assign(fn, { [MutatorSchemaSymbol]: schema });
|
|
12
|
-
}
|
|
13
|
-
return Rec.map(mutators, (v, name) => {
|
|
14
|
-
return Match.value([v, schema[name]]).pipe(Match.when([Predicate.isFunction, Schema.isSchema], ([mutator, schema]) => makeMutator(schema, mutator)), Match.when([Predicate.isObject, Predicate.isObject], ([mutator, schema]) => Rec.map(mutator, (mutator, name) => makeMutator(Option.getOrThrow(Rec.get(schema, name)), mutator))), Match.orElseAbsurd);
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=mutators.js.map
|
package/dist/mutators.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mutators.js","sourceRoot":"","sources":["../src/mutators.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,GAAG,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAsB/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC;AA+BzE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAoC,MAAe,EAAE,EAAE,CAAC,MAAM,CAAC;AAMrF,MAAM,UAAU,IAAI,CAAC,MAAyB,EAAE,QAAuB;IACrE,SAAS,WAAW,CAAC,MAAwB,EAAE,EAAgB;QAC7D,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE;QACnC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CACxC,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACxG,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,CACzE,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CACpG,EACD,KAAK,CAAC,YAAY,CACnB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/src/mutators.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import type * as Effect from "effect/Effect";
|
|
2
|
-
import * as Match from "effect/Match";
|
|
3
|
-
import * as Option from "effect/Option";
|
|
4
|
-
import * as Predicate from "effect/Predicate";
|
|
5
|
-
import * as Rec from "effect/Record";
|
|
6
|
-
import * as Schema from "effect/Schema";
|
|
7
|
-
import { prefixId } from "./internal/utils.js";
|
|
8
|
-
|
|
9
|
-
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
10
|
-
export type AnyMutatorFn<R = any, TArgs extends any[] = any[]> = (...args: TArgs) => Effect.Effect<any, any, R>;
|
|
11
|
-
|
|
12
|
-
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
13
|
-
export type AnyMutatorFns<R = any> = {
|
|
14
|
-
[K: string]: AnyMutatorFn<R> | { [K: string]: AnyMutatorFn<R> };
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
18
|
-
export type AnyMutatorSchema = Schema.Codec<any, any>;
|
|
19
|
-
export type AnyMutatorSchemas = Record<string, AnyMutatorSchema | Record<string, AnyMutatorSchema>>;
|
|
20
|
-
|
|
21
|
-
export type MutatorFns<TSchema extends AnyMutatorSchemas> = {
|
|
22
|
-
[K in keyof TSchema]: TSchema[K] extends AnyMutatorSchema
|
|
23
|
-
? AnyMutatorFn<unknown, [Schema.Schema.Type<TSchema[K]>]>
|
|
24
|
-
: TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchema>
|
|
25
|
-
? { [K in keyof TSchema]: AnyMutatorFn<unknown, [Schema.Schema.Type<TSchema[K]>]> }
|
|
26
|
-
: never;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const MutatorSchemaSymbol = Symbol.for(prefixId("MutatorSchema"));
|
|
30
|
-
|
|
31
|
-
export type Mutator<
|
|
32
|
-
TFunc extends AnyMutatorFn = AnyMutatorFn,
|
|
33
|
-
TSchema extends AnyMutatorSchema = AnyMutatorSchema,
|
|
34
|
-
> = TFunc & {
|
|
35
|
-
[MutatorSchemaSymbol]: TSchema;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type Mutators<TSchema extends AnyMutatorSchemas, TFns extends AnyMutatorFns> = {
|
|
39
|
-
[K in keyof TFns & keyof TSchema]: TFns[K] extends AnyMutatorFn
|
|
40
|
-
? TSchema[K] extends AnyMutatorSchema
|
|
41
|
-
? Mutator<TFns[K], TSchema[K]>
|
|
42
|
-
: never
|
|
43
|
-
: TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchema>
|
|
44
|
-
? TFns[K] extends infer TFns extends Record<string, AnyMutatorFn>
|
|
45
|
-
? { [K in keyof TFns & keyof TSchema]: Mutator<TFns[K], TSchema[K]> }
|
|
46
|
-
: never
|
|
47
|
-
: never;
|
|
48
|
-
} & {};
|
|
49
|
-
|
|
50
|
-
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
51
|
-
export type AnyMutator<R = any, E = any> = Mutator<(...args: any[]) => Effect.Effect<any, E, R>>;
|
|
52
|
-
|
|
53
|
-
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
54
|
-
export type AnyMutators<R = any> = Record<string, AnyMutator<R> | Record<string, AnyMutator<R>>>;
|
|
55
|
-
|
|
56
|
-
export type ExtractMutatorsRequirements<TMutators extends AnyMutators> = TMutators extends AnyMutators<infer R>
|
|
57
|
-
? R
|
|
58
|
-
: never;
|
|
59
|
-
|
|
60
|
-
export const schema = <TSchema extends AnyMutatorSchemas>(schema: TSchema) => schema;
|
|
61
|
-
|
|
62
|
-
export function make<TSchema extends AnyMutatorSchemas, TFns extends MutatorFns<TSchema>>(
|
|
63
|
-
schema: TSchema,
|
|
64
|
-
mutators: TFns,
|
|
65
|
-
): Mutators<TSchema, TFns>;
|
|
66
|
-
export function make(schema: AnyMutatorSchemas, mutators: AnyMutatorFns): AnyMutators {
|
|
67
|
-
function makeMutator(schema: AnyMutatorSchema, fn: AnyMutatorFn) {
|
|
68
|
-
return Object.assign(fn, { [MutatorSchemaSymbol]: schema });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return Rec.map(mutators, (v, name) => {
|
|
72
|
-
return Match.value([v, schema[name]]).pipe(
|
|
73
|
-
Match.when([Predicate.isFunction, Schema.isSchema], ([mutator, schema]) => makeMutator(schema, mutator)),
|
|
74
|
-
Match.when([Predicate.isObject, Predicate.isObject], ([mutator, schema]) =>
|
|
75
|
-
Rec.map(mutator, (mutator, name) => makeMutator(Option.getOrThrow(Rec.get(schema, name)), mutator)),
|
|
76
|
-
),
|
|
77
|
-
Match.orElseAbsurd,
|
|
78
|
-
);
|
|
79
|
-
});
|
|
80
|
-
}
|