@adonis-agora/authkit-react 0.16.0 → 0.18.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 (51) hide show
  1. package/build/index.d.ts +92 -84
  2. package/build/index.js +48 -44
  3. package/build/src/authkit_provider.js +1 -1
  4. package/build/src/client/client.d.ts +1 -1
  5. package/build/src/client/client.js +4 -2
  6. package/build/src/client/context.d.ts +1 -1
  7. package/build/src/client/context.js +1 -1
  8. package/build/src/components/authenticated.js +1 -1
  9. package/build/src/components/can_permission.d.ts +1 -1
  10. package/build/src/components/can_permission.js +2 -2
  11. package/build/src/components/interaction_form.d.ts +5 -5
  12. package/build/src/components/interaction_form.js +19 -4
  13. package/build/src/components/key_rotation.js +1 -1
  14. package/build/src/components/magic_link_button.d.ts +5 -3
  15. package/build/src/components/magic_link_button.js +10 -8
  16. package/build/src/components/oauth_button.d.ts +2 -2
  17. package/build/src/components/oauth_button.js +5 -5
  18. package/build/src/components/organization_profile.js +3 -3
  19. package/build/src/components/passkey_button.d.ts +2 -2
  20. package/build/src/components/passkey_button.js +9 -9
  21. package/build/src/components/password_strength_meter.js +1 -4
  22. package/build/src/components/user_button.js +1 -1
  23. package/build/src/components/user_profile.js +1 -1
  24. package/build/src/config.d.ts +1 -1
  25. package/build/src/config.js +16 -19
  26. package/build/src/hooks/use_can.js +8 -8
  27. package/build/src/hooks/use_organization.js +3 -1
  28. package/build/src/hooks/use_passkey_assertion.d.ts +12 -0
  29. package/build/src/hooks/use_passkey_assertion.js +19 -0
  30. package/build/src/hooks/use_passkey_autofill.js +10 -11
  31. package/build/src/hooks/use_passkey_login.js +2 -2
  32. package/build/src/hooks/use_passkey_registration.d.ts +12 -0
  33. package/build/src/hooks/use_passkey_registration.js +19 -0
  34. package/build/src/hooks/use_profile.d.ts +1 -1
  35. package/build/src/hooks/use_profile.js +5 -1
  36. package/build/src/hooks/use_resource.js +1 -1
  37. package/build/src/hooks/use_sign_in.js +1 -1
  38. package/build/src/hooks/use_sign_out.js +1 -1
  39. package/build/src/interaction/urls.d.ts +3 -1
  40. package/build/src/interaction/urls.js +4 -2
  41. package/build/src/passkey/authenticate.d.ts +20 -1
  42. package/build/src/passkey/authenticate.js +51 -31
  43. package/build/src/passkey/classic_form.d.ts +9 -0
  44. package/build/src/passkey/classic_form.js +18 -0
  45. package/build/src/passkey/sudo.d.ts +12 -0
  46. package/build/src/passkey/sudo.js +20 -0
  47. package/build/src/queries/account/index.d.ts +1 -1
  48. package/build/src/queries/admin/index.d.ts +1 -1
  49. package/build/src/use_auth.js +1 -1
  50. package/build/src/utils.js +6 -6
  51. package/package.json +7 -1
@@ -12,10 +12,7 @@ export function PasswordStrengthMeter({ password, scorer, showFeedback = true, l
12
12
  const cls = ['authkit-strength', className].filter(Boolean).join(' ');
13
13
  const segments = [0, 1, 2, 3].map((i) => createElement('span', {
14
14
  key: i,
15
- className: [
16
- 'authkit-strength__segment',
17
- i < score ? 'authkit-strength__segment--filled' : '',
18
- ]
15
+ className: ['authkit-strength__segment', i < score ? 'authkit-strength__segment--filled' : '']
19
16
  .filter(Boolean)
20
17
  .join(' '),
21
18
  }));
@@ -1,7 +1,7 @@
1
1
  import { createElement, useState } from 'react';
2
- import { useAuth } from '../use_auth.js';
3
2
  import { useAuthkitConfig } from '../config.js';
4
3
  import { useSignOut } from '../hooks/use_sign_out.js';
4
+ import { useAuth } from '../use_auth.js';
5
5
  import { Avatar } from './avatar.js';
6
6
  export function UserButton({ profileLabel = 'Perfil', signOutLabel = 'Sair', className, }) {
7
7
  const { user, isAuthenticated } = useAuth();
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createElement, useState } from 'react';
3
3
  import { useAuthkitConfig } from '../config.js';
4
- import { useAuth } from '../use_auth.js';
5
4
  import { useProfile } from '../hooks/use_profile.js';
5
+ import { useAuth } from '../use_auth.js';
6
6
  import { Avatar } from './avatar.js';
7
7
  function UserProfileInner({ className }) {
8
8
  const { user, isAuthenticated } = useAuth();
@@ -7,7 +7,7 @@ export interface AuthkitEndpoints {
7
7
  orgInvitations: string;
8
8
  can: string;
9
9
  }
10
- export type AuthkitIdpMode = "authkit" | "external";
10
+ export type AuthkitIdpMode = 'authkit' | 'external';
11
11
  export interface AuthkitConfig {
12
12
  loginUrl?: string;
13
13
  logoutUrl?: string;
@@ -1,17 +1,17 @@
1
- import { createContext, useContext } from "react";
1
+ import { createContext, useContext } from 'react';
2
2
  export const DEFAULT_CONFIG = {
3
- idp: "authkit",
4
- loginUrl: "/auth/login",
5
- logoutUrl: "/account/logout",
6
- profileUrl: "/account/security",
3
+ idp: 'authkit',
4
+ loginUrl: '/auth/login',
5
+ logoutUrl: '/account/logout',
6
+ profileUrl: '/account/security',
7
7
  endpoints: {
8
- profile: "/account/security/profile",
9
- sessions: "/account/security",
10
- apps: "/account/apps",
11
- passkeys: "/account/mfa/passkeys",
12
- orgs: "/account/orgs/json",
13
- orgInvitations: "/account/orgs/invitations/json",
14
- can: "/authz/can",
8
+ profile: '/account/security/profile',
9
+ sessions: '/account/security',
10
+ apps: '/account/apps',
11
+ passkeys: '/account/mfa/passkeys',
12
+ orgs: '/account/orgs/json',
13
+ orgInvitations: '/account/orgs/invitations/json',
14
+ can: '/authz/can',
15
15
  },
16
16
  };
17
17
  export function resolveConfig(config) {
@@ -25,20 +25,17 @@ export function resolveConfig(config) {
25
25
  apps: config?.endpoints?.apps ?? DEFAULT_CONFIG.endpoints.apps,
26
26
  passkeys: config?.endpoints?.passkeys ?? DEFAULT_CONFIG.endpoints.passkeys,
27
27
  orgs: config?.endpoints?.orgs ?? DEFAULT_CONFIG.endpoints.orgs,
28
- orgInvitations: config?.endpoints?.orgInvitations ??
29
- DEFAULT_CONFIG.endpoints.orgInvitations,
30
- can: config?.endpoints?.can ??
31
- config?.canPath ??
32
- DEFAULT_CONFIG.endpoints.can,
28
+ orgInvitations: config?.endpoints?.orgInvitations ?? DEFAULT_CONFIG.endpoints.orgInvitations,
29
+ can: config?.endpoints?.can ?? config?.canPath ?? DEFAULT_CONFIG.endpoints.can,
33
30
  },
34
31
  csrfToken: config?.csrfToken,
35
- idp: config?.idp ?? "authkit",
32
+ idp: config?.idp ?? 'authkit',
36
33
  };
37
34
  }
38
35
  export function buildAuthUrl(base, returnTo) {
39
36
  if (!returnTo)
40
37
  return base;
41
- const sep = base.includes("?") ? "&" : "?";
38
+ const sep = base.includes('?') ? '&' : '?';
42
39
  return `${base}${sep}returnTo=${encodeURIComponent(returnTo)}`;
43
40
  }
44
41
  export const AuthkitConfigContext = createContext(DEFAULT_CONFIG);
@@ -1,9 +1,9 @@
1
- import { useContext, useEffect, useState } from "react";
2
- import { usePage } from "@inertiajs/react";
3
- import { useAuthkitConfig } from "../config.js";
4
- import { AuthContext } from "../provider.js";
5
- import { jsonRequest } from "./use_resource.js";
6
- const ANON_PRINCIPAL = "anon";
1
+ import { usePage } from '@inertiajs/react';
2
+ import { useContext, useEffect, useState } from 'react';
3
+ import { useAuthkitConfig } from '../config.js';
4
+ import { AuthContext } from '../provider.js';
5
+ import { jsonRequest } from './use_resource.js';
6
+ const ANON_PRINCIPAL = 'anon';
7
7
  function usePrincipalId() {
8
8
  const fromContext = useContext(AuthContext);
9
9
  let fromPage;
@@ -16,7 +16,7 @@ function usePrincipalId() {
16
16
  return (fromContext ?? fromPage)?.user?.id ?? ANON_PRINCIPAL;
17
17
  }
18
18
  function cacheKey(path, principal, permission, resource) {
19
- return [principal, path, permission, resource ?? ""].join("|");
19
+ return [principal, path, permission, resource ?? ''].join('|');
20
20
  }
21
21
  export const canCache = {
22
22
  resolved: new Map(),
@@ -38,7 +38,7 @@ export async function checkCan(path, permission, resource, csrfToken, principal
38
38
  if (pending)
39
39
  return pending;
40
40
  const promise = jsonRequest(path, {
41
- method: "POST",
41
+ method: 'POST',
42
42
  csrfToken,
43
43
  body: JSON.stringify({ permission, ...(resource ? { resource } : {}) }),
44
44
  })
@@ -2,7 +2,9 @@ import { useAuthkitConfig } from '../config.js';
2
2
  import { useResource } from './use_resource.js';
3
3
  export function useOrganization(orgId) {
4
4
  const config = useAuthkitConfig();
5
- const url = orgId ? `${config.endpoints.orgs.replace('/json', '')}/${encodeURIComponent(orgId)}/json` : '';
5
+ const url = orgId
6
+ ? `${config.endpoints.orgs.replace('/json', '')}/${encodeURIComponent(orgId)}/json`
7
+ : '';
6
8
  const { data, loading, error, refetch } = useResource(url, config.csrfToken);
7
9
  return { data, loading: url ? loading : false, error, actions: { refetch } };
8
10
  }
@@ -0,0 +1,12 @@
1
+ export interface UsePasskeyAssertionOptions {
2
+ optionsUrl: string;
3
+ actionUrl: string;
4
+ csrfToken?: string;
5
+ returnTo?: string | null;
6
+ }
7
+ export interface UsePasskeyAssertionResult {
8
+ run: () => Promise<void>;
9
+ running: boolean;
10
+ error: Error | null;
11
+ }
12
+ export declare function usePasskeyAssertion(options: UsePasskeyAssertionOptions): UsePasskeyAssertionResult;
@@ -0,0 +1,19 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { runPasskeyAssertion } from '../passkey/sudo.js';
3
+ export function usePasskeyAssertion(options) {
4
+ const { optionsUrl, actionUrl, csrfToken, returnTo } = options;
5
+ const [running, setRunning] = useState(false);
6
+ const [error, setError] = useState(null);
7
+ const run = useCallback(async () => {
8
+ setError(null);
9
+ setRunning(true);
10
+ try {
11
+ await runPasskeyAssertion({ optionsUrl, actionUrl, csrfToken, returnTo });
12
+ }
13
+ catch (err) {
14
+ setError(err instanceof Error ? err : new Error(String(err)));
15
+ setRunning(false);
16
+ }
17
+ }, [optionsUrl, actionUrl, csrfToken, returnTo]);
18
+ return { run, running, error };
19
+ }
@@ -1,12 +1,12 @@
1
- import { useEffect, useRef } from "react";
2
- import { loadStartAuthentication, } from "../passkey/authenticate.js";
1
+ import { useEffect, useRef } from 'react';
2
+ import { loadStartAuthentication } from '../passkey/authenticate.js';
3
3
  export function usePasskeyAutofill(options) {
4
- const { optionsUrl, verifyUrl, onSuccess, csrfToken, enabled = true, } = options;
4
+ const { optionsUrl, verifyUrl, onSuccess, csrfToken, enabled = true } = options;
5
5
  const abortRef = useRef(null);
6
6
  useEffect(() => {
7
7
  if (!enabled)
8
8
  return;
9
- if (typeof window === "undefined" || typeof navigator === "undefined")
9
+ if (typeof window === 'undefined' || typeof navigator === 'undefined')
10
10
  return;
11
11
  if (!window.PublicKeyCredential)
12
12
  return;
@@ -15,8 +15,7 @@ export function usePasskeyAutofill(options) {
15
15
  abortRef.current = ac;
16
16
  const run = async () => {
17
17
  try {
18
- const supported = typeof PublicKeyCredential
19
- .isConditionalMediationAvailable === "function"
18
+ const supported = typeof PublicKeyCredential.isConditionalMediationAvailable === 'function'
20
19
  ? await PublicKeyCredential.isConditionalMediationAvailable()
21
20
  : false;
22
21
  if (!supported || cancelled)
@@ -31,12 +30,12 @@ export function usePasskeyAutofill(options) {
31
30
  if (cancelled)
32
31
  return;
33
32
  const headers = {
34
- "content-type": "application/json",
33
+ 'content-type': 'application/json',
35
34
  };
36
35
  if (csrfToken)
37
- headers["x-csrf-token"] = csrfToken;
36
+ headers['x-csrf-token'] = csrfToken;
38
37
  const optRes = await fetch(optionsUrl, {
39
- method: "POST",
38
+ method: 'POST',
40
39
  headers,
41
40
  body: JSON.stringify({}),
42
41
  signal: ac.signal,
@@ -44,7 +43,7 @@ export function usePasskeyAutofill(options) {
44
43
  if (!optRes.ok || cancelled)
45
44
  return;
46
45
  const optionsJSON = await optRes.json();
47
- delete optionsJSON._discoverable;
46
+ optionsJSON._discoverable = undefined;
48
47
  if (cancelled)
49
48
  return;
50
49
  const assertion = await startAuthentication({
@@ -65,5 +64,5 @@ export function usePasskeyAutofill(options) {
65
64
  ac.abort();
66
65
  abortRef.current = null;
67
66
  };
68
- }, [enabled, optionsUrl, verifyUrl, csrfToken]);
67
+ }, [enabled, optionsUrl, verifyUrl, onSuccess, csrfToken]);
69
68
  }
@@ -1,5 +1,5 @@
1
- import { useCallback, useState } from "react";
2
- import { authenticatePasskey, submitPasskeyVerification, } from "../passkey/authenticate.js";
1
+ import { useCallback, useState } from 'react';
2
+ import { authenticatePasskey, submitPasskeyVerification } from '../passkey/authenticate.js';
3
3
  export function usePasskeyLogin(options) {
4
4
  const { optionsUrl, verifyUrl, csrfToken, onSuccess } = options;
5
5
  const [busy, setBusy] = useState(false);
@@ -0,0 +1,12 @@
1
+ export interface UsePasskeyRegistrationOptions {
2
+ optionsUrl: string;
3
+ actionUrl: string;
4
+ csrfToken?: string;
5
+ returnTo?: string | null;
6
+ }
7
+ export interface UsePasskeyRegistrationResult {
8
+ run: () => Promise<void>;
9
+ running: boolean;
10
+ error: Error | null;
11
+ }
12
+ export declare function usePasskeyRegistration(options: UsePasskeyRegistrationOptions): UsePasskeyRegistrationResult;
@@ -0,0 +1,19 @@
1
+ import { useCallback, useState } from 'react';
2
+ import { runPasskeyRegistration } from '../passkey/sudo.js';
3
+ export function usePasskeyRegistration(options) {
4
+ const { optionsUrl, actionUrl, csrfToken, returnTo } = options;
5
+ const [running, setRunning] = useState(false);
6
+ const [error, setError] = useState(null);
7
+ const run = useCallback(async () => {
8
+ setError(null);
9
+ setRunning(true);
10
+ try {
11
+ await runPasskeyRegistration({ optionsUrl, actionUrl, csrfToken, returnTo });
12
+ }
13
+ catch (err) {
14
+ setError(err instanceof Error ? err : new Error(String(err)));
15
+ setRunning(false);
16
+ }
17
+ }, [optionsUrl, actionUrl, csrfToken, returnTo]);
18
+ return { run, running, error };
19
+ }
@@ -1,5 +1,5 @@
1
- import { type ResourceState } from './use_resource.js';
2
1
  import type { AuthUser } from '../types.js';
2
+ import { type ResourceState } from './use_resource.js';
3
3
  export interface ProfileUpdate {
4
4
  name?: string;
5
5
  avatarUrl?: string;
@@ -18,7 +18,11 @@ export function useProfile() {
18
18
  body: JSON.stringify(data),
19
19
  csrfToken: config.csrfToken,
20
20
  });
21
- setState({ data: updated ?? { ...user, ...data }, loading: false, error: null });
21
+ setState({
22
+ data: updated ?? { ...user, ...data },
23
+ loading: false,
24
+ error: null,
25
+ });
22
26
  }
23
27
  catch (err) {
24
28
  setState((s) => ({ ...s, loading: false, error: err }));
@@ -4,7 +4,7 @@ export async function jsonRequest(url, init = {}) {
4
4
  const res = await fetch(url, {
5
5
  credentials: 'same-origin',
6
6
  headers: {
7
- 'Accept': 'application/json',
7
+ Accept: 'application/json',
8
8
  ...(rest.body ? { 'Content-Type': 'application/json' } : {}),
9
9
  ...(csrfToken ? { 'X-CSRF-TOKEN': csrfToken } : {}),
10
10
  ...headers,
@@ -1,5 +1,5 @@
1
1
  import { useCallback } from 'react';
2
- import { useAuthkitConfig, buildAuthUrl } from '../config.js';
2
+ import { buildAuthUrl, useAuthkitConfig } from '../config.js';
3
3
  import { currentUrl } from '../utils.js';
4
4
  export function useSignIn() {
5
5
  const config = useAuthkitConfig();
@@ -1,5 +1,5 @@
1
1
  import { useCallback } from 'react';
2
- import { useAuthkitConfig, buildAuthUrl } from '../config.js';
2
+ import { buildAuthUrl, useAuthkitConfig } from '../config.js';
3
3
  export function useSignOut() {
4
4
  const config = useAuthkitConfig();
5
5
  const signOut = useCallback((opts) => {
@@ -6,7 +6,9 @@ export interface InteractionUrls {
6
6
  switch: string;
7
7
  passkeyOptions: string;
8
8
  passkeyVerify: string;
9
+ otpVerify: string;
9
10
  }
10
11
  export declare function interactionUrls(uid: string, basePath?: string): InteractionUrls;
11
- export type InteractionPostStep = "identifier" | "login" | "magic";
12
+ export type InteractionPostStep = 'identifier' | 'login' | 'magic' | 'otpVerify';
13
+ export declare const OTP_CODE_FIELD = "code";
12
14
  export declare function oauthRedirectUrl(provider: string, uid: string, basePath?: string): string;
@@ -1,4 +1,4 @@
1
- export function interactionUrls(uid, basePath = "/auth/interaction") {
1
+ export function interactionUrls(uid, basePath = '/auth/interaction') {
2
2
  const base = `${basePath}/${uid}`;
3
3
  return {
4
4
  identifier: `${base}/identifier`,
@@ -8,8 +8,10 @@ export function interactionUrls(uid, basePath = "/auth/interaction") {
8
8
  switch: `${base}/switch`,
9
9
  passkeyOptions: `${base}/passkey/options`,
10
10
  passkeyVerify: `${base}/passkey/verify`,
11
+ otpVerify: `${base}/otp-verify`,
11
12
  };
12
13
  }
13
- export function oauthRedirectUrl(provider, uid, basePath = "/auth") {
14
+ export const OTP_CODE_FIELD = 'code';
15
+ export function oauthRedirectUrl(provider, uid, basePath = '/auth') {
14
16
  return `${basePath}/${provider}/redirect/${uid}`;
15
17
  }
@@ -3,7 +3,15 @@ export type StartAuthenticationFn = (opts: {
3
3
  useBrowserAutofill?: boolean;
4
4
  verifyBrowserAutofillInput?: boolean;
5
5
  }, signal?: AbortSignal) => Promise<unknown>;
6
- export declare function loadStartAuthentication(): Promise<StartAuthenticationFn>;
6
+ export type StartRegistrationFn = (opts: {
7
+ optionsJSON: unknown;
8
+ }) => Promise<unknown>;
9
+ declare function importWebAuthnBrowser(): Promise<{
10
+ startAuthentication: StartAuthenticationFn;
11
+ startRegistration: StartRegistrationFn;
12
+ }>;
13
+ export declare function loadStartAuthentication(importModule?: typeof importWebAuthnBrowser): Promise<StartAuthenticationFn>;
14
+ export declare function loadStartRegistration(importModule?: typeof importWebAuthnBrowser): Promise<StartRegistrationFn>;
7
15
  export interface AuthenticatePasskeyOptions {
8
16
  optionsUrl: string;
9
17
  csrfToken?: string;
@@ -14,9 +22,20 @@ export interface PasskeyCeremonyDeps {
14
22
  loadStartAuthentication?: () => Promise<StartAuthenticationFn>;
15
23
  }
16
24
  export declare function authenticatePasskey(options: AuthenticatePasskeyOptions, deps?: PasskeyCeremonyDeps): Promise<string>;
25
+ export interface RegisterPasskeyOptions {
26
+ optionsUrl: string;
27
+ csrfToken?: string;
28
+ signal?: AbortSignal;
29
+ }
30
+ export interface PasskeyRegistrationDeps {
31
+ fetch?: typeof globalThis.fetch;
32
+ loadStartRegistration?: () => Promise<StartRegistrationFn>;
33
+ }
34
+ export declare function registerPasskey(options: RegisterPasskeyOptions, deps?: PasskeyRegistrationDeps): Promise<string>;
17
35
  export interface SubmitPasskeyVerificationOptions {
18
36
  verifyUrl: string;
19
37
  assertion: string;
20
38
  csrfToken?: string;
21
39
  }
22
40
  export declare function submitPasskeyVerification(options: SubmitPasskeyVerificationOptions): void;
41
+ export {};
@@ -6,28 +6,46 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
6
6
  }
7
7
  return path;
8
8
  };
9
- const CDN_URL = "https://cdn.jsdelivr.net/npm/@simplewebauthn/browser@13/dist/bundle/index.js";
10
- export async function loadStartAuthentication() {
9
+ import { submitClassicForm } from './classic_form.js';
10
+ async function importWebAuthnBrowser() {
11
+ return await import(__rewriteRelativeImportExtension('@simplewebauthn/browser'));
12
+ }
13
+ function missingPeerError(cause) {
14
+ return new Error('@adonis-agora/authkit-react: a passkey requer o pacote ' +
15
+ '`@simplewebauthn/browser`, que não foi encontrado. Instale-o no seu app ' +
16
+ '(`npm i @simplewebauthn/browser@^13`) — ele é uma peer dependency ' +
17
+ 'opcional, e não uma dependência direta, porque quem faz o bundle do ' +
18
+ 'frontend é o seu app: embutir uma segunda cópia da lib duplicaria o ' +
19
+ 'código e brigaria com a versão que você já usa. Este pacote também não ' +
20
+ 'cai num CDN público: isso colocaria um terceiro dentro do caminho de ' +
21
+ 'autenticação, em silêncio.', { cause });
22
+ }
23
+ export async function loadStartAuthentication(importModule = importWebAuthnBrowser) {
11
24
  try {
12
- const mod = await import(__rewriteRelativeImportExtension("@simplewebauthn/browser"));
25
+ const mod = await importModule();
13
26
  return mod.startAuthentication;
14
27
  }
15
- catch {
16
- const mod = await import(__rewriteRelativeImportExtension(CDN_URL));
17
- return mod.startAuthentication;
28
+ catch (cause) {
29
+ throw missingPeerError(cause);
18
30
  }
19
31
  }
20
- export async function authenticatePasskey(options, deps = {}) {
21
- const { optionsUrl, csrfToken, signal } = options;
22
- const doFetch = deps.fetch ?? globalThis.fetch;
23
- const loadFn = deps.loadStartAuthentication ?? loadStartAuthentication;
32
+ export async function loadStartRegistration(importModule = importWebAuthnBrowser) {
33
+ try {
34
+ const mod = await importModule();
35
+ return mod.startRegistration;
36
+ }
37
+ catch (cause) {
38
+ throw missingPeerError(cause);
39
+ }
40
+ }
41
+ async function fetchCeremonyOptions(optionsUrl, csrfToken, doFetch, signal) {
24
42
  const headers = {
25
- "content-type": "application/json",
43
+ 'content-type': 'application/json',
26
44
  };
27
45
  if (csrfToken)
28
- headers["x-csrf-token"] = csrfToken;
46
+ headers['x-csrf-token'] = csrfToken;
29
47
  const res = await doFetch(optionsUrl, {
30
- method: "POST",
48
+ method: 'POST',
31
49
  headers,
32
50
  body: JSON.stringify({}),
33
51
  signal,
@@ -35,29 +53,31 @@ export async function authenticatePasskey(options, deps = {}) {
35
53
  if (!res.ok) {
36
54
  throw new Error(`passkey options request failed: ${res.status}`);
37
55
  }
38
- const optionsJSON = await res.json();
56
+ return res.json();
57
+ }
58
+ export async function authenticatePasskey(options, deps = {}) {
59
+ const { optionsUrl, csrfToken, signal } = options;
60
+ const doFetch = deps.fetch ?? globalThis.fetch;
61
+ const loadFn = deps.loadStartAuthentication ?? loadStartAuthentication;
62
+ const optionsJSON = await fetchCeremonyOptions(optionsUrl, csrfToken, doFetch, signal);
39
63
  const startAuthentication = await loadFn();
40
64
  const assertion = await startAuthentication({ optionsJSON }, signal);
41
65
  return JSON.stringify(assertion);
42
66
  }
67
+ export async function registerPasskey(options, deps = {}) {
68
+ const { optionsUrl, csrfToken, signal } = options;
69
+ const doFetch = deps.fetch ?? globalThis.fetch;
70
+ const loadFn = deps.loadStartRegistration ?? loadStartRegistration;
71
+ const optionsJSON = await fetchCeremonyOptions(optionsUrl, csrfToken, doFetch, signal);
72
+ const startRegistration = await loadFn();
73
+ const attestation = await startRegistration({ optionsJSON });
74
+ return JSON.stringify(attestation);
75
+ }
43
76
  export function submitPasskeyVerification(options) {
44
77
  const { verifyUrl, assertion, csrfToken } = options;
45
- if (typeof document === "undefined")
46
- return;
47
- const form = document.createElement("form");
48
- form.method = "POST";
49
- form.action = verifyUrl;
50
- form.hidden = true;
78
+ const fields = {};
51
79
  if (csrfToken)
52
- form.appendChild(hiddenInput("_csrf", csrfToken));
53
- form.appendChild(hiddenInput("response", assertion));
54
- document.body.appendChild(form);
55
- form.submit();
56
- }
57
- function hiddenInput(name, value) {
58
- const input = document.createElement("input");
59
- input.type = "hidden";
60
- input.name = name;
61
- input.value = value;
62
- return input;
80
+ fields._csrf = csrfToken;
81
+ fields.response = assertion;
82
+ submitClassicForm({ action: verifyUrl, fields });
63
83
  }
@@ -0,0 +1,9 @@
1
+ export interface SubmitClassicFormOptions {
2
+ action: string;
3
+ fields: Record<string, string>;
4
+ method?: string;
5
+ }
6
+ export interface SubmitClassicFormDeps {
7
+ document?: Document;
8
+ }
9
+ export declare function submitClassicForm(options: SubmitClassicFormOptions, deps?: SubmitClassicFormDeps): void;
@@ -0,0 +1,18 @@
1
+ export function submitClassicForm(options, deps = {}) {
2
+ const doc = deps.document ?? (typeof document !== 'undefined' ? document : undefined);
3
+ if (!doc)
4
+ return;
5
+ const form = doc.createElement('form');
6
+ form.method = options.method ?? 'POST';
7
+ form.action = options.action;
8
+ form.hidden = true;
9
+ for (const [name, value] of Object.entries(options.fields)) {
10
+ const input = doc.createElement('input');
11
+ input.type = 'hidden';
12
+ input.name = name;
13
+ input.value = value;
14
+ form.appendChild(input);
15
+ }
16
+ doc.body.appendChild(form);
17
+ form.submit();
18
+ }
@@ -0,0 +1,12 @@
1
+ import { type PasskeyCeremonyDeps, type PasskeyRegistrationDeps } from './authenticate.js';
2
+ import { type SubmitClassicFormDeps } from './classic_form.js';
3
+ export interface RunPasskeyFlowOptions {
4
+ optionsUrl: string;
5
+ actionUrl: string;
6
+ csrfToken?: string;
7
+ returnTo?: string | null;
8
+ }
9
+ export type RunPasskeyAssertionDeps = PasskeyCeremonyDeps & SubmitClassicFormDeps;
10
+ export type RunPasskeyRegistrationDeps = PasskeyRegistrationDeps & SubmitClassicFormDeps;
11
+ export declare function runPasskeyAssertion(options: RunPasskeyFlowOptions, deps?: RunPasskeyAssertionDeps): Promise<void>;
12
+ export declare function runPasskeyRegistration(options: RunPasskeyFlowOptions, deps?: RunPasskeyRegistrationDeps): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import { authenticatePasskey, registerPasskey, } from './authenticate.js';
2
+ import { submitClassicForm } from './classic_form.js';
3
+ function flowFields(response, csrfToken, returnTo) {
4
+ const fields = { response };
5
+ if (csrfToken)
6
+ fields._csrf = csrfToken;
7
+ if (returnTo)
8
+ fields.return_to = returnTo;
9
+ return fields;
10
+ }
11
+ export async function runPasskeyAssertion(options, deps = {}) {
12
+ const { optionsUrl, actionUrl, csrfToken, returnTo } = options;
13
+ const assertion = await authenticatePasskey({ optionsUrl, csrfToken }, { fetch: deps.fetch, loadStartAuthentication: deps.loadStartAuthentication });
14
+ submitClassicForm({ action: actionUrl, fields: flowFields(assertion, csrfToken, returnTo) }, { document: deps.document });
15
+ }
16
+ export async function runPasskeyRegistration(options, deps = {}) {
17
+ const { optionsUrl, actionUrl, csrfToken, returnTo } = options;
18
+ const attestation = await registerPasskey({ optionsUrl, csrfToken }, { fetch: deps.fetch, loadStartRegistration: deps.loadStartRegistration });
19
+ submitClassicForm({ action: actionUrl, fields: flowFields(attestation, csrfToken, returnTo) }, { document: deps.document });
20
+ }
@@ -1,4 +1,4 @@
1
- import type { AccountMe, AccountSecurityOverview, UpdateProfileInput, UpdateProfileResult, ChangePasswordInput, RequestEmailChangeInput, OkResult, EmailChangeResult, AccountSessionsResult, RevokeSessionResult, RevokeOthersResult, RevokeAllResult, AccountAppsResult, RevokeAppResult, AccountMfaStatus, AccountPasskeysResult, RemovePasskeyResult, AccountTokensResult, CreatedPatResult, RevokeTokenResult, CreateTokenInput, AccountOrgsResult, AccountOrgDetail, AccountOrgInvitationsResult } from '../../client/types.js';
1
+ import type { AccountAppsResult, AccountMe, AccountMfaStatus, AccountOrgDetail, AccountOrgInvitationsResult, AccountOrgsResult, AccountPasskeysResult, AccountSecurityOverview, AccountSessionsResult, AccountTokensResult, ChangePasswordInput, CreateTokenInput, CreatedPatResult, EmailChangeResult, OkResult, RemovePasskeyResult, RequestEmailChangeInput, RevokeAllResult, RevokeAppResult, RevokeOthersResult, RevokeSessionResult, RevokeTokenResult, UpdateProfileInput, UpdateProfileResult } from '../../client/types.js';
2
2
  export declare function useMeQueryOptions(): {
3
3
  queryKey: readonly ["authkit", "account", "me"];
4
4
  queryFn: () => Promise<AccountMe>;
@@ -1,4 +1,4 @@
1
- import type { AdminOverview, AdminUser, AdminUserListResult, CreateUserInput, UpdateUserInput, UserSessionsResult, RevokeSessionsResult, AdminClientListResult, AdminClient, CreatedClientResult, RegenerateSecretResult, CreateClientInput, UpdateClientInput, RoleListResult, RoleCatalogEntry, CreateRoleInput, UpdateRoleInput, AdminOrgListResult, AdminOrgDetail, AdminOrgInvitation, AuditListResult, AuditListParams, SettingListResult, SettingEntry, ImpersonationPanel, AdminOrgEntry, CreateOrgInput, UpdateOrgInput, KeysStatus, KeysRotateInput, KeysRotateResult } from '../../client/types.js';
1
+ import type { AdminClient, AdminClientListResult, AdminOrgDetail, AdminOrgEntry, AdminOrgInvitation, AdminOrgListResult, AdminOverview, AdminUser, AdminUserListResult, AuditListParams, AuditListResult, CreateClientInput, CreateOrgInput, CreateRoleInput, CreateUserInput, CreatedClientResult, ImpersonationPanel, KeysRotateInput, KeysRotateResult, KeysStatus, RegenerateSecretResult, RevokeSessionsResult, RoleCatalogEntry, RoleListResult, SettingEntry, SettingListResult, UpdateClientInput, UpdateOrgInput, UpdateRoleInput, UpdateUserInput, UserSessionsResult } from '../../client/types.js';
2
2
  export declare function useOverviewQueryOptions(): {
3
3
  queryKey: readonly ["authkit", "admin", "overview"];
4
4
  queryFn: () => Promise<AdminOverview>;
@@ -1,5 +1,5 @@
1
- import { useContext, useMemo } from 'react';
2
1
  import { usePage } from '@inertiajs/react';
2
+ import { useContext, useMemo } from 'react';
3
3
  import { AuthContext } from './provider.js';
4
4
  import { hasAllGlobalRoles as hasAllGlobalRolesPure, hasAnyGlobalRole as hasAnyGlobalRolePure, hasGlobalRole as hasGlobalRolePure, } from './roles.js';
5
5
  const UNAUTHENTICATED = {
@@ -1,21 +1,21 @@
1
1
  export function deriveInitials(name, email) {
2
- const source = (name ?? "").trim();
2
+ const source = (name ?? '').trim();
3
3
  if (source) {
4
4
  const parts = source.split(/\s+/).filter(Boolean);
5
5
  if (parts.length === 1)
6
6
  return parts[0].slice(0, 2).toUpperCase();
7
7
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
8
8
  }
9
- const e = (email ?? "").trim();
9
+ const e = (email ?? '').trim();
10
10
  if (e)
11
11
  return e[0].toUpperCase();
12
- return "?";
12
+ return '?';
13
13
  }
14
14
  export function currentUrl() {
15
- if (typeof window === "undefined")
16
- return "";
15
+ if (typeof window === 'undefined')
16
+ return '';
17
17
  return window.location.pathname + window.location.search;
18
18
  }
19
19
  export function buttonClass(variant, extra) {
20
- return ["authkit-button", variant, extra].filter(Boolean).join(" ");
20
+ return ['authkit-button', variant, extra].filter(Boolean).join(' ');
21
21
  }