@fytkit/sdk 3.1.0 → 3.3.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/CHANGELOG.md +22 -0
- package/README.md +16 -3
- package/dist/index.d.ts +269 -28
- package/dist/index.js +77 -19
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to `@fytkit/sdk` are documented in this file.
|
|
|
4
4
|
Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/).
|
|
5
5
|
Versioning: [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.3.0](https://github.com/cbarlow1993/fytkit-web/compare/@fytkit/sdk@3.2.0...@fytkit/sdk@3.3.0) (2026-10-01)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **public-api:** list/search/filter exercises; open the workout, exercise and program catalogues ([#407](https://github.com/cbarlow1993/fytkit-web/issues/407)) ([c1bb93f](https://github.com/cbarlow1993/fytkit-web/commit/c1bb93f44e5773ea15cb7b4300d003ee4f531323))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Bug Fixes
|
|
16
|
+
|
|
17
|
+
* public API and SDK fixes from the Fitness with Rachael pre-production review ([#442](https://github.com/cbarlow1993/fytkit-web/issues/442)) ([49e8038](https://github.com/cbarlow1993/fytkit-web/commit/49e80381f4717cf40d14ab0079b9bf2ce22d4f26))
|
|
18
|
+
|
|
19
|
+
## [3.2.0](https://github.com/cbarlow1993/fytkit-web/compare/@fytkit/sdk@3.1.0...@fytkit/sdk@3.2.0) (2026-09-05)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* **api:** return real workout counts per category from browse ([#189](https://github.com/cbarlow1993/fytkit-web/issues/189)) ([2520f3f](https://github.com/cbarlow1993/fytkit-web/commit/2520f3f80df0e1e5cbeca29919c065400c011c07))
|
|
25
|
+
* **content:** trainer-authored locations for workouts and programs ([#311](https://github.com/cbarlow1993/fytkit-web/issues/311)) ([f410b4d](https://github.com/cbarlow1993/fytkit-web/commit/f410b4d8e1020c110d3ed34b9b95342412e30337))
|
|
26
|
+
* equipment filtering for workouts & programs ([#229](https://github.com/cbarlow1993/fytkit-web/issues/229)) ([7d9267d](https://github.com/cbarlow1993/fytkit-web/commit/7d9267d8b0e326a78ad02e650bd0a10eea3f8987))
|
|
27
|
+
* **workouts:** select and filter by multiple muscle groups ([#200](https://github.com/cbarlow1993/fytkit-web/issues/200)) ([0ee04fd](https://github.com/cbarlow1993/fytkit-web/commit/0ee04fd962f8e039b61feb386461e691d3aefe6f))
|
|
28
|
+
|
|
7
29
|
## [3.1.0](https://github.com/cbarlow1993/fytkit-web/compare/@fytkit/sdk@3.0.0...@fytkit/sdk@3.1.0) (2026-08-14)
|
|
8
30
|
|
|
9
31
|
|
package/README.md
CHANGED
|
@@ -128,8 +128,21 @@ await fytkit.auth.changeEmail({ newEmail });
|
|
|
128
128
|
const sessions = await fytkit.auth.listSessions();
|
|
129
129
|
await fytkit.auth.revokeSession({ revokeId: sessions.find((s) => !s.isCurrent)!.revokeId });
|
|
130
130
|
await fytkit.auth.revokeOtherSessions(); // "sign out of all other devices"
|
|
131
|
+
|
|
132
|
+
// Permanently close the account (re-verifies email + password). On success the
|
|
133
|
+
// SDK clears the session and emits signed_out.
|
|
134
|
+
await fytkit.auth.closeAccount({ confirmEmail, password });
|
|
131
135
|
```
|
|
132
136
|
|
|
137
|
+
A wrong password or one-time code is a `{ kind: "server", status: 400 }` error
|
|
138
|
+
with `code: "invalid_password"` / `"invalid_code"`; a change that needs a
|
|
139
|
+
fresh sign-in is `{ kind: "forbidden", code: "reauth_required" }`. None of
|
|
140
|
+
these sign the trainee out — only a 401 on an authenticated call means the
|
|
141
|
+
session is gone. A wrong password on `signIn` (for example, signing in again
|
|
142
|
+
after `reauth_required`) is a plain `auth_required` and leaves the current
|
|
143
|
+
session alone. Enrolling twice in a program is `{ kind: "conflict" }` with the
|
|
144
|
+
existing `enrollmentId`.
|
|
145
|
+
|
|
133
146
|
## Notification preferences
|
|
134
147
|
|
|
135
148
|
Per-member toggles stored server-side (defaults apply until first write):
|
|
@@ -144,17 +157,17 @@ await fytkit.preferences.updateNotifications({ streakAlerts: false }); // partia
|
|
|
144
157
|
- `auth.signUp` / `signIn` / `signOut` / `getSession` / `onAuthStateChange`
|
|
145
158
|
- `auth.requestPasswordReset` / `confirmPasswordReset` / `confirmEmail`
|
|
146
159
|
- Two-factor: `auth.verifyTotp` / `verifyBackupCode` / `requestEmailOtp` / `verifyEmailOtp` (sign-in), `enableTotp` / `verifyTotpSetup` / `disableTwoFactor` / `regenerateBackupCodes` / `getSecurityStatus` (management)
|
|
147
|
-
- Account security: `auth.changePassword` / `changeEmail` / `listSessions` / `revokeSession` / `revokeOtherSessions`
|
|
160
|
+
- Account security: `auth.changePassword` / `changeEmail` / `listSessions` / `revokeSession` / `revokeOtherSessions` / `closeAccount`
|
|
148
161
|
- Data namespaces: `workouts`, `programs`, `recipes`, `nutrition`, `nutritionLog`, `profile`, `preferences`, `articles`, `enrollments`, `sessionLogs`, `progression`, `progress`, `bodyMetrics`, `media`, `appConfig`, `subscription`
|
|
149
162
|
- Workout tracking: program session logs and ad-hoc workout logs (`sessionLogs.create` with `workoutId`), set logging, per-workout history (`sessionLogs.list({ workoutId })`)
|
|
150
163
|
- Progress: `progress.getSummary` / `getAdherence` / `getStreak` (stored streaks), `progression.getPrSummary` / `listPrHistory` (stored PR history) / `getHistory`, `bodyMetrics.list` / `record` / `delete`
|
|
151
164
|
- Automatic header injection (`X-Fytkit-Client-Id`, `Authorization: Bearer …`)
|
|
152
|
-
- Proactive refresh ~60 s before token expiry + reactive 401 retry
|
|
165
|
+
- Proactive refresh ~60 s before token expiry (retried with backoff when offline) + reactive 401 retry; only a server-rejected refresh signs out
|
|
153
166
|
- Pluggable token storage (`localStorage` default, in-memory + cookie for SSR)
|
|
154
167
|
|
|
155
168
|
## Storage trade-off
|
|
156
169
|
|
|
157
|
-
Access tokens land in `localStorage` by default, namespaced by `clientId`. Any script running on your origin can read them — ship a strict CSP and treat the SDK like any other auth-bearing dependency.
|
|
170
|
+
Access tokens land in `localStorage` by default, namespaced by `clientId`. Any script running on your origin can read them — ship a strict CSP and treat the SDK like any other auth-bearing dependency. A token is a server session that lasts up to 7 days; signing out, closing the account or revoking the developer app ends it server-side.
|
|
158
171
|
|
|
159
172
|
Use `createMemoryStorageAdapter()` for SSR + tests.
|
|
160
173
|
|
package/dist/index.d.ts
CHANGED
|
@@ -17,8 +17,10 @@ import { ZodNullable } from 'zod';
|
|
|
17
17
|
import { ZodNumber } from 'zod';
|
|
18
18
|
import { ZodObject } from 'zod';
|
|
19
19
|
import { ZodOptional } from 'zod';
|
|
20
|
+
import { ZodPipe } from 'zod';
|
|
20
21
|
import { ZodReadonly } from 'zod';
|
|
21
22
|
import { ZodString } from 'zod';
|
|
23
|
+
import { ZodTransform } from 'zod';
|
|
22
24
|
import { ZodUnion } from 'zod';
|
|
23
25
|
|
|
24
26
|
declare interface ApiKeyContext {
|
|
@@ -149,11 +151,21 @@ export declare interface FytkitClient {
|
|
|
149
151
|
revokeId: string;
|
|
150
152
|
}) => Promise<void>;
|
|
151
153
|
revokeOtherSessions: () => Promise<void>;
|
|
154
|
+
/** Permanently closes the member's account (cancels their subscriptions,
|
|
155
|
+
* anonymises their data, deletes the login) after re-verifying the email
|
|
156
|
+
* and password. On success the SDK clears its session and emits
|
|
157
|
+
* `signed_out`. A wrong password rejects with `{ kind: "server", status:
|
|
158
|
+
* 400, code: "invalid_password" }` and leaves the session signed in. */
|
|
159
|
+
closeAccount: (input: {
|
|
160
|
+
confirmEmail: string;
|
|
161
|
+
password: string;
|
|
162
|
+
}) => Promise<void>;
|
|
152
163
|
};
|
|
153
164
|
readonly workouts: PublicApi["workout"];
|
|
154
165
|
readonly exercises: PublicApi["exercise"];
|
|
155
166
|
readonly programs: PublicApi["program"];
|
|
156
167
|
readonly goals: PublicApi["goal"];
|
|
168
|
+
readonly equipment: PublicApi["equipment"];
|
|
157
169
|
readonly recipes: PublicApi["recipe"];
|
|
158
170
|
readonly nutrition: PublicApi["nutrition"];
|
|
159
171
|
readonly articles: PublicApi["article"];
|
|
@@ -186,12 +198,14 @@ export declare type FytkitError = {
|
|
|
186
198
|
} | {
|
|
187
199
|
readonly kind: "forbidden";
|
|
188
200
|
readonly reason: string;
|
|
201
|
+
readonly code?: FytkitErrorCode;
|
|
189
202
|
} | {
|
|
190
203
|
readonly kind: "payment_required";
|
|
191
204
|
readonly message: string;
|
|
192
205
|
} | {
|
|
193
206
|
readonly kind: "conflict";
|
|
194
207
|
readonly message: string;
|
|
208
|
+
readonly enrollmentId?: string;
|
|
195
209
|
} | {
|
|
196
210
|
readonly kind: "not_found";
|
|
197
211
|
} | {
|
|
@@ -204,10 +218,29 @@ export declare type FytkitError = {
|
|
|
204
218
|
readonly kind: "server";
|
|
205
219
|
readonly status: number;
|
|
206
220
|
readonly message?: string;
|
|
221
|
+
readonly code?: FytkitErrorCode;
|
|
207
222
|
} | {
|
|
208
223
|
readonly kind: "network";
|
|
209
224
|
};
|
|
210
225
|
|
|
226
|
+
/**
|
|
227
|
+
* Machine-readable reasons the server attaches to some errors (as `code` on
|
|
228
|
+
* the `forbidden` and `server` kinds). Branch on these instead of matching
|
|
229
|
+
* `message`/`reason` text. The union is open — the server may add codes, so
|
|
230
|
+
* always keep a fallback branch.
|
|
231
|
+
*
|
|
232
|
+
* - `"reauth_required"` (`forbidden`, 403) — the session is valid but too old
|
|
233
|
+
* for this change (e.g. `changeEmail` more than 15 minutes after sign-in).
|
|
234
|
+
* Ask the member to sign in again; do NOT treat it as signed out.
|
|
235
|
+
* - `"invalid_password"` (`server`, 400) — the re-typed password was wrong
|
|
236
|
+
* (`changePassword`, `closeAccount`, `enableTotp`, `disableTwoFactor`,
|
|
237
|
+
* `regenerateBackupCodes`). The session is untouched.
|
|
238
|
+
* - `"invalid_code"` (`server`, 400) — a TOTP, backup or email one-time code
|
|
239
|
+
* was wrong (`verifyTotp`, `verifyBackupCode`, `verifyEmailOtp`,
|
|
240
|
+
* `verifyTotpSetup`).
|
|
241
|
+
*/
|
|
242
|
+
export declare type FytkitErrorCode = "reauth_required" | "invalid_password" | "invalid_code" | (string & {});
|
|
243
|
+
|
|
211
244
|
export declare type PublicApi = RouterClient<PublicRouter>;
|
|
212
245
|
|
|
213
246
|
declare type PublicRouter = typeof publicRouter;
|
|
@@ -806,6 +839,12 @@ declare const publicRouter: {
|
|
|
806
839
|
intermediate: "intermediate";
|
|
807
840
|
advanced: "advanced";
|
|
808
841
|
}>>;
|
|
842
|
+
accessLevel: ZodOptional<ZodEnum< {
|
|
843
|
+
free: "free";
|
|
844
|
+
premium: "premium";
|
|
845
|
+
}>>;
|
|
846
|
+
equipmentAvailable: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<string[], string | string[]>>>;
|
|
847
|
+
locations: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<("home" | "gym" | "outdoors")[], string | string[]>>>;
|
|
809
848
|
favouritesOnly: ZodOptional<ZodUnion<readonly [ZodBoolean, ZodCodec<ZodString, ZodBoolean>]>>;
|
|
810
849
|
}, $strip>, ZodObject< {
|
|
811
850
|
data: ZodArray<ZodObject< {
|
|
@@ -817,9 +856,10 @@ declare const publicRouter: {
|
|
|
817
856
|
free: "free";
|
|
818
857
|
premium: "premium";
|
|
819
858
|
}>;
|
|
859
|
+
canAccess: ZodBoolean;
|
|
820
860
|
status: ZodEnum< {
|
|
821
|
-
draft: "draft";
|
|
822
861
|
published: "published";
|
|
862
|
+
draft: "draft";
|
|
823
863
|
archived: "archived";
|
|
824
864
|
}>;
|
|
825
865
|
durationMinutes: ZodNullable<ZodNumber>;
|
|
@@ -828,6 +868,13 @@ declare const publicRouter: {
|
|
|
828
868
|
intermediate: "intermediate";
|
|
829
869
|
advanced: "advanced";
|
|
830
870
|
}>>;
|
|
871
|
+
muscleGroups: ZodArray<ZodString>;
|
|
872
|
+
equipment: ZodArray<ZodString>;
|
|
873
|
+
locations: ZodArray<ZodEnum< {
|
|
874
|
+
home: "home";
|
|
875
|
+
gym: "gym";
|
|
876
|
+
outdoors: "outdoors";
|
|
877
|
+
}>>;
|
|
831
878
|
publishedAt: ZodNullable<ZodDate>;
|
|
832
879
|
videoPlaybackMode: ZodEnum< {
|
|
833
880
|
full_video: "full_video";
|
|
@@ -863,9 +910,10 @@ declare const publicRouter: {
|
|
|
863
910
|
free: "free";
|
|
864
911
|
premium: "premium";
|
|
865
912
|
}>;
|
|
913
|
+
canAccess: ZodBoolean;
|
|
866
914
|
status: ZodEnum< {
|
|
867
|
-
draft: "draft";
|
|
868
915
|
published: "published";
|
|
916
|
+
draft: "draft";
|
|
869
917
|
archived: "archived";
|
|
870
918
|
}>;
|
|
871
919
|
durationMinutes: ZodNullable<ZodNumber>;
|
|
@@ -874,6 +922,13 @@ declare const publicRouter: {
|
|
|
874
922
|
intermediate: "intermediate";
|
|
875
923
|
advanced: "advanced";
|
|
876
924
|
}>>;
|
|
925
|
+
muscleGroups: ZodArray<ZodString>;
|
|
926
|
+
equipment: ZodArray<ZodString>;
|
|
927
|
+
locations: ZodArray<ZodEnum< {
|
|
928
|
+
home: "home";
|
|
929
|
+
gym: "gym";
|
|
930
|
+
outdoors: "outdoors";
|
|
931
|
+
}>>;
|
|
877
932
|
publishedAt: ZodNullable<ZodDate>;
|
|
878
933
|
videoPlaybackMode: ZodEnum< {
|
|
879
934
|
full_video: "full_video";
|
|
@@ -966,9 +1021,10 @@ declare const publicRouter: {
|
|
|
966
1021
|
free: "free";
|
|
967
1022
|
premium: "premium";
|
|
968
1023
|
}>;
|
|
1024
|
+
canAccess: ZodBoolean;
|
|
969
1025
|
status: ZodEnum< {
|
|
970
|
-
draft: "draft";
|
|
971
1026
|
published: "published";
|
|
1027
|
+
draft: "draft";
|
|
972
1028
|
archived: "archived";
|
|
973
1029
|
}>;
|
|
974
1030
|
durationMinutes: ZodNullable<ZodNumber>;
|
|
@@ -977,6 +1033,13 @@ declare const publicRouter: {
|
|
|
977
1033
|
intermediate: "intermediate";
|
|
978
1034
|
advanced: "advanced";
|
|
979
1035
|
}>>;
|
|
1036
|
+
muscleGroups: ZodArray<ZodString>;
|
|
1037
|
+
equipment: ZodArray<ZodString>;
|
|
1038
|
+
locations: ZodArray<ZodEnum< {
|
|
1039
|
+
home: "home";
|
|
1040
|
+
gym: "gym";
|
|
1041
|
+
outdoors: "outdoors";
|
|
1042
|
+
}>>;
|
|
980
1043
|
publishedAt: ZodNullable<ZodDate>;
|
|
981
1044
|
videoPlaybackMode: ZodEnum< {
|
|
982
1045
|
full_video: "full_video";
|
|
@@ -988,6 +1051,8 @@ declare const publicRouter: {
|
|
|
988
1051
|
createdAt: ZodDate;
|
|
989
1052
|
}, $strip>>;
|
|
990
1053
|
allWorkoutsNextCursor: ZodNullable<ZodString>;
|
|
1054
|
+
totalWorkouts: ZodNumber;
|
|
1055
|
+
uncategorisedWorkouts: ZodNumber;
|
|
991
1056
|
categories: ZodArray<ZodObject< {
|
|
992
1057
|
id: ZodString;
|
|
993
1058
|
name: ZodString;
|
|
@@ -1002,9 +1067,10 @@ declare const publicRouter: {
|
|
|
1002
1067
|
free: "free";
|
|
1003
1068
|
premium: "premium";
|
|
1004
1069
|
}>;
|
|
1070
|
+
canAccess: ZodBoolean;
|
|
1005
1071
|
status: ZodEnum< {
|
|
1006
|
-
draft: "draft";
|
|
1007
1072
|
published: "published";
|
|
1073
|
+
draft: "draft";
|
|
1008
1074
|
archived: "archived";
|
|
1009
1075
|
}>;
|
|
1010
1076
|
durationMinutes: ZodNullable<ZodNumber>;
|
|
@@ -1013,6 +1079,13 @@ declare const publicRouter: {
|
|
|
1013
1079
|
intermediate: "intermediate";
|
|
1014
1080
|
advanced: "advanced";
|
|
1015
1081
|
}>>;
|
|
1082
|
+
muscleGroups: ZodArray<ZodString>;
|
|
1083
|
+
equipment: ZodArray<ZodString>;
|
|
1084
|
+
locations: ZodArray<ZodEnum< {
|
|
1085
|
+
home: "home";
|
|
1086
|
+
gym: "gym";
|
|
1087
|
+
outdoors: "outdoors";
|
|
1088
|
+
}>>;
|
|
1016
1089
|
publishedAt: ZodNullable<ZodDate>;
|
|
1017
1090
|
videoPlaybackMode: ZodEnum< {
|
|
1018
1091
|
full_video: "full_video";
|
|
@@ -1024,6 +1097,7 @@ declare const publicRouter: {
|
|
|
1024
1097
|
createdAt: ZodDate;
|
|
1025
1098
|
}, $strip>>;
|
|
1026
1099
|
nextCursor: ZodNullable<ZodString>;
|
|
1100
|
+
workoutCount: ZodNumber;
|
|
1027
1101
|
}, $strip>>;
|
|
1028
1102
|
}, $strip>;
|
|
1029
1103
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
@@ -1046,6 +1120,23 @@ declare const publicRouter: {
|
|
|
1046
1120
|
}, $strip>>;
|
|
1047
1121
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1048
1122
|
};
|
|
1123
|
+
equipment: {
|
|
1124
|
+
list: DecoratedProcedure<MergedInitialContext< {
|
|
1125
|
+
headers: Headers;
|
|
1126
|
+
} & Record<never, never>, {
|
|
1127
|
+
headers: Headers;
|
|
1128
|
+
} & Record<never, never>, {
|
|
1129
|
+
headers: Headers;
|
|
1130
|
+
}>, MergedCurrentContext< {
|
|
1131
|
+
headers: Headers;
|
|
1132
|
+
}, ApiKeyContext>, Schema<unknown, unknown>, ZodObject< {
|
|
1133
|
+
data: ZodArray<ZodObject< {
|
|
1134
|
+
name: ZodString;
|
|
1135
|
+
workoutCount: ZodNumber;
|
|
1136
|
+
programCount: ZodNumber;
|
|
1137
|
+
}, $strip>>;
|
|
1138
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1139
|
+
};
|
|
1049
1140
|
nutrition: {
|
|
1050
1141
|
list: DecoratedProcedure<MergedInitialContext< {
|
|
1051
1142
|
headers: Headers;
|
|
@@ -1069,9 +1160,10 @@ declare const publicRouter: {
|
|
|
1069
1160
|
free: "free";
|
|
1070
1161
|
premium: "premium";
|
|
1071
1162
|
}>;
|
|
1163
|
+
canAccess: ZodBoolean;
|
|
1072
1164
|
status: ZodEnum< {
|
|
1073
|
-
draft: "draft";
|
|
1074
1165
|
published: "published";
|
|
1166
|
+
draft: "draft";
|
|
1075
1167
|
archived: "archived";
|
|
1076
1168
|
}>;
|
|
1077
1169
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1111,9 +1203,10 @@ declare const publicRouter: {
|
|
|
1111
1203
|
free: "free";
|
|
1112
1204
|
premium: "premium";
|
|
1113
1205
|
}>;
|
|
1206
|
+
canAccess: ZodBoolean;
|
|
1114
1207
|
status: ZodEnum< {
|
|
1115
|
-
draft: "draft";
|
|
1116
1208
|
published: "published";
|
|
1209
|
+
draft: "draft";
|
|
1117
1210
|
archived: "archived";
|
|
1118
1211
|
}>;
|
|
1119
1212
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1139,8 +1232,8 @@ declare const publicRouter: {
|
|
|
1139
1232
|
dayIndex: ZodNumber;
|
|
1140
1233
|
kind: ZodEnum< {
|
|
1141
1234
|
custom: "custom";
|
|
1142
|
-
note: "note";
|
|
1143
1235
|
recipe: "recipe";
|
|
1236
|
+
note: "note";
|
|
1144
1237
|
}>;
|
|
1145
1238
|
recipeId: ZodNullable<ZodString>;
|
|
1146
1239
|
servings: ZodNumber;
|
|
@@ -1169,9 +1262,10 @@ declare const publicRouter: {
|
|
|
1169
1262
|
free: "free";
|
|
1170
1263
|
premium: "premium";
|
|
1171
1264
|
}>;
|
|
1265
|
+
canAccess: ZodBoolean;
|
|
1172
1266
|
status: ZodEnum< {
|
|
1173
|
-
draft: "draft";
|
|
1174
1267
|
published: "published";
|
|
1268
|
+
draft: "draft";
|
|
1175
1269
|
archived: "archived";
|
|
1176
1270
|
}>;
|
|
1177
1271
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1364,8 +1458,8 @@ declare const publicRouter: {
|
|
|
1364
1458
|
email: ZodString;
|
|
1365
1459
|
avatarUrl: ZodNullable<ZodString>;
|
|
1366
1460
|
weightUnit: ZodEnum< {
|
|
1367
|
-
kg: "kg";
|
|
1368
1461
|
lb: "lb";
|
|
1462
|
+
kg: "kg";
|
|
1369
1463
|
}>;
|
|
1370
1464
|
timezone: ZodNullable<ZodString>;
|
|
1371
1465
|
fitnessGoal: ZodNullable<ZodEnum< {
|
|
@@ -1399,8 +1493,8 @@ declare const publicRouter: {
|
|
|
1399
1493
|
avatarUrl: ZodOptional<ZodNullable<ZodString>>;
|
|
1400
1494
|
timezone: ZodOptional<ZodNullable<ZodString>>;
|
|
1401
1495
|
weightUnit: ZodOptional<ZodEnum< {
|
|
1402
|
-
kg: "kg";
|
|
1403
1496
|
lb: "lb";
|
|
1497
|
+
kg: "kg";
|
|
1404
1498
|
}>>;
|
|
1405
1499
|
fitnessGoal: ZodOptional<ZodNullable<ZodEnum< {
|
|
1406
1500
|
lose_fat: "lose_fat";
|
|
@@ -1418,8 +1512,8 @@ declare const publicRouter: {
|
|
|
1418
1512
|
email: ZodString;
|
|
1419
1513
|
avatarUrl: ZodNullable<ZodString>;
|
|
1420
1514
|
weightUnit: ZodEnum< {
|
|
1421
|
-
kg: "kg";
|
|
1422
1515
|
lb: "lb";
|
|
1516
|
+
kg: "kg";
|
|
1423
1517
|
}>;
|
|
1424
1518
|
timezone: ZodNullable<ZodString>;
|
|
1425
1519
|
fitnessGoal: ZodNullable<ZodEnum< {
|
|
@@ -1506,9 +1600,10 @@ declare const publicRouter: {
|
|
|
1506
1600
|
free: "free";
|
|
1507
1601
|
premium: "premium";
|
|
1508
1602
|
}>;
|
|
1603
|
+
canAccess: ZodBoolean;
|
|
1509
1604
|
status: ZodEnum< {
|
|
1510
|
-
draft: "draft";
|
|
1511
1605
|
published: "published";
|
|
1606
|
+
draft: "draft";
|
|
1512
1607
|
archived: "archived";
|
|
1513
1608
|
}>;
|
|
1514
1609
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1540,9 +1635,10 @@ declare const publicRouter: {
|
|
|
1540
1635
|
free: "free";
|
|
1541
1636
|
premium: "premium";
|
|
1542
1637
|
}>;
|
|
1638
|
+
canAccess: ZodBoolean;
|
|
1543
1639
|
status: ZodEnum< {
|
|
1544
|
-
draft: "draft";
|
|
1545
1640
|
published: "published";
|
|
1641
|
+
draft: "draft";
|
|
1546
1642
|
archived: "archived";
|
|
1547
1643
|
}>;
|
|
1548
1644
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1591,9 +1687,10 @@ declare const publicRouter: {
|
|
|
1591
1687
|
free: "free";
|
|
1592
1688
|
premium: "premium";
|
|
1593
1689
|
}>;
|
|
1690
|
+
canAccess: ZodBoolean;
|
|
1594
1691
|
status: ZodEnum< {
|
|
1595
|
-
draft: "draft";
|
|
1596
1692
|
published: "published";
|
|
1693
|
+
draft: "draft";
|
|
1597
1694
|
archived: "archived";
|
|
1598
1695
|
}>;
|
|
1599
1696
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1637,9 +1734,10 @@ declare const publicRouter: {
|
|
|
1637
1734
|
free: "free";
|
|
1638
1735
|
premium: "premium";
|
|
1639
1736
|
}>;
|
|
1737
|
+
canAccess: ZodBoolean;
|
|
1640
1738
|
status: ZodEnum< {
|
|
1641
|
-
draft: "draft";
|
|
1642
1739
|
published: "published";
|
|
1740
|
+
draft: "draft";
|
|
1643
1741
|
archived: "archived";
|
|
1644
1742
|
}>;
|
|
1645
1743
|
publishedAt: ZodNullable<ZodDate>;
|
|
@@ -1668,6 +1766,72 @@ declare const publicRouter: {
|
|
|
1668
1766
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1669
1767
|
};
|
|
1670
1768
|
exercise: {
|
|
1769
|
+
list: DecoratedProcedure<MergedInitialContext< {
|
|
1770
|
+
headers: Headers;
|
|
1771
|
+
} & Record<never, never>, {
|
|
1772
|
+
headers: Headers;
|
|
1773
|
+
} & Record<never, never>, {
|
|
1774
|
+
headers: Headers;
|
|
1775
|
+
}>, MergedCurrentContext< {
|
|
1776
|
+
headers: Headers;
|
|
1777
|
+
}, ApiKeyContext>, ZodObject< {
|
|
1778
|
+
cursor: ZodOptional<ZodString>;
|
|
1779
|
+
limit: ZodDefault<ZodCoercedNumber<unknown>>;
|
|
1780
|
+
q: ZodOptional<ZodString>;
|
|
1781
|
+
type: ZodOptional<ZodEnum< {
|
|
1782
|
+
compound: "compound";
|
|
1783
|
+
isolation: "isolation";
|
|
1784
|
+
cardio: "cardio";
|
|
1785
|
+
mobility: "mobility";
|
|
1786
|
+
}>>;
|
|
1787
|
+
difficulty: ZodOptional<ZodEnum< {
|
|
1788
|
+
beginner: "beginner";
|
|
1789
|
+
intermediate: "intermediate";
|
|
1790
|
+
advanced: "advanced";
|
|
1791
|
+
}>>;
|
|
1792
|
+
accessLevel: ZodOptional<ZodEnum< {
|
|
1793
|
+
free: "free";
|
|
1794
|
+
premium: "premium";
|
|
1795
|
+
}>>;
|
|
1796
|
+
muscleGroups: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<string[], string | string[]>>>;
|
|
1797
|
+
equipmentAvailable: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<string[], string | string[]>>>;
|
|
1798
|
+
hasVideo: ZodOptional<ZodUnion<readonly [ZodBoolean, ZodCodec<ZodString, ZodBoolean>]>>;
|
|
1799
|
+
}, $strip>, ZodObject< {
|
|
1800
|
+
data: ZodArray<ZodObject< {
|
|
1801
|
+
id: ZodString;
|
|
1802
|
+
trainerId: ZodString;
|
|
1803
|
+
name: ZodString;
|
|
1804
|
+
description: ZodString;
|
|
1805
|
+
cue: ZodString;
|
|
1806
|
+
type: ZodEnum< {
|
|
1807
|
+
compound: "compound";
|
|
1808
|
+
isolation: "isolation";
|
|
1809
|
+
cardio: "cardio";
|
|
1810
|
+
mobility: "mobility";
|
|
1811
|
+
}>;
|
|
1812
|
+
accessLevel: ZodEnum< {
|
|
1813
|
+
free: "free";
|
|
1814
|
+
premium: "premium";
|
|
1815
|
+
}>;
|
|
1816
|
+
canAccess: ZodBoolean;
|
|
1817
|
+
difficulty: ZodEnum< {
|
|
1818
|
+
beginner: "beginner";
|
|
1819
|
+
intermediate: "intermediate";
|
|
1820
|
+
advanced: "advanced";
|
|
1821
|
+
}>;
|
|
1822
|
+
muscleGroups: ZodArray<ZodString>;
|
|
1823
|
+
equipment: ZodArray<ZodString>;
|
|
1824
|
+
headerImageId: ZodNullable<ZodString>;
|
|
1825
|
+
headerImageUrl: ZodNullable<ZodString>;
|
|
1826
|
+
videoAssetId: ZodNullable<ZodString>;
|
|
1827
|
+
videoAutoLoop: ZodBoolean;
|
|
1828
|
+
createdAt: ZodDate;
|
|
1829
|
+
}, $strip>>;
|
|
1830
|
+
meta: ZodObject< {
|
|
1831
|
+
nextCursor: ZodNullable<ZodString>;
|
|
1832
|
+
limit: ZodNumber;
|
|
1833
|
+
}, $strip>;
|
|
1834
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1671
1835
|
get: DecoratedProcedure<MergedInitialContext< {
|
|
1672
1836
|
headers: Headers;
|
|
1673
1837
|
} & Record<never, never>, {
|
|
@@ -1695,6 +1859,7 @@ declare const publicRouter: {
|
|
|
1695
1859
|
free: "free";
|
|
1696
1860
|
premium: "premium";
|
|
1697
1861
|
}>;
|
|
1862
|
+
canAccess: ZodBoolean;
|
|
1698
1863
|
difficulty: ZodEnum< {
|
|
1699
1864
|
beginner: "beginner";
|
|
1700
1865
|
intermediate: "intermediate";
|
|
@@ -1706,6 +1871,7 @@ declare const publicRouter: {
|
|
|
1706
1871
|
headerImageUrl: ZodNullable<ZodString>;
|
|
1707
1872
|
videoAssetId: ZodNullable<ZodString>;
|
|
1708
1873
|
videoAutoLoop: ZodBoolean;
|
|
1874
|
+
createdAt: ZodDate;
|
|
1709
1875
|
instructions: ZodArray<ZodObject< {
|
|
1710
1876
|
id: ZodString;
|
|
1711
1877
|
order: ZodNumber;
|
|
@@ -1758,7 +1924,13 @@ declare const publicRouter: {
|
|
|
1758
1924
|
intermediate: "intermediate";
|
|
1759
1925
|
advanced: "advanced";
|
|
1760
1926
|
}>>;
|
|
1927
|
+
accessLevel: ZodOptional<ZodEnum< {
|
|
1928
|
+
free: "free";
|
|
1929
|
+
premium: "premium";
|
|
1930
|
+
}>>;
|
|
1761
1931
|
goalId: ZodOptional<ZodString>;
|
|
1932
|
+
equipmentAvailable: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<string[], string | string[]>>>;
|
|
1933
|
+
locations: ZodOptional<ZodPipe<ZodUnion<readonly [ZodArray<ZodString>, ZodString]>, ZodTransform<("home" | "gym" | "outdoors")[], string | string[]>>>;
|
|
1762
1934
|
favouritesOnly: ZodOptional<ZodUnion<readonly [ZodBoolean, ZodCodec<ZodString, ZodBoolean>]>>;
|
|
1763
1935
|
}, $strip>, ZodObject< {
|
|
1764
1936
|
data: ZodArray<ZodObject< {
|
|
@@ -1770,9 +1942,10 @@ declare const publicRouter: {
|
|
|
1770
1942
|
free: "free";
|
|
1771
1943
|
premium: "premium";
|
|
1772
1944
|
}>;
|
|
1945
|
+
canAccess: ZodBoolean;
|
|
1773
1946
|
status: ZodEnum< {
|
|
1774
|
-
draft: "draft";
|
|
1775
1947
|
published: "published";
|
|
1948
|
+
draft: "draft";
|
|
1776
1949
|
archived: "archived";
|
|
1777
1950
|
}>;
|
|
1778
1951
|
difficulty: ZodNullable<ZodEnum< {
|
|
@@ -1780,10 +1953,18 @@ declare const publicRouter: {
|
|
|
1780
1953
|
intermediate: "intermediate";
|
|
1781
1954
|
advanced: "advanced";
|
|
1782
1955
|
}>>;
|
|
1956
|
+
equipment: ZodArray<ZodString>;
|
|
1957
|
+
locations: ZodArray<ZodEnum< {
|
|
1958
|
+
home: "home";
|
|
1959
|
+
gym: "gym";
|
|
1960
|
+
outdoors: "outdoors";
|
|
1961
|
+
}>>;
|
|
1783
1962
|
coverImageId: ZodNullable<ZodString>;
|
|
1784
1963
|
coverImageUrl: ZodNullable<ZodString>;
|
|
1785
1964
|
publishedAt: ZodNullable<ZodString>;
|
|
1786
1965
|
createdAt: ZodString;
|
|
1966
|
+
sessionsPerWeek: ZodNullable<ZodNumber>;
|
|
1967
|
+
weekCount: ZodNumber;
|
|
1787
1968
|
}, $strip>>;
|
|
1788
1969
|
meta: ZodObject< {
|
|
1789
1970
|
nextCursor: ZodNullable<ZodString>;
|
|
@@ -1810,9 +1991,10 @@ declare const publicRouter: {
|
|
|
1810
1991
|
free: "free";
|
|
1811
1992
|
premium: "premium";
|
|
1812
1993
|
}>;
|
|
1994
|
+
canAccess: ZodBoolean;
|
|
1813
1995
|
status: ZodEnum< {
|
|
1814
|
-
draft: "draft";
|
|
1815
1996
|
published: "published";
|
|
1997
|
+
draft: "draft";
|
|
1816
1998
|
archived: "archived";
|
|
1817
1999
|
}>;
|
|
1818
2000
|
difficulty: ZodNullable<ZodEnum< {
|
|
@@ -1820,6 +2002,12 @@ declare const publicRouter: {
|
|
|
1820
2002
|
intermediate: "intermediate";
|
|
1821
2003
|
advanced: "advanced";
|
|
1822
2004
|
}>>;
|
|
2005
|
+
equipment: ZodArray<ZodString>;
|
|
2006
|
+
locations: ZodArray<ZodEnum< {
|
|
2007
|
+
home: "home";
|
|
2008
|
+
gym: "gym";
|
|
2009
|
+
outdoors: "outdoors";
|
|
2010
|
+
}>>;
|
|
1823
2011
|
coverImageId: ZodNullable<ZodString>;
|
|
1824
2012
|
coverImageUrl: ZodNullable<ZodString>;
|
|
1825
2013
|
publishedAt: ZodNullable<ZodString>;
|
|
@@ -1851,12 +2039,12 @@ declare const publicRouter: {
|
|
|
1851
2039
|
weekOrder: ZodNullable<ZodNumber>;
|
|
1852
2040
|
dayOfWeek: ZodEnum< {
|
|
1853
2041
|
mon: "mon";
|
|
2042
|
+
sun: "sun";
|
|
1854
2043
|
tue: "tue";
|
|
1855
2044
|
wed: "wed";
|
|
1856
2045
|
thu: "thu";
|
|
1857
2046
|
fri: "fri";
|
|
1858
2047
|
sat: "sat";
|
|
1859
|
-
sun: "sun";
|
|
1860
2048
|
}>;
|
|
1861
2049
|
workoutId: ZodString;
|
|
1862
2050
|
order: ZodNumber;
|
|
@@ -1911,12 +2099,12 @@ declare const publicRouter: {
|
|
|
1911
2099
|
weekOrder: ZodNullable<ZodNumber>;
|
|
1912
2100
|
dayOfWeek: ZodEnum< {
|
|
1913
2101
|
mon: "mon";
|
|
2102
|
+
sun: "sun";
|
|
1914
2103
|
tue: "tue";
|
|
1915
2104
|
wed: "wed";
|
|
1916
2105
|
thu: "thu";
|
|
1917
2106
|
fri: "fri";
|
|
1918
2107
|
sat: "sat";
|
|
1919
|
-
sun: "sun";
|
|
1920
2108
|
}>;
|
|
1921
2109
|
workoutId: ZodString;
|
|
1922
2110
|
order: ZodNumber;
|
|
@@ -1984,12 +2172,12 @@ declare const publicRouter: {
|
|
|
1984
2172
|
weekOrder: ZodNullable<ZodNumber>;
|
|
1985
2173
|
dayOfWeek: ZodEnum< {
|
|
1986
2174
|
mon: "mon";
|
|
2175
|
+
sun: "sun";
|
|
1987
2176
|
tue: "tue";
|
|
1988
2177
|
wed: "wed";
|
|
1989
2178
|
thu: "thu";
|
|
1990
2179
|
fri: "fri";
|
|
1991
2180
|
sat: "sat";
|
|
1992
|
-
sun: "sun";
|
|
1993
2181
|
}>;
|
|
1994
2182
|
workoutId: ZodString;
|
|
1995
2183
|
order: ZodNumber;
|
|
@@ -2095,9 +2283,10 @@ declare const publicRouter: {
|
|
|
2095
2283
|
free: "free";
|
|
2096
2284
|
premium: "premium";
|
|
2097
2285
|
}>;
|
|
2286
|
+
canAccess: ZodBoolean;
|
|
2098
2287
|
status: ZodEnum< {
|
|
2099
|
-
draft: "draft";
|
|
2100
2288
|
published: "published";
|
|
2289
|
+
draft: "draft";
|
|
2101
2290
|
archived: "archived";
|
|
2102
2291
|
}>;
|
|
2103
2292
|
difficulty: ZodNullable<ZodEnum< {
|
|
@@ -2105,6 +2294,12 @@ declare const publicRouter: {
|
|
|
2105
2294
|
intermediate: "intermediate";
|
|
2106
2295
|
advanced: "advanced";
|
|
2107
2296
|
}>>;
|
|
2297
|
+
equipment: ZodArray<ZodString>;
|
|
2298
|
+
locations: ZodArray<ZodEnum< {
|
|
2299
|
+
home: "home";
|
|
2300
|
+
gym: "gym";
|
|
2301
|
+
outdoors: "outdoors";
|
|
2302
|
+
}>>;
|
|
2108
2303
|
coverImageId: ZodNullable<ZodString>;
|
|
2109
2304
|
coverImageUrl: ZodNullable<ZodString>;
|
|
2110
2305
|
publishedAt: ZodNullable<ZodString>;
|
|
@@ -2186,16 +2381,16 @@ declare const publicRouter: {
|
|
|
2186
2381
|
entityType: ZodOptional<ZodEnum< {
|
|
2187
2382
|
workout: "workout";
|
|
2188
2383
|
program: "program";
|
|
2189
|
-
nutrition_plan: "nutrition_plan";
|
|
2190
2384
|
recipe: "recipe";
|
|
2385
|
+
nutrition_plan: "nutrition_plan";
|
|
2191
2386
|
}>>;
|
|
2192
2387
|
}, $strip>, ZodObject< {
|
|
2193
2388
|
data: ZodArray<ZodObject< {
|
|
2194
2389
|
entityType: ZodEnum< {
|
|
2195
2390
|
workout: "workout";
|
|
2196
2391
|
program: "program";
|
|
2197
|
-
nutrition_plan: "nutrition_plan";
|
|
2198
2392
|
recipe: "recipe";
|
|
2393
|
+
nutrition_plan: "nutrition_plan";
|
|
2199
2394
|
}>;
|
|
2200
2395
|
entityId: ZodString;
|
|
2201
2396
|
favouritedAt: ZodString;
|
|
@@ -2217,8 +2412,8 @@ declare const publicRouter: {
|
|
|
2217
2412
|
entityType: ZodEnum< {
|
|
2218
2413
|
workout: "workout";
|
|
2219
2414
|
program: "program";
|
|
2220
|
-
nutrition_plan: "nutrition_plan";
|
|
2221
2415
|
recipe: "recipe";
|
|
2416
|
+
nutrition_plan: "nutrition_plan";
|
|
2222
2417
|
}>;
|
|
2223
2418
|
entityId: ZodString;
|
|
2224
2419
|
}, $strip>, ZodObject< {
|
|
@@ -2226,8 +2421,8 @@ declare const publicRouter: {
|
|
|
2226
2421
|
entityType: ZodEnum< {
|
|
2227
2422
|
workout: "workout";
|
|
2228
2423
|
program: "program";
|
|
2229
|
-
nutrition_plan: "nutrition_plan";
|
|
2230
2424
|
recipe: "recipe";
|
|
2425
|
+
nutrition_plan: "nutrition_plan";
|
|
2231
2426
|
}>;
|
|
2232
2427
|
entityId: ZodString;
|
|
2233
2428
|
favouritedAt: ZodString;
|
|
@@ -2245,8 +2440,8 @@ declare const publicRouter: {
|
|
|
2245
2440
|
entityType: ZodEnum< {
|
|
2246
2441
|
workout: "workout";
|
|
2247
2442
|
program: "program";
|
|
2248
|
-
nutrition_plan: "nutrition_plan";
|
|
2249
2443
|
recipe: "recipe";
|
|
2444
|
+
nutrition_plan: "nutrition_plan";
|
|
2250
2445
|
}>;
|
|
2251
2446
|
entityId: ZodString;
|
|
2252
2447
|
}, $strip>, ZodObject< {
|
|
@@ -2254,8 +2449,8 @@ declare const publicRouter: {
|
|
|
2254
2449
|
entityType: ZodEnum< {
|
|
2255
2450
|
workout: "workout";
|
|
2256
2451
|
program: "program";
|
|
2257
|
-
nutrition_plan: "nutrition_plan";
|
|
2258
2452
|
recipe: "recipe";
|
|
2453
|
+
nutrition_plan: "nutrition_plan";
|
|
2259
2454
|
}>;
|
|
2260
2455
|
entityId: ZodString;
|
|
2261
2456
|
deleted: ZodLiteral<true>;
|
|
@@ -2762,9 +2957,9 @@ declare const publicRouter: {
|
|
|
2762
2957
|
adaptiveIconUrl: ZodNullable<ZodString>;
|
|
2763
2958
|
faviconUrl: ZodNullable<ZodString>;
|
|
2764
2959
|
buildStatus: ZodEnum< {
|
|
2765
|
-
published: "published";
|
|
2766
2960
|
idle: "idle";
|
|
2767
2961
|
building: "building";
|
|
2962
|
+
published: "published";
|
|
2768
2963
|
failed: "failed";
|
|
2769
2964
|
}>;
|
|
2770
2965
|
buildVersion: ZodNullable<ZodString>;
|
|
@@ -2851,6 +3046,7 @@ declare const publicRouter: {
|
|
|
2851
3046
|
startedAt: ZodNullable<ZodDate>;
|
|
2852
3047
|
expiresAt: ZodNullable<ZodDate>;
|
|
2853
3048
|
}, $strip>>;
|
|
3049
|
+
hasBillingAccount: ZodBoolean;
|
|
2854
3050
|
entitlements: ZodUnion<readonly [ZodLiteral<"all">, ZodArray<ZodEnum< {
|
|
2855
3051
|
premium_workouts: "premium_workouts";
|
|
2856
3052
|
premium_programs: "premium_programs";
|
|
@@ -2880,6 +3076,51 @@ declare const publicRouter: {
|
|
|
2880
3076
|
url: ZodString;
|
|
2881
3077
|
}, $strip>;
|
|
2882
3078
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
3079
|
+
confirmCheckout: DecoratedProcedure<MergedInitialContext< {
|
|
3080
|
+
headers: Headers;
|
|
3081
|
+
} & Record<never, never>, {
|
|
3082
|
+
headers: Headers;
|
|
3083
|
+
} & Record<never, never>, {
|
|
3084
|
+
headers: Headers;
|
|
3085
|
+
}>, MergedCurrentContext< {
|
|
3086
|
+
headers: Headers;
|
|
3087
|
+
}, ApiKeyContext>, ZodObject< {
|
|
3088
|
+
sessionId: ZodString;
|
|
3089
|
+
}, $strip>, ZodObject< {
|
|
3090
|
+
data: ZodObject< {
|
|
3091
|
+
hasActiveSubscription: ZodBoolean;
|
|
3092
|
+
subscription: ZodNullable<ZodObject< {
|
|
3093
|
+
plan: ZodEnum< {
|
|
3094
|
+
free: "free";
|
|
3095
|
+
premium: "premium";
|
|
3096
|
+
basic: "basic";
|
|
3097
|
+
}>;
|
|
3098
|
+
planId: ZodNullable<ZodString>;
|
|
3099
|
+
planName: ZodNullable<ZodString>;
|
|
3100
|
+
status: ZodEnum< {
|
|
3101
|
+
active: "active";
|
|
3102
|
+
cancelled: "cancelled";
|
|
3103
|
+
past_due: "past_due";
|
|
3104
|
+
}>;
|
|
3105
|
+
interval: ZodNullable<ZodEnum< {
|
|
3106
|
+
monthly: "monthly";
|
|
3107
|
+
annual: "annual";
|
|
3108
|
+
}>>;
|
|
3109
|
+
priceCents: ZodNullable<ZodNumber>;
|
|
3110
|
+
startedAt: ZodNullable<ZodDate>;
|
|
3111
|
+
expiresAt: ZodNullable<ZodDate>;
|
|
3112
|
+
}, $strip>>;
|
|
3113
|
+
hasBillingAccount: ZodBoolean;
|
|
3114
|
+
entitlements: ZodUnion<readonly [ZodLiteral<"all">, ZodArray<ZodEnum< {
|
|
3115
|
+
premium_workouts: "premium_workouts";
|
|
3116
|
+
premium_programs: "premium_programs";
|
|
3117
|
+
premium_nutrition: "premium_nutrition";
|
|
3118
|
+
premium_recipes: "premium_recipes";
|
|
3119
|
+
premium_articles: "premium_articles";
|
|
3120
|
+
}>>]>;
|
|
3121
|
+
confirmed: ZodBoolean;
|
|
3122
|
+
}, $strip>;
|
|
3123
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
2883
3124
|
createPortal: DecoratedProcedure<MergedInitialContext< {
|
|
2884
3125
|
headers: Headers;
|
|
2885
3126
|
} & Record<never, never>, {
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,11 @@ function pickRetryAfter(data) {
|
|
|
12
12
|
const raw = data.retryAfterMs;
|
|
13
13
|
return typeof raw === "number" && raw >= 0 ? raw : 0;
|
|
14
14
|
}
|
|
15
|
+
function pickStringField(data, key) {
|
|
16
|
+
if (!data || typeof data !== "object") return {};
|
|
17
|
+
const raw = data[key];
|
|
18
|
+
return typeof raw === "string" && raw.length > 0 ? { [key]: raw } : {};
|
|
19
|
+
}
|
|
15
20
|
function normalizeError(err) {
|
|
16
21
|
if (err instanceof TypeError) return { kind: "network" };
|
|
17
22
|
if (err instanceof ORPCError) {
|
|
@@ -23,11 +28,19 @@ function normalizeError(err) {
|
|
|
23
28
|
case "UNAUTHORIZED":
|
|
24
29
|
return { kind: "auth_required", message };
|
|
25
30
|
case "FORBIDDEN":
|
|
26
|
-
return {
|
|
31
|
+
return {
|
|
32
|
+
kind: "forbidden",
|
|
33
|
+
reason: message || "Forbidden",
|
|
34
|
+
...pickStringField(data, "code")
|
|
35
|
+
};
|
|
27
36
|
case "PAYMENT_REQUIRED":
|
|
28
37
|
return { kind: "payment_required", message: message || "Payment Required" };
|
|
29
38
|
case "CONFLICT":
|
|
30
|
-
return {
|
|
39
|
+
return {
|
|
40
|
+
kind: "conflict",
|
|
41
|
+
message: message || "Conflict",
|
|
42
|
+
...pickStringField(data, "enrollmentId")
|
|
43
|
+
};
|
|
31
44
|
case "NOT_FOUND":
|
|
32
45
|
return { kind: "not_found" };
|
|
33
46
|
case "TOO_MANY_REQUESTS":
|
|
@@ -36,10 +49,10 @@ function normalizeError(err) {
|
|
|
36
49
|
case "UNPROCESSABLE_CONTENT": {
|
|
37
50
|
const issues = pickIssues(data);
|
|
38
51
|
if (issues) return { kind: "validation", issues };
|
|
39
|
-
return { kind: "server", status, message };
|
|
52
|
+
return { kind: "server", status, message, ...pickStringField(data, "code") };
|
|
40
53
|
}
|
|
41
54
|
default:
|
|
42
|
-
return { kind: "server", status, message };
|
|
55
|
+
return { kind: "server", status, message, ...pickStringField(data, "code") };
|
|
43
56
|
}
|
|
44
57
|
}
|
|
45
58
|
return { kind: "server", status: 0 };
|
|
@@ -69,6 +82,16 @@ function createEventBus() {
|
|
|
69
82
|
|
|
70
83
|
// src/auth.ts
|
|
71
84
|
var PROACTIVE_REFRESH_LEAD_MS = 6e4;
|
|
85
|
+
var REFRESH_RETRY_BASE_MS = 5e3;
|
|
86
|
+
var REFRESH_RETRY_MAX_MS = 5 * 6e4;
|
|
87
|
+
var REFRESH_MAX_RETRIES = 6;
|
|
88
|
+
function isSessionRejected(err) {
|
|
89
|
+
return err.kind === "auth_required" || err.kind === "forbidden";
|
|
90
|
+
}
|
|
91
|
+
function refreshRetryDelay(attempt, err) {
|
|
92
|
+
const backoff = Math.min(REFRESH_RETRY_MAX_MS, REFRESH_RETRY_BASE_MS * 2 ** attempt);
|
|
93
|
+
return err.kind === "rate_limited" ? Math.max(backoff, err.retryAfter) : backoff;
|
|
94
|
+
}
|
|
72
95
|
function createAuthNamespace(opts) {
|
|
73
96
|
const bus = createEventBus();
|
|
74
97
|
let cached = null;
|
|
@@ -83,18 +106,23 @@ function createAuthNamespace(opts) {
|
|
|
83
106
|
}
|
|
84
107
|
}
|
|
85
108
|
const MAX_TIMEOUT_MS = 2147483647;
|
|
86
|
-
function
|
|
109
|
+
function armRefreshTimer(delay, attempt) {
|
|
87
110
|
clearTimer();
|
|
88
|
-
const expiresMs = new Date(session.expiresAt).getTime();
|
|
89
|
-
if (Number.isNaN(expiresMs)) return;
|
|
90
|
-
const rawDelay = expiresMs - Date.now() - PROACTIVE_REFRESH_LEAD_MS;
|
|
91
|
-
const delay = Math.min(MAX_TIMEOUT_MS, Math.max(0, rawDelay));
|
|
92
111
|
timer = setTimeout(() => {
|
|
93
112
|
timer = null;
|
|
94
|
-
void refreshFn().catch(() => {
|
|
113
|
+
void refreshFn().catch((err) => {
|
|
114
|
+
if (cached === null || timer !== null || attempt >= REFRESH_MAX_RETRIES) return;
|
|
115
|
+
armRefreshTimer(refreshRetryDelay(attempt, err), attempt + 1);
|
|
95
116
|
});
|
|
96
117
|
}, delay);
|
|
97
118
|
}
|
|
119
|
+
function scheduleRefresh(session) {
|
|
120
|
+
clearTimer();
|
|
121
|
+
const expiresMs = new Date(session.expiresAt).getTime();
|
|
122
|
+
if (Number.isNaN(expiresMs)) return;
|
|
123
|
+
const rawDelay = expiresMs - Date.now() - PROACTIVE_REFRESH_LEAD_MS;
|
|
124
|
+
armRefreshTimer(Math.min(MAX_TIMEOUT_MS, Math.max(0, rawDelay)), 0);
|
|
125
|
+
}
|
|
98
126
|
function applySession(session, event) {
|
|
99
127
|
cached = session;
|
|
100
128
|
void opts.storage.set(session);
|
|
@@ -253,6 +281,15 @@ function createAuthNamespace(opts) {
|
|
|
253
281
|
const revokeOtherSessions = async () => {
|
|
254
282
|
await call(() => opts.transport.client.auth.revokeOtherSessions());
|
|
255
283
|
};
|
|
284
|
+
const closeAccount = async (input) => {
|
|
285
|
+
await call(
|
|
286
|
+
() => opts.transport.client.auth.closeAccount({
|
|
287
|
+
confirmEmail: input.confirmEmail,
|
|
288
|
+
password: input.password
|
|
289
|
+
})
|
|
290
|
+
);
|
|
291
|
+
clearSession();
|
|
292
|
+
};
|
|
256
293
|
const _refresh = async () => {
|
|
257
294
|
let current = cached;
|
|
258
295
|
if (!current) {
|
|
@@ -274,8 +311,9 @@ function createAuthNamespace(opts) {
|
|
|
274
311
|
"session_refreshed"
|
|
275
312
|
);
|
|
276
313
|
} catch (err) {
|
|
277
|
-
|
|
278
|
-
|
|
314
|
+
const normalized = normalizeError(err);
|
|
315
|
+
if (isSessionRejected(normalized)) clearSession();
|
|
316
|
+
throw normalized;
|
|
279
317
|
}
|
|
280
318
|
};
|
|
281
319
|
const _signOutLocal = () => clearSession();
|
|
@@ -303,6 +341,7 @@ function createAuthNamespace(opts) {
|
|
|
303
341
|
listSessions,
|
|
304
342
|
revokeSession,
|
|
305
343
|
revokeOtherSessions,
|
|
344
|
+
closeAccount,
|
|
306
345
|
_refresh,
|
|
307
346
|
_signOutLocal
|
|
308
347
|
};
|
|
@@ -337,6 +376,7 @@ function createDataNamespaces(transport) {
|
|
|
337
376
|
exercises: wrapSlice(c.exercise),
|
|
338
377
|
programs: wrapSlice(c.program),
|
|
339
378
|
goals: wrapSlice(c.goal),
|
|
379
|
+
equipment: wrapSlice(c.equipment),
|
|
340
380
|
recipes: wrapSlice(c.recipe),
|
|
341
381
|
nutrition: wrapSlice(c.nutrition),
|
|
342
382
|
articles: wrapSlice(c.article),
|
|
@@ -437,15 +477,32 @@ function createTransport(options) {
|
|
|
437
477
|
};
|
|
438
478
|
}
|
|
439
479
|
var REFRESH_HEADER = "X-Fytkit-Refresh";
|
|
440
|
-
|
|
441
|
-
|
|
480
|
+
var CREDENTIAL_PROCEDURES = [
|
|
481
|
+
"auth/signIn",
|
|
482
|
+
"auth/signUp",
|
|
483
|
+
"auth/requestPasswordReset",
|
|
484
|
+
"auth/confirmPasswordReset",
|
|
485
|
+
"auth/confirmEmail",
|
|
486
|
+
"auth/verifyTotp",
|
|
487
|
+
"auth/verifyBackupCode",
|
|
488
|
+
"auth/requestEmailOtp",
|
|
489
|
+
"auth/verifyEmailOtp"
|
|
490
|
+
];
|
|
491
|
+
function requestPathname(request) {
|
|
442
492
|
try {
|
|
443
|
-
|
|
444
|
-
return path.endsWith("/auth/refresh");
|
|
493
|
+
return new URL(request.url).pathname;
|
|
445
494
|
} catch {
|
|
446
|
-
return
|
|
495
|
+
return "";
|
|
447
496
|
}
|
|
448
497
|
}
|
|
498
|
+
function isRefreshRequest(request) {
|
|
499
|
+
if (request.headers.get(REFRESH_HEADER) === "1") return true;
|
|
500
|
+
return requestPathname(request).endsWith("/auth/refresh");
|
|
501
|
+
}
|
|
502
|
+
function isCredentialRequest(request) {
|
|
503
|
+
const path = requestPathname(request);
|
|
504
|
+
return CREDENTIAL_PROCEDURES.some((procedure) => path.endsWith(`/${procedure}`));
|
|
505
|
+
}
|
|
449
506
|
function attachRefreshInterceptor(opts) {
|
|
450
507
|
let inflight = null;
|
|
451
508
|
const refreshOnce = () => {
|
|
@@ -457,7 +514,7 @@ function attachRefreshInterceptor(opts) {
|
|
|
457
514
|
return inflight;
|
|
458
515
|
};
|
|
459
516
|
opts.transport._setFetchInterceptor(async (request, next) => {
|
|
460
|
-
if (isRefreshRequest(request)) {
|
|
517
|
+
if (isRefreshRequest(request) || isCredentialRequest(request)) {
|
|
461
518
|
return next(request);
|
|
462
519
|
}
|
|
463
520
|
const buffered = await request.clone().arrayBuffer();
|
|
@@ -536,7 +593,8 @@ function createFytkitClient(options) {
|
|
|
536
593
|
changeEmail: authInstance.changeEmail,
|
|
537
594
|
listSessions: authInstance.listSessions,
|
|
538
595
|
revokeSession: authInstance.revokeSession,
|
|
539
|
-
revokeOtherSessions: authInstance.revokeOtherSessions
|
|
596
|
+
revokeOtherSessions: authInstance.revokeOtherSessions,
|
|
597
|
+
closeAccount: authInstance.closeAccount
|
|
540
598
|
},
|
|
541
599
|
...data
|
|
542
600
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/error.ts","../src/events.ts","../src/auth.ts","../src/data.ts","../src/storage.ts","../src/transport.ts","../src/index.ts"],"names":["cached"],"mappings":"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","file":"index.js","sourcesContent":["import { ORPCError } from \"@orpc/client\";\nimport type { FytkitError } from \"./types\";\n\ninterface MaybeIssuesData {\n issues?: readonly unknown[];\n}\ninterface MaybeRetryAfterData {\n retryAfterMs?: number;\n}\n\nfunction pickIssues(data: unknown): readonly unknown[] | null {\n if (!data || typeof data !== \"object\") return null;\n const issues = (data as MaybeIssuesData).issues;\n return Array.isArray(issues) ? issues : null;\n}\n\nfunction pickRetryAfter(data: unknown): number {\n if (!data || typeof data !== \"object\") return 0;\n const raw = (data as MaybeRetryAfterData).retryAfterMs;\n return typeof raw === \"number\" && raw >= 0 ? raw : 0;\n}\n\n/**\n * Map any error thrown by `@orpc/client` (or the underlying fetch) into the\n * SDK's `FytkitError` discriminated union. The SDK never re-throws raw orpc\n * or network errors at the public surface.\n */\nexport function normalizeError(err: unknown): FytkitError {\n // Network failures from fetch surface as TypeError.\n if (err instanceof TypeError) return { kind: \"network\" };\n\n if (err instanceof ORPCError) {\n const code = err.code;\n const status = err.status;\n const data: unknown = err.data;\n const message = err.message;\n\n switch (code) {\n case \"UNAUTHORIZED\":\n // Carry the server's reason (e.g. \"Invalid credentials\" on a failed\n // sign-in) so the consumer can show it instead of a generic\n // 'session expired' copy. The synthetic no-session case in auth.ts\n // is built directly and stays message-less.\n return { kind: \"auth_required\", message };\n case \"FORBIDDEN\":\n return { kind: \"forbidden\", reason: message || \"Forbidden\" };\n case \"PAYMENT_REQUIRED\":\n return { kind: \"payment_required\", message: message || \"Payment Required\" };\n case \"CONFLICT\":\n return { kind: \"conflict\", message: message || \"Conflict\" };\n case \"NOT_FOUND\":\n return { kind: \"not_found\" };\n case \"TOO_MANY_REQUESTS\":\n return { kind: \"rate_limited\", retryAfter: pickRetryAfter(data) };\n case \"BAD_REQUEST\":\n case \"UNPROCESSABLE_CONTENT\": {\n const issues = pickIssues(data);\n if (issues) return { kind: \"validation\", issues };\n // No structured issues — still carry the server's explanation so it\n // isn't dropped into a bare status code.\n return { kind: \"server\", status, message };\n }\n default:\n return { kind: \"server\", status, message };\n }\n }\n\n return { kind: \"server\", status: 0 };\n}\n","export interface EventBus<T> {\n readonly on: (listener: (value: T) => void) => () => void;\n readonly emit: (value: T) => void;\n}\n\nexport function createEventBus<T>(): EventBus<T> {\n const listeners = new Set<(value: T) => void>();\n return {\n on: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n emit: (value) => {\n for (const listener of listeners) {\n try {\n listener(value);\n } catch (err) {\n // A buggy listener must not break siblings or the calling flow.\n console.error(\"[fytkit-sdk] event listener threw\", err);\n }\n }\n },\n };\n}\n","import { normalizeError } from \"./error\";\nimport { createEventBus } from \"./events\";\nimport type { Transport } from \"./transport\";\nimport type {\n AuthState,\n FytkitError,\n SecurityStatus,\n Session,\n SessionInfo,\n SignInResult,\n TokenStorage,\n TotpEnrollment,\n TwoFactorChallenge,\n TwoFactorToken,\n} from \"./types\";\n\nexport interface AuthNamespaceOptions {\n readonly transport: Transport;\n readonly storage: TokenStorage;\n /** Called after the SDK signs out for any reason (manual, refresh failure). */\n readonly onSignedOut?: () => void;\n}\n\nexport interface AuthNamespace {\n readonly signUp: (input: { email: string; password: string; name: string }) => Promise<Session>;\n readonly signIn: (input: { email: string; password: string }) => Promise<SignInResult>;\n readonly signOut: () => Promise<void>;\n readonly getSession: () => Session | null;\n readonly onAuthStateChange: (listener: (state: AuthState) => void) => () => void;\n readonly requestPasswordReset: (input: { email: string }) => Promise<void>;\n readonly confirmPasswordReset: (input: { token: string; password: string }) => Promise<void>;\n readonly confirmEmail: (input: { token: string }) => Promise<void>;\n readonly verifyTotp: (input: {\n challenge: TwoFactorChallenge;\n code: string;\n }) => Promise<Session>;\n readonly verifyBackupCode: (input: {\n challenge: TwoFactorChallenge;\n code: string;\n }) => Promise<Session>;\n readonly requestEmailOtp: (input: { challenge: TwoFactorChallenge }) => Promise<void>;\n readonly verifyEmailOtp: (input: {\n challenge: TwoFactorChallenge;\n code: string;\n }) => Promise<Session>;\n readonly getSecurityStatus: () => Promise<SecurityStatus>;\n readonly enableTotp: (input: { password: string }) => Promise<TotpEnrollment>;\n readonly verifyTotpSetup: (input: { code: string }) => Promise<void>;\n readonly disableTwoFactor: (input: { password: string }) => Promise<void>;\n readonly regenerateBackupCodes: (input: { password: string }) => Promise<readonly string[]>;\n readonly changePassword: (input: {\n currentPassword: string;\n newPassword: string;\n revokeOtherSessions?: boolean;\n }) => Promise<void>;\n readonly changeEmail: (input: { newEmail: string }) => Promise<void>;\n readonly listSessions: () => Promise<readonly SessionInfo[]>;\n readonly revokeSession: (input: { revokeId: string }) => Promise<void>;\n readonly revokeOtherSessions: () => Promise<void>;\n /** Internal: force a refresh now. Wired by transport's 401 retry path. */\n readonly _refresh: () => Promise<Session>;\n /** Internal: clear cached session + emit signed_out. */\n readonly _signOutLocal: () => void;\n}\n\n/**\n * Schedule a proactive refresh this many ms before `expiresAt`. The\n * server-side access-token TTL is ~15 min so a 60-second lead time gives\n * us enough headroom to refresh transparently without burning sessions\n * needlessly while keeping the user signed-in across long-running tabs.\n */\nconst PROACTIVE_REFRESH_LEAD_MS = 60_000;\n\n/**\n * The auth namespace owns the cached session. It is the single writer to\n * `storage`; everything else reads via `getSession`. Calls that mutate\n * the session also emit on the event bus and (re)schedule the proactive\n * refresh timer against the new expiry.\n */\nexport function createAuthNamespace(opts: AuthNamespaceOptions): AuthNamespace {\n const bus = createEventBus<AuthState>();\n let cached: Session | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n // Forward declaration so scheduleRefresh can call the same _refresh body\n // the public surface exposes. Assigned at the bottom of the factory.\n let refreshFn: () => Promise<Session> = () => {\n throw new Error(\"refreshFn called before initialization\");\n };\n\n function clearTimer(): void {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n // `setTimeout` clamps any delay > 2^31-1 ms (~24.8 days) to 1 ms and\n // prints a Node deprecation warning. Sessions with an exotic far-future\n // expiry (test fixtures, mis-configured server) would otherwise fire the\n // timer instantly; cap the delay to the safe upper bound so the timer\n // simply re-arms on its next firing.\n const MAX_TIMEOUT_MS = 2_147_483_647;\n\n function scheduleRefresh(session: Session): void {\n clearTimer();\n const expiresMs = new Date(session.expiresAt).getTime();\n if (Number.isNaN(expiresMs)) return; // bad date — bail; reactive 401 path will handle it\n const rawDelay = expiresMs - Date.now() - PROACTIVE_REFRESH_LEAD_MS;\n const delay = Math.min(MAX_TIMEOUT_MS, Math.max(0, rawDelay));\n timer = setTimeout(() => {\n timer = null;\n void refreshFn().catch(() => {\n // refreshFn already handles sign-out on failure.\n });\n }, delay);\n }\n\n function applySession(session: Session, event: \"signed_in\" | \"session_refreshed\"): Session {\n cached = session;\n void opts.storage.set(session);\n bus.emit({ type: event, session });\n scheduleRefresh(session);\n return session;\n }\n\n function clearSession(emit = true): void {\n cached = null;\n clearTimer();\n void opts.storage.remove();\n if (emit) bus.emit({ type: \"signed_out\" });\n opts.onSignedOut?.();\n }\n\n async function call<T>(thunk: () => Promise<T>): Promise<T> {\n try {\n return await thunk();\n } catch (err) {\n throw normalizeError(err);\n }\n }\n\n // Best-effort hydrate at construction. If the storage already holds a\n // session (warm reload, second tab), restore it and arm the timer.\n void Promise.resolve(opts.storage.get()).then((s) => {\n if (s) {\n cached = s;\n scheduleRefresh(s);\n }\n });\n\n const signUp: AuthNamespace[\"signUp\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.signUp(input));\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const signIn: AuthNamespace[\"signIn\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.signIn(input));\n if (result.data.kind === \"two_factor_required\") {\n // Mint the branded token exactly once at the network boundary.\n const token = result.data.twoFactorToken as TwoFactorToken;\n return {\n kind: \"two_factor_required\",\n challenge: { token, availableMethods: result.data.availableMethods },\n };\n }\n if (result.data.kind === \"signed_in\") {\n const { user, session } = result.data;\n const cached = applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n return { kind: \"signed_in\", session: cached };\n }\n // Exhaustiveness guard — a future server-side variant must not silently fall through.\n const _exhaustive: never = result.data;\n throw _exhaustive;\n };\n\n const signOut: AuthNamespace[\"signOut\"] = async () => {\n const current = cached;\n if (!current) return;\n try {\n await opts.transport.client.auth.signOut({ token: current.accessToken });\n } catch (err) {\n // Even if the server rejects (e.g. token already revoked), clear\n // the local cache so the user is signed out client-side.\n void err;\n }\n clearSession();\n };\n\n const getSession: AuthNamespace[\"getSession\"] = () => cached;\n const onAuthStateChange: AuthNamespace[\"onAuthStateChange\"] = (listener) => bus.on(listener);\n\n const requestPasswordReset: AuthNamespace[\"requestPasswordReset\"] = async (input) => {\n await call(() => opts.transport.client.auth.requestPasswordReset(input));\n };\n const confirmPasswordReset: AuthNamespace[\"confirmPasswordReset\"] = async (input) => {\n await call(() => opts.transport.client.auth.confirmPasswordReset(input));\n };\n const confirmEmail: AuthNamespace[\"confirmEmail\"] = async (input) => {\n await call(() => opts.transport.client.auth.confirmEmail(input));\n };\n\n // --- Two-factor sign-in completion -----------------------------------------\n //\n // Each consumes the challenge minted by `signIn` and, on success, caches the\n // issued session exactly like the signed_in branch of `signIn`.\n\n const verifyTotp: AuthNamespace[\"verifyTotp\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyTotp({ token: input.challenge.token, code: input.code }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const verifyBackupCode: AuthNamespace[\"verifyBackupCode\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyBackupCode({\n token: input.challenge.token,\n code: input.code,\n }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const requestEmailOtp: AuthNamespace[\"requestEmailOtp\"] = async (input) => {\n await call(() => opts.transport.client.auth.requestEmailOtp({ token: input.challenge.token }));\n };\n\n const verifyEmailOtp: AuthNamespace[\"verifyEmailOtp\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyEmailOtp({ token: input.challenge.token, code: input.code }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n /**\n * The server rotated the calling session and returned the replacement token\n * (TOTP-setup verification and password change with revokeOtherSessions do\n * this). Swap the cached token immediately — the old bearer is already dead,\n * so any request between now and the swap would 401. `expiresAt` is carried\n * over from the old session; it is at worst *earlier* than the new session's\n * real expiry, so the proactive refresh timer fires early and corrects it.\n */\n function adoptRotatedToken(accessToken: string): void {\n const current = cached;\n if (!current || !accessToken || accessToken === current.accessToken) return;\n applySession({ ...current, accessToken }, \"session_refreshed\");\n }\n\n const getSecurityStatus: AuthNamespace[\"getSecurityStatus\"] = async () => {\n const result = await call(() => opts.transport.client.auth.getSecurityStatus());\n return result.data;\n };\n\n const enableTotp: AuthNamespace[\"enableTotp\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.enableTotp(input));\n return result.data;\n };\n\n const verifyTotpSetup: AuthNamespace[\"verifyTotpSetup\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.verifyTotpSetup(input));\n adoptRotatedToken(result.data.accessToken);\n };\n\n const disableTwoFactor: AuthNamespace[\"disableTwoFactor\"] = async (input) => {\n await call(() => opts.transport.client.auth.disableTwoFactor(input));\n };\n\n const regenerateBackupCodes: AuthNamespace[\"regenerateBackupCodes\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.regenerateBackupCodes(input));\n return result.data.backupCodes;\n };\n\n // --- Account security -------------------------------------------------------\n\n const changePassword: AuthNamespace[\"changePassword\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.changePassword({\n currentPassword: input.currentPassword,\n newPassword: input.newPassword,\n revokeOtherSessions: input.revokeOtherSessions,\n }),\n );\n adoptRotatedToken(result.data.accessToken);\n };\n\n const changeEmail: AuthNamespace[\"changeEmail\"] = async (input) => {\n await call(() => opts.transport.client.auth.changeEmail(input));\n };\n\n const listSessions: AuthNamespace[\"listSessions\"] = async () => {\n const result = await call(() => opts.transport.client.auth.listSessions());\n return result.data;\n };\n\n const revokeSession: AuthNamespace[\"revokeSession\"] = async (input) => {\n await call(() => opts.transport.client.auth.revokeSession(input));\n };\n\n const revokeOtherSessions: AuthNamespace[\"revokeOtherSessions\"] = async () => {\n await call(() => opts.transport.client.auth.revokeOtherSessions());\n };\n\n const _refresh: AuthNamespace[\"_refresh\"] = async () => {\n // Re-read storage as a fallback so a session written after\n // construction (e.g. on tab restore or in tests) is honoured.\n let current = cached;\n if (!current) {\n const fromStorage = await Promise.resolve(opts.storage.get());\n if (fromStorage) {\n cached = fromStorage;\n current = fromStorage;\n }\n }\n if (!current) {\n const err: FytkitError = { kind: \"auth_required\" };\n throw err;\n }\n try {\n const result = await opts.transport.client.auth.refresh({ token: current.accessToken });\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"session_refreshed\",\n );\n } catch (err) {\n clearSession();\n throw normalizeError(err);\n }\n };\n\n const _signOutLocal: AuthNamespace[\"_signOutLocal\"] = () => clearSession();\n\n refreshFn = _refresh;\n\n return {\n signUp,\n signIn,\n signOut,\n getSession,\n onAuthStateChange,\n requestPasswordReset,\n confirmPasswordReset,\n confirmEmail,\n verifyTotp,\n verifyBackupCode,\n requestEmailOtp,\n verifyEmailOtp,\n getSecurityStatus,\n enableTotp,\n verifyTotpSetup,\n disableTwoFactor,\n regenerateBackupCodes,\n changePassword,\n changeEmail,\n listSessions,\n revokeSession,\n revokeOtherSessions,\n _refresh,\n _signOutLocal,\n };\n}\n","import { normalizeError } from \"./error\";\nimport type { Transport } from \"./transport\";\n\n/**\n * Wrap every method on a public-router slice so thrown ORPCErrors become\n * normalised FytkitErrors at the SDK boundary.\n *\n * The slice we receive is an `@orpc/client` Proxy whose own keys are not\n * enumerable — every property lookup is intercepted lazily. We mirror that\n * shape by returning a Proxy of our own that wraps each function on first\n * access and caches the result. This way the SDK never needs to know the\n * method names ahead of time, and the typed shape from the server router\n * flows through unchanged.\n */\nfunction wrapSlice<T extends object>(slice: T): T {\n const cache = new Map<string | symbol, unknown>();\n return new Proxy(slice, {\n get(target, prop, receiver) {\n if (cache.has(prop)) return cache.get(prop);\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== \"function\") {\n // Allow nested namespaces to flow through unchanged (the orpc\n // proxy returns another proxy here, not a plain object).\n return value;\n }\n const wrapped = async (...args: unknown[]) => {\n try {\n return await (value as (...a: unknown[]) => Promise<unknown>)(...args);\n } catch (err) {\n throw normalizeError(err);\n }\n };\n cache.set(prop, wrapped);\n return wrapped;\n },\n }) as T;\n}\n\nexport interface DataNamespaces {\n readonly workouts: Transport[\"client\"][\"workout\"];\n readonly exercises: Transport[\"client\"][\"exercise\"];\n readonly programs: Transport[\"client\"][\"program\"];\n readonly goals: Transport[\"client\"][\"goal\"];\n readonly recipes: Transport[\"client\"][\"recipe\"];\n readonly nutrition: Transport[\"client\"][\"nutrition\"];\n readonly articles: Transport[\"client\"][\"article\"];\n readonly enrollments: Transport[\"client\"][\"enrollment\"];\n readonly favourites: Transport[\"client\"][\"favourite\"];\n readonly sessionLogs: Transport[\"client\"][\"sessionLog\"];\n readonly progression: Transport[\"client\"][\"progression\"];\n readonly bodyMetrics: Transport[\"client\"][\"bodyMetric\"];\n readonly progress: Transport[\"client\"][\"progress\"];\n readonly media: Transport[\"client\"][\"media\"];\n readonly appConfig: Transport[\"client\"][\"appConfig\"];\n readonly subscription: Transport[\"client\"][\"subscription\"];\n readonly profile: Transport[\"client\"][\"profile\"];\n readonly nutritionLog: Transport[\"client\"][\"nutritionLog\"];\n readonly preferences: Transport[\"client\"][\"preferences\"];\n}\n\nexport function createDataNamespaces(transport: Transport): DataNamespaces {\n const c = transport.client;\n return {\n workouts: wrapSlice(c.workout),\n exercises: wrapSlice(c.exercise),\n programs: wrapSlice(c.program),\n goals: wrapSlice(c.goal),\n recipes: wrapSlice(c.recipe),\n nutrition: wrapSlice(c.nutrition),\n articles: wrapSlice(c.article),\n enrollments: wrapSlice(c.enrollment),\n favourites: wrapSlice(c.favourite),\n sessionLogs: wrapSlice(c.sessionLog),\n progression: wrapSlice(c.progression),\n bodyMetrics: wrapSlice(c.bodyMetric),\n progress: wrapSlice(c.progress),\n media: wrapSlice(c.media),\n appConfig: wrapSlice(c.appConfig),\n subscription: wrapSlice(c.subscription),\n profile: wrapSlice(c.profile),\n nutritionLog: wrapSlice(c.nutritionLog),\n preferences: wrapSlice(c.preferences),\n };\n}\n","import type { Session, TokenStorage } from \"./types\";\n\nconst STORAGE_KEY_PREFIX = \"fytkit:\";\nconst STORAGE_KEY_SUFFIX = \":tokens\";\n\nfunction keyFor(clientId: string): string {\n return `${STORAGE_KEY_PREFIX}${clientId}${STORAGE_KEY_SUFFIX}`;\n}\n\nfunction isValidSession(value: unknown): value is Session {\n if (!value || typeof value !== \"object\") return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.accessToken === \"string\" &&\n typeof v.expiresAt === \"string\" &&\n typeof v.user === \"object\" &&\n v.user !== null &&\n typeof (v.user as { id?: unknown }).id === \"string\" &&\n typeof (v.user as { email?: unknown }).email === \"string\"\n );\n}\n\n/**\n * Default web storage. Reads/writes JSON under `fytkit:{clientId}:tokens`.\n * Silently no-ops when localStorage throws (Safari private mode, SSR).\n */\nexport function createLocalStorageAdapter(clientId: string): TokenStorage {\n const key = keyFor(clientId);\n return {\n get: () => {\n try {\n const raw = globalThis.localStorage?.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n return isValidSession(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n set: (session: Session) => {\n try {\n globalThis.localStorage?.setItem(key, JSON.stringify(session));\n } catch {\n // Quota / private-mode / SSR — swallow and let the caller treat the\n // session as in-memory-only for this tab.\n }\n },\n remove: () => {\n try {\n globalThis.localStorage?.removeItem(key);\n } catch {\n // see set() rationale\n }\n },\n };\n}\n\n/** In-memory storage. Useful for tests and SSR. */\nexport function createMemoryStorageAdapter(): TokenStorage {\n let current: Session | null = null;\n return {\n get: () => current,\n set: (session: Session) => {\n current = session;\n },\n remove: () => {\n current = null;\n },\n };\n}\n","import type { PublicApi } from \"@fytkit/types\";\nimport { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { Session } from \"./types\";\n\nexport interface CreateTransportOptions {\n readonly baseUrl: string;\n readonly clientId: string;\n readonly getSession: () => Session | null;\n readonly fetch?: typeof fetch;\n}\n\nexport interface Transport {\n readonly client: PublicApi;\n /** Internal: hook for attachRefreshInterceptor to install a fetch wrapper. */\n readonly _setFetchInterceptor: (interceptor: FetchInterceptor) => void;\n}\n\ntype FetchInterceptor = (\n request: Request,\n next: (req: Request) => Promise<Response>,\n) => Promise<Response>;\n\nexport function createTransport(options: CreateTransportOptions): Transport {\n let interceptor: FetchInterceptor | null = null;\n const baseFetch: typeof fetch = options.fetch ?? fetch.bind(globalThis);\n\n // The fetch handed to RPCLink resolves the interceptor lazily so callers\n // can install one after construction (see attachRefreshInterceptor).\n const wrappedFetch: typeof fetch = (input, init) => {\n const request = input instanceof Request ? input : new Request(input, init);\n const next = (req: Request) => baseFetch(req);\n if (!interceptor) return next(request);\n return interceptor(request, next);\n };\n\n const link = new RPCLink({\n url: () => `${options.baseUrl}/rpc`,\n headers: () => {\n const session = options.getSession();\n const headers: Record<string, string> = {\n \"X-Fytkit-Client-Id\": options.clientId,\n };\n if (session) {\n headers.Authorization = `Bearer ${session.accessToken}`;\n }\n return headers;\n },\n fetch: wrappedFetch,\n });\n\n const client: PublicApi = createORPCClient(link);\n return {\n client,\n _setFetchInterceptor: (i) => {\n interceptor = i;\n },\n };\n}\n\n/** Internal marker header — set on the refresh call so we never recurse. */\nconst REFRESH_HEADER = \"X-Fytkit-Refresh\";\n\n/**\n * Detect whether a request targets the refresh procedure. The RPCLink\n * routes per-procedure calls under a URL whose pathname ends with the\n * procedure path (joined as `/segment/segment`), so we look for the\n * `auth/refresh` suffix. We use endsWith so trailing query strings or\n * link-level prefixes do not break detection.\n */\nfunction isRefreshRequest(request: Request): boolean {\n if (request.headers.get(REFRESH_HEADER) === \"1\") return true;\n try {\n const path = new URL(request.url).pathname;\n return path.endsWith(\"/auth/refresh\");\n } catch {\n return false;\n }\n}\n\nexport interface AttachRefreshInterceptorOptions {\n readonly transport: Transport;\n readonly auth: {\n readonly _refresh: () => Promise<Session>;\n readonly _signOutLocal: () => void;\n readonly getSession: () => Session | null;\n };\n}\n\n/**\n * Install a fetch interceptor that, on a 401 response, calls auth._refresh\n * once and retries the original request. Concurrent 401s de-duplicate\n * onto a single in-flight refresh promise. A 401 from refresh itself or\n * from the retry triggers a local sign-out and propagates the original\n * 401 to the caller (after which orpc throws ORPCError(\"UNAUTHORIZED\")).\n */\nexport function attachRefreshInterceptor(opts: AttachRefreshInterceptorOptions): void {\n let inflight: Promise<Session> | null = null;\n\n const refreshOnce = (): Promise<Session> => {\n if (!inflight) {\n inflight = opts.auth._refresh().finally(() => {\n inflight = null;\n });\n }\n return inflight;\n };\n\n opts.transport._setFetchInterceptor(async (request, next) => {\n // Refresh calls must never trigger a recursive refresh.\n if (isRefreshRequest(request)) {\n return next(request);\n }\n\n // Capture the request body now, before we pass `request` to `next` —\n // once fetch consumes a Request body it can no longer be cloned.\n const buffered = await request.clone().arrayBuffer();\n\n const firstResponse = await next(request);\n if (firstResponse.status !== 401) return firstResponse;\n\n try {\n await refreshOnce();\n } catch {\n // _refresh already called clearSession + emitted signed_out.\n return firstResponse;\n }\n\n // Rebuild headers so the new Authorization header replaces the stale\n // one — the RPCLink only re-evaluates its own `headers()` once per call,\n // so we patch the bearer ourselves here.\n const replayedHeaders = new Headers(request.headers);\n const session = opts.auth.getSession();\n if (session) {\n replayedHeaders.set(\"Authorization\", `Bearer ${session.accessToken}`);\n } else {\n replayedHeaders.delete(\"Authorization\");\n }\n const replayed = new Request(request.url, {\n method: request.method,\n headers: replayedHeaders,\n body: buffered.byteLength > 0 ? buffered : undefined,\n credentials: request.credentials,\n mode: request.mode,\n cache: request.cache,\n redirect: request.redirect,\n referrer: request.referrer,\n integrity: request.integrity,\n });\n\n const retried = await next(replayed);\n if (retried.status === 401) {\n // Refresh succeeded server-side but the server still rejects — the\n // session is dead. Sign out locally and let orpc surface the 401.\n opts.auth._signOutLocal();\n }\n return retried;\n });\n}\n","import { createAuthNamespace } from \"./auth\";\nimport { createDataNamespaces } from \"./data\";\nimport { createLocalStorageAdapter, createMemoryStorageAdapter } from \"./storage\";\nimport { attachRefreshInterceptor, createTransport } from \"./transport\";\nimport type { FytkitClient, FytkitClientOptions } from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://api.fytkit.com\";\n\nexport function createFytkitClient(options: FytkitClientOptions): FytkitClient {\n if (!options || typeof options.clientId !== \"string\" || options.clientId.length === 0) {\n throw new Error(\"createFytkitClient: `clientId` is required\");\n }\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const storage = options.storage ?? createLocalStorageAdapter(options.clientId);\n\n // `auth` is declared after `transport` because `createAuthNamespace`\n // needs the transport to make its RPC calls. The transport in turn needs\n // a `getSession` that reads the auth cache — we resolve the cycle with a\n // late-bound reference: the closure below reads `auth` lazily, which is\n // safe because no request can fire before construction finishes.\n let auth: ReturnType<typeof createAuthNamespace> | null = null;\n\n const transport = createTransport({\n baseUrl,\n clientId: options.clientId,\n getSession: () => auth?.getSession() ?? null,\n fetch: options.fetch,\n });\n\n const authInstance = createAuthNamespace({ transport, storage });\n auth = authInstance;\n attachRefreshInterceptor({ transport, auth: authInstance });\n\n const data = createDataNamespaces(transport);\n\n return {\n auth: {\n signUp: authInstance.signUp,\n signIn: authInstance.signIn,\n signOut: authInstance.signOut,\n getSession: authInstance.getSession,\n onAuthStateChange: authInstance.onAuthStateChange,\n requestPasswordReset: authInstance.requestPasswordReset,\n confirmPasswordReset: authInstance.confirmPasswordReset,\n confirmEmail: authInstance.confirmEmail,\n verifyTotp: authInstance.verifyTotp,\n verifyBackupCode: authInstance.verifyBackupCode,\n requestEmailOtp: authInstance.requestEmailOtp,\n verifyEmailOtp: authInstance.verifyEmailOtp,\n getSecurityStatus: authInstance.getSecurityStatus,\n enableTotp: authInstance.enableTotp,\n verifyTotpSetup: authInstance.verifyTotpSetup,\n disableTwoFactor: authInstance.disableTwoFactor,\n regenerateBackupCodes: authInstance.regenerateBackupCodes,\n changePassword: authInstance.changePassword,\n changeEmail: authInstance.changeEmail,\n listSessions: authInstance.listSessions,\n revokeSession: authInstance.revokeSession,\n revokeOtherSessions: authInstance.revokeOtherSessions,\n },\n ...data,\n };\n}\n\n// Public re-exports.\nexport { createLocalStorageAdapter, createMemoryStorageAdapter };\nexport type {\n AuthState,\n FytkitClient,\n FytkitClientOptions,\n FytkitError,\n SecurityStatus,\n Session,\n SessionInfo,\n SignInResult,\n TokenStorage,\n TotpEnrollment,\n TwoFactorChallenge,\n TwoFactorMethod,\n TwoFactorToken,\n} from \"./types\";\n// `PublicApi` is the inferred router type that backs every namespace\n// on `FytkitClient` (e.g. `client.workouts` is `PublicApi[\"workout\"]`).\n// Re-exported so consumers can write generics over the router shape —\n// previously this surfaced as an `ae-forgotten-export` warning on\n// `FytkitClient` in the api-extractor report. The api-extractor will\n// still warn about `PublicRouter`/`publicRouter` being unexported —\n// that is intentional, those are implementation-detail names from the\n// generated snapshot that should not be part of the consumer surface.\nexport type { PublicApi } from \"@fytkit/types\";\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/error.ts","../src/events.ts","../src/auth.ts","../src/data.ts","../src/storage.ts","../src/transport.ts","../src/index.ts"],"names":["cached"],"mappings":"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","file":"index.js","sourcesContent":["import { ORPCError } from \"@orpc/client\";\nimport type { FytkitError } from \"./types\";\n\ninterface MaybeIssuesData {\n issues?: readonly unknown[];\n}\ninterface MaybeRetryAfterData {\n retryAfterMs?: number;\n}\n\nfunction pickIssues(data: unknown): readonly unknown[] | null {\n if (!data || typeof data !== \"object\") return null;\n const issues = (data as MaybeIssuesData).issues;\n return Array.isArray(issues) ? issues : null;\n}\n\nfunction pickRetryAfter(data: unknown): number {\n if (!data || typeof data !== \"object\") return 0;\n const raw = (data as MaybeRetryAfterData).retryAfterMs;\n return typeof raw === \"number\" && raw >= 0 ? raw : 0;\n}\n\n/**\n * A non-empty string field of the error's `data`, when the server sent one:\n * `code` (the machine-readable reason, e.g. \"invalid_password\") or\n * `enrollmentId` (the existing enrolment on \"Already enrolled\"). Returned as\n * a spread-able object so kinds only gain the key when there is a value —\n * existing `toEqual` shapes stay intact.\n */\nfunction pickStringField<K extends \"code\" | \"enrollmentId\">(\n data: unknown,\n key: K,\n): { [P in K]?: string } {\n if (!data || typeof data !== \"object\") return {};\n const raw = (data as Partial<Record<K, unknown>>)[key];\n return typeof raw === \"string\" && raw.length > 0 ? ({ [key]: raw } as { [P in K]?: string }) : {};\n}\n\n/**\n * Map any error thrown by `@orpc/client` (or the underlying fetch) into the\n * SDK's `FytkitError` discriminated union. The SDK never re-throws raw orpc\n * or network errors at the public surface.\n */\nexport function normalizeError(err: unknown): FytkitError {\n // Network failures from fetch surface as TypeError.\n if (err instanceof TypeError) return { kind: \"network\" };\n\n if (err instanceof ORPCError) {\n const code = err.code;\n const status = err.status;\n const data: unknown = err.data;\n const message = err.message;\n\n switch (code) {\n case \"UNAUTHORIZED\":\n // Carry the server's reason (e.g. \"Invalid credentials\" on a failed\n // sign-in) so the consumer can show it instead of a generic\n // 'session expired' copy. The synthetic no-session case in auth.ts\n // is built directly and stays message-less.\n return { kind: \"auth_required\", message };\n case \"FORBIDDEN\":\n return {\n kind: \"forbidden\",\n reason: message || \"Forbidden\",\n ...pickStringField(data, \"code\"),\n };\n case \"PAYMENT_REQUIRED\":\n return { kind: \"payment_required\", message: message || \"Payment Required\" };\n case \"CONFLICT\":\n return {\n kind: \"conflict\",\n message: message || \"Conflict\",\n ...pickStringField(data, \"enrollmentId\"),\n };\n case \"NOT_FOUND\":\n return { kind: \"not_found\" };\n case \"TOO_MANY_REQUESTS\":\n return { kind: \"rate_limited\", retryAfter: pickRetryAfter(data) };\n case \"BAD_REQUEST\":\n case \"UNPROCESSABLE_CONTENT\": {\n const issues = pickIssues(data);\n if (issues) return { kind: \"validation\", issues };\n // No structured issues — still carry the server's explanation (and\n // its code, e.g. \"invalid_password\") so it isn't dropped into a bare\n // status code.\n return { kind: \"server\", status, message, ...pickStringField(data, \"code\") };\n }\n default:\n return { kind: \"server\", status, message, ...pickStringField(data, \"code\") };\n }\n }\n\n return { kind: \"server\", status: 0 };\n}\n","export interface EventBus<T> {\n readonly on: (listener: (value: T) => void) => () => void;\n readonly emit: (value: T) => void;\n}\n\nexport function createEventBus<T>(): EventBus<T> {\n const listeners = new Set<(value: T) => void>();\n return {\n on: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n emit: (value) => {\n for (const listener of listeners) {\n try {\n listener(value);\n } catch (err) {\n // A buggy listener must not break siblings or the calling flow.\n console.error(\"[fytkit-sdk] event listener threw\", err);\n }\n }\n },\n };\n}\n","import { normalizeError } from \"./error\";\nimport { createEventBus } from \"./events\";\nimport type { Transport } from \"./transport\";\nimport type {\n AuthState,\n FytkitError,\n SecurityStatus,\n Session,\n SessionInfo,\n SignInResult,\n TokenStorage,\n TotpEnrollment,\n TwoFactorChallenge,\n TwoFactorToken,\n} from \"./types\";\n\nexport interface AuthNamespaceOptions {\n readonly transport: Transport;\n readonly storage: TokenStorage;\n /** Called after the SDK signs out for any reason (manual, refresh failure). */\n readonly onSignedOut?: () => void;\n}\n\nexport interface AuthNamespace {\n readonly signUp: (input: { email: string; password: string; name: string }) => Promise<Session>;\n readonly signIn: (input: { email: string; password: string }) => Promise<SignInResult>;\n readonly signOut: () => Promise<void>;\n readonly getSession: () => Session | null;\n readonly onAuthStateChange: (listener: (state: AuthState) => void) => () => void;\n readonly requestPasswordReset: (input: { email: string }) => Promise<void>;\n readonly confirmPasswordReset: (input: { token: string; password: string }) => Promise<void>;\n readonly confirmEmail: (input: { token: string }) => Promise<void>;\n readonly verifyTotp: (input: { challenge: TwoFactorChallenge; code: string }) => Promise<Session>;\n readonly verifyBackupCode: (input: {\n challenge: TwoFactorChallenge;\n code: string;\n }) => Promise<Session>;\n readonly requestEmailOtp: (input: { challenge: TwoFactorChallenge }) => Promise<void>;\n readonly verifyEmailOtp: (input: {\n challenge: TwoFactorChallenge;\n code: string;\n }) => Promise<Session>;\n readonly getSecurityStatus: () => Promise<SecurityStatus>;\n readonly enableTotp: (input: { password: string }) => Promise<TotpEnrollment>;\n readonly verifyTotpSetup: (input: { code: string }) => Promise<void>;\n readonly disableTwoFactor: (input: { password: string }) => Promise<void>;\n readonly regenerateBackupCodes: (input: { password: string }) => Promise<readonly string[]>;\n readonly changePassword: (input: {\n currentPassword: string;\n newPassword: string;\n revokeOtherSessions?: boolean;\n }) => Promise<void>;\n readonly changeEmail: (input: { newEmail: string }) => Promise<void>;\n readonly listSessions: () => Promise<readonly SessionInfo[]>;\n readonly revokeSession: (input: { revokeId: string }) => Promise<void>;\n readonly revokeOtherSessions: () => Promise<void>;\n readonly closeAccount: (input: { confirmEmail: string; password: string }) => Promise<void>;\n /** Internal: force a refresh now. Wired by transport's 401 retry path. */\n readonly _refresh: () => Promise<Session>;\n /** Internal: clear cached session + emit signed_out. */\n readonly _signOutLocal: () => void;\n}\n\n/**\n * Schedule a proactive refresh this many ms before `expiresAt`. The token\n * is a server session (7 days, extended on use), and a 60-second lead time\n * refreshes it transparently in long-running tabs without refreshing\n * needlessly.\n */\nconst PROACTIVE_REFRESH_LEAD_MS = 60_000;\n\n/**\n * When a proactive refresh fails for a reason other than the server rejecting\n * the token (offline, 5xx, rate limit), the session is kept and the timer\n * retries with exponential backoff: 5 s, 10 s, 20 s … capped at 5 min, for\n * at most this many attempts. After that the SDK stops polling; the next\n * request's reactive 401 path takes over if the token has actually lapsed.\n */\nconst REFRESH_RETRY_BASE_MS = 5_000;\nconst REFRESH_RETRY_MAX_MS = 5 * 60_000;\nconst REFRESH_MAX_RETRIES = 6;\n\n/**\n * Only an explicit server rejection of the token (401/403) ends the session.\n * Network failures, 5xx and rate limits say nothing about the token, so\n * signing the member out on them would be wrong — and on a phone that drops\n * signal it signs members out constantly.\n */\nfunction isSessionRejected(err: FytkitError): boolean {\n return err.kind === \"auth_required\" || err.kind === \"forbidden\";\n}\n\nfunction refreshRetryDelay(attempt: number, err: FytkitError): number {\n const backoff = Math.min(REFRESH_RETRY_MAX_MS, REFRESH_RETRY_BASE_MS * 2 ** attempt);\n // Honour the server's rate-limit window when it is longer than our backoff.\n return err.kind === \"rate_limited\" ? Math.max(backoff, err.retryAfter) : backoff;\n}\n\n/**\n * The auth namespace owns the cached session. It is the single writer to\n * `storage`; everything else reads via `getSession`. Calls that mutate\n * the session also emit on the event bus and (re)schedule the proactive\n * refresh timer against the new expiry.\n */\nexport function createAuthNamespace(opts: AuthNamespaceOptions): AuthNamespace {\n const bus = createEventBus<AuthState>();\n let cached: Session | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n // Forward declaration so scheduleRefresh can call the same _refresh body\n // the public surface exposes. Assigned at the bottom of the factory.\n let refreshFn: () => Promise<Session> = () => {\n throw new Error(\"refreshFn called before initialization\");\n };\n\n function clearTimer(): void {\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n // `setTimeout` clamps any delay > 2^31-1 ms (~24.8 days) to 1 ms and\n // prints a Node deprecation warning. Sessions with an exotic far-future\n // expiry (test fixtures, mis-configured server) would otherwise fire the\n // timer instantly; cap the delay to the safe upper bound so the timer\n // simply re-arms on its next firing.\n const MAX_TIMEOUT_MS = 2_147_483_647;\n\n // `attempt` counts consecutive failed proactive refreshes; 0 for the\n // expiry-driven firing, 1+ for backoff retries.\n function armRefreshTimer(delay: number, attempt: number): void {\n clearTimer();\n timer = setTimeout(() => {\n timer = null;\n void refreshFn().catch((err: FytkitError) => {\n // A rejected token already cleared the session inside _refresh.\n // Otherwise keep it and retry — unless something re-armed the timer\n // meanwhile (a sign-in, a rotated token) or we are out of attempts.\n if (cached === null || timer !== null || attempt >= REFRESH_MAX_RETRIES) return;\n armRefreshTimer(refreshRetryDelay(attempt, err), attempt + 1);\n });\n }, delay);\n }\n\n function scheduleRefresh(session: Session): void {\n clearTimer();\n const expiresMs = new Date(session.expiresAt).getTime();\n if (Number.isNaN(expiresMs)) return; // bad date — bail; reactive 401 path will handle it\n const rawDelay = expiresMs - Date.now() - PROACTIVE_REFRESH_LEAD_MS;\n armRefreshTimer(Math.min(MAX_TIMEOUT_MS, Math.max(0, rawDelay)), 0);\n }\n\n function applySession(session: Session, event: \"signed_in\" | \"session_refreshed\"): Session {\n cached = session;\n void opts.storage.set(session);\n bus.emit({ type: event, session });\n scheduleRefresh(session);\n return session;\n }\n\n function clearSession(emit = true): void {\n cached = null;\n clearTimer();\n void opts.storage.remove();\n if (emit) bus.emit({ type: \"signed_out\" });\n opts.onSignedOut?.();\n }\n\n async function call<T>(thunk: () => Promise<T>): Promise<T> {\n try {\n return await thunk();\n } catch (err) {\n throw normalizeError(err);\n }\n }\n\n // Best-effort hydrate at construction. If the storage already holds a\n // session (warm reload, second tab), restore it and arm the timer.\n void Promise.resolve(opts.storage.get()).then((s) => {\n if (s) {\n cached = s;\n scheduleRefresh(s);\n }\n });\n\n const signUp: AuthNamespace[\"signUp\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.signUp(input));\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const signIn: AuthNamespace[\"signIn\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.signIn(input));\n if (result.data.kind === \"two_factor_required\") {\n // Mint the branded token exactly once at the network boundary.\n const token = result.data.twoFactorToken as TwoFactorToken;\n return {\n kind: \"two_factor_required\",\n challenge: { token, availableMethods: result.data.availableMethods },\n };\n }\n if (result.data.kind === \"signed_in\") {\n const { user, session } = result.data;\n const cached = applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n return { kind: \"signed_in\", session: cached };\n }\n // Exhaustiveness guard — a future server-side variant must not silently fall through.\n const _exhaustive: never = result.data;\n throw _exhaustive;\n };\n\n const signOut: AuthNamespace[\"signOut\"] = async () => {\n const current = cached;\n if (!current) return;\n try {\n await opts.transport.client.auth.signOut({ token: current.accessToken });\n } catch (err) {\n // Even if the server rejects (e.g. token already revoked), clear\n // the local cache so the user is signed out client-side.\n void err;\n }\n clearSession();\n };\n\n const getSession: AuthNamespace[\"getSession\"] = () => cached;\n const onAuthStateChange: AuthNamespace[\"onAuthStateChange\"] = (listener) => bus.on(listener);\n\n const requestPasswordReset: AuthNamespace[\"requestPasswordReset\"] = async (input) => {\n await call(() => opts.transport.client.auth.requestPasswordReset(input));\n };\n const confirmPasswordReset: AuthNamespace[\"confirmPasswordReset\"] = async (input) => {\n await call(() => opts.transport.client.auth.confirmPasswordReset(input));\n };\n const confirmEmail: AuthNamespace[\"confirmEmail\"] = async (input) => {\n await call(() => opts.transport.client.auth.confirmEmail(input));\n };\n\n // --- Two-factor sign-in completion -----------------------------------------\n //\n // Each consumes the challenge minted by `signIn` and, on success, caches the\n // issued session exactly like the signed_in branch of `signIn`.\n\n const verifyTotp: AuthNamespace[\"verifyTotp\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyTotp({ token: input.challenge.token, code: input.code }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const verifyBackupCode: AuthNamespace[\"verifyBackupCode\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyBackupCode({\n token: input.challenge.token,\n code: input.code,\n }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n const requestEmailOtp: AuthNamespace[\"requestEmailOtp\"] = async (input) => {\n await call(() => opts.transport.client.auth.requestEmailOtp({ token: input.challenge.token }));\n };\n\n const verifyEmailOtp: AuthNamespace[\"verifyEmailOtp\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.verifyEmailOtp({ token: input.challenge.token, code: input.code }),\n );\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"signed_in\",\n );\n };\n\n /**\n * The server rotated the calling session and returned the replacement token\n * (TOTP-setup verification and password change with revokeOtherSessions do\n * this). Swap the cached token immediately — the old bearer is already dead,\n * so any request between now and the swap would 401. `expiresAt` is carried\n * over from the old session; it is at worst *earlier* than the new session's\n * real expiry, so the proactive refresh timer fires early and corrects it.\n */\n function adoptRotatedToken(accessToken: string): void {\n const current = cached;\n if (!current || !accessToken || accessToken === current.accessToken) return;\n applySession({ ...current, accessToken }, \"session_refreshed\");\n }\n\n const getSecurityStatus: AuthNamespace[\"getSecurityStatus\"] = async () => {\n const result = await call(() => opts.transport.client.auth.getSecurityStatus());\n return result.data;\n };\n\n const enableTotp: AuthNamespace[\"enableTotp\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.enableTotp(input));\n return result.data;\n };\n\n const verifyTotpSetup: AuthNamespace[\"verifyTotpSetup\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.verifyTotpSetup(input));\n adoptRotatedToken(result.data.accessToken);\n };\n\n const disableTwoFactor: AuthNamespace[\"disableTwoFactor\"] = async (input) => {\n await call(() => opts.transport.client.auth.disableTwoFactor(input));\n };\n\n const regenerateBackupCodes: AuthNamespace[\"regenerateBackupCodes\"] = async (input) => {\n const result = await call(() => opts.transport.client.auth.regenerateBackupCodes(input));\n return result.data.backupCodes;\n };\n\n // --- Account security -------------------------------------------------------\n\n const changePassword: AuthNamespace[\"changePassword\"] = async (input) => {\n const result = await call(() =>\n opts.transport.client.auth.changePassword({\n currentPassword: input.currentPassword,\n newPassword: input.newPassword,\n revokeOtherSessions: input.revokeOtherSessions,\n }),\n );\n adoptRotatedToken(result.data.accessToken);\n };\n\n const changeEmail: AuthNamespace[\"changeEmail\"] = async (input) => {\n await call(() => opts.transport.client.auth.changeEmail(input));\n };\n\n const listSessions: AuthNamespace[\"listSessions\"] = async () => {\n const result = await call(() => opts.transport.client.auth.listSessions());\n return result.data;\n };\n\n const revokeSession: AuthNamespace[\"revokeSession\"] = async (input) => {\n await call(() => opts.transport.client.auth.revokeSession(input));\n };\n\n const revokeOtherSessions: AuthNamespace[\"revokeOtherSessions\"] = async () => {\n await call(() => opts.transport.client.auth.revokeOtherSessions());\n };\n\n // The server deletes the login, so the cached bearer is dead the moment\n // this resolves — drop it locally (emits signed_out). On failure (wrong\n // password, network) the session is untouched and the error propagates.\n const closeAccount: AuthNamespace[\"closeAccount\"] = async (input) => {\n await call(() =>\n opts.transport.client.auth.closeAccount({\n confirmEmail: input.confirmEmail,\n password: input.password,\n }),\n );\n clearSession();\n };\n\n const _refresh: AuthNamespace[\"_refresh\"] = async () => {\n // Re-read storage as a fallback so a session written after\n // construction (e.g. on tab restore or in tests) is honoured.\n let current = cached;\n if (!current) {\n const fromStorage = await Promise.resolve(opts.storage.get());\n if (fromStorage) {\n cached = fromStorage;\n current = fromStorage;\n }\n }\n if (!current) {\n const err: FytkitError = { kind: \"auth_required\" };\n throw err;\n }\n try {\n const result = await opts.transport.client.auth.refresh({ token: current.accessToken });\n const { user, session } = result.data;\n return applySession(\n { accessToken: session.accessToken, expiresAt: session.expiresAt, user },\n \"session_refreshed\",\n );\n } catch (err) {\n const normalized = normalizeError(err);\n // Sign out only when the server actually rejected the token. A network\n // or server failure leaves the session in place for a later retry.\n if (isSessionRejected(normalized)) clearSession();\n throw normalized;\n }\n };\n\n const _signOutLocal: AuthNamespace[\"_signOutLocal\"] = () => clearSession();\n\n refreshFn = _refresh;\n\n return {\n signUp,\n signIn,\n signOut,\n getSession,\n onAuthStateChange,\n requestPasswordReset,\n confirmPasswordReset,\n confirmEmail,\n verifyTotp,\n verifyBackupCode,\n requestEmailOtp,\n verifyEmailOtp,\n getSecurityStatus,\n enableTotp,\n verifyTotpSetup,\n disableTwoFactor,\n regenerateBackupCodes,\n changePassword,\n changeEmail,\n listSessions,\n revokeSession,\n revokeOtherSessions,\n closeAccount,\n _refresh,\n _signOutLocal,\n };\n}\n","import { normalizeError } from \"./error\";\nimport type { Transport } from \"./transport\";\n\n/**\n * Wrap every method on a public-router slice so thrown ORPCErrors become\n * normalised FytkitErrors at the SDK boundary.\n *\n * The slice we receive is an `@orpc/client` Proxy whose own keys are not\n * enumerable — every property lookup is intercepted lazily. We mirror that\n * shape by returning a Proxy of our own that wraps each function on first\n * access and caches the result. This way the SDK never needs to know the\n * method names ahead of time, and the typed shape from the server router\n * flows through unchanged.\n */\nfunction wrapSlice<T extends object>(slice: T): T {\n const cache = new Map<string | symbol, unknown>();\n return new Proxy(slice, {\n get(target, prop, receiver) {\n if (cache.has(prop)) return cache.get(prop);\n const value = Reflect.get(target, prop, receiver);\n if (typeof value !== \"function\") {\n // Allow nested namespaces to flow through unchanged (the orpc\n // proxy returns another proxy here, not a plain object).\n return value;\n }\n const wrapped = async (...args: unknown[]) => {\n try {\n return await (value as (...a: unknown[]) => Promise<unknown>)(...args);\n } catch (err) {\n throw normalizeError(err);\n }\n };\n cache.set(prop, wrapped);\n return wrapped;\n },\n }) as T;\n}\n\nexport interface DataNamespaces {\n readonly workouts: Transport[\"client\"][\"workout\"];\n readonly exercises: Transport[\"client\"][\"exercise\"];\n readonly programs: Transport[\"client\"][\"program\"];\n readonly goals: Transport[\"client\"][\"goal\"];\n readonly equipment: Transport[\"client\"][\"equipment\"];\n readonly recipes: Transport[\"client\"][\"recipe\"];\n readonly nutrition: Transport[\"client\"][\"nutrition\"];\n readonly articles: Transport[\"client\"][\"article\"];\n readonly enrollments: Transport[\"client\"][\"enrollment\"];\n readonly favourites: Transport[\"client\"][\"favourite\"];\n readonly sessionLogs: Transport[\"client\"][\"sessionLog\"];\n readonly progression: Transport[\"client\"][\"progression\"];\n readonly bodyMetrics: Transport[\"client\"][\"bodyMetric\"];\n readonly progress: Transport[\"client\"][\"progress\"];\n readonly media: Transport[\"client\"][\"media\"];\n readonly appConfig: Transport[\"client\"][\"appConfig\"];\n readonly subscription: Transport[\"client\"][\"subscription\"];\n readonly profile: Transport[\"client\"][\"profile\"];\n readonly nutritionLog: Transport[\"client\"][\"nutritionLog\"];\n readonly preferences: Transport[\"client\"][\"preferences\"];\n}\n\nexport function createDataNamespaces(transport: Transport): DataNamespaces {\n const c = transport.client;\n return {\n workouts: wrapSlice(c.workout),\n exercises: wrapSlice(c.exercise),\n programs: wrapSlice(c.program),\n goals: wrapSlice(c.goal),\n equipment: wrapSlice(c.equipment),\n recipes: wrapSlice(c.recipe),\n nutrition: wrapSlice(c.nutrition),\n articles: wrapSlice(c.article),\n enrollments: wrapSlice(c.enrollment),\n favourites: wrapSlice(c.favourite),\n sessionLogs: wrapSlice(c.sessionLog),\n progression: wrapSlice(c.progression),\n bodyMetrics: wrapSlice(c.bodyMetric),\n progress: wrapSlice(c.progress),\n media: wrapSlice(c.media),\n appConfig: wrapSlice(c.appConfig),\n subscription: wrapSlice(c.subscription),\n profile: wrapSlice(c.profile),\n nutritionLog: wrapSlice(c.nutritionLog),\n preferences: wrapSlice(c.preferences),\n };\n}\n","import type { Session, TokenStorage } from \"./types\";\n\nconst STORAGE_KEY_PREFIX = \"fytkit:\";\nconst STORAGE_KEY_SUFFIX = \":tokens\";\n\nfunction keyFor(clientId: string): string {\n return `${STORAGE_KEY_PREFIX}${clientId}${STORAGE_KEY_SUFFIX}`;\n}\n\nfunction isValidSession(value: unknown): value is Session {\n if (!value || typeof value !== \"object\") return false;\n const v = value as Record<string, unknown>;\n return (\n typeof v.accessToken === \"string\" &&\n typeof v.expiresAt === \"string\" &&\n typeof v.user === \"object\" &&\n v.user !== null &&\n typeof (v.user as { id?: unknown }).id === \"string\" &&\n typeof (v.user as { email?: unknown }).email === \"string\"\n );\n}\n\n/**\n * Default web storage. Reads/writes JSON under `fytkit:{clientId}:tokens`.\n * Silently no-ops when localStorage throws (Safari private mode, SSR).\n */\nexport function createLocalStorageAdapter(clientId: string): TokenStorage {\n const key = keyFor(clientId);\n return {\n get: () => {\n try {\n const raw = globalThis.localStorage?.getItem(key);\n if (!raw) return null;\n const parsed: unknown = JSON.parse(raw);\n return isValidSession(parsed) ? parsed : null;\n } catch {\n return null;\n }\n },\n set: (session: Session) => {\n try {\n globalThis.localStorage?.setItem(key, JSON.stringify(session));\n } catch {\n // Quota / private-mode / SSR — swallow and let the caller treat the\n // session as in-memory-only for this tab.\n }\n },\n remove: () => {\n try {\n globalThis.localStorage?.removeItem(key);\n } catch {\n // see set() rationale\n }\n },\n };\n}\n\n/** In-memory storage. Useful for tests and SSR. */\nexport function createMemoryStorageAdapter(): TokenStorage {\n let current: Session | null = null;\n return {\n get: () => current,\n set: (session: Session) => {\n current = session;\n },\n remove: () => {\n current = null;\n },\n };\n}\n","import type { PublicApi } from \"@fytkit/types\";\nimport { createORPCClient } from \"@orpc/client\";\nimport { RPCLink } from \"@orpc/client/fetch\";\nimport type { Session } from \"./types\";\n\nexport interface CreateTransportOptions {\n readonly baseUrl: string;\n readonly clientId: string;\n readonly getSession: () => Session | null;\n readonly fetch?: typeof fetch;\n}\n\nexport interface Transport {\n readonly client: PublicApi;\n /** Internal: hook for attachRefreshInterceptor to install a fetch wrapper. */\n readonly _setFetchInterceptor: (interceptor: FetchInterceptor) => void;\n}\n\ntype FetchInterceptor = (\n request: Request,\n next: (req: Request) => Promise<Response>,\n) => Promise<Response>;\n\nexport function createTransport(options: CreateTransportOptions): Transport {\n let interceptor: FetchInterceptor | null = null;\n const baseFetch: typeof fetch = options.fetch ?? fetch.bind(globalThis);\n\n // The fetch handed to RPCLink resolves the interceptor lazily so callers\n // can install one after construction (see attachRefreshInterceptor).\n const wrappedFetch: typeof fetch = (input, init) => {\n const request = input instanceof Request ? input : new Request(input, init);\n const next = (req: Request) => baseFetch(req);\n if (!interceptor) return next(request);\n return interceptor(request, next);\n };\n\n const link = new RPCLink({\n url: () => `${options.baseUrl}/rpc`,\n headers: () => {\n const session = options.getSession();\n const headers: Record<string, string> = {\n \"X-Fytkit-Client-Id\": options.clientId,\n };\n if (session) {\n headers.Authorization = `Bearer ${session.accessToken}`;\n }\n return headers;\n },\n fetch: wrappedFetch,\n });\n\n const client: PublicApi = createORPCClient(link);\n return {\n client,\n _setFetchInterceptor: (i) => {\n interceptor = i;\n },\n };\n}\n\n/** Internal marker header — set on the refresh call so we never recurse. */\nconst REFRESH_HEADER = \"X-Fytkit-Refresh\";\n\n/**\n * Procedures that authenticate with credentials in their input (a password,\n * an emailed token, a one-time code or a sign-in challenge), never with the\n * bearer. A 401 from one of them means those credentials were rejected, not\n * that the session is dead, so it passes straight through: no refresh, no\n * replay, no local sign-out. Otherwise a member who mistypes their password\n * while signing in again (after `reauth_required`) would be signed out.\n */\nconst CREDENTIAL_PROCEDURES: readonly string[] = [\n \"auth/signIn\",\n \"auth/signUp\",\n \"auth/requestPasswordReset\",\n \"auth/confirmPasswordReset\",\n \"auth/confirmEmail\",\n \"auth/verifyTotp\",\n \"auth/verifyBackupCode\",\n \"auth/requestEmailOtp\",\n \"auth/verifyEmailOtp\",\n];\n\n/**\n * The RPCLink routes per-procedure calls under a URL whose pathname ends\n * with the procedure path (joined as `/segment/segment`), so procedures are\n * detected by suffix. endsWith keeps trailing query strings or link-level\n * prefixes from breaking detection.\n */\nfunction requestPathname(request: Request): string {\n try {\n return new URL(request.url).pathname;\n } catch {\n return \"\";\n }\n}\n\n/** Detect whether a request targets the refresh procedure. */\nfunction isRefreshRequest(request: Request): boolean {\n if (request.headers.get(REFRESH_HEADER) === \"1\") return true;\n return requestPathname(request).endsWith(\"/auth/refresh\");\n}\n\n/** Detect whether a request targets one of the `CREDENTIAL_PROCEDURES`. */\nfunction isCredentialRequest(request: Request): boolean {\n const path = requestPathname(request);\n return CREDENTIAL_PROCEDURES.some((procedure) => path.endsWith(`/${procedure}`));\n}\n\nexport interface AttachRefreshInterceptorOptions {\n readonly transport: Transport;\n readonly auth: {\n readonly _refresh: () => Promise<Session>;\n readonly _signOutLocal: () => void;\n readonly getSession: () => Session | null;\n };\n}\n\n/**\n * Install a fetch interceptor that, on a 401 response, calls auth._refresh\n * once and retries the original request. Concurrent 401s de-duplicate\n * onto a single in-flight refresh promise. A 401/403 from refresh itself or\n * a 401 from the retry triggers a local sign-out and propagates the original\n * 401 to the caller (after which orpc throws ORPCError(\"UNAUTHORIZED\")). A\n * refresh that fails for any other reason (offline, 5xx) also propagates the\n * original 401, but keeps the session so a later call can succeed. A 401 from\n * a credential procedure (`CREDENTIAL_PROCEDURES`) is never refreshed or\n * replayed: it rejects the credentials, not the session.\n */\nexport function attachRefreshInterceptor(opts: AttachRefreshInterceptorOptions): void {\n let inflight: Promise<Session> | null = null;\n\n const refreshOnce = (): Promise<Session> => {\n if (!inflight) {\n inflight = opts.auth._refresh().finally(() => {\n inflight = null;\n });\n }\n return inflight;\n };\n\n opts.transport._setFetchInterceptor(async (request, next) => {\n // Refresh calls must never trigger a recursive refresh, and a 401 from a\n // credential procedure is a wrong password or code, not a dead session.\n if (isRefreshRequest(request) || isCredentialRequest(request)) {\n return next(request);\n }\n\n // Capture the request body now, before we pass `request` to `next` —\n // once fetch consumes a Request body it can no longer be cloned.\n const buffered = await request.clone().arrayBuffer();\n\n const firstResponse = await next(request);\n if (firstResponse.status !== 401) return firstResponse;\n\n try {\n await refreshOnce();\n } catch {\n // _refresh decides whether the session survives: it signs out only\n // when the server rejected the token, not on a network/server failure.\n return firstResponse;\n }\n\n // Rebuild headers so the new Authorization header replaces the stale\n // one — the RPCLink only re-evaluates its own `headers()` once per call,\n // so we patch the bearer ourselves here.\n const replayedHeaders = new Headers(request.headers);\n const session = opts.auth.getSession();\n if (session) {\n replayedHeaders.set(\"Authorization\", `Bearer ${session.accessToken}`);\n } else {\n replayedHeaders.delete(\"Authorization\");\n }\n const replayed = new Request(request.url, {\n method: request.method,\n headers: replayedHeaders,\n body: buffered.byteLength > 0 ? buffered : undefined,\n credentials: request.credentials,\n mode: request.mode,\n cache: request.cache,\n redirect: request.redirect,\n referrer: request.referrer,\n integrity: request.integrity,\n });\n\n const retried = await next(replayed);\n if (retried.status === 401) {\n // Refresh succeeded server-side but the server still rejects — the\n // session is dead. Sign out locally and let orpc surface the 401.\n opts.auth._signOutLocal();\n }\n return retried;\n });\n}\n","import { createAuthNamespace } from \"./auth\";\nimport { createDataNamespaces } from \"./data\";\nimport { createLocalStorageAdapter, createMemoryStorageAdapter } from \"./storage\";\nimport { attachRefreshInterceptor, createTransport } from \"./transport\";\nimport type { FytkitClient, FytkitClientOptions } from \"./types\";\n\nconst DEFAULT_BASE_URL = \"https://api.fytkit.com\";\n\nexport function createFytkitClient(options: FytkitClientOptions): FytkitClient {\n if (!options || typeof options.clientId !== \"string\" || options.clientId.length === 0) {\n throw new Error(\"createFytkitClient: `clientId` is required\");\n }\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n const storage = options.storage ?? createLocalStorageAdapter(options.clientId);\n\n // `auth` is declared after `transport` because `createAuthNamespace`\n // needs the transport to make its RPC calls. The transport in turn needs\n // a `getSession` that reads the auth cache — we resolve the cycle with a\n // late-bound reference: the closure below reads `auth` lazily, which is\n // safe because no request can fire before construction finishes.\n let auth: ReturnType<typeof createAuthNamespace> | null = null;\n\n const transport = createTransport({\n baseUrl,\n clientId: options.clientId,\n getSession: () => auth?.getSession() ?? null,\n fetch: options.fetch,\n });\n\n const authInstance = createAuthNamespace({ transport, storage });\n auth = authInstance;\n attachRefreshInterceptor({ transport, auth: authInstance });\n\n const data = createDataNamespaces(transport);\n\n return {\n auth: {\n signUp: authInstance.signUp,\n signIn: authInstance.signIn,\n signOut: authInstance.signOut,\n getSession: authInstance.getSession,\n onAuthStateChange: authInstance.onAuthStateChange,\n requestPasswordReset: authInstance.requestPasswordReset,\n confirmPasswordReset: authInstance.confirmPasswordReset,\n confirmEmail: authInstance.confirmEmail,\n verifyTotp: authInstance.verifyTotp,\n verifyBackupCode: authInstance.verifyBackupCode,\n requestEmailOtp: authInstance.requestEmailOtp,\n verifyEmailOtp: authInstance.verifyEmailOtp,\n getSecurityStatus: authInstance.getSecurityStatus,\n enableTotp: authInstance.enableTotp,\n verifyTotpSetup: authInstance.verifyTotpSetup,\n disableTwoFactor: authInstance.disableTwoFactor,\n regenerateBackupCodes: authInstance.regenerateBackupCodes,\n changePassword: authInstance.changePassword,\n changeEmail: authInstance.changeEmail,\n listSessions: authInstance.listSessions,\n revokeSession: authInstance.revokeSession,\n revokeOtherSessions: authInstance.revokeOtherSessions,\n closeAccount: authInstance.closeAccount,\n },\n ...data,\n };\n}\n\n// Public re-exports.\nexport { createLocalStorageAdapter, createMemoryStorageAdapter };\n// `PublicApi` is the inferred router type that backs every namespace\n// on `FytkitClient` (e.g. `client.workouts` is `PublicApi[\"workout\"]`).\n// Re-exported so consumers can write generics over the router shape —\n// previously this surfaced as an `ae-forgotten-export` warning on\n// `FytkitClient` in the api-extractor report. The api-extractor will\n// still warn about `PublicRouter`/`publicRouter` being unexported —\n// that is intentional, those are implementation-detail names from the\n// generated snapshot that should not be part of the consumer surface.\nexport type { PublicApi } from \"@fytkit/types\";\nexport type {\n AuthState,\n FytkitClient,\n FytkitClientOptions,\n FytkitError,\n FytkitErrorCode,\n SecurityStatus,\n Session,\n SessionInfo,\n SignInResult,\n TokenStorage,\n TotpEnrollment,\n TwoFactorChallenge,\n TwoFactorMethod,\n TwoFactorToken,\n} from \"./types\";\n"]}
|