@foir/sdk 0.21.0 → 0.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/CHANGELOG.md +84 -1
  2. package/README.md +9 -9
  3. package/dist/app/client.d.ts +90 -84
  4. package/dist/app/contract/proto/apps/v1/apps_pb.d.ts +14 -13
  5. package/dist/app/dispatch.d.ts +5 -5
  6. package/dist/app/errors.d.ts +11 -11
  7. package/dist/app/index.d.ts +4 -4
  8. package/dist/app/naming.d.ts +1 -1
  9. package/dist/app/ticket.d.ts +2 -2
  10. package/dist/app/vocabulary.generated.d.ts +2 -2
  11. package/dist/app-contract.js +3 -3
  12. package/dist/app.js +92 -90
  13. package/dist/auth/access.d.ts +19 -19
  14. package/dist/auth/auth.d.ts +216 -114
  15. package/dist/auth/hosted.d.ts +14 -14
  16. package/dist/auth/index.d.ts +7 -7
  17. package/dist/auth/operations.d.ts +128 -32
  18. package/dist/auth/ops.d.ts +39 -21
  19. package/dist/auth/session-client.d.ts +3 -3
  20. package/dist/auth-session.js +3 -3
  21. package/dist/auth.js +234 -135
  22. package/dist/client.js +4 -4
  23. package/dist/data/builtins.d.ts +26 -26
  24. package/dist/data/client.d.ts +2 -2
  25. package/dist/data/decimal.d.ts +1 -1
  26. package/dist/data/index.d.ts +1 -1
  27. package/dist/data/manifest.d.ts +1 -1
  28. package/dist/data/schema.d.ts +1 -1
  29. package/dist/data/transport.d.ts +10 -10
  30. package/dist/data/ws-transport.d.ts +1 -1
  31. package/dist/data.js +6 -6
  32. package/dist/graphql/content-client.d.ts +13 -13
  33. package/dist/live/drift.d.ts +1 -1
  34. package/dist/media/screen-capture.d.ts +1 -1
  35. package/dist/next/index.d.ts +2 -2
  36. package/dist/next/session.d.ts +10 -10
  37. package/dist/next.js +77 -56
  38. package/dist/placement/index.d.ts +13 -13
  39. package/dist/placement.js +9 -6
  40. package/dist/push.js +61 -40
  41. package/dist/react/FoirFeedback.d.ts +2 -2
  42. package/dist/react/FoirProvider.d.ts +23 -23
  43. package/dist/react/SignIn.d.ts +4 -4
  44. package/dist/react/UserButton.d.ts +1 -1
  45. package/dist/react/feedback-notes.d.ts +4 -4
  46. package/dist/react/index.d.ts +3 -3
  47. package/dist/react.js +119 -95
  48. package/dist/realtime/index.d.ts +1 -1
  49. package/dist/server/callback-client.d.ts +4 -4
  50. package/dist/server/events-client.d.ts +16 -16
  51. package/dist/server/operation-types.d.ts +8 -8
  52. package/dist/server/require-scoped-token.d.ts +3 -3
  53. package/dist/server/types.d.ts +1 -1
  54. package/dist/server/verify-scoped-token.d.ts +3 -3
  55. package/dist/server.js +16 -13
  56. package/dist/transport/foir-http.d.ts +13 -13
  57. package/dist/types/index.d.ts +2 -2
  58. package/package.json +3 -3
@@ -1,5 +1,5 @@
1
1
  /**
2
- * What the signed-in customer may see: the roles they hold and the scopes those
2
+ * What the signed-in user may see: the roles they hold and the scopes those
3
3
  * roles resolve to, as the platform resolved them for the request that asked.
4
4
  *
5
5
  * Use it to decide what to SHOW: a staff menu, an edit button. It guards
@@ -14,48 +14,48 @@ import { type AuthOpOptions } from './ops';
14
14
  import { type SessionAdapter } from './auth';
15
15
  import type { FoirEnv } from '../graphql/foir-request';
16
16
  /**
17
- * A signed-in customer's access, as the platform resolved it. Plain data, so it
17
+ * A signed-in user's access, as the platform resolved it. Plain data, so it
18
18
  * can be returned from a loader or a server component and read on the other
19
19
  * side with {@link hasRole} and {@link hasScope}.
20
20
  */
21
21
  export interface FoirAccess {
22
- /** The signed-in customer. */
23
- customerId: string;
22
+ /** The signed-in user. */
23
+ userId: string;
24
24
  /**
25
- * The keys of the roles the customer holds here, now: across the project, and
25
+ * The keys of the roles the user holds here, now: across the project, and
26
26
  * in the organization they stand in. An empty list means they hold none.
27
27
  *
28
28
  * `null` means the platform did not say, which is not the same thing: treat it
29
29
  * as not known, never as "holds no role". {@link hasRole} answers false for
30
30
  * it, and {@link requireRole} refuses with `roles_unknown` so an outage is not
31
- * mistaken for a customer who is not staff.
31
+ * mistaken for a user who holds no role.
32
32
  */
33
33
  roles: string[] | null;
34
34
  /**
35
- * Everything the customer may do through this key: the set the platform's own
35
+ * Everything the user may do through this key: the set the platform's own
36
36
  * checks read for the request. Ask it with {@link hasScope} and not by looking
37
37
  * for a string, because a wider grant covers a narrower one.
38
38
  */
39
39
  scopes: string[];
40
40
  }
41
41
  /**
42
- * The access of the customer a token belongs to, or `null` when the request
43
- * carries no customer. Pass the customer's access token as
42
+ * The access of the user a token belongs to, or `null` when the request
43
+ * carries no user. Pass the user's access token as
44
44
  * `options.bearerToken`.
45
45
  */
46
- export declare function customerAccess(env: FoirEnv, options?: AuthOpOptions): Promise<FoirAccess | null>;
46
+ export declare function userAccess(env: FoirEnv, options?: AuthOpOptions): Promise<FoirAccess | null>;
47
47
  /**
48
- * The access of the session's customer, or `null` when nobody is signed in.
48
+ * The access of the session's user, or `null` when nobody is signed in.
49
49
  * Renews a lapsed session once, as every signed-in read does.
50
50
  */
51
51
  export declare function getSessionAccess(adapter: SessionAdapter, env: FoirEnv): Promise<FoirAccess | null>;
52
52
  /**
53
- * Whether the customer holds the role with this key. False when nobody is
53
+ * Whether the user holds the role with this key. False when nobody is
54
54
  * signed in, and false when their roles are not known.
55
55
  */
56
56
  export declare function hasRole(access: FoirAccess | null | undefined, key: string): boolean;
57
57
  /**
58
- * Whether the customer's scopes cover this one, by the platform's rule: a wider
58
+ * Whether the user's scopes cover this one, by the platform's rule: a wider
59
59
  * reach covers a narrower one (`records:read.all` covers `records:read`), a
60
60
  * grant for every model covers one model (`records:write` covers
61
61
  * `records:write:post`), and never the other way round. A scope that is not a
@@ -66,11 +66,11 @@ export declare function hasScope(access: FoirAccess | null | undefined, scope: s
66
66
  export type FoirAccessDenial =
67
67
  /** Nobody is signed in. */
68
68
  'signed_out'
69
- /** The customer does not hold the role. */
69
+ /** The user does not hold the role. */
70
70
  | 'role_not_held'
71
- /** The platform did not say which roles the customer holds. */
71
+ /** The platform did not say which roles the user holds. */
72
72
  | 'roles_unknown'
73
- /** The customer's scopes do not cover the scope. */
73
+ /** The user's scopes do not cover the scope. */
74
74
  | 'scope_not_held';
75
75
  /**
76
76
  * What {@link requireRole} and {@link requireScope} throw. Catch it by class or
@@ -90,16 +90,16 @@ export declare class FoirAccessDeniedError extends Error {
90
90
  });
91
91
  }
92
92
  /**
93
- * Require a signed-in customer who holds the role with this key, in a server
93
+ * Require a signed-in user who holds the role with this key, in a server
94
94
  * route or a loader. Returns their access; throws
95
95
  * {@link FoirAccessDeniedError} otherwise.
96
96
  *
97
- * This keeps a page from rendering for the wrong customer. It is not what
97
+ * This keeps a page from rendering for the wrong user. It is not what
98
98
  * protects the data: the platform checks every request the page then makes.
99
99
  */
100
100
  export declare function requireRole(adapter: SessionAdapter, env: FoirEnv, key: string): Promise<FoirAccess>;
101
101
  /**
102
- * Require a signed-in customer whose scopes cover this one, by the rule
102
+ * Require a signed-in user whose scopes cover this one, by the rule
103
103
  * {@link hasScope} reads. Returns their access; throws
104
104
  * {@link FoirAccessDeniedError} otherwise.
105
105
  */
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Foir customer auth — framework-agnostic flows, token lifecycle, and guards.
2
+ * Foir sign-in for your app's users: framework-agnostic flows, token
3
+ * lifecycle, and guards.
3
4
  *
4
5
  * Session I/O is injected via {@link SessionAdapter} (no Hydrogen/React-Router
5
6
  * coupling). Pre-login flows authenticate with the project `x-api-key`;
6
- * post-login reads add the customer bearer. The project-specific profile (e.g.
7
- * `isAdmin`) is resolved by a consumer-supplied `resolveUser` — the SDK never
8
- * hardcodes the per-project customer profile shape.
7
+ * post-login reads add the user's bearer. Anything project-specific about the
8
+ * user (a profile record, say) is resolved by a consumer-supplied
9
+ * `resolveUser`: the SDK never hardcodes a per-project profile shape.
9
10
  *
10
11
  * TRANSPORT. Every flow below addresses the server's generated `auth` namespace
11
12
  * through `./ops`, which is `@foir/sdk/data`'s op transport. This module holds
@@ -16,23 +17,17 @@
16
17
  */
17
18
  import { type FoirEnv } from '../graphql/foir-request';
18
19
  import { type AuthOpName, type AuthOpOptions } from './ops';
19
- import { type AuthConfig, type AuthProviderPublic, type CurrentUser, type CustomerAuthResult, type DefaultAuthProvider, type DeleteAccountResult, type MyOrganization, type SelectedOrganization, type ProviderCallbackInput, type ProviderLoginInput, type ProviderLoginResult, type ProviderOTPVerifyInput, type ProviderToken, type SignupContext, type WaitlistJoinResult } from './operations';
20
+ import { type AuthConfig, type AuthProviderPublic, type CurrentUser, type AuthResult, type DefaultAuthProvider, type AuthorizedApp, type DeleteAccountResult, type MyOrganization, type MyProfile, type MyProfileChange, type MySession, type MyFactor, type StepUp, type FactorEnrollment, type MySignInMethod, type NewPersonalAccessToken, type ProviderCallbackInput, type ProviderLoginInput, type ProviderLoginResult, type ProviderOTPVerifyInput, type ProviderToken, type SignupContext, type WaitlistJoinResult } from './operations';
20
21
  import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
21
22
  /** An access token + its rotating refresh token. */
22
23
  export interface FoirAuthTokens {
23
24
  token: string;
24
25
  refreshToken: string;
25
26
  }
26
- /** The customer identity carried by an auth result. */
27
- export interface FoirCustomer {
28
- id: string;
29
- email: string;
30
- }
31
- /** The resolved customer for a guarded surface. */
27
+ /** The signed-in user an auth result and a session carry. */
32
28
  export interface FoirUser {
33
29
  id: string;
34
30
  email: string;
35
- isAdmin: boolean;
36
31
  }
37
32
  /**
38
33
  * Injected session store. Methods may be sync or async so consumers can plug
@@ -44,39 +39,70 @@ export interface SessionAdapter {
44
39
  unset(key: string): void | Promise<void>;
45
40
  }
46
41
  /** Login with email + password. Requires the project to have passwords enabled. */
47
- export declare function customerLogin(env: FoirEnv, vars: {
42
+ export declare function login(env: FoirEnv, vars: {
48
43
  email: string;
49
44
  password: string;
50
- }): Promise<CustomerAuthResult>;
51
- /** Register a new customer with email + password. */
52
- export declare function customerRegister(env: FoirEnv, vars: {
45
+ }): Promise<AuthResult>;
46
+ /** Register a new user with email + password. */
47
+ export declare function register(env: FoirEnv, vars: {
53
48
  email: string;
54
49
  password: string;
55
- }): Promise<CustomerAuthResult>;
56
- /** Request a one-time password be emailed to the customer. */
57
- export declare function customerRequestOTP(env: FoirEnv, email: string): Promise<boolean>;
50
+ }): Promise<AuthResult>;
51
+ /** Request a one-time password be emailed to the user. */
52
+ export declare function requestOTP(env: FoirEnv, email: string): Promise<boolean>;
58
53
  /** Complete an OTP login. */
59
- export declare function customerLoginOTP(env: FoirEnv, vars: {
54
+ export declare function loginWithOTP(env: FoirEnv, vars: {
60
55
  email: string;
61
56
  otp: string;
62
- }): Promise<CustomerAuthResult>;
57
+ }): Promise<AuthResult>;
63
58
  /** Rotate an access token using a refresh token. */
64
- export declare function customerRefreshToken(env: FoirEnv, refreshToken: string): Promise<CustomerAuthResult>;
59
+ export declare function refreshTokens(env: FoirEnv, refreshToken: string): Promise<AuthResult>;
65
60
  /**
66
61
  * Initiate provider (OAuth/OIDC) login — returns a `redirectUrl` to send the
67
62
  * user to, or an inline `token` for non-redirect providers.
68
63
  */
69
- export declare function customerLoginWithProvider(env: FoirEnv, input: ProviderLoginInput): Promise<ProviderLoginResult>;
64
+ export declare function loginWithProvider(env: FoirEnv, input: ProviderLoginInput): Promise<ProviderLoginResult>;
70
65
  /** Complete a provider login from the OAuth callback (`code`/`state`). */
71
- export declare function customerProviderCallback(env: FoirEnv, input: ProviderCallbackInput): Promise<CustomerAuthResult>;
66
+ export declare function providerCallback(env: FoirEnv, input: ProviderCallbackInput): Promise<AuthResult>;
72
67
  /** Verify an OTP issued by an external provider. */
73
- export declare function customerProviderVerifyOTP(env: FoirEnv, input: ProviderOTPVerifyInput): Promise<CustomerAuthResult>;
68
+ export declare function providerVerifyOTP(env: FoirEnv, input: ProviderOTPVerifyInput): Promise<AuthResult>;
69
+ /**
70
+ * Why a provider sign-in did not finish, as the platform said it: a stable code
71
+ * your app shows its own words for (`signup_closed`, `provider_named_no_address`,
72
+ * `account_unavailable`, ...). When the code is `link_code_sent`, the sign-in
73
+ * named an address somebody already holds, through a provider that does not
74
+ * prove the address is theirs, and a code was sent to it: `pending` names the
75
+ * wait, and {@link confirmProviderLink} finishes the sign-in with that code.
76
+ * Null for any other failure.
77
+ */
78
+ export declare function providerSignInRefusalOf(error: unknown): {
79
+ code: string;
80
+ pending?: string;
81
+ } | null;
82
+ /**
83
+ * Finish a provider sign-in that is waiting for the code sent to its address,
84
+ * connecting the provider to the account that holds the address. See
85
+ * {@link providerSignInRefusalOf}.
86
+ */
87
+ export declare function confirmProviderLink(env: FoirEnv, input: {
88
+ pending: string;
89
+ code: string;
90
+ }): Promise<AuthResult>;
91
+ /**
92
+ * Send a new code for a provider sign-in that is waiting for one. The new code
93
+ * replaces the one before, and the answer names the new wait.
94
+ */
95
+ export declare function resendProviderLinkCode(env: FoirEnv, input: {
96
+ pending: string;
97
+ }): Promise<{
98
+ pending: string;
99
+ }>;
74
100
  /** List the project's configured auth providers (for a login UI). */
75
101
  export declare function getAuthProviders(env: FoirEnv): Promise<AuthProviderPublic[]>;
76
102
  /**
77
103
  * Read the project's public auth configuration — which built-in methods are
78
104
  * enabled and which external providers to offer. This is what a login screen
79
- * renders itself from, before any customer token exists.
105
+ * renders itself from, before any user token exists.
80
106
  */
81
107
  export declare function getAuthConfig(env: FoirEnv): Promise<AuthConfig>;
82
108
  /**
@@ -85,55 +111,55 @@ export declare function getAuthConfig(env: FoirEnv): Promise<AuthConfig>;
85
111
  */
86
112
  export declare function getDefaultAuthProvider(env: FoirEnv): Promise<DefaultAuthProvider | null>;
87
113
  /**
88
- * Read the project's customer signup mode (public/restricted/waitlist/closed)
114
+ * Read the project's signup mode (public/restricted/waitlist/closed)
89
115
  * so a self-hosted frontend can render the right signup surface proactively.
90
116
  */
91
- export declare function customerSignupContext(env: FoirEnv): Promise<SignupContext>;
117
+ export declare function signupContext(env: FoirEnv): Promise<SignupContext>;
92
118
  /** Join the project's signup waitlist. The project must be in waitlist mode. */
93
- export declare function customerJoinWaitlist(env: FoirEnv, email: string): Promise<WaitlistJoinResult>;
119
+ export declare function joinWaitlist(env: FoirEnv, email: string): Promise<WaitlistJoinResult>;
94
120
  /**
95
121
  * Send a password-reset email. Resolves `true` whether or not the address has
96
122
  * an account: the server answers identically either way, on purpose, so this
97
123
  * endpoint cannot be used to test whether someone has signed up.
98
124
  */
99
- export declare function customerRequestPasswordReset(env: FoirEnv, email: string): Promise<boolean>;
125
+ export declare function requestPasswordReset(env: FoirEnv, email: string): Promise<boolean>;
100
126
  /**
101
127
  * Redeem an emailed reset token and set a new password. Returns a fresh session
102
- * — resetting a password signs the customer in — so pair it with
128
+ * (resetting a password signs the user in), so pair it with
103
129
  * {@link saveSession}, or use {@link resetPasswordAndSignIn} which does both.
104
130
  */
105
- export declare function customerResetPassword(env: FoirEnv, vars: {
131
+ export declare function resetPassword(env: FoirEnv, vars: {
106
132
  token: string;
107
133
  newPassword: string;
108
- }): Promise<CustomerAuthResult>;
134
+ }): Promise<AuthResult>;
109
135
  /** Redeem an emailed verification token. */
110
- export declare function customerVerifyEmail(env: FoirEnv, token: string): Promise<boolean>;
136
+ export declare function verifyEmail(env: FoirEnv, token: string): Promise<boolean>;
111
137
  /**
112
- * Change the calling customer's password. Requires the current password as well
138
+ * Change the calling user's password. Requires the current password as well
113
139
  * as the bearer, so a stolen token alone cannot take the account over.
114
140
  */
115
- export declare function customerUpdatePassword(env: FoirEnv, vars: {
141
+ export declare function updatePassword(env: FoirEnv, vars: {
116
142
  currentPassword: string;
117
143
  newPassword: string;
118
144
  }, options?: AuthOpOptions): Promise<boolean>;
119
145
  /**
120
- * The calling customer, or `null` when the request carried no customer token.
146
+ * The calling user, or `null` when the request carried no user token.
121
147
  * An absent session is an answer rather than a failure, so this does not throw.
122
148
  */
123
149
  export declare function currentUser(env: FoirEnv, options?: AuthOpOptions): Promise<CurrentUser | null>;
124
150
  /**
125
- * The stored upstream provider token for the calling customer, refreshed
151
+ * The stored upstream provider token for the calling user, refreshed
126
152
  * transparently by the server when it has expired. `null` when there is no
127
- * customer token on the request or none stored for that provider.
153
+ * user token on the request or none stored for that provider.
128
154
  */
129
155
  export declare function myProviderToken(env: FoirEnv, providerKey: string, options?: AuthOpOptions): Promise<ProviderToken | null>;
130
156
  /**
131
157
  * End the session server-side, revoking stored provider tokens. This does NOT
132
158
  * clear local session state — {@link signOut} is the pairing that does both.
133
159
  */
134
- export declare function customerLogout(env: FoirEnv, options?: AuthOpOptions): Promise<boolean>;
160
+ export declare function logout(env: FoirEnv, options?: AuthOpOptions): Promise<boolean>;
135
161
  /**
136
- * Delete the calling customer's account and their owned records and files.
162
+ * Delete the calling user's account and their owned records and files.
137
163
  * Irreversible. `password` is required for password accounts and omitted for
138
164
  * provider-only ones; the server enforces the actual re-auth gate and fails
139
165
  * closed, so omitting it is refused rather than allowed.
@@ -143,60 +169,140 @@ export declare function deleteMyAccount(env: FoirEnv, vars: {
143
169
  password?: string;
144
170
  }, options?: AuthOpOptions): Promise<DeleteAccountResult>;
145
171
  /**
146
- * The organizations this operator may stand in.
172
+ * Change the calling user's own name, picture or language. It asks no
173
+ * permission: these are theirs.
174
+ */
175
+ export declare function updateMyProfile(env: FoirEnv, change: MyProfileChange, options?: AuthOpOptions): Promise<MyProfile>;
176
+ /**
177
+ * The apps the calling user has agreed may act for them, and what each may
178
+ * carry: the list an account page shows with a way to take each one back.
179
+ */
180
+ export declare function myAuthorizedApps(env: FoirEnv, options?: AuthOpOptions): Promise<AuthorizedApp[]>;
181
+ /**
182
+ * Take back an app's authority to act for the calling user. Its tokens for
183
+ * them stop working at once, and it has to ask them again.
184
+ */
185
+ export declare function revokeAuthorizedApp(env: FoirEnv, id: string, options?: AuthOpOptions): Promise<boolean>;
186
+ /** Where the calling user is signed in, and the personal access tokens they hold. */
187
+ export declare function mySessions(env: FoirEnv, options?: AuthOpOptions): Promise<MySession[]>;
188
+ /** Sign the calling user out of one session, or revoke one of their tokens, by its id. */
189
+ export declare function endMySession(env: FoirEnv, id: string, options?: AuthOpOptions): Promise<boolean>;
190
+ /**
191
+ * Sign the calling user out of every session and every app, and answer how
192
+ * many sessions ended. Their personal access tokens stay. `keepThis` keeps the
193
+ * session making the request.
194
+ */
195
+ export declare function signOutEverywhere(env: FoirEnv, vars?: {
196
+ keepThis?: boolean;
197
+ }, options?: AuthOpOptions): Promise<number>;
198
+ /**
199
+ * Make a personal access token for the calling user: a standing credential
200
+ * they present beside the app's key, as `Authorization: Bearer`. Its value is
201
+ * answered here once.
202
+ */
203
+ export declare function createPersonalAccessToken(env: FoirEnv, vars: {
204
+ name: string;
205
+ expiresInDays: number;
206
+ }, options?: AuthOpOptions): Promise<NewPersonalAccessToken>;
207
+ /** The providers the calling user signs in with. */
208
+ export declare function mySignInMethods(env: FoirEnv, options?: AuthOpOptions): Promise<MySignInMethod[]>;
209
+ /**
210
+ * Start connecting one of the project's providers to the calling user's
211
+ * account, and answer the provider's address to send the browser to. It comes
212
+ * back to `returnTo` with `connected` or `connect_error` added.
213
+ */
214
+ export declare function connectSignInMethod(env: FoirEnv, vars: {
215
+ provider: string;
216
+ returnTo: string;
217
+ }, options?: AuthOpOptions): Promise<string>;
218
+ /** Disconnect a provider from the calling user's account. */
219
+ export declare function disconnectSignInMethod(env: FoirEnv, provider: string, options?: AuthOpOptions): Promise<boolean>;
220
+ /** The second factors, passkeys and recovery codes the calling user holds. */
221
+ export declare function myFactors(env: FoirEnv, options?: AuthOpOptions): Promise<MyFactor[]>;
222
+ /**
223
+ * Begin proving a second factor with the calling user's password.
224
+ * {@link completeStepUp} finishes it; for a user who holds none, the answer's
225
+ * `elevatedHandle` is already the proof.
226
+ */
227
+ export declare function beginStepUp(env: FoirEnv, password: string, options?: AuthOpOptions): Promise<StepUp>;
228
+ /**
229
+ * Prove a second factor with exactly one of a passkey's or security key's
230
+ * assertion, an authenticator app's code or a recovery code, which is then
231
+ * spent. The session making the request counts as two factors from here, and
232
+ * the answer is an elevated handle for one change to the user's factors in
233
+ * the next ten minutes.
234
+ */
235
+ export declare function completeStepUp(env: FoirEnv, vars: {
236
+ handle: string;
237
+ webauthnAssertionJson?: string;
238
+ totpCode?: string;
239
+ recoveryCode?: string;
240
+ }, options?: AuthOpOptions): Promise<string>;
241
+ /**
242
+ * Begin adding `totp` (an authenticator app), `webauthn` (a security key held
243
+ * as a second factor) or `passkey` (a passkey that signs the user in on its
244
+ * own), with the `elevatedHandle` {@link beginStepUp} or
245
+ * {@link completeStepUp} answered.
246
+ */
247
+ export declare function beginFactorEnrollment(env: FoirEnv, vars: {
248
+ method: 'webauthn' | 'totp' | 'passkey';
249
+ elevatedHandle: string;
250
+ }, options?: AuthOpOptions): Promise<FactorEnrollment>;
251
+ /**
252
+ * Finish adding a second factor, with the `navigator.credentials.create`
253
+ * result or the authenticator app's code.
254
+ */
255
+ export declare function completeFactorEnrollment(env: FoirEnv, vars: {
256
+ handle: string;
257
+ webauthnAttestationJson?: string;
258
+ totpCode?: string;
259
+ name?: string;
260
+ }, options?: AuthOpOptions): Promise<boolean>;
261
+ /** Remove one of the calling user's factors, with an elevated handle from {@link completeStepUp}. */
262
+ export declare function removeFactor(env: FoirEnv, vars: {
263
+ elevatedHandle: string;
264
+ kind: string;
265
+ id: string;
266
+ }, options?: AuthOpOptions): Promise<boolean>;
267
+ /**
268
+ * Make the calling user new recovery codes, with an elevated handle from
269
+ * {@link completeStepUp}. They replace any held and are answered here once.
270
+ */
271
+ export declare function makeRecoveryCodes(env: FoirEnv, elevatedHandle: string, options?: AuthOpOptions): Promise<string[]>;
272
+ /**
273
+ * The organizations this user may stand in.
147
274
  *
148
- * Answered from the CALLING customer's own memberships: each organization they
149
- * hold one in and every organization beneath it, so an operator is shown
150
- * exactly the set they can stand in, and a customer with no memberships sees
151
- * an empty list rather than a refusal. Requires the customer bearer; it is not
152
- * the project's inventory and cannot be used as one.
275
+ * Answered from the calling user's own memberships: each organization they
276
+ * hold one in and every organization beneath it, so the list is exactly the
277
+ * set a request of theirs may name, and a user with no memberships sees an
278
+ * empty list rather than a refusal. Requires the user's bearer; it is not the
279
+ * project's inventory and cannot be used as one.
280
+ *
281
+ * A MEMBERSHIP REACHES DOWNWARD. Someone who is a member of an organization may
282
+ * stand in any organization beneath it without holding a row of their own
283
+ * there. The reverse never works: a membership at a branch stands in no
284
+ * ancestor and in no sibling branch, and a request naming either is refused as
285
+ * not-found, the same answer an organization that does not exist gets.
286
+ * {@link MyOrganization.role} names ONE of the roles that apply where the
287
+ * person stands (the membership held in the organization itself, when there is
288
+ * one); their authority there is the union of every membership that reaches
289
+ * it, together with their own roles in the project.
153
290
  */
154
291
  export declare function myOrganizations(env: FoirEnv, vars?: {
155
292
  first?: number;
156
293
  after?: string;
157
294
  }, options?: AuthOpOptions): Promise<MyOrganization[]>;
158
- /**
159
- * Stand in one of them, for this customer, until they choose otherwise.
160
- *
161
- * Set once — not per call. The selection is stored against the customer and
162
- * resolved into the claim on every subsequent request, so nothing downstream
163
- * takes an org argument. Pass an empty `orgId` to clear it and return to the
164
- * project-shared view.
165
- *
166
- * The server authorises the choice against a live membership and refuses
167
- * otherwise, so a caller cannot select their way into an organization they do
168
- * not run.
169
- *
170
- * A MEMBERSHIP REACHES DOWNWARD, which is what "a live membership" means now
171
- * that organizations nest. Someone who is a member of an organization may stand in any
172
- * organization BENEATH it without holding a row of their own there, and
173
- * {@link myOrganizations} offers exactly that set — so any id it returned can
174
- * be passed here. The reverse never works: a membership at a branch stands in
175
- * no ancestor and in no sibling branch, and both are refused as not-found,
176
- * which is the same answer an organization that does not exist gets.
177
- *
178
- * WHAT STANDING THERE MEANS is every membership that reaches the organization
179
- * selected. Reach a client through a membership above it and the role shown is
180
- * that membership's; authority is the union of every membership that reaches
181
- * it, together with the customer's own roles in the project.
182
- * {@link MyOrganization.role} names ONE of those roles (the membership held in
183
- * the organization itself, when there is one), so it is part of what the next
184
- * request resolves and not the whole of it.
185
- */
186
- export declare function selectOrganization(env: FoirEnv, vars: {
187
- orgId: string;
188
- }, options?: AuthOpOptions): Promise<SelectedOrganization>;
189
295
  /**
190
296
  * Found an organization, as its first member.
191
297
  *
192
298
  * The caller decides the NAME and, optionally, where it hangs — and nothing
193
- * else. The founder is the customer behind the bearer, the id is minted
299
+ * else. The founder is the user behind the bearer, the id is minted
194
300
  * server-side the way a project's and a tenant's are, and the role they hold in
195
301
  * the new organization is the one the PROJECT named in its settings
196
- * (`operatorSignupRole`). The server creates the organization and that one
302
+ * (`organizationSignupRole`). The server creates the organization and that one
197
303
  * membership together.
198
304
  *
199
- * `parentId` FOUNDS A CHILD, which is what lets your own customer create its own
305
+ * `parentId` FOUNDS A CHILD, which is what lets the people you serve create their own
200
306
  * sub-tenants with no administrator in the loop — a reseller adding a client, a
201
307
  * franchise adding a branch. It is resolved against the caller's own
202
308
  * MEMBERSHIPS, not merely against the project: on this lane "an organization
@@ -204,59 +310,59 @@ export declare function selectOrganization(env: FoirEnv, vars: {
204
310
  * not-found. Omit it to found a root, which is what every registration did
205
311
  * before organizations nested.
206
312
  *
207
- * Exists on the wire only while the project's `operatorSignupEnabled` setting
313
+ * Exists on the wire only while the project's `organizationSignupEnabled` setting
208
314
  * is on; a project that never opted in has no such field, and this refuses
209
315
  * naming it. Returns the same entry `myOrganizations` would then list, role
210
- * included, so the application can go straight to {@link selectOrganization}.
316
+ * included, so the application can name it on its next request.
211
317
  */
212
318
  export declare function registerOrganization(env: FoirEnv, vars: {
213
319
  name: string;
214
320
  parentId?: string;
215
321
  }, options?: AuthOpOptions): Promise<MyOrganization>;
216
322
  /**
217
- * Persist an auth result to the session; returns the customer identity.
323
+ * Persist an auth result to the session; returns the signed-in user.
218
324
  *
219
- * A result that names no customer keeps the identity already stored. A refresh
325
+ * A result that names no user keeps the identity already stored. A refresh
220
326
  * rotates the tokens of a session that already knows who it belongs to, and a
221
- * platform that answers a refresh without the customer must not blank that:
327
+ * platform that answers a refresh without the user must not blank that:
222
328
  * {@link requireAuth} reads the stored identity, so a valid token beside an
223
329
  * empty identity reads as signed out.
224
330
  */
225
- export declare function saveSession(adapter: SessionAdapter, result: CustomerAuthResult): Promise<FoirCustomer>;
331
+ export declare function saveSession(adapter: SessionAdapter, result: AuthResult): Promise<FoirUser>;
226
332
  /** Clear all Foir auth keys from the session. */
227
333
  export declare function clearSession(adapter: SessionAdapter): Promise<void>;
228
334
  /** Read the stored access token (null when signed out). */
229
335
  export declare function getSessionToken(adapter: SessionAdapter): Promise<string | null>;
230
- /** Read the stored customer identity (null when signed out). */
231
- export declare function getSessionCustomer(adapter: SessionAdapter): Promise<FoirCustomer | null>;
336
+ /** Read the stored user (null when signed out). */
337
+ export declare function getSessionUser(adapter: SessionAdapter): Promise<FoirUser | null>;
232
338
  /** Login with email + password and persist the session. */
233
- export declare function loginWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
339
+ export declare function signInWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
234
340
  email: string;
235
341
  password: string;
236
- }): Promise<FoirCustomer>;
342
+ }): Promise<FoirUser>;
237
343
  /** Register with email + password and persist the session. */
238
- export declare function registerWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
344
+ export declare function signUpWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
239
345
  email: string;
240
346
  password: string;
241
- }): Promise<FoirCustomer>;
347
+ }): Promise<FoirUser>;
242
348
  /** Complete an OTP login and persist the session. */
243
- export declare function loginWithOTP(adapter: SessionAdapter, env: FoirEnv, vars: {
349
+ export declare function signInWithOTP(adapter: SessionAdapter, env: FoirEnv, vars: {
244
350
  email: string;
245
351
  otp: string;
246
- }): Promise<FoirCustomer>;
352
+ }): Promise<FoirUser>;
247
353
  /**
248
354
  * Complete a forgot-password flow: redeem the emailed token, set the new
249
355
  * password, and persist the session the server mints. The peer of
250
- * {@link loginWithPassword} for the branch where the customer cannot log in.
356
+ * {@link signInWithPassword} for the branch where the user cannot log in.
251
357
  */
252
358
  export declare function resetPasswordAndSignIn(adapter: SessionAdapter, env: FoirEnv, vars: {
253
359
  token: string;
254
360
  newPassword: string;
255
- }): Promise<FoirCustomer>;
361
+ }): Promise<FoirUser>;
256
362
  /**
257
363
  * End the session on both sides: revoke it server-side, then clear local state.
258
364
  *
259
- * The local clear happens even when the server call fails. A customer who
365
+ * The local clear happens even when the server call fails. Someone who
260
366
  * pressed sign-out and got a network error must not be left holding a session
261
367
  * on the device in front of them — the token expires on its own, and the
262
368
  * failure mode of clearing anyway (one orphaned provider token) is strictly
@@ -295,16 +401,18 @@ export declare function authedRequest<TData, TVariables>(adapter: SessionAdapter
295
401
  * management, which is the half a generated namespace does not give you.
296
402
  */
297
403
  export declare function authedOp<T>(adapter: SessionAdapter, env: FoirEnv, op: AuthOpName, args?: Record<string, unknown>): Promise<T>;
298
- export interface RequireAuthOptions {
404
+ export interface RequireAuthOptions<TUser = FoirUser> {
299
405
  /**
300
- * Resolve the full {@link FoirUser} (including the project-specific
301
- * `isAdmin`) from the session identity. Typically runs the project's
302
- * `myProfile` query via {@link authedRequest}. Defaults to `isAdmin: false`.
406
+ * Resolve what the guarded surface needs about the user from the session:
407
+ * typically the project's own profile record, read through
408
+ * {@link authedRequest}. Without it the guard answers the {@link FoirUser}
409
+ * the session holds. What the user may do is a role or a scope: guard on
410
+ * those with {@link requireRole} and {@link requireScope}.
303
411
  */
304
412
  resolveUser?: (ctx: {
305
413
  token: string;
306
- customer: FoirCustomer;
307
- }) => FoirUser | Promise<FoirUser>;
414
+ user: FoirUser;
415
+ }) => TUser | Promise<TUser>;
308
416
  /**
309
417
  * Called when there's no valid session — throw your framework's redirect
310
418
  * (e.g. `throw redirect(loginUrl)`). Must not return.
@@ -319,14 +427,8 @@ export interface RequireAuthOptions {
319
427
  env?: FoirEnv;
320
428
  }
321
429
  /**
322
- * Require a signed-in customer. Resolves the {@link FoirUser} via
323
- * `resolveUser` (or a minimal identity), or invokes `onUnauthenticated` when
324
- * there's no session.
430
+ * Require a signed-in user. Answers what `resolveUser` resolves (or the
431
+ * session's {@link FoirUser}), or invokes `onUnauthenticated` when there's no
432
+ * session.
325
433
  */
326
- export declare function requireAuth(adapter: SessionAdapter, options: RequireAuthOptions): Promise<FoirUser>;
327
- export interface RequireAdminOptions extends RequireAuthOptions {
328
- /** Called when the user is authenticated but not an admin. Must not return. */
329
- onForbidden: () => never | Promise<never>;
330
- }
331
- /** Require a signed-in customer who is also an admin. */
332
- export declare function requireAdmin(adapter: SessionAdapter, options: RequireAdminOptions): Promise<FoirUser>;
434
+ export declare function requireAuth<TUser = FoirUser>(adapter: SessionAdapter, options: RequireAuthOptions<TUser>): Promise<TUser>;