najm-auth 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +79 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -830,6 +830,85 @@ const session = await serverAuth.requireRole(['admin', 'operator']);
830
830
  non-React consumers of `najm-auth` are unaffected. Importing it from a Client
831
831
  Component or the Edge runtime fails at build time.
832
832
 
833
+ ### `auth.ts` and `session.ts` cannot be merged
834
+
835
+ Two files looks like one too many until you try it. Both directions fail, for
836
+ the same reason in mirror image:
837
+
838
+ | Module | Must be reachable from | Must never be reachable from |
839
+ |---|---|---|
840
+ | the `defineAuth()` module | browser, Edge, server | — |
841
+ | the `createReactServerAuth()` module | server only | browser, Edge |
842
+
843
+ `auth.client` and `auth.api` are what Client Components call, and
844
+ `auth.middleware` is what the Edge proxy calls, so the `defineAuth()` module is
845
+ always in the browser and Edge graphs. The adapter must never be. Putting both
846
+ in one file puts the adapter everywhere `auth` already is, and the `browser`
847
+ export condition — which exists precisely to catch this — resolves to a module
848
+ that throws:
849
+
850
+ ```text
851
+ The export createReactServerAuth was not found in module
852
+ …/najm-auth/dist/client/server/reactClientGuard.js [app-client]
853
+
854
+ Import traces:
855
+ Middleware: ./src/lib/auth.ts → ./src/proxy.ts
856
+ Client Component Browser: ./src/lib/auth.ts → … → ./src/app/dashboard/page.tsx
857
+ Client Component SSR: ./src/lib/auth.ts → … → ./src/app/dashboard/page.tsx
858
+ Server Component: ./src/lib/auth.ts → ./src/lib/session.ts → layout.tsx
859
+ ```
860
+
861
+ Renaming the files changes nothing; there simply have to be two. This is a
862
+ property of the runtime boundary, not of the package.
863
+
864
+ ### Protected trees must opt out of prerendering
865
+
866
+ `requireSession()` reads a per-request cookie. A route Next.js tries to
867
+ prerender has no request, so the read fails and the guard reports a
868
+ configuration error — correct behavior, wrong context. Mark the protected
869
+ segment dynamic:
870
+
871
+ ```tsx
872
+ // src/app/(dashboard)/layout.tsx
873
+ export const dynamic = 'force-dynamic';
874
+
875
+ export default async function DashboardLayout({ children }) {
876
+ await serverAuth.requireSession();
877
+ return <Shell>{children}</Shell>;
878
+ }
879
+ ```
880
+
881
+ `getSession()` needs no such opt-out — it returns `null` rather than throwing,
882
+ so a prerendered public page renders anonymous. Do not "fix" a prerender failure
883
+ by wrapping a strict guard in `.catch(() => null)`; that turns a real outage
884
+ into a silently anonymous page.
885
+
886
+ ### What the app owns, what the package owns
887
+
888
+ | App, via `defineAuth()` | Package |
889
+ |---|---|
890
+ | `loginRoute`, `forbiddenRoute`, route matchers, `roleRoutes` | when to redirect where |
891
+ | cookie names, `apiBaseURL`, `authPrefix`, recovery URL | request memoization |
892
+ | `refreshThreshold`, `tabSync`, `verifyAlways` | strict vs optional semantics |
893
+ | — | `session.roles` / `user.role` fallback |
894
+ | — | error classification |
895
+
896
+ If a new app has to copy anything beyond the three files above, that logic
897
+ belongs in the package instead.
898
+
899
+ ### What a new app must prove
900
+
901
+ At its real Next.js production boundary, not with mocks:
902
+
903
+ - two concurrent renders never observe each other's session;
904
+ - root layout, nested layout, and page resolve once per render — measurable by
905
+ counting recovery round trips;
906
+ - anonymous navigation to a protected route redirects to `loginRoute`;
907
+ - an authenticated role mismatch reaches `forbiddenRoute` without a login loop;
908
+ - an unset session secret or an unreachable recovery endpoint stays a visible
909
+ failure rather than a login redirect;
910
+ - the Edge/proxy bundle builds without pulling in React.
911
+
833
912
  ---
834
913
 
835
914
  ## TypeScript Types
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-auth",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "Authentication and authorization library for najm framework",
5
5
  "type": "module",
6
6
  "files": [