@clipin/convex-wearables 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/README.md +616 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +4 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +244 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +555 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/types.d.ts +689 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/client/types.js +112 -0
- package/dist/client/types.js.map +1 -0
- package/dist/component/_generated/_ignore.d.ts +1 -0
- package/dist/component/_generated/_ignore.d.ts.map +1 -0
- package/dist/component/_generated/_ignore.js +4 -0
- package/dist/component/_generated/_ignore.js.map +1 -0
- package/dist/component/_generated/api.d.ts +13 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +14 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +28 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +23 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +18 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/backfillJobs.d.ts +121 -0
- package/dist/component/backfillJobs.d.ts.map +1 -0
- package/dist/component/backfillJobs.js +233 -0
- package/dist/component/backfillJobs.js.map +1 -0
- package/dist/component/connections.d.ts +159 -0
- package/dist/component/connections.d.ts.map +1 -0
- package/dist/component/connections.js +288 -0
- package/dist/component/connections.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +6 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/dataPoints.d.ts +81 -0
- package/dist/component/dataPoints.d.ts.map +1 -0
- package/dist/component/dataPoints.js +258 -0
- package/dist/component/dataPoints.js.map +1 -0
- package/dist/component/dataSources.d.ts +56 -0
- package/dist/component/dataSources.d.ts.map +1 -0
- package/dist/component/dataSources.js +95 -0
- package/dist/component/dataSources.js.map +1 -0
- package/dist/component/events.d.ts +203 -0
- package/dist/component/events.d.ts.map +1 -0
- package/dist/component/events.js +251 -0
- package/dist/component/events.js.map +1 -0
- package/dist/component/garminBackfill.d.ts +40 -0
- package/dist/component/garminBackfill.d.ts.map +1 -0
- package/dist/component/garminBackfill.js +296 -0
- package/dist/component/garminBackfill.js.map +1 -0
- package/dist/component/garminWebhooks.d.ts +17 -0
- package/dist/component/garminWebhooks.d.ts.map +1 -0
- package/dist/component/garminWebhooks.js +505 -0
- package/dist/component/garminWebhooks.js.map +1 -0
- package/dist/component/httpHandlers.d.ts +32 -0
- package/dist/component/httpHandlers.d.ts.map +1 -0
- package/dist/component/httpHandlers.js +131 -0
- package/dist/component/httpHandlers.js.map +1 -0
- package/dist/component/lifecycle.d.ts +12 -0
- package/dist/component/lifecycle.d.ts.map +1 -0
- package/dist/component/lifecycle.js +79 -0
- package/dist/component/lifecycle.js.map +1 -0
- package/dist/component/menstrualCycles.d.ts +98 -0
- package/dist/component/menstrualCycles.d.ts.map +1 -0
- package/dist/component/menstrualCycles.js +112 -0
- package/dist/component/menstrualCycles.js.map +1 -0
- package/dist/component/oauthActions.d.ts +52 -0
- package/dist/component/oauthActions.d.ts.map +1 -0
- package/dist/component/oauthActions.js +208 -0
- package/dist/component/oauthActions.js.map +1 -0
- package/dist/component/oauthStates.d.ts +47 -0
- package/dist/component/oauthStates.d.ts.map +1 -0
- package/dist/component/oauthStates.js +77 -0
- package/dist/component/oauthStates.js.map +1 -0
- package/dist/component/providerSettings.d.ts +15 -0
- package/dist/component/providerSettings.d.ts.map +1 -0
- package/dist/component/providerSettings.js +57 -0
- package/dist/component/providerSettings.js.map +1 -0
- package/dist/component/providers/garmin.d.ts +306 -0
- package/dist/component/providers/garmin.d.ts.map +1 -0
- package/dist/component/providers/garmin.js +675 -0
- package/dist/component/providers/garmin.js.map +1 -0
- package/dist/component/providers/oauth.d.ts +42 -0
- package/dist/component/providers/oauth.d.ts.map +1 -0
- package/dist/component/providers/oauth.js +181 -0
- package/dist/component/providers/oauth.js.map +1 -0
- package/dist/component/providers/polar.d.ts +6 -0
- package/dist/component/providers/polar.d.ts.map +1 -0
- package/dist/component/providers/polar.js +175 -0
- package/dist/component/providers/polar.js.map +1 -0
- package/dist/component/providers/registry.d.ts +14 -0
- package/dist/component/providers/registry.d.ts.map +1 -0
- package/dist/component/providers/registry.js +32 -0
- package/dist/component/providers/registry.js.map +1 -0
- package/dist/component/providers/strava.d.ts +45 -0
- package/dist/component/providers/strava.d.ts.map +1 -0
- package/dist/component/providers/strava.js +182 -0
- package/dist/component/providers/strava.js.map +1 -0
- package/dist/component/providers/suunto.d.ts +5 -0
- package/dist/component/providers/suunto.d.ts.map +1 -0
- package/dist/component/providers/suunto.js +502 -0
- package/dist/component/providers/suunto.js.map +1 -0
- package/dist/component/providers/types.d.ts +139 -0
- package/dist/component/providers/types.d.ts.map +1 -0
- package/dist/component/providers/types.js +5 -0
- package/dist/component/providers/types.js.map +1 -0
- package/dist/component/providers/whoop.d.ts +4 -0
- package/dist/component/providers/whoop.d.ts.map +1 -0
- package/dist/component/providers/whoop.js +439 -0
- package/dist/component/providers/whoop.js.map +1 -0
- package/dist/component/schema.d.ts +429 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +282 -0
- package/dist/component/schema.js.map +1 -0
- package/dist/component/sdkPush.d.ts +143 -0
- package/dist/component/sdkPush.d.ts.map +1 -0
- package/dist/component/sdkPush.js +338 -0
- package/dist/component/sdkPush.js.map +1 -0
- package/dist/component/summaries.d.ts +129 -0
- package/dist/component/summaries.d.ts.map +1 -0
- package/dist/component/summaries.js +129 -0
- package/dist/component/summaries.js.map +1 -0
- package/dist/component/syncJobs.d.ts +142 -0
- package/dist/component/syncJobs.d.ts.map +1 -0
- package/dist/component/syncJobs.js +136 -0
- package/dist/component/syncJobs.js.map +1 -0
- package/dist/component/syncWorkflow.d.ts +99 -0
- package/dist/component/syncWorkflow.d.ts.map +1 -0
- package/dist/component/syncWorkflow.js +579 -0
- package/dist/component/syncWorkflow.js.map +1 -0
- package/dist/component/workflowManager.d.ts +3 -0
- package/dist/component/workflowManager.d.ts.map +1 -0
- package/dist/component/workflowManager.js +17 -0
- package/dist/component/workflowManager.js.map +1 -0
- package/package.json +84 -0
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP action handlers for OAuth callbacks and provider webhooks.
|
|
3
|
+
*
|
|
4
|
+
* These are Convex httpAction endpoints that handle:
|
|
5
|
+
* 1. OAuth callback redirects (GET /oauth/callback)
|
|
6
|
+
* 2. Provider webhook pushes (POST /webhooks/:provider)
|
|
7
|
+
*/
|
|
8
|
+
import { internal } from "./_generated/api";
|
|
9
|
+
import { httpAction } from "./_generated/server";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// OAuth callback handler
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Handles the OAuth redirect callback from a provider.
|
|
15
|
+
*
|
|
16
|
+
* Expected query params:
|
|
17
|
+
* - state: The OAuth state token
|
|
18
|
+
* - code: The authorization code
|
|
19
|
+
*
|
|
20
|
+
* The host app must mount this at a route and pass client credentials
|
|
21
|
+
* via the component configuration.
|
|
22
|
+
*/
|
|
23
|
+
export const oauthCallback = httpAction(async (ctx, request) => {
|
|
24
|
+
const url = new URL(request.url);
|
|
25
|
+
const state = url.searchParams.get("state");
|
|
26
|
+
const code = url.searchParams.get("code");
|
|
27
|
+
const error = url.searchParams.get("error");
|
|
28
|
+
if (error) {
|
|
29
|
+
return new Response(JSON.stringify({ error: `OAuth error: ${error}` }), {
|
|
30
|
+
status: 400,
|
|
31
|
+
headers: { "Content-Type": "application/json" },
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
if (!state || !code) {
|
|
35
|
+
return new Response(JSON.stringify({ error: "Missing state or code parameter" }), {
|
|
36
|
+
status: 400,
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Look up the state to find which provider and user this is for
|
|
41
|
+
const oauthState = await ctx.runQuery(internal.oauthStates.getByState, {
|
|
42
|
+
state,
|
|
43
|
+
});
|
|
44
|
+
if (!oauthState) {
|
|
45
|
+
return new Response(JSON.stringify({ error: "Invalid or expired OAuth state" }), {
|
|
46
|
+
status: 400,
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Return the state and code to be processed by the client-side handler.
|
|
51
|
+
// The host app will call handleCallback action with credentials.
|
|
52
|
+
return new Response(JSON.stringify({
|
|
53
|
+
state,
|
|
54
|
+
code,
|
|
55
|
+
provider: oauthState.provider,
|
|
56
|
+
userId: oauthState.userId,
|
|
57
|
+
}), { status: 200, headers: { "Content-Type": "application/json" } });
|
|
58
|
+
});
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Strava webhook verification (GET)
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
/**
|
|
63
|
+
* Strava webhook subscription verification.
|
|
64
|
+
* Strava sends a GET request with hub.challenge to verify the endpoint.
|
|
65
|
+
*/
|
|
66
|
+
export const stravaWebhookVerify = httpAction(async (_ctx, request) => {
|
|
67
|
+
const url = new URL(request.url);
|
|
68
|
+
const mode = url.searchParams.get("hub.mode");
|
|
69
|
+
const challenge = url.searchParams.get("hub.challenge");
|
|
70
|
+
const _verifyToken = url.searchParams.get("hub.verify_token");
|
|
71
|
+
if (mode !== "subscribe" || !challenge) {
|
|
72
|
+
return new Response("Invalid request", { status: 400 });
|
|
73
|
+
}
|
|
74
|
+
// The verify token should match what was set during subscription creation.
|
|
75
|
+
// For now, accept any verify token — the host app should validate this
|
|
76
|
+
// in their configuration.
|
|
77
|
+
return new Response(JSON.stringify({ "hub.challenge": challenge }), {
|
|
78
|
+
status: 200,
|
|
79
|
+
headers: { "Content-Type": "application/json" },
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
// Strava webhook events (POST)
|
|
84
|
+
// ---------------------------------------------------------------------------
|
|
85
|
+
/**
|
|
86
|
+
* Handles incoming Strava webhook events.
|
|
87
|
+
*
|
|
88
|
+
* Strava pushes activity create/update/delete events here.
|
|
89
|
+
* We process activity creates/updates by fetching the full activity
|
|
90
|
+
* and storing it. Deletes are handled by removing the corresponding event.
|
|
91
|
+
*/
|
|
92
|
+
export const stravaWebhookEvent = httpAction(async (_ctx, request) => {
|
|
93
|
+
try {
|
|
94
|
+
const body = await request.json();
|
|
95
|
+
// Strava webhook payload format:
|
|
96
|
+
// { object_type: "activity", object_id: 123, aspect_type: "create"|"update"|"delete",
|
|
97
|
+
// owner_id: 456, subscription_id: 789 }
|
|
98
|
+
const { object_type, object_id, aspect_type, owner_id } = body;
|
|
99
|
+
if (object_type !== "activity") {
|
|
100
|
+
// We only handle activity events for now
|
|
101
|
+
return new Response("OK", { status: 200 });
|
|
102
|
+
}
|
|
103
|
+
const ownerId = String(owner_id);
|
|
104
|
+
const connection = await _ctx.runQuery(internal.connections.getByProviderUser, {
|
|
105
|
+
provider: "strava",
|
|
106
|
+
providerUserId: ownerId,
|
|
107
|
+
});
|
|
108
|
+
if (!connection) {
|
|
109
|
+
return new Response("OK", { status: 200 });
|
|
110
|
+
}
|
|
111
|
+
if (aspect_type === "delete") {
|
|
112
|
+
await _ctx.runMutation(internal.events.deleteByExternalId, {
|
|
113
|
+
externalId: `strava-${object_id}`,
|
|
114
|
+
});
|
|
115
|
+
return new Response("OK", { status: 200 });
|
|
116
|
+
}
|
|
117
|
+
const now = Date.now();
|
|
118
|
+
await _ctx.runMutation(internal.syncWorkflow.requestConnectionSync, {
|
|
119
|
+
connectionId: connection._id,
|
|
120
|
+
mode: "webhook",
|
|
121
|
+
triggerSource: `strava:${aspect_type}:${object_id}`,
|
|
122
|
+
windowStart: now - 30 * 24 * 60 * 60 * 1000,
|
|
123
|
+
windowEnd: now + 5 * 60 * 1000,
|
|
124
|
+
});
|
|
125
|
+
return new Response("OK", { status: 200 });
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return new Response("Internal error", { status: 500 });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
//# sourceMappingURL=httpHandlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"httpHandlers.js","sourceRoot":"","sources":["../../src/component/httpHandlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Delete ALL data for a user across all component tables.
|
|
3
|
+
* Used for GDPR compliance and account deletion.
|
|
4
|
+
*
|
|
5
|
+
* This is a "best-effort" deletion within a single mutation.
|
|
6
|
+
* For users with very large amounts of data, the host app should
|
|
7
|
+
* call this repeatedly or use a workflow.
|
|
8
|
+
*/
|
|
9
|
+
export declare const deleteAllUserData: import("convex/server").RegisteredMutation<"public", {
|
|
10
|
+
userId: string;
|
|
11
|
+
}, Promise<void>>;
|
|
12
|
+
//# sourceMappingURL=lifecycle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/component/lifecycle.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;;iBAwE5B,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { mutation } from "./_generated/server";
|
|
3
|
+
/**
|
|
4
|
+
* Delete ALL data for a user across all component tables.
|
|
5
|
+
* Used for GDPR compliance and account deletion.
|
|
6
|
+
*
|
|
7
|
+
* This is a "best-effort" deletion within a single mutation.
|
|
8
|
+
* For users with very large amounts of data, the host app should
|
|
9
|
+
* call this repeatedly or use a workflow.
|
|
10
|
+
*/
|
|
11
|
+
export const deleteAllUserData = mutation({
|
|
12
|
+
args: { userId: v.string() },
|
|
13
|
+
handler: async (ctx, args) => {
|
|
14
|
+
const { userId } = args;
|
|
15
|
+
// 1. Delete connections
|
|
16
|
+
const connections = await ctx.db
|
|
17
|
+
.query("connections")
|
|
18
|
+
.withIndex("by_user", (idx) => idx.eq("userId", userId))
|
|
19
|
+
.collect();
|
|
20
|
+
for (const conn of connections) {
|
|
21
|
+
// Delete backfill jobs for this connection
|
|
22
|
+
const backfills = await ctx.db
|
|
23
|
+
.query("backfillJobs")
|
|
24
|
+
.withIndex("by_connection", (idx) => idx.eq("connectionId", conn._id))
|
|
25
|
+
.collect();
|
|
26
|
+
for (const bf of backfills) {
|
|
27
|
+
await ctx.db.delete(bf._id);
|
|
28
|
+
}
|
|
29
|
+
await ctx.db.delete(conn._id);
|
|
30
|
+
}
|
|
31
|
+
// 2. Delete data sources and their data points
|
|
32
|
+
const sources = await ctx.db
|
|
33
|
+
.query("dataSources")
|
|
34
|
+
.withIndex("by_user_provider", (idx) => idx.eq("userId", userId))
|
|
35
|
+
.collect();
|
|
36
|
+
for (const source of sources) {
|
|
37
|
+
// Delete data points in batches
|
|
38
|
+
let points = await ctx.db
|
|
39
|
+
.query("dataPoints")
|
|
40
|
+
.withIndex("by_source_type_time", (idx) => idx.eq("dataSourceId", source._id))
|
|
41
|
+
.take(500);
|
|
42
|
+
while (points.length > 0) {
|
|
43
|
+
for (const p of points) {
|
|
44
|
+
await ctx.db.delete(p._id);
|
|
45
|
+
}
|
|
46
|
+
points = await ctx.db
|
|
47
|
+
.query("dataPoints")
|
|
48
|
+
.withIndex("by_source_type_time", (idx) => idx.eq("dataSourceId", source._id))
|
|
49
|
+
.take(500);
|
|
50
|
+
}
|
|
51
|
+
await ctx.db.delete(source._id);
|
|
52
|
+
}
|
|
53
|
+
// 3. Delete events
|
|
54
|
+
const events = await ctx.db
|
|
55
|
+
.query("events")
|
|
56
|
+
.withIndex("by_user_category_time", (idx) => idx.eq("userId", userId))
|
|
57
|
+
.collect();
|
|
58
|
+
for (const event of events) {
|
|
59
|
+
await ctx.db.delete(event._id);
|
|
60
|
+
}
|
|
61
|
+
// 4. Delete daily summaries
|
|
62
|
+
const summaries = await ctx.db
|
|
63
|
+
.query("dailySummaries")
|
|
64
|
+
.withIndex("by_user_date", (idx) => idx.eq("userId", userId))
|
|
65
|
+
.collect();
|
|
66
|
+
for (const summary of summaries) {
|
|
67
|
+
await ctx.db.delete(summary._id);
|
|
68
|
+
}
|
|
69
|
+
// 5. Delete sync jobs
|
|
70
|
+
const jobs = await ctx.db
|
|
71
|
+
.query("syncJobs")
|
|
72
|
+
.withIndex("by_user", (idx) => idx.eq("userId", userId))
|
|
73
|
+
.collect();
|
|
74
|
+
for (const job of jobs) {
|
|
75
|
+
await ctx.db.delete(job._id);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/component/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get menstrual cycle records for a user within a date range.
|
|
3
|
+
*/
|
|
4
|
+
export declare const getByUserDateRange: import("convex/server").RegisteredQuery<"public", {
|
|
5
|
+
userId: string;
|
|
6
|
+
startDate: string;
|
|
7
|
+
endDate: string;
|
|
8
|
+
}, Promise<{
|
|
9
|
+
_id: import("convex/values").GenericId<"menstrualCycles">;
|
|
10
|
+
_creationTime: number;
|
|
11
|
+
externalId?: string | undefined;
|
|
12
|
+
currentPhase?: number | undefined;
|
|
13
|
+
dayInCycle?: number | undefined;
|
|
14
|
+
cycleLength?: number | undefined;
|
|
15
|
+
predictedCycleLength?: number | undefined;
|
|
16
|
+
periodLength?: number | undefined;
|
|
17
|
+
currentPhaseType?: string | undefined;
|
|
18
|
+
lengthOfCurrentPhase?: number | undefined;
|
|
19
|
+
daysUntilNextPhase?: number | undefined;
|
|
20
|
+
isPredictedCycle?: boolean | undefined;
|
|
21
|
+
fertileWindowStart?: number | undefined;
|
|
22
|
+
lengthOfFertileWindow?: number | undefined;
|
|
23
|
+
lastUpdatedAt?: number | undefined;
|
|
24
|
+
isPregnant?: boolean | undefined;
|
|
25
|
+
pregnancyDueDate?: string | undefined;
|
|
26
|
+
pregnancyOriginalDueDate?: string | undefined;
|
|
27
|
+
pregnancyCycleStartDate?: string | undefined;
|
|
28
|
+
pregnancyTitle?: string | undefined;
|
|
29
|
+
numberOfBabies?: string | undefined;
|
|
30
|
+
provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
|
|
31
|
+
userId: string;
|
|
32
|
+
periodStartDate: string;
|
|
33
|
+
}[]>>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the latest menstrual cycle record for a user.
|
|
36
|
+
*/
|
|
37
|
+
export declare const getLatest: import("convex/server").RegisteredQuery<"public", {
|
|
38
|
+
userId: string;
|
|
39
|
+
}, Promise<{
|
|
40
|
+
_id: import("convex/values").GenericId<"menstrualCycles">;
|
|
41
|
+
_creationTime: number;
|
|
42
|
+
externalId?: string | undefined;
|
|
43
|
+
currentPhase?: number | undefined;
|
|
44
|
+
dayInCycle?: number | undefined;
|
|
45
|
+
cycleLength?: number | undefined;
|
|
46
|
+
predictedCycleLength?: number | undefined;
|
|
47
|
+
periodLength?: number | undefined;
|
|
48
|
+
currentPhaseType?: string | undefined;
|
|
49
|
+
lengthOfCurrentPhase?: number | undefined;
|
|
50
|
+
daysUntilNextPhase?: number | undefined;
|
|
51
|
+
isPredictedCycle?: boolean | undefined;
|
|
52
|
+
fertileWindowStart?: number | undefined;
|
|
53
|
+
lengthOfFertileWindow?: number | undefined;
|
|
54
|
+
lastUpdatedAt?: number | undefined;
|
|
55
|
+
isPregnant?: boolean | undefined;
|
|
56
|
+
pregnancyDueDate?: string | undefined;
|
|
57
|
+
pregnancyOriginalDueDate?: string | undefined;
|
|
58
|
+
pregnancyCycleStartDate?: string | undefined;
|
|
59
|
+
pregnancyTitle?: string | undefined;
|
|
60
|
+
numberOfBabies?: string | undefined;
|
|
61
|
+
provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
|
|
62
|
+
userId: string;
|
|
63
|
+
periodStartDate: string;
|
|
64
|
+
} | null>>;
|
|
65
|
+
/**
|
|
66
|
+
* Upsert a menstrual cycle record. Deduplicates by externalId.
|
|
67
|
+
*/
|
|
68
|
+
export declare const upsert: import("convex/server").RegisteredMutation<"internal", {
|
|
69
|
+
externalId?: string | undefined;
|
|
70
|
+
currentPhase?: number | undefined;
|
|
71
|
+
dayInCycle?: number | undefined;
|
|
72
|
+
cycleLength?: number | undefined;
|
|
73
|
+
predictedCycleLength?: number | undefined;
|
|
74
|
+
periodLength?: number | undefined;
|
|
75
|
+
currentPhaseType?: string | undefined;
|
|
76
|
+
lengthOfCurrentPhase?: number | undefined;
|
|
77
|
+
daysUntilNextPhase?: number | undefined;
|
|
78
|
+
isPredictedCycle?: boolean | undefined;
|
|
79
|
+
fertileWindowStart?: number | undefined;
|
|
80
|
+
lengthOfFertileWindow?: number | undefined;
|
|
81
|
+
lastUpdatedAt?: number | undefined;
|
|
82
|
+
isPregnant?: boolean | undefined;
|
|
83
|
+
pregnancyDueDate?: string | undefined;
|
|
84
|
+
pregnancyOriginalDueDate?: string | undefined;
|
|
85
|
+
pregnancyCycleStartDate?: string | undefined;
|
|
86
|
+
pregnancyTitle?: string | undefined;
|
|
87
|
+
numberOfBabies?: string | undefined;
|
|
88
|
+
provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
|
|
89
|
+
userId: string;
|
|
90
|
+
periodStartDate: string;
|
|
91
|
+
}, Promise<import("convex/values").GenericId<"menstrualCycles">>>;
|
|
92
|
+
/**
|
|
93
|
+
* Delete all menstrual cycle data for a user.
|
|
94
|
+
*/
|
|
95
|
+
export declare const deleteByUser: import("convex/server").RegisteredMutation<"internal", {
|
|
96
|
+
userId: string;
|
|
97
|
+
}, Promise<void>>;
|
|
98
|
+
//# sourceMappingURL=menstrualCycles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menstrualCycles.d.ts","sourceRoot":"","sources":["../../src/component/menstrualCycles.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAkB7B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;UAUpB,CAAC;AAMH;;GAEG;AACH,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;iEAsDjB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,YAAY;;iBAWvB,CAAC"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { internalMutation, query } from "./_generated/server";
|
|
3
|
+
import { providerName } from "./schema";
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Queries
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
/**
|
|
8
|
+
* Get menstrual cycle records for a user within a date range.
|
|
9
|
+
*/
|
|
10
|
+
export const getByUserDateRange = query({
|
|
11
|
+
args: {
|
|
12
|
+
userId: v.string(),
|
|
13
|
+
startDate: v.string(), // ISO date "2026-01-01"
|
|
14
|
+
endDate: v.string(),
|
|
15
|
+
},
|
|
16
|
+
returns: v.array(v.any()),
|
|
17
|
+
handler: async (ctx, args) => {
|
|
18
|
+
return await ctx.db
|
|
19
|
+
.query("menstrualCycles")
|
|
20
|
+
.withIndex("by_user_date", (idx) => idx
|
|
21
|
+
.eq("userId", args.userId)
|
|
22
|
+
.gte("periodStartDate", args.startDate)
|
|
23
|
+
.lte("periodStartDate", args.endDate))
|
|
24
|
+
.collect();
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Get the latest menstrual cycle record for a user.
|
|
29
|
+
*/
|
|
30
|
+
export const getLatest = query({
|
|
31
|
+
args: { userId: v.string() },
|
|
32
|
+
returns: v.any(),
|
|
33
|
+
handler: async (ctx, args) => {
|
|
34
|
+
return await ctx.db
|
|
35
|
+
.query("menstrualCycles")
|
|
36
|
+
.withIndex("by_user_date", (idx) => idx.eq("userId", args.userId))
|
|
37
|
+
.order("desc")
|
|
38
|
+
.first();
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Mutations
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
/**
|
|
45
|
+
* Upsert a menstrual cycle record. Deduplicates by externalId.
|
|
46
|
+
*/
|
|
47
|
+
export const upsert = internalMutation({
|
|
48
|
+
args: {
|
|
49
|
+
userId: v.string(),
|
|
50
|
+
provider: providerName,
|
|
51
|
+
externalId: v.optional(v.string()),
|
|
52
|
+
periodStartDate: v.string(),
|
|
53
|
+
dayInCycle: v.optional(v.number()),
|
|
54
|
+
cycleLength: v.optional(v.number()),
|
|
55
|
+
predictedCycleLength: v.optional(v.number()),
|
|
56
|
+
periodLength: v.optional(v.number()),
|
|
57
|
+
currentPhase: v.optional(v.number()),
|
|
58
|
+
currentPhaseType: v.optional(v.string()),
|
|
59
|
+
lengthOfCurrentPhase: v.optional(v.number()),
|
|
60
|
+
daysUntilNextPhase: v.optional(v.number()),
|
|
61
|
+
isPredictedCycle: v.optional(v.boolean()),
|
|
62
|
+
fertileWindowStart: v.optional(v.number()),
|
|
63
|
+
lengthOfFertileWindow: v.optional(v.number()),
|
|
64
|
+
lastUpdatedAt: v.optional(v.number()),
|
|
65
|
+
isPregnant: v.optional(v.boolean()),
|
|
66
|
+
pregnancyDueDate: v.optional(v.string()),
|
|
67
|
+
pregnancyOriginalDueDate: v.optional(v.string()),
|
|
68
|
+
pregnancyCycleStartDate: v.optional(v.string()),
|
|
69
|
+
pregnancyTitle: v.optional(v.string()),
|
|
70
|
+
numberOfBabies: v.optional(v.string()),
|
|
71
|
+
},
|
|
72
|
+
returns: v.id("menstrualCycles"),
|
|
73
|
+
handler: async (ctx, args) => {
|
|
74
|
+
// Dedup by externalId
|
|
75
|
+
if (args.externalId) {
|
|
76
|
+
const existing = await ctx.db
|
|
77
|
+
.query("menstrualCycles")
|
|
78
|
+
.withIndex("by_external_id", (idx) => idx.eq("externalId", args.externalId))
|
|
79
|
+
.first();
|
|
80
|
+
if (existing) {
|
|
81
|
+
await ctx.db.patch(existing._id, args);
|
|
82
|
+
return existing._id;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Dedup by user + periodStartDate
|
|
86
|
+
const existing = await ctx.db
|
|
87
|
+
.query("menstrualCycles")
|
|
88
|
+
.withIndex("by_user_date", (idx) => idx.eq("userId", args.userId).eq("periodStartDate", args.periodStartDate))
|
|
89
|
+
.first();
|
|
90
|
+
if (existing) {
|
|
91
|
+
await ctx.db.patch(existing._id, args);
|
|
92
|
+
return existing._id;
|
|
93
|
+
}
|
|
94
|
+
return await ctx.db.insert("menstrualCycles", args);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* Delete all menstrual cycle data for a user.
|
|
99
|
+
*/
|
|
100
|
+
export const deleteByUser = internalMutation({
|
|
101
|
+
args: { userId: v.string() },
|
|
102
|
+
handler: async (ctx, args) => {
|
|
103
|
+
const records = await ctx.db
|
|
104
|
+
.query("menstrualCycles")
|
|
105
|
+
.withIndex("by_user_provider", (idx) => idx.eq("userId", args.userId))
|
|
106
|
+
.collect();
|
|
107
|
+
for (const r of records) {
|
|
108
|
+
await ctx.db.delete(r._id);
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=menstrualCycles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menstrualCycles.js","sourceRoot":"","sources":["../../src/component/menstrualCycles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAExC,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CAAC;IACtC,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,wBAAwB;QAC/C,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;KACpB;IACD,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;IACzB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,OAAO,MAAM,GAAG,CAAC,EAAE;aAChB,KAAK,CAAC,iBAAiB,CAAC;aACxB,SAAS,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CACjC,GAAG;aACA,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC;aACzB,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,SAAS,CAAC;aACtC,GAAG,CAAC,iBAAiB,EAAE,IAAI,CAAC,OAAO,CAAC,CACxC;aACA,OAAO,EAAE,CAAC;IACf,CAAC;CACF,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,KAAK,CAAC;IAC7B,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;IAC5B,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE;IAChB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,OAAO,MAAM,GAAG,CAAC,EAAE;aAChB,KAAK,CAAC,iBAAiB,CAAC;aACxB,SAAS,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aACjE,KAAK,CAAC,MAAM,CAAC;aACb,KAAK,EAAE,CAAC;IACb,CAAC;CACF,CAAC,CAAC;AAEH,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E;;GAEG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,gBAAgB,CAAC;IACrC,IAAI,EAAE;QACJ,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;QAClB,QAAQ,EAAE,YAAY;QACtB,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAClC,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;QAC3B,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAClC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACnC,oBAAoB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC5C,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACpC,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACpC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACxC,oBAAoB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC5C,kBAAkB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1C,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACzC,kBAAkB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC1C,qBAAqB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC7C,aAAa,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACrC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACnC,gBAAgB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACxC,wBAAwB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChD,uBAAuB,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC/C,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACtC,cAAc,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;KACvC;IACD,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,iBAAiB,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,sBAAsB;QACtB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,EAAE;iBAC1B,KAAK,CAAC,iBAAiB,CAAC;iBACxB,SAAS,CAAC,gBAAgB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;iBAC3E,KAAK,EAAE,CAAC;YACX,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;gBACvC,OAAO,QAAQ,CAAC,GAAG,CAAC;YACtB,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,EAAE;aAC1B,KAAK,CAAC,iBAAiB,CAAC;aACxB,SAAS,CAAC,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CACjC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,iBAAiB,EAAE,IAAI,CAAC,eAAe,CAAC,CAC1E;aACA,KAAK,EAAE,CAAC;QAEX,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACvC,OAAO,QAAQ,CAAC,GAAG,CAAC;QACtB,CAAC;QAED,OAAO,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IACtD,CAAC;CACF,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,gBAAgB,CAAC;IAC3C,IAAI,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;IAC5B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QAC3B,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,EAAE;aACzB,KAAK,CAAC,iBAAiB,CAAC;aACxB,SAAS,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;aACrE,OAAO,EAAE,CAAC;QACb,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth flow Convex actions.
|
|
3
|
+
*
|
|
4
|
+
* Actions (not mutations) because they make external HTTP calls to
|
|
5
|
+
* provider token endpoints and APIs.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Generate an OAuth authorization URL for a provider.
|
|
9
|
+
*
|
|
10
|
+
* Stores the state token in the oauthStates table and returns the URL
|
|
11
|
+
* the client should redirect the user to.
|
|
12
|
+
*/
|
|
13
|
+
export declare const generateAuthUrl: import("convex/server").RegisteredAction<"public", {
|
|
14
|
+
subscriptionKey?: string | undefined;
|
|
15
|
+
provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
|
|
16
|
+
userId: string;
|
|
17
|
+
redirectUri: string;
|
|
18
|
+
clientId: string;
|
|
19
|
+
clientSecret: string;
|
|
20
|
+
}, Promise<string>>;
|
|
21
|
+
/**
|
|
22
|
+
* Handle the OAuth callback. Consumes the state token, exchanges the
|
|
23
|
+
* authorization code for access/refresh tokens, fetches the user's
|
|
24
|
+
* provider profile, and creates/updates the connection.
|
|
25
|
+
*/
|
|
26
|
+
export declare const handleCallback: import("convex/server").RegisteredAction<"public", {
|
|
27
|
+
subscriptionKey?: string | undefined;
|
|
28
|
+
state: string;
|
|
29
|
+
clientId: string;
|
|
30
|
+
clientSecret: string;
|
|
31
|
+
code: string;
|
|
32
|
+
}, Promise<{
|
|
33
|
+
provider: any;
|
|
34
|
+
userId: any;
|
|
35
|
+
connectionId: string;
|
|
36
|
+
}>>;
|
|
37
|
+
/**
|
|
38
|
+
* Ensure a connection has a valid (non-expired) access token.
|
|
39
|
+
* If expired, refreshes the token and updates the connection.
|
|
40
|
+
* Returns the valid access token.
|
|
41
|
+
*/
|
|
42
|
+
export declare const ensureValidToken: import("convex/server").RegisteredAction<"internal", {
|
|
43
|
+
refreshToken?: string | undefined;
|
|
44
|
+
tokenExpiresAt?: number | undefined;
|
|
45
|
+
subscriptionKey?: string | undefined;
|
|
46
|
+
provider: "garmin" | "suunto" | "polar" | "whoop" | "strava" | "apple" | "samsung" | "google";
|
|
47
|
+
accessToken: string;
|
|
48
|
+
connectionId: import("convex/values").GenericId<"connections">;
|
|
49
|
+
clientId: string;
|
|
50
|
+
clientSecret: string;
|
|
51
|
+
}, Promise<string>>;
|
|
52
|
+
//# sourceMappingURL=oauthActions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauthActions.d.ts","sourceRoot":"","sources":["../../src/component/oauthActions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoBH;;;;;GAKG;AACH,eAAO,MAAM,eAAe;;;;;;;mBA4D1B,CAAC;AAMH;;;;GAIG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;GAkGzB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;mBAqD3B,CAAC"}
|