@passflow/react 0.2.10 → 0.3.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.
- package/dist/index.cjs.js +4 -4
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +217 -2
- package/dist/index.es.js.map +1 -1
- package/dist/src/components/flow/passflow/index.d.ts.map +1 -1
- package/dist/src/components/form/cli-browser-auth/index.d.ts +2 -0
- package/dist/src/components/form/cli-browser-auth/index.d.ts.map +1 -0
- package/dist/src/components/form/cli-qr-auth/index.d.ts +2 -0
- package/dist/src/components/form/cli-qr-auth/index.d.ts.map +1 -0
- package/dist/src/components/form/index.d.ts +2 -0
- package/dist/src/components/form/index.d.ts.map +1 -1
- package/dist/src/components/form/two-factor-challenge/index.d.ts.map +1 -1
- package/dist/src/components/form/two-factor-challenge/method-selector.d.ts.map +1 -1
- package/dist/src/context/auth-context.d.ts.map +1 -1
- package/dist/src/context/router-context.d.ts +6 -0
- package/dist/src/context/router-context.d.ts.map +1 -1
- package/dist/src/hooks/index.d.ts +2 -1
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/use-cli-auth.d.ts +9 -0
- package/dist/src/hooks/use-cli-auth.d.ts.map +1 -0
- package/dist/src/hooks/use-two-factor-challenge.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +3 -2
package/dist/index.es.js
CHANGED
|
@@ -20,7 +20,7 @@ import { phone as phone$1 } from 'phone';
|
|
|
20
20
|
import { useForm, Controller } from 'react-hook-form';
|
|
21
21
|
import 'react-dom';
|
|
22
22
|
|
|
23
|
-
const version = "0.
|
|
23
|
+
const version = "0.3.0";
|
|
24
24
|
|
|
25
25
|
window.passflowReactAppVersion = () => {
|
|
26
26
|
console.log(`App Version: ${version}`);
|
|
@@ -769,6 +769,12 @@ const routes = {
|
|
|
769
769
|
},
|
|
770
770
|
two_factor_setup_magic_link: {
|
|
771
771
|
path: "/two-factor-setup-magic-link/:token"
|
|
772
|
+
},
|
|
773
|
+
cli_browser: {
|
|
774
|
+
path: "/cli/browser/:sessionId"
|
|
775
|
+
},
|
|
776
|
+
cli_qr: {
|
|
777
|
+
path: "/cli/auth/:sessionId"
|
|
772
778
|
}
|
|
773
779
|
};
|
|
774
780
|
|
|
@@ -1980,6 +1986,109 @@ function useSessionExpired(options) {
|
|
|
1980
1986
|
};
|
|
1981
1987
|
}
|
|
1982
1988
|
|
|
1989
|
+
const useCLIAuth = (sessionId) => {
|
|
1990
|
+
const [state, setState] = useState("loading");
|
|
1991
|
+
const [error, setError] = useState(null);
|
|
1992
|
+
const [expiresAt, setExpiresAt] = useState(null);
|
|
1993
|
+
const [challenge, setChallenge] = useState(null);
|
|
1994
|
+
const serverUrl = window.location.origin;
|
|
1995
|
+
const fetchStatus = useCallback(async () => {
|
|
1996
|
+
try {
|
|
1997
|
+
const response = await fetch(`${serverUrl}/cli/auth/status/${sessionId}`);
|
|
1998
|
+
if (!response.ok) {
|
|
1999
|
+
throw new Error(`Failed to fetch CLI auth status: ${response.statusText}`);
|
|
2000
|
+
}
|
|
2001
|
+
const data = await response.json();
|
|
2002
|
+
setExpiresAt(data.expires_at || null);
|
|
2003
|
+
switch (data.status) {
|
|
2004
|
+
case "pending":
|
|
2005
|
+
setState("pending");
|
|
2006
|
+
setChallenge(data.challenge || null);
|
|
2007
|
+
break;
|
|
2008
|
+
case "completed":
|
|
2009
|
+
setState("completed");
|
|
2010
|
+
break;
|
|
2011
|
+
case "expired":
|
|
2012
|
+
setState("expired");
|
|
2013
|
+
setError("This authentication session has expired. Please start a new one from your terminal.");
|
|
2014
|
+
break;
|
|
2015
|
+
case "failed":
|
|
2016
|
+
setState("error");
|
|
2017
|
+
setError(data.error || "Authentication failed");
|
|
2018
|
+
break;
|
|
2019
|
+
}
|
|
2020
|
+
} catch (err) {
|
|
2021
|
+
setState("error");
|
|
2022
|
+
setError(err instanceof Error ? err.message : "Failed to load authentication status");
|
|
2023
|
+
}
|
|
2024
|
+
}, [sessionId, serverUrl]);
|
|
2025
|
+
const authenticate = useCallback(async () => {
|
|
2026
|
+
if (!challenge) {
|
|
2027
|
+
setError("No challenge available for authentication");
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
setState("authenticating");
|
|
2031
|
+
setError(null);
|
|
2032
|
+
try {
|
|
2033
|
+
const { startAuthentication } = await import('@simplewebauthn/browser');
|
|
2034
|
+
const optionsJSON = challenge.publicKey || challenge;
|
|
2035
|
+
const webauthnResponse = await startAuthentication({ optionsJSON });
|
|
2036
|
+
const completeResponse = await fetch(`${serverUrl}/auth/passkey/authenticate/complete`, {
|
|
2037
|
+
method: "POST",
|
|
2038
|
+
headers: {
|
|
2039
|
+
"Content-Type": "application/json"
|
|
2040
|
+
},
|
|
2041
|
+
body: JSON.stringify(webauthnResponse)
|
|
2042
|
+
});
|
|
2043
|
+
if (!completeResponse.ok) {
|
|
2044
|
+
throw new Error(`Passkey authentication failed: ${completeResponse.statusText}`);
|
|
2045
|
+
}
|
|
2046
|
+
const authData = await completeResponse.json();
|
|
2047
|
+
if (!authData.access_token || !authData.refresh_token) {
|
|
2048
|
+
throw new Error("Invalid authentication response: missing tokens");
|
|
2049
|
+
}
|
|
2050
|
+
const cliCompleteRequest = {
|
|
2051
|
+
session_id: sessionId,
|
|
2052
|
+
access_token: authData.access_token,
|
|
2053
|
+
refresh_token: authData.refresh_token,
|
|
2054
|
+
user_id: authData.user_id,
|
|
2055
|
+
expires_in: authData.expires_in
|
|
2056
|
+
};
|
|
2057
|
+
const cliCompleteResponse = await fetch(`${serverUrl}/cli/auth/complete`, {
|
|
2058
|
+
method: "POST",
|
|
2059
|
+
headers: {
|
|
2060
|
+
"Content-Type": "application/json"
|
|
2061
|
+
},
|
|
2062
|
+
body: JSON.stringify(cliCompleteRequest)
|
|
2063
|
+
});
|
|
2064
|
+
if (!cliCompleteResponse.ok) {
|
|
2065
|
+
throw new Error(`CLI authentication completion failed: ${cliCompleteResponse.statusText}`);
|
|
2066
|
+
}
|
|
2067
|
+
setState("completed");
|
|
2068
|
+
} catch (err) {
|
|
2069
|
+
setState("error");
|
|
2070
|
+
if (err instanceof Error) {
|
|
2071
|
+
if (err.name === "NotAllowedError") {
|
|
2072
|
+
setError("Authentication was cancelled or not allowed");
|
|
2073
|
+
} else {
|
|
2074
|
+
setError(err.message);
|
|
2075
|
+
}
|
|
2076
|
+
} else {
|
|
2077
|
+
setError("Authentication failed");
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
}, [challenge, sessionId, serverUrl]);
|
|
2081
|
+
useEffect(() => {
|
|
2082
|
+
void fetchStatus();
|
|
2083
|
+
}, [fetchStatus]);
|
|
2084
|
+
return {
|
|
2085
|
+
authenticate,
|
|
2086
|
+
state,
|
|
2087
|
+
error,
|
|
2088
|
+
expiresAt
|
|
2089
|
+
};
|
|
2090
|
+
};
|
|
2091
|
+
|
|
1983
2092
|
const FieldPhone = ({ id, onChange, isError = false, className = "" }) => {
|
|
1984
2093
|
const [show, setShow] = useState(false);
|
|
1985
2094
|
const [filterValue, setFilterValue] = useState("");
|
|
@@ -6465,6 +6574,110 @@ const index = /*#__PURE__*/Object.freeze(/*#__PURE__*/Object.defineProperty({
|
|
|
6465
6574
|
useRoutes
|
|
6466
6575
|
}, Symbol.toStringTag, { value: 'Module' }));
|
|
6467
6576
|
|
|
6577
|
+
const CLIBrowserAuthForm = () => {
|
|
6578
|
+
const { sessionId } = useParams();
|
|
6579
|
+
if (!sessionId) {
|
|
6580
|
+
throw new Error("Session ID is required");
|
|
6581
|
+
}
|
|
6582
|
+
const { authenticate, state, error } = useCLIAuth(sessionId);
|
|
6583
|
+
const handleAuthenticate = async () => {
|
|
6584
|
+
await authenticate();
|
|
6585
|
+
};
|
|
6586
|
+
return /* @__PURE__ */ jsx(Wrapper, { title: "CLI Authentication", subtitle: "Authenticate your CLI tool", className: "passflow-cli-auth-wrapper", children: /* @__PURE__ */ jsxs("div", { className: "passflow-form", children: [
|
|
6587
|
+
state === "loading" && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Loading authentication session..." }) }),
|
|
6588
|
+
state === "pending" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6589
|
+
/* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Click the button below to authenticate with your passkey." }) }),
|
|
6590
|
+
/* @__PURE__ */ jsxs(
|
|
6591
|
+
Button,
|
|
6592
|
+
{
|
|
6593
|
+
size: "big",
|
|
6594
|
+
variant: "dark",
|
|
6595
|
+
type: "button",
|
|
6596
|
+
className: "passflow-button-passkey",
|
|
6597
|
+
withIcon: true,
|
|
6598
|
+
onClick: handleAuthenticate,
|
|
6599
|
+
children: [
|
|
6600
|
+
/* @__PURE__ */ jsx(Icon, { id: "key", size: "small", type: "general", className: "icon-white passflow-button-passkey-icon" }),
|
|
6601
|
+
"Authenticate with Passkey"
|
|
6602
|
+
]
|
|
6603
|
+
}
|
|
6604
|
+
)
|
|
6605
|
+
] }),
|
|
6606
|
+
state === "authenticating" && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Authenticating..." }) }),
|
|
6607
|
+
state === "completed" && /* @__PURE__ */ jsxs("div", { className: "passflow-form-container", children: [
|
|
6608
|
+
/* @__PURE__ */ jsxs("div", { className: "passflow-form-success", children: [
|
|
6609
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "check", type: "general", className: "icon-success" }),
|
|
6610
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-success-text", children: "Authentication successful!" })
|
|
6611
|
+
] }),
|
|
6612
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "You can close this window and return to your terminal." })
|
|
6613
|
+
] }),
|
|
6614
|
+
state === "expired" && /* @__PURE__ */ jsxs("div", { className: "passflow-form-container", children: [
|
|
6615
|
+
/* @__PURE__ */ jsxs("div", { className: "passflow-form-error", children: [
|
|
6616
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "warning", type: "general", className: "icon-warning" }),
|
|
6617
|
+
/* @__PURE__ */ jsx("span", { className: "passflow-form-error-text", children: "Session Expired" })
|
|
6618
|
+
] }),
|
|
6619
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "This authentication session has expired. Please start a new one from your terminal." })
|
|
6620
|
+
] }),
|
|
6621
|
+
state === "error" && error && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsxs("div", { className: "passflow-form-error", children: [
|
|
6622
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "warning", type: "general", className: "icon-warning" }),
|
|
6623
|
+
/* @__PURE__ */ jsx("span", { className: "passflow-form-error-text", children: error })
|
|
6624
|
+
] }) })
|
|
6625
|
+
] }) });
|
|
6626
|
+
};
|
|
6627
|
+
const CLIBrowserAuth = withError(CLIBrowserAuthForm, ErrorComponent);
|
|
6628
|
+
|
|
6629
|
+
const CLIQRAuthForm = () => {
|
|
6630
|
+
const { sessionId } = useParams();
|
|
6631
|
+
if (!sessionId) {
|
|
6632
|
+
throw new Error("Session ID is required");
|
|
6633
|
+
}
|
|
6634
|
+
const { authenticate, state, error } = useCLIAuth(sessionId);
|
|
6635
|
+
const handleAuthenticate = async () => {
|
|
6636
|
+
await authenticate();
|
|
6637
|
+
};
|
|
6638
|
+
return /* @__PURE__ */ jsx(Wrapper, { title: "CLI Authentication", subtitle: "Authenticate for your CLI application", className: "passflow-cli-auth-wrapper", children: /* @__PURE__ */ jsxs("div", { className: "passflow-form", children: [
|
|
6639
|
+
state === "loading" && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Loading authentication session..." }) }),
|
|
6640
|
+
state === "pending" && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6641
|
+
/* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Tap the button below to authenticate with your passkey." }) }),
|
|
6642
|
+
/* @__PURE__ */ jsxs(
|
|
6643
|
+
Button,
|
|
6644
|
+
{
|
|
6645
|
+
size: "big",
|
|
6646
|
+
variant: "dark",
|
|
6647
|
+
type: "button",
|
|
6648
|
+
className: "passflow-button-passkey",
|
|
6649
|
+
withIcon: true,
|
|
6650
|
+
onClick: handleAuthenticate,
|
|
6651
|
+
children: [
|
|
6652
|
+
/* @__PURE__ */ jsx(Icon, { id: "key", size: "small", type: "general", className: "icon-white passflow-button-passkey-icon" }),
|
|
6653
|
+
"Authenticate with Passkey"
|
|
6654
|
+
]
|
|
6655
|
+
}
|
|
6656
|
+
)
|
|
6657
|
+
] }),
|
|
6658
|
+
state === "authenticating" && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "Authenticating..." }) }),
|
|
6659
|
+
state === "completed" && /* @__PURE__ */ jsxs("div", { className: "passflow-form-container", children: [
|
|
6660
|
+
/* @__PURE__ */ jsxs("div", { className: "passflow-form-success", children: [
|
|
6661
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "check", type: "general", className: "icon-success" }),
|
|
6662
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-success-text", children: "Authentication successful!" })
|
|
6663
|
+
] }),
|
|
6664
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "You can close this app and return to your terminal." })
|
|
6665
|
+
] }),
|
|
6666
|
+
state === "expired" && /* @__PURE__ */ jsxs("div", { className: "passflow-form-container", children: [
|
|
6667
|
+
/* @__PURE__ */ jsxs("div", { className: "passflow-form-error", children: [
|
|
6668
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "warning", type: "general", className: "icon-warning" }),
|
|
6669
|
+
/* @__PURE__ */ jsx("span", { className: "passflow-form-error-text", children: "Session Expired" })
|
|
6670
|
+
] }),
|
|
6671
|
+
/* @__PURE__ */ jsx("p", { className: "passflow-form-text", children: "This authentication session has expired. Please start a new one from your terminal." })
|
|
6672
|
+
] }),
|
|
6673
|
+
state === "error" && error && /* @__PURE__ */ jsx("div", { className: "passflow-form-container", children: /* @__PURE__ */ jsxs("div", { className: "passflow-form-error", children: [
|
|
6674
|
+
/* @__PURE__ */ jsx(Icon, { size: "small", id: "warning", type: "general", className: "icon-warning" }),
|
|
6675
|
+
/* @__PURE__ */ jsx("span", { className: "passflow-form-error-text", children: error })
|
|
6676
|
+
] }) })
|
|
6677
|
+
] }) });
|
|
6678
|
+
};
|
|
6679
|
+
const CLIQRAuth = withError(CLIQRAuthForm, ErrorComponent);
|
|
6680
|
+
|
|
6468
6681
|
const normalizePathPrefix = (path) => {
|
|
6469
6682
|
if (!path) return "";
|
|
6470
6683
|
const pathReplace = path.replace(/^\/+|\/+$/g, "");
|
|
@@ -6645,6 +6858,8 @@ const PassflowWrapper = ({
|
|
|
6645
6858
|
)
|
|
6646
6859
|
}
|
|
6647
6860
|
),
|
|
6861
|
+
/* @__PURE__ */ jsx(Route, { path: routes.cli_browser.path, element: /* @__PURE__ */ jsx(CLIBrowserAuth, {}) }),
|
|
6862
|
+
/* @__PURE__ */ jsx(Route, { path: routes.cli_qr.path, element: /* @__PURE__ */ jsx(CLIQRAuth, {}) }),
|
|
6648
6863
|
/* @__PURE__ */ jsx(
|
|
6649
6864
|
Route,
|
|
6650
6865
|
{
|
|
@@ -6842,5 +7057,5 @@ const PassflowProvider = ({
|
|
|
6842
7057
|
return /* @__PURE__ */ jsx(PassflowContext.Provider, { value: passflowValue, children: /* @__PURE__ */ jsx(NavigationContext$1.Provider, { value: navigationValue, children: /* @__PURE__ */ jsx(AuthProvider, { children }) }) });
|
|
6843
7058
|
};
|
|
6844
7059
|
|
|
6845
|
-
export { Button, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, FieldPassword, FieldPhone, FieldText, ForgotPassword, ForgotPasswordSuccess, Icon, InvitationJoin, Link, PassflowFlow, PassflowProvider, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProvidersBox, ResetPassword, SignIn, SignInForm, SignUp, SignUpForm, Switch, TwoFactorChallenge, TwoFactorRecoveryForm, TwoFactorSetupForm, TwoFactorSetupMagicLinkFlow, TwoFactorVerifyForm, VerifyChallengeMagicLink, VerifyChallengeOTP, Wrapper, useAppSettings, useAuth, useAuthCloudRedirect, useForgotPassword, useJoinInvite, useLogout, useNavigation, useOutsideClick, usePassflow, usePasswordlessComplete, useProvider, useResetPassword, useSessionExpired, useSignIn, useSignUp, useTwoFactorChallenge, useTwoFactorManage, useTwoFactorMethods, useTwoFactorSetup, useTwoFactorSetupMagicLink, useTwoFactorStatus, useTwoFactorVerify, useUserPasskeys };
|
|
7060
|
+
export { Button, CLIBrowserAuth, CLIQRAuth, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, FieldPassword, FieldPhone, FieldText, ForgotPassword, ForgotPasswordSuccess, Icon, InvitationJoin, Link, PassflowFlow, PassflowProvider, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, ProvidersBox, ResetPassword, SignIn, SignInForm, SignUp, SignUpForm, Switch, TwoFactorChallenge, TwoFactorRecoveryForm, TwoFactorSetupForm, TwoFactorSetupMagicLinkFlow, TwoFactorVerifyForm, VerifyChallengeMagicLink, VerifyChallengeOTP, Wrapper, useAppSettings, useAuth, useAuthCloudRedirect, useCLIAuth, useForgotPassword, useJoinInvite, useLogout, useNavigation, useOutsideClick, usePassflow, usePasswordlessComplete, useProvider, useResetPassword, useSessionExpired, useSignIn, useSignUp, useTwoFactorChallenge, useTwoFactorManage, useTwoFactorMethods, useTwoFactorSetup, useTwoFactorSetupMagicLink, useTwoFactorStatus, useTwoFactorVerify, useUserPasskeys };
|
|
6846
7061
|
//# sourceMappingURL=index.es.js.map
|