alchemy 2.0.0-beta.35 → 2.0.0-beta.37
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 +176 -26
- package/bin/exec.js.map +1 -1
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +22 -2
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/Apply.d.ts.map +1 -1
- package/lib/Apply.js +6 -1
- package/lib/Apply.js.map +1 -1
- package/lib/Cli/main.d.ts.map +1 -1
- package/lib/Cli/main.js +2 -0
- package/lib/Cli/main.js.map +1 -1
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts +54 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js +17 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.js.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts +37 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js +45 -0
- package/lib/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.js.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/index.d.ts +3 -0
- package/lib/Cloudflare/AnalyticsEngine/index.d.ts.map +1 -0
- package/lib/Cloudflare/AnalyticsEngine/index.js +3 -0
- package/lib/Cloudflare/AnalyticsEngine/index.js.map +1 -0
- package/lib/Cloudflare/D1/D1Connection.d.ts +47 -3
- package/lib/Cloudflare/D1/D1Connection.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Connection.js +62 -5
- package/lib/Cloudflare/D1/D1Connection.js.map +1 -1
- package/lib/Cloudflare/Images/Images.d.ts +103 -0
- package/lib/Cloudflare/Images/Images.d.ts.map +1 -0
- package/lib/Cloudflare/Images/Images.js +82 -0
- package/lib/Cloudflare/Images/Images.js.map +1 -0
- package/lib/Cloudflare/Images/ImagesBinding.d.ts +73 -0
- package/lib/Cloudflare/Images/ImagesBinding.d.ts.map +1 -0
- package/lib/Cloudflare/Images/ImagesBinding.js +83 -0
- package/lib/Cloudflare/Images/ImagesBinding.js.map +1 -0
- package/lib/Cloudflare/Images/index.d.ts +3 -0
- package/lib/Cloudflare/Images/index.d.ts.map +1 -0
- package/lib/Cloudflare/Images/index.js +3 -0
- package/lib/Cloudflare/Images/index.js.map +1 -0
- package/lib/Cloudflare/Local/SidecarHandlers.js +9 -1
- package/lib/Cloudflare/Local/SidecarHandlers.js.map +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Providers.js +6 -1
- package/lib/Cloudflare/Providers.js.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.d.ts +135 -0
- package/lib/Cloudflare/R2/R2Bucket.d.ts.map +1 -1
- package/lib/Cloudflare/R2/R2Bucket.js +146 -7
- package/lib/Cloudflare/R2/R2Bucket.js.map +1 -1
- package/lib/Cloudflare/StateStore/Api.d.ts +6 -1
- package/lib/Cloudflare/StateStore/Api.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Api.js +23 -1
- package/lib/Cloudflare/StateStore/Api.js.map +1 -1
- package/lib/Cloudflare/StateStore/Store.d.ts +16 -1
- package/lib/Cloudflare/StateStore/Store.d.ts.map +1 -1
- package/lib/Cloudflare/StateStore/Store.js +22 -5
- package/lib/Cloudflare/StateStore/Store.js.map +1 -1
- package/lib/Cloudflare/Workers/CronEventSource.d.ts +35 -0
- package/lib/Cloudflare/Workers/CronEventSource.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/CronEventSource.js +55 -0
- package/lib/Cloudflare/Workers/CronEventSource.js.map +1 -0
- package/lib/Cloudflare/Workers/InferEnv.d.ts +37 -2
- 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 +2 -1
- package/lib/Cloudflare/Workers/LocalWorkerProvider.js.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.d.ts +76 -3
- package/lib/Cloudflare/Workers/Rpc.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Rpc.js +197 -13
- package/lib/Cloudflare/Workers/Rpc.js.map +1 -1
- package/lib/Cloudflare/Workers/Worker.d.ts +26 -6
- package/lib/Cloudflare/Workers/Worker.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Worker.js +183 -41
- package/lib/Cloudflare/Workers/Worker.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBundle.js +15 -5
- package/lib/Cloudflare/Workers/WorkerBundle.js.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts +50 -47
- package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.js +41 -35
- package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
- package/lib/Cloudflare/Workers/index.d.ts +1 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +1 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/index.d.ts +2 -0
- package/lib/Cloudflare/index.d.ts.map +1 -1
- package/lib/Cloudflare/index.js +2 -0
- package/lib/Cloudflare/index.js.map +1 -1
- package/lib/Deploy.d.ts +4 -1
- package/lib/Deploy.d.ts.map +1 -1
- package/lib/Deploy.js +2 -2
- package/lib/Deploy.js.map +1 -1
- package/lib/Destroy.d.ts +4 -1
- package/lib/Destroy.d.ts.map +1 -1
- package/lib/Destroy.js +2 -2
- package/lib/Destroy.js.map +1 -1
- package/lib/Output.d.ts +45 -5
- package/lib/Output.d.ts.map +1 -1
- package/lib/Output.js +100 -4
- package/lib/Output.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +93 -12
- package/lib/Plan.js.map +1 -1
- package/lib/Platform.d.ts.map +1 -1
- package/lib/Platform.js +16 -3
- package/lib/Platform.js.map +1 -1
- package/lib/Ref.d.ts +4 -1
- package/lib/Ref.d.ts.map +1 -1
- package/lib/Ref.js +1 -1
- package/lib/Ref.js.map +1 -1
- package/lib/Resource.d.ts +8 -0
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js +10 -0
- package/lib/Resource.js.map +1 -1
- package/lib/RuntimeContext.d.ts +3 -1
- package/lib/RuntimeContext.d.ts.map +1 -1
- package/lib/RuntimeContext.js.map +1 -1
- package/lib/Secret.d.ts +50 -0
- package/lib/Secret.d.ts.map +1 -0
- package/lib/Secret.js +23 -0
- package/lib/Secret.js.map +1 -0
- package/lib/Serverless/Function.d.ts +9 -1
- package/lib/Serverless/Function.d.ts.map +1 -1
- package/lib/Stack.d.ts +14 -5
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js +31 -19
- package/lib/Stack.js.map +1 -1
- package/lib/State/HttpStateApi.d.ts +15 -1
- package/lib/State/HttpStateApi.d.ts.map +1 -1
- package/lib/State/HttpStateApi.js +11 -0
- package/lib/State/HttpStateApi.js.map +1 -1
- package/lib/State/HttpStateStore.d.ts.map +1 -1
- package/lib/State/HttpStateStore.js +11 -0
- package/lib/State/HttpStateStore.js.map +1 -1
- package/lib/State/InMemoryState.d.ts +2 -2
- package/lib/State/InMemoryState.d.ts.map +1 -1
- package/lib/State/InMemoryState.js +12 -6
- package/lib/State/InMemoryState.js.map +1 -1
- package/lib/State/LocalState.d.ts.map +1 -1
- package/lib/State/LocalState.js +11 -2
- package/lib/State/LocalState.js.map +1 -1
- package/lib/State/State.d.ts +21 -0
- package/lib/State/State.d.ts.map +1 -1
- package/lib/Test/Bun.d.ts.map +1 -1
- package/lib/Test/Bun.js +30 -7
- package/lib/Test/Bun.js.map +1 -1
- package/lib/Test/Core.d.ts +17 -2
- package/lib/Test/Core.d.ts.map +1 -1
- package/lib/Test/Core.js +29 -11
- package/lib/Test/Core.js.map +1 -1
- package/lib/Test/Vitest.d.ts.map +1 -1
- package/lib/Test/Vitest.js +26 -5
- package/lib/Test/Vitest.js.map +1 -1
- package/lib/Util/LocalhostDns.d.ts +23 -0
- package/lib/Util/LocalhostDns.d.ts.map +1 -0
- package/lib/Util/LocalhostDns.js +46 -0
- package/lib/Util/LocalhostDns.js.map +1 -0
- package/lib/Util/PlatformServices.d.ts.map +1 -1
- package/lib/Util/PlatformServices.js +2 -0
- package/lib/Util/PlatformServices.js.map +1 -1
- package/lib/Util/effect.d.ts +7 -0
- package/lib/Util/effect.d.ts.map +1 -1
- package/lib/Util/effect.js +6 -0
- package/lib/Util/effect.js.map +1 -1
- package/lib/Variable.d.ts +29 -0
- package/lib/Variable.d.ts.map +1 -0
- package/lib/Variable.js +9 -0
- package/lib/Variable.js.map +1 -0
- package/lib/index.d.ts +3 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -0
- package/lib/index.js.map +1 -1
- package/lib/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/AWS/Lambda/Function.ts +30 -2
- package/src/Apply.ts +8 -1
- package/src/Cli/main.ts +3 -0
- package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDataset.ts +82 -0
- package/src/Cloudflare/AnalyticsEngine/AnalyticsEngineDatasetBinding.ts +106 -0
- package/src/Cloudflare/AnalyticsEngine/index.ts +2 -0
- package/src/Cloudflare/D1/D1Connection.ts +95 -12
- package/src/Cloudflare/Images/Images.ts +121 -0
- package/src/Cloudflare/Images/ImagesBinding.ts +192 -0
- package/src/Cloudflare/Images/index.ts +2 -0
- package/src/Cloudflare/Local/SidecarHandlers.ts +9 -1
- package/src/Cloudflare/Providers.ts +8 -0
- package/src/Cloudflare/R2/R2Bucket.ts +271 -7
- package/src/Cloudflare/StateStore/Api.ts +34 -1
- package/src/Cloudflare/StateStore/Store.ts +40 -10
- package/src/Cloudflare/Workers/CronEventSource.ts +89 -0
- package/src/Cloudflare/Workers/InferEnv.ts +94 -16
- package/src/Cloudflare/Workers/LocalWorkerProvider.ts +9 -1
- package/src/Cloudflare/Workers/Rpc.ts +227 -18
- package/src/Cloudflare/Workers/Worker.ts +295 -62
- package/src/Cloudflare/Workers/WorkerBundle.ts +15 -5
- package/src/Cloudflare/Workers/Workflow.ts +74 -70
- package/src/Cloudflare/Workers/index.ts +1 -0
- package/src/Cloudflare/index.ts +2 -0
- package/src/Deploy.ts +5 -1
- package/src/Destroy.ts +5 -1
- package/src/Output.ts +121 -12
- package/src/Plan.ts +101 -12
- package/src/Platform.ts +19 -4
- package/src/Ref.ts +10 -5
- package/src/Resource.ts +22 -0
- package/src/RuntimeContext.ts +1 -0
- package/src/Secret.ts +87 -0
- package/src/Serverless/Function.ts +10 -1
- package/src/Stack.ts +52 -29
- package/src/State/HttpStateApi.ts +21 -0
- package/src/State/HttpStateStore.ts +21 -0
- package/src/State/InMemoryState.ts +29 -8
- package/src/State/LocalState.ts +28 -4
- package/src/State/State.ts +21 -0
- package/src/Test/Bun.ts +43 -7
- package/src/Test/Core.ts +29 -8
- package/src/Test/Vitest.ts +36 -4
- package/src/Util/LocalhostDns.ts +52 -0
- package/src/Util/PlatformServices.ts +2 -0
- package/src/Util/effect.ts +25 -0
- package/src/Variable.ts +44 -0
- package/src/index.ts +3 -0
|
@@ -9,17 +9,18 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
|
|
|
9
9
|
import cloudflareVite from "@distilled.cloud/cloudflare-vite-plugin";
|
|
10
10
|
import * as workers from "@distilled.cloud/cloudflare/workers";
|
|
11
11
|
import * as zones from "@distilled.cloud/cloudflare/zones";
|
|
12
|
+
import * as Cause from "effect/Cause";
|
|
12
13
|
import * as Context from "effect/Context";
|
|
13
14
|
import * as Data from "effect/Data";
|
|
14
15
|
import * as Effect from "effect/Effect";
|
|
15
16
|
import * as Exit from "effect/Exit";
|
|
16
|
-
import * as FileSystem from "effect/FileSystem";
|
|
17
17
|
import * as Layer from "effect/Layer";
|
|
18
18
|
import * as Option from "effect/Option";
|
|
19
19
|
import * as Path from "effect/Path";
|
|
20
20
|
import * as Redacted from "effect/Redacted";
|
|
21
21
|
import * as Schedule from "effect/Schedule";
|
|
22
22
|
import * as Scope from "effect/Scope";
|
|
23
|
+
import * as Stream from "effect/Stream";
|
|
23
24
|
import { createRequire } from "node:module";
|
|
24
25
|
import path from "node:path";
|
|
25
26
|
import { pathToFileURL } from "node:url";
|
|
@@ -32,14 +33,17 @@ import { isResolved } from "../../Diff.js";
|
|
|
32
33
|
import { ExecutionContext } from "../../ExecutionContext.js";
|
|
33
34
|
import * as Output from "../../Output.js";
|
|
34
35
|
import { Platform, } from "../../Platform.js";
|
|
36
|
+
import { isYieldableEffectLike } from "../../Util/effect.js";
|
|
35
37
|
import * as Provider from "../../Provider.js";
|
|
36
38
|
import { Resource } from "../../Resource.js";
|
|
37
39
|
import * as Serverless from "../../Serverless/index.js";
|
|
38
40
|
import { Stack } from "../../Stack.js";
|
|
41
|
+
import { isAnalyticsEngineDataset, } from "../AnalyticsEngine/AnalyticsEngineDataset.js";
|
|
39
42
|
import { isArtifacts as isArtifactsBinding, } from "../Artifacts/Artifacts.js";
|
|
40
43
|
import { CloudflareEnvironment } from "../CloudflareEnvironment.js";
|
|
41
44
|
import { D1Database } from "../D1/D1Database.js";
|
|
42
45
|
import { fromCloudflareFetcher } from "../Fetcher.js";
|
|
46
|
+
import { isImages as isImagesBinding, } from "../Images/Images.js";
|
|
43
47
|
import { SidecarLive } from "../Local/Sidecar.js";
|
|
44
48
|
import { CloudflareLogs } from "../Logs.js";
|
|
45
49
|
import { isAssets, readAssets, uploadAssets, } from "./Assets.js";
|
|
@@ -48,7 +52,7 @@ import { isDurableObjectExport, isDurableObjectNamespaceLike, } from "./DurableO
|
|
|
48
52
|
import { workersHttpHandler } from "./HttpServer.js";
|
|
49
53
|
import { LocalWorkerProvider } from "./LocalWorkerProvider.js";
|
|
50
54
|
import { Request } from "./Request.js";
|
|
51
|
-
import { makeRpcStub } from "./Rpc.js";
|
|
55
|
+
import { encodeRpcError, ErrorTag, makeRpcStub, toRpcStream, } from "./Rpc.js";
|
|
52
56
|
import { WorkerBundle } from "./WorkerBundle.js";
|
|
53
57
|
import { createWorkerName } from "./WorkerName.js";
|
|
54
58
|
const WorkerTypeId = "Cloudflare.Worker";
|
|
@@ -434,8 +438,11 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
434
438
|
for (const bindingName in props.bindings) {
|
|
435
439
|
// @ts-expect-error
|
|
436
440
|
const bindingEff = props.bindings?.[bindingName];
|
|
437
|
-
|
|
438
|
-
|
|
441
|
+
// Bindings can be passed as a plain resource value, an Effect that
|
|
442
|
+
// yields a resource, or an effect-class (e.g. a `Cloudflare.Worker`
|
|
443
|
+
// class). Resolve the yieldable forms before deriving binding metadata.
|
|
444
|
+
const binding = isYieldableEffectLike(bindingEff)
|
|
445
|
+
? (yield* bindingEff)
|
|
439
446
|
: bindingEff;
|
|
440
447
|
const bindingMeta = isAssets(binding)
|
|
441
448
|
? {
|
|
@@ -448,44 +455,69 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
448
455
|
name: bindingName,
|
|
449
456
|
namespace: binding.namespace,
|
|
450
457
|
}
|
|
451
|
-
:
|
|
458
|
+
: isImagesBinding(binding)
|
|
452
459
|
? {
|
|
453
|
-
type: "
|
|
460
|
+
type: "images",
|
|
454
461
|
name: bindingName,
|
|
455
|
-
className: binding.className ?? binding.name,
|
|
456
462
|
}
|
|
457
|
-
: binding
|
|
463
|
+
: isAnalyticsEngineDataset(binding)
|
|
458
464
|
? {
|
|
459
|
-
type: "
|
|
460
|
-
id: binding.databaseId,
|
|
465
|
+
type: "analytics_engine",
|
|
461
466
|
name: bindingName,
|
|
467
|
+
dataset: binding.dataset,
|
|
462
468
|
}
|
|
463
|
-
: binding
|
|
469
|
+
: isDurableObjectNamespaceLike(binding)
|
|
464
470
|
? {
|
|
465
|
-
type: "
|
|
471
|
+
type: "durable_object_namespace",
|
|
466
472
|
name: bindingName,
|
|
467
|
-
|
|
468
|
-
jurisdiction: binding.jurisdiction.pipe(Output.map((jurisdiction) => jurisdiction === "default" ? undefined : jurisdiction)),
|
|
473
|
+
className: binding.className ?? binding.name,
|
|
469
474
|
}
|
|
470
|
-
: binding.Type === "Cloudflare.
|
|
475
|
+
: binding.Type === "Cloudflare.D1Database"
|
|
471
476
|
? {
|
|
472
|
-
type: "
|
|
477
|
+
type: "d1",
|
|
478
|
+
id: binding.databaseId,
|
|
473
479
|
name: bindingName,
|
|
474
|
-
namespaceId: binding.namespaceId,
|
|
475
480
|
}
|
|
476
|
-
: binding.Type === "Cloudflare.
|
|
481
|
+
: binding.Type === "Cloudflare.R2Bucket"
|
|
477
482
|
? {
|
|
478
|
-
type: "
|
|
483
|
+
type: "r2_bucket",
|
|
479
484
|
name: bindingName,
|
|
480
|
-
|
|
485
|
+
bucketName: binding.bucketName,
|
|
486
|
+
jurisdiction: binding.jurisdiction.pipe(Output.map((jurisdiction) => jurisdiction === "default"
|
|
487
|
+
? undefined
|
|
488
|
+
: jurisdiction)),
|
|
481
489
|
}
|
|
482
|
-
: binding.Type === "Cloudflare.
|
|
490
|
+
: binding.Type === "Cloudflare.KVNamespace"
|
|
483
491
|
? {
|
|
484
|
-
type: "
|
|
492
|
+
type: "kv_namespace",
|
|
485
493
|
name: bindingName,
|
|
494
|
+
namespaceId: binding.namespaceId,
|
|
486
495
|
}
|
|
487
|
-
:
|
|
488
|
-
|
|
496
|
+
: binding.Type === "Cloudflare.Queue"
|
|
497
|
+
? {
|
|
498
|
+
type: "queue",
|
|
499
|
+
name: bindingName,
|
|
500
|
+
queueName: binding.queueName,
|
|
501
|
+
}
|
|
502
|
+
: binding.Type === "Cloudflare.AiGateway"
|
|
503
|
+
? {
|
|
504
|
+
type: "ai",
|
|
505
|
+
name: bindingName,
|
|
506
|
+
}
|
|
507
|
+
: binding.Type === "Cloudflare.Hyperdrive"
|
|
508
|
+
? {
|
|
509
|
+
type: "hyperdrive",
|
|
510
|
+
name: bindingName,
|
|
511
|
+
id: binding.hyperdriveId,
|
|
512
|
+
}
|
|
513
|
+
: isWorker(binding)
|
|
514
|
+
? {
|
|
515
|
+
type: "service",
|
|
516
|
+
name: bindingName,
|
|
517
|
+
service: binding.workerName,
|
|
518
|
+
}
|
|
519
|
+
: // TODO(sam): handle others
|
|
520
|
+
undefined;
|
|
489
521
|
if (bindingMeta) {
|
|
490
522
|
yield* resource.bind `${bindingName}`({
|
|
491
523
|
bindings: [bindingMeta],
|
|
@@ -501,6 +533,7 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
501
533
|
const listeners = [];
|
|
502
534
|
const exports = {};
|
|
503
535
|
const env = {};
|
|
536
|
+
let userShape;
|
|
504
537
|
const ctx = {
|
|
505
538
|
Type: WorkerTypeId,
|
|
506
539
|
id,
|
|
@@ -546,7 +579,14 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
546
579
|
: JSON.stringify(value)));
|
|
547
580
|
return key;
|
|
548
581
|
}),
|
|
549
|
-
serve: (handler) =>
|
|
582
|
+
serve: (handler, options) => {
|
|
583
|
+
// Capture the user's full default-export shape so `exports` can
|
|
584
|
+
// expose any non-handler methods on it as RPC methods on the
|
|
585
|
+
// deployed `WorkerEntrypoint` subclass — see `__rpc__` below.
|
|
586
|
+
if (options?.shape)
|
|
587
|
+
userShape = options.shape;
|
|
588
|
+
return ctx.listen(workersHttpHandler(handler));
|
|
589
|
+
},
|
|
550
590
|
listen: ((handler) => Effect.sync(() => Effect.isEffect(handler)
|
|
551
591
|
? listeners.push(handler)
|
|
552
592
|
: listeners.push(Effect.succeed(handler)))),
|
|
@@ -558,6 +598,18 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
558
598
|
concurrency: "unbounded",
|
|
559
599
|
});
|
|
560
600
|
const services = yield* Effect.context();
|
|
601
|
+
// Provide the per-request runtime layer (services + `WorkerExecutionContext`
|
|
602
|
+
// + a fresh `ExecutionContext`/`Scope`) to a user effect, then run it.
|
|
603
|
+
// This is the bridge between Cloudflare's request-time callback and
|
|
604
|
+
// the user's Effect-native handler. Used by both the standard
|
|
605
|
+
// `handle()` dispatch (fetch/scheduled/…) and the per-RPC dispatchers
|
|
606
|
+
// below — keeping them on a single layer-provision path.
|
|
607
|
+
const runUserEffect = (eff, context) => {
|
|
608
|
+
const scope = Scope.makeUnsafe();
|
|
609
|
+
return eff
|
|
610
|
+
.pipe(Effect.provideContext(services), Scope.provide(scope), Effect.provide(Layer.succeed(WorkerExecutionContext, context)), Effect.provide(Layer.succeed(ExecutionContext, { scope, cache: {} })), Effect.runPromiseExit)
|
|
611
|
+
.finally(() => context.waitUntil(Effect.runPromise(Scope.close(scope, Exit.void))));
|
|
612
|
+
};
|
|
561
613
|
const handle = (type) => (request, env, context) => {
|
|
562
614
|
const event = {
|
|
563
615
|
kind: "Cloudflare.Workers.WorkerEvent",
|
|
@@ -569,20 +621,60 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
569
621
|
for (const handler of handlers) {
|
|
570
622
|
const eff = handler(event);
|
|
571
623
|
if (Effect.isEffect(eff)) {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
})), Effect.runPromise)
|
|
578
|
-
.finally(() => context.waitUntil(Effect.runPromise(Scope.close(scope, Exit.void))));
|
|
624
|
+
return runUserEffect(eff, context).then((exit) => {
|
|
625
|
+
if (exit._tag === "Success")
|
|
626
|
+
return exit.value;
|
|
627
|
+
throw Cause.squash(exit.cause);
|
|
628
|
+
});
|
|
579
629
|
}
|
|
580
630
|
}
|
|
581
631
|
return Promise.reject(new Error("No event handler found"));
|
|
582
632
|
};
|
|
633
|
+
// RPC method dispatchers — one per non-handler method on the user's
|
|
634
|
+
// shape. Each dispatcher is invoked by the WorkerEntrypoint bridge
|
|
635
|
+
// as `dispatcher(args, ctx)`: `args` are the user-facing call args,
|
|
636
|
+
// `ctx` is the `this.ctx` that Cloudflare hands the bridge per RPC
|
|
637
|
+
// request. The dispatcher runs the user effect with the same runtime
|
|
638
|
+
// layer the fetch path uses, then envelope-encodes the result so
|
|
639
|
+
// `Effect.fail` round-trips as `RpcErrorEnvelope` and `Stream` as
|
|
640
|
+
// `RpcStreamEnvelope` (consumers wrap the binding with
|
|
641
|
+
// `toPromiseApi`/`bindWorker` to decode).
|
|
642
|
+
const exportedHandlerSet = new Set(ExportedHandlerMethods);
|
|
643
|
+
const rpcDispatchers = {};
|
|
644
|
+
if (userShape) {
|
|
645
|
+
for (const [name, value] of Object.entries(userShape)) {
|
|
646
|
+
if (exportedHandlerSet.has(name))
|
|
647
|
+
continue;
|
|
648
|
+
if (typeof value !== "function")
|
|
649
|
+
continue;
|
|
650
|
+
rpcDispatchers[name] = async (args, context) => {
|
|
651
|
+
const result = value(...args);
|
|
652
|
+
if (!Effect.isEffect(result))
|
|
653
|
+
return result;
|
|
654
|
+
const exit = await runUserEffect(result, context);
|
|
655
|
+
if (exit._tag === "Success") {
|
|
656
|
+
if (Stream.isStream(exit.value)) {
|
|
657
|
+
return await Effect.runPromise(toRpcStream(exit.value));
|
|
658
|
+
}
|
|
659
|
+
return exit.value;
|
|
660
|
+
}
|
|
661
|
+
const failReason = exit.cause.reasons.find(Cause.isFailReason);
|
|
662
|
+
if (failReason) {
|
|
663
|
+
return {
|
|
664
|
+
_tag: ErrorTag,
|
|
665
|
+
error: encodeRpcError(failReason.error),
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
const dieReason = exit.cause.reasons.find(Cause.isDieReason);
|
|
669
|
+
throw (dieReason?.defect ??
|
|
670
|
+
new Error("RPC method failed with an unexpected cause"));
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
}
|
|
583
674
|
return {
|
|
584
675
|
...exports,
|
|
585
676
|
default: Object.fromEntries(ExportedHandlerMethods.map((method) => [method, handle(method)])),
|
|
677
|
+
__rpc__: rpcDispatchers,
|
|
586
678
|
};
|
|
587
679
|
}),
|
|
588
680
|
};
|
|
@@ -590,7 +682,10 @@ export const Worker = Platform(WorkerTypeId, {
|
|
|
590
682
|
},
|
|
591
683
|
});
|
|
592
684
|
export const bindWorker = Effect.fnUntraced(function* (workerEff) {
|
|
593
|
-
|
|
685
|
+
// Worker classes and regular Effects are both yieldable here.
|
|
686
|
+
const worker = isYieldableEffectLike(workerEff)
|
|
687
|
+
? yield* workerEff
|
|
688
|
+
: workerEff;
|
|
594
689
|
const self = yield* Worker;
|
|
595
690
|
yield* self.bind `${worker}`({
|
|
596
691
|
bindings: [
|
|
@@ -601,10 +696,12 @@ export const bindWorker = Effect.fnUntraced(function* (workerEff) {
|
|
|
601
696
|
},
|
|
602
697
|
],
|
|
603
698
|
});
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
//
|
|
607
|
-
|
|
699
|
+
// `bindWorker` runs at *init* phase (both at plantime and at runtime
|
|
700
|
+
// cold-start). `WorkerEnvironment` only exists at exec phase on the
|
|
701
|
+
// deployed worker, so we hand `makeRpcStub` an `Effect<stub>` that
|
|
702
|
+
// resolves the binding lazily on each method call.
|
|
703
|
+
const stubEff = WorkerEnvironment.asEffect().pipe(Effect.map((env) => env[worker.LogicalId]));
|
|
704
|
+
return makeRpcStub(stubEff);
|
|
608
705
|
});
|
|
609
706
|
export class BindWorkerPolicy extends Binding.Policy()("Cloudflare.Worker.Bind") {
|
|
610
707
|
}
|
|
@@ -650,6 +747,9 @@ function getDurableObjectBindings(bindings, workerName) {
|
|
|
650
747
|
]
|
|
651
748
|
: []));
|
|
652
749
|
}
|
|
750
|
+
export function getCronBindings(bindings) {
|
|
751
|
+
return Array.from(new Set(bindings.flatMap((b) => b.data.crons ?? [])));
|
|
752
|
+
}
|
|
653
753
|
function getDurableObjectTagMap(tags) {
|
|
654
754
|
return Object.fromEntries(tags.flatMap((tag) => {
|
|
655
755
|
if (!tag.startsWith("alchemy:do:")) {
|
|
@@ -667,18 +767,18 @@ export const WorkerProvider = () => selectLayer({
|
|
|
667
767
|
dev: () => Layer.provide(LocalWorkerProvider(), SidecarLive),
|
|
668
768
|
});
|
|
669
769
|
export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(function* () {
|
|
670
|
-
const fs = yield* FileSystem.FileSystem;
|
|
671
770
|
const path = yield* Path.Path;
|
|
672
771
|
const { accountId } = yield* CloudflareEnvironment;
|
|
673
|
-
const virtualEntryPlugin = yield* Bundle.virtualEntryPlugin;
|
|
674
772
|
const bundler = yield* WorkerBundle;
|
|
675
773
|
const stack = yield* Stack;
|
|
676
774
|
const createScriptSubdomain = yield* workers.createScriptSubdomain;
|
|
677
775
|
const deleteScript = yield* workers.deleteScript;
|
|
678
776
|
const getScriptSubdomain = yield* workers.getScriptSubdomain;
|
|
777
|
+
const getScriptSchedule = yield* workers.getScriptSchedule;
|
|
679
778
|
const getScriptSettings = yield* workers.getScriptScriptAndVersionSetting;
|
|
680
779
|
const getSubdomain = yield* workers.getSubdomain;
|
|
681
780
|
const putScript = yield* workers.putScript;
|
|
781
|
+
const putScriptSchedule = yield* workers.putScriptSchedule;
|
|
682
782
|
const putDomain = yield* workers.putDomain;
|
|
683
783
|
const listDomains = yield* workers.listDomains;
|
|
684
784
|
const deleteDomain = yield* workers.deleteDomain;
|
|
@@ -713,6 +813,32 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
713
813
|
const normalizeDomains = (domain) => domain === undefined
|
|
714
814
|
? []
|
|
715
815
|
: Array.from(new Set((Array.isArray(domain) ? domain : [domain]).map(toPunycode)));
|
|
816
|
+
const normalizeCrons = (crons) => Array.from(new Set(crons ?? []));
|
|
817
|
+
const getWorkerCrons = (scriptName) => getScriptSchedule({
|
|
818
|
+
accountId,
|
|
819
|
+
scriptName,
|
|
820
|
+
}).pipe(Effect.map((response) => normalizeCrons(response.schedules.map((schedule) => schedule.cron))), Effect.catchTag("WorkerNotFound", () => Effect.succeed([])));
|
|
821
|
+
const reconcileCrons = (scriptName, desired, previous, session) => Effect.gen(function* () {
|
|
822
|
+
const live = yield* getWorkerCrons(scriptName);
|
|
823
|
+
const desiredSorted = [...desired].sort();
|
|
824
|
+
const liveSorted = [...live].sort();
|
|
825
|
+
const changed = desiredSorted.length !== liveSorted.length ||
|
|
826
|
+
desiredSorted.some((cron, index) => cron !== liveSorted[index]);
|
|
827
|
+
if (!changed)
|
|
828
|
+
return live;
|
|
829
|
+
if (desired.length > 0 || previous.length > 0 || live.length > 0) {
|
|
830
|
+
yield* session.note(`Reconciling Cron Triggers (${desired.length}) ...`);
|
|
831
|
+
}
|
|
832
|
+
const result = yield* putScriptSchedule({
|
|
833
|
+
accountId,
|
|
834
|
+
scriptName,
|
|
835
|
+
body: desired.map((cron) => ({ cron })),
|
|
836
|
+
}).pipe(Effect.retry({
|
|
837
|
+
while: (error) => error?._tag === "WorkerNotFound",
|
|
838
|
+
schedule: Schedule.exponential(200).pipe(Schedule.both(Schedule.recurs(15))),
|
|
839
|
+
}));
|
|
840
|
+
return normalizeCrons(result.schedules.map((schedule) => schedule.cron));
|
|
841
|
+
});
|
|
716
842
|
/**
|
|
717
843
|
* Infer the Cloudflare Zone ID for a given hostname by listing the
|
|
718
844
|
* account's zones and matching the hostname against each zone's name —
|
|
@@ -1304,6 +1430,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1304
1430
|
yield* session.note(`Reconciling custom domains (${desiredDomains.length}) ...`);
|
|
1305
1431
|
}
|
|
1306
1432
|
const domains = yield* reconcileDomains(name, desiredDomains, previousDomains);
|
|
1433
|
+
const crons = yield* reconcileCrons(name, normalizeCrons([...getCronBindings(bindings), ...(news.crons ?? [])]), output?.crons ?? [], session);
|
|
1307
1434
|
return {
|
|
1308
1435
|
workerId: worker.id ?? name,
|
|
1309
1436
|
workerName: name,
|
|
@@ -1315,6 +1442,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1315
1442
|
durableObjectNamespaces,
|
|
1316
1443
|
accountId,
|
|
1317
1444
|
domains,
|
|
1445
|
+
crons,
|
|
1318
1446
|
hash,
|
|
1319
1447
|
};
|
|
1320
1448
|
});
|
|
@@ -1361,7 +1489,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1361
1489
|
});
|
|
1362
1490
|
return Worker.Provider.of({
|
|
1363
1491
|
stables: ["workerId", "workerName"],
|
|
1364
|
-
diff: Effect.fnUntraced(function* ({ id, news, olds, output }) {
|
|
1492
|
+
diff: Effect.fnUntraced(function* ({ id, news, olds, output, newBindings, }) {
|
|
1365
1493
|
if (!isResolved(news))
|
|
1366
1494
|
return undefined;
|
|
1367
1495
|
if ((output?.accountId ?? accountId) !== accountId) {
|
|
@@ -1383,7 +1511,18 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1383
1511
|
.sort();
|
|
1384
1512
|
const domainsChanged = newDomains.length !== oldDomains.length ||
|
|
1385
1513
|
newDomains.some((d, i) => d !== oldDomains[i]);
|
|
1386
|
-
|
|
1514
|
+
const newCrons = normalizeCrons([
|
|
1515
|
+
...(Array.isArray(newBindings)
|
|
1516
|
+
? getCronBindings(newBindings)
|
|
1517
|
+
: []),
|
|
1518
|
+
...(news.crons ?? []),
|
|
1519
|
+
]).sort();
|
|
1520
|
+
const oldCrons = [...(output?.crons ?? [])].sort();
|
|
1521
|
+
const cronsChanged = newCrons.length !== oldCrons.length ||
|
|
1522
|
+
newCrons.some((cron, index) => cron !== oldCrons[index]);
|
|
1523
|
+
if (domainsChanged ||
|
|
1524
|
+
cronsChanged ||
|
|
1525
|
+
(yield* hasChanged(id, news, output))) {
|
|
1387
1526
|
return {
|
|
1388
1527
|
action: "update",
|
|
1389
1528
|
stables: oldWorkerName === workerName ? ["workerName"] : undefined,
|
|
@@ -1484,6 +1623,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1484
1623
|
durableObjectNamespaces,
|
|
1485
1624
|
accountId,
|
|
1486
1625
|
domains: [],
|
|
1626
|
+
crons: [],
|
|
1487
1627
|
};
|
|
1488
1628
|
}),
|
|
1489
1629
|
read: Effect.fnUntraced(function* ({ id, output, olds }) {
|
|
@@ -1511,6 +1651,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1511
1651
|
service: workerName,
|
|
1512
1652
|
}).pipe(Effect.map((r) => r.result ?? [])),
|
|
1513
1653
|
]);
|
|
1654
|
+
const crons = yield* getWorkerCrons(workerName);
|
|
1514
1655
|
yield* Effect.logInfo(`Cloudflare Worker read: found ${workerName}`);
|
|
1515
1656
|
const attrs = {
|
|
1516
1657
|
accountId,
|
|
@@ -1525,6 +1666,7 @@ export const LiveWorkerProvider = () => Provider.effect(Worker, Effect.gen(funct
|
|
|
1525
1666
|
domains: domainsList.flatMap((d) => d.id && d.hostname && d.zoneId
|
|
1526
1667
|
? [{ id: d.id, hostname: d.hostname, zoneId: d.zoneId }]
|
|
1527
1668
|
: []),
|
|
1669
|
+
crons,
|
|
1528
1670
|
};
|
|
1529
1671
|
// Centralized ownership decision: the engine routes `read`'s
|
|
1530
1672
|
// return value based on `AdoptPolicy`. We hand it the attrs
|