effect-zero 0.0.0-alpha.0 → 0.1.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.
- package/LICENSE +1 -1
- package/README.md +187 -0
- package/dist/client.d.ts +47 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +61 -0
- package/dist/client.js.map +1 -0
- package/dist/mutators.d.ts +35 -0
- package/dist/mutators.d.ts.map +1 -0
- package/dist/mutators.js +26 -0
- package/dist/mutators.js.map +1 -0
- package/dist/server.d.ts +188 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +235 -0
- package/dist/server.js.map +1 -0
- package/dist/snapshot.d.ts +10 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +67 -0
- package/dist/snapshot.js.map +1 -0
- package/dist/types.d.ts +174 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +151 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +5 -0
- package/dist/utils.js.map +1 -0
- package/package.json +64 -15
- package/src/client.ts +130 -0
- package/src/mutators.ts +82 -0
- package/src/server.ts +377 -0
- package/src/snapshot.ts +91 -0
- package/src/types.ts +201 -0
- package/src/utils.ts +4 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
// The code below was converted to Effect Schema from:
|
|
3
|
+
// https://github.com/rocicorp/mono/blob/30f209f2946b4cf2cd2dee459849351498f11308/packages/zero-protocol/src/push.ts
|
|
4
|
+
/** TODO: Defined as unknown for now */
|
|
5
|
+
const JsonSchema = Schema.Unknown;
|
|
6
|
+
const ZeroPrimaryKey = Schema.Array(Schema.String);
|
|
7
|
+
const ZeroPrimaryKeyValue = Schema.Union(Schema.String, Schema.Number, Schema.Boolean);
|
|
8
|
+
const ZeroPrimaryKeyValueRecord = Schema.Record({ key: Schema.String, value: ZeroPrimaryKeyValue });
|
|
9
|
+
const ZeroValue = Schema.Union(JsonSchema, Schema.Undefined);
|
|
10
|
+
const ZeroRow = Schema.Record({ key: Schema.String, value: ZeroValue });
|
|
11
|
+
const CRUD_MUTATION_NAME = "_zero_crud";
|
|
12
|
+
/**
|
|
13
|
+
* Inserts if entity with id does not already exist.
|
|
14
|
+
*/
|
|
15
|
+
const ZeroInsertOp = Schema.Struct({
|
|
16
|
+
op: Schema.Literal("insert"),
|
|
17
|
+
tableName: Schema.String,
|
|
18
|
+
primaryKey: ZeroPrimaryKey,
|
|
19
|
+
value: ZeroRow,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Upsert semantics. Inserts if entity with id does not already exist,
|
|
23
|
+
* otherwise updates existing entity with id.
|
|
24
|
+
*/
|
|
25
|
+
const ZeroUpsertOp = Schema.Struct({
|
|
26
|
+
op: Schema.Literal("upsert"),
|
|
27
|
+
tableName: Schema.String,
|
|
28
|
+
primaryKey: ZeroPrimaryKey,
|
|
29
|
+
value: ZeroRow,
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* Updates if entity with id exists, otherwise does nothing.
|
|
33
|
+
*/
|
|
34
|
+
const ZeroUpdateOp = Schema.Struct({
|
|
35
|
+
op: Schema.Literal("update"),
|
|
36
|
+
tableName: Schema.String,
|
|
37
|
+
primaryKey: ZeroPrimaryKey,
|
|
38
|
+
// Partial value with at least the primary key fields
|
|
39
|
+
value: ZeroRow,
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Deletes entity with id if it exists, otherwise does nothing.
|
|
43
|
+
*/
|
|
44
|
+
const ZeroDeleteOp = Schema.Struct({
|
|
45
|
+
op: Schema.Literal("delete"),
|
|
46
|
+
tableName: Schema.String,
|
|
47
|
+
primaryKey: ZeroPrimaryKey,
|
|
48
|
+
// Partial value representing the primary key
|
|
49
|
+
value: ZeroPrimaryKeyValueRecord,
|
|
50
|
+
});
|
|
51
|
+
const ZeroCrudOp = Schema.Union(ZeroInsertOp, ZeroUpsertOp, ZeroUpdateOp, ZeroDeleteOp);
|
|
52
|
+
const ZeroCrudArg = Schema.Struct({
|
|
53
|
+
ops: Schema.Array(ZeroCrudOp),
|
|
54
|
+
});
|
|
55
|
+
const ZeroCrudArgs = Schema.Tuple(ZeroCrudArg);
|
|
56
|
+
const ZeroCrudMutation = Schema.Struct({
|
|
57
|
+
type: Schema.Literal("crud"),
|
|
58
|
+
id: Schema.Number,
|
|
59
|
+
clientID: Schema.String,
|
|
60
|
+
name: Schema.Literal(CRUD_MUTATION_NAME),
|
|
61
|
+
args: ZeroCrudArgs,
|
|
62
|
+
timestamp: Schema.Number,
|
|
63
|
+
});
|
|
64
|
+
const ZeroCustomMutation = Schema.Struct({
|
|
65
|
+
type: Schema.Literal("custom"),
|
|
66
|
+
id: Schema.Number,
|
|
67
|
+
clientID: Schema.String,
|
|
68
|
+
name: Schema.String,
|
|
69
|
+
args: Schema.Array(JsonSchema),
|
|
70
|
+
timestamp: Schema.Number,
|
|
71
|
+
});
|
|
72
|
+
export const ZeroMutation = Schema.Union(ZeroCrudMutation, ZeroCustomMutation);
|
|
73
|
+
export const ZeroPushBody = Schema.Struct({
|
|
74
|
+
clientGroupID: Schema.String,
|
|
75
|
+
mutations: Schema.Array(ZeroMutation),
|
|
76
|
+
pushVersion: Schema.Number,
|
|
77
|
+
// For legacy (CRUD) mutations, the schema is tied to the client group /
|
|
78
|
+
// sync connection. For custom mutations, schema versioning is delegated
|
|
79
|
+
// to the custom protocol / api-server.
|
|
80
|
+
schemaVersion: Schema.optional(Schema.Number),
|
|
81
|
+
timestamp: Schema.Number,
|
|
82
|
+
requestID: Schema.String,
|
|
83
|
+
});
|
|
84
|
+
// biome-ignore lint/correctness/noUnusedVariables: borrowed code
|
|
85
|
+
const ZeroPushMessage = Schema.Tuple(Schema.Literal("push"), ZeroPushBody);
|
|
86
|
+
const ZeroMutationId = Schema.Struct({
|
|
87
|
+
id: Schema.Number,
|
|
88
|
+
clientID: Schema.String,
|
|
89
|
+
});
|
|
90
|
+
export const ZeroAppError = Schema.Struct({
|
|
91
|
+
error: Schema.Literal("app"),
|
|
92
|
+
// The user can return any additional data here
|
|
93
|
+
details: Schema.optional(JsonSchema),
|
|
94
|
+
});
|
|
95
|
+
export const ZeroError = Schema.Struct({
|
|
96
|
+
error: Schema.Union(Schema.Literal("oooMutation"), Schema.Literal("alreadyProcessed")),
|
|
97
|
+
details: Schema.optional(JsonSchema),
|
|
98
|
+
});
|
|
99
|
+
const ZeroMutationOk = Schema.Struct({
|
|
100
|
+
// The user can return any additional data here
|
|
101
|
+
data: Schema.optional(JsonSchema),
|
|
102
|
+
});
|
|
103
|
+
const ZeroMutationError = Schema.Union(ZeroAppError, ZeroError);
|
|
104
|
+
// We flip the original order here as otherwise values of type ZeroMutationError would get parsed as ZeroMutationOk with empty `data`
|
|
105
|
+
export const ZeroMutationResult = Schema.Union(ZeroMutationError, ZeroMutationOk);
|
|
106
|
+
export const ZeroMutationResponse = Schema.Struct({
|
|
107
|
+
id: ZeroMutationId,
|
|
108
|
+
result: ZeroMutationResult,
|
|
109
|
+
});
|
|
110
|
+
const ZeroPushOk = Schema.Struct({
|
|
111
|
+
mutations: Schema.Array(ZeroMutationResponse),
|
|
112
|
+
});
|
|
113
|
+
const ZeroUnsupportedPushVersion = Schema.Struct({
|
|
114
|
+
error: Schema.Literal("unsupportedPushVersion"),
|
|
115
|
+
// optional for backwards compatibility
|
|
116
|
+
// This field is included so the client knows which mutations
|
|
117
|
+
// were not processed by the server.
|
|
118
|
+
mutationIDs: Schema.optional(Schema.Array(ZeroMutationId)),
|
|
119
|
+
});
|
|
120
|
+
const ZeroUnsupportedSchemaVersion = Schema.Struct({
|
|
121
|
+
error: Schema.Literal("unsupportedSchemaVersion"),
|
|
122
|
+
// optional for backwards compatibility
|
|
123
|
+
// This field is included so the client knows which mutations
|
|
124
|
+
// were not processed by the server.
|
|
125
|
+
mutationIDs: Schema.optional(Schema.Array(ZeroMutationId)),
|
|
126
|
+
});
|
|
127
|
+
const ZeroHttpError = Schema.Struct({
|
|
128
|
+
error: Schema.Literal("http"),
|
|
129
|
+
status: Schema.Number,
|
|
130
|
+
details: Schema.String,
|
|
131
|
+
mutationIDs: Schema.optional(Schema.Array(ZeroMutationId)),
|
|
132
|
+
});
|
|
133
|
+
const ZeroPusherError = Schema.Struct({
|
|
134
|
+
error: Schema.Literal("zeroPusher"),
|
|
135
|
+
details: Schema.String,
|
|
136
|
+
mutationIDs: Schema.optional(Schema.Array(ZeroMutationId)),
|
|
137
|
+
});
|
|
138
|
+
const ZeroPushError = Schema.Union(ZeroUnsupportedPushVersion, ZeroUnsupportedSchemaVersion, ZeroHttpError, ZeroPusherError);
|
|
139
|
+
export const ZeroPushResponse = Schema.Union(ZeroPushOk, ZeroPushError);
|
|
140
|
+
// biome-ignore lint/correctness/noUnusedVariables: borrowed code
|
|
141
|
+
const ZeroPushResponseMessage = Schema.Tuple(Schema.Literal("pushResponse"), ZeroPushResponse);
|
|
142
|
+
// biome-ignore lint/correctness/noUnusedVariables: borrowed code
|
|
143
|
+
const ZeroAckMutationResponsesMessage = Schema.Tuple(Schema.Literal("ackMutationResponses"), ZeroMutationId);
|
|
144
|
+
/**
|
|
145
|
+
* The schema for the querystring parameters of the custom push endpoint.
|
|
146
|
+
*/
|
|
147
|
+
export const ZeroPushParams = Schema.Struct({
|
|
148
|
+
schema: Schema.String,
|
|
149
|
+
appID: Schema.String,
|
|
150
|
+
});
|
|
151
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,MAAM,EAAE,MAAM,CAAC,uBAAmC,CAAC"}
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAmB,IAAO,EAAE,EAAE,CAAC,eAAe,IAAI,EAAW,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,21 +1,70 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "effect-zero",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"repository": {
|
|
6
|
+
"url": "https://github.com/realms-labs/effect-zero"
|
|
7
|
+
},
|
|
6
8
|
"scripts": {
|
|
7
|
-
"
|
|
9
|
+
"typecheck": "tsc --noEmit --incremental",
|
|
10
|
+
"lint": "biome check --error-on-warnings",
|
|
11
|
+
"lint:fix": "biome check --write --unsafe",
|
|
12
|
+
"build": "bun scripts/build.ts"
|
|
8
13
|
},
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
16
|
+
"@types/bun": "latest",
|
|
17
|
+
"@types/fs-extra": "^11.0.4",
|
|
18
|
+
"fs-extra": "^11.3.2",
|
|
19
|
+
"typescript": "5.9.2",
|
|
20
|
+
"@effect-atom/atom": "^0.3.3",
|
|
21
|
+
"@rocicorp/zero": "^0.24.2025101500",
|
|
22
|
+
"effect": "^3.18.4",
|
|
23
|
+
"ts-patch": "^3.3.0",
|
|
24
|
+
"@biomejs/biome": "^2.2.6",
|
|
25
|
+
"@effect/language-service": "^0.45.1"
|
|
12
26
|
},
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"bugs": {
|
|
18
|
-
"url": "https://github.com/realms-labs/effect-zero/issues"
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"@effect-atom/atom": "*",
|
|
29
|
+
"@rocicorp/zero": "*",
|
|
30
|
+
"effect": "3"
|
|
19
31
|
},
|
|
20
|
-
"
|
|
21
|
-
|
|
32
|
+
"exports": {
|
|
33
|
+
"./utils": {
|
|
34
|
+
"import": {
|
|
35
|
+
"types": "./dist/utils.d.ts",
|
|
36
|
+
"default": "./dist/utils.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"./server": {
|
|
40
|
+
"import": {
|
|
41
|
+
"types": "./dist/server.d.ts",
|
|
42
|
+
"default": "./dist/server.js"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"./mutators": {
|
|
46
|
+
"import": {
|
|
47
|
+
"types": "./dist/mutators.d.ts",
|
|
48
|
+
"default": "./dist/mutators.js"
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"./client": {
|
|
52
|
+
"import": {
|
|
53
|
+
"types": "./dist/client.d.ts",
|
|
54
|
+
"default": "./dist/client.js"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"./types": {
|
|
58
|
+
"import": {
|
|
59
|
+
"types": "./dist/types.d.ts",
|
|
60
|
+
"default": "./dist/types.js"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
"./snapshot": {
|
|
64
|
+
"import": {
|
|
65
|
+
"types": "./dist/snapshot.d.ts",
|
|
66
|
+
"default": "./dist/snapshot.js"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { Atom } from "@effect-atom/atom";
|
|
2
|
+
import type { HumanReadable, Query, ReadonlyJSONValue, Transaction, Schema as ZeroSchema } from "@rocicorp/zero";
|
|
3
|
+
import type { QueryResult } from "@rocicorp/zero/react";
|
|
4
|
+
import * as Cause from "effect/Cause";
|
|
5
|
+
import * as Context from "effect/Context";
|
|
6
|
+
import * as Data from "effect/Data";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Exit from "effect/Exit";
|
|
9
|
+
import * as Match from "effect/Match";
|
|
10
|
+
import type * as ParseResult from "effect/ParseResult";
|
|
11
|
+
import * as Predicate from "effect/Predicate";
|
|
12
|
+
import * as Rec from "effect/Record";
|
|
13
|
+
import * as Runtime from "effect/Runtime";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import * as Stream from "effect/Stream";
|
|
16
|
+
import * as Subscribable from "effect/Subscribable";
|
|
17
|
+
import * as SubscriptionRef from "effect/SubscriptionRef";
|
|
18
|
+
import {
|
|
19
|
+
type AnyMutator,
|
|
20
|
+
type AnyMutators,
|
|
21
|
+
type ExtractMutatorsRequirements,
|
|
22
|
+
MutatorArgsSchemaSym,
|
|
23
|
+
} from "./mutators.js";
|
|
24
|
+
import { deepClone, getDefaultSnapshot, getSnapshot } from "./snapshot.js";
|
|
25
|
+
import { prefixId } from "./utils.js";
|
|
26
|
+
|
|
27
|
+
// Updated to: https://github.com/rocicorp/mono/blob/2e18f2e1d084c530ebd9bd7fef9bb848e607cc19/packages/zero-pg/src/push-processor.ts
|
|
28
|
+
|
|
29
|
+
// Necessary workaround for TS declaration generation
|
|
30
|
+
export interface ZeroClientTransaction {
|
|
31
|
+
readonly _tag: unique symbol;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const makeClient = <S extends ZeroSchema>() => {
|
|
35
|
+
// TODO: Maybe prefix this / suffix this with a tag passed in to `make`?
|
|
36
|
+
const ZeroClientTransaction = Context.Tag(prefixId("ZeroClientTransaction"))<ZeroClientTransaction, Transaction<S>>();
|
|
37
|
+
|
|
38
|
+
const use = <A>(fn: (transaction: Transaction<S>, options: { readonly signal: AbortSignal }) => PromiseLike<A>) =>
|
|
39
|
+
Effect.flatMap(ZeroClientTransaction, (transaction) =>
|
|
40
|
+
Effect.promise((signal) => fn(transaction, { signal })),
|
|
41
|
+
).pipe(
|
|
42
|
+
Effect.tapErrorCause((cause) => Effect.logError(cause)),
|
|
43
|
+
Effect.sandbox,
|
|
44
|
+
Effect.annotateLogs({ module: prefixId("ZeroClient.Transaction"), method: "use" }),
|
|
45
|
+
Effect.mapError((cause) => new ZeroClientTransactionError({ cause })),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const unwrapMutators = Effect.fn(function* <T extends AnyMutators>(mutators: T) {
|
|
49
|
+
const runtime = yield* Effect.runtime<Exclude<ExtractMutatorsRequirements<T>, ZeroClientTransaction>>();
|
|
50
|
+
|
|
51
|
+
function unwrapMutator<E>(mutator: AnyMutator<ExtractMutatorsRequirements<T>, E>) {
|
|
52
|
+
return async (tx: Transaction<S>, args: unknown) => {
|
|
53
|
+
const exit = await Schema.decode(mutator[MutatorArgsSchemaSym])(args).pipe(
|
|
54
|
+
Effect.catchTag("ParseError", (e) => new ZeroClientArgsParseError({ cause: Cause.fail(e) })),
|
|
55
|
+
Effect.flatMap(mutator),
|
|
56
|
+
Effect.provideService(ZeroClientTransaction, tx),
|
|
57
|
+
Runtime.runPromiseExit(runtime),
|
|
58
|
+
);
|
|
59
|
+
return Exit.getOrElse(exit, (c) => {
|
|
60
|
+
// Extract underlying error bypassing FiberFailure
|
|
61
|
+
throw Cause.squash(c);
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return Rec.map(mutators, (v) =>
|
|
67
|
+
Match.value(v).pipe(Match.when(Predicate.isFunction, unwrapMutator), Match.orElse(Rec.map(unwrapMutator))),
|
|
68
|
+
) as UnwrapMutators<S, T>;
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const querySub = Effect.fn(function* <T extends keyof S["tables"] & string, R>(query: Query<S, T, R>) {
|
|
72
|
+
const view = yield* Effect.acquireRelease(
|
|
73
|
+
Effect.sync(() => query.materialize()),
|
|
74
|
+
(view) => Effect.sync(() => view.destroy()),
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const subscriptionRef = yield* SubscriptionRef.make<QueryResult<R>>(getDefaultSnapshot(query.format.singular));
|
|
78
|
+
|
|
79
|
+
yield* Stream.asyncEffect<Parameters<Parameters<(typeof view)["addListener"]>[0]>>((emit) =>
|
|
80
|
+
Effect.sync(() => view.addListener((...args) => emit.single(args))),
|
|
81
|
+
).pipe(
|
|
82
|
+
Stream.mapEffect(([data, resultType]) =>
|
|
83
|
+
Effect.sync(() => {
|
|
84
|
+
// logic here borrowed from: https://github.com/rocicorp/mono/blob/288b00ec94f5a9ae6e988513423af25c281dbb2a/packages/zero-react/src/use-query.tsx#L295
|
|
85
|
+
const cloned = data === undefined ? data : (deepClone(data as ReadonlyJSONValue) as HumanReadable<R>);
|
|
86
|
+
return getSnapshot<R>(query.format.singular, cloned, resultType);
|
|
87
|
+
}),
|
|
88
|
+
),
|
|
89
|
+
Stream.runForEach((snapshot) => SubscriptionRef.set(subscriptionRef, snapshot)),
|
|
90
|
+
Effect.forkScoped,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
return subscriptionRef.pipe(
|
|
94
|
+
Subscribable.map(([data, { type: status }]) => ({
|
|
95
|
+
data,
|
|
96
|
+
status,
|
|
97
|
+
})),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
/** Create an Atom for the query */
|
|
102
|
+
const queryAtom = Atom.family(<T extends keyof S["tables"] & string, R>(query: Query<S, T, R>) =>
|
|
103
|
+
Atom.subscribable(querySub(query)).pipe(Atom.mapResult((res) => res.data)),
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
unwrapMutators,
|
|
108
|
+
querySub,
|
|
109
|
+
queryAtom,
|
|
110
|
+
Transaction: Object.assign(ZeroClientTransaction, { use }),
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
type UnwrapMutator<S extends ZeroSchema, T extends AnyMutator> = Parameters<T> extends []
|
|
115
|
+
? (transaction: Transaction<S>) => Promise<void>
|
|
116
|
+
: (transaction: Transaction<S>, args: Schema.Schema.Encoded<T[typeof MutatorArgsSchemaSym]>) => Promise<void>;
|
|
117
|
+
|
|
118
|
+
export type UnwrapMutators<S extends ZeroSchema, T extends AnyMutators> = {
|
|
119
|
+
[A in keyof T]: T[A] extends AnyMutator
|
|
120
|
+
? UnwrapMutator<S, T[A]>
|
|
121
|
+
: { [B in keyof T[A]]: T[A][B] extends AnyMutator ? UnwrapMutator<S, T[A][B]> : never };
|
|
122
|
+
} & {};
|
|
123
|
+
|
|
124
|
+
export class ZeroClientTransactionError extends Data.TaggedError("ZeroClientTransactionError")<{
|
|
125
|
+
cause: Cause.Cause<unknown>;
|
|
126
|
+
}> {}
|
|
127
|
+
|
|
128
|
+
export class ZeroClientArgsParseError extends Data.TaggedError("ZeroClientArgsParseError")<{
|
|
129
|
+
cause: Cause.Cause<ParseResult.ParseError>;
|
|
130
|
+
}> {}
|
package/src/mutators.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
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 "./utils.js";
|
|
8
|
+
|
|
9
|
+
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
10
|
+
export type AnyMutatorDef<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 AnyMutatorDefs<R = any> = {
|
|
14
|
+
[K: string]: AnyMutatorDef<R> | { [K: string]: AnyMutatorDef<R> };
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// biome-ignore lint/suspicious/noExplicitAny: upper bound to allow everything
|
|
18
|
+
export type AnyMutatorSchemaArgs = Schema.Schema<any, any, never>;
|
|
19
|
+
export type AnyMutatorSchema = Record<string, AnyMutatorSchemaArgs | Record<string, AnyMutatorSchemaArgs>>;
|
|
20
|
+
|
|
21
|
+
export type MutatorDefs<TSchema extends AnyMutatorSchema> = {
|
|
22
|
+
[K in keyof TSchema]: TSchema[K] extends AnyMutatorSchemaArgs
|
|
23
|
+
? AnyMutatorDef<unknown, [Schema.Schema.Type<TSchema[K]>]>
|
|
24
|
+
: TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchemaArgs>
|
|
25
|
+
? { [K in keyof TSchema]: AnyMutatorDef<unknown, [Schema.Schema.Type<TSchema[K]>]> }
|
|
26
|
+
: never;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const MutatorArgsSchemaSym = Symbol.for(prefixId("MutatorArgsSchema"));
|
|
30
|
+
|
|
31
|
+
export type Mutator<
|
|
32
|
+
TFunc extends AnyMutatorDef = AnyMutatorDef,
|
|
33
|
+
TSchema extends AnyMutatorSchemaArgs = AnyMutatorSchemaArgs,
|
|
34
|
+
> = TFunc & {
|
|
35
|
+
[MutatorArgsSchemaSym]: TSchema;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export type Mutators<TSchema extends AnyMutatorSchema, TDefs extends AnyMutatorDefs> = {
|
|
39
|
+
[K in keyof TDefs & keyof TSchema]: TDefs[K] extends AnyMutatorDef
|
|
40
|
+
? TSchema[K] extends AnyMutatorSchemaArgs
|
|
41
|
+
? Mutator<TDefs[K], TSchema[K]>
|
|
42
|
+
: never
|
|
43
|
+
: TSchema[K] extends infer TSchema extends Record<string, AnyMutatorSchemaArgs>
|
|
44
|
+
? TDefs[K] extends infer TDefs extends Record<string, AnyMutatorDef>
|
|
45
|
+
? { [K in keyof TDefs & keyof TSchema]: Mutator<TDefs[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<T extends AnyMutators> = T extends AnyMutators<infer R> ? R : never;
|
|
57
|
+
|
|
58
|
+
export class MutatorSchema<T extends AnyMutatorSchema> {
|
|
59
|
+
private constructor(public schema: T) {}
|
|
60
|
+
|
|
61
|
+
static make<T extends AnyMutatorSchema>(schema: T) {
|
|
62
|
+
return new MutatorSchema(schema);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Associates mutator with its args schema
|
|
66
|
+
private makeMutator(argsSchema: AnyMutatorSchemaArgs, fn: AnyMutatorDef): AnyMutator {
|
|
67
|
+
return Object.assign(fn, { [MutatorArgsSchemaSym]: argsSchema });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
makeMutators<TDefs extends MutatorDefs<T>>(mutators: TDefs): Mutators<T, TDefs>;
|
|
71
|
+
makeMutators(mutators: AnyMutatorDefs): AnyMutators {
|
|
72
|
+
return Rec.map(mutators, (v, name) => {
|
|
73
|
+
return Match.value([v, this.schema[name]]).pipe(
|
|
74
|
+
Match.when([Predicate.isFunction, Schema.isSchema], ([mutator, schema]) => this.makeMutator(schema, mutator)),
|
|
75
|
+
Match.when([Predicate.isRecord, Predicate.isRecord], ([mutator, schema]) =>
|
|
76
|
+
Rec.map(mutator, (mutator, name) => this.makeMutator(Option.getOrThrow(Rec.get(schema, name)), mutator)),
|
|
77
|
+
),
|
|
78
|
+
Match.orElseAbsurd,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|