@fytkit/sdk 4.0.0 → 4.2.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 +33 -0
- package/README.md +27 -2
- package/dist/index.d.ts +309 -17
- package/dist/index.js +100 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,39 @@ 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
|
+
## 4.2.0
|
|
8
|
+
|
|
9
|
+
To be published by hand with sdk-publish.yml (the manifest records 4.2.0). Create the tag and GitHub release `@fytkit/sdk@4.2.0` when it is published.
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* `nutritionFollows`: the meal plan the trainee follows, one at a time. `list()` resolves to the active follow with its plan (`{ id, planId, status, startDate, startedAt, stoppedAt, plan: { id, title, description, accessLevel, canAccess, status, durationWeeks, headerImageUrl } }`), or to `[]`. `start({ planId, startDate? })` follows one of the studio's published plans from `startDate` ("YYYY-MM-DD", day 1 of week 1 in the trainee's calendar; their local today when omitted) and stops the trainee's current follow of another plan in the same write, naming it in `stoppedFollowId`; following the plan already followed changes nothing and returns that follow. `stop({ id })` stops a follow. A premium plan without `premium_nutrition` rejects as `nutrition.get` does (`payment_required` or `forbidden`); a draft, another studio's or an unknown plan, and another trainee's follow, reject with `not_found`; stopping a follow already stopped rejects with `conflict`. Writes are refused while a fytkit admin is signed in as the trainee. Additive ([#594](https://github.com/cbarlow1993/fytkit-web/issues/594))
|
|
14
|
+
* `auth.signInWithIdToken({ provider, idToken, nonce, name? })`: Sign in with Apple or Google in Fytkit Coach. Signs in, signs up, or joins this studio with the provider's ID token, and resolves like `signIn`: `{ kind: "signed_in", session, memberCreated }` (the session is cached and `signed_in` emitted; `memberCreated` is true when this call made the person a member of this studio, for onboarding) or `{ kind: "two_factor_required", challenge }`, completed with the existing `verify*` methods. `nonce` is the raw nonce the app generated (pass its SHA-256 hex to Apple, the raw nonce to Google); `name` is the name Apple gives the app on the first authorisation only. A credential call: a 401 never refreshes or signs out. Studio-owned (custom) apps are refused. New types `IdTokenProvider` and `IdTokenSignInResult` ([#544](https://github.com/cbarlow1993/fytkit-web/issues/544))
|
|
15
|
+
* `FytkitErrorCode` gains `social_sign_in_unavailable` and `social_email_has_password`, `social_email_has_other_provider`, `two_factor_join_unsupported` (on `forbidden`, 403) and `invalid_id_token`, `social_email_unverified` (on `server`, 400), the refusals of `signInWithIdToken`; `first_party_account` is sent by it too ([#544](https://github.com/cbarlow1993/fytkit-web/issues/544))
|
|
16
|
+
* `auth.closeAccount` accepts a fresh Apple or Google ID token instead of a password, so a member whose account has no password (it signs in with Apple or Google only) can close it in the app: `closeAccount({ confirmEmail, identityToken: { provider, idToken, nonce, authorizationCode? } })`. Run the provider's sign-in again with a new nonce; the token must be at most 10 minutes old and belong to the Apple or Google account the member signs in with. An account with a password still confirms with `closeAccount({ confirmEmail, password })`. The input is the new exported union `CloseAccountInput`, so sending both proofs, or neither, does not compile; the existing password call is unchanged. New type `IdTokenReauthentication`. On success the session is cleared as before ([#544](https://github.com/cbarlow1993/fytkit-web/issues/544))
|
|
17
|
+
* `auth.signInWithIdToken` takes an optional `authorizationCode` (Apple only; a validation error with Google): Apple's authorization code from the same sign-in, which the server exchanges for a refresh token so the app's Apple tokens can be revoked when the account is closed. `closeAccount`'s `identityToken.authorizationCode` does the same for a member whose code was never sent. A failed exchange never fails sign-in. Additive ([#544](https://github.com/cbarlow1993/fytkit-web/issues/544))
|
|
18
|
+
* `FytkitErrorCode` gains `password_not_set` (on `server`, 400: `closeAccount` was sent a password but the account has none; send `identityToken`), `password_required` (on `server`, 400: `closeAccount` was sent `identityToken` but the account has a password) and `reauth_identity_mismatch` (on `forbidden`, 403: the ID token is for another Apple or Google account than the member's). `invalid_id_token` and `social_sign_in_unavailable` can now come from `closeAccount` too. Every `closeAccount` refusal keeps the session ([#544](https://github.com/cbarlow1993/fytkit-web/issues/544))
|
|
19
|
+
|
|
20
|
+
### Changed (server)
|
|
21
|
+
|
|
22
|
+
* `nutrition.list` and `recipes.list` now return premium plans and recipes the caller cannot open, with `canAccess: false`, where before they left them out. The gate is unchanged on `nutrition.get` and `recipes.get` (`payment_required`). This is a server change, so every SDK version sees it ([#597](https://github.com/cbarlow1993/fytkit-web/issues/597))
|
|
23
|
+
|
|
24
|
+
## 4.1.0
|
|
25
|
+
|
|
26
|
+
To be published by hand with sdk-publish.yml (the manifest records 4.1.0). Create the tag and GitHub release `@fytkit/sdk@4.1.0` when it is published.
|
|
27
|
+
|
|
28
|
+
### Features
|
|
29
|
+
|
|
30
|
+
* `subscribeToMessages` takes an optional `onCoachTyping`, for a "Sam is writing…" line: who on the trainee's coaching team is writing to them right now, as `{ kind: "typing", names }` (staff display names, as the conversation shows them) or `{ kind: "idle" }`. Heard only while the status is `live`; a name drops out by itself `COACH_TYPING_EXPIRY_MS` (8 seconds) after its last sign, so a lost stop never leaves it showing, and the state goes `idle` when the channel is lost. Additive. New type `CoachTypingState` and constant `COACH_TYPING_EXPIRY_MS` (W16)
|
|
31
|
+
* `programs.get` and `programs.getSession` carry `durationMinutes` on each session's workout: the trainer's planned time for the workout, null when unset. Additive (W13)
|
|
32
|
+
* `auth.getSecurityStatus()` adds `passwordChangedAt` (when the password was last set or changed, ISO 8601; null when the account has no password) and `backupCodesRemaining` (unused backup codes left; null when two-factor is off, 0 when every code is used), and `SecurityStatus` gains both fields. Additive (W20)
|
|
33
|
+
* `profile.get` and `profile.update` carry `lengthUnit` (`"in"` or `"cm"`), the member's unit for body measurements, beside `weightUnit`; `profile.update` takes it optionally. Additive (W19)
|
|
34
|
+
* `bodyMeasurements.record` takes an optional `clientRequestId` (a UUID) for offline replay, as `bodyMetrics.record` does: a replay with the same key returns the stored measurements instead of recording them twice. Calls without a key are unchanged (W21)
|
|
35
|
+
|
|
36
|
+
### Bug Fixes
|
|
37
|
+
|
|
38
|
+
* `auth.disableTwoFactor` now signs out every other device, and the server rotates the caller's session; the SDK swaps its stored token transparently, so the caller stays signed in ([#494](https://github.com/cbarlow1993/fytkit-web/pull/494))
|
|
39
|
+
|
|
7
40
|
## 4.0.0
|
|
8
41
|
|
|
9
42
|
To be published by hand (release-please, which runs on GitHub Actions, does not cut this release; the manifest records 4.0.0 so the next automated release bumps from it). Create the tag and GitHub release `@fytkit/sdk@4.0.0` when it is published, or release-please proposes 4.0.0 again.
|
package/README.md
CHANGED
|
@@ -161,6 +161,13 @@ await fytkit.auth.changePassword({ currentPassword, newPassword, revokeOtherSess
|
|
|
161
161
|
// nothing changes until the trainee opens it.
|
|
162
162
|
await fytkit.auth.changeEmail({ newEmail });
|
|
163
163
|
|
|
164
|
+
// Resend the sign-up verification email to the trainee's own address (there
|
|
165
|
+
// is no email input). Resolves to { status: "sent" } or, when the address is
|
|
166
|
+
// already verified and nothing is sent, { status: "already_verified" }.
|
|
167
|
+
// Throttled per account (one a minute, five an hour): over the limit it
|
|
168
|
+
// rejects with { kind: "rate_limited", retryAfter } (milliseconds).
|
|
169
|
+
const { status } = await fytkit.auth.resendVerification();
|
|
170
|
+
|
|
164
171
|
// Devices signed in through this app (plus the calling one); the trainee's
|
|
165
172
|
// sessions elsewhere are never listed. revokeId is an opaque id (never the
|
|
166
173
|
// bearer token).
|
|
@@ -181,7 +188,7 @@ session is gone. A wrong password on `signIn` (for example, signing in again
|
|
|
181
188
|
after `reauth_required`) is a plain `auth_required` and leaves the current
|
|
182
189
|
session alone. An account that also runs or works at a trainer on Fytkit can't
|
|
183
190
|
sign in, sign up or complete two-factor through an app, and an existing app
|
|
184
|
-
session can't change its password or email or close it:
|
|
191
|
+
session can't change its password or email, resend its verification email or close it:
|
|
185
192
|
`{ kind: "forbidden", code: "first_party_account" }`; point it to Fytkit's own
|
|
186
193
|
sign-in. Enrolling twice in a program is `{ kind: "conflict" }` with the
|
|
187
194
|
existing `enrollmentId`.
|
|
@@ -251,6 +258,23 @@ const unsubscribe = subscribeToMessages(fytkit, {
|
|
|
251
258
|
unsubscribe();
|
|
252
259
|
```
|
|
253
260
|
|
|
261
|
+
To show "Sam is writing…" while someone on the trainee's coaching team
|
|
262
|
+
writes a reply, pass `onCoachTyping`. It reports `{ kind: "typing", names }`
|
|
263
|
+
(display names, as the conversation shows them on their messages) and
|
|
264
|
+
`{ kind: "idle" }`. It is live only: a name drops out by itself 8 seconds
|
|
265
|
+
after its last sign (`COACH_TYPING_EXPIRY_MS`), so a lost "stopped" never
|
|
266
|
+
leaves it showing, it goes `idle` when the channel is lost, and while you
|
|
267
|
+
poll it never shows.
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
subscribeToMessages(fytkit, {
|
|
271
|
+
realtime,
|
|
272
|
+
onChange: () => refreshConversation(),
|
|
273
|
+
onCoachTyping: (typing) =>
|
|
274
|
+
setWritingLine(typing.kind === "typing" ? `${firstName(typing.names[0])} is writing…` : null),
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
254
278
|
Polling spends your app's per-minute request limit, which all its users
|
|
255
279
|
share, so stop as soon as the status is `live`. The full guide:
|
|
256
280
|
[`messages.realtimeToken`](../../docs/developer/reference/data-namespaces.md#messagesrealtimetoken)
|
|
@@ -269,7 +293,8 @@ await fytkit.preferences.updateNotifications({ streakAlerts: false }); // partia
|
|
|
269
293
|
|
|
270
294
|
- `resolveJoinCode` (a studio's join code to its client id, name, logo and app theme, with no client) and `app.bootstrap` (the launch read, revalidated with its ETag), with `resolvePaymentMode` ("Subscribe" link-out or "What your plan includes", per storefront)
|
|
271
295
|
- `auth.signUp` / `signIn` / `signOut` / `getSession` / `onAuthStateChange`
|
|
272
|
-
- `auth.
|
|
296
|
+
- `auth.signInWithIdToken` (Sign in with Apple or Google, Fytkit Coach only: pass the raw nonce; Apple gets its SHA-256 hex, Google the raw nonce)
|
|
297
|
+
- `auth.requestPasswordReset` / `confirmPasswordReset` / `confirmEmail` / `resendVerification`
|
|
273
298
|
- Two-factor: `auth.verifyTotp` / `verifyBackupCode` / `requestEmailOtp` / `verifyEmailOtp` (sign-in), `enableTotp` / `verifyTotpSetup` / `disableTwoFactor` / `regenerateBackupCodes` / `getSecurityStatus` (management)
|
|
274
299
|
- Account security: `auth.changePassword` / `changeEmail` / `confirmEmailChange` / `listSessions` / `revokeSession` / `revokeOtherSessions` / `closeAccount`
|
|
275
300
|
- Data namespaces: `workouts`, `programs`, `recipes`, `nutrition`, `nutritionLog`, `profile`, `preferences`, `articles`, `enrollments`, `sessionLogs`, `progression`, `progress`, `bodyMetrics`, `bodyMeasurements`, `progressPhotos`, `checkIns`, `messages`, `timeline`, `health`, `habits`, `media`, `subscription`
|
package/dist/index.d.ts
CHANGED
|
@@ -156,6 +156,49 @@ declare type ClientEntitlementCode = "premium_workouts" | "premium_programs" | "
|
|
|
156
156
|
|
|
157
157
|
declare type ClientEntitlements = readonly ClientEntitlementCode[] | "all";
|
|
158
158
|
|
|
159
|
+
/**
|
|
160
|
+
* The input to `auth.closeAccount()`: the member's email as confirmation
|
|
161
|
+
* plus exactly one proof. `password` for an account with a password;
|
|
162
|
+
* `identityToken` for an account that signs in with Apple or Google only
|
|
163
|
+
* and has no password. Sending both, or neither, does not compile.
|
|
164
|
+
*/
|
|
165
|
+
export declare type CloseAccountInput = {
|
|
166
|
+
confirmEmail: string;
|
|
167
|
+
password: string;
|
|
168
|
+
identityToken?: never;
|
|
169
|
+
} | {
|
|
170
|
+
confirmEmail: string;
|
|
171
|
+
identityToken: IdTokenReauthentication;
|
|
172
|
+
password?: never;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* How long a staff member stays in {@link CoachTypingState}'s `names` after
|
|
177
|
+
* the last sign that they are writing. The dashboard repeats the sign every
|
|
178
|
+
* 3 seconds while they write.
|
|
179
|
+
*/
|
|
180
|
+
export declare const COACH_TYPING_EXPIRY_MS = 8000;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Whether the trainee's coaching team is writing to them right now, for a
|
|
184
|
+
* "Sam is writing…" line under the conversation:
|
|
185
|
+
* - `idle`: nobody is.
|
|
186
|
+
* - `typing`: the staff members in `names` are, by the display name the
|
|
187
|
+
* conversation shows on their messages, each name once, in the order
|
|
188
|
+
* they started. Show the first, or "Sam and Alex are writing…".
|
|
189
|
+
*
|
|
190
|
+
* A hint, live only: it is heard only while the status is `live`, and goes
|
|
191
|
+
* back to `idle` when the channel is lost. A name that hears nothing more
|
|
192
|
+
* for 8 seconds ({@link COACH_TYPING_EXPIRY_MS}) drops out by itself, so a
|
|
193
|
+
* lost "stopped" never leaves it showing. While polling it stays `idle`.
|
|
194
|
+
*/
|
|
195
|
+
export declare type CoachTypingState = {
|
|
196
|
+
readonly kind: "idle";
|
|
197
|
+
} | {
|
|
198
|
+
readonly kind: "typing";
|
|
199
|
+
readonly names: readonly string[];
|
|
200
|
+
};
|
|
201
|
+
|
|
159
202
|
export declare function createFytkitClient(options: FytkitClientOptions): FytkitClient;
|
|
160
203
|
|
|
161
204
|
/**
|
|
@@ -169,7 +212,7 @@ export declare function createMemoryStorageAdapter(): TokenStorage;
|
|
|
169
212
|
|
|
170
213
|
declare interface DeveloperAppRequestContext {
|
|
171
214
|
readonly headers: Headers;
|
|
172
|
-
readonly surface
|
|
215
|
+
readonly surface: RequestSurface;
|
|
173
216
|
}
|
|
174
217
|
|
|
175
218
|
/** The full SDK client surface. `auth.*` plus the public-router slices, minus auth (those live on `client.auth`). */
|
|
@@ -191,6 +234,23 @@ export declare interface FytkitClient {
|
|
|
191
234
|
email: string;
|
|
192
235
|
password: string;
|
|
193
236
|
}) => Promise<SignInResult>;
|
|
237
|
+
/** Signs in, signs up or joins this studio with an Apple or Google ID
|
|
238
|
+
* token (Fytkit Coach only). `nonce` is the raw nonce the app generated:
|
|
239
|
+
* pass its SHA-256 hex to Apple, or the raw nonce to Google. `name` is the
|
|
240
|
+
* name Apple hands the app on the first authorisation (it is never in the
|
|
241
|
+
* token). `authorizationCode` is Apple's authorization code from the
|
|
242
|
+
* same sign-in (Apple only; a validation error with Google): the server
|
|
243
|
+
* exchanges it for a refresh token so it can revoke the app's Apple
|
|
244
|
+
* tokens when the account is closed. On `signed_in` the session is cached
|
|
245
|
+
* (emits signed_in); on `two_factor_required` continue with the `verify*`
|
|
246
|
+
* methods. Refusals carry a `code` (see `FytkitErrorCode`). */
|
|
247
|
+
signInWithIdToken: (input: {
|
|
248
|
+
provider: IdTokenProvider;
|
|
249
|
+
idToken: string;
|
|
250
|
+
nonce: string;
|
|
251
|
+
name?: string;
|
|
252
|
+
authorizationCode?: string;
|
|
253
|
+
}) => Promise<IdTokenSignInResult>;
|
|
194
254
|
signOut: () => Promise<void>;
|
|
195
255
|
/** Synchronously read the cached session, if any. */
|
|
196
256
|
getSession: () => Session | null;
|
|
@@ -236,6 +296,8 @@ export declare interface FytkitClient {
|
|
|
236
296
|
verifyTotpSetup: (input: {
|
|
237
297
|
code: string;
|
|
238
298
|
}) => Promise<void>;
|
|
299
|
+
/** Turns off 2FA and signs out every other device. The server rotates
|
|
300
|
+
* this session; the SDK swaps its stored token transparently. */
|
|
239
301
|
disableTwoFactor: (input: {
|
|
240
302
|
password: string;
|
|
241
303
|
}) => Promise<void>;
|
|
@@ -283,14 +345,18 @@ export declare interface FytkitClient {
|
|
|
283
345
|
* untouched; `changePassword` with `revokeOtherSessions: true` ends those. */
|
|
284
346
|
revokeOtherSessions: () => Promise<void>;
|
|
285
347
|
/** Permanently closes the member's account (cancels their subscriptions,
|
|
286
|
-
* anonymises their data, deletes the login
|
|
287
|
-
*
|
|
288
|
-
* `
|
|
289
|
-
*
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
348
|
+
* anonymises their data, deletes the login, revokes the app's Sign in
|
|
349
|
+
* with Apple tokens) after re-verifying the email and one proof: the
|
|
350
|
+
* `password`, or, for an account without a password, a fresh Apple or
|
|
351
|
+
* Google `identityToken` (see `CloseAccountInput`). On success the SDK
|
|
352
|
+
* clears its session and emits `signed_out`. Every refusal leaves the
|
|
353
|
+
* session signed in: a wrong password rejects with `{ kind: "server",
|
|
354
|
+
* status: 400, code: "invalid_password" }`; the wrong proof for the
|
|
355
|
+
* account with `password_not_set` or `password_required` (`server`, 400);
|
|
356
|
+
* an ID token for another Apple or Google account with
|
|
357
|
+
* `reauth_identity_mismatch` (`forbidden`, 403); an unverifiable, reused
|
|
358
|
+
* or stale ID token with `invalid_id_token` (`server`, 400). */
|
|
359
|
+
closeAccount: (input: CloseAccountInput) => Promise<void>;
|
|
294
360
|
};
|
|
295
361
|
readonly workouts: PublicApi["workout"];
|
|
296
362
|
readonly exercises: PublicApi["exercise"];
|
|
@@ -299,6 +365,15 @@ export declare interface FytkitClient {
|
|
|
299
365
|
readonly equipment: PublicApi["equipment"];
|
|
300
366
|
readonly recipes: PublicApi["recipe"];
|
|
301
367
|
readonly nutrition: PublicApi["nutrition"];
|
|
368
|
+
/**
|
|
369
|
+
* The meal plan the trainee follows, one at a time: `list` (the active
|
|
370
|
+
* follow with its plan, or nothing), `start({ planId, startDate? })`, which
|
|
371
|
+
* stops the trainee's current follow of another plan, and `stop({ id })`.
|
|
372
|
+
* `startDate` is day 1 of week 1 in the trainee's own calendar, for
|
|
373
|
+
* "week 2 of 4, day 3". Writes are refused while a fytkit admin is signed
|
|
374
|
+
* in as the trainee.
|
|
375
|
+
*/
|
|
376
|
+
readonly nutritionFollows: PublicApi["nutritionFollow"];
|
|
302
377
|
readonly articles: PublicApi["article"];
|
|
303
378
|
readonly enrollments: PublicApi["enrollment"];
|
|
304
379
|
readonly favourites: PublicApi["favourite"];
|
|
@@ -440,13 +515,53 @@ export declare type FytkitError = {
|
|
|
440
515
|
* - `"first_party_account"` (`forbidden`, 403) — the account also runs or
|
|
441
516
|
* works at a trainer on Fytkit, so an app may not sign it in, sign it up,
|
|
442
517
|
* reset its password or handle its two-factor steps (`signIn`, `signUp`,
|
|
443
|
-
* the `verify*` and TOTP methods), and an existing session can't change
|
|
518
|
+
* `signInWithIdToken`, the `verify*` and TOTP methods), and an existing session can't change
|
|
444
519
|
* its password or email or close it (`changePassword`, `changeEmail`,
|
|
445
520
|
* `closeAccount`). The credentials were right; tell the
|
|
446
521
|
* person to sign in with Fytkit itself. `requestPasswordReset` never sends
|
|
447
|
-
* this: it answers `ok` and sends no email.
|
|
522
|
+
* this: it answers `ok` and sends no email. `signInWithIdToken` also sends
|
|
523
|
+
* it for a Fytkit platform administrator.
|
|
524
|
+
*
|
|
525
|
+
* `closeAccount` re-authentication refusals (see `CloseAccountInput`):
|
|
526
|
+
*
|
|
527
|
+
* - `"password_not_set"` (`server`, 400) — `password` was sent, but the
|
|
528
|
+
* account has no password (it signs in with Apple or Google). Re-run the
|
|
529
|
+
* provider's sign-in and send `identityToken` instead.
|
|
530
|
+
* - `"password_required"` (`server`, 400) — `identityToken` was sent, but the
|
|
531
|
+
* account has a password. Ask for the password; an account with a password
|
|
532
|
+
* always confirms with it.
|
|
533
|
+
* - `"reauth_identity_mismatch"` (`forbidden`, 403) — the ID token is valid
|
|
534
|
+
* but is not for the Apple or Google account the member signs in with.
|
|
535
|
+
* Ask them to use that account. The session is untouched.
|
|
536
|
+
*
|
|
537
|
+
* `closeAccount` with `identityToken` can also send `invalid_id_token` (the
|
|
538
|
+
* token could not be verified, was already used, or is older than 10
|
|
539
|
+
* minutes) and `social_sign_in_unavailable`, with the meanings below.
|
|
540
|
+
*
|
|
541
|
+
* `signInWithIdToken` refusals (the ID token is checked first, except for
|
|
542
|
+
* `social_sign_in_unavailable`); the first two are also `closeAccount`
|
|
543
|
+
* refusals:
|
|
544
|
+
*
|
|
545
|
+
* - `"social_sign_in_unavailable"` (`forbidden`, 403) — this app can't use
|
|
546
|
+
* Sign in with Apple or Google: the provider is not configured for it, or
|
|
547
|
+
* the app is a studio's own (custom) app. Hide the button.
|
|
548
|
+
* - `"invalid_id_token"` (`server`, 400) — the ID token could not be
|
|
549
|
+
* verified (expired, wrong audience, nonce mismatch, already used, or no
|
|
550
|
+
* email on a first sign-in). Start the provider's sign-in again with a new
|
|
551
|
+
* nonce.
|
|
552
|
+
* - `"social_email_unverified"` (`server`, 400) — the provider has not
|
|
553
|
+
* verified the account's email address.
|
|
554
|
+
* - `"social_email_has_password"` (`forbidden`, 403) — the email already
|
|
555
|
+
* belongs to an account with a password. Ask the person to sign in with
|
|
556
|
+
* their password; accounts are never linked implicitly.
|
|
557
|
+
* - `"social_email_has_other_provider"` (`forbidden`, 403) — the email
|
|
558
|
+
* already belongs to an account that signs in with the other provider.
|
|
559
|
+
* Ask the person to use that one.
|
|
560
|
+
* - `"two_factor_join_unsupported"` (`forbidden`, 403) — the account uses
|
|
561
|
+
* two-step verification and is not yet a member of this studio; it can't
|
|
562
|
+
* join a new studio from the app.
|
|
448
563
|
*/
|
|
449
|
-
export declare type FytkitErrorCode = "reauth_required" | "invalid_password" | "invalid_code" | "first_party_account" | (string & {});
|
|
564
|
+
export declare type FytkitErrorCode = "reauth_required" | "invalid_password" | "invalid_code" | "first_party_account" | "social_sign_in_unavailable" | "invalid_id_token" | "social_email_unverified" | "social_email_has_password" | "social_email_has_other_provider" | "two_factor_join_unsupported" | "password_not_set" | "password_required" | "reauth_identity_mismatch" | (string & {});
|
|
450
565
|
|
|
451
566
|
/**
|
|
452
567
|
* The server's structured refusal on a `FytkitError`: why it said no and
|
|
@@ -663,6 +778,43 @@ export declare interface FytkitRefusalRetryAt {
|
|
|
663
778
|
readonly retryAfterMs?: number;
|
|
664
779
|
}
|
|
665
780
|
|
|
781
|
+
/** The identity providers whose ID tokens `auth.signInWithIdToken` accepts. */
|
|
782
|
+
export declare type IdTokenProvider = "apple" | "google";
|
|
783
|
+
|
|
784
|
+
/**
|
|
785
|
+
* A fresh Apple or Google ID token that proves the signed-in member is
|
|
786
|
+
* present, for `auth.closeAccount` on an account without a password. Run
|
|
787
|
+
* the provider's sign-in again with a new nonce, as for `signInWithIdToken`:
|
|
788
|
+
* `nonce` is the raw nonce the app generated (pass its SHA-256 hex to Apple,
|
|
789
|
+
* the raw nonce to Google). The token must be at most 10 minutes old and
|
|
790
|
+
* belong to the Apple or Google account the member signs in with.
|
|
791
|
+
* `authorizationCode` is Apple's authorization code from that same sign-in
|
|
792
|
+
* (Apple only); send it so the server can revoke the app's Apple tokens.
|
|
793
|
+
*/
|
|
794
|
+
export declare interface IdTokenReauthentication {
|
|
795
|
+
provider: IdTokenProvider;
|
|
796
|
+
idToken: string;
|
|
797
|
+
nonce: string;
|
|
798
|
+
authorizationCode?: string;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* The discriminated return value from `auth.signInWithIdToken()`. As
|
|
803
|
+
* `SignInResult`, plus `memberCreated` on `"signed_in"`: true when this call
|
|
804
|
+
* made the person a member of this studio (a new account, or an existing
|
|
805
|
+
* account joining this studio for the first time), so the app can show its
|
|
806
|
+
* onboarding. `"two_factor_required"` continues with the same `verify*`
|
|
807
|
+
* methods as `signIn`'s challenge.
|
|
808
|
+
*/
|
|
809
|
+
export declare type IdTokenSignInResult = {
|
|
810
|
+
readonly kind: "signed_in";
|
|
811
|
+
readonly session: Session;
|
|
812
|
+
readonly memberCreated: boolean;
|
|
813
|
+
} | {
|
|
814
|
+
readonly kind: "two_factor_required";
|
|
815
|
+
readonly challenge: TwoFactorChallenge;
|
|
816
|
+
};
|
|
817
|
+
|
|
666
818
|
/** A coach a join code's studio names publicly. */
|
|
667
819
|
export declare interface JoinCodeCoach {
|
|
668
820
|
/** The coach's public name. */
|
|
@@ -906,6 +1058,46 @@ declare const publicRouter: {
|
|
|
906
1058
|
}>>;
|
|
907
1059
|
}, $strip>], "kind">;
|
|
908
1060
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1061
|
+
signInWithIdToken: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, {
|
|
1062
|
+
trainerId: string;
|
|
1063
|
+
appId: ActiveDeveloperAppId;
|
|
1064
|
+
clientId: string | undefined;
|
|
1065
|
+
hasActiveSubscription: boolean;
|
|
1066
|
+
clientEntitlements: ClientEntitlements;
|
|
1067
|
+
authMode: "dev-app";
|
|
1068
|
+
developerApp: CallingDeveloperApp;
|
|
1069
|
+
impersonatedBy: string | null;
|
|
1070
|
+
}>, ZodObject< {
|
|
1071
|
+
provider: ZodEnum< {
|
|
1072
|
+
apple: "apple";
|
|
1073
|
+
google: "google";
|
|
1074
|
+
}>;
|
|
1075
|
+
idToken: ZodString;
|
|
1076
|
+
nonce: ZodString;
|
|
1077
|
+
name: ZodOptional<ZodString>;
|
|
1078
|
+
authorizationCode: ZodOptional<ZodString>;
|
|
1079
|
+
}, $strip>, ZodObject< {
|
|
1080
|
+
data: ZodDiscriminatedUnion<[ZodObject< {
|
|
1081
|
+
kind: ZodLiteral<"signed_in">;
|
|
1082
|
+
user: ZodObject< {
|
|
1083
|
+
id: ZodString;
|
|
1084
|
+
email: ZodString;
|
|
1085
|
+
}, $strip>;
|
|
1086
|
+
session: ZodObject< {
|
|
1087
|
+
accessToken: ZodString;
|
|
1088
|
+
expiresAt: ZodString;
|
|
1089
|
+
}, $strip>;
|
|
1090
|
+
memberCreated: ZodBoolean;
|
|
1091
|
+
}, $strip>, ZodObject< {
|
|
1092
|
+
kind: ZodLiteral<"two_factor_required">;
|
|
1093
|
+
twoFactorToken: ZodString;
|
|
1094
|
+
availableMethods: ZodArray<ZodEnum< {
|
|
1095
|
+
totp: "totp";
|
|
1096
|
+
backup_code: "backup_code";
|
|
1097
|
+
email_otp: "email_otp";
|
|
1098
|
+
}>>;
|
|
1099
|
+
}, $strip>], "kind">;
|
|
1100
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
909
1101
|
signOut: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, {
|
|
910
1102
|
trainerId: string;
|
|
911
1103
|
appId: ActiveDeveloperAppId;
|
|
@@ -1059,6 +1251,7 @@ declare const publicRouter: {
|
|
|
1059
1251
|
}, $strip>, ZodObject< {
|
|
1060
1252
|
data: ZodObject< {
|
|
1061
1253
|
success: ZodLiteral<true>;
|
|
1254
|
+
accessToken: ZodString;
|
|
1062
1255
|
}, $strip>;
|
|
1063
1256
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1064
1257
|
regenerateBackupCodes: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, {
|
|
@@ -1179,6 +1372,8 @@ declare const publicRouter: {
|
|
|
1179
1372
|
twoFactorEnabled: ZodBoolean;
|
|
1180
1373
|
totpEnabled: ZodBoolean;
|
|
1181
1374
|
hasBackupCodes: ZodBoolean;
|
|
1375
|
+
passwordChangedAt: ZodNullable<ZodString>;
|
|
1376
|
+
backupCodesRemaining: ZodNullable<ZodNumber>;
|
|
1182
1377
|
}, $strip>;
|
|
1183
1378
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1184
1379
|
changePassword: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, {
|
|
@@ -1243,7 +1438,16 @@ declare const publicRouter: {
|
|
|
1243
1438
|
impersonatedBy: string | null;
|
|
1244
1439
|
}>, ZodObject< {
|
|
1245
1440
|
confirmEmail: ZodString;
|
|
1246
|
-
password: ZodString
|
|
1441
|
+
password: ZodOptional<ZodString>;
|
|
1442
|
+
identityToken: ZodOptional<ZodObject< {
|
|
1443
|
+
provider: ZodEnum< {
|
|
1444
|
+
apple: "apple";
|
|
1445
|
+
google: "google";
|
|
1446
|
+
}>;
|
|
1447
|
+
idToken: ZodString;
|
|
1448
|
+
nonce: ZodString;
|
|
1449
|
+
authorizationCode: ZodOptional<ZodString>;
|
|
1450
|
+
}, $strip>>;
|
|
1247
1451
|
}, $strip>, ZodObject< {
|
|
1248
1452
|
data: ZodObject< {
|
|
1249
1453
|
success: ZodLiteral<true>;
|
|
@@ -1694,6 +1898,63 @@ declare const publicRouter: {
|
|
|
1694
1898
|
}, $strip>;
|
|
1695
1899
|
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1696
1900
|
};
|
|
1901
|
+
nutritionFollow: {
|
|
1902
|
+
list: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, ApiKeyContext>, Schema<unknown, unknown>, ZodObject< {
|
|
1903
|
+
data: ZodArray<ZodObject< {
|
|
1904
|
+
id: ZodString;
|
|
1905
|
+
planId: ZodString;
|
|
1906
|
+
status: ZodEnum< {
|
|
1907
|
+
active: "active";
|
|
1908
|
+
stopped: "stopped";
|
|
1909
|
+
}>;
|
|
1910
|
+
startDate: ZodISODate;
|
|
1911
|
+
startedAt: ZodString;
|
|
1912
|
+
stoppedAt: ZodNullable<ZodString>;
|
|
1913
|
+
plan: ZodObject< {
|
|
1914
|
+
id: ZodString;
|
|
1915
|
+
title: ZodString;
|
|
1916
|
+
description: ZodString;
|
|
1917
|
+
accessLevel: ZodEnum< {
|
|
1918
|
+
free: "free";
|
|
1919
|
+
premium: "premium";
|
|
1920
|
+
}>;
|
|
1921
|
+
canAccess: ZodBoolean;
|
|
1922
|
+
status: ZodEnum< {
|
|
1923
|
+
draft: "draft";
|
|
1924
|
+
published: "published";
|
|
1925
|
+
archived: "archived";
|
|
1926
|
+
}>;
|
|
1927
|
+
durationWeeks: ZodNumber;
|
|
1928
|
+
headerImageUrl: ZodNullable<ZodString>;
|
|
1929
|
+
}, $strip>;
|
|
1930
|
+
}, $strip>>;
|
|
1931
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1932
|
+
start: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, ApiKeyContext>, ZodObject< {
|
|
1933
|
+
planId: ZodString;
|
|
1934
|
+
startDate: ZodOptional<ZodISODate>;
|
|
1935
|
+
}, $strip>, ZodObject< {
|
|
1936
|
+
data: ZodObject< {
|
|
1937
|
+
id: ZodString;
|
|
1938
|
+
planId: ZodString;
|
|
1939
|
+
status: ZodEnum< {
|
|
1940
|
+
active: "active";
|
|
1941
|
+
stopped: "stopped";
|
|
1942
|
+
}>;
|
|
1943
|
+
startDate: ZodISODate;
|
|
1944
|
+
startedAt: ZodString;
|
|
1945
|
+
stoppedAt: ZodNullable<ZodString>;
|
|
1946
|
+
stoppedFollowId: ZodNullable<ZodString>;
|
|
1947
|
+
}, $strip>;
|
|
1948
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1949
|
+
stop: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, ApiKeyContext>, ZodObject< {
|
|
1950
|
+
id: ZodString;
|
|
1951
|
+
}, $strip>, ZodObject< {
|
|
1952
|
+
data: ZodObject< {
|
|
1953
|
+
id: ZodString;
|
|
1954
|
+
status: ZodLiteral<"stopped">;
|
|
1955
|
+
}, $strip>;
|
|
1956
|
+
}, $strip>, Record<never, never>, Record<never, never>>;
|
|
1957
|
+
};
|
|
1697
1958
|
nutritionLog: {
|
|
1698
1959
|
getDay: DecoratedProcedure<MergedInitialContext<DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext & Record<never, never>, DeveloperAppRequestContext>, MergedCurrentContext<DeveloperAppRequestContext, ApiKeyContext>, ZodObject< {
|
|
1699
1960
|
date: ZodString;
|
|
@@ -1830,6 +2091,10 @@ declare const publicRouter: {
|
|
|
1830
2091
|
lb: "lb";
|
|
1831
2092
|
kg: "kg";
|
|
1832
2093
|
}>;
|
|
2094
|
+
lengthUnit: ZodEnum< {
|
|
2095
|
+
in: "in";
|
|
2096
|
+
cm: "cm";
|
|
2097
|
+
}>;
|
|
1833
2098
|
timezone: ZodNullable<ZodString>;
|
|
1834
2099
|
fitnessGoal: ZodNullable<ZodEnum< {
|
|
1835
2100
|
lose_fat: "lose_fat";
|
|
@@ -1857,6 +2122,10 @@ declare const publicRouter: {
|
|
|
1857
2122
|
lb: "lb";
|
|
1858
2123
|
kg: "kg";
|
|
1859
2124
|
}>>;
|
|
2125
|
+
lengthUnit: ZodOptional<ZodEnum< {
|
|
2126
|
+
in: "in";
|
|
2127
|
+
cm: "cm";
|
|
2128
|
+
}>>;
|
|
1860
2129
|
fitnessGoal: ZodOptional<ZodNullable<ZodEnum< {
|
|
1861
2130
|
lose_fat: "lose_fat";
|
|
1862
2131
|
build_muscle: "build_muscle";
|
|
@@ -1876,6 +2145,10 @@ declare const publicRouter: {
|
|
|
1876
2145
|
lb: "lb";
|
|
1877
2146
|
kg: "kg";
|
|
1878
2147
|
}>;
|
|
2148
|
+
lengthUnit: ZodEnum< {
|
|
2149
|
+
in: "in";
|
|
2150
|
+
cm: "cm";
|
|
2151
|
+
}>;
|
|
1879
2152
|
timezone: ZodNullable<ZodString>;
|
|
1880
2153
|
fitnessGoal: ZodNullable<ZodEnum< {
|
|
1881
2154
|
lose_fat: "lose_fat";
|
|
@@ -2376,6 +2649,7 @@ declare const publicRouter: {
|
|
|
2376
2649
|
videoAssetId: ZodNullable<ZodString>;
|
|
2377
2650
|
headerImageId: ZodNullable<ZodString>;
|
|
2378
2651
|
headerImageUrl: ZodNullable<ZodString>;
|
|
2652
|
+
durationMinutes: ZodNullable<ZodNumber>;
|
|
2379
2653
|
blocks: ZodArray<ZodObject< {
|
|
2380
2654
|
id: ZodString;
|
|
2381
2655
|
title: ZodString;
|
|
@@ -2448,6 +2722,7 @@ declare const publicRouter: {
|
|
|
2448
2722
|
videoAssetId: ZodNullable<ZodString>;
|
|
2449
2723
|
headerImageId: ZodNullable<ZodString>;
|
|
2450
2724
|
headerImageUrl: ZodNullable<ZodString>;
|
|
2725
|
+
durationMinutes: ZodNullable<ZodNumber>;
|
|
2451
2726
|
blocks: ZodArray<ZodObject< {
|
|
2452
2727
|
id: ZodString;
|
|
2453
2728
|
title: ZodString;
|
|
@@ -2513,6 +2788,7 @@ declare const publicRouter: {
|
|
|
2513
2788
|
videoAssetId: ZodNullable<ZodString>;
|
|
2514
2789
|
headerImageId: ZodNullable<ZodString>;
|
|
2515
2790
|
headerImageUrl: ZodNullable<ZodString>;
|
|
2791
|
+
durationMinutes: ZodNullable<ZodNumber>;
|
|
2516
2792
|
blocks: ZodArray<ZodObject< {
|
|
2517
2793
|
id: ZodString;
|
|
2518
2794
|
title: ZodString;
|
|
@@ -3219,6 +3495,7 @@ declare const publicRouter: {
|
|
|
3219
3495
|
}>;
|
|
3220
3496
|
valueCm: ZodString;
|
|
3221
3497
|
}, $strip>>;
|
|
3498
|
+
clientRequestId: ZodOptional<ZodString>;
|
|
3222
3499
|
}, $strip>, ZodObject< {
|
|
3223
3500
|
data: ZodArray<ZodObject< {
|
|
3224
3501
|
id: ZodString;
|
|
@@ -5431,12 +5708,12 @@ declare const publicRouter: {
|
|
|
5431
5708
|
name: ZodString;
|
|
5432
5709
|
description: ZodString;
|
|
5433
5710
|
icon: ZodNullable<ZodEnum< {
|
|
5711
|
+
Apple: "Apple";
|
|
5434
5712
|
Footprints: "Footprints";
|
|
5435
5713
|
Moon: "Moon";
|
|
5436
5714
|
GlassWater: "GlassWater";
|
|
5437
5715
|
Beef: "Beef";
|
|
5438
5716
|
StretchHorizontal: "StretchHorizontal";
|
|
5439
|
-
Apple: "Apple";
|
|
5440
5717
|
Brain: "Brain";
|
|
5441
5718
|
Sun: "Sun";
|
|
5442
5719
|
}>>;
|
|
@@ -5588,12 +5865,12 @@ declare const publicRouter: {
|
|
|
5588
5865
|
name: ZodString;
|
|
5589
5866
|
description: ZodString;
|
|
5590
5867
|
icon: ZodNullable<ZodEnum< {
|
|
5868
|
+
Apple: "Apple";
|
|
5591
5869
|
Footprints: "Footprints";
|
|
5592
5870
|
Moon: "Moon";
|
|
5593
5871
|
GlassWater: "GlassWater";
|
|
5594
5872
|
Beef: "Beef";
|
|
5595
5873
|
StretchHorizontal: "StretchHorizontal";
|
|
5596
|
-
Apple: "Apple";
|
|
5597
5874
|
Brain: "Brain";
|
|
5598
5875
|
Sun: "Sun";
|
|
5599
5876
|
}>>;
|
|
@@ -6267,7 +6544,7 @@ export declare interface RealtimeConnection {
|
|
|
6267
6544
|
*/
|
|
6268
6545
|
export declare function refusalData<R extends keyof FytkitRefusalDataByReason>(error: unknown, reason: R): FytkitRefusalDataByReason[R] | null;
|
|
6269
6546
|
|
|
6270
|
-
declare type RequestSurface = "rpc" | "rest";
|
|
6547
|
+
declare type RequestSurface = "rpc" | "rest" | "internal";
|
|
6271
6548
|
|
|
6272
6549
|
/**
|
|
6273
6550
|
* Returned by `auth.resendVerification`. `already_verified`: the member's
|
|
@@ -6356,6 +6633,10 @@ export declare interface SecurityStatus {
|
|
|
6356
6633
|
readonly twoFactorEnabled: boolean;
|
|
6357
6634
|
readonly totpEnabled: boolean;
|
|
6358
6635
|
readonly hasBackupCodes: boolean;
|
|
6636
|
+
/** When the password was last set or changed (ISO 8601); null when the account has no password. */
|
|
6637
|
+
readonly passwordChangedAt: string | null;
|
|
6638
|
+
/** Unused backup codes left; null when two-factor is off, 0 when every code is used. */
|
|
6639
|
+
readonly backupCodesRemaining: number | null;
|
|
6359
6640
|
}
|
|
6360
6641
|
|
|
6361
6642
|
/** Cached session in storage. `expiresAt` is an ISO-8601 string from the server. */
|
|
@@ -6418,7 +6699,10 @@ export declare type SignInResult = {
|
|
|
6418
6699
|
* `refused`.
|
|
6419
6700
|
*
|
|
6420
6701
|
* `onChange` carries no data: read the conversation and the unread count
|
|
6421
|
-
* again.
|
|
6702
|
+
* again. `onCoachTyping`, when given, says who on the coaching team is
|
|
6703
|
+
* writing to the trainee while the channel is live
|
|
6704
|
+
* ({@link CoachTypingState}). Poll while the status is `connecting` or
|
|
6705
|
+
* `fallback`. Needs
|
|
6422
6706
|
* `@supabase/supabase-js` 2.87.1 or later (see {@link RealtimeClientFactory}).
|
|
6423
6707
|
*
|
|
6424
6708
|
* @example
|
|
@@ -6451,6 +6735,14 @@ export declare interface SubscribeToMessagesOptions {
|
|
|
6451
6735
|
readonly onChange: () => void;
|
|
6452
6736
|
/** Each change of {@link MessagesRealtimeStatus}, starting with `connecting`. */
|
|
6453
6737
|
readonly onStatus?: (status: MessagesRealtimeStatus) => void;
|
|
6738
|
+
/**
|
|
6739
|
+
* Each change of {@link CoachTypingState}: someone on the trainee's
|
|
6740
|
+
* coaching team started or stopped writing to them. Optional; never
|
|
6741
|
+
* called before a `typing`. A subscription that ends by itself
|
|
6742
|
+
* (`refused`, or `fallback` for good) reports `idle` first if anyone was
|
|
6743
|
+
* writing; after `unsubscribe()`, nothing is reported.
|
|
6744
|
+
*/
|
|
6745
|
+
readonly onCoachTyping?: (typing: CoachTypingState) => void;
|
|
6454
6746
|
}
|
|
6455
6747
|
|
|
6456
6748
|
/** Pluggable storage so the SDK runs in browser, SSR, and tests. */
|