alchemy 2.0.0-beta.50 → 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 +133 -135
- package/bin/exec.js.map +1 -1
- package/lib/AWS/Lambda/BucketEventSource.d.ts.map +1 -1
- package/lib/AWS/Lambda/BucketEventSource.js +13 -2
- package/lib/AWS/Lambda/BucketEventSource.js.map +1 -1
- package/lib/AWS/S3/Bucket.d.ts.map +1 -1
- package/lib/AWS/S3/Bucket.js +49 -0
- package/lib/AWS/S3/Bucket.js.map +1 -1
- package/lib/AWS/S3/BucketNotifications.d.ts +10 -0
- package/lib/AWS/S3/BucketNotifications.d.ts.map +1 -1
- package/lib/AWS/S3/BucketNotifications.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/Cli/commands/cloudflare.d.ts +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/AiGateway/AiGatewayBinding.d.ts +1 -1
- package/lib/Cloudflare/AiGateway/AiGatewayBinding.d.ts.map +1 -1
- package/lib/Cloudflare/AiGateway/AiGatewayBinding.js +6 -2
- package/lib/Cloudflare/AiGateway/AiGatewayBinding.js.map +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 +6 -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/Ruleset/Ruleset.d.ts +82 -0
- package/lib/Cloudflare/Ruleset/Ruleset.d.ts.map +1 -0
- package/lib/Cloudflare/Ruleset/Ruleset.js +126 -0
- package/lib/Cloudflare/Ruleset/Ruleset.js.map +1 -0
- package/lib/Cloudflare/Ruleset/index.d.ts +2 -0
- package/lib/Cloudflare/Ruleset/index.d.ts.map +1 -0
- package/lib/Cloudflare/Ruleset/index.js +2 -0
- package/lib/Cloudflare/Ruleset/index.js.map +1 -0
- package/lib/Cloudflare/SecretsStore/Secret.d.ts +1 -0
- package/lib/Cloudflare/SecretsStore/Secret.d.ts.map +1 -1
- package/lib/Cloudflare/SecretsStore/Secret.js +2 -0
- package/lib/Cloudflare/SecretsStore/Secret.js.map +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts +1 -1
- package/lib/Cloudflare/StateStore/State.d.ts.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/DurableObjectChatPersistence.d.ts +69 -0
- package/lib/Cloudflare/Workers/DurableObjectChatPersistence.d.ts.map +1 -0
- package/lib/Cloudflare/Workers/DurableObjectChatPersistence.js +104 -0
- package/lib/Cloudflare/Workers/DurableObjectChatPersistence.js.map +1 -0
- 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 +20 -19
- 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 +16 -0
- package/lib/Cloudflare/Workers/WorkerAsyncBindings.js.map +1 -1
- package/lib/Cloudflare/Workers/WorkerBinding.d.ts +3 -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 +3 -0
- package/lib/Cloudflare/Workers/index.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/index.js +3 -0
- package/lib/Cloudflare/Workers/index.js.map +1 -1
- package/lib/Cloudflare/Zaraz/ZarazConfig.d.ts.map +1 -1
- 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/Deploy.d.ts +3 -2
- package/lib/Deploy.d.ts.map +1 -1
- package/lib/Deploy.js.map +1 -1
- package/lib/Destroy.d.ts +3 -2
- package/lib/Destroy.d.ts.map +1 -1
- package/lib/Destroy.js.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 +20 -9
- 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/Output.d.ts.map +1 -1
- package/lib/Output.js +11 -10
- package/lib/Output.js.map +1 -1
- package/lib/Plan.d.ts.map +1 -1
- package/lib/Plan.js +5 -1
- package/lib/Plan.js.map +1 -1
- package/lib/Planetscale/MySQL/MySQLDatabase.d.ts +0 -2
- package/lib/Planetscale/MySQL/MySQLDatabase.d.ts.map +1 -1
- package/lib/Planetscale/MySQL/MySQLDatabase.js +1 -3
- package/lib/Planetscale/MySQL/MySQLDatabase.js.map +1 -1
- package/lib/Planetscale/Postgres/PostgresDatabase.d.ts +0 -2
- package/lib/Planetscale/Postgres/PostgresDatabase.d.ts.map +1 -1
- package/lib/Planetscale/Postgres/PostgresDatabase.js +1 -3
- package/lib/Planetscale/Postgres/PostgresDatabase.js.map +1 -1
- package/lib/Platform.d.ts +4 -4
- 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 +7 -1
- package/lib/Resource.d.ts.map +1 -1
- package/lib/Resource.js +11 -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/Stack.d.ts +5 -4
- package/lib/Stack.d.ts.map +1 -1
- package/lib/Stack.js.map +1 -1
- package/lib/Test/Core.d.ts +2 -2
- package/lib/Test/Core.d.ts.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/AWS/Lambda/BucketEventSource.ts +16 -1
- package/src/AWS/S3/Bucket.ts +78 -0
- package/src/AWS/S3/BucketNotifications.ts +10 -0
- 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/AiGateway/AiGatewayBinding.ts +8 -3
- 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 +8 -0
- package/src/Cloudflare/RateLimit/RateLimit.ts +4 -3
- package/src/Cloudflare/Ruleset/Ruleset.ts +223 -0
- package/src/Cloudflare/Ruleset/index.ts +1 -0
- package/src/Cloudflare/SecretsStore/Secret.ts +4 -0
- 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/DurableObjectChatPersistence.ts +131 -0
- 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 +66 -82
- package/src/Cloudflare/Workers/WorkerAsyncBindings.ts +14 -0
- package/src/Cloudflare/Workers/WorkerBinding.ts +4 -0
- package/src/Cloudflare/Workers/Workflow.ts +12 -1
- package/src/Cloudflare/Workers/WorkflowBridge.ts +47 -6
- package/src/Cloudflare/Workers/index.ts +3 -0
- package/src/Cloudflare/index.ts +1 -0
- package/src/Deploy.ts +2 -1
- package/src/Destroy.ts +2 -1
- package/src/Diff.ts +7 -0
- package/src/Drizzle/Postgres.ts +13 -12
- package/src/Drizzle/Schema.ts +27 -9
- package/src/Local/RpcSerialization.ts +5 -2
- package/src/Output.ts +12 -10
- package/src/Plan.ts +5 -1
- package/src/Planetscale/MySQL/MySQLDatabase.ts +1 -6
- package/src/Planetscale/Postgres/PostgresDatabase.ts +1 -5
- package/src/Platform.ts +48 -36
- package/src/Resource.ts +22 -13
- package/src/Runtime.ts +3 -7
- package/src/Stack.ts +11 -10
- package/src/Util/effect.ts +13 -17
- package/src/Util/poll.ts +3 -3
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type * as cf from "@cloudflare/workers-types";
|
|
2
2
|
import * as workers from "@distilled.cloud/cloudflare/workers";
|
|
3
3
|
import * as zones from "@distilled.cloud/cloudflare/zones";
|
|
4
|
+
import type { ConfigError } from "effect/Config";
|
|
4
5
|
import * as Config from "effect/Config";
|
|
5
6
|
import * as Context from "effect/Context";
|
|
6
7
|
import * as Data from "effect/Data";
|
|
7
8
|
import * as Effect from "effect/Effect";
|
|
8
9
|
import * as Layer from "effect/Layer";
|
|
9
10
|
import * as Path from "effect/Path";
|
|
11
|
+
import * as Predicate from "effect/Predicate";
|
|
10
12
|
import * as Redacted from "effect/Redacted";
|
|
11
13
|
import * as Schedule from "effect/Schedule";
|
|
12
14
|
import * as crypto from "node:crypto";
|
|
@@ -30,7 +32,6 @@ import {
|
|
|
30
32
|
readAssets,
|
|
31
33
|
uploadAssets,
|
|
32
34
|
type Assets,
|
|
33
|
-
type AssetsConfig,
|
|
34
35
|
type AssetsProps,
|
|
35
36
|
} from "./Assets.ts";
|
|
36
37
|
import { getCompatibility } from "./Compatibility.ts";
|
|
@@ -98,20 +99,12 @@ export const isWorkerEvent = (value: any): value is WorkerEvent =>
|
|
|
98
99
|
* When hash is provided, it's used directly for diffing instead of computing from directory contents.
|
|
99
100
|
* This is useful when integrating with Build resources that produce a deterministic hash.
|
|
100
101
|
*/
|
|
101
|
-
export interface AssetsWithHash {
|
|
102
|
-
/**
|
|
103
|
-
* Path to the assets directory.
|
|
104
|
-
*/
|
|
105
|
-
path: string;
|
|
102
|
+
export interface AssetsWithHash extends AssetsProps {
|
|
106
103
|
/**
|
|
107
104
|
* Pre-computed hash of the assets. When provided, this hash is used for diffing
|
|
108
105
|
* to determine if the worker needs to be redeployed.
|
|
109
106
|
*/
|
|
110
107
|
hash: string;
|
|
111
|
-
/**
|
|
112
|
-
* Optional assets configuration.
|
|
113
|
-
*/
|
|
114
|
-
config?: AssetsConfig;
|
|
115
108
|
}
|
|
116
109
|
|
|
117
110
|
export interface WorkerObservability extends Exclude<
|
|
@@ -165,7 +158,7 @@ export type WorkerBindingProps = {
|
|
|
165
158
|
| Effect.Effect<WorkerBindingResource, any, any>;
|
|
166
159
|
};
|
|
167
160
|
|
|
168
|
-
type NormalizedBindings<
|
|
161
|
+
export type NormalizedBindings<
|
|
169
162
|
Bindings extends WorkerBindingProps = {},
|
|
170
163
|
AssetsConfig extends WorkerAssetsConfig | undefined = undefined,
|
|
171
164
|
> = {
|
|
@@ -286,26 +279,33 @@ export interface WorkerProps<
|
|
|
286
279
|
/**
|
|
287
280
|
* Options for the local dev server that runs this Worker under `alchemy dev`.
|
|
288
281
|
* Each Worker is served on its own port.
|
|
282
|
+
*
|
|
283
|
+
* Set to `false` to skip starting a local Worker entirely — useful when an
|
|
284
|
+
* external dev server (e.g. one spawned via `Build.DevCommand`) is
|
|
285
|
+
* serving the content this Worker would otherwise host.
|
|
289
286
|
*/
|
|
290
|
-
dev?:
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
287
|
+
dev?:
|
|
288
|
+
| false
|
|
289
|
+
| string
|
|
290
|
+
| {
|
|
291
|
+
/**
|
|
292
|
+
* Host the local dev server binds to.
|
|
293
|
+
* @default "localhost"
|
|
294
|
+
*/
|
|
295
|
+
host?: string;
|
|
296
|
+
/**
|
|
297
|
+
* Port the local dev server listens on. If the port is unavailable,
|
|
298
|
+
* the next free port is used unless {@link strictPort} is `true`.
|
|
299
|
+
* @default 1337
|
|
300
|
+
*/
|
|
301
|
+
port?: number;
|
|
302
|
+
/**
|
|
303
|
+
* When `true`, fail instead of falling back to another port if
|
|
304
|
+
* {@link port} is already in use.
|
|
305
|
+
* @default false
|
|
306
|
+
*/
|
|
307
|
+
strictPort?: boolean;
|
|
308
|
+
};
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
export type Worker<Bindings extends WorkerBindings = any> = Resource<
|
|
@@ -708,7 +708,11 @@ export const Worker: Platform<
|
|
|
708
708
|
id: string,
|
|
709
709
|
props:
|
|
710
710
|
| InputProps<WorkerProps<Bindings, Assets>>
|
|
711
|
-
| Effect.Effect<
|
|
711
|
+
| Effect.Effect<
|
|
712
|
+
InputProps<WorkerProps<Bindings, Assets>>,
|
|
713
|
+
ConfigError,
|
|
714
|
+
Req
|
|
715
|
+
>,
|
|
712
716
|
): Effect.Effect<
|
|
713
717
|
Worker<{
|
|
714
718
|
[binding in keyof NormalizedBindings<
|
|
@@ -1124,15 +1128,9 @@ export const LiveWorkerProvider = () =>
|
|
|
1124
1128
|
return undefined;
|
|
1125
1129
|
}
|
|
1126
1130
|
|
|
1127
|
-
if (
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
"hash" in assets
|
|
1131
|
-
) {
|
|
1132
|
-
return yield* readAssets({
|
|
1133
|
-
directory: assets.path as string,
|
|
1134
|
-
config: assets.config,
|
|
1135
|
-
});
|
|
1131
|
+
if (typeof assets === "object" && "hash" in assets) {
|
|
1132
|
+
const { hash: _, ...config } = assets;
|
|
1133
|
+
return yield* readAssets(config);
|
|
1136
1134
|
}
|
|
1137
1135
|
|
|
1138
1136
|
// Handle string path or AssetsProps
|
|
@@ -1181,7 +1179,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1181
1179
|
typeof Redacted.value(value) === "string"
|
|
1182
1180
|
? Redacted.value(value)
|
|
1183
1181
|
: Config.isConfig(value) || Effect.isEffect(value)
|
|
1184
|
-
? yield* value
|
|
1182
|
+
? yield* value as Effect.Effect<any>
|
|
1185
1183
|
: undefined,
|
|
1186
1184
|
];
|
|
1187
1185
|
}),
|
|
@@ -1203,11 +1201,10 @@ export const LiveWorkerProvider = () =>
|
|
|
1203
1201
|
[
|
|
1204
1202
|
assetsDirectory
|
|
1205
1203
|
? readAssets({
|
|
1204
|
+
...(props.assets && typeof props.assets !== "string"
|
|
1205
|
+
? props.assets
|
|
1206
|
+
: undefined),
|
|
1206
1207
|
directory: assetsDirectory,
|
|
1207
|
-
config:
|
|
1208
|
-
typeof props.assets === "object" && "config" in props.assets
|
|
1209
|
-
? props.assets.config
|
|
1210
|
-
: undefined,
|
|
1211
1208
|
})
|
|
1212
1209
|
: Effect.succeed(undefined),
|
|
1213
1210
|
serverBundle
|
|
@@ -1293,6 +1290,15 @@ export const LiveWorkerProvider = () =>
|
|
|
1293
1290
|
})),
|
|
1294
1291
|
);
|
|
1295
1292
|
|
|
1293
|
+
const normalizePrebuiltAssets = (
|
|
1294
|
+
assets: WorkerProps["assets"],
|
|
1295
|
+
output: Worker["Attributes"] | undefined,
|
|
1296
|
+
) => {
|
|
1297
|
+
if (!Predicate.hasProperty(assets, "hash")) return undefined;
|
|
1298
|
+
const { directory: _, hash, ...config } = assets;
|
|
1299
|
+
return { config, hash, skip: hash === output?.hash?.assets };
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1296
1302
|
const putWorker = Effect.fnUntraced(function* (
|
|
1297
1303
|
id: string,
|
|
1298
1304
|
news: WorkerProps,
|
|
@@ -1311,28 +1317,14 @@ export const LiveWorkerProvider = () =>
|
|
|
1311
1317
|
// entirely and tell Cloudflare to keep the assets it already
|
|
1312
1318
|
// has bound to this script. The disk read is the expensive
|
|
1313
1319
|
// part; the script PUT happens either way.
|
|
1314
|
-
const
|
|
1315
|
-
const precomputedAssetsHash =
|
|
1316
|
-
news.assets &&
|
|
1317
|
-
typeof news.assets === "object" &&
|
|
1318
|
-
"path" in news.assets &&
|
|
1319
|
-
"hash" in news.assets
|
|
1320
|
-
? (news.assets.hash as string)
|
|
1321
|
-
: undefined;
|
|
1322
|
-
const assetsConfigFromProps =
|
|
1323
|
-
news.assets &&
|
|
1324
|
-
typeof news.assets === "object" &&
|
|
1325
|
-
"config" in news.assets
|
|
1326
|
-
? news.assets.config
|
|
1327
|
-
: undefined;
|
|
1328
|
-
const skipAssetsRead =
|
|
1329
|
-
precomputedAssetsHash !== undefined &&
|
|
1330
|
-
precomputedAssetsHash === previousAssetsHash;
|
|
1320
|
+
const prebuiltAssets = normalizePrebuiltAssets(news.assets, output);
|
|
1331
1321
|
const {
|
|
1332
1322
|
assets,
|
|
1333
1323
|
bundle,
|
|
1334
1324
|
hash: preparedHash,
|
|
1335
|
-
} = yield* prepareAssetsAndBundle(id, news, {
|
|
1325
|
+
} = yield* prepareAssetsAndBundle(id, news, {
|
|
1326
|
+
skipAssetsRead: prebuiltAssets?.skip,
|
|
1327
|
+
});
|
|
1336
1328
|
// When the caller supplied a precomputed hash (e.g. via
|
|
1337
1329
|
// `Build.Command`), store *that* hash in output state so the
|
|
1338
1330
|
// next diff can short-circuit by comparing it directly. The
|
|
@@ -1341,7 +1333,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1341
1333
|
// build-input hash and will never match it on the next pass.
|
|
1342
1334
|
const hash = {
|
|
1343
1335
|
...preparedHash,
|
|
1344
|
-
assets:
|
|
1336
|
+
assets: prebuiltAssets?.hash ?? preparedHash.assets,
|
|
1345
1337
|
} satisfies Worker["Attributes"]["hash"];
|
|
1346
1338
|
const metadataBindings = bindings.flatMap((b) => b.data.bindings ?? []);
|
|
1347
1339
|
const expectedDurableObjectClassNames =
|
|
@@ -1350,16 +1342,14 @@ export const LiveWorkerProvider = () =>
|
|
|
1350
1342
|
| workers.PutScriptRequest["metadata"]["assets"]
|
|
1351
1343
|
| undefined;
|
|
1352
1344
|
let keepAssets = false;
|
|
1353
|
-
if (
|
|
1345
|
+
if (prebuiltAssets?.skip) {
|
|
1354
1346
|
// Hash matched what's already on Cloudflare: keep the
|
|
1355
1347
|
// existing asset manifest and skip the upload session.
|
|
1356
1348
|
yield* Effect.logInfo(
|
|
1357
1349
|
`Cloudflare Worker update: assets unchanged for ${name}, keeping existing`,
|
|
1358
1350
|
);
|
|
1359
1351
|
keepAssets = true;
|
|
1360
|
-
metadataAssets =
|
|
1361
|
-
? { config: assetsConfigFromProps }
|
|
1362
|
-
: undefined;
|
|
1352
|
+
metadataAssets = { config: prebuiltAssets.config };
|
|
1363
1353
|
metadataBindings.push({
|
|
1364
1354
|
type: "assets",
|
|
1365
1355
|
name: "ASSETS",
|
|
@@ -1372,7 +1362,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1372
1362
|
// disk). In that case still keep the existing manifest and
|
|
1373
1363
|
// skip the upload session — Cloudflare's content-addressed
|
|
1374
1364
|
// session would no-op on every byte anyway.
|
|
1375
|
-
if (assets.hash ===
|
|
1365
|
+
if (assets.hash === prebuiltAssets?.hash) {
|
|
1376
1366
|
yield* Effect.logInfo(
|
|
1377
1367
|
`Cloudflare Worker update: assets unchanged for ${name}, keeping existing`,
|
|
1378
1368
|
);
|
|
@@ -1759,12 +1749,9 @@ export const LiveWorkerProvider = () =>
|
|
|
1759
1749
|
if (!props.assets) {
|
|
1760
1750
|
return false;
|
|
1761
1751
|
}
|
|
1762
|
-
const assetsHash =
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
"hash" in props.assets
|
|
1766
|
-
? (props.assets.hash as string)
|
|
1767
|
-
: undefined;
|
|
1752
|
+
const assetsHash = Predicate.hasProperty(props.assets, "hash")
|
|
1753
|
+
? props.assets.hash
|
|
1754
|
+
: undefined;
|
|
1768
1755
|
if (assetsHash === undefined) {
|
|
1769
1756
|
return true;
|
|
1770
1757
|
}
|
|
@@ -1802,12 +1789,9 @@ export const LiveWorkerProvider = () =>
|
|
|
1802
1789
|
// assume the assets changed; `putWorker` will read once,
|
|
1803
1790
|
// hash, and use `keepAssets` if it turns out nothing actually
|
|
1804
1791
|
// changed.
|
|
1805
|
-
const assetsHash =
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
"hash" in props.assets
|
|
1809
|
-
? (props.assets.hash as string)
|
|
1810
|
-
: undefined;
|
|
1792
|
+
const assetsHash = Predicate.hasProperty(props.assets, "hash")
|
|
1793
|
+
? props.assets.hash
|
|
1794
|
+
: undefined;
|
|
1811
1795
|
if (assetsHash === undefined) {
|
|
1812
1796
|
return true;
|
|
1813
1797
|
}
|
|
@@ -1976,7 +1960,7 @@ export const LiveWorkerProvider = () =>
|
|
|
1976
1960
|
// @distilled.cloud/cloudflare versions that haven't picked
|
|
1977
1961
|
// up the patch yet.
|
|
1978
1962
|
Effect.retry({
|
|
1979
|
-
while: (e
|
|
1963
|
+
while: (e) =>
|
|
1980
1964
|
e._tag === "InternalServerError" ||
|
|
1981
1965
|
e._tag === "UnknownCloudflareError",
|
|
1982
1966
|
schedule: Schedule.exponential(1000).pipe(
|
|
@@ -20,10 +20,12 @@ import { isKVNamespace } from "../KV/KVNamespace.ts";
|
|
|
20
20
|
import { isQueue } from "../Queue/Queue.ts";
|
|
21
21
|
import { isR2Bucket } from "../R2/R2Bucket.ts";
|
|
22
22
|
import { isRateLimit } from "../RateLimit/RateLimit.ts";
|
|
23
|
+
import { isSecret } from "../SecretsStore/Secret.ts";
|
|
23
24
|
import { isVectorizeIndex } from "../Vectorize/VectorizeIndex.ts";
|
|
24
25
|
import { isAssets } from "./Assets.ts";
|
|
25
26
|
import { isDurableObjectNamespaceLike } from "./DurableObjectNamespace.ts";
|
|
26
27
|
import { isDynamicWorkerLoader } from "./DynamicWorkerLoader.ts";
|
|
28
|
+
import { isVersionMetadata } from "./VersionMetadata.ts";
|
|
27
29
|
import type { WorkerBindingProps } from "./Worker.ts";
|
|
28
30
|
import { isWorker, type Worker, type WorkerProps } from "./Worker.ts";
|
|
29
31
|
import type { WorkerBinding, WorkerBindingResource } from "./WorkerBinding.ts";
|
|
@@ -210,6 +212,18 @@ const toBinding = (
|
|
|
210
212
|
name: bindingName,
|
|
211
213
|
indexName: binding.indexName,
|
|
212
214
|
};
|
|
215
|
+
} else if (isSecret(binding)) {
|
|
216
|
+
return {
|
|
217
|
+
type: "secrets_store_secret",
|
|
218
|
+
name: bindingName,
|
|
219
|
+
secretName: binding.secretName,
|
|
220
|
+
storeId: binding.storeId,
|
|
221
|
+
};
|
|
222
|
+
} else if (isVersionMetadata(binding)) {
|
|
223
|
+
return {
|
|
224
|
+
type: "version_metadata",
|
|
225
|
+
name: bindingName,
|
|
226
|
+
};
|
|
213
227
|
} else if (isDynamicWorkerLoader(binding)) {
|
|
214
228
|
return {
|
|
215
229
|
type: "worker_loader",
|
|
@@ -18,10 +18,12 @@ import type { KVNamespace } from "../KV/KVNamespace.ts";
|
|
|
18
18
|
import type { Queue } from "../Queue/Queue.ts";
|
|
19
19
|
import type { R2Bucket } from "../R2/R2Bucket.ts";
|
|
20
20
|
import type { RateLimit } from "../RateLimit/RateLimit.ts";
|
|
21
|
+
import type { Secret } from "../SecretsStore/Secret.ts";
|
|
21
22
|
import type { VectorizeIndex } from "../Vectorize/VectorizeIndex.ts";
|
|
22
23
|
import type { Assets } from "./Assets.ts";
|
|
23
24
|
import type { DurableObjectNamespaceLike } from "./DurableObjectNamespace.ts";
|
|
24
25
|
import type { DynamicWorkerLoader } from "./DynamicWorkerLoader.ts";
|
|
26
|
+
import type { VersionMetadata } from "./VersionMetadata.ts";
|
|
25
27
|
import { makeRpcStub } from "./Rpc.ts";
|
|
26
28
|
import { isWorker, Worker, WorkerEnvironment } from "./Worker.ts";
|
|
27
29
|
|
|
@@ -55,8 +57,10 @@ export type WorkerBindingResource =
|
|
|
55
57
|
| Images
|
|
56
58
|
| Hyperdrive
|
|
57
59
|
| VectorizeIndex
|
|
60
|
+
| Secret
|
|
58
61
|
| Worker
|
|
59
62
|
| DynamicWorkerLoader
|
|
63
|
+
| VersionMetadata
|
|
60
64
|
| DurableObjectNamespaceLike<any>;
|
|
61
65
|
|
|
62
66
|
export type WorkerBindings = {
|
|
@@ -3,6 +3,7 @@ import type { ConfigError } from "effect/Config";
|
|
|
3
3
|
import * as Context from "effect/Context";
|
|
4
4
|
import * as Effect from "effect/Effect";
|
|
5
5
|
import { AlchemyContext } from "../../AlchemyContext.ts";
|
|
6
|
+
import { ExecutionContext } from "../../ExecutionContext.ts";
|
|
6
7
|
import { ALCHEMY_PHASE } from "../../Phase.ts";
|
|
7
8
|
import type { PlatformServices } from "../../Platform.ts";
|
|
8
9
|
import * as Provider from "../../Provider.ts";
|
|
@@ -100,8 +101,18 @@ export const sleepUntil = (
|
|
|
100
101
|
* from inside workflow steps via `yield* WorkerEnvironment` — the type must
|
|
101
102
|
* reflect that or `yield* WorkerEnvironment` fails to type-check inside a
|
|
102
103
|
* body even though it succeeds at runtime.
|
|
104
|
+
*
|
|
105
|
+
* `ExecutionContext` (scope + cache) is provided per run-invocation by
|
|
106
|
+
* `WorkflowBridge.run` and threaded into every `task` via the surrounding
|
|
107
|
+
* body context, so `@binding` helpers that need it (e.g. `Drizzle.postgres`)
|
|
108
|
+
* resolve their per-run resources inside workflow steps just as they do in a
|
|
109
|
+
* Worker `fetch`/`queue` handler.
|
|
103
110
|
*/
|
|
104
|
-
export type WorkflowRunServices =
|
|
111
|
+
export type WorkflowRunServices =
|
|
112
|
+
| WorkflowEvent
|
|
113
|
+
| WorkflowStep
|
|
114
|
+
| WorkerServices
|
|
115
|
+
| ExecutionContext;
|
|
105
116
|
|
|
106
117
|
export type WorkflowServices = WorkflowRunServices | PlatformServices;
|
|
107
118
|
|
|
@@ -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
|
|
|
@@ -2,6 +2,7 @@ export * from "./Assets.ts";
|
|
|
2
2
|
export * from "./ConfigProvider.ts";
|
|
3
3
|
export * from "./CronEventSource.ts";
|
|
4
4
|
export * from "./DurableObjectBridge.ts";
|
|
5
|
+
export * from "./DurableObjectChatPersistence.ts";
|
|
5
6
|
export * from "./DurableObjectNamespace.ts";
|
|
6
7
|
export * from "./DurableObjectState.ts";
|
|
7
8
|
export * from "./DurableObjectStorage.ts";
|
|
@@ -15,6 +16,8 @@ export * from "./Rpc.ts";
|
|
|
15
16
|
export * from "./RpcDurableObjectNamespace.ts";
|
|
16
17
|
export * from "./RpcWorker.ts";
|
|
17
18
|
export * from "./ScheduledEvents.ts";
|
|
19
|
+
export * from "./VersionMetadata.ts";
|
|
20
|
+
export * from "./VersionMetadataBinding.ts";
|
|
18
21
|
export * from "./WebSocket.ts";
|
|
19
22
|
export * from "./Worker.ts";
|
|
20
23
|
export * from "./WorkerBinding.ts";
|
package/src/Cloudflare/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from "./Providers.ts";
|
|
|
17
17
|
export * from "./Queue/index.ts";
|
|
18
18
|
export * from "./R2/index.ts";
|
|
19
19
|
export * from "./RateLimit/index.ts";
|
|
20
|
+
export * from "./Ruleset/index.ts";
|
|
20
21
|
export * from "./SecretsStore/index.ts";
|
|
21
22
|
export * from "./StateStore/index.ts";
|
|
22
23
|
export * from "./Tunnel/index.ts";
|
package/src/Deploy.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConfigError } from "effect/Config";
|
|
1
2
|
import * as Effect from "effect/Effect";
|
|
2
3
|
import type * as Scope from "effect/Scope";
|
|
3
4
|
import { AlchemyContext } from "./AlchemyContext.ts";
|
|
@@ -14,7 +15,7 @@ export const deploy = <A>({
|
|
|
14
15
|
scope,
|
|
15
16
|
force,
|
|
16
17
|
}: {
|
|
17
|
-
stack: StackEffect<CompiledStack<A>, Stage | AlchemyContext>;
|
|
18
|
+
stack: StackEffect<CompiledStack<A>, ConfigError, Stage | AlchemyContext>;
|
|
18
19
|
stage: string;
|
|
19
20
|
dev?: boolean;
|
|
20
21
|
/** See {@link evalStack} — when set, scoped resources outlive `deploy`. */
|
package/src/Destroy.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConfigError } from "effect/Config";
|
|
1
2
|
import { Effect } from "effect";
|
|
2
3
|
import type * as Scope from "effect/Scope";
|
|
3
4
|
import type { AlchemyContext } from "./AlchemyContext.ts";
|
|
@@ -13,7 +14,7 @@ export const destroy = ({
|
|
|
13
14
|
dev,
|
|
14
15
|
scope,
|
|
15
16
|
}: {
|
|
16
|
-
stack: StackEffect<CompiledStack, Stage | AlchemyContext>;
|
|
17
|
+
stack: StackEffect<CompiledStack, ConfigError, Stage | AlchemyContext>;
|
|
17
18
|
stage: string;
|
|
18
19
|
dev?: boolean;
|
|
19
20
|
/** See {@link evalStack} — when set, scoped resources outlive `destroy`. */
|
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";
|
|
@@ -9,6 +9,10 @@ import type { Providers } from "./Providers.ts";
|
|
|
9
9
|
|
|
10
10
|
export type Dialect = "postgres" | "mysql" | "sqlite";
|
|
11
11
|
|
|
12
|
+
type DrizzleSnapshot = {
|
|
13
|
+
id?: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
12
16
|
export type SchemaProps = {
|
|
13
17
|
/**
|
|
14
18
|
* Path to the schema module, relative to the current working directory.
|
|
@@ -41,7 +45,7 @@ export type Schema = Resource<
|
|
|
41
45
|
"Drizzle.Schema",
|
|
42
46
|
SchemaProps,
|
|
43
47
|
{
|
|
44
|
-
/**
|
|
48
|
+
/** Path to the migrations directory, relative to the current working directory. */
|
|
45
49
|
out: string;
|
|
46
50
|
/**
|
|
47
51
|
* sha256 of the latest snapshot.json. Stable across deploys when the
|
|
@@ -113,6 +117,12 @@ export const SchemaProvider = () =>
|
|
|
113
117
|
const resolveOut = (p: SchemaProps) =>
|
|
114
118
|
path.resolve(process.cwd(), p.out ?? "./migrations");
|
|
115
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
|
+
|
|
116
126
|
const resolveSchema = (p: SchemaProps) =>
|
|
117
127
|
path.resolve(process.cwd(), p.schema);
|
|
118
128
|
|
|
@@ -164,7 +174,10 @@ export const SchemaProvider = () =>
|
|
|
164
174
|
const exists = yield* fs.exists(snapshotPath);
|
|
165
175
|
if (!exists) continue;
|
|
166
176
|
const text = yield* fs.readFileString(snapshotPath);
|
|
167
|
-
return {
|
|
177
|
+
return {
|
|
178
|
+
snapshot: JSON.parse(text) as DrizzleSnapshot,
|
|
179
|
+
hash: sha(text),
|
|
180
|
+
};
|
|
168
181
|
}
|
|
169
182
|
return undefined;
|
|
170
183
|
});
|
|
@@ -181,13 +194,14 @@ export const SchemaProvider = () =>
|
|
|
181
194
|
const dialect = props.dialect ?? "postgres";
|
|
182
195
|
const kit = yield* loadKit(dialect);
|
|
183
196
|
const schemaModule = yield* loadSchemaModule(props);
|
|
197
|
+
const prevEntry = yield* readLatestSnapshot(out);
|
|
184
198
|
const cur = yield* Effect.tryPromise({
|
|
185
|
-
try: () =>
|
|
199
|
+
try: () =>
|
|
200
|
+
kit.generateDrizzleJson(schemaModule, prevEntry?.snapshot.id),
|
|
186
201
|
catch: (cause) =>
|
|
187
202
|
new Error(`drizzle-kit generateDrizzleJson failed: ${cause}`),
|
|
188
203
|
});
|
|
189
204
|
|
|
190
|
-
const prevEntry = yield* readLatestSnapshot(out);
|
|
191
205
|
// For the initial migration, drizzle-kit needs an *empty* snapshot
|
|
192
206
|
// produced by `generateDrizzleJson({})`, not a bare `{}` — the
|
|
193
207
|
// snapshot has internal fields (`ddl`, etc.) that the differ reads.
|
|
@@ -233,7 +247,7 @@ export const SchemaProvider = () =>
|
|
|
233
247
|
const migrations = yield* listMigrationDirs(out);
|
|
234
248
|
const latest = yield* readLatestSnapshot(out);
|
|
235
249
|
return {
|
|
236
|
-
out,
|
|
250
|
+
out: relativeOut(out),
|
|
237
251
|
snapshotHash: latest?.hash ?? sha(JSON.stringify(cur)),
|
|
238
252
|
migrations,
|
|
239
253
|
};
|
|
@@ -248,8 +262,12 @@ export const SchemaProvider = () =>
|
|
|
248
262
|
// `schema.out` as an unresolved Output during plan and cascade
|
|
249
263
|
// into spurious updates of their own.
|
|
250
264
|
const { sqlStatements } = yield* detectDrift(news);
|
|
251
|
-
|
|
252
|
-
|
|
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;
|
|
253
271
|
}),
|
|
254
272
|
read: Effect.fn(function* ({ olds, output }) {
|
|
255
273
|
if (!output) return undefined;
|
|
@@ -259,7 +277,7 @@ export const SchemaProvider = () =>
|
|
|
259
277
|
const latest = yield* readLatestSnapshot(out);
|
|
260
278
|
const migrations = yield* listMigrationDirs(out);
|
|
261
279
|
return {
|
|
262
|
-
out,
|
|
280
|
+
out: relativeOut(out),
|
|
263
281
|
snapshotHash: latest?.hash ?? output.snapshotHash,
|
|
264
282
|
migrations,
|
|
265
283
|
};
|