alchemy 2.0.0-beta.21 → 2.0.0-beta.23
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/alchemy.js +3 -3
- package/bin/alchemy.js.map +1 -1
- package/bin/commands/logs.ts +1 -1
- package/bin/commands/tail.ts +1 -1
- package/lib/AWS/Lambda/Function.d.ts.map +1 -1
- package/lib/AWS/Lambda/Function.js +25 -21
- package/lib/AWS/Lambda/Function.js.map +1 -1
- package/lib/AWS/Lambda/HttpServer.d.ts.map +1 -1
- package/lib/AWS/Lambda/HttpServer.js +3 -1
- package/lib/AWS/Lambda/HttpServer.js.map +1 -1
- package/lib/Cloudflare/Container/Container.d.ts +55 -2
- package/lib/Cloudflare/Container/Container.d.ts.map +1 -1
- package/lib/Cloudflare/Container/Container.js +55 -2
- package/lib/Cloudflare/Container/Container.js.map +1 -1
- package/lib/Cloudflare/D1/D1Clone.d.ts +13 -0
- package/lib/Cloudflare/D1/D1Clone.d.ts.map +1 -0
- package/lib/Cloudflare/D1/D1Clone.js +31 -0
- package/lib/Cloudflare/D1/D1Clone.js.map +1 -0
- package/lib/Cloudflare/D1/D1Database.d.ts +150 -5
- package/lib/Cloudflare/D1/D1Database.d.ts.map +1 -1
- package/lib/Cloudflare/D1/D1Database.js +253 -0
- package/lib/Cloudflare/D1/D1Database.js.map +1 -1
- package/lib/Cloudflare/D1/D1Export.d.ts +24 -0
- package/lib/Cloudflare/D1/D1Export.d.ts.map +1 -0
- package/lib/Cloudflare/D1/D1Export.js +34 -0
- package/lib/Cloudflare/D1/D1Export.js.map +1 -0
- package/lib/Cloudflare/D1/D1Import.d.ts +21 -0
- package/lib/Cloudflare/D1/D1Import.d.ts.map +1 -0
- package/lib/Cloudflare/D1/D1Import.js +87 -0
- package/lib/Cloudflare/D1/D1Import.js.map +1 -0
- package/lib/Cloudflare/D1/D1Migrations.d.ts +16 -0
- package/lib/Cloudflare/D1/D1Migrations.d.ts.map +1 -0
- package/lib/Cloudflare/D1/D1Migrations.js +110 -0
- package/lib/Cloudflare/D1/D1Migrations.js.map +1 -0
- package/lib/Cloudflare/D1/D1SqlFile.d.ts +20 -0
- package/lib/Cloudflare/D1/D1SqlFile.d.ts.map +1 -0
- package/lib/Cloudflare/D1/D1SqlFile.js +46 -0
- package/lib/Cloudflare/D1/D1SqlFile.js.map +1 -0
- package/lib/Cloudflare/Providers.d.ts +1 -1
- package/lib/Cloudflare/Providers.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/Queue.d.ts +34 -4
- package/lib/Cloudflare/Queue/Queue.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/Queue.js +34 -4
- package/lib/Cloudflare/Queue/Queue.js.map +1 -1
- package/lib/Cloudflare/Queue/QueueBinding.d.ts +33 -0
- package/lib/Cloudflare/Queue/QueueBinding.d.ts.map +1 -1
- package/lib/Cloudflare/Queue/QueueBinding.js +33 -0
- package/lib/Cloudflare/Queue/QueueBinding.js.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectNamespace.d.ts +103 -6
- package/lib/Cloudflare/Workers/DurableObjectNamespace.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/DurableObjectNamespace.js +103 -6
- package/lib/Cloudflare/Workers/DurableObjectNamespace.js.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.d.ts +94 -0
- package/lib/Cloudflare/Workers/Workflow.d.ts.map +1 -1
- package/lib/Cloudflare/Workers/Workflow.js +94 -0
- package/lib/Cloudflare/Workers/Workflow.js.map +1 -1
- package/lib/Platform.js +1 -1
- package/lib/Platform.js.map +1 -1
- package/package.json +1 -1
- package/src/AWS/Lambda/Function.ts +30 -24
- package/src/AWS/Lambda/HttpServer.ts +3 -1
- package/src/Cloudflare/Container/Container.ts +55 -2
- package/src/Cloudflare/D1/D1Clone.ts +42 -0
- package/src/Cloudflare/D1/D1Database.ts +386 -3
- package/src/Cloudflare/D1/D1Export.ts +66 -0
- package/src/Cloudflare/D1/D1Import.ts +156 -0
- package/src/Cloudflare/D1/D1Migrations.ts +229 -0
- package/src/Cloudflare/D1/D1SqlFile.ts +55 -0
- package/src/Cloudflare/Queue/Queue.ts +34 -4
- package/src/Cloudflare/Queue/QueueBinding.ts +33 -0
- package/src/Cloudflare/Workers/DurableObjectNamespace.ts +103 -6
- package/src/Cloudflare/Workers/Workflow.ts +94 -0
- package/src/Platform.ts +1 -1
|
@@ -23,6 +23,7 @@ import { Platform, type Main, type PlatformProps } from "../../Platform.ts";
|
|
|
23
23
|
import type { LogLine, LogsInput } from "../../Provider.ts";
|
|
24
24
|
import * as Provider from "../../Provider.ts";
|
|
25
25
|
import { Resource, type ResourceBinding } from "../../Resource.ts";
|
|
26
|
+
import { Self } from "../../Self.ts";
|
|
26
27
|
import * as Serverless from "../../Serverless/index.ts";
|
|
27
28
|
import { Stack } from "../../Stack.ts";
|
|
28
29
|
import { createInternalTags, createTagsList, hasTags } from "../../Tags.ts";
|
|
@@ -617,7 +618,6 @@ export const FunctionProvider = () =>
|
|
|
617
618
|
cwd,
|
|
618
619
|
external: [
|
|
619
620
|
/^@aws-sdk\//,
|
|
620
|
-
/^@smithy\//,
|
|
621
621
|
...((props.build?.input?.external as string[]) ?? []),
|
|
622
622
|
],
|
|
623
623
|
platform: "node",
|
|
@@ -627,8 +627,9 @@ export const FunctionProvider = () =>
|
|
|
627
627
|
...props.build?.output,
|
|
628
628
|
format: "esm",
|
|
629
629
|
sourcemap: rolldownSourcemap,
|
|
630
|
-
minify: props.build?.output?.minify ??
|
|
630
|
+
minify: props.build?.output?.minify ?? false,
|
|
631
631
|
entryFileNames: "index.js",
|
|
632
|
+
codeSplitting: props.build?.output?.codeSplitting ?? false,
|
|
632
633
|
},
|
|
633
634
|
);
|
|
634
635
|
});
|
|
@@ -639,30 +640,34 @@ export const FunctionProvider = () =>
|
|
|
639
640
|
realMain,
|
|
640
641
|
virtualEntryPlugin(
|
|
641
642
|
(importPath) => `
|
|
642
|
-
import {
|
|
643
|
+
import { layer as nodeServicesLayer } from "@effect/platform-node/NodeServices";
|
|
643
644
|
import { Stack } from "alchemy/Stack";
|
|
644
645
|
import * as Config from "effect/Config";
|
|
645
646
|
import * as ConfigProvider from "effect/ConfigProvider";
|
|
646
647
|
import * as Credentials from "@distilled.cloud/aws/Credentials";
|
|
647
648
|
import * as Effect from "effect/Effect";
|
|
648
|
-
import
|
|
649
|
+
import { layer as fetchHttpClientLayer } from "effect/unstable/http/FetchHttpClient";
|
|
649
650
|
import * as Layer from "effect/Layer";
|
|
650
651
|
import * as Logger from "effect/Logger";
|
|
651
652
|
import * as Region from "@distilled.cloud/aws/Region";
|
|
652
653
|
import * as Context from "effect/Context";
|
|
653
654
|
import { MinimumLogLevel } from "effect/References";
|
|
654
655
|
|
|
655
|
-
import
|
|
656
|
+
import entry from "${importPath}";
|
|
657
|
+
|
|
658
|
+
const tag = Context.Service("${Self.key}")
|
|
659
|
+
const layer =
|
|
660
|
+
typeof entry?.build === "function"
|
|
661
|
+
? entry
|
|
662
|
+
: Layer.effect(tag, typeof entry?.asEffect === "function" ? entry.asEffect() : entry);
|
|
656
663
|
|
|
657
664
|
const platform = Layer.mergeAll(
|
|
658
|
-
|
|
659
|
-
|
|
665
|
+
nodeServicesLayer,
|
|
666
|
+
fetchHttpClientLayer,
|
|
660
667
|
// TODO(sam): wire this up to telemetry more directly
|
|
661
668
|
Logger.layer([Logger.consolePretty()]),
|
|
662
669
|
);
|
|
663
670
|
|
|
664
|
-
const tag = Context.Service("${FunctionTypeId}<${id}>")
|
|
665
|
-
|
|
666
671
|
const stack = Layer.effect(
|
|
667
672
|
Stack,
|
|
668
673
|
Effect.all([
|
|
@@ -679,7 +684,8 @@ const stack = Layer.effect(
|
|
|
679
684
|
);
|
|
680
685
|
|
|
681
686
|
const handlerEffect = tag.asEffect().pipe(
|
|
682
|
-
Effect.flatMap(func => func.ExecutionContext.exports
|
|
687
|
+
Effect.flatMap(func => func.ExecutionContext.exports),
|
|
688
|
+
Effect.flatMap(exports => exports.handler),
|
|
683
689
|
Effect.provide(
|
|
684
690
|
layer.pipe(
|
|
685
691
|
Layer.provideMerge(stack),
|
|
@@ -714,23 +720,23 @@ export default await Effect.runPromise(handlerEffect)
|
|
|
714
720
|
? new TextEncoder().encode(mainFile.content)
|
|
715
721
|
: mainFile.content;
|
|
716
722
|
|
|
717
|
-
const
|
|
718
|
-
uploadSourceMap && (sourcemap === true || sourcemap === "hidden")
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
+
const includeSourceMaps =
|
|
724
|
+
uploadSourceMap && (sourcemap === true || sourcemap === "hidden");
|
|
725
|
+
|
|
726
|
+
const extraFiles = bundleOutput.files
|
|
727
|
+
.slice(1)
|
|
728
|
+
.filter(
|
|
729
|
+
(f: Bundle.BundleFile) =>
|
|
730
|
+
includeSourceMaps || !f.path.endsWith(".map"),
|
|
731
|
+
)
|
|
732
|
+
.map((f: Bundle.BundleFile) => ({
|
|
733
|
+
path: f.path,
|
|
734
|
+
content: f.content,
|
|
735
|
+
}));
|
|
723
736
|
|
|
724
737
|
const archive = yield* zipCode(
|
|
725
738
|
code,
|
|
726
|
-
|
|
727
|
-
? [
|
|
728
|
-
{
|
|
729
|
-
path: sourceMapFile.path,
|
|
730
|
-
content: sourceMapFile.content,
|
|
731
|
-
},
|
|
732
|
-
]
|
|
733
|
-
: undefined,
|
|
739
|
+
extraFiles.length > 0 ? extraFiles : undefined,
|
|
734
740
|
);
|
|
735
741
|
return {
|
|
736
742
|
archive,
|
|
@@ -19,7 +19,9 @@ export const makeFunctionHttpHandler = <Req>(handler: Http.HttpEffect<Req>) => {
|
|
|
19
19
|
const safeHandler = Http.safeHttpEffect(handler);
|
|
20
20
|
return (event: any) => {
|
|
21
21
|
if (isFunctionURLEvent(event)) {
|
|
22
|
-
const
|
|
22
|
+
const webRequest = toWebRequest(event);
|
|
23
|
+
const request = HttpServerRequest.fromWeb(webRequest).modify({
|
|
24
|
+
url: webRequest.url,
|
|
23
25
|
remoteAddress: Option.some(event.requestContext.http.sourceIp),
|
|
24
26
|
});
|
|
25
27
|
return safeHandler.pipe(
|
|
@@ -118,8 +118,10 @@ export type Container = {
|
|
|
118
118
|
* @section Configuration
|
|
119
119
|
* The props object accepts `main` (entrypoint file), `instanceType`
|
|
120
120
|
* (compute size), `runtime` (`"bun"` or `"node"`), and
|
|
121
|
-
* `observability` settings. Use `Stack.useSync` to
|
|
122
|
-
*
|
|
121
|
+
* `observability` settings. Use `Stack.useSync` to read the
|
|
122
|
+
* surrounding stack at declaration time and pick a beefier
|
|
123
|
+
* `instanceType` in prod while keeping the cheap `dev` instance for
|
|
124
|
+
* preview environments.
|
|
123
125
|
*
|
|
124
126
|
* @example Stage-dependent configuration
|
|
125
127
|
* ```typescript
|
|
@@ -133,6 +135,57 @@ export type Container = {
|
|
|
133
135
|
* ) {}
|
|
134
136
|
* ```
|
|
135
137
|
*
|
|
138
|
+
* @section Stack-level wiring
|
|
139
|
+
* The `.make()` `export default` is the side-effect that registers
|
|
140
|
+
* the container's runtime. It must be reachable from your
|
|
141
|
+
* `alchemy.run.ts` so the bundler emits the runtime entrypoint.
|
|
142
|
+
* Provide it on the Stack's generator with `Effect.provide`.
|
|
143
|
+
*
|
|
144
|
+
* @example Wiring SandboxLive into the Stack
|
|
145
|
+
* ```typescript
|
|
146
|
+
* // alchemy.run.ts
|
|
147
|
+
* import SandboxLive from "./src/Sandbox.runtime.ts";
|
|
148
|
+
*
|
|
149
|
+
* export default Alchemy.Stack(
|
|
150
|
+
* "MyApp",
|
|
151
|
+
* { providers: Cloudflare.providers(), state: Cloudflare.state() },
|
|
152
|
+
* Effect.gen(function* () {
|
|
153
|
+
* const worker = yield* Worker;
|
|
154
|
+
* return { url: worker.url };
|
|
155
|
+
* }).pipe(Effect.provide(SandboxLive)),
|
|
156
|
+
* );
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @section Calling from a Durable Object
|
|
160
|
+
* Use `Cloudflare.Container.bind(Sandbox)` in the **outer** init
|
|
161
|
+
* phase of a Durable Object — only the class is imported, so the
|
|
162
|
+
* DO bundle stays tiny. Then `Cloudflare.start(sandbox)` in the
|
|
163
|
+
* **inner** per-instance phase ensures the container is running
|
|
164
|
+
* and gives you a typed handle that exposes every method declared
|
|
165
|
+
* on the container's shape **plus** a `getTcpPort` helper.
|
|
166
|
+
*
|
|
167
|
+
* @example Binding and starting a container from a DO
|
|
168
|
+
* ```typescript
|
|
169
|
+
* export default class Agent extends Cloudflare.DurableObjectNamespace<Agent>()(
|
|
170
|
+
* "Agents",
|
|
171
|
+
* Effect.gen(function* () {
|
|
172
|
+
* // OUTER (init): only the class is referenced — the runtime
|
|
173
|
+
* // implementation in `Sandbox.runtime.ts` is tree-shaken out
|
|
174
|
+
* // of this DO's bundle.
|
|
175
|
+
* const sandbox = yield* Cloudflare.Container.bind(Sandbox);
|
|
176
|
+
*
|
|
177
|
+
* return Effect.gen(function* () {
|
|
178
|
+
* // INNER (per-instance): start the container and expose RPC.
|
|
179
|
+
* const container = yield* Cloudflare.start(sandbox);
|
|
180
|
+
*
|
|
181
|
+
* return {
|
|
182
|
+
* exec: (cmd: string) => container.exec(cmd),
|
|
183
|
+
* };
|
|
184
|
+
* });
|
|
185
|
+
* }),
|
|
186
|
+
* ) {}
|
|
187
|
+
* ```
|
|
188
|
+
*
|
|
136
189
|
* @section Starting from a Durable Object
|
|
137
190
|
* Use `Cloudflare.Container.bind` in the outer init phase to bind
|
|
138
191
|
* the container class, then `Cloudflare.start` in the inner
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as HttpClient from "effect/unstable/http/HttpClient";
|
|
3
|
+
import * as HttpClientRequest from "effect/unstable/http/HttpClientRequest";
|
|
4
|
+
import { exportD1Database } from "./D1Export.ts";
|
|
5
|
+
import { importD1Database } from "./D1Import.ts";
|
|
6
|
+
|
|
7
|
+
export interface CloneD1DatabaseOptions {
|
|
8
|
+
accountId: string;
|
|
9
|
+
sourceDatabaseId: string;
|
|
10
|
+
targetDatabaseId: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Clone a D1 database by exporting from the source and importing into the
|
|
15
|
+
* target. Fetches the SQL dump from the export's signed URL and streams the
|
|
16
|
+
* payload through the import flow.
|
|
17
|
+
*/
|
|
18
|
+
export const cloneD1Database = (options: CloneD1DatabaseOptions) =>
|
|
19
|
+
Effect.gen(function* () {
|
|
20
|
+
const exportResult = yield* exportD1Database({
|
|
21
|
+
accountId: options.accountId,
|
|
22
|
+
databaseId: options.sourceDatabaseId,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const client = yield* HttpClient.HttpClient;
|
|
26
|
+
const dumpRes = yield* client
|
|
27
|
+
.execute(HttpClientRequest.get(exportResult.signedUrl))
|
|
28
|
+
.pipe(Effect.orDie);
|
|
29
|
+
if (dumpRes.status < 200 || dumpRes.status >= 300) {
|
|
30
|
+
return yield* Effect.die(
|
|
31
|
+
`Failed to fetch D1 export dump (${dumpRes.status})`,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
const sqlData = yield* dumpRes.text.pipe(Effect.orDie);
|
|
35
|
+
|
|
36
|
+
return yield* importD1Database({
|
|
37
|
+
accountId: options.accountId,
|
|
38
|
+
databaseId: options.targetDatabaseId,
|
|
39
|
+
sqlData,
|
|
40
|
+
filename: exportResult.filename,
|
|
41
|
+
});
|
|
42
|
+
});
|