@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/dist/index.js
ADDED
|
@@ -0,0 +1,2023 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
ACTIVITY_METRICS: () => ACTIVITY_METRICS,
|
|
24
|
+
ALL_METRICS: () => ALL_METRICS,
|
|
25
|
+
AuthenticationError: () => AuthenticationError,
|
|
26
|
+
AuthorizationError: () => AuthorizationError,
|
|
27
|
+
BODY_METRICS: () => BODY_METRICS,
|
|
28
|
+
DistanceConverter: () => DistanceConverter,
|
|
29
|
+
HeightConverter: () => HeightConverter,
|
|
30
|
+
NetworkError: () => NetworkError,
|
|
31
|
+
NotFoundError: () => NotFoundError,
|
|
32
|
+
OpenLifeLog: () => OpenLifeLog,
|
|
33
|
+
OpenLifeLogError: () => OpenLifeLogError,
|
|
34
|
+
PaginatedIterator: () => PaginatedIterator,
|
|
35
|
+
RateLimitError: () => RateLimitError,
|
|
36
|
+
SLEEP_METRICS: () => SLEEP_METRICS,
|
|
37
|
+
ServerError: () => ServerError,
|
|
38
|
+
TimeoutError: () => TimeoutError,
|
|
39
|
+
UnitConversionError: () => UnitConversionError,
|
|
40
|
+
UnitConverter: () => UnitConverter,
|
|
41
|
+
VITAL_METRICS: () => VITAL_METRICS,
|
|
42
|
+
ValidationError: () => ValidationError,
|
|
43
|
+
WELLNESS_METRICS: () => WELLNESS_METRICS,
|
|
44
|
+
WeightConverter: () => WeightConverter,
|
|
45
|
+
createPaginatedIterator: () => createPaginatedIterator,
|
|
46
|
+
createUnitConverter: () => createUnitConverter,
|
|
47
|
+
default: () => OpenLifeLog,
|
|
48
|
+
fetchAllPages: () => fetchAllPages,
|
|
49
|
+
getMetricDefinition: () => getMetricDefinition,
|
|
50
|
+
getMetricsByCategory: () => getMetricsByCategory,
|
|
51
|
+
hasMorePages: () => hasMorePages
|
|
52
|
+
});
|
|
53
|
+
module.exports = __toCommonJS(index_exports);
|
|
54
|
+
|
|
55
|
+
// config.ts
|
|
56
|
+
var DEFAULT_CONFIG = {
|
|
57
|
+
baseUrl: "https://api.openlifelog.com",
|
|
58
|
+
measurementSystem: "metric",
|
|
59
|
+
autoConvertUnits: true,
|
|
60
|
+
timeout: 3e4,
|
|
61
|
+
maxRetries: 3,
|
|
62
|
+
enableRetries: true,
|
|
63
|
+
debug: false
|
|
64
|
+
};
|
|
65
|
+
function mergeConfig(userConfig) {
|
|
66
|
+
return {
|
|
67
|
+
...DEFAULT_CONFIG,
|
|
68
|
+
...userConfig,
|
|
69
|
+
apiKey: userConfig.apiKey,
|
|
70
|
+
headers: userConfig.headers || {},
|
|
71
|
+
// Bind fetch to globalThis to preserve context
|
|
72
|
+
fetch: userConfig.fetch || globalThis.fetch.bind(globalThis)
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// utils/errors.ts
|
|
77
|
+
var OpenLifeLogError = class extends Error {
|
|
78
|
+
constructor(message, statusCode, code, rawError) {
|
|
79
|
+
super(message);
|
|
80
|
+
this.name = "OpenLifeLogError";
|
|
81
|
+
this.statusCode = statusCode;
|
|
82
|
+
this.code = code;
|
|
83
|
+
this.rawError = rawError;
|
|
84
|
+
if (Error.captureStackTrace) {
|
|
85
|
+
Error.captureStackTrace(this, this.constructor);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var AuthenticationError = class extends OpenLifeLogError {
|
|
90
|
+
constructor(message = "Authentication failed. Please check your credentials.", rawError) {
|
|
91
|
+
super(message, 401, "AUTHENTICATION_ERROR", rawError);
|
|
92
|
+
this.name = "AuthenticationError";
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
var AuthorizationError = class extends OpenLifeLogError {
|
|
96
|
+
constructor(message = "You do not have permission to access this resource.", rawError) {
|
|
97
|
+
super(message, 403, "AUTHORIZATION_ERROR", rawError);
|
|
98
|
+
this.name = "AuthorizationError";
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
var NotFoundError = class extends OpenLifeLogError {
|
|
102
|
+
constructor(message = "The requested resource was not found.", rawError) {
|
|
103
|
+
super(message, 404, "NOT_FOUND", rawError);
|
|
104
|
+
this.name = "NotFoundError";
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var ValidationError = class extends OpenLifeLogError {
|
|
108
|
+
constructor(message = "Validation failed.", validationErrors, rawError) {
|
|
109
|
+
super(message, 400, "VALIDATION_ERROR", rawError);
|
|
110
|
+
this.name = "ValidationError";
|
|
111
|
+
this.validationErrors = validationErrors;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var RateLimitError = class extends OpenLifeLogError {
|
|
115
|
+
constructor(message = "Rate limit exceeded. Please try again later.", retryAfter, rawError) {
|
|
116
|
+
super(message, 429, "RATE_LIMIT_ERROR", rawError);
|
|
117
|
+
this.name = "RateLimitError";
|
|
118
|
+
this.retryAfter = retryAfter;
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
var ServerError = class extends OpenLifeLogError {
|
|
122
|
+
constructor(message = "An internal server error occurred.", rawError) {
|
|
123
|
+
super(message, 500, "SERVER_ERROR", rawError);
|
|
124
|
+
this.name = "ServerError";
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var NetworkError = class extends OpenLifeLogError {
|
|
128
|
+
constructor(message = "A network error occurred. Please check your connection.", rawError) {
|
|
129
|
+
super(message, void 0, "NETWORK_ERROR", rawError);
|
|
130
|
+
this.name = "NetworkError";
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
var TimeoutError = class extends OpenLifeLogError {
|
|
134
|
+
constructor(message = "The request timed out.", rawError) {
|
|
135
|
+
super(message, 408, "TIMEOUT_ERROR", rawError);
|
|
136
|
+
this.name = "TimeoutError";
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var UnitConversionError = class extends OpenLifeLogError {
|
|
140
|
+
constructor(message = "Failed to convert units.", rawError) {
|
|
141
|
+
super(message, void 0, "UNIT_CONVERSION_ERROR", rawError);
|
|
142
|
+
this.name = "UnitConversionError";
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
function parseErrorResponse(error, statusCode) {
|
|
146
|
+
const message = error?.message || error?.error || "An unknown error occurred";
|
|
147
|
+
const rawError = error;
|
|
148
|
+
if (statusCode === 401) {
|
|
149
|
+
return new AuthenticationError(message, rawError);
|
|
150
|
+
}
|
|
151
|
+
if (statusCode === 403) {
|
|
152
|
+
return new AuthorizationError(message, rawError);
|
|
153
|
+
}
|
|
154
|
+
if (statusCode === 404) {
|
|
155
|
+
return new NotFoundError(message, rawError);
|
|
156
|
+
}
|
|
157
|
+
if (statusCode === 400) {
|
|
158
|
+
return new ValidationError(message, error?.validationErrors, rawError);
|
|
159
|
+
}
|
|
160
|
+
if (statusCode === 429) {
|
|
161
|
+
return new RateLimitError(message, error?.retryAfter, rawError);
|
|
162
|
+
}
|
|
163
|
+
if (statusCode && statusCode >= 500) {
|
|
164
|
+
return new ServerError(message, rawError);
|
|
165
|
+
}
|
|
166
|
+
return new OpenLifeLogError(message, statusCode, error?.code, rawError);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// utils/http.ts
|
|
170
|
+
var HttpClient = class {
|
|
171
|
+
constructor(config) {
|
|
172
|
+
this.config = config;
|
|
173
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Update the API key (token)
|
|
177
|
+
*/
|
|
178
|
+
setApiKey(apiKey) {
|
|
179
|
+
this.config.apiKey = apiKey;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Get the current API key
|
|
183
|
+
*/
|
|
184
|
+
getApiKey() {
|
|
185
|
+
return this.config.apiKey;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Convert camelCase to snake_case
|
|
189
|
+
*/
|
|
190
|
+
toSnakeCase(str) {
|
|
191
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Build full URL with query parameters
|
|
195
|
+
*/
|
|
196
|
+
buildUrl(path, params) {
|
|
197
|
+
const url = new URL(path.startsWith("/") ? `${this.baseUrl}${path}` : `${this.baseUrl}/${path}`);
|
|
198
|
+
if (params) {
|
|
199
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
200
|
+
if (value !== void 0 && value !== null) {
|
|
201
|
+
const snakeKey = this.toSnakeCase(key);
|
|
202
|
+
if (Array.isArray(value)) {
|
|
203
|
+
value.forEach((v) => url.searchParams.append(snakeKey, String(v)));
|
|
204
|
+
} else {
|
|
205
|
+
url.searchParams.append(snakeKey, String(value));
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return url.toString();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Build request headers
|
|
214
|
+
*/
|
|
215
|
+
buildHeaders(customHeaders) {
|
|
216
|
+
const headers = {
|
|
217
|
+
"Content-Type": "application/json",
|
|
218
|
+
...this.config.headers,
|
|
219
|
+
...customHeaders
|
|
220
|
+
};
|
|
221
|
+
if (this.config.apiKey) {
|
|
222
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
223
|
+
}
|
|
224
|
+
return headers;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Execute request with timeout support
|
|
228
|
+
*/
|
|
229
|
+
async executeWithTimeout(url, init, timeout) {
|
|
230
|
+
const controller = new AbortController();
|
|
231
|
+
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
232
|
+
try {
|
|
233
|
+
const response = await this.config.fetch(url, {
|
|
234
|
+
...init,
|
|
235
|
+
signal: controller.signal
|
|
236
|
+
});
|
|
237
|
+
clearTimeout(timeoutId);
|
|
238
|
+
return response;
|
|
239
|
+
} catch (error) {
|
|
240
|
+
clearTimeout(timeoutId);
|
|
241
|
+
if (error.name === "AbortError") {
|
|
242
|
+
throw new TimeoutError(`Request timed out after ${timeout}ms`);
|
|
243
|
+
}
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Sleep for exponential backoff
|
|
249
|
+
*/
|
|
250
|
+
async sleep(ms) {
|
|
251
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Determine if error is retryable
|
|
255
|
+
*/
|
|
256
|
+
isRetryableError(error, statusCode) {
|
|
257
|
+
if (error instanceof NetworkError || error instanceof TimeoutError) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
if (statusCode && statusCode >= 500 && statusCode < 600) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
if (statusCode === 429) {
|
|
264
|
+
return true;
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Calculate exponential backoff delay
|
|
270
|
+
*/
|
|
271
|
+
getRetryDelay(attempt) {
|
|
272
|
+
const baseDelay = Math.pow(2, attempt) * 1e3;
|
|
273
|
+
const jitter = Math.random() * 1e3;
|
|
274
|
+
return baseDelay + jitter;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Make HTTP request with automatic retries
|
|
278
|
+
*/
|
|
279
|
+
async request(path, options = {}) {
|
|
280
|
+
const {
|
|
281
|
+
method = "GET",
|
|
282
|
+
headers: customHeaders,
|
|
283
|
+
body,
|
|
284
|
+
params,
|
|
285
|
+
timeout = this.config.timeout,
|
|
286
|
+
skipRetry = false
|
|
287
|
+
} = options;
|
|
288
|
+
const url = this.buildUrl(path, params);
|
|
289
|
+
const headers = this.buildHeaders(customHeaders);
|
|
290
|
+
const requestInit = {
|
|
291
|
+
method,
|
|
292
|
+
headers
|
|
293
|
+
};
|
|
294
|
+
if (body && (method === "POST" || method === "PUT" || method === "PATCH")) {
|
|
295
|
+
requestInit.body = JSON.stringify(body);
|
|
296
|
+
}
|
|
297
|
+
const maxAttempts = skipRetry || !this.config.enableRetries ? 1 : this.config.maxRetries + 1;
|
|
298
|
+
let lastError;
|
|
299
|
+
if (this.config.debug) {
|
|
300
|
+
console.log(`[OpenLifeLog SDK] ${method} ${url}`, body ? { body } : "");
|
|
301
|
+
}
|
|
302
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
303
|
+
try {
|
|
304
|
+
if (attempt > 0) {
|
|
305
|
+
const delay = this.getRetryDelay(attempt - 1);
|
|
306
|
+
if (this.config.debug) {
|
|
307
|
+
console.log(`[OpenLifeLog SDK] Retry attempt ${attempt}/${maxAttempts - 1}, waiting ${delay}ms`);
|
|
308
|
+
}
|
|
309
|
+
await this.sleep(delay);
|
|
310
|
+
}
|
|
311
|
+
const response = await this.executeWithTimeout(url, requestInit, timeout);
|
|
312
|
+
if (!response.ok) {
|
|
313
|
+
let errorData;
|
|
314
|
+
try {
|
|
315
|
+
errorData = await response.json();
|
|
316
|
+
} catch {
|
|
317
|
+
errorData = { error: response.statusText };
|
|
318
|
+
}
|
|
319
|
+
const error = parseErrorResponse(errorData, response.status);
|
|
320
|
+
if (this.isRetryableError(error, response.status) && attempt < maxAttempts - 1) {
|
|
321
|
+
lastError = error;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
326
|
+
let data;
|
|
327
|
+
const contentType = response.headers.get("content-type");
|
|
328
|
+
if (contentType?.includes("application/json")) {
|
|
329
|
+
data = await response.json();
|
|
330
|
+
} else {
|
|
331
|
+
data = await response.text();
|
|
332
|
+
}
|
|
333
|
+
if (this.config.debug) {
|
|
334
|
+
console.log(`[OpenLifeLog SDK] Response ${response.status}`, data);
|
|
335
|
+
}
|
|
336
|
+
return {
|
|
337
|
+
data,
|
|
338
|
+
status: response.status,
|
|
339
|
+
headers: response.headers
|
|
340
|
+
};
|
|
341
|
+
} catch (error) {
|
|
342
|
+
if (error.name === "TypeError" && error.message.includes("fetch")) {
|
|
343
|
+
lastError = new NetworkError(error.message, error);
|
|
344
|
+
} else if (error instanceof TimeoutError) {
|
|
345
|
+
lastError = error;
|
|
346
|
+
} else if (error.name === "AbortError") {
|
|
347
|
+
lastError = new TimeoutError("Request was aborted", error);
|
|
348
|
+
} else {
|
|
349
|
+
lastError = error;
|
|
350
|
+
}
|
|
351
|
+
if (this.isRetryableError(lastError) && attempt < maxAttempts - 1) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
throw lastError;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
throw lastError;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* GET request
|
|
361
|
+
*/
|
|
362
|
+
async get(path, params, options) {
|
|
363
|
+
return this.request(path, { ...options, method: "GET", params });
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* POST request
|
|
367
|
+
*/
|
|
368
|
+
async post(path, body, options) {
|
|
369
|
+
return this.request(path, { ...options, method: "POST", body });
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* PUT request
|
|
373
|
+
*/
|
|
374
|
+
async put(path, body, options) {
|
|
375
|
+
return this.request(path, { ...options, method: "PUT", body });
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* PATCH request
|
|
379
|
+
*/
|
|
380
|
+
async patch(path, body, options) {
|
|
381
|
+
return this.request(path, { ...options, method: "PATCH", body });
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* DELETE request
|
|
385
|
+
*/
|
|
386
|
+
async delete(path, options) {
|
|
387
|
+
return this.request(path, { ...options, method: "DELETE" });
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
// utils/units.ts
|
|
392
|
+
var KG_TO_LBS = 2.20462;
|
|
393
|
+
var LBS_TO_KG = 1 / KG_TO_LBS;
|
|
394
|
+
var METERS_TO_MILES = 621371e-9;
|
|
395
|
+
var MILES_TO_METERS = 1 / METERS_TO_MILES;
|
|
396
|
+
var METERS_TO_FEET = 3.28084;
|
|
397
|
+
var FEET_TO_METERS = 1 / METERS_TO_FEET;
|
|
398
|
+
var CM_TO_INCHES = 0.393701;
|
|
399
|
+
var INCHES_TO_CM = 1 / CM_TO_INCHES;
|
|
400
|
+
var WeightConverter = class {
|
|
401
|
+
/**
|
|
402
|
+
* Convert kilograms to pounds
|
|
403
|
+
*/
|
|
404
|
+
static kgToLbs(kg) {
|
|
405
|
+
return kg * KG_TO_LBS;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Convert pounds to kilograms
|
|
409
|
+
*/
|
|
410
|
+
static lbsToKg(lbs) {
|
|
411
|
+
return lbs * LBS_TO_KG;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Convert weight from metric to the target measurement system
|
|
415
|
+
*/
|
|
416
|
+
static fromMetric(kg, targetSystem) {
|
|
417
|
+
if (targetSystem === "imperial") {
|
|
418
|
+
return this.kgToLbs(kg);
|
|
419
|
+
}
|
|
420
|
+
return kg;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Convert weight to metric from the source measurement system
|
|
424
|
+
*/
|
|
425
|
+
static toMetric(value, sourceSystem) {
|
|
426
|
+
if (sourceSystem === "imperial") {
|
|
427
|
+
return this.lbsToKg(value);
|
|
428
|
+
}
|
|
429
|
+
return value;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
var DistanceConverter = class {
|
|
433
|
+
/**
|
|
434
|
+
* Convert meters to miles
|
|
435
|
+
*/
|
|
436
|
+
static metersToMiles(meters) {
|
|
437
|
+
return meters * METERS_TO_MILES;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Convert miles to meters
|
|
441
|
+
*/
|
|
442
|
+
static milesToMeters(miles) {
|
|
443
|
+
return miles * MILES_TO_METERS;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Convert meters to feet
|
|
447
|
+
*/
|
|
448
|
+
static metersToFeet(meters) {
|
|
449
|
+
return meters * METERS_TO_FEET;
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Convert feet to meters
|
|
453
|
+
*/
|
|
454
|
+
static feetToMeters(feet) {
|
|
455
|
+
return feet * FEET_TO_METERS;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Convert distance from metric to the target measurement system
|
|
459
|
+
* For larger distances (> 1000m), converts to miles, otherwise to feet
|
|
460
|
+
*/
|
|
461
|
+
static fromMetric(meters, targetSystem, preferMiles = false) {
|
|
462
|
+
if (targetSystem === "imperial") {
|
|
463
|
+
if (preferMiles || meters >= 1e3) {
|
|
464
|
+
return this.metersToMiles(meters);
|
|
465
|
+
}
|
|
466
|
+
return this.metersToFeet(meters);
|
|
467
|
+
}
|
|
468
|
+
return meters;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Convert distance to metric from the source measurement system
|
|
472
|
+
*/
|
|
473
|
+
static toMetric(value, sourceSystem, isMiles = false) {
|
|
474
|
+
if (sourceSystem === "imperial") {
|
|
475
|
+
return isMiles ? this.milesToMeters(value) : this.feetToMeters(value);
|
|
476
|
+
}
|
|
477
|
+
return value;
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
var HeightConverter = class {
|
|
481
|
+
/**
|
|
482
|
+
* Convert centimeters to inches
|
|
483
|
+
*/
|
|
484
|
+
static cmToInches(cm) {
|
|
485
|
+
return cm * CM_TO_INCHES;
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Convert inches to centimeters
|
|
489
|
+
*/
|
|
490
|
+
static inchesToCm(inches) {
|
|
491
|
+
return inches * INCHES_TO_CM;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Convert centimeters to feet and inches
|
|
495
|
+
*/
|
|
496
|
+
static cmToFeetInches(cm) {
|
|
497
|
+
const totalInches = this.cmToInches(cm);
|
|
498
|
+
const feet = Math.floor(totalInches / 12);
|
|
499
|
+
const inches = Math.round(totalInches % 12);
|
|
500
|
+
return { feet, inches };
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Convert feet and inches to centimeters
|
|
504
|
+
*/
|
|
505
|
+
static feetInchesToCm(feet, inches) {
|
|
506
|
+
const totalInches = feet * 12 + inches;
|
|
507
|
+
return this.inchesToCm(totalInches);
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Convert height from metric to the target measurement system
|
|
511
|
+
*/
|
|
512
|
+
static fromMetric(cm, targetSystem) {
|
|
513
|
+
if (targetSystem === "imperial") {
|
|
514
|
+
return this.cmToInches(cm);
|
|
515
|
+
}
|
|
516
|
+
return cm;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Convert height to metric from the source measurement system
|
|
520
|
+
*/
|
|
521
|
+
static toMetric(value, sourceSystem) {
|
|
522
|
+
if (sourceSystem === "imperial") {
|
|
523
|
+
return this.inchesToCm(value);
|
|
524
|
+
}
|
|
525
|
+
return value;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
var UnitConverter = class {
|
|
529
|
+
constructor(measurementSystem = "metric") {
|
|
530
|
+
this.measurementSystem = measurementSystem;
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Update the measurement system
|
|
534
|
+
*/
|
|
535
|
+
setMeasurementSystem(system) {
|
|
536
|
+
this.measurementSystem = system;
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Get the current measurement system
|
|
540
|
+
*/
|
|
541
|
+
getMeasurementSystem() {
|
|
542
|
+
return this.measurementSystem;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Convert weight from metric (API storage format) to user preference
|
|
546
|
+
*/
|
|
547
|
+
weightFromMetric(kg) {
|
|
548
|
+
if (kg === null || kg === void 0) return null;
|
|
549
|
+
return WeightConverter.fromMetric(kg, this.measurementSystem);
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Convert weight to metric (API storage format) from user preference
|
|
553
|
+
*/
|
|
554
|
+
weightToMetric(value) {
|
|
555
|
+
if (value === null || value === void 0) return null;
|
|
556
|
+
return WeightConverter.toMetric(value, this.measurementSystem);
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Convert distance from metric to user preference
|
|
560
|
+
*/
|
|
561
|
+
distanceFromMetric(meters, preferMiles = false) {
|
|
562
|
+
if (meters === null || meters === void 0) return null;
|
|
563
|
+
return DistanceConverter.fromMetric(meters, this.measurementSystem, preferMiles);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Convert distance to metric from user preference
|
|
567
|
+
*/
|
|
568
|
+
distanceToMetric(value, isMiles = false) {
|
|
569
|
+
if (value === null || value === void 0) return null;
|
|
570
|
+
return DistanceConverter.toMetric(value, this.measurementSystem, isMiles);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Convert height from metric to user preference
|
|
574
|
+
*/
|
|
575
|
+
heightFromMetric(cm) {
|
|
576
|
+
if (cm === null || cm === void 0) return null;
|
|
577
|
+
return HeightConverter.fromMetric(cm, this.measurementSystem);
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Convert height to metric from user preference
|
|
581
|
+
*/
|
|
582
|
+
heightToMetric(value) {
|
|
583
|
+
if (value === null || value === void 0) return null;
|
|
584
|
+
return HeightConverter.toMetric(value, this.measurementSystem);
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Round number to specified decimal places
|
|
588
|
+
*/
|
|
589
|
+
static round(value, decimals = 2) {
|
|
590
|
+
return Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Get the appropriate unit label for weight
|
|
594
|
+
*/
|
|
595
|
+
getWeightUnit() {
|
|
596
|
+
return this.measurementSystem === "imperial" ? "lbs" : "kg";
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Get the appropriate unit label for distance
|
|
600
|
+
*/
|
|
601
|
+
getDistanceUnit(preferMiles = false) {
|
|
602
|
+
if (this.measurementSystem === "imperial") {
|
|
603
|
+
return preferMiles ? "mi" : "ft";
|
|
604
|
+
}
|
|
605
|
+
return "m";
|
|
606
|
+
}
|
|
607
|
+
/**
|
|
608
|
+
* Get the appropriate unit label for height
|
|
609
|
+
*/
|
|
610
|
+
getHeightUnit() {
|
|
611
|
+
return this.measurementSystem === "imperial" ? "in" : "cm";
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
function createUnitConverter(measurementSystem = "metric") {
|
|
615
|
+
return new UnitConverter(measurementSystem);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// resources/auth.ts
|
|
619
|
+
var AuthResource = class {
|
|
620
|
+
constructor(http) {
|
|
621
|
+
this.http = http;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Sign up a new user
|
|
625
|
+
*
|
|
626
|
+
* @example
|
|
627
|
+
* ```typescript
|
|
628
|
+
* const { token, user } = await client.auth.signup({
|
|
629
|
+
* name: 'John Doe',
|
|
630
|
+
* email: 'john@example.com',
|
|
631
|
+
* password: 'securePassword123'
|
|
632
|
+
* });
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
async signup(request) {
|
|
636
|
+
const response = await this.http.post("/v1/auth/signup", request);
|
|
637
|
+
this.http.setApiKey(response.data.token);
|
|
638
|
+
return response.data;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Log in an existing user
|
|
642
|
+
*
|
|
643
|
+
* @example
|
|
644
|
+
* ```typescript
|
|
645
|
+
* const { token, user } = await client.auth.login({
|
|
646
|
+
* email: 'john@example.com',
|
|
647
|
+
* password: 'securePassword123'
|
|
648
|
+
* });
|
|
649
|
+
* ```
|
|
650
|
+
*/
|
|
651
|
+
async login(request) {
|
|
652
|
+
const response = await this.http.post("/v1/auth/login", request);
|
|
653
|
+
this.http.setApiKey(response.data.token);
|
|
654
|
+
return response.data;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Request a password reset
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```typescript
|
|
661
|
+
* await client.auth.requestPasswordReset({
|
|
662
|
+
* email: 'john@example.com'
|
|
663
|
+
* });
|
|
664
|
+
* ```
|
|
665
|
+
*/
|
|
666
|
+
async requestPasswordReset(request) {
|
|
667
|
+
await this.http.post("/v1/auth/password-reset/request", request);
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* Confirm password reset with token
|
|
671
|
+
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```typescript
|
|
674
|
+
* await client.auth.confirmPasswordReset({
|
|
675
|
+
* token: 'reset-token-from-email',
|
|
676
|
+
* newPassword: 'newSecurePassword123'
|
|
677
|
+
* });
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
async confirmPasswordReset(request) {
|
|
681
|
+
await this.http.post("/v1/auth/password-reset/confirm", request);
|
|
682
|
+
}
|
|
683
|
+
/**
|
|
684
|
+
* Log out the current user (clears the API key)
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* client.auth.logout();
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
logout() {
|
|
692
|
+
this.http.setApiKey("");
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
// utils/pagination.ts
|
|
697
|
+
var PaginatedIterator = class {
|
|
698
|
+
constructor(fetchPage) {
|
|
699
|
+
this.currentPage = [];
|
|
700
|
+
this.currentIndex = 0;
|
|
701
|
+
this.hasMore = true;
|
|
702
|
+
this.isFirstFetch = true;
|
|
703
|
+
this.fetchPage = fetchPage;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Async iterator implementation
|
|
707
|
+
*/
|
|
708
|
+
async *[Symbol.asyncIterator]() {
|
|
709
|
+
while (this.hasMore || this.currentIndex < this.currentPage.length) {
|
|
710
|
+
if (this.currentIndex >= this.currentPage.length) {
|
|
711
|
+
if (!this.hasMore) {
|
|
712
|
+
break;
|
|
713
|
+
}
|
|
714
|
+
const response = await this.fetchPage(this.isFirstFetch ? void 0 : this.nextCursor);
|
|
715
|
+
this.isFirstFetch = false;
|
|
716
|
+
this.currentPage = response.data;
|
|
717
|
+
this.currentIndex = 0;
|
|
718
|
+
this.nextCursor = response.pageInfo.nextCursor;
|
|
719
|
+
this.hasMore = response.pageInfo.hasMore;
|
|
720
|
+
if (this.currentPage.length === 0) {
|
|
721
|
+
break;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
yield this.currentPage[this.currentIndex++];
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Get all items from all pages (be careful with large datasets!)
|
|
729
|
+
*/
|
|
730
|
+
async toArray() {
|
|
731
|
+
const items = [];
|
|
732
|
+
for await (const item of this) {
|
|
733
|
+
items.push(item);
|
|
734
|
+
}
|
|
735
|
+
return items;
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
function createPaginatedIterator(fetchPage) {
|
|
739
|
+
return new PaginatedIterator(fetchPage);
|
|
740
|
+
}
|
|
741
|
+
async function fetchAllPages(fetchPage, maxPages) {
|
|
742
|
+
const allItems = [];
|
|
743
|
+
let cursor;
|
|
744
|
+
let hasMore = true;
|
|
745
|
+
let pageCount = 0;
|
|
746
|
+
while (hasMore && (!maxPages || pageCount < maxPages)) {
|
|
747
|
+
const response = await fetchPage(cursor);
|
|
748
|
+
allItems.push(...response.data);
|
|
749
|
+
cursor = response.pageInfo.nextCursor;
|
|
750
|
+
hasMore = response.pageInfo.hasMore;
|
|
751
|
+
pageCount++;
|
|
752
|
+
if (!hasMore || !cursor) {
|
|
753
|
+
break;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return allItems;
|
|
757
|
+
}
|
|
758
|
+
function hasMorePages(pageInfo) {
|
|
759
|
+
return pageInfo.hasMore && !!pageInfo.nextCursor;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// resources/users.ts
|
|
763
|
+
var UsersResource = class {
|
|
764
|
+
constructor(http) {
|
|
765
|
+
this.http = http;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get current authenticated user
|
|
769
|
+
*
|
|
770
|
+
* @example
|
|
771
|
+
* ```typescript
|
|
772
|
+
* const user = await client.users.me();
|
|
773
|
+
* console.log(user.name, user.email);
|
|
774
|
+
* ```
|
|
775
|
+
*/
|
|
776
|
+
async me() {
|
|
777
|
+
const response = await this.http.get("/v1/users/me");
|
|
778
|
+
return response.data;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Update current user profile
|
|
782
|
+
*
|
|
783
|
+
* @example
|
|
784
|
+
* ```typescript
|
|
785
|
+
* const user = await client.users.update({
|
|
786
|
+
* name: 'Updated Name',
|
|
787
|
+
* isOnboarded: true
|
|
788
|
+
* });
|
|
789
|
+
* ```
|
|
790
|
+
*/
|
|
791
|
+
async update(request) {
|
|
792
|
+
const response = await this.http.patch("/v1/users/me", request);
|
|
793
|
+
return response.data;
|
|
794
|
+
}
|
|
795
|
+
/**
|
|
796
|
+
* Get user preferences
|
|
797
|
+
*
|
|
798
|
+
* @example
|
|
799
|
+
* ```typescript
|
|
800
|
+
* const prefs = await client.users.getPreferences();
|
|
801
|
+
* console.log(prefs.measurementSystem); // 'metric' or 'imperial'
|
|
802
|
+
* ```
|
|
803
|
+
*/
|
|
804
|
+
async getPreferences() {
|
|
805
|
+
const response = await this.http.get("/v1/users/me/preferences");
|
|
806
|
+
return response.data;
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Update user preferences
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```typescript
|
|
813
|
+
* const prefs = await client.users.updatePreferences({
|
|
814
|
+
* measurementSystem: 'imperial'
|
|
815
|
+
* });
|
|
816
|
+
* ```
|
|
817
|
+
*/
|
|
818
|
+
async updatePreferences(request) {
|
|
819
|
+
const response = await this.http.patch("/v1/users/me/preferences", request);
|
|
820
|
+
return response.data;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* List all users (for admin/public lists)
|
|
824
|
+
*
|
|
825
|
+
* @example
|
|
826
|
+
* ```typescript
|
|
827
|
+
* const { data, pageInfo } = await client.users.list({ limit: 20 });
|
|
828
|
+
* ```
|
|
829
|
+
*/
|
|
830
|
+
async list(params) {
|
|
831
|
+
const response = await this.http.get("/v1/users", params);
|
|
832
|
+
return response.data;
|
|
833
|
+
}
|
|
834
|
+
/**
|
|
835
|
+
* Search for users by name or email
|
|
836
|
+
*
|
|
837
|
+
* @example
|
|
838
|
+
* ```typescript
|
|
839
|
+
* const { data, pageInfo } = await client.users.search({ q: 'john' });
|
|
840
|
+
* ```
|
|
841
|
+
*/
|
|
842
|
+
async search(params) {
|
|
843
|
+
const response = await this.http.get("/v1/users/search", params);
|
|
844
|
+
return response.data;
|
|
845
|
+
}
|
|
846
|
+
/**
|
|
847
|
+
* List all users with automatic pagination
|
|
848
|
+
*
|
|
849
|
+
* @example
|
|
850
|
+
* ```typescript
|
|
851
|
+
* for await (const user of client.users.listAutoPaginate({ limit: 100 })) {
|
|
852
|
+
* console.log(user.name);
|
|
853
|
+
* }
|
|
854
|
+
* ```
|
|
855
|
+
*/
|
|
856
|
+
listAutoPaginate(params) {
|
|
857
|
+
return createPaginatedIterator(
|
|
858
|
+
(cursor) => this.list({ ...params, cursor })
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Get specific user by ID
|
|
863
|
+
*
|
|
864
|
+
* @example
|
|
865
|
+
* ```typescript
|
|
866
|
+
* const user = await client.users.get('user-id');
|
|
867
|
+
* ```
|
|
868
|
+
*/
|
|
869
|
+
async get(userId) {
|
|
870
|
+
const response = await this.http.get(`/v1/users/${userId}`);
|
|
871
|
+
return response.data;
|
|
872
|
+
}
|
|
873
|
+
};
|
|
874
|
+
|
|
875
|
+
// resources/foods.ts
|
|
876
|
+
var FoodsResource = class {
|
|
877
|
+
constructor(http) {
|
|
878
|
+
this.http = http;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* List foods with pagination and search
|
|
882
|
+
*
|
|
883
|
+
* @example
|
|
884
|
+
* ```typescript
|
|
885
|
+
* const { data, pageInfo } = await client.foods.list({
|
|
886
|
+
* limit: 20,
|
|
887
|
+
* search: 'chicken'
|
|
888
|
+
* });
|
|
889
|
+
* ```
|
|
890
|
+
*/
|
|
891
|
+
async list(params) {
|
|
892
|
+
const response = await this.http.get("/v1/foods", params);
|
|
893
|
+
return response.data;
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* List foods with automatic pagination
|
|
897
|
+
*
|
|
898
|
+
* @example
|
|
899
|
+
* ```typescript
|
|
900
|
+
* for await (const food of client.foods.listAutoPaginate({ limit: 100 })) {
|
|
901
|
+
* console.log(food.name);
|
|
902
|
+
* }
|
|
903
|
+
* ```
|
|
904
|
+
*/
|
|
905
|
+
listAutoPaginate(params) {
|
|
906
|
+
return createPaginatedIterator(
|
|
907
|
+
(cursor) => this.list({ ...params, cursor })
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Get total count of foods
|
|
912
|
+
*
|
|
913
|
+
* @example
|
|
914
|
+
* ```typescript
|
|
915
|
+
* const { count } = await client.foods.count();
|
|
916
|
+
* console.log(`Database has ${count} foods`);
|
|
917
|
+
* ```
|
|
918
|
+
*/
|
|
919
|
+
async count() {
|
|
920
|
+
const response = await this.http.get("/v1/foods/count");
|
|
921
|
+
return response.data;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Search foods by name or brand
|
|
925
|
+
*
|
|
926
|
+
* @example
|
|
927
|
+
* ```typescript
|
|
928
|
+
* const { data } = await client.foods.search({
|
|
929
|
+
* q: 'chicken breast',
|
|
930
|
+
* limit: 10
|
|
931
|
+
* });
|
|
932
|
+
* ```
|
|
933
|
+
*/
|
|
934
|
+
async search(params) {
|
|
935
|
+
const response = await this.http.get("/v1/foods/search", params);
|
|
936
|
+
return response.data;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Get specific food by ID
|
|
940
|
+
*
|
|
941
|
+
* @example
|
|
942
|
+
* ```typescript
|
|
943
|
+
* const food = await client.foods.get('food-id');
|
|
944
|
+
* console.log(food.nutrients);
|
|
945
|
+
* ```
|
|
946
|
+
*/
|
|
947
|
+
async get(foodId) {
|
|
948
|
+
const response = await this.http.get(`/v1/foods/${foodId}`);
|
|
949
|
+
return response.data;
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Create a new food item
|
|
953
|
+
*
|
|
954
|
+
* @example
|
|
955
|
+
* ```typescript
|
|
956
|
+
* const food = await client.foods.create({
|
|
957
|
+
* name: 'Custom Protein Shake',
|
|
958
|
+
* type: 'beverage',
|
|
959
|
+
* nutrients: {
|
|
960
|
+
* calories: 300,
|
|
961
|
+
* protein: 40,
|
|
962
|
+
* carbohydrates: 20,
|
|
963
|
+
* fat: 5
|
|
964
|
+
* },
|
|
965
|
+
* servingSizes: [{
|
|
966
|
+
* name: '1 serving',
|
|
967
|
+
* grams: 300,
|
|
968
|
+
* isDefault: true
|
|
969
|
+
* }]
|
|
970
|
+
* });
|
|
971
|
+
* ```
|
|
972
|
+
*/
|
|
973
|
+
async create(request) {
|
|
974
|
+
const response = await this.http.post("/v1/foods", request);
|
|
975
|
+
return response.data;
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* Update an existing food item
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* ```typescript
|
|
982
|
+
* const food = await client.foods.update('food-id', {
|
|
983
|
+
* description: 'Updated description'
|
|
984
|
+
* });
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
987
|
+
async update(foodId, request) {
|
|
988
|
+
const response = await this.http.put(`/v1/foods/${foodId}`, request);
|
|
989
|
+
return response.data;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Delete a food item
|
|
993
|
+
*
|
|
994
|
+
* @example
|
|
995
|
+
* ```typescript
|
|
996
|
+
* await client.foods.delete('food-id');
|
|
997
|
+
* ```
|
|
998
|
+
*/
|
|
999
|
+
async delete(foodId) {
|
|
1000
|
+
await this.http.delete(`/v1/foods/${foodId}`);
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Get favorite foods
|
|
1004
|
+
*
|
|
1005
|
+
* @example
|
|
1006
|
+
* ```typescript
|
|
1007
|
+
* const { data } = await client.foods.getFavorites();
|
|
1008
|
+
* ```
|
|
1009
|
+
*/
|
|
1010
|
+
async getFavorites(params) {
|
|
1011
|
+
const response = await this.http.get("/v1/foods/favorites", params);
|
|
1012
|
+
return response.data;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Add food to favorites
|
|
1016
|
+
*
|
|
1017
|
+
* @example
|
|
1018
|
+
* ```typescript
|
|
1019
|
+
* await client.foods.addToFavorites('food-id');
|
|
1020
|
+
* ```
|
|
1021
|
+
*/
|
|
1022
|
+
async addToFavorites(foodId) {
|
|
1023
|
+
await this.http.post(`/v1/foods/${foodId}/favorite`);
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Remove food from favorites
|
|
1027
|
+
*
|
|
1028
|
+
* @example
|
|
1029
|
+
* ```typescript
|
|
1030
|
+
* await client.foods.removeFromFavorites('food-id');
|
|
1031
|
+
* ```
|
|
1032
|
+
*/
|
|
1033
|
+
async removeFromFavorites(foodId) {
|
|
1034
|
+
await this.http.delete(`/v1/foods/${foodId}/favorite`);
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
// resources/food-logs.ts
|
|
1039
|
+
var FoodLogsResource = class {
|
|
1040
|
+
constructor(http) {
|
|
1041
|
+
this.http = http;
|
|
1042
|
+
}
|
|
1043
|
+
/**
|
|
1044
|
+
* List food log entries with filtering
|
|
1045
|
+
*
|
|
1046
|
+
* @example
|
|
1047
|
+
* ```typescript
|
|
1048
|
+
* const logs = await client.foodLogs.list({
|
|
1049
|
+
* date: '2024-01-15',
|
|
1050
|
+
* mealType: 'lunch'
|
|
1051
|
+
* });
|
|
1052
|
+
* ```
|
|
1053
|
+
*/
|
|
1054
|
+
async list(params) {
|
|
1055
|
+
const response = await this.http.get("/v1/food-logs", params);
|
|
1056
|
+
return response.data;
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Get daily nutrition summary
|
|
1060
|
+
*
|
|
1061
|
+
* @example
|
|
1062
|
+
* ```typescript
|
|
1063
|
+
* const summary = await client.foodLogs.getDailySummary({
|
|
1064
|
+
* date: '2024-01-15'
|
|
1065
|
+
* });
|
|
1066
|
+
* console.log(`Total calories: ${summary.totalCalories}`);
|
|
1067
|
+
* ```
|
|
1068
|
+
*/
|
|
1069
|
+
async getDailySummary(params) {
|
|
1070
|
+
const response = await this.http.get("/v1/food-logs/summary", params);
|
|
1071
|
+
return response.data;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Get specific food log entry
|
|
1075
|
+
*
|
|
1076
|
+
* @example
|
|
1077
|
+
* ```typescript
|
|
1078
|
+
* const log = await client.foodLogs.get('log-id');
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
async get(logId) {
|
|
1082
|
+
const response = await this.http.get(`/v1/food-logs/${logId}`);
|
|
1083
|
+
return response.data;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* Create a food log entry
|
|
1087
|
+
*
|
|
1088
|
+
* @example
|
|
1089
|
+
* ```typescript
|
|
1090
|
+
* const log = await client.foodLogs.create({
|
|
1091
|
+
* foodId: 'food-uuid',
|
|
1092
|
+
* name: 'Chicken Breast',
|
|
1093
|
+
* servingSizeName: 'breast (200g)',
|
|
1094
|
+
* quantity: 1.5,
|
|
1095
|
+
* unitGrams: 200,
|
|
1096
|
+
* mealType: 'lunch',
|
|
1097
|
+
* notes: 'Grilled with olive oil'
|
|
1098
|
+
* });
|
|
1099
|
+
* ```
|
|
1100
|
+
*/
|
|
1101
|
+
async create(request) {
|
|
1102
|
+
const response = await this.http.post("/v1/food-logs", request);
|
|
1103
|
+
return response.data;
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Quick entry food log with just name and nutrients
|
|
1107
|
+
* Creates a food log entry without creating a food (one-off entry)
|
|
1108
|
+
*
|
|
1109
|
+
* @example
|
|
1110
|
+
* ```typescript
|
|
1111
|
+
* const log = await client.foodLogs.quickEntry({
|
|
1112
|
+
* name: 'Homemade Salad',
|
|
1113
|
+
* protein: 15,
|
|
1114
|
+
* carbohydrates: 20,
|
|
1115
|
+
* fat: 10,
|
|
1116
|
+
* mealType: 'lunch'
|
|
1117
|
+
* });
|
|
1118
|
+
* ```
|
|
1119
|
+
*/
|
|
1120
|
+
async quickEntry(request) {
|
|
1121
|
+
const response = await this.http.post("/v1/food-logs-quick-entry", request);
|
|
1122
|
+
return response.data;
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Update a food log entry
|
|
1126
|
+
*
|
|
1127
|
+
* @example
|
|
1128
|
+
* ```typescript
|
|
1129
|
+
* const log = await client.foodLogs.update('log-id', {
|
|
1130
|
+
* quantity: 2,
|
|
1131
|
+
* notes: 'Updated portion size'
|
|
1132
|
+
* });
|
|
1133
|
+
* ```
|
|
1134
|
+
*/
|
|
1135
|
+
async update(logId, request) {
|
|
1136
|
+
const response = await this.http.put(`/v1/food-logs/${logId}`, request);
|
|
1137
|
+
return response.data;
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Delete a food log entry
|
|
1141
|
+
*
|
|
1142
|
+
* @example
|
|
1143
|
+
* ```typescript
|
|
1144
|
+
* await client.foodLogs.delete('log-id');
|
|
1145
|
+
* ```
|
|
1146
|
+
*/
|
|
1147
|
+
async delete(logId) {
|
|
1148
|
+
await this.http.delete(`/v1/food-logs/${logId}`);
|
|
1149
|
+
}
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
// resources/exercises.ts
|
|
1153
|
+
var ExercisesResource = class {
|
|
1154
|
+
constructor(http) {
|
|
1155
|
+
this.http = http;
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* List exercises with filtering
|
|
1159
|
+
*
|
|
1160
|
+
* @example
|
|
1161
|
+
* ```typescript
|
|
1162
|
+
* const { data } = await client.exercises.list({
|
|
1163
|
+
* category: 'strength',
|
|
1164
|
+
* muscleGroup: 'chest'
|
|
1165
|
+
* });
|
|
1166
|
+
* ```
|
|
1167
|
+
*/
|
|
1168
|
+
async list(params) {
|
|
1169
|
+
const response = await this.http.get("/v1/exercises", params);
|
|
1170
|
+
return response.data;
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* List exercises with automatic pagination
|
|
1174
|
+
*/
|
|
1175
|
+
listAutoPaginate(params) {
|
|
1176
|
+
return createPaginatedIterator(
|
|
1177
|
+
(cursor) => this.list({ ...params, cursor })
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Get total count of exercises
|
|
1182
|
+
*/
|
|
1183
|
+
async count() {
|
|
1184
|
+
const response = await this.http.get("/v1/exercises/count");
|
|
1185
|
+
return response.data;
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Search exercises by name
|
|
1189
|
+
*/
|
|
1190
|
+
async search(params) {
|
|
1191
|
+
const response = await this.http.get("/v1/exercises/search", params);
|
|
1192
|
+
return response.data;
|
|
1193
|
+
}
|
|
1194
|
+
/**
|
|
1195
|
+
* Get specific exercise by ID
|
|
1196
|
+
*/
|
|
1197
|
+
async get(exerciseId) {
|
|
1198
|
+
const response = await this.http.get(`/v1/exercises/${exerciseId}`);
|
|
1199
|
+
return response.data;
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Create a new exercise
|
|
1203
|
+
*/
|
|
1204
|
+
async create(request) {
|
|
1205
|
+
const response = await this.http.post("/v1/exercises", request);
|
|
1206
|
+
return response.data;
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Update an existing exercise
|
|
1210
|
+
*/
|
|
1211
|
+
async update(exerciseId, request) {
|
|
1212
|
+
const response = await this.http.put(`/v1/exercises/${exerciseId}`, request);
|
|
1213
|
+
return response.data;
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Delete an exercise
|
|
1217
|
+
*/
|
|
1218
|
+
async delete(exerciseId) {
|
|
1219
|
+
await this.http.delete(`/v1/exercises/${exerciseId}`);
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Get favorite exercises
|
|
1223
|
+
*/
|
|
1224
|
+
async getFavorites(params) {
|
|
1225
|
+
const response = await this.http.get("/v1/exercises/favorites", params);
|
|
1226
|
+
return response.data;
|
|
1227
|
+
}
|
|
1228
|
+
/**
|
|
1229
|
+
* Add exercise to favorites
|
|
1230
|
+
*/
|
|
1231
|
+
async addToFavorites(exerciseId) {
|
|
1232
|
+
await this.http.post(`/v1/exercises/${exerciseId}/favorite`);
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Remove exercise from favorites
|
|
1236
|
+
*/
|
|
1237
|
+
async removeFromFavorites(exerciseId) {
|
|
1238
|
+
await this.http.delete(`/v1/exercises/${exerciseId}/favorite`);
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
|
|
1242
|
+
// resources/workouts.ts
|
|
1243
|
+
var WorkoutsResource = class {
|
|
1244
|
+
constructor(http) {
|
|
1245
|
+
this.http = http;
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* List workout templates
|
|
1249
|
+
*/
|
|
1250
|
+
async list(params) {
|
|
1251
|
+
const response = await this.http.get("/v1/workouts", params);
|
|
1252
|
+
return response.data;
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* List workouts with automatic pagination
|
|
1256
|
+
*/
|
|
1257
|
+
listAutoPaginate(params) {
|
|
1258
|
+
return createPaginatedIterator(
|
|
1259
|
+
(cursor) => this.list({ ...params, cursor })
|
|
1260
|
+
);
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Get total count of workouts
|
|
1264
|
+
*/
|
|
1265
|
+
async count() {
|
|
1266
|
+
const response = await this.http.get("/v1/workouts/count");
|
|
1267
|
+
return response.data;
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* Search workouts by name
|
|
1271
|
+
*/
|
|
1272
|
+
async search(params) {
|
|
1273
|
+
const response = await this.http.get("/v1/workouts/search", params);
|
|
1274
|
+
return response.data;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Get specific workout with all exercises
|
|
1278
|
+
*/
|
|
1279
|
+
async get(workoutId) {
|
|
1280
|
+
const response = await this.http.get(`/v1/workouts/${workoutId}`);
|
|
1281
|
+
return response.data;
|
|
1282
|
+
}
|
|
1283
|
+
/**
|
|
1284
|
+
* Create a new workout template
|
|
1285
|
+
*/
|
|
1286
|
+
async create(request) {
|
|
1287
|
+
const response = await this.http.post("/v1/workouts", request);
|
|
1288
|
+
return response.data;
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Update a workout template
|
|
1292
|
+
*/
|
|
1293
|
+
async update(workoutId, request) {
|
|
1294
|
+
const response = await this.http.put(`/v1/workouts/${workoutId}`, request);
|
|
1295
|
+
return response.data;
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Clone an existing workout
|
|
1299
|
+
*/
|
|
1300
|
+
async clone(workoutId) {
|
|
1301
|
+
const response = await this.http.post(`/v1/workouts/${workoutId}/clone`);
|
|
1302
|
+
return response.data;
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Delete a workout template
|
|
1306
|
+
*/
|
|
1307
|
+
async delete(workoutId) {
|
|
1308
|
+
await this.http.delete(`/v1/workouts/${workoutId}`);
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Add exercises to workout
|
|
1312
|
+
*/
|
|
1313
|
+
async addExercises(workoutId, request) {
|
|
1314
|
+
await this.http.post(`/v1/workouts/${workoutId}/exercises`, request);
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Update exercise in workout
|
|
1318
|
+
*/
|
|
1319
|
+
async updateExercise(workoutId, exerciseId, request) {
|
|
1320
|
+
await this.http.put(`/v1/workouts/${workoutId}/exercises/${exerciseId}`, request);
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Remove exercise from workout
|
|
1324
|
+
*/
|
|
1325
|
+
async removeExercise(workoutId, exerciseId) {
|
|
1326
|
+
await this.http.delete(`/v1/workouts/${workoutId}/exercises/${exerciseId}`);
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Get all workouts containing a specific exercise
|
|
1330
|
+
*/
|
|
1331
|
+
async getWorkoutsByExercise(exerciseId) {
|
|
1332
|
+
const response = await this.http.get(`/v1/exercises/${exerciseId}/workouts`);
|
|
1333
|
+
return response.data;
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Get favorite workouts
|
|
1337
|
+
*/
|
|
1338
|
+
async getFavorites(params) {
|
|
1339
|
+
const response = await this.http.get("/v1/workouts/favorites", params);
|
|
1340
|
+
return response.data;
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Add workout to favorites
|
|
1344
|
+
*/
|
|
1345
|
+
async addToFavorites(workoutId) {
|
|
1346
|
+
await this.http.post(`/v1/workouts/${workoutId}/favorite`);
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* Remove workout from favorites
|
|
1350
|
+
*/
|
|
1351
|
+
async removeFromFavorites(workoutId) {
|
|
1352
|
+
await this.http.delete(`/v1/workouts/${workoutId}/favorite`);
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
|
|
1356
|
+
// resources/sessions.ts
|
|
1357
|
+
var SessionsResource = class {
|
|
1358
|
+
constructor(http) {
|
|
1359
|
+
this.http = http;
|
|
1360
|
+
}
|
|
1361
|
+
/**
|
|
1362
|
+
* List workout sessions with filtering
|
|
1363
|
+
*/
|
|
1364
|
+
async list(params) {
|
|
1365
|
+
const response = await this.http.get("/v1/workout-sessions", params);
|
|
1366
|
+
return response.data;
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* List sessions with automatic pagination
|
|
1370
|
+
*/
|
|
1371
|
+
listAutoPaginate(params) {
|
|
1372
|
+
return createPaginatedIterator(
|
|
1373
|
+
(cursor) => this.list({ ...params, cursor })
|
|
1374
|
+
);
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Create a new workout session
|
|
1378
|
+
*/
|
|
1379
|
+
async create(request) {
|
|
1380
|
+
const response = await this.http.post("/v1/workout-sessions", request);
|
|
1381
|
+
return response.data;
|
|
1382
|
+
}
|
|
1383
|
+
/**
|
|
1384
|
+
* Start a workout session (convenience method)
|
|
1385
|
+
*/
|
|
1386
|
+
async start(request) {
|
|
1387
|
+
return this.create({ ...request, status: "in_progress" });
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Get specific session with all exercise data
|
|
1391
|
+
*/
|
|
1392
|
+
async get(sessionId) {
|
|
1393
|
+
const response = await this.http.get(`/v1/workout-sessions/${sessionId}`);
|
|
1394
|
+
return response.data;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Update a workout session
|
|
1398
|
+
*/
|
|
1399
|
+
async update(sessionId, request) {
|
|
1400
|
+
const response = await this.http.patch(`/v1/workout-sessions/${sessionId}`, request);
|
|
1401
|
+
return response.data;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Complete a workout session (convenience method)
|
|
1405
|
+
*/
|
|
1406
|
+
async complete(sessionId, notes) {
|
|
1407
|
+
return this.update(sessionId, {
|
|
1408
|
+
status: "completed",
|
|
1409
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1410
|
+
...notes && { notes }
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
* Add exercises to a session (convenience method)
|
|
1415
|
+
*
|
|
1416
|
+
* @example
|
|
1417
|
+
* ```typescript
|
|
1418
|
+
* await client.sessions.addExercises('session-123', [
|
|
1419
|
+
* { exerciseId: 'ex-1', targetSets: 3 },
|
|
1420
|
+
* { exerciseId: 'ex-2', targetSets: 4, notes: 'Focus on form' }
|
|
1421
|
+
* ]);
|
|
1422
|
+
* ```
|
|
1423
|
+
*/
|
|
1424
|
+
async addExercises(sessionId, exercises) {
|
|
1425
|
+
return this.update(sessionId, { addExercises: exercises });
|
|
1426
|
+
}
|
|
1427
|
+
/**
|
|
1428
|
+
* Delete a workout session
|
|
1429
|
+
*/
|
|
1430
|
+
async delete(sessionId) {
|
|
1431
|
+
await this.http.delete(`/v1/workout-sessions/${sessionId}`);
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Get all sessions for a specific workout
|
|
1435
|
+
*/
|
|
1436
|
+
async getSessionsByWorkout(workoutId, params) {
|
|
1437
|
+
const response = await this.http.get(`/v1/workouts/${workoutId}/sessions`, params);
|
|
1438
|
+
return response.data;
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Get exercise performance history across sessions
|
|
1442
|
+
*/
|
|
1443
|
+
async getExerciseHistory(exerciseId) {
|
|
1444
|
+
const response = await this.http.get(`/v1/exercises/${exerciseId}/history`);
|
|
1445
|
+
return response.data;
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Get user's personal records
|
|
1449
|
+
*/
|
|
1450
|
+
async getPersonalRecords() {
|
|
1451
|
+
const response = await this.http.get("/v1/personal-records");
|
|
1452
|
+
return response.data;
|
|
1453
|
+
}
|
|
1454
|
+
/**
|
|
1455
|
+
* Get personal records for a specific exercise
|
|
1456
|
+
*/
|
|
1457
|
+
async getExercisePersonalRecords(exerciseId) {
|
|
1458
|
+
const response = await this.http.get(`/v1/exercises/${exerciseId}/personal-records`);
|
|
1459
|
+
return response.data;
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Get personal record progression history for an exercise
|
|
1463
|
+
*/
|
|
1464
|
+
async getPersonalRecordHistory(exerciseId) {
|
|
1465
|
+
const response = await this.http.get(`/v1/exercises/${exerciseId}/personal-records/history`);
|
|
1466
|
+
return response.data;
|
|
1467
|
+
}
|
|
1468
|
+
};
|
|
1469
|
+
|
|
1470
|
+
// resources/programs.ts
|
|
1471
|
+
var ProgramsResource = class {
|
|
1472
|
+
constructor(http) {
|
|
1473
|
+
this.http = http;
|
|
1474
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* List user's programs and enrollments
|
|
1477
|
+
*/
|
|
1478
|
+
async list(params) {
|
|
1479
|
+
const response = await this.http.get("/v1/programs", params);
|
|
1480
|
+
return response.data;
|
|
1481
|
+
}
|
|
1482
|
+
/**
|
|
1483
|
+
* List available program templates
|
|
1484
|
+
*/
|
|
1485
|
+
async listTemplates(params) {
|
|
1486
|
+
const response = await this.http.get("/v1/programs/templates", params);
|
|
1487
|
+
return response.data;
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Create a new program
|
|
1491
|
+
*/
|
|
1492
|
+
async create(request) {
|
|
1493
|
+
const response = await this.http.post("/v1/programs", request);
|
|
1494
|
+
return response.data;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* Get specific program details
|
|
1498
|
+
*/
|
|
1499
|
+
async get(programId) {
|
|
1500
|
+
const response = await this.http.get(`/v1/programs/${programId}`);
|
|
1501
|
+
return response.data;
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Update a program
|
|
1505
|
+
*/
|
|
1506
|
+
async update(programId, request) {
|
|
1507
|
+
const response = await this.http.put(`/v1/programs/${programId}`, request);
|
|
1508
|
+
return response.data;
|
|
1509
|
+
}
|
|
1510
|
+
/**
|
|
1511
|
+
* Delete a program
|
|
1512
|
+
*/
|
|
1513
|
+
async delete(programId) {
|
|
1514
|
+
await this.http.delete(`/v1/programs/${programId}`);
|
|
1515
|
+
}
|
|
1516
|
+
/**
|
|
1517
|
+
* Enroll in a program
|
|
1518
|
+
*/
|
|
1519
|
+
async enroll(programId, request) {
|
|
1520
|
+
const response = await this.http.post(`/v1/programs/${programId}/enroll`, request);
|
|
1521
|
+
return response.data;
|
|
1522
|
+
}
|
|
1523
|
+
/**
|
|
1524
|
+
* List program enrollments
|
|
1525
|
+
*/
|
|
1526
|
+
async listEnrollments(params) {
|
|
1527
|
+
const response = await this.http.get("/v1/enrollments", params);
|
|
1528
|
+
return response.data;
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Get enrollment details
|
|
1532
|
+
*/
|
|
1533
|
+
async getEnrollment(enrollmentId) {
|
|
1534
|
+
const response = await this.http.get(`/v1/enrollments/${enrollmentId}`);
|
|
1535
|
+
return response.data;
|
|
1536
|
+
}
|
|
1537
|
+
/**
|
|
1538
|
+
* Update enrollment (pause, resume, etc.)
|
|
1539
|
+
*/
|
|
1540
|
+
async updateEnrollment(enrollmentId, request) {
|
|
1541
|
+
const response = await this.http.put(`/v1/enrollments/${enrollmentId}`, request);
|
|
1542
|
+
return response.data;
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Unenroll from a program
|
|
1546
|
+
*/
|
|
1547
|
+
async unenroll(enrollmentId) {
|
|
1548
|
+
await this.http.delete(`/v1/enrollments/${enrollmentId}`);
|
|
1549
|
+
}
|
|
1550
|
+
/**
|
|
1551
|
+
* Get enrollment progress
|
|
1552
|
+
*/
|
|
1553
|
+
async getEnrollmentProgress(enrollmentId) {
|
|
1554
|
+
const response = await this.http.get(`/v1/enrollments/${enrollmentId}/progress`);
|
|
1555
|
+
return response.data;
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Get current week schedule for enrollment
|
|
1559
|
+
*/
|
|
1560
|
+
async getCurrentWeek(enrollmentId) {
|
|
1561
|
+
const response = await this.http.get(`/v1/enrollments/${enrollmentId}/current-week`);
|
|
1562
|
+
return response.data;
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
// resources/metrics.ts
|
|
1567
|
+
var MetricsResource = class {
|
|
1568
|
+
constructor(http) {
|
|
1569
|
+
this.http = http;
|
|
1570
|
+
}
|
|
1571
|
+
/**
|
|
1572
|
+
* List available metrics
|
|
1573
|
+
*/
|
|
1574
|
+
async list() {
|
|
1575
|
+
const response = await this.http.get("/v1/metrics");
|
|
1576
|
+
return response.data;
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Get specific metric details
|
|
1580
|
+
*/
|
|
1581
|
+
async get(metricId) {
|
|
1582
|
+
const response = await this.http.get(`/v1/metrics/${metricId}`);
|
|
1583
|
+
return response.data;
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* Get metrics by category
|
|
1587
|
+
*/
|
|
1588
|
+
async getByCategory(category) {
|
|
1589
|
+
const response = await this.http.get(`/v1/metrics/category/${category}`);
|
|
1590
|
+
return response.data;
|
|
1591
|
+
}
|
|
1592
|
+
/**
|
|
1593
|
+
* Get daily aggregated metric value
|
|
1594
|
+
*/
|
|
1595
|
+
async getDailyMetric(metricKey, params) {
|
|
1596
|
+
const response = await this.http.get(`/v1/metrics/daily/${metricKey}`, params);
|
|
1597
|
+
return response.data;
|
|
1598
|
+
}
|
|
1599
|
+
/**
|
|
1600
|
+
* List metric events (data points)
|
|
1601
|
+
*/
|
|
1602
|
+
async listEvents(params) {
|
|
1603
|
+
const response = await this.http.get("/v1/metric-events", params);
|
|
1604
|
+
return response.data;
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* List metric events with automatic pagination
|
|
1608
|
+
*/
|
|
1609
|
+
listEventsAutoPaginate(params) {
|
|
1610
|
+
return createPaginatedIterator(
|
|
1611
|
+
(cursor) => this.listEvents({ ...params, cursor })
|
|
1612
|
+
);
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Get specific metric event
|
|
1616
|
+
*/
|
|
1617
|
+
async getEvent(eventId) {
|
|
1618
|
+
const response = await this.http.get(`/v1/metric-events/${eventId}`);
|
|
1619
|
+
return response.data;
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* Log a metric value (convenience method)
|
|
1623
|
+
*/
|
|
1624
|
+
async log(request) {
|
|
1625
|
+
const response = await this.http.post("/v1/metric-events", request);
|
|
1626
|
+
return response.data;
|
|
1627
|
+
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Create a metric event
|
|
1630
|
+
*/
|
|
1631
|
+
async createEvent(request) {
|
|
1632
|
+
return this.log(request);
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Bulk create metric events
|
|
1636
|
+
*/
|
|
1637
|
+
async bulkCreateEvents(request) {
|
|
1638
|
+
await this.http.post("/v1/metric-events/bulk", request);
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Update a metric event
|
|
1642
|
+
*/
|
|
1643
|
+
async updateEvent(eventId, request) {
|
|
1644
|
+
const response = await this.http.put(`/v1/metric-events/${eventId}`, request);
|
|
1645
|
+
return response.data;
|
|
1646
|
+
}
|
|
1647
|
+
/**
|
|
1648
|
+
* Delete a metric event
|
|
1649
|
+
*/
|
|
1650
|
+
async deleteEvent(eventId) {
|
|
1651
|
+
await this.http.delete(`/v1/metric-events/${eventId}`);
|
|
1652
|
+
}
|
|
1653
|
+
};
|
|
1654
|
+
|
|
1655
|
+
// resources/goals.ts
|
|
1656
|
+
var GoalsResource = class {
|
|
1657
|
+
constructor(http) {
|
|
1658
|
+
this.http = http;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* Get active user goals
|
|
1662
|
+
*/
|
|
1663
|
+
async list() {
|
|
1664
|
+
const response = await this.http.get("/v1/goals");
|
|
1665
|
+
return response.data;
|
|
1666
|
+
}
|
|
1667
|
+
/**
|
|
1668
|
+
* Get goals effective on a specific date
|
|
1669
|
+
*/
|
|
1670
|
+
async getByDate(date) {
|
|
1671
|
+
const response = await this.http.get(`/v1/goals/date/${date}`);
|
|
1672
|
+
return response.data;
|
|
1673
|
+
}
|
|
1674
|
+
/**
|
|
1675
|
+
* Create a new goal
|
|
1676
|
+
*/
|
|
1677
|
+
async create(request) {
|
|
1678
|
+
const response = await this.http.post("/v1/goals", request);
|
|
1679
|
+
return response.data;
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Update a goal
|
|
1683
|
+
*/
|
|
1684
|
+
async update(goalId, request) {
|
|
1685
|
+
const response = await this.http.put(`/v1/goals/${goalId}`, request);
|
|
1686
|
+
return response.data;
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Delete a goal
|
|
1690
|
+
*/
|
|
1691
|
+
async delete(goalId) {
|
|
1692
|
+
await this.http.delete(`/v1/goals/${goalId}`);
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Get today's goal progress
|
|
1696
|
+
*/
|
|
1697
|
+
async getProgress() {
|
|
1698
|
+
const response = await this.http.get("/v1/goals/progress");
|
|
1699
|
+
return response.data;
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* Get goal progress for a specific date
|
|
1703
|
+
*/
|
|
1704
|
+
async getProgressByDate(date) {
|
|
1705
|
+
const response = await this.http.get(`/v1/goals/progress/${date}`);
|
|
1706
|
+
return response.data;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Get current nutrition goals
|
|
1710
|
+
*/
|
|
1711
|
+
async getNutritionGoals() {
|
|
1712
|
+
const response = await this.http.get("/v1/nutrition/goals");
|
|
1713
|
+
return response.data;
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Get nutrition goals for a specific date
|
|
1717
|
+
*/
|
|
1718
|
+
async getNutritionGoalsByDate(date) {
|
|
1719
|
+
const response = await this.http.get(`/v1/nutrition/goals/date/${date}`);
|
|
1720
|
+
return response.data;
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Create nutrition goals
|
|
1724
|
+
*/
|
|
1725
|
+
async createNutritionGoals(request) {
|
|
1726
|
+
const response = await this.http.post("/v1/nutrition/goals", request);
|
|
1727
|
+
return response.data;
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Update nutrition goals for a specific date
|
|
1731
|
+
*/
|
|
1732
|
+
async updateNutritionGoals(date, request) {
|
|
1733
|
+
const response = await this.http.put(`/v1/nutrition/goals/date/${date}`, request);
|
|
1734
|
+
return response.data;
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Delete nutrition goals for a specific date
|
|
1738
|
+
*/
|
|
1739
|
+
async deleteNutritionGoals(date) {
|
|
1740
|
+
await this.http.delete(`/v1/nutrition/goals/date/${date}`);
|
|
1741
|
+
}
|
|
1742
|
+
/**
|
|
1743
|
+
* Bulk create nutrition goals for multiple dates
|
|
1744
|
+
*/
|
|
1745
|
+
async bulkCreateNutritionGoals(request) {
|
|
1746
|
+
await this.http.post("/v1/nutrition/goals/bulk", request);
|
|
1747
|
+
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Copy nutrition goals from one date to another
|
|
1750
|
+
*/
|
|
1751
|
+
async copyNutritionGoals(request) {
|
|
1752
|
+
await this.http.post("/v1/nutrition/goals/copy", request);
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Get nutrition goals history
|
|
1756
|
+
*/
|
|
1757
|
+
async getNutritionGoalsHistory(params) {
|
|
1758
|
+
const response = await this.http.get("/v1/nutrition/goals/history", params);
|
|
1759
|
+
return response.data;
|
|
1760
|
+
}
|
|
1761
|
+
/**
|
|
1762
|
+
* Get today's nutrition progress toward goals
|
|
1763
|
+
*/
|
|
1764
|
+
async getNutritionProgress() {
|
|
1765
|
+
const response = await this.http.get("/v1/nutrition/progress/today");
|
|
1766
|
+
return response.data;
|
|
1767
|
+
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Get nutrition progress for a specific date
|
|
1770
|
+
*/
|
|
1771
|
+
async getNutritionProgressByDate(date) {
|
|
1772
|
+
const response = await this.http.get(`/v1/nutrition/progress/date/${date}`);
|
|
1773
|
+
return response.data;
|
|
1774
|
+
}
|
|
1775
|
+
};
|
|
1776
|
+
|
|
1777
|
+
// resources/ai.ts
|
|
1778
|
+
var AIResource = class {
|
|
1779
|
+
constructor(http) {
|
|
1780
|
+
this.http = http;
|
|
1781
|
+
}
|
|
1782
|
+
/**
|
|
1783
|
+
* Get AI-generated nutrition insights
|
|
1784
|
+
*
|
|
1785
|
+
* @example
|
|
1786
|
+
* ```typescript
|
|
1787
|
+
* const insights = await client.ai.getFoodInsights({
|
|
1788
|
+
* startDate: '2024-01-01',
|
|
1789
|
+
* endDate: '2024-01-15'
|
|
1790
|
+
* });
|
|
1791
|
+
* ```
|
|
1792
|
+
*/
|
|
1793
|
+
async getFoodInsights(params) {
|
|
1794
|
+
const response = await this.http.get("/v1/ai/food-insights", params);
|
|
1795
|
+
return response.data;
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
|
|
1799
|
+
// client.ts
|
|
1800
|
+
var OpenLifeLog = class {
|
|
1801
|
+
constructor(config = {}) {
|
|
1802
|
+
this.config = mergeConfig(config);
|
|
1803
|
+
this.httpClient = new HttpClient(this.config);
|
|
1804
|
+
this.unitConverter = createUnitConverter(this.config.measurementSystem);
|
|
1805
|
+
this.auth = new AuthResource(this.httpClient);
|
|
1806
|
+
this.users = new UsersResource(this.httpClient);
|
|
1807
|
+
this.foods = new FoodsResource(this.httpClient);
|
|
1808
|
+
this.foodLogs = new FoodLogsResource(this.httpClient);
|
|
1809
|
+
this.exercises = new ExercisesResource(this.httpClient);
|
|
1810
|
+
this.workouts = new WorkoutsResource(this.httpClient);
|
|
1811
|
+
this.sessions = new SessionsResource(this.httpClient);
|
|
1812
|
+
this.programs = new ProgramsResource(this.httpClient);
|
|
1813
|
+
this.metrics = new MetricsResource(this.httpClient);
|
|
1814
|
+
this.goals = new GoalsResource(this.httpClient);
|
|
1815
|
+
this.ai = new AIResource(this.httpClient);
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Update the API key (JWT token)
|
|
1819
|
+
*
|
|
1820
|
+
* @example
|
|
1821
|
+
* ```typescript
|
|
1822
|
+
* client.setApiKey('new-jwt-token');
|
|
1823
|
+
* ```
|
|
1824
|
+
*/
|
|
1825
|
+
setApiKey(apiKey) {
|
|
1826
|
+
this.httpClient.setApiKey(apiKey);
|
|
1827
|
+
}
|
|
1828
|
+
/**
|
|
1829
|
+
* Get the current API key
|
|
1830
|
+
*/
|
|
1831
|
+
getApiKey() {
|
|
1832
|
+
return this.httpClient.getApiKey();
|
|
1833
|
+
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Get the unit converter instance
|
|
1836
|
+
*/
|
|
1837
|
+
getUnitConverter() {
|
|
1838
|
+
return this.unitConverter;
|
|
1839
|
+
}
|
|
1840
|
+
/**
|
|
1841
|
+
* Update the measurement system preference
|
|
1842
|
+
*
|
|
1843
|
+
* @example
|
|
1844
|
+
* ```typescript
|
|
1845
|
+
* client.setMeasurementSystem('imperial');
|
|
1846
|
+
* ```
|
|
1847
|
+
*/
|
|
1848
|
+
setMeasurementSystem(system) {
|
|
1849
|
+
this.config.measurementSystem = system;
|
|
1850
|
+
this.unitConverter.setMeasurementSystem(system);
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Get the current measurement system
|
|
1854
|
+
*/
|
|
1855
|
+
getMeasurementSystem() {
|
|
1856
|
+
return this.config.measurementSystem;
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Convenience method: Log food (combines food lookup and logging)
|
|
1860
|
+
*
|
|
1861
|
+
* This is a high-level method that developers love - simple and intuitive.
|
|
1862
|
+
*
|
|
1863
|
+
* @example
|
|
1864
|
+
* ```typescript
|
|
1865
|
+
* const log = await client.logFood({
|
|
1866
|
+
* foodId: 'food-uuid',
|
|
1867
|
+
* name: 'Chicken Breast',
|
|
1868
|
+
* servingSizeName: 'breast (200g)',
|
|
1869
|
+
* quantity: 1.5,
|
|
1870
|
+
* mealType: 'lunch',
|
|
1871
|
+
* notes: 'Grilled with olive oil'
|
|
1872
|
+
* });
|
|
1873
|
+
* ```
|
|
1874
|
+
*/
|
|
1875
|
+
async logFood(request) {
|
|
1876
|
+
return this.foodLogs.create(request);
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Convenience method: Get today's nutrition summary
|
|
1880
|
+
*
|
|
1881
|
+
* @example
|
|
1882
|
+
* ```typescript
|
|
1883
|
+
* const summary = await client.getTodayNutrition();
|
|
1884
|
+
* console.log(`Calories: ${summary.totalCalories}`);
|
|
1885
|
+
* ```
|
|
1886
|
+
*/
|
|
1887
|
+
async getTodayNutrition() {
|
|
1888
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1889
|
+
return this.foodLogs.getDailySummary({ date: today });
|
|
1890
|
+
}
|
|
1891
|
+
/**
|
|
1892
|
+
* Convenience method: Get today's goal progress
|
|
1893
|
+
*
|
|
1894
|
+
* @example
|
|
1895
|
+
* ```typescript
|
|
1896
|
+
* const progress = await client.getTodayProgress();
|
|
1897
|
+
* ```
|
|
1898
|
+
*/
|
|
1899
|
+
async getTodayProgress() {
|
|
1900
|
+
return this.goals.getProgress();
|
|
1901
|
+
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Convenience method: Get today's nutrition progress
|
|
1904
|
+
*
|
|
1905
|
+
* @example
|
|
1906
|
+
* ```typescript
|
|
1907
|
+
* const progress = await client.getTodayNutritionProgress();
|
|
1908
|
+
* ```
|
|
1909
|
+
*/
|
|
1910
|
+
async getTodayNutritionProgress() {
|
|
1911
|
+
return this.goals.getNutritionProgress();
|
|
1912
|
+
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Check if user is authenticated
|
|
1915
|
+
*/
|
|
1916
|
+
isAuthenticated() {
|
|
1917
|
+
return !!this.httpClient.getApiKey();
|
|
1918
|
+
}
|
|
1919
|
+
};
|
|
1920
|
+
|
|
1921
|
+
// constants/metrics.ts
|
|
1922
|
+
var BODY_METRICS = [
|
|
1923
|
+
{ key: "height", displayName: "Height", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1924
|
+
{ key: "weight", displayName: "Body Weight", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
|
|
1925
|
+
{ key: "body_fat", displayName: "Body Fat %", category: "body", unit: "%", aggregation: "last" },
|
|
1926
|
+
{ key: "muscle_mass", displayName: "Muscle Mass", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
|
|
1927
|
+
{ key: "bone_mass", displayName: "Bone Mass", category: "body", unit: "kg", aggregation: "last", imperialUnit: "lbs", imperialConversion: 2.20462 },
|
|
1928
|
+
{ key: "body_water", displayName: "Body Water %", category: "body", unit: "%", aggregation: "last" },
|
|
1929
|
+
{ key: "bmi", displayName: "BMI", category: "body", unit: "kg/m\xB2", aggregation: "last" },
|
|
1930
|
+
{ key: "waist", displayName: "Waist Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1931
|
+
{ key: "hip", displayName: "Hip Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1932
|
+
{ key: "chest", displayName: "Chest Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1933
|
+
{ key: "neck", displayName: "Neck Circumference", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1934
|
+
{ key: "left_bicep", displayName: "Left Bicep", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1935
|
+
{ key: "right_bicep", displayName: "Right Bicep", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1936
|
+
{ key: "left_forearm", displayName: "Left Forearm", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1937
|
+
{ key: "right_forearm", displayName: "Right Forearm", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1938
|
+
{ key: "left_thigh", displayName: "Left Thigh", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1939
|
+
{ key: "right_thigh", displayName: "Right Thigh", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1940
|
+
{ key: "left_calf", displayName: "Left Calf", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 },
|
|
1941
|
+
{ key: "right_calf", displayName: "Right Calf", category: "body", unit: "cm", aggregation: "last", imperialUnit: "in", imperialConversion: 0.393701 }
|
|
1942
|
+
];
|
|
1943
|
+
var ACTIVITY_METRICS = [
|
|
1944
|
+
{ key: "steps", displayName: "Steps", category: "activity", unit: "steps", aggregation: "sum" },
|
|
1945
|
+
{ key: "distance", displayName: "Distance", category: "activity", unit: "km", aggregation: "sum", imperialUnit: "mi", imperialConversion: 0.621371 },
|
|
1946
|
+
{ key: "active_minutes", displayName: "Active Minutes", category: "activity", unit: "min", aggregation: "sum" },
|
|
1947
|
+
{ key: "exercise_minutes", displayName: "Exercise Minutes", category: "activity", unit: "min", aggregation: "sum" },
|
|
1948
|
+
{ key: "exercise_calories", displayName: "Exercise Calories", category: "activity", unit: "kcal", aggregation: "sum" },
|
|
1949
|
+
{ key: "floors_climbed", displayName: "Floors Climbed", category: "activity", unit: "floors", aggregation: "sum" },
|
|
1950
|
+
{ key: "standing_hours", displayName: "Standing Hours", category: "activity", unit: "hours", aggregation: "sum" },
|
|
1951
|
+
{ key: "vo2_max", displayName: "VO2 Max", category: "activity", unit: "ml/kg/min", aggregation: "last" }
|
|
1952
|
+
];
|
|
1953
|
+
var SLEEP_METRICS = [
|
|
1954
|
+
{ key: "sleep_duration", displayName: "Sleep Duration", category: "sleep", unit: "hours", aggregation: "last" },
|
|
1955
|
+
{ key: "deep_sleep", displayName: "Deep Sleep", category: "sleep", unit: "hours", aggregation: "last" },
|
|
1956
|
+
{ key: "rem_sleep", displayName: "REM Sleep", category: "sleep", unit: "hours", aggregation: "last" },
|
|
1957
|
+
{ key: "light_sleep", displayName: "Light Sleep", category: "sleep", unit: "hours", aggregation: "last" },
|
|
1958
|
+
{ key: "sleep_quality", displayName: "Sleep Quality", category: "sleep", unit: "score", aggregation: "avg" },
|
|
1959
|
+
{ key: "sleep_efficiency", displayName: "Sleep Efficiency", category: "sleep", unit: "%", aggregation: "avg" },
|
|
1960
|
+
{ key: "time_to_fall_asleep", displayName: "Time to Fall Asleep", category: "sleep", unit: "min", aggregation: "avg" },
|
|
1961
|
+
{ key: "times_awakened", displayName: "Times Awakened", category: "sleep", unit: "count", aggregation: "sum" }
|
|
1962
|
+
];
|
|
1963
|
+
var VITAL_METRICS = [
|
|
1964
|
+
{ key: "heart_rate", displayName: "Heart Rate", category: "vital", unit: "bpm", aggregation: "avg" },
|
|
1965
|
+
{ key: "resting_heart_rate", displayName: "Resting Heart Rate", category: "vital", unit: "bpm", aggregation: "min" },
|
|
1966
|
+
{ key: "heart_rate_variability", displayName: "Heart Rate Variability", category: "vital", unit: "ms", aggregation: "avg" },
|
|
1967
|
+
{ key: "blood_pressure_systolic", displayName: "Blood Pressure (Systolic)", category: "vital", unit: "mmHg", aggregation: "last" },
|
|
1968
|
+
{ key: "blood_pressure_diastolic", displayName: "Blood Pressure (Diastolic)", category: "vital", unit: "mmHg", aggregation: "last" },
|
|
1969
|
+
{ key: "blood_glucose", displayName: "Blood Glucose", category: "vital", unit: "mg/dL", aggregation: "avg" },
|
|
1970
|
+
{ key: "blood_oxygen", displayName: "Blood Oxygen", category: "vital", unit: "%", aggregation: "avg" },
|
|
1971
|
+
{ key: "respiratory_rate", displayName: "Respiratory Rate", category: "vital", unit: "breaths/min", aggregation: "avg" },
|
|
1972
|
+
{ key: "body_temperature", displayName: "Body Temperature", category: "vital", unit: "\xB0C", aggregation: "avg", imperialUnit: "\xB0F", imperialConversion: 1.8 }
|
|
1973
|
+
// Note: Fahrenheit conversion requires adding 32, handle separately
|
|
1974
|
+
];
|
|
1975
|
+
var WELLNESS_METRICS = [
|
|
1976
|
+
{ key: "mood", displayName: "Mood", category: "wellness", unit: "score", aggregation: "avg" },
|
|
1977
|
+
{ key: "energy_level", displayName: "Energy Level", category: "wellness", unit: "score", aggregation: "avg" },
|
|
1978
|
+
{ key: "stress_level", displayName: "Stress Level", category: "wellness", unit: "score", aggregation: "avg" }
|
|
1979
|
+
];
|
|
1980
|
+
var ALL_METRICS = [
|
|
1981
|
+
...BODY_METRICS,
|
|
1982
|
+
...ACTIVITY_METRICS,
|
|
1983
|
+
...SLEEP_METRICS,
|
|
1984
|
+
...VITAL_METRICS,
|
|
1985
|
+
...WELLNESS_METRICS
|
|
1986
|
+
];
|
|
1987
|
+
function getMetricDefinition(key) {
|
|
1988
|
+
return ALL_METRICS.find((m) => m.key === key);
|
|
1989
|
+
}
|
|
1990
|
+
function getMetricsByCategory(category) {
|
|
1991
|
+
return ALL_METRICS.filter((m) => m.category === category);
|
|
1992
|
+
}
|
|
1993
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1994
|
+
0 && (module.exports = {
|
|
1995
|
+
ACTIVITY_METRICS,
|
|
1996
|
+
ALL_METRICS,
|
|
1997
|
+
AuthenticationError,
|
|
1998
|
+
AuthorizationError,
|
|
1999
|
+
BODY_METRICS,
|
|
2000
|
+
DistanceConverter,
|
|
2001
|
+
HeightConverter,
|
|
2002
|
+
NetworkError,
|
|
2003
|
+
NotFoundError,
|
|
2004
|
+
OpenLifeLog,
|
|
2005
|
+
OpenLifeLogError,
|
|
2006
|
+
PaginatedIterator,
|
|
2007
|
+
RateLimitError,
|
|
2008
|
+
SLEEP_METRICS,
|
|
2009
|
+
ServerError,
|
|
2010
|
+
TimeoutError,
|
|
2011
|
+
UnitConversionError,
|
|
2012
|
+
UnitConverter,
|
|
2013
|
+
VITAL_METRICS,
|
|
2014
|
+
ValidationError,
|
|
2015
|
+
WELLNESS_METRICS,
|
|
2016
|
+
WeightConverter,
|
|
2017
|
+
createPaginatedIterator,
|
|
2018
|
+
createUnitConverter,
|
|
2019
|
+
fetchAllPages,
|
|
2020
|
+
getMetricDefinition,
|
|
2021
|
+
getMetricsByCategory,
|
|
2022
|
+
hasMorePages
|
|
2023
|
+
});
|