creek 0.3.0 → 0.3.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.
- package/bin.js +2 -0
- package/hono.d.ts +1 -0
- package/hono.js +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +30 -35
- package/react.d.ts +1 -0
- package/react.js +1 -0
- package/README.md +0 -184
- package/dist/commands/claim.d.ts +0 -18
- package/dist/commands/claim.js +0 -93
- package/dist/commands/deploy.d.ts +0 -38
- package/dist/commands/deploy.js +0 -807
- package/dist/commands/deployments.d.ts +0 -18
- package/dist/commands/deployments.js +0 -84
- package/dist/commands/env.d.ts +0 -2
- package/dist/commands/env.js +0 -104
- package/dist/commands/init.d.ts +0 -18
- package/dist/commands/init.js +0 -69
- package/dist/commands/login.d.ts +0 -23
- package/dist/commands/login.js +0 -120
- package/dist/commands/projects.d.ts +0 -13
- package/dist/commands/projects.js +0 -38
- package/dist/commands/status.d.ts +0 -18
- package/dist/commands/status.js +0 -115
- package/dist/commands/whoami.d.ts +0 -13
- package/dist/commands/whoami.js +0 -43
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -36
- package/dist/utils/auth-server.d.ts +0 -22
- package/dist/utils/auth-server.js +0 -91
- package/dist/utils/bundle.d.ts +0 -6
- package/dist/utils/bundle.js +0 -39
- package/dist/utils/config.d.ts +0 -12
- package/dist/utils/config.js +0 -37
- package/dist/utils/git-clone.d.ts +0 -44
- package/dist/utils/git-clone.js +0 -193
- package/dist/utils/nextjs.d.ts +0 -48
- package/dist/utils/nextjs.js +0 -368
- package/dist/utils/output.d.ts +0 -38
- package/dist/utils/output.js +0 -45
- package/dist/utils/repo-url.d.ts +0 -48
- package/dist/utils/repo-url.js +0 -201
- package/dist/utils/sandbox.d.ts +0 -50
- package/dist/utils/sandbox.js +0 -69
- package/dist/utils/ssr-bundle.d.ts +0 -6
- package/dist/utils/ssr-bundle.js +0 -48
- package/dist/utils/tos.d.ts +0 -28
- package/dist/utils/tos.js +0 -95
package/dist/commands/whoami.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
import consola from "consola";
|
|
3
|
-
import { CreekClient } from "@solcreek/sdk";
|
|
4
|
-
import { getToken, getApiUrl } from "../utils/config.js";
|
|
5
|
-
import { globalArgs, resolveJsonMode, jsonOutput } from "../utils/output.js";
|
|
6
|
-
export const whoamiCommand = defineCommand({
|
|
7
|
-
meta: {
|
|
8
|
-
name: "whoami",
|
|
9
|
-
description: "Show the currently authenticated user",
|
|
10
|
-
},
|
|
11
|
-
args: { ...globalArgs },
|
|
12
|
-
async run({ args }) {
|
|
13
|
-
const jsonMode = resolveJsonMode(args);
|
|
14
|
-
const token = getToken();
|
|
15
|
-
if (!token) {
|
|
16
|
-
if (jsonMode)
|
|
17
|
-
jsonOutput({ ok: false, authenticated: false, error: "not_authenticated" }, 1);
|
|
18
|
-
consola.error("Not authenticated. Run `creek login` first.");
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
const client = new CreekClient(getApiUrl(), token);
|
|
22
|
-
const session = await client.getSession();
|
|
23
|
-
if (!session?.user) {
|
|
24
|
-
if (jsonMode)
|
|
25
|
-
jsonOutput({ ok: false, authenticated: false, error: "session_expired" }, 1);
|
|
26
|
-
consola.error("Session expired or invalid. Run `creek login` to re-authenticate.");
|
|
27
|
-
process.exit(1);
|
|
28
|
-
}
|
|
29
|
-
if (jsonMode) {
|
|
30
|
-
jsonOutput({
|
|
31
|
-
ok: true,
|
|
32
|
-
authenticated: true,
|
|
33
|
-
user: session.user.name,
|
|
34
|
-
email: session.user.email,
|
|
35
|
-
api: getApiUrl(),
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
consola.log(` User: ${session.user.name}`);
|
|
39
|
-
consola.log(` Email: ${session.user.email}`);
|
|
40
|
-
consola.log(` API: ${getApiUrl()}`);
|
|
41
|
-
},
|
|
42
|
-
});
|
|
43
|
-
//# sourceMappingURL=whoami.js.map
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { defineCommand, runMain } from "citty";
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
import { dirname, join } from "node:path";
|
|
6
|
-
import { loginCommand } from "./commands/login.js";
|
|
7
|
-
import { whoamiCommand } from "./commands/whoami.js";
|
|
8
|
-
import { initCommand } from "./commands/init.js";
|
|
9
|
-
import { deployCommand } from "./commands/deploy.js";
|
|
10
|
-
import { claimCommand } from "./commands/claim.js";
|
|
11
|
-
import { envCommand } from "./commands/env.js";
|
|
12
|
-
import { projectsCommand } from "./commands/projects.js";
|
|
13
|
-
import { deploymentsCommand } from "./commands/deployments.js";
|
|
14
|
-
import { statusCommand } from "./commands/status.js";
|
|
15
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
17
|
-
const main = defineCommand({
|
|
18
|
-
meta: {
|
|
19
|
-
name: "creek",
|
|
20
|
-
version: pkg.version,
|
|
21
|
-
description: "Deploy full-stack apps to the edge",
|
|
22
|
-
},
|
|
23
|
-
subCommands: {
|
|
24
|
-
deploy: deployCommand,
|
|
25
|
-
status: statusCommand,
|
|
26
|
-
projects: projectsCommand,
|
|
27
|
-
deployments: deploymentsCommand,
|
|
28
|
-
login: loginCommand,
|
|
29
|
-
whoami: whoamiCommand,
|
|
30
|
-
init: initCommand,
|
|
31
|
-
claim: claimCommand,
|
|
32
|
-
env: envCommand,
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
runMain(main);
|
|
36
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export interface AuthCallbackResult {
|
|
2
|
-
key: string;
|
|
3
|
-
state: string;
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Start a temporary local HTTP server to receive the OAuth-style callback
|
|
7
|
-
* from the dashboard after CLI auth.
|
|
8
|
-
*
|
|
9
|
-
* Flow:
|
|
10
|
-
* 1. Server starts on a random available port
|
|
11
|
-
* 2. CLI opens browser to dashboard /cli-auth?port=X&state=Y
|
|
12
|
-
* 3. Dashboard creates API key, redirects to http://localhost:X/callback?key=...&state=...
|
|
13
|
-
* 4. This server receives the callback, validates state, resolves the promise
|
|
14
|
-
* 5. Server auto-closes
|
|
15
|
-
*/
|
|
16
|
-
export declare function startAuthServer(): {
|
|
17
|
-
port: number;
|
|
18
|
-
state: string;
|
|
19
|
-
waitForCallback: () => Promise<string>;
|
|
20
|
-
close: () => void;
|
|
21
|
-
};
|
|
22
|
-
//# sourceMappingURL=auth-server.d.ts.map
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { createServer } from "node:http";
|
|
2
|
-
import { randomBytes } from "node:crypto";
|
|
3
|
-
/**
|
|
4
|
-
* Start a temporary local HTTP server to receive the OAuth-style callback
|
|
5
|
-
* from the dashboard after CLI auth.
|
|
6
|
-
*
|
|
7
|
-
* Flow:
|
|
8
|
-
* 1. Server starts on a random available port
|
|
9
|
-
* 2. CLI opens browser to dashboard /cli-auth?port=X&state=Y
|
|
10
|
-
* 3. Dashboard creates API key, redirects to http://localhost:X/callback?key=...&state=...
|
|
11
|
-
* 4. This server receives the callback, validates state, resolves the promise
|
|
12
|
-
* 5. Server auto-closes
|
|
13
|
-
*/
|
|
14
|
-
export function startAuthServer() {
|
|
15
|
-
const state = randomBytes(16).toString("hex");
|
|
16
|
-
let resolveCallback;
|
|
17
|
-
let rejectCallback;
|
|
18
|
-
const callbackPromise = new Promise((resolve, reject) => {
|
|
19
|
-
resolveCallback = resolve;
|
|
20
|
-
rejectCallback = reject;
|
|
21
|
-
});
|
|
22
|
-
const server = createServer((req, res) => {
|
|
23
|
-
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
24
|
-
if (url.pathname === "/callback") {
|
|
25
|
-
const key = url.searchParams.get("key");
|
|
26
|
-
const returnedState = url.searchParams.get("state");
|
|
27
|
-
if (returnedState !== state) {
|
|
28
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
29
|
-
res.end(htmlPage("Authentication Failed", "Invalid state parameter. Please try again."));
|
|
30
|
-
rejectCallback(new Error("State mismatch — possible CSRF attack"));
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
if (!key) {
|
|
34
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
35
|
-
res.end(htmlPage("Authentication Failed", "No API key received. Please try again."));
|
|
36
|
-
rejectCallback(new Error("No API key in callback"));
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
40
|
-
res.end(htmlPage("Authenticated!", "You can close this window and return to the terminal."));
|
|
41
|
-
resolveCallback(key);
|
|
42
|
-
setTimeout(() => server.close(), 500);
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
res.writeHead(404);
|
|
46
|
-
res.end("Not found");
|
|
47
|
-
});
|
|
48
|
-
// Listen on port 0 = OS picks a random available port
|
|
49
|
-
server.listen(0, "localhost");
|
|
50
|
-
const address = server.address();
|
|
51
|
-
const port = typeof address === "object" && address ? address.port : 0;
|
|
52
|
-
// Timeout after 2 minutes
|
|
53
|
-
const timeout = setTimeout(() => {
|
|
54
|
-
rejectCallback(new Error("Login timed out after 2 minutes"));
|
|
55
|
-
server.close();
|
|
56
|
-
}, 120_000);
|
|
57
|
-
return {
|
|
58
|
-
port,
|
|
59
|
-
state,
|
|
60
|
-
waitForCallback: () => callbackPromise.finally(() => clearTimeout(timeout)),
|
|
61
|
-
close: () => {
|
|
62
|
-
clearTimeout(timeout);
|
|
63
|
-
server.close();
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
function escapeHtml(s) {
|
|
68
|
-
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
69
|
-
}
|
|
70
|
-
function htmlPage(title, message) {
|
|
71
|
-
return `<!DOCTYPE html>
|
|
72
|
-
<html>
|
|
73
|
-
<head>
|
|
74
|
-
<meta charset="utf-8">
|
|
75
|
-
<title>Creek CLI - ${escapeHtml(title)}</title>
|
|
76
|
-
<style>
|
|
77
|
-
body { font-family: system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #0a0a0a; color: #eee; }
|
|
78
|
-
.card { text-align: center; padding: 2rem; }
|
|
79
|
-
h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }
|
|
80
|
-
p { color: #888; }
|
|
81
|
-
</style>
|
|
82
|
-
</head>
|
|
83
|
-
<body>
|
|
84
|
-
<div class="card">
|
|
85
|
-
<h1>${escapeHtml(title)}</h1>
|
|
86
|
-
<p>${escapeHtml(message)}</p>
|
|
87
|
-
</div>
|
|
88
|
-
</body>
|
|
89
|
-
</html>`;
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=auth-server.js.map
|
package/dist/utils/bundle.d.ts
DELETED
package/dist/utils/bundle.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { readFileSync, readdirSync } from "node:fs";
|
|
2
|
-
import { join, relative } from "node:path";
|
|
3
|
-
const IGNORED_DIRS = new Set([
|
|
4
|
-
"node_modules", ".git", ".svn", ".hg", ".next", ".nuxt", ".output",
|
|
5
|
-
]);
|
|
6
|
-
const IGNORED_FILES = new Set([
|
|
7
|
-
".DS_Store", "Thumbs.db", ".env", ".env.local", ".env.production",
|
|
8
|
-
".gitignore", ".npmrc", ".eslintcache",
|
|
9
|
-
]);
|
|
10
|
-
function isIgnored(name) {
|
|
11
|
-
return name.startsWith(".") && IGNORED_FILES.has(name)
|
|
12
|
-
|| IGNORED_FILES.has(name)
|
|
13
|
-
|| name.endsWith("~")
|
|
14
|
-
|| name.endsWith(".swp");
|
|
15
|
-
}
|
|
16
|
-
export function collectAssets(dir, baseDir) {
|
|
17
|
-
const base = baseDir ?? dir;
|
|
18
|
-
const assets = {};
|
|
19
|
-
const fileList = [];
|
|
20
|
-
const entries = readdirSync(dir, { withFileTypes: true });
|
|
21
|
-
for (const entry of entries) {
|
|
22
|
-
if (IGNORED_DIRS.has(entry.name))
|
|
23
|
-
continue;
|
|
24
|
-
const fullPath = join(dir, entry.name);
|
|
25
|
-
if (entry.isDirectory()) {
|
|
26
|
-
const sub = collectAssets(fullPath, base);
|
|
27
|
-
Object.assign(assets, sub.assets);
|
|
28
|
-
fileList.push(...sub.fileList);
|
|
29
|
-
}
|
|
30
|
-
else if (entry.isFile() && !isIgnored(entry.name)) {
|
|
31
|
-
const relPath = relative(base, fullPath);
|
|
32
|
-
const content = readFileSync(fullPath);
|
|
33
|
-
assets[relPath] = content.toString("base64");
|
|
34
|
-
fileList.push(relPath);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
return { assets, fileList };
|
|
38
|
-
}
|
|
39
|
-
//# sourceMappingURL=bundle.js.map
|
package/dist/utils/config.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
interface CliConfig {
|
|
2
|
-
token?: string;
|
|
3
|
-
apiUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
export declare function getConfigDir(): string;
|
|
6
|
-
export declare function readCliConfig(): CliConfig;
|
|
7
|
-
export declare function writeCliConfig(config: CliConfig): void;
|
|
8
|
-
export declare function getToken(): string | undefined;
|
|
9
|
-
export declare function getApiUrl(): string;
|
|
10
|
-
export declare function getSandboxApiUrl(): string;
|
|
11
|
-
export {};
|
|
12
|
-
//# sourceMappingURL=config.d.ts.map
|
package/dist/utils/config.js
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
|
-
import { homedir } from "node:os";
|
|
4
|
-
const CONFIG_DIR = join(homedir(), ".creek");
|
|
5
|
-
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
6
|
-
export function getConfigDir() {
|
|
7
|
-
return CONFIG_DIR;
|
|
8
|
-
}
|
|
9
|
-
export function readCliConfig() {
|
|
10
|
-
if (!existsSync(CONFIG_FILE))
|
|
11
|
-
return {};
|
|
12
|
-
try {
|
|
13
|
-
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return {};
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export function writeCliConfig(config) {
|
|
20
|
-
if (!existsSync(CONFIG_DIR)) {
|
|
21
|
-
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
22
|
-
}
|
|
23
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
24
|
-
}
|
|
25
|
-
export function getToken() {
|
|
26
|
-
return process.env.CREEK_TOKEN ?? readCliConfig().token;
|
|
27
|
-
}
|
|
28
|
-
export function getApiUrl() {
|
|
29
|
-
return (process.env.CREEK_API_URL ??
|
|
30
|
-
readCliConfig().apiUrl ??
|
|
31
|
-
"https://api.creek.dev");
|
|
32
|
-
}
|
|
33
|
-
export function getSandboxApiUrl() {
|
|
34
|
-
return (process.env.CREEK_SANDBOX_API_URL ??
|
|
35
|
-
"https://sandbox-api.creek.dev");
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=config.js.map
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { ParsedRepoUrl } from "./repo-url.js";
|
|
2
|
-
export interface CloneOptions {
|
|
3
|
-
subpath?: string | null;
|
|
4
|
-
timeoutMs?: number;
|
|
5
|
-
maxSizeMb?: number;
|
|
6
|
-
}
|
|
7
|
-
export interface CloneResult {
|
|
8
|
-
tmpDir: string;
|
|
9
|
-
workDir: string;
|
|
10
|
-
sizeMb: number;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Check if git CLI is available. Throws with install instructions if not.
|
|
14
|
-
*/
|
|
15
|
-
export declare function checkGitInstalled(): void;
|
|
16
|
-
/**
|
|
17
|
-
* Clone a repository with full security hardening.
|
|
18
|
-
*
|
|
19
|
-
* Security measures:
|
|
20
|
-
* - --depth 1 (shallow, limits disk usage)
|
|
21
|
-
* - --single-branch (don't fetch other branches)
|
|
22
|
-
* - --no-recurse-submodules (prevent submodule attacks)
|
|
23
|
-
* - core.hooksPath=/dev/null (disable git hooks)
|
|
24
|
-
* - protocol.ext.allow=never (block ext:: protocol handler)
|
|
25
|
-
* - protocol.file.allow=never (block file:// protocol)
|
|
26
|
-
* - GIT_TERMINAL_PROMPT=0 (disable interactive auth)
|
|
27
|
-
* - .git directory deleted immediately after clone
|
|
28
|
-
* - Post-clone size check
|
|
29
|
-
*/
|
|
30
|
-
export declare function cloneRepo(parsed: ParsedRepoUrl, options?: CloneOptions): CloneResult;
|
|
31
|
-
export type PackageManager = "npm" | "pnpm" | "yarn" | "bun";
|
|
32
|
-
/**
|
|
33
|
-
* Detect package manager from lock file.
|
|
34
|
-
*/
|
|
35
|
-
export declare function detectPackageManager(cwd: string): PackageManager;
|
|
36
|
-
/**
|
|
37
|
-
* Install dependencies using the detected package manager.
|
|
38
|
-
*/
|
|
39
|
-
export declare function installDependencies(cwd: string, pm: PackageManager): void;
|
|
40
|
-
export declare function cleanupDir(dir: string): void;
|
|
41
|
-
export declare class GitCloneError extends Error {
|
|
42
|
-
constructor(message: string);
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=git-clone.d.ts.map
|
package/dist/utils/git-clone.js
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdtempSync, rmSync, readdirSync } from "node:fs";
|
|
3
|
-
import { join, resolve } from "node:path";
|
|
4
|
-
import { tmpdir } from "node:os";
|
|
5
|
-
/**
|
|
6
|
-
* Check if git CLI is available. Throws with install instructions if not.
|
|
7
|
-
*/
|
|
8
|
-
export function checkGitInstalled() {
|
|
9
|
-
try {
|
|
10
|
-
execFileSync("git", ["--version"], { stdio: "pipe" });
|
|
11
|
-
}
|
|
12
|
-
catch {
|
|
13
|
-
throw new GitCloneError("Git is not installed.\n" +
|
|
14
|
-
" Install it from: https://git-scm.com/downloads\n" +
|
|
15
|
-
" Or deploy a local directory: creek deploy ./my-project");
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Clone a repository with full security hardening.
|
|
20
|
-
*
|
|
21
|
-
* Security measures:
|
|
22
|
-
* - --depth 1 (shallow, limits disk usage)
|
|
23
|
-
* - --single-branch (don't fetch other branches)
|
|
24
|
-
* - --no-recurse-submodules (prevent submodule attacks)
|
|
25
|
-
* - core.hooksPath=/dev/null (disable git hooks)
|
|
26
|
-
* - protocol.ext.allow=never (block ext:: protocol handler)
|
|
27
|
-
* - protocol.file.allow=never (block file:// protocol)
|
|
28
|
-
* - GIT_TERMINAL_PROMPT=0 (disable interactive auth)
|
|
29
|
-
* - .git directory deleted immediately after clone
|
|
30
|
-
* - Post-clone size check
|
|
31
|
-
*/
|
|
32
|
-
export function cloneRepo(parsed, options = {}) {
|
|
33
|
-
const { subpath, timeoutMs = 60_000, maxSizeMb = 500 } = options;
|
|
34
|
-
const tmpDir = mkdtempSync(join(tmpdir(), "creek-repo-"));
|
|
35
|
-
try {
|
|
36
|
-
const args = [
|
|
37
|
-
"clone",
|
|
38
|
-
"--depth", "1",
|
|
39
|
-
"--single-branch",
|
|
40
|
-
...(parsed.branch ? ["--branch", parsed.branch] : []),
|
|
41
|
-
"--no-recurse-submodules",
|
|
42
|
-
"--config", "core.hooksPath=/dev/null",
|
|
43
|
-
"--config", "protocol.ext.allow=never",
|
|
44
|
-
"--config", "protocol.file.allow=never",
|
|
45
|
-
parsed.cloneUrl,
|
|
46
|
-
tmpDir,
|
|
47
|
-
];
|
|
48
|
-
execFileSync("git", args, {
|
|
49
|
-
stdio: "pipe",
|
|
50
|
-
timeout: timeoutMs,
|
|
51
|
-
env: {
|
|
52
|
-
...process.env,
|
|
53
|
-
GIT_TERMINAL_PROMPT: "0",
|
|
54
|
-
GIT_ASKPASS: "/bin/echo",
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
catch (err) {
|
|
59
|
-
// Parse git error for helpful messages
|
|
60
|
-
const stderr = err instanceof Error && "stderr" in err
|
|
61
|
-
? String(err.stderr)
|
|
62
|
-
: "";
|
|
63
|
-
cleanupDir(tmpDir);
|
|
64
|
-
if (stderr.includes("Repository not found") || stderr.includes("not found")) {
|
|
65
|
-
throw new GitCloneError(`Repository not found: ${parsed.displayUrl}`);
|
|
66
|
-
}
|
|
67
|
-
if (stderr.includes("Authentication failed") || stderr.includes("could not read Username")) {
|
|
68
|
-
throw new GitCloneError(`This appears to be a private repository: ${parsed.displayUrl}\n` +
|
|
69
|
-
" Creek currently supports public repos only.\n" +
|
|
70
|
-
" To deploy a private repo, clone it locally first:\n" +
|
|
71
|
-
` git clone ${parsed.cloneUrl} && cd ${parsed.repo} && creek deploy`);
|
|
72
|
-
}
|
|
73
|
-
if (stderr.includes("empty repository") || stderr.includes("warning: You appear to have cloned an empty repository")) {
|
|
74
|
-
throw new GitCloneError(`Repository is empty: ${parsed.displayUrl}`);
|
|
75
|
-
}
|
|
76
|
-
if (err instanceof Error && "killed" in err && err.killed) {
|
|
77
|
-
throw new GitCloneError(`Clone timed out after ${Math.round(timeoutMs / 1000)}s: ${parsed.displayUrl}\n` +
|
|
78
|
-
" The repository may be too large for direct deploy.\n" +
|
|
79
|
-
" Try cloning locally: git clone --depth 1 " + parsed.cloneUrl);
|
|
80
|
-
}
|
|
81
|
-
if (stderr.includes("Remote branch") && stderr.includes("not found")) {
|
|
82
|
-
throw new GitCloneError(`Branch '${parsed.branch}' not found in ${parsed.displayUrl}`);
|
|
83
|
-
}
|
|
84
|
-
throw new GitCloneError(`Failed to clone ${parsed.displayUrl}: ${stderr || (err instanceof Error ? err.message : String(err))}`);
|
|
85
|
-
}
|
|
86
|
-
// Immediately remove .git directory (prevent hook attacks, save disk)
|
|
87
|
-
rmSync(join(tmpDir, ".git"), { recursive: true, force: true });
|
|
88
|
-
// Also remove .gitmodules if present (prevent submodule tricks)
|
|
89
|
-
const gitmodulesPath = join(tmpDir, ".gitmodules");
|
|
90
|
-
if (existsSync(gitmodulesPath)) {
|
|
91
|
-
rmSync(gitmodulesPath, { force: true });
|
|
92
|
-
}
|
|
93
|
-
// Check repo size
|
|
94
|
-
const sizeMb = getDirSizeMb(tmpDir);
|
|
95
|
-
if (sizeMb > maxSizeMb) {
|
|
96
|
-
cleanupDir(tmpDir);
|
|
97
|
-
throw new GitCloneError(`Repository is too large (${Math.round(sizeMb)}MB, limit is ${maxSizeMb}MB).\n` +
|
|
98
|
-
" Clone locally and use creek deploy from the directory instead.");
|
|
99
|
-
}
|
|
100
|
-
// Resolve subpath if specified
|
|
101
|
-
let workDir = tmpDir;
|
|
102
|
-
if (subpath) {
|
|
103
|
-
workDir = resolve(tmpDir, subpath);
|
|
104
|
-
// Belt-and-suspenders: verify resolved path is within tmpDir
|
|
105
|
-
if (!resolve(workDir).startsWith(resolve(tmpDir))) {
|
|
106
|
-
cleanupDir(tmpDir);
|
|
107
|
-
throw new GitCloneError("Subpath resolved outside the repository (path traversal blocked)");
|
|
108
|
-
}
|
|
109
|
-
if (!existsSync(workDir)) {
|
|
110
|
-
cleanupDir(tmpDir);
|
|
111
|
-
throw new GitCloneError(`Subdirectory '${subpath}' not found in ${parsed.displayUrl}.\n` +
|
|
112
|
-
` Available directories: ${listTopDirs(tmpDir).join(", ") || "(none)"}`);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return { tmpDir, workDir, sizeMb };
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Detect package manager from lock file.
|
|
119
|
-
*/
|
|
120
|
-
export function detectPackageManager(cwd) {
|
|
121
|
-
if (existsSync(join(cwd, "pnpm-lock.yaml")))
|
|
122
|
-
return "pnpm";
|
|
123
|
-
if (existsSync(join(cwd, "yarn.lock")))
|
|
124
|
-
return "yarn";
|
|
125
|
-
if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock")))
|
|
126
|
-
return "bun";
|
|
127
|
-
return "npm";
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Install dependencies using the detected package manager.
|
|
131
|
-
*/
|
|
132
|
-
export function installDependencies(cwd, pm) {
|
|
133
|
-
const commands = {
|
|
134
|
-
npm: ["npm", "install", "--no-audit", "--no-fund"],
|
|
135
|
-
pnpm: ["pnpm", "install"],
|
|
136
|
-
yarn: ["yarn", "install"],
|
|
137
|
-
bun: ["bun", "install"],
|
|
138
|
-
};
|
|
139
|
-
const [cmd, ...args] = commands[pm];
|
|
140
|
-
try {
|
|
141
|
-
execFileSync(cmd, args, {
|
|
142
|
-
cwd,
|
|
143
|
-
stdio: "pipe",
|
|
144
|
-
timeout: 120_000,
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
catch (err) {
|
|
148
|
-
const stderr = err instanceof Error && "stderr" in err
|
|
149
|
-
? String(err.stderr).slice(0, 500)
|
|
150
|
-
: "";
|
|
151
|
-
throw new GitCloneError(`Failed to install dependencies with ${pm}.\n` +
|
|
152
|
-
(stderr ? ` ${stderr}\n` : "") +
|
|
153
|
-
` Try: cd ${cwd} && ${cmd} ${args.join(" ")}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// --- Helpers ---
|
|
157
|
-
function getDirSizeMb(dir) {
|
|
158
|
-
try {
|
|
159
|
-
const output = execFileSync("du", ["-sk", dir], { stdio: "pipe" }).toString();
|
|
160
|
-
const kb = parseInt(output.split("\t")[0], 10);
|
|
161
|
-
return kb / 1024;
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return 0; // Can't determine size, allow it
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
function listTopDirs(dir) {
|
|
168
|
-
try {
|
|
169
|
-
return readdirSync(dir, { withFileTypes: true })
|
|
170
|
-
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
|
|
171
|
-
.map((d) => d.name)
|
|
172
|
-
.slice(0, 10);
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
return [];
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
export function cleanupDir(dir) {
|
|
179
|
-
try {
|
|
180
|
-
rmSync(dir, { recursive: true, force: true });
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
// Best effort
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
// --- Error ---
|
|
187
|
-
export class GitCloneError extends Error {
|
|
188
|
-
constructor(message) {
|
|
189
|
-
super(message);
|
|
190
|
-
this.name = "GitCloneError";
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
//# sourceMappingURL=git-clone.js.map
|
package/dist/utils/nextjs.d.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Next.js-specific build utilities for Creek CLI.
|
|
3
|
-
*
|
|
4
|
-
* Two build paths:
|
|
5
|
-
* - **Adapter path** (Next.js >= 16.2): Uses @solcreek/adapter-nextjs via
|
|
6
|
-
* NEXT_ADAPTER_PATH. Zero workarounds, typed outputs, direct esbuild bundle.
|
|
7
|
-
* - **Legacy path** (Next.js < 16.2): Uses @opennextjs/cloudflare with
|
|
8
|
-
* workarounds (standalone patch, middleware manifest inline, etc.)
|
|
9
|
-
*
|
|
10
|
-
* The CLI auto-detects the Next.js version and picks the right path.
|
|
11
|
-
*/
|
|
12
|
-
/** Read the installed Next.js version from node_modules. */
|
|
13
|
-
export declare function getNextVersion(cwd: string): string | null;
|
|
14
|
-
/**
|
|
15
|
-
* Unified Next.js build entry point.
|
|
16
|
-
*
|
|
17
|
-
* - Next.js >= 16.2: Creek adapter path (recommended)
|
|
18
|
-
* - Next.js < 16.2: legacy opennext path (best effort)
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildNextjs(cwd: string, isMonorepo: boolean, projectName?: string): void;
|
|
21
|
-
/** Check if the adapter output exists (vs legacy opennext output). */
|
|
22
|
-
export declare function hasAdapterOutput(cwd: string): boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Patch the bundled worker to fix opennext's dynamic require issues.
|
|
25
|
-
*
|
|
26
|
-
* @deprecated Legacy path — only used for Next.js < 16.2. For >= 16.2,
|
|
27
|
-
* the Creek adapter handles middleware via typed AdapterOutputs.
|
|
28
|
-
*/
|
|
29
|
-
export declare function patchBundledWorker(bundleDir: string, openNextDir: string): void;
|
|
30
|
-
/**
|
|
31
|
-
* Fix the standalone output path for monorepo builds.
|
|
32
|
-
*
|
|
33
|
-
* When outputFileTracingRoot points to the monorepo root, Next.js outputs to:
|
|
34
|
-
* .next/standalone/{relative-app-path}/.next/
|
|
35
|
-
* instead of:
|
|
36
|
-
* .next/standalone/.next/
|
|
37
|
-
*
|
|
38
|
-
* This breaks @opennextjs/cloudflare's createCacheAssets.
|
|
39
|
-
*/
|
|
40
|
-
export declare function fixStandalonePath(appDir: string): boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Build a Next.js app for Cloudflare Workers via legacy opennext path.
|
|
43
|
-
*
|
|
44
|
-
* @deprecated Legacy path for Next.js < 16.2. Use buildNextjs() which
|
|
45
|
-
* auto-selects the adapter path for >= 16.2.
|
|
46
|
-
*/
|
|
47
|
-
export declare function buildNextjsForWorkers(cwd: string, isMonorepo: boolean, projectName?: string): void;
|
|
48
|
-
//# sourceMappingURL=nextjs.d.ts.map
|