alchemy 2.0.0-beta.43 → 2.0.0-beta.44
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/bin/cli.js +18 -5
- package/bin/exec.js +315 -233
- package/bin/exec.js.map +1 -1
- package/lib/Auth/Lock.js +2 -2
- package/lib/Auth/Lock.js.map +1 -1
- package/lib/Bundle/Bundle.d.ts +11 -0
- package/lib/Bundle/Bundle.d.ts.map +1 -1
- package/lib/Bundle/Bundle.js +19 -12
- package/lib/Bundle/Bundle.js.map +1 -1
- package/lib/Bundle/BundleAnalyzerPlugin.d.ts +25 -0
- package/lib/Bundle/BundleAnalyzerPlugin.d.ts.map +1 -0
- package/lib/Bundle/BundleAnalyzerPlugin.js +16 -0
- package/lib/Bundle/BundleAnalyzerPlugin.js.map +1 -0
- package/lib/Bundle/RawPlugin.d.ts +36 -0
- package/lib/Bundle/RawPlugin.d.ts.map +1 -0
- package/lib/Bundle/RawPlugin.js +80 -0
- package/lib/Bundle/RawPlugin.js.map +1 -0
- package/lib/Bundle/index.d.ts +2 -0
- package/lib/Bundle/index.d.ts.map +1 -1
- package/lib/Bundle/index.js +2 -0
- package/lib/Bundle/index.js.map +1 -1
- package/lib/Cli/commands/dev.d.ts +3 -2
- package/lib/Cli/commands/dev.d.ts.map +1 -1
- package/lib/Cli/commands/dev.js +9 -1
- package/lib/Cli/commands/dev.js.map +1 -1
- package/lib/Cli/exec.d.ts.map +1 -1
- package/lib/Cli/exec.js +2 -1
- package/lib/Cli/exec.js.map +1 -1
- package/lib/Cloudflare/Local.d.ts +2 -0
- package/lib/Cloudflare/Local.d.ts.map +1 -0
- package/lib/Cloudflare/Local.js +9 -0
- package/lib/Cloudflare/Local.js.map +1 -0
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +3 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.js +0 -1
- package/lib/Cloudflare/Workers/DurableObjectBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts +22 -3
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +413 -21
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +6 -19
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +3 -4
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBridge.js +3 -5
- package/lib/Cloudflare/Workers/WorkerBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts +1 -2
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +3 -6
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts +184 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.js +216 -0
- package/lib/Cloudflare/Zaraz/ZarazConfig.js.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.d.ts +188 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.js +4 -0
- package/lib/Cloudflare/Zaraz/ZarazEventTypes.js.map +1 -0
- package/lib/Cloudflare/Zaraz/index.d.ts +3 -0
- package/lib/Cloudflare/Zaraz/index.d.ts.map +1 -0
- package/lib/Cloudflare/Zaraz/index.js +2 -0
- package/lib/Cloudflare/Zaraz/index.js.map +1 -0
- package/lib/Cloudflare/index.d.ts +1 -0
- package/lib/Cloudflare/index.d.ts.map +1 -1
- package/lib/Cloudflare/index.js +1 -0
- package/lib/Cloudflare/index.js.map +1 -1
- package/lib/Local/RpcProvider.d.ts +54 -0
- package/lib/Local/RpcProvider.d.ts.map +1 -0
- package/lib/Local/RpcProvider.js +57 -0
- package/lib/Local/RpcProvider.js.map +1 -0
- package/lib/Local/RpcProviderProxy.d.ts +19 -0
- package/lib/Local/RpcProviderProxy.d.ts.map +1 -0
- package/lib/Local/RpcProviderProxy.js +48 -0
- package/lib/Local/RpcProviderProxy.js.map +1 -0
- package/lib/Local/RpcSerialization.d.ts +34 -0
- package/lib/Local/RpcSerialization.d.ts.map +1 -0
- package/lib/Local/RpcSerialization.js +120 -0
- package/lib/Local/RpcSerialization.js.map +1 -0
- package/lib/Local/RpcServer.d.ts +63 -0
- package/lib/Local/RpcServer.d.ts.map +1 -0
- package/lib/Local/RpcServer.js +72 -0
- package/lib/Local/RpcServer.js.map +1 -0
- package/lib/Local/RpcServerBun.d.ts +3 -0
- package/lib/Local/RpcServerBun.d.ts.map +1 -0
- package/lib/Local/RpcServerBun.js +47 -0
- package/lib/Local/RpcServerBun.js.map +1 -0
- package/lib/Local/RpcServerEnvironment.d.ts +20 -0
- package/lib/Local/RpcServerEnvironment.d.ts.map +1 -0
- package/lib/Local/RpcServerEnvironment.js +22 -0
- package/lib/Local/RpcServerEnvironment.js.map +1 -0
- package/lib/Local/RpcServerNode.d.ts +3 -0
- package/lib/Local/RpcServerNode.d.ts.map +1 -0
- package/lib/Local/RpcServerNode.js +43 -0
- package/lib/Local/RpcServerNode.js.map +1 -0
- package/lib/Local/RpcServerSession.d.ts +27 -0
- package/lib/Local/RpcServerSession.d.ts.map +1 -0
- package/lib/Local/RpcServerSession.js +68 -0
- package/lib/Local/RpcServerSession.js.map +1 -0
- package/lib/Local/RpcSpawner.d.ts +21 -0
- package/lib/Local/RpcSpawner.d.ts.map +1 -0
- package/lib/Local/RpcSpawner.js +132 -0
- package/lib/Local/RpcSpawner.js.map +1 -0
- package/lib/Util/PlatformServices.d.ts +7 -0
- package/lib/Util/PlatformServices.d.ts.map +1 -1
- package/lib/Util/PlatformServices.js +22 -11
- package/lib/Util/PlatformServices.js.map +1 -1
- package/lib/Util/camel.d.ts.map +1 -1
- package/lib/Util/camel.js +2 -3
- package/lib/Util/camel.js.map +1 -1
- package/lib/Util/data.d.ts +5 -0
- package/lib/Util/data.d.ts.map +1 -1
- package/lib/Util/data.js +29 -0
- package/lib/Util/data.js.map +1 -1
- package/lib/Util/stable.d.ts.map +1 -1
- package/lib/Util/stable.js +3 -6
- package/lib/Util/stable.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +12 -14
- package/src/Auth/Lock.ts +2 -2
- package/src/Bundle/Bundle.ts +35 -13
- package/src/Bundle/BundleAnalyzerPlugin.ts +33 -0
- package/src/Bundle/RawPlugin.ts +82 -0
- package/src/Bundle/index.ts +2 -0
- package/src/Cli/commands/dev.ts +51 -37
- package/src/Cli/exec.ts +12 -7
- package/src/Cloudflare/Local.ts +23 -0
- package/src/Cloudflare/Providers.ts +3 -0
- package/src/Cloudflare/Workers/DurableObjectBridge.ts +0 -1
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +547 -21
- package/src/Cloudflare/Workers/Worker.ts +11 -22
- package/src/Cloudflare/Workers/WorkerBridge.ts +3 -5
- package/src/Cloudflare/Workers/WorkerBundle.ts +4 -8
- package/src/Cloudflare/Zaraz/ZarazConfig.ts +403 -0
- package/src/Cloudflare/Zaraz/ZarazEventTypes.ts +257 -0
- package/src/Cloudflare/Zaraz/index.ts +25 -0
- package/src/Cloudflare/index.ts +1 -0
- package/src/Local/RpcProvider.ts +102 -0
- package/src/Local/RpcProviderProxy.ts +86 -0
- package/src/Local/RpcSerialization.ts +225 -0
- package/src/Local/RpcServer.ts +138 -0
- package/src/Local/RpcServerBun.ts +59 -0
- package/src/Local/RpcServerEnvironment.ts +55 -0
- package/src/Local/RpcServerNode.ts +58 -0
- package/src/Local/RpcServerSession.ts +87 -0
- package/src/Local/RpcSpawner.ts +196 -0
- package/src/Util/PlatformServices.ts +41 -27
- package/src/Util/camel.ts +3 -5
- package/src/Util/data.ts +38 -0
- package/src/Util/stable.ts +4 -10
- package/lib/Cloudflare/Local/Sidecar.d.ts +0 -63
- package/lib/Cloudflare/Local/Sidecar.d.ts.map +0 -1
- package/lib/Cloudflare/Local/Sidecar.js +0 -50
- package/lib/Cloudflare/Local/Sidecar.js.map +0 -1
- package/lib/Cloudflare/Local/SidecarHandlers.d.ts +0 -8
- package/lib/Cloudflare/Local/SidecarHandlers.d.ts.map +0 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js +0 -381
- package/lib/Cloudflare/Local/SidecarHandlers.js.map +0 -1
- package/lib/Cloudflare/Local/SidecarServer.d.ts +0 -2
- package/lib/Cloudflare/Local/SidecarServer.d.ts.map +0 -1
- package/lib/Cloudflare/Local/SidecarServer.js +0 -34
- package/lib/Cloudflare/Local/SidecarServer.js.map +0 -1
- package/lib/Sidecar/Lock.d.ts +0 -23
- package/lib/Sidecar/Lock.d.ts.map +0 -1
- package/lib/Sidecar/Lock.js +0 -39
- package/lib/Sidecar/Lock.js.map +0 -1
- package/lib/Sidecar/RpcClient.d.ts +0 -15
- package/lib/Sidecar/RpcClient.d.ts.map +0 -1
- package/lib/Sidecar/RpcClient.js +0 -78
- package/lib/Sidecar/RpcClient.js.map +0 -1
- package/lib/Sidecar/RpcHandler.d.ts +0 -51
- package/lib/Sidecar/RpcHandler.d.ts.map +0 -1
- package/lib/Sidecar/RpcHandler.js +0 -87
- package/lib/Sidecar/RpcHandler.js.map +0 -1
- package/lib/Sidecar/RpcPaths.d.ts +0 -19
- package/lib/Sidecar/RpcPaths.d.ts.map +0 -1
- package/lib/Sidecar/RpcPaths.js +0 -31
- package/lib/Sidecar/RpcPaths.js.map +0 -1
- package/lib/Sidecar/RpcServer.d.ts +0 -30
- package/lib/Sidecar/RpcServer.d.ts.map +0 -1
- package/lib/Sidecar/RpcServer.js +0 -105
- package/lib/Sidecar/RpcServer.js.map +0 -1
- package/lib/Sidecar/RpcServerBun.d.ts +0 -4
- package/lib/Sidecar/RpcServerBun.d.ts.map +0 -1
- package/lib/Sidecar/RpcServerBun.js +0 -28
- package/lib/Sidecar/RpcServerBun.js.map +0 -1
- package/lib/Sidecar/RpcServerNode.d.ts +0 -4
- package/lib/Sidecar/RpcServerNode.d.ts.map +0 -1
- package/lib/Sidecar/RpcServerNode.js +0 -39
- package/lib/Sidecar/RpcServerNode.js.map +0 -1
- package/lib/Sidecar/RpcServices.d.ts +0 -6
- package/lib/Sidecar/RpcServices.d.ts.map +0 -1
- package/lib/Sidecar/RpcServices.js +0 -29
- package/lib/Sidecar/RpcServices.js.map +0 -1
- package/src/Cloudflare/Local/Sidecar.ts +0 -81
- package/src/Cloudflare/Local/SidecarHandlers.ts +0 -491
- package/src/Cloudflare/Local/SidecarServer.ts +0 -70
- package/src/Sidecar/Lock.ts +0 -66
- package/src/Sidecar/RpcClient.ts +0 -142
- package/src/Sidecar/RpcHandler.ts +0 -205
- package/src/Sidecar/RpcPaths.ts +0 -39
- package/src/Sidecar/RpcServer.ts +0 -153
- package/src/Sidecar/RpcServerBun.ts +0 -41
- package/src/Sidecar/RpcServerNode.ts +0 -51
- package/src/Sidecar/RpcServices.ts +0 -48
package/src/Sidecar/RpcClient.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { newWebSocketRpcSession } from "capnweb";
|
|
2
|
-
import * as Context from "effect/Context";
|
|
3
|
-
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as Fiber from "effect/Fiber";
|
|
5
|
-
import * as FileSystem from "effect/FileSystem";
|
|
6
|
-
import * as Layer from "effect/Layer";
|
|
7
|
-
import * as Schedule from "effect/Schedule";
|
|
8
|
-
import * as Schema from "effect/Schema";
|
|
9
|
-
import * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
10
|
-
import * as Lock from "./Lock.ts";
|
|
11
|
-
import {
|
|
12
|
-
deserializeRpcHandlers,
|
|
13
|
-
type RpcHandlerDecoders,
|
|
14
|
-
type RpcHandlers,
|
|
15
|
-
type SerializedRpcHandlers,
|
|
16
|
-
} from "./RpcHandler.ts";
|
|
17
|
-
import * as RpcPaths from "./RpcPaths.ts";
|
|
18
|
-
|
|
19
|
-
export const RpcClientService = <Self, T extends RpcHandlers>() =>
|
|
20
|
-
Context.Service<Self, T>();
|
|
21
|
-
|
|
22
|
-
class RpcClientError extends Schema.TaggedErrorClass<RpcClientError>()(
|
|
23
|
-
"RpcClientError",
|
|
24
|
-
{
|
|
25
|
-
reason: Schema.Literals(["InvalidURL", "WebSocketError"]),
|
|
26
|
-
message: Schema.String,
|
|
27
|
-
cause: Schema.optional(Schema.DefectWithStack),
|
|
28
|
-
},
|
|
29
|
-
) {}
|
|
30
|
-
|
|
31
|
-
export const layer = <Self, T extends RpcHandlers>(
|
|
32
|
-
tag: Context.ServiceClass<Self, any, T>,
|
|
33
|
-
options: {
|
|
34
|
-
main: string;
|
|
35
|
-
schema: RpcHandlerDecoders<T>;
|
|
36
|
-
},
|
|
37
|
-
) =>
|
|
38
|
-
Layer.effect(
|
|
39
|
-
tag,
|
|
40
|
-
Effect.gen(function* () {
|
|
41
|
-
const fiber = yield* maybeStartRpcServer(options.main).pipe(
|
|
42
|
-
Effect.flatMap(() => RpcSession),
|
|
43
|
-
Effect.map((session) =>
|
|
44
|
-
deserializeRpcHandlers(
|
|
45
|
-
session as SerializedRpcHandlers<T>,
|
|
46
|
-
options.schema,
|
|
47
|
-
),
|
|
48
|
-
),
|
|
49
|
-
Effect.retry(Schedule.exponential("100 millis")),
|
|
50
|
-
Effect.provide(
|
|
51
|
-
Layer.provideMerge(Lock.LockLive, RpcPaths.layer(options.main)),
|
|
52
|
-
),
|
|
53
|
-
Effect.forkScoped,
|
|
54
|
-
);
|
|
55
|
-
return new Proxy({} as T, {
|
|
56
|
-
get(_, prop) {
|
|
57
|
-
return (...args: any[]) =>
|
|
58
|
-
Fiber.join(fiber).pipe(
|
|
59
|
-
Effect.flatMap((session) => session[prop as never](...args)),
|
|
60
|
-
);
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}),
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const maybeStartRpcServer = Effect.fn(function* (main: string) {
|
|
67
|
-
const lock = yield* Lock.Lock;
|
|
68
|
-
if (!(yield* lock.check)) {
|
|
69
|
-
main = RpcPaths.sanitizeSidecarMain(main);
|
|
70
|
-
const bin = typeof globalThis.Bun !== "undefined" ? "bun" : "node";
|
|
71
|
-
yield* Effect.logDebug("[RpcClient] Starting RPC server", main);
|
|
72
|
-
yield* ChildProcess.make(bin, { bun: ["run", main], node: [main] }[bin], {
|
|
73
|
-
stdout: "inherit",
|
|
74
|
-
stderr: "inherit",
|
|
75
|
-
extendEnv: true,
|
|
76
|
-
// Effect's default behavior is detached: true on posix and false on Windows.
|
|
77
|
-
// Ideally we would set detached: true on Windows, but that would create a separate console window for every server instance.
|
|
78
|
-
});
|
|
79
|
-
} else {
|
|
80
|
-
yield* Effect.logDebug("[RpcClient] RPC server already running", main);
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
const RpcSession = Effect.gen(function* () {
|
|
85
|
-
const paths = yield* RpcPaths.RpcPaths;
|
|
86
|
-
const fs = yield* FileSystem.FileSystem;
|
|
87
|
-
const ws = yield* fs.readFileString(paths.url).pipe(
|
|
88
|
-
Effect.flatMap((url) =>
|
|
89
|
-
Effect.try({
|
|
90
|
-
try: () => new URL(url),
|
|
91
|
-
catch: (e) =>
|
|
92
|
-
new RpcClientError({
|
|
93
|
-
reason: "InvalidURL",
|
|
94
|
-
message: `"${url}" is not a valid URL`,
|
|
95
|
-
cause: e,
|
|
96
|
-
}),
|
|
97
|
-
}),
|
|
98
|
-
),
|
|
99
|
-
Effect.flatMap((url) =>
|
|
100
|
-
Effect.callback<WebSocket, RpcClientError>((resume) => {
|
|
101
|
-
const ws = new WebSocket(url);
|
|
102
|
-
ws.onopen = () => resume(Effect.succeed(ws));
|
|
103
|
-
ws.onerror = (e) =>
|
|
104
|
-
resume(
|
|
105
|
-
Effect.fail(
|
|
106
|
-
new RpcClientError({
|
|
107
|
-
reason: "WebSocketError",
|
|
108
|
-
message: "WebSocket connection failed",
|
|
109
|
-
cause: e,
|
|
110
|
-
}),
|
|
111
|
-
),
|
|
112
|
-
);
|
|
113
|
-
return Effect.sync(() => ws.close());
|
|
114
|
-
}),
|
|
115
|
-
),
|
|
116
|
-
Effect.retry({
|
|
117
|
-
while: (e) => e.reason !== "WebSocketError",
|
|
118
|
-
schedule: Schedule.spaced("50 millis"),
|
|
119
|
-
times: 100,
|
|
120
|
-
}),
|
|
121
|
-
Effect.retry({
|
|
122
|
-
while: (e) => e.reason === "WebSocketError",
|
|
123
|
-
schedule: Schedule.exponential("100 millis"),
|
|
124
|
-
times: 3,
|
|
125
|
-
}),
|
|
126
|
-
);
|
|
127
|
-
const session = yield* Effect.acquireRelease(
|
|
128
|
-
Effect.sync(() =>
|
|
129
|
-
newWebSocketRpcSession<{
|
|
130
|
-
heartbeat: () => Promise<void>;
|
|
131
|
-
shutdown: () => Promise<void>;
|
|
132
|
-
}>(ws),
|
|
133
|
-
),
|
|
134
|
-
(session) => Effect.sync(() => session[Symbol.dispose]()),
|
|
135
|
-
);
|
|
136
|
-
yield* Effect.promise(() => session.heartbeat()).pipe(
|
|
137
|
-
Effect.repeat(Schedule.spaced("1 second")),
|
|
138
|
-
Effect.ensuring(Effect.promise(() => session.shutdown())),
|
|
139
|
-
Effect.forkScoped,
|
|
140
|
-
);
|
|
141
|
-
return session;
|
|
142
|
-
});
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import type { RpcCompatible } from "capnweb";
|
|
2
|
-
import * as Cause from "effect/Cause";
|
|
3
|
-
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as Exit from "effect/Exit";
|
|
5
|
-
import { flow } from "effect/Function";
|
|
6
|
-
import * as Redacted from "effect/Redacted";
|
|
7
|
-
import * as Schema from "effect/Schema";
|
|
8
|
-
|
|
9
|
-
type RpcHandler<Args extends Array<any>, Success, Error> = (
|
|
10
|
-
...args: Args
|
|
11
|
-
) => Effect.Effect<Success, Error>;
|
|
12
|
-
|
|
13
|
-
type SerializedArgs<T> = string & { __serializedArgs: T };
|
|
14
|
-
|
|
15
|
-
type SerializedRpcHandler<Args, Success, Error> = (
|
|
16
|
-
args: SerializedArgs<Args>,
|
|
17
|
-
) => Promise<SerializedExit<RpcCompatible<Success>, RpcCompatible<Error>>>;
|
|
18
|
-
|
|
19
|
-
type SerializedCause<Error> =
|
|
20
|
-
| { _tag: "Fail"; error: Error }
|
|
21
|
-
| { _tag: "Die"; defect: unknown }
|
|
22
|
-
| { _tag: "Interrupt"; fiberId: number | undefined };
|
|
23
|
-
|
|
24
|
-
type SerializedExit<Success, Error> =
|
|
25
|
-
| { _tag: "Success"; value: Success }
|
|
26
|
-
| {
|
|
27
|
-
_tag: "Failure";
|
|
28
|
-
cause: Array<SerializedCause<Error>>;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type RpcHandlers = Record<string, RpcHandler<any, any, any>>;
|
|
32
|
-
|
|
33
|
-
export type SerializedRpcHandlers<T extends RpcHandlers> = {
|
|
34
|
-
[K in keyof T]: T[K] extends RpcHandler<
|
|
35
|
-
infer Args,
|
|
36
|
-
infer Success,
|
|
37
|
-
infer Error
|
|
38
|
-
>
|
|
39
|
-
? SerializedRpcHandler<Args, Success, Error>
|
|
40
|
-
: never;
|
|
41
|
-
} extends infer O extends object & RpcCompatible<O>
|
|
42
|
-
? O
|
|
43
|
-
: never;
|
|
44
|
-
|
|
45
|
-
type RpcHandlerEncoder<Success, Error> = {
|
|
46
|
-
success: Schema.Encoder<Success>;
|
|
47
|
-
error: Schema.Encoder<Error>;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export type RpcHandlerEncoders<T extends RpcHandlers> = {
|
|
51
|
-
[K in keyof T]: T[K] extends RpcHandler<any, infer Success, infer Error>
|
|
52
|
-
? RpcHandlerEncoder<Success, Error>
|
|
53
|
-
: never;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
type RpcHandlerDecoder<Success, Error> = {
|
|
57
|
-
success: Schema.Decoder<Success>;
|
|
58
|
-
error: Schema.Decoder<Error>;
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export type RpcHandlerDecoders<T extends RpcHandlers> = {
|
|
62
|
-
[K in keyof T]: T[K] extends RpcHandler<any, infer Success, infer Error>
|
|
63
|
-
? RpcHandlerDecoder<Success, Error>
|
|
64
|
-
: never;
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const serializeRpcHandler = <Args extends Array<any>, Success, Error>(
|
|
68
|
-
handler: RpcHandler<Args, Success, Error>,
|
|
69
|
-
schema: RpcHandlerEncoder<Success, Error>,
|
|
70
|
-
): SerializedRpcHandler<Args, Success, Error> =>
|
|
71
|
-
flow(
|
|
72
|
-
(args) =>
|
|
73
|
-
Effect.sync(
|
|
74
|
-
() =>
|
|
75
|
-
JSON.parse(args, (_, value) => {
|
|
76
|
-
if (
|
|
77
|
-
typeof value === "object" &&
|
|
78
|
-
value !== null &&
|
|
79
|
-
"_tag" in value &&
|
|
80
|
-
value._tag === "Redacted"
|
|
81
|
-
) {
|
|
82
|
-
return Redacted.make(value.value);
|
|
83
|
-
}
|
|
84
|
-
return value;
|
|
85
|
-
}) as Args,
|
|
86
|
-
),
|
|
87
|
-
Effect.flatMap((args) => handler(...args)),
|
|
88
|
-
Effect.exit,
|
|
89
|
-
Effect.map((exit): SerializedExit<Success, Error> => {
|
|
90
|
-
if (exit._tag === "Success") {
|
|
91
|
-
return {
|
|
92
|
-
_tag: "Success",
|
|
93
|
-
value: Schema.encodeSync(schema.success)(exit.value),
|
|
94
|
-
} as const;
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
_tag: "Failure",
|
|
98
|
-
cause: exit.cause.reasons.map((reason): SerializedCause<Error> => {
|
|
99
|
-
switch (reason._tag) {
|
|
100
|
-
case "Fail":
|
|
101
|
-
return {
|
|
102
|
-
_tag: "Fail",
|
|
103
|
-
error: Schema.encodeSync(schema.error)(reason.error),
|
|
104
|
-
};
|
|
105
|
-
case "Die":
|
|
106
|
-
return {
|
|
107
|
-
_tag: "Die",
|
|
108
|
-
defect: Schema.encodeSync(Schema.DefectWithStack)(
|
|
109
|
-
reason.defect,
|
|
110
|
-
),
|
|
111
|
-
};
|
|
112
|
-
case "Interrupt":
|
|
113
|
-
return { _tag: "Interrupt", fiberId: reason.fiberId };
|
|
114
|
-
}
|
|
115
|
-
}),
|
|
116
|
-
} as const;
|
|
117
|
-
}),
|
|
118
|
-
Effect.runPromise,
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
export const serializeRpcHandlers = <T extends RpcHandlers>(
|
|
122
|
-
handlers: T,
|
|
123
|
-
schema: RpcHandlerEncoders<T>,
|
|
124
|
-
): SerializedRpcHandlers<T> =>
|
|
125
|
-
Object.fromEntries(
|
|
126
|
-
Object.entries(schema).map(([key, schema]) => [
|
|
127
|
-
key,
|
|
128
|
-
serializeRpcHandler(handlers[key], schema),
|
|
129
|
-
]),
|
|
130
|
-
) as SerializedRpcHandlers<T>;
|
|
131
|
-
|
|
132
|
-
const encodeRedacted = (value: unknown): unknown => {
|
|
133
|
-
if (Redacted.isRedacted(value)) {
|
|
134
|
-
return { _tag: "Redacted", value: Redacted.value(value) };
|
|
135
|
-
}
|
|
136
|
-
if (Array.isArray(value)) {
|
|
137
|
-
return value.map(encodeRedacted);
|
|
138
|
-
}
|
|
139
|
-
if (value && typeof value === "object" && !("toJSON" in value)) {
|
|
140
|
-
return Object.fromEntries(
|
|
141
|
-
Object.entries(value).map(([key, child]) => [key, encodeRedacted(child)]),
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
return value;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const deserializeRpcHandler =
|
|
148
|
-
<Args extends Array<any>, Success, Error>(
|
|
149
|
-
handler: SerializedRpcHandler<Args, Success, Error>,
|
|
150
|
-
schema: RpcHandlerDecoder<Success, Error>,
|
|
151
|
-
): RpcHandler<Args, Success, Error> =>
|
|
152
|
-
(...args) =>
|
|
153
|
-
Effect.promise(async () => {
|
|
154
|
-
try {
|
|
155
|
-
const serializedArgs = JSON.stringify(
|
|
156
|
-
encodeRedacted(args),
|
|
157
|
-
) as SerializedArgs<Args>;
|
|
158
|
-
return await handler(serializedArgs);
|
|
159
|
-
} catch (error) {
|
|
160
|
-
console.error("Error calling handler", error);
|
|
161
|
-
throw error;
|
|
162
|
-
}
|
|
163
|
-
}).pipe(
|
|
164
|
-
Effect.map((exit): Exit.Exit<Success, Error> => {
|
|
165
|
-
if (exit._tag === "Success") {
|
|
166
|
-
return Exit.succeed(Schema.decodeSync(schema.success)(exit.value));
|
|
167
|
-
}
|
|
168
|
-
return Exit.failCause(
|
|
169
|
-
Cause.fromReasons(
|
|
170
|
-
exit.cause.map((reason): Cause.Reason<Error> => {
|
|
171
|
-
switch (reason._tag) {
|
|
172
|
-
case "Fail":
|
|
173
|
-
return Cause.makeFailReason(
|
|
174
|
-
Schema.decodeSync(schema.error)(reason.error),
|
|
175
|
-
);
|
|
176
|
-
case "Die":
|
|
177
|
-
return Cause.makeDieReason(
|
|
178
|
-
Schema.decodeSync(Schema.DefectWithStack)(reason.defect),
|
|
179
|
-
);
|
|
180
|
-
case "Interrupt":
|
|
181
|
-
return Cause.makeInterruptReason(reason.fiberId);
|
|
182
|
-
}
|
|
183
|
-
}),
|
|
184
|
-
),
|
|
185
|
-
);
|
|
186
|
-
}),
|
|
187
|
-
Effect.flatMap((exit) => exit),
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
export const deserializeRpcHandlers = <T extends RpcHandlers>(
|
|
191
|
-
handlers: SerializedRpcHandlers<T>,
|
|
192
|
-
schema: RpcHandlerDecoders<T>,
|
|
193
|
-
): T =>
|
|
194
|
-
Object.fromEntries(
|
|
195
|
-
Object.entries(schema).map(([key, schema]) => [
|
|
196
|
-
key,
|
|
197
|
-
deserializeRpcHandler(handlers[key as never], schema),
|
|
198
|
-
]),
|
|
199
|
-
) as T;
|
|
200
|
-
|
|
201
|
-
export const defineSchema = <T extends RpcHandlers>(schema: {
|
|
202
|
-
[K in keyof T]: T[K] extends RpcHandler<any, infer Success, infer Error>
|
|
203
|
-
? { success: Schema.Codec<Success, any>; error: Schema.Codec<Error, any> }
|
|
204
|
-
: never;
|
|
205
|
-
}) => schema as RpcHandlerEncoders<T> & RpcHandlerDecoders<T>;
|
package/src/Sidecar/RpcPaths.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import * as Context from "effect/Context";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as FileSystem from "effect/FileSystem";
|
|
4
|
-
import * as Hash from "effect/Hash";
|
|
5
|
-
import * as Layer from "effect/Layer";
|
|
6
|
-
import * as Path from "effect/Path";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import * as AlchemyContext from "../AlchemyContext.ts";
|
|
9
|
-
|
|
10
|
-
export class RpcPaths extends Context.Service<
|
|
11
|
-
RpcPaths,
|
|
12
|
-
{ readonly lock: string; readonly url: string }
|
|
13
|
-
>()("RpcPaths") {}
|
|
14
|
-
|
|
15
|
-
export const layer = (main: string) =>
|
|
16
|
-
Layer.effect(
|
|
17
|
-
RpcPaths,
|
|
18
|
-
Effect.gen(function* () {
|
|
19
|
-
const { dotAlchemy } = yield* AlchemyContext.AlchemyContext;
|
|
20
|
-
const path = yield* Path.Path;
|
|
21
|
-
const fs = yield* FileSystem.FileSystem;
|
|
22
|
-
const id = Math.abs(Hash.string(sanitizeSidecarMain(main)));
|
|
23
|
-
const dir = path.resolve(dotAlchemy, "local");
|
|
24
|
-
yield* fs.makeDirectory(dir, { recursive: true });
|
|
25
|
-
return RpcPaths.of({
|
|
26
|
-
lock: path.join(dir, `${id}.lock`),
|
|
27
|
-
url: path.join(dir, `${id}.url`),
|
|
28
|
-
});
|
|
29
|
-
}),
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* The sidecar main file is provided using `import.meta.resolve("./SidecarServer.ts", import.meta.url)`.
|
|
34
|
-
* This changes the extension to .js if you're currently running in js.
|
|
35
|
-
*/
|
|
36
|
-
export const sanitizeSidecarMain = (url: string) => {
|
|
37
|
-
const main = fileURLToPath(url);
|
|
38
|
-
return import.meta.url.endsWith(".js") ? main.replace(".ts", ".js") : main;
|
|
39
|
-
};
|
package/src/Sidecar/RpcServer.ts
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { RpcSession, type RpcCompatible, type RpcTransport } from "capnweb";
|
|
2
|
-
import * as Context from "effect/Context";
|
|
3
|
-
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as Fiber from "effect/Fiber";
|
|
5
|
-
import * as FileSystem from "effect/FileSystem";
|
|
6
|
-
import * as Schedule from "effect/Schedule";
|
|
7
|
-
import type * as Scope from "effect/Scope";
|
|
8
|
-
import * as Lock from "./Lock.ts";
|
|
9
|
-
import {
|
|
10
|
-
serializeRpcHandlers,
|
|
11
|
-
type RpcHandlerEncoders,
|
|
12
|
-
type RpcHandlers,
|
|
13
|
-
} from "./RpcHandler.ts";
|
|
14
|
-
import * as RpcPaths from "./RpcPaths.ts";
|
|
15
|
-
|
|
16
|
-
export class RpcServer extends Context.Service<
|
|
17
|
-
RpcServer,
|
|
18
|
-
{
|
|
19
|
-
make: <T extends RpcCompatible<T>>(
|
|
20
|
-
main: () => T,
|
|
21
|
-
) => Effect.Effect<
|
|
22
|
-
{
|
|
23
|
-
readonly url: string;
|
|
24
|
-
},
|
|
25
|
-
never,
|
|
26
|
-
Scope.Scope
|
|
27
|
-
>;
|
|
28
|
-
}
|
|
29
|
-
>()("RpcServer") {}
|
|
30
|
-
|
|
31
|
-
export const makeRpcServer = Effect.fn(function* <T extends RpcHandlers, E, R>(
|
|
32
|
-
handlersEffect: Effect.Effect<T, E, R>,
|
|
33
|
-
schema: RpcHandlerEncoders<T>,
|
|
34
|
-
) {
|
|
35
|
-
const lock = yield* Lock.Lock.use((lock) => lock.acquire);
|
|
36
|
-
const fs = yield* FileSystem.FileSystem;
|
|
37
|
-
const paths = yield* RpcPaths.RpcPaths;
|
|
38
|
-
|
|
39
|
-
const server = yield* Effect.gen(function* () {
|
|
40
|
-
const heartbeat = yield* Heartbeat;
|
|
41
|
-
const handlers = yield* handlersEffect;
|
|
42
|
-
const server = yield* RpcServer.use((server) =>
|
|
43
|
-
server.make(() =>
|
|
44
|
-
Object.assign(serializeRpcHandlers(handlers, schema), {
|
|
45
|
-
heartbeat: () => Effect.runPromise(heartbeat.touch),
|
|
46
|
-
shutdown: () => Effect.runPromise(heartbeat.shutdown),
|
|
47
|
-
}),
|
|
48
|
-
),
|
|
49
|
-
);
|
|
50
|
-
yield* fs.writeFileString(paths.url, server.url);
|
|
51
|
-
yield* Effect.addFinalizer(() =>
|
|
52
|
-
fs.readFileString(paths.url).pipe(
|
|
53
|
-
Effect.flatMap((text) =>
|
|
54
|
-
text === server.url ? fs.remove(paths.url) : Effect.void,
|
|
55
|
-
),
|
|
56
|
-
Effect.ignore,
|
|
57
|
-
),
|
|
58
|
-
);
|
|
59
|
-
yield* heartbeat.await;
|
|
60
|
-
}).pipe(Effect.forkScoped);
|
|
61
|
-
|
|
62
|
-
yield* Fiber.joinAll([lock, server]);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
const Heartbeat = Effect.gen(function* () {
|
|
66
|
-
let last = Date.now();
|
|
67
|
-
const fiber = yield* Effect.suspend(() => {
|
|
68
|
-
if (Date.now() - last > 10_000) {
|
|
69
|
-
return Effect.fail({ _tag: "Timeout" } as const);
|
|
70
|
-
}
|
|
71
|
-
return Effect.void;
|
|
72
|
-
}).pipe(Effect.repeat(Schedule.spaced("4 seconds")), Effect.forkScoped);
|
|
73
|
-
return {
|
|
74
|
-
touch: Effect.sync(() => {
|
|
75
|
-
last = Date.now();
|
|
76
|
-
}),
|
|
77
|
-
shutdown: Fiber.interrupt(fiber),
|
|
78
|
-
await: Fiber.join(fiber),
|
|
79
|
-
};
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
interface ServerWebSocketLike {
|
|
83
|
-
send: (message: string) => any | Promise<any>;
|
|
84
|
-
close: (code?: number, reason?: string) => void;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export type WebSocketRpcSession<T extends RpcCompatible<T>> = ReturnType<
|
|
88
|
-
typeof makeWebSocketRpcSession<T>
|
|
89
|
-
>;
|
|
90
|
-
|
|
91
|
-
export function makeWebSocketRpcSession<T extends RpcCompatible<T>>(
|
|
92
|
-
ws: ServerWebSocketLike,
|
|
93
|
-
main: () => T,
|
|
94
|
-
) {
|
|
95
|
-
const { transport, dispatch } = makeWebSocketRpcTransport(ws);
|
|
96
|
-
const session = new RpcSession(transport, main());
|
|
97
|
-
return { session, dispatch };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function makeWebSocketRpcTransport(ws: ServerWebSocketLike) {
|
|
101
|
-
let receiveQueue: Array<string> = [];
|
|
102
|
-
let receiveResolver: ((value: string) => void) | undefined;
|
|
103
|
-
let receiveRejecter: ((reason: unknown) => void) | undefined;
|
|
104
|
-
let error: unknown | undefined;
|
|
105
|
-
return {
|
|
106
|
-
transport: {
|
|
107
|
-
send: async (message: string) => await ws.send(message),
|
|
108
|
-
receive: async () => {
|
|
109
|
-
const next = receiveQueue.shift();
|
|
110
|
-
if (next) {
|
|
111
|
-
return next;
|
|
112
|
-
} else if (error) {
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
115
|
-
return new Promise<string>((resolve, reject) => {
|
|
116
|
-
receiveResolver = resolve;
|
|
117
|
-
receiveRejecter = reject;
|
|
118
|
-
});
|
|
119
|
-
},
|
|
120
|
-
abort: (reason: unknown) => {
|
|
121
|
-
const message =
|
|
122
|
-
reason instanceof Error ? reason.message : String(reason);
|
|
123
|
-
ws.close(3000, message);
|
|
124
|
-
error ??= reason;
|
|
125
|
-
},
|
|
126
|
-
} satisfies RpcTransport,
|
|
127
|
-
dispatch: {
|
|
128
|
-
message: (data: string | Buffer<ArrayBuffer>) => {
|
|
129
|
-
if (error) {
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
data = typeof data === "string" ? data : data.toString("utf-8");
|
|
133
|
-
if (receiveResolver) {
|
|
134
|
-
receiveResolver(data);
|
|
135
|
-
receiveResolver = undefined;
|
|
136
|
-
receiveRejecter = undefined;
|
|
137
|
-
} else {
|
|
138
|
-
receiveQueue.push(data);
|
|
139
|
-
}
|
|
140
|
-
},
|
|
141
|
-
close: (code: number, reason: string) => {
|
|
142
|
-
if (!error) {
|
|
143
|
-
error = new Error(`WebSocket closed with code ${code}: ${reason}`);
|
|
144
|
-
if (receiveRejecter) {
|
|
145
|
-
receiveRejecter(error);
|
|
146
|
-
receiveRejecter = undefined;
|
|
147
|
-
receiveResolver = undefined;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { RpcCompatible } from "capnweb";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as Layer from "effect/Layer";
|
|
4
|
-
import type { WebSocketRpcSession } from "./RpcServer.ts";
|
|
5
|
-
import { makeWebSocketRpcSession, RpcServer } from "./RpcServer.ts";
|
|
6
|
-
|
|
7
|
-
export const RpcServerBun = Layer.succeed(
|
|
8
|
-
RpcServer,
|
|
9
|
-
RpcServer.of({
|
|
10
|
-
make: <T extends RpcCompatible<T>>(main: () => T) =>
|
|
11
|
-
Effect.acquireRelease(
|
|
12
|
-
Effect.sync(() =>
|
|
13
|
-
Bun.serve<WebSocketRpcSession<T>>({
|
|
14
|
-
port: 0,
|
|
15
|
-
fetch: (request, server) => {
|
|
16
|
-
if (server.upgrade(request, { data: undefined! })) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
return new Response("Upgrade failed", { status: 400 });
|
|
20
|
-
},
|
|
21
|
-
websocket: {
|
|
22
|
-
open: (ws) => {
|
|
23
|
-
ws.data = makeWebSocketRpcSession(ws, main);
|
|
24
|
-
},
|
|
25
|
-
message: (ws, message) => {
|
|
26
|
-
ws.data.dispatch.message(message);
|
|
27
|
-
},
|
|
28
|
-
close: (ws, code, reason) => {
|
|
29
|
-
ws.data.dispatch.close(code, reason);
|
|
30
|
-
},
|
|
31
|
-
},
|
|
32
|
-
}),
|
|
33
|
-
),
|
|
34
|
-
(server) => Effect.sync(() => server.stop(true)),
|
|
35
|
-
).pipe(
|
|
36
|
-
Effect.map((server) => ({
|
|
37
|
-
url: `ws://${server.hostname}:${server.port}`,
|
|
38
|
-
})),
|
|
39
|
-
),
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import * as Effect from "effect/Effect";
|
|
2
|
-
import * as Layer from "effect/Layer";
|
|
3
|
-
import { WebSocketServer, type Server } from "ws";
|
|
4
|
-
import { makeWebSocketRpcSession, RpcServer } from "./RpcServer.ts";
|
|
5
|
-
|
|
6
|
-
export const RpcServerNode = Layer.succeed(
|
|
7
|
-
RpcServer,
|
|
8
|
-
RpcServer.of({
|
|
9
|
-
make: Effect.fnUntraced(function* (main) {
|
|
10
|
-
const server = new WebSocketServer({ host: "127.0.0.1", port: 0 });
|
|
11
|
-
const url = yield* Effect.callback<string>((resume) => {
|
|
12
|
-
server.on("connection", (ws) => {
|
|
13
|
-
const session = makeWebSocketRpcSession(ws, main);
|
|
14
|
-
ws.on("message", (data) => {
|
|
15
|
-
session.dispatch.message(data.toString());
|
|
16
|
-
});
|
|
17
|
-
ws.on("close", (code, reason) => {
|
|
18
|
-
session.dispatch.close(code, reason.toString());
|
|
19
|
-
});
|
|
20
|
-
});
|
|
21
|
-
server.on("error", (error) => {
|
|
22
|
-
resume(Effect.die(error));
|
|
23
|
-
});
|
|
24
|
-
server.on("listening", () => {
|
|
25
|
-
resume(getServerAddress(server));
|
|
26
|
-
});
|
|
27
|
-
});
|
|
28
|
-
yield* Effect.addFinalizer(() => Effect.sync(() => server.close()));
|
|
29
|
-
return { url };
|
|
30
|
-
}),
|
|
31
|
-
}),
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
function getServerAddress(server: Server): Effect.Effect<string> {
|
|
35
|
-
const address = server.address();
|
|
36
|
-
if (
|
|
37
|
-
typeof address === "object" &&
|
|
38
|
-
address !== null &&
|
|
39
|
-
"address" in address &&
|
|
40
|
-
"port" in address
|
|
41
|
-
) {
|
|
42
|
-
return Effect.succeed(
|
|
43
|
-
`ws://${address.address === "::" ? "localhost" : address.address}:${address.port}`,
|
|
44
|
-
);
|
|
45
|
-
}
|
|
46
|
-
return Effect.die(
|
|
47
|
-
new Error(
|
|
48
|
-
`Server address is not an object with address and port properties: ${JSON.stringify(address)}`,
|
|
49
|
-
),
|
|
50
|
-
);
|
|
51
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import * as ConfigProvider from "effect/ConfigProvider";
|
|
2
|
-
import * as Effect from "effect/Effect";
|
|
3
|
-
import * as Layer from "effect/Layer";
|
|
4
|
-
import * as Option from "effect/Option";
|
|
5
|
-
import * as AlchemyContext from "../AlchemyContext.ts";
|
|
6
|
-
import { withProfileOverride } from "../Auth/Profile.ts";
|
|
7
|
-
import type { ExecStackOptionsEncoded } from "../Cli/commands/deploy.ts";
|
|
8
|
-
import { loadConfigProvider } from "../Util/ConfigProvider.ts";
|
|
9
|
-
import * as Lock from "./Lock.ts";
|
|
10
|
-
import * as RpcPaths from "./RpcPaths.ts";
|
|
11
|
-
|
|
12
|
-
export const layer = (main: string) =>
|
|
13
|
-
Layer.provideMerge(
|
|
14
|
-
Lock.LockLive,
|
|
15
|
-
Layer.provideMerge(
|
|
16
|
-
RpcPaths.layer(main),
|
|
17
|
-
Layer.mergeAll(
|
|
18
|
-
AlchemyContext.AlchemyContextLive,
|
|
19
|
-
makeConfigProvider(),
|
|
20
|
-
Layer.unwrap(
|
|
21
|
-
Effect.promise(() => {
|
|
22
|
-
if ("Bun" in globalThis) {
|
|
23
|
-
return import("./RpcServerBun.ts").then((m) => m.RpcServerBun);
|
|
24
|
-
} else {
|
|
25
|
-
return import("./RpcServerNode.js").then((m) => m.RpcServerNode);
|
|
26
|
-
}
|
|
27
|
-
}),
|
|
28
|
-
),
|
|
29
|
-
),
|
|
30
|
-
),
|
|
31
|
-
);
|
|
32
|
-
|
|
33
|
-
const makeConfigProvider = () => {
|
|
34
|
-
let options: Partial<ExecStackOptionsEncoded>;
|
|
35
|
-
try {
|
|
36
|
-
options = JSON.parse(
|
|
37
|
-
process.env.ALCHEMY_EXEC_OPTIONS!,
|
|
38
|
-
) as ExecStackOptionsEncoded;
|
|
39
|
-
} catch {
|
|
40
|
-
options = {};
|
|
41
|
-
}
|
|
42
|
-
const envFile = Option.fromUndefinedOr(options.envFile);
|
|
43
|
-
return ConfigProvider.layer(
|
|
44
|
-
loadConfigProvider(envFile).pipe(
|
|
45
|
-
Effect.map((base) => withProfileOverride(base, options.profile)),
|
|
46
|
-
),
|
|
47
|
-
);
|
|
48
|
-
};
|