@codeguide/core 0.0.27 → 0.0.29
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 +50 -41
- package/__tests__/services/codespace/codespace-v2.test.ts +29 -18
- package/__tests__/services/usage/usage-service.test.ts +597 -85
- package/codeguide.ts +6 -0
- package/dist/codeguide.d.ts +3 -1
- package/dist/codeguide.js +2 -0
- package/dist/index.d.ts +4 -3
- package/dist/services/base/base-service.d.ts +21 -0
- package/dist/services/base/base-service.js +114 -0
- package/dist/services/codespace/codespace-service.d.ts +55 -1
- package/dist/services/codespace/codespace-service.js +260 -5
- package/dist/services/codespace/codespace-types.d.ts +193 -13
- package/dist/services/codespace/index.d.ts +1 -1
- package/dist/services/index.d.ts +4 -0
- package/dist/services/index.js +7 -1
- package/dist/services/projects/project-types.d.ts +66 -32
- package/dist/services/repository-analysis/repository-types.d.ts +1 -0
- package/dist/services/starter-kits/index.d.ts +2 -0
- package/dist/services/starter-kits/index.js +20 -0
- package/dist/services/starter-kits/starter-kits-service.d.ts +13 -0
- package/dist/services/starter-kits/starter-kits-service.js +27 -0
- package/dist/services/starter-kits/starter-kits-types.d.ts +34 -0
- package/dist/services/starter-kits/starter-kits-types.js +2 -0
- package/dist/services/tasks/task-service.d.ts +2 -1
- package/dist/services/tasks/task-service.js +8 -0
- package/dist/services/tasks/task-types.d.ts +26 -7
- package/dist/services/usage/usage-service.d.ts +5 -2
- package/dist/services/usage/usage-service.js +58 -9
- package/dist/services/usage/usage-types.d.ts +207 -34
- package/dist/services/users/index.d.ts +2 -0
- package/dist/services/users/index.js +20 -0
- package/dist/services/users/user-service.d.ts +12 -0
- package/dist/services/users/user-service.js +17 -0
- package/dist/services/users/user-types.d.ts +55 -0
- package/dist/services/users/user-types.js +2 -0
- package/docs/.vitepress/README.md +51 -0
- package/docs/.vitepress/config.ts +139 -0
- package/docs/.vitepress/theme/custom.css +80 -0
- package/docs/.vitepress/theme/index.ts +13 -0
- package/docs/.vitepress/tsconfig.json +19 -0
- package/docs/QUICKSTART.md +77 -0
- package/docs/README.md +134 -0
- package/docs/README_SETUP.md +46 -0
- package/docs/authentication.md +351 -0
- package/docs/codeguide-client.md +350 -0
- package/docs/codespace-models.md +1004 -0
- package/docs/codespace-service.md +558 -81
- package/docs/index.md +135 -0
- package/docs/package.json +14 -0
- package/docs/projects-service.md +688 -0
- package/docs/security-keys-service.md +773 -0
- package/docs/starter-kits-service.md +249 -0
- package/docs/task-service.md +955 -0
- package/docs/testsprite_tests/TC001_Homepage_Load_and_Hero_Section_Display.py +70 -0
- package/docs/testsprite_tests/TC002_Sidebar_Navigation_ExpandCollapse_Functionality.py +73 -0
- package/docs/testsprite_tests/TC003_Full_Text_Local_Search_with_Keyboard_Shortcut.py +90 -0
- package/docs/testsprite_tests/TC004_Dark_Mode_Toggle_and_Persistence.py +73 -0
- package/docs/testsprite_tests/TC005_Mobile_Responsiveness_and_Touch_Navigation.py +113 -0
- package/docs/testsprite_tests/TC006_GitHub_Integration_Edit_this_page_Links.py +73 -0
- package/docs/testsprite_tests/TC007_Syntax_Highlighting_and_Code_Copy_Functionality.py +73 -0
- package/docs/testsprite_tests/TC008_Auto_Generated_Table_of_Contents_Accuracy.py +73 -0
- package/docs/testsprite_tests/TC009_SEO_and_Content_Discoverability_Verification.py +73 -0
- package/docs/testsprite_tests/TC010_Accessibility_Compliance_WCAG_AA.py +73 -0
- package/docs/testsprite_tests/TC011_Local_Development_Workflow_Build_and_Hot_Reload.py +74 -0
- package/docs/testsprite_tests/TC012_Performance_Metrics_Compliance.py +73 -0
- package/docs/testsprite_tests/standard_prd.json +122 -0
- package/docs/testsprite_tests/testsprite-mcp-test-report.html +2508 -0
- package/docs/testsprite_tests/testsprite-mcp-test-report.md +273 -0
- package/docs/testsprite_tests/testsprite_frontend_test_plan.json +390 -0
- package/docs/usage-service.md +616 -0
- package/index.ts +11 -3
- package/package.json +16 -2
- package/plans/CODESPACE_LOGS_STREAMING_GUIDE.md +320 -0
- package/plans/CODESPACE_TASK_LOGS_API_COMPLETE_GUIDE.md +821 -0
- package/services/base/base-service.ts +130 -0
- package/services/codespace/codespace-service.ts +347 -8
- package/services/codespace/codespace-types.ts +263 -14
- package/services/codespace/index.ts +16 -1
- package/services/index.ts +4 -0
- package/services/projects/README.md +107 -34
- package/services/projects/project-types.ts +69 -32
- package/services/repository-analysis/repository-types.ts +1 -0
- package/services/starter-kits/index.ts +2 -0
- package/services/starter-kits/starter-kits-service.ts +33 -0
- package/services/starter-kits/starter-kits-types.ts +38 -0
- package/services/tasks/task-service.ts +10 -0
- package/services/tasks/task-types.ts +29 -7
- package/services/usage/usage-service.ts +59 -10
- package/services/usage/usage-types.ts +239 -34
- package/services/users/index.ts +2 -0
- package/services/users/user-service.ts +15 -0
- package/services/users/user-types.ts +59 -0
|
@@ -4,13 +4,21 @@ import axios from 'axios'
|
|
|
4
4
|
import MockAdapter from 'axios-mock-adapter'
|
|
5
5
|
import {
|
|
6
6
|
TrackUsageRequest,
|
|
7
|
+
TrackUsageResponse,
|
|
7
8
|
CreditBalanceResponse,
|
|
9
|
+
CreditBalanceData,
|
|
8
10
|
CreditCheckResponse,
|
|
9
11
|
UsageSummaryResponse,
|
|
10
12
|
AuthorizationResponse,
|
|
11
13
|
CalculateUsageResponse,
|
|
12
14
|
TrackCodespaceUsageResponse,
|
|
13
15
|
CodespaceTaskUsageResponse,
|
|
16
|
+
DashboardAnalyticsRequest,
|
|
17
|
+
DashboardAnalyticsResponse,
|
|
18
|
+
UsageDetailsRequest,
|
|
19
|
+
UsageDetailsResponse,
|
|
20
|
+
ServiceBreakdownRequest,
|
|
21
|
+
ServiceBreakdownResponse,
|
|
14
22
|
} from '../../../services/usage/usage-types'
|
|
15
23
|
|
|
16
24
|
describe('UsageService', () => {
|
|
@@ -19,12 +27,12 @@ describe('UsageService', () => {
|
|
|
19
27
|
let config: APIServiceConfig
|
|
20
28
|
|
|
21
29
|
beforeEach(() => {
|
|
22
|
-
mockAxios = new MockAdapter(axios)
|
|
23
30
|
config = {
|
|
24
31
|
baseUrl: 'https://api.codeguide.app',
|
|
25
32
|
databaseApiKey: 'sk_test123',
|
|
26
33
|
}
|
|
27
34
|
usageService = new UsageService(config)
|
|
35
|
+
mockAxios = new MockAdapter((usageService as any).client)
|
|
28
36
|
})
|
|
29
37
|
|
|
30
38
|
afterEach(() => {
|
|
@@ -48,7 +56,7 @@ describe('UsageService', () => {
|
|
|
48
56
|
message: 'Usage tracked successfully',
|
|
49
57
|
}
|
|
50
58
|
|
|
51
|
-
mockAxios.onPost('/
|
|
59
|
+
mockAxios.onPost('/usage/track', request).reply(200, response)
|
|
52
60
|
|
|
53
61
|
const result = await usageService.trackUsage(request)
|
|
54
62
|
|
|
@@ -62,7 +70,7 @@ describe('UsageService', () => {
|
|
|
62
70
|
output_tokens: 50,
|
|
63
71
|
}
|
|
64
72
|
|
|
65
|
-
mockAxios.onPost('/
|
|
73
|
+
mockAxios.onPost('/usage/track', request).reply(400, {
|
|
66
74
|
detail: 'Invalid request',
|
|
67
75
|
})
|
|
68
76
|
|
|
@@ -72,7 +80,7 @@ describe('UsageService', () => {
|
|
|
72
80
|
|
|
73
81
|
describe('getCreditBalance', () => {
|
|
74
82
|
it('should get credit balance successfully', async () => {
|
|
75
|
-
const
|
|
83
|
+
const creditBalanceData: CreditBalanceData = {
|
|
76
84
|
user_id: 'user123',
|
|
77
85
|
total_consumed: 10.5,
|
|
78
86
|
total_allotted: 100,
|
|
@@ -86,7 +94,11 @@ describe('UsageService', () => {
|
|
|
86
94
|
},
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
|
|
97
|
+
const response: CreditBalanceResponse = {
|
|
98
|
+
data: creditBalanceData,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
mockAxios.onGet('/usage/credit-balance').reply(200, response)
|
|
90
102
|
|
|
91
103
|
const result = await usageService.getCreditBalance()
|
|
92
104
|
|
|
@@ -112,7 +124,7 @@ describe('UsageService', () => {
|
|
|
112
124
|
|
|
113
125
|
mockAxios
|
|
114
126
|
.onGet(
|
|
115
|
-
'/
|
|
127
|
+
'/usage/credit-check?model_key=gpt-4&input_tokens=100&output_tokens=50&call_seconds=2'
|
|
116
128
|
)
|
|
117
129
|
.reply(200, response)
|
|
118
130
|
|
|
@@ -135,7 +147,7 @@ describe('UsageService', () => {
|
|
|
135
147
|
}
|
|
136
148
|
|
|
137
149
|
mockAxios
|
|
138
|
-
.onGet('/
|
|
150
|
+
.onGet('/usage/credit-check?model_key=gpt-4&input_tokens=100')
|
|
139
151
|
.reply(200, response)
|
|
140
152
|
|
|
141
153
|
const result = await usageService.checkCredits(params)
|
|
@@ -144,94 +156,180 @@ describe('UsageService', () => {
|
|
|
144
156
|
})
|
|
145
157
|
})
|
|
146
158
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
|
|
160
|
+
describe('getAuthorization', () => {
|
|
161
|
+
it('should get authorization info successfully', async () => {
|
|
162
|
+
const response: AuthorizationResponse = {
|
|
163
|
+
success: true,
|
|
164
|
+
data: {
|
|
165
|
+
user_id: 'user_32CKVjVlcRfh4HAqpVckgILey0Z',
|
|
166
|
+
subscription: null,
|
|
167
|
+
credit_balance: {
|
|
168
|
+
total_allotted: 500,
|
|
169
|
+
total_consumed: 0,
|
|
170
|
+
remaining_credits: 500,
|
|
171
|
+
is_over_limit: false,
|
|
172
|
+
utilization_percentage: 0.0,
|
|
173
|
+
billing_cycle_start: '2025-11-03',
|
|
174
|
+
billing_cycle_end: '2025-11-10',
|
|
175
|
+
},
|
|
176
|
+
has_active_subscription: false,
|
|
177
|
+
has_previous_subscriptions: false,
|
|
178
|
+
is_within_credit_limit: true,
|
|
179
|
+
authorization_level: 'free',
|
|
180
|
+
restrictions: [],
|
|
181
|
+
can_create_tasks: true,
|
|
182
|
+
can_analyze_repos: true,
|
|
183
|
+
can_access_previous_projects: false,
|
|
184
|
+
plan_limits: {
|
|
185
|
+
plan_type: 'free',
|
|
186
|
+
limits: {
|
|
187
|
+
codespace_tasks: {
|
|
188
|
+
allowed: true,
|
|
189
|
+
current_usage: 0,
|
|
190
|
+
limit: 2,
|
|
191
|
+
remaining: 2,
|
|
192
|
+
period_type: 'lifetime',
|
|
193
|
+
period_start: null,
|
|
194
|
+
period_end: null,
|
|
195
|
+
message: 'Can create 2 more codespace tasks. 2 codespace tasks (lifetime limit)',
|
|
196
|
+
is_unlimited: false,
|
|
197
|
+
},
|
|
198
|
+
api_calls: {
|
|
199
|
+
limit: 500,
|
|
200
|
+
period: '7_days',
|
|
201
|
+
description: '500 API credits (valid for 7 days)',
|
|
202
|
+
is_unlimited: false,
|
|
203
|
+
},
|
|
204
|
+
storage_gb: {
|
|
205
|
+
limit: 1,
|
|
206
|
+
period: 'lifetime',
|
|
207
|
+
description: '1 GB storage',
|
|
208
|
+
is_unlimited: false,
|
|
209
|
+
},
|
|
210
|
+
projects: {
|
|
211
|
+
limit: 3,
|
|
212
|
+
period: 'lifetime',
|
|
213
|
+
description: '3 projects maximum',
|
|
214
|
+
is_unlimited: false,
|
|
215
|
+
},
|
|
216
|
+
collaborators: {
|
|
217
|
+
limit: 0,
|
|
218
|
+
period: 'lifetime',
|
|
219
|
+
description: 'No team collaboration',
|
|
220
|
+
is_unlimited: false,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
codespace_task_limit: {
|
|
225
|
+
allowed: true,
|
|
226
|
+
current_usage: 0,
|
|
227
|
+
limit: 2,
|
|
228
|
+
remaining: 2,
|
|
229
|
+
period_type: 'lifetime',
|
|
230
|
+
period_start: null,
|
|
231
|
+
period_end: null,
|
|
232
|
+
message: 'Can create 2 more codespace tasks. 2 codespace tasks (lifetime limit)',
|
|
233
|
+
is_unlimited: false,
|
|
166
234
|
},
|
|
167
|
-
daily_usage: [
|
|
168
|
-
{ date: '2024-01-01', credits_used: 1.5, calls: 5 },
|
|
169
|
-
{ date: '2024-01-02', credits_used: 2.0, calls: 8 },
|
|
170
|
-
],
|
|
171
|
-
},
|
|
172
|
-
subscription: {
|
|
173
|
-
plan: 'pro',
|
|
174
|
-
status: 'active',
|
|
175
|
-
},
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
mockAxios
|
|
179
|
-
.onGet('/v1/usage/summary?start_date=2024-01-01&end_date=2024-01-31')
|
|
180
|
-
.reply(200, response)
|
|
181
|
-
|
|
182
|
-
const result = await usageService.getUsageSummary(params)
|
|
183
|
-
|
|
184
|
-
expect(result).toEqual(response)
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
it('should get usage summary without date range', async () => {
|
|
188
|
-
const response: UsageSummaryResponse = {
|
|
189
|
-
user_id: 'user123',
|
|
190
|
-
period: {
|
|
191
|
-
start_date: '2024-01-01',
|
|
192
|
-
end_date: '2024-01-31',
|
|
193
|
-
},
|
|
194
|
-
usage_summary: {
|
|
195
|
-
total_credits_used: 15.5,
|
|
196
|
-
total_calls: 42,
|
|
197
|
-
model_breakdown: {},
|
|
198
|
-
daily_usage: [],
|
|
199
|
-
},
|
|
200
|
-
subscription: {
|
|
201
|
-
plan: 'pro',
|
|
202
|
-
status: 'active',
|
|
203
235
|
},
|
|
236
|
+
message: 'Authorization status retrieved successfully',
|
|
204
237
|
}
|
|
205
238
|
|
|
206
|
-
mockAxios.onGet('/
|
|
239
|
+
mockAxios.onGet('/usage/authorization').reply(200, response)
|
|
207
240
|
|
|
208
|
-
const result = await usageService.
|
|
241
|
+
const result = await usageService.getAuthorization()
|
|
209
242
|
|
|
210
243
|
expect(result).toEqual(response)
|
|
211
244
|
})
|
|
212
|
-
})
|
|
213
245
|
|
|
214
|
-
|
|
215
|
-
it('should get authorization info successfully', async () => {
|
|
246
|
+
it('should get authorization info for subscribed user successfully', async () => {
|
|
216
247
|
const response: AuthorizationResponse = {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
success: true,
|
|
249
|
+
data: {
|
|
250
|
+
user_id: 'user_2qaB6nlVH3R9QXhQZpt1nmVDymN',
|
|
251
|
+
subscription: {
|
|
252
|
+
id: 'sub_1RbggdFb0vIg7N8EFOPTEhDh',
|
|
253
|
+
status: 'active',
|
|
254
|
+
interval: 'month',
|
|
255
|
+
current_period_start: '2025-10-19T11:31:19+00:00',
|
|
256
|
+
current_period_end: '2025-11-19T11:31:19+00:00',
|
|
257
|
+
price_id: 'price_1QYtmGFb0vIg7N8E71nw8g27',
|
|
258
|
+
product_name: null,
|
|
259
|
+
plan_name: 'Monthly Plan',
|
|
260
|
+
},
|
|
261
|
+
credit_balance: {
|
|
262
|
+
total_allotted: 5000,
|
|
263
|
+
total_consumed: 658,
|
|
264
|
+
remaining_credits: 4342,
|
|
265
|
+
is_over_limit: false,
|
|
266
|
+
utilization_percentage: 13.16,
|
|
267
|
+
billing_cycle_start: '2025-10-19',
|
|
268
|
+
billing_cycle_end: '2025-11-19',
|
|
269
|
+
},
|
|
270
|
+
has_active_subscription: true,
|
|
271
|
+
has_previous_subscriptions: true,
|
|
272
|
+
is_within_credit_limit: true,
|
|
273
|
+
authorization_level: 'basic',
|
|
274
|
+
restrictions: [],
|
|
275
|
+
can_create_tasks: true,
|
|
276
|
+
can_analyze_repos: true,
|
|
277
|
+
can_access_previous_projects: true,
|
|
278
|
+
plan_limits: {
|
|
279
|
+
plan_type: 'basic',
|
|
280
|
+
limits: {
|
|
281
|
+
codespace_tasks: {
|
|
282
|
+
allowed: true,
|
|
283
|
+
current_usage: 0,
|
|
284
|
+
limit: -1,
|
|
285
|
+
remaining: -1,
|
|
286
|
+
period_type: 'monthly',
|
|
287
|
+
period_start: null,
|
|
288
|
+
period_end: null,
|
|
289
|
+
message: 'Unlimited codespace tasks',
|
|
290
|
+
is_unlimited: true,
|
|
291
|
+
},
|
|
292
|
+
api_calls: {
|
|
293
|
+
limit: 5000,
|
|
294
|
+
period: 'monthly',
|
|
295
|
+
description: '5000 API credits per month',
|
|
296
|
+
is_unlimited: false,
|
|
297
|
+
},
|
|
298
|
+
storage_gb: {
|
|
299
|
+
limit: 10,
|
|
300
|
+
period: 'lifetime',
|
|
301
|
+
description: '10 GB storage',
|
|
302
|
+
is_unlimited: false,
|
|
303
|
+
},
|
|
304
|
+
projects: {
|
|
305
|
+
limit: 20,
|
|
306
|
+
period: 'lifetime',
|
|
307
|
+
description: '20 projects maximum',
|
|
308
|
+
is_unlimited: false,
|
|
309
|
+
},
|
|
310
|
+
collaborators: {
|
|
311
|
+
limit: 3,
|
|
312
|
+
period: 'monthly',
|
|
313
|
+
description: '3 team collaborators',
|
|
314
|
+
is_unlimited: false,
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
codespace_task_limit: null,
|
|
226
319
|
},
|
|
227
|
-
|
|
320
|
+
message: 'Authorization status retrieved successfully',
|
|
228
321
|
}
|
|
229
322
|
|
|
230
|
-
mockAxios.onGet('/
|
|
323
|
+
mockAxios.onGet('/usage/authorization').reply(200, response)
|
|
231
324
|
|
|
232
325
|
const result = await usageService.getAuthorization()
|
|
233
326
|
|
|
234
327
|
expect(result).toEqual(response)
|
|
328
|
+
expect(result.data.has_active_subscription).toBe(true)
|
|
329
|
+
expect(result.data.subscription).not.toBeNull()
|
|
330
|
+
expect(result.data.subscription?.plan_name).toBe('Monthly Plan')
|
|
331
|
+
expect(result.data.codespace_task_limit).toBeNull()
|
|
332
|
+
expect(result.data.plan_limits.limits.codespace_tasks.is_unlimited).toBe(true)
|
|
235
333
|
})
|
|
236
334
|
})
|
|
237
335
|
|
|
@@ -244,7 +342,7 @@ describe('UsageService', () => {
|
|
|
244
342
|
credits_expire_at: '2024-12-31',
|
|
245
343
|
}
|
|
246
344
|
|
|
247
|
-
mockAxios.onGet('/
|
|
345
|
+
mockAxios.onGet('/usage/free-user-status').reply(200, response)
|
|
248
346
|
|
|
249
347
|
const result = await usageService.getFreeUserStatus()
|
|
250
348
|
|
|
@@ -275,7 +373,7 @@ describe('UsageService', () => {
|
|
|
275
373
|
|
|
276
374
|
mockAxios
|
|
277
375
|
.onGet(
|
|
278
|
-
'/
|
|
376
|
+
'/usage/calculate?model_key=gpt-4&input_tokens=100&output_tokens=50&call_seconds=2&cost_amount=0.05'
|
|
279
377
|
)
|
|
280
378
|
.reply(200, response)
|
|
281
379
|
|
|
@@ -308,7 +406,7 @@ describe('UsageService', () => {
|
|
|
308
406
|
created_at: '2024-01-01T00:00:00Z',
|
|
309
407
|
}
|
|
310
408
|
|
|
311
|
-
mockAxios.onPost('/
|
|
409
|
+
mockAxios.onPost('/usage/codespace/track', request).reply(200, response)
|
|
312
410
|
|
|
313
411
|
const result = await usageService.trackCodespaceUsage(request)
|
|
314
412
|
|
|
@@ -341,7 +439,7 @@ describe('UsageService', () => {
|
|
|
341
439
|
],
|
|
342
440
|
}
|
|
343
441
|
|
|
344
|
-
mockAxios.onGet('/
|
|
442
|
+
mockAxios.onGet('/usage/codespace/task/task123').reply(200, response)
|
|
345
443
|
|
|
346
444
|
const result = await usageService.getCodespaceTaskUsage('task123')
|
|
347
445
|
|
|
@@ -351,7 +449,7 @@ describe('UsageService', () => {
|
|
|
351
449
|
|
|
352
450
|
describe('healthCheck', () => {
|
|
353
451
|
it('should return true when API is healthy', async () => {
|
|
354
|
-
mockAxios.onGet('/
|
|
452
|
+
mockAxios.onGet('/usage/health').reply(200, {
|
|
355
453
|
status: 'healthy',
|
|
356
454
|
timestamp: '2024-01-01T00:00:00Z',
|
|
357
455
|
version: '1.0.0',
|
|
@@ -363,7 +461,7 @@ describe('UsageService', () => {
|
|
|
363
461
|
})
|
|
364
462
|
|
|
365
463
|
it('should return false when API is not healthy', async () => {
|
|
366
|
-
mockAxios.onGet('/
|
|
464
|
+
mockAxios.onGet('/usage/health').reply(200, {
|
|
367
465
|
status: 'unhealthy',
|
|
368
466
|
timestamp: '2024-01-01T00:00:00Z',
|
|
369
467
|
version: '1.0.0',
|
|
@@ -375,11 +473,425 @@ describe('UsageService', () => {
|
|
|
375
473
|
})
|
|
376
474
|
|
|
377
475
|
it('should return false when health check fails', async () => {
|
|
378
|
-
mockAxios.onGet('/
|
|
476
|
+
mockAxios.onGet('/usage/health').reply(500)
|
|
379
477
|
|
|
380
478
|
const result = await usageService.healthCheck()
|
|
381
479
|
|
|
382
480
|
expect(result).toBe(false)
|
|
383
481
|
})
|
|
384
482
|
})
|
|
483
|
+
|
|
484
|
+
// Dashboard Analytics Tests
|
|
485
|
+
describe('getDashboardAnalytics', () => {
|
|
486
|
+
it('should get dashboard analytics with period parameter', async () => {
|
|
487
|
+
const params: DashboardAnalyticsRequest = {
|
|
488
|
+
period: '7d'
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
const response: DashboardAnalyticsResponse = {
|
|
492
|
+
status: 'success',
|
|
493
|
+
data: {
|
|
494
|
+
period: {
|
|
495
|
+
start: '2024-01-25',
|
|
496
|
+
end: '2024-01-31',
|
|
497
|
+
label: '7d'
|
|
498
|
+
},
|
|
499
|
+
daily_usage: [
|
|
500
|
+
{
|
|
501
|
+
date: '2024-01-25',
|
|
502
|
+
credits_consumed: 1250,
|
|
503
|
+
cost_usd: 3.75,
|
|
504
|
+
requests_count: 15,
|
|
505
|
+
average_credits_per_request: 83.33
|
|
506
|
+
}
|
|
507
|
+
],
|
|
508
|
+
totals: {
|
|
509
|
+
credits_consumed: 13870,
|
|
510
|
+
cost_usd: 41.61,
|
|
511
|
+
requests_count: 142
|
|
512
|
+
},
|
|
513
|
+
averages: {
|
|
514
|
+
daily_credits: 1981.43,
|
|
515
|
+
daily_requests: 20.29
|
|
516
|
+
},
|
|
517
|
+
trends: {
|
|
518
|
+
credits_consumed: 15.7,
|
|
519
|
+
requests_count: 8.3
|
|
520
|
+
},
|
|
521
|
+
top_services: [
|
|
522
|
+
{
|
|
523
|
+
service_type: 'docs',
|
|
524
|
+
credits_consumed: 5230,
|
|
525
|
+
requests_count: 58
|
|
526
|
+
}
|
|
527
|
+
]
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
mockAxios.onGet('/usage/dashboard/analytics?period=7d').reply(200, response)
|
|
532
|
+
|
|
533
|
+
const result = await usageService.getDashboardAnalytics(params)
|
|
534
|
+
|
|
535
|
+
expect(result).toEqual(response)
|
|
536
|
+
})
|
|
537
|
+
|
|
538
|
+
it('should get dashboard analytics with all parameters', async () => {
|
|
539
|
+
const params: DashboardAnalyticsRequest = {
|
|
540
|
+
start_date: '2024-01-01',
|
|
541
|
+
end_date: '2024-01-31',
|
|
542
|
+
service_type: 'docs'
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const response: DashboardAnalyticsResponse = {
|
|
546
|
+
status: 'success',
|
|
547
|
+
data: {
|
|
548
|
+
period: {
|
|
549
|
+
start: '2024-01-01',
|
|
550
|
+
end: '2024-01-31',
|
|
551
|
+
label: 'custom'
|
|
552
|
+
},
|
|
553
|
+
daily_usage: [],
|
|
554
|
+
totals: {
|
|
555
|
+
credits_consumed: 5000,
|
|
556
|
+
cost_usd: 15.0,
|
|
557
|
+
requests_count: 45
|
|
558
|
+
},
|
|
559
|
+
averages: {
|
|
560
|
+
daily_credits: 161.29,
|
|
561
|
+
daily_requests: 1.45
|
|
562
|
+
},
|
|
563
|
+
trends: {
|
|
564
|
+
credits_consumed: 12.5,
|
|
565
|
+
requests_count: 5.2
|
|
566
|
+
},
|
|
567
|
+
top_services: [
|
|
568
|
+
{
|
|
569
|
+
service_type: 'docs',
|
|
570
|
+
credits_consumed: 5000,
|
|
571
|
+
requests_count: 45
|
|
572
|
+
}
|
|
573
|
+
]
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
mockAxios.onGet('/usage/dashboard/analytics?start_date=2024-01-01&end_date=2024-01-31&service_type=docs').reply(200, response)
|
|
578
|
+
|
|
579
|
+
const result = await usageService.getDashboardAnalytics(params)
|
|
580
|
+
|
|
581
|
+
expect(result).toEqual(response)
|
|
582
|
+
})
|
|
583
|
+
|
|
584
|
+
it('should get dashboard analytics without parameters', async () => {
|
|
585
|
+
const response: DashboardAnalyticsResponse = {
|
|
586
|
+
status: 'success',
|
|
587
|
+
data: {
|
|
588
|
+
period: {
|
|
589
|
+
start: '2024-01-01',
|
|
590
|
+
end: '2024-01-07',
|
|
591
|
+
label: '7d'
|
|
592
|
+
},
|
|
593
|
+
daily_usage: [],
|
|
594
|
+
totals: {
|
|
595
|
+
credits_consumed: 1000,
|
|
596
|
+
cost_usd: 3.0,
|
|
597
|
+
requests_count: 10
|
|
598
|
+
},
|
|
599
|
+
averages: {
|
|
600
|
+
daily_credits: 142.86,
|
|
601
|
+
daily_requests: 1.43
|
|
602
|
+
},
|
|
603
|
+
trends: {
|
|
604
|
+
credits_consumed: 5.0,
|
|
605
|
+
requests_count: 2.0
|
|
606
|
+
},
|
|
607
|
+
top_services: []
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
mockAxios.onGet('/usage/dashboard/analytics').reply(200, response)
|
|
612
|
+
|
|
613
|
+
const result = await usageService.getDashboardAnalytics()
|
|
614
|
+
|
|
615
|
+
expect(result).toEqual(response)
|
|
616
|
+
})
|
|
617
|
+
})
|
|
618
|
+
|
|
619
|
+
describe('getUsageDetails', () => {
|
|
620
|
+
it('should get usage details with pagination parameters', async () => {
|
|
621
|
+
const params: UsageDetailsRequest = {
|
|
622
|
+
page: 1,
|
|
623
|
+
page_size: 25,
|
|
624
|
+
sort_by: 'credits_consumed',
|
|
625
|
+
sort_order: 'desc'
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
const response: UsageDetailsResponse = {
|
|
629
|
+
status: 'success',
|
|
630
|
+
data: [
|
|
631
|
+
{
|
|
632
|
+
id: 'rec_123456789',
|
|
633
|
+
created_at: '2024-01-31T14:30:15.123Z',
|
|
634
|
+
service_type: 'docs',
|
|
635
|
+
model_name: 'GPT-4',
|
|
636
|
+
usage_type: 'output_tokens',
|
|
637
|
+
units_consumed: 1250,
|
|
638
|
+
credits_consumed: 156,
|
|
639
|
+
cost_amount: 0.468
|
|
640
|
+
}
|
|
641
|
+
],
|
|
642
|
+
pagination: {
|
|
643
|
+
page: 1,
|
|
644
|
+
page_size: 25,
|
|
645
|
+
total_count: 142,
|
|
646
|
+
total_pages: 6,
|
|
647
|
+
has_next: true,
|
|
648
|
+
has_prev: false
|
|
649
|
+
},
|
|
650
|
+
filters: {
|
|
651
|
+
period: null,
|
|
652
|
+
start_date: null,
|
|
653
|
+
end_date: null,
|
|
654
|
+
service_type: null
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
mockAxios.onGet('/usage/dashboard/details?page=1&page_size=25&sort_by=credits_consumed&sort_order=desc').reply(200, response)
|
|
659
|
+
|
|
660
|
+
const result = await usageService.getUsageDetails(params)
|
|
661
|
+
|
|
662
|
+
expect(result).toEqual(response)
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
it('should get usage details with filtering parameters', async () => {
|
|
666
|
+
const params: UsageDetailsRequest = {
|
|
667
|
+
period: '1m',
|
|
668
|
+
service_type: 'chat'
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const response: UsageDetailsResponse = {
|
|
672
|
+
status: 'success',
|
|
673
|
+
data: [
|
|
674
|
+
{
|
|
675
|
+
id: 'rec_123456790',
|
|
676
|
+
created_at: '2024-01-30T10:15:20.456Z',
|
|
677
|
+
service_type: 'chat',
|
|
678
|
+
model_name: 'GPT-3.5 Turbo',
|
|
679
|
+
usage_type: 'input_tokens',
|
|
680
|
+
units_consumed: 890,
|
|
681
|
+
credits_consumed: 89,
|
|
682
|
+
cost_amount: null
|
|
683
|
+
}
|
|
684
|
+
],
|
|
685
|
+
pagination: {
|
|
686
|
+
page: 1,
|
|
687
|
+
page_size: 50,
|
|
688
|
+
total_count: 25,
|
|
689
|
+
total_pages: 1,
|
|
690
|
+
has_next: false,
|
|
691
|
+
has_prev: false
|
|
692
|
+
},
|
|
693
|
+
filters: {
|
|
694
|
+
period: '1m',
|
|
695
|
+
start_date: null,
|
|
696
|
+
end_date: null,
|
|
697
|
+
service_type: 'chat'
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
mockAxios.onGet('/usage/dashboard/details?period=1m&service_type=chat').reply(200, response)
|
|
702
|
+
|
|
703
|
+
const result = await usageService.getUsageDetails(params)
|
|
704
|
+
|
|
705
|
+
expect(result).toEqual(response)
|
|
706
|
+
})
|
|
707
|
+
})
|
|
708
|
+
|
|
709
|
+
describe('getUsageSummary', () => {
|
|
710
|
+
it('should get usage summary dashboard with period parameter', async () => {
|
|
711
|
+
const params = {
|
|
712
|
+
period: '7d' as const
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const response: UsageSummaryResponse = {
|
|
716
|
+
status: 'success',
|
|
717
|
+
data: {
|
|
718
|
+
current_period: {
|
|
719
|
+
credits_consumed: 13870,
|
|
720
|
+
cost_usd: 41.61,
|
|
721
|
+
requests_count: 142
|
|
722
|
+
},
|
|
723
|
+
previous_period: {
|
|
724
|
+
credits_consumed: 11990,
|
|
725
|
+
cost_usd: 35.97,
|
|
726
|
+
requests_count: 131
|
|
727
|
+
},
|
|
728
|
+
billing_cycle: {
|
|
729
|
+
total_allotted: 50000,
|
|
730
|
+
total_consumed: 28450,
|
|
731
|
+
remaining_credits: 21550
|
|
732
|
+
},
|
|
733
|
+
utilization_percentage: 56.9,
|
|
734
|
+
remaining_credits: 21550,
|
|
735
|
+
daily_average: 1981.43,
|
|
736
|
+
projected_monthly: 59443
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
mockAxios.onGet('/usage/dashboard/summary?period=7d').reply(200, response)
|
|
741
|
+
|
|
742
|
+
const result = await usageService.getUsageSummary(params)
|
|
743
|
+
|
|
744
|
+
expect(result).toEqual(response)
|
|
745
|
+
})
|
|
746
|
+
|
|
747
|
+
it('should get usage summary dashboard with custom date range', async () => {
|
|
748
|
+
const params = {
|
|
749
|
+
start_date: '2024-01-01',
|
|
750
|
+
end_date: '2024-01-31'
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
const response: UsageSummaryResponse = {
|
|
754
|
+
status: 'success',
|
|
755
|
+
data: {
|
|
756
|
+
current_period: {
|
|
757
|
+
credits_consumed: 25000,
|
|
758
|
+
cost_usd: 75.0,
|
|
759
|
+
requests_count: 300
|
|
760
|
+
},
|
|
761
|
+
previous_period: {
|
|
762
|
+
credits_consumed: 22000,
|
|
763
|
+
cost_usd: 66.0,
|
|
764
|
+
requests_count: 275
|
|
765
|
+
},
|
|
766
|
+
billing_cycle: {
|
|
767
|
+
total_allotted: 50000,
|
|
768
|
+
total_consumed: 47000,
|
|
769
|
+
remaining_credits: 3000
|
|
770
|
+
},
|
|
771
|
+
utilization_percentage: 94.0,
|
|
772
|
+
remaining_credits: 3000,
|
|
773
|
+
daily_average: 806.45,
|
|
774
|
+
projected_monthly: 25000
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
mockAxios.onGet('/usage/dashboard/summary?start_date=2024-01-01&end_date=2024-01-31').reply(200, response)
|
|
779
|
+
|
|
780
|
+
const result = await usageService.getUsageSummary(params)
|
|
781
|
+
|
|
782
|
+
expect(result).toEqual(response)
|
|
783
|
+
})
|
|
784
|
+
})
|
|
785
|
+
|
|
786
|
+
describe('getServiceBreakdown', () => {
|
|
787
|
+
it('should get service breakdown with period parameter', async () => {
|
|
788
|
+
const params: ServiceBreakdownRequest = {
|
|
789
|
+
period: '7d'
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const response: ServiceBreakdownResponse = {
|
|
793
|
+
status: 'success',
|
|
794
|
+
data: {
|
|
795
|
+
period: {
|
|
796
|
+
start: '2024-01-25',
|
|
797
|
+
end: '2024-01-31',
|
|
798
|
+
label: '7d'
|
|
799
|
+
},
|
|
800
|
+
services: [
|
|
801
|
+
{
|
|
802
|
+
service_type: 'docs',
|
|
803
|
+
credits_consumed: 5230,
|
|
804
|
+
percentage: 37.71,
|
|
805
|
+
cost_usd: 15.69,
|
|
806
|
+
requests_count: 58,
|
|
807
|
+
trend: 12.5
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
service_type: 'chat',
|
|
811
|
+
credits_consumed: 4120,
|
|
812
|
+
percentage: 29.71,
|
|
813
|
+
cost_usd: 12.36,
|
|
814
|
+
requests_count: 47,
|
|
815
|
+
trend: -5.2
|
|
816
|
+
}
|
|
817
|
+
],
|
|
818
|
+
total_credits: 13870,
|
|
819
|
+
total_cost: 41.61
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
mockAxios.onGet('/usage/dashboard/services?period=7d').reply(200, response)
|
|
824
|
+
|
|
825
|
+
const result = await usageService.getServiceBreakdown(params)
|
|
826
|
+
|
|
827
|
+
expect(result).toEqual(response)
|
|
828
|
+
})
|
|
829
|
+
|
|
830
|
+
it('should get service breakdown with custom date range', async () => {
|
|
831
|
+
const params: ServiceBreakdownRequest = {
|
|
832
|
+
start_date: '2024-01-01',
|
|
833
|
+
end_date: '2024-01-31'
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const response: ServiceBreakdownResponse = {
|
|
837
|
+
status: 'success',
|
|
838
|
+
data: {
|
|
839
|
+
period: {
|
|
840
|
+
start: '2024-01-01',
|
|
841
|
+
end: '2024-01-31',
|
|
842
|
+
label: 'custom'
|
|
843
|
+
},
|
|
844
|
+
services: [
|
|
845
|
+
{
|
|
846
|
+
service_type: 'codespace_task',
|
|
847
|
+
credits_consumed: 15000,
|
|
848
|
+
percentage: 60.0,
|
|
849
|
+
cost_usd: 45.0,
|
|
850
|
+
requests_count: 25,
|
|
851
|
+
trend: 28.4
|
|
852
|
+
}
|
|
853
|
+
],
|
|
854
|
+
total_credits: 25000,
|
|
855
|
+
total_cost: 75.0
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
mockAxios.onGet('/usage/dashboard/services?start_date=2024-01-01&end_date=2024-01-31').reply(200, response)
|
|
860
|
+
|
|
861
|
+
const result = await usageService.getServiceBreakdown(params)
|
|
862
|
+
|
|
863
|
+
expect(result).toEqual(response)
|
|
864
|
+
})
|
|
865
|
+
|
|
866
|
+
it('should get service breakdown without parameters', async () => {
|
|
867
|
+
const response: ServiceBreakdownResponse = {
|
|
868
|
+
status: 'success',
|
|
869
|
+
data: {
|
|
870
|
+
period: {
|
|
871
|
+
start: '2024-01-01',
|
|
872
|
+
end: '2024-01-07',
|
|
873
|
+
label: '7d'
|
|
874
|
+
},
|
|
875
|
+
services: [
|
|
876
|
+
{
|
|
877
|
+
service_type: 'api',
|
|
878
|
+
credits_consumed: 700,
|
|
879
|
+
percentage: 100.0,
|
|
880
|
+
cost_usd: 2.10,
|
|
881
|
+
requests_count: 5,
|
|
882
|
+
trend: 0.0
|
|
883
|
+
}
|
|
884
|
+
],
|
|
885
|
+
total_credits: 700,
|
|
886
|
+
total_cost: 2.10
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
mockAxios.onGet('/usage/dashboard/services').reply(200, response)
|
|
891
|
+
|
|
892
|
+
const result = await usageService.getServiceBreakdown()
|
|
893
|
+
|
|
894
|
+
expect(result).toEqual(response)
|
|
895
|
+
})
|
|
896
|
+
})
|
|
385
897
|
})
|