sekisho 0.2.0 → 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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  <h1 align="center">⛩️ sekisho</h1>
2
2
  <p align="center"><sup>(関所, <em>historical checkpoint for travel and security</em> in Japanese)</sup></p>
3
- <p align="center">Authentication and Access Control for any React app ([online demo](https://sekisho-demo.pages.dev/login))</p>
3
+ <p align="center">Authentication and Access Control for any React app <a href="https://sekisho-demo.pages.dev" target="_blank">online demo</a></p>
4
4
 
5
5
  ----
6
6
 
@@ -61,38 +61,38 @@ export default function RootLayout({ children }: { children: React.ReactNode })
61
61
  }
62
62
  ```
63
63
 
64
- By default, `SekishoProvider` already includes `SekishoErrorBoundary` that will catch any `NotAuthenticatedError` thrown by `needLogin()` in the subtree. But if you have special error handling needs in certain parts of your app, you can also always import `SekishoErrorBoundary` directly to wrap those parts:
64
+ By default, `SekishoProvider` already includes `NotAuthenticatedBoundary` that will catch any `NotAuthenticatedError` thrown by `needLogin()` in the subtree. But if you have special error handling needs in certain parts of your app, you can also always import `NotAuthenticatedBoundary` directly to wrap those parts:
65
65
 
66
66
  ```tsx
67
- import { SekishoErrorBoundary } from 'sekisho';
67
+ import { NotAuthenticatedBoundary } from 'sekisho';
68
68
 
69
69
  function SomePartOfApp() {
70
70
  return (
71
- <SekishoErrorBoundary>
71
+ <NotAuthenticatedBoundary>
72
72
  {/* ... */}
73
- </SekishoErrorBoundary>
73
+ </NotAuthenticatedBoundary>
74
74
  );
75
75
  }
76
76
  ```
77
77
 
78
- And if you are using Next.js App Router and `error.tsx` file, due to Next.js layout, page, and error boundary heirarchy, you will also need to wrap the `error.tsx` with `SekishoErrorWrapper`:
78
+ And if you are using Next.js App Router and `error.tsx` file, due to Next.js layout, page, and error boundary heirarchy, you will also need to wrap the `error.tsx` with `NotAuthenticatedErrorWrapper`:
79
79
 
80
80
  ```tsx
81
81
  // app/error.tsx
82
82
  'use client';
83
83
 
84
- import { SekishoErrorWrapper } from 'sekisho';
84
+ import { NotAuthenticatedErrorWrapper } from 'sekisho';
85
85
 
86
86
  export default function ErrorPage({ error, reset }) {
87
87
  return (
88
- <SekishoErrorWrapper error={error}>
88
+ <NotAuthenticatedErrorWrapper error={error}>
89
89
  {/* Your existing error UI goes in here */}
90
- </SekishoErrorWrapper>
90
+ </NotAuthenticatedErrorWrapper>
91
91
  );
92
92
  }
93
93
  ```
94
94
 
95
- > `SekishoErrorWrapper` is actually used by `SekishoErrorBoundary` internally, containing all the core logic.
95
+ > `NotAuthenticatedErrorWrapper` is actually used by `NotAuthenticatedBoundary` internally, containing all the core logic.
96
96
 
97
97
  ### Triggering a login redirect
98
98
 
@@ -133,10 +133,10 @@ export const requireAuthMiddleware: Middleware = (useSWRNext) => (key, fetcher,
133
133
 
134
134
  ### Restricting access
135
135
 
136
- Wrap any part of the UI with `SekishoAccessContainer` and call `accessRestricted()` inside it when the user lacks the required role or permission. Unlike `needLogin()`, which triggers a global redirect via `onNeedLogin`, `accessRestricted()` is local — `SekishoAccessContainer` simply renders `fallback` in place of its children:
136
+ Wrap any part of the UI with `AccessRestrictedContainer` and call `accessRestricted()` inside it when the user lacks the required role or permission. Unlike `needLogin()`, which triggers a global redirect via `onNeedLogin`, `accessRestricted()` is local — `AccessRestrictedContainer` simply renders `fallback` in place of its children:
137
137
 
138
138
  ```tsx
139
- import { accessRestricted, SekishoAccessContainer } from 'sekisho';
139
+ import { accessRestricted, AccessRestrictedContainer } from 'sekisho';
140
140
 
141
141
  function AdminPanel() {
142
142
  const { role } = useCurrentUser();
@@ -150,16 +150,16 @@ function AdminPanel() {
150
150
 
151
151
  function Page() {
152
152
  return (
153
- <SekishoAccessContainer
153
+ <AccessRestrictedContainer
154
154
  fallback={<p>You don't have permission to view this section.</p>}
155
155
  >
156
156
  <AdminPanel />
157
- </SekishoAccessContainer>
157
+ </AccessRestrictedContainer>
158
158
  );
159
159
  }
160
160
  ```
161
161
 
162
- This kinda like `<Suspense />` but for access control instead. And like `<Suspense />`, you can have multiple `SekishoAccessContainer`s nested independently — each one only catches the `accessRestricted()` calls within its own subtree.
162
+ This kinda like `<Suspense />` but for access control instead. And like `<Suspense />`, you can have multiple `AccessRestrictedContainer`s nested independently — each one only catches the `accessRestricted()` calls within its own subtree.
163
163
 
164
164
  ## Explanation
165
165
 
@@ -167,12 +167,12 @@ Sekisho is built on top of React's error boundaries. Both `needLogin()` and `acc
167
167
 
168
168
  | Function | Error thrown | Caught by | Behaviour |
169
169
  |---|---|---|---|
170
- | `needLogin()` | `NotAuthenticatedError` | `SekishoErrorBoundary` / `SekishoErrorWrapper` | Calls `onNeedLogin` from `SekishoProvider` (global redirect) |
171
- | `accessRestricted()` | `AccessRestrictedError` | `SekishoAccessContainer` | Renders the `fallback` prop in place of children (local swap) |
170
+ | `needLogin()` | `NotAuthenticatedError` | `NotAuthenticatedBoundary` / `NotAuthenticatedErrorWrapper` | Calls `onNeedLogin` from `SekishoProvider` (global redirect) |
171
+ | `accessRestricted()` | `AccessRestrictedError` | `AccessRestrictedContainer` | Renders the `fallback` prop in place of children (local swap) |
172
172
 
173
- Each boundary re-throws errors it does not own, so `SekishoAccessContainer` never swallows an auth error, and `SekishoErrorBoundary` never swallows an access error. Your own error boundaries are unaffected by either.
173
+ Each boundary re-throws errors it does not own, so `AccessRestrictedContainer` never swallows an auth error, and `NotAuthenticatedBoundary` never swallows an access error. Your own error boundaries are unaffected by either.
174
174
 
175
- With `SekishoErrorWrapper` / `SekishoErrorBoundary` you can create protected and unprotected routes in any React app:
175
+ With `NotAuthenticatedErrorWrapper` / `NotAuthenticatedBoundary` you can create protected and unprotected routes in any React app:
176
176
 
177
177
  **Next.js App Router**
178
178
 
@@ -180,7 +180,7 @@ With `SekishoErrorWrapper` / `SekishoErrorBoundary` you can create protected and
180
180
  app/
181
181
  ├── (protected)/ ← all protected routes goes under here
182
182
  │ ├── layout.tsx ← wrap children with <SekishoProvider> here
183
- │ ├── error.tsx ← wrap with <SekishoErrorWrapper> here
183
+ │ ├── error.tsx ← wrap with <NotAuthenticatedErrorWrapper> here
184
184
  │ └── page.tsx ← homepage, where you call needLogin() when authentication is needed
185
185
  ├── (unprotected)/ ← all unprotected routes goes under here
186
186
  │ └── login/
@@ -206,9 +206,9 @@ const router = createBrowserRouter([
206
206
  {
207
207
  component() {
208
208
  return (
209
- <SekishoErrorBoundary>
209
+ <NotAuthenticatedBoundary>
210
210
  <Outlet />
211
- </SekishoErrorBoundary>
211
+ </NotAuthenticatedBoundary>
212
212
  );
213
213
  },
214
214
  children: [
@@ -221,6 +221,53 @@ const router = createBrowserRouter([
221
221
  ]);
222
222
  ```
223
223
 
224
+ ## Build your own guard
225
+
226
+ Sekisho also provides a low-level abstraction `createSekisho` from `sekisho/factory` for building your own custom gate with the same underlying mechanism. Let's say you want to build a guard for new user onboarding flow, where users need to complete their profile before accessing certain parts of the app:
227
+
228
+ ```tsx
229
+ import { createSekisho } from 'sekisho/factory';
230
+
231
+ const [requireOnboarding, OnboardingGate] = createSekisho('OnboardingRequired');
232
+
233
+ function Dashboard() {
234
+ const user = useUser();
235
+
236
+ if (!user.profileComplete) {
237
+ requireOnboarding('Profile incomplete');
238
+ }
239
+
240
+ // actual dashboard content
241
+ return <div>Welcome back, {user.name}</div>;
242
+ }
243
+
244
+ function OnboardingGuard({ error }) {
245
+ redirect('/onboarding');
246
+ }
247
+
248
+ // Wrap your app with the boundary component
249
+ function Page() {
250
+ return (
251
+ <OnboardingGate
252
+ fallback={<OnboardingGuard />}
253
+ // or you can pass a component that receives the error prop
254
+ fallbackComponent={OnboardingGuard}
255
+ >
256
+ <Dashboard />
257
+ </OnboardingGate>
258
+ );
259
+ }
260
+ ```
261
+
262
+ The `createSekisho()` factory returns a 4-tuple: `[throwFn, BoundaryComponent, isError, ErrorClass]`. You can name each element whatever makes sense for your use case:
263
+
264
+ - **`throwFn`** — Call this during render to trigger the guard when a condition is unmet
265
+ - **`BoundaryComponent`** — Error boundary that catches errors thrown by `throwFn`. Accepts `fallback` (static UI) or `fallbackComponent` (component that receives `{ error }`)
266
+ - **`isError`** — Type guard to check if an error is from this guard (useful in middleware or error handlers)
267
+ - **`ErrorClass`** — The error constructor, if you need `instanceof` checks
268
+
269
+ Each call to `createSekisho()` is isolated — guards never accidentally catch each other's errors, even if nested.
270
+
224
271
  ## License
225
272
 
226
273
  [MIT](LICENSE)
@@ -0,0 +1 @@
1
+ "use client";Object.defineProperty(exports,"__esModule",{value:!0});var r=require("react/jsx-runtime"),e=require("foxact/create-stackless-error"),t=require("react");exports.createSekisho=function(s){let o=new WeakSet;class n extends Error{constructor(r){super(r),this.digest="BAILOUT_TO_CLIENT_SIDE_RENDERING",this.name=s??"SekishoGuardError",o.add(this)}}function a(r){return!!r&&"object"==typeof r&&o.has(r)}class c extends t.Component{constructor(r){super(r),this.state={caughtError:null}}static getDerivedStateFromError(r){if(a(r))return{caughtError:r};throw r}render(){let{caughtError:e}=this.state;if(null!==e){let{fallback:t,fallbackComponent:s}=this.props;return s?r.jsx(s,{error:e}):t}return this.props.children}}return[function(r){throw e.createStacklessError(()=>new n(r))},c,a,n]};
@@ -0,0 +1,65 @@
1
+ /** Base interface for every guard error created by `createSekisho`. */
2
+ interface SekishoGuardError extends Error {
3
+ readonly digest: 'BAILOUT_TO_CLIENT_SIDE_RENDERING';
4
+ }
5
+ /**
6
+ * Props accepted by the boundary component returned from `createSekisho`.
7
+ *
8
+ * Exactly one of `fallback` or `fallbackComponent` must be provided:
9
+ *
10
+ * - `fallback` — a static `ReactNode` rendered in place of children when the
11
+ * guard fires (access-control pattern).
12
+ * - `fallbackComponent` — a React component that receives `{ error }` as props.
13
+ * Use this when you need the caught error object, e.g. to trigger a
14
+ * navigation side-effect (auth pattern).
15
+ */
16
+ type SekishoGuardBoundaryProps = React.PropsWithChildren & ({
17
+ fallback: React.ReactNode;
18
+ fallbackComponent?: never;
19
+ } | {
20
+ fallback?: never;
21
+ fallbackComponent: React.ComponentType<{
22
+ error: SekishoGuardError;
23
+ }>;
24
+ });
25
+ interface SekishoGuardBoundaryState {
26
+ caughtError: SekishoGuardError | null;
27
+ }
28
+ /**
29
+ * Creates a paired guard throw function, error boundary component, type guard,
30
+ * and error class — all isolated from every other guard in the tree.
31
+ *
32
+ * Call the returned throw function anywhere in the React render phase to signal
33
+ * that a condition is unmet. The nearest boundary component in the tree will
34
+ * catch it and render its `fallback` prop instead of `children`. Every other
35
+ * error boundary — including ones from other `createSekisho()` calls —
36
+ * re-throws the error unchanged.
37
+ *
38
+ * Returns a 4-tuple so each element can be named freely on destructure:
39
+ * `[throwFn, BoundaryComponent, isError, ErrorClass]`
40
+ *
41
+ * @example
42
+ * // Access-control pattern — static fallback element:
43
+ * const [requireOnboarding, OnboardingGate] = createSekisho();
44
+ *
45
+ * <OnboardingGate fallback={<OnboardingWizard />}>
46
+ * <Profile />
47
+ * </OnboardingGate>
48
+ *
49
+ * @example
50
+ * // Callback pattern — component receives the error object:
51
+ * const [requireAuth, AuthGate] = createSekisho();
52
+ *
53
+ * <AuthGate fallbackComponent={AuthErrorHandler}>
54
+ * <Dashboard />
55
+ * </AuthGate>
56
+ */
57
+ declare function createSekisho(errorName?: string): [
58
+ throwError: (message: string) => never,
59
+ BoundaryComponent: React.ComponentClass<SekishoGuardBoundaryProps, SekishoGuardBoundaryState>,
60
+ isError: (error: unknown) => error is SekishoGuardError,
61
+ ErrorClass: new (message: string) => SekishoGuardError
62
+ ];
63
+
64
+ export { createSekisho };
65
+ export type { SekishoGuardBoundaryProps, SekishoGuardBoundaryState, SekishoGuardError };
@@ -0,0 +1 @@
1
+ "use client";import{jsx as r}from"react/jsx-runtime";import{createStacklessError as t}from"foxact/create-stackless-error";import{Component as e}from"react";function o(o){let s=new WeakSet;class n extends Error{constructor(r){super(r),this.digest="BAILOUT_TO_CLIENT_SIDE_RENDERING",this.name=o??"SekishoGuardError",s.add(this)}}function i(r){return!!r&&"object"==typeof r&&s.has(r)}return[function(r){throw t(()=>new n(r))},class extends e{constructor(r){super(r),this.state={caughtError:null}}static getDerivedStateFromError(r){if(i(r))return{caughtError:r};throw r}render(){let{caughtError:t}=this.state;if(null!==t){let{fallback:e,fallbackComponent:o}=this.props;return o?r(o,{error:t}):e}return this.props.children}},i,n]}export{o as createSekisho};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use client";Object.defineProperty(exports,"__esModule",{value:!0});var r=require("foxact/use-isomorphic-layout-effect"),e=require("foxact/nullthrow"),t=require("react"),s=require("foxact/use-stable-handler-only-when-you-know-what-you-are-doing-or-you-will-be-fired"),o=require("react/jsx-runtime");let i=Object.getOwnPropertyDescriptor(Error,"stackTraceLimit"),n=i?.writable&&"number"==typeof i.value;function c(r){let e=Error.stackTraceLimit;n&&(Error.stackTraceLimit=0);let t=r();return n&&(Error.stackTraceLimit=e),t}class u extends Error{constructor(...r){super(...r),this.name="NotAuthenticatedError",this.notAuthenticated=!0,this.$sekishoError=!0}}function a(r){return!!r&&"object"==typeof r&&"notAuthenticated"in r&&!0===r.notAuthenticated&&"$sekishoError"in r&&!0===r.$sekishoError}let h=t.createContext(null);function d({error:o,children:i}){let{onNeedLogin:n}=e.nullthrow(t.useContext(h),"useSekishoOptions must be used within a SekishoOptionsProvider"),c=a(o),u=s.useStableHandler(n);return(r.useLayoutEffect(()=>{c&&u()},[c,u]),c)?null:i}class l extends t.Component{constructor(r){super(r),this.state={needLoginErrorObject:null}}static getDerivedStateFromError(r){if(a(r))return{needLoginErrorObject:r};throw r}render(){return this.state.needLoginErrorObject?o.jsx(d,{error:this.state.needLoginErrorObject,children:this.props.children}):this.props.children}}class p extends Error{constructor(...r){super(...r),this.name="AccessRestrictedError",this.accessRestricted=!0,this.$sekishoError=!0}}function E(r){return!!r&&"object"==typeof r&&"accessRestricted"in r&&!0===r.accessRestricted&&"$sekishoError"in r&&!0===r.$sekishoError}class x extends t.Component{constructor(r){super(r),this.state={restricted:!1}}static getDerivedStateFromError(r){if(E(r))return{restricted:!0};throw r}render(){return this.state.restricted?this.props.fallback:this.props.children}}exports.AccessRestrictedError=p,exports.NotAuthenticatedError=u,exports.SekishoAccessContainer=x,exports.SekishoErrorBoundary=l,exports.SekishoErrorWrapper=d,exports.SekishoProvider=function({children:r,...e}){return o.jsx(h.Provider,{value:e,children:o.jsx(l,{children:r})})},exports.accessRestricted=function(r){throw c(()=>new p(r))},exports.isAccessRestrictedError=E,exports.isNeedLoginError=a,exports.needLogin=function(r){throw c(()=>new u(r))};
1
+ "use client";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react/jsx-runtime"),r=require("foxact/use-isomorphic-layout-effect"),t=require("foxact/use-stable-handler-only-when-you-know-what-you-are-doing-or-you-will-be-fired"),o=require("./factory.cjs"),s=require("foxact/nullthrow"),i=require("react");let n=i.createContext(null),[c,u,a,l]=o.createSekisho("NotAuthenticatedError");function d({error:e,children:o}){let{onNeedLogin:c}=s.nullthrow(i.useContext(n),"useSekishoOptions must be used within a SekishoOptionsProvider"),u=a(e),l=t.useStableHandler(c);return(r.useLayoutEffect(()=>{u&&l()},[u,l]),u)?null:o}function p({children:r}){return e.jsx(u,{fallbackComponent:d,children:r})}let[h,x,f,k]=o.createSekisho("AccessRestrictedError");Object.defineProperty(exports,"createSekisho",{enumerable:!0,get:function(){return o.createSekisho}}),exports.AccessRestrictedContainer=x,exports.AccessRestrictedError=k,exports.NotAuthenticatedBoundary=p,exports.NotAuthenticatedError=l,exports.NotAuthenticatedErrorWrapper=d,exports.SekishoAccessContainer=x,exports.SekishoErrorBoundary=p,exports.SekishoErrorWrapper=d,exports.SekishoProvider=function({children:r,...t}){return e.jsx(n.Provider,{value:t,children:e.jsx(p,{children:r})})},exports.accessRestricted=h,exports.isAccessRestrictedError=f,exports.isNeedLoginError=a,exports.needLogin=c;
package/dist/index.d.ts CHANGED
@@ -1,46 +1,39 @@
1
1
  import * as react from 'react';
2
- import { Component } from 'react';
2
+ import * as __factory from './factory.js';
3
+ import { SekishoGuardBoundaryProps } from './factory.js';
4
+ export { SekishoGuardBoundaryProps, SekishoGuardBoundaryState, SekishoGuardError, createSekisho } from './factory.js';
3
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
6
 
5
- declare class NotAuthenticatedError extends Error {
6
- readonly name = "NotAuthenticatedError";
7
- readonly notAuthenticated = true;
8
- readonly $sekishoError = true;
7
+ declare const needLogin: (message: string) => never;
8
+ declare const isNeedLoginError: (error: unknown) => error is __factory.SekishoGuardError;
9
+ declare const NotAuthenticatedError: new (message: string) => __factory.SekishoGuardError;
10
+
11
+ interface NotAuthenticatedErrorWrapperProps extends React.PropsWithChildren {
12
+ error: unknown | null | undefined;
9
13
  }
10
- declare function isNeedLoginError(error: unknown): error is NotAuthenticatedError;
14
+ /** @deprecated `SekishoErrorWrapperProps` has since been renamed to `NotAuthenticatedErrorWrapperProps` */
15
+ type SekishoErrorWrapperProps = NotAuthenticatedErrorWrapperProps;
11
16
  /**
12
- * Throw a `NotAuthenticatedError` from anywhere in the React render phase.
13
- *
14
- * The error is caught by the nearest `SekishoErrorWrapper` or
15
- * `SekishoErrorBoundary`, which then calls the `onNeedLogin` callback supplied
16
- * to `SekishoProvider`.
17
+ * The actual error handling and redirection logic for "Not Authenticated" error.
17
18
  *
18
- * Common call sites: ky afterResponse hooks (HTTP 401), SWR middleware, or
19
- * directly inside a component when session state is absent.
19
+ * Used internally by `NotAuthenticatedBoundary`. You can also use this directly in
20
+ * a Next.js `app/error.tsx` file for custom error handling.
20
21
  */
21
- declare function needLogin(message: string): never;
22
+ declare function NotAuthenticatedErrorWrapper({ error, children }: NotAuthenticatedErrorWrapperProps): react.ReactNode;
22
23
 
23
- interface SekishoErrorWrapperProps extends React.PropsWithChildren {
24
- error: unknown | null | undefined;
24
+ interface NotAuthenticatedBoundaryProps extends React.PropsWithChildren {
25
25
  }
26
26
  /**
27
- * The actual error handling and redirection logic for "Not Authenticated" error
27
+ * Error boundary that catches `NotAuthenticatedError` thrown by `needLogin()`
28
+ * within its subtree and calls the `onNeedLogin` callback from `SekishoProvider`.
29
+ * All other errors are re-thrown to the next boundary up the tree.
28
30
  *
29
- * This is used internally by SekishoErrorBoundary. And if you are using Next.js App Router,
30
- * you can use this directly in the "error.tsx" file.
31
+ * This is included inside `SekishoProvider` automatically; you only need to use
32
+ * it directly if you want a narrower boundary for a specific subtree.
31
33
  */
32
- declare function SekishoErrorWrapper({ error, children }: SekishoErrorWrapperProps): react.ReactNode;
33
-
34
- interface SekishoErrorBoundaryProps extends React.PropsWithChildren {
35
- }
36
- interface SekishoErrorBoundaryState {
37
- needLoginErrorObject: unknown | null | undefined;
38
- }
39
- declare class SekishoErrorBoundary extends Component<SekishoErrorBoundaryProps, SekishoErrorBoundaryState> {
40
- constructor(props: SekishoErrorBoundaryProps);
41
- static getDerivedStateFromError(this: void, error: unknown): SekishoErrorBoundaryState;
42
- render(): React.ReactNode;
43
- }
34
+ declare function NotAuthenticatedBoundary({ children }: NotAuthenticatedBoundaryProps): React.ReactNode;
35
+ /** @deprecated `SekishoErrorBoundaryProps` has since been renamed to `NotAuthenticatedBoundaryProps` */
36
+ type SekishoErrorBoundaryProps = NotAuthenticatedBoundaryProps;
44
37
 
45
38
  interface SekishoOptions {
46
39
  onNeedLogin: () => void;
@@ -50,37 +43,15 @@ interface SekishoProviderProps extends React.PropsWithChildren, SekishoOptions {
50
43
  }
51
44
  declare function SekishoProvider({ children, ...auth }: SekishoProviderProps): react_jsx_runtime.JSX.Element;
52
45
 
53
- declare class AccessRestrictedError extends Error {
54
- readonly name = "AccessRestrictedError";
55
- readonly accessRestricted = true;
56
- readonly $sekishoError = true;
57
- }
58
- declare function isAccessRestrictedError(error: unknown): error is AccessRestrictedError;
59
- /**
60
- * Throw an `AccessRestrictedError` from anywhere in the React render phase.
61
- *
62
- * The error is caught by the nearest `SekishoAccessContainer`, which renders
63
- * its `fallback` prop instead of its children. Any other error boundary in the
64
- * tree (including `SekishoErrorBoundary`) re-throws it unchanged.
65
- */
66
- declare function accessRestricted(message: string): never;
67
-
68
- interface SekishoAccessContainerProps extends React.PropsWithChildren {
69
- fallback: React.ReactNode;
70
- }
71
- interface State {
72
- restricted: boolean;
73
- }
74
- /**
75
- * Error boundary that catches `AccessRestrictedError` thrown by
76
- * `accessRestricted()` within its subtree and renders `fallback` in place of
77
- * `children`. All other errors are re-thrown to the next boundary up the tree.
78
- */
79
- declare class SekishoAccessContainer extends Component<SekishoAccessContainerProps, State> {
80
- constructor(props: SekishoAccessContainerProps);
81
- static getDerivedStateFromError(this: void, error: unknown): State;
82
- render(): React.ReactNode;
83
- }
84
-
85
- export { AccessRestrictedError, NotAuthenticatedError, SekishoAccessContainer, SekishoErrorBoundary, SekishoErrorWrapper, SekishoProvider, accessRestricted, isAccessRestrictedError, isNeedLoginError, needLogin };
86
- export type { SekishoAccessContainerProps, SekishoErrorBoundaryProps, SekishoErrorWrapperProps, SekishoOptions, SekishoProviderProps };
46
+ declare const accessRestricted: (message: string) => never;
47
+ declare const AccessRestrictedContainer: react.ComponentClass<SekishoGuardBoundaryProps, __factory.SekishoGuardBoundaryState>;
48
+ declare const isAccessRestrictedError: (error: unknown) => error is __factory.SekishoGuardError;
49
+ declare const AccessRestrictedError: new (message: string) => __factory.SekishoGuardError;
50
+ type AccessRestrictedContainerProps = SekishoGuardBoundaryProps;
51
+ /** @deprecated `SekishoAccessContainer` has since been renamed to `AccessRestrictedContainer` */
52
+ declare const SekishoAccessContainer: react.ComponentClass<SekishoGuardBoundaryProps, __factory.SekishoGuardBoundaryState>;
53
+ /** @deprecated `SekishoAccessContainerProps` has since been renamed to `AccessRestrictedContainerProps` */
54
+ type SekishoAccessContainerProps = AccessRestrictedContainerProps;
55
+
56
+ export { AccessRestrictedContainer, AccessRestrictedError, NotAuthenticatedBoundary, NotAuthenticatedError, NotAuthenticatedErrorWrapper, SekishoAccessContainer, NotAuthenticatedBoundary as SekishoErrorBoundary, NotAuthenticatedErrorWrapper as SekishoErrorWrapper, SekishoProvider, accessRestricted, isAccessRestrictedError, isNeedLoginError, needLogin };
57
+ export type { AccessRestrictedContainerProps, NotAuthenticatedBoundaryProps, NotAuthenticatedErrorWrapperProps, SekishoAccessContainerProps, SekishoErrorBoundaryProps, SekishoErrorWrapperProps, SekishoOptions, SekishoProviderProps };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- "use client";import{useLayoutEffect as r}from"foxact/use-isomorphic-layout-effect";import{nullthrow as e}from"foxact/nullthrow";import{createContext as t,useContext as o,Component as s}from"react";import{useStableHandler as i}from"foxact/use-stable-handler-only-when-you-know-what-you-are-doing-or-you-will-be-fired";import{jsx as n}from"react/jsx-runtime";let c=Object.getOwnPropertyDescriptor(Error,"stackTraceLimit"),a=c?.writable&&"number"==typeof c.value;function h(r){let e=Error.stackTraceLimit;a&&(Error.stackTraceLimit=0);let t=r();return a&&(Error.stackTraceLimit=e),t}class u extends Error{constructor(...r){super(...r),this.name="NotAuthenticatedError",this.notAuthenticated=!0,this.$sekishoError=!0}}function d(r){return!!r&&"object"==typeof r&&"notAuthenticated"in r&&!0===r.notAuthenticated&&"$sekishoError"in r&&!0===r.$sekishoError}function l(r){throw h(()=>new u(r))}let p=t(null);function E({error:t,children:s}){let{onNeedLogin:n}=e(o(p),"useSekishoOptions must be used within a SekishoOptionsProvider"),c=d(t),a=i(n);return(r(()=>{c&&a()},[c,a]),c)?null:s}class f extends s{constructor(r){super(r),this.state={needLoginErrorObject:null}}static getDerivedStateFromError(r){if(d(r))return{needLoginErrorObject:r};throw r}render(){return this.state.needLoginErrorObject?n(E,{error:this.state.needLoginErrorObject,children:this.props.children}):this.props.children}}function m({children:r,...e}){return n(p.Provider,{value:e,children:n(f,{children:r})})}class k extends Error{constructor(...r){super(...r),this.name="AccessRestrictedError",this.accessRestricted=!0,this.$sekishoError=!0}}function w(r){return!!r&&"object"==typeof r&&"accessRestricted"in r&&!0===r.accessRestricted&&"$sekishoError"in r&&!0===r.$sekishoError}function b(r){throw h(()=>new k(r))}class g extends s{constructor(r){super(r),this.state={restricted:!1}}static getDerivedStateFromError(r){if(w(r))return{restricted:!0};throw r}render(){return this.state.restricted?this.props.fallback:this.props.children}}export{k as AccessRestrictedError,u as NotAuthenticatedError,g as SekishoAccessContainer,f as SekishoErrorBoundary,E as SekishoErrorWrapper,m as SekishoProvider,b as accessRestricted,w as isAccessRestrictedError,d as isNeedLoginError,l as needLogin};
1
+ "use client";import{jsx as r}from"react/jsx-runtime";import{useLayoutEffect as e}from"foxact/use-isomorphic-layout-effect";import{useStableHandler as t}from"foxact/use-stable-handler-only-when-you-know-what-you-are-doing-or-you-will-be-fired";import{createSekisho as o}from"./factory.mjs";export{createSekisho}from"./factory.mjs";import{nullthrow as i}from"foxact/nullthrow";import{createContext as n,useContext as c}from"react";let s=n(null),[a,u,d,h]=o("NotAuthenticatedError");function l({error:r,children:o}){let{onNeedLogin:n}=i(c(s),"useSekishoOptions must be used within a SekishoOptionsProvider"),a=d(r),u=t(n);return(e(()=>{a&&u()},[a,u]),a)?null:o}function f({children:e}){return r(u,{fallbackComponent:l,children:e})}function m({children:e,...t}){return r(s.Provider,{value:t,children:r(f,{children:e})})}let[p,A,y,E]=o("AccessRestrictedError"),k=A;export{A as AccessRestrictedContainer,E as AccessRestrictedError,f as NotAuthenticatedBoundary,h as NotAuthenticatedError,l as NotAuthenticatedErrorWrapper,k as SekishoAccessContainer,f as SekishoErrorBoundary,l as SekishoErrorWrapper,m as SekishoProvider,p as accessRestricted,y as isAccessRestrictedError,d as isNeedLoginError,a as needLogin};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sekisho",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Authentication and Access Control for any React app",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,15 +21,21 @@
21
21
  "require": "./dist/index.cjs",
22
22
  "default": "./dist/index.cjs"
23
23
  },
24
+ "./factory": {
25
+ "types": "./dist/factory.d.ts",
26
+ "import": "./dist/factory.mjs",
27
+ "require": "./dist/factory.cjs",
28
+ "default": "./dist/factory.cjs"
29
+ },
24
30
  "./package.json": "./package.json"
25
31
  },
26
32
  "author": "Sukka <https://skk.moe>",
27
33
  "license": "MIT",
28
34
  "dependencies": {
29
- "foxact": "^0.3.0"
35
+ "foxact": "^0.3.1"
30
36
  },
31
37
  "devDependencies": {
32
- "@swc/core": "^1.15.30",
38
+ "@swc/core": "^1.15.33",
33
39
  "@types/react": "^19.2.14",
34
40
  "bunchee": "^6.10.0"
35
41
  },