alchemy 0.85.1 → 0.86.0
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 +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/sveltekit/plugin.d.ts.map +1 -1
- package/lib/cloudflare/sveltekit/plugin.js +11 -5
- package/lib/cloudflare/sveltekit/plugin.js.map +1 -1
- package/lib/cloudflare/vite/vite.d.ts.map +1 -1
- package/lib/cloudflare/vite/vite.js +2 -1
- package/lib/cloudflare/vite/vite.js.map +1 -1
- package/lib/cloudflare/vpc-service-ref.d.ts +38 -0
- package/lib/cloudflare/vpc-service-ref.d.ts.map +1 -0
- package/lib/cloudflare/vpc-service-ref.js +33 -0
- package/lib/cloudflare/vpc-service-ref.js.map +1 -0
- package/lib/cloudflare/vpc-service.d.ts +4 -4
- package/lib/cloudflare/vpc-service.d.ts.map +1 -1
- package/lib/cloudflare/vpc-service.js +44 -38
- package/lib/cloudflare/vpc-service.js.map +1 -1
- package/lib/docker/api.d.ts +33 -2
- package/lib/docker/api.d.ts.map +1 -1
- package/lib/docker/api.js +8 -4
- package/lib/docker/api.js.map +1 -1
- package/lib/docker/container.d.ts +1 -1
- package/lib/docker/container.d.ts.map +1 -1
- package/lib/docker/container.js +244 -15
- package/lib/docker/container.js.map +1 -1
- package/lib/test/bun.js +1 -1
- package/lib/test/vitest.js +1 -1
- package/package.json +1 -1
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/sveltekit/plugin.ts +17 -8
- package/src/cloudflare/vite/vite.ts +4 -2
- package/src/cloudflare/vpc-service-ref.ts +60 -0
- package/src/cloudflare/vpc-service.ts +53 -46
- package/src/docker/api.ts +47 -4
- package/src/docker/container.ts +318 -18
- package/src/test/bun.ts +1 -1
- package/src/test/vitest.ts +1 -1
- package/workers/tunnel-proxy.js +1 -1
package/src/docker/api.ts
CHANGED
|
@@ -69,10 +69,44 @@ type VolumeInfo = {
|
|
|
69
69
|
Scope: string;
|
|
70
70
|
};
|
|
71
71
|
|
|
72
|
-
type ContainerInfo = {
|
|
72
|
+
export type ContainerInfo = {
|
|
73
73
|
Id: string;
|
|
74
74
|
State: { Status: "created" | "running" | "paused" | "stopped" | "exited" };
|
|
75
75
|
Created: string;
|
|
76
|
+
Config: {
|
|
77
|
+
Image: string;
|
|
78
|
+
Cmd: string[] | null;
|
|
79
|
+
Env: string[] | null;
|
|
80
|
+
Healthcheck?: {
|
|
81
|
+
Test: string[] | null;
|
|
82
|
+
Interval?: number;
|
|
83
|
+
Timeout?: number;
|
|
84
|
+
Retries?: number;
|
|
85
|
+
StartPeriod?: number;
|
|
86
|
+
StartInterval?: number;
|
|
87
|
+
} | null;
|
|
88
|
+
};
|
|
89
|
+
HostConfig: {
|
|
90
|
+
PortBindings: Record<
|
|
91
|
+
string,
|
|
92
|
+
Array<{ HostIp: string; HostPort: string }> | null
|
|
93
|
+
> | null;
|
|
94
|
+
Binds: string[] | null;
|
|
95
|
+
RestartPolicy: {
|
|
96
|
+
Name: string;
|
|
97
|
+
MaximumRetryCount: number;
|
|
98
|
+
};
|
|
99
|
+
AutoRemove: boolean;
|
|
100
|
+
};
|
|
101
|
+
NetworkSettings: {
|
|
102
|
+
Networks: Record<
|
|
103
|
+
string,
|
|
104
|
+
{
|
|
105
|
+
NetworkID: string;
|
|
106
|
+
Aliases: string[] | null;
|
|
107
|
+
}
|
|
108
|
+
> | null;
|
|
109
|
+
};
|
|
76
110
|
};
|
|
77
111
|
|
|
78
112
|
/**
|
|
@@ -103,6 +137,7 @@ export class DockerApi {
|
|
|
103
137
|
async exec(
|
|
104
138
|
args: string[],
|
|
105
139
|
remainingAttempts = 3,
|
|
140
|
+
quiet = false,
|
|
106
141
|
): Promise<{ stdout: string; stderr: string }> {
|
|
107
142
|
// If a custom config directory is provided, ensure all commands use it by
|
|
108
143
|
// setting the DOCKER_CONFIG env variable for the spawned process.
|
|
@@ -124,13 +159,17 @@ export class DockerApi {
|
|
|
124
159
|
|
|
125
160
|
// Stream stdout in real-time
|
|
126
161
|
subprocess.stdout?.on("data", (chunk: string) => {
|
|
127
|
-
|
|
162
|
+
if (!quiet) {
|
|
163
|
+
process.stdout.write(chunk);
|
|
164
|
+
}
|
|
128
165
|
stdout += chunk;
|
|
129
166
|
});
|
|
130
167
|
|
|
131
168
|
// Stream stderr in real-time
|
|
132
169
|
subprocess.stderr?.on("data", (chunk: string) => {
|
|
133
|
-
|
|
170
|
+
if (!quiet) {
|
|
171
|
+
process.stderr.write(chunk);
|
|
172
|
+
}
|
|
134
173
|
stderr += chunk;
|
|
135
174
|
});
|
|
136
175
|
|
|
@@ -364,7 +403,11 @@ export class DockerApi {
|
|
|
364
403
|
* @returns Container details in JSON format
|
|
365
404
|
*/
|
|
366
405
|
async inspectContainer(containerId: string): Promise<ContainerInfo[]> {
|
|
367
|
-
const { stdout } = await this.exec(
|
|
406
|
+
const { stdout } = await this.exec(
|
|
407
|
+
["container", "inspect", containerId],
|
|
408
|
+
undefined,
|
|
409
|
+
true,
|
|
410
|
+
);
|
|
368
411
|
try {
|
|
369
412
|
return JSON.parse(stdout.trim()) as ContainerInfo[];
|
|
370
413
|
} catch (_error) {
|
package/src/docker/container.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Context } from "../context.ts";
|
|
2
2
|
import { Resource } from "../resource.ts";
|
|
3
|
-
import { DockerApi } from "./api.ts";
|
|
3
|
+
import { DockerApi, normalizeDuration, type ContainerInfo } from "./api.ts";
|
|
4
4
|
import type { Image } from "./image.ts";
|
|
5
5
|
import type { RemoteImage } from "./remote-image.ts";
|
|
6
6
|
|
|
@@ -201,7 +201,7 @@ export interface Container extends ContainerProps {
|
|
|
201
201
|
/**
|
|
202
202
|
* Container state
|
|
203
203
|
*/
|
|
204
|
-
state
|
|
204
|
+
state: "created" | "running" | "paused" | "stopped" | "exited";
|
|
205
205
|
|
|
206
206
|
/**
|
|
207
207
|
* Time when the container was created
|
|
@@ -277,6 +277,7 @@ export interface Container extends ContainerProps {
|
|
|
277
277
|
*/
|
|
278
278
|
export const Container = Resource(
|
|
279
279
|
"docker::Container",
|
|
280
|
+
{ alwaysUpdate: true },
|
|
280
281
|
async function (
|
|
281
282
|
this: Context<Container>,
|
|
282
283
|
id: string,
|
|
@@ -311,39 +312,63 @@ export const Container = Resource(
|
|
|
311
312
|
return this.destroy();
|
|
312
313
|
}
|
|
313
314
|
|
|
314
|
-
let containerState:
|
|
315
|
+
let containerState: Container["state"] = "created";
|
|
315
316
|
|
|
316
317
|
// Check if container already exists
|
|
317
318
|
const containerExists = await api.containerExists(containerName);
|
|
318
319
|
|
|
319
320
|
if (containerExists) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
321
|
+
// Create phase - check for adoption
|
|
322
|
+
if (this.phase === "create" && !props.adopt) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
`Container "${containerName}" already exists. Use adopt: true to adopt it.`,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const [containerInfo] = await api.inspectContainer(containerName);
|
|
329
|
+
|
|
330
|
+
// Compute what changes are needed
|
|
331
|
+
if (shouldReplace(imageRef, props, containerInfo)) {
|
|
332
|
+
// Need to recreate - remove existing container
|
|
333
|
+
if (this.phase === "update") {
|
|
334
|
+
// In update phase, we can replace the resource
|
|
335
|
+
// Force because we need to delete the old one first if the name is the same
|
|
336
|
+
return this.replace(true);
|
|
337
|
+
} else {
|
|
338
|
+
// In create phase, we cannot replace the resource, so manually delete instead
|
|
339
|
+
await api.removeContainer(containerName, true);
|
|
340
|
+
}
|
|
323
341
|
} else {
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
342
|
+
// Apply incremental changes without recreating the container
|
|
343
|
+
|
|
344
|
+
const { toConnect, toDisconnect } = getNetworkChanges(
|
|
345
|
+
props,
|
|
346
|
+
containerInfo,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
// Apply network disconnections
|
|
350
|
+
for (const network of toDisconnect) {
|
|
351
|
+
await api.disconnectNetwork(containerInfo.Id, network);
|
|
329
352
|
}
|
|
330
353
|
|
|
331
|
-
//
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
354
|
+
// Apply network connections
|
|
355
|
+
for (const network of toConnect) {
|
|
356
|
+
await api.connectNetwork(containerInfo.Id, network.name, {
|
|
357
|
+
aliases: network.aliases,
|
|
358
|
+
});
|
|
359
|
+
}
|
|
335
360
|
|
|
336
361
|
// Optionally start the container if requested
|
|
337
362
|
if (props.start && containerInfo.State.Status !== "running") {
|
|
338
|
-
await api.startContainer(
|
|
339
|
-
|
|
363
|
+
await api.startContainer(containerInfo.Id);
|
|
364
|
+
containerState = "running";
|
|
340
365
|
}
|
|
341
366
|
|
|
342
367
|
return {
|
|
343
368
|
...props,
|
|
344
369
|
id: containerInfo.Id,
|
|
345
370
|
name: containerName,
|
|
346
|
-
state:
|
|
371
|
+
state: containerState,
|
|
347
372
|
createdAt: new Date(containerInfo.Created).getTime(),
|
|
348
373
|
};
|
|
349
374
|
}
|
|
@@ -402,3 +427,278 @@ export const Container = Resource(
|
|
|
402
427
|
};
|
|
403
428
|
},
|
|
404
429
|
);
|
|
430
|
+
|
|
431
|
+
function getNetworkChanges(
|
|
432
|
+
props: ContainerProps,
|
|
433
|
+
containerInfo: ContainerInfo,
|
|
434
|
+
): { toConnect: NetworkMapping[]; toDisconnect: string[] } {
|
|
435
|
+
const currentNetworks = new Set(
|
|
436
|
+
Object.keys(containerInfo.NetworkSettings.Networks || {}),
|
|
437
|
+
);
|
|
438
|
+
const desiredNetworks = new Map(
|
|
439
|
+
(props.networks || []).map((n) => [n.name, n]),
|
|
440
|
+
);
|
|
441
|
+
const toConnect: NetworkMapping[] = [];
|
|
442
|
+
const toDisconnect: string[] = [];
|
|
443
|
+
for (const network of currentNetworks) {
|
|
444
|
+
if (!desiredNetworks.has(network) && network !== "bridge") {
|
|
445
|
+
toDisconnect.push(network);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
for (const [name, config] of desiredNetworks) {
|
|
449
|
+
if (!currentNetworks.has(name)) {
|
|
450
|
+
toConnect.push(config);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return { toConnect, toDisconnect };
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function shouldReplace(
|
|
457
|
+
imageRef: string,
|
|
458
|
+
props: ContainerProps,
|
|
459
|
+
containerInfo: ContainerInfo,
|
|
460
|
+
): boolean {
|
|
461
|
+
// Check immutable properties that require recreation
|
|
462
|
+
|
|
463
|
+
// Image change - compare the image ID/digest if available
|
|
464
|
+
// The container stores the resolved image ID, so we compare against imageRef
|
|
465
|
+
if (containerInfo.Config.Image !== imageRef) {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Command change
|
|
470
|
+
const containerCmd = containerInfo.Config.Cmd || [];
|
|
471
|
+
if (
|
|
472
|
+
props.command && // only compare if command is set; otherwise we'd be comparing against the image's default command
|
|
473
|
+
(props.command.length !== containerCmd.length ||
|
|
474
|
+
!props.command.every((c, i) => c === containerCmd[i]))
|
|
475
|
+
) {
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Environment variables
|
|
480
|
+
if (!compareEnv(props.environment, containerInfo.Config.Env)) {
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// Port bindings
|
|
485
|
+
if (!comparePorts(props.ports, containerInfo.HostConfig.PortBindings)) {
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Volume bindings
|
|
490
|
+
if (!compareVolumes(props.volumes, containerInfo.HostConfig.Binds)) {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// Healthcheck
|
|
495
|
+
if (
|
|
496
|
+
!compareHealthcheck(props.healthcheck, containerInfo.Config.Healthcheck)
|
|
497
|
+
) {
|
|
498
|
+
return true;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Restart policy
|
|
502
|
+
if (
|
|
503
|
+
!compareRestartPolicy(props.restart, containerInfo.HostConfig.RestartPolicy)
|
|
504
|
+
) {
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// AutoRemove (removeOnExit)
|
|
509
|
+
if ((props.removeOnExit || false) !== containerInfo.HostConfig.AutoRemove) {
|
|
510
|
+
return true;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Normalize port mappings to a comparable format
|
|
518
|
+
* @internal
|
|
519
|
+
*/
|
|
520
|
+
function normalizePortMappings(
|
|
521
|
+
ports: PortMapping[] | undefined,
|
|
522
|
+
): Map<string, string> {
|
|
523
|
+
const map = new Map<string, string>();
|
|
524
|
+
if (!ports) return map;
|
|
525
|
+
for (const port of ports) {
|
|
526
|
+
const protocol = port.protocol || "tcp";
|
|
527
|
+
map.set(`${port.external}`, `${port.internal}/${protocol}`);
|
|
528
|
+
}
|
|
529
|
+
return map;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Normalize volume mappings to a comparable format
|
|
534
|
+
* @internal
|
|
535
|
+
*/
|
|
536
|
+
function normalizeVolumeMappings(
|
|
537
|
+
volumes: VolumeMapping[] | undefined,
|
|
538
|
+
): Set<string> {
|
|
539
|
+
const set = new Set<string>();
|
|
540
|
+
if (!volumes) return set;
|
|
541
|
+
for (const volume of volumes) {
|
|
542
|
+
const readOnlyFlag = volume.readOnly ? ":ro" : "";
|
|
543
|
+
set.add(`${volume.hostPath}:${volume.containerPath}${readOnlyFlag}`);
|
|
544
|
+
}
|
|
545
|
+
return set;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Compare environment variables
|
|
550
|
+
* @internal
|
|
551
|
+
*/
|
|
552
|
+
function compareEnv(
|
|
553
|
+
propsEnv: Record<string, string> | undefined,
|
|
554
|
+
containerEnv: string[] | null,
|
|
555
|
+
): boolean {
|
|
556
|
+
const propsEntries = Object.entries(propsEnv || {}).sort(([a], [b]) =>
|
|
557
|
+
a.localeCompare(b),
|
|
558
|
+
);
|
|
559
|
+
const containerEntries = (containerEnv || [])
|
|
560
|
+
.map((e) => {
|
|
561
|
+
const idx = e.indexOf("=");
|
|
562
|
+
return idx >= 0 ? ([e.slice(0, idx), e.slice(idx + 1)] as const) : null;
|
|
563
|
+
})
|
|
564
|
+
.filter((e): e is [string, string] => e !== null)
|
|
565
|
+
// Filter out PATH and other system env vars that Docker adds
|
|
566
|
+
.filter(([key]) => propsEnv && key in propsEnv)
|
|
567
|
+
.sort(([a], [b]) => a.localeCompare(b));
|
|
568
|
+
|
|
569
|
+
if (propsEntries.length !== containerEntries.length) return false;
|
|
570
|
+
for (let i = 0; i < propsEntries.length; i++) {
|
|
571
|
+
if (
|
|
572
|
+
propsEntries[i][0] !== containerEntries[i][0] ||
|
|
573
|
+
propsEntries[i][1] !== containerEntries[i][1]
|
|
574
|
+
) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Compare port bindings
|
|
583
|
+
* @internal
|
|
584
|
+
*/
|
|
585
|
+
function comparePorts(
|
|
586
|
+
propsPorts: PortMapping[] | undefined,
|
|
587
|
+
containerPorts: Record<
|
|
588
|
+
string,
|
|
589
|
+
Array<{ HostIp: string; HostPort: string }> | null
|
|
590
|
+
> | null,
|
|
591
|
+
): boolean {
|
|
592
|
+
const propsMap = normalizePortMappings(propsPorts);
|
|
593
|
+
|
|
594
|
+
// Extract container port mappings
|
|
595
|
+
const containerMap = new Map<string, string>();
|
|
596
|
+
if (containerPorts) {
|
|
597
|
+
for (const [containerPort, bindings] of Object.entries(containerPorts)) {
|
|
598
|
+
if (bindings && bindings.length > 0) {
|
|
599
|
+
containerMap.set(bindings[0].HostPort, containerPort);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (propsMap.size !== containerMap.size) return false;
|
|
605
|
+
for (const [hostPort, containerPort] of propsMap) {
|
|
606
|
+
if (containerMap.get(hostPort) !== containerPort) return false;
|
|
607
|
+
}
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Compare volume bindings
|
|
613
|
+
* @internal
|
|
614
|
+
*/
|
|
615
|
+
function compareVolumes(
|
|
616
|
+
propsVolumes: VolumeMapping[] | undefined,
|
|
617
|
+
containerBinds: string[] | null,
|
|
618
|
+
): boolean {
|
|
619
|
+
const propsSet = normalizeVolumeMappings(propsVolumes);
|
|
620
|
+
const containerSet = new Set(containerBinds || []);
|
|
621
|
+
|
|
622
|
+
if (propsSet.size !== containerSet.size) return false;
|
|
623
|
+
for (const bind of propsSet) {
|
|
624
|
+
if (!containerSet.has(bind)) return false;
|
|
625
|
+
}
|
|
626
|
+
return true;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/**
|
|
630
|
+
* Compare healthcheck configuration
|
|
631
|
+
* @internal
|
|
632
|
+
*/
|
|
633
|
+
function compareHealthcheck(
|
|
634
|
+
propsHc: HealthcheckConfig | undefined,
|
|
635
|
+
containerHc:
|
|
636
|
+
| {
|
|
637
|
+
Test: string[] | null;
|
|
638
|
+
Interval?: number;
|
|
639
|
+
Timeout?: number;
|
|
640
|
+
Retries?: number;
|
|
641
|
+
StartPeriod?: number;
|
|
642
|
+
StartInterval?: number;
|
|
643
|
+
}
|
|
644
|
+
| null
|
|
645
|
+
| undefined,
|
|
646
|
+
): boolean {
|
|
647
|
+
// Both undefined/null
|
|
648
|
+
if (!propsHc && !containerHc) return true;
|
|
649
|
+
// One defined, one not
|
|
650
|
+
if (!propsHc || !containerHc) return false;
|
|
651
|
+
|
|
652
|
+
// Compare command
|
|
653
|
+
const propsCmd = Array.isArray(propsHc.cmd)
|
|
654
|
+
? propsHc.cmd.join(" ")
|
|
655
|
+
: propsHc.cmd;
|
|
656
|
+
const containerCmd = containerHc.Test
|
|
657
|
+
? containerHc.Test.slice(1).join(" ")
|
|
658
|
+
: "";
|
|
659
|
+
if (propsCmd !== containerCmd) return false;
|
|
660
|
+
|
|
661
|
+
// Helper to convert Duration to nanoseconds for comparison
|
|
662
|
+
const toNanos = (d: Duration | undefined): number => {
|
|
663
|
+
if (d === undefined) return 0;
|
|
664
|
+
const str = normalizeDuration(d);
|
|
665
|
+
const match = str.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)$/);
|
|
666
|
+
if (!match) return 0;
|
|
667
|
+
const value = parseFloat(match[1]);
|
|
668
|
+
const unit = match[2];
|
|
669
|
+
switch (unit) {
|
|
670
|
+
case "ms":
|
|
671
|
+
return value * 1_000_000;
|
|
672
|
+
case "s":
|
|
673
|
+
return value * 1_000_000_000;
|
|
674
|
+
case "m":
|
|
675
|
+
return value * 60 * 1_000_000_000;
|
|
676
|
+
case "h":
|
|
677
|
+
return value * 3600 * 1_000_000_000;
|
|
678
|
+
default:
|
|
679
|
+
return 0;
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
|
|
683
|
+
if (toNanos(propsHc.interval) !== (containerHc.Interval || 0)) return false;
|
|
684
|
+
if (toNanos(propsHc.timeout) !== (containerHc.Timeout || 0)) return false;
|
|
685
|
+
if ((propsHc.retries || 0) !== (containerHc.Retries || 0)) return false;
|
|
686
|
+
if (toNanos(propsHc.startPeriod) !== (containerHc.StartPeriod || 0))
|
|
687
|
+
return false;
|
|
688
|
+
if (toNanos(propsHc.startInterval) !== (containerHc.StartInterval || 0))
|
|
689
|
+
return false;
|
|
690
|
+
|
|
691
|
+
return true;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Compare restart policy
|
|
696
|
+
* @internal
|
|
697
|
+
*/
|
|
698
|
+
function compareRestartPolicy(
|
|
699
|
+
propsRestart: ContainerProps["restart"] | undefined,
|
|
700
|
+
containerRestart: { Name: string; MaximumRetryCount: number },
|
|
701
|
+
): boolean {
|
|
702
|
+
const propsPolicy = propsRestart || "no";
|
|
703
|
+
return propsPolicy === containerRestart.Name;
|
|
704
|
+
}
|
package/src/test/bun.ts
CHANGED
|
@@ -157,7 +157,7 @@ export function test(meta: ImportMeta, defaultOptions?: TestOptions): test {
|
|
|
157
157
|
const timeout =
|
|
158
158
|
typeof args[args.length - 1] === "number"
|
|
159
159
|
? (args[args.length - 1] as number)
|
|
160
|
-
:
|
|
160
|
+
: 150000;
|
|
161
161
|
const spread = (obj: any) =>
|
|
162
162
|
obj && typeof obj === "object"
|
|
163
163
|
? Object.fromEntries(
|
package/src/test/vitest.ts
CHANGED
package/workers/tunnel-proxy.js
CHANGED
|
@@ -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.
|
|
86
|
+
<p class="text-sm text-slate-500">Alchemy 0.86.0</p>
|
|
87
87
|
</div>
|
|
88
88
|
</div>
|
|
89
89
|
</body>
|