najm-auth 3.2.1 → 3.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.
@@ -1,4 +1,3 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
1
  import * as react from 'react';
3
2
  import { ReactNode, CSSProperties, ReactElement } from 'react';
4
3
  import { N as NajmAuthClient, H as HydrateSession } from '../../NajmAuthClient-ZtXTIUSF.js';
@@ -20,7 +19,7 @@ interface AuthProviderProps {
20
19
  */
21
20
  autoRefresh?: boolean;
22
21
  }
23
- declare function AuthProvider({ client, children, initialSession, autoRefresh, }: AuthProviderProps): react_jsx_runtime.JSX.Element;
22
+ declare function AuthProvider({ client, children, initialSession, autoRefresh, }: AuthProviderProps): react.JSX.Element;
24
23
 
25
24
  interface AuthBoundaryProps {
26
25
  children: ReactNode;
@@ -28,7 +27,7 @@ interface AuthBoundaryProps {
28
27
  /** Only gate while we truly have no identity; default false. */
29
28
  requireToken?: boolean;
30
29
  }
31
- declare function AuthBoundary({ children, fallback, requireToken, }: AuthBoundaryProps): react_jsx_runtime.JSX.Element;
30
+ declare function AuthBoundary({ children, fallback, requireToken, }: AuthBoundaryProps): react.JSX.Element;
32
31
 
33
32
  declare function useAuthClient(): NajmAuthClient;
34
33
 
@@ -240,7 +239,7 @@ interface SignedInProps {
240
239
  * </SignedIn>
241
240
  * ```
242
241
  */
243
- declare function SignedIn({ children }: SignedInProps): react_jsx_runtime.JSX.Element;
242
+ declare function SignedIn({ children }: SignedInProps): react.JSX.Element;
244
243
 
245
244
  interface SignedOutProps {
246
245
  children: ReactNode;
@@ -256,7 +255,7 @@ interface SignedOutProps {
256
255
  * </SignedOut>
257
256
  * ```
258
257
  */
259
- declare function SignedOut({ children }: SignedOutProps): react_jsx_runtime.JSX.Element;
258
+ declare function SignedOut({ children }: SignedOutProps): react.JSX.Element;
260
259
 
261
260
  interface AuthLoadingProps {
262
261
  children: ReactNode;
@@ -274,7 +273,7 @@ interface AuthLoadingProps {
274
273
  * <SignedOut>...</SignedOut>
275
274
  * ```
276
275
  */
277
- declare function AuthLoading({ children }: AuthLoadingProps): react_jsx_runtime.JSX.Element;
276
+ declare function AuthLoading({ children }: AuthLoadingProps): react.JSX.Element;
278
277
 
279
278
  interface CanProps {
280
279
  /** Required permission (e.g., 'read:posts') */
@@ -300,7 +299,7 @@ interface CanProps {
300
299
  * </Can>
301
300
  * ```
302
301
  */
303
- declare function Can({ permission, role, children, fallback }: CanProps): react_jsx_runtime.JSX.Element;
302
+ declare function Can({ permission, role, children, fallback }: CanProps): react.JSX.Element;
304
303
 
305
304
  interface RoleProps {
306
305
  /** Required role name */
@@ -324,7 +323,7 @@ interface RoleProps {
324
323
  * </Role>
325
324
  * ```
326
325
  */
327
- declare function Role(props: RoleProps): react_jsx_runtime.JSX.Element;
326
+ declare function Role(props: RoleProps): react.JSX.Element;
328
327
 
329
328
  interface IfAuthProps {
330
329
  /** Render when authenticated — receives user */
@@ -346,7 +345,7 @@ interface IfAuthProps {
346
345
  * />
347
346
  * ```
348
347
  */
349
- declare function IfAuth({ authenticated, unauthenticated, loading }: IfAuthProps): react_jsx_runtime.JSX.Element;
348
+ declare function IfAuth({ authenticated, unauthenticated, loading }: IfAuthProps): react.JSX.Element;
350
349
 
351
350
  interface ProtectedProps {
352
351
  children: ReactNode;
@@ -377,7 +376,7 @@ interface ProtectedProps {
377
376
  * </Protected>
378
377
  * ```
379
378
  */
380
- declare function Protected({ children, redirectTo, onUnauthenticated, role, permission, loadingFallback, fallback, }: ProtectedProps): react_jsx_runtime.JSX.Element;
379
+ declare function Protected({ children, redirectTo, onUnauthenticated, role, permission, loadingFallback, fallback, }: ProtectedProps): react.JSX.Element;
381
380
 
382
381
  interface AuthGateProps {
383
382
  children: ReactNode;
@@ -407,7 +406,7 @@ interface AuthGateProps {
407
406
  * **Without SSR hydration** (client-side nav, hard reload without initialSession):
408
407
  * Shows `loader` while attempting a token refresh, then either opens or redirects.
409
408
  */
410
- declare function AuthGate({ children, loader, redirectTo, onUnauthenticated, role, permission, denied, }: AuthGateProps): react_jsx_runtime.JSX.Element;
409
+ declare function AuthGate({ children, loader, redirectTo, onUnauthenticated, role, permission, denied, }: AuthGateProps): react.JSX.Element;
411
410
 
412
411
  interface UserNameProps {
413
412
  /** Optional fallback shown when no user is loaded */
@@ -422,7 +421,7 @@ interface UserNameProps {
422
421
  * <span>Hi, <UserName fallback="guest" />!</span>
423
422
  * ```
424
423
  */
425
- declare function UserName({ fallback }: UserNameProps): react_jsx_runtime.JSX.Element;
424
+ declare function UserName({ fallback }: UserNameProps): react.JSX.Element;
426
425
 
427
426
  interface UserEmailProps {
428
427
  fallback?: string;
@@ -435,7 +434,7 @@ interface UserEmailProps {
435
434
  * <p>Email: <UserEmail fallback="Not available" /></p>
436
435
  * ```
437
436
  */
438
- declare function UserEmail({ fallback }: UserEmailProps): react_jsx_runtime.JSX.Element;
437
+ declare function UserEmail({ fallback }: UserEmailProps): react.JSX.Element;
439
438
 
440
439
  interface UserRoleProps {
441
440
  fallback?: string;
@@ -448,7 +447,7 @@ interface UserRoleProps {
448
447
  * <span>Role: <UserRole fallback="none" /></span>
449
448
  * ```
450
449
  */
451
- declare function UserRole({ fallback }: UserRoleProps): react_jsx_runtime.JSX.Element;
450
+ declare function UserRole({ fallback }: UserRoleProps): react.JSX.Element;
452
451
 
453
452
  interface UserAvatarProps {
454
453
  /** Pixel size of the avatar (default: 32) */
@@ -474,7 +473,7 @@ interface UserAvatarProps {
474
473
  * <UserAvatar className="my-avatar" />
475
474
  * ```
476
475
  */
477
- declare function UserAvatar({ size, className, style, alt }: UserAvatarProps): react_jsx_runtime.JSX.Element;
476
+ declare function UserAvatar({ size, className, style, alt }: UserAvatarProps): react.JSX.Element;
478
477
 
479
478
  interface PermissionListProps {
480
479
  /** Render function for each permission */
@@ -492,7 +491,7 @@ interface PermissionListProps {
492
491
  * </PermissionList>
493
492
  * ```
494
493
  */
495
- declare function PermissionList({ children, fallback }: PermissionListProps): react_jsx_runtime.JSX.Element;
494
+ declare function PermissionList({ children, fallback }: PermissionListProps): react.JSX.Element;
496
495
 
497
496
  interface SignOutButtonProps {
498
497
  /** A single clickable child element. Its `onClick` will be wired to logout. */
@@ -579,6 +578,6 @@ interface OAuthCallbackProps {
579
578
  }) => ReactNode);
580
579
  defaultRedirect?: string;
581
580
  }
582
- declare function OAuthCallback({ fallback, errorFallback, defaultRedirect, }: OAuthCallbackProps): react_jsx_runtime.JSX.Element;
581
+ declare function OAuthCallback({ fallback, errorFallback, defaultRedirect, }: OAuthCallbackProps): react.JSX.Element;
583
582
 
584
583
  export { AuthBoundary, type AuthEventEntry, AuthGate, AuthLoading, AuthProvider, Can, GoogleLoginButton, IfAuth, LoginButton, OAuthCallback, PermissionList, Protected, RedirectToLogin, Role, type SessionStatus, SignOutButton, SignedIn, SignedOut, UserAvatar, UserEmail, UserName, UserRole, useAuth, useAuthClient, useAuthEvent, useAuthEvents, useChangePassword, useForgotPassword, useGoogleLogin, useLogin, useLogout, useOAuthCallback, usePermissions, useRegister, useResetPassword, useSession, useUser };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as najm_core from 'najm-core';
2
2
  import { Container } from 'najm-core';
3
3
  import { ValidationPluginConfig } from 'najm-validation';
4
- import { RateLimitPluginConfig, TimeWindow } from 'najm-rate';
4
+ import { RateLimitPluginConfig, RateLimitKeyContext, TimeWindow } from 'najm-rate';
5
+ import { CachePluginConfig, CacheService } from 'najm-cache';
5
6
  import { EmailPluginConfig, EmailService } from 'najm-email';
6
7
  import { R as ResolvedIdentityConfig, I as IdentityConfig, T as TemporaryCredentialInput } from './ma-sNHnUGLO.js';
7
8
  export { D as DEFAULT_IDENTITY_PRESET, E as EXACT_TEMPORARY_CREDENTIAL_KIND, a as IDENTITY_PRESETS, b as IdentityNormalizer, c as IdentityPreset, d as IdentityPresetName, M as MOROCCAN_CIN_TEMPORARY_CREDENTIAL_KIND, e as TemporaryCredential, f as TemporaryCredentialKind, g as compactPhone, i as isMoroccanCin, h as isTemporaryCredentialKind, m as moroccanCinTemporaryCredential, j as moroccoIdentityPreset, n as normalizeMoroccanCin, k as normalizeMoroccanPhone, l as normalizeTunisianPhone, r as resolveTemporaryCredentialKind, t as toTemporaryCredential, o as tunisiaIdentityPreset } from './ma-sNHnUGLO.js';
@@ -10,7 +11,6 @@ import { I18nService } from 'najm-i18n';
10
11
  import { TDb, SeedEntry } from 'najm-database';
11
12
  import { User, NewUser, RoleEntity, NewRoleEntity, Permission, NewPermission, RolePermission } from './schema/pg.js';
12
13
  export { CredentialSetupRequirement, CredentialSetupSession, NewCredentialSetupRequirement, NewCredentialSetupSession, NewOAuthAccount, NewRolePermission, NewToken, OAuthAccount, Token, authSchema, baseFields, credentialSetupRequirementsTable, credentialSetupSessionsTable, oauthAccountsTable, permissionsTable, rolePermissionsTable, rolesTable, tokenStatusEnum, tokenTypeEnum, tokensTable, userStatusEnum, usersTable } from './schema/pg.js';
13
- import { CacheService } from 'najm-cache';
14
14
  import { CookieService } from 'najm-cookies';
15
15
  import { Context } from 'hono';
16
16
  import { GuardResult } from 'najm-guard';
@@ -269,6 +269,15 @@ type AuthPluginConfig = {
269
269
  validation?: ValidationPluginConfig;
270
270
  /** Optional config forwarded to rateLimit() dependency */
271
271
  rateLimit?: RateLimitPluginConfig;
272
+ /**
273
+ * Optional config forwarded to the package-owned cache() dependency.
274
+ *
275
+ * Auth registers cache() itself, so a consumer cannot configure the store by
276
+ * registering its own plugin first. Pass it here to select a shared, durable
277
+ * backend — required in production wherever the cache backs rate limiting,
278
+ * since a per-process memory bucket resets on every restart.
279
+ */
280
+ cache?: CachePluginConfig;
272
281
  /** Email transport used by password reset and verification flows. */
273
282
  email?: EmailPluginConfig;
274
283
  /** AES-256-GCM key for reversible encryption (e.g. API keys). Falls back to NAJM_ENCRYPTION_KEY env var. */
@@ -1653,11 +1662,14 @@ declare class AuthService {
1653
1662
  }
1654
1663
 
1655
1664
  /**
1656
- * Composite key: IP + hashed normalized login/registration identity.
1657
- * Buckets rate limits per IP+credential combo so different users
1658
- * on the same IP (e.g. localhost, NAT) don't share a single bucket.
1665
+ * Composite key: resolved client address + hashed normalized identity.
1666
+ * Buckets rate limits per client+credential combo so different users
1667
+ * on the same address (e.g. localhost, NAT) don't share a single bucket.
1668
+ *
1669
+ * The address arrives already resolved through the configured trusted-proxy
1670
+ * boundary; this module must never parse forwarding headers itself.
1659
1671
  */
1660
- declare const authIdentityRateLimitKey: (ctx: Context) => Promise<string>;
1672
+ declare const authIdentityRateLimitKey: (ctx: Context, keyContext?: RateLimitKeyContext) => Promise<string>;
1661
1673
  declare class AuthController {
1662
1674
  private authService;
1663
1675
  constructor(authService: AuthService);
package/dist/index.js CHANGED
@@ -3561,7 +3561,7 @@ var isAdministrator = composeGuards(isAuth(), Role(ROLE_GROUPS.ADMINISTRATORS));
3561
3561
 
3562
3562
  // src/auth/AuthController.ts
3563
3563
  import { Validate } from "najm-validation";
3564
- import { RateLimit } from "najm-rate";
3564
+ import { RateLimit, UNRESOLVED_CLIENT_ADDRESS } from "najm-rate";
3565
3565
  import { createHash as createHash3 } from "crypto";
3566
3566
 
3567
3567
  // src/identity/requestResolver.ts
@@ -3739,14 +3739,13 @@ var __param5 = function(paramIndex, decorator) {
3739
3739
  };
3740
3740
  var _a12;
3741
3741
  var hashKeyPart = /* @__PURE__ */ __name((value) => createHash3("sha256").update(value).digest("base64url").slice(0, 32), "hashKeyPart");
3742
- var cookieFingerprint = /* @__PURE__ */ __name(() => (ctx) => {
3743
- const ip = ctx.req.header("x-forwarded-for")?.split(",")[0]?.trim() ?? ctx.req.header("x-real-ip") ?? "unknown";
3742
+ var cookieFingerprint = /* @__PURE__ */ __name(() => (ctx, { clientIp }) => {
3744
3743
  const cookie = ctx.req.raw.headers.get("cookie") ?? "";
3745
3744
  const fingerprint = cookie ? hashKeyPart(cookie) : "none";
3746
- return `${ip}:${fingerprint}`;
3745
+ return `${clientIp}:${fingerprint}`;
3747
3746
  }, "cookieFingerprint");
3748
- var authIdentityRateLimitKey = /* @__PURE__ */ __name(async (ctx) => {
3749
- const ip = ctx.req.header("x-forwarded-for")?.split(",")[0]?.trim() ?? ctx.req.header("x-real-ip") ?? "unknown";
3747
+ var authIdentityRateLimitKey = /* @__PURE__ */ __name(async (ctx, keyContext) => {
3748
+ const ip = keyContext?.clientIp ?? UNRESOLVED_CLIENT_ADDRESS;
3750
3749
  try {
3751
3750
  const body = await ctx.req.json();
3752
3751
  const identity = body?.identifier ?? body?.email;
@@ -6574,8 +6573,8 @@ var __param13 = function(paramIndex, decorator) {
6574
6573
  };
6575
6574
  };
6576
6575
  var _a25;
6577
- var callbackKey = /* @__PURE__ */ __name((ctx) => {
6578
- const ip = ctx.req.header("x-forwarded-for")?.split(",")[0]?.trim() ?? ctx.req.header("x-real-ip") ?? "unknown";
6576
+ var callbackKey = /* @__PURE__ */ __name((ctx, { clientIp }) => {
6577
+ const ip = clientIp;
6579
6578
  const state = ctx.req.query("state") ?? "none";
6580
6579
  const fingerprint = createHash5("sha256").update(state).digest("base64url").slice(0, 24);
6581
6580
  return `${ip}:${fingerprint}`;
@@ -6862,7 +6861,7 @@ var selectAuthSchema = /* @__PURE__ */ __name((config) => {
6862
6861
  return authSchema;
6863
6862
  }
6864
6863
  }, "selectAuthSchema");
6865
- var auth = /* @__PURE__ */ __name((config) => plugin("auth").version("1.0.0").depends(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");
6864
+ 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");
6866
6865
 
6867
6866
  // src/seed.ts
6868
6867
  var toSeedId = /* @__PURE__ */ __name((prefix, value) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-auth",
3
- "version": "3.2.1",
3
+ "version": "3.3.0",
4
4
  "description": "Authentication and authorization library for najm framework",
5
5
  "type": "module",
6
6
  "files": [
@@ -95,9 +95,9 @@
95
95
  "najm-database": "^2.0.3",
96
96
  "najm-guard": "^2.0.2",
97
97
  "najm-i18n": "^2.0.3",
98
- "najm-cache": "^2.0.2",
98
+ "najm-cache": "^2.1.0",
99
99
  "najm-email": "^2.0.2",
100
- "najm-rate": "^2.0.3",
100
+ "najm-rate": "^2.1.0",
101
101
  "najm-validation": "^2.0.2",
102
102
  "jsonwebtoken": "^9.0.3",
103
103
  "jose": "^6.1.3",