alchemy 0.93.0 → 0.93.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.
Files changed (48) hide show
  1. package/bin/alchemy.js +2 -2
  2. package/lib/cloudflare/ai-search-namespace.d.ts.map +1 -1
  3. package/lib/cloudflare/ai-search-namespace.js +7 -10
  4. package/lib/cloudflare/ai-search-namespace.js.map +1 -1
  5. package/lib/cloudflare/ai-search.d.ts.map +1 -1
  6. package/lib/cloudflare/ai-search.js +7 -24
  7. package/lib/cloudflare/ai-search.js.map +1 -1
  8. package/lib/cloudflare/container.d.ts.map +1 -1
  9. package/lib/cloudflare/container.js +14 -8
  10. package/lib/cloudflare/container.js.map +1 -1
  11. package/lib/cloudflare/custom-domain.d.ts +14 -0
  12. package/lib/cloudflare/custom-domain.d.ts.map +1 -1
  13. package/lib/cloudflare/custom-domain.js +3 -0
  14. package/lib/cloudflare/custom-domain.js.map +1 -1
  15. package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
  16. package/lib/cloudflare/miniflare/build-worker-options.js +12 -6
  17. package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
  18. package/lib/cloudflare/miniflare/remote-binding-proxy.d.ts.map +1 -1
  19. package/lib/cloudflare/miniflare/remote-binding-proxy.js +31 -13
  20. package/lib/cloudflare/miniflare/remote-binding-proxy.js.map +1 -1
  21. package/lib/cloudflare/website.d.ts +4 -0
  22. package/lib/cloudflare/website.d.ts.map +1 -1
  23. package/lib/cloudflare/website.js +15 -1
  24. package/lib/cloudflare/website.js.map +1 -1
  25. package/lib/cloudflare/worker.d.ts +6 -0
  26. package/lib/cloudflare/worker.d.ts.map +1 -1
  27. package/lib/cloudflare/worker.js +3 -0
  28. package/lib/cloudflare/worker.js.map +1 -1
  29. package/lib/docker/image.d.ts +1 -1
  30. package/lib/docker/image.d.ts.map +1 -1
  31. package/lib/docker/image.js +4 -44
  32. package/lib/docker/image.js.map +1 -1
  33. package/lib/docker/registry.d.ts +11 -0
  34. package/lib/docker/registry.d.ts.map +1 -0
  35. package/lib/docker/registry.js +41 -0
  36. package/lib/docker/registry.js.map +1 -0
  37. package/package.json +2 -2
  38. package/src/cloudflare/ai-search-namespace.ts +7 -11
  39. package/src/cloudflare/ai-search.ts +7 -26
  40. package/src/cloudflare/container.ts +15 -8
  41. package/src/cloudflare/custom-domain.ts +25 -1
  42. package/src/cloudflare/miniflare/build-worker-options.ts +19 -9
  43. package/src/cloudflare/miniflare/remote-binding-proxy.ts +58 -34
  44. package/src/cloudflare/website.ts +19 -1
  45. package/src/cloudflare/worker.ts +9 -0
  46. package/src/docker/image.ts +5 -56
  47. package/src/docker/registry.ts +62 -0
  48. package/workers/tunnel-proxy.js +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/docker/image.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/docker/image.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type Secret as SecretValue } from "../secret.ts";
2
+ export interface RegistryPushCredentials {
3
+ server: string;
4
+ username: string;
5
+ password: string | SecretValue;
6
+ }
7
+ export declare function pushImageToRegistry(imageRef: string, registry: RegistryPushCredentials): Promise<{
8
+ imageRef: string;
9
+ repoDigest?: string;
10
+ }>;
11
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/docker/registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAU,KAAK,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAGlE,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,GAAG,WAAW,CAAC;CAChC;AAED,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,uBAAuB,GAChC,OAAO,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC,CA2CD"}
@@ -0,0 +1,41 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "pathe";
4
+ import { Secret } from "../secret.js";
5
+ import { DockerApi } from "./api.js";
6
+ export async function pushImageToRegistry(imageRef, registry) {
7
+ const registryHost = registry.server.replace(/\/$/, "");
8
+ const password = Secret.unwrap(registry.password);
9
+ const firstSegment = imageRef.split("/")[0];
10
+ const hasRegistryPrefix = firstSegment.includes(".");
11
+ const targetImage = hasRegistryPrefix
12
+ ? imageRef
13
+ : `${registryHost}/${imageRef}`;
14
+ let repoDigest;
15
+ let api;
16
+ try {
17
+ const tempConfigDir = await fs.mkdtemp(path.join(os.tmpdir(), "docker-config-"));
18
+ api = new DockerApi({ configDir: tempConfigDir });
19
+ await api.login(registryHost, registry.username, password);
20
+ if (targetImage !== imageRef) {
21
+ await api.exec(["tag", imageRef, targetImage]);
22
+ }
23
+ const { stdout } = await api.exec(["push", targetImage]);
24
+ const digestMatch = /digest:\s+([a-z0-9]+:[a-f0-9]{64})/.exec(stdout);
25
+ if (digestMatch) {
26
+ const digestHash = digestMatch[1];
27
+ const [repoWithoutTag] = targetImage.split(":").length > 2
28
+ ? [targetImage]
29
+ : [targetImage.substring(0, targetImage.lastIndexOf(":"))];
30
+ repoDigest = `${repoWithoutTag}@${digestHash}`;
31
+ }
32
+ return {
33
+ imageRef: targetImage,
34
+ repoDigest,
35
+ };
36
+ }
37
+ finally {
38
+ await api?.logout(registryHost);
39
+ }
40
+ }
41
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/docker/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,OAAO,CAAC;AACzB,OAAO,EAAE,MAAM,EAA8B,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAQrC,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,QAAiC;IAKjC,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAElD,MAAM,YAAY,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5C,MAAM,iBAAiB,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,WAAW,GAAG,iBAAiB;QACnC,CAAC,CAAC,QAAQ;QACV,CAAC,CAAC,GAAG,YAAY,IAAI,QAAQ,EAAE,CAAC;IAElC,IAAI,UAA8B,CAAC;IACnC,IAAI,GAA0B,CAAC;IAE/B,IAAI,CAAC;QACH,MAAM,aAAa,GAAG,MAAM,EAAE,CAAC,OAAO,CACpC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gBAAgB,CAAC,CACzC,CAAC;QACF,GAAG,GAAG,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QAElD,MAAM,GAAG,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAE3D,IAAI,WAAW,KAAK,QAAQ,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;QACzD,MAAM,WAAW,GAAG,oCAAoC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtE,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YAClC,MAAM,CAAC,cAAc,CAAC,GACpB,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;gBAC/B,CAAC,CAAC,CAAC,WAAW,CAAC;gBACf,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC/D,UAAU,GAAG,GAAG,cAAc,IAAI,UAAU,EAAE,CAAC;QACjD,CAAC;QAED,OAAO;YACL,QAAQ,EAAE,WAAW;YACrB,UAAU;SACX,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IAClC,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alchemy",
3
- "version": "0.93.0",
3
+ "version": "0.93.1",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Sam Goodwin <sam@alchemy.run>",
6
6
  "homepage": "https://alchemy.run",
@@ -195,7 +195,7 @@
195
195
  "glob": "^10.0.0",
196
196
  "jszip": "^3.0.0",
197
197
  "libsodium-wrappers": "^0.8.0",
198
- "miniflare": "4.20260310.0",
198
+ "miniflare": "4.20260329.0",
199
199
  "neverthrow": "^8.2.0",
200
200
  "open": "^10.1.2",
201
201
  "openapi-types": "^12.1.3",
@@ -194,17 +194,13 @@ export const AiSearchNamespace = Resource(
194
194
  );
195
195
  }
196
196
 
197
- if (this.scope.local) {
198
- // Local development mode return mock output
199
- return {
200
- type: "ai_search_namespace",
201
- id: namespace,
202
- namespace,
203
- description: props.description ?? null,
204
- createdAt: new Date().toISOString(),
205
- };
206
- }
207
-
197
+ // NOTE: AI Search is an always-remote binding (no Miniflare-native
198
+ // implementation). `alchemy dev` wires the worker binding via
199
+ // `remote-binding-proxy`, which requires the namespace to actually exist
200
+ // on Cloudflare at preview-token creation time — a locally mocked
201
+ // resource would cause the Worker deploy to fail with error 10359
202
+ // ("namespace … does not exist"). Follow the same pattern as Vectorize
203
+ // and skip the `scope.local` mock branch entirely.
208
204
  const api = await createCloudflareApi(props);
209
205
 
210
206
  if (this.phase === "delete") {
@@ -373,32 +373,13 @@ export const AiSearch = Resource(
373
373
  // Resolve namespace: AiSearchNamespace resource → string, default to "default"
374
374
  const namespace = resolveNamespace(props.namespace);
375
375
 
376
- if (this.scope.local) {
377
- // Local development mode return a mock shape so `alchemy dev` does
378
- // not hit the real Cloudflare API. Matches the AiSearchNamespace
379
- // local-mode pattern and satisfies AGENTS.md requirements.
380
- const name =
381
- props.name ??
382
- this.output?.name ??
383
- this.scope.createPhysicalName(id, "-", 32);
384
- const now = new Date().toISOString();
385
- // `AiSearch` is `SnakeToCamel<ApiResponse>` intersected with extras —
386
- // all non-required fields are optional, so we only populate what's
387
- // needed. No `as unknown as` escape hatch required.
388
- const mock: AiSearch = {
389
- id: name,
390
- name,
391
- namespace,
392
- accountId: "local",
393
- accountTag: "local",
394
- createdAt: now,
395
- internalId: name,
396
- modifiedAt: now,
397
- vectorizeName: "",
398
- };
399
- return mock;
400
- }
401
-
376
+ // NOTE: AI Search is an always-remote binding (no Miniflare-native
377
+ // implementation). `alchemy dev` wires the worker binding via
378
+ // `remote-binding-proxy`, which requires the instance to actually exist
379
+ // on Cloudflare at preview-token creation time a locally mocked
380
+ // resource would cause the Worker deploy to fail with error 10360
381
+ // ("instance … not found"). Follow the same pattern as Vectorize and
382
+ // skip the `scope.local` mock branch entirely.
402
383
  const api = await createCloudflareApi(props);
403
384
 
404
385
  const validateBucketSource = async (
@@ -5,10 +5,10 @@ import {
5
5
  type DockerBuildOptions,
6
6
  type ImageProps,
7
7
  } from "../docker/image.ts";
8
+ import { pushImageToRegistry } from "../docker/registry.ts";
8
9
  import type { RemoteImage } from "../docker/remote-image.ts";
9
10
  import { Resource } from "../resource.ts";
10
11
  import { Scope } from "../scope.ts";
11
- import { secret } from "../secret.ts";
12
12
  import {
13
13
  createCloudflareApi,
14
14
  type CloudflareApi,
@@ -467,7 +467,6 @@ export async function Container<T>(
467
467
  }
468
468
 
469
469
  const api = await createCloudflareApi(props);
470
- const credentials = await getContainerCredentials(api);
471
470
 
472
471
  const image = await Image(id, {
473
472
  name: `${api.accountId}/${name}`,
@@ -482,16 +481,24 @@ export async function Container<T>(
482
481
  platform: "linux/amd64",
483
482
  context: process.cwd(),
484
483
  },
485
- registry: {
486
- server: "registry.cloudflare.com",
487
- username: credentials.username || credentials.user!,
488
- password: secret(credentials.password),
489
- },
484
+ image: props.image,
485
+ skipPush: true,
490
486
  } as ImageProps);
491
487
 
488
+ const credentials = await getContainerCredentials(api);
489
+ const pushedImage = await pushImageToRegistry(image.imageRef, {
490
+ server: "registry.cloudflare.com",
491
+ username: credentials.username || credentials.user!,
492
+ password: credentials.password,
493
+ });
494
+
492
495
  return {
493
496
  ...output,
494
- image,
497
+ image: {
498
+ ...image,
499
+ imageRef: pushedImage.imageRef,
500
+ repoDigest: pushedImage.repoDigest,
501
+ },
495
502
  };
496
503
  }
497
504
 
@@ -44,6 +44,21 @@ export interface CustomDomainProps extends CloudflareApiOptions {
44
44
  */
45
45
  adopt?: boolean;
46
46
 
47
+ /**
48
+ * If true, forcibly transfer the hostname when it is currently bound to a
49
+ * different Worker service. Without this flag, Cloudflare rejects the
50
+ * upsert with HTTP 409 / error code 100116 "Hostname '<host>' already in
51
+ * use by other custom domain".
52
+ *
53
+ * This is destructive to the previously bound Worker (its traffic on this
54
+ * hostname stops immediately), so it is opt-in. Only relevant when the
55
+ * existing binding points at a different `workerName` or `environment`.
56
+ *
57
+ * @see https://developers.cloudflare.com/api/resources/workers/subresources/domains/methods/update/
58
+ * @default false
59
+ */
60
+ overrideExistingOrigin?: boolean;
61
+
47
62
  /**
48
63
  * Whether to delete the custom domain when removed from Alchemy.
49
64
  * If set to false, the custom domain will remain but the resource will be removed from state.
@@ -269,12 +284,21 @@ async function ensureCustomDomain(
269
284
  if (!bindingExists || needsUpdate) {
270
285
  operationPerformed = bindingExists ? "update" : "create";
271
286
 
272
- const putPayload = {
287
+ const putPayload: {
288
+ zone_id: string;
289
+ hostname: string;
290
+ service: string;
291
+ environment: string;
292
+ override_existing_origin?: boolean;
293
+ } = {
273
294
  zone_id: props.zoneId,
274
295
  hostname: domainHostname,
275
296
  service: props.workerName,
276
297
  environment: environment,
277
298
  };
299
+ if (props.overrideExistingOrigin !== undefined) {
300
+ putPayload.override_existing_origin = props.overrideExistingOrigin;
301
+ }
278
302
 
279
303
  const putResponse = await api.put(
280
304
  `/accounts/${api.accountId}/workers/domains`,
@@ -40,8 +40,6 @@ type RemoteBinding =
40
40
  {
41
41
  type:
42
42
  | "ai"
43
- | "ai_search"
44
- | "ai_search_namespace"
45
43
  | "browser"
46
44
  | "dispatch_namespace"
47
45
  | "mtls_certificate"
@@ -57,7 +55,13 @@ type RemoteBinding =
57
55
  | Extract<
58
56
  WorkerBindingSpec,
59
57
  { type: "send_email" | "service" | "vpc_service" }
60
- >;
58
+ >
59
+ // AI Search bindings reject the `raw` flag at the Cloudflare API
60
+ // validation layer (10333). Wrangler's upload form deliberately omits
61
+ // `raw` for these two binding types in
62
+ // packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts,
63
+ // so we mirror that here for the remote-binding-proxy upload.
64
+ | Extract<WorkerBindingSpec, { type: "ai_search" | "ai_search_namespace" }>;
61
65
 
62
66
  type BaseWorkerOptions = {
63
67
  [K in keyof miniflare.WorkerOptions]: K extends
@@ -96,24 +100,30 @@ export const buildWorkerOptions = async (
96
100
  }
97
101
  if (isAiSearch(binding)) {
98
102
  // AI Search instance bindings are not supported natively by Miniflare;
99
- // proxy them to the deployed instance (same mechanism used by `ai`,
100
- // `vectorize`, etc.). Instance bindings are always scoped to the
101
- // default namespace on the CF side, so the namespace need not be
102
- // surfaced in the remote-proxy metadata.
103
+ // proxy them to the deployed instance via the `remote-binding-proxy`
104
+ // worker (same mechanism used by `ai`, `vectorize`, etc.). Instance
105
+ // bindings are always scoped to the default namespace on the CF side,
106
+ // so the namespace need not be surfaced in the remote-proxy metadata.
107
+ //
108
+ // Note: unlike `ai`/`browser`/`vectorize`, AI Search bindings must NOT
109
+ // carry `raw: true` — CF's API rejects that field on `ai_search` and
110
+ // `ai_search_namespace` bindings (error 10333). This mirrors wrangler's
111
+ // create-worker-upload-form.ts which also omits `raw` for these two
112
+ // binding types.
103
113
  remoteBindings.push({
104
114
  type: "ai_search",
105
115
  name: key,
106
116
  instance_name: binding.name,
107
- raw: true,
108
117
  });
109
118
  continue;
110
119
  }
111
120
  if (isAiSearchNamespace(binding)) {
121
+ // See comment above on `ai_search`: `raw: true` is rejected by CF for
122
+ // this binding type, so we push without it.
112
123
  remoteBindings.push({
113
124
  type: "ai_search_namespace",
114
125
  name: key,
115
126
  namespace: binding.namespace,
116
- raw: true,
117
127
  });
118
128
  continue;
119
129
  }
@@ -39,7 +39,12 @@ export async function createRemoteProxyWorker(input: {
39
39
  bindings: WorkerBindingSpec[];
40
40
  }): Promise<RemoteBindingProxy> {
41
41
  const script = await getInternalWorkerBundle("remote-binding-proxy");
42
- const [token, { host, accessToken }] = await Promise.all([
42
+ // We must create the preview token BEFORE probing for Cloudflare Access:
43
+ // a preview worker URL only returns the Access 302 when the request carries
44
+ // the preview token (otherwise CF responds with 404 regardless of Access
45
+ // configuration). Probing without the token would incorrectly report
46
+ // "no Access" for accounts that do gate workers.dev behind Access.
47
+ const [token, subdomain] = await Promise.all([
43
48
  createWorkersPreviewToken(input.api, {
44
49
  name: input.name,
45
50
  metadata: {
@@ -54,14 +59,10 @@ export async function createRemoteProxyWorker(input: {
54
59
  minimal_mode: true,
55
60
  },
56
61
  }),
57
- getAccountSubdomain(input.api).then(async (subdomain) => {
58
- const host = `${input.name}.${subdomain}.workers.dev`;
59
- return {
60
- host,
61
- accessToken: await getAccessToken(host),
62
- };
63
- }),
62
+ getAccountSubdomain(input.api),
64
63
  ]);
64
+ const host = `${input.name}.${subdomain}.workers.dev`;
65
+ const accessToken = await getAccessToken(host, token);
65
66
 
66
67
  const baseHeaders: Record<string, string> = {
67
68
  "cf-workers-preview-token": token,
@@ -158,7 +159,13 @@ async function createWorkersPreviewToken(
158
159
 
159
160
  async function prewarm(url: string, previewToken: string) {
160
161
  try {
161
- const accessToken = await getAccessToken(new URL(url).hostname);
162
+ // Pass the preview token to the Access probe — prewarm targets a preview
163
+ // worker URL, which only surfaces an Access 302 when the request carries
164
+ // the preview token.
165
+ const accessToken = await getAccessToken(
166
+ new URL(url).hostname,
167
+ previewToken,
168
+ );
162
169
  await fetch(url, {
163
170
  method: "POST",
164
171
  headers: {
@@ -197,42 +204,59 @@ async function createWorkersPreviewSession(api: CloudflareApi) {
197
204
  /**
198
205
  * If the given domain uses Cloudflare Access, fetches the access token for the domain.
199
206
  * Otherwise, returns undefined.
207
+ *
208
+ * For workers.dev preview URLs, pass the `cf-workers-preview-token` alongside
209
+ * the HEAD probe: the preview worker only surfaces its Access 302 when the
210
+ * request carries the preview token (a bare HEAD returns 404 regardless of
211
+ * Access configuration).
212
+ *
200
213
  * @see https://github.com/cloudflare/workers-sdk/blob/a5eb5134f73d3983655d325a4de71c6370c57faa/packages/wrangler/src/user/access.ts#L10
201
214
  */
202
- const getAccessToken = memoize(async (hostname: string) => {
203
- if (!(await domainUsesAccess(hostname))) {
204
- return undefined;
205
- }
206
- const result = await Scope.current
207
- .exec(`access-${hostname}`, `cloudflared access login ${hostname}`)
208
- .catch(() => {
209
- throw new Error(
210
- [
211
- `The \`cloudflared\` CLI is not installed, but is required to access the domain "${hostname}".`,
212
- `Please install it from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation and run \`cloudflare access login ${hostname}\`.`,
213
- ].join("\n"),
214
- );
215
- });
216
- const matches = result.stdout.match(/fetched your token:\n\n(.*)/m);
217
- if (matches?.[1]) {
218
- return matches[1];
219
- }
220
- const error = new Error(
221
- `Failed to get access token for domain "${hostname}".`,
222
- );
223
- Object.assign(error, result);
224
- throw error;
225
- });
215
+ const getAccessToken = memoize(
216
+ async (hostname: string, previewToken?: string) => {
217
+ if (!(await domainUsesAccess(hostname, previewToken))) {
218
+ return undefined;
219
+ }
220
+ const result = await Scope.current
221
+ .exec(`access-${hostname}`, `cloudflared access login ${hostname}`)
222
+ .catch(() => {
223
+ throw new Error(
224
+ [
225
+ `The \`cloudflared\` CLI is not installed, but is required to access the domain "${hostname}".`,
226
+ `Please install it from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation and run \`cloudflare access login ${hostname}\`.`,
227
+ ].join("\n"),
228
+ );
229
+ });
230
+ const matches = result.stdout.match(/fetched your token:\n\n(.*)/m);
231
+ if (matches?.[1]) {
232
+ return matches[1];
233
+ }
234
+ const error = new Error(
235
+ `Failed to get access token for domain "${hostname}".`,
236
+ );
237
+ Object.assign(error, result);
238
+ throw error;
239
+ },
240
+ (hostname) => hostname,
241
+ );
226
242
 
227
243
  /**
228
244
  * Returns true if the domain uses Cloudflare Access.
245
+ *
246
+ * @param hostname the workers.dev preview host
247
+ * @param previewToken optional preview token; required when probing a
248
+ * preview-worker URL because CF only serves the Access 302 to requests
249
+ * that carry the token.
229
250
  */
230
- async function domainUsesAccess(hostname: string) {
251
+ async function domainUsesAccess(hostname: string, previewToken?: string) {
231
252
  try {
232
253
  const response = await fetch(`https://${hostname}`, {
233
254
  method: "HEAD",
234
255
  redirect: "manual",
235
256
  signal: AbortSignal.timeout(1000),
257
+ headers: previewToken
258
+ ? { "cf-workers-preview-token": previewToken }
259
+ : undefined,
236
260
  });
237
261
  return !!(
238
262
  response.status === 302 &&
@@ -10,6 +10,7 @@ import { Assets } from "./assets.ts";
10
10
  import type { Bindings } from "./bindings.ts";
11
11
  import { DEFAULT_COMPATIBILITY_DATE } from "./compatibility-date.ts";
12
12
  import { unionCompatibilityFlags } from "./compatibility-presets.ts";
13
+ import { quickTunnel } from "./quick-tunnel.ts";
13
14
  import {
14
15
  extractStringAndSecretBindings,
15
16
  unencryptSecrets,
@@ -78,6 +79,10 @@ export interface WebsiteProps<
78
79
  * The local domain to use for the dev server
79
80
  */
80
81
  domain?: string;
82
+ /**
83
+ * Whether to use a Cloudflare Tunnel for the dev server
84
+ */
85
+ tunnel?: boolean;
81
86
  /**
82
87
  * Additional environment variables to set when running the dev command
83
88
  */
@@ -363,6 +368,10 @@ export async function Website<
363
368
  ALCHEMY_ROOT: Scope.current.rootDir,
364
369
  },
365
370
  });
371
+ if (url && ((typeof dev === "object" && dev.tunnel) || scope.tunnel)) {
372
+ const { tunnelUrl } = await quickTunnel(scope, url);
373
+ url = tunnelUrl;
374
+ }
366
375
  }
367
376
 
368
377
  return (await Worker(id, {
@@ -377,7 +386,16 @@ export async function Website<
377
386
  }
378
387
  : {}),
379
388
  },
380
- dev: url ? { url } : undefined,
389
+ dev: worker.dev
390
+ ? {
391
+ url: url as never,
392
+ port: worker.dev.port,
393
+ remote: worker.dev.remote,
394
+ tunnel: worker.dev.tunnel,
395
+ }
396
+ : url
397
+ ? { url }
398
+ : undefined,
381
399
  })) as Website<B, RPC>;
382
400
  }
383
401
 
@@ -329,6 +329,12 @@ export interface BaseWorkerProps<
329
329
  * @default false
330
330
  */
331
331
  adopt?: boolean;
332
+ /**
333
+ * Forcibly transfer the hostname when it is currently bound to a
334
+ * different Worker service. See {@link CustomDomainProps.overrideExistingOrigin}.
335
+ * @default false
336
+ */
337
+ overrideExistingOrigin?: boolean;
332
338
  }
333
339
  )[];
334
340
 
@@ -1497,6 +1503,7 @@ async function provisionResources<B extends Bindings>(
1497
1503
  name: domain,
1498
1504
  zoneId: undefined,
1499
1505
  adopt: props.adopt,
1506
+ overrideExistingOrigin: undefined,
1500
1507
  };
1501
1508
  }
1502
1509
  if (domain.domainName === "") {
@@ -1506,6 +1513,7 @@ async function provisionResources<B extends Bindings>(
1506
1513
  name: domain.domainName,
1507
1514
  zoneId: domain.zoneId,
1508
1515
  adopt: domain.adopt ?? props.adopt,
1516
+ overrideExistingOrigin: domain.overrideExistingOrigin,
1509
1517
  };
1510
1518
  }),
1511
1519
  eventSources: props.eventSources?.map((eventSource) => {
@@ -1578,6 +1586,7 @@ async function provisionResources<B extends Bindings>(
1578
1586
  name: domain.name,
1579
1587
  zoneId: domain.zoneId,
1580
1588
  adopt: domain.adopt,
1589
+ overrideExistingOrigin: domain.overrideExistingOrigin,
1581
1590
  delete: props.delete,
1582
1591
  workerName: options.name,
1583
1592
  dev: options.local,
@@ -1,10 +1,10 @@
1
1
  import fs from "node:fs/promises";
2
- import os from "node:os";
3
2
  import path from "pathe";
4
3
  import type { Context } from "../context.ts";
5
4
  import { Resource } from "../resource.ts";
6
5
  import type { Secret } from "../secret.ts";
7
6
  import { DockerApi } from "./api.ts";
7
+ import { pushImageToRegistry } from "./registry.ts";
8
8
  import type { RemoteImage } from "./remote-image.ts";
9
9
 
10
10
  /**
@@ -66,9 +66,9 @@ export interface DockerBuildOptions {
66
66
  }
67
67
 
68
68
  export interface ImageRegistry {
69
+ server: string;
69
70
  username: string;
70
71
  password: Secret;
71
- server: string;
72
72
  }
73
73
 
74
74
  /**
@@ -285,63 +285,12 @@ export const Image = Resource(
285
285
  let repoDigest: string | undefined;
286
286
  let finalImageRef = imageRef;
287
287
  if (props.registry && !props.skipPush) {
288
- const { server, username, password } = props.registry;
289
-
290
- // Ensure the registry server does not have trailing slash
291
- const registryHost = server.replace(/\/$/, "");
292
-
293
- // Determine if the built image already includes a registry host (e.g. ghcr.io/user/repo)
294
- const firstSegment = imageRef.split("/")[0];
295
- const hasRegistryPrefix = firstSegment.includes(".");
296
-
297
- // Compose the target image reference that will be pushed
298
- const targetImage = hasRegistryPrefix
299
- ? imageRef // already fully-qualified
300
- : `${registryHost}/${imageRef}`;
301
-
302
- try {
303
- // Create a temporary directory that will act as an isolated Docker config
304
- // (credentials) directory. This prevents race-conditions when multiple
305
- // concurrent tests perform `docker login` / `logout` by ensuring each
306
- // Image operation has its own credential store.
307
- const tempConfigDir = await fs.mkdtemp(
308
- path.join(os.tmpdir(), "docker-config-"),
309
- );
310
- const api = new DockerApi({ configDir: tempConfigDir });
311
-
312
- // Authenticate to registry using the isolated config directory
313
- await api.login(registryHost, username, password.unencrypted);
314
-
315
- // Tag local image with fully qualified name if necessary
316
- if (targetImage !== imageRef) {
317
- await api.exec(["tag", imageRef, targetImage]);
318
- }
319
-
320
- // Push the image
321
- const { stdout: pushOut } = await api.exec(["push", targetImage]);
322
-
323
- // Attempt to extract the repo digest from push output
324
- const digestMatch = /digest:\s+([a-z0-9]+:[a-f0-9]{64})/.exec(pushOut);
325
- if (digestMatch) {
326
- const digestHash = digestMatch[1];
327
- // Strip tag (anything after last :) to build image@digest reference
328
- const [repoWithoutTag] =
329
- targetImage.split(":").length > 2
330
- ? [targetImage] // unlikely but safety
331
- : [targetImage.substring(0, targetImage.lastIndexOf(":"))];
332
- repoDigest = `${repoWithoutTag}@${digestHash}`;
333
- }
334
-
335
- // Update the final image reference to point at the pushed image
336
- finalImageRef = targetImage;
337
- } finally {
338
- // Clean up credentials from the isolated config
339
- await api.logout(registryHost);
340
- }
288
+ const pushedImage = await pushImageToRegistry(imageRef, props.registry);
289
+ finalImageRef = pushedImage.imageRef;
290
+ repoDigest = pushedImage.repoDigest;
341
291
  }
342
292
  return {
343
293
  kind: "Image",
344
- ...props,
345
294
  tag,
346
295
  name,
347
296
  imageRef: finalImageRef,