@prisma/cli 3.0.0-beta.0 → 3.0.0-beta.10
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 +18 -3
- package/dist/adapters/git.js +8 -3
- package/dist/adapters/local-state.js +12 -4
- package/dist/adapters/mock-api.js +81 -2
- package/dist/adapters/token-storage.js +63 -22
- package/dist/cli.js +17 -2
- package/dist/cli2.js +7 -3
- package/dist/commands/app/index.js +26 -13
- package/dist/commands/branch/index.js +2 -27
- package/dist/commands/database/index.js +159 -0
- package/dist/commands/env.js +8 -4
- package/dist/commands/project/index.js +28 -2
- package/dist/controllers/app-env-api.js +54 -0
- package/dist/controllers/app-env-file.js +181 -0
- package/dist/controllers/app-env.js +284 -132
- package/dist/controllers/app.js +493 -344
- package/dist/controllers/auth.js +8 -8
- package/dist/controllers/branch.js +78 -48
- package/dist/controllers/database.js +318 -0
- package/dist/controllers/project.js +302 -75
- package/dist/lib/app/branch-database-deploy.js +373 -0
- package/dist/lib/app/branch-database.js +316 -0
- package/dist/lib/app/bun-project.js +12 -5
- package/dist/lib/app/deploy-output.js +10 -1
- package/dist/lib/app/env-config.js +1 -1
- package/dist/lib/app/env-file.js +82 -0
- package/dist/lib/app/env-vars.js +28 -2
- package/dist/lib/app/local-dev.js +34 -18
- package/dist/lib/app/preview-branch-database.js +102 -0
- package/dist/lib/app/preview-build-settings.js +385 -0
- package/dist/lib/app/preview-build.js +272 -81
- package/dist/lib/app/preview-provider.js +163 -54
- package/dist/lib/app/production-deploy-gate.js +161 -0
- package/dist/lib/auth/auth-ops.js +69 -19
- package/dist/lib/auth/guard.js +3 -2
- package/dist/lib/auth/login.js +109 -14
- package/dist/lib/database/provider.js +167 -0
- package/dist/lib/diagnostics.js +15 -0
- package/dist/lib/git/local-branch.js +41 -0
- package/dist/lib/git/local-status.js +57 -0
- package/dist/lib/project/interactive-setup.js +56 -0
- package/dist/lib/project/local-pin.js +182 -33
- package/dist/lib/project/resolution.js +287 -105
- package/dist/lib/project/setup.js +132 -0
- package/dist/presenters/app-env.js +149 -14
- package/dist/presenters/app.js +170 -20
- package/dist/presenters/auth.js +19 -6
- package/dist/presenters/branch.js +37 -102
- package/dist/presenters/database.js +274 -0
- package/dist/presenters/project.js +100 -47
- package/dist/presenters/verbose-context.js +64 -0
- package/dist/shell/command-arguments.js +6 -0
- package/dist/shell/command-meta.js +139 -16
- package/dist/shell/command-runner.js +38 -8
- package/dist/shell/diagnostics-output.js +63 -0
- package/dist/shell/errors.js +14 -1
- package/dist/shell/output.js +13 -2
- package/dist/shell/runtime.js +3 -3
- package/dist/shell/ui.js +23 -1
- package/dist/shell/update-check.js +247 -0
- package/dist/use-cases/auth.js +15 -4
- package/dist/use-cases/branch.js +20 -68
- package/dist/use-cases/create-cli-gateways.js +2 -17
- package/dist/use-cases/project.js +2 -1
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -57,6 +57,8 @@ Useful next commands:
|
|
|
57
57
|
npx prisma-cli app logs
|
|
58
58
|
npx prisma-cli app open
|
|
59
59
|
npx prisma-cli project env add DATABASE_URL=postgresql://example --role preview
|
|
60
|
+
npx prisma-cli project env add --file .env --role preview
|
|
61
|
+
npx prisma-cli project env list
|
|
60
62
|
npx prisma-cli project env list --role preview
|
|
61
63
|
```
|
|
62
64
|
|
|
@@ -73,7 +75,7 @@ The beta package exposes `prisma-cli` so it can coexist with the existing
|
|
|
73
75
|
| `auth` | Log in, log out, and inspect the active Prisma account. |
|
|
74
76
|
| `project` | List projects, show the resolved project, and manage project environment variables. |
|
|
75
77
|
| `git` | Connect or disconnect a project from a GitHub repository. |
|
|
76
|
-
| `branch` |
|
|
78
|
+
| `branch` | List Prisma branches for the resolved project. |
|
|
77
79
|
| `app` | Build, run, deploy, inspect, open, stream logs, promote, roll back, and remove apps. |
|
|
78
80
|
|
|
79
81
|
Common examples:
|
|
@@ -82,7 +84,7 @@ Common examples:
|
|
|
82
84
|
npx prisma-cli version
|
|
83
85
|
npx prisma-cli auth whoami
|
|
84
86
|
npx prisma-cli project show
|
|
85
|
-
npx prisma-cli branch
|
|
87
|
+
npx prisma-cli branch list
|
|
86
88
|
npx prisma-cli app deploy --branch feat-login --framework nextjs
|
|
87
89
|
npx prisma-cli app promote <deployment-id>
|
|
88
90
|
```
|
|
@@ -96,11 +98,24 @@ npx prisma-cli app promote <deployment-id>
|
|
|
96
98
|
- Stable command groups, flags, and error codes for scripts and agents.
|
|
97
99
|
- Environment variable values are not printed back to the terminal.
|
|
98
100
|
|
|
101
|
+
### Agent skills
|
|
102
|
+
|
|
103
|
+
For agent-guided Next.js deploys, install the Prisma CLI skill cluster at the
|
|
104
|
+
project level. Match the skill ref to the installed CLI version:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx prisma-cli version
|
|
108
|
+
pnpm dlx skills@latest add prisma/prisma-cli/skills#cli-v<cli-version> --all
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The skills teach agents how to prepare a Next.js app, run `app deploy`, verify
|
|
112
|
+
the result, and route CLI / Compute feedback to the right Prisma channel.
|
|
113
|
+
|
|
99
114
|
---
|
|
100
115
|
|
|
101
116
|
## Beta notes
|
|
102
117
|
|
|
103
|
-
- Requires Node.js
|
|
118
|
+
- Requires Node.js 22.12 or newer.
|
|
104
119
|
- This is a beta package and may change quickly.
|
|
105
120
|
- Official beta releases publish as `@prisma/cli`.
|
|
106
121
|
- The package binary is `prisma-cli`, not `prisma`, during beta.
|
package/dist/adapters/git.js
CHANGED
|
@@ -2,7 +2,7 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { promisify } from "node:util";
|
|
3
3
|
//#region src/adapters/git.ts
|
|
4
4
|
const execFileAsync = promisify(execFile);
|
|
5
|
-
async function readGitOriginRemote(cwd) {
|
|
5
|
+
async function readGitOriginRemote(cwd, signal) {
|
|
6
6
|
try {
|
|
7
7
|
const { stdout } = await execFileAsync("git", [
|
|
8
8
|
"config",
|
|
@@ -10,14 +10,19 @@ async function readGitOriginRemote(cwd) {
|
|
|
10
10
|
"remote.origin.url"
|
|
11
11
|
], {
|
|
12
12
|
cwd,
|
|
13
|
-
timeout: 5e3
|
|
13
|
+
timeout: 5e3,
|
|
14
|
+
signal
|
|
14
15
|
});
|
|
15
16
|
const remote = stdout.trim();
|
|
16
17
|
return remote.length > 0 ? remote : null;
|
|
17
|
-
} catch {
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (signal?.aborted || isAbortError(error)) throw error;
|
|
18
20
|
return null;
|
|
19
21
|
}
|
|
20
22
|
}
|
|
23
|
+
function isAbortError(error) {
|
|
24
|
+
return error instanceof Error && error.name === "AbortError";
|
|
25
|
+
}
|
|
21
26
|
function parseGitHubRepositoryUrl(value) {
|
|
22
27
|
const input = value.trim();
|
|
23
28
|
const shorthand = input.match(/^git@github\.com:([^/\s]+)\/([^/\s]+?)(?:\.git)?$/);
|
|
@@ -20,12 +20,17 @@ function resolveLocalStateFilePath(stateDir) {
|
|
|
20
20
|
}
|
|
21
21
|
var LocalStateStore = class {
|
|
22
22
|
stateFilePath;
|
|
23
|
-
constructor(stateDir) {
|
|
23
|
+
constructor(stateDir, signal) {
|
|
24
|
+
this.signal = signal;
|
|
24
25
|
this.stateFilePath = resolveLocalStateFilePath(stateDir);
|
|
25
26
|
}
|
|
26
27
|
async read() {
|
|
28
|
+
this.signal?.throwIfAborted();
|
|
27
29
|
try {
|
|
28
|
-
const raw = await readFile(this.stateFilePath,
|
|
30
|
+
const raw = await readFile(this.stateFilePath, {
|
|
31
|
+
encoding: "utf8",
|
|
32
|
+
signal: this.signal
|
|
33
|
+
});
|
|
29
34
|
const parsed = JSON.parse(raw);
|
|
30
35
|
return {
|
|
31
36
|
auth: parsed.auth ?? structuredClone(DEFAULT_STATE.auth),
|
|
@@ -46,8 +51,11 @@ var LocalStateStore = class {
|
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
53
|
async write(state) {
|
|
54
|
+
this.signal?.throwIfAborted();
|
|
49
55
|
await mkdir(path.dirname(this.stateFilePath), { recursive: true });
|
|
50
|
-
|
|
56
|
+
this.signal?.throwIfAborted();
|
|
57
|
+
await writeFile(this.stateFilePath, `${JSON.stringify(state, null, 2)}\n`, { encoding: "utf8" });
|
|
58
|
+
this.signal?.throwIfAborted();
|
|
51
59
|
}
|
|
52
60
|
async setAuthSession(session) {
|
|
53
61
|
const state = await this.read();
|
|
@@ -133,4 +141,4 @@ var LocalStateStore = class {
|
|
|
133
141
|
}
|
|
134
142
|
};
|
|
135
143
|
//#endregion
|
|
136
|
-
export { LocalStateStore };
|
|
144
|
+
export { LocalStateStore, resolveLocalStateFilePath };
|
|
@@ -5,8 +5,12 @@ var MockApi = class MockApi {
|
|
|
5
5
|
constructor(data) {
|
|
6
6
|
this.data = data;
|
|
7
7
|
}
|
|
8
|
-
static async load(fixturePath) {
|
|
9
|
-
|
|
8
|
+
static async load(fixturePath, signal) {
|
|
9
|
+
signal?.throwIfAborted();
|
|
10
|
+
const raw = await readFile(fixturePath, {
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
signal
|
|
13
|
+
});
|
|
10
14
|
return new MockApi(JSON.parse(raw));
|
|
11
15
|
}
|
|
12
16
|
listProviders() {
|
|
@@ -52,6 +56,81 @@ var MockApi = class MockApi {
|
|
|
52
56
|
getDeployment(deploymentId) {
|
|
53
57
|
return this.data.deployments.find((deployment) => deployment.id === deploymentId);
|
|
54
58
|
}
|
|
59
|
+
listDatabasesForProject(projectId, branchName) {
|
|
60
|
+
return (this.data.databases ?? []).filter((database) => database.projectId === projectId && (!branchName || database.branchName === branchName));
|
|
61
|
+
}
|
|
62
|
+
getDatabase(databaseId) {
|
|
63
|
+
return (this.data.databases ?? []).find((database) => database.id === databaseId);
|
|
64
|
+
}
|
|
65
|
+
createDatabase(input) {
|
|
66
|
+
this.data.databases ??= [];
|
|
67
|
+
this.data.databaseConnections ??= [];
|
|
68
|
+
const database = {
|
|
69
|
+
id: `db_${this.data.databases.length + 1e3}`,
|
|
70
|
+
projectId: input.projectId,
|
|
71
|
+
branchId: input.branchName ? this.getBranchForProject(input.projectId, input.branchName)?.id ?? null : null,
|
|
72
|
+
branchName: input.branchName ?? null,
|
|
73
|
+
name: input.name,
|
|
74
|
+
region: input.region ?? null,
|
|
75
|
+
status: "ready",
|
|
76
|
+
isDefault: false,
|
|
77
|
+
createdAt: "2026-06-09T00:00:00.000Z"
|
|
78
|
+
};
|
|
79
|
+
const connectionString = `postgresql://${database.id}.example.prisma.io/postgres`;
|
|
80
|
+
const connection = {
|
|
81
|
+
id: `conn_${this.data.databaseConnections.length + 1e3}`,
|
|
82
|
+
databaseId: database.id,
|
|
83
|
+
name: "primary",
|
|
84
|
+
createdAt: "2026-06-09T00:00:00.000Z",
|
|
85
|
+
connectionString
|
|
86
|
+
};
|
|
87
|
+
this.data.databases.push(database);
|
|
88
|
+
this.data.databaseConnections.push(connection);
|
|
89
|
+
return {
|
|
90
|
+
database,
|
|
91
|
+
connection,
|
|
92
|
+
connectionString
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
removeDatabase(databaseId) {
|
|
96
|
+
this.data.databases ??= [];
|
|
97
|
+
this.data.databaseConnections ??= [];
|
|
98
|
+
const database = this.getDatabase(databaseId);
|
|
99
|
+
if (!database) return;
|
|
100
|
+
this.data.databases = this.data.databases.filter((candidate) => candidate.id !== databaseId);
|
|
101
|
+
this.data.databaseConnections = this.data.databaseConnections.filter((connection) => connection.databaseId !== databaseId);
|
|
102
|
+
return database;
|
|
103
|
+
}
|
|
104
|
+
listDatabaseConnections(databaseId) {
|
|
105
|
+
return (this.data.databaseConnections ?? []).filter((connection) => connection.databaseId === databaseId);
|
|
106
|
+
}
|
|
107
|
+
getDatabaseConnection(connectionId) {
|
|
108
|
+
return (this.data.databaseConnections ?? []).find((connection) => connection.id === connectionId);
|
|
109
|
+
}
|
|
110
|
+
createDatabaseConnection(input) {
|
|
111
|
+
if (!this.getDatabase(input.databaseId)) return;
|
|
112
|
+
this.data.databaseConnections ??= [];
|
|
113
|
+
const connectionString = `postgresql://${input.databaseId}-${this.data.databaseConnections.length + 1}.example.prisma.io/postgres`;
|
|
114
|
+
const connection = {
|
|
115
|
+
id: `conn_${this.data.databaseConnections.length + 1e3}`,
|
|
116
|
+
databaseId: input.databaseId,
|
|
117
|
+
name: input.name,
|
|
118
|
+
createdAt: "2026-06-09T00:00:00.000Z",
|
|
119
|
+
connectionString
|
|
120
|
+
};
|
|
121
|
+
this.data.databaseConnections.push(connection);
|
|
122
|
+
return {
|
|
123
|
+
connection,
|
|
124
|
+
connectionString
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
removeDatabaseConnection(connectionId) {
|
|
128
|
+
this.data.databaseConnections ??= [];
|
|
129
|
+
const connection = this.getDatabaseConnection(connectionId);
|
|
130
|
+
if (!connection) return;
|
|
131
|
+
this.data.databaseConnections = this.data.databaseConnections.filter((candidate) => candidate.id !== connectionId);
|
|
132
|
+
return connection;
|
|
133
|
+
}
|
|
55
134
|
};
|
|
56
135
|
//#endregion
|
|
57
136
|
export { MockApi };
|
|
@@ -20,37 +20,60 @@ function findLatestValidTokens(allCredentials) {
|
|
|
20
20
|
function tokensEqual(a, b) {
|
|
21
21
|
return a?.workspaceId === b?.workspaceId && a?.accessToken === b?.accessToken && a?.refreshToken === b?.refreshToken;
|
|
22
22
|
}
|
|
23
|
-
function sleep(ms) {
|
|
24
|
-
|
|
23
|
+
function sleep(ms, signal) {
|
|
24
|
+
signal?.throwIfAborted();
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const onAbort = () => {
|
|
27
|
+
clearTimeout(timeout);
|
|
28
|
+
reject(signal?.reason);
|
|
29
|
+
};
|
|
30
|
+
const timeout = setTimeout(() => {
|
|
31
|
+
signal?.removeEventListener("abort", onAbort);
|
|
32
|
+
resolve();
|
|
33
|
+
}, ms);
|
|
34
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
35
|
+
});
|
|
25
36
|
}
|
|
26
37
|
var FileTokenStorage = class {
|
|
27
38
|
credentialsStore;
|
|
28
39
|
lockFilePath;
|
|
29
|
-
constructor(env = process.env) {
|
|
40
|
+
constructor(env = process.env, signal) {
|
|
41
|
+
this.signal = signal;
|
|
30
42
|
const authFilePath = getAuthFilePath(env);
|
|
31
43
|
this.credentialsStore = new CredentialsStore(authFilePath);
|
|
32
44
|
this.lockFilePath = `${authFilePath}.lock`;
|
|
33
45
|
}
|
|
34
46
|
async getTokens() {
|
|
47
|
+
this.signal?.throwIfAborted();
|
|
35
48
|
try {
|
|
36
|
-
|
|
37
|
-
|
|
49
|
+
const all = await this.credentialsStore.getCredentials();
|
|
50
|
+
this.signal?.throwIfAborted();
|
|
51
|
+
return findLatestValidTokens(all);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
if (this.signal?.aborted) throw this.signal.reason;
|
|
38
54
|
return null;
|
|
39
55
|
}
|
|
40
56
|
}
|
|
41
57
|
async setTokens(tokens) {
|
|
58
|
+
this.signal?.throwIfAborted();
|
|
42
59
|
await this.credentialsStore.storeCredentials({
|
|
43
60
|
workspaceId: tokens.workspaceId,
|
|
44
61
|
token: tokens.accessToken,
|
|
45
62
|
refreshToken: tokens.refreshToken
|
|
46
63
|
});
|
|
64
|
+
this.signal?.throwIfAborted();
|
|
47
65
|
}
|
|
48
66
|
async clearTokens() {
|
|
49
|
-
|
|
67
|
+
this.signal?.throwIfAborted();
|
|
68
|
+
const all = await this.credentialsStore.getCredentials();
|
|
69
|
+
this.signal?.throwIfAborted();
|
|
70
|
+
const tokens = findLatestValidTokens(all);
|
|
50
71
|
if (!tokens) return;
|
|
51
72
|
await this.credentialsStore.deleteCredentials(tokens.workspaceId);
|
|
73
|
+
this.signal?.throwIfAborted();
|
|
52
74
|
}
|
|
53
75
|
async clearTokensIfCurrent(tokens) {
|
|
76
|
+
this.signal?.throwIfAborted();
|
|
54
77
|
if (!tokensEqual(await this.getTokens(), tokens)) return;
|
|
55
78
|
await this.clearTokens();
|
|
56
79
|
}
|
|
@@ -64,34 +87,52 @@ var FileTokenStorage = class {
|
|
|
64
87
|
}
|
|
65
88
|
async acquireRefreshLock() {
|
|
66
89
|
const lockId = randomUUID();
|
|
90
|
+
this.signal?.throwIfAborted();
|
|
67
91
|
await fs.mkdir(path.dirname(this.lockFilePath), { recursive: true });
|
|
68
|
-
while (true)
|
|
69
|
-
|
|
92
|
+
while (true) {
|
|
93
|
+
this.signal?.throwIfAborted();
|
|
94
|
+
let lockFileCreated = false;
|
|
70
95
|
try {
|
|
71
|
-
await
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
const handle = await fs.open(this.lockFilePath, "wx");
|
|
97
|
+
lockFileCreated = true;
|
|
98
|
+
try {
|
|
99
|
+
this.signal?.throwIfAborted();
|
|
100
|
+
await handle.writeFile(lockId, { encoding: "utf8" });
|
|
101
|
+
this.signal?.throwIfAborted();
|
|
102
|
+
} finally {
|
|
103
|
+
await handle.close();
|
|
104
|
+
}
|
|
105
|
+
return lockId;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (lockFileCreated) await fs.unlink(this.lockFilePath).catch(() => void 0);
|
|
108
|
+
if (error.code !== "EEXIST") throw error;
|
|
109
|
+
const staleLockId = await this.getStaleRefreshLockId();
|
|
110
|
+
if (staleLockId) {
|
|
111
|
+
await this.releaseRefreshLock(staleLockId);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
await sleep(100, this.signal);
|
|
82
115
|
}
|
|
83
|
-
await sleep(100);
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
118
|
async getStaleRefreshLockId() {
|
|
87
|
-
|
|
119
|
+
this.signal?.throwIfAborted();
|
|
120
|
+
const lockId = await fs.readFile(this.lockFilePath, {
|
|
121
|
+
encoding: "utf8",
|
|
122
|
+
signal: this.signal
|
|
123
|
+
}).catch((error) => {
|
|
124
|
+
if (this.signal?.aborted) throw error;
|
|
125
|
+
return null;
|
|
126
|
+
});
|
|
88
127
|
if (lockId === null) return null;
|
|
128
|
+
this.signal?.throwIfAborted();
|
|
89
129
|
const stats = await fs.stat(this.lockFilePath).catch(() => null);
|
|
130
|
+
this.signal?.throwIfAborted();
|
|
90
131
|
if (!stats) return null;
|
|
91
132
|
return Date.now() - stats.mtimeMs > 3e4 ? lockId : null;
|
|
92
133
|
}
|
|
93
134
|
async releaseRefreshLock(lockId) {
|
|
94
|
-
if (await fs.readFile(this.lockFilePath, "utf8").catch(() => null) !== lockId) return;
|
|
135
|
+
if (await fs.readFile(this.lockFilePath, { encoding: "utf8" }).catch(() => null) !== lockId) return;
|
|
95
136
|
await fs.unlink(this.lockFilePath).catch(() => {});
|
|
96
137
|
}
|
|
97
138
|
};
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { runUpdateDiscoveryWorker } from "./shell/update-check.js";
|
|
2
3
|
import { runCli } from "./cli2.js";
|
|
3
4
|
import process from "node:process";
|
|
4
5
|
//#region src/bin.ts
|
|
5
|
-
|
|
6
|
-
process.exitCode =
|
|
6
|
+
if (process.env.PRISMA_CLI_RUN_UPDATE_CHECK_WORKER === "1") runUpdateDiscoveryWorker().then(() => {
|
|
7
|
+
process.exitCode = 0;
|
|
7
8
|
});
|
|
9
|
+
else {
|
|
10
|
+
const controller = new AbortController();
|
|
11
|
+
const abortCli = () => {
|
|
12
|
+
if (!controller.signal.aborted) controller.abort(new DOMException("Command canceled", "AbortError"));
|
|
13
|
+
};
|
|
14
|
+
process.once("SIGINT", abortCli);
|
|
15
|
+
process.once("SIGTERM", abortCli);
|
|
16
|
+
runCli({ signal: controller.signal }).then((exitCode) => {
|
|
17
|
+
process.exitCode = exitCode;
|
|
18
|
+
}).finally(() => {
|
|
19
|
+
process.off("SIGINT", abortCli);
|
|
20
|
+
process.off("SIGTERM", abortCli);
|
|
21
|
+
});
|
|
22
|
+
}
|
|
8
23
|
//#endregion
|
|
9
24
|
export {};
|
package/dist/cli2.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CliError } from "./shell/errors.js";
|
|
2
2
|
import { createShellUi } from "./shell/ui.js";
|
|
3
|
-
import { writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
|
|
3
|
+
import { formatUnexpectedError, writeHumanError, writeJsonError, writeJsonSuccess } from "./shell/output.js";
|
|
4
4
|
import { attachCommandDescriptor } from "./shell/command-meta.js";
|
|
5
5
|
import { addCompactGlobalFlags } from "./shell/global-flags.js";
|
|
6
6
|
import { configureRuntimeCommand, createCommandContext } from "./shell/runtime.js";
|
|
@@ -8,11 +8,13 @@ import "./shell/prompt.js";
|
|
|
8
8
|
import { createAppCommand } from "./commands/app/index.js";
|
|
9
9
|
import { createAuthCommand } from "./commands/auth/index.js";
|
|
10
10
|
import { createBranchCommand } from "./commands/branch/index.js";
|
|
11
|
+
import { createDatabaseCommand } from "./commands/database/index.js";
|
|
11
12
|
import { createGitCommand } from "./commands/git/index.js";
|
|
12
13
|
import { createProjectCommand } from "./commands/project/index.js";
|
|
13
14
|
import { getCliName, getCliVersion } from "./lib/version.js";
|
|
14
15
|
import { runVersion } from "./controllers/version.js";
|
|
15
16
|
import { createVersionCommand } from "./commands/version/index.js";
|
|
17
|
+
import { maybeWriteCachedUpdateNotification } from "./shell/update-check.js";
|
|
16
18
|
import process from "node:process";
|
|
17
19
|
import { Command, CommanderError, Option } from "commander";
|
|
18
20
|
//#region src/cli.ts
|
|
@@ -21,6 +23,7 @@ async function runCli(options = {}) {
|
|
|
21
23
|
const program = createProgram(runtime);
|
|
22
24
|
process.exitCode = 0;
|
|
23
25
|
try {
|
|
26
|
+
await maybeWriteCachedUpdateNotification(runtime);
|
|
24
27
|
if (runtime.argv.includes("--version")) return await handleVersionFlag(runtime);
|
|
25
28
|
const bareHelpCommand = resolveBareHelpCommand(program, runtime.argv);
|
|
26
29
|
if (bareHelpCommand) {
|
|
@@ -31,8 +34,7 @@ async function runCli(options = {}) {
|
|
|
31
34
|
return process.exitCode ?? 0;
|
|
32
35
|
} catch (error) {
|
|
33
36
|
if (error instanceof CommanderError) return error.code === "commander.helpDisplayed" ? 0 : 2;
|
|
34
|
-
|
|
35
|
-
runtime.stderr.write(`${message}\n`);
|
|
37
|
+
runtime.stderr.write(formatUnexpectedError(error, runtime.argv.includes("--trace")));
|
|
36
38
|
return 1;
|
|
37
39
|
} finally {
|
|
38
40
|
runtime.stdin;
|
|
@@ -48,6 +50,7 @@ function createProgram(runtime) {
|
|
|
48
50
|
program.addCommand(createProjectCommand(runtime));
|
|
49
51
|
program.addCommand(createGitCommand(runtime));
|
|
50
52
|
program.addCommand(createBranchCommand(runtime));
|
|
53
|
+
program.addCommand(createDatabaseCommand(runtime));
|
|
51
54
|
program.addCommand(createAppCommand(runtime));
|
|
52
55
|
return program;
|
|
53
56
|
}
|
|
@@ -104,6 +107,7 @@ function resolveRuntime(options) {
|
|
|
104
107
|
argv: options.argv ?? process.argv.slice(2),
|
|
105
108
|
cwd: options.cwd ?? process.env.INIT_CWD ?? process.cwd(),
|
|
106
109
|
env: options.env ?? process.env,
|
|
110
|
+
signal: options.signal ?? new AbortController().signal,
|
|
107
111
|
stdin: options.stdin ?? process.stdin,
|
|
108
112
|
stdout: options.stdout ?? process.stdout,
|
|
109
113
|
stderr: options.stderr ?? process.stderr,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { usageError } from "../../shell/errors.js";
|
|
1
2
|
import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
2
3
|
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
|
|
3
4
|
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
@@ -59,36 +60,48 @@ function createRunCommand(runtime) {
|
|
|
59
60
|
}
|
|
60
61
|
function createDeployCommand(runtime) {
|
|
61
62
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("deploy"), runtime), "app.deploy");
|
|
62
|
-
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--branch <name>", "Branch name")).addOption(new Option("--framework <name>", "Framework to deploy").choices([
|
|
63
|
+
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name")).addOption(new Option("--create-project <name>", "Create and link a new Project before deploying")).addOption(new Option("--branch <name>", "Branch name")).addOption(new Option("--framework <name>", "Framework to deploy").choices([
|
|
63
64
|
"nextjs",
|
|
64
65
|
"hono",
|
|
65
|
-
"tanstack-start"
|
|
66
|
-
|
|
66
|
+
"tanstack-start",
|
|
67
|
+
"bun"
|
|
68
|
+
])).addOption(new Option("--entry <path>", "Entrypoint path for Bun deploys")).addOption(new Option("--http-port <port>", "HTTP port override for the deployed app")).addOption(new Option("--env <name=value|file>", "Environment variable assignment or dotenv file").argParser(collectRepeatableValues)).addOption(new Option("--db", "Create and wire a Prisma Postgres database for this deploy target")).addOption(new Option("--no-db", "Skip database setup")).addOption(new Option("--prod", "Confirm intent to deploy to production"));
|
|
67
69
|
addGlobalFlags(command);
|
|
68
70
|
command.action(async (options) => {
|
|
69
71
|
const appName = options.app;
|
|
70
72
|
const entry = options.entry;
|
|
71
|
-
const buildType = options.buildType;
|
|
72
73
|
const branchName = options.branch;
|
|
73
74
|
const framework = options.framework;
|
|
74
75
|
const httpPort = options.httpPort;
|
|
75
76
|
const envAssignments = options.env;
|
|
76
77
|
const projectRef = options.project;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
const createProjectName = options.createProject;
|
|
79
|
+
const prod = options.prod;
|
|
80
|
+
const db = options.db;
|
|
81
|
+
const hasDbConflict = hasFlag(runtime.argv, "--db") && hasFlag(runtime.argv, "--no-db");
|
|
82
|
+
await runCommand(runtime, "app.deploy", options, (context) => {
|
|
83
|
+
if (hasDbConflict) throw usageError("app deploy accepts either --db or --no-db", "--db requests database setup, while --no-db disables it.", "Pass exactly one database setup flag.", ["prisma-cli app deploy --db", "prisma-cli app deploy --no-db"], "app");
|
|
84
|
+
return runAppDeploy(context, appName, {
|
|
85
|
+
projectRef,
|
|
86
|
+
createProjectName,
|
|
87
|
+
branchName,
|
|
88
|
+
entrypoint: entry,
|
|
89
|
+
framework,
|
|
90
|
+
httpPort,
|
|
91
|
+
envAssignments,
|
|
92
|
+
prod: prod === true,
|
|
93
|
+
db
|
|
94
|
+
});
|
|
95
|
+
}, {
|
|
86
96
|
renderHuman: (context, descriptor, result) => renderAppDeploy(context, descriptor, result),
|
|
87
97
|
renderJson: (result) => serializeAppDeploy(result)
|
|
88
98
|
});
|
|
89
99
|
});
|
|
90
100
|
return command;
|
|
91
101
|
}
|
|
102
|
+
function hasFlag(argv, flag) {
|
|
103
|
+
return argv.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
104
|
+
}
|
|
92
105
|
function createShowCommand(runtime) {
|
|
93
106
|
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "app.show");
|
|
94
107
|
command.addOption(new Option("--app <name>", "App name")).addOption(new Option("--project <id-or-name>", "Project id or name"));
|
|
@@ -2,16 +2,14 @@ import { attachCommandDescriptor } from "../../shell/command-meta.js";
|
|
|
2
2
|
import { addCompactGlobalFlags, addGlobalFlags } from "../../shell/global-flags.js";
|
|
3
3
|
import { configureRuntimeCommand } from "../../shell/runtime.js";
|
|
4
4
|
import { runCommand } from "../../shell/command-runner.js";
|
|
5
|
-
import { runBranchList
|
|
6
|
-
import { renderBranchList,
|
|
5
|
+
import { runBranchList } from "../../controllers/branch.js";
|
|
6
|
+
import { renderBranchList, serializeBranchList } from "../../presenters/branch.js";
|
|
7
7
|
import { Command } from "commander";
|
|
8
8
|
//#region src/commands/branch/index.ts
|
|
9
9
|
function createBranchCommand(runtime) {
|
|
10
10
|
const branch = attachCommandDescriptor(configureRuntimeCommand(new Command("branch"), runtime), "branch");
|
|
11
11
|
addCompactGlobalFlags(branch);
|
|
12
12
|
branch.addCommand(createBranchListCommand(runtime));
|
|
13
|
-
branch.addCommand(createBranchShowCommand(runtime));
|
|
14
|
-
branch.addCommand(createBranchUseCommand(runtime));
|
|
15
13
|
return branch;
|
|
16
14
|
}
|
|
17
15
|
function createBranchListCommand(runtime) {
|
|
@@ -25,28 +23,5 @@ function createBranchListCommand(runtime) {
|
|
|
25
23
|
});
|
|
26
24
|
return command;
|
|
27
25
|
}
|
|
28
|
-
function createBranchShowCommand(runtime) {
|
|
29
|
-
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("show"), runtime), "branch.show");
|
|
30
|
-
addGlobalFlags(command);
|
|
31
|
-
command.action(async (options) => {
|
|
32
|
-
await runCommand(runtime, "branch.show", options, (context) => runBranchShow(context), {
|
|
33
|
-
renderHuman: (context, descriptor, result) => renderBranchShow(context, descriptor, result),
|
|
34
|
-
renderJson: (result) => serializeBranchShow(result)
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
return command;
|
|
38
|
-
}
|
|
39
|
-
function createBranchUseCommand(runtime) {
|
|
40
|
-
const command = attachCommandDescriptor(configureRuntimeCommand(new Command("use"), runtime), "branch.use");
|
|
41
|
-
command.argument("[name]", "Branch name");
|
|
42
|
-
addGlobalFlags(command);
|
|
43
|
-
command.action(async (branchName, options) => {
|
|
44
|
-
await runCommand(runtime, "branch.use", options, (context) => runBranchUse(context, branchName), {
|
|
45
|
-
renderHuman: (context, descriptor, result) => renderBranchUse(context, descriptor, result),
|
|
46
|
-
renderJson: (result) => serializeBranchShow(result)
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
return command;
|
|
50
|
-
}
|
|
51
26
|
//#endregion
|
|
52
27
|
export { createBranchCommand };
|