alchemy 0.93.0 → 0.93.2

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 (52) 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/vite/plugin.d.ts.map +1 -1
  22. package/lib/cloudflare/vite/plugin.js +7 -1
  23. package/lib/cloudflare/vite/plugin.js.map +1 -1
  24. package/lib/cloudflare/website.d.ts +4 -0
  25. package/lib/cloudflare/website.d.ts.map +1 -1
  26. package/lib/cloudflare/website.js +17 -1
  27. package/lib/cloudflare/website.js.map +1 -1
  28. package/lib/cloudflare/worker.d.ts +6 -0
  29. package/lib/cloudflare/worker.d.ts.map +1 -1
  30. package/lib/cloudflare/worker.js +3 -0
  31. package/lib/cloudflare/worker.js.map +1 -1
  32. package/lib/docker/image.d.ts +1 -1
  33. package/lib/docker/image.d.ts.map +1 -1
  34. package/lib/docker/image.js +4 -44
  35. package/lib/docker/image.js.map +1 -1
  36. package/lib/docker/registry.d.ts +11 -0
  37. package/lib/docker/registry.d.ts.map +1 -0
  38. package/lib/docker/registry.js +41 -0
  39. package/lib/docker/registry.js.map +1 -0
  40. package/package.json +2 -2
  41. package/src/cloudflare/ai-search-namespace.ts +7 -11
  42. package/src/cloudflare/ai-search.ts +7 -26
  43. package/src/cloudflare/container.ts +15 -8
  44. package/src/cloudflare/custom-domain.ts +25 -1
  45. package/src/cloudflare/miniflare/build-worker-options.ts +19 -9
  46. package/src/cloudflare/miniflare/remote-binding-proxy.ts +58 -34
  47. package/src/cloudflare/vite/plugin.ts +7 -1
  48. package/src/cloudflare/website.ts +22 -1
  49. package/src/cloudflare/worker.ts +9 -0
  50. package/src/docker/image.ts +5 -56
  51. package/src/docker/registry.ts +62 -0
  52. package/workers/tunnel-proxy.js +1 -1
@@ -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,
@@ -0,0 +1,62 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "pathe";
4
+ import { Secret, type Secret as SecretValue } from "../secret.ts";
5
+ import { DockerApi } from "./api.ts";
6
+
7
+ export interface RegistryPushCredentials {
8
+ server: string;
9
+ username: string;
10
+ password: string | SecretValue;
11
+ }
12
+
13
+ export async function pushImageToRegistry(
14
+ imageRef: string,
15
+ registry: RegistryPushCredentials,
16
+ ): Promise<{
17
+ imageRef: string;
18
+ repoDigest?: string;
19
+ }> {
20
+ const registryHost = registry.server.replace(/\/$/, "");
21
+ const password = Secret.unwrap(registry.password);
22
+
23
+ const firstSegment = imageRef.split("/")[0];
24
+ const hasRegistryPrefix = firstSegment.includes(".");
25
+ const targetImage = hasRegistryPrefix
26
+ ? imageRef
27
+ : `${registryHost}/${imageRef}`;
28
+
29
+ let repoDigest: string | undefined;
30
+ let api: DockerApi | undefined;
31
+
32
+ try {
33
+ const tempConfigDir = await fs.mkdtemp(
34
+ path.join(os.tmpdir(), "docker-config-"),
35
+ );
36
+ api = new DockerApi({ configDir: tempConfigDir });
37
+
38
+ await api.login(registryHost, registry.username, password);
39
+
40
+ if (targetImage !== imageRef) {
41
+ await api.exec(["tag", imageRef, targetImage]);
42
+ }
43
+
44
+ const { stdout } = await api.exec(["push", targetImage]);
45
+ const digestMatch = /digest:\s+([a-z0-9]+:[a-f0-9]{64})/.exec(stdout);
46
+ if (digestMatch) {
47
+ const digestHash = digestMatch[1];
48
+ const [repoWithoutTag] =
49
+ targetImage.split(":").length > 2
50
+ ? [targetImage]
51
+ : [targetImage.substring(0, targetImage.lastIndexOf(":"))];
52
+ repoDigest = `${repoWithoutTag}@${digestHash}`;
53
+ }
54
+
55
+ return {
56
+ imageRef: targetImage,
57
+ repoDigest,
58
+ };
59
+ } finally {
60
+ await api?.logout(registryHost);
61
+ }
62
+ }
@@ -83,7 +83,7 @@ const renderErrorHtml = (props) => `
83
83
  Alchemy</a>.</p>
84
84
  </div>
85
85
  <div class="bg-slate-200 px-5 py-3 flex flex-col w-full max-w-lg">
86
- <p class="text-sm text-slate-500">Alchemy 0.93.0</p>
86
+ <p class="text-sm text-slate-500">Alchemy 0.93.2</p>
87
87
  </div>
88
88
  </div>
89
89
  </body>