@openlifelog/sdk 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/EXAMPLES.md +624 -0
- package/README.md +824 -0
- package/client.ts +190 -0
- package/config.ts +96 -0
- package/constants/metrics.ts +116 -0
- package/dist/index.d.mts +1101 -0
- package/dist/index.d.ts +1101 -0
- package/dist/index.js +2023 -0
- package/dist/index.mjs +1969 -0
- package/index.ts +49 -0
- package/package.json +53 -0
- package/resources/ai.ts +26 -0
- package/resources/auth.ts +98 -0
- package/resources/exercises.ts +112 -0
- package/resources/food-logs.ts +132 -0
- package/resources/foods.ts +185 -0
- package/resources/goals.ts +155 -0
- package/resources/metrics.ts +115 -0
- package/resources/programs.ts +123 -0
- package/resources/sessions.ts +142 -0
- package/resources/users.ts +132 -0
- package/resources/workouts.ts +147 -0
- package/tsconfig.json +27 -0
- package/types/ai.ts +55 -0
- package/types/common.ts +177 -0
- package/types/exercise.ts +75 -0
- package/types/food.ts +208 -0
- package/types/goal.ts +169 -0
- package/types/index.ts +17 -0
- package/types/metric.ts +108 -0
- package/types/program.ts +120 -0
- package/types/session.ts +196 -0
- package/types/user.ts +79 -0
- package/types/workout.ts +97 -0
- package/utils/errors.ts +159 -0
- package/utils/http.ts +313 -0
- package/utils/index.ts +8 -0
- package/utils/pagination.ts +106 -0
- package/utils/units.ts +279 -0
package/index.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenLifeLog TypeScript SDK
|
|
3
|
+
*
|
|
4
|
+
* A comprehensive TypeScript SDK for the OpenLifeLog API - the complete
|
|
5
|
+
* fitness and nutrition tracking platform.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Main client
|
|
11
|
+
export { OpenLifeLog } from './client';
|
|
12
|
+
|
|
13
|
+
// Configuration
|
|
14
|
+
export type { OpenLifeLogConfig } from './config';
|
|
15
|
+
|
|
16
|
+
// All types
|
|
17
|
+
export * from './types';
|
|
18
|
+
|
|
19
|
+
// Constants (metrics, etc.)
|
|
20
|
+
export * from './constants/metrics';
|
|
21
|
+
|
|
22
|
+
// Utilities (for advanced usage)
|
|
23
|
+
export {
|
|
24
|
+
// Errors
|
|
25
|
+
OpenLifeLogError,
|
|
26
|
+
AuthenticationError,
|
|
27
|
+
AuthorizationError,
|
|
28
|
+
NotFoundError,
|
|
29
|
+
ValidationError,
|
|
30
|
+
RateLimitError,
|
|
31
|
+
ServerError,
|
|
32
|
+
NetworkError,
|
|
33
|
+
TimeoutError,
|
|
34
|
+
UnitConversionError,
|
|
35
|
+
// Unit conversion
|
|
36
|
+
WeightConverter,
|
|
37
|
+
DistanceConverter,
|
|
38
|
+
HeightConverter,
|
|
39
|
+
UnitConverter,
|
|
40
|
+
createUnitConverter,
|
|
41
|
+
// Pagination
|
|
42
|
+
PaginatedIterator,
|
|
43
|
+
createPaginatedIterator,
|
|
44
|
+
fetchAllPages,
|
|
45
|
+
hasMorePages,
|
|
46
|
+
} from './utils';
|
|
47
|
+
|
|
48
|
+
// Default export
|
|
49
|
+
export { OpenLifeLog as default } from './client';
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openlifelog/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "TypeScript SDK for the OpenLifeLog API - A comprehensive fitness and nutrition tracking platform",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup index.ts --format cjs,esm --dts",
|
|
17
|
+
"dev": "tsup index.ts --format cjs,esm --dts --watch",
|
|
18
|
+
"test": "jest",
|
|
19
|
+
"lint": "eslint . --ext .ts",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"openlifelog",
|
|
24
|
+
"fitness",
|
|
25
|
+
"nutrition",
|
|
26
|
+
"workout",
|
|
27
|
+
"tracking",
|
|
28
|
+
"health",
|
|
29
|
+
"sdk",
|
|
30
|
+
"typescript",
|
|
31
|
+
"api-client"
|
|
32
|
+
],
|
|
33
|
+
"author": "OpenLifeLog",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/kukicado/openlifelog.git",
|
|
38
|
+
"directory": "src/sdk/typescript"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/kukicado/openlifelog/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/kukicado/openlifelog#readme",
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20.0.0",
|
|
46
|
+
"tsup": "^8.0.0",
|
|
47
|
+
"typescript": "^5.3.0"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=18.0.0"
|
|
52
|
+
}
|
|
53
|
+
}
|
package/resources/ai.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HttpClient } from '../utils/http';
|
|
2
|
+
import type { FoodInsightsResponse, GetFoodInsightsParams } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AI resource
|
|
6
|
+
* Handles AI-powered insights and recommendations
|
|
7
|
+
*/
|
|
8
|
+
export class AIResource {
|
|
9
|
+
constructor(private http: HttpClient) {}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get AI-generated nutrition insights
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* const insights = await client.ai.getFoodInsights({
|
|
17
|
+
* startDate: '2024-01-01',
|
|
18
|
+
* endDate: '2024-01-15'
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
async getFoodInsights(params?: GetFoodInsightsParams): Promise<FoodInsightsResponse> {
|
|
23
|
+
const response = await this.http.get<FoodInsightsResponse>('/v1/ai/food-insights', params);
|
|
24
|
+
return response.data;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { HttpClient } from '../utils/http';
|
|
2
|
+
import type {
|
|
3
|
+
SignupRequest,
|
|
4
|
+
LoginRequest,
|
|
5
|
+
AuthResponse,
|
|
6
|
+
PasswordResetRequest,
|
|
7
|
+
PasswordResetConfirm,
|
|
8
|
+
} from '../types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Authentication resource
|
|
12
|
+
* Handles user authentication operations
|
|
13
|
+
*/
|
|
14
|
+
export class AuthResource {
|
|
15
|
+
constructor(private http: HttpClient) {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Sign up a new user
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```typescript
|
|
22
|
+
* const { token, user } = await client.auth.signup({
|
|
23
|
+
* name: 'John Doe',
|
|
24
|
+
* email: 'john@example.com',
|
|
25
|
+
* password: 'securePassword123'
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
async signup(request: SignupRequest): Promise<AuthResponse> {
|
|
30
|
+
const response = await this.http.post<AuthResponse>('/v1/auth/signup', request);
|
|
31
|
+
|
|
32
|
+
// Automatically set the API key after successful signup
|
|
33
|
+
this.http.setApiKey(response.data.token);
|
|
34
|
+
|
|
35
|
+
return response.data;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Log in an existing user
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* const { token, user } = await client.auth.login({
|
|
44
|
+
* email: 'john@example.com',
|
|
45
|
+
* password: 'securePassword123'
|
|
46
|
+
* });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
async login(request: LoginRequest): Promise<AuthResponse> {
|
|
50
|
+
const response = await this.http.post<AuthResponse>('/v1/auth/login', request);
|
|
51
|
+
|
|
52
|
+
// Automatically set the API key after successful login
|
|
53
|
+
this.http.setApiKey(response.data.token);
|
|
54
|
+
|
|
55
|
+
return response.data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Request a password reset
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* await client.auth.requestPasswordReset({
|
|
64
|
+
* email: 'john@example.com'
|
|
65
|
+
* });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
async requestPasswordReset(request: PasswordResetRequest): Promise<void> {
|
|
69
|
+
await this.http.post('/v1/auth/password-reset/request', request);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Confirm password reset with token
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* await client.auth.confirmPasswordReset({
|
|
78
|
+
* token: 'reset-token-from-email',
|
|
79
|
+
* newPassword: 'newSecurePassword123'
|
|
80
|
+
* });
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
async confirmPasswordReset(request: PasswordResetConfirm): Promise<void> {
|
|
84
|
+
await this.http.post('/v1/auth/password-reset/confirm', request);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Log out the current user (clears the API key)
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* client.auth.logout();
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
logout(): void {
|
|
96
|
+
this.http.setApiKey('');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import type { HttpClient } from '../utils/http';
|
|
2
|
+
import type {
|
|
3
|
+
Exercise,
|
|
4
|
+
CreateExerciseRequest,
|
|
5
|
+
UpdateExerciseRequest,
|
|
6
|
+
ListExercisesParams,
|
|
7
|
+
ListResponse,
|
|
8
|
+
CountResponse,
|
|
9
|
+
} from '../types';
|
|
10
|
+
import { createPaginatedIterator, type PaginatedIterator } from '../utils/pagination';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Exercises resource
|
|
14
|
+
* Handles exercise database operations
|
|
15
|
+
*/
|
|
16
|
+
export class ExercisesResource {
|
|
17
|
+
constructor(private http: HttpClient) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* List exercises with filtering
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const { data } = await client.exercises.list({
|
|
25
|
+
* category: 'strength',
|
|
26
|
+
* muscleGroup: 'chest'
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async list(params?: ListExercisesParams): Promise<ListResponse<Exercise>> {
|
|
31
|
+
const response = await this.http.get<ListResponse<Exercise>>('/v1/exercises', params);
|
|
32
|
+
return response.data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* List exercises with automatic pagination
|
|
37
|
+
*/
|
|
38
|
+
listAutoPaginate(params?: ListExercisesParams): PaginatedIterator<Exercise> {
|
|
39
|
+
return createPaginatedIterator((cursor) =>
|
|
40
|
+
this.list({ ...params, cursor })
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get total count of exercises
|
|
46
|
+
*/
|
|
47
|
+
async count(): Promise<CountResponse> {
|
|
48
|
+
const response = await this.http.get<CountResponse>('/v1/exercises/count');
|
|
49
|
+
return response.data;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Search exercises by name
|
|
54
|
+
*/
|
|
55
|
+
async search(params: { q: string; limit?: number; cursor?: string }): Promise<ListResponse<Exercise>> {
|
|
56
|
+
const response = await this.http.get<ListResponse<Exercise>>('/v1/exercises/search', params);
|
|
57
|
+
return response.data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get specific exercise by ID
|
|
62
|
+
*/
|
|
63
|
+
async get(exerciseId: string): Promise<Exercise> {
|
|
64
|
+
const response = await this.http.get<Exercise>(`/v1/exercises/${exerciseId}`);
|
|
65
|
+
return response.data;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Create a new exercise
|
|
70
|
+
*/
|
|
71
|
+
async create(request: CreateExerciseRequest): Promise<Exercise> {
|
|
72
|
+
const response = await this.http.post<Exercise>('/v1/exercises', request);
|
|
73
|
+
return response.data;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Update an existing exercise
|
|
78
|
+
*/
|
|
79
|
+
async update(exerciseId: string, request: UpdateExerciseRequest): Promise<Exercise> {
|
|
80
|
+
const response = await this.http.put<Exercise>(`/v1/exercises/${exerciseId}`, request);
|
|
81
|
+
return response.data;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Delete an exercise
|
|
86
|
+
*/
|
|
87
|
+
async delete(exerciseId: string): Promise<void> {
|
|
88
|
+
await this.http.delete(`/v1/exercises/${exerciseId}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Get favorite exercises
|
|
93
|
+
*/
|
|
94
|
+
async getFavorites(params?: ListExercisesParams): Promise<ListResponse<Exercise>> {
|
|
95
|
+
const response = await this.http.get<ListResponse<Exercise>>('/v1/exercises/favorites', params);
|
|
96
|
+
return response.data;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Add exercise to favorites
|
|
101
|
+
*/
|
|
102
|
+
async addToFavorites(exerciseId: string): Promise<void> {
|
|
103
|
+
await this.http.post(`/v1/exercises/${exerciseId}/favorite`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Remove exercise from favorites
|
|
108
|
+
*/
|
|
109
|
+
async removeFromFavorites(exerciseId: string): Promise<void> {
|
|
110
|
+
await this.http.delete(`/v1/exercises/${exerciseId}/favorite`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { HttpClient } from '../utils/http';
|
|
2
|
+
import type {
|
|
3
|
+
FoodLog,
|
|
4
|
+
CreateFoodLogRequest,
|
|
5
|
+
UpdateFoodLogRequest,
|
|
6
|
+
QuickEntryFoodLogRequest,
|
|
7
|
+
ListFoodLogsParams,
|
|
8
|
+
DailyNutritionSummary,
|
|
9
|
+
GetDailySummaryParams,
|
|
10
|
+
} from '../types';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Food Logs resource
|
|
14
|
+
* Handles food logging and nutrition tracking
|
|
15
|
+
*/
|
|
16
|
+
export class FoodLogsResource {
|
|
17
|
+
constructor(private http: HttpClient) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* List food log entries with filtering
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const logs = await client.foodLogs.list({
|
|
25
|
+
* date: '2024-01-15',
|
|
26
|
+
* mealType: 'lunch'
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async list(params?: ListFoodLogsParams): Promise<FoodLog[]> {
|
|
31
|
+
const response = await this.http.get<FoodLog[]>('/v1/food-logs', params);
|
|
32
|
+
return response.data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get daily nutrition summary
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const summary = await client.foodLogs.getDailySummary({
|
|
41
|
+
* date: '2024-01-15'
|
|
42
|
+
* });
|
|
43
|
+
* console.log(`Total calories: ${summary.totalCalories}`);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
async getDailySummary(params?: GetDailySummaryParams): Promise<DailyNutritionSummary> {
|
|
47
|
+
const response = await this.http.get<DailyNutritionSummary>('/v1/food-logs/summary', params);
|
|
48
|
+
return response.data;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get specific food log entry
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const log = await client.foodLogs.get('log-id');
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
async get(logId: string): Promise<FoodLog> {
|
|
60
|
+
const response = await this.http.get<FoodLog>(`/v1/food-logs/${logId}`);
|
|
61
|
+
return response.data;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Create a food log entry
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* const log = await client.foodLogs.create({
|
|
70
|
+
* foodId: 'food-uuid',
|
|
71
|
+
* name: 'Chicken Breast',
|
|
72
|
+
* servingSizeName: 'breast (200g)',
|
|
73
|
+
* quantity: 1.5,
|
|
74
|
+
* unitGrams: 200,
|
|
75
|
+
* mealType: 'lunch',
|
|
76
|
+
* notes: 'Grilled with olive oil'
|
|
77
|
+
* });
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
async create(request: CreateFoodLogRequest): Promise<FoodLog> {
|
|
81
|
+
const response = await this.http.post<FoodLog>('/v1/food-logs', request);
|
|
82
|
+
return response.data;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Quick entry food log with just name and nutrients
|
|
87
|
+
* Creates a food log entry without creating a food (one-off entry)
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const log = await client.foodLogs.quickEntry({
|
|
92
|
+
* name: 'Homemade Salad',
|
|
93
|
+
* protein: 15,
|
|
94
|
+
* carbohydrates: 20,
|
|
95
|
+
* fat: 10,
|
|
96
|
+
* mealType: 'lunch'
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
async quickEntry(request: QuickEntryFoodLogRequest): Promise<FoodLog> {
|
|
101
|
+
const response = await this.http.post<FoodLog>('/v1/food-logs-quick-entry', request);
|
|
102
|
+
return response.data;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Update a food log entry
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const log = await client.foodLogs.update('log-id', {
|
|
111
|
+
* quantity: 2,
|
|
112
|
+
* notes: 'Updated portion size'
|
|
113
|
+
* });
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
async update(logId: string, request: UpdateFoodLogRequest): Promise<FoodLog> {
|
|
117
|
+
const response = await this.http.put<FoodLog>(`/v1/food-logs/${logId}`, request);
|
|
118
|
+
return response.data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Delete a food log entry
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```typescript
|
|
126
|
+
* await client.foodLogs.delete('log-id');
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async delete(logId: string): Promise<void> {
|
|
130
|
+
await this.http.delete(`/v1/food-logs/${logId}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import type { HttpClient } from '../utils/http';
|
|
2
|
+
import type {
|
|
3
|
+
Food,
|
|
4
|
+
CreateFoodRequest,
|
|
5
|
+
UpdateFoodRequest,
|
|
6
|
+
ListFoodsParams,
|
|
7
|
+
ListResponse,
|
|
8
|
+
CountResponse,
|
|
9
|
+
} from '../types';
|
|
10
|
+
import { createPaginatedIterator, type PaginatedIterator } from '../utils/pagination';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Foods resource
|
|
14
|
+
* Handles food database operations
|
|
15
|
+
*/
|
|
16
|
+
export class FoodsResource {
|
|
17
|
+
constructor(private http: HttpClient) {}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* List foods with pagination and search
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const { data, pageInfo } = await client.foods.list({
|
|
25
|
+
* limit: 20,
|
|
26
|
+
* search: 'chicken'
|
|
27
|
+
* });
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
async list(params?: ListFoodsParams): Promise<ListResponse<Food>> {
|
|
31
|
+
const response = await this.http.get<ListResponse<Food>>('/v1/foods', params);
|
|
32
|
+
return response.data;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* List foods with automatic pagination
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* for await (const food of client.foods.listAutoPaginate({ limit: 100 })) {
|
|
41
|
+
* console.log(food.name);
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
listAutoPaginate(params?: ListFoodsParams): PaginatedIterator<Food> {
|
|
46
|
+
return createPaginatedIterator((cursor) =>
|
|
47
|
+
this.list({ ...params, cursor })
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get total count of foods
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* const { count } = await client.foods.count();
|
|
57
|
+
* console.log(`Database has ${count} foods`);
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
async count(): Promise<CountResponse> {
|
|
61
|
+
const response = await this.http.get<CountResponse>('/v1/foods/count');
|
|
62
|
+
return response.data;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Search foods by name or brand
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const { data } = await client.foods.search({
|
|
71
|
+
* q: 'chicken breast',
|
|
72
|
+
* limit: 10
|
|
73
|
+
* });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
async search(params: { q: string; limit?: number; cursor?: string }): Promise<ListResponse<Food>> {
|
|
77
|
+
const response = await this.http.get<ListResponse<Food>>('/v1/foods/search', params);
|
|
78
|
+
return response.data;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get specific food by ID
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* ```typescript
|
|
86
|
+
* const food = await client.foods.get('food-id');
|
|
87
|
+
* console.log(food.nutrients);
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
async get(foodId: string): Promise<Food> {
|
|
91
|
+
const response = await this.http.get<Food>(`/v1/foods/${foodId}`);
|
|
92
|
+
return response.data;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Create a new food item
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* const food = await client.foods.create({
|
|
101
|
+
* name: 'Custom Protein Shake',
|
|
102
|
+
* type: 'beverage',
|
|
103
|
+
* nutrients: {
|
|
104
|
+
* calories: 300,
|
|
105
|
+
* protein: 40,
|
|
106
|
+
* carbohydrates: 20,
|
|
107
|
+
* fat: 5
|
|
108
|
+
* },
|
|
109
|
+
* servingSizes: [{
|
|
110
|
+
* name: '1 serving',
|
|
111
|
+
* grams: 300,
|
|
112
|
+
* isDefault: true
|
|
113
|
+
* }]
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
async create(request: CreateFoodRequest): Promise<Food> {
|
|
118
|
+
const response = await this.http.post<Food>('/v1/foods', request);
|
|
119
|
+
return response.data;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Update an existing food item
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const food = await client.foods.update('food-id', {
|
|
128
|
+
* description: 'Updated description'
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
async update(foodId: string, request: UpdateFoodRequest): Promise<Food> {
|
|
133
|
+
const response = await this.http.put<Food>(`/v1/foods/${foodId}`, request);
|
|
134
|
+
return response.data;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Delete a food item
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* await client.foods.delete('food-id');
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
async delete(foodId: string): Promise<void> {
|
|
146
|
+
await this.http.delete(`/v1/foods/${foodId}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get favorite foods
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* const { data } = await client.foods.getFavorites();
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
async getFavorites(params?: ListFoodsParams): Promise<ListResponse<Food>> {
|
|
158
|
+
const response = await this.http.get<ListResponse<Food>>('/v1/foods/favorites', params);
|
|
159
|
+
return response.data;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Add food to favorites
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* await client.foods.addToFavorites('food-id');
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
async addToFavorites(foodId: string): Promise<void> {
|
|
171
|
+
await this.http.post(`/v1/foods/${foodId}/favorite`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Remove food from favorites
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* await client.foods.removeFromFavorites('food-id');
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
async removeFromFavorites(foodId: string): Promise<void> {
|
|
183
|
+
await this.http.delete(`/v1/foods/${foodId}/favorite`);
|
|
184
|
+
}
|
|
185
|
+
}
|