najm-auth 6.0.0 → 6.2.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.
@@ -216,6 +216,22 @@ declare function useOAuthCallback(options?: UseOAuthCallbackOptions): {
216
216
  */
217
217
  declare function useAuthEvent<K extends AuthEvent>(event: K, handler: (data: AuthEventMap[K]) => void): void;
218
218
 
219
+ /**
220
+ * Sends the user to sign in when the session ends while a page is open.
221
+ *
222
+ * A server page checks the session only when it renders, so a session revoked
223
+ * or expired afterwards leaves the page up: every read then answers 401, and a
224
+ * list shows as empty instead of asking the user to sign in again.
225
+ *
226
+ * It is a full navigation, so the auth middleware can clear the dead cookies,
227
+ * and `from` brings the user back to this page afterwards, as the middleware's
228
+ * own redirect does. A normal sign-out emits `logout`, not `sessionExpired`,
229
+ * so the sign-out button keeps its own navigation.
230
+ *
231
+ * Mount it once, in the layout every signed-in page shares.
232
+ */
233
+ declare function useRedirectOnSessionExpired(loginRoute?: string): void;
234
+
219
235
  interface AuthEventEntry {
220
236
  event: AuthEvent;
221
237
  data: unknown;
@@ -600,4 +616,4 @@ interface OAuthCallbackProps {
600
616
  }
601
617
  declare function OAuthCallback({ fallback, errorFallback, defaultRedirect, }: OAuthCallbackProps): react.JSX.Element;
602
618
 
603
- export { AuthBoundary, type AuthEventEntry, AuthGate, AuthLoading, AuthProvider, Can, GitHubLoginButton, GoogleLoginButton, IfAuth, LoginButton, OAuthCallback, PermissionList, Protected, RedirectToLogin, Role, type SessionStatus, SignOutButton, SignedIn, SignedOut, UserAvatar, UserEmail, UserName, UserRole, useAuth, useAuthClient, useAuthEvent, useAuthEvents, useChangePassword, useForgotPassword, useGitHubLogin, useGoogleLogin, useLogin, useLogout, useOAuthCallback, usePermissions, useRegister, useResetPassword, useSession, useUser };
619
+ export { AuthBoundary, type AuthEventEntry, AuthGate, AuthLoading, AuthProvider, Can, GitHubLoginButton, GoogleLoginButton, IfAuth, LoginButton, OAuthCallback, PermissionList, Protected, RedirectToLogin, Role, type SessionStatus, SignOutButton, SignedIn, SignedOut, UserAvatar, UserEmail, UserName, UserRole, useAuth, useAuthClient, useAuthEvent, useAuthEvents, useChangePassword, useForgotPassword, useGitHubLogin, useGoogleLogin, useLogin, useLogout, useOAuthCallback, usePermissions, useRedirectOnSessionExpired, useRegister, useResetPassword, useSession, useUser };
@@ -431,6 +431,16 @@ function useAuthEvent(event, handler) {
431
431
  }
432
432
  __name(useAuthEvent, "useAuthEvent");
433
433
 
434
+ // src/client/react/useRedirectOnSessionExpired.ts
435
+ function useRedirectOnSessionExpired(loginRoute = "/login") {
436
+ useAuthEvent("sessionExpired", () => {
437
+ const login = new URL(loginRoute, window.location.origin);
438
+ login.searchParams.set("from", `${window.location.pathname}${window.location.search}`);
439
+ window.location.assign(login.toString());
440
+ });
441
+ }
442
+ __name(useRedirectOnSessionExpired, "useRedirectOnSessionExpired");
443
+
434
444
  // src/client/react/useAuthEvents.ts
435
445
  import { useEffect as useEffect4, useRef as useRef5, useState as useState12 } from "react";
436
446
  var ALL_EVENTS = [
@@ -845,6 +855,7 @@ export {
845
855
  useLogout,
846
856
  useOAuthCallback,
847
857
  usePermissions,
858
+ useRedirectOnSessionExpired,
848
859
  useRegister,
849
860
  useResetPassword,
850
861
  useSession,
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import * as najm_core from 'najm-core';
2
- import { Container } from 'najm-core';
1
+ import { NajmPlugin, Container } from 'najm-core';
3
2
  import { ValidationPluginConfig } from 'najm-validation';
4
3
  import { RateLimitPluginConfig, RateLimitKeyContext, TimeWindow } from 'najm-rate';
5
4
  import { CachePluginConfig, CacheService } from 'najm-cache';
@@ -315,20 +314,23 @@ type AuthPluginConfig = {
315
314
  * a user has a durable setup requirement.
316
315
  */
317
316
  credentialSetup?: CredentialSetupConfig;
318
- /** Optional config forwarded to validation() dependency */
317
+ /** Config for the validation() plugin auth registers when the application has none. */
319
318
  validation?: ValidationPluginConfig;
320
- /** Optional config forwarded to rateLimit() dependency */
319
+ /** Config for the rateLimit() plugin auth registers when the application has none. */
321
320
  rateLimit?: RateLimitPluginConfig;
322
321
  /**
323
- * Optional config forwarded to the package-owned cache() dependency.
324
- *
325
- * Auth registers cache() itself, so a consumer cannot configure the store by
326
- * registering its own plugin first. Pass it here to select a shared, durable
327
- * backend — required in production wherever the cache backs rate limiting,
328
- * since a per-process memory bucket resets on every restart.
322
+ * Config for the cache() plugin auth registers when the application has
323
+ * none. Select a shared, durable backend — here or on the application's own
324
+ * `cache()` — in production wherever the cache backs rate limiting, since a
325
+ * per-process memory bucket resets on every restart.
329
326
  */
330
327
  cache?: CachePluginConfig;
331
- /** Email transport used by password reset and verification flows. */
328
+ /**
329
+ * Email transport for password reset and verification flows, used when the
330
+ * application registers no email() plugin. Auth builds its email plugin only
331
+ * in that case, so an application with its own needs no `EMAIL_PROVIDER`
332
+ * for auth to start.
333
+ */
332
334
  email?: EmailPluginConfig;
333
335
  /** AES-256-GCM key for reversible encryption (e.g. API keys). Falls back to NAJM_ENCRYPTION_KEY env var. */
334
336
  encryptionKey?: string;
@@ -384,7 +386,7 @@ interface AuthUser {
384
386
  permissions?: string[];
385
387
  }
386
388
 
387
- declare const auth$1: (config?: AuthPluginConfig) => najm_core.NajmPlugin;
389
+ declare const auth$1: (config?: AuthPluginConfig) => NajmPlugin;
388
390
 
389
391
  declare const AUTH_CONFIG: unique symbol;
390
392
  declare const AUTH_SCHEMA: unique symbol;
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // src/AuthPlugin.ts
9
- import { Err as Err17, plugin } from "najm-core";
9
+ import { Err as Err17, lazyPlugin, plugin } from "najm-core";
10
10
  import { cache } from "najm-cache";
11
11
 
12
12
  // src/auth.tokens.ts
@@ -8281,7 +8281,10 @@ var selectAuthSchema = /* @__PURE__ */ __name((config) => {
8281
8281
  return authSchema;
8282
8282
  }
8283
8283
  }, "selectAuthSchema");
8284
- var auth = /* @__PURE__ */ __name((config) => plugin("auth").version("1.0.0").depends(cache(config?.cache), cookies(), i18n(), guards(), validation(config?.validation), rateLimit(config?.rateLimit), email(config?.email)).requires("database").contributes(I18N_CONTRIBUTIONS, AUTH_LOCALES).services(AUTH_CORE_MODULE, config?.publicRegistration === false ? [] : PUBLIC_REGISTRATION_MODULE, OAUTH_MODULE, users_exports, roles_exports, permissions_exports, tokens_exports, CREDENTIAL_SETUP_MODULE, ScopeContext).config(AUTH_CONFIG, resolveAuthConfig(config)).set(AUTH_SCHEMA, selectAuthSchema(config)).set(AUTH_ENCRYPTION_KEY, config?.encryptionKey ?? null).build(), "auth");
8284
+ var configurableDependency = /* @__PURE__ */ __name((config, option, name, create) => lazyPlugin(name, () => create(config?.[option]), {
8285
+ forwardedConfig: config?.[option] === void 0 ? void 0 : `auth({ ${option} })`
8286
+ }), "configurableDependency");
8287
+ var auth = /* @__PURE__ */ __name((config) => plugin("auth").version("1.0.0").depends(configurableDependency(config, "cache", "cache", cache), cookies(), i18n(), guards(), configurableDependency(config, "validation", "validation", validation), configurableDependency(config, "rateLimit", "rate-limit", rateLimit), configurableDependency(config, "email", "email", email)).requires("database").contributes(I18N_CONTRIBUTIONS, AUTH_LOCALES).services(AUTH_CORE_MODULE, config?.publicRegistration === false ? [] : PUBLIC_REGISTRATION_MODULE, OAUTH_MODULE, users_exports, roles_exports, permissions_exports, tokens_exports, CREDENTIAL_SETUP_MODULE, ScopeContext).config(AUTH_CONFIG, resolveAuthConfig(config)).set(AUTH_SCHEMA, selectAuthSchema(config)).set(AUTH_ENCRYPTION_KEY, config?.encryptionKey ?? null).build(), "auth");
8285
8288
 
8286
8289
  // src/seed.ts
8287
8290
  var toSeedId = /* @__PURE__ */ __name((prefix, value) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-auth",
3
- "version": "6.0.0",
3
+ "version": "6.2.0",
4
4
  "description": "Authentication and authorization library for najm framework",
5
5
  "type": "module",
6
6
  "files": [
@@ -93,8 +93,8 @@
93
93
  "dependencies": {
94
94
  "bcryptjs": "^3.0.2",
95
95
  "najm-cookies": "^2.0.3",
96
- "najm-core": "^3.0.3",
97
- "najm-database": "^2.2.0",
96
+ "najm-core": "^3.1.0",
97
+ "najm-database": "^2.2.1",
98
98
  "najm-guard": "^2.2.1",
99
99
  "najm-i18n": "^2.1.3",
100
100
  "najm-cache": "^2.2.0",