cauthy-auth 0.30.0 → 0.32.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 (46) hide show
  1. package/README.md +50 -5
  2. package/dist/{cauthy-BXgsZ-Um.d.mts → cauthy-2jtP2LVQ.d.mts} +1 -1
  3. package/dist/{cauthy-CHENs452.d.ts → cauthy-CKfvvv_i.d.ts} +1 -1
  4. package/dist/cli.js +8 -5
  5. package/dist/client.d.mts +47 -6
  6. package/dist/client.d.ts +47 -6
  7. package/dist/client.js +16 -2
  8. package/dist/client.js.map +1 -1
  9. package/dist/client.mjs +16 -2
  10. package/dist/client.mjs.map +1 -1
  11. package/dist/express.d.mts +2 -2
  12. package/dist/express.d.ts +2 -2
  13. package/dist/fastify.d.mts +2 -2
  14. package/dist/fastify.d.ts +2 -2
  15. package/dist/hono.d.mts +2 -2
  16. package/dist/hono.d.ts +2 -2
  17. package/dist/index.d.mts +2 -2
  18. package/dist/index.d.ts +2 -2
  19. package/dist/index.js +64 -21
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +64 -21
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/next.d.mts +2 -2
  24. package/dist/next.d.ts +2 -2
  25. package/dist/react.d.mts +339 -31
  26. package/dist/react.d.ts +339 -31
  27. package/dist/react.js +616 -225
  28. package/dist/react.js.map +1 -1
  29. package/dist/react.mjs +610 -230
  30. package/dist/react.mjs.map +1 -1
  31. package/dist/styles.css +8 -0
  32. package/dist/svelte.d.mts +2 -2
  33. package/dist/svelte.d.ts +2 -2
  34. package/dist/svelte.js +16 -2
  35. package/dist/svelte.js.map +1 -1
  36. package/dist/svelte.mjs +16 -2
  37. package/dist/svelte.mjs.map +1 -1
  38. package/dist/{system-0mHrdAgO.d.mts → system-BrrJsrFW.d.mts} +14 -0
  39. package/dist/{system-BIYbS7h2.d.ts → system-BvvoNs2y.d.ts} +14 -0
  40. package/dist/vue.d.mts +2 -2
  41. package/dist/vue.d.ts +2 -2
  42. package/dist/vue.js +16 -2
  43. package/dist/vue.js.map +1 -1
  44. package/dist/vue.mjs +16 -2
  45. package/dist/vue.mjs.map +1 -1
  46. package/package.json +2 -1
package/README.md CHANGED
@@ -47,21 +47,38 @@ const { signIn } = useAuth()
47
47
  const r = await signIn.email({ email, password }) // r.ok, r.status, r.error.field
48
48
  ```
49
49
 
50
- What Cauthy mails opens your pages too: a new password, a confirmed address, a sign-in link.
50
+ What Cauthy mails opens your pages too: a new password, a confirmed address, a sign-in link, an invitation.
51
51
 
52
52
  ```ts
53
- export const auth = createCauthy({ pages: { signIn: '/sign-in', resetPassword: '/new-password', verifyEmail: '/confirm' } })
53
+ export const auth = createCauthy({ pages: { signIn: '/sign-in', resetPassword: '/new-password', verifyEmail: '/confirm', acceptInvite: '/accept-invite' } })
54
54
  ```
55
55
 
56
56
  ```tsx
57
- import { ResetPassword, VerifyEmail } from 'cauthy-auth/react'
57
+ import { AcceptInvite, ResetPassword, VerifyEmail } from 'cauthy-auth/react'
58
+ <AcceptInvite links={{ signIn: '/sign-in' }} returnTo="/" /> // "You've been invited to Acme", a password, signed in
59
+ <AcceptInvite onSaved={(e) => track(e.kind)} /> // 'invitation.accepted', with the address
60
+
61
+ const { invitation, acceptInvitation } = useAuth() // or with your own form
58
62
  ```
59
63
 
64
+ The forms follow what the workspace turned on in Cauthy's dashboard: each provider's button carries its logo (`classNames.providerIcon` styles it), and a workspace that turned off the password or passkeys does not see them offered. `methods()` says so: `passwordSignIn`, `passkey`, `providers[].iconUrl`.
65
+
60
66
  And the person's account, in your application: name, password, second step, sessions.
61
67
 
62
68
  ```tsx
63
- import { Account } from 'cauthy-auth/react'
69
+ import { Account, AccountPasskeys } from 'cauthy-auth/react'
64
70
  <Account /> // or: const { account } = useAuth()
71
+ <Account sections={['profile', 'password', 'sessions']} onSaved={(e) => toast(e.kind)} />
72
+ <AccountPasskeys /> // each part on its own card
73
+ ```
74
+
75
+ `sections` lists the parts shown, in that order: `profile`, `email`, `password`, `linked`, `secondStep`, `phone`, `passkeys`, `agents`, `sessions` (default: all). Each is also its own component: `AccountProfile`, `AccountEmail`, `AccountPassword`, `AccountLinked`, `AccountSecondStep`, `AccountPhone`, `AccountPasskeys`, `AccountAgents`, `AccountSessions`. `onSaved` is called after every change saved, with `{ kind, ... }`: `profile.saved`, `email.change_requested`, `password.changed`, `identity.linked`, `identity.unlinked`, `mfa.enabled`, `mfa.disabled`, `recovery_codes.regenerated`, `phone.added`, `phone.removed`, `passkey.added`, `passkey.removed`, `agent.disconnected`, `sessions.ended`.
76
+
77
+ The legal documents a signed-in person still owes (a new version of the terms), with the action that accepts them. It shows nothing when nothing is owed:
78
+
79
+ ```tsx
80
+ import { PendingTerms } from 'cauthy-auth/react'
81
+ <PendingTerms onSuccess={() => refresh()} /> // or: account.legal(), account.acceptLegal()
65
82
  ```
66
83
 
67
84
  And the person's organizations, run by their own members: the people of one, and the organization itself. Cauthy decides each change by the person's role in the system's catalog, with their own session:
@@ -69,6 +86,12 @@ And the person's organizations, run by their own members: the people of one, and
69
86
  ```tsx
70
87
  import { OrganizationMembers } from 'cauthy-auth/react'
71
88
  <OrganizationMembers organizationId={org.id} /> // shows only what the person's role allows
89
+ <OrganizationMembers
90
+ organizationId={org.id}
91
+ roles={(role) => role !== 'billing'} // the roles offered when adding or changing one
92
+ hide={['archive', 'delete']} // never offered: 'archive', 'delete', 'rename', 'leave'
93
+ onSaved={(e) => toast(e.kind)} // member.added, member.role_changed, member.removed, member.left,
94
+ /> // member.invited_again, organization.renamed, .archived, .deleted
72
95
 
73
96
  const { organizations } = useAuth()
74
97
  const [org] = await organizations.list() // org.can: { readMembers, manageMembers, removeMembers, update, archive, delete }
@@ -150,7 +173,27 @@ The ready-made forms wear the look set for your application in Cauthy's dashboar
150
173
  import 'cauthy-auth/styles.css'
151
174
  ```
152
175
 
153
- Or draw them with your own `components` and `classNames`, and pass `unstyled`. The dashboard can start the look from your stylesheet (shadcn/ui and Tailwind, Stackmyth, or variables of your own); `npx cauthy-auth theme --css src/app/globals.css` reads it the same way from a terminal.
176
+ Or draw them with your own `components` and `classNames`, and pass `unstyled`. Every part the forms draw can be yours; a part not given is drawn as before. With every part given and `unstyled`, the forms add only structural wrappers (`div`, `form`, `section`, lists):
177
+
178
+ ```tsx
179
+ <SignIn unstyled components={{ Button, Input, Checkbox, Select, Field, Text, Badge, Link, Divider, Alert, Confirm }} />
180
+ ```
181
+
182
+ | Part | Is given |
183
+ | --- | --- |
184
+ | `Button` | `type`, `disabled`, `className`, `onClick`, `children` |
185
+ | `Input` | `id`, `name`, `type`, `value`, `autoComplete`, `required`, `className`, `aria-invalid`, `aria-describedby`, `onChange(e)` |
186
+ | `Checkbox` | `id`, `name`, `checked`, `required`, `disabled`, `className`, `onChange(checked)`, `children` (its label) |
187
+ | `Select` | `id`, `name`, `value`, `options: { value, label }[]`, `disabled`, `className`, `aria-label`, `onChange(value)` |
188
+ | `Field` | `id`, `label`, `aside`, `help`, `error`, `required`, `className`, `children` (the control). Give the help the id `${id}-hint` and the error `${id}-error` |
189
+ | `Text` | `as` (`p`, `span`, `h2`), `tone` (`muted`, `danger`, `success`), `size` (`sm`, `md`, `lg`), `children` |
190
+ | `Badge` | `tone` (`neutral`, `success`, `warning`, `danger`), `children` |
191
+ | `Link` | `href`, `onClick`, `newTab`, `children` |
192
+ | `Divider` | `label` |
193
+ | `Alert` | `tone` (`danger`, `info`, `success`), `children`. Announce it: `role="alert"` or `role="status"` |
194
+ | `Confirm` | A function, `({ title, body, confirmLabel, cancelLabel, danger }) => Promise<boolean>`: your own dialog before removing a member, leaving, archiving or deleting. Without it, the question shows inline |
195
+
196
+ `texts` changes any sentence. Its keys are stable: `email`, `password`, `name`, `code`, `signIn`, `signUp`, `continueWith`, `orWithEmail`, `forgotPassword`, `noAccount`, `createAccount`, `company`, `iAccept`, `and`, `termsOfService`, `privacyPolicy`, `haveAccount`, `sendLink`, `linkSent`, `codeHelp`, `codeHelpPhone`, `codeHelpEmail`, `sendEmailAgain`, `sendCodeSms`, `sendCodeWhatsapp`, `codeSent`, `pushSend`, `pushPick`, `pushWaiting`, `phone`, `phoneHelp`, `phoneOn`, `phoneOff`, `addPhone`, `removePhone`, `bySms`, `byWhatsapp`, `channel`, `verify`, `checkEmail`, `backToSignIn`, `emailMeALink`, `usePasskey`, `codeFromMail`, `signInLinkSent`, `newPassword`, `savePassword`, `passwordChanged`, `confirming`, `emailConfirmed`, `invitedTo`, `invitedToOrganization`, `invitedAs`, `choosePassword`, `acceptInvite`, `openingInvitation`, `invitationInvalid`, `profile`, `save`, `saved`, `currentPassword`, `changePassword`, `passwordChangedHere`, `secondStep`, `secondStepOn`, `secondStepOff`, `turnOn`, `turnOff`, `addToApp`, `openInApp`, `recoveryCodes`, `newRecoveryCodes`, `keepCodes`, `passkeys`, `managePasskeys`, `passkeysHelp`, `noPasskeys`, `passkeyName`, `addPasskey` (unused), `addPasskeyDevice`, `addSecurityKey`, `passkeyKinds`, `removePasskey`, `passkeyAdded`, `passkeyUnnamed`, `sessions`, `signOutEverywhere`, `agents`, `agentsHelp`, `disconnect`, `anAgent`, `unknownDevice`, `emailAddress`, `newEmail`, `changeEmail`, `emailSent`, `linkedAccounts`, `noLinkedAccounts`, `linkWith`, `unlink`, `linked`, `ssoOnly`, `members`, `membersHidden`, `organizationMissing`, `memberYou`, `memberInvited`, `memberManager`, `memberRole`, `memberAdd`, `memberAdded`, `memberRemove`, `memberRemoveConfirm`, `memberLeave`, `memberLeaveConfirm`, `memberInviteAgain`, `memberInvitationSent`, `organization`, `organizationRename`, `organizationRenamed`, `organizationArchive`, `organizationArchiveConfirm`, `organizationArchived`, `organizationDelete`, `organizationDeleteConfirm`, `organizationDeleted`, `yes`, `cancel`, `termsChanged`, `termsChangedHelp`, `acceptTerms`, and `errors` by error code. Built in: English and Spanish (`locale`). The dashboard can start the look from your stylesheet (shadcn/ui and Tailwind, Stackmyth, or variables of your own); `npx cauthy-auth theme --css src/app/globals.css` reads it the same way from a terminal.
154
197
 
155
198
  Connect your application to Cauthy in one step, from Cauthy's dashboard ("Connect a System") or from a terminal. In the application's folder, `init` reads its framework (Next.js, TanStack Start, React Router or Remix, SvelteKit, Vite + React, Express, Hono, Fastify), makes the client, writes every variable to its env file, `CAUTHY_SECRET` included, and lays down the route and a sign-in page, never over a file that is there:
156
199
 
@@ -166,6 +209,8 @@ const org = await auth.system.organizations.create({ name: 'Acme' })
166
209
  await auth.system.members.add(org.id, { role: 'owner', email: 'ana@acme.com' })
167
210
  ```
168
211
 
212
+ Its invitations open your `pages.acceptInvite` when the application knows its public origin (`baseURL`, `CAUTHY_BASE_URL`); otherwise Cauthy's own page.
213
+
169
214
  A backend that is handed a Cauthy access token checks it with Cauthy's published keys: no secret, no call per request.
170
215
 
171
216
  ```ts
@@ -1,4 +1,4 @@
1
- import { J as JsonValue, S as Session, t as SessionStatus, s as SessionOrganization, f as CheckQuestion, k as OrganizationRef, g as CheckResult, d as CauthySystem, q as PublicSession, c as CauthyOptions } from './system-0mHrdAgO.mjs';
1
+ import { J as JsonValue, S as Session, t as SessionStatus, s as SessionOrganization, f as CheckQuestion, k as OrganizationRef, g as CheckResult, d as CauthySystem, q as PublicSession, c as CauthyOptions } from './system-BrrJsrFW.mjs';
2
2
  import { JWTVerifyGetKey } from 'jose';
3
3
 
4
4
  /** Something that happened in Cauthy, as a subscriber is told. Moments are UTC. */
@@ -1,4 +1,4 @@
1
- import { J as JsonValue, S as Session, t as SessionStatus, s as SessionOrganization, f as CheckQuestion, k as OrganizationRef, g as CheckResult, d as CauthySystem, q as PublicSession, c as CauthyOptions } from './system-BIYbS7h2.js';
1
+ import { J as JsonValue, S as Session, t as SessionStatus, s as SessionOrganization, f as CheckQuestion, k as OrganizationRef, g as CheckResult, d as CauthySystem, q as PublicSession, c as CauthyOptions } from './system-BvvoNs2y.js';
2
2
  import { JWTVerifyGetKey } from 'jose';
3
3
 
4
4
  /** Something that happened in Cauthy, as a subscriber is told. Moments are UTC. */
package/dist/cli.js CHANGED
@@ -989,6 +989,8 @@ function createSystem(given = {}) {
989
989
  const envKey = env("CAUTHY_SYSTEM_KEY");
990
990
  const key = given.key ?? (envKey ? { privateKey: envKey, keyId: env("CAUTHY_SYSTEM_KEY_ID") ?? "" } : void 0);
991
991
  const ownSystem = given.system ?? env("CAUTHY_SYSTEM") ?? "";
992
+ const acceptInviteUrl = given.acceptInviteUrl ?? env("CAUTHY_ACCEPT_INVITE_URL") ?? "";
993
+ const inviteHeaders = /^https?:\/\//.test(acceptInviteUrl) ? { "x-cauthy-client-id": clientId, "x-cauthy-link-to": acceptInviteUrl } : {};
992
994
  const doFetch = (...args) => (given.fetch ?? fetch)(...args);
993
995
  const tokenEndpoint = `${issuer}/v1/oauth/token`;
994
996
  function configured() {
@@ -1031,10 +1033,10 @@ function createSystem(given = {}) {
1031
1033
  asking = void 0;
1032
1034
  });
1033
1035
  }
1034
- async function call(method, path, body) {
1036
+ async function call(method, path, body, extra = {}) {
1035
1037
  const send = async () => doFetch(`${issuer}${path}`, {
1036
1038
  method,
1037
- headers: { authorization: `Bearer ${await token()}`, ...body === void 0 ? {} : { "content-type": "application/json" } },
1039
+ headers: { authorization: `Bearer ${await token()}`, ...extra, ...body === void 0 ? {} : { "content-type": "application/json" } },
1038
1040
  body: body === void 0 ? void 0 : JSON.stringify(body)
1039
1041
  });
1040
1042
  let res = await send();
@@ -1045,7 +1047,7 @@ function createSystem(given = {}) {
1045
1047
  if (!res.ok) await fail2(res, `${method} ${path}`);
1046
1048
  return res.status === 204 ? void 0 : res.json();
1047
1049
  }
1048
- const data = async (method, path, body) => (await call(method, path, body))?.data;
1050
+ const data = async (method, path, body, extra) => (await call(method, path, body, extra))?.data;
1049
1051
  const id = encodeURIComponent;
1050
1052
  return {
1051
1053
  token,
@@ -1082,7 +1084,8 @@ function createSystem(given = {}) {
1082
1084
  return toMember(await data(
1083
1085
  "POST",
1084
1086
  `/v1/organizations/${id(orgId)}/members`,
1085
- { role: m.role, user_id: m.userId, email: m.email, name: m.name, locale: m.locale, client_id: clientId }
1087
+ { role: m.role, user_id: m.userId, email: m.email, name: m.name, locale: m.locale, client_id: clientId },
1088
+ inviteHeaders
1086
1089
  ));
1087
1090
  },
1088
1091
  async setRole(orgId, userId, role) {
@@ -1093,7 +1096,7 @@ function createSystem(given = {}) {
1093
1096
  }
1094
1097
  },
1095
1098
  async invite(person) {
1096
- const u = await data("POST", "/v1/users", { ...person, client_id: clientId });
1099
+ const u = await data("POST", "/v1/users", { ...person, client_id: clientId }, inviteHeaders);
1097
1100
  return { id: u.id, email: u.email };
1098
1101
  },
1099
1102
  theme: {
package/dist/client.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CauthyTheme } from './theme.mjs';
2
- import { q as PublicSession, f as CheckQuestion, k as OrganizationRef, g as CheckResult } from './system-0mHrdAgO.mjs';
3
- export { h as CheckRule } from './system-0mHrdAgO.mjs';
2
+ import { q as PublicSession, f as CheckQuestion, k as OrganizationRef, g as CheckResult } from './system-BrrJsrFW.mjs';
3
+ export { h as CheckRule } from './system-BrrJsrFW.mjs';
4
4
  import { A as AuthField, b as PasswordPolicy } from './validate-sEXG82po.mjs';
5
5
  export { D as DEFAULT_PASSWORD_POLICY, F as FieldProblem, M as MIN_PASSWORD, P as PasswordClass, a as PasswordLocale, c as PasswordReason, d as checkCode, e as checkEmail, f as checkName, g as checkNewPassword, h as checkPassword, i as describePasswordPolicy, j as explainPasswordProblems, p as passwordPolicyOf, k as passwordProblems } from './validate-sEXG82po.mjs';
6
6
  import 'jose';
@@ -74,11 +74,25 @@ type AuthResult<S extends string, More = unknown> = ({
74
74
  };
75
75
  /** What the screen may offer. */
76
76
  interface AuthMethods {
77
- /** The providers the workspace signs people in with: `{ id: 'google', name: 'Google' }`. */
77
+ /**
78
+ * The providers the workspace signs people in with and has turned on:
79
+ * `{ id: 'google', name: 'Google', iconUrl: 'https://…/v1/social/icons/google.svg' }`.
80
+ * `iconUrl` is the provider's logo, served by Cauthy; absent from a Cauthy
81
+ * that does not serve logos.
82
+ */
78
83
  providers: {
79
84
  id: string;
80
85
  name: string;
86
+ iconUrl?: string;
81
87
  }[];
88
+ /**
89
+ * Whether the workspace signs people in with a password. False: the
90
+ * password field, "forgot your password" and a sign-up with a password are
91
+ * not offered, and Cauthy refuses them (`password_disabled`). True from a
92
+ * server that does not say. (`password` is something else: the policy a new
93
+ * password must meet.)
94
+ */
95
+ passwordSignIn: boolean;
82
96
  /** Whether people may create an account themselves. */
83
97
  signUp: boolean;
84
98
  /** Set when the application's system makes an organization per sign-up: the form asks the company's name. */
@@ -87,7 +101,7 @@ interface AuthMethods {
87
101
  required: boolean;
88
102
  };
89
103
  magicLink: boolean;
90
- /** Whether to offer a passkey. */
104
+ /** Whether to offer a passkey. False when the workspace turned passkeys off. */
91
105
  passkey: boolean;
92
106
  /**
93
107
  * Whether the passkey is used on this page itself. False: `signIn.passkey`
@@ -139,6 +153,15 @@ interface AuthMethods {
139
153
  */
140
154
  password?: PasswordPolicy;
141
155
  }
156
+ /** An invitation, as its page shows it before the person chooses a password. */
157
+ interface Invitation {
158
+ /** The address invited: the account the person signs in as. */
159
+ email: string;
160
+ /** The workspace's name. */
161
+ workspace: string;
162
+ /** The organization the person was invited to, when there is one. */
163
+ organization?: string;
164
+ }
142
165
  /** A legal document the person owes: not yet accepted in its current version. */
143
166
  interface PendingLegal {
144
167
  kind: string;
@@ -730,7 +753,25 @@ interface AuthClient {
730
753
  token: string;
731
754
  password: string;
732
755
  }): Promise<AuthResult<'changed'>>;
733
- /** Confirms the address, with the token the mailed link opened the page with (`token`). */
756
+ /**
757
+ * Who an invitation is for and to what, with the token the mailed link
758
+ * opened the page with (`token`). Reading it does not spend it.
759
+ * `invalid_token`: unknown, spent or expired.
760
+ */
761
+ invitation(token: string): Promise<AuthResult<'ok', {
762
+ invitation: Invitation;
763
+ }>>;
764
+ /**
765
+ * Accepts an invitation with the password the person chose (the workspace's
766
+ * policy, as for a sign-up) and signs them in. `mfa_required`: the account
767
+ * owes a second step; ask for the code and call `signIn.mfa`, as after
768
+ * `signIn.email`. A password refused leaves the invitation good.
769
+ */
770
+ acceptInvitation(token: string, password: string): Promise<AuthResult<'signed_in', {
771
+ session: PublicSession;
772
+ }> | AuthResult<'mfa_required', {
773
+ method?: 'email';
774
+ }>>;
734
775
  /** Confirms the address a mailed link is for. The person is signed in from the link when their account asks no second step. */
735
776
  verifyEmail(form: {
736
777
  token: string;
@@ -765,4 +806,4 @@ interface AuthClientOptions {
765
806
  }
766
807
  declare function createAuthClient(options?: AuthClientOptions): AuthClient;
767
808
 
768
- export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, CheckQuestion, CheckResult, type ConnectedAgent, type LinkedIdentity, type OrganizationPerson, OrganizationRef, type OrganizationRoleChoice, type OrganizationSeat, type OrganizationsClient, type Passkey, type PasskeyKind, PasswordPolicy, type PendingLegal, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
809
+ export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, CheckQuestion, CheckResult, type ConnectedAgent, type Invitation, type LinkedIdentity, type OrganizationPerson, OrganizationRef, type OrganizationRoleChoice, type OrganizationSeat, type OrganizationsClient, type Passkey, type PasskeyKind, PasswordPolicy, type PendingLegal, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
package/dist/client.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { CauthyTheme } from './theme.js';
2
- import { q as PublicSession, f as CheckQuestion, k as OrganizationRef, g as CheckResult } from './system-BIYbS7h2.js';
3
- export { h as CheckRule } from './system-BIYbS7h2.js';
2
+ import { q as PublicSession, f as CheckQuestion, k as OrganizationRef, g as CheckResult } from './system-BvvoNs2y.js';
3
+ export { h as CheckRule } from './system-BvvoNs2y.js';
4
4
  import { A as AuthField, b as PasswordPolicy } from './validate-sEXG82po.js';
5
5
  export { D as DEFAULT_PASSWORD_POLICY, F as FieldProblem, M as MIN_PASSWORD, P as PasswordClass, a as PasswordLocale, c as PasswordReason, d as checkCode, e as checkEmail, f as checkName, g as checkNewPassword, h as checkPassword, i as describePasswordPolicy, j as explainPasswordProblems, p as passwordPolicyOf, k as passwordProblems } from './validate-sEXG82po.js';
6
6
  import 'jose';
@@ -74,11 +74,25 @@ type AuthResult<S extends string, More = unknown> = ({
74
74
  };
75
75
  /** What the screen may offer. */
76
76
  interface AuthMethods {
77
- /** The providers the workspace signs people in with: `{ id: 'google', name: 'Google' }`. */
77
+ /**
78
+ * The providers the workspace signs people in with and has turned on:
79
+ * `{ id: 'google', name: 'Google', iconUrl: 'https://…/v1/social/icons/google.svg' }`.
80
+ * `iconUrl` is the provider's logo, served by Cauthy; absent from a Cauthy
81
+ * that does not serve logos.
82
+ */
78
83
  providers: {
79
84
  id: string;
80
85
  name: string;
86
+ iconUrl?: string;
81
87
  }[];
88
+ /**
89
+ * Whether the workspace signs people in with a password. False: the
90
+ * password field, "forgot your password" and a sign-up with a password are
91
+ * not offered, and Cauthy refuses them (`password_disabled`). True from a
92
+ * server that does not say. (`password` is something else: the policy a new
93
+ * password must meet.)
94
+ */
95
+ passwordSignIn: boolean;
82
96
  /** Whether people may create an account themselves. */
83
97
  signUp: boolean;
84
98
  /** Set when the application's system makes an organization per sign-up: the form asks the company's name. */
@@ -87,7 +101,7 @@ interface AuthMethods {
87
101
  required: boolean;
88
102
  };
89
103
  magicLink: boolean;
90
- /** Whether to offer a passkey. */
104
+ /** Whether to offer a passkey. False when the workspace turned passkeys off. */
91
105
  passkey: boolean;
92
106
  /**
93
107
  * Whether the passkey is used on this page itself. False: `signIn.passkey`
@@ -139,6 +153,15 @@ interface AuthMethods {
139
153
  */
140
154
  password?: PasswordPolicy;
141
155
  }
156
+ /** An invitation, as its page shows it before the person chooses a password. */
157
+ interface Invitation {
158
+ /** The address invited: the account the person signs in as. */
159
+ email: string;
160
+ /** The workspace's name. */
161
+ workspace: string;
162
+ /** The organization the person was invited to, when there is one. */
163
+ organization?: string;
164
+ }
142
165
  /** A legal document the person owes: not yet accepted in its current version. */
143
166
  interface PendingLegal {
144
167
  kind: string;
@@ -730,7 +753,25 @@ interface AuthClient {
730
753
  token: string;
731
754
  password: string;
732
755
  }): Promise<AuthResult<'changed'>>;
733
- /** Confirms the address, with the token the mailed link opened the page with (`token`). */
756
+ /**
757
+ * Who an invitation is for and to what, with the token the mailed link
758
+ * opened the page with (`token`). Reading it does not spend it.
759
+ * `invalid_token`: unknown, spent or expired.
760
+ */
761
+ invitation(token: string): Promise<AuthResult<'ok', {
762
+ invitation: Invitation;
763
+ }>>;
764
+ /**
765
+ * Accepts an invitation with the password the person chose (the workspace's
766
+ * policy, as for a sign-up) and signs them in. `mfa_required`: the account
767
+ * owes a second step; ask for the code and call `signIn.mfa`, as after
768
+ * `signIn.email`. A password refused leaves the invitation good.
769
+ */
770
+ acceptInvitation(token: string, password: string): Promise<AuthResult<'signed_in', {
771
+ session: PublicSession;
772
+ }> | AuthResult<'mfa_required', {
773
+ method?: 'email';
774
+ }>>;
734
775
  /** Confirms the address a mailed link is for. The person is signed in from the link when their account asks no second step. */
735
776
  verifyEmail(form: {
736
777
  token: string;
@@ -765,4 +806,4 @@ interface AuthClientOptions {
765
806
  }
766
807
  declare function createAuthClient(options?: AuthClientOptions): AuthClient;
767
808
 
768
- export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, CheckQuestion, CheckResult, type ConnectedAgent, type LinkedIdentity, type OrganizationPerson, OrganizationRef, type OrganizationRoleChoice, type OrganizationSeat, type OrganizationsClient, type Passkey, type PasskeyKind, PasswordPolicy, type PendingLegal, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
809
+ export { type Account, type AccountClient, type AccountSession, type AuthClient, type AuthClientOptions, type AuthError, AuthField, type AuthMethods, type AuthResult, CheckQuestion, CheckResult, type ConnectedAgent, type Invitation, type LinkedIdentity, type OrganizationPerson, OrganizationRef, type OrganizationRoleChoice, type OrganizationSeat, type OrganizationsClient, type Passkey, type PasskeyKind, PasswordPolicy, type PendingLegal, type SSOConnection, type SecondStep, type SessionState, type SessionStore, type SessionStoreOptions, canAutofillPasskeys, canUsePasskeys, createAuthClient, createSessionStore };
package/dist/client.js CHANGED
@@ -492,11 +492,11 @@ function createAuthClient(options = {}) {
492
492
  if (res.ok) {
493
493
  const m = await res.json();
494
494
  if (m.password) policy = passwordPolicyOf(m.password);
495
- return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
495
+ return { providers: [], signUp: true, magicLink: false, passkey: false, ...m, ...policy ? { password: policy } : {}, passwordSignIn: m.passwordSignIn !== false, passkeyHere: m.passkeyHere === true, passkeyOnCauthy: m.passkeyOnCauthy ?? m.passkey === true, sso: m.sso === true };
496
496
  }
497
497
  } catch {
498
498
  }
499
- return { providers: [], signUp: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
499
+ return { providers: [], signUp: true, passwordSignIn: true, magicLink: false, passkey: false, passkeyHere: false, passkeyOnCauthy: false, sso: false };
500
500
  }
501
501
  async function ceremony(begin, finish, form, run, more = {}) {
502
502
  const begun = await post(begin, form, null);
@@ -643,6 +643,20 @@ function createAuthClient(options = {}) {
643
643
  forgotPassword: (f) => post("/forgot-password", { email: f.email }, checkEmail(f.email), f.captchaToken),
644
644
  resetPassword: (f) => post("/reset-password", { token: f.token, password: f.password }, checkNewPassword(f.password, policy)),
645
645
  verifyEmail: (f) => post("/verify-email", { token: f.token }, null),
646
+ async invitation(token) {
647
+ const bad = { ok: false, error: { code: "invalid_token", message: "This invitation is not valid, or it has expired." } };
648
+ if (typeof token !== "string" || token.trim() === "") return bad;
649
+ try {
650
+ const res = await doFetch(`${base}/invitation?token=${encodeURIComponent(token.trim())}`, { credentials: "same-origin", headers: { accept: "application/json" } });
651
+ const body = await res.json().catch(() => null);
652
+ if (res.ok && body?.invitation) return { ok: true, status: "ok", invitation: body.invitation };
653
+ const e = body?.error;
654
+ return { ok: false, error: e && typeof e.code === "string" ? { code: e.code, message: String(e.message ?? "") } : UNAVAILABLE };
655
+ } catch {
656
+ return { ok: false, error: UNAVAILABLE };
657
+ }
658
+ },
659
+ acceptInvitation: (token, password) => post("/invitation/accept", { token, password }, checkNewPassword(password, policy)),
646
660
  signOut: () => post("/sign-out", {}, null),
647
661
  organizations: {
648
662
  async list(system) {