alchemy 0.47.0 → 0.48.1
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.mjs +63 -56
- package/lib/alchemy.d.ts +9 -3
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +19 -39
- package/lib/alchemy.js.map +1 -1
- package/lib/cloudflare/astro.d.ts.map +1 -1
- package/lib/cloudflare/astro.js +3 -0
- package/lib/cloudflare/astro.js.map +1 -1
- package/lib/cloudflare/compatibility-date.gen.d.ts +5 -0
- package/lib/cloudflare/compatibility-date.gen.d.ts.map +1 -0
- package/lib/cloudflare/compatibility-date.gen.js +7 -0
- package/lib/cloudflare/compatibility-date.gen.js.map +1 -0
- package/lib/cloudflare/container.js +1 -1
- package/lib/cloudflare/container.js.map +1 -1
- package/lib/cloudflare/d1-migrations.d.ts.map +1 -1
- package/lib/cloudflare/d1-migrations.js +6 -11
- package/lib/cloudflare/d1-migrations.js.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/cloudflare/miniflare/miniflare-worker-options.d.ts +2 -2
- package/lib/cloudflare/miniflare/miniflare-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-options.js +11 -2
- package/lib/cloudflare/miniflare/miniflare-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts +20 -0
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -0
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +80 -0
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -0
- package/lib/cloudflare/miniflare/miniflare.d.ts +6 -6
- package/lib/cloudflare/miniflare/miniflare.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare.js +25 -16
- package/lib/cloudflare/miniflare/miniflare.js.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts +10 -10
- package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/remote-binding-proxy.js +34 -44
- package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
- package/lib/cloudflare/nuxt.d.ts.map +1 -1
- package/lib/cloudflare/nuxt.js +3 -0
- package/lib/cloudflare/nuxt.js.map +1 -1
- package/lib/cloudflare/oauth.js +3 -3
- package/lib/cloudflare/oauth.js.map +1 -1
- package/lib/cloudflare/pipeline.d.ts.map +1 -1
- package/lib/cloudflare/pipeline.js +1 -3
- package/lib/cloudflare/pipeline.js.map +1 -1
- package/lib/cloudflare/react-router.d.ts.map +1 -1
- package/lib/cloudflare/react-router.js +3 -0
- package/lib/cloudflare/react-router.js.map +1 -1
- package/lib/cloudflare/vite.d.ts.map +1 -1
- package/lib/cloudflare/vite.js +0 -1
- package/lib/cloudflare/vite.js.map +1 -1
- package/lib/cloudflare/website.d.ts +0 -1
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +15 -8
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +8 -4
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js +82 -72
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/scope.d.ts +14 -2
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +8 -3
- package/lib/scope.js.map +1 -1
- package/lib/state/cloudflare-state-store.d.ts.map +1 -1
- package/lib/state/cloudflare-state-store.js +2 -2
- package/lib/state/cloudflare-state-store.js.map +1 -1
- package/lib/util/http.d.ts +13 -0
- package/lib/util/http.d.ts.map +1 -0
- package/lib/util/http.js +78 -0
- package/lib/util/http.js.map +1 -0
- package/lib/util/safe-fetch.d.ts.map +1 -1
- package/lib/util/safe-fetch.js +1 -0
- package/lib/util/safe-fetch.js.map +1 -1
- package/package.json +5 -4
- package/src/alchemy.ts +28 -49
- package/src/cloudflare/astro.ts +3 -0
- package/src/cloudflare/compatibility-date.gen.ts +7 -0
- package/src/cloudflare/container.ts +1 -1
- package/src/cloudflare/d1-migrations.ts +8 -21
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/miniflare/miniflare-worker-options.ts +13 -1
- package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +97 -0
- package/src/cloudflare/miniflare/miniflare.ts +30 -21
- package/src/cloudflare/miniflare/remote-binding-proxy.ts +40 -52
- package/src/cloudflare/nuxt.ts +3 -0
- package/src/cloudflare/oauth.ts +3 -3
- package/src/cloudflare/pipeline.ts +1 -3
- package/src/cloudflare/react-router.ts +3 -0
- package/src/cloudflare/vite.ts +0 -1
- package/src/cloudflare/website.ts +16 -14
- package/src/cloudflare/worker.ts +104 -106
- package/src/scope.ts +21 -4
- package/src/state/cloudflare-state-store.ts +2 -2
- package/src/util/http.ts +94 -0
- package/src/util/safe-fetch.ts +1 -0
- package/templates/react-router/package.json +1 -1
- package/templates/react-router/tsconfig.cloudflare.json +5 -1
- package/templates/react-router/tsconfig.json +0 -3
- package/templates/react-router/tsconfig.node.json +0 -4
- package/lib/build-date.d.ts +0 -6
- package/lib/build-date.d.ts.map +0 -1
- package/lib/build-date.js +0 -8
- package/lib/build-date.js.map +0 -1
- package/lib/util/http-server.d.ts +0 -14
- package/lib/util/http-server.d.ts.map +0 -1
- package/lib/util/http-server.js +0 -71
- package/lib/util/http-server.js.map +0 -1
- package/src/build-date.ts +0 -8
- package/src/util/http-server.ts +0 -84
|
@@ -2,14 +2,11 @@ import path from "node:path";
|
|
|
2
2
|
import { alchemy } from "../alchemy.ts";
|
|
3
3
|
import { Exec } from "../os/exec.ts";
|
|
4
4
|
import { Scope } from "../scope.ts";
|
|
5
|
+
import { detectPackageManager } from "../util/detect-package-manager.ts";
|
|
5
6
|
import { Assets } from "./assets.ts";
|
|
6
7
|
import type { Bindings } from "./bindings.ts";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
Worker,
|
|
10
|
-
type AssetsConfig,
|
|
11
|
-
type WorkerProps,
|
|
12
|
-
} from "./worker.ts";
|
|
8
|
+
import { DEFAULT_COMPATIBILITY_DATE } from "./compatibility-date.gen.ts";
|
|
9
|
+
import { Worker, type AssetsConfig, type WorkerProps } from "./worker.ts";
|
|
13
10
|
import { WranglerJson, type WranglerJsonSpec } from "./wrangler.json.ts";
|
|
14
11
|
|
|
15
12
|
export interface WebsiteProps<B extends Bindings>
|
|
@@ -100,7 +97,6 @@ export interface WebsiteProps<B extends Bindings>
|
|
|
100
97
|
*/
|
|
101
98
|
dev?: {
|
|
102
99
|
command: string;
|
|
103
|
-
url: string;
|
|
104
100
|
};
|
|
105
101
|
|
|
106
102
|
/**
|
|
@@ -123,6 +119,15 @@ export interface WebsiteProps<B extends Bindings>
|
|
|
123
119
|
};
|
|
124
120
|
}
|
|
125
121
|
|
|
122
|
+
const packageManager = await detectPackageManager();
|
|
123
|
+
const devCommand = {
|
|
124
|
+
npm: "npx vite dev",
|
|
125
|
+
bun: "bun vite dev",
|
|
126
|
+
pnpm: "pnpm vite dev",
|
|
127
|
+
yarn: "yarn vite dev",
|
|
128
|
+
deno: "deno task dev",
|
|
129
|
+
}[packageManager];
|
|
130
|
+
|
|
126
131
|
export type Website<B extends Bindings> = B extends { ASSETS: any }
|
|
127
132
|
? never
|
|
128
133
|
: Worker<B & { ASSETS: Assets }>;
|
|
@@ -189,12 +194,9 @@ export default {
|
|
|
189
194
|
};`,
|
|
190
195
|
url: props.url ?? true,
|
|
191
196
|
adopt: props.adopt ?? true,
|
|
192
|
-
dev:
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
url: props.dev.url,
|
|
196
|
-
}
|
|
197
|
-
: undefined,
|
|
197
|
+
dev: {
|
|
198
|
+
command: props.dev?.command ?? devCommand,
|
|
199
|
+
},
|
|
198
200
|
} as WorkerProps<any> & { name: string };
|
|
199
201
|
|
|
200
202
|
if (wrangler) {
|
|
@@ -216,7 +218,7 @@ export default {
|
|
|
216
218
|
});
|
|
217
219
|
}
|
|
218
220
|
|
|
219
|
-
const isDev = scope.
|
|
221
|
+
const isDev = scope.local;
|
|
220
222
|
|
|
221
223
|
if (props.command && !isDev) {
|
|
222
224
|
await Exec("build", {
|
package/src/cloudflare/worker.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
1
|
import type esbuild from "esbuild";
|
|
2
2
|
import kleur from "kleur";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import
|
|
5
|
-
existsSync,
|
|
6
|
-
mkdirSync,
|
|
7
|
-
readFileSync,
|
|
8
|
-
unlinkSync,
|
|
9
|
-
writeFileSync,
|
|
10
|
-
} from "node:fs";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
11
5
|
import { isDeepStrictEqual } from "node:util";
|
|
12
6
|
import path from "pathe";
|
|
13
|
-
import { BUILD_DATE } from "../build-date.ts";
|
|
14
7
|
import type { Context } from "../context.ts";
|
|
15
8
|
import type { BundleProps } from "../esbuild/bundle.ts";
|
|
16
9
|
import { InnerResourceScope, Resource, ResourceKind } from "../resource.ts";
|
|
@@ -18,7 +11,7 @@ import { getBindKey, tryGetBinding } from "../runtime/bind.ts";
|
|
|
18
11
|
import { isRuntime } from "../runtime/global.ts";
|
|
19
12
|
import { bootstrapPlugin } from "../runtime/plugin.ts";
|
|
20
13
|
import { Scope } from "../scope.ts";
|
|
21
|
-
import { Secret, secret } from "../secret.ts";
|
|
14
|
+
import { Secret, isSecret, secret } from "../secret.ts";
|
|
22
15
|
import { serializeScope } from "../serde.ts";
|
|
23
16
|
import type { type } from "../type.ts";
|
|
24
17
|
import { DeferredPromise } from "../util/deferred-promise.ts";
|
|
@@ -49,6 +42,7 @@ import {
|
|
|
49
42
|
normalizeWorkerBundle,
|
|
50
43
|
} from "./bundle/index.ts";
|
|
51
44
|
import { wrap } from "./bundle/normalize.ts";
|
|
45
|
+
import { DEFAULT_COMPATIBILITY_DATE } from "./compatibility-date.gen.ts";
|
|
52
46
|
import {
|
|
53
47
|
type CompatibilityPreset,
|
|
54
48
|
unionCompatibilityFlags,
|
|
@@ -92,6 +86,7 @@ import { Workflow, isWorkflow, upsertWorkflow } from "./workflow.ts";
|
|
|
92
86
|
// Previous versions of `Worker` used the `Bundle` resource.
|
|
93
87
|
// This import is here to avoid errors when destroying the `Bundle` resource.
|
|
94
88
|
import "../esbuild/bundle.ts";
|
|
89
|
+
import { exists } from "../util/exists.ts";
|
|
95
90
|
|
|
96
91
|
/**
|
|
97
92
|
* Configuration options for static assets
|
|
@@ -217,7 +212,7 @@ export interface BaseWorkerProps<
|
|
|
217
212
|
|
|
218
213
|
/**
|
|
219
214
|
* The compatibility date for the worker
|
|
220
|
-
* @default
|
|
215
|
+
* @default DEFAULT_WORKER_COMPATIBILITY_DATE - automatically pinned to the latest Workers release
|
|
221
216
|
*/
|
|
222
217
|
compatibilityDate?: string;
|
|
223
218
|
|
|
@@ -353,7 +348,6 @@ export interface BaseWorkerProps<
|
|
|
353
348
|
* the worker will be emulated locally and available at a randomly selected port.
|
|
354
349
|
*/
|
|
355
350
|
dev?:
|
|
356
|
-
| boolean
|
|
357
351
|
| {
|
|
358
352
|
/**
|
|
359
353
|
* Port to use for local development
|
|
@@ -365,11 +359,16 @@ export interface BaseWorkerProps<
|
|
|
365
359
|
* @default false
|
|
366
360
|
*/
|
|
367
361
|
remote?: boolean;
|
|
362
|
+
/** @internal */
|
|
363
|
+
command?: undefined;
|
|
368
364
|
}
|
|
369
365
|
| {
|
|
370
366
|
command: string;
|
|
371
|
-
url: string;
|
|
372
367
|
cwd?: string;
|
|
368
|
+
/** @internal */
|
|
369
|
+
port?: undefined;
|
|
370
|
+
/** @internal */
|
|
371
|
+
remote?: undefined;
|
|
373
372
|
};
|
|
374
373
|
|
|
375
374
|
/**
|
|
@@ -1014,8 +1013,6 @@ export function Worker<const B extends Bindings>(
|
|
|
1014
1013
|
});
|
|
1015
1014
|
}
|
|
1016
1015
|
|
|
1017
|
-
export const DEFAULT_COMPATIBILITY_DATE = BUILD_DATE;
|
|
1018
|
-
|
|
1019
1016
|
export const _Worker = Resource(
|
|
1020
1017
|
"cloudflare::Worker",
|
|
1021
1018
|
{
|
|
@@ -1047,8 +1044,6 @@ export const _Worker = Resource(
|
|
|
1047
1044
|
? props.namespace
|
|
1048
1045
|
: props.namespace?.namespaceName;
|
|
1049
1046
|
|
|
1050
|
-
const dev = normalizeDev(this, props.dev);
|
|
1051
|
-
|
|
1052
1047
|
const [bundle, error] = wrap(() =>
|
|
1053
1048
|
normalizeWorkerBundle({
|
|
1054
1049
|
entrypoint: props.entrypoint,
|
|
@@ -1067,34 +1062,46 @@ export const _Worker = Resource(
|
|
|
1067
1062
|
}),
|
|
1068
1063
|
);
|
|
1069
1064
|
|
|
1070
|
-
|
|
1065
|
+
// run locally if
|
|
1066
|
+
const local = this.scope.local && !props.dev?.remote;
|
|
1067
|
+
const watch = this.scope.watch;
|
|
1068
|
+
|
|
1069
|
+
if (local) {
|
|
1071
1070
|
let url: string | undefined;
|
|
1072
1071
|
if (error) {
|
|
1073
1072
|
throw error;
|
|
1074
1073
|
}
|
|
1075
1074
|
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1075
|
+
if (props.dev?.command) {
|
|
1076
|
+
const { url: commandUrl } = await createDevCommand({
|
|
1077
|
+
id,
|
|
1078
|
+
command: props.dev.command,
|
|
1079
|
+
cwd: props.dev.cwd || props.cwd || process.cwd(),
|
|
1080
|
+
env: {
|
|
1081
|
+
...props.env,
|
|
1082
|
+
...Object.fromEntries(
|
|
1083
|
+
Object.entries(props.bindings ?? {}).flatMap(([key, value]) =>
|
|
1084
|
+
typeof value === "string"
|
|
1085
|
+
? [[key, value]]
|
|
1086
|
+
: isSecret(value)
|
|
1087
|
+
? [[key, value.unencrypted]]
|
|
1088
|
+
: [],
|
|
1089
|
+
),
|
|
1090
|
+
),
|
|
1091
|
+
},
|
|
1092
|
+
});
|
|
1093
|
+
url = commandUrl;
|
|
1094
|
+
} else {
|
|
1095
|
+
url = await createMiniflare({
|
|
1096
|
+
id,
|
|
1097
|
+
workerName,
|
|
1098
|
+
compatibilityDate,
|
|
1099
|
+
compatibilityFlags,
|
|
1100
|
+
bindings: props.bindings,
|
|
1101
|
+
bundle,
|
|
1102
|
+
port: props.dev?.port,
|
|
1103
|
+
assets: props.assets,
|
|
1104
|
+
});
|
|
1098
1105
|
}
|
|
1099
1106
|
|
|
1100
1107
|
return this({
|
|
@@ -1218,7 +1225,7 @@ export const _Worker = Resource(
|
|
|
1218
1225
|
}
|
|
1219
1226
|
|
|
1220
1227
|
let putWorkerResult: PutWorkerResult;
|
|
1221
|
-
if (
|
|
1228
|
+
if (watch) {
|
|
1222
1229
|
// todo(john): clean this up and add log tail
|
|
1223
1230
|
const controller = new AbortController();
|
|
1224
1231
|
cleanups.push(() => controller.abort());
|
|
@@ -1436,57 +1443,6 @@ process.on("SIGINT", async () => {
|
|
|
1436
1443
|
process.exit(0);
|
|
1437
1444
|
});
|
|
1438
1445
|
|
|
1439
|
-
type Dev =
|
|
1440
|
-
| {
|
|
1441
|
-
type: "none";
|
|
1442
|
-
local: false;
|
|
1443
|
-
}
|
|
1444
|
-
| {
|
|
1445
|
-
type: "miniflare";
|
|
1446
|
-
port?: number;
|
|
1447
|
-
local: true;
|
|
1448
|
-
}
|
|
1449
|
-
| {
|
|
1450
|
-
type: "command";
|
|
1451
|
-
command: string;
|
|
1452
|
-
url: string;
|
|
1453
|
-
cwd?: string;
|
|
1454
|
-
local: true;
|
|
1455
|
-
}
|
|
1456
|
-
| {
|
|
1457
|
-
type: "remote";
|
|
1458
|
-
local: false;
|
|
1459
|
-
};
|
|
1460
|
-
|
|
1461
|
-
const normalizeDev = (ctx: Context<any>, dev: WorkerProps["dev"]): Dev => {
|
|
1462
|
-
if (!ctx.scope.dev || ctx.phase === "delete" || dev === false) {
|
|
1463
|
-
return {
|
|
1464
|
-
type: "none",
|
|
1465
|
-
local: false,
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
|
-
const devObj = dev === true ? {} : (dev ?? {});
|
|
1469
|
-
if ("command" in devObj) {
|
|
1470
|
-
// Commands are always local
|
|
1471
|
-
return {
|
|
1472
|
-
type: "command",
|
|
1473
|
-
...devObj,
|
|
1474
|
-
local: true,
|
|
1475
|
-
};
|
|
1476
|
-
}
|
|
1477
|
-
if (devObj.remote === false || ctx.scope.dev === "prefer-local") {
|
|
1478
|
-
return {
|
|
1479
|
-
type: "miniflare",
|
|
1480
|
-
port: devObj.port,
|
|
1481
|
-
local: true,
|
|
1482
|
-
};
|
|
1483
|
-
}
|
|
1484
|
-
return {
|
|
1485
|
-
type: "remote",
|
|
1486
|
-
local: false,
|
|
1487
|
-
};
|
|
1488
|
-
};
|
|
1489
|
-
|
|
1490
1446
|
const assertUnique = <T, Key extends keyof T>(
|
|
1491
1447
|
inputs: T[],
|
|
1492
1448
|
key: Key,
|
|
@@ -1714,6 +1670,7 @@ async function createMiniflare(props: {
|
|
|
1714
1670
|
bindings: Bindings | undefined;
|
|
1715
1671
|
port: number | undefined;
|
|
1716
1672
|
bundle: WorkerBundleProvider;
|
|
1673
|
+
assets: AssetsConfig | undefined;
|
|
1717
1674
|
}) {
|
|
1718
1675
|
const sharedOptions: Omit<MiniflareWorkerOptions, "bundle"> = {
|
|
1719
1676
|
name: props.workerName,
|
|
@@ -1721,6 +1678,7 @@ async function createMiniflare(props: {
|
|
|
1721
1678
|
compatibilityFlags: props.compatibilityFlags,
|
|
1722
1679
|
bindings: props.bindings,
|
|
1723
1680
|
port: props.port,
|
|
1681
|
+
assets: props.assets,
|
|
1724
1682
|
};
|
|
1725
1683
|
|
|
1726
1684
|
const startPromise = new DeferredPromise<string>();
|
|
@@ -1858,15 +1816,15 @@ async function createMiniflare(props: {
|
|
|
1858
1816
|
return await startPromise.value;
|
|
1859
1817
|
}
|
|
1860
1818
|
|
|
1861
|
-
function createDevCommand(props: {
|
|
1819
|
+
async function createDevCommand(props: {
|
|
1862
1820
|
id: string;
|
|
1863
1821
|
command: string;
|
|
1864
1822
|
cwd: string;
|
|
1865
1823
|
env: Record<string, string>;
|
|
1866
|
-
}) {
|
|
1824
|
+
}): Promise<{ url: string }> {
|
|
1867
1825
|
const persistFile = path.join(process.cwd(), ".alchemy", `${props.id}.pid`);
|
|
1868
|
-
if (
|
|
1869
|
-
const pid = Number.parseInt(
|
|
1826
|
+
if (await exists(persistFile)) {
|
|
1827
|
+
const pid = Number.parseInt(await fs.readFile(persistFile, "utf8"));
|
|
1870
1828
|
try {
|
|
1871
1829
|
// Actually kill the process if it's alive
|
|
1872
1830
|
process.kill(pid, "SIGTERM");
|
|
@@ -1874,7 +1832,7 @@ function createDevCommand(props: {
|
|
|
1874
1832
|
// ignore
|
|
1875
1833
|
}
|
|
1876
1834
|
try {
|
|
1877
|
-
|
|
1835
|
+
await fs.unlink(persistFile);
|
|
1878
1836
|
} catch {
|
|
1879
1837
|
// ignore
|
|
1880
1838
|
}
|
|
@@ -1890,21 +1848,61 @@ function createDevCommand(props: {
|
|
|
1890
1848
|
".alchemy",
|
|
1891
1849
|
"miniflare",
|
|
1892
1850
|
),
|
|
1851
|
+
// Force colors in the child process since we're piping output
|
|
1852
|
+
// FORCE_COLOR: "1",
|
|
1893
1853
|
},
|
|
1894
|
-
stdio: ["inherit", "
|
|
1854
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
1895
1855
|
});
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1856
|
+
const { url } = await new Promise<{ url: string }>((resolve, reject) => {
|
|
1857
|
+
let urlFound = false;
|
|
1858
|
+
let stdout = "";
|
|
1859
|
+
let stderr = "";
|
|
1860
|
+
const urlRegex =
|
|
1861
|
+
/http:\/\/(?:(?:localhost|0\.0\.0\.0|127\.0\.0\.1)|(?:\d{1,3}\.){3}\d{1,3}):\d+(?:\/)?/;
|
|
1862
|
+
|
|
1863
|
+
const parseOutput = (data: string) => {
|
|
1864
|
+
if (!urlFound) {
|
|
1865
|
+
const match = data.match(urlRegex);
|
|
1866
|
+
if (match) {
|
|
1867
|
+
urlFound = true;
|
|
1868
|
+
resolve({ url: match[0] });
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
};
|
|
1872
|
+
|
|
1873
|
+
// Handle stdout - parse for URL and write through with colors preserved
|
|
1874
|
+
proc.stdout?.on("data", (data) => {
|
|
1875
|
+
parseOutput(
|
|
1876
|
+
(stdout += data.toString().replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "")),
|
|
1877
|
+
);
|
|
1878
|
+
process.stdout.write(data);
|
|
1879
|
+
});
|
|
1880
|
+
|
|
1881
|
+
proc.stderr?.on("data", (data) => {
|
|
1882
|
+
parseOutput(
|
|
1883
|
+
(stderr += data.toString().replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "")),
|
|
1884
|
+
);
|
|
1885
|
+
process.stderr.write(data);
|
|
1886
|
+
});
|
|
1887
|
+
|
|
1888
|
+
proc.on("error", (error) => {
|
|
1889
|
+
reject(error);
|
|
1890
|
+
});
|
|
1891
|
+
|
|
1892
|
+
cleanups.push(async () => {
|
|
1893
|
+
try {
|
|
1894
|
+
await fs.unlink(persistFile);
|
|
1895
|
+
} catch {
|
|
1896
|
+
// ignore
|
|
1897
|
+
}
|
|
1898
|
+
proc.kill();
|
|
1899
|
+
});
|
|
1903
1900
|
});
|
|
1904
1901
|
if (proc.pid) {
|
|
1905
|
-
|
|
1906
|
-
|
|
1902
|
+
await fs.mkdir(path.dirname(persistFile), { recursive: true });
|
|
1903
|
+
await fs.writeFile(persistFile, proc.pid.toString());
|
|
1907
1904
|
}
|
|
1905
|
+
return { url };
|
|
1908
1906
|
}
|
|
1909
1907
|
|
|
1910
1908
|
type PutWorkerOptions = Omit<WorkerProps, "entrypoint"> & {
|
package/src/scope.ts
CHANGED
|
@@ -38,7 +38,18 @@ export interface ScopeOptions {
|
|
|
38
38
|
stateStore?: StateStoreType;
|
|
39
39
|
quiet?: boolean;
|
|
40
40
|
phase?: Phase;
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Determines if resources should be simulated locally (where possible)
|
|
43
|
+
*
|
|
44
|
+
* @default - `true` if ran with `alchemy dev` or `bun ./alchemy.run.ts --dev`
|
|
45
|
+
*/
|
|
46
|
+
local?: boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Determines if local changes to resources should be reactively pushed to the local or remote environment.
|
|
49
|
+
*
|
|
50
|
+
* @default - `true` if ran with `alchemy dev`, `alchemy watch`, `bun --watch ./alchemy.run.ts`
|
|
51
|
+
*/
|
|
52
|
+
watch?: boolean;
|
|
42
53
|
telemetryClient?: ITelemetryClient;
|
|
43
54
|
logger?: LoggerApi;
|
|
44
55
|
}
|
|
@@ -107,7 +118,8 @@ export class Scope {
|
|
|
107
118
|
public readonly stateStore: StateStoreType;
|
|
108
119
|
public readonly quiet: boolean;
|
|
109
120
|
public readonly phase: Phase;
|
|
110
|
-
public readonly
|
|
121
|
+
public readonly local: boolean;
|
|
122
|
+
public readonly watch: boolean;
|
|
111
123
|
public readonly logger: LoggerApi;
|
|
112
124
|
public readonly telemetryClient: ITelemetryClient;
|
|
113
125
|
public readonly dataMutex: AsyncMutex;
|
|
@@ -162,9 +174,10 @@ export class Scope {
|
|
|
162
174
|
options.logger,
|
|
163
175
|
);
|
|
164
176
|
|
|
165
|
-
this.
|
|
177
|
+
this.local = options.local ?? this.parent?.local ?? false;
|
|
178
|
+
this.watch = options.watch ?? this.parent?.watch ?? false;
|
|
166
179
|
|
|
167
|
-
if (this.
|
|
180
|
+
if (this.local) {
|
|
168
181
|
this.logger.warnOnce(
|
|
169
182
|
"Development mode is in beta. Please report any issues to https://github.com/sam-goodwin/alchemy/issues.",
|
|
170
183
|
);
|
|
@@ -415,6 +428,10 @@ export class Scope {
|
|
|
415
428
|
await this.rootTelemetryClient?.finalize()?.catch((error) => {
|
|
416
429
|
this.logger.warn("Telemetry finalization failed:", error);
|
|
417
430
|
});
|
|
431
|
+
|
|
432
|
+
if (!this.parent && process.env.ALCHEMY_TEST_KILL_ON_FINALIZE) {
|
|
433
|
+
process.exit(0);
|
|
434
|
+
}
|
|
418
435
|
}
|
|
419
436
|
|
|
420
437
|
public async destroyPendingDeletions() {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { alchemy } from "../alchemy.ts";
|
|
2
|
-
import { BUILD_DATE } from "../build-date.ts";
|
|
3
2
|
import type { CloudflareApiOptions } from "../cloudflare/api.ts";
|
|
4
3
|
import { createCloudflareApi } from "../cloudflare/api.ts";
|
|
5
4
|
import { getInternalWorkerBundle } from "../cloudflare/bundle/internal-worker-bundle.ts";
|
|
5
|
+
import { DEFAULT_COMPATIBILITY_DATE } from "../cloudflare/compatibility-date.gen.ts";
|
|
6
6
|
import { DurableObjectNamespace } from "../cloudflare/durable-object-namespace.ts";
|
|
7
7
|
import { getWorkerSettings } from "../cloudflare/worker-metadata.ts";
|
|
8
8
|
import {
|
|
@@ -109,7 +109,7 @@ const provision = memoize(async (options: CloudflareStateStoreOptions) => {
|
|
|
109
109
|
);
|
|
110
110
|
await putWorker(api, {
|
|
111
111
|
workerName: scriptName,
|
|
112
|
-
compatibilityDate:
|
|
112
|
+
compatibilityDate: DEFAULT_COMPATIBILITY_DATE,
|
|
113
113
|
format: "esm",
|
|
114
114
|
scriptBundle: {
|
|
115
115
|
entrypoint: bundle.file.name,
|
package/src/util/http.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import http from "node:http";
|
|
2
|
+
import type { AddressInfo } from "node:net";
|
|
3
|
+
import { Readable } from "node:stream";
|
|
4
|
+
|
|
5
|
+
export class HTTPServer {
|
|
6
|
+
httpServer: http.Server;
|
|
7
|
+
|
|
8
|
+
constructor(options: {
|
|
9
|
+
fetch: (request: Request) => Promise<Response>;
|
|
10
|
+
}) {
|
|
11
|
+
this.httpServer = http.createServer();
|
|
12
|
+
this.httpServer.on("request", async (req, res) => {
|
|
13
|
+
const response = await options.fetch(toWebRequest(req));
|
|
14
|
+
await writeNodeResponse(res, response);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
listen(port?: number) {
|
|
19
|
+
return new Promise<this>((resolve, reject) => {
|
|
20
|
+
this.httpServer.on("listening", () => {
|
|
21
|
+
resolve(this);
|
|
22
|
+
});
|
|
23
|
+
this.httpServer.on("error", (error) => {
|
|
24
|
+
reject(error);
|
|
25
|
+
});
|
|
26
|
+
this.httpServer.listen(port);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
get url() {
|
|
31
|
+
const address = this.httpServer.address() as AddressInfo | null;
|
|
32
|
+
if (!address) {
|
|
33
|
+
throw new Error("Server is not listening");
|
|
34
|
+
}
|
|
35
|
+
const hostname = address.address === "::" ? "localhost" : address.address;
|
|
36
|
+
return `http://${hostname}:${address.port}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
close() {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
this.httpServer.close((err) => {
|
|
42
|
+
if (err) {
|
|
43
|
+
reject(err);
|
|
44
|
+
} else {
|
|
45
|
+
resolve(undefined);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function toWebRequest(
|
|
53
|
+
req: http.IncomingMessage,
|
|
54
|
+
host?: string,
|
|
55
|
+
): Request {
|
|
56
|
+
const method = req.method ?? "GET";
|
|
57
|
+
const url = new URL(req.url ?? "/", `http://${host ?? req.headers.host}`);
|
|
58
|
+
const body =
|
|
59
|
+
["GET", "HEAD", "OPTIONS"].includes(method) || !req.readable
|
|
60
|
+
? undefined
|
|
61
|
+
: Readable.toWeb(req);
|
|
62
|
+
return new Request(url.toString(), {
|
|
63
|
+
method,
|
|
64
|
+
headers: req.headers as Record<string, string>,
|
|
65
|
+
body: body as unknown as BodyInit,
|
|
66
|
+
// @ts-expect-error - caused by @cloudflare/workers-types
|
|
67
|
+
duplex: body ? "half" : undefined,
|
|
68
|
+
redirect: "manual",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function writeNodeResponse(
|
|
73
|
+
res: http.ServerResponse,
|
|
74
|
+
response: Response,
|
|
75
|
+
) {
|
|
76
|
+
res.statusCode = response.status;
|
|
77
|
+
response.headers.forEach((value, key) => {
|
|
78
|
+
res.setHeader(key, value);
|
|
79
|
+
});
|
|
80
|
+
if (response.body) {
|
|
81
|
+
await response.body.pipeTo(
|
|
82
|
+
new WritableStream({
|
|
83
|
+
write(chunk) {
|
|
84
|
+
res.write(chunk);
|
|
85
|
+
},
|
|
86
|
+
close() {
|
|
87
|
+
res.end();
|
|
88
|
+
},
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
} else {
|
|
92
|
+
res.end();
|
|
93
|
+
}
|
|
94
|
+
}
|
package/src/util/safe-fetch.ts
CHANGED
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
"composite": true,
|
|
12
12
|
"strict": true,
|
|
13
13
|
"lib": ["DOM", "DOM.Iterable", "ES2022"],
|
|
14
|
-
"types": [
|
|
14
|
+
"types": [
|
|
15
|
+
"vite/client",
|
|
16
|
+
"@cloudflare/workers-types",
|
|
17
|
+
"./types/env.d.ts"
|
|
18
|
+
],
|
|
15
19
|
"target": "ES2022",
|
|
16
20
|
"module": "ES2022",
|
|
17
21
|
"moduleResolution": "bundler",
|
package/lib/build-date.d.ts
DELETED
package/lib/build-date.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-date.d.ts","sourceRoot":"","sources":["../src/build-date.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,eAAO,MAAM,UAAU,eAAe,CAAC"}
|
package/lib/build-date.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// This file is auto-generated during build
|
|
2
|
-
// Do not edit manually
|
|
3
|
-
/**
|
|
4
|
-
* The build date used as the default worker compatibility date.
|
|
5
|
-
* This is set to the date when the package was built.
|
|
6
|
-
*/
|
|
7
|
-
export const BUILD_DATE = "2025-07-16";
|
|
8
|
-
//# sourceMappingURL=build-date.js.map
|
package/lib/build-date.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-date.js","sourceRoot":"","sources":["../src/build-date.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,uBAAuB;AAEvB;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import http from "node:http";
|
|
2
|
-
export declare class HTTPServer {
|
|
3
|
-
server: http.Server;
|
|
4
|
-
ready: Promise<void>;
|
|
5
|
-
constructor(options: {
|
|
6
|
-
port?: number;
|
|
7
|
-
fetch: (request: Request) => Promise<Response>;
|
|
8
|
-
});
|
|
9
|
-
get port(): number;
|
|
10
|
-
get hostname(): string;
|
|
11
|
-
get url(): string;
|
|
12
|
-
stop(): Promise<unknown>;
|
|
13
|
-
}
|
|
14
|
-
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../../src/util/http-server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,qBAAa,UAAU;IACrB,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAET,OAAO,EAAE;QACnB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;KAChD;IAWD,IAAI,IAAI,WAEP;IAED,IAAI,QAAQ,WAMX;IAED,IAAI,GAAG,WAEN;IAED,IAAI;CAWL"}
|