jobseek-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/dist/commands/applications.d.ts +2 -0
- package/dist/commands/applications.js +198 -0
- package/dist/commands/applications.js.map +1 -0
- package/dist/commands/auth.d.ts +2 -0
- package/dist/commands/auth.js +315 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/claims.d.ts +2 -0
- package/dist/commands/claims.js +355 -0
- package/dist/commands/claims.js.map +1 -0
- package/dist/commands/jobs.d.ts +2 -0
- package/dist/commands/jobs.js +240 -0
- package/dist/commands/jobs.js.map +1 -0
- package/dist/commands/profile.d.ts +2 -0
- package/dist/commands/profile.js +116 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/question.d.ts +2 -0
- package/dist/commands/question.js +54 -0
- package/dist/commands/question.js.map +1 -0
- package/dist/commands/resume.d.ts +2 -0
- package/dist/commands/resume.js +209 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +192 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/ssh-key.d.ts +2 -0
- package/dist/commands/ssh-key.js +151 -0
- package/dist/commands/ssh-key.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +72 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api-client.d.ts +16 -0
- package/dist/lib/api-client.js +59 -0
- package/dist/lib/api-client.js.map +1 -0
- package/dist/lib/config.d.ts +19 -0
- package/dist/lib/config.js +56 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/errors.d.ts +11 -0
- package/dist/lib/errors.js +23 -0
- package/dist/lib/errors.js.map +1 -0
- package/dist/lib/oauth.d.ts +41 -0
- package/dist/lib/oauth.js +210 -0
- package/dist/lib/oauth.js.map +1 -0
- package/dist/lib/output.d.ts +20 -0
- package/dist/lib/output.js +109 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/ssh.d.ts +25 -0
- package/dist/lib/ssh.js +103 -0
- package/dist/lib/ssh.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { select, confirm } from '@inquirer/prompts';
|
|
2
|
+
import { requireApiKey, resolveApiUrl } from '../lib/config.js';
|
|
3
|
+
import { ApiClient } from '../lib/api-client.js';
|
|
4
|
+
import { findSshKeys, readPublicKey } from '../lib/ssh.js';
|
|
5
|
+
import * as out from '../lib/output.js';
|
|
6
|
+
export function registerSshKeyCommands(program) {
|
|
7
|
+
const sshKey = program
|
|
8
|
+
.command('ssh-key')
|
|
9
|
+
.description('Manage SSH keys for authentication');
|
|
10
|
+
sshKey
|
|
11
|
+
.command('add')
|
|
12
|
+
.description('Register an SSH public key with JobSeek')
|
|
13
|
+
.option('--key <path>', 'Path to the public key file')
|
|
14
|
+
.option('--name <name>', 'Name for the key')
|
|
15
|
+
.action(async (opts) => {
|
|
16
|
+
const parentOpts = program.opts();
|
|
17
|
+
const apiKey = requireApiKey(parentOpts.apiKey);
|
|
18
|
+
const apiUrl = resolveApiUrl(parentOpts.apiUrl);
|
|
19
|
+
const client = new ApiClient(apiUrl, apiKey);
|
|
20
|
+
let pubKeyPath;
|
|
21
|
+
if (opts.key) {
|
|
22
|
+
pubKeyPath = opts.key;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const keys = findSshKeys();
|
|
26
|
+
if (keys.length === 0) {
|
|
27
|
+
out.error('No SSH keys found in ~/.ssh/');
|
|
28
|
+
out.info('Generate one with: ssh-keygen -t ed25519');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
const chosen = await select({
|
|
32
|
+
message: 'Which SSH key would you like to register?',
|
|
33
|
+
choices: keys.map(k => ({
|
|
34
|
+
name: `${k.type} ${k.fingerprint} ${k.comment || k.path}`,
|
|
35
|
+
value: k.path,
|
|
36
|
+
})),
|
|
37
|
+
});
|
|
38
|
+
pubKeyPath = chosen;
|
|
39
|
+
}
|
|
40
|
+
const publicKey = readPublicKey(pubKeyPath);
|
|
41
|
+
const spin = out.spinner('Registering SSH key...');
|
|
42
|
+
spin.start();
|
|
43
|
+
try {
|
|
44
|
+
const result = await client.post('/api/auth/ssh/register', {
|
|
45
|
+
publicKey,
|
|
46
|
+
name: opts.name,
|
|
47
|
+
});
|
|
48
|
+
spin.stop();
|
|
49
|
+
out.success(`SSH key registered: ${result.fingerprint}`);
|
|
50
|
+
out.keyValue('Name', result.name);
|
|
51
|
+
out.keyValue('Fingerprint', result.fingerprint);
|
|
52
|
+
out.info('You can now use `js login --ssh` to authenticate with this key.');
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
spin.stop();
|
|
56
|
+
out.error(`Failed to register SSH key: ${err.message}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
sshKey
|
|
61
|
+
.command('list')
|
|
62
|
+
.description('List registered SSH keys')
|
|
63
|
+
.action(async () => {
|
|
64
|
+
const parentOpts = program.opts();
|
|
65
|
+
const apiKey = requireApiKey(parentOpts.apiKey);
|
|
66
|
+
const apiUrl = resolveApiUrl(parentOpts.apiUrl);
|
|
67
|
+
const client = new ApiClient(apiUrl, apiKey);
|
|
68
|
+
const spin = out.spinner('Fetching SSH keys...');
|
|
69
|
+
spin.start();
|
|
70
|
+
try {
|
|
71
|
+
const data = await client.get('/api/auth/ssh/keys');
|
|
72
|
+
spin.stop();
|
|
73
|
+
if (out.isJsonMode()) {
|
|
74
|
+
out.outputJson(data.keys);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (data.keys.length === 0) {
|
|
78
|
+
out.info('No SSH keys registered. Use `js ssh-key add` to register one.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
out.heading('Registered SSH Keys');
|
|
82
|
+
const table = out.createTable(['Name', 'Fingerprint', 'Last Used', 'Added']);
|
|
83
|
+
for (const key of data.keys) {
|
|
84
|
+
table.push([
|
|
85
|
+
key.name,
|
|
86
|
+
key.fingerprint,
|
|
87
|
+
key.lastUsedAt ? out.formatDate(key.lastUsedAt) : 'Never',
|
|
88
|
+
out.formatDate(key.createdAt),
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
console.log(table.toString());
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
spin.stop();
|
|
95
|
+
out.error(`Failed to list SSH keys: ${err.message}`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
sshKey
|
|
100
|
+
.command('remove')
|
|
101
|
+
.description('Remove a registered SSH key')
|
|
102
|
+
.argument('[fingerprint]', 'Fingerprint of the key to remove')
|
|
103
|
+
.action(async (fingerprint) => {
|
|
104
|
+
const parentOpts = program.opts();
|
|
105
|
+
const apiKey = requireApiKey(parentOpts.apiKey);
|
|
106
|
+
const apiUrl = resolveApiUrl(parentOpts.apiUrl);
|
|
107
|
+
const client = new ApiClient(apiUrl, apiKey);
|
|
108
|
+
if (!fingerprint) {
|
|
109
|
+
// Fetch keys and let user choose
|
|
110
|
+
const spin = out.spinner('Fetching SSH keys...');
|
|
111
|
+
spin.start();
|
|
112
|
+
const data = await client.get('/api/auth/ssh/keys');
|
|
113
|
+
spin.stop();
|
|
114
|
+
if (data.keys.length === 0) {
|
|
115
|
+
out.info('No SSH keys registered.');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
fingerprint = await select({
|
|
119
|
+
message: 'Which key would you like to remove?',
|
|
120
|
+
choices: data.keys.map(k => ({
|
|
121
|
+
name: `${k.name} (${k.fingerprint})`,
|
|
122
|
+
value: k.fingerprint,
|
|
123
|
+
})),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
const confirmed = await confirm({
|
|
127
|
+
message: `Remove SSH key ${fingerprint}?`,
|
|
128
|
+
default: false,
|
|
129
|
+
});
|
|
130
|
+
if (!confirmed) {
|
|
131
|
+
out.info('Cancelled.');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const spin = out.spinner('Removing SSH key...');
|
|
135
|
+
spin.start();
|
|
136
|
+
try {
|
|
137
|
+
await client.request('/api/auth/ssh/keys', {
|
|
138
|
+
method: 'DELETE',
|
|
139
|
+
body: { fingerprint },
|
|
140
|
+
});
|
|
141
|
+
spin.stop();
|
|
142
|
+
out.success(`SSH key removed: ${fingerprint}`);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
spin.stop();
|
|
146
|
+
out.error(`Failed to remove SSH key: ${err.message}`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=ssh-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-key.js","sourceRoot":"","sources":["../../src/commands/ssh-key.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { setJsonMode } from './lib/output.js';
|
|
5
|
+
import { registerAuthCommands } from './commands/auth.js';
|
|
6
|
+
import { registerProfileCommands } from './commands/profile.js';
|
|
7
|
+
import { registerResumeCommands } from './commands/resume.js';
|
|
8
|
+
import { registerJobCommands } from './commands/jobs.js';
|
|
9
|
+
import { registerApplicationCommands } from './commands/applications.js';
|
|
10
|
+
import { registerSearchCommands } from './commands/search.js';
|
|
11
|
+
import { registerClaimsCommands } from './commands/claims.js';
|
|
12
|
+
import { registerQuestionCommands } from './commands/question.js';
|
|
13
|
+
import { registerSshKeyCommands } from './commands/ssh-key.js';
|
|
14
|
+
import { ConfigError, AuthError, ApiError } from './lib/errors.js';
|
|
15
|
+
const program = new Command();
|
|
16
|
+
program
|
|
17
|
+
.name('js')
|
|
18
|
+
.description('JobSeek CLI — AI-powered job search from your terminal')
|
|
19
|
+
.version('1.0.0')
|
|
20
|
+
.option('--api-url <url>', 'Override API base URL')
|
|
21
|
+
.option('--api-key <key>', 'Override API key')
|
|
22
|
+
.option('--json', 'Output as JSON')
|
|
23
|
+
.option('--no-color', 'Disable color output')
|
|
24
|
+
.hook('preAction', (thisCommand) => {
|
|
25
|
+
const opts = thisCommand.opts();
|
|
26
|
+
if (opts.json)
|
|
27
|
+
setJsonMode(true);
|
|
28
|
+
if (opts.color === false) {
|
|
29
|
+
// chalk respects NO_COLOR env var
|
|
30
|
+
process.env.NO_COLOR = '1';
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// Register all command groups
|
|
34
|
+
registerAuthCommands(program);
|
|
35
|
+
registerProfileCommands(program);
|
|
36
|
+
registerResumeCommands(program);
|
|
37
|
+
registerJobCommands(program);
|
|
38
|
+
registerApplicationCommands(program);
|
|
39
|
+
registerSearchCommands(program);
|
|
40
|
+
registerClaimsCommands(program);
|
|
41
|
+
registerQuestionCommands(program);
|
|
42
|
+
registerSshKeyCommands(program);
|
|
43
|
+
// Global error handler
|
|
44
|
+
process.on('uncaughtException', (err) => {
|
|
45
|
+
if (err instanceof ConfigError) {
|
|
46
|
+
console.error(chalk.red('✗') + ' ' + err.message);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
if (err instanceof AuthError) {
|
|
50
|
+
console.error(chalk.red('✗') + ' ' + err.message);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
if (err instanceof ApiError) {
|
|
54
|
+
console.error(chalk.red('✗') + ` API Error (${err.statusCode}): ${err.message}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
console.error(chalk.red('✗') + ` Unexpected error: ${err.message}`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
});
|
|
60
|
+
program.parseAsync(process.argv).catch((err) => {
|
|
61
|
+
if (err instanceof ConfigError || err instanceof AuthError || err instanceof ApiError) {
|
|
62
|
+
console.error(chalk.red('✗') + ' ' + err.message);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
// Don't log ExitPromptError (user cancelled prompt with Ctrl+C)
|
|
66
|
+
if (err.name === 'ExitPromptError') {
|
|
67
|
+
process.exit(130);
|
|
68
|
+
}
|
|
69
|
+
console.error(chalk.red('✗') + ` ${err.message}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface RequestOptions {
|
|
2
|
+
method?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';
|
|
3
|
+
body?: unknown;
|
|
4
|
+
params?: Record<string, string | number | boolean | undefined>;
|
|
5
|
+
}
|
|
6
|
+
export declare class ApiClient {
|
|
7
|
+
private baseUrl;
|
|
8
|
+
private apiKey;
|
|
9
|
+
constructor(baseUrl: string, apiKey: string);
|
|
10
|
+
private buildUrl;
|
|
11
|
+
request<T = unknown>(path: string, options?: RequestOptions): Promise<T>;
|
|
12
|
+
get<T = unknown>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
|
|
13
|
+
post<T = unknown>(path: string, body?: unknown, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
|
|
14
|
+
patch<T = unknown>(path: string, body?: unknown): Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ApiError, AuthError } from './errors.js';
|
|
2
|
+
export class ApiClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
constructor(baseUrl, apiKey) {
|
|
6
|
+
this.baseUrl = baseUrl;
|
|
7
|
+
this.apiKey = apiKey;
|
|
8
|
+
}
|
|
9
|
+
buildUrl(path, params) {
|
|
10
|
+
const url = new URL(path, this.baseUrl);
|
|
11
|
+
if (params) {
|
|
12
|
+
for (const [key, value] of Object.entries(params)) {
|
|
13
|
+
if (value !== undefined && value !== '') {
|
|
14
|
+
url.searchParams.set(key, String(value));
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return url.toString();
|
|
19
|
+
}
|
|
20
|
+
async request(path, options = {}) {
|
|
21
|
+
const { method = 'GET', body, params } = options;
|
|
22
|
+
const url = this.buildUrl(path, params);
|
|
23
|
+
const headers = {
|
|
24
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
25
|
+
};
|
|
26
|
+
if (body !== undefined) {
|
|
27
|
+
headers['Content-Type'] = 'application/json';
|
|
28
|
+
}
|
|
29
|
+
const response = await fetch(url, {
|
|
30
|
+
method,
|
|
31
|
+
headers,
|
|
32
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
if (response.status === 401) {
|
|
36
|
+
throw new AuthError('Invalid or expired API key. Run `jobseek login` to re-authenticate.');
|
|
37
|
+
}
|
|
38
|
+
let errorBody;
|
|
39
|
+
try {
|
|
40
|
+
errorBody = await response.json();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
errorBody = {};
|
|
44
|
+
}
|
|
45
|
+
throw new ApiError(errorBody.error || `Request failed with status ${response.status}`, response.status, errorBody);
|
|
46
|
+
}
|
|
47
|
+
return response.json();
|
|
48
|
+
}
|
|
49
|
+
get(path, params) {
|
|
50
|
+
return this.request(path, { params });
|
|
51
|
+
}
|
|
52
|
+
post(path, body, params) {
|
|
53
|
+
return this.request(path, { method: 'POST', body, params });
|
|
54
|
+
}
|
|
55
|
+
patch(path, body) {
|
|
56
|
+
return this.request(path, { method: 'PATCH', body });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/lib/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAQlD,MAAM,OAAO,SAAS;IAEN;IACA;IAFZ,YACY,OAAe,EACf,MAAc;QADd,YAAO,GAAP,OAAO,CAAQ;QACf,WAAM,GAAN,MAAM,CAAQ;IACvB,CAAC;IAEI,QAAQ,CAAC,IAAY,EAAE,MAA8D;QACzF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,MAAM,EAAE,CAAC;YACT,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAChD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;oBACtC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAC7C,CAAC;YACL,CAAC;QACL,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,IAAY,EAAE,UAA0B,EAAE;QACjE,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAExC,MAAM,OAAO,GAA2B;YACpC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;SAC3C,CAAC;QAEF,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACrB,OAAO,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC;QACjD,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAC9B,MAAM;YACN,OAAO;YACP,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAC9D,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC1B,MAAM,IAAI,SAAS,CAAC,qEAAqE,CAAC,CAAC;YAC/F,CAAC;YAED,IAAI,SAAc,CAAC;YACnB,IAAI,CAAC;gBACD,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACL,SAAS,GAAG,EAAE,CAAC;YACnB,CAAC;YAED,MAAM,IAAI,QAAQ,CACd,SAAS,CAAC,KAAK,IAAI,8BAA8B,QAAQ,CAAC,MAAM,EAAE,EAClE,QAAQ,CAAC,MAAM,EACf,SAAS,CACZ,CAAC;QACN,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAgB,CAAC;IACzC,CAAC;IAED,GAAG,CAAc,IAAY,EAAE,MAA8D;QACzF,OAAO,IAAI,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,IAAI,CAAc,IAAY,EAAE,IAAc,EAAE,MAA8D;QAC1G,OAAO,IAAI,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAc,IAAY,EAAE,IAAc;QAC3C,OAAO,IAAI,CAAC,OAAO,CAAI,IAAI,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;CACJ"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface JobseekConfig {
|
|
2
|
+
apiKey?: string;
|
|
3
|
+
apiUrl?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function readConfig(): JobseekConfig;
|
|
6
|
+
export declare function writeConfig(config: JobseekConfig): void;
|
|
7
|
+
export declare function clearConfig(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve API key from: CLI flag > env var > config file
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveApiKey(flagValue?: string): string | undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve API URL from: CLI flag > env var > config file > default
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveApiUrl(flagValue?: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Require an API key or exit with an error message
|
|
18
|
+
*/
|
|
19
|
+
export declare function requireApiKey(flagValue?: string): string;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, chmodSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { ConfigError } from './errors.js';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.jobseek');
|
|
6
|
+
const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const DEFAULT_API_URL = 'https://www.getjobseek.com';
|
|
8
|
+
export function readConfig() {
|
|
9
|
+
try {
|
|
10
|
+
if (!existsSync(CONFIG_FILE))
|
|
11
|
+
return {};
|
|
12
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
13
|
+
return JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export function writeConfig(config) {
|
|
20
|
+
try {
|
|
21
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
22
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
|
|
25
|
+
chmodSync(CONFIG_FILE, 0o600);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
throw new ConfigError(`Failed to write config: ${err.message}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export function clearConfig() {
|
|
32
|
+
writeConfig({});
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Resolve API key from: CLI flag > env var > config file
|
|
36
|
+
*/
|
|
37
|
+
export function resolveApiKey(flagValue) {
|
|
38
|
+
return flagValue || process.env.JOBSEEK_API_KEY || readConfig().apiKey;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve API URL from: CLI flag > env var > config file > default
|
|
42
|
+
*/
|
|
43
|
+
export function resolveApiUrl(flagValue) {
|
|
44
|
+
return flagValue || process.env.JOBSEEK_API_URL || readConfig().apiUrl || DEFAULT_API_URL;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Require an API key or exit with an error message
|
|
48
|
+
*/
|
|
49
|
+
export function requireApiKey(flagValue) {
|
|
50
|
+
const key = resolveApiKey(flagValue);
|
|
51
|
+
if (!key) {
|
|
52
|
+
throw new ConfigError('No API key configured. Run `jobseek login` or set JOBSEEK_API_KEY env var.');
|
|
53
|
+
}
|
|
54
|
+
return key;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AACpD,MAAM,eAAe,GAAG,4BAA4B,CAAC;AAOrD,MAAM,UAAU,UAAU;IACtB,IAAI,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAkB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,MAAqB;IAC7C,IAAI,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC1B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;QACD,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACrE,SAAS,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,IAAI,WAAW,CAAC,2BAA4B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC/E,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,WAAW,CAAC,EAAE,CAAC,CAAC;AACpB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC5C,OAAO,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,EAAE,CAAC,MAAM,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC5C,OAAO,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,UAAU,EAAE,CAAC,MAAM,IAAI,eAAe,CAAC;AAC9F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,SAAkB;IAC5C,MAAM,GAAG,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,MAAM,IAAI,WAAW,CACjB,4EAA4E,CAC/E,CAAC;IACN,CAAC;IACD,OAAO,GAAG,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class ApiError extends Error {
|
|
2
|
+
statusCode: number;
|
|
3
|
+
responseBody?: unknown | undefined;
|
|
4
|
+
constructor(message: string, statusCode: number, responseBody?: unknown | undefined);
|
|
5
|
+
}
|
|
6
|
+
export declare class ConfigError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
export declare class AuthError extends Error {
|
|
10
|
+
constructor(message: string);
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class ApiError extends Error {
|
|
2
|
+
statusCode;
|
|
3
|
+
responseBody;
|
|
4
|
+
constructor(message, statusCode, responseBody) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.statusCode = statusCode;
|
|
7
|
+
this.responseBody = responseBody;
|
|
8
|
+
this.name = 'ApiError';
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export class ConfigError extends Error {
|
|
12
|
+
constructor(message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'ConfigError';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class AuthError extends Error {
|
|
18
|
+
constructor(message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'AuthError';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGpB;IACA;IAHX,YACI,OAAe,EACR,UAAkB,EAClB,YAAsB;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,eAAU,GAAV,UAAU,CAAQ;QAClB,iBAAY,GAAZ,YAAY,CAAU;QAG7B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IAC3B,CAAC;CACJ;AAED,MAAM,OAAO,WAAY,SAAQ,KAAK;IAClC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC9B,CAAC;CACJ;AAED,MAAM,OAAO,SAAU,SAAQ,KAAK;IAChC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;IAC5B,CAAC;CACJ"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface PkceChallenge {
|
|
2
|
+
codeVerifier: string;
|
|
3
|
+
codeChallenge: string;
|
|
4
|
+
}
|
|
5
|
+
export interface CallbackResult {
|
|
6
|
+
code: string;
|
|
7
|
+
state: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Generate a PKCE code_verifier and code_challenge (S256).
|
|
11
|
+
*/
|
|
12
|
+
export declare function generatePkce(): Promise<PkceChallenge>;
|
|
13
|
+
/**
|
|
14
|
+
* Generate a random state parameter for CSRF protection.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateState(): string;
|
|
17
|
+
/**
|
|
18
|
+
* Start a temporary local HTTP server to receive the OAuth callback.
|
|
19
|
+
* Returns a promise that resolves with the authorization code and state.
|
|
20
|
+
* The server shuts down automatically after receiving the callback.
|
|
21
|
+
*/
|
|
22
|
+
export declare function startCallbackServer(port: number): Promise<CallbackResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Find an available port for the callback server.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findAvailablePort(): Promise<number>;
|
|
27
|
+
/**
|
|
28
|
+
* Register a dynamic OAuth client with the server.
|
|
29
|
+
*/
|
|
30
|
+
export declare function registerOAuthClient(apiUrl: string, redirectUri: string): Promise<{
|
|
31
|
+
clientId: string;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Exchange an authorization code for an API key via the token endpoint.
|
|
35
|
+
* Decodes the access token JWT to extract the apiKey field.
|
|
36
|
+
*/
|
|
37
|
+
export declare function exchangeCodeForApiKey(apiUrl: string, clientId: string, code: string, codeVerifier: string, redirectUri: string): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* Build the authorization URL for the browser.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildAuthorizeUrl(apiUrl: string, clientId: string, redirectUri: string, codeChallenge: string, state: string): string;
|