@foir/sdk 0.21.0 → 0.23.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 (62) hide show
  1. package/CHANGELOG.md +135 -1
  2. package/README.md +15 -15
  3. package/dist/app/client.d.ts +93 -86
  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 +17 -15
  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 +251 -117
  15. package/dist/auth/grant-table.generated.d.ts +5 -4
  16. package/dist/auth/hosted.d.ts +38 -14
  17. package/dist/auth/index.d.ts +9 -9
  18. package/dist/auth/operations.d.ts +153 -33
  19. package/dist/auth/ops.d.ts +39 -21
  20. package/dist/auth/session-client.d.ts +3 -3
  21. package/dist/auth-session.js +3 -3
  22. package/dist/auth.js +400 -250
  23. package/dist/client.js +5 -8
  24. package/dist/codegen/preset.d.ts +1 -1
  25. package/dist/data/builtins.d.ts +26 -26
  26. package/dist/data/client.d.ts +3 -3
  27. package/dist/data/decimal.d.ts +1 -1
  28. package/dist/data/index.d.ts +1 -1
  29. package/dist/data/manifest.d.ts +1 -1
  30. package/dist/data/schema.d.ts +2 -2
  31. package/dist/data/transport.d.ts +14 -13
  32. package/dist/data/ws-transport.d.ts +1 -1
  33. package/dist/data.js +8 -11
  34. package/dist/graphql/content-client.d.ts +13 -13
  35. package/dist/index.js +1 -4
  36. package/dist/live/drift.d.ts +1 -1
  37. package/dist/media/screen-capture.d.ts +1 -1
  38. package/dist/next/index.d.ts +2 -2
  39. package/dist/next/session.d.ts +10 -10
  40. package/dist/next.js +78 -60
  41. package/dist/placement/index.d.ts +13 -13
  42. package/dist/placement.js +127 -116
  43. package/dist/push.js +62 -44
  44. package/dist/react/FoirFeedback.d.ts +2 -2
  45. package/dist/react/FoirProvider.d.ts +24 -24
  46. package/dist/react/SignIn.d.ts +4 -4
  47. package/dist/react/UserButton.d.ts +1 -1
  48. package/dist/react/feedback-notes.d.ts +8 -6
  49. package/dist/react/index.d.ts +3 -3
  50. package/dist/react.js +238 -209
  51. package/dist/realtime/index.d.ts +1 -1
  52. package/dist/server/callback-client.d.ts +4 -4
  53. package/dist/server/events-client.d.ts +21 -21
  54. package/dist/server/operation-types.d.ts +8 -8
  55. package/dist/server/require-scoped-token.d.ts +3 -3
  56. package/dist/server/types.d.ts +2 -2
  57. package/dist/server/verify-scoped-token.d.ts +3 -3
  58. package/dist/server.js +130 -126
  59. package/dist/transport/foir-http.d.ts +14 -14
  60. package/dist/transport/key-kind.d.ts +1 -12
  61. package/dist/types/index.d.ts +2 -2
  62. package/package.json +1 -1
@@ -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,80 @@ 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
+ * Why a sign-in your app's own form sent was refused, as the platform said it:
84
+ * a stable code your app shows its own words for. `password_sign_in_off` from
85
+ * {@link login} or {@link register} where the project, or the app the sign-in
86
+ * came through, takes no password; `code_sign_in_off` from {@link requestOTP}
87
+ * or {@link loginWithOTP} where it takes no code. Null for any other failure.
88
+ */
89
+ export declare function signInRefusalOf(error: unknown): {
90
+ code: string;
91
+ } | null;
92
+ /**
93
+ * Finish a provider sign-in that is waiting for the code sent to its address,
94
+ * connecting the provider to the account that holds the address. See
95
+ * {@link providerSignInRefusalOf}.
96
+ */
97
+ export declare function confirmProviderLink(env: FoirEnv, input: {
98
+ pending: string;
99
+ code: string;
100
+ }): Promise<AuthResult>;
101
+ /**
102
+ * Send a new code for a provider sign-in that is waiting for one. The new code
103
+ * replaces the one before, and the answer names the new wait.
104
+ */
105
+ export declare function resendProviderLinkCode(env: FoirEnv, input: {
106
+ pending: string;
107
+ }): Promise<{
108
+ pending: string;
109
+ }>;
74
110
  /** List the project's configured auth providers (for a login UI). */
75
111
  export declare function getAuthProviders(env: FoirEnv): Promise<AuthProviderPublic[]>;
76
112
  /**
77
113
  * Read the project's public auth configuration — which built-in methods are
78
114
  * enabled and which external providers to offer. This is what a login screen
79
- * renders itself from, before any customer token exists.
115
+ * renders itself from, before any user token exists.
80
116
  */
81
117
  export declare function getAuthConfig(env: FoirEnv): Promise<AuthConfig>;
82
118
  /**
@@ -85,55 +121,69 @@ export declare function getAuthConfig(env: FoirEnv): Promise<AuthConfig>;
85
121
  */
86
122
  export declare function getDefaultAuthProvider(env: FoirEnv): Promise<DefaultAuthProvider | null>;
87
123
  /**
88
- * Read the project's customer signup mode (public/restricted/waitlist/closed)
124
+ * Read the project's signup mode (public/restricted/waitlist/closed)
89
125
  * so a self-hosted frontend can render the right signup surface proactively.
90
126
  */
91
- export declare function customerSignupContext(env: FoirEnv): Promise<SignupContext>;
127
+ export declare function signupContext(env: FoirEnv): Promise<SignupContext>;
92
128
  /** Join the project's signup waitlist. The project must be in waitlist mode. */
93
- export declare function customerJoinWaitlist(env: FoirEnv, email: string): Promise<WaitlistJoinResult>;
129
+ export declare function joinWaitlist(env: FoirEnv, email: string): Promise<WaitlistJoinResult>;
94
130
  /**
95
131
  * Send a password-reset email. Resolves `true` whether or not the address has
96
132
  * an account: the server answers identically either way, on purpose, so this
97
133
  * endpoint cannot be used to test whether someone has signed up.
134
+ *
135
+ * `clientId` names your app. Where the email's link goes to Foir's hosted
136
+ * reset page (the project has no App base URL), the page then sends the user
137
+ * to your app's initiate login URL to sign in.
98
138
  */
99
- export declare function customerRequestPasswordReset(env: FoirEnv, email: string): Promise<boolean>;
139
+ export declare function requestPasswordReset(env: FoirEnv, email: string, options?: {
140
+ clientId?: string;
141
+ }): Promise<boolean>;
100
142
  /**
101
143
  * 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
144
+ * (resetting a password signs the user in), so pair it with
103
145
  * {@link saveSession}, or use {@link resetPasswordAndSignIn} which does both.
104
146
  */
105
- export declare function customerResetPassword(env: FoirEnv, vars: {
147
+ export declare function resetPassword(env: FoirEnv, vars: {
106
148
  token: string;
107
149
  newPassword: string;
108
- }): Promise<CustomerAuthResult>;
150
+ }): Promise<AuthResult>;
109
151
  /** Redeem an emailed verification token. */
110
- export declare function customerVerifyEmail(env: FoirEnv, token: string): Promise<boolean>;
152
+ export declare function verifyEmail(env: FoirEnv, token: string): Promise<boolean>;
111
153
  /**
112
- * Change the calling customer's password. Requires the current password as well
154
+ * Change the calling user's password. Requires the current password as well
113
155
  * as the bearer, so a stolen token alone cannot take the account over.
114
156
  */
115
- export declare function customerUpdatePassword(env: FoirEnv, vars: {
157
+ export declare function updatePassword(env: FoirEnv, vars: {
116
158
  currentPassword: string;
117
159
  newPassword: string;
118
160
  }, options?: AuthOpOptions): Promise<boolean>;
119
161
  /**
120
- * The calling customer, or `null` when the request carried no customer token.
162
+ * The calling user, or `null` when the request carried no user token.
121
163
  * An absent session is an answer rather than a failure, so this does not throw.
122
164
  */
123
165
  export declare function currentUser(env: FoirEnv, options?: AuthOpOptions): Promise<CurrentUser | null>;
124
166
  /**
125
- * The stored upstream provider token for the calling customer, refreshed
126
- * 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.
167
+ * The stored upstream provider token for the calling user, renewed by the
168
+ * server when it is due: near its stated expiry, or with no expiry stated.
169
+ * `null` when there is no user token on the request; `linked: false` when the
170
+ * user has none stored for that provider.
171
+ *
172
+ * Pass `forceRefresh` after the provider refused the token it was last given:
173
+ * the server renews it then, at most once a minute for one user and provider.
174
+ * `refresh` says what the read did, and `reauthenticate` says when only the
175
+ * user signing in with the provider again mends the connection.
128
176
  */
129
- export declare function myProviderToken(env: FoirEnv, providerKey: string, options?: AuthOpOptions): Promise<ProviderToken | null>;
177
+ export declare function myProviderToken(env: FoirEnv, providerKey: string, options?: AuthOpOptions & {
178
+ forceRefresh?: boolean;
179
+ }): Promise<ProviderToken | null>;
130
180
  /**
131
181
  * End the session server-side, revoking stored provider tokens. This does NOT
132
182
  * clear local session state — {@link signOut} is the pairing that does both.
133
183
  */
134
- export declare function customerLogout(env: FoirEnv, options?: AuthOpOptions): Promise<boolean>;
184
+ export declare function logout(env: FoirEnv, options?: AuthOpOptions): Promise<boolean>;
135
185
  /**
136
- * Delete the calling customer's account and their owned records and files.
186
+ * Delete the calling user's account and their owned records and files.
137
187
  * Irreversible. `password` is required for password accounts and omitted for
138
188
  * provider-only ones; the server enforces the actual re-auth gate and fails
139
189
  * closed, so omitting it is refused rather than allowed.
@@ -143,60 +193,141 @@ export declare function deleteMyAccount(env: FoirEnv, vars: {
143
193
  password?: string;
144
194
  }, options?: AuthOpOptions): Promise<DeleteAccountResult>;
145
195
  /**
146
- * The organizations this operator may stand in.
196
+ * Change the calling user's own name, picture or language. It asks no
197
+ * permission: these are theirs.
198
+ */
199
+ export declare function updateMyProfile(env: FoirEnv, change: MyProfileChange, options?: AuthOpOptions): Promise<MyProfile>;
200
+ /**
201
+ * The apps the calling user has agreed may act for them, and what each may
202
+ * carry: the list an account page shows with a way to take each one back.
203
+ */
204
+ export declare function myAuthorizedApps(env: FoirEnv, options?: AuthOpOptions): Promise<AuthorizedApp[]>;
205
+ /**
206
+ * Take back an app's authority to act for the calling user. Its tokens for
207
+ * them stop working at once, and it has to ask them again.
208
+ */
209
+ export declare function revokeAuthorizedApp(env: FoirEnv, id: string, options?: AuthOpOptions): Promise<boolean>;
210
+ /** Where the calling user is signed in, and the personal access tokens they hold. */
211
+ export declare function mySessions(env: FoirEnv, options?: AuthOpOptions): Promise<MySession[]>;
212
+ /** Sign the calling user out of one session, or revoke one of their tokens, by its id. */
213
+ export declare function endMySession(env: FoirEnv, id: string, options?: AuthOpOptions): Promise<boolean>;
214
+ /**
215
+ * Sign the calling user out of every session and every app, and answer how
216
+ * many sessions ended. Their personal access tokens stay. `keepThis` keeps the
217
+ * session making the request.
218
+ */
219
+ export declare function signOutEverywhere(env: FoirEnv, vars?: {
220
+ keepThis?: boolean;
221
+ }, options?: AuthOpOptions): Promise<number>;
222
+ /**
223
+ * Make a personal access token for the calling user: a standing credential
224
+ * they present beside the app's key, as `Authorization: Bearer`. Its value is
225
+ * answered here once.
226
+ */
227
+ export declare function createPersonalAccessToken(env: FoirEnv, vars: {
228
+ name: string;
229
+ expiresInDays: number;
230
+ }, options?: AuthOpOptions): Promise<NewPersonalAccessToken>;
231
+ /** The providers the calling user signs in with. */
232
+ export declare function mySignInMethods(env: FoirEnv, options?: AuthOpOptions): Promise<MySignInMethod[]>;
233
+ /**
234
+ * Start connecting one of the project's providers to the calling user's
235
+ * account, and answer the provider's address to send the browser to. It comes
236
+ * back to `returnTo` with `connected` or `connect_error` added.
237
+ */
238
+ export declare function connectSignInMethod(env: FoirEnv, vars: {
239
+ provider: string;
240
+ returnTo: string;
241
+ }, options?: AuthOpOptions): Promise<string>;
242
+ /** Disconnect a provider from the calling user's account. */
243
+ export declare function disconnectSignInMethod(env: FoirEnv, provider: string, options?: AuthOpOptions): Promise<boolean>;
244
+ /** The second factors, passkeys and recovery codes the calling user holds. */
245
+ export declare function myFactors(env: FoirEnv, options?: AuthOpOptions): Promise<MyFactor[]>;
246
+ /**
247
+ * Begin proving a second factor with the calling user's password.
248
+ * {@link completeStepUp} finishes it; for a user who holds none, the answer's
249
+ * `elevatedHandle` is already the proof.
250
+ */
251
+ export declare function beginStepUp(env: FoirEnv, password: string, options?: AuthOpOptions): Promise<StepUp>;
252
+ /**
253
+ * Prove a second factor with exactly one of a passkey's or security key's
254
+ * assertion, an authenticator app's code or a recovery code, which is then
255
+ * spent. The session making the request counts as two factors from here, and
256
+ * the answer is an elevated handle for one change to the user's factors in
257
+ * the next ten minutes.
258
+ */
259
+ export declare function completeStepUp(env: FoirEnv, vars: {
260
+ handle: string;
261
+ webauthnAssertionJson?: string;
262
+ totpCode?: string;
263
+ recoveryCode?: string;
264
+ }, options?: AuthOpOptions): Promise<string>;
265
+ /**
266
+ * Begin adding `totp` (an authenticator app), `webauthn` (a security key held
267
+ * as a second factor) or `passkey` (a passkey that signs the user in on its
268
+ * own), with the `elevatedHandle` {@link beginStepUp} or
269
+ * {@link completeStepUp} answered.
270
+ */
271
+ export declare function beginFactorEnrollment(env: FoirEnv, vars: {
272
+ method: 'webauthn' | 'totp' | 'passkey';
273
+ elevatedHandle: string;
274
+ }, options?: AuthOpOptions): Promise<FactorEnrollment>;
275
+ /**
276
+ * Finish adding a second factor, with the `navigator.credentials.create`
277
+ * result or the authenticator app's code.
278
+ */
279
+ export declare function completeFactorEnrollment(env: FoirEnv, vars: {
280
+ handle: string;
281
+ webauthnAttestationJson?: string;
282
+ totpCode?: string;
283
+ name?: string;
284
+ }, options?: AuthOpOptions): Promise<boolean>;
285
+ /** Remove one of the calling user's factors, with an elevated handle from {@link completeStepUp}. */
286
+ export declare function removeFactor(env: FoirEnv, vars: {
287
+ elevatedHandle: string;
288
+ kind: string;
289
+ id: string;
290
+ }, options?: AuthOpOptions): Promise<boolean>;
291
+ /**
292
+ * Make the calling user new recovery codes, with an elevated handle from
293
+ * {@link completeStepUp}. They replace any held and are answered here once.
294
+ */
295
+ export declare function makeRecoveryCodes(env: FoirEnv, elevatedHandle: string, options?: AuthOpOptions): Promise<string[]>;
296
+ /**
297
+ * The organizations this user may stand in.
147
298
  *
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.
299
+ * Answered from the calling user's own memberships: each organization they
300
+ * hold one in and every organization beneath it, so the list is exactly the
301
+ * set a request of theirs may name, and a user with no memberships sees an
302
+ * empty list rather than a refusal. Requires the user's bearer. A user whose
303
+ * role holds `organizations:read` in the project is listed every organization
304
+ * of it instead, suspended ones included.
305
+ *
306
+ * A MEMBERSHIP REACHES DOWNWARD. Someone who is a member of an organization may
307
+ * stand in any organization beneath it without holding a row of their own
308
+ * there. The reverse never works: a membership at a branch stands in no
309
+ * ancestor and in no sibling branch, and a request naming either is refused as
310
+ * not-found, the same answer an organization that does not exist gets.
311
+ * {@link MyOrganization.role} names ONE of the roles that apply where the
312
+ * person stands (the membership held in the organization itself, when there is
313
+ * one); their authority there is the union of every membership that reaches
314
+ * it, together with their own roles in the project.
153
315
  */
154
316
  export declare function myOrganizations(env: FoirEnv, vars?: {
155
317
  first?: number;
156
318
  after?: string;
157
319
  }, 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
320
  /**
190
321
  * Found an organization, as its first member.
191
322
  *
192
- * 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
323
+ * The caller decides the NAME and, optionally, where it hangs and where it
324
+ * lives — and nothing else. The founder is the user behind the bearer, the id is minted
194
325
  * server-side the way a project's and a tenant's are, and the role they hold in
195
326
  * the new organization is the one the PROJECT named in its settings
196
- * (`operatorSignupRole`). The server creates the organization and that one
327
+ * (`organizationSignupRole`). The server creates the organization and that one
197
328
  * membership together.
198
329
  *
199
- * `parentId` FOUNDS A CHILD, which is what lets your own customer create its own
330
+ * `parentId` FOUNDS A CHILD, which is what lets the people you serve create their own
200
331
  * sub-tenants with no administrator in the loop — a reseller adding a client, a
201
332
  * franchise adding a branch. It is resolved against the caller's own
202
333
  * MEMBERSHIPS, not merely against the project: on this lane "an organization
@@ -204,59 +335,66 @@ export declare function selectOrganization(env: FoirEnv, vars: {
204
335
  * not-found. Omit it to found a root, which is what every registration did
205
336
  * before organizations nested.
206
337
  *
207
- * Exists on the wire only while the project's `operatorSignupEnabled` setting
338
+ * `appBaseUrl` is where the organization's app lives, so an app that finds its
339
+ * organization from the page address (`orgUrl`) finds this one at once. It is
340
+ * held to the rule every organization address is: under the project's own app
341
+ * address or a domain the project verified, and not one another organization
342
+ * of the project holds.
343
+ *
344
+ * Exists on the wire only while the project's `organizationSignupEnabled` setting
208
345
  * is on; a project that never opted in has no such field, and this refuses
209
346
  * naming it. Returns the same entry `myOrganizations` would then list, role
210
- * included, so the application can go straight to {@link selectOrganization}.
347
+ * included, so the application can name it on its next request.
211
348
  */
212
349
  export declare function registerOrganization(env: FoirEnv, vars: {
213
350
  name: string;
214
351
  parentId?: string;
352
+ appBaseUrl?: string;
215
353
  }, options?: AuthOpOptions): Promise<MyOrganization>;
216
354
  /**
217
- * Persist an auth result to the session; returns the customer identity.
355
+ * Persist an auth result to the session; returns the signed-in user.
218
356
  *
219
- * A result that names no customer keeps the identity already stored. A refresh
357
+ * A result that names no user keeps the identity already stored. A refresh
220
358
  * 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:
359
+ * platform that answers a refresh without the user must not blank that:
222
360
  * {@link requireAuth} reads the stored identity, so a valid token beside an
223
361
  * empty identity reads as signed out.
224
362
  */
225
- export declare function saveSession(adapter: SessionAdapter, result: CustomerAuthResult): Promise<FoirCustomer>;
363
+ export declare function saveSession(adapter: SessionAdapter, result: AuthResult): Promise<FoirUser>;
226
364
  /** Clear all Foir auth keys from the session. */
227
365
  export declare function clearSession(adapter: SessionAdapter): Promise<void>;
228
366
  /** Read the stored access token (null when signed out). */
229
367
  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>;
368
+ /** Read the stored user (null when signed out). */
369
+ export declare function getSessionUser(adapter: SessionAdapter): Promise<FoirUser | null>;
232
370
  /** Login with email + password and persist the session. */
233
- export declare function loginWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
371
+ export declare function signInWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
234
372
  email: string;
235
373
  password: string;
236
- }): Promise<FoirCustomer>;
374
+ }): Promise<FoirUser>;
237
375
  /** Register with email + password and persist the session. */
238
- export declare function registerWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
376
+ export declare function signUpWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
239
377
  email: string;
240
378
  password: string;
241
- }): Promise<FoirCustomer>;
379
+ }): Promise<FoirUser>;
242
380
  /** Complete an OTP login and persist the session. */
243
- export declare function loginWithOTP(adapter: SessionAdapter, env: FoirEnv, vars: {
381
+ export declare function signInWithOTP(adapter: SessionAdapter, env: FoirEnv, vars: {
244
382
  email: string;
245
383
  otp: string;
246
- }): Promise<FoirCustomer>;
384
+ }): Promise<FoirUser>;
247
385
  /**
248
386
  * Complete a forgot-password flow: redeem the emailed token, set the new
249
387
  * password, and persist the session the server mints. The peer of
250
- * {@link loginWithPassword} for the branch where the customer cannot log in.
388
+ * {@link signInWithPassword} for the branch where the user cannot log in.
251
389
  */
252
390
  export declare function resetPasswordAndSignIn(adapter: SessionAdapter, env: FoirEnv, vars: {
253
391
  token: string;
254
392
  newPassword: string;
255
- }): Promise<FoirCustomer>;
393
+ }): Promise<FoirUser>;
256
394
  /**
257
395
  * End the session on both sides: revoke it server-side, then clear local state.
258
396
  *
259
- * The local clear happens even when the server call fails. A customer who
397
+ * The local clear happens even when the server call fails. Someone who
260
398
  * pressed sign-out and got a network error must not be left holding a session
261
399
  * on the device in front of them — the token expires on its own, and the
262
400
  * failure mode of clearing anyway (one orphaned provider token) is strictly
@@ -295,16 +433,18 @@ export declare function authedRequest<TData, TVariables>(adapter: SessionAdapter
295
433
  * management, which is the half a generated namespace does not give you.
296
434
  */
297
435
  export declare function authedOp<T>(adapter: SessionAdapter, env: FoirEnv, op: AuthOpName, args?: Record<string, unknown>): Promise<T>;
298
- export interface RequireAuthOptions {
436
+ export interface RequireAuthOptions<TUser = FoirUser> {
299
437
  /**
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`.
438
+ * Resolve what the guarded surface needs about the user from the session:
439
+ * typically the project's own profile record, read through
440
+ * {@link authedRequest}. Without it the guard answers the {@link FoirUser}
441
+ * the session holds. What the user may do is a role or a scope: guard on
442
+ * those with {@link requireRole} and {@link requireScope}.
303
443
  */
304
444
  resolveUser?: (ctx: {
305
445
  token: string;
306
- customer: FoirCustomer;
307
- }) => FoirUser | Promise<FoirUser>;
446
+ user: FoirUser;
447
+ }) => TUser | Promise<TUser>;
308
448
  /**
309
449
  * Called when there's no valid session — throw your framework's redirect
310
450
  * (e.g. `throw redirect(loginUrl)`). Must not return.
@@ -319,14 +459,8 @@ export interface RequireAuthOptions {
319
459
  env?: FoirEnv;
320
460
  }
321
461
  /**
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.
462
+ * Require a signed-in user. Answers what `resolveUser` resolves (or the
463
+ * session's {@link FoirUser}), or invokes `onUnauthenticated` when there's no
464
+ * session.
325
465
  */
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>;
466
+ export declare function requireAuth<TUser = FoirUser>(adapter: SessionAdapter, options: RequireAuthOptions<TUser>): Promise<TUser>;
@@ -1,12 +1,13 @@
1
1
  export type GrantReach = 'own' | 'named' | 'all';
2
+ export type GrantTarget = 'none' | 'model' | 'operation';
2
3
  /**
3
- * One permission: its name, whether a grant of it may name a target, the
4
- * reaches it may be granted at (none: only its bare form exists), and the
5
- * grants a holder of it also holds.
4
+ * One permission: its name, what a grant of it may name, the reaches it may be
5
+ * granted at (none: only its bare form exists), and the grants a holder of it
6
+ * also holds.
6
7
  */
7
8
  export type GrantTableRow = readonly [
8
9
  name: string,
9
- takesTarget: boolean,
10
+ target: GrantTarget,
10
11
  reaches: readonly GrantReach[],
11
12
  implies: readonly string[]
12
13
  ];