@moinulmoin/eden 0.11.2 → 0.11.3
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/README.md +3 -3
- package/dist/eve-control-plane.js +97 -21
- package/dist/eve-packaging.js +17 -5
- package/dist/eve-runtime-config.js +2 -1
- package/dist/eve-runtime-image.js +12 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,15 +12,15 @@ If you already have an Eve project, start with `eden deploy`.
|
|
|
12
12
|
Use any one of these package managers:
|
|
13
13
|
|
|
14
14
|
```sh
|
|
15
|
-
npm install --global @moinulmoin/eden@0.11.
|
|
15
|
+
npm install --global @moinulmoin/eden@0.11.3
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
```sh
|
|
19
|
-
pnpm add --global @moinulmoin/eden@0.11.
|
|
19
|
+
pnpm add --global @moinulmoin/eden@0.11.3
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
```sh
|
|
23
|
-
bun add --global @moinulmoin/eden@0.11.
|
|
23
|
+
bun add --global @moinulmoin/eden@0.11.3
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Then confirm the CLI is available:
|
|
@@ -583,14 +583,14 @@ function candidateMetadata(candidate, imageDigest) {
|
|
|
583
583
|
...(imageDigest === undefined ? {} : { imageDigest }),
|
|
584
584
|
};
|
|
585
585
|
}
|
|
586
|
-
function safeWranglerEnvironment() {
|
|
586
|
+
function safeWranglerEnvironment(cwd) {
|
|
587
587
|
return {
|
|
588
|
-
|
|
589
|
-
HOME: process.env.HOME,
|
|
590
|
-
TMPDIR: process.env.TMPDIR,
|
|
591
|
-
LANG: process.env.LANG,
|
|
592
|
-
LC_ALL: process.env.LC_ALL,
|
|
588
|
+
...safeDockerEnvironment(),
|
|
593
589
|
CLOUDFLARE_API_TOKEN: process.env.CLOUDFLARE_API_TOKEN,
|
|
590
|
+
CLOUDFLARE_ACCOUNT_ID: process.env.CLOUDFLARE_ACCOUNT_ID,
|
|
591
|
+
NODE_EXTRA_CA_CERTS: process.env.NODE_EXTRA_CA_CERTS,
|
|
592
|
+
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,
|
|
593
|
+
WRANGLER_CACHE_DIR: join(cwd, "cache"),
|
|
594
594
|
CLOUDFLARE_API_BASE_URL: "https://api.cloudflare.com/client/v4",
|
|
595
595
|
NODE_OPTIONS: undefined,
|
|
596
596
|
};
|
|
@@ -604,11 +604,23 @@ function safeDockerEnvironment() {
|
|
|
604
604
|
LC_ALL: process.env.LC_ALL,
|
|
605
605
|
DOCKER_HOST: process.env.DOCKER_HOST,
|
|
606
606
|
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
607
|
+
DOCKER_CONFIG: process.env.DOCKER_CONFIG,
|
|
608
|
+
DOCKER_CERT_PATH: process.env.DOCKER_CERT_PATH,
|
|
609
|
+
DOCKER_TLS_VERIFY: process.env.DOCKER_TLS_VERIFY,
|
|
610
|
+
HTTP_PROXY: process.env.HTTP_PROXY,
|
|
611
|
+
HTTPS_PROXY: process.env.HTTPS_PROXY,
|
|
612
|
+
NO_PROXY: process.env.NO_PROXY,
|
|
613
|
+
http_proxy: process.env.http_proxy,
|
|
614
|
+
https_proxy: process.env.https_proxy,
|
|
615
|
+
no_proxy: process.env.no_proxy,
|
|
607
616
|
};
|
|
608
617
|
}
|
|
609
618
|
async function withWranglerDirectory(operation) {
|
|
619
|
+
// An explicit --config and WRANGLER_CACHE_DIR inside this private folder
|
|
620
|
+
// stop Wrangler from searching its (possibly shared) parent directories.
|
|
610
621
|
const cwd = await mkdtemp(join(tmpdir(), "eden-wrangler-"));
|
|
611
622
|
try {
|
|
623
|
+
await writeFile(join(cwd, "wrangler.json"), "{}\n", { mode: 0o600 });
|
|
612
624
|
return await operation(cwd);
|
|
613
625
|
}
|
|
614
626
|
finally {
|
|
@@ -617,8 +629,8 @@ async function withWranglerDirectory(operation) {
|
|
|
617
629
|
}
|
|
618
630
|
async function readWranglerJson(args, timeoutMs = 30_000) {
|
|
619
631
|
try {
|
|
620
|
-
const result = await withWranglerDirectory((cwd) => execFileAsync(process.execPath, [wranglerEntrypoint, ...args], {
|
|
621
|
-
env: safeWranglerEnvironment(),
|
|
632
|
+
const result = await withWranglerDirectory((cwd) => execFileAsync(process.execPath, [wranglerEntrypoint, ...args, "--config", join(cwd, "wrangler.json")], {
|
|
633
|
+
env: safeWranglerEnvironment(cwd),
|
|
622
634
|
cwd,
|
|
623
635
|
maxBuffer: 2 * 1024 * 1024,
|
|
624
636
|
timeout: timeoutMs,
|
|
@@ -648,7 +660,7 @@ function jsonCollection(value) {
|
|
|
648
660
|
}
|
|
649
661
|
return undefined;
|
|
650
662
|
}
|
|
651
|
-
function exactContainerEntries(value, name) {
|
|
663
|
+
function exactContainerEntries(value, name, complete = false) {
|
|
652
664
|
const collection = jsonCollection(value);
|
|
653
665
|
if (collection === undefined)
|
|
654
666
|
return undefined;
|
|
@@ -668,7 +680,8 @@ function exactContainerEntries(value, name) {
|
|
|
668
680
|
});
|
|
669
681
|
}
|
|
670
682
|
}
|
|
671
|
-
|
|
683
|
+
// Without proven pagination, a full page that lacks the name proves nothing.
|
|
684
|
+
if (entries.length === 0 && !complete && collection.length >= 100) {
|
|
672
685
|
return undefined;
|
|
673
686
|
}
|
|
674
687
|
return entries;
|
|
@@ -697,16 +710,25 @@ function authenticatedAccountId(value) {
|
|
|
697
710
|
const account = accounts[0];
|
|
698
711
|
if (typeof account !== "object" ||
|
|
699
712
|
account === null ||
|
|
713
|
+
!("id" in account) ||
|
|
700
714
|
typeof account.id !== "string") {
|
|
701
715
|
return undefined;
|
|
702
716
|
}
|
|
717
|
+
const selectedAccount = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
718
|
+
if (selectedAccount && selectedAccount !== account.id) {
|
|
719
|
+
return undefined;
|
|
720
|
+
}
|
|
703
721
|
return account.id;
|
|
704
722
|
}
|
|
705
723
|
async function readWranglerOAuthToken() {
|
|
706
|
-
const
|
|
724
|
+
const legacyRoot = join(homedir(), ".wrangler");
|
|
725
|
+
const legacyExists = (await lstat(legacyRoot).catch(() => undefined))?.isDirectory();
|
|
726
|
+
const configHome = process.env.XDG_CONFIG_HOME ??
|
|
707
727
|
(process.platform === "darwin"
|
|
708
|
-
? join(homedir(), "Library", "Preferences"
|
|
709
|
-
: join(homedir(), ".config"
|
|
728
|
+
? join(homedir(), "Library", "Preferences")
|
|
729
|
+
: join(homedir(), ".config"));
|
|
730
|
+
const root = process.env.WRANGLER_HOME ??
|
|
731
|
+
(legacyExists ? legacyRoot : join(configHome, ".wrangler"));
|
|
710
732
|
const raw = await readFile(join(root, "config", "default.toml"), "utf8")
|
|
711
733
|
.catch(() => undefined);
|
|
712
734
|
if (raw === undefined)
|
|
@@ -756,19 +778,71 @@ async function readWorkersDevSubdomain(accountId) {
|
|
|
756
778
|
export function exactTargetContainerEntries(value, name) {
|
|
757
779
|
return exactContainerEntries(value, boundedResourceName(name, "container"));
|
|
758
780
|
}
|
|
781
|
+
async function readTargetContainers(name) {
|
|
782
|
+
const account = await readWranglerJson(["whoami", "--json"]);
|
|
783
|
+
const accountId = authenticatedAccountId(account.value);
|
|
784
|
+
const token = process.env.CLOUDFLARE_API_TOKEN || await readWranglerOAuthToken();
|
|
785
|
+
if (accountId === undefined || !token)
|
|
786
|
+
return { failed: true };
|
|
787
|
+
// Unlike `containers list --json`, this endpoint supports an exact name
|
|
788
|
+
// filter and exposes result_info.next_page_token. No per_page means all.
|
|
789
|
+
const entries = [];
|
|
790
|
+
const seenTokens = new Set();
|
|
791
|
+
let pageToken;
|
|
792
|
+
try {
|
|
793
|
+
do {
|
|
794
|
+
const url = new URL(`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(accountId)}/containers/applications`);
|
|
795
|
+
url.searchParams.set("name", name);
|
|
796
|
+
if (pageToken !== undefined)
|
|
797
|
+
url.searchParams.set("page_token", pageToken);
|
|
798
|
+
const response = await fetch(url, {
|
|
799
|
+
headers: { Authorization: `Bearer ${token}`, Accept: "application/json" },
|
|
800
|
+
signal: AbortSignal.timeout(30_000),
|
|
801
|
+
});
|
|
802
|
+
if (!response.ok)
|
|
803
|
+
return { failed: true };
|
|
804
|
+
const body = await response.json();
|
|
805
|
+
if (typeof body !== "object" || body === null ||
|
|
806
|
+
!("success" in body) || body.success !== true ||
|
|
807
|
+
!("result" in body) || !Array.isArray(body.result))
|
|
808
|
+
return { failed: true };
|
|
809
|
+
const info = "result_info" in body ? body.result_info : undefined;
|
|
810
|
+
if (info !== undefined &&
|
|
811
|
+
(typeof info !== "object" || info === null || Array.isArray(info))) {
|
|
812
|
+
return { failed: true };
|
|
813
|
+
}
|
|
814
|
+
const next = info !== undefined && "next_page_token" in info
|
|
815
|
+
? info.next_page_token
|
|
816
|
+
: undefined;
|
|
817
|
+
if (next !== undefined && next !== null && typeof next !== "string") {
|
|
818
|
+
return { failed: true };
|
|
819
|
+
}
|
|
820
|
+
// Missing pagination metadata on a full page cannot prove absence.
|
|
821
|
+
if (info === undefined && body.result.length >= 100)
|
|
822
|
+
return { failed: true };
|
|
823
|
+
entries.push(...body.result);
|
|
824
|
+
pageToken = typeof next === "string" && next.length > 0 ? next : undefined;
|
|
825
|
+
if (pageToken !== undefined) {
|
|
826
|
+
if (seenTokens.has(pageToken))
|
|
827
|
+
return { failed: true };
|
|
828
|
+
seenTokens.add(pageToken);
|
|
829
|
+
}
|
|
830
|
+
} while (pageToken !== undefined);
|
|
831
|
+
return { failed: false, value: entries };
|
|
832
|
+
}
|
|
833
|
+
catch {
|
|
834
|
+
return { failed: true };
|
|
835
|
+
}
|
|
836
|
+
}
|
|
759
837
|
async function readExactTargetInventory(workerName, containerApp) {
|
|
760
|
-
|
|
761
|
-
// without the exact name remains indeterminate in exactContainerEntries.
|
|
762
|
-
const containers = await readWranglerJson([
|
|
763
|
-
"containers", "list", "--json", "--per-page", "100",
|
|
764
|
-
]);
|
|
838
|
+
const containers = await readTargetContainers(containerApp);
|
|
765
839
|
const deployments = await readWranglerJson([
|
|
766
840
|
"deployments", "list", "--name", workerName, "--json",
|
|
767
841
|
]);
|
|
768
842
|
return {
|
|
769
843
|
containers,
|
|
770
844
|
deployments,
|
|
771
|
-
containerEntries: containers.failed ? undefined : exactContainerEntries(containers.value, containerApp),
|
|
845
|
+
containerEntries: containers.failed ? undefined : exactContainerEntries(containers.value, containerApp, true),
|
|
772
846
|
deploymentEntries: exactDeploymentEntries(deployments.value),
|
|
773
847
|
};
|
|
774
848
|
}
|
|
@@ -1282,9 +1356,11 @@ const WRANGLER_PUBLICATION_TIMEOUT_MS = 600_000;
|
|
|
1282
1356
|
async function runWranglerWithInput(args, input, timeoutMs = WRANGLER_OPERATION_TIMEOUT_MS) {
|
|
1283
1357
|
// The project's TypeScript lib predates Promise.withResolvers.
|
|
1284
1358
|
return withWranglerDirectory((cwd) => new Promise((resolveResult) => {
|
|
1285
|
-
const child = spawn(process.execPath, [wranglerEntrypoint, ...args
|
|
1359
|
+
const child = spawn(process.execPath, [wranglerEntrypoint, ...args, ...(args.includes("--config")
|
|
1360
|
+
? []
|
|
1361
|
+
: ["--config", join(cwd, "wrangler.json")])], {
|
|
1286
1362
|
cwd,
|
|
1287
|
-
env: safeWranglerEnvironment(),
|
|
1363
|
+
env: safeWranglerEnvironment(cwd),
|
|
1288
1364
|
stdio: ["pipe", "pipe", "pipe"],
|
|
1289
1365
|
});
|
|
1290
1366
|
let stdout = "";
|
package/dist/eve-packaging.js
CHANGED
|
@@ -363,6 +363,7 @@ const EVE_EXCLUDED_FILE_NAMES = new Set([
|
|
|
363
363
|
".pnpmrc",
|
|
364
364
|
".pypirc",
|
|
365
365
|
".bunfig.toml",
|
|
366
|
+
"bunfig.toml",
|
|
366
367
|
".yarnrc",
|
|
367
368
|
".yarnrc.yml",
|
|
368
369
|
".dev.vars",
|
|
@@ -372,6 +373,9 @@ const EVE_EXCLUDED_FILE_NAMES = new Set([
|
|
|
372
373
|
"id_ecdsa",
|
|
373
374
|
"id_ed25519",
|
|
374
375
|
"id_dsa",
|
|
376
|
+
"id_ecdsa_sk",
|
|
377
|
+
"id_ed25519_sk",
|
|
378
|
+
"id_xmss",
|
|
375
379
|
"secrets.json",
|
|
376
380
|
"credentials.json",
|
|
377
381
|
"service-account.json",
|
|
@@ -427,15 +431,23 @@ function isAllowedSystemAlias(path) {
|
|
|
427
431
|
const normalized = resolve(path);
|
|
428
432
|
return normalized === "/var" || normalized === "/tmp";
|
|
429
433
|
}
|
|
434
|
+
function isEnvironmentFile(name) {
|
|
435
|
+
const normalizedName = name.toLowerCase();
|
|
436
|
+
return normalizedName.startsWith(".env") || normalizedName.endsWith(".env");
|
|
437
|
+
}
|
|
430
438
|
function isCredentialPath(relativePath) {
|
|
431
439
|
const parts = relativePath.split("/");
|
|
432
|
-
const
|
|
433
|
-
|
|
440
|
+
const originalName = parts[parts.length - 1];
|
|
441
|
+
if (originalName === undefined)
|
|
442
|
+
return false;
|
|
443
|
+
const name = originalName.toLowerCase();
|
|
444
|
+
return (EVE_EXCLUDED_FILE_NAMES.has(originalName) ||
|
|
445
|
+
EVE_EXCLUDED_FILE_NAMES.has(name) ||
|
|
434
446
|
name.startsWith(".dev.vars.") ||
|
|
435
447
|
name.endsWith(".pem") || name.endsWith(".key") ||
|
|
436
448
|
name.endsWith(".p12") || name.endsWith(".pfx") ||
|
|
437
449
|
name.endsWith(".tfvars") ||
|
|
438
|
-
(name === "credentials" && parts[parts.length - 2] === ".aws"));
|
|
450
|
+
(name === "credentials" && parts[parts.length - 2]?.toLowerCase() === ".aws"));
|
|
439
451
|
}
|
|
440
452
|
function isPathExcluded(relativePath, runtimeEnvRelativePath) {
|
|
441
453
|
const parts = relativePath.split("/");
|
|
@@ -455,7 +467,7 @@ function isPathExcluded(relativePath, runtimeEnvRelativePath) {
|
|
|
455
467
|
if (runtimeEnvRelativePath !== undefined && relativePath === runtimeEnvRelativePath) {
|
|
456
468
|
return { excluded: true, category: "runtime-env" };
|
|
457
469
|
}
|
|
458
|
-
if (name !== undefined && name
|
|
470
|
+
if (name !== undefined && isEnvironmentFile(name)) {
|
|
459
471
|
return { excluded: true, category: "runtime-env" };
|
|
460
472
|
}
|
|
461
473
|
if (isCredentialPath(relativePath)) {
|
|
@@ -1753,7 +1765,7 @@ async function assertGeneratedTreesExcludeSecrets(snapshotRoot) {
|
|
|
1753
1765
|
? entry.name
|
|
1754
1766
|
: `${relativeDirectory}/${entry.name}`;
|
|
1755
1767
|
const candidate = join(directory, entry.name);
|
|
1756
|
-
if (entry.name
|
|
1768
|
+
if (isEnvironmentFile(entry.name) ||
|
|
1757
1769
|
isCredentialPath(relativePath)) {
|
|
1758
1770
|
throw new EvePackagingError({
|
|
1759
1771
|
code: "SECRET_EXCLUSION_FAILED",
|
|
@@ -195,7 +195,8 @@ function parseEnvironmentText(text) {
|
|
|
195
195
|
variableName: name,
|
|
196
196
|
});
|
|
197
197
|
}
|
|
198
|
-
if (EVE_RESERVED_HOST_VARIABLES.includes(name)
|
|
198
|
+
if (EVE_RESERVED_HOST_VARIABLES.includes(name) ||
|
|
199
|
+
/^(DOCKER_|BUILDKIT_|BUILDX_|COMPOSE_|LD_|DYLD_)/u.test(name)) {
|
|
199
200
|
throw new EveRuntimeConfigError({
|
|
200
201
|
code: "EVE_ENV_RESERVED_VARIABLE",
|
|
201
202
|
message: `The explicit Eve environment file attempts to override reserved host variable ${name}.` +
|
|
@@ -556,6 +556,15 @@ function safeDockerEnvironment() {
|
|
|
556
556
|
LC_ALL: process.env.LC_ALL,
|
|
557
557
|
DOCKER_HOST: process.env.DOCKER_HOST,
|
|
558
558
|
DOCKER_CONTEXT: process.env.DOCKER_CONTEXT,
|
|
559
|
+
DOCKER_CONFIG: process.env.DOCKER_CONFIG,
|
|
560
|
+
DOCKER_CERT_PATH: process.env.DOCKER_CERT_PATH,
|
|
561
|
+
DOCKER_TLS_VERIFY: process.env.DOCKER_TLS_VERIFY,
|
|
562
|
+
HTTP_PROXY: process.env.HTTP_PROXY,
|
|
563
|
+
HTTPS_PROXY: process.env.HTTPS_PROXY,
|
|
564
|
+
NO_PROXY: process.env.NO_PROXY,
|
|
565
|
+
http_proxy: process.env.http_proxy,
|
|
566
|
+
https_proxy: process.env.https_proxy,
|
|
567
|
+
no_proxy: process.env.no_proxy,
|
|
559
568
|
};
|
|
560
569
|
}
|
|
561
570
|
/**
|
|
@@ -567,7 +576,7 @@ function safeDockerEnvironment() {
|
|
|
567
576
|
*/
|
|
568
577
|
async function docker(state, args, options = {}) {
|
|
569
578
|
return execFileAsync(state.command, [...args], {
|
|
570
|
-
env: { ...
|
|
579
|
+
env: { ...options.environment, ...state.env },
|
|
571
580
|
cwd: state.generationRoot,
|
|
572
581
|
maxBuffer: options.maxBuffer ?? 4 * 1024 * 1024,
|
|
573
582
|
});
|
|
@@ -987,7 +996,8 @@ export async function buildEveRuntimeImage(request) {
|
|
|
987
996
|
run: (startRequest) => startRequest.env,
|
|
988
997
|
});
|
|
989
998
|
if (request.runtimeInjection !== undefined) {
|
|
990
|
-
const collision = Object.keys(runtimeEnvironment).find((name) => DOCKER_CLI_OWNED_VARIABLES.includes(name)
|
|
999
|
+
const collision = Object.keys(runtimeEnvironment).find((name) => DOCKER_CLI_OWNED_VARIABLES.includes(name) ||
|
|
1000
|
+
/^(DOCKER_|BUILDKIT_|BUILDX_|COMPOSE_|LD_|DYLD_)/u.test(name));
|
|
991
1001
|
if (collision !== undefined) {
|
|
992
1002
|
throw packagingError("DOCKER_PLATFORM_BLOCKED", "runtime variable name", `The runtime variable ${collision} would replace the local Docker CLI's own ${collision}.`, `Rename ${collision} in --env-file; ${DOCKER_CLI_OWNED_VARIABLES.join(", ")} are reserved for the local Docker CLI.`);
|
|
993
1003
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moinulmoin/eden",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"description": "Deploy existing Eve projects to your own Cloudflare account.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"NOTICE"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@moinulmoin/eden-runtime-cloudflare": "0.11.
|
|
35
|
+
"@moinulmoin/eden-runtime-cloudflare": "0.11.3",
|
|
36
36
|
"wrangler": "4.147.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|