@otakit/cli 1.0.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/LICENSE +21 -0
- package/README.md +145 -0
- package/bin/otakit.js +3 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +115 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/delete.d.ts +3 -0
- package/dist/commands/delete.d.ts.map +1 -0
- package/dist/commands/delete.js +30 -0
- package/dist/commands/delete.js.map +1 -0
- package/dist/commands/generate-signing-key.d.ts +3 -0
- package/dist/commands/generate-signing-key.d.ts.map +1 -0
- package/dist/commands/generate-signing-key.js +41 -0
- package/dist/commands/generate-signing-key.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +30 -0
- package/dist/commands/list.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 +79 -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 +25 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/register.d.ts +3 -0
- package/dist/commands/register.d.ts.map +1 -0
- package/dist/commands/register.js +77 -0
- package/dist/commands/register.js.map +1 -0
- package/dist/commands/release.d.ts +3 -0
- package/dist/commands/release.d.ts.map +1 -0
- package/dist/commands/release.js +40 -0
- package/dist/commands/release.js.map +1 -0
- package/dist/commands/releases.d.ts +3 -0
- package/dist/commands/releases.d.ts.map +1 -0
- package/dist/commands/releases.js +49 -0
- package/dist/commands/releases.js.map +1 -0
- package/dist/commands/upload.d.ts +3 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +76 -0
- package/dist/commands/upload.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 +43 -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 +32 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +61 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +102 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/capacitor-config.d.ts +11 -0
- package/dist/lib/capacitor-config.d.ts.map +1 -0
- package/dist/lib/capacitor-config.js +105 -0
- package/dist/lib/capacitor-config.js.map +1 -0
- package/dist/lib/config.d.ts +60 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +253 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/errors.d.ts +6 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +19 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/hash.d.ts +9 -0
- package/dist/lib/hash.d.ts.map +1 -0
- package/dist/lib/hash.js +21 -0
- package/dist/lib/hash.js.map +1 -0
- package/dist/lib/http.d.ts +9 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +43 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/prompt.d.ts +3 -0
- package/dist/lib/prompt.d.ts.map +1 -0
- package/dist/lib/prompt.js +23 -0
- package/dist/lib/prompt.js.map +1 -0
- package/dist/lib/token-store.d.ts +12 -0
- package/dist/lib/token-store.d.ts.map +1 -0
- package/dist/lib/token-store.js +151 -0
- package/dist/lib/token-store.js.map +1 -0
- package/dist/lib/upload-workflow.d.ts +27 -0
- package/dist/lib/upload-workflow.d.ts.map +1 -0
- package/dist/lib/upload-workflow.js +252 -0
- package/dist/lib/upload-workflow.js.map +1 -0
- package/dist/lib/validate.d.ts +3 -0
- package/dist/lib/validate.d.ts.map +1 -0
- package/dist/lib/validate.js +16 -0
- package/dist/lib/validate.js.map +1 -0
- package/dist/lib/version.d.ts +4 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +24 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/zip.d.ts +8 -0
- package/dist/lib/zip.d.ts.map +1 -0
- package/dist/lib/zip.js +78 -0
- package/dist/lib/zip.js.map +1 -0
- package/package.json +63 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 OtaKit
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @otakit/cli
|
|
2
|
+
|
|
3
|
+
Upload and release CLI for OtaKit.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
- reads project config from `capacitor.config.*`
|
|
8
|
+
- authenticates with login or env tokens
|
|
9
|
+
- zips the build output
|
|
10
|
+
- computes the bundle SHA-256 checksum
|
|
11
|
+
- creates an upload session
|
|
12
|
+
- uploads the zip directly to object storage
|
|
13
|
+
- finalizes the bundle
|
|
14
|
+
- optionally releases it to the unnamed channel or a named channel
|
|
15
|
+
|
|
16
|
+
The normal hosted flow is dashboard-first. Create the app in the dashboard,
|
|
17
|
+
paste its `appId` into `plugins.OtaKit.appId`, then ship:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
otakit login
|
|
21
|
+
npm run build
|
|
22
|
+
otakit upload --release
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If you want to create the app from the CLI instead:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
otakit register --slug com.example.app
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
There is no `otakit init`.
|
|
32
|
+
|
|
33
|
+
## Config model
|
|
34
|
+
|
|
35
|
+
The CLI reads these files when present:
|
|
36
|
+
|
|
37
|
+
- `capacitor.config.ts`
|
|
38
|
+
- `capacitor.config.js`
|
|
39
|
+
- `capacitor.config.mjs`
|
|
40
|
+
- `capacitor.config.cjs`
|
|
41
|
+
- `capacitor.config.json`
|
|
42
|
+
|
|
43
|
+
Important values:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
webDir: "out",
|
|
47
|
+
plugins: {
|
|
48
|
+
OtaKit: {
|
|
49
|
+
appId: "app_xxxxxxxx",
|
|
50
|
+
// Optional:
|
|
51
|
+
// channel: "staging",
|
|
52
|
+
// serverUrl: "https://your-server.com/api/v1"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Resolution order:
|
|
58
|
+
|
|
59
|
+
1. CLI flags
|
|
60
|
+
2. environment variables
|
|
61
|
+
3. `capacitor.config.*`
|
|
62
|
+
4. built-in defaults
|
|
63
|
+
|
|
64
|
+
Main rules:
|
|
65
|
+
|
|
66
|
+
1. `appId`: `--app-id` -> `OTAKIT_APP_ID` -> `plugins.OtaKit.appId`
|
|
67
|
+
2. `serverUrl`: `--server` -> `OTAKIT_SERVER_URL` -> `plugins.OtaKit.serverUrl` -> `https://otakit.app/api/v1`
|
|
68
|
+
3. `outputDir`: upload path arg -> `OTAKIT_BUILD_DIR` / `OTAKIT_OUTPUT_DIR` -> `webDir`
|
|
69
|
+
4. release channel: `--release` -> unnamed channel, `--release <channel>` -> named channel
|
|
70
|
+
|
|
71
|
+
Auth precedence:
|
|
72
|
+
|
|
73
|
+
1. `OTAKIT_TOKEN`
|
|
74
|
+
2. `OTAKIT_ACCESS_TOKEN`
|
|
75
|
+
3. stored token from `otakit login`
|
|
76
|
+
4. `OTAKIT_SECRET_KEY`
|
|
77
|
+
|
|
78
|
+
Version precedence:
|
|
79
|
+
|
|
80
|
+
1. `--version`
|
|
81
|
+
2. `OTAKIT_VERSION`
|
|
82
|
+
3. auto-generated `<base>+otk.<commit>.<run>`
|
|
83
|
+
|
|
84
|
+
## Release model
|
|
85
|
+
|
|
86
|
+
- `otakit upload`
|
|
87
|
+
upload only
|
|
88
|
+
- `otakit upload --release`
|
|
89
|
+
upload and release to the unnamed channel
|
|
90
|
+
- `otakit upload --release staging`
|
|
91
|
+
upload and release to a named channel
|
|
92
|
+
- `otakit release <bundleId> --channel staging`
|
|
93
|
+
promote an existing bundle later
|
|
94
|
+
|
|
95
|
+
Releases are append-only. The newest release for `(appId, channel)` is what
|
|
96
|
+
devices see on manifest checks.
|
|
97
|
+
|
|
98
|
+
## Common commands
|
|
99
|
+
|
|
100
|
+
- `otakit login`
|
|
101
|
+
- `otakit logout`
|
|
102
|
+
- `otakit whoami`
|
|
103
|
+
- `otakit register --slug <slug>`
|
|
104
|
+
- `otakit upload [path] [--release [channel]]`
|
|
105
|
+
- `otakit release [bundleId] [--channel <channel>]`
|
|
106
|
+
- `otakit releases [--channel <channel> | --base]`
|
|
107
|
+
- `otakit list`
|
|
108
|
+
- `otakit delete <bundleId> --force`
|
|
109
|
+
- `otakit config validate`
|
|
110
|
+
- `otakit config resolve --json`
|
|
111
|
+
- `otakit generate-signing-key`
|
|
112
|
+
|
|
113
|
+
## CI
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
export OTAKIT_SECRET_KEY=otakit_sk_...
|
|
117
|
+
export OTAKIT_APP_ID=app_xxxxxxxx
|
|
118
|
+
export OTAKIT_BUILD_DIR=out
|
|
119
|
+
|
|
120
|
+
otakit upload --release
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Set `OTAKIT_SERVER_URL` only for custom or self-hosted servers.
|
|
124
|
+
|
|
125
|
+
## Upload flow
|
|
126
|
+
|
|
127
|
+
1. resolve the build output directory
|
|
128
|
+
2. require `index.html`
|
|
129
|
+
3. zip the output
|
|
130
|
+
4. compute SHA-256 and size
|
|
131
|
+
5. call `bundles/initiate`
|
|
132
|
+
6. upload directly to object storage
|
|
133
|
+
7. call `bundles/finalize`
|
|
134
|
+
8. optionally call `releases`
|
|
135
|
+
|
|
136
|
+
The CLI does not own app creation or channel strategy. It packages the build,
|
|
137
|
+
uploads it, and optionally promotes it.
|
|
138
|
+
|
|
139
|
+
## Build locally
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
pnpm --filter @otakit/cli build
|
|
143
|
+
pnpm --filter @otakit/cli typecheck
|
|
144
|
+
pnpm --filter @otakit/cli dev
|
|
145
|
+
```
|
package/bin/otakit.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmKpC,eAAO,MAAM,aAAa,SAGM,CAAC"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { PROJECT_CONFIG_LABEL, readProjectConfig, resolveConfigSnapshot } from '../lib/config.js';
|
|
3
|
+
import { CliError, runCommand } from '../lib/errors.js';
|
|
4
|
+
function formatMaybe(value) {
|
|
5
|
+
return value ?? '(unset)';
|
|
6
|
+
}
|
|
7
|
+
function formatAuthSource(source) {
|
|
8
|
+
if (!source) {
|
|
9
|
+
return 'none';
|
|
10
|
+
}
|
|
11
|
+
if (source === 'env_access_token') {
|
|
12
|
+
return 'env (OTAKIT_ACCESS_TOKEN)';
|
|
13
|
+
}
|
|
14
|
+
if (source === 'env_secret_key') {
|
|
15
|
+
return 'env (OTAKIT_SECRET_KEY)';
|
|
16
|
+
}
|
|
17
|
+
if (source === 'env_token') {
|
|
18
|
+
return 'env (OTAKIT_TOKEN)';
|
|
19
|
+
}
|
|
20
|
+
return source;
|
|
21
|
+
}
|
|
22
|
+
const resolveSubcommand = new Command('resolve')
|
|
23
|
+
.description('Resolve effective config values and their sources')
|
|
24
|
+
.option('--app-id <id>', 'App ID override')
|
|
25
|
+
.option('--server <url>', 'Server URL override')
|
|
26
|
+
.option('--output-dir <path>', 'Output directory override')
|
|
27
|
+
.option('--channel <channel>', 'Channel override')
|
|
28
|
+
.option('--json', 'Print machine-readable JSON output')
|
|
29
|
+
.action(async (options) => {
|
|
30
|
+
await runCommand(async () => {
|
|
31
|
+
const snapshot = await resolveConfigSnapshot({
|
|
32
|
+
appId: options.appId,
|
|
33
|
+
serverUrl: options.server,
|
|
34
|
+
outputDir: options.outputDir,
|
|
35
|
+
channel: options.channel,
|
|
36
|
+
});
|
|
37
|
+
const jsonPayload = {
|
|
38
|
+
configFile: snapshot.configFile,
|
|
39
|
+
appId: snapshot.appId,
|
|
40
|
+
serverUrl: snapshot.serverUrl,
|
|
41
|
+
outputDir: snapshot.outputDir,
|
|
42
|
+
channel: snapshot.channel,
|
|
43
|
+
auth: {
|
|
44
|
+
present: snapshot.authToken.value !== null,
|
|
45
|
+
source: snapshot.authSource ?? 'none',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
if (options.json) {
|
|
49
|
+
console.log(JSON.stringify(jsonPayload, null, 2));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
console.log(`config file: ${snapshot.configFile.path}`);
|
|
53
|
+
console.log(`config found: ${snapshot.configFile.found ? 'yes' : 'no'}`);
|
|
54
|
+
console.log(`appId: ${formatMaybe(snapshot.appId.value)} (${snapshot.appId.source})`);
|
|
55
|
+
console.log(`serverUrl: ${snapshot.serverUrl.value} (${snapshot.serverUrl.source})`);
|
|
56
|
+
console.log(`outputDir: ${formatMaybe(snapshot.outputDir.value)} (${snapshot.outputDir.source})`);
|
|
57
|
+
console.log(`channel: ${formatMaybe(snapshot.channel.value)} (${snapshot.channel.source})`);
|
|
58
|
+
console.log(`auth token: ${snapshot.authToken.value ? 'present' : 'missing'} (${formatAuthSource(snapshot.authSource)})`);
|
|
59
|
+
if (!snapshot.appId.value) {
|
|
60
|
+
console.log('fix appId: export OTAKIT_APP_ID=<app-id>');
|
|
61
|
+
}
|
|
62
|
+
if (!snapshot.authToken.value) {
|
|
63
|
+
console.log('fix auth: export OTAKIT_TOKEN=<token> # or run: otakit login');
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
const validateSubcommand = new Command('validate')
|
|
68
|
+
.description('Validate capacitor.config.* OtaKit settings in the current project')
|
|
69
|
+
.option('--json', 'Print machine-readable JSON output')
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
await runCommand(async () => {
|
|
72
|
+
try {
|
|
73
|
+
const config = readProjectConfig();
|
|
74
|
+
if (!config) {
|
|
75
|
+
const message = `No ${PROJECT_CONFIG_LABEL} found in the current directory or its parents.`;
|
|
76
|
+
if (options.json) {
|
|
77
|
+
console.log(JSON.stringify({
|
|
78
|
+
ok: false,
|
|
79
|
+
error: message,
|
|
80
|
+
}, null, 2));
|
|
81
|
+
process.exitCode = 2;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
throw new CliError([
|
|
85
|
+
message,
|
|
86
|
+
'Add OtaKit plugin config to capacitor.config.ts, or pass flags/env directly.',
|
|
87
|
+
].join('\n'), 2);
|
|
88
|
+
}
|
|
89
|
+
if (options.json) {
|
|
90
|
+
console.log(JSON.stringify({
|
|
91
|
+
ok: true,
|
|
92
|
+
config,
|
|
93
|
+
}, null, 2));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
console.log(`${PROJECT_CONFIG_LABEL} OtaKit settings are valid.`);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (!options.json) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
const message = error instanceof Error ? error.message : 'Config validation failed.';
|
|
103
|
+
console.log(JSON.stringify({
|
|
104
|
+
ok: false,
|
|
105
|
+
error: message,
|
|
106
|
+
}, null, 2));
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
export const configCommand = new Command('config')
|
|
112
|
+
.description('Validate and inspect resolved CLI configuration')
|
|
113
|
+
.addCommand(validateSubcommand)
|
|
114
|
+
.addCommand(resolveSubcommand);
|
|
115
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/commands/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,eAAO,MAAM,aAAa,SAyBtB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { ApiClient } from '../lib/api.js';
|
|
3
|
+
import { requireConfig } from '../lib/config.js';
|
|
4
|
+
import { runCommand } from '../lib/errors.js';
|
|
5
|
+
import { confirm } from '../lib/prompt.js';
|
|
6
|
+
export const deleteCommand = new Command('delete')
|
|
7
|
+
.description('Delete a bundle')
|
|
8
|
+
.argument('<bundleId>', 'Bundle ID to delete')
|
|
9
|
+
.option('--app-id <id>', 'App ID override')
|
|
10
|
+
.option('--server <url>', 'Server URL override')
|
|
11
|
+
.option('--force', 'Skip confirmation')
|
|
12
|
+
.action(async (bundleId, options) => {
|
|
13
|
+
await runCommand(async () => {
|
|
14
|
+
const config = await requireConfig({
|
|
15
|
+
appId: options.appId,
|
|
16
|
+
serverUrl: options.server,
|
|
17
|
+
});
|
|
18
|
+
const api = new ApiClient(config);
|
|
19
|
+
if (!options.force) {
|
|
20
|
+
const accepted = await confirm(`Delete bundle ${bundleId}?`);
|
|
21
|
+
if (!accepted) {
|
|
22
|
+
console.log('Cancelled.');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
await api.deleteBundle(bundleId);
|
|
27
|
+
console.log(`Deleted bundle ${bundleId}.`);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/commands/delete.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQ3C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,iBAAiB,CAAC;KAC9B,QAAQ,CAAC,YAAY,EAAE,qBAAqB,CAAC;KAC7C,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC;KAC1C,MAAM,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;KAC/C,MAAM,CAAC,SAAS,EAAE,mBAAmB,CAAC;KACtC,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,OAAsB,EAAE,EAAE;IACzD,MAAM,UAAU,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;YACjC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,OAAO,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAElC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,iBAAiB,QAAQ,GAAG,CAAC,CAAC;YAC7D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;gBAC1B,OAAO;YACT,CAAC;QACH,CAAC;QAED,MAAM,GAAG,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,kBAAkB,QAAQ,GAAG,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-signing-key.d.ts","sourceRoot":"","sources":["../../src/commands/generate-signing-key.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,eAAO,MAAM,yBAAyB,SA+ClC,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { runCommand } from '../lib/errors.js';
|
|
4
|
+
export const generateSigningKeyCommand = new Command('generate-signing-key')
|
|
5
|
+
.description('Generate an ES256 key pair for manifest signing')
|
|
6
|
+
.option('--kid <kid>', 'Key ID (default: auto-generated)')
|
|
7
|
+
.action(async (options) => {
|
|
8
|
+
await runCommand(async () => {
|
|
9
|
+
const kid = options.kid ??
|
|
10
|
+
`key-${new Date().toISOString().slice(0, 10)}-${crypto.randomBytes(4).toString('hex')}`;
|
|
11
|
+
const keyPair = crypto.generateKeyPairSync('ec', {
|
|
12
|
+
namedCurve: 'prime256v1',
|
|
13
|
+
});
|
|
14
|
+
const verificationKeyObject = keyPair['public' + 'Key'];
|
|
15
|
+
if (!(verificationKeyObject instanceof crypto.KeyObject)) {
|
|
16
|
+
throw new Error('Failed to derive verification key');
|
|
17
|
+
}
|
|
18
|
+
const verificationKeyDer = verificationKeyObject.export({
|
|
19
|
+
type: 'spki',
|
|
20
|
+
format: 'der',
|
|
21
|
+
});
|
|
22
|
+
const signingKeyPem = keyPair.privateKey.export({
|
|
23
|
+
type: 'pkcs8',
|
|
24
|
+
format: 'pem',
|
|
25
|
+
});
|
|
26
|
+
const verificationKeyBase64 = verificationKeyDer.toString('base64');
|
|
27
|
+
console.log('=== Manifest Signing Key Pair ===\n');
|
|
28
|
+
console.log(`Key ID (kid): ${kid}\n`);
|
|
29
|
+
console.log('--- Server Environment Variable ---');
|
|
30
|
+
console.log('Add these to your server .env:\n');
|
|
31
|
+
console.log(`MANIFEST_SIGNING_KID=${kid}`);
|
|
32
|
+
console.log(`MANIFEST_SIGNING_KEY="${signingKeyPem.replace(/\n/g, '\\n')}"\n`);
|
|
33
|
+
console.log('--- Plugin Config (capacitor.config.ts) ---');
|
|
34
|
+
console.log('Add this to your OtaKit plugin config:\n');
|
|
35
|
+
console.log(JSON.stringify({
|
|
36
|
+
manifestKeys: [{ kid, key: verificationKeyBase64 }],
|
|
37
|
+
}, null, 2));
|
|
38
|
+
console.log('');
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=generate-signing-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-signing-key.js","sourceRoot":"","sources":["../../src/commands/generate-signing-key.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,OAAO,CAAC,sBAAsB,CAAC;KACzE,WAAW,CAAC,iDAAiD,CAAC;KAC9D,MAAM,CAAC,aAAa,EAAE,kCAAkC,CAAC;KACzD,MAAM,CAAC,KAAK,EAAE,OAAyB,EAAE,EAAE;IAC1C,MAAM,UAAU,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,GAAG,GACP,OAAO,CAAC,GAAG;YACX,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAE1F,MAAM,OAAO,GAAG,MAAM,CAAC,mBAAmB,CAAC,IAAI,EAAE;YAC/C,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QACH,MAAM,qBAAqB,GAAI,OAAuD,CACpF,QAAQ,GAAG,KAAK,CACjB,CAAC;QACF,IAAI,CAAC,CAAC,qBAAqB,YAAY,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC;YACzD,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,kBAAkB,GAAG,qBAAqB,CAAC,MAAM,CAAC;YACtD,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,KAAK;SACd,CAAW,CAAC;QACb,MAAM,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC;YAC9C,IAAI,EAAE,OAAO;YACb,MAAM,EAAE,KAAK;SACd,CAAW,CAAC;QACb,MAAM,qBAAqB,GAAG,kBAAkB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEpE,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,yBAAyB,aAAa,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/E,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QACxD,OAAO,CAAC,GAAG,CACT,IAAI,CAAC,SAAS,CACZ;YACE,YAAY,EAAE,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,qBAAqB,EAAE,CAAC;SACpD,EACD,IAAI,EACJ,CAAC,CACF,CACF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,eAAO,MAAM,WAAW,SA2BpB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { ApiClient } from '../lib/api.js';
|
|
3
|
+
import { requireConfig } from '../lib/config.js';
|
|
4
|
+
import { runCommand } from '../lib/errors.js';
|
|
5
|
+
import { parsePositiveInteger } from '../lib/validate.js';
|
|
6
|
+
export const listCommand = new Command('list')
|
|
7
|
+
.description('List all bundles')
|
|
8
|
+
.option('--app-id <id>', 'App ID override')
|
|
9
|
+
.option('--server <url>', 'Server URL override')
|
|
10
|
+
.option('--limit <n>', 'Limit results', '20')
|
|
11
|
+
.action(async (options) => {
|
|
12
|
+
await runCommand(async () => {
|
|
13
|
+
const config = await requireConfig({
|
|
14
|
+
appId: options.appId,
|
|
15
|
+
serverUrl: options.server,
|
|
16
|
+
});
|
|
17
|
+
const api = new ApiClient(config);
|
|
18
|
+
const limit = Math.min(parsePositiveInteger(options.limit, 'limit'), 200);
|
|
19
|
+
const response = await api.listBundles({ limit });
|
|
20
|
+
if (response.bundles.length === 0) {
|
|
21
|
+
console.log('No bundles found.');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
for (const bundle of response.bundles) {
|
|
25
|
+
console.log(`${bundle.id} ${bundle.version} ${bundle.size} bytes`);
|
|
26
|
+
}
|
|
27
|
+
console.log(`Total: ${response.total}`);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAQ1D,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,kBAAkB,CAAC;KAC/B,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC;KAC1C,MAAM,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;KAC/C,MAAM,CAAC,aAAa,EAAE,eAAe,EAAE,IAAI,CAAC;KAC5C,MAAM,CAAC,KAAK,EAAE,OAAoB,EAAE,EAAE;IACrC,MAAM,UAAU,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC;YACjC,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,SAAS,EAAE,OAAO,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC;QAElC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;QAE1E,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAElD,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;YACjC,OAAO;QACT,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;YACtC,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,CAAC;QACvE,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,UAAU,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6BpC,eAAO,MAAM,YAAY,SAsFrB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { resolveServerUrl } from '../lib/config.js';
|
|
4
|
+
import { CliError, runCommand } from '../lib/errors.js';
|
|
5
|
+
import { fetchCli, parseApiError } from '../lib/http.js';
|
|
6
|
+
import { ask } from '../lib/prompt.js';
|
|
7
|
+
import { storeAccessToken } from '../lib/token-store.js';
|
|
8
|
+
const OTP_REGEX = /^\d{6}$/;
|
|
9
|
+
function toShellLiteral(value) {
|
|
10
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
11
|
+
}
|
|
12
|
+
export const loginCommand = new Command('login')
|
|
13
|
+
.description('Sign in with email OTP and store access token')
|
|
14
|
+
.option('--email <email>', 'Email address')
|
|
15
|
+
.option('--server <url>', 'Server URL')
|
|
16
|
+
.option('--token-only', 'Print only the token to stdout')
|
|
17
|
+
.action(async (options) => {
|
|
18
|
+
await runCommand(async () => {
|
|
19
|
+
const serverUrl = resolveServerUrl(process.cwd(), options.server);
|
|
20
|
+
const emailInput = options.email?.trim().toLowerCase() || (await ask('Email: ')).trim().toLowerCase();
|
|
21
|
+
if (!emailInput) {
|
|
22
|
+
throw new CliError('Email is required.');
|
|
23
|
+
}
|
|
24
|
+
const sendSpinner = ora('Sending verification code...').start();
|
|
25
|
+
const sendOtpResponse = await fetchCli(`${serverUrl}/api/auth/email-otp/send-verification-otp`, {
|
|
26
|
+
method: 'POST',
|
|
27
|
+
headers: {
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify({ email: emailInput, type: 'sign-in' }),
|
|
31
|
+
});
|
|
32
|
+
if (!sendOtpResponse.ok) {
|
|
33
|
+
sendSpinner.fail('Could not send verification code');
|
|
34
|
+
throw new CliError(await parseApiError(sendOtpResponse));
|
|
35
|
+
}
|
|
36
|
+
sendSpinner.succeed('Verification code sent');
|
|
37
|
+
const otp = (await ask('Verification code: ')).trim();
|
|
38
|
+
if (!OTP_REGEX.test(otp)) {
|
|
39
|
+
throw new CliError('Invalid verification code. Enter the 6-digit code.');
|
|
40
|
+
}
|
|
41
|
+
const verifySpinner = ora('Verifying code...').start();
|
|
42
|
+
const signInResponse = await fetchCli(`${serverUrl}/api/auth/sign-in/email-otp`, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: {
|
|
45
|
+
'Content-Type': 'application/json',
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify({ email: emailInput, otp }),
|
|
48
|
+
});
|
|
49
|
+
if (!signInResponse.ok) {
|
|
50
|
+
verifySpinner.fail('Sign-in failed');
|
|
51
|
+
throw new CliError(await parseApiError(signInResponse));
|
|
52
|
+
}
|
|
53
|
+
const payload = (await signInResponse.json());
|
|
54
|
+
const token = typeof payload.token === 'string' ? payload.token.trim() : '';
|
|
55
|
+
if (!token) {
|
|
56
|
+
verifySpinner.fail('Sign-in failed');
|
|
57
|
+
throw new CliError('Server returned an invalid auth response.');
|
|
58
|
+
}
|
|
59
|
+
const storeResult = await storeAccessToken(serverUrl, token);
|
|
60
|
+
verifySpinner.succeed('Signed in');
|
|
61
|
+
if (options.tokenOnly) {
|
|
62
|
+
process.stdout.write(`${token}\n`);
|
|
63
|
+
if (!storeResult.ok) {
|
|
64
|
+
console.error(`Warning: could not store token locally (${storeResult.reason ?? 'unknown reason'}).`);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (storeResult.ok) {
|
|
69
|
+
const signedInAs = typeof payload.user?.email === 'string' ? ` as ${payload.user.email}` : '';
|
|
70
|
+
console.log(`Logged in${signedInAs}.`);
|
|
71
|
+
console.log(`Token stored locally for ${serverUrl}.`);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
console.warn(`Could not store token locally: ${storeResult.reason ?? 'unknown reason'}.`);
|
|
75
|
+
console.log('Use env fallback in this shell:');
|
|
76
|
+
console.log(`export OTAKIT_TOKEN=${toShellLiteral(token)}`);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,GAAG,MAAM,KAAK,CAAC;AAEtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAezD,MAAM,SAAS,GAAG,SAAS,CAAC;AAE5B,SAAS,cAAc,CAAC,KAAa;IACnC,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,+CAA+C,CAAC;KAC5D,MAAM,CAAC,iBAAiB,EAAE,eAAe,CAAC;KAC1C,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAAC;KACtC,MAAM,CAAC,cAAc,EAAE,gCAAgC,CAAC;KACxD,MAAM,CAAC,KAAK,EAAE,OAAqB,EAAE,EAAE;IACtC,MAAM,UAAU,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,UAAU,GACd,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAErF,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,MAAM,IAAI,QAAQ,CAAC,oBAAoB,CAAC,CAAC;QAC3C,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,CAAC,8BAA8B,CAAC,CAAC,KAAK,EAAE,CAAC;QAEhE,MAAM,eAAe,GAAG,MAAM,QAAQ,CACpC,GAAG,SAAS,2CAA2C,EACvD;YACE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;SAC7D,CACF,CAAC;QAEF,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;YACxB,WAAW,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;YACrD,MAAM,IAAI,QAAQ,CAAC,MAAM,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,WAAW,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC;QAE9C,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,QAAQ,CAAC,oDAAoD,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,aAAa,GAAG,GAAG,CAAC,mBAAmB,CAAC,CAAC,KAAK,EAAE,CAAC;QACvD,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,GAAG,SAAS,6BAA6B,EAAE;YAC/E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC;SACjD,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACrC,MAAM,IAAI,QAAQ,CAAC,MAAM,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC;QAC1D,CAAC;QAED,MAAM,OAAO,GAAG,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,CAAmB,CAAC;QAChE,MAAM,KAAK,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YACrC,MAAM,IAAI,QAAQ,CAAC,2CAA2C,CAAC,CAAC;QAClE,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QAC7D,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAEnC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;YACnC,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;gBACpB,OAAO,CAAC,KAAK,CACX,2CAA2C,WAAW,CAAC,MAAM,IAAI,gBAAgB,IAAI,CACtF,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,WAAW,CAAC,EAAE,EAAE,CAAC;YACnB,MAAM,UAAU,GACd,OAAO,OAAO,CAAC,IAAI,EAAE,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7E,OAAO,CAAC,GAAG,CAAC,YAAY,UAAU,GAAG,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,4BAA4B,SAAS,GAAG,CAAC,CAAC;YACtD,OAAO;QACT,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,kCAAkC,WAAW,CAAC,MAAM,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAC1F,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,uBAAuB,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,eAAO,MAAM,aAAa,SAmBtB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { resolveServerUrl } from '../lib/config.js';
|
|
3
|
+
import { runCommand } from '../lib/errors.js';
|
|
4
|
+
import { clearStoredAccessToken } from '../lib/token-store.js';
|
|
5
|
+
export const logoutCommand = new Command('logout')
|
|
6
|
+
.description('Remove stored access token')
|
|
7
|
+
.option('--server <url>', 'Server URL')
|
|
8
|
+
.action(async (options) => {
|
|
9
|
+
await runCommand(async () => {
|
|
10
|
+
const serverUrl = resolveServerUrl(process.cwd(), options.server);
|
|
11
|
+
const result = await clearStoredAccessToken(serverUrl);
|
|
12
|
+
if (!result.ok) {
|
|
13
|
+
console.warn(`Could not update local token store: ${result.reason ?? 'unknown reason'}.`);
|
|
14
|
+
}
|
|
15
|
+
else if (result.deleted) {
|
|
16
|
+
console.log(`Removed stored token for ${serverUrl}.`);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(`No stored token found for ${serverUrl}.`);
|
|
20
|
+
}
|
|
21
|
+
console.log('If needed for this shell session, also run:');
|
|
22
|
+
console.log('unset OTAKIT_TOKEN');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
//# sourceMappingURL=logout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAM/D,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,gBAAgB,EAAE,YAAY,CAAC;KACtC,MAAM,CAAC,KAAK,EAAE,OAAsB,EAAE,EAAE;IACvC,MAAM,UAAU,CAAC,KAAK,IAAI,EAAE;QAC1B,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAClE,MAAM,MAAM,GAAG,MAAM,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAEvD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,uCAAuC,MAAM,CAAC,MAAM,IAAI,gBAAgB,GAAG,CAAC,CAAC;QAC5F,CAAC;aAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,4BAA4B,SAAS,GAAG,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,6BAA6B,SAAS,GAAG,CAAC,CAAC;QACzD,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/commands/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBpC,eAAO,MAAM,eAAe,SAmFxB,CAAC"}
|