@codeguide/core 0.0.1

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 (79) hide show
  1. package/__tests__/authentication.test.ts +259 -0
  2. package/__tests__/codeguide.test.ts +293 -0
  3. package/__tests__/services/base/base-service.test.ts +334 -0
  4. package/__tests__/services/generation/generation-service.test.ts +294 -0
  5. package/__tests__/services/usage/usage-service.test.ts +385 -0
  6. package/__tests__/simple.test.ts +10 -0
  7. package/__tests__/test-service.ts +37 -0
  8. package/api-service.ts +67 -0
  9. package/codeguide.ts +70 -0
  10. package/dist/__tests__/test-service.d.ts +12 -0
  11. package/dist/__tests__/test-service.js +32 -0
  12. package/dist/api-service.d.ts +8 -0
  13. package/dist/api-service.js +64 -0
  14. package/dist/codeguide.d.ts +14 -0
  15. package/dist/codeguide.js +53 -0
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.js +31 -0
  18. package/dist/services/base/base-service.d.ts +30 -0
  19. package/dist/services/base/base-service.js +187 -0
  20. package/dist/services/base/index.d.ts +1 -0
  21. package/dist/services/base/index.js +5 -0
  22. package/dist/services/generation/generation-service.d.ts +15 -0
  23. package/dist/services/generation/generation-service.js +40 -0
  24. package/dist/services/generation/generation-types.d.ts +111 -0
  25. package/dist/services/generation/generation-types.js +2 -0
  26. package/dist/services/generation/index.d.ts +2 -0
  27. package/dist/services/generation/index.js +20 -0
  28. package/dist/services/index.d.ts +11 -0
  29. package/dist/services/index.js +45 -0
  30. package/dist/services/projects/index.d.ts +2 -0
  31. package/dist/services/projects/index.js +20 -0
  32. package/dist/services/projects/project-service.d.ts +14 -0
  33. package/dist/services/projects/project-service.js +53 -0
  34. package/dist/services/projects/project-types.d.ts +97 -0
  35. package/dist/services/projects/project-types.js +2 -0
  36. package/dist/services/repository-analysis/index.d.ts +2 -0
  37. package/dist/services/repository-analysis/index.js +20 -0
  38. package/dist/services/repository-analysis/repository-service.d.ts +10 -0
  39. package/dist/services/repository-analysis/repository-service.js +31 -0
  40. package/dist/services/repository-analysis/repository-types.d.ts +90 -0
  41. package/dist/services/repository-analysis/repository-types.js +2 -0
  42. package/dist/services/tasks/index.d.ts +2 -0
  43. package/dist/services/tasks/index.js +20 -0
  44. package/dist/services/tasks/task-service.d.ts +30 -0
  45. package/dist/services/tasks/task-service.js +105 -0
  46. package/dist/services/tasks/task-types.d.ts +144 -0
  47. package/dist/services/tasks/task-types.js +2 -0
  48. package/dist/services/usage/index.d.ts +2 -0
  49. package/dist/services/usage/index.js +20 -0
  50. package/dist/services/usage/usage-service.d.ts +14 -0
  51. package/dist/services/usage/usage-service.js +68 -0
  52. package/dist/services/usage/usage-types.d.ts +133 -0
  53. package/dist/services/usage/usage-types.js +2 -0
  54. package/dist/types.d.ts +42 -0
  55. package/dist/types.js +2 -0
  56. package/index.ts +12 -0
  57. package/jest.config.json +19 -0
  58. package/package.json +45 -0
  59. package/services/README.md +113 -0
  60. package/services/base/base-service.ts +230 -0
  61. package/services/base/index.ts +1 -0
  62. package/services/generation/generation-service.ts +81 -0
  63. package/services/generation/generation-types.ts +131 -0
  64. package/services/generation/index.ts +2 -0
  65. package/services/index.ts +22 -0
  66. package/services/projects/index.ts +2 -0
  67. package/services/projects/project-service.ts +67 -0
  68. package/services/projects/project-types.ts +108 -0
  69. package/services/repository-analysis/index.ts +2 -0
  70. package/services/repository-analysis/repository-service.ts +42 -0
  71. package/services/repository-analysis/repository-types.ts +99 -0
  72. package/services/tasks/index.ts +2 -0
  73. package/services/tasks/task-service.ts +143 -0
  74. package/services/tasks/task-types.ts +165 -0
  75. package/services/usage/index.ts +2 -0
  76. package/services/usage/usage-service.ts +96 -0
  77. package/services/usage/usage-types.ts +147 -0
  78. package/tsconfig.json +10 -0
  79. package/types.ts +51 -0
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.UsageService = void 0;
4
+ const base_service_1 = require("../base/base-service");
5
+ class UsageService extends base_service_1.BaseService {
6
+ async trackUsage(request) {
7
+ return this.post('/usage/track', request);
8
+ }
9
+ async getCreditBalance() {
10
+ return this.get('/usage/credit-balance');
11
+ }
12
+ async checkCredits(params) {
13
+ const queryParams = new URLSearchParams();
14
+ if (params.input_tokens !== undefined)
15
+ queryParams.append('input_tokens', params.input_tokens.toString());
16
+ if (params.output_tokens !== undefined)
17
+ queryParams.append('output_tokens', params.output_tokens.toString());
18
+ if (params.call_seconds !== undefined)
19
+ queryParams.append('call_seconds', params.call_seconds.toString());
20
+ const url = `/usage/credit-check?${queryParams.toString()}`;
21
+ return this.get(url);
22
+ }
23
+ async getUsageSummary(params) {
24
+ const queryParams = new URLSearchParams();
25
+ if (params?.start_date)
26
+ queryParams.append('start_date', params.start_date);
27
+ if (params?.end_date)
28
+ queryParams.append('end_date', params.end_date);
29
+ const url = `/usage/summary${queryParams.toString() ? `?${queryParams.toString()}` : ''}`;
30
+ return this.get(url);
31
+ }
32
+ async getAuthorization() {
33
+ return this.get('/usage/authorization');
34
+ }
35
+ async getFreeUserStatus() {
36
+ return this.get('/usage/free-user-status');
37
+ }
38
+ async calculateUsageCost(params) {
39
+ const queryParams = new URLSearchParams();
40
+ queryParams.append('model_key', params.model_key);
41
+ if (params.input_tokens !== undefined)
42
+ queryParams.append('input_tokens', params.input_tokens.toString());
43
+ if (params.output_tokens !== undefined)
44
+ queryParams.append('output_tokens', params.output_tokens.toString());
45
+ if (params.call_seconds !== undefined)
46
+ queryParams.append('call_seconds', params.call_seconds.toString());
47
+ if (params.cost_amount !== undefined)
48
+ queryParams.append('cost_amount', params.cost_amount.toString());
49
+ const url = `/usage/calculate?${queryParams.toString()}`;
50
+ return this.get(url);
51
+ }
52
+ async trackCodespaceUsage(request) {
53
+ return this.post('/usage/codespace/track', request);
54
+ }
55
+ async getCodespaceTaskUsage(codespaceTaskId) {
56
+ return this.get(`/usage/codespace/task/${codespaceTaskId}`);
57
+ }
58
+ async healthCheck() {
59
+ try {
60
+ const response = await this.get('/usage/health');
61
+ return response.status === 'healthy';
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ }
67
+ }
68
+ exports.UsageService = UsageService;
@@ -0,0 +1,133 @@
1
+ export interface TrackUsageRequest {
2
+ model_key: string;
3
+ input_tokens: number;
4
+ output_tokens: number;
5
+ call_seconds?: number;
6
+ cost_amount?: number;
7
+ }
8
+ export interface TrackUsageResponse {
9
+ success: boolean;
10
+ credits_used: number;
11
+ remaining_credits: number;
12
+ message: string;
13
+ }
14
+ export interface CreditBalanceResponse {
15
+ user_id: string;
16
+ total_consumed: number;
17
+ total_allotted: number;
18
+ remaining_credits: number;
19
+ utilization_percentage: number;
20
+ billing_cycle_start: string;
21
+ billing_cycle_end: string;
22
+ subscription: {
23
+ plan: string;
24
+ status: string;
25
+ };
26
+ }
27
+ export interface CreditCheckRequest {
28
+ model_key: string;
29
+ input_tokens?: number;
30
+ output_tokens?: number;
31
+ call_seconds?: number;
32
+ }
33
+ export interface CreditCheckResponse {
34
+ has_sufficient_credits: boolean;
35
+ estimated_cost: number;
36
+ remaining_credits: number;
37
+ model_key: string;
38
+ }
39
+ export interface UsageSummaryRequest {
40
+ start_date?: string;
41
+ end_date?: string;
42
+ }
43
+ export interface UsageSummaryResponse {
44
+ user_id: string;
45
+ period: {
46
+ start_date: string;
47
+ end_date: string;
48
+ };
49
+ usage_summary: {
50
+ total_credits_used: number;
51
+ total_calls: number;
52
+ model_breakdown: Record<string, any>;
53
+ daily_usage: Array<{
54
+ date: string;
55
+ credits_used: number;
56
+ calls: number;
57
+ }>;
58
+ };
59
+ subscription: {
60
+ plan: string;
61
+ status: string;
62
+ };
63
+ }
64
+ export interface AuthorizationResponse {
65
+ user_id: string;
66
+ subscription: {
67
+ plan: string;
68
+ status: string;
69
+ features: string[];
70
+ };
71
+ usage_limits: {
72
+ monthly_credits: number;
73
+ max_calls_per_day: number;
74
+ };
75
+ permissions: string[];
76
+ }
77
+ export interface FreeUserStatusResponse {
78
+ is_free_user: boolean;
79
+ has_available_credits: boolean;
80
+ credits_remaining: number;
81
+ credits_expire_at?: string;
82
+ }
83
+ export interface CalculateUsageRequest {
84
+ model_key: string;
85
+ input_tokens?: number;
86
+ output_tokens?: number;
87
+ call_seconds?: number;
88
+ cost_amount?: number;
89
+ }
90
+ export interface CalculateUsageResponse {
91
+ model_key: string;
92
+ estimated_cost: number;
93
+ calculation_breakdown: {
94
+ input_cost: number;
95
+ output_cost: number;
96
+ time_cost: number;
97
+ total_cost: number;
98
+ };
99
+ }
100
+ export interface TrackCodespaceUsageRequest {
101
+ codespace_task_id: string;
102
+ model_key: string;
103
+ input_tokens: number;
104
+ output_tokens: number;
105
+ call_seconds?: number;
106
+ cost_amount?: number;
107
+ }
108
+ export interface TrackCodespaceUsageResponse {
109
+ id: string;
110
+ codespace_task_id: string;
111
+ user_id: string;
112
+ model_key: string;
113
+ input_tokens: number;
114
+ output_tokens: number;
115
+ call_seconds: number;
116
+ cost_amount: number;
117
+ created_at: string;
118
+ }
119
+ export interface CodespaceTaskUsageResponse {
120
+ codespace_task_id: string;
121
+ total_usage: {
122
+ total_input_tokens: number;
123
+ total_output_tokens: number;
124
+ total_call_seconds: number;
125
+ total_cost: number;
126
+ };
127
+ usage_records: TrackCodespaceUsageResponse[];
128
+ }
129
+ export interface HealthResponse {
130
+ status: string;
131
+ timestamp: string;
132
+ version: string;
133
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,42 @@
1
+ export interface CodeGuideRequest {
2
+ prompt: string;
3
+ language?: string;
4
+ context?: string;
5
+ }
6
+ export interface CodeGuideResponse {
7
+ id?: string;
8
+ response?: string;
9
+ refined_prompt?: string;
10
+ content?: string;
11
+ timestamp: string;
12
+ language?: string;
13
+ }
14
+ export interface APIServiceConfig {
15
+ baseUrl: string;
16
+ databaseApiKey?: string;
17
+ apiKey?: string;
18
+ userId?: string;
19
+ jwtToken?: string;
20
+ timeout?: number;
21
+ }
22
+ export interface AuthenticationMethod {
23
+ type: 'database-api-key' | 'legacy-api-key' | 'clerk-jwt';
24
+ priority: number;
25
+ headers: Record<string, string>;
26
+ }
27
+ export interface AuthenticationResult {
28
+ success: boolean;
29
+ method?: AuthenticationMethod;
30
+ user?: {
31
+ id: string;
32
+ email?: string;
33
+ subscriptionStatus?: string;
34
+ creditsRemaining?: number;
35
+ };
36
+ error?: string;
37
+ }
38
+ export interface CodeGuideOptions {
39
+ language?: string;
40
+ context?: string;
41
+ verbose?: boolean;
42
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ import dotenv from 'dotenv'
2
+ import path from 'path'
3
+
4
+ // Load environment variables from project root
5
+ dotenv.config({
6
+ path: path.resolve(__dirname, '../../../.env'),
7
+ quiet: true,
8
+ })
9
+
10
+ export { CodeGuide } from './codeguide'
11
+ export * from './services'
12
+ export * from './types'
@@ -0,0 +1,19 @@
1
+ {
2
+ "preset": "ts-jest",
3
+ "testEnvironment": "node",
4
+ "roots": ["<rootDir>"],
5
+ "testMatch": ["**/__tests__/**/*.test.ts"],
6
+ "transform": {
7
+ "^.+\\.ts$": "ts-jest"
8
+ },
9
+ "collectCoverageFrom": [
10
+ "**/*.ts",
11
+ "!**/*.d.ts",
12
+ "!**/index.ts",
13
+ "!**/node_modules/**",
14
+ "!**/__tests__/**"
15
+ ],
16
+ "coverageDirectory": "coverage",
17
+ "coverageReporters": ["text", "lcov"],
18
+ "setupFilesAfterEnv": ["<rootDir>/../../jest.setup.js"]
19
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@codeguide/core",
3
+ "version": "0.0.1",
4
+ "description": "Core package for code guidance with programmatic API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "test": "jest --config=jest.config.json",
10
+ "test:watch": "jest --config=jest.config.json --watch",
11
+ "test:coverage": "jest --config=jest.config.json --coverage"
12
+ },
13
+ "keywords": [
14
+ "api",
15
+ "typescript",
16
+ "code",
17
+ "development",
18
+ "productivity",
19
+ "ai",
20
+ "sdk"
21
+ ],
22
+ "author": "CodeGuide Team",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/CodeGuide-dev/codeguide.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/CodeGuide-dev/codeguide/issues"
29
+ },
30
+ "homepage": "https://github.com/CodeGuide-dev/codeguide#readme",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "axios": "^1.6.0",
34
+ "dotenv": "^17.2.2"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "typescript": "^5.0.0",
39
+ "jest": "^29.0.0",
40
+ "@types/jest": "^29.0.0",
41
+ "ts-jest": "^29.0.0",
42
+ "axios-mock-adapter": "^1.22.0",
43
+ "@types/dotenv": "^6.1.1"
44
+ }
45
+ }
@@ -0,0 +1,113 @@
1
+ # CodeGuide API Services
2
+
3
+ This directory contains modular services for interacting with different CodeGuide API endpoints.
4
+
5
+ ## Available Services
6
+
7
+ ### 1. GenerationService (`/generate`)
8
+
9
+ Handles AI-powered content generation:
10
+
11
+ - `refinePrompt()` - Refine user prompts
12
+ - `generateTitle()` - Generate project titles
13
+ - `generateQuestionnaire()` - Generate questionnaires
14
+ - `generatePRD()` - Generate Project Requirements Documents
15
+ - `generateCategory()` - Suggest project categories
16
+ - `generateOutline()` - Generate document outlines
17
+ - `generateDocument()` - Generate custom documents
18
+ - `generateMultipleDocuments()` - Generate multiple documents in parallel
19
+ - `startBackgroundGeneration()` - Start background generation jobs
20
+ - `getBackgroundGenerationStatus()` - Check background job status
21
+
22
+ ### 2. ProjectService (`/projects`)
23
+
24
+ Manages projects:
25
+
26
+ - `getAllProjects()` - Get all user projects
27
+ - `getPaginatedProjects()` - Get paginated projects with filtering
28
+ - `getProjectById()` - Get specific project
29
+ - `createProject()` - Create new project
30
+ - `updateProject()` - Update existing project
31
+ - `deleteProject()` - Delete project
32
+
33
+ ### 3. UsageService (`/usage`)
34
+
35
+ Handles usage tracking and credits:
36
+
37
+ - `trackUsage()` - Track API usage
38
+ - `getCreditBalance()` - Get current credit balance
39
+ - `checkCredits()` - Check if sufficient credits available
40
+ - `getUsageSummary()` - Get detailed usage summary
41
+ - `getAuthorization()` - Get user authorization status
42
+ - `getFreeUserStatus()` - Check free user status
43
+ - `calculateUsageCost()` - Calculate usage costs
44
+ - `trackCodespaceUsage()` - Track codespace usage
45
+ - `getCodespaceTaskUsage()` - Get codespace usage details
46
+ - `healthCheck()` - Check API health
47
+
48
+ ### 4. RepositoryAnalysisService (`/repository-analysis`)
49
+
50
+ Analyzes GitHub repositories:
51
+
52
+ - `analyzeRepository()` - Start repository analysis
53
+ - `getAnalysisStatus()` - Check analysis status
54
+ - `getAnalysisResult()` - Get analysis results
55
+ - `listRepositories()` - List analyzed repositories
56
+ - `getRepositoryDetails()` - Get repository details
57
+ - `deleteRepository()` - Delete repository analysis
58
+
59
+ ### 5. TaskService (`/task-groups`, `/project-tasks`)
60
+
61
+ Manages task groups and project tasks:
62
+
63
+ - **Task Groups**: CRUD operations for task groups
64
+ - **Project Tasks**: CRUD operations for project tasks
65
+ - **Pagination**: Support for paginated results
66
+ - **Filtering**: Filter by status, project, parent task, etc.
67
+
68
+ ### 6. BaseService
69
+
70
+ Base class providing common functionality:
71
+
72
+ - HTTP client setup with proper headers
73
+ - Error handling with standardized responses
74
+ - Authentication handling (API Key + User ID)
75
+ - Request/response interceptors
76
+ - Common HTTP methods (GET, POST, PUT, DELETE)
77
+
78
+ ## Usage Example
79
+
80
+ ```typescript
81
+ import { CodeGuide, APIServiceConfig } from '@codeguide/core'
82
+
83
+ const config: APIServiceConfig = {
84
+ baseUrl: 'https://api.codeguide.app',
85
+ apiKey: 'your-api-key',
86
+ userId: 'your-user-id',
87
+ }
88
+
89
+ const codeguide = new CodeGuide(config)
90
+
91
+ // Use different services
92
+ const projects = await codeguide.projects.getAllProjects()
93
+ const creditBalance = await codeguide.usage.getCreditBalance()
94
+ const refinedPrompt = await codeguide.generation.refinePrompt({
95
+ user_prompt: 'How do I create a React component?',
96
+ })
97
+ ```
98
+
99
+ ## Configuration
100
+
101
+ All services accept the same configuration:
102
+
103
+ - `baseUrl`: API base URL (defaults to https://api.codeguide.app)
104
+ - `apiKey`: API key for authentication
105
+ - `userId`: User ID for authentication
106
+ - `timeout`: Request timeout (default: 3600000ms / 1 hour)
107
+
108
+ ## Authentication
109
+
110
+ Services use the CodeGuide API authentication scheme:
111
+
112
+ - Primary: `X-API-Key` + `X-User-ID` headers
113
+ - Fallback: `Authorization: Bearer <token>`
@@ -0,0 +1,230 @@
1
+ import axios, { AxiosInstance, AxiosResponse } from 'axios'
2
+ import { APIServiceConfig, AuthenticationMethod, AuthenticationResult } from '../../types'
3
+
4
+ export abstract class BaseService {
5
+ protected client: AxiosInstance
6
+ protected config: APIServiceConfig
7
+
8
+ constructor(config: APIServiceConfig) {
9
+ this.config = config
10
+
11
+ // Ensure baseUrl includes the API version
12
+ const baseUrl = config.baseUrl
13
+
14
+ this.client = axios.create({
15
+ baseURL: baseUrl,
16
+ timeout: config.timeout || 3600000, // 1 hour timeout for document generation
17
+ headers: this.getAuthenticationHeaders(),
18
+ })
19
+
20
+ this.setupInterceptors()
21
+ }
22
+
23
+ /**
24
+ * Determine and return authentication headers based on priority
25
+ * Priority: 1. Database API Key, 2. Legacy API Key, 3. Clerk JWT
26
+ */
27
+ private getAuthenticationHeaders(): Record<string, string> {
28
+ const headers: Record<string, string> = {
29
+ 'Content-Type': 'application/json',
30
+ }
31
+
32
+ // Priority 1: Database API Key (format: sk_...)
33
+ if (this.config.databaseApiKey && this.config.databaseApiKey.startsWith('sk_')) {
34
+ headers['Authorization'] = `Bearer ${this.config.databaseApiKey}`
35
+ return headers
36
+ }
37
+
38
+ return headers
39
+ }
40
+
41
+ /**
42
+ * Get the current authentication method being used
43
+ */
44
+ public getAuthenticationMethod(): AuthenticationMethod | null {
45
+ // Priority 1: Database API Key
46
+ if (this.config.databaseApiKey && this.config.databaseApiKey.startsWith('sk_')) {
47
+ return {
48
+ type: 'database-api-key',
49
+ priority: 1,
50
+ headers: {
51
+ Authorization: `Bearer ${this.config.databaseApiKey}`,
52
+ 'Content-Type': 'application/json',
53
+ },
54
+ }
55
+ }
56
+
57
+ // Priority 2: Legacy API Key + User ID
58
+ if (this.config.apiKey && this.config.userId) {
59
+ return {
60
+ type: 'legacy-api-key',
61
+ priority: 2,
62
+ headers: {
63
+ 'X-API-Key': this.config.apiKey,
64
+ 'X-User-ID': this.config.userId,
65
+ 'Content-Type': 'application/json',
66
+ },
67
+ }
68
+ }
69
+
70
+ // Priority 3: Clerk JWT Token
71
+ if (this.config.jwtToken) {
72
+ return {
73
+ type: 'clerk-jwt',
74
+ priority: 3,
75
+ headers: {
76
+ Authorization: `Bearer ${this.config.jwtToken}`,
77
+ 'Content-Type': 'application/json',
78
+ },
79
+ }
80
+ }
81
+
82
+ // Fallback: Legacy API key without user ID
83
+ if (this.config.apiKey) {
84
+ return {
85
+ type: 'legacy-api-key',
86
+ priority: 2,
87
+ headers: {
88
+ 'X-API-Key': this.config.apiKey,
89
+ 'Content-Type': 'application/json',
90
+ },
91
+ }
92
+ }
93
+
94
+ return null
95
+ }
96
+
97
+ /**
98
+ * Validate the current authentication configuration
99
+ */
100
+ public validateAuthentication(): AuthenticationResult {
101
+ const method = this.getAuthenticationMethod()
102
+
103
+ if (!method) {
104
+ return {
105
+ success: false,
106
+ error:
107
+ 'No authentication method configured. Please provide either databaseApiKey, apiKey + userId, or jwtToken.',
108
+ }
109
+ }
110
+
111
+ // Validate database API key format
112
+ if (method.type === 'database-api-key') {
113
+ if (!this.config.databaseApiKey?.startsWith('sk_')) {
114
+ return {
115
+ success: false,
116
+ error: 'Database API key must start with "sk_"',
117
+ }
118
+ }
119
+ }
120
+
121
+ // Validate legacy API key requires user ID
122
+ if (method.type === 'legacy-api-key' && !this.config.userId) {
123
+ return {
124
+ success: false,
125
+ error: 'Legacy API key authentication requires both apiKey and userId',
126
+ }
127
+ }
128
+
129
+ return {
130
+ success: true,
131
+ method,
132
+ }
133
+ }
134
+
135
+ private setupInterceptors(): void {
136
+ this.client.interceptors.response.use(
137
+ (response: AxiosResponse) => response,
138
+ error => {
139
+ if (axios.isAxiosError(error)) {
140
+ const authMethod = this.getAuthenticationMethod()
141
+ const status = error.response?.status
142
+ const detail = error.response?.data?.detail
143
+ const message = error.response?.data?.message || error.message
144
+
145
+ // Handle authentication-specific errors
146
+ if (status === 401) {
147
+ if (authMethod?.type === 'database-api-key') {
148
+ throw new Error(
149
+ `Database API key authentication failed: ${this.formatErrorMessage(detail, 'Invalid, expired, or inactive API key')}`
150
+ )
151
+ } else if (authMethod?.type === 'legacy-api-key') {
152
+ throw new Error(
153
+ `Legacy API key authentication failed: ${this.formatErrorMessage(detail, 'Invalid API key or user ID')}`
154
+ )
155
+ } else if (authMethod?.type === 'clerk-jwt') {
156
+ throw new Error(
157
+ `Clerk JWT authentication failed: ${this.formatErrorMessage(detail, 'Invalid or expired token')}`
158
+ )
159
+ } else {
160
+ throw new Error(
161
+ `Authentication failed: ${this.formatErrorMessage(detail || message, 'Authentication failed')}`
162
+ )
163
+ }
164
+ }
165
+
166
+ // Handle subscription/permission errors
167
+ if (status === 403) {
168
+ throw new Error(
169
+ `Access denied: ${this.formatErrorMessage(detail, 'Insufficient permissions or subscription required')}`
170
+ )
171
+ }
172
+
173
+ // Handle rate limiting
174
+ if (status === 429) {
175
+ throw new Error(
176
+ `Rate limit exceeded: ${this.formatErrorMessage(detail, 'Too many requests. Please try again later.')}`
177
+ )
178
+ }
179
+
180
+ // Handle usage limit errors
181
+ if (detail?.includes('credits') || detail?.includes('usage')) {
182
+ throw new Error(
183
+ `Usage limit exceeded: ${this.formatErrorMessage(detail, 'Usage limit exceeded')}`
184
+ )
185
+ }
186
+
187
+ // Generic API error
188
+ throw new Error(
189
+ `API Error: ${this.formatErrorMessage(detail || message, 'Unknown API error')}`
190
+ )
191
+ }
192
+ throw error
193
+ }
194
+ )
195
+ }
196
+
197
+ protected async get<T>(url: string, config?: any): Promise<T> {
198
+ const response = await this.client.get<T>(url, config)
199
+ return response.data
200
+ }
201
+
202
+ /**
203
+ * Safely format error message to avoid [object Object]
204
+ */
205
+ private formatErrorMessage(value: any, fallback: string): string {
206
+ if (value && typeof value === 'object') {
207
+ return JSON.stringify(value)
208
+ }
209
+ return value || fallback
210
+ }
211
+
212
+ protected async post<T>(url: string, data?: any, config?: any): Promise<T> {
213
+ const response = await this.client.post<T>(url, data, config)
214
+ return response.data
215
+ }
216
+
217
+ protected async put<T>(url: string, data?: any, config?: any): Promise<T> {
218
+ const response = await this.client.put<T>(url, data, config)
219
+ return response.data
220
+ }
221
+
222
+ protected async delete<T>(url: string, config?: any): Promise<T> {
223
+ const response = await this.client.delete<T>(url, config)
224
+ return response.data
225
+ }
226
+
227
+ protected buildUrl(endpoint: string): string {
228
+ return endpoint.startsWith('/') ? endpoint : `/${endpoint}`
229
+ }
230
+ }
@@ -0,0 +1 @@
1
+ export { BaseService } from './base-service'