@zautha/react 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hasan Talha Yalmanbas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # @zautha/react
2
+
3
+ React bindings for [Zautha](https://zautha.com): `<ZauthaProvider>`, hooks (`useAuth`, `useUser`,
4
+ `useSession`, …), `<Show>`, and the prebuilt components from `@zautha/ui`.
5
+
6
+ ## Install
7
+
8
+ ```sh
9
+ npm i @zautha/react @zautha/ui
10
+ ```
11
+
12
+ ## Quickstart (React + Vite)
13
+
14
+ ```tsx
15
+ import { Show, SignIn, UserButton, ZauthaProvider } from "@zautha/react";
16
+ import { ui } from "@zautha/ui";
17
+ import "@zautha/ui/styles.css";
18
+
19
+ export function App() {
20
+ return (
21
+ <ZauthaProvider publishableKey="pk_test_…" ui={ui}>
22
+ <Show when="signed-out">
23
+ <SignIn />
24
+ </Show>
25
+ <Show when="signed-in">
26
+ <UserButton />
27
+ </Show>
28
+ </ZauthaProvider>
29
+ );
30
+ }
31
+ ```
32
+
33
+ ## License
34
+
35
+ MIT, see [LICENSE](./LICENSE).
package/dist/index.cjs ADDED
@@ -0,0 +1,345 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ let _zautha_js = require("@zautha/js");
4
+ let react = require("react");
5
+ let react_jsx_runtime = require("react/jsx-runtime");
6
+ //#region src/provider.tsx
7
+ const ZauthaContext = (0, react.createContext)(void 0);
8
+ /**
9
+ * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR
10
+ * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report
11
+ * `isLoaded: false`.
12
+ */
13
+ function ZauthaProvider({ publishableKey, children, ...options }) {
14
+ const [zautha, setZautha] = (0, react.useState)(null);
15
+ const { ui, appearance, localization, signInUrl, signUpUrl, navigate } = options;
16
+ (0, react.useEffect)(() => {
17
+ const instance = new _zautha_js.Zautha(publishableKey, {
18
+ ...ui === void 0 ? {} : { ui },
19
+ ...appearance === void 0 ? {} : { appearance },
20
+ ...localization === void 0 ? {} : { localization },
21
+ ...signInUrl === void 0 ? {} : { signInUrl },
22
+ ...signUpUrl === void 0 ? {} : { signUpUrl },
23
+ ...navigate === void 0 ? {} : { navigate }
24
+ });
25
+ setZautha(instance);
26
+ instance.load();
27
+ return () => {
28
+ instance.dispose();
29
+ setZautha(null);
30
+ };
31
+ }, [publishableKey]);
32
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ZauthaContext.Provider, {
33
+ value: zautha,
34
+ children
35
+ });
36
+ }
37
+ /** The Zautha instance, or null before the provider has created it. */
38
+ function useZautha() {
39
+ const zautha = (0, react.useContext)(ZauthaContext);
40
+ if (zautha === void 0) throw new Error("Zautha hooks and components must be used inside <ZauthaProvider>.");
41
+ return zautha;
42
+ }
43
+ const NO_STATE = {
44
+ status: "loading",
45
+ environment: null,
46
+ client: null,
47
+ session: null,
48
+ user: null
49
+ };
50
+ const noop = () => () => void 0;
51
+ /** Reactive snapshot of the instance state (the loading state before the instance exists). */
52
+ function useZauthaState() {
53
+ const zautha = useZautha();
54
+ return (0, react.useSyncExternalStore)(zautha?.subscribe ?? noop, () => zautha?.getSnapshot() ?? NO_STATE, () => NO_STATE);
55
+ }
56
+ //#endregion
57
+ //#region src/hooks.ts
58
+ const isLoadedStatus = (status) => status === "ready" || status === "degraded";
59
+ function useAuth() {
60
+ const zautha = useZautha();
61
+ const state = useZauthaState();
62
+ const getToken = (0, react.useCallback)((options) => zautha?.getToken(options) ?? Promise.resolve(null), [zautha]);
63
+ const signOut = (0, react.useCallback)((options) => zautha?.signOut(options) ?? Promise.resolve(), [zautha]);
64
+ const signedIn = state.session !== null;
65
+ const has = (0, react.useCallback)((params) => signedIn && params.role === void 0 && params.permission === void 0, [signedIn]);
66
+ return {
67
+ isLoaded: isLoadedStatus(state.status),
68
+ isSignedIn: signedIn,
69
+ userId: state.session?.userId ?? null,
70
+ sessionId: state.session?.id ?? null,
71
+ getToken,
72
+ signOut,
73
+ has
74
+ };
75
+ }
76
+ function useUser() {
77
+ const state = useZauthaState();
78
+ return {
79
+ isLoaded: isLoadedStatus(state.status),
80
+ isSignedIn: state.session !== null,
81
+ user: state.user
82
+ };
83
+ }
84
+ function useSession() {
85
+ const state = useZauthaState();
86
+ return {
87
+ isLoaded: isLoadedStatus(state.status),
88
+ isSignedIn: state.session !== null,
89
+ session: state.session
90
+ };
91
+ }
92
+ const noopSubscribe = () => () => void 0;
93
+ function useResource(resource) {
94
+ return (0, react.useSyncExternalStore)(resource?.subscribe ?? noopSubscribe, () => resource?.snapshot ?? null, () => null);
95
+ }
96
+ const NO_ERRORS = {
97
+ fields: {},
98
+ global: []
99
+ };
100
+ function useSignIn() {
101
+ const zautha = useZautha();
102
+ const state = useZauthaState();
103
+ const snapshot = useResource(zautha?.signIn ?? null);
104
+ return {
105
+ isLoaded: isLoadedStatus(state.status),
106
+ signIn: zautha?.signIn ?? null,
107
+ errors: snapshot?.errors ?? NO_ERRORS,
108
+ fetchStatus: snapshot?.fetchStatus ?? "idle"
109
+ };
110
+ }
111
+ function useSignUp() {
112
+ const zautha = useZautha();
113
+ const state = useZauthaState();
114
+ const snapshot = useResource(zautha?.signUp ?? null);
115
+ return {
116
+ isLoaded: isLoadedStatus(state.status),
117
+ signUp: zautha?.signUp ?? null,
118
+ errors: snapshot?.errors ?? NO_ERRORS,
119
+ fetchStatus: snapshot?.fetchStatus ?? "idle"
120
+ };
121
+ }
122
+ //#endregion
123
+ //#region src/control.tsx
124
+ /**
125
+ * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has
126
+ * loaded, so a signed-in user never sees a signed-out flash.
127
+ */
128
+ function Show(props) {
129
+ const { isLoaded, isSignedIn, has } = useAuth();
130
+ if (!isLoaded) return null;
131
+ const { when } = props;
132
+ return (when === "signed-in" ? isSignedIn : when === "signed-out" ? !isSignedIn : typeof when === "function" ? when(has) : has(when)) ? props.children : props.fallback ?? null;
133
+ }
134
+ function ZauthaLoading(props) {
135
+ return useZauthaState().status === "loading" ? props.children : null;
136
+ }
137
+ /** Loaded, including degraded (network trouble after load: last known state is shown). */
138
+ function ZauthaLoaded(props) {
139
+ const { status } = useZauthaState();
140
+ return status === "ready" || status === "degraded" ? props.children : null;
141
+ }
142
+ function ZauthaDegraded(props) {
143
+ return useZauthaState().status === "degraded" ? props.children : null;
144
+ }
145
+ function ZauthaFailed(props) {
146
+ return useZauthaState().status === "failed" ? props.children : null;
147
+ }
148
+ /** Sends a signed-out visitor to sign-in once loaded; renders nothing. */
149
+ function RedirectToSignIn(props) {
150
+ const zautha = useZautha();
151
+ const { isLoaded, isSignedIn } = useAuth();
152
+ const { redirectUrl } = props;
153
+ (0, react.useEffect)(() => {
154
+ if (zautha !== null && isLoaded && !isSignedIn) zautha.redirectToSignIn(redirectUrl === void 0 ? {} : { redirectUrl });
155
+ }, [
156
+ zautha,
157
+ isLoaded,
158
+ isSignedIn,
159
+ redirectUrl
160
+ ]);
161
+ return null;
162
+ }
163
+ function RedirectToSignUp(props) {
164
+ const zautha = useZautha();
165
+ const { isLoaded, isSignedIn } = useAuth();
166
+ const { redirectUrl } = props;
167
+ (0, react.useEffect)(() => {
168
+ if (zautha !== null && isLoaded && !isSignedIn) zautha.redirectToSignUp(redirectUrl === void 0 ? {} : { redirectUrl });
169
+ }, [
170
+ zautha,
171
+ isLoaded,
172
+ isSignedIn,
173
+ redirectUrl
174
+ ]);
175
+ return null;
176
+ }
177
+ //#endregion
178
+ //#region src/buttons.tsx
179
+ /** Wraps its single child (or renders a plain button) and wires the click. Unstyled by design. */
180
+ function Trigger(props) {
181
+ const child = react.Children.count(props.children) === 1 ? react.Children.only(props.children) : null;
182
+ if ((0, react.isValidElement)(child)) {
183
+ const original = child.props.onClick;
184
+ return (0, react.cloneElement)(child, { onClick: (event) => {
185
+ original?.(event);
186
+ if (!event.defaultPrevented) props.onClick();
187
+ } });
188
+ }
189
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
190
+ type: "button",
191
+ onClick: props.onClick,
192
+ children: props.children ?? props.label
193
+ });
194
+ }
195
+ function SignInButton(props) {
196
+ const zautha = useZautha();
197
+ const options = props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl };
198
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trigger, {
199
+ label: "Sign in",
200
+ onClick: () => props.mode === "modal" ? zautha?.openSignIn(options) : zautha?.redirectToSignIn(options),
201
+ children: props.children
202
+ });
203
+ }
204
+ function SignUpButton(props) {
205
+ const zautha = useZautha();
206
+ const options = props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl };
207
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trigger, {
208
+ label: "Sign up",
209
+ onClick: () => props.mode === "modal" ? zautha?.openSignUp(options) : zautha?.redirectToSignUp(options),
210
+ children: props.children
211
+ });
212
+ }
213
+ function SignOutButton(props) {
214
+ const zautha = useZautha();
215
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Trigger, {
216
+ label: "Sign out",
217
+ onClick: () => void zautha?.signOut(props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl }),
218
+ children: props.children
219
+ });
220
+ }
221
+ //#endregion
222
+ //#region src/prebuilt.tsx
223
+ /**
224
+ * Mounts a @zautha/ui component into a div once the instance exists; later prop changes update it in
225
+ * place. SSR renders only the empty div.
226
+ */
227
+ function Mounted(props) {
228
+ const zautha = useZautha();
229
+ const ref = (0, react.useRef)(null);
230
+ const mountedWith = (0, react.useRef)(null);
231
+ const { name, componentProps } = props;
232
+ (0, react.useEffect)(() => {
233
+ const element = ref.current;
234
+ if (zautha === null || element === null) return;
235
+ zautha.mount(name, element, componentProps);
236
+ mountedWith.current = componentProps;
237
+ return () => {
238
+ mountedWith.current = null;
239
+ zautha.unmount(element);
240
+ };
241
+ }, [zautha, name]);
242
+ (0, react.useEffect)(() => {
243
+ const element = ref.current;
244
+ if (zautha === null || element === null || mountedWith.current === null || mountedWith.current === componentProps) return;
245
+ mountedWith.current = componentProps;
246
+ zautha.updateMounted(element, componentProps);
247
+ }, [zautha, componentProps]);
248
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { ref });
249
+ }
250
+ function SignIn(props) {
251
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Mounted, {
252
+ name: "SignIn",
253
+ componentProps: props
254
+ });
255
+ }
256
+ function SignUp(props) {
257
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Mounted, {
258
+ name: "SignUp",
259
+ componentProps: props
260
+ });
261
+ }
262
+ function UserButton(props) {
263
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Mounted, {
264
+ name: "UserButton",
265
+ componentProps: props
266
+ });
267
+ }
268
+ function OAuthConsent(props) {
269
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Mounted, {
270
+ name: "OAuthConsent",
271
+ componentProps: props
272
+ });
273
+ }
274
+ //#endregion
275
+ exports.OAuthConsent = OAuthConsent;
276
+ exports.RedirectToSignIn = RedirectToSignIn;
277
+ exports.RedirectToSignUp = RedirectToSignUp;
278
+ exports.Show = Show;
279
+ exports.SignIn = SignIn;
280
+ exports.SignInButton = SignInButton;
281
+ exports.SignOutButton = SignOutButton;
282
+ exports.SignUp = SignUp;
283
+ exports.SignUpButton = SignUpButton;
284
+ exports.UserButton = UserButton;
285
+ Object.defineProperty(exports, "ZauthaApiError", {
286
+ enumerable: true,
287
+ get: function() {
288
+ return _zautha_js.ZauthaApiError;
289
+ }
290
+ });
291
+ exports.ZauthaDegraded = ZauthaDegraded;
292
+ Object.defineProperty(exports, "ZauthaError", {
293
+ enumerable: true,
294
+ get: function() {
295
+ return _zautha_js.ZauthaError;
296
+ }
297
+ });
298
+ exports.ZauthaFailed = ZauthaFailed;
299
+ exports.ZauthaLoaded = ZauthaLoaded;
300
+ exports.ZauthaLoading = ZauthaLoading;
301
+ Object.defineProperty(exports, "ZauthaNetworkError", {
302
+ enumerable: true,
303
+ get: function() {
304
+ return _zautha_js.ZauthaNetworkError;
305
+ }
306
+ });
307
+ Object.defineProperty(exports, "ZauthaOfflineError", {
308
+ enumerable: true,
309
+ get: function() {
310
+ return _zautha_js.ZauthaOfflineError;
311
+ }
312
+ });
313
+ exports.ZauthaProvider = ZauthaProvider;
314
+ Object.defineProperty(exports, "isZauthaApiError", {
315
+ enumerable: true,
316
+ get: function() {
317
+ return _zautha_js.isZauthaApiError;
318
+ }
319
+ });
320
+ Object.defineProperty(exports, "isZauthaError", {
321
+ enumerable: true,
322
+ get: function() {
323
+ return _zautha_js.isZauthaError;
324
+ }
325
+ });
326
+ Object.defineProperty(exports, "isZauthaNetworkError", {
327
+ enumerable: true,
328
+ get: function() {
329
+ return _zautha_js.isZauthaNetworkError;
330
+ }
331
+ });
332
+ Object.defineProperty(exports, "isZauthaOfflineError", {
333
+ enumerable: true,
334
+ get: function() {
335
+ return _zautha_js.isZauthaOfflineError;
336
+ }
337
+ });
338
+ exports.useAuth = useAuth;
339
+ exports.useSession = useSession;
340
+ exports.useSignIn = useSignIn;
341
+ exports.useSignUp = useSignUp;
342
+ exports.useUser = useUser;
343
+ exports.useZautha = useZautha;
344
+
345
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["createContext","useState","Zautha","useContext","useSyncExternalStore","useCallback","useSyncExternalStore","Children","isValidElement","cloneElement","useRef"],"sources":["../src/provider.tsx","../src/hooks.ts","../src/control.tsx","../src/buttons.tsx","../src/prebuilt.tsx"],"sourcesContent":["import { Zautha, type ZauthaOptions, type ZauthaState } from \"@zautha/js\";\nimport { createContext, useContext, useEffect, useState, useSyncExternalStore, type ReactNode } from \"react\";\n\nconst ZauthaContext = createContext<Zautha | null | undefined>(undefined);\n\nexport interface ZauthaProviderProps extends Omit<ZauthaOptions, \"fetch\"> {\n publishableKey: string;\n children?: ReactNode;\n}\n\n/**\n * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR\n * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report\n * `isLoaded: false`.\n */\nexport function ZauthaProvider({ publishableKey, children, ...options }: ZauthaProviderProps): ReactNode {\n const [zautha, setZautha] = useState<Zautha | null>(null);\n const { ui, appearance, localization, signInUrl, signUpUrl, navigate } = options;\n\n useEffect(() => {\n const instance = new Zautha(publishableKey, {\n ...(ui === undefined ? {} : { ui }),\n ...(appearance === undefined ? {} : { appearance }),\n ...(localization === undefined ? {} : { localization }),\n ...(signInUrl === undefined ? {} : { signInUrl }),\n ...(signUpUrl === undefined ? {} : { signUpUrl }),\n ...(navigate === undefined ? {} : { navigate }),\n });\n // The instance is an external system: it is created here, never during render, and published through state.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setZautha(instance);\n void instance.load();\n return () => {\n instance.dispose();\n setZautha(null);\n };\n // Appearance/localization objects are read at mount; changing the key re-creates the instance.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey]);\n\n return <ZauthaContext.Provider value={zautha}>{children}</ZauthaContext.Provider>;\n}\n\n/** The Zautha instance, or null before the provider has created it. */\nexport function useZautha(): Zautha | null {\n const zautha = useContext(ZauthaContext);\n if (zautha === undefined) throw new Error(\"Zautha hooks and components must be used inside <ZauthaProvider>.\");\n return zautha;\n}\n\nconst NO_STATE: ZauthaState = { status: \"loading\", environment: null, client: null, session: null, user: null };\nconst noop = (): (() => void) => () => undefined;\n\n/** Reactive snapshot of the instance state (the loading state before the instance exists). */\nexport function useZauthaState(): ZauthaState {\n const zautha = useZautha();\n return useSyncExternalStore(\n zautha?.subscribe ?? noop,\n () => zautha?.getSnapshot() ?? NO_STATE,\n () => NO_STATE,\n );\n}\n","import type { AttemptErrors, FetchStatus, Session, SignInResource, SignUpResource, User } from \"@zautha/js\";\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport { useZautha, useZauthaState } from \"./provider\";\n\n/** Authorization check. In 3a there are no organization claims yet, so role/permission checks are false. */\nexport type HasParams = { role?: string; permission?: string };\nexport type Has = (params: HasParams) => boolean;\n\nexport interface UseAuthResult {\n isLoaded: boolean;\n isSignedIn: boolean;\n userId: string | null;\n sessionId: string | null;\n getToken: (options?: { skipCache?: boolean }) => Promise<string | null>;\n signOut: (options?: { redirectUrl?: string }) => Promise<void>;\n has: Has;\n}\n\nconst isLoadedStatus = (status: string): boolean => status === \"ready\" || status === \"degraded\";\n\nexport function useAuth(): UseAuthResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const getToken = useCallback(\n (options?: { skipCache?: boolean }) => zautha?.getToken(options) ?? Promise.resolve(null),\n [zautha],\n );\n const signOut = useCallback(\n (options?: { redirectUrl?: string }) => zautha?.signOut(options) ?? Promise.resolve(),\n [zautha],\n );\n const signedIn = state.session !== null;\n const has = useCallback<Has>(\n (params) => signedIn && params.role === undefined && params.permission === undefined,\n [signedIn],\n );\n return {\n isLoaded: isLoadedStatus(state.status),\n isSignedIn: signedIn,\n userId: state.session?.userId ?? null,\n sessionId: state.session?.id ?? null,\n getToken,\n signOut,\n has,\n };\n}\n\nexport function useUser(): { isLoaded: boolean; isSignedIn: boolean; user: User | null } {\n const state = useZauthaState();\n return { isLoaded: isLoadedStatus(state.status), isSignedIn: state.session !== null, user: state.user };\n}\n\nexport function useSession(): { isLoaded: boolean; isSignedIn: boolean; session: Session | null } {\n const state = useZauthaState();\n return { isLoaded: isLoadedStatus(state.status), isSignedIn: state.session !== null, session: state.session };\n}\n\nconst noopSubscribe = (): (() => void) => () => undefined;\n\nfunction useResource<T extends SignInResource | SignUpResource>(resource: T | null) {\n const snapshot = useSyncExternalStore(\n resource?.subscribe ?? noopSubscribe,\n () => resource?.snapshot ?? null,\n () => null,\n );\n return snapshot;\n}\n\nexport interface UseSignInResult {\n isLoaded: boolean;\n /** The sign-in resource; null until the provider has created the instance. */\n signIn: SignInResource | null;\n errors: AttemptErrors;\n fetchStatus: FetchStatus;\n}\n\nconst NO_ERRORS: AttemptErrors = { fields: {}, global: [] };\n\nexport function useSignIn(): UseSignInResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const snapshot = useResource(zautha?.signIn ?? null);\n return {\n isLoaded: isLoadedStatus(state.status),\n signIn: zautha?.signIn ?? null,\n errors: snapshot?.errors ?? NO_ERRORS,\n fetchStatus: snapshot?.fetchStatus ?? \"idle\",\n };\n}\n\nexport interface UseSignUpResult {\n isLoaded: boolean;\n signUp: SignUpResource | null;\n errors: AttemptErrors;\n fetchStatus: FetchStatus;\n}\n\nexport function useSignUp(): UseSignUpResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const snapshot = useResource(zautha?.signUp ?? null);\n return {\n isLoaded: isLoadedStatus(state.status),\n signUp: zautha?.signUp ?? null,\n errors: snapshot?.errors ?? NO_ERRORS,\n fetchStatus: snapshot?.fetchStatus ?? \"idle\",\n };\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useAuth, type Has, type HasParams } from \"./hooks\";\nimport { useZautha, useZauthaState } from \"./provider\";\n\nexport type ShowWhen = \"signed-in\" | \"signed-out\" | HasParams | ((has: Has) => boolean);\n\n/**\n * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has\n * loaded, so a signed-in user never sees a signed-out flash.\n */\nexport function Show(props: { when: ShowWhen; fallback?: ReactNode; children?: ReactNode }): ReactNode {\n const { isLoaded, isSignedIn, has } = useAuth();\n if (!isLoaded) return null;\n const { when } = props;\n const pass =\n when === \"signed-in\"\n ? isSignedIn\n : when === \"signed-out\"\n ? !isSignedIn\n : typeof when === \"function\"\n ? when(has)\n : has(when);\n return pass ? props.children : (props.fallback ?? null);\n}\n\nexport function ZauthaLoading(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"loading\" ? props.children : null;\n}\n\n/** Loaded, including degraded (network trouble after load: last known state is shown). */\nexport function ZauthaLoaded(props: { children?: ReactNode }): ReactNode {\n const { status } = useZauthaState();\n return status === \"ready\" || status === \"degraded\" ? props.children : null;\n}\n\nexport function ZauthaDegraded(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"degraded\" ? props.children : null;\n}\n\nexport function ZauthaFailed(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"failed\" ? props.children : null;\n}\n\n/** Sends a signed-out visitor to sign-in once loaded; renders nothing. */\nexport function RedirectToSignIn(props: { redirectUrl?: string }): ReactNode {\n const zautha = useZautha();\n const { isLoaded, isSignedIn } = useAuth();\n const { redirectUrl } = props;\n useEffect(() => {\n if (zautha !== null && isLoaded && !isSignedIn)\n zautha.redirectToSignIn(redirectUrl === undefined ? {} : { redirectUrl });\n }, [zautha, isLoaded, isSignedIn, redirectUrl]);\n return null;\n}\n\nexport function RedirectToSignUp(props: { redirectUrl?: string }): ReactNode {\n const zautha = useZautha();\n const { isLoaded, isSignedIn } = useAuth();\n const { redirectUrl } = props;\n useEffect(() => {\n if (zautha !== null && isLoaded && !isSignedIn)\n zautha.redirectToSignUp(redirectUrl === undefined ? {} : { redirectUrl });\n }, [zautha, isLoaded, isSignedIn, redirectUrl]);\n return null;\n}\n","import { Children, cloneElement, isValidElement, type MouseEvent, type ReactElement, type ReactNode } from \"react\";\nimport { useZautha } from \"./provider\";\n\ninterface ButtonProps {\n /** `redirect` (default) goes to the sign-in page; `modal` opens the prebuilt component (needs `ui`). */\n mode?: \"redirect\" | \"modal\";\n redirectUrl?: string;\n children?: ReactNode;\n}\n\n/** Wraps its single child (or renders a plain button) and wires the click. Unstyled by design. */\nfunction Trigger(props: { children: ReactNode; label: string; onClick: () => void }): ReactNode {\n const child = Children.count(props.children) === 1 ? Children.only(props.children) : null;\n if (isValidElement<{ onClick?: (event: MouseEvent) => void }>(child)) {\n const original = child.props.onClick;\n return cloneElement(child as ReactElement<{ onClick?: (event: MouseEvent) => void }>, {\n onClick: (event: MouseEvent) => {\n original?.(event);\n if (!event.defaultPrevented) props.onClick();\n },\n });\n }\n return (\n <button type=\"button\" onClick={props.onClick}>\n {props.children ?? props.label}\n </button>\n );\n}\n\nexport function SignInButton(props: ButtonProps): ReactNode {\n const zautha = useZautha();\n const options = props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl };\n return (\n <Trigger\n label=\"Sign in\"\n onClick={() => (props.mode === \"modal\" ? zautha?.openSignIn(options) : zautha?.redirectToSignIn(options))}\n >\n {props.children}\n </Trigger>\n );\n}\n\nexport function SignUpButton(props: ButtonProps): ReactNode {\n const zautha = useZautha();\n const options = props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl };\n return (\n <Trigger\n label=\"Sign up\"\n onClick={() => (props.mode === \"modal\" ? zautha?.openSignUp(options) : zautha?.redirectToSignUp(options))}\n >\n {props.children}\n </Trigger>\n );\n}\n\nexport function SignOutButton(props: { redirectUrl?: string; children?: ReactNode }): ReactNode {\n const zautha = useZautha();\n return (\n <Trigger\n label=\"Sign out\"\n onClick={() => void zautha?.signOut(props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl })}\n >\n {props.children}\n </Trigger>\n );\n}\n","import type { UiComponentName } from \"@zautha/js\";\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { useZautha } from \"./provider\";\n\n/**\n * Mounts a @zautha/ui component into a div once the instance exists; later prop changes update it in\n * place. SSR renders only the empty div.\n */\nfunction Mounted(props: { name: UiComponentName; componentProps: object }): ReactNode {\n const zautha = useZautha();\n const ref = useRef<HTMLDivElement>(null);\n const mountedWith = useRef<object | null>(null);\n const { name, componentProps } = props;\n\n useEffect(() => {\n const element = ref.current;\n if (zautha === null || element === null) return;\n zautha.mount(name, element, componentProps);\n mountedWith.current = componentProps;\n return () => {\n mountedWith.current = null;\n zautha.unmount(element);\n };\n // componentProps changes are applied by the effect below without remounting.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [zautha, name]);\n\n useEffect(() => {\n const element = ref.current;\n if (zautha === null || element === null || mountedWith.current === null || mountedWith.current === componentProps)\n return;\n mountedWith.current = componentProps;\n zautha.updateMounted(element, componentProps);\n }, [zautha, componentProps]);\n\n return <div ref={ref} />;\n}\n\n// Prop types live in @zautha/ui; they are structural here so @zautha/react has no runtime dependency on it.\nexport function SignIn(props: import(\"@zautha/ui\").SignInProps): ReactNode {\n return <Mounted name=\"SignIn\" componentProps={props} />;\n}\n\nexport function SignUp(props: import(\"@zautha/ui\").SignUpProps): ReactNode {\n return <Mounted name=\"SignUp\" componentProps={props} />;\n}\n\nexport function UserButton(props: import(\"@zautha/ui\").UserButtonProps): ReactNode {\n return <Mounted name=\"UserButton\" componentProps={props} />;\n}\n\nexport function OAuthConsent(props: import(\"@zautha/ui\").OAuthConsentProps): ReactNode {\n return <Mounted name=\"OAuthConsent\" componentProps={props} />;\n}\n"],"mappings":"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"}
@@ -0,0 +1,118 @@
1
+
2
+ import { AttemptErrors, Environment, FetchStatus, Session, Session as Session$1, SignInResource, SignInResource as SignInResource$1, SignUpResource, SignUpResource as SignUpResource$1, User, User as User$1, Zautha, ZauthaApiError, ZauthaError, ZauthaErrorCode, ZauthaNetworkError, ZauthaOfflineError, ZauthaOptions, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError } from "@zautha/js";
3
+ import { ReactNode } from "react";
4
+ //#region src/provider.d.ts
5
+ interface ZauthaProviderProps extends Omit<ZauthaOptions, "fetch"> {
6
+ publishableKey: string;
7
+ children?: ReactNode;
8
+ }
9
+ /**
10
+ * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR
11
+ * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report
12
+ * `isLoaded: false`.
13
+ */
14
+ export declare function ZauthaProvider({ publishableKey, children, ...options }: ZauthaProviderProps): ReactNode;
15
+ /** The Zautha instance, or null before the provider has created it. */
16
+ export declare function useZautha(): Zautha | null;
17
+ //#endregion
18
+ //#region src/hooks.d.ts
19
+ /** Authorization check. In 3a there are no organization claims yet, so role/permission checks are false. */
20
+ type HasParams = {
21
+ role?: string;
22
+ permission?: string;
23
+ };
24
+ type Has = (params: HasParams) => boolean;
25
+ interface UseAuthResult {
26
+ isLoaded: boolean;
27
+ isSignedIn: boolean;
28
+ userId: string | null;
29
+ sessionId: string | null;
30
+ getToken: (options?: {
31
+ skipCache?: boolean;
32
+ }) => Promise<string | null>;
33
+ signOut: (options?: {
34
+ redirectUrl?: string;
35
+ }) => Promise<void>;
36
+ has: Has;
37
+ }
38
+ export declare function useAuth(): UseAuthResult;
39
+ export declare function useUser(): {
40
+ isLoaded: boolean;
41
+ isSignedIn: boolean;
42
+ user: User$1 | null;
43
+ };
44
+ export declare function useSession(): {
45
+ isLoaded: boolean;
46
+ isSignedIn: boolean;
47
+ session: Session$1 | null;
48
+ };
49
+ interface UseSignInResult {
50
+ isLoaded: boolean;
51
+ /** The sign-in resource; null until the provider has created the instance. */
52
+ signIn: SignInResource$1 | null;
53
+ errors: AttemptErrors;
54
+ fetchStatus: FetchStatus;
55
+ }
56
+ export declare function useSignIn(): UseSignInResult;
57
+ interface UseSignUpResult {
58
+ isLoaded: boolean;
59
+ signUp: SignUpResource$1 | null;
60
+ errors: AttemptErrors;
61
+ fetchStatus: FetchStatus;
62
+ }
63
+ export declare function useSignUp(): UseSignUpResult;
64
+ //#endregion
65
+ //#region src/control.d.ts
66
+ type ShowWhen = "signed-in" | "signed-out" | HasParams | ((has: Has) => boolean);
67
+ /**
68
+ * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has
69
+ * loaded, so a signed-in user never sees a signed-out flash.
70
+ */
71
+ export declare function Show(props: {
72
+ when: ShowWhen;
73
+ fallback?: ReactNode;
74
+ children?: ReactNode;
75
+ }): ReactNode;
76
+ export declare function ZauthaLoading(props: {
77
+ children?: ReactNode;
78
+ }): ReactNode;
79
+ /** Loaded, including degraded (network trouble after load: last known state is shown). */
80
+ export declare function ZauthaLoaded(props: {
81
+ children?: ReactNode;
82
+ }): ReactNode;
83
+ export declare function ZauthaDegraded(props: {
84
+ children?: ReactNode;
85
+ }): ReactNode;
86
+ export declare function ZauthaFailed(props: {
87
+ children?: ReactNode;
88
+ }): ReactNode;
89
+ /** Sends a signed-out visitor to sign-in once loaded; renders nothing. */
90
+ export declare function RedirectToSignIn(props: {
91
+ redirectUrl?: string;
92
+ }): ReactNode;
93
+ export declare function RedirectToSignUp(props: {
94
+ redirectUrl?: string;
95
+ }): ReactNode;
96
+ //#endregion
97
+ //#region src/buttons.d.ts
98
+ interface ButtonProps {
99
+ /** `redirect` (default) goes to the sign-in page; `modal` opens the prebuilt component (needs `ui`). */
100
+ mode?: "redirect" | "modal";
101
+ redirectUrl?: string;
102
+ children?: ReactNode;
103
+ }
104
+ export declare function SignInButton(props: ButtonProps): ReactNode;
105
+ export declare function SignUpButton(props: ButtonProps): ReactNode;
106
+ export declare function SignOutButton(props: {
107
+ redirectUrl?: string;
108
+ children?: ReactNode;
109
+ }): ReactNode;
110
+ //#endregion
111
+ //#region src/prebuilt.d.ts
112
+ export declare function SignIn(props: import("@zautha/ui").SignInProps): ReactNode;
113
+ export declare function SignUp(props: import("@zautha/ui").SignUpProps): ReactNode;
114
+ export declare function UserButton(props: import("@zautha/ui").UserButtonProps): ReactNode;
115
+ export declare function OAuthConsent(props: import("@zautha/ui").OAuthConsentProps): ReactNode;
116
+ //#endregion
117
+ export { type Environment, type Has, type HasParams, type Session, type ShowWhen, type SignInResource, type SignUpResource, type UseAuthResult, type UseSignInResult, type UseSignUpResult, type User, ZauthaApiError, ZauthaError, type ZauthaErrorCode, ZauthaNetworkError, ZauthaOfflineError, type ZauthaProviderProps, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError };
118
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,118 @@
1
+
2
+ import { AttemptErrors, Environment, FetchStatus, Session, Session as Session$1, SignInResource, SignInResource as SignInResource$1, SignUpResource, SignUpResource as SignUpResource$1, User, User as User$1, Zautha, ZauthaApiError, ZauthaError, ZauthaErrorCode, ZauthaNetworkError, ZauthaOfflineError, ZauthaOptions, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError } from "@zautha/js";
3
+ import { ReactNode } from "react";
4
+ //#region src/provider.d.ts
5
+ interface ZauthaProviderProps extends Omit<ZauthaOptions, "fetch"> {
6
+ publishableKey: string;
7
+ children?: ReactNode;
8
+ }
9
+ /**
10
+ * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR
11
+ * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report
12
+ * `isLoaded: false`.
13
+ */
14
+ export declare function ZauthaProvider({ publishableKey, children, ...options }: ZauthaProviderProps): ReactNode;
15
+ /** The Zautha instance, or null before the provider has created it. */
16
+ export declare function useZautha(): Zautha | null;
17
+ //#endregion
18
+ //#region src/hooks.d.ts
19
+ /** Authorization check. In 3a there are no organization claims yet, so role/permission checks are false. */
20
+ type HasParams = {
21
+ role?: string;
22
+ permission?: string;
23
+ };
24
+ type Has = (params: HasParams) => boolean;
25
+ interface UseAuthResult {
26
+ isLoaded: boolean;
27
+ isSignedIn: boolean;
28
+ userId: string | null;
29
+ sessionId: string | null;
30
+ getToken: (options?: {
31
+ skipCache?: boolean;
32
+ }) => Promise<string | null>;
33
+ signOut: (options?: {
34
+ redirectUrl?: string;
35
+ }) => Promise<void>;
36
+ has: Has;
37
+ }
38
+ export declare function useAuth(): UseAuthResult;
39
+ export declare function useUser(): {
40
+ isLoaded: boolean;
41
+ isSignedIn: boolean;
42
+ user: User$1 | null;
43
+ };
44
+ export declare function useSession(): {
45
+ isLoaded: boolean;
46
+ isSignedIn: boolean;
47
+ session: Session$1 | null;
48
+ };
49
+ interface UseSignInResult {
50
+ isLoaded: boolean;
51
+ /** The sign-in resource; null until the provider has created the instance. */
52
+ signIn: SignInResource$1 | null;
53
+ errors: AttemptErrors;
54
+ fetchStatus: FetchStatus;
55
+ }
56
+ export declare function useSignIn(): UseSignInResult;
57
+ interface UseSignUpResult {
58
+ isLoaded: boolean;
59
+ signUp: SignUpResource$1 | null;
60
+ errors: AttemptErrors;
61
+ fetchStatus: FetchStatus;
62
+ }
63
+ export declare function useSignUp(): UseSignUpResult;
64
+ //#endregion
65
+ //#region src/control.d.ts
66
+ type ShowWhen = "signed-in" | "signed-out" | HasParams | ((has: Has) => boolean);
67
+ /**
68
+ * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has
69
+ * loaded, so a signed-in user never sees a signed-out flash.
70
+ */
71
+ export declare function Show(props: {
72
+ when: ShowWhen;
73
+ fallback?: ReactNode;
74
+ children?: ReactNode;
75
+ }): ReactNode;
76
+ export declare function ZauthaLoading(props: {
77
+ children?: ReactNode;
78
+ }): ReactNode;
79
+ /** Loaded, including degraded (network trouble after load: last known state is shown). */
80
+ export declare function ZauthaLoaded(props: {
81
+ children?: ReactNode;
82
+ }): ReactNode;
83
+ export declare function ZauthaDegraded(props: {
84
+ children?: ReactNode;
85
+ }): ReactNode;
86
+ export declare function ZauthaFailed(props: {
87
+ children?: ReactNode;
88
+ }): ReactNode;
89
+ /** Sends a signed-out visitor to sign-in once loaded; renders nothing. */
90
+ export declare function RedirectToSignIn(props: {
91
+ redirectUrl?: string;
92
+ }): ReactNode;
93
+ export declare function RedirectToSignUp(props: {
94
+ redirectUrl?: string;
95
+ }): ReactNode;
96
+ //#endregion
97
+ //#region src/buttons.d.ts
98
+ interface ButtonProps {
99
+ /** `redirect` (default) goes to the sign-in page; `modal` opens the prebuilt component (needs `ui`). */
100
+ mode?: "redirect" | "modal";
101
+ redirectUrl?: string;
102
+ children?: ReactNode;
103
+ }
104
+ export declare function SignInButton(props: ButtonProps): ReactNode;
105
+ export declare function SignUpButton(props: ButtonProps): ReactNode;
106
+ export declare function SignOutButton(props: {
107
+ redirectUrl?: string;
108
+ children?: ReactNode;
109
+ }): ReactNode;
110
+ //#endregion
111
+ //#region src/prebuilt.d.ts
112
+ export declare function SignIn(props: import("@zautha/ui").SignInProps): ReactNode;
113
+ export declare function SignUp(props: import("@zautha/ui").SignUpProps): ReactNode;
114
+ export declare function UserButton(props: import("@zautha/ui").UserButtonProps): ReactNode;
115
+ export declare function OAuthConsent(props: import("@zautha/ui").OAuthConsentProps): ReactNode;
116
+ //#endregion
117
+ export { type Environment, type Has, type HasParams, type Session, type ShowWhen, type SignInResource, type SignUpResource, type UseAuthResult, type UseSignInResult, type UseSignUpResult, type User, ZauthaApiError, ZauthaError, type ZauthaErrorCode, ZauthaNetworkError, ZauthaOfflineError, type ZauthaProviderProps, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError };
118
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,276 @@
1
+ "use client";
2
+ import { Zautha, ZauthaApiError, ZauthaError, ZauthaNetworkError, ZauthaOfflineError, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError } from "@zautha/js";
3
+ import { Children, cloneElement, createContext, isValidElement, useCallback, useContext, useEffect, useRef, useState, useSyncExternalStore } from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ //#region src/provider.tsx
6
+ const ZauthaContext = createContext(void 0);
7
+ /**
8
+ * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR
9
+ * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report
10
+ * `isLoaded: false`.
11
+ */
12
+ function ZauthaProvider({ publishableKey, children, ...options }) {
13
+ const [zautha, setZautha] = useState(null);
14
+ const { ui, appearance, localization, signInUrl, signUpUrl, navigate } = options;
15
+ useEffect(() => {
16
+ const instance = new Zautha(publishableKey, {
17
+ ...ui === void 0 ? {} : { ui },
18
+ ...appearance === void 0 ? {} : { appearance },
19
+ ...localization === void 0 ? {} : { localization },
20
+ ...signInUrl === void 0 ? {} : { signInUrl },
21
+ ...signUpUrl === void 0 ? {} : { signUpUrl },
22
+ ...navigate === void 0 ? {} : { navigate }
23
+ });
24
+ setZautha(instance);
25
+ instance.load();
26
+ return () => {
27
+ instance.dispose();
28
+ setZautha(null);
29
+ };
30
+ }, [publishableKey]);
31
+ return /* @__PURE__ */ jsx(ZauthaContext.Provider, {
32
+ value: zautha,
33
+ children
34
+ });
35
+ }
36
+ /** The Zautha instance, or null before the provider has created it. */
37
+ function useZautha() {
38
+ const zautha = useContext(ZauthaContext);
39
+ if (zautha === void 0) throw new Error("Zautha hooks and components must be used inside <ZauthaProvider>.");
40
+ return zautha;
41
+ }
42
+ const NO_STATE = {
43
+ status: "loading",
44
+ environment: null,
45
+ client: null,
46
+ session: null,
47
+ user: null
48
+ };
49
+ const noop = () => () => void 0;
50
+ /** Reactive snapshot of the instance state (the loading state before the instance exists). */
51
+ function useZauthaState() {
52
+ const zautha = useZautha();
53
+ return useSyncExternalStore(zautha?.subscribe ?? noop, () => zautha?.getSnapshot() ?? NO_STATE, () => NO_STATE);
54
+ }
55
+ //#endregion
56
+ //#region src/hooks.ts
57
+ const isLoadedStatus = (status) => status === "ready" || status === "degraded";
58
+ function useAuth() {
59
+ const zautha = useZautha();
60
+ const state = useZauthaState();
61
+ const getToken = useCallback((options) => zautha?.getToken(options) ?? Promise.resolve(null), [zautha]);
62
+ const signOut = useCallback((options) => zautha?.signOut(options) ?? Promise.resolve(), [zautha]);
63
+ const signedIn = state.session !== null;
64
+ const has = useCallback((params) => signedIn && params.role === void 0 && params.permission === void 0, [signedIn]);
65
+ return {
66
+ isLoaded: isLoadedStatus(state.status),
67
+ isSignedIn: signedIn,
68
+ userId: state.session?.userId ?? null,
69
+ sessionId: state.session?.id ?? null,
70
+ getToken,
71
+ signOut,
72
+ has
73
+ };
74
+ }
75
+ function useUser() {
76
+ const state = useZauthaState();
77
+ return {
78
+ isLoaded: isLoadedStatus(state.status),
79
+ isSignedIn: state.session !== null,
80
+ user: state.user
81
+ };
82
+ }
83
+ function useSession() {
84
+ const state = useZauthaState();
85
+ return {
86
+ isLoaded: isLoadedStatus(state.status),
87
+ isSignedIn: state.session !== null,
88
+ session: state.session
89
+ };
90
+ }
91
+ const noopSubscribe = () => () => void 0;
92
+ function useResource(resource) {
93
+ return useSyncExternalStore(resource?.subscribe ?? noopSubscribe, () => resource?.snapshot ?? null, () => null);
94
+ }
95
+ const NO_ERRORS = {
96
+ fields: {},
97
+ global: []
98
+ };
99
+ function useSignIn() {
100
+ const zautha = useZautha();
101
+ const state = useZauthaState();
102
+ const snapshot = useResource(zautha?.signIn ?? null);
103
+ return {
104
+ isLoaded: isLoadedStatus(state.status),
105
+ signIn: zautha?.signIn ?? null,
106
+ errors: snapshot?.errors ?? NO_ERRORS,
107
+ fetchStatus: snapshot?.fetchStatus ?? "idle"
108
+ };
109
+ }
110
+ function useSignUp() {
111
+ const zautha = useZautha();
112
+ const state = useZauthaState();
113
+ const snapshot = useResource(zautha?.signUp ?? null);
114
+ return {
115
+ isLoaded: isLoadedStatus(state.status),
116
+ signUp: zautha?.signUp ?? null,
117
+ errors: snapshot?.errors ?? NO_ERRORS,
118
+ fetchStatus: snapshot?.fetchStatus ?? "idle"
119
+ };
120
+ }
121
+ //#endregion
122
+ //#region src/control.tsx
123
+ /**
124
+ * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has
125
+ * loaded, so a signed-in user never sees a signed-out flash.
126
+ */
127
+ function Show(props) {
128
+ const { isLoaded, isSignedIn, has } = useAuth();
129
+ if (!isLoaded) return null;
130
+ const { when } = props;
131
+ return (when === "signed-in" ? isSignedIn : when === "signed-out" ? !isSignedIn : typeof when === "function" ? when(has) : has(when)) ? props.children : props.fallback ?? null;
132
+ }
133
+ function ZauthaLoading(props) {
134
+ return useZauthaState().status === "loading" ? props.children : null;
135
+ }
136
+ /** Loaded, including degraded (network trouble after load: last known state is shown). */
137
+ function ZauthaLoaded(props) {
138
+ const { status } = useZauthaState();
139
+ return status === "ready" || status === "degraded" ? props.children : null;
140
+ }
141
+ function ZauthaDegraded(props) {
142
+ return useZauthaState().status === "degraded" ? props.children : null;
143
+ }
144
+ function ZauthaFailed(props) {
145
+ return useZauthaState().status === "failed" ? props.children : null;
146
+ }
147
+ /** Sends a signed-out visitor to sign-in once loaded; renders nothing. */
148
+ function RedirectToSignIn(props) {
149
+ const zautha = useZautha();
150
+ const { isLoaded, isSignedIn } = useAuth();
151
+ const { redirectUrl } = props;
152
+ useEffect(() => {
153
+ if (zautha !== null && isLoaded && !isSignedIn) zautha.redirectToSignIn(redirectUrl === void 0 ? {} : { redirectUrl });
154
+ }, [
155
+ zautha,
156
+ isLoaded,
157
+ isSignedIn,
158
+ redirectUrl
159
+ ]);
160
+ return null;
161
+ }
162
+ function RedirectToSignUp(props) {
163
+ const zautha = useZautha();
164
+ const { isLoaded, isSignedIn } = useAuth();
165
+ const { redirectUrl } = props;
166
+ useEffect(() => {
167
+ if (zautha !== null && isLoaded && !isSignedIn) zautha.redirectToSignUp(redirectUrl === void 0 ? {} : { redirectUrl });
168
+ }, [
169
+ zautha,
170
+ isLoaded,
171
+ isSignedIn,
172
+ redirectUrl
173
+ ]);
174
+ return null;
175
+ }
176
+ //#endregion
177
+ //#region src/buttons.tsx
178
+ /** Wraps its single child (or renders a plain button) and wires the click. Unstyled by design. */
179
+ function Trigger(props) {
180
+ const child = Children.count(props.children) === 1 ? Children.only(props.children) : null;
181
+ if (isValidElement(child)) {
182
+ const original = child.props.onClick;
183
+ return cloneElement(child, { onClick: (event) => {
184
+ original?.(event);
185
+ if (!event.defaultPrevented) props.onClick();
186
+ } });
187
+ }
188
+ return /* @__PURE__ */ jsx("button", {
189
+ type: "button",
190
+ onClick: props.onClick,
191
+ children: props.children ?? props.label
192
+ });
193
+ }
194
+ function SignInButton(props) {
195
+ const zautha = useZautha();
196
+ const options = props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl };
197
+ return /* @__PURE__ */ jsx(Trigger, {
198
+ label: "Sign in",
199
+ onClick: () => props.mode === "modal" ? zautha?.openSignIn(options) : zautha?.redirectToSignIn(options),
200
+ children: props.children
201
+ });
202
+ }
203
+ function SignUpButton(props) {
204
+ const zautha = useZautha();
205
+ const options = props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl };
206
+ return /* @__PURE__ */ jsx(Trigger, {
207
+ label: "Sign up",
208
+ onClick: () => props.mode === "modal" ? zautha?.openSignUp(options) : zautha?.redirectToSignUp(options),
209
+ children: props.children
210
+ });
211
+ }
212
+ function SignOutButton(props) {
213
+ const zautha = useZautha();
214
+ return /* @__PURE__ */ jsx(Trigger, {
215
+ label: "Sign out",
216
+ onClick: () => void zautha?.signOut(props.redirectUrl === void 0 ? {} : { redirectUrl: props.redirectUrl }),
217
+ children: props.children
218
+ });
219
+ }
220
+ //#endregion
221
+ //#region src/prebuilt.tsx
222
+ /**
223
+ * Mounts a @zautha/ui component into a div once the instance exists; later prop changes update it in
224
+ * place. SSR renders only the empty div.
225
+ */
226
+ function Mounted(props) {
227
+ const zautha = useZautha();
228
+ const ref = useRef(null);
229
+ const mountedWith = useRef(null);
230
+ const { name, componentProps } = props;
231
+ useEffect(() => {
232
+ const element = ref.current;
233
+ if (zautha === null || element === null) return;
234
+ zautha.mount(name, element, componentProps);
235
+ mountedWith.current = componentProps;
236
+ return () => {
237
+ mountedWith.current = null;
238
+ zautha.unmount(element);
239
+ };
240
+ }, [zautha, name]);
241
+ useEffect(() => {
242
+ const element = ref.current;
243
+ if (zautha === null || element === null || mountedWith.current === null || mountedWith.current === componentProps) return;
244
+ mountedWith.current = componentProps;
245
+ zautha.updateMounted(element, componentProps);
246
+ }, [zautha, componentProps]);
247
+ return /* @__PURE__ */ jsx("div", { ref });
248
+ }
249
+ function SignIn(props) {
250
+ return /* @__PURE__ */ jsx(Mounted, {
251
+ name: "SignIn",
252
+ componentProps: props
253
+ });
254
+ }
255
+ function SignUp(props) {
256
+ return /* @__PURE__ */ jsx(Mounted, {
257
+ name: "SignUp",
258
+ componentProps: props
259
+ });
260
+ }
261
+ function UserButton(props) {
262
+ return /* @__PURE__ */ jsx(Mounted, {
263
+ name: "UserButton",
264
+ componentProps: props
265
+ });
266
+ }
267
+ function OAuthConsent(props) {
268
+ return /* @__PURE__ */ jsx(Mounted, {
269
+ name: "OAuthConsent",
270
+ componentProps: props
271
+ });
272
+ }
273
+ //#endregion
274
+ export { OAuthConsent, RedirectToSignIn, RedirectToSignUp, Show, SignIn, SignInButton, SignOutButton, SignUp, SignUpButton, UserButton, ZauthaApiError, ZauthaDegraded, ZauthaError, ZauthaFailed, ZauthaLoaded, ZauthaLoading, ZauthaNetworkError, ZauthaOfflineError, ZauthaProvider, isZauthaApiError, isZauthaError, isZauthaNetworkError, isZauthaOfflineError, useAuth, useSession, useSignIn, useSignUp, useUser, useZautha };
275
+
276
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/provider.tsx","../src/hooks.ts","../src/control.tsx","../src/buttons.tsx","../src/prebuilt.tsx"],"sourcesContent":["import { Zautha, type ZauthaOptions, type ZauthaState } from \"@zautha/js\";\nimport { createContext, useContext, useEffect, useState, useSyncExternalStore, type ReactNode } from \"react\";\n\nconst ZauthaContext = createContext<Zautha | null | undefined>(undefined);\n\nexport interface ZauthaProviderProps extends Omit<ZauthaOptions, \"fetch\"> {\n publishableKey: string;\n children?: ReactNode;\n}\n\n/**\n * Creates the Zautha instance after mount (never during render, so StrictMode's double mount and SSR\n * create no timers or channels), loads it, and disposes it on unmount. Until then hooks report\n * `isLoaded: false`.\n */\nexport function ZauthaProvider({ publishableKey, children, ...options }: ZauthaProviderProps): ReactNode {\n const [zautha, setZautha] = useState<Zautha | null>(null);\n const { ui, appearance, localization, signInUrl, signUpUrl, navigate } = options;\n\n useEffect(() => {\n const instance = new Zautha(publishableKey, {\n ...(ui === undefined ? {} : { ui }),\n ...(appearance === undefined ? {} : { appearance }),\n ...(localization === undefined ? {} : { localization }),\n ...(signInUrl === undefined ? {} : { signInUrl }),\n ...(signUpUrl === undefined ? {} : { signUpUrl }),\n ...(navigate === undefined ? {} : { navigate }),\n });\n // The instance is an external system: it is created here, never during render, and published through state.\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setZautha(instance);\n void instance.load();\n return () => {\n instance.dispose();\n setZautha(null);\n };\n // Appearance/localization objects are read at mount; changing the key re-creates the instance.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [publishableKey]);\n\n return <ZauthaContext.Provider value={zautha}>{children}</ZauthaContext.Provider>;\n}\n\n/** The Zautha instance, or null before the provider has created it. */\nexport function useZautha(): Zautha | null {\n const zautha = useContext(ZauthaContext);\n if (zautha === undefined) throw new Error(\"Zautha hooks and components must be used inside <ZauthaProvider>.\");\n return zautha;\n}\n\nconst NO_STATE: ZauthaState = { status: \"loading\", environment: null, client: null, session: null, user: null };\nconst noop = (): (() => void) => () => undefined;\n\n/** Reactive snapshot of the instance state (the loading state before the instance exists). */\nexport function useZauthaState(): ZauthaState {\n const zautha = useZautha();\n return useSyncExternalStore(\n zautha?.subscribe ?? noop,\n () => zautha?.getSnapshot() ?? NO_STATE,\n () => NO_STATE,\n );\n}\n","import type { AttemptErrors, FetchStatus, Session, SignInResource, SignUpResource, User } from \"@zautha/js\";\nimport { useCallback, useSyncExternalStore } from \"react\";\nimport { useZautha, useZauthaState } from \"./provider\";\n\n/** Authorization check. In 3a there are no organization claims yet, so role/permission checks are false. */\nexport type HasParams = { role?: string; permission?: string };\nexport type Has = (params: HasParams) => boolean;\n\nexport interface UseAuthResult {\n isLoaded: boolean;\n isSignedIn: boolean;\n userId: string | null;\n sessionId: string | null;\n getToken: (options?: { skipCache?: boolean }) => Promise<string | null>;\n signOut: (options?: { redirectUrl?: string }) => Promise<void>;\n has: Has;\n}\n\nconst isLoadedStatus = (status: string): boolean => status === \"ready\" || status === \"degraded\";\n\nexport function useAuth(): UseAuthResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const getToken = useCallback(\n (options?: { skipCache?: boolean }) => zautha?.getToken(options) ?? Promise.resolve(null),\n [zautha],\n );\n const signOut = useCallback(\n (options?: { redirectUrl?: string }) => zautha?.signOut(options) ?? Promise.resolve(),\n [zautha],\n );\n const signedIn = state.session !== null;\n const has = useCallback<Has>(\n (params) => signedIn && params.role === undefined && params.permission === undefined,\n [signedIn],\n );\n return {\n isLoaded: isLoadedStatus(state.status),\n isSignedIn: signedIn,\n userId: state.session?.userId ?? null,\n sessionId: state.session?.id ?? null,\n getToken,\n signOut,\n has,\n };\n}\n\nexport function useUser(): { isLoaded: boolean; isSignedIn: boolean; user: User | null } {\n const state = useZauthaState();\n return { isLoaded: isLoadedStatus(state.status), isSignedIn: state.session !== null, user: state.user };\n}\n\nexport function useSession(): { isLoaded: boolean; isSignedIn: boolean; session: Session | null } {\n const state = useZauthaState();\n return { isLoaded: isLoadedStatus(state.status), isSignedIn: state.session !== null, session: state.session };\n}\n\nconst noopSubscribe = (): (() => void) => () => undefined;\n\nfunction useResource<T extends SignInResource | SignUpResource>(resource: T | null) {\n const snapshot = useSyncExternalStore(\n resource?.subscribe ?? noopSubscribe,\n () => resource?.snapshot ?? null,\n () => null,\n );\n return snapshot;\n}\n\nexport interface UseSignInResult {\n isLoaded: boolean;\n /** The sign-in resource; null until the provider has created the instance. */\n signIn: SignInResource | null;\n errors: AttemptErrors;\n fetchStatus: FetchStatus;\n}\n\nconst NO_ERRORS: AttemptErrors = { fields: {}, global: [] };\n\nexport function useSignIn(): UseSignInResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const snapshot = useResource(zautha?.signIn ?? null);\n return {\n isLoaded: isLoadedStatus(state.status),\n signIn: zautha?.signIn ?? null,\n errors: snapshot?.errors ?? NO_ERRORS,\n fetchStatus: snapshot?.fetchStatus ?? \"idle\",\n };\n}\n\nexport interface UseSignUpResult {\n isLoaded: boolean;\n signUp: SignUpResource | null;\n errors: AttemptErrors;\n fetchStatus: FetchStatus;\n}\n\nexport function useSignUp(): UseSignUpResult {\n const zautha = useZautha();\n const state = useZauthaState();\n const snapshot = useResource(zautha?.signUp ?? null);\n return {\n isLoaded: isLoadedStatus(state.status),\n signUp: zautha?.signUp ?? null,\n errors: snapshot?.errors ?? NO_ERRORS,\n fetchStatus: snapshot?.fetchStatus ?? \"idle\",\n };\n}\n","import { useEffect, type ReactNode } from \"react\";\nimport { useAuth, type Has, type HasParams } from \"./hooks\";\nimport { useZautha, useZauthaState } from \"./provider\";\n\nexport type ShowWhen = \"signed-in\" | \"signed-out\" | HasParams | ((has: Has) => boolean);\n\n/**\n * Renders `children` when the condition holds, else `fallback`. Renders nothing until Zautha has\n * loaded, so a signed-in user never sees a signed-out flash.\n */\nexport function Show(props: { when: ShowWhen; fallback?: ReactNode; children?: ReactNode }): ReactNode {\n const { isLoaded, isSignedIn, has } = useAuth();\n if (!isLoaded) return null;\n const { when } = props;\n const pass =\n when === \"signed-in\"\n ? isSignedIn\n : when === \"signed-out\"\n ? !isSignedIn\n : typeof when === \"function\"\n ? when(has)\n : has(when);\n return pass ? props.children : (props.fallback ?? null);\n}\n\nexport function ZauthaLoading(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"loading\" ? props.children : null;\n}\n\n/** Loaded, including degraded (network trouble after load: last known state is shown). */\nexport function ZauthaLoaded(props: { children?: ReactNode }): ReactNode {\n const { status } = useZauthaState();\n return status === \"ready\" || status === \"degraded\" ? props.children : null;\n}\n\nexport function ZauthaDegraded(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"degraded\" ? props.children : null;\n}\n\nexport function ZauthaFailed(props: { children?: ReactNode }): ReactNode {\n return useZauthaState().status === \"failed\" ? props.children : null;\n}\n\n/** Sends a signed-out visitor to sign-in once loaded; renders nothing. */\nexport function RedirectToSignIn(props: { redirectUrl?: string }): ReactNode {\n const zautha = useZautha();\n const { isLoaded, isSignedIn } = useAuth();\n const { redirectUrl } = props;\n useEffect(() => {\n if (zautha !== null && isLoaded && !isSignedIn)\n zautha.redirectToSignIn(redirectUrl === undefined ? {} : { redirectUrl });\n }, [zautha, isLoaded, isSignedIn, redirectUrl]);\n return null;\n}\n\nexport function RedirectToSignUp(props: { redirectUrl?: string }): ReactNode {\n const zautha = useZautha();\n const { isLoaded, isSignedIn } = useAuth();\n const { redirectUrl } = props;\n useEffect(() => {\n if (zautha !== null && isLoaded && !isSignedIn)\n zautha.redirectToSignUp(redirectUrl === undefined ? {} : { redirectUrl });\n }, [zautha, isLoaded, isSignedIn, redirectUrl]);\n return null;\n}\n","import { Children, cloneElement, isValidElement, type MouseEvent, type ReactElement, type ReactNode } from \"react\";\nimport { useZautha } from \"./provider\";\n\ninterface ButtonProps {\n /** `redirect` (default) goes to the sign-in page; `modal` opens the prebuilt component (needs `ui`). */\n mode?: \"redirect\" | \"modal\";\n redirectUrl?: string;\n children?: ReactNode;\n}\n\n/** Wraps its single child (or renders a plain button) and wires the click. Unstyled by design. */\nfunction Trigger(props: { children: ReactNode; label: string; onClick: () => void }): ReactNode {\n const child = Children.count(props.children) === 1 ? Children.only(props.children) : null;\n if (isValidElement<{ onClick?: (event: MouseEvent) => void }>(child)) {\n const original = child.props.onClick;\n return cloneElement(child as ReactElement<{ onClick?: (event: MouseEvent) => void }>, {\n onClick: (event: MouseEvent) => {\n original?.(event);\n if (!event.defaultPrevented) props.onClick();\n },\n });\n }\n return (\n <button type=\"button\" onClick={props.onClick}>\n {props.children ?? props.label}\n </button>\n );\n}\n\nexport function SignInButton(props: ButtonProps): ReactNode {\n const zautha = useZautha();\n const options = props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl };\n return (\n <Trigger\n label=\"Sign in\"\n onClick={() => (props.mode === \"modal\" ? zautha?.openSignIn(options) : zautha?.redirectToSignIn(options))}\n >\n {props.children}\n </Trigger>\n );\n}\n\nexport function SignUpButton(props: ButtonProps): ReactNode {\n const zautha = useZautha();\n const options = props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl };\n return (\n <Trigger\n label=\"Sign up\"\n onClick={() => (props.mode === \"modal\" ? zautha?.openSignUp(options) : zautha?.redirectToSignUp(options))}\n >\n {props.children}\n </Trigger>\n );\n}\n\nexport function SignOutButton(props: { redirectUrl?: string; children?: ReactNode }): ReactNode {\n const zautha = useZautha();\n return (\n <Trigger\n label=\"Sign out\"\n onClick={() => void zautha?.signOut(props.redirectUrl === undefined ? {} : { redirectUrl: props.redirectUrl })}\n >\n {props.children}\n </Trigger>\n );\n}\n","import type { UiComponentName } from \"@zautha/js\";\nimport { useEffect, useRef, type ReactNode } from \"react\";\nimport { useZautha } from \"./provider\";\n\n/**\n * Mounts a @zautha/ui component into a div once the instance exists; later prop changes update it in\n * place. SSR renders only the empty div.\n */\nfunction Mounted(props: { name: UiComponentName; componentProps: object }): ReactNode {\n const zautha = useZautha();\n const ref = useRef<HTMLDivElement>(null);\n const mountedWith = useRef<object | null>(null);\n const { name, componentProps } = props;\n\n useEffect(() => {\n const element = ref.current;\n if (zautha === null || element === null) return;\n zautha.mount(name, element, componentProps);\n mountedWith.current = componentProps;\n return () => {\n mountedWith.current = null;\n zautha.unmount(element);\n };\n // componentProps changes are applied by the effect below without remounting.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [zautha, name]);\n\n useEffect(() => {\n const element = ref.current;\n if (zautha === null || element === null || mountedWith.current === null || mountedWith.current === componentProps)\n return;\n mountedWith.current = componentProps;\n zautha.updateMounted(element, componentProps);\n }, [zautha, componentProps]);\n\n return <div ref={ref} />;\n}\n\n// Prop types live in @zautha/ui; they are structural here so @zautha/react has no runtime dependency on it.\nexport function SignIn(props: import(\"@zautha/ui\").SignInProps): ReactNode {\n return <Mounted name=\"SignIn\" componentProps={props} />;\n}\n\nexport function SignUp(props: import(\"@zautha/ui\").SignUpProps): ReactNode {\n return <Mounted name=\"SignUp\" componentProps={props} />;\n}\n\nexport function UserButton(props: import(\"@zautha/ui\").UserButtonProps): ReactNode {\n return <Mounted name=\"UserButton\" componentProps={props} />;\n}\n\nexport function OAuthConsent(props: import(\"@zautha/ui\").OAuthConsentProps): ReactNode {\n return <Mounted name=\"OAuthConsent\" componentProps={props} />;\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@zautha/react",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "React bindings for Zautha: provider, hooks, <Show>, buttons and prebuilt components.",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/hasanyalmanbas/zautha.git",
10
+ "directory": "web/packages/react"
11
+ },
12
+ "type": "module",
13
+ "sideEffects": false,
14
+ "exports": {
15
+ ".": {
16
+ "import": {
17
+ "types": "./dist/index.d.mts",
18
+ "default": "./dist/index.mjs"
19
+ },
20
+ "require": {
21
+ "types": "./dist/index.d.cts",
22
+ "default": "./dist/index.cjs"
23
+ }
24
+ }
25
+ },
26
+ "main": "./dist/index.cjs",
27
+ "module": "./dist/index.mjs",
28
+ "types": "./dist/index.d.cts",
29
+ "files": [
30
+ "dist",
31
+ "LICENSE"
32
+ ],
33
+ "dependencies": {
34
+ "@zautha/js": "^0.1.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^19.0.0",
38
+ "react-dom": "^19.0.0",
39
+ "@zautha/ui": "^0.1.0"
40
+ },
41
+ "devDependencies": {
42
+ "@size-limit/preset-small-lib": "14.0.1",
43
+ "@testing-library/react": "16.3.3",
44
+ "@testing-library/user-event": "14.6.7",
45
+ "@types/react": "19.3.0",
46
+ "@types/react-dom": "19.3.0",
47
+ "@zautha/ui": "0.1.0",
48
+ "happy-dom": "20.14.5",
49
+ "msw": "2.15.0",
50
+ "react": "19.3.0",
51
+ "react-dom": "19.3.0",
52
+ "size-limit": "14.0.1",
53
+ "tsdown": "0.23.0",
54
+ "typescript": "6.0.3",
55
+ "vitest": "5.0.2"
56
+ },
57
+ "size-limit": [
58
+ {
59
+ "path": "dist/index.mjs",
60
+ "limit": "4 kB",
61
+ "ignore": [
62
+ "react",
63
+ "react-dom",
64
+ "@zautha/js"
65
+ ]
66
+ }
67
+ ],
68
+ "peerDependenciesMeta": {
69
+ "@zautha/ui": {
70
+ "optional": true
71
+ }
72
+ },
73
+ "publishConfig": {
74
+ "access": "public"
75
+ },
76
+ "scripts": {
77
+ "build": "tsdown",
78
+ "typecheck": "tsc --noEmit",
79
+ "test": "vitest run",
80
+ "size": "size-limit"
81
+ }
82
+ }