@kingslanding/cli 0.1.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/README.md +157 -0
- package/dist/commands/deploy-key.d.ts +3 -0
- package/dist/commands/deploy-key.d.ts.map +1 -0
- package/dist/commands/deploy-key.js +113 -0
- package/dist/commands/deploy-key.js.map +1 -0
- package/dist/commands/deploy.d.ts +3 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +139 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +63 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +65 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +3 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +22 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/projects.d.ts +3 -0
- package/dist/commands/projects.d.ts.map +1 -0
- package/dist/commands/projects.js +39 -0
- package/dist/commands/projects.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +24 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +104 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +118 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/auth.d.ts +15 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +81 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/config.d.ts +13 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +66 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/errors.d.ts +16 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +34 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/files.d.ts +11 -0
- package/dist/lib/files.d.ts.map +1 -0
- package/dist/lib/files.js +60 -0
- package/dist/lib/files.js.map +1 -0
- package/dist/lib/ignore.d.ts +3 -0
- package/dist/lib/ignore.d.ts.map +1 -0
- package/dist/lib/ignore.js +20 -0
- package/dist/lib/ignore.js.map +1 -0
- package/dist/lib/output.d.ts +5 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +15 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/services/auth-service.d.ts +15 -0
- package/dist/services/auth-service.d.ts.map +1 -0
- package/dist/services/auth-service.js +65 -0
- package/dist/services/auth-service.js.map +1 -0
- package/dist/services/deploy-key-service.d.ts +9 -0
- package/dist/services/deploy-key-service.d.ts.map +1 -0
- package/dist/services/deploy-key-service.js +16 -0
- package/dist/services/deploy-key-service.js.map +1 -0
- package/dist/services/deploy-service.d.ts +19 -0
- package/dist/services/deploy-service.d.ts.map +1 -0
- package/dist/services/deploy-service.js +68 -0
- package/dist/services/deploy-service.js.map +1 -0
- package/dist/services/project-service.d.ts +10 -0
- package/dist/services/project-service.d.ts.map +1 -0
- package/dist/services/project-service.js +29 -0
- package/dist/services/project-service.js.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# kl — King's Landing CLI
|
|
2
|
+
|
|
3
|
+
Deploy static sites to [King's Landing](https://kingslanding.io) from any terminal or CI/CD pipeline.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @kingslanding/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run without installing:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @kingslanding/cli deploy ./dist
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with Docker (no Node.js required):
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
docker run --rm -v $(pwd):/app -w /app ghcr.io/boxshopio/kl deploy ./dist
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Requirements:** Node.js >= 18 (npm install), or Docker.
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
# Authenticate
|
|
29
|
+
kl login
|
|
30
|
+
|
|
31
|
+
# Initialize a project config
|
|
32
|
+
kl init
|
|
33
|
+
|
|
34
|
+
# Deploy
|
|
35
|
+
kl deploy ./dist
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
| Command | Description |
|
|
41
|
+
|---------|-------------|
|
|
42
|
+
| `kl login` | Authenticate via browser |
|
|
43
|
+
| `kl logout` | Clear credentials |
|
|
44
|
+
| `kl init` | Create `kl.json` project config |
|
|
45
|
+
| `kl deploy [dir]` | Deploy a directory (default: `.`) |
|
|
46
|
+
| `kl projects` | List your projects |
|
|
47
|
+
| `kl whoami` | Show current user |
|
|
48
|
+
| `kl deploy-key create` | Generate a deploy key for CI/CD |
|
|
49
|
+
| `kl deploy-key status` | Check if a deploy key exists |
|
|
50
|
+
| `kl deploy-key revoke` | Revoke a deploy key |
|
|
51
|
+
|
|
52
|
+
## Deploy
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# Deploy current directory
|
|
56
|
+
kl deploy
|
|
57
|
+
|
|
58
|
+
# Deploy a specific directory
|
|
59
|
+
kl deploy ./dist
|
|
60
|
+
|
|
61
|
+
# Deploy with a project name (skips kl.json)
|
|
62
|
+
kl deploy ./dist --project my-site
|
|
63
|
+
|
|
64
|
+
# Auto-create project if it doesn't exist (for CI)
|
|
65
|
+
kl deploy ./dist --project my-site --create
|
|
66
|
+
|
|
67
|
+
# Detailed output
|
|
68
|
+
kl deploy ./dist --verbose
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Project config
|
|
72
|
+
|
|
73
|
+
Run `kl init` to create a `kl.json` in your project root:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"project": "my-site",
|
|
78
|
+
"directory": "dist",
|
|
79
|
+
"team": null
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| Field | Description | Default |
|
|
84
|
+
|-------|-------------|---------|
|
|
85
|
+
| `project` | Project name on King's Landing | *required* |
|
|
86
|
+
| `directory` | Directory to deploy | `.` |
|
|
87
|
+
| `team` | Team slug (for team-owned projects) | `null` |
|
|
88
|
+
|
|
89
|
+
## CI/CD
|
|
90
|
+
|
|
91
|
+
### GitHub Actions
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
name: Deploy
|
|
95
|
+
on:
|
|
96
|
+
push:
|
|
97
|
+
branches: [main]
|
|
98
|
+
|
|
99
|
+
jobs:
|
|
100
|
+
deploy:
|
|
101
|
+
runs-on: ubuntu-latest
|
|
102
|
+
steps:
|
|
103
|
+
- uses: actions/checkout@v4
|
|
104
|
+
- run: npx @kingslanding/cli deploy ./dist --project my-site --create
|
|
105
|
+
env:
|
|
106
|
+
KL_DEPLOY_KEY: ${{ secrets.KL_DEPLOY_KEY }}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Generate a deploy key
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
kl deploy-key create --project my-site
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The key is shown once. Add it as `KL_DEPLOY_KEY` in your CI secrets.
|
|
116
|
+
|
|
117
|
+
### Any CI provider
|
|
118
|
+
|
|
119
|
+
The CLI detects `KL_DEPLOY_KEY` automatically. No `kl login` needed.
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
export KL_DEPLOY_KEY=kl_your_key_here
|
|
123
|
+
npx @kingslanding/cli deploy ./dist --project my-site --create
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## File filtering
|
|
127
|
+
|
|
128
|
+
Create a `.klignore` file (gitignore syntax) to control which files are deployed:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
node_modules
|
|
132
|
+
.git
|
|
133
|
+
.env*
|
|
134
|
+
.DS_Store
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
If no `.klignore` exists, these defaults apply automatically.
|
|
138
|
+
|
|
139
|
+
## Docker usage
|
|
140
|
+
|
|
141
|
+
For environments without Node.js:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Deploy
|
|
145
|
+
docker run --rm -v $(pwd):/app -w /app ghcr.io/boxshopio/kl deploy ./dist --project my-site --create
|
|
146
|
+
|
|
147
|
+
# With deploy key
|
|
148
|
+
docker run --rm -e KL_DEPLOY_KEY=$KL_DEPLOY_KEY -v $(pwd):/app -w /app ghcr.io/boxshopio/kl deploy ./dist
|
|
149
|
+
|
|
150
|
+
# Shell alias for convenience
|
|
151
|
+
alias kl='docker run --rm -e KL_DEPLOY_KEY -v $(pwd):/app -w /app ghcr.io/boxshopio/kl'
|
|
152
|
+
kl deploy ./dist
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
Proprietary. See [kingslanding.io](https://kingslanding.io) for terms.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-key.d.ts","sourceRoot":"","sources":["../../src/commands/deploy-key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBzC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsH/D"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { confirm } from "@inquirer/prompts";
|
|
2
|
+
import { ApiClient } from "../lib/api.js";
|
|
3
|
+
import { resolveApiUrl, loadProjectConfig } from "../lib/config.js";
|
|
4
|
+
import { getAuthHeader } from "../lib/auth.js";
|
|
5
|
+
import { CLIError, AuthError } from "../lib/errors.js";
|
|
6
|
+
import { DeployKeyService } from "../services/deploy-key-service.js";
|
|
7
|
+
import { ProjectService } from "../services/project-service.js";
|
|
8
|
+
function resolveProjectAndTeam(options) {
|
|
9
|
+
const config = loadProjectConfig(process.cwd());
|
|
10
|
+
const projectName = options.project ?? config?.project;
|
|
11
|
+
if (!projectName) {
|
|
12
|
+
throw new CLIError("No project name. Use --project <name> or run `kl init`.");
|
|
13
|
+
}
|
|
14
|
+
const teamSlug = options.team ?? config?.team ?? undefined;
|
|
15
|
+
return { projectName, teamSlug };
|
|
16
|
+
}
|
|
17
|
+
export function registerDeployKeyCommand(program) {
|
|
18
|
+
const cmd = program
|
|
19
|
+
.command("deploy-key")
|
|
20
|
+
.description("Manage deploy keys for CI/CD");
|
|
21
|
+
cmd
|
|
22
|
+
.command("create")
|
|
23
|
+
.description("Create a deploy key for a project")
|
|
24
|
+
.option("-p, --project <name>", "Project name")
|
|
25
|
+
.option("-t, --team <slug>", "Team slug")
|
|
26
|
+
.action(async (options) => {
|
|
27
|
+
const apiUrl = resolveApiUrl();
|
|
28
|
+
const authHeader = getAuthHeader(apiUrl);
|
|
29
|
+
if (!authHeader) {
|
|
30
|
+
throw new AuthError("Not logged in. Run `kl login` first.");
|
|
31
|
+
}
|
|
32
|
+
const { projectName, teamSlug } = resolveProjectAndTeam(options);
|
|
33
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
34
|
+
let teamId;
|
|
35
|
+
if (teamSlug) {
|
|
36
|
+
const projectService = new ProjectService(api);
|
|
37
|
+
teamId = await projectService.resolveTeamId(teamSlug);
|
|
38
|
+
}
|
|
39
|
+
const deployKeyService = new DeployKeyService(api);
|
|
40
|
+
const result = await deployKeyService.create(projectName, teamId);
|
|
41
|
+
console.log();
|
|
42
|
+
console.log("Deploy key created for " + projectName + ":");
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(" " + result.key);
|
|
45
|
+
console.log();
|
|
46
|
+
console.log("Save this key now — it will not be shown again.");
|
|
47
|
+
console.log("Set it as KL_DEPLOY_KEY in your CI/CD environment.");
|
|
48
|
+
});
|
|
49
|
+
cmd
|
|
50
|
+
.command("revoke")
|
|
51
|
+
.description("Revoke the deploy key for a project")
|
|
52
|
+
.option("-p, --project <name>", "Project name")
|
|
53
|
+
.option("-t, --team <slug>", "Team slug")
|
|
54
|
+
.action(async (options) => {
|
|
55
|
+
const apiUrl = resolveApiUrl();
|
|
56
|
+
const authHeader = getAuthHeader(apiUrl);
|
|
57
|
+
if (!authHeader) {
|
|
58
|
+
throw new AuthError("Not logged in. Run `kl login` first.");
|
|
59
|
+
}
|
|
60
|
+
const { projectName, teamSlug } = resolveProjectAndTeam(options);
|
|
61
|
+
const shouldRevoke = await confirm({
|
|
62
|
+
message: "Revoke the deploy key for " +
|
|
63
|
+
projectName +
|
|
64
|
+
"? This cannot be undone.",
|
|
65
|
+
default: false,
|
|
66
|
+
});
|
|
67
|
+
if (!shouldRevoke) {
|
|
68
|
+
console.log("Cancelled.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
72
|
+
let teamId;
|
|
73
|
+
if (teamSlug) {
|
|
74
|
+
const projectService = new ProjectService(api);
|
|
75
|
+
teamId = await projectService.resolveTeamId(teamSlug);
|
|
76
|
+
}
|
|
77
|
+
const deployKeyService = new DeployKeyService(api);
|
|
78
|
+
await deployKeyService.revoke(projectName, teamId);
|
|
79
|
+
console.log("Deploy key revoked for " + projectName + ".");
|
|
80
|
+
});
|
|
81
|
+
cmd
|
|
82
|
+
.command("status")
|
|
83
|
+
.description("Check deploy key status for a project")
|
|
84
|
+
.option("-p, --project <name>", "Project name")
|
|
85
|
+
.option("-t, --team <slug>", "Team slug")
|
|
86
|
+
.action(async (options) => {
|
|
87
|
+
const apiUrl = resolveApiUrl();
|
|
88
|
+
const authHeader = getAuthHeader(apiUrl);
|
|
89
|
+
if (!authHeader) {
|
|
90
|
+
throw new AuthError("Not logged in. Run `kl login` first.");
|
|
91
|
+
}
|
|
92
|
+
const { projectName, teamSlug } = resolveProjectAndTeam(options);
|
|
93
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
94
|
+
let teamId;
|
|
95
|
+
if (teamSlug) {
|
|
96
|
+
const projectService = new ProjectService(api);
|
|
97
|
+
teamId = await projectService.resolveTeamId(teamSlug);
|
|
98
|
+
}
|
|
99
|
+
const deployKeyService = new DeployKeyService(api);
|
|
100
|
+
const result = await deployKeyService.status(projectName, teamId);
|
|
101
|
+
if (result.exists) {
|
|
102
|
+
console.log("Deploy key active for " + projectName);
|
|
103
|
+
console.log(" Prefix: " + result.key_prefix);
|
|
104
|
+
if (result.created_at) {
|
|
105
|
+
console.log(" Created: " + new Date(result.created_at * 1000).toISOString());
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
console.log("No deploy key configured for " + projectName + ".");
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=deploy-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-key.js","sourceRoot":"","sources":["../../src/commands/deploy-key.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+J5D"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { confirm } from "@inquirer/prompts";
|
|
3
|
+
import { ApiClient } from "../lib/api.js";
|
|
4
|
+
import { resolveApiUrl, loadProjectConfig } from "../lib/config.js";
|
|
5
|
+
import { getAuthHeader, loadCredentials, isDeployKeyAuth } from "../lib/auth.js";
|
|
6
|
+
import { buildFileManifest } from "../lib/files.js";
|
|
7
|
+
import { createSpinner, formatBytes } from "../lib/output.js";
|
|
8
|
+
import { CLIError, ApiError, AuthError } from "../lib/errors.js";
|
|
9
|
+
import { AuthService } from "../services/auth-service.js";
|
|
10
|
+
import { DeployService, defaultReadFile } from "../services/deploy-service.js";
|
|
11
|
+
import { ProjectService } from "../services/project-service.js";
|
|
12
|
+
export function registerDeployCommand(program) {
|
|
13
|
+
program
|
|
14
|
+
.command("deploy")
|
|
15
|
+
.description("Deploy a directory to King's Landing")
|
|
16
|
+
.argument("[dir]", "Directory to deploy")
|
|
17
|
+
.option("-p, --project <name>", "Project name")
|
|
18
|
+
.option("-t, --team <slug>", "Team slug")
|
|
19
|
+
.option("--create", "Create project if it does not exist")
|
|
20
|
+
.option("-v, --verbose", "Show detailed output")
|
|
21
|
+
.action(async (dirArg, options) => {
|
|
22
|
+
const cwd = process.cwd();
|
|
23
|
+
const config = loadProjectConfig(cwd);
|
|
24
|
+
const apiUrl = resolveApiUrl(cwd);
|
|
25
|
+
// Resolve project name
|
|
26
|
+
const projectName = options.project ?? config?.project;
|
|
27
|
+
if (!projectName) {
|
|
28
|
+
throw new CLIError("No project name. Use --project <name> or run `kl init`.");
|
|
29
|
+
}
|
|
30
|
+
// Resolve deploy directory
|
|
31
|
+
const relativeDir = dirArg ?? config?.directory ?? ".";
|
|
32
|
+
const deployDir = path.resolve(cwd, relativeDir);
|
|
33
|
+
// Resolve team
|
|
34
|
+
let teamId;
|
|
35
|
+
const teamSlug = options.team ?? config?.team;
|
|
36
|
+
// Ensure auth
|
|
37
|
+
let authHeader = getAuthHeader(apiUrl);
|
|
38
|
+
if (!authHeader) {
|
|
39
|
+
throw new AuthError("Not logged in. Run `kl login` first.");
|
|
40
|
+
}
|
|
41
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
42
|
+
// Refresh token if needed (JWT only, not deploy keys)
|
|
43
|
+
if (!isDeployKeyAuth()) {
|
|
44
|
+
const creds = loadCredentials(apiUrl);
|
|
45
|
+
if (creds) {
|
|
46
|
+
const authService = new AuthService(api, apiUrl);
|
|
47
|
+
await authService.refreshIfNeeded(creds);
|
|
48
|
+
// Re-read auth header after potential refresh
|
|
49
|
+
authHeader = getAuthHeader(apiUrl);
|
|
50
|
+
if (authHeader) {
|
|
51
|
+
api.updateAuthHeader(authHeader);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Resolve team slug to ID
|
|
56
|
+
if (teamSlug) {
|
|
57
|
+
const projectService = new ProjectService(api);
|
|
58
|
+
teamId = await projectService.resolveTeamId(teamSlug);
|
|
59
|
+
}
|
|
60
|
+
// Build manifest
|
|
61
|
+
const files = buildFileManifest(deployDir, cwd);
|
|
62
|
+
if (options.verbose) {
|
|
63
|
+
console.log("Deploying " +
|
|
64
|
+
files.length +
|
|
65
|
+
" files (" +
|
|
66
|
+
formatBytes(files.reduce((sum, f) => sum + f.size, 0)) +
|
|
67
|
+
") from " +
|
|
68
|
+
deployDir);
|
|
69
|
+
}
|
|
70
|
+
const deployService = new DeployService(api);
|
|
71
|
+
const spinner = createSpinner("Deploying...");
|
|
72
|
+
spinner.start();
|
|
73
|
+
const startTime = Date.now();
|
|
74
|
+
const runDeploy = async (create) => {
|
|
75
|
+
return deployService.deploy({
|
|
76
|
+
projectName,
|
|
77
|
+
files,
|
|
78
|
+
readFile: defaultReadFile,
|
|
79
|
+
onProgress: (completed, total) => {
|
|
80
|
+
spinner.text = "Uploading " + completed + "/" + total + " files...";
|
|
81
|
+
},
|
|
82
|
+
create,
|
|
83
|
+
teamId,
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
try {
|
|
87
|
+
let result;
|
|
88
|
+
try {
|
|
89
|
+
result = await runDeploy(options.create);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
if (err instanceof ApiError &&
|
|
93
|
+
err.status === 404 &&
|
|
94
|
+
!options.create) {
|
|
95
|
+
spinner.stop();
|
|
96
|
+
const isTTY = process.stdout.isTTY;
|
|
97
|
+
if (isTTY) {
|
|
98
|
+
const shouldCreate = await confirm({
|
|
99
|
+
message: 'Project "' +
|
|
100
|
+
projectName +
|
|
101
|
+
'" does not exist. Create it?',
|
|
102
|
+
default: true,
|
|
103
|
+
});
|
|
104
|
+
if (!shouldCreate) {
|
|
105
|
+
throw new CLIError("Deploy cancelled.");
|
|
106
|
+
}
|
|
107
|
+
spinner.start();
|
|
108
|
+
result = await runDeploy(true);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
throw new CLIError('Project "' +
|
|
112
|
+
projectName +
|
|
113
|
+
'" not found. Use --create to create it.');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
throw err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
spinner.stop();
|
|
121
|
+
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
122
|
+
if (options.verbose) {
|
|
123
|
+
console.log("Deployed " +
|
|
124
|
+
result.files +
|
|
125
|
+
" files (" +
|
|
126
|
+
formatBytes(result.total_size) +
|
|
127
|
+
") in " +
|
|
128
|
+
elapsed +
|
|
129
|
+
"s");
|
|
130
|
+
}
|
|
131
|
+
console.log("Done. " + result.url);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
spinner.stop();
|
|
135
|
+
throw err;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=deploy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,sCAAsC,CAAC;SACnD,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC;SACxC,MAAM,CAAC,sBAAsB,EAAE,cAAc,CAAC;SAC9C,MAAM,CAAC,mBAAmB,EAAE,WAAW,CAAC;SACxC,MAAM,CAAC,UAAU,EAAE,qCAAqC,CAAC;SACzD,MAAM,CAAC,eAAe,EAAE,sBAAsB,CAAC;SAC/C,MAAM,CACL,KAAK,EACH,MAA0B,EAC1B,OAKC,EACD,EAAE;QACF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAElC,uBAAuB;QACvB,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,EAAE,OAAO,CAAC;QACvD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,QAAQ,CAChB,yDAAyD,CAC1D,CAAC;QACJ,CAAC;QAED,2BAA2B;QAC3B,MAAM,WAAW,GAAG,MAAM,IAAI,MAAM,EAAE,SAAS,IAAI,GAAG,CAAC;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAEjD,eAAe;QACf,IAAI,MAA0B,CAAC;QAC/B,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM,EAAE,IAAI,CAAC;QAE9C,cAAc;QACd,IAAI,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,SAAS,CAAC,sCAAsC,CAAC,CAAC;QAC9D,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAE9C,sDAAsD;QACtD,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;YACtC,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;gBACjD,MAAM,WAAW,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;gBACzC,8CAA8C;gBAC9C,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;gBACnC,IAAI,UAAU,EAAE,CAAC;oBACf,GAAG,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;YAC/C,MAAM,GAAG,MAAM,cAAc,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACxD,CAAC;QAED,iBAAiB;QACjB,MAAM,KAAK,GAAG,iBAAiB,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CACT,YAAY;gBACV,KAAK,CAAC,MAAM;gBACZ,UAAU;gBACV,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;gBACtD,SAAS;gBACT,SAAS,CACZ,CAAC;QACJ,CAAC;QAED,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;QAC9C,OAAO,CAAC,KAAK,EAAE,CAAC;QAEhB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,MAAM,SAAS,GAAG,KAAK,EAAE,MAAgB,EAAE,EAAE;YAC3C,OAAO,aAAa,CAAC,MAAM,CAAC;gBAC1B,WAAW;gBACX,KAAK;gBACL,QAAQ,EAAE,eAAe;gBACzB,UAAU,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;oBAC/B,OAAO,CAAC,IAAI,GAAG,YAAY,GAAG,SAAS,GAAG,GAAG,GAAG,KAAK,GAAG,WAAW,CAAC;gBACtE,CAAC;gBACD,MAAM;gBACN,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC;YACH,IAAI,MAAM,CAAC;YACX,IAAI,CAAC;gBACH,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IACE,GAAG,YAAY,QAAQ;oBACvB,GAAG,CAAC,MAAM,KAAK,GAAG;oBAClB,CAAC,OAAO,CAAC,MAAM,EACf,CAAC;oBACD,OAAO,CAAC,IAAI,EAAE,CAAC;oBAEf,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;oBACnC,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC;4BACjC,OAAO,EACL,WAAW;gCACX,WAAW;gCACX,8BAA8B;4BAChC,OAAO,EAAE,IAAI;yBACd,CAAC,CAAC;wBACH,IAAI,CAAC,YAAY,EAAE,CAAC;4BAClB,MAAM,IAAI,QAAQ,CAAC,mBAAmB,CAAC,CAAC;wBAC1C,CAAC;wBACD,OAAO,CAAC,KAAK,EAAE,CAAC;wBAChB,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;oBACjC,CAAC;yBAAM,CAAC;wBACN,MAAM,IAAI,QAAQ,CAChB,WAAW;4BACT,WAAW;4BACX,yCAAyC,CAC5C,CAAC;oBACJ,CAAC;gBACH,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,CAAC;gBACZ,CAAC;YACH,CAAC;YAED,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAE7D,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CACT,WAAW;oBACT,MAAM,CAAC,KAAK;oBACZ,UAAU;oBACV,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;oBAC9B,OAAO;oBACP,OAAO;oBACP,GAAG,CACN,CAAC;YACJ,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,EAAE,CAAC;YACf,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAczC,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA6D1D"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { input, select } from "@inquirer/prompts";
|
|
2
|
+
import { ApiClient } from "../lib/api.js";
|
|
3
|
+
import { resolveApiUrl, loadProjectConfig, writeProjectConfig, } from "../lib/config.js";
|
|
4
|
+
import { getAuthHeader } from "../lib/auth.js";
|
|
5
|
+
import { CLIError } from "../lib/errors.js";
|
|
6
|
+
import { ProjectService } from "../services/project-service.js";
|
|
7
|
+
const PROJECT_NAME_REGEX = /^[a-z0-9][a-z0-9-]{2,61}[a-z0-9]$/;
|
|
8
|
+
export function registerInitCommand(program) {
|
|
9
|
+
program
|
|
10
|
+
.command("init")
|
|
11
|
+
.description("Create a kl.json config in the current directory")
|
|
12
|
+
.action(async () => {
|
|
13
|
+
const cwd = process.cwd();
|
|
14
|
+
const existing = loadProjectConfig(cwd);
|
|
15
|
+
if (existing) {
|
|
16
|
+
throw new CLIError("kl.json already exists in this directory. Delete it first to re-initialize.");
|
|
17
|
+
}
|
|
18
|
+
const project = await input({
|
|
19
|
+
message: "Project name",
|
|
20
|
+
validate: (value) => {
|
|
21
|
+
if (!PROJECT_NAME_REGEX.test(value)) {
|
|
22
|
+
return "Must be 4-63 characters, lowercase alphanumeric and hyphens, start/end with alphanumeric.";
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
const directory = await input({
|
|
28
|
+
message: "Deploy directory",
|
|
29
|
+
default: ".",
|
|
30
|
+
});
|
|
31
|
+
let team = null;
|
|
32
|
+
const apiUrl = resolveApiUrl(cwd);
|
|
33
|
+
const authHeader = getAuthHeader(apiUrl);
|
|
34
|
+
if (authHeader) {
|
|
35
|
+
try {
|
|
36
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
37
|
+
const projectService = new ProjectService(api);
|
|
38
|
+
const teams = await projectService.getUserTeams();
|
|
39
|
+
if (teams.length > 0) {
|
|
40
|
+
const choices = [
|
|
41
|
+
{ name: "Personal (no team)", value: "" },
|
|
42
|
+
...teams.map((t) => ({
|
|
43
|
+
name: t.team.name + " (" + t.team.slug + ")",
|
|
44
|
+
value: t.team.slug,
|
|
45
|
+
})),
|
|
46
|
+
];
|
|
47
|
+
const selected = await select({
|
|
48
|
+
message: "Team",
|
|
49
|
+
choices,
|
|
50
|
+
});
|
|
51
|
+
if (selected)
|
|
52
|
+
team = selected;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// If we can't fetch teams (not logged in, etc.), skip the prompt
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
writeProjectConfig(cwd, { project, directory, team });
|
|
60
|
+
console.log("Created kl.json");
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAEhE,MAAM,kBAAkB,GAAG,mCAAmC,CAAC;AAE/D,MAAM,UAAU,mBAAmB,CAAC,OAAgB;IAClD,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,IAAI,QAAQ,CAChB,6EAA6E,CAC9E,CAAC;QACJ,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC;YAC1B,OAAO,EAAE,cAAc;YACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBAClB,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACpC,OAAO,2FAA2F,CAAC;gBACrG,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;SACF,CAAC,CAAC;QAEH,MAAM,SAAS,GAAG,MAAM,KAAK,CAAC;YAC5B,OAAO,EAAE,kBAAkB;YAC3B,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QAEH,IAAI,IAAI,GAAkB,IAAI,CAAC;QAE/B,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;gBAC9C,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;gBAC/C,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,YAAY,EAAE,CAAC;gBAElD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,MAAM,OAAO,GAAG;wBACd,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,EAAE,EAAE;wBACzC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BACnB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,GAAG;4BAC5C,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI;yBACnB,CAAC,CAAC;qBACJ,CAAC;oBAEF,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC;wBAC5B,OAAO,EAAE,MAAM;wBACf,OAAO;qBACR,CAAC,CAAC;oBACH,IAAI,QAAQ;wBAAE,IAAI,GAAG,QAAQ,CAAC;gBAChC,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,iEAAiE;YACnE,CAAC;QACH,CAAC;QAED,kBAAkB,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAyD3D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { ApiClient } from "../lib/api.js";
|
|
3
|
+
import { resolveApiUrl, isLocalMode } from "../lib/config.js";
|
|
4
|
+
import { getAuthHeader, loadCredentials, isTokenExpiringSoon, } from "../lib/auth.js";
|
|
5
|
+
import { createSpinner } from "../lib/output.js";
|
|
6
|
+
import { AuthService } from "../services/auth-service.js";
|
|
7
|
+
function tryOpenBrowser(url) {
|
|
8
|
+
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
|
9
|
+
exec(`${cmd} ${JSON.stringify(url)}`, () => {
|
|
10
|
+
// Silent failure — user can copy/paste the URL
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export function registerLoginCommand(program) {
|
|
14
|
+
program
|
|
15
|
+
.command("login")
|
|
16
|
+
.description("Authenticate with King's Landing")
|
|
17
|
+
.action(async () => {
|
|
18
|
+
const apiUrl = resolveApiUrl();
|
|
19
|
+
if (isLocalMode(apiUrl)) {
|
|
20
|
+
console.log("Local mode — no login required.");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const creds = loadCredentials(apiUrl);
|
|
24
|
+
if (creds && !isTokenExpiringSoon(creds)) {
|
|
25
|
+
const api = new ApiClient(apiUrl, "Bearer " + creds.access_token);
|
|
26
|
+
try {
|
|
27
|
+
const account = await api.getAccount();
|
|
28
|
+
console.log("Already logged in as " + account.email);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Token invalid — proceed with login
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const authHeader = getAuthHeader(apiUrl);
|
|
36
|
+
const api = new ApiClient(apiUrl, authHeader);
|
|
37
|
+
const authService = new AuthService(api, apiUrl);
|
|
38
|
+
const spinner = createSpinner("Waiting for browser authorization...");
|
|
39
|
+
await authService.login((userCode, verificationUrl) => {
|
|
40
|
+
console.log();
|
|
41
|
+
console.log("Open this URL in your browser:");
|
|
42
|
+
console.log(" " + verificationUrl);
|
|
43
|
+
console.log();
|
|
44
|
+
console.log("Enter code: " + userCode);
|
|
45
|
+
console.log();
|
|
46
|
+
tryOpenBrowser(verificationUrl);
|
|
47
|
+
spinner.start();
|
|
48
|
+
});
|
|
49
|
+
spinner.stop();
|
|
50
|
+
const newCreds = loadCredentials(apiUrl);
|
|
51
|
+
if (!newCreds) {
|
|
52
|
+
console.log("Logged in.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
api.updateAuthHeader("Bearer " + newCreds.access_token);
|
|
56
|
+
try {
|
|
57
|
+
const account = await api.getAccount();
|
|
58
|
+
console.log("Logged in as " + account.email);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
console.log("Logged in.");
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAkB5D"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ApiClient } from "../lib/api.js";
|
|
2
|
+
import { resolveApiUrl } from "../lib/config.js";
|
|
3
|
+
import { loadCredentials } from "../lib/auth.js";
|
|
4
|
+
import { AuthService } from "../services/auth-service.js";
|
|
5
|
+
export function registerLogoutCommand(program) {
|
|
6
|
+
program
|
|
7
|
+
.command("logout")
|
|
8
|
+
.description("Clear stored credentials")
|
|
9
|
+
.action(async () => {
|
|
10
|
+
const apiUrl = resolveApiUrl();
|
|
11
|
+
const creds = loadCredentials(apiUrl);
|
|
12
|
+
if (!creds) {
|
|
13
|
+
console.log("Not logged in.");
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const api = new ApiClient(apiUrl, "Bearer " + creds.access_token);
|
|
17
|
+
const authService = new AuthService(api, apiUrl);
|
|
18
|
+
await authService.logout(creds.refresh_token);
|
|
19
|
+
console.log("Logged out.");
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAE1D,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,0BAA0B,CAAC;SACvC,MAAM,CAAC,KAAK,IAAI,EAAE;QACjB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAEtC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC9B,OAAO;QACT,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC;QAClE,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACjD,MAAM,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/commands/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0C9D"}
|