huntr-cli 1.0.9

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.
Files changed (117) hide show
  1. package/.env.example +7 -0
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +43 -0
  3. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
  5. package/.github/labels.json +92 -0
  6. package/.github/pull_request_template.md +64 -0
  7. package/.github/workflows/ci.yml +87 -0
  8. package/.github/workflows/labels.yml +27 -0
  9. package/.github/workflows/manual-publish.yml +105 -0
  10. package/.github/workflows/publish.yml +57 -0
  11. package/.github/workflows/release.yml +124 -0
  12. package/.github/workflows/security-audit.yml +44 -0
  13. package/.husky/pre-commit +12 -0
  14. package/.husky/pre-push +27 -0
  15. package/.lintstagedrc.json +3 -0
  16. package/AGENTS.md +449 -0
  17. package/CHANGELOG.md +38 -0
  18. package/CHANGES.md +259 -0
  19. package/LICENSE +15 -0
  20. package/PUBLISHING.md +191 -0
  21. package/README.md +385 -0
  22. package/ROADMAP.md +158 -0
  23. package/SETUP-COMPLETE.md +446 -0
  24. package/WORKFLOW-SUMMARY.md +368 -0
  25. package/completions/_huntr +168 -0
  26. package/completions/huntr.1 +266 -0
  27. package/completions/huntr.bash +91 -0
  28. package/dist/api/client.d.ts +14 -0
  29. package/dist/api/client.d.ts.map +1 -0
  30. package/dist/api/client.js +74 -0
  31. package/dist/api/client.js.map +1 -0
  32. package/dist/api/personal/activities.d.ts +20 -0
  33. package/dist/api/personal/activities.d.ts.map +1 -0
  34. package/dist/api/personal/activities.js +50 -0
  35. package/dist/api/personal/activities.js.map +1 -0
  36. package/dist/api/personal/boards.d.ts +9 -0
  37. package/dist/api/personal/boards.d.ts.map +1 -0
  38. package/dist/api/personal/boards.js +16 -0
  39. package/dist/api/personal/boards.js.map +1 -0
  40. package/dist/api/personal/index.d.ts +17 -0
  41. package/dist/api/personal/index.d.ts.map +1 -0
  42. package/dist/api/personal/index.js +37 -0
  43. package/dist/api/personal/index.js.map +1 -0
  44. package/dist/api/personal/jobs.d.ts +13 -0
  45. package/dist/api/personal/jobs.d.ts.map +1 -0
  46. package/dist/api/personal/jobs.js +31 -0
  47. package/dist/api/personal/jobs.js.map +1 -0
  48. package/dist/api/personal/user.d.ts +8 -0
  49. package/dist/api/personal/user.d.ts.map +1 -0
  50. package/dist/api/personal/user.js +13 -0
  51. package/dist/api/personal/user.js.map +1 -0
  52. package/dist/cli.d.ts +3 -0
  53. package/dist/cli.d.ts.map +1 -0
  54. package/dist/cli.js +501 -0
  55. package/dist/cli.js.map +1 -0
  56. package/dist/commands/capture-session.d.ts +10 -0
  57. package/dist/commands/capture-session.d.ts.map +1 -0
  58. package/dist/commands/capture-session.js +478 -0
  59. package/dist/commands/capture-session.js.map +1 -0
  60. package/dist/config/clerk-session-manager.d.ts +44 -0
  61. package/dist/config/clerk-session-manager.d.ts.map +1 -0
  62. package/dist/config/clerk-session-manager.js +232 -0
  63. package/dist/config/clerk-session-manager.js.map +1 -0
  64. package/dist/config/config-manager.d.ts +15 -0
  65. package/dist/config/config-manager.d.ts.map +1 -0
  66. package/dist/config/config-manager.js +51 -0
  67. package/dist/config/config-manager.js.map +1 -0
  68. package/dist/config/keychain-manager.d.ts +6 -0
  69. package/dist/config/keychain-manager.d.ts.map +1 -0
  70. package/dist/config/keychain-manager.js +37 -0
  71. package/dist/config/keychain-manager.js.map +1 -0
  72. package/dist/config/token-capture.d.ts +11 -0
  73. package/dist/config/token-capture.d.ts.map +1 -0
  74. package/dist/config/token-capture.js +252 -0
  75. package/dist/config/token-capture.js.map +1 -0
  76. package/dist/config/token-manager.d.ts +38 -0
  77. package/dist/config/token-manager.d.ts.map +1 -0
  78. package/dist/config/token-manager.js +153 -0
  79. package/dist/config/token-manager.js.map +1 -0
  80. package/dist/lib/list-options.d.ts +69 -0
  81. package/dist/lib/list-options.d.ts.map +1 -0
  82. package/dist/lib/list-options.js +299 -0
  83. package/dist/lib/list-options.js.map +1 -0
  84. package/dist/types/personal.d.ts +113 -0
  85. package/dist/types/personal.d.ts.map +1 -0
  86. package/dist/types/personal.js +4 -0
  87. package/dist/types/personal.js.map +1 -0
  88. package/docs/AUTOMATIC-PUBLISHING.md +520 -0
  89. package/docs/CHANGELOG-AUTOMATION.md +418 -0
  90. package/docs/CI-CD-SETUP.md +582 -0
  91. package/docs/DEV-SETUP.md +512 -0
  92. package/docs/ENHANCEMENT-PLAN.md +204 -0
  93. package/docs/ENTITY-TYPES.md +462 -0
  94. package/docs/GITHUB-ACTIONS-GUIDE.md +367 -0
  95. package/docs/NPM-PUBLISHING.md +324 -0
  96. package/docs/OUTPUT-EXAMPLES.md +414 -0
  97. package/docs/OUTPUT-FORMATS.md +299 -0
  98. package/docs/TESTING.md +216 -0
  99. package/eslint.config.js +68 -0
  100. package/package.json +64 -0
  101. package/src/api/client.ts +88 -0
  102. package/src/api/personal/activities.ts +66 -0
  103. package/src/api/personal/boards.ts +14 -0
  104. package/src/api/personal/index.ts +25 -0
  105. package/src/api/personal/jobs.ts +33 -0
  106. package/src/api/personal/user.ts +10 -0
  107. package/src/cli.ts +487 -0
  108. package/src/commands/capture-session.ts +582 -0
  109. package/src/config/clerk-session-manager.ts +263 -0
  110. package/src/config/config-manager.ts +56 -0
  111. package/src/config/keychain-manager.ts +30 -0
  112. package/src/config/token-capture.ts +233 -0
  113. package/src/config/token-manager.ts +139 -0
  114. package/src/lib/list-options.ts +370 -0
  115. package/src/types/personal.ts +114 -0
  116. package/tests/example.test.ts +130 -0
  117. package/tsconfig.json +19 -0
@@ -0,0 +1,216 @@
1
+ # Testing Guide
2
+
3
+ Guide to testing huntr-cli following the development workflow.
4
+
5
+ ## Overview
6
+
7
+ Tests use **Vitest** (Vite-native test framework) and document the complete huntr-cli workflow:
8
+ - Git workflow (conventional commits, hooks)
9
+ - Publishing workflow (automatic releases)
10
+ - Output formatting features
11
+ - Command structure
12
+
13
+ ## Running Tests
14
+
15
+ ### All Tests
16
+ ```bash
17
+ npm test
18
+ ```
19
+
20
+ ### Specific Test Suite
21
+ ```bash
22
+ npm test -- --testNamePattern="Publishing"
23
+ ```
24
+
25
+ ### Watch Mode
26
+ ```bash
27
+ npm test -- --watch
28
+ ```
29
+
30
+ ### Coverage Report
31
+ ```bash
32
+ npm test -- --coverage
33
+ ```
34
+
35
+ ## Test Structure
36
+
37
+ ### tests/example.test.ts
38
+
39
+ Documents the complete workflow:
40
+
41
+ | Section | Purpose |
42
+ |---------|---------|
43
+ | **Command Structure** | Verifies CLI commands and output formats |
44
+ | **Build & Compilation** | TypeScript and ESLint pass in CI |
45
+ | **Git Workflow** | Conventional commits and git hooks |
46
+ | **Publishing Workflow** | Automatic npm publishing and versioning |
47
+ | **Output Formatting** | Field selection and export formats |
48
+ | **Documentation** | Guides and man pages exist |
49
+
50
+ ## Workflow Verification
51
+
52
+ ### ✅ Local Development
53
+ ```bash
54
+ # 1. Create feature branch
55
+ git checkout -b feat/my-feature
56
+
57
+ # 2. Make changes
58
+ npm run lint:fix
59
+ npm run build
60
+
61
+ # 3. Commit (pre-commit hook runs)
62
+ git commit -m "feat: add feature"
63
+
64
+ # 4. Push (pre-push hook runs: typecheck → lint → build)
65
+ git push origin feat/my-feature
66
+ ```
67
+
68
+ ### ✅ Pull Request
69
+ - Create PR on GitHub
70
+ - CI runs automatically (lint, typecheck, build, test)
71
+ - All checks must pass
72
+ - Code review and approval
73
+
74
+ ### ✅ Publishing
75
+ ```bash
76
+ # 1. Bump version
77
+ git checkout main
78
+ npm version minor # Creates commit + tag
79
+
80
+ # 2. Push with tags
81
+ git push origin main --tags
82
+
83
+ # 3. Release created automatically
84
+ # - release.yml creates GitHub Release with artifacts
85
+ # - publish.yml triggers on release
86
+ # - npm package published automatically
87
+ ```
88
+
89
+ ### ✅ Version Verification
90
+ ```bash
91
+ # Check npm registry
92
+ npm view huntr-cli version
93
+
94
+ # Install latest
95
+ npm install -g huntr-cli@latest
96
+
97
+ # Verify
98
+ huntr --version
99
+ ```
100
+
101
+ ## Test Examples
102
+
103
+ ### Example: Command Structure
104
+ ```typescript
105
+ it('should support boards list command', () => {
106
+ const commands = ['boards', 'jobs', 'activities'];
107
+ expect(commands).toContain('boards');
108
+ });
109
+ ```
110
+
111
+ ### Example: Publishing Workflow
112
+ ```typescript
113
+ it('should create artifacts on version bump', () => {
114
+ // release.yml detects version change
115
+ // Creates tar.gz and zip archives
116
+ // Creates GitHub Release with artifacts
117
+ expect(true).toBe(true);
118
+ });
119
+ ```
120
+
121
+ ### Example: Git Workflow
122
+ ```typescript
123
+ it('should trigger pre-push hook on git push', () => {
124
+ // Pre-push hook runs: typecheck → lint → build
125
+ expect(true).toBe(true);
126
+ });
127
+ ```
128
+
129
+ ## CI Test Execution
130
+
131
+ GitHub Actions runs tests automatically:
132
+
133
+ ```yaml
134
+ # .github/workflows/ci.yml
135
+ - name: Run tests
136
+ run: npm test
137
+ ```
138
+
139
+ Tests verify:
140
+ - Command structure is correct
141
+ - All output formats available
142
+ - Publishing workflow documented
143
+ - Git workflow enforced
144
+ - Documentation complete
145
+
146
+ ## Writing New Tests
147
+
148
+ When adding features, add tests to `tests/example.test.ts`:
149
+
150
+ ```typescript
151
+ describe('New Feature', () => {
152
+ it('should do something', () => {
153
+ const result = newFeature();
154
+ expect(result).toBe(true);
155
+ });
156
+ });
157
+ ```
158
+
159
+ Test structure:
160
+ - **Describe:** Feature or workflow area
161
+ - **It:** Specific behavior or requirement
162
+ - **Expect:** Assertion of correct behavior
163
+
164
+ ## Continuous Integration
165
+
166
+ ### On Every Push
167
+ ```
168
+ → Pre-commit hook (lint)
169
+ → Pre-push hook (typecheck, lint, build)
170
+ → GitHub Actions CI (lint, typecheck, build, test)
171
+ ```
172
+
173
+ ### On Pull Request
174
+ ```
175
+ → Same CI checks
176
+ → Code review required
177
+ → Tests must pass
178
+ ```
179
+
180
+ ### On Main Branch Push
181
+ ```
182
+ → All CI checks pass
183
+ → Version bump triggers release.yml
184
+ → GitHub Release created with artifacts
185
+ → npm publishing triggered
186
+ ```
187
+
188
+ ## Troubleshooting
189
+
190
+ ### Tests Failing
191
+ ```bash
192
+ # Run with verbose output
193
+ npm test -- --reporter=verbose
194
+
195
+ # Check test names
196
+ npm test -- --listTests
197
+ ```
198
+
199
+ ### Missing Dependencies
200
+ ```bash
201
+ npm install
202
+ npm run build:shared # For workspace tests
203
+ ```
204
+
205
+ ### ESLint/Typecheck Failing
206
+ ```bash
207
+ npm run lint:fix
208
+ npm run typecheck
209
+ ```
210
+
211
+ ## See Also
212
+
213
+ - [DEV-SETUP.md](./DEV-SETUP.md) — Development workflow
214
+ - [CI-CD-SETUP.md](./CI-CD-SETUP.md) — Hook configuration
215
+ - [AUTOMATIC-PUBLISHING.md](./AUTOMATIC-PUBLISHING.md) — Publishing workflow
216
+ - [.github/workflows/ci.yml](../.github/workflows/ci.yml) — CI configuration
@@ -0,0 +1,68 @@
1
+ import js from '@eslint/js';
2
+ import tsParser from '@typescript-eslint/parser';
3
+ import tsPlugin from '@typescript-eslint/eslint-plugin';
4
+
5
+ export default [
6
+ {
7
+ ignores: ['dist/**', 'node_modules/**', '*.config.js'],
8
+ },
9
+ {
10
+ files: ['src/**/*.ts'],
11
+ languageOptions: {
12
+ parser: tsParser,
13
+ parserOptions: {
14
+ ecmaVersion: 2022,
15
+ sourceType: 'module',
16
+ project: './tsconfig.json',
17
+ },
18
+ globals: {
19
+ console: 'readonly',
20
+ process: 'readonly',
21
+ Buffer: 'readonly',
22
+ setTimeout: 'readonly',
23
+ fetch: 'readonly',
24
+ URL: 'readonly',
25
+ require: 'readonly',
26
+ WebSocket: 'readonly',
27
+ MessageEvent: 'readonly',
28
+ Blob: 'readonly',
29
+ },
30
+ },
31
+ plugins: {
32
+ '@typescript-eslint': tsPlugin,
33
+ },
34
+ rules: {
35
+ ...js.configs.recommended.rules,
36
+ ...tsPlugin.configs.recommended.rules,
37
+ '@typescript-eslint/no-unused-vars': [
38
+ 'warn',
39
+ {
40
+ argsIgnorePattern: '^_',
41
+ varsIgnorePattern: '^_',
42
+ },
43
+ ],
44
+ '@typescript-eslint/no-explicit-any': 'warn',
45
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
46
+ '@typescript-eslint/no-floating-promises': 'warn',
47
+ '@typescript-eslint/no-misused-promises': 'warn',
48
+ 'no-console': 'off',
49
+ 'no-process-exit': 'off',
50
+ 'curly': ['error', 'multi-line'],
51
+ 'eol-last': ['error', 'always'],
52
+ 'no-trailing-spaces': 'error',
53
+ 'no-multiple-empty-lines': ['error', { max: 1 }],
54
+ 'quotes': ['error', 'single', { avoidEscape: true }],
55
+ 'semi': ['error', 'always'],
56
+ 'comma-dangle': [
57
+ 'error',
58
+ {
59
+ arrays: 'always-multiline',
60
+ objects: 'always-multiline',
61
+ imports: 'always-multiline',
62
+ exports: 'always-multiline',
63
+ functions: 'always-multiline',
64
+ },
65
+ ],
66
+ },
67
+ },
68
+ ];
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "huntr-cli",
3
+ "version": "1.0.9",
4
+ "type": "module",
5
+ "description": "CLI tool for managing your Huntr job search board. Track activities, search jobs, and manage your application pipeline from the terminal.",
6
+ "main": "dist/cli.js",
7
+ "bin": {
8
+ "huntr": "./dist/cli.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/cli.ts",
13
+ "start": "node dist/cli.js",
14
+ "lint": "eslint src --max-warnings 13",
15
+ "lint:fix": "eslint src --fix",
16
+ "typecheck": "tsc --noEmit",
17
+ "test": "vitest run",
18
+ "test:watch": "vitest watch",
19
+ "prepare": "husky install",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/mattmck/huntr-cli.git"
25
+ },
26
+ "keywords": [
27
+ "huntr",
28
+ "job-search",
29
+ "cli",
30
+ "job-tracking",
31
+ "activities",
32
+ "command-line"
33
+ ],
34
+ "author": "Matt McKnight <mcknight.matthew@gmail.com>",
35
+ "license": "ISC",
36
+ "bugs": {
37
+ "url": "https://github.com/mattmck/huntr-cli/issues"
38
+ },
39
+ "homepage": "https://github.com/mattmck/huntr-cli#readme",
40
+ "engines": {
41
+ "node": ">=18.0.0"
42
+ },
43
+ "dependencies": {
44
+ "@inquirer/prompts": "^8.2.1",
45
+ "axios": "^1.13.5",
46
+ "commander": "^14.0.3",
47
+ "dotenv": "^17.3.1",
48
+ "exceljs": "^4.4.0",
49
+ "keytar": "^7.9.0",
50
+ "pdfkit": "^0.13.0"
51
+ },
52
+ "devDependencies": {
53
+ "@eslint/js": "^8.56.0",
54
+ "@types/node": "^25.3.0",
55
+ "@typescript-eslint/eslint-plugin": "^7.0.0",
56
+ "@typescript-eslint/parser": "^7.0.0",
57
+ "eslint": "^8.56.0",
58
+ "husky": "^9.0.0",
59
+ "lint-staged": "^15.0.0",
60
+ "tsx": "^4.21.0",
61
+ "typescript": "^5.9.3",
62
+ "vitest": "^1.6.0"
63
+ }
64
+ }
@@ -0,0 +1,88 @@
1
+ import axios, { AxiosInstance, AxiosError } from 'axios';
2
+ import dotenv from 'dotenv';
3
+
4
+ // Load .env file silently (debug: false suppresses info messages)
5
+ dotenv.config({ debug: false });
6
+
7
+ /** A static token string OR an async function that returns a fresh token. */
8
+ export type TokenProvider = string | (() => Promise<string>);
9
+
10
+ export class HuntrApiClient {
11
+ private axiosInstance: AxiosInstance;
12
+ private tokenProvider: () => Promise<string>;
13
+
14
+ constructor(tokenProvider: TokenProvider, baseURL: string = 'https://api.huntr.co/org') {
15
+ this.tokenProvider =
16
+ typeof tokenProvider === 'string'
17
+ ? async () => tokenProvider
18
+ : tokenProvider;
19
+
20
+ this.axiosInstance = axios.create({ baseURL });
21
+
22
+ // Inject a fresh Authorization header before every request
23
+ this.axiosInstance.interceptors.request.use(async (config) => {
24
+ const token = await this.tokenProvider();
25
+ if (!token) throw new Error('No API token available.');
26
+ config.headers = config.headers ?? {};
27
+ config.headers['Authorization'] = `Bearer ${token}`;
28
+ config.headers['Content-Type'] = 'application/json';
29
+ return config;
30
+ });
31
+
32
+ this.axiosInstance.interceptors.response.use(
33
+ (response) => response,
34
+ (error: AxiosError) => {
35
+ if (error.response) {
36
+ const status = error.response.status;
37
+ const apiError = error.response.data as any;
38
+ const message = apiError?.error?.message ?? apiError?.message ?? 'API request failed';
39
+ throw new Error(`HTTP ${status}: ${message}`);
40
+ }
41
+ if (error.request) {
42
+ throw new Error('No response from API - check your network connection');
43
+ }
44
+ throw error;
45
+ },
46
+ );
47
+ }
48
+
49
+ async get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {
50
+ const response = await this.axiosInstance.get<T>(endpoint, { params });
51
+ return response.data;
52
+ }
53
+
54
+ async post<T>(endpoint: string, data?: any): Promise<T> {
55
+ const response = await this.axiosInstance.post<T>(endpoint, data);
56
+ return response.data;
57
+ }
58
+
59
+ async put<T>(endpoint: string, data?: any): Promise<T> {
60
+ const response = await this.axiosInstance.put<T>(endpoint, data);
61
+ return response.data;
62
+ }
63
+
64
+ async delete<T>(endpoint: string): Promise<T> {
65
+ const response = await this.axiosInstance.delete<T>(endpoint);
66
+ return response.data;
67
+ }
68
+
69
+ async *paginate<T>(
70
+ endpoint: string,
71
+ params: Record<string, any> = {},
72
+ limit: number = 100,
73
+ ): AsyncGenerator<T[], void, undefined> {
74
+ let next: string | undefined = undefined;
75
+
76
+ do {
77
+ const queryParams: Record<string, any> = { ...params, limit };
78
+ if (next) queryParams.next = next;
79
+ const response = await this.get<{ data: T[]; next?: string }>(endpoint, queryParams);
80
+ yield response.data;
81
+ next = response.next;
82
+ } while (next);
83
+ }
84
+ }
85
+
86
+ export const createClient = (tokenProvider: TokenProvider, baseURL?: string): HuntrApiClient => {
87
+ return new HuntrApiClient(tokenProvider, baseURL);
88
+ };
@@ -0,0 +1,66 @@
1
+ import { HuntrApiClient } from '../client';
2
+ import { PersonalAction, PersonalJob, PersonalJobsResponse } from '../../types/personal';
3
+
4
+ export class PersonalActionsApi {
5
+ constructor(private client: HuntrApiClient) {}
6
+
7
+ // Returns object map { [actionId]: PersonalAction }
8
+ async listByBoard(boardId: string): Promise<Record<string, PersonalAction>> {
9
+ return this.client.get<Record<string, PersonalAction>>(`/board/${boardId}/actions`);
10
+ }
11
+
12
+ // Returns flattened array sorted by date desc, optionally filtered by action types
13
+ async listByBoardFlat(
14
+ boardId: string,
15
+ opts?: { since?: Date; types?: string[] },
16
+ ): Promise<PersonalAction[]> {
17
+ const raw = await this.listByBoard(boardId);
18
+ let actions = Object.values(raw);
19
+
20
+ if (opts?.since) {
21
+ const cutoff = opts.since.getTime();
22
+ actions = actions.filter(a => new Date(a.date || a.createdAt).getTime() >= cutoff);
23
+ }
24
+
25
+ if (opts?.types && opts.types.length > 0) {
26
+ actions = actions.filter(a => opts.types!.includes(a.actionType));
27
+ }
28
+
29
+ return actions.sort((a, b) =>
30
+ new Date(b.date || b.createdAt).getTime() - new Date(a.date || a.createdAt).getTime(),
31
+ );
32
+ }
33
+
34
+ // Joins actions with job data to produce enriched rows
35
+ async weekSummary(boardId: string): Promise<Array<{
36
+ date: string;
37
+ actionType: string;
38
+ company: string;
39
+ jobTitle: string;
40
+ status: string;
41
+ url: string;
42
+ }>> {
43
+ const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
44
+ const [actions, jobsResponse] = await Promise.all([
45
+ this.listByBoardFlat(boardId, { since }),
46
+ this.client.get<PersonalJobsResponse>(`/board/${boardId}/jobs`),
47
+ ]);
48
+
49
+ const jobs = jobsResponse.jobs;
50
+
51
+ return actions
52
+ .filter(a => a.actionType !== 'ACTIVITY_CREATED')
53
+ .map(a => {
54
+ const jobId = a.data?._job;
55
+ const job: PersonalJob | undefined = jobId ? jobs[jobId] : undefined;
56
+ return {
57
+ date: new Date(a.date || a.createdAt).toISOString().substring(0, 16),
58
+ actionType: a.actionType,
59
+ company: a.data?.company?.name ?? '',
60
+ jobTitle: a.data?.job?.title ?? '',
61
+ status: a.data?.toList?.name ?? '',
62
+ url: job?.url ?? '',
63
+ };
64
+ });
65
+ }
66
+ }
@@ -0,0 +1,14 @@
1
+ import { HuntrApiClient } from '../client';
2
+ import { Board } from '../../types/personal';
3
+
4
+ export class PersonalBoardsApi {
5
+ constructor(private client: HuntrApiClient) {}
6
+
7
+ async list(): Promise<Board[]> {
8
+ return this.client.get<Board[]>('/boards');
9
+ }
10
+
11
+ async get(boardId: string): Promise<Board> {
12
+ return this.client.get<Board>(`/boards/${boardId}`);
13
+ }
14
+ }
@@ -0,0 +1,25 @@
1
+ import { createClient, TokenProvider } from '../client';
2
+ import { PersonalUserApi } from './user';
3
+ import { PersonalBoardsApi } from './boards';
4
+ import { PersonalJobsApi } from './jobs';
5
+ import { PersonalActionsApi } from './activities';
6
+
7
+ export class HuntrPersonalApi {
8
+ public user: PersonalUserApi;
9
+ public boards: PersonalBoardsApi;
10
+ public jobs: PersonalJobsApi;
11
+ public actions: PersonalActionsApi;
12
+
13
+ constructor(tokenProvider: TokenProvider) {
14
+ const client = createClient(tokenProvider, 'https://api.huntr.co/api');
15
+ this.user = new PersonalUserApi(client);
16
+ this.boards = new PersonalBoardsApi(client);
17
+ this.jobs = new PersonalJobsApi(client);
18
+ this.actions = new PersonalActionsApi(client);
19
+ }
20
+ }
21
+
22
+ export * from './user';
23
+ export * from './boards';
24
+ export * from './jobs';
25
+ export * from './activities';
@@ -0,0 +1,33 @@
1
+ import { HuntrApiClient } from '../client';
2
+ import { PersonalJob, PersonalJobsResponse } from '../../types/personal';
3
+
4
+ export class PersonalJobsApi {
5
+ constructor(private client: HuntrApiClient) {}
6
+
7
+ // API returns { jobs: { [id]: PersonalJob } } — an object map, not an array
8
+ async listByBoard(boardId: string): Promise<PersonalJobsResponse> {
9
+ return this.client.get<PersonalJobsResponse>(`/board/${boardId}/jobs`);
10
+ }
11
+
12
+ // Convenience: returns flat array
13
+ async listByBoardFlat(boardId: string): Promise<PersonalJob[]> {
14
+ const response = await this.listByBoard(boardId);
15
+ return Object.values(response.jobs);
16
+ }
17
+
18
+ async get(boardId: string, jobId: string): Promise<PersonalJob> {
19
+ return this.client.get<PersonalJob>(`/board/${boardId}/jobs/${jobId}`);
20
+ }
21
+
22
+ async create(boardId: string, job: Partial<PersonalJob>): Promise<PersonalJob> {
23
+ return this.client.post<PersonalJob>(`/board/${boardId}/jobs`, job);
24
+ }
25
+
26
+ async update(boardId: string, jobId: string, updates: Partial<PersonalJob>): Promise<PersonalJob> {
27
+ return this.client.put<PersonalJob>(`/board/${boardId}/jobs/${jobId}`, updates);
28
+ }
29
+
30
+ async delete(boardId: string, jobId: string): Promise<void> {
31
+ return this.client.delete<void>(`/board/${boardId}/jobs/${jobId}`);
32
+ }
33
+ }
@@ -0,0 +1,10 @@
1
+ import { HuntrApiClient } from '../client';
2
+ import { UserProfile } from '../../types/personal';
3
+
4
+ export class PersonalUserApi {
5
+ constructor(private client: HuntrApiClient) {}
6
+
7
+ async getProfile(): Promise<UserProfile> {
8
+ return this.client.get<UserProfile>('/me');
9
+ }
10
+ }