alchemy 2.0.0-beta.51 → 2.0.0-beta.52
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/exec.js +16 -22
- package/bin/exec.js.map +1 -1
- package/lib/Apply.js +15 -3
- package/lib/Apply.js.map +1 -1
- package/lib/Auth/AuthProvider.js +1 -1
- package/lib/Auth/AuthProvider.js.map +1 -1
- package/lib/Binding.d.ts.map +1 -1
- package/lib/Binding.js +12 -8
- package/lib/Binding.js.map +1 -1
- package/lib/Build/DevServer.d.ts +113 -0
- package/lib/Build/DevServer.d.ts.map +1 -0
- package/lib/Build/DevServer.js +212 -0
- package/lib/Build/DevServer.js.map +1 -0
- package/lib/Build/Local.d.ts +2 -0
- package/lib/Build/Local.d.ts.map +1 -0
- package/lib/Build/Local.js +4 -0
- package/lib/Build/Local.js.map +1 -0
- package/lib/Bundle/Bundle.js +1 -1
- package/lib/Bundle/Bundle.js.map +1 -1
- package/lib/Cloudflare/Access.js +1 -1
- package/lib/Cloudflare/Access.js.map +1 -1
- package/lib/Cloudflare/AiGateway/AiGateway.d.ts +1 -1
- package/lib/Cloudflare/AiGateway/AiGateway.js +1 -1
- package/lib/Cloudflare/Browser/Browser.d.ts +84 -12
- package/lib/Cloudflare/Browser/Browser.d.ts.map +1 -1
- package/lib/Cloudflare/Browser/Browser.js +80 -9
- package/lib/Cloudflare/Browser/Browser.js.map +1 -1
- package/lib/Cloudflare/Browser/BrowserBinding.d.ts +90 -16
- package/lib/Cloudflare/Browser/BrowserBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Browser/BrowserBinding.js +41 -6
- package/lib/Cloudflare/Browser/BrowserBinding.js.map +1 -1
- package/lib/Cloudflare/Browser/index.d.ts +1 -1
- package/lib/Cloudflare/Browser/index.d.ts.map +1 -1
- package/lib/Cloudflare/Browser/index.js.map +1 -1
- package/lib/Cloudflare/Container/ContainerBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Container/ContainerBinding.js +2 -4
- package/lib/Cloudflare/Container/ContainerBinding.js.map +1 -1
- package/lib/Cloudflare/Images/Images.d.ts +4 -3
- package/lib/Cloudflare/Images/Images.d.ts.map +1 -1
- package/lib/Cloudflare/Images/Images.js.map +1 -1
- package/lib/Cloudflare/Providers.d.ts +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +4 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/RateLimit/RateLimit.d.ts +4 -3
- package/lib/Cloudflare/RateLimit/RateLimit.d.ts.map +1 -1
- package/lib/Cloudflare/RateLimit/RateLimit.js.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.d.ts +64 -12
- package/lib/Cloudflare/Website/StaticSite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/StaticSite.js +80 -30
- package/lib/Cloudflare/Website/StaticSite.js.map +1 -1
- package/lib/Cloudflare/Website/Vite.d.ts +36 -7
- package/lib/Cloudflare/Website/Vite.d.ts.map +1 -1
- package/lib/Cloudflare/Website/Vite.js +26 -8
- package/lib/Cloudflare/Website/Vite.js.map +1 -1
- package/lib/Cloudflare/Workers/Assets.d.ts +10 -4
- package/lib/Cloudflare/Workers/Assets.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Assets.js +6 -6
- package/lib/Cloudflare/Workers/Assets.js.map +1 -1
- package/lib/Cloudflare/Workers/DynamicWorkerLoader.d.ts +4 -4
- package/lib/Cloudflare/Workers/InferEnv.d.ts +1 -1
- package/lib/Cloudflare/Workers/InferEnv.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js +45 -11
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.d.ts +5 -4
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.js +4 -2
- package/lib/Cloudflare/Workers/RpcDurableObjectNamespace.js.map +1 -1
- package/lib/Cloudflare/Workers/RpcWorker.d.ts +3 -2
- package/lib/Cloudflare/Workers/RpcWorker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/RpcWorker.js +5 -3
- package/lib/Cloudflare/Workers/RpcWorker.js.map +1 -1
- package/lib/Cloudflare/Workers/VersionMetadata.d.ts +99 -0
- package/lib/Cloudflare/Workers/VersionMetadata.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/VersionMetadata.js +65 -0
- package/lib/Cloudflare/Workers/VersionMetadata.js.map +1 -0
- package/lib/Cloudflare/Workers/VersionMetadataBinding.d.ts +35 -0
- package/lib/Cloudflare/Workers/VersionMetadataBinding.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/VersionMetadataBinding.js +31 -0
- package/lib/Cloudflare/Workers/VersionMetadataBinding.js.map +1 -0
- package/lib/Cloudflare/Workers/Worker.d.ts +18 -18
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +23 -37
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js +7 -0
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +2 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.js.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts +8 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.js +1 -0
- package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkflowBridge.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkflowBridge.js +31 -2
- package/lib/Cloudflare/Workers/WorkflowBridge.js.map +1 -1
- package/lib/Cloudflare/Workers/index.d.ts +2 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +2 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts.map +1 -1
- package/lib/Diff.d.ts.map +1 -1
- package/lib/Diff.js +7 -0
- package/lib/Diff.js.map +1 -1
- package/lib/Drizzle/Postgres.d.ts +13 -12
- package/lib/Drizzle/Postgres.d.ts.map +1 -1
- package/lib/Drizzle/Postgres.js +13 -12
- package/lib/Drizzle/Postgres.js.map +1 -1
- package/lib/Drizzle/Schema.d.ts +1 -1
- package/lib/Drizzle/Schema.d.ts.map +1 -1
- package/lib/Drizzle/Schema.js +14 -6
- package/lib/Drizzle/Schema.js.map +1 -1
- package/lib/Local/RpcSerialization.js +5 -2
- package/lib/Local/RpcSerialization.js.map +1 -1
- package/lib/Platform.d.ts.map +1 -1
- package/lib/Platform.js +27 -25
- package/lib/Platform.js.map +1 -1
- package/lib/Resource.d.ts +1 -1
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js +9 -12
- package/lib/Resource.js.map +1 -1
- package/lib/Runtime.d.ts +1 -1
- package/lib/Runtime.d.ts.map +1 -1
- package/lib/Runtime.js +3 -4
- package/lib/Runtime.js.map +1 -1
- package/lib/Util/effect.d.ts.map +1 -1
- package/lib/Util/effect.js +13 -15
- package/lib/Util/effect.js.map +1 -1
- package/lib/Util/poll.d.ts +0 -1
- package/lib/Util/poll.d.ts.map +1 -1
- package/lib/Util/poll.js +2 -2
- package/lib/Util/poll.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +20 -20
- package/src/Apply.ts +22 -3
- package/src/Auth/AuthProvider.ts +1 -1
- package/src/Binding.ts +45 -38
- package/src/Build/DevServer.ts +330 -0
- package/src/Build/Local.ts +4 -0
- package/src/Bundle/Bundle.ts +1 -1
- package/src/Cloudflare/Access.ts +1 -1
- package/src/Cloudflare/AiGateway/AiGateway.ts +1 -1
- package/src/Cloudflare/Browser/Browser.ts +84 -12
- package/src/Cloudflare/Browser/BrowserBinding.ts +205 -33
- package/src/Cloudflare/Browser/index.ts +15 -2
- package/src/Cloudflare/Container/ContainerBinding.ts +5 -10
- package/src/Cloudflare/Images/Images.ts +4 -3
- package/src/Cloudflare/Providers.ts +5 -0
- package/src/Cloudflare/RateLimit/RateLimit.ts +4 -3
- package/src/Cloudflare/Website/StaticSite.ts +154 -41
- package/src/Cloudflare/Website/Vite.ts +73 -25
- package/src/Cloudflare/Workers/Assets.ts +10 -8
- package/src/Cloudflare/Workers/DynamicWorkerLoader.ts +4 -4
- package/src/Cloudflare/Workers/InferEnv.ts +14 -12
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +54 -13
- package/src/Cloudflare/Workers/RpcDurableObjectNamespace.ts +11 -8
- package/src/Cloudflare/Workers/RpcWorker.ts +8 -7
- package/src/Cloudflare/Workers/VersionMetadata.ts +129 -0
- package/src/Cloudflare/Workers/VersionMetadataBinding.ts +82 -0
- package/src/Cloudflare/Workers/Worker.ts +60 -81
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +6 -0
- package/src/Cloudflare/Workers/WorkerBinding.ts +2 -0
- package/src/Cloudflare/Workers/Workflow.ts +12 -1
- package/src/Cloudflare/Workers/WorkflowBridge.ts +47 -6
- package/src/Cloudflare/Workers/index.ts +2 -0
- package/src/Diff.ts +7 -0
- package/src/Drizzle/Postgres.ts +13 -12
- package/src/Drizzle/Schema.ts +16 -6
- package/src/Local/RpcSerialization.ts +5 -2
- package/src/Platform.ts +36 -32
- package/src/Resource.ts +12 -13
- package/src/Runtime.ts +3 -7
- package/src/Util/effect.ts +13 -17
- package/src/Util/poll.ts +3 -3
|
@@ -1,11 +1,17 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
1
2
|
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Exit from "effect/Exit";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Scope from "effect/Scope";
|
|
6
|
+
import { ExecutionContext } from "../../ExecutionContext.ts";
|
|
7
|
+
import { isScopeEjected } from "./HttpServer.ts";
|
|
8
|
+
import { getWorkerExport } from "./WorkerBridge.ts";
|
|
2
9
|
import {
|
|
3
10
|
WorkflowEvent as WorkflowEventService,
|
|
4
11
|
type WorkflowExport,
|
|
5
12
|
type WorkflowImpl,
|
|
6
13
|
WorkflowStep,
|
|
7
14
|
} from "./Workflow.ts";
|
|
8
|
-
import { getWorkerExport } from "./WorkerBridge.ts";
|
|
9
15
|
|
|
10
16
|
/**
|
|
11
17
|
* Create a WorkflowBridge class that extends `WorkflowEntrypoint` and
|
|
@@ -52,15 +58,50 @@ export const makeWorkflowBridge =
|
|
|
52
58
|
|
|
53
59
|
async run(event: any, step: any): Promise<unknown> {
|
|
54
60
|
const fn = await this.fn;
|
|
55
|
-
|
|
61
|
+
// Each run-invocation gets a fresh ExecutionContext (scope + cache),
|
|
62
|
+
// following the same per-invocation-scope pattern as
|
|
63
|
+
// `WorkerBridge.processEvent`. `task` threads this into every step via
|
|
64
|
+
// the surrounding body context, so `@binding` helpers that need it
|
|
65
|
+
// (e.g. `Drizzle.postgres`) resolve their per-run resources inside
|
|
66
|
+
// workflow steps. The same scope is also provided as the ambient
|
|
67
|
+
// `Scope` service, matching the Worker and Durable Object bridges.
|
|
68
|
+
const scope = Scope.makeUnsafe();
|
|
69
|
+
const exit = await Effect.runPromiseExit(
|
|
56
70
|
fn(event.payload).pipe(
|
|
57
|
-
Effect.
|
|
58
|
-
|
|
59
|
-
|
|
71
|
+
Effect.provide(
|
|
72
|
+
Layer.succeed(
|
|
73
|
+
WorkflowEventService,
|
|
74
|
+
wrapWorkflowEvent(event),
|
|
75
|
+
).pipe(
|
|
76
|
+
Layer.provideMerge(
|
|
77
|
+
Layer.succeed(WorkflowStep, wrapWorkflowStep(step)),
|
|
78
|
+
),
|
|
79
|
+
Layer.provideMerge(
|
|
80
|
+
Layer.succeed(ExecutionContext, { scope, cache: {} }),
|
|
81
|
+
),
|
|
82
|
+
Layer.provideMerge(Layer.succeed(Scope.Scope, scope)),
|
|
83
|
+
),
|
|
60
84
|
),
|
|
61
|
-
Effect.provideService(WorkflowStep, wrapWorkflowStep(step)),
|
|
62
85
|
) as Effect.Effect<unknown>,
|
|
63
86
|
);
|
|
87
|
+
// Settle the run's resources with its real exit, unless a binding
|
|
88
|
+
// ejected the scope to outlive the invocation. The workflow runtime has
|
|
89
|
+
// no `waitUntil` to detach cleanup to, so close inline — a failing
|
|
90
|
+
// finalizer (e.g. a pg pool `end()` on a dropped connection) is logged
|
|
91
|
+
// and ignored so it can't mask the run's outcome.
|
|
92
|
+
if (!isScopeEjected(scope)) {
|
|
93
|
+
await Scope.close(scope, exit).pipe(
|
|
94
|
+
Effect.ignoreCause({
|
|
95
|
+
log: "Warn",
|
|
96
|
+
message: "Workflow run scope close failed",
|
|
97
|
+
}),
|
|
98
|
+
Effect.runPromise,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
if (Exit.isSuccess(exit)) {
|
|
102
|
+
return exit.value;
|
|
103
|
+
}
|
|
104
|
+
throw Cause.squash(exit.cause);
|
|
64
105
|
}
|
|
65
106
|
};
|
|
66
107
|
|
|
@@ -16,6 +16,8 @@ export * from "./Rpc.ts";
|
|
|
16
16
|
export * from "./RpcDurableObjectNamespace.ts";
|
|
17
17
|
export * from "./RpcWorker.ts";
|
|
18
18
|
export * from "./ScheduledEvents.ts";
|
|
19
|
+
export * from "./VersionMetadata.ts";
|
|
20
|
+
export * from "./VersionMetadataBinding.ts";
|
|
19
21
|
export * from "./WebSocket.ts";
|
|
20
22
|
export * from "./Worker.ts";
|
|
21
23
|
export * from "./WorkerBinding.ts";
|
package/src/Diff.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Redacted from "effect/Redacted";
|
|
2
3
|
import type { Input } from "./Input.ts";
|
|
3
4
|
import * as Output from "./Output.ts";
|
|
4
5
|
import type { BindingNode } from "./Plan.ts";
|
|
@@ -119,6 +120,12 @@ export const deepEqual = (
|
|
|
119
120
|
|
|
120
121
|
const canonicalize = (value: unknown, stripNullish: boolean): unknown => {
|
|
121
122
|
if (stripNullish && value == null) return undefined;
|
|
123
|
+
if (Redacted.isRedacted(value)) {
|
|
124
|
+
return {
|
|
125
|
+
_tag: "Redacted",
|
|
126
|
+
value: Redacted.value(value),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
122
129
|
if (Array.isArray(value)) {
|
|
123
130
|
return value.map((v) => canonicalize(v, stripNullish));
|
|
124
131
|
}
|
package/src/Drizzle/Postgres.ts
CHANGED
|
@@ -25,19 +25,20 @@ import { proxyChain } from "../Util/proxy-chain.ts";
|
|
|
25
25
|
* });
|
|
26
26
|
* ```
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
* so the pool is built at most
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
28
|
+
* The connect work is deferred until the first query and memoized on the
|
|
29
|
+
* current `ExecutionContext` (`ctx.cache`), so the pool is built at most
|
|
30
|
+
* once per execution — a Worker `fetch`/`queue`/`scheduled` event or a
|
|
31
|
+
* Workflow run — and reused across every query and `task` step in that
|
|
32
|
+
* execution. Yielding the connection string is likewise deferred, so
|
|
33
|
+
* deploy / plan-time invocations (where `WorkerEnvironment` isn't
|
|
34
|
+
* provided) never trigger a real connection attempt.
|
|
33
35
|
*
|
|
34
|
-
* The
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* inside `Effect.scoped
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* use a pool after end".
|
|
36
|
+
* The pool is built against the execution's `Scope` (`ctx.scope`), so its
|
|
37
|
+
* `end` finalizer fires when that scope closes — when the request / run
|
|
38
|
+
* settles, not when the `Cloudflare.Worker` init scope closes. Init runs
|
|
39
|
+
* inside `Effect.scoped` and closes after returning the exports object;
|
|
40
|
+
* building lazily against `ctx.scope` (rather than that init scope) is
|
|
41
|
+
* what keeps later requests from seeing "Cannot use a pool after end".
|
|
41
42
|
*
|
|
42
43
|
* @binding
|
|
43
44
|
*/
|
package/src/Drizzle/Schema.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as crypto from "node:crypto";
|
|
2
1
|
import * as Effect from "effect/Effect";
|
|
3
2
|
import * as FileSystem from "effect/FileSystem";
|
|
4
3
|
import * as Path from "effect/Path";
|
|
4
|
+
import * as crypto from "node:crypto";
|
|
5
5
|
import { isResolved } from "../Diff.ts";
|
|
6
6
|
import * as Provider from "../Provider.ts";
|
|
7
7
|
import { Resource } from "../Resource.ts";
|
|
@@ -45,7 +45,7 @@ export type Schema = Resource<
|
|
|
45
45
|
"Drizzle.Schema",
|
|
46
46
|
SchemaProps,
|
|
47
47
|
{
|
|
48
|
-
/**
|
|
48
|
+
/** Path to the migrations directory, relative to the current working directory. */
|
|
49
49
|
out: string;
|
|
50
50
|
/**
|
|
51
51
|
* sha256 of the latest snapshot.json. Stable across deploys when the
|
|
@@ -117,6 +117,12 @@ export const SchemaProvider = () =>
|
|
|
117
117
|
const resolveOut = (p: SchemaProps) =>
|
|
118
118
|
path.resolve(process.cwd(), p.out ?? "./migrations");
|
|
119
119
|
|
|
120
|
+
// The `out` attribute is exposed as a path relative to the current
|
|
121
|
+
// working directory so that persisted state stays portable across
|
|
122
|
+
// machines/checkouts. Internal filesystem ops always use the absolute
|
|
123
|
+
// `resolveOut` form.
|
|
124
|
+
const relativeOut = (abs: string) => path.relative(process.cwd(), abs);
|
|
125
|
+
|
|
120
126
|
const resolveSchema = (p: SchemaProps) =>
|
|
121
127
|
path.resolve(process.cwd(), p.schema);
|
|
122
128
|
|
|
@@ -241,7 +247,7 @@ export const SchemaProvider = () =>
|
|
|
241
247
|
const migrations = yield* listMigrationDirs(out);
|
|
242
248
|
const latest = yield* readLatestSnapshot(out);
|
|
243
249
|
return {
|
|
244
|
-
out,
|
|
250
|
+
out: relativeOut(out),
|
|
245
251
|
snapshotHash: latest?.hash ?? sha(JSON.stringify(cur)),
|
|
246
252
|
migrations,
|
|
247
253
|
};
|
|
@@ -256,8 +262,12 @@ export const SchemaProvider = () =>
|
|
|
256
262
|
// `schema.out` as an unresolved Output during plan and cascade
|
|
257
263
|
// into spurious updates of their own.
|
|
258
264
|
const { sqlStatements } = yield* detectDrift(news);
|
|
259
|
-
|
|
260
|
-
|
|
265
|
+
// Originally `output.out` was an absolute path, which is not portable.
|
|
266
|
+
// So, we trigger an update to migrate existing resources.
|
|
267
|
+
// This is safe because `regenerate` is idempotent.
|
|
268
|
+
return sqlStatements.length > 0 || path.isAbsolute(output.out)
|
|
269
|
+
? { action: "update" }
|
|
270
|
+
: undefined;
|
|
261
271
|
}),
|
|
262
272
|
read: Effect.fn(function* ({ olds, output }) {
|
|
263
273
|
if (!output) return undefined;
|
|
@@ -267,7 +277,7 @@ export const SchemaProvider = () =>
|
|
|
267
277
|
const latest = yield* readLatestSnapshot(out);
|
|
268
278
|
const migrations = yield* listMigrationDirs(out);
|
|
269
279
|
return {
|
|
270
|
-
out,
|
|
280
|
+
out: relativeOut(out),
|
|
271
281
|
snapshotHash: latest?.hash ?? output.snapshotHash,
|
|
272
282
|
migrations,
|
|
273
283
|
};
|
|
@@ -89,7 +89,7 @@ export const unwrapRpcHandlers = <T extends Record<string, any>>(
|
|
|
89
89
|
) as RpcUnwrapped<T>;
|
|
90
90
|
};
|
|
91
91
|
|
|
92
|
-
const serializeError = Schema.encodeSync(Schema.Defect);
|
|
92
|
+
const serializeError = Schema.encodeSync(Schema.Defect());
|
|
93
93
|
|
|
94
94
|
const wrapRpcEffectHandler = <Args extends Array<any>, Success, Error>(
|
|
95
95
|
handler: RpcEffectHandler<Args, Success, Error>,
|
|
@@ -107,7 +107,10 @@ const wrapRpcEffectHandler = <Args extends Array<any>, Success, Error>(
|
|
|
107
107
|
cause: exit.cause.reasons.map((reason): RpcSerializedCause<Error> => {
|
|
108
108
|
switch (reason._tag) {
|
|
109
109
|
case "Fail":
|
|
110
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
_tag: "Fail",
|
|
112
|
+
error: serializeError(reason.error) as Error,
|
|
113
|
+
};
|
|
111
114
|
case "Die":
|
|
112
115
|
return { _tag: "Die", defect: serializeError(reason.defect) };
|
|
113
116
|
case "Interrupt":
|
package/src/Platform.ts
CHANGED
|
@@ -2,13 +2,12 @@ import * as ConfigError from "effect/Config";
|
|
|
2
2
|
import * as ConfigProvider from "effect/ConfigProvider";
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
|
-
import
|
|
5
|
+
import * as Effectable from "effect/Effectable";
|
|
6
6
|
import * as Layer from "effect/Layer";
|
|
7
7
|
import * as Option from "effect/Option";
|
|
8
8
|
import * as Redacted from "effect/Redacted";
|
|
9
9
|
import type { Scope } from "effect/Scope";
|
|
10
10
|
import type { HttpClient } from "effect/unstable/http/HttpClient";
|
|
11
|
-
import { SingleShotGen } from "effect/Utils";
|
|
12
11
|
import type { PolicyLike } from "./Binding.ts";
|
|
13
12
|
import type { Dependencies } from "./Dependencies.ts";
|
|
14
13
|
import type { ExecutionContext } from "./ExecutionContext.ts";
|
|
@@ -225,7 +224,7 @@ export const Platform = <
|
|
|
225
224
|
constructor(id, props, impl, true);
|
|
226
225
|
} else if (!impl) {
|
|
227
226
|
const cls = makeClass(id, props);
|
|
228
|
-
const
|
|
227
|
+
const evaluate = () =>
|
|
229
228
|
(!isTag
|
|
230
229
|
? // this is a non-tagged resource yielded without providing an implementation
|
|
231
230
|
// e.g.
|
|
@@ -272,7 +271,7 @@ export const Platform = <
|
|
|
272
271
|
);
|
|
273
272
|
return Object.assign(
|
|
274
273
|
function (impl: Impl) {
|
|
275
|
-
return cls.
|
|
274
|
+
return cls.Self.pipe(Effect.provide(cls.make(impl)));
|
|
276
275
|
},
|
|
277
276
|
// we splice in the Effect so this can be yielded to indicate a non-Effect native instance
|
|
278
277
|
// e.g. here, we yield it - in this case we don't want to provide an implementation
|
|
@@ -280,42 +279,29 @@ export const Platform = <
|
|
|
280
279
|
// main: "./src/worker.ts"
|
|
281
280
|
// });
|
|
282
281
|
cls,
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
282
|
+
// Spread the Effect prototype LAST so it overrides the evaluate copied
|
|
283
|
+
// from `cls`: yielding this no-impl form bridges to the (possibly
|
|
284
|
+
// non-Effect-native) resource rather than resolving the Self tag.
|
|
285
|
+
Effectable.Prototype({
|
|
286
|
+
label: `${type}<${id}>`,
|
|
287
|
+
evaluate,
|
|
288
|
+
}),
|
|
289
289
|
);
|
|
290
290
|
} else {
|
|
291
291
|
// impl was provided inline, this is a non-tagged eager instance
|
|
292
292
|
// e.g.
|
|
293
293
|
// export default Cloudflare.Worker("id", { main: "./src/worker.ts" }, Effect.gen(function* () { .. })
|
|
294
294
|
const cls = makeClass(id, props);
|
|
295
|
-
return cls.
|
|
295
|
+
return cls.Self.pipe(Effect.provide(cls.make(impl)), effectClass);
|
|
296
296
|
}
|
|
297
297
|
};
|
|
298
298
|
|
|
299
299
|
const makeClass = (id: string, props: Props) => {
|
|
300
|
-
|
|
300
|
+
class Platform {
|
|
301
301
|
static readonly Self = Self(`${type}<${id}>`);
|
|
302
302
|
static readonly Platform = Context.Service<Platform, Platform>(
|
|
303
303
|
`Platform<${type}<${id}>>`,
|
|
304
304
|
);
|
|
305
|
-
static [Symbol.iterator](): Iterator<
|
|
306
|
-
Effect.Effect<void, never, Self>,
|
|
307
|
-
Resource,
|
|
308
|
-
void
|
|
309
|
-
> {
|
|
310
|
-
return new SingleShotGen(this.asEffect()) as any;
|
|
311
|
-
}
|
|
312
|
-
static asEffect() {
|
|
313
|
-
return this.Self;
|
|
314
|
-
}
|
|
315
|
-
static pipe(...args: any[]) {
|
|
316
|
-
// @ts-expect-error
|
|
317
|
-
return pipe(this, ...args);
|
|
318
|
-
}
|
|
319
305
|
static of = (shape: any) => shape;
|
|
320
306
|
static make = (impl: Impl) => {
|
|
321
307
|
// build the Layer once for the root Self
|
|
@@ -460,13 +446,31 @@ export const Platform = <
|
|
|
460
446
|
SelfLayer,
|
|
461
447
|
);
|
|
462
448
|
};
|
|
463
|
-
}
|
|
449
|
+
}
|
|
450
|
+
// Make the platform class itself a real Effect: `yield* MyWorker` resolves
|
|
451
|
+
// the Self tag. Replaces the hand-rolled asEffect/pipe/[Symbol.iterator].
|
|
452
|
+
return Object.assign(
|
|
453
|
+
Platform,
|
|
454
|
+
Effectable.Prototype({
|
|
455
|
+
label: `${type}<${id}>`,
|
|
456
|
+
evaluate: () => Platform.Self,
|
|
457
|
+
}),
|
|
458
|
+
);
|
|
464
459
|
};
|
|
465
460
|
|
|
466
|
-
const instance = Object.assign(
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
461
|
+
const instance = Object.assign(
|
|
462
|
+
constructor,
|
|
463
|
+
resource,
|
|
464
|
+
// Spread the Effect prototype LAST so it overrides any evaluate inherited
|
|
465
|
+
// from `resource`; `yield* Cloudflare.Worker` resolves the resource Self.
|
|
466
|
+
Effectable.Prototype({
|
|
467
|
+
label: `${type}`,
|
|
468
|
+
evaluate: () => resource.Self,
|
|
469
|
+
}),
|
|
470
|
+
{
|
|
471
|
+
Platform: Platform,
|
|
472
|
+
...methods,
|
|
473
|
+
},
|
|
474
|
+
) as any;
|
|
471
475
|
return instance;
|
|
472
476
|
};
|
package/src/Resource.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Effectable from "effect/Effectable";
|
|
2
3
|
import * as Option from "effect/Option";
|
|
3
|
-
import {
|
|
4
|
-
import { SingleShotGen } from "effect/Utils";
|
|
4
|
+
import type { Pipeable } from "effect/Pipeable";
|
|
5
5
|
import { AdoptPolicy } from "./AdoptPolicy.ts";
|
|
6
6
|
import { toFqn } from "./FQN.ts";
|
|
7
7
|
import type { Input, InputProps } from "./Input.ts";
|
|
@@ -287,17 +287,6 @@ export function Resource<R extends ResourceLike>(
|
|
|
287
287
|
const ProviderTag = Provider(type);
|
|
288
288
|
|
|
289
289
|
const Service = {
|
|
290
|
-
[Symbol.iterator]() {
|
|
291
|
-
return new SingleShotGen(this.asEffect());
|
|
292
|
-
},
|
|
293
|
-
pipe() {
|
|
294
|
-
return pipeArguments(this, arguments);
|
|
295
|
-
},
|
|
296
|
-
asEffect() {
|
|
297
|
-
return Effect.succeed((id: string, props: R["Props"]) =>
|
|
298
|
-
constructor(id, props),
|
|
299
|
-
);
|
|
300
|
-
},
|
|
301
290
|
/**
|
|
302
291
|
* Build a typed reference to a deployed instance of this resource
|
|
303
292
|
* — in the current stack/stage by default, or in another via
|
|
@@ -323,6 +312,16 @@ export function Resource<R extends ResourceLike>(
|
|
|
323
312
|
? Object.assign(ResourceClass, args[0])
|
|
324
313
|
: constructor(...(args as [string, R["Props"]])),
|
|
325
314
|
Service,
|
|
315
|
+
// Make the constructor itself a real Effect: `yield* MyResource` resolves
|
|
316
|
+
// to the constructor function (same as the old `asEffect()`), and
|
|
317
|
+
// `Effect.isEffect(MyResource)` is now true so `Effect.all`/`forEach` work.
|
|
318
|
+
Effectable.Prototype({
|
|
319
|
+
label: `Resource<${type}>`,
|
|
320
|
+
evaluate: () =>
|
|
321
|
+
Effect.succeed((id: string, props: R["Props"]) =>
|
|
322
|
+
constructor(id, props),
|
|
323
|
+
),
|
|
324
|
+
}),
|
|
326
325
|
) as any;
|
|
327
326
|
|
|
328
327
|
return ResourceClass;
|
package/src/Runtime.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import * as Layer from "effect/Layer";
|
|
10
|
+
import { asEffect } from "./Util/types.ts";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Resolve the user's default-export entrypoint into a `Layer` for the
|
|
@@ -14,7 +15,7 @@ import * as Layer from "effect/Layer";
|
|
|
14
15
|
*
|
|
15
16
|
* `entrypoint` may be any of:
|
|
16
17
|
* - a `Layer` factory (`{ build: (...) => ... }`) — used as-is
|
|
17
|
-
* - an
|
|
18
|
+
* - an Alchemy `Platform`/`Worker` construct (now a real `Effect`)
|
|
18
19
|
* - a plain `Effect`
|
|
19
20
|
*
|
|
20
21
|
* Centralized so the inline ternary doesn't have to be re-emitted into
|
|
@@ -29,10 +30,5 @@ export const makeEntrypointLayer = (
|
|
|
29
30
|
if (typeof entrypoint?.build === "function") {
|
|
30
31
|
return entrypoint;
|
|
31
32
|
}
|
|
32
|
-
return Layer.effect(
|
|
33
|
-
tag,
|
|
34
|
-
typeof entrypoint?.asEffect === "function"
|
|
35
|
-
? entrypoint.asEffect()
|
|
36
|
-
: entrypoint,
|
|
37
|
-
);
|
|
33
|
+
return Layer.effect(tag, asEffect(entrypoint));
|
|
38
34
|
};
|
package/src/Util/effect.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as Context from "effect/Context";
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
|
-
import
|
|
4
|
-
import { SingleShotGen } from "effect/Utils";
|
|
3
|
+
import * as Effectable from "effect/Effectable";
|
|
5
4
|
|
|
6
5
|
export type EffectClass<Shape, A, Err = never, Req = never> = Effect.Effect<
|
|
7
6
|
A,
|
|
@@ -22,18 +21,15 @@ export const effectClass: {
|
|
|
22
21
|
impl === undefined
|
|
23
22
|
? (innerImpl: any) => effectClass(innerImpl)
|
|
24
23
|
: (Object.assign(
|
|
25
|
-
class {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
impl,
|
|
24
|
+
class {},
|
|
25
|
+
// Spreading the Effect prototype onto the class (static side) makes the
|
|
26
|
+
// class itself a real Effect — `Effect.isEffect(X)` is true, so
|
|
27
|
+
// `Effect.all([X])` / `Effect.forEach` work — and subclasses
|
|
28
|
+
// (`class Y extends effectClass(impl)`) inherit the protocol statically.
|
|
29
|
+
Effectable.Prototype({
|
|
30
|
+
label: "alchemy/EffectClass",
|
|
31
|
+
evaluate: () => impl,
|
|
32
|
+
}),
|
|
37
33
|
) as unknown as EffectClass<any, any, any, any>)) as any;
|
|
38
34
|
|
|
39
35
|
export const taggedFunction = <
|
|
@@ -43,10 +39,10 @@ export const taggedFunction = <
|
|
|
43
39
|
tag: Tag,
|
|
44
40
|
fn: Fn,
|
|
45
41
|
): Tag & Fn => {
|
|
42
|
+
// The Proxy below forwards every Effect-protocol key to `tag` (already an
|
|
43
|
+
// Effect), so `asEffect`/`[Symbol.iterator]`/`pipe` need no explicit
|
|
44
|
+
// override — only `toString` diverges.
|
|
46
45
|
const overrides = {
|
|
47
|
-
asEffect: () => tag,
|
|
48
|
-
[Symbol.iterator]: () => tag[Symbol.iterator](),
|
|
49
|
-
pipe: (...fns: any[]) => pipeArguments(tag, fns as any),
|
|
50
46
|
toString: () => `${tag.toString()}.${fn.name}`,
|
|
51
47
|
};
|
|
52
48
|
|
package/src/Util/poll.ts
CHANGED
|
@@ -27,7 +27,6 @@ export const poll = Effect.fn("poll")(
|
|
|
27
27
|
effect: Effect.Effect<A, E, R>;
|
|
28
28
|
predicate: (value: A) => boolean;
|
|
29
29
|
schedule?: Schedule.Schedule<unknown, unknown, never>;
|
|
30
|
-
times?: number;
|
|
31
30
|
}) =>
|
|
32
31
|
input.effect.pipe(
|
|
33
32
|
Effect.filterOrFail(
|
|
@@ -40,8 +39,9 @@ export const poll = Effect.fn("poll")(
|
|
|
40
39
|
),
|
|
41
40
|
Effect.retry({
|
|
42
41
|
while: isPredicateFailed,
|
|
43
|
-
schedule:
|
|
44
|
-
|
|
42
|
+
schedule:
|
|
43
|
+
input.schedule ??
|
|
44
|
+
Schedule.both(Schedule.spaced("5 seconds"), Schedule.recurs(50)),
|
|
45
45
|
}),
|
|
46
46
|
),
|
|
47
47
|
);
|