@foir/sdk 0.20.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 (65) hide show
  1. package/CHANGELOG.md +135 -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 +291 -146
  22. package/dist/client/platform-client.d.ts +1 -1
  23. package/dist/client.js +32 -5
  24. package/dist/codegen/index.js +1 -1
  25. package/dist/data/builtins.d.ts +41 -82
  26. package/dist/data/client.d.ts +2 -2
  27. package/dist/data/decimal.d.ts +1 -1
  28. package/dist/data/document.d.ts +14 -0
  29. package/dist/data/index.d.ts +2 -2
  30. package/dist/data/manifest.d.ts +1 -1
  31. package/dist/data/schema.d.ts +1 -1
  32. package/dist/data/transport.d.ts +33 -26
  33. package/dist/data/ws-transport.d.ts +1 -1
  34. package/dist/data.js +97 -19
  35. package/dist/graphql/content-client.d.ts +13 -13
  36. package/dist/index.js +24 -0
  37. package/dist/live/drift.d.ts +1 -1
  38. package/dist/media/screen-capture.d.ts +1 -1
  39. package/dist/next/index.d.ts +2 -2
  40. package/dist/next/session.d.ts +10 -10
  41. package/dist/next.js +121 -61
  42. package/dist/placement/index.d.ts +15 -32
  43. package/dist/placement.js +18 -20
  44. package/dist/push.js +113 -46
  45. package/dist/react/FoirFeedback.d.ts +2 -2
  46. package/dist/react/FoirProvider.d.ts +23 -23
  47. package/dist/react/SignIn.d.ts +4 -4
  48. package/dist/react/UserButton.d.ts +1 -1
  49. package/dist/react/feedback-notes.d.ts +4 -4
  50. package/dist/react/index.d.ts +3 -3
  51. package/dist/react.js +168 -105
  52. package/dist/realtime/index.d.ts +1 -1
  53. package/dist/server/callback-client.d.ts +4 -4
  54. package/dist/server/events-client.d.ts +18 -18
  55. package/dist/server/operation-types.d.ts +8 -8
  56. package/dist/server/require-scoped-token.d.ts +3 -3
  57. package/dist/server/server-client.d.ts +1 -1
  58. package/dist/server/types.d.ts +1 -1
  59. package/dist/server/verify-scoped-token.d.ts +4 -28
  60. package/dist/server.js +67 -112
  61. package/dist/transport/foir-http.d.ts +57 -18
  62. package/dist/transport/key-kind.d.ts +40 -0
  63. package/dist/types/index.d.ts +2 -2
  64. package/package.json +3 -3
  65. package/dist/server/older-claims.generated.d.ts +0 -8
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Foir customer-auth result and input types.
2
+ * Foir sign-in result and input types.
3
3
  *
4
4
  * These are PLATFORM-STABLE primitives — login / register / refresh / OTP /
5
5
  * provider login / password management / account lifecycle are fixed-shape
@@ -25,15 +25,15 @@
25
25
  * and they are the reason `@foir/sdk/auth/session` had to exist as a
26
26
  * separate graphql-free door.
27
27
  *
28
- * The project-specific customer PROFILE (e.g. `myProfile.isAdmin`) is still NOT
29
- * here — that shape varies per project, so it stays consumer-injected (see
28
+ * Anything project-specific about the user (a profile record, say) is NOT
29
+ * here: that shape varies per project, so it stays consumer-injected (see
30
30
  * `requireAuth`'s `resolveUser`).
31
31
  */
32
32
  /** The common auth result every login/register/refresh mutation returns. */
33
- export interface CustomerAuthResult {
33
+ export interface AuthResult {
34
34
  token: string;
35
35
  refreshToken: string;
36
- customerId: string;
36
+ userId: string;
37
37
  email: string;
38
38
  }
39
39
  /** Result of initiating a provider login — a redirect URL or an inline token. */
@@ -70,7 +70,7 @@ export interface ProviderOTPVerifyInput {
70
70
  email: string;
71
71
  otp: string;
72
72
  }
73
- /** The project's customer signup mode. */
73
+ /** The project's signup mode. */
74
74
  export type SignupMode = 'PUBLIC' | 'RESTRICTED' | 'WAITLIST' | 'CLOSED';
75
75
  /** The signup surface a self-hosted frontend reads to render the right UI. */
76
76
  export interface SignupContext {
@@ -93,7 +93,7 @@ export interface AuthConfigProvider {
93
93
  /**
94
94
  * The project's public auth configuration: which built-in methods are on, and
95
95
  * which external providers a login screen should offer. Readable before any
96
- * customer token exists — it is what a login screen renders itself from.
96
+ * user token exists: it is what a login screen renders itself from.
97
97
  */
98
98
  export interface AuthConfig {
99
99
  passwordEnabled: boolean;
@@ -110,8 +110,8 @@ export interface DefaultAuthProvider {
110
110
  type: string | null;
111
111
  }
112
112
  /**
113
- * The calling customer, resolved from the bearer token. `null` when the request
114
- * carried no customer token — an absent session is an answer, not a failure.
113
+ * The calling user, resolved from the bearer token. `null` when the request
114
+ * carried no user token: an absent session is an answer, not a failure.
115
115
  */
116
116
  export interface CurrentUser {
117
117
  id: string;
@@ -124,8 +124,8 @@ export interface CurrentUser {
124
124
  createdAt: string;
125
125
  }
126
126
  /**
127
- * A stored upstream provider token for the calling customer. `null` when there
128
- * is no customer token on the request, or none stored for that provider.
127
+ * A stored upstream provider token for the calling user. `null` when there
128
+ * is no user token on the request, or none stored for that provider.
129
129
  */
130
130
  export interface ProviderToken {
131
131
  providerKey: string;
@@ -142,11 +142,119 @@ export interface DeleteAccountResult {
142
142
  recordsDeleted: number;
143
143
  filesDeleted: number;
144
144
  }
145
+ /** The calling user's own profile, as `updateMyProfile` answers it. */
146
+ export interface MyProfile {
147
+ id: string;
148
+ email: string;
149
+ firstName: string | null;
150
+ lastName: string | null;
151
+ avatarUrl: string | null;
152
+ /** BCP47, or null where they follow the project default. */
153
+ preferredLocale: string | null;
154
+ }
145
155
  /**
146
- * One organization the calling operator may stand in, as `myOrganizations`
156
+ * What `updateMyProfile` changes. A field left out stays as it is; an empty
157
+ * string clears it.
158
+ */
159
+ export type MyProfileChange = {
160
+ firstName?: string;
161
+ lastName?: string;
162
+ avatarUrl?: string;
163
+ /** A locale the project publishes. */
164
+ preferredLocale?: string;
165
+ };
166
+ /** Somewhere the calling user is signed in, or a personal access token they hold. */
167
+ export interface MySession {
168
+ /** The session's handle, which {@link endMySession} takes. It signs nobody in. */
169
+ id: string;
170
+ /** `browser` for a sign-in, `personal_access_token` for a token. */
171
+ kind: string;
172
+ /** A personal access token's name. */
173
+ name: string | null;
174
+ /** The first characters of a personal access token's value. */
175
+ tokenPrefix: string | null;
176
+ /** The app it was signed in through. */
177
+ appName: string | null;
178
+ /** ISO-8601. */
179
+ createdAt: string | null;
180
+ /** ISO-8601. */
181
+ lastSeenAt: string | null;
182
+ /** ISO-8601. */
183
+ expiresAt: string | null;
184
+ ipAddress: string | null;
185
+ userAgent: string | null;
186
+ /** Whether it is the session making the request. */
187
+ current: boolean;
188
+ }
189
+ /** A personal access token just made: its value is shown here once. */
190
+ export interface NewPersonalAccessToken {
191
+ token: MySession;
192
+ value: string;
193
+ }
194
+ /** A provider the calling user signs in with. */
195
+ export interface MySignInMethod {
196
+ provider: string;
197
+ /** The address the provider gave when it was connected. */
198
+ email: string | null;
199
+ /** ISO-8601. */
200
+ connectedAt: string | null;
201
+ }
202
+ /** A second factor, passkey or set of recovery codes the calling user holds. */
203
+ export interface MyFactor {
204
+ /** `totp`, `security_key`, `passkey` or `recovery_codes`. */
205
+ kind: string;
206
+ /** What {@link removeFactor} takes. */
207
+ id: string;
208
+ /** A security key's or passkey's name. */
209
+ name: string | null;
210
+ /** ISO-8601. */
211
+ addedAt: string | null;
212
+ /** For recovery codes: how many are left unused. */
213
+ remaining: number | null;
214
+ }
215
+ /**
216
+ * A step-up begun with the calling user's password: waiting for a second
217
+ * factor, or, for a user who holds none, already proven by the password.
218
+ */
219
+ export interface StepUp {
220
+ /** What {@link completeStepUp} takes, for a user who holds a second factor. */
221
+ handle: string | null;
222
+ /** For a user who holds no second factor: the proof their password is, for one change to their factors. */
223
+ elevatedHandle: string | null;
224
+ /** Whether a security key or passkey can prove it. */
225
+ webauthn: boolean;
226
+ /** Whether an authenticator app's code can prove it. */
227
+ totp: boolean;
228
+ /** The publicKey options for `navigator.credentials.get`, as JSON. */
229
+ webauthnOptionsJson: string | null;
230
+ }
231
+ /** A second factor being added, waiting for the browser or the authenticator app. */
232
+ export interface FactorEnrollment {
233
+ /** What {@link completeFactorEnrollment} takes. */
234
+ handle: string;
235
+ /** For a security key or passkey: the publicKey options for `navigator.credentials.create`, as JSON. */
236
+ webauthnOptionsJson: string | null;
237
+ /** For an authenticator app: the key to enter by hand. */
238
+ totpSecret: string | null;
239
+ /** For an authenticator app: a QR code of the key, as a data URI. */
240
+ totpQr: string | null;
241
+ }
242
+ /** An app the calling user has agreed may act for them. */
243
+ export interface AuthorizedApp {
244
+ /** The consent's id, which {@link revokeAuthorizedApp} takes. */
245
+ id: string;
246
+ clientId: string;
247
+ clientName: string;
248
+ /** What the app may carry for them, in the permission catalogue's names. */
249
+ grants: string[];
250
+ /** ISO-8601. */
251
+ grantedAt: string | null;
252
+ }
253
+ /**
254
+ * One organization the calling user may stand in, as `myOrganizations`
147
255
  * returns it.
148
256
  *
149
- * Identity, not configuration: the id to hand to {@link selectOrganization}, a
257
+ * Identity, not configuration: the id a request names to act there, a
150
258
  * name to render, the status, and where it sits. Only active organizations are
151
259
  * returned today; `status` is here so that a widening is visible to the caller
152
260
  * rather than silent.
@@ -157,7 +265,7 @@ export interface DeleteAccountResult {
157
265
  * this surface's to hand out.
158
266
  *
159
267
  * THE LIST IS A SUBTREE. A membership at an organization reaches everything
160
- * beneath it, so an operator who runs a group is offered the group and every
268
+ * beneath it, so someone who runs a group is offered the group and every
161
269
  * client under it. Draw it flat and a reseller's clients render as its
162
270
  * siblings, which is what the three position fields are for.
163
271
  */
@@ -168,7 +276,7 @@ export interface MyOrganization {
168
276
  /**
169
277
  * The immediate parent, or null for a root.
170
278
  *
171
- * A root OF THE PROJECT, not of the caller's view: an operator whose
279
+ * A root OF THE PROJECT, not of the caller's view: a member whose
172
280
  * membership sits three levels down sees their own organization with a parent
173
281
  * they cannot read. Null means there is no parent; it is never the empty
174
282
  * string, because that is a third value with no reading.
@@ -179,16 +287,16 @@ export interface MyOrganization {
179
287
  * project root.
180
288
  *
181
289
  * IDS, not names, and the whole path — including ancestors this caller cannot
182
- * read. An id is disclosed to everything below it; a name is row content an
183
- * operator further down may not be entitled to. A path trimmed to the
184
- * readable ancestors would have gaps or a false root, and two operators of
290
+ * read. An id is disclosed to everything below it; a name is row content a
291
+ * member further down may not be entitled to. A path trimmed to the
292
+ * readable ancestors would have gaps or a false root, and two members of
185
293
  * one organization would then see different paths to it.
186
294
  */
187
295
  ancestorIds: string[];
188
296
  /**
189
297
  * Levels above this organization in the PROJECT's tree: 0 is a project root.
190
298
  *
191
- * The project's depth rather than the caller's, so two operators looking at
299
+ * The project's depth rather than the caller's, so two members looking at
192
300
  * the same organization agree about where it is. Indent by the difference
193
301
  * from the shallowest entry in the list if you want the caller's own view.
194
302
  */
@@ -197,7 +305,7 @@ export interface MyOrganization {
197
305
  * The caller's own role in this organization, or null when their
198
306
  * membership carries none (or a disabled one). Never another member's role.
199
307
  *
200
- * ONE ROLE, NOT THE WHOLE AUTHORITY. The platform resolves the operator's
308
+ * ONE ROLE, NOT THE WHOLE AUTHORITY. The platform resolves the member's
201
309
  * authority per request as the union of the roles on every membership that
202
310
  * reaches this organization (one held in it and every one held above it),
203
311
  * together with their own roles in the project. This field is the role of
@@ -219,15 +327,3 @@ export interface MyOrganizationRole {
219
327
  */
220
328
  grants: string[];
221
329
  }
222
- /**
223
- * Where the caller now stands, as `selectMyOrganization` returns it.
224
- *
225
- * Two fields, because two are all there is to say. It is NOT a session context:
226
- * an operator is a customer, and the platform's admin session shape — user,
227
- * available tenants, effective permissions — describes a population this level
228
- * exists to keep them out of.
229
- */
230
- export interface SelectedOrganization {
231
- orgId: string;
232
- orgName: string;
233
- }
@@ -41,37 +41,55 @@ export declare const AUTH_OPS: {
41
41
  readonly authConfig: "authConfig";
42
42
  readonly authProviders: "authProviders";
43
43
  readonly defaultAuthProvider: "defaultAuthProvider";
44
- readonly customerSignupContext: "customerSignupContext";
44
+ readonly signupContext: "signupContext";
45
45
  readonly currentUser: "currentUser";
46
46
  readonly myProviderToken: "myProviderToken";
47
47
  readonly whoami: "whoami";
48
- readonly customerLogin: "customerLogin";
49
- readonly customerRegister: "customerRegister";
50
- readonly customerRequestOTP: "customerRequestOTP";
51
- readonly customerLoginOTP: "customerLoginOTP";
52
- readonly customerRefreshToken: "customerRefreshToken";
53
- readonly customerLogout: "customerLogout";
54
- readonly customerJoinWaitlist: "customerJoinWaitlist";
55
- readonly customerRequestPasswordReset: "customerRequestPasswordReset";
56
- readonly customerResetPassword: "customerResetPassword";
57
- readonly customerUpdatePassword: "customerUpdatePassword";
58
- readonly customerVerifyEmail: "customerVerifyEmail";
48
+ readonly login: "login";
49
+ readonly register: "register";
50
+ readonly requestOTP: "requestOTP";
51
+ readonly loginWithOTP: "loginWithOTP";
52
+ readonly refreshToken: "refreshToken";
53
+ readonly logout: "logout";
54
+ readonly joinWaitlist: "joinWaitlist";
55
+ readonly requestPasswordReset: "requestPasswordReset";
56
+ readonly resetPassword: "resetPassword";
57
+ readonly updatePassword: "updatePassword";
58
+ readonly verifyEmail: "verifyEmail";
59
59
  readonly deleteMyAccount: "deleteMyAccount";
60
+ readonly updateMyProfile: "updateMyProfile";
61
+ readonly myAuthorizedApps: "myAuthorizedApps";
62
+ readonly revokeAuthorizedApp: "revokeAuthorizedApp";
63
+ readonly mySessions: "mySessions";
64
+ readonly endMySession: "endMySession";
65
+ readonly signOutEverywhere: "signOutEverywhere";
66
+ readonly createPersonalAccessToken: "createPersonalAccessToken";
67
+ readonly mySignInMethods: "mySignInMethods";
68
+ readonly connectSignInMethod: "connectSignInMethod";
69
+ readonly disconnectSignInMethod: "disconnectSignInMethod";
70
+ readonly myFactors: "myFactors";
71
+ readonly beginStepUp: "beginStepUp";
72
+ readonly completeStepUp: "completeStepUp";
73
+ readonly beginFactorEnrollment: "beginFactorEnrollment";
74
+ readonly completeFactorEnrollment: "completeFactorEnrollment";
75
+ readonly removeFactor: "removeFactor";
76
+ readonly makeRecoveryCodes: "makeRecoveryCodes";
60
77
  readonly myOrganizations: "myOrganizations";
61
- readonly selectMyOrganization: "selectMyOrganization";
62
- readonly registerOperatorOrganization: "registerOperatorOrganization";
63
- readonly customerLoginWithProvider: "customerLoginWithProvider";
64
- readonly customerProviderCallback: "customerProviderCallback";
65
- readonly customerProviderVerifyOTP: "customerProviderVerifyOTP";
78
+ readonly registerOrganization: "registerOrganization";
79
+ readonly loginWithProvider: "loginWithProvider";
80
+ readonly providerCallback: "providerCallback";
81
+ readonly providerVerifyOTP: "providerVerifyOTP";
82
+ readonly confirmProviderLink: "confirmProviderLink";
83
+ readonly resendProviderLinkCode: "resendProviderLinkCode";
66
84
  };
67
85
  /** One of the auth namespace's root field names. */
68
86
  export type AuthOpName = (typeof AUTH_OPS)[keyof typeof AUTH_OPS];
69
87
  /** Per-call overrides for an auth op. */
70
88
  export interface AuthOpOptions {
71
89
  /**
72
- * Customer bearer token. api-public still needs the `x-api-key` to resolve
73
- * the project; the bearer adds the customer identity the post-credential ops
74
- * (`currentUser`, `customerUpdatePassword`, `deleteMyAccount`, …) are
90
+ * User bearer token. api-public still needs the `x-api-key` to resolve
91
+ * the project; the bearer adds the user identity the post-credential ops
92
+ * (`currentUser`, `updatePassword`, `deleteMyAccount`, …) are
75
93
  * authorised by. Ignored by the pre-credential ops, which mint it.
76
94
  */
77
95
  bearerToken?: string;
@@ -85,7 +103,7 @@ export interface AuthOpOptions {
85
103
  /**
86
104
  * The organization the call acts in, named by the address of the page it is
87
105
  * for, sent as `X-Org-Url`: same contract as `FoirClientConfig.orgUrl`. A
88
- * storefront on a path per organization signs its customers in on those
106
+ * storefront on a path per organization signs its users in on those
89
107
  * pages, and names the organization the way every other request from them
90
108
  * does.
91
109
  */
@@ -19,7 +19,7 @@
19
19
  * There is no refresh token in this flow. Re-exchanging the cookie IS the
20
20
  * refresh, which is why nothing here needs rotation or reuse-detection: the
21
21
  * durable credential is an opaque server-side session handle, revocable at any
22
- * time from the admin panel or `signOut()`.
22
+ * time from the console or `signOut()`.
23
23
  *
24
24
  * REQUIRES a verified custom login domain that shares a registrable domain with
25
25
  * your app (app.acme.com + login.acme.com). That is what makes the cookie
@@ -47,7 +47,7 @@ export interface FoirSessionConfig {
47
47
  }
48
48
  /** The identity behind the current session. */
49
49
  export interface FoirSessionUser {
50
- customerId: string;
50
+ userId: string;
51
51
  email: string;
52
52
  }
53
53
  export interface FoirSessionClient {
@@ -57,7 +57,7 @@ export interface FoirSessionClient {
57
57
  * exchange. Call this before each API request — do not cache the result.
58
58
  */
59
59
  getToken(): Promise<string | null>;
60
- /** The signed-in customer, or null. Exchanges if the session isn't loaded yet. */
60
+ /** The signed-in user, or null. Exchanges if the session isn't loaded yet. */
61
61
  getUser(): Promise<FoirSessionUser | null>;
62
62
  /** Revoke the session server-side and clear the cookie. Idempotent. */
63
63
  signOut(): Promise<void>;
@@ -64,14 +64,14 @@ function createFoirSessionClient(config) {
64
64
  } catch {
65
65
  return cached;
66
66
  }
67
- if (!json.access_token || !json.customer_id) return cached;
67
+ if (!json.access_token || !json.user_id) return cached;
68
68
  const expiresIn = typeof json.expires_in === "number" ? json.expires_in : 0;
69
69
  const next = {
70
70
  token: json.access_token,
71
71
  expiresAt: Date.now() + expiresIn * 1e3,
72
- user: { customerId: json.customer_id, email: json.email ?? "" }
72
+ user: { userId: json.user_id, email: json.email ?? "" }
73
73
  };
74
- const changed = cached?.user.customerId !== next.user.customerId;
74
+ const changed = cached?.user.userId !== next.user.userId;
75
75
  cached = next;
76
76
  scheduleRefresh(next.expiresAt);
77
77
  if (changed) emit(next.user);