@nativesquare/soma 0.11.0 → 0.13.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.
Files changed (60) hide show
  1. package/dist/client/garmin.d.ts +291 -0
  2. package/dist/client/garmin.d.ts.map +1 -0
  3. package/dist/client/garmin.js +493 -0
  4. package/dist/client/garmin.js.map +1 -0
  5. package/dist/client/index.d.ts +29 -394
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +30 -520
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/client/strava.d.ts +97 -0
  10. package/dist/client/strava.d.ts.map +1 -0
  11. package/dist/client/strava.js +160 -0
  12. package/dist/client/strava.js.map +1 -0
  13. package/dist/client/types.d.ts +238 -0
  14. package/dist/client/types.d.ts.map +1 -1
  15. package/dist/component/_generated/component.d.ts +24 -12
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/garmin/private.d.ts +53 -68
  18. package/dist/component/garmin/private.d.ts.map +1 -1
  19. package/dist/component/garmin/private.js +87 -85
  20. package/dist/component/garmin/private.js.map +1 -1
  21. package/dist/component/garmin/public.d.ts +97 -53
  22. package/dist/component/garmin/public.d.ts.map +1 -1
  23. package/dist/component/garmin/public.js +75 -148
  24. package/dist/component/garmin/public.js.map +1 -1
  25. package/dist/component/garmin/webhooks.d.ts +22 -20
  26. package/dist/component/garmin/webhooks.d.ts.map +1 -1
  27. package/dist/component/garmin/webhooks.js +115 -76
  28. package/dist/component/garmin/webhooks.js.map +1 -1
  29. package/dist/component/public.d.ts +15 -15
  30. package/dist/component/schema.d.ts +25 -25
  31. package/dist/component/strava/public.d.ts +12 -8
  32. package/dist/component/strava/public.d.ts.map +1 -1
  33. package/dist/component/strava/public.js +7 -7
  34. package/dist/component/strava/public.js.map +1 -1
  35. package/dist/component/validators/activity.d.ts +4 -4
  36. package/dist/component/validators/body.d.ts +4 -4
  37. package/dist/component/validators/daily.d.ts +4 -4
  38. package/dist/component/validators/nutrition.d.ts +3 -3
  39. package/dist/component/validators/samples.d.ts +4 -4
  40. package/dist/component/validators/shared.d.ts +13 -4
  41. package/dist/component/validators/shared.d.ts.map +1 -1
  42. package/dist/component/validators/shared.js +7 -0
  43. package/dist/component/validators/shared.js.map +1 -1
  44. package/dist/component/validators/sleep.d.ts +5 -5
  45. package/dist/validators.d.ts +41 -40
  46. package/dist/validators.d.ts.map +1 -1
  47. package/dist/validators.js +1 -0
  48. package/dist/validators.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/client/garmin.ts +692 -0
  51. package/src/client/index.ts +68 -933
  52. package/src/client/strava.ts +199 -0
  53. package/src/client/types.ts +285 -0
  54. package/src/component/_generated/component.ts +19 -32
  55. package/src/component/garmin/private.ts +1872 -1870
  56. package/src/component/garmin/public.ts +1073 -1184
  57. package/src/component/garmin/webhooks.ts +898 -857
  58. package/src/component/strava/public.ts +393 -393
  59. package/src/component/validators/shared.ts +9 -0
  60. package/src/validators.ts +1 -0
@@ -0,0 +1,199 @@
1
+ import type { SomaComponent } from "./index.js";
2
+ import type { ActionCtx, SomaStravaConfig, RegisterRoutesOptions } from "./types.js";
3
+ import { httpActionGeneric, type HttpRouter } from "convex/server";
4
+
5
+ export const STRAVA_CALLBACK_PATH = "/api/strava/callback";
6
+
7
+ export class SomaStrava {
8
+ constructor(
9
+ private component: SomaComponent,
10
+ private requireConfig: () => SomaStravaConfig,
11
+ ) {}
12
+
13
+ /**
14
+ * Generate a Strava OAuth authorization URL.
15
+ *
16
+ * The state parameter is stored inside the component automatically,
17
+ * and the callback handler registered by `registerRoutes` will
18
+ * complete the flow without further host-app intervention.
19
+ *
20
+ * @param ctx - Action context from the host app
21
+ * @param opts.userId - The host app's user identifier
22
+ * @param opts.redirectUri - The URL Strava will redirect to after authorization
23
+ * @param opts.scope - Comma-separated Strava OAuth scopes (default: "read,activity:read_all,profile:read_all")
24
+ * @returns `{ authUrl, state }`
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const { authUrl } = await soma.strava.getAuthUrl(ctx, {
29
+ * userId: "user_123",
30
+ * redirectUri: "https://your-app.convex.site/api/strava/callback",
31
+ * });
32
+ * // Redirect user to authUrl — the callback is handled automatically
33
+ * ```
34
+ */
35
+ async getAuthUrl(
36
+ ctx: ActionCtx,
37
+ opts: { userId: string; redirectUri: string; scope?: string },
38
+ ) {
39
+ const config = this.requireConfig();
40
+ return await ctx.runAction(this.component.strava.public.getStravaAuthUrl, {
41
+ clientId: config.clientId,
42
+ redirectUri: opts.redirectUri,
43
+ scope: opts.scope,
44
+ userId: opts.userId,
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Sync activities from Strava for an already-connected user.
50
+ *
51
+ * Automatically refreshes the access token if expired. Fetches the
52
+ * athlete profile and activities, transforms them, and ingests into Soma.
53
+ *
54
+ * @param ctx - Action context from the host app
55
+ * @param args.userId - The host app's user identifier
56
+ * @param args.after - Only sync activities after this Unix epoch timestamp (for incremental sync)
57
+ * @returns `{ synced, errors }`
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * export const syncStrava = action({
62
+ * args: { userId: v.string() },
63
+ * handler: async (ctx, { userId }) => {
64
+ * return await soma.strava.sync(ctx, { userId });
65
+ * },
66
+ * });
67
+ * ```
68
+ */
69
+ async sync(
70
+ ctx: ActionCtx,
71
+ args: { userId: string; after?: number },
72
+ ) {
73
+ const config = this.requireConfig();
74
+ return await ctx.runAction(this.component.strava.public.syncStrava, {
75
+ ...args,
76
+ clientId: config.clientId,
77
+ clientSecret: config.clientSecret,
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Disconnect a user from Strava.
83
+ *
84
+ * Revokes the token at Strava (best-effort), deletes stored tokens,
85
+ * and sets the connection to inactive.
86
+ *
87
+ * @param ctx - Action context from the host app
88
+ * @param args.userId - The host app's user identifier
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * export const disconnectStrava = action({
93
+ * args: { userId: v.string() },
94
+ * handler: async (ctx, { userId }) => {
95
+ * await soma.strava.disconnect(ctx, { userId });
96
+ * },
97
+ * });
98
+ * ```
99
+ */
100
+ async disconnect(
101
+ ctx: ActionCtx,
102
+ args: { userId: string },
103
+ ) {
104
+ const config = this.requireConfig();
105
+ return await ctx.runAction(this.component.strava.public.disconnectStrava, {
106
+ ...args,
107
+ clientId: config.clientId,
108
+ clientSecret: config.clientSecret,
109
+ });
110
+ }
111
+
112
+ static registerRoutes(
113
+ http: HttpRouter,
114
+ component: SomaComponent,
115
+ opts?: RegisterRoutesOptions["strava"],
116
+ ) {
117
+ const oauth = opts?.oauth ?? {};
118
+ const path = oauth.path ?? STRAVA_CALLBACK_PATH;
119
+
120
+ http.route({
121
+ path,
122
+ method: "GET",
123
+ handler: httpActionGeneric(async (ctx, request) => {
124
+ const url = new URL(request.url);
125
+ const code = url.searchParams.get("code");
126
+ const state = url.searchParams.get("state");
127
+
128
+ if (!code) {
129
+ return new Response("Missing authorization code", { status: 400 });
130
+ }
131
+ if (!state) {
132
+ return new Response(
133
+ "Missing state parameter. Ensure the state was included " +
134
+ "when building the Strava auth URL via getStravaAuthUrl.",
135
+ { status: 400 },
136
+ );
137
+ }
138
+
139
+ const clientId =
140
+ opts?.clientId ?? process.env.STRAVA_CLIENT_ID;
141
+ const clientSecret =
142
+ opts?.clientSecret ?? process.env.STRAVA_CLIENT_SECRET;
143
+
144
+ if (!clientId || !clientSecret) {
145
+ return new Response(
146
+ "Strava credentials not configured. Set STRAVA_CLIENT_ID and " +
147
+ "STRAVA_CLIENT_SECRET environment variables, or pass them to registerRoutes.",
148
+ { status: 500 },
149
+ );
150
+ }
151
+
152
+ let result: {
153
+ connectionId: string;
154
+ userId: string;
155
+ };
156
+ try {
157
+ result = await ctx.runAction(component.strava.public.completeStravaOAuth, {
158
+ code,
159
+ state,
160
+ clientId,
161
+ clientSecret,
162
+ });
163
+ } catch (error) {
164
+ const message =
165
+ error instanceof Error ? error.message : "Unknown error";
166
+ return new Response(`Strava OAuth callback failed: ${message}`, {
167
+ status: 500,
168
+ });
169
+ }
170
+
171
+ if (oauth.onComplete) {
172
+ try {
173
+ await oauth.onComplete(ctx, {
174
+ provider: "STRAVA",
175
+ userId: result.userId,
176
+ connectionId: result.connectionId,
177
+ });
178
+ } catch (callbackError) {
179
+ console.error(
180
+ "[soma] strava onComplete callback error:",
181
+ callbackError instanceof Error ? callbackError.message : callbackError,
182
+ );
183
+ }
184
+ }
185
+
186
+ if (oauth.redirectTo) {
187
+ return new Response(null, {
188
+ status: 302,
189
+ headers: { Location: oauth.redirectTo },
190
+ });
191
+ }
192
+
193
+ return new Response("Successfully connected to Strava!", {
194
+ status: 200,
195
+ });
196
+ }),
197
+ });
198
+ }
199
+ }
@@ -5,6 +5,10 @@ import type {
5
5
  GenericDataModel,
6
6
  } from "convex/server";
7
7
 
8
+ // ─── Context Types ──────────────────────────────────────────────────────────
9
+ // Narrowed Convex context types that only expose the runner methods each
10
+ // operation actually needs.
11
+
8
12
  export type QueryCtx = Pick<GenericQueryCtx<GenericDataModel>, "runQuery">;
9
13
 
10
14
  export type MutationCtx = Pick<
@@ -16,3 +20,284 @@ export type ActionCtx = Pick<
16
20
  GenericActionCtx<GenericDataModel>,
17
21
  "runQuery" | "runMutation" | "runAction"
18
22
  >;
23
+
24
+ // ─── Provider Configuration ─────────────────────────────────────────────────
25
+
26
+ /**
27
+ * Configuration for the Strava integration.
28
+ *
29
+ * If not provided to the Soma constructor, the class will attempt to
30
+ * read `STRAVA_CLIENT_ID` and `STRAVA_CLIENT_SECRET`
31
+ * from environment variables automatically.
32
+ */
33
+ export interface SomaStravaConfig {
34
+ /** Your Strava application's Client ID. */
35
+ clientId: string;
36
+ /** Your Strava application's Client Secret. */
37
+ clientSecret: string;
38
+ }
39
+
40
+ /**
41
+ * Configuration for the Garmin integration.
42
+ *
43
+ * If not provided to the Soma constructor, the class will attempt to
44
+ * read `GARMIN_CLIENT_ID` and `GARMIN_CLIENT_SECRET` from
45
+ * environment variables automatically.
46
+ */
47
+ export interface SomaGarminConfig {
48
+ /** Your Garmin application's Client ID. */
49
+ clientId: string;
50
+ /** Your Garmin application's Client Secret. */
51
+ clientSecret: string;
52
+ }
53
+
54
+ // ─── Shared Error & Result Types ───────────────────────────────────────────
55
+
56
+ /**
57
+ * A structured error from a Soma operation.
58
+ *
59
+ * Operational errors (API failures, transform errors, ingestion failures)
60
+ * are returned in the result — not thrown. Only configuration errors
61
+ * (missing connection, nonexistent document) are thrown as exceptions.
62
+ */
63
+ export interface SomaError {
64
+ /** Category of the failed item (e.g. `"activity"`, `"pushWorkout"`, `"ingest"`). */
65
+ type: string;
66
+ /** Identifier of the failed item, or `"fetch"` for API-level failures. */
67
+ id: string;
68
+ /** Human-readable error description. */
69
+ message: string;
70
+ }
71
+
72
+ /**
73
+ * Standard result wrapper for all Soma data operations.
74
+ *
75
+ * - `data` contains the operation's success payload.
76
+ * - `errors` contains any operational failures that occurred.
77
+ *
78
+ * For **batch operations** (pull, sync), partial success is possible:
79
+ * `data` contains the counts of successfully processed items, while
80
+ * `errors` lists the individual failures.
81
+ *
82
+ * For **atomic operations** (push, delete), `data` is `null` when the
83
+ * operation fails, with a single entry in `errors` describing the cause.
84
+ */
85
+ export type SomaResult<T> = {
86
+ data: T;
87
+ errors: SomaError[];
88
+ };
89
+
90
+ // ─── Data Query & Ingestion Args ────────────────────────────────────────────
91
+
92
+ /**
93
+ * Common args shape for all ingestion methods.
94
+ *
95
+ * Requires `connectionId` and `userId` at minimum — additional fields
96
+ * come from the transformer output (e.g., `metadata`, `calories_data`, etc.)
97
+ * and are validated server-side by Convex validators.
98
+ */
99
+ export type IngestArgs = {
100
+ connectionId: string;
101
+ userId: string;
102
+ } & Record<string, unknown>;
103
+
104
+ /**
105
+ * Base args for time-range filtered queries.
106
+ *
107
+ * - `userId` is required for all health data queries.
108
+ * - `startTime` / `endTime` are optional ISO-8601 bounds on `metadata.start_time`.
109
+ */
110
+ export type TimeRangeArgs = {
111
+ userId: string;
112
+ startTime?: string;
113
+ endTime?: string;
114
+ };
115
+
116
+ /**
117
+ * Args for list (collect-all) queries with optional ordering and limit.
118
+ */
119
+ export type ListTimeRangeArgs = TimeRangeArgs & {
120
+ order?: "asc" | "desc";
121
+ limit?: number;
122
+ };
123
+
124
+ /**
125
+ * Args for paginated queries with Convex pagination options.
126
+ */
127
+ export type PaginateTimeRangeArgs = TimeRangeArgs & {
128
+ paginationOpts: { numItems: number; cursor: string | null };
129
+ };
130
+
131
+ // ─── OAuth Callback Events ──────────────────────────────────────────────────
132
+
133
+ /** Data passed to `onComplete` after Strava OAuth completes. */
134
+ export interface StravaConnectEvent {
135
+ provider: "STRAVA";
136
+ userId: string;
137
+ connectionId: string;
138
+ }
139
+
140
+ /** Data passed to `oauth.onComplete` after Garmin OAuth completes. */
141
+ export interface GarminConnectEvent {
142
+ provider: "GARMIN";
143
+ userId: string;
144
+ connectionId: string;
145
+ }
146
+
147
+ // ─── Garmin Webhook Types ───────────────────────────────────────────────────
148
+
149
+ /** Args accepted by all Garmin webhook handler actions inside the component. */
150
+ export type GarminWebhookActionArgs = {
151
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
152
+ payload: any;
153
+ autoIngest?: boolean;
154
+ };
155
+
156
+ /** Result returned by all Garmin webhook handler actions inside the component. */
157
+ export interface GarminWebhookActionResult {
158
+ errors: SomaError[];
159
+ items: GarminWebhookItem[];
160
+ }
161
+
162
+ /** A single transformed item with its user/connection mapping. */
163
+ export interface GarminWebhookItem {
164
+ /** The Soma connection ID that this data belongs to. */
165
+ connectionId: string;
166
+ /** The host app's user ID. */
167
+ userId: string;
168
+ /** The transformed data in Soma's normalized format. */
169
+ data: Record<string, unknown>;
170
+ }
171
+
172
+ /**
173
+ * Data passed to webhook `events` handlers and `onEvent` after processing.
174
+ *
175
+ * The host app receives the full set of transformed items plus the raw Garmin
176
+ * payload, regardless of the `autoIngest` setting.
177
+ */
178
+ export interface GarminWebhookEvent {
179
+ /** The Garmin data type that triggered this webhook (e.g. `"activities"`, `"sleeps"`). */
180
+ dataType: string;
181
+ /** Errors encountered during connection resolution, transformation, or ingestion. */
182
+ errors: SomaError[];
183
+ /** The raw JSON payload received from Garmin, before any transformation. */
184
+ rawPayload: unknown;
185
+ /**
186
+ * Transformed items in Soma's normalized format.
187
+ *
188
+ * Always contains the full set of successfully transformed items, regardless
189
+ * of the `autoIngest` setting. When `autoIngest` is `true`, these are the
190
+ * same items that were written to the database. When `autoIngest` is `false`,
191
+ * the host app can use them for custom ingestion or processing.
192
+ *
193
+ * Empty for ping-mode webhooks (which contain no data).
194
+ */
195
+ items: GarminWebhookItem[];
196
+ }
197
+
198
+ /** Webhook endpoint names matching the Garmin API data types. */
199
+ export type GarminWebhookEventName =
200
+ | "activities" | "activity-details" | "manually-updated-activities" | "move-iq"
201
+ | "blood-pressures" | "body-compositions" | "dailies" | "epochs"
202
+ | "health-snapshot" | "sleeps" | "hrv" | "stress" | "pulse-ox"
203
+ | "respiration" | "skin-temp" | "user-metrics" | "menstrual-cycle-tracking";
204
+
205
+ /** Handler for a specific webhook event or the catch-all `onEvent`. */
206
+ export type GarminWebhookHandler = (
207
+ ctx: GenericActionCtx<GenericDataModel>,
208
+ event: GarminWebhookEvent,
209
+ ) => Promise<void>;
210
+
211
+ // ─── Route Registration Options ─────────────────────────────────────────────
212
+
213
+ /**
214
+ * Per-provider options for `registerRoutes`.
215
+ */
216
+ export interface StravaOAuthOptions {
217
+ /** HTTP path for the OAuth callback. @default "/api/strava/callback" */
218
+ path?: string;
219
+ /** URL to redirect the user to after a successful connection. */
220
+ redirectTo?: string;
221
+ /** Called after Strava OAuth completes and the connection is established. */
222
+ onComplete?: (
223
+ ctx: GenericActionCtx<GenericDataModel>,
224
+ event: StravaConnectEvent,
225
+ ) => Promise<void>;
226
+ }
227
+
228
+ export interface GarminOAuthOptions {
229
+ /** HTTP path for the OAuth callback. @default "/api/garmin/callback" */
230
+ path?: string;
231
+ /** URL to redirect the user to after a successful connection. */
232
+ redirectTo?: string;
233
+ /** Called after Garmin OAuth completes and the connection is established. */
234
+ onComplete?: (
235
+ ctx: GenericActionCtx<GenericDataModel>,
236
+ event: GarminConnectEvent,
237
+ ) => Promise<void>;
238
+ }
239
+
240
+ export interface GarminWebhookOptions {
241
+ /** Base path prefix for all webhook routes. @default "/api/garmin/webhook" */
242
+ basePath?: string;
243
+ /**
244
+ * Whether to automatically ingest (upsert) transformed data into the Soma
245
+ * database when a webhook payload is received.
246
+ *
247
+ * When `true` (default), incoming data is validated, transformed, and written
248
+ * to the database automatically. When `false`, the webhook still receives and
249
+ * validates the payload, but skips the database write — useful when you want
250
+ * to handle ingestion yourself via the `onEvent` / per-type callbacks.
251
+ *
252
+ * @default true
253
+ */
254
+ autoIngest?: boolean;
255
+ /** Called after every webhook payload is processed, regardless of data type. */
256
+ onEvent?: GarminWebhookHandler;
257
+ /**
258
+ * Per-data-type webhook registration.
259
+ *
260
+ * **Only data types listed here get an HTTP route registered.**
261
+ * Unlisted types are ignored — Garmin receives a 404 if it POSTs to them.
262
+ *
263
+ * Pass a handler function to run custom logic after ingestion,
264
+ * or `true` to register the route with default processing only.
265
+ *
266
+ * @example
267
+ * ```ts
268
+ * events: {
269
+ * "activities": async (ctx, event) => { // custom side-effect },
270
+ * "sleeps": true, // register route, default processing only
271
+ * "dailies": true,
272
+ * }
273
+ * ```
274
+ */
275
+ events?: Partial<Record<GarminWebhookEventName, GarminWebhookHandler | true>>;
276
+ }
277
+
278
+ export interface RegisterRoutesOptions {
279
+ strava?: {
280
+ /** Override STRAVA_CLIENT_ID env var. */
281
+ clientId?: string;
282
+ /** Override STRAVA_CLIENT_SECRET env var. */
283
+ clientSecret?: string;
284
+ /** OAuth callback configuration. */
285
+ oauth?: StravaOAuthOptions;
286
+ };
287
+ garmin?: {
288
+ /** Override GARMIN_CLIENT_ID env var. */
289
+ clientId?: string;
290
+ /** Override GARMIN_CLIENT_SECRET env var. */
291
+ clientSecret?: string;
292
+ /** OAuth callback configuration. */
293
+ oauth?: GarminOAuthOptions;
294
+ /**
295
+ * Webhook route configuration.
296
+ *
297
+ * Routes are **disabled by default**. Only data types listed in `events`
298
+ * get an HTTP endpoint registered. Omit entirely or set to `false` to
299
+ * skip all webhook routes.
300
+ */
301
+ webhook?: GarminWebhookOptions | false;
302
+ };
303
+ }
@@ -245,19 +245,6 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
245
245
  any,
246
246
  Name
247
247
  >;
248
- pushPlannedWorkout: FunctionReference<
249
- "action",
250
- "internal",
251
- {
252
- clientId: string;
253
- clientSecret: string;
254
- plannedWorkoutId: string;
255
- userId: string;
256
- workoutProvider?: string;
257
- },
258
- any,
259
- Name
260
- >;
261
248
  pushSchedule: FunctionReference<
262
249
  "action",
263
250
  "internal",
@@ -289,119 +276,119 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
289
276
  handleGarminWebhookActivities: FunctionReference<
290
277
  "action",
291
278
  "internal",
292
- { payload: any },
279
+ { autoIngest?: boolean; payload: any },
293
280
  any,
294
281
  Name
295
282
  >;
296
283
  handleGarminWebhookActivityDetails: FunctionReference<
297
284
  "action",
298
285
  "internal",
299
- { payload: any },
286
+ { autoIngest?: boolean; payload: any },
300
287
  any,
301
288
  Name
302
289
  >;
303
290
  handleGarminWebhookBloodPressures: FunctionReference<
304
291
  "action",
305
292
  "internal",
306
- { payload: any },
293
+ { autoIngest?: boolean; payload: any },
307
294
  any,
308
295
  Name
309
296
  >;
310
297
  handleGarminWebhookBodyCompositions: FunctionReference<
311
298
  "action",
312
299
  "internal",
313
- { payload: any },
300
+ { autoIngest?: boolean; payload: any },
314
301
  any,
315
302
  Name
316
303
  >;
317
304
  handleGarminWebhookDailies: FunctionReference<
318
305
  "action",
319
306
  "internal",
320
- { payload: any },
307
+ { autoIngest?: boolean; payload: any },
321
308
  any,
322
309
  Name
323
310
  >;
324
311
  handleGarminWebhookEpochs: FunctionReference<
325
312
  "action",
326
313
  "internal",
327
- { payload: any },
314
+ { autoIngest?: boolean; payload: any },
328
315
  any,
329
316
  Name
330
317
  >;
331
318
  handleGarminWebhookHealthSnapshot: FunctionReference<
332
319
  "action",
333
320
  "internal",
334
- { payload: any },
321
+ { autoIngest?: boolean; payload: any },
335
322
  any,
336
323
  Name
337
324
  >;
338
325
  handleGarminWebhookHRVSummary: FunctionReference<
339
326
  "action",
340
327
  "internal",
341
- { payload: any },
328
+ { autoIngest?: boolean; payload: any },
342
329
  any,
343
330
  Name
344
331
  >;
345
332
  handleGarminWebhookManuallyUpdatedActivities: FunctionReference<
346
333
  "action",
347
334
  "internal",
348
- { payload: any },
335
+ { autoIngest?: boolean; payload: any },
349
336
  any,
350
337
  Name
351
338
  >;
352
339
  handleGarminWebhookMenstrualCycleTracking: FunctionReference<
353
340
  "action",
354
341
  "internal",
355
- { payload: any },
342
+ { autoIngest?: boolean; payload: any },
356
343
  any,
357
344
  Name
358
345
  >;
359
346
  handleGarminWebhookMoveIQ: FunctionReference<
360
347
  "action",
361
348
  "internal",
362
- { payload: any },
349
+ { autoIngest?: boolean; payload: any },
363
350
  any,
364
351
  Name
365
352
  >;
366
353
  handleGarminWebhookPulseOx: FunctionReference<
367
354
  "action",
368
355
  "internal",
369
- { payload: any },
356
+ { autoIngest?: boolean; payload: any },
370
357
  any,
371
358
  Name
372
359
  >;
373
360
  handleGarminWebhookRespiration: FunctionReference<
374
361
  "action",
375
362
  "internal",
376
- { payload: any },
363
+ { autoIngest?: boolean; payload: any },
377
364
  any,
378
365
  Name
379
366
  >;
380
367
  handleGarminWebhookSkinTemp: FunctionReference<
381
368
  "action",
382
369
  "internal",
383
- { payload: any },
370
+ { autoIngest?: boolean; payload: any },
384
371
  any,
385
372
  Name
386
373
  >;
387
374
  handleGarminWebhookSleeps: FunctionReference<
388
375
  "action",
389
376
  "internal",
390
- { payload: any },
377
+ { autoIngest?: boolean; payload: any },
391
378
  any,
392
379
  Name
393
380
  >;
394
381
  handleGarminWebhookStress: FunctionReference<
395
382
  "action",
396
383
  "internal",
397
- { payload: any },
384
+ { autoIngest?: boolean; payload: any },
398
385
  any,
399
386
  Name
400
387
  >;
401
388
  handleGarminWebhookUserMetrics: FunctionReference<
402
389
  "action",
403
390
  "internal",
404
- { payload: any },
391
+ { autoIngest?: boolean; payload: any },
405
392
  any,
406
393
  Name
407
394
  >;
@@ -1880,8 +1867,8 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
1880
1867
  userId: string;
1881
1868
  },
1882
1869
  {
1883
- errors: Array<{ error: string; id: string; type: string }>;
1884
- synced: { activities: number; athletes: number };
1870
+ data: { synced: { activities: number; athletes: number } };
1871
+ errors: Array<{ id: string; message: string; type: string }>;
1885
1872
  },
1886
1873
  Name
1887
1874
  >;