@stupidcodefactory/freeagent-mcp-server 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/README.md +187 -0
- package/dist/api/freeagent-client.d.ts +12 -0
- package/dist/api/freeagent-client.d.ts.map +1 -0
- package/dist/api/freeagent-client.js +114 -0
- package/dist/api/freeagent-client.js.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +4 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/rate-limiter.d.ts +15 -0
- package/dist/api/rate-limiter.d.ts.map +1 -0
- package/dist/api/rate-limiter.js +62 -0
- package/dist/api/rate-limiter.js.map +1 -0
- package/dist/api/retry-handler.d.ts +14 -0
- package/dist/api/retry-handler.d.ts.map +1 -0
- package/dist/api/retry-handler.js +49 -0
- package/dist/api/retry-handler.js.map +1 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +4 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth.d.ts +16 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +64 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/token-manager.d.ts +10 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +71 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/auth/token-store.d.ts +10 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +84 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/config.d.ts +73 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +46 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/cash-flow-forecast.d.ts +12 -0
- package/dist/prompts/cash-flow-forecast.d.ts.map +1 -0
- package/dist/prompts/cash-flow-forecast.js +93 -0
- package/dist/prompts/cash-flow-forecast.js.map +1 -0
- package/dist/prompts/index.d.ts +8 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +8 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/invoice-from-description.d.ts +12 -0
- package/dist/prompts/invoice-from-description.d.ts.map +1 -0
- package/dist/prompts/invoice-from-description.js +49 -0
- package/dist/prompts/invoice-from-description.js.map +1 -0
- package/dist/prompts/monthly-expense-summary.d.ts +12 -0
- package/dist/prompts/monthly-expense-summary.d.ts.map +1 -0
- package/dist/prompts/monthly-expense-summary.js +84 -0
- package/dist/prompts/monthly-expense-summary.js.map +1 -0
- package/dist/prompts/overdue-invoice-followup.d.ts +12 -0
- package/dist/prompts/overdue-invoice-followup.d.ts.map +1 -0
- package/dist/prompts/overdue-invoice-followup.js +63 -0
- package/dist/prompts/overdue-invoice-followup.js.map +1 -0
- package/dist/prompts/project-profitability.d.ts +12 -0
- package/dist/prompts/project-profitability.d.ts.map +1 -0
- package/dist/prompts/project-profitability.js +103 -0
- package/dist/prompts/project-profitability.js.map +1 -0
- package/dist/prompts/quarterly-tax-estimate.d.ts +12 -0
- package/dist/prompts/quarterly-tax-estimate.d.ts.map +1 -0
- package/dist/prompts/quarterly-tax-estimate.js +132 -0
- package/dist/prompts/quarterly-tax-estimate.js.map +1 -0
- package/dist/prompts/transaction-categorization.d.ts +12 -0
- package/dist/prompts/transaction-categorization.d.ts.map +1 -0
- package/dist/prompts/transaction-categorization.js +81 -0
- package/dist/prompts/transaction-categorization.js.map +1 -0
- package/dist/resources/bank-accounts.d.ts +8 -0
- package/dist/resources/bank-accounts.d.ts.map +1 -0
- package/dist/resources/bank-accounts.js +34 -0
- package/dist/resources/bank-accounts.js.map +1 -0
- package/dist/resources/bank-transactions.d.ts +11 -0
- package/dist/resources/bank-transactions.d.ts.map +1 -0
- package/dist/resources/bank-transactions.js +34 -0
- package/dist/resources/bank-transactions.js.map +1 -0
- package/dist/resources/bills.d.ts +13 -0
- package/dist/resources/bills.d.ts.map +1 -0
- package/dist/resources/bills.js +38 -0
- package/dist/resources/bills.js.map +1 -0
- package/dist/resources/categories.d.ts +4 -0
- package/dist/resources/categories.d.ts.map +1 -0
- package/dist/resources/categories.js +21 -0
- package/dist/resources/categories.js.map +1 -0
- package/dist/resources/company.d.ts +3 -0
- package/dist/resources/company.d.ts.map +1 -0
- package/dist/resources/company.js +12 -0
- package/dist/resources/company.js.map +1 -0
- package/dist/resources/contacts.d.ts +9 -0
- package/dist/resources/contacts.d.ts.map +1 -0
- package/dist/resources/contacts.js +37 -0
- package/dist/resources/contacts.js.map +1 -0
- package/dist/resources/expenses.d.ts +12 -0
- package/dist/resources/expenses.d.ts.map +1 -0
- package/dist/resources/expenses.js +36 -0
- package/dist/resources/expenses.js.map +1 -0
- package/dist/resources/index.d.ts +20 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +12 -0
- package/dist/resources/index.js.map +1 -0
- package/dist/resources/invoices.d.ts +14 -0
- package/dist/resources/invoices.d.ts.map +1 -0
- package/dist/resources/invoices.js +40 -0
- package/dist/resources/invoices.js.map +1 -0
- package/dist/resources/projects.d.ts +10 -0
- package/dist/resources/projects.d.ts.map +1 -0
- package/dist/resources/projects.js +39 -0
- package/dist/resources/projects.js.map +1 -0
- package/dist/resources/timeslips.d.ts +12 -0
- package/dist/resources/timeslips.d.ts.map +1 -0
- package/dist/resources/timeslips.js +36 -0
- package/dist/resources/timeslips.js.map +1 -0
- package/dist/resources/users.d.ts +5 -0
- package/dist/resources/users.d.ts.map +1 -0
- package/dist/resources/users.js +30 -0
- package/dist/resources/users.js.map +1 -0
- package/dist/server.d.ts +9 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +568 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/bank-tools.d.ts +112 -0
- package/dist/tools/bank-tools.d.ts.map +1 -0
- package/dist/tools/bank-tools.js +143 -0
- package/dist/tools/bank-tools.js.map +1 -0
- package/dist/tools/bill-tools.d.ts +129 -0
- package/dist/tools/bill-tools.d.ts.map +1 -0
- package/dist/tools/bill-tools.js +121 -0
- package/dist/tools/bill-tools.js.map +1 -0
- package/dist/tools/contact-tools.d.ts +147 -0
- package/dist/tools/contact-tools.d.ts.map +1 -0
- package/dist/tools/contact-tools.js +140 -0
- package/dist/tools/contact-tools.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/invoice-tools.d.ts +171 -0
- package/dist/tools/invoice-tools.d.ts.map +1 -0
- package/dist/tools/invoice-tools.js +168 -0
- package/dist/tools/invoice-tools.js.map +1 -0
- package/dist/tools/project-tools.d.ts +117 -0
- package/dist/tools/project-tools.d.ts.map +1 -0
- package/dist/tools/project-tools.js +153 -0
- package/dist/tools/project-tools.js.map +1 -0
- package/dist/tools/query-tools.d.ts +91 -0
- package/dist/tools/query-tools.d.ts.map +1 -0
- package/dist/tools/query-tools.js +127 -0
- package/dist/tools/query-tools.js.map +1 -0
- package/dist/transformers/bank-transformer.d.ts +8 -0
- package/dist/transformers/bank-transformer.d.ts.map +1 -0
- package/dist/transformers/bank-transformer.js +46 -0
- package/dist/transformers/bank-transformer.js.map +1 -0
- package/dist/transformers/bill-transformer.d.ts +6 -0
- package/dist/transformers/bill-transformer.d.ts.map +1 -0
- package/dist/transformers/bill-transformer.js +34 -0
- package/dist/transformers/bill-transformer.js.map +1 -0
- package/dist/transformers/category-transformer.d.ts +5 -0
- package/dist/transformers/category-transformer.d.ts.map +1 -0
- package/dist/transformers/category-transformer.js +14 -0
- package/dist/transformers/category-transformer.js.map +1 -0
- package/dist/transformers/common.d.ts +7 -0
- package/dist/transformers/common.d.ts.map +1 -0
- package/dist/transformers/common.js +33 -0
- package/dist/transformers/common.js.map +1 -0
- package/dist/transformers/company-transformer.d.ts +4 -0
- package/dist/transformers/company-transformer.d.ts.map +1 -0
- package/dist/transformers/company-transformer.js +10 -0
- package/dist/transformers/company-transformer.js.map +1 -0
- package/dist/transformers/contact-transformer.d.ts +5 -0
- package/dist/transformers/contact-transformer.d.ts.map +1 -0
- package/dist/transformers/contact-transformer.js +18 -0
- package/dist/transformers/contact-transformer.js.map +1 -0
- package/dist/transformers/expense-transformer.d.ts +5 -0
- package/dist/transformers/expense-transformer.d.ts.map +1 -0
- package/dist/transformers/expense-transformer.js +19 -0
- package/dist/transformers/expense-transformer.js.map +1 -0
- package/dist/transformers/index.d.ts +11 -0
- package/dist/transformers/index.d.ts.map +1 -0
- package/dist/transformers/index.js +11 -0
- package/dist/transformers/index.js.map +1 -0
- package/dist/transformers/invoice-transformer.d.ts +6 -0
- package/dist/transformers/invoice-transformer.d.ts.map +1 -0
- package/dist/transformers/invoice-transformer.js +39 -0
- package/dist/transformers/invoice-transformer.js.map +1 -0
- package/dist/transformers/project-transformer.d.ts +9 -0
- package/dist/transformers/project-transformer.d.ts.map +1 -0
- package/dist/transformers/project-transformer.js +53 -0
- package/dist/transformers/project-transformer.js.map +1 -0
- package/dist/transformers/user-transformer.d.ts +5 -0
- package/dist/transformers/user-transformer.d.ts.map +1 -0
- package/dist/transformers/user-transformer.js +14 -0
- package/dist/transformers/user-transformer.js.map +1 -0
- package/dist/types/freeagent/index.d.ts +256 -0
- package/dist/types/freeagent/index.d.ts.map +1 -0
- package/dist/types/freeagent/index.js +3 -0
- package/dist/types/freeagent/index.js.map +1 -0
- package/dist/types/llm/index.d.ts +159 -0
- package/dist/types/llm/index.d.ts.map +1 -0
- package/dist/types/llm/index.js +3 -0
- package/dist/types/llm/index.js.map +1 -0
- package/dist/utils/error-handler.d.ts +11 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +57 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/sanitizer.d.ts +4 -0
- package/dist/utils/sanitizer.d.ts.map +1 -0
- package/dist/utils/sanitizer.js +42 -0
- package/dist/utils/sanitizer.js.map +1 -0
- package/dist/utils/validators.d.ts +19 -0
- package/dist/utils/validators.d.ts.map +1 -0
- package/dist/utils/validators.js +83 -0
- package/dist/utils/validators.js.map +1 -0
- package/dist/utils/zod-to-json-schema.d.ts +24 -0
- package/dist/utils/zod-to-json-schema.d.ts.map +1 -0
- package/dist/utils/zod-to-json-schema.js +141 -0
- package/dist/utils/zod-to-json-schema.js.map +1 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# FreeAgent MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the FreeAgent accounting API. Enables LLMs to securely access and manage accounting data including contacts, invoices, bills, bank transactions, and more.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js 24 LTS or later
|
|
8
|
+
- A FreeAgent account with API access
|
|
9
|
+
- FreeAgent API credentials (Client ID and Secret)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
### From npm (recommended)
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g freeagent-mcp-server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### From source
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/StupidCodeFactory/freeagent-mcp.git
|
|
23
|
+
cd freeagent-mcp
|
|
24
|
+
npm install
|
|
25
|
+
npm run build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
### 1. Get FreeAgent API Credentials
|
|
31
|
+
|
|
32
|
+
1. Log in to your FreeAgent account
|
|
33
|
+
2. Go to **Settings** → **Integrations** → **Developer Dashboard**
|
|
34
|
+
3. Create a new app to get your Client ID and Client Secret
|
|
35
|
+
4. Set the redirect URI to `http://localhost:3000/callback`
|
|
36
|
+
|
|
37
|
+
### 2. Set Environment Variables
|
|
38
|
+
|
|
39
|
+
Create a `.env` file or export the following environment variables:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export FREEAGENT_CLIENT_ID="your_client_id"
|
|
43
|
+
export FREEAGENT_CLIENT_SECRET="your_client_secret"
|
|
44
|
+
export FREEAGENT_REDIRECT_URI="http://localhost:3000/callback"
|
|
45
|
+
export FREEAGENT_ENVIRONMENT="sandbox" # or "production"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Optional:
|
|
49
|
+
```bash
|
|
50
|
+
export TOKEN_ENCRYPTION_KEY="$(openssl rand -hex 32)" # For persistent token storage
|
|
51
|
+
export LOG_LEVEL="info"
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage with Claude Desktop
|
|
55
|
+
|
|
56
|
+
Add to your Claude Desktop configuration file:
|
|
57
|
+
|
|
58
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
59
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"freeagent": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["freeagent-mcp-server"],
|
|
67
|
+
"env": {
|
|
68
|
+
"FREEAGENT_CLIENT_ID": "your_client_id",
|
|
69
|
+
"FREEAGENT_CLIENT_SECRET": "your_client_secret",
|
|
70
|
+
"FREEAGENT_REDIRECT_URI": "http://localhost:3000/callback",
|
|
71
|
+
"FREEAGENT_ENVIRONMENT": "sandbox"
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or if installed from source:
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"mcpServers": {
|
|
83
|
+
"freeagent": {
|
|
84
|
+
"command": "node",
|
|
85
|
+
"args": ["/path/to/freeagent-mcp/dist/index.js"],
|
|
86
|
+
"env": {
|
|
87
|
+
"FREEAGENT_CLIENT_ID": "your_client_id",
|
|
88
|
+
"FREEAGENT_CLIENT_SECRET": "your_client_secret",
|
|
89
|
+
"FREEAGENT_REDIRECT_URI": "http://localhost:3000/callback",
|
|
90
|
+
"FREEAGENT_ENVIRONMENT": "sandbox"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Authentication
|
|
98
|
+
|
|
99
|
+
On first use, the server will provide an authorization URL. Visit this URL to authorize the app with your FreeAgent account. After authorization, tokens are stored and refreshed automatically.
|
|
100
|
+
|
|
101
|
+
## Available Resources
|
|
102
|
+
|
|
103
|
+
| Resource | URI | Description |
|
|
104
|
+
|----------|-----|-------------|
|
|
105
|
+
| Company | `freeagent://company` | Company profile and settings |
|
|
106
|
+
| Contacts | `freeagent://contacts` | Clients and suppliers |
|
|
107
|
+
| Invoices | `freeagent://invoices` | Sales invoices |
|
|
108
|
+
| Bills | `freeagent://bills` | Supplier bills |
|
|
109
|
+
| Bank Accounts | `freeagent://bank_accounts` | Bank account list |
|
|
110
|
+
| Bank Transactions | `freeagent://bank_transactions?bank_account={id}` | Transaction feed |
|
|
111
|
+
| Projects | `freeagent://projects` | Projects |
|
|
112
|
+
| Timeslips | `freeagent://timeslips` | Time entries |
|
|
113
|
+
| Expenses | `freeagent://expenses` | Expense claims |
|
|
114
|
+
| Categories | `freeagent://categories` | Account categories |
|
|
115
|
+
| Users | `freeagent://users` | Team members |
|
|
116
|
+
|
|
117
|
+
## Available Tools
|
|
118
|
+
|
|
119
|
+
### Invoices
|
|
120
|
+
- `create_invoice` - Create a new invoice
|
|
121
|
+
- `update_invoice` - Update a draft invoice
|
|
122
|
+
- `send_invoice` - Email invoice to contact
|
|
123
|
+
- `mark_invoice_sent` - Mark as sent without emailing
|
|
124
|
+
- `mark_invoice_paid` - Record payment
|
|
125
|
+
- `delete_invoice` - Delete draft invoice
|
|
126
|
+
|
|
127
|
+
### Contacts
|
|
128
|
+
- `create_contact` - Add new client/supplier
|
|
129
|
+
- `update_contact` - Update contact details
|
|
130
|
+
- `delete_contact` - Remove contact
|
|
131
|
+
|
|
132
|
+
### Bank Transactions
|
|
133
|
+
- `explain_transaction` - Categorize transaction
|
|
134
|
+
- `match_transaction_to_invoice` - Match to invoice payment
|
|
135
|
+
- `match_transaction_to_bill` - Match to bill payment
|
|
136
|
+
- `split_transaction` - Split across categories
|
|
137
|
+
- `unexplain_transaction` - Remove explanation
|
|
138
|
+
|
|
139
|
+
### Bills
|
|
140
|
+
- `create_bill` - Record supplier bill
|
|
141
|
+
- `update_bill` - Modify bill
|
|
142
|
+
- `delete_bill` - Remove bill
|
|
143
|
+
|
|
144
|
+
### Projects
|
|
145
|
+
- `create_project` - Create project
|
|
146
|
+
- `update_project` - Update project
|
|
147
|
+
- `create_task` - Add task to project
|
|
148
|
+
- `create_timeslip` - Log time entry
|
|
149
|
+
|
|
150
|
+
### Queries
|
|
151
|
+
- `list_unpaid_invoices` - Get overdue/open invoices
|
|
152
|
+
- `get_bank_summary` - Aggregate balances
|
|
153
|
+
- `search_transactions` - Search by description
|
|
154
|
+
- `get_unexplained_transactions` - List unexplained transactions
|
|
155
|
+
|
|
156
|
+
## Available Prompts
|
|
157
|
+
|
|
158
|
+
- `monthly_expense_summary` - Categorized expense report
|
|
159
|
+
- `invoice_from_description` - Create invoice from natural language
|
|
160
|
+
- `cash_flow_forecast` - Project cash position (30/60/90 days)
|
|
161
|
+
- `overdue_invoice_followup` - Draft reminder emails
|
|
162
|
+
- `transaction_categorization` - Suggest categories for unexplained transactions
|
|
163
|
+
- `project_profitability` - Analyze project margins
|
|
164
|
+
- `quarterly_tax_estimate` - Estimate tax liability
|
|
165
|
+
|
|
166
|
+
## Development
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Install dependencies
|
|
170
|
+
npm install
|
|
171
|
+
|
|
172
|
+
# Run in development mode
|
|
173
|
+
npm run dev
|
|
174
|
+
|
|
175
|
+
# Run tests
|
|
176
|
+
npm test
|
|
177
|
+
|
|
178
|
+
# Type check
|
|
179
|
+
npm run typecheck
|
|
180
|
+
|
|
181
|
+
# Build
|
|
182
|
+
npm run build
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TokenManager } from '../auth/token-manager.js';
|
|
2
|
+
import { type RateLimiter } from './rate-limiter.js';
|
|
3
|
+
export interface FreeAgentClient {
|
|
4
|
+
get<T>(endpoint: string, params?: Record<string, string>): Promise<T>;
|
|
5
|
+
post<T>(endpoint: string, body: unknown): Promise<T>;
|
|
6
|
+
put<T>(endpoint: string, body: unknown): Promise<T>;
|
|
7
|
+
delete(endpoint: string): Promise<void>;
|
|
8
|
+
fetchAllPages<T>(endpoint: string, entityKey: string, params?: Record<string, string>): Promise<T[]>;
|
|
9
|
+
getRateLimitStatus(): ReturnType<RateLimiter['getStatus']>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createFreeAgentClient(tokenManager: TokenManager): FreeAgentClient;
|
|
12
|
+
//# sourceMappingURL=freeagent-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freeagent-client.d.ts","sourceRoot":"","sources":["../../src/api/freeagent-client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGxE,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACtE,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACrD,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,aAAa,CAAC,CAAC,EACb,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAChB,kBAAkB,IAAI,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC;CAC5D;AAQD,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,YAAY,GAAG,eAAe,CAmJjF"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { FREEAGENT_API_BASE } from '../config.js';
|
|
2
|
+
import { createRateLimiter } from './rate-limiter.js';
|
|
3
|
+
import { withRetry } from './retry-handler.js';
|
|
4
|
+
export function createFreeAgentClient(tokenManager) {
|
|
5
|
+
const rateLimiter = createRateLimiter();
|
|
6
|
+
async function request(method, endpoint, body, params) {
|
|
7
|
+
return withRetry(async () => {
|
|
8
|
+
await rateLimiter.checkLimits();
|
|
9
|
+
const accessToken = await tokenManager.getAccessToken();
|
|
10
|
+
let url = `${FREEAGENT_API_BASE}${endpoint}`;
|
|
11
|
+
if (params && Object.keys(params).length > 0) {
|
|
12
|
+
const searchParams = new URLSearchParams(params);
|
|
13
|
+
url += `?${searchParams.toString()}`;
|
|
14
|
+
}
|
|
15
|
+
const headers = {
|
|
16
|
+
Authorization: `Bearer ${accessToken}`,
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
Accept: 'application/json',
|
|
19
|
+
'User-Agent': 'FreeAgent-MCP-Server/1.0.0',
|
|
20
|
+
};
|
|
21
|
+
const options = {
|
|
22
|
+
method,
|
|
23
|
+
headers,
|
|
24
|
+
};
|
|
25
|
+
if (body && (method === 'POST' || method === 'PUT')) {
|
|
26
|
+
options.body = JSON.stringify(body);
|
|
27
|
+
}
|
|
28
|
+
const response = await fetch(url, options);
|
|
29
|
+
rateLimiter.recordRequest();
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
const error = await parseErrorResponse(response);
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
if (method === 'DELETE' || response.status === 204) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return response.json();
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async function parseErrorResponse(response) {
|
|
41
|
+
let message;
|
|
42
|
+
let retryAfter;
|
|
43
|
+
try {
|
|
44
|
+
const data = (await response.json());
|
|
45
|
+
if (data.errors && data.errors.length > 0) {
|
|
46
|
+
message = data.errors.map((e) => e.message).join('; ');
|
|
47
|
+
}
|
|
48
|
+
else if (data.error_description) {
|
|
49
|
+
message = data.error_description;
|
|
50
|
+
}
|
|
51
|
+
else if (data.error) {
|
|
52
|
+
message = data.error;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
message = `HTTP ${response.status}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
message = `HTTP ${response.status}: ${response.statusText}`;
|
|
60
|
+
}
|
|
61
|
+
const retryAfterHeader = response.headers.get('Retry-After');
|
|
62
|
+
if (retryAfterHeader) {
|
|
63
|
+
retryAfter = parseInt(retryAfterHeader, 10);
|
|
64
|
+
}
|
|
65
|
+
const error = new Error(message);
|
|
66
|
+
error.status = response.status;
|
|
67
|
+
error.retryAfter = retryAfter;
|
|
68
|
+
return error;
|
|
69
|
+
}
|
|
70
|
+
const client = {
|
|
71
|
+
async get(endpoint, params) {
|
|
72
|
+
return request('GET', endpoint, undefined, params);
|
|
73
|
+
},
|
|
74
|
+
async post(endpoint, body) {
|
|
75
|
+
return request('POST', endpoint, body);
|
|
76
|
+
},
|
|
77
|
+
async put(endpoint, body) {
|
|
78
|
+
return request('PUT', endpoint, body);
|
|
79
|
+
},
|
|
80
|
+
async delete(endpoint) {
|
|
81
|
+
await request('DELETE', endpoint);
|
|
82
|
+
},
|
|
83
|
+
async fetchAllPages(endpoint, entityKey, params = {}) {
|
|
84
|
+
const results = [];
|
|
85
|
+
let page = 1;
|
|
86
|
+
const perPage = '100';
|
|
87
|
+
const maxPages = 50; // Safety limit
|
|
88
|
+
while (page <= maxPages) {
|
|
89
|
+
const pageParams = {
|
|
90
|
+
...params,
|
|
91
|
+
page: page.toString(),
|
|
92
|
+
per_page: perPage,
|
|
93
|
+
};
|
|
94
|
+
const response = await request('GET', endpoint, undefined, pageParams);
|
|
95
|
+
const items = response[entityKey];
|
|
96
|
+
if (!items || items.length === 0) {
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
results.push(...items);
|
|
100
|
+
// If we got fewer than requested, we're done
|
|
101
|
+
if (items.length < parseInt(perPage, 10)) {
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
page++;
|
|
105
|
+
}
|
|
106
|
+
return results;
|
|
107
|
+
},
|
|
108
|
+
getRateLimitStatus() {
|
|
109
|
+
return rateLimiter.getStatus();
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
return client;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=freeagent-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freeagent-client.js","sourceRoot":"","sources":["../../src/api/freeagent-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createFreeAgentClient } from './freeagent-client.js';
|
|
2
|
+
export type { FreeAgentClient } from './freeagent-client.js';
|
|
3
|
+
export { createRateLimiter } from './rate-limiter.js';
|
|
4
|
+
export type { RateLimiter, RateLimitStatus } from './rate-limiter.js';
|
|
5
|
+
export { withRetry, isHttpError, DEFAULT_RETRY_CONFIG } from './retry-handler.js';
|
|
6
|
+
export type { RetryConfig, HttpError } from './retry-handler.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAClF,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface RateLimiter {
|
|
2
|
+
checkLimits(): Promise<void>;
|
|
3
|
+
recordRequest(): void;
|
|
4
|
+
getStatus(): RateLimitStatus;
|
|
5
|
+
}
|
|
6
|
+
export interface RateLimitStatus {
|
|
7
|
+
minuteCount: number;
|
|
8
|
+
minuteLimit: number;
|
|
9
|
+
hourCount: number;
|
|
10
|
+
hourLimit: number;
|
|
11
|
+
minuteResetAt: number;
|
|
12
|
+
hourResetAt: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function createRateLimiter(): RateLimiter;
|
|
15
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../../src/api/rate-limiter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,aAAa,IAAI,IAAI,CAAC;IACtB,SAAS,IAAI,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;CACrB;AAKD,wBAAgB,iBAAiB,IAAI,WAAW,CAiE/C"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
const MINUTE_LIMIT = 100; // Buffer below 120
|
|
2
|
+
const HOUR_LIMIT = 3400; // Buffer below 3600
|
|
3
|
+
export function createRateLimiter() {
|
|
4
|
+
let minuteCount = 0;
|
|
5
|
+
let hourCount = 0;
|
|
6
|
+
let minuteResetAt = Date.now() + 60 * 1000;
|
|
7
|
+
let hourResetAt = Date.now() + 60 * 60 * 1000;
|
|
8
|
+
function resetCountersIfNeeded() {
|
|
9
|
+
const now = Date.now();
|
|
10
|
+
if (now >= minuteResetAt) {
|
|
11
|
+
minuteCount = 0;
|
|
12
|
+
minuteResetAt = now + 60 * 1000;
|
|
13
|
+
}
|
|
14
|
+
if (now >= hourResetAt) {
|
|
15
|
+
hourCount = 0;
|
|
16
|
+
hourResetAt = now + 60 * 60 * 1000;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const limiter = {
|
|
20
|
+
async checkLimits() {
|
|
21
|
+
resetCountersIfNeeded();
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
// Check minute limit
|
|
24
|
+
if (minuteCount >= MINUTE_LIMIT) {
|
|
25
|
+
const waitTime = minuteResetAt - now;
|
|
26
|
+
if (waitTime > 0) {
|
|
27
|
+
await sleep(waitTime);
|
|
28
|
+
resetCountersIfNeeded();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Check hour limit
|
|
32
|
+
if (hourCount >= HOUR_LIMIT) {
|
|
33
|
+
const waitTime = hourResetAt - now;
|
|
34
|
+
if (waitTime > 0) {
|
|
35
|
+
await sleep(waitTime);
|
|
36
|
+
resetCountersIfNeeded();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
recordRequest() {
|
|
41
|
+
resetCountersIfNeeded();
|
|
42
|
+
minuteCount++;
|
|
43
|
+
hourCount++;
|
|
44
|
+
},
|
|
45
|
+
getStatus() {
|
|
46
|
+
resetCountersIfNeeded();
|
|
47
|
+
return {
|
|
48
|
+
minuteCount,
|
|
49
|
+
minuteLimit: MINUTE_LIMIT,
|
|
50
|
+
hourCount,
|
|
51
|
+
hourLimit: HOUR_LIMIT,
|
|
52
|
+
minuteResetAt,
|
|
53
|
+
hourResetAt,
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
return limiter;
|
|
58
|
+
}
|
|
59
|
+
function sleep(ms) {
|
|
60
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../src/api/rate-limiter.ts"],"names":[],"mappings":"AAeA,MAAM,YAAY,GAAG,GAAG,CAAC,CAAC,mBAAmB;AAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,oBAAoB;AAE7C,MAAM,UAAU,iBAAiB;IAC/B,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAC3C,IAAI,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;IAE9C,SAAS,qBAAqB;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,GAAG,IAAI,aAAa,EAAE,CAAC;YACzB,WAAW,GAAG,CAAC,CAAC;YAChB,aAAa,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;QAClC,CAAC;QAED,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;YACvB,SAAS,GAAG,CAAC,CAAC;YACd,WAAW,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QACrC,CAAC;IACH,CAAC;IAED,MAAM,OAAO,GAAgB;QAC3B,KAAK,CAAC,WAAW;YACf,qBAAqB,EAAE,CAAC;YAExB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAEvB,qBAAqB;YACrB,IAAI,WAAW,IAAI,YAAY,EAAE,CAAC;gBAChC,MAAM,QAAQ,GAAG,aAAa,GAAG,GAAG,CAAC;gBACrC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;oBACjB,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;oBACtB,qBAAqB,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC;YAED,mBAAmB;YACnB,IAAI,SAAS,IAAI,UAAU,EAAE,CAAC;gBAC5B,MAAM,QAAQ,GAAG,WAAW,GAAG,GAAG,CAAC;gBACnC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;oBACjB,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;oBACtB,qBAAqB,EAAE,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QAED,aAAa;YACX,qBAAqB,EAAE,CAAC;YACxB,WAAW,EAAE,CAAC;YACd,SAAS,EAAE,CAAC;QACd,CAAC;QAED,SAAS;YACP,qBAAqB,EAAE,CAAC;YACxB,OAAO;gBACL,WAAW;gBACX,WAAW,EAAE,YAAY;gBACzB,SAAS;gBACT,SAAS,EAAE,UAAU;gBACrB,aAAa;gBACb,WAAW;aACZ,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RetryConfig {
|
|
2
|
+
maxRetries: number;
|
|
3
|
+
baseDelayMs: number;
|
|
4
|
+
maxDelayMs: number;
|
|
5
|
+
retryableStatuses: number[];
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_RETRY_CONFIG: RetryConfig;
|
|
8
|
+
export interface HttpError extends Error {
|
|
9
|
+
status: number;
|
|
10
|
+
retryAfter?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare function isHttpError(error: unknown): error is HttpError;
|
|
13
|
+
export declare function withRetry<T>(fn: () => Promise<T>, config?: RetryConfig): Promise<T>;
|
|
14
|
+
//# sourceMappingURL=retry-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-handler.d.ts","sourceRoot":"","sources":["../../src/api/retry-handler.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,eAAO,MAAM,oBAAoB,EAAE,WAKlC,CAAC;AAEF,MAAM,WAAW,SAAU,SAAQ,KAAK;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,MAAM,GAAE,WAAkC,GACzC,OAAO,CAAC,CAAC,CAAC,CAwCZ"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const DEFAULT_RETRY_CONFIG = {
|
|
2
|
+
maxRetries: 3,
|
|
3
|
+
baseDelayMs: 1000,
|
|
4
|
+
maxDelayMs: 30000,
|
|
5
|
+
retryableStatuses: [429, 500, 502, 503, 504],
|
|
6
|
+
};
|
|
7
|
+
export function isHttpError(error) {
|
|
8
|
+
return error instanceof Error && 'status' in error && typeof error.status === 'number';
|
|
9
|
+
}
|
|
10
|
+
export async function withRetry(fn, config = DEFAULT_RETRY_CONFIG) {
|
|
11
|
+
let lastError;
|
|
12
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
13
|
+
try {
|
|
14
|
+
return await fn();
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!(error instanceof Error)) {
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
lastError = error;
|
|
21
|
+
// Check if error is retryable
|
|
22
|
+
if (!isHttpError(error) || !config.retryableStatuses.includes(error.status)) {
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
// Don't retry after last attempt
|
|
26
|
+
if (attempt === config.maxRetries) {
|
|
27
|
+
throw error;
|
|
28
|
+
}
|
|
29
|
+
// Calculate delay
|
|
30
|
+
let delay;
|
|
31
|
+
if (error.status === 429 && error.retryAfter) {
|
|
32
|
+
// Use server-provided retry-after value
|
|
33
|
+
delay = error.retryAfter * 1000;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Exponential backoff with jitter
|
|
37
|
+
const exponentialDelay = config.baseDelayMs * Math.pow(2, attempt);
|
|
38
|
+
const jitter = Math.random() * 0.3 * exponentialDelay; // 0-30% jitter
|
|
39
|
+
delay = Math.min(exponentialDelay + jitter, config.maxDelayMs);
|
|
40
|
+
}
|
|
41
|
+
await sleep(delay);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
throw lastError ?? new Error('Retry failed');
|
|
45
|
+
}
|
|
46
|
+
function sleep(ms) {
|
|
47
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=retry-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retry-handler.js","sourceRoot":"","sources":["../../src/api/retry-handler.ts"],"names":[],"mappings":"AAOA,MAAM,CAAC,MAAM,oBAAoB,GAAgB;IAC/C,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,KAAK;IACjB,iBAAiB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC;CAC7C,CAAC;AAOF,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,QAAQ,IAAI,KAAK,IAAI,OAAQ,KAAmB,CAAC,MAAM,KAAK,QAAQ,CAAC;AACxG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,SAAsB,oBAAoB;IAE1C,IAAI,SAA4B,CAAC;IAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QAC9D,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,KAAK,CAAC;YACd,CAAC;YAED,SAAS,GAAG,KAAK,CAAC;YAElB,8BAA8B;YAC9B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5E,MAAM,KAAK,CAAC;YACd,CAAC;YAED,iCAAiC;YACjC,IAAI,OAAO,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;gBAClC,MAAM,KAAK,CAAC;YACd,CAAC;YAED,kBAAkB;YAClB,IAAI,KAAa,CAAC;YAClB,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;gBAC7C,wCAAwC;gBACxC,KAAK,GAAG,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;YAClC,CAAC;iBAAM,CAAC;gBACN,kCAAkC;gBAClC,MAAM,gBAAgB,GAAG,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;gBACnE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,gBAAgB,CAAC,CAAC,eAAe;gBACtE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,GAAG,MAAM,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YACjE,CAAC;YAED,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { generateAuthorizationUrl, exchangeCodeForTokens, refreshAccessToken } from './oauth.js';
|
|
2
|
+
export type { TokenData } from './oauth.js';
|
|
3
|
+
export { createTokenStore } from './token-store.js';
|
|
4
|
+
export type { TokenStore } from './token-store.js';
|
|
5
|
+
export { createTokenManager } from './token-manager.js';
|
|
6
|
+
export type { TokenManager } from './token-manager.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACjG,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface TokenResponse {
|
|
2
|
+
access_token: string;
|
|
3
|
+
token_type: string;
|
|
4
|
+
expires_in: number;
|
|
5
|
+
refresh_token: string;
|
|
6
|
+
}
|
|
7
|
+
export interface TokenData {
|
|
8
|
+
accessToken: string;
|
|
9
|
+
refreshToken: string;
|
|
10
|
+
expiresAt: number;
|
|
11
|
+
refreshTokenExpiresAt: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function generateAuthorizationUrl(state?: string): string;
|
|
14
|
+
export declare function exchangeCodeForTokens(code: string): Promise<TokenData>;
|
|
15
|
+
export declare function refreshAccessToken(refreshToken: string): Promise<TokenData>;
|
|
16
|
+
//# sourceMappingURL=oauth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,wBAAwB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAY/D;AAED,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAyB5E;AAED,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAwBjF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { config, FREEAGENT_AUTH_URL, FREEAGENT_TOKEN_URL } from '../config.js';
|
|
2
|
+
export function generateAuthorizationUrl(state) {
|
|
3
|
+
const params = new URLSearchParams({
|
|
4
|
+
client_id: config.freeagent.clientId,
|
|
5
|
+
redirect_uri: config.freeagent.redirectUri,
|
|
6
|
+
response_type: 'code',
|
|
7
|
+
});
|
|
8
|
+
if (state) {
|
|
9
|
+
params.set('state', state);
|
|
10
|
+
}
|
|
11
|
+
return `${FREEAGENT_AUTH_URL}?${params.toString()}`;
|
|
12
|
+
}
|
|
13
|
+
export async function exchangeCodeForTokens(code) {
|
|
14
|
+
const credentials = Buffer.from(`${config.freeagent.clientId}:${config.freeagent.clientSecret}`).toString('base64');
|
|
15
|
+
const response = await fetch(FREEAGENT_TOKEN_URL, {
|
|
16
|
+
method: 'POST',
|
|
17
|
+
headers: {
|
|
18
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
19
|
+
Authorization: `Basic ${credentials}`,
|
|
20
|
+
},
|
|
21
|
+
body: new URLSearchParams({
|
|
22
|
+
grant_type: 'authorization_code',
|
|
23
|
+
code,
|
|
24
|
+
redirect_uri: config.freeagent.redirectUri,
|
|
25
|
+
}),
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
const error = await response.text();
|
|
29
|
+
throw new Error(`Token exchange failed: ${response.status} - ${error}`);
|
|
30
|
+
}
|
|
31
|
+
const data = (await response.json());
|
|
32
|
+
return tokenResponseToTokenData(data);
|
|
33
|
+
}
|
|
34
|
+
export async function refreshAccessToken(refreshToken) {
|
|
35
|
+
const credentials = Buffer.from(`${config.freeagent.clientId}:${config.freeagent.clientSecret}`).toString('base64');
|
|
36
|
+
const response = await fetch(FREEAGENT_TOKEN_URL, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
40
|
+
Authorization: `Basic ${credentials}`,
|
|
41
|
+
},
|
|
42
|
+
body: new URLSearchParams({
|
|
43
|
+
grant_type: 'refresh_token',
|
|
44
|
+
refresh_token: refreshToken,
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
const error = await response.text();
|
|
49
|
+
throw new Error(`Token refresh failed: ${response.status} - ${error}`);
|
|
50
|
+
}
|
|
51
|
+
const data = (await response.json());
|
|
52
|
+
return tokenResponseToTokenData(data);
|
|
53
|
+
}
|
|
54
|
+
function tokenResponseToTokenData(response) {
|
|
55
|
+
const now = Date.now();
|
|
56
|
+
return {
|
|
57
|
+
accessToken: response.access_token,
|
|
58
|
+
refreshToken: response.refresh_token,
|
|
59
|
+
expiresAt: now + response.expires_in * 1000,
|
|
60
|
+
// Refresh tokens typically expire in 14 days
|
|
61
|
+
refreshTokenExpiresAt: now + 14 * 24 * 60 * 60 * 1000,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type TokenData } from './oauth.js';
|
|
2
|
+
import type { TokenStore } from './token-store.js';
|
|
3
|
+
export interface TokenManager {
|
|
4
|
+
getAccessToken(): Promise<string>;
|
|
5
|
+
setTokens(tokens: TokenData): Promise<void>;
|
|
6
|
+
isAuthenticated(): boolean;
|
|
7
|
+
clearTokens(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createTokenManager(store: TokenStore): TokenManager;
|
|
10
|
+
//# sourceMappingURL=token-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKnD,MAAM,WAAW,YAAY;IAC3B,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,SAAS,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,eAAe,IAAI,OAAO,CAAC;IAC3B,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,YAAY,CAiFlE"}
|