@nativesquare/soma 0.10.0 → 0.10.2
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/dist/client/index.d.ts +85 -163
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +109 -130
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +92 -35
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/garmin/private.d.ts +9 -0
- package/dist/component/garmin/private.d.ts.map +1 -1
- package/dist/component/garmin/private.js +49 -0
- package/dist/component/garmin/private.js.map +1 -1
- package/dist/component/garmin/public.d.ts +237 -62
- package/dist/component/garmin/public.d.ts.map +1 -1
- package/dist/component/garmin/public.js +683 -253
- package/dist/component/garmin/public.js.map +1 -1
- package/dist/component/garmin/utils.d.ts +8 -0
- package/dist/component/garmin/utils.d.ts.map +1 -1
- package/dist/component/garmin/utils.js +9 -0
- package/dist/component/garmin/utils.js.map +1 -1
- package/dist/component/strava/public.d.ts +12 -52
- package/dist/component/strava/public.d.ts.map +1 -1
- package/dist/component/strava/public.js +16 -92
- package/dist/component/strava/public.js.map +1 -1
- package/dist/component/strava/transform/activity.js +15 -9
- package/dist/component/strava/transform/activity.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +210 -158
- package/src/component/_generated/component.ts +165 -31
- package/src/component/garmin/private.ts +84 -0
- package/src/component/garmin/public.ts +804 -347
- package/src/component/garmin/utils.ts +17 -0
- package/src/component/strava/public.ts +17 -123
package/src/client/index.ts
CHANGED
|
@@ -75,8 +75,11 @@ export interface SomaGarminConfig {
|
|
|
75
75
|
* provider: "GARMIN",
|
|
76
76
|
* });
|
|
77
77
|
*
|
|
78
|
-
* //
|
|
79
|
-
* const
|
|
78
|
+
* // Start Strava OAuth (redirects user, callback handled by registerRoutes):
|
|
79
|
+
* const { authUrl } = await soma.getStravaAuthUrl(ctx, {
|
|
80
|
+
* userId: "user_123",
|
|
81
|
+
* redirectUri: "https://your-app.convex.site/api/strava/callback",
|
|
82
|
+
* });
|
|
80
83
|
* ```
|
|
81
84
|
*/
|
|
82
85
|
export class Soma {
|
|
@@ -879,18 +882,14 @@ export class Soma {
|
|
|
879
882
|
/**
|
|
880
883
|
* Generate a Strava OAuth authorization URL.
|
|
881
884
|
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
* intervention. This is the recommended approach.
|
|
886
|
-
*
|
|
887
|
-
* If `userId` is omitted, the host app must store the returned `state`
|
|
888
|
-
* itself and handle the callback via `connectStrava`.
|
|
885
|
+
* The state parameter is stored inside the component automatically,
|
|
886
|
+
* and the callback handler registered by `registerRoutes` will
|
|
887
|
+
* complete the flow without further host-app intervention.
|
|
889
888
|
*
|
|
890
889
|
* @param ctx - Action context from the host app
|
|
890
|
+
* @param opts.userId - The host app's user identifier
|
|
891
891
|
* @param opts.redirectUri - The URL Strava will redirect to after authorization
|
|
892
892
|
* @param opts.scope - Comma-separated Strava OAuth scopes (default: "read,activity:read_all,profile:read_all")
|
|
893
|
-
* @param opts.userId - The host app's user identifier (required for `registerRoutes` flow)
|
|
894
893
|
* @returns `{ authUrl, state }`
|
|
895
894
|
*
|
|
896
895
|
* @example
|
|
@@ -904,7 +903,7 @@ export class Soma {
|
|
|
904
903
|
*/
|
|
905
904
|
async getStravaAuthUrl(
|
|
906
905
|
ctx: ActionCtx,
|
|
907
|
-
opts: {
|
|
906
|
+
opts: { userId: string; redirectUri: string; scope?: string },
|
|
908
907
|
) {
|
|
909
908
|
const config = this.requireStravaConfig();
|
|
910
909
|
return await ctx.runAction(this.component.strava.public.getStravaAuthUrl, {
|
|
@@ -915,69 +914,6 @@ export class Soma {
|
|
|
915
914
|
});
|
|
916
915
|
}
|
|
917
916
|
|
|
918
|
-
/**
|
|
919
|
-
* Handle the Strava OAuth callback.
|
|
920
|
-
*
|
|
921
|
-
* Exchanges the authorization code for tokens, creates/reactivates the
|
|
922
|
-
* Soma connection, stores tokens securely in the component, syncs the
|
|
923
|
-
* athlete profile, and syncs all activities.
|
|
924
|
-
*
|
|
925
|
-
* Call this from your OAuth callback endpoint after receiving the `code`
|
|
926
|
-
* query parameter from Strava.
|
|
927
|
-
*
|
|
928
|
-
* @param ctx - Action context from the host app
|
|
929
|
-
* @param args.userId - The host app's user identifier
|
|
930
|
-
* @param args.code - The authorization code from the OAuth callback
|
|
931
|
-
* @returns `{ connectionId, synced, errors }`
|
|
932
|
-
*
|
|
933
|
-
* @example
|
|
934
|
-
* ```ts
|
|
935
|
-
* export const handleStravaCallback = action({
|
|
936
|
-
* args: { userId: v.string(), code: v.string() },
|
|
937
|
-
* handler: async (ctx, { userId, code }) => {
|
|
938
|
-
* return await soma.connectStrava(ctx, { userId, code });
|
|
939
|
-
* },
|
|
940
|
-
* });
|
|
941
|
-
* ```
|
|
942
|
-
*/
|
|
943
|
-
async connectStrava(
|
|
944
|
-
ctx: ActionCtx,
|
|
945
|
-
args: { userId: string; code: string },
|
|
946
|
-
) {
|
|
947
|
-
const config = this.requireStravaConfig();
|
|
948
|
-
return await ctx.runAction(this.component.strava.public.connectStrava, {
|
|
949
|
-
...args,
|
|
950
|
-
clientId: config.clientId,
|
|
951
|
-
clientSecret: config.clientSecret,
|
|
952
|
-
});
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
/**
|
|
956
|
-
* Complete a Strava OAuth flow using stored pending state.
|
|
957
|
-
*
|
|
958
|
-
* This is called automatically by the `registerRoutes` callback handler.
|
|
959
|
-
* It looks up the pending OAuth state stored during `getStravaAuthUrl`,
|
|
960
|
-
* exchanges for tokens, creates the connection, and syncs data.
|
|
961
|
-
*
|
|
962
|
-
* @param ctx - Action context from the host app
|
|
963
|
-
* @param args.code - The authorization code from the callback query params
|
|
964
|
-
* @param args.state - The state parameter from the callback query params
|
|
965
|
-
* @returns `{ connectionId, userId, synced, errors }`
|
|
966
|
-
*/
|
|
967
|
-
async completeStravaOAuth(
|
|
968
|
-
ctx: ActionCtx,
|
|
969
|
-
args: { code: string; state: string },
|
|
970
|
-
) {
|
|
971
|
-
const config = this.requireStravaConfig();
|
|
972
|
-
return await ctx.runAction(
|
|
973
|
-
this.component.strava.public.completeStravaOAuth,
|
|
974
|
-
{
|
|
975
|
-
...args,
|
|
976
|
-
clientId: config.clientId,
|
|
977
|
-
clientSecret: config.clientSecret,
|
|
978
|
-
},
|
|
979
|
-
);
|
|
980
|
-
}
|
|
981
917
|
|
|
982
918
|
/**
|
|
983
919
|
* Sync activities from Strava for an already-connected user.
|
|
@@ -1051,20 +987,13 @@ export class Soma {
|
|
|
1051
987
|
/**
|
|
1052
988
|
* Generate a Garmin OAuth 2.0 authorization URL with PKCE.
|
|
1053
989
|
*
|
|
1054
|
-
*
|
|
1055
|
-
* and
|
|
1056
|
-
*
|
|
1057
|
-
* If `userId` is provided, the PKCE state is stored inside the component
|
|
1058
|
-
* automatically, and the callback handler registered by `registerRoutes`
|
|
1059
|
-
* will complete the flow without further host-app intervention. This is
|
|
1060
|
-
* the recommended approach.
|
|
1061
|
-
*
|
|
1062
|
-
* If `userId` is omitted, the host app must store the returned
|
|
1063
|
-
* `codeVerifier` itself and pass it to `connectGarmin` manually.
|
|
990
|
+
* The PKCE state is stored inside the component automatically,
|
|
991
|
+
* and the callback handler registered by `registerRoutes` will
|
|
992
|
+
* complete the flow without further host-app intervention.
|
|
1064
993
|
*
|
|
1065
994
|
* @param ctx - Action context from the host app
|
|
995
|
+
* @param opts.userId - The host app's user identifier
|
|
1066
996
|
* @param opts.redirectUri - The URL Garmin will redirect to after authorization
|
|
1067
|
-
* @param opts.userId - The host app's user identifier (required for `registerRoutes` flow)
|
|
1068
997
|
* @returns `{ authUrl, state, codeVerifier }`
|
|
1069
998
|
*
|
|
1070
999
|
* @example
|
|
@@ -1078,7 +1007,7 @@ export class Soma {
|
|
|
1078
1007
|
*/
|
|
1079
1008
|
async getGarminAuthUrl(
|
|
1080
1009
|
ctx: ActionCtx,
|
|
1081
|
-
opts: {
|
|
1010
|
+
opts: { userId: string; redirectUri?: string },
|
|
1082
1011
|
) {
|
|
1083
1012
|
const config = this.requireGarminConfig();
|
|
1084
1013
|
return await ctx.runAction(this.component.garmin.public.getGarminAuthUrl, {
|
|
@@ -1088,73 +1017,208 @@ export class Soma {
|
|
|
1088
1017
|
});
|
|
1089
1018
|
}
|
|
1090
1019
|
|
|
1091
|
-
|
|
1092
|
-
* Handle the Garmin OAuth 2.0 callback (manual flow).
|
|
1093
|
-
*
|
|
1094
|
-
* Exchanges the authorization code for tokens, creates/reactivates the
|
|
1095
|
-
* Soma connection, stores tokens securely, and syncs the last 30 days
|
|
1096
|
-
* of all data types.
|
|
1097
|
-
*
|
|
1098
|
-
* Call this from your OAuth callback endpoint after receiving the `code`
|
|
1099
|
-
* query parameter from Garmin.
|
|
1100
|
-
*
|
|
1101
|
-
* @param ctx - Action context from the host app
|
|
1102
|
-
* @param args.userId - The host app's user identifier
|
|
1103
|
-
* @param args.code - The authorization code from the callback
|
|
1104
|
-
* @param args.codeVerifier - The PKCE code verifier from Step 1
|
|
1105
|
-
* @param args.redirectUri - The redirect URI used in the authorization request
|
|
1106
|
-
* @returns `{ connectionId, synced, errors }`
|
|
1107
|
-
*
|
|
1108
|
-
* @example
|
|
1109
|
-
* ```ts
|
|
1110
|
-
* export const handleGarminCallback = action({
|
|
1111
|
-
* args: {
|
|
1112
|
-
* userId: v.string(),
|
|
1113
|
-
* code: v.string(),
|
|
1114
|
-
* codeVerifier: v.string(),
|
|
1115
|
-
* },
|
|
1116
|
-
* handler: async (ctx, args) => {
|
|
1117
|
-
* return await soma.connectGarmin(ctx, args);
|
|
1118
|
-
* },
|
|
1119
|
-
* });
|
|
1120
|
-
* ```
|
|
1121
|
-
*/
|
|
1122
|
-
async connectGarmin(
|
|
1020
|
+
async pullGarminActivities(
|
|
1123
1021
|
ctx: ActionCtx,
|
|
1124
1022
|
args: {
|
|
1125
1023
|
userId: string;
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
redirectUri?: string;
|
|
1024
|
+
startTimeInSeconds?: number;
|
|
1025
|
+
endTimeInSeconds?: number;
|
|
1129
1026
|
},
|
|
1130
1027
|
) {
|
|
1131
1028
|
const config = this.requireGarminConfig();
|
|
1132
|
-
return await ctx.runAction(this.component.garmin.public.
|
|
1029
|
+
return await ctx.runAction(this.component.garmin.public.pullActivities, {
|
|
1133
1030
|
...args,
|
|
1134
1031
|
clientId: config.clientId,
|
|
1135
1032
|
clientSecret: config.clientSecret,
|
|
1136
1033
|
});
|
|
1137
1034
|
}
|
|
1138
1035
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1036
|
+
async pullGarminDailies(
|
|
1037
|
+
ctx: ActionCtx,
|
|
1038
|
+
args: {
|
|
1039
|
+
userId: string;
|
|
1040
|
+
startTimeInSeconds?: number;
|
|
1041
|
+
endTimeInSeconds?: number;
|
|
1042
|
+
},
|
|
1043
|
+
) {
|
|
1044
|
+
const config = this.requireGarminConfig();
|
|
1045
|
+
return await ctx.runAction(this.component.garmin.public.pullDailies, {
|
|
1046
|
+
...args,
|
|
1047
|
+
clientId: config.clientId,
|
|
1048
|
+
clientSecret: config.clientSecret,
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
async pullGarminSleep(
|
|
1153
1053
|
ctx: ActionCtx,
|
|
1154
|
-
args: {
|
|
1054
|
+
args: {
|
|
1055
|
+
userId: string;
|
|
1056
|
+
startTimeInSeconds?: number;
|
|
1057
|
+
endTimeInSeconds?: number;
|
|
1058
|
+
},
|
|
1155
1059
|
) {
|
|
1156
1060
|
const config = this.requireGarminConfig();
|
|
1157
|
-
return await ctx.runAction(this.component.garmin.public.
|
|
1061
|
+
return await ctx.runAction(this.component.garmin.public.pullSleep, {
|
|
1062
|
+
...args,
|
|
1063
|
+
clientId: config.clientId,
|
|
1064
|
+
clientSecret: config.clientSecret,
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
async pullGarminBody(
|
|
1069
|
+
ctx: ActionCtx,
|
|
1070
|
+
args: {
|
|
1071
|
+
userId: string;
|
|
1072
|
+
startTimeInSeconds?: number;
|
|
1073
|
+
endTimeInSeconds?: number;
|
|
1074
|
+
},
|
|
1075
|
+
) {
|
|
1076
|
+
const config = this.requireGarminConfig();
|
|
1077
|
+
return await ctx.runAction(this.component.garmin.public.pullBody, {
|
|
1078
|
+
...args,
|
|
1079
|
+
clientId: config.clientId,
|
|
1080
|
+
clientSecret: config.clientSecret,
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
async pullGarminMenstruation(
|
|
1085
|
+
ctx: ActionCtx,
|
|
1086
|
+
args: {
|
|
1087
|
+
userId: string;
|
|
1088
|
+
startTimeInSeconds?: number;
|
|
1089
|
+
endTimeInSeconds?: number;
|
|
1090
|
+
},
|
|
1091
|
+
) {
|
|
1092
|
+
const config = this.requireGarminConfig();
|
|
1093
|
+
return await ctx.runAction(this.component.garmin.public.pullMenstruation, {
|
|
1094
|
+
...args,
|
|
1095
|
+
clientId: config.clientId,
|
|
1096
|
+
clientSecret: config.clientSecret,
|
|
1097
|
+
});
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
async pullGarminBloodPressures(
|
|
1101
|
+
ctx: ActionCtx,
|
|
1102
|
+
args: {
|
|
1103
|
+
userId: string;
|
|
1104
|
+
startTimeInSeconds?: number;
|
|
1105
|
+
endTimeInSeconds?: number;
|
|
1106
|
+
},
|
|
1107
|
+
) {
|
|
1108
|
+
const config = this.requireGarminConfig();
|
|
1109
|
+
return await ctx.runAction(this.component.garmin.public.pullBloodPressures, {
|
|
1110
|
+
...args,
|
|
1111
|
+
clientId: config.clientId,
|
|
1112
|
+
clientSecret: config.clientSecret,
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
async pullGarminSkinTemperature(
|
|
1117
|
+
ctx: ActionCtx,
|
|
1118
|
+
args: {
|
|
1119
|
+
userId: string;
|
|
1120
|
+
startTimeInSeconds?: number;
|
|
1121
|
+
endTimeInSeconds?: number;
|
|
1122
|
+
},
|
|
1123
|
+
) {
|
|
1124
|
+
const config = this.requireGarminConfig();
|
|
1125
|
+
return await ctx.runAction(this.component.garmin.public.pullSkinTemperature, {
|
|
1126
|
+
...args,
|
|
1127
|
+
clientId: config.clientId,
|
|
1128
|
+
clientSecret: config.clientSecret,
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
async pullGarminUserMetrics(
|
|
1133
|
+
ctx: ActionCtx,
|
|
1134
|
+
args: {
|
|
1135
|
+
userId: string;
|
|
1136
|
+
startTimeInSeconds?: number;
|
|
1137
|
+
endTimeInSeconds?: number;
|
|
1138
|
+
},
|
|
1139
|
+
) {
|
|
1140
|
+
const config = this.requireGarminConfig();
|
|
1141
|
+
return await ctx.runAction(this.component.garmin.public.pullUserMetrics, {
|
|
1142
|
+
...args,
|
|
1143
|
+
clientId: config.clientId,
|
|
1144
|
+
clientSecret: config.clientSecret,
|
|
1145
|
+
});
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
async pullGarminHRV(
|
|
1149
|
+
ctx: ActionCtx,
|
|
1150
|
+
args: {
|
|
1151
|
+
userId: string;
|
|
1152
|
+
startTimeInSeconds?: number;
|
|
1153
|
+
endTimeInSeconds?: number;
|
|
1154
|
+
},
|
|
1155
|
+
) {
|
|
1156
|
+
const config = this.requireGarminConfig();
|
|
1157
|
+
return await ctx.runAction(this.component.garmin.public.pullHRV, {
|
|
1158
|
+
...args,
|
|
1159
|
+
clientId: config.clientId,
|
|
1160
|
+
clientSecret: config.clientSecret,
|
|
1161
|
+
});
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
async pullGarminStressDetails(
|
|
1165
|
+
ctx: ActionCtx,
|
|
1166
|
+
args: {
|
|
1167
|
+
userId: string;
|
|
1168
|
+
startTimeInSeconds?: number;
|
|
1169
|
+
endTimeInSeconds?: number;
|
|
1170
|
+
},
|
|
1171
|
+
) {
|
|
1172
|
+
const config = this.requireGarminConfig();
|
|
1173
|
+
return await ctx.runAction(this.component.garmin.public.pullStressDetails, {
|
|
1174
|
+
...args,
|
|
1175
|
+
clientId: config.clientId,
|
|
1176
|
+
clientSecret: config.clientSecret,
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
async pullGarminPulseOx(
|
|
1181
|
+
ctx: ActionCtx,
|
|
1182
|
+
args: {
|
|
1183
|
+
userId: string;
|
|
1184
|
+
startTimeInSeconds?: number;
|
|
1185
|
+
endTimeInSeconds?: number;
|
|
1186
|
+
},
|
|
1187
|
+
) {
|
|
1188
|
+
const config = this.requireGarminConfig();
|
|
1189
|
+
return await ctx.runAction(this.component.garmin.public.pullPulseOx, {
|
|
1190
|
+
...args,
|
|
1191
|
+
clientId: config.clientId,
|
|
1192
|
+
clientSecret: config.clientSecret,
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
async pullGarminRespiration(
|
|
1197
|
+
ctx: ActionCtx,
|
|
1198
|
+
args: {
|
|
1199
|
+
userId: string;
|
|
1200
|
+
startTimeInSeconds?: number;
|
|
1201
|
+
endTimeInSeconds?: number;
|
|
1202
|
+
},
|
|
1203
|
+
) {
|
|
1204
|
+
const config = this.requireGarminConfig();
|
|
1205
|
+
return await ctx.runAction(this.component.garmin.public.pullRespiration, {
|
|
1206
|
+
...args,
|
|
1207
|
+
clientId: config.clientId,
|
|
1208
|
+
clientSecret: config.clientSecret,
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
async pullGarminAll(
|
|
1213
|
+
ctx: ActionCtx,
|
|
1214
|
+
args: {
|
|
1215
|
+
userId: string;
|
|
1216
|
+
startTimeInSeconds?: number;
|
|
1217
|
+
endTimeInSeconds?: number;
|
|
1218
|
+
},
|
|
1219
|
+
) {
|
|
1220
|
+
const config = this.requireGarminConfig();
|
|
1221
|
+
return await ctx.runAction(this.component.garmin.public.pullAll, {
|
|
1158
1222
|
...args,
|
|
1159
1223
|
clientId: config.clientId,
|
|
1160
1224
|
clientSecret: config.clientSecret,
|
|
@@ -1282,7 +1346,7 @@ export interface StravaOAuthOptions {
|
|
|
1282
1346
|
clientSecret?: string;
|
|
1283
1347
|
/** URL to redirect the user to after a successful connection. */
|
|
1284
1348
|
redirectTo?: string;
|
|
1285
|
-
/** Called after Strava OAuth completes and
|
|
1349
|
+
/** Called after Strava OAuth completes and the connection is established. */
|
|
1286
1350
|
onComplete?: (
|
|
1287
1351
|
ctx: GenericActionCtx<GenericDataModel>,
|
|
1288
1352
|
event: StravaConnectEvent,
|
|
@@ -1291,24 +1355,20 @@ export interface StravaOAuthOptions {
|
|
|
1291
1355
|
|
|
1292
1356
|
// ─── Strava Callback Event Types ────────────────────────────────────────────
|
|
1293
1357
|
|
|
1294
|
-
/** Data passed to `onComplete` after Strava OAuth
|
|
1358
|
+
/** Data passed to `onComplete` after Strava OAuth completes. */
|
|
1295
1359
|
export interface StravaConnectEvent {
|
|
1296
1360
|
provider: "STRAVA";
|
|
1297
1361
|
userId: string;
|
|
1298
1362
|
connectionId: string;
|
|
1299
|
-
synced: Record<string, number>;
|
|
1300
|
-
errors: Array<{ type: string; id: string; error: string }>;
|
|
1301
1363
|
}
|
|
1302
1364
|
|
|
1303
1365
|
// ─── Garmin Callback Event Types ─────────────────────────────────────────────
|
|
1304
1366
|
|
|
1305
|
-
/** Data passed to `oauth.onComplete` after Garmin OAuth
|
|
1367
|
+
/** Data passed to `oauth.onComplete` after Garmin OAuth completes. */
|
|
1306
1368
|
export interface GarminConnectEvent {
|
|
1307
1369
|
provider: "GARMIN";
|
|
1308
1370
|
userId: string;
|
|
1309
1371
|
connectionId: string;
|
|
1310
|
-
synced: Record<string, number>;
|
|
1311
|
-
errors: Array<{ type: string; id: string; error: string }>;
|
|
1312
1372
|
}
|
|
1313
1373
|
|
|
1314
1374
|
/** Data passed to webhook `events` handlers and `onEvent` after data ingestion. */
|
|
@@ -1331,7 +1391,7 @@ export interface GarminOAuthOptions {
|
|
|
1331
1391
|
clientSecret?: string;
|
|
1332
1392
|
/** URL to redirect the user to after a successful connection. */
|
|
1333
1393
|
redirectTo?: string;
|
|
1334
|
-
/** Called after Garmin OAuth completes and
|
|
1394
|
+
/** Called after Garmin OAuth completes and the connection is established. */
|
|
1335
1395
|
onComplete?: (
|
|
1336
1396
|
ctx: GenericActionCtx<GenericDataModel>,
|
|
1337
1397
|
event: GarminConnectEvent,
|
|
@@ -1378,8 +1438,8 @@ export interface RegisterRoutesOptions {
|
|
|
1378
1438
|
*
|
|
1379
1439
|
* Call this from your `convex/http.ts` to set up the callback endpoints
|
|
1380
1440
|
* that Strava and Garmin redirect to after user authorization. The handlers
|
|
1381
|
-
* complete the OAuth exchange, create the connection, and
|
|
1382
|
-
*
|
|
1441
|
+
* complete the OAuth exchange, create the connection, and store tokens.
|
|
1442
|
+
* The host app is responsible for calling sync separately.
|
|
1383
1443
|
*
|
|
1384
1444
|
* When called with no `opts`, registers both Strava and Garmin routes with
|
|
1385
1445
|
* default paths and credentials from environment variables. When `opts` is
|
|
@@ -1410,7 +1470,7 @@ export interface RegisterRoutesOptions {
|
|
|
1410
1470
|
* path: "/oauth/strava/callback",
|
|
1411
1471
|
* redirectTo: "https://myapp.com/settings",
|
|
1412
1472
|
* onComplete: async (ctx, event) => {
|
|
1413
|
-
* // Runs after OAuth
|
|
1473
|
+
* // Runs after OAuth completes and connection is established
|
|
1414
1474
|
* await ctx.runMutation(internal.users.markConnected, {
|
|
1415
1475
|
* userId: event.userId,
|
|
1416
1476
|
* provider: event.provider,
|
|
@@ -1422,7 +1482,7 @@ export interface RegisterRoutesOptions {
|
|
|
1422
1482
|
* oauth: {
|
|
1423
1483
|
* redirectTo: "https://myapp.com/settings",
|
|
1424
1484
|
* onComplete: async (ctx, event) => {
|
|
1425
|
-
* // Runs after OAuth
|
|
1485
|
+
* // Runs after OAuth completes and connection is established
|
|
1426
1486
|
* await ctx.runMutation(internal.users.markConnected, {
|
|
1427
1487
|
* userId: event.userId,
|
|
1428
1488
|
* provider: event.provider,
|
|
@@ -1491,8 +1551,6 @@ export function registerRoutes(
|
|
|
1491
1551
|
let result: {
|
|
1492
1552
|
connectionId: string;
|
|
1493
1553
|
userId: string;
|
|
1494
|
-
synced: Record<string, number>;
|
|
1495
|
-
errors: Array<{ type: string; id: string; error: string }>;
|
|
1496
1554
|
};
|
|
1497
1555
|
try {
|
|
1498
1556
|
result = await ctx.runAction(component.strava.public.completeStravaOAuth, {
|
|
@@ -1515,8 +1573,6 @@ export function registerRoutes(
|
|
|
1515
1573
|
provider: "STRAVA",
|
|
1516
1574
|
userId: result.userId,
|
|
1517
1575
|
connectionId: result.connectionId,
|
|
1518
|
-
synced: result.synced,
|
|
1519
|
-
errors: result.errors,
|
|
1520
1576
|
});
|
|
1521
1577
|
} catch (callbackError) {
|
|
1522
1578
|
console.error(
|
|
@@ -1582,8 +1638,6 @@ export function registerRoutes(
|
|
|
1582
1638
|
let result: {
|
|
1583
1639
|
connectionId: string;
|
|
1584
1640
|
userId: string;
|
|
1585
|
-
synced: Record<string, number>;
|
|
1586
|
-
errors: Array<{ type: string; id: string; error: string }>;
|
|
1587
1641
|
};
|
|
1588
1642
|
try {
|
|
1589
1643
|
result = await ctx.runAction(component.garmin.public.completeGarminOAuth, {
|
|
@@ -1606,8 +1660,6 @@ export function registerRoutes(
|
|
|
1606
1660
|
provider: "GARMIN",
|
|
1607
1661
|
userId: result.userId,
|
|
1608
1662
|
connectionId: result.connectionId,
|
|
1609
|
-
synced: result.synced,
|
|
1610
|
-
errors: result.errors,
|
|
1611
1663
|
});
|
|
1612
1664
|
} catch (callbackError) {
|
|
1613
1665
|
console.error(
|