@reckona/mreact-auth 0.0.85 → 0.0.87

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/dist/index.js CHANGED
@@ -167,16 +167,22 @@ function readClaimsFromDocument() {
167
167
  }
168
168
  }
169
169
  function defaultSerializeSessionClaims(data) {
170
- const claims = normalizeSessionClaims(data);
171
- if (claims === undefined) {
170
+ if (typeof data !== "object" || data === null) {
171
+ return undefined;
172
+ }
173
+ const claims = data;
174
+ const roles = normalizeStringArray(claims.roles);
175
+ const permissions = normalizeStringArray(claims.permissions);
176
+ if ((claims.roles !== undefined && roles === undefined) ||
177
+ (claims.permissions !== undefined && permissions === undefined)) {
172
178
  return undefined;
173
179
  }
174
180
  const safeClaims = {};
175
- if (claims.permissions !== undefined) {
176
- safeClaims.permissions = claims.permissions;
181
+ if (permissions !== undefined) {
182
+ safeClaims.permissions = permissions;
177
183
  }
178
- if (claims.roles !== undefined) {
179
- safeClaims.roles = claims.roles;
184
+ if (roles !== undefined) {
185
+ safeClaims.roles = roles;
180
186
  }
181
187
  return Object.keys(safeClaims).length === 0 ? undefined : safeClaims;
182
188
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createMemorySessionStore,\n createSession,\n destroySession as destroyRouterSession,\n getSession,\n rotateSession as rotateRouterSession,\n type SessionCookieOptions,\n type SessionRecord,\n type SessionStore,\n} from \"@reckona/mreact-router/session\";\nimport { getGlobalRuntimeState } from \"@reckona/mreact-reactive-core/runtime-state\";\nimport { redirect } from \"@reckona/mreact-router\";\n\nexport {\n createMemorySessionStore,\n createSession,\n destroyRouterSession as destroySession,\n getSession,\n rotateRouterSession as rotateSession,\n};\nexport type { SessionCookieOptions, SessionRecord, SessionStore };\n\nexport const __MREACT_AUTH_SESSION_SCRIPT_ID = \"__mreact_auth_session\";\n\nexport interface AuthSessionClaims {\n [claim: string]: unknown;\n permissions?: readonly string[] | undefined;\n roles?: readonly string[] | undefined;\n}\n\nexport interface AuthGuardOptions {\n forbiddenTo?: string | undefined;\n mode?: AuthRequirementMode | undefined;\n redirectTo?: string | undefined;\n}\n\nexport interface AuthConfig {\n forbiddenTo?: string | undefined;\n redirectTo?: string | undefined;\n serializeClaims?: AuthClaimsSerializer | undefined;\n}\n\ninterface ResolvedAuthConfig {\n forbiddenTo: string;\n redirectTo: string;\n serializeClaims: AuthClaimsSerializer;\n}\n\nexport type AuthRequirement = string | readonly string[];\nexport type AuthRequirementMode = \"all\" | \"any\";\nexport type AuthClaimsSerializer = (data: unknown) => AuthSessionClaims | undefined;\n\nexport interface AuthorizationPolicy {\n permissions?: readonly string[] | undefined;\n roles?: readonly string[] | undefined;\n}\n\nexport type AuthorizationResult =\n | {\n authorized: true;\n }\n | {\n authorized: false;\n reason: \"missing-permission\" | \"missing-role\";\n };\n\nexport type TryAuthResult<TData> =\n | {\n authorized: true;\n session: SessionRecord<TData>;\n }\n | {\n authorized: false;\n reason: \"missing-permission\" | \"missing-role\" | \"missing-session\";\n };\n\nconst authRuntimeStateKey = \"__mreactAuthRuntimeState\";\n\ninterface AuthRuntimeRequestState {\n claims?: AuthSessionClaims | undefined;\n}\n\ninterface AuthRuntimeState {\n browserClaims?: AuthSessionClaims | undefined;\n currentClaims?: AuthSessionClaims | undefined;\n storage?:\n | {\n getStore(): AuthRuntimeRequestState | undefined;\n }\n | undefined;\n}\n\nlet authConfig: ResolvedAuthConfig = {\n forbiddenTo: \"/forbidden\",\n redirectTo: \"/login\",\n serializeClaims: defaultSerializeSessionClaims,\n};\n\nexport function configureAuth(config: AuthConfig): void {\n authConfig = {\n forbiddenTo: config.forbiddenTo ?? authConfig.forbiddenTo,\n redirectTo: config.redirectTo ?? authConfig.redirectTo,\n serializeClaims: config.serializeClaims ?? authConfig.serializeClaims,\n };\n}\n\nexport async function getCurrentSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const session = await getSession(request, store, options);\n\n setSessionClaims(session?.data);\n\n return session;\n}\n\nexport async function requireSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n redirect(authRedirectTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function requireRole<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n role: AuthRequirement,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await requireSession(request, store, options);\n const result = authorizeRequirement(session.data.roles, role, \"missing-role\", options.mode);\n\n if (!result.authorized) {\n redirect(authForbiddenTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function requirePermission<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n permission: AuthRequirement,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await requireSession(request, store, options);\n const result = authorizeRequirement(\n session.data.permissions,\n permission,\n \"missing-permission\",\n options.mode,\n );\n\n if (!result.authorized) {\n redirect(authForbiddenTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function tryRequireRole<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n role: AuthRequirement,\n options: Pick<AuthGuardOptions, \"mode\"> = {},\n): Promise<TryAuthResult<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n return { authorized: false, reason: \"missing-session\" };\n }\n\n const result = authorizeRequirement(session.data.roles, role, \"missing-role\", options.mode);\n\n return result.authorized ? { authorized: true, session } : result;\n}\n\nexport async function tryRequirePermission<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n permission: AuthRequirement,\n options: Pick<AuthGuardOptions, \"mode\"> = {},\n): Promise<TryAuthResult<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n return { authorized: false, reason: \"missing-session\" };\n }\n\n const result = authorizeRequirement(\n session.data.permissions,\n permission,\n \"missing-permission\",\n options.mode,\n );\n\n return result.authorized ? { authorized: true, session } : result;\n}\n\nexport function authorizeSession<TData extends AuthSessionClaims>(\n data: TData,\n policy: AuthorizationPolicy,\n): AuthorizationResult {\n if (!hasAll(data.roles, policy.roles)) {\n return {\n authorized: false,\n reason: \"missing-role\",\n };\n }\n\n if (!hasAll(data.permissions, policy.permissions)) {\n return {\n authorized: false,\n reason: \"missing-permission\",\n };\n }\n\n return { authorized: true };\n}\n\nexport async function refreshSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const session = await rotateRouterSession(request, response, store, options);\n\n setSessionClaims(session?.data);\n\n return session;\n}\n\nexport async function revokeCurrentSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<void> {\n await destroyRouterSession(request, response, store, options);\n setSessionClaims(undefined);\n}\n\nexport function getSessionClaims<TData extends AuthSessionClaims = AuthSessionClaims>():\n | TData\n | undefined {\n const state = authRuntimeState();\n const requestClaims = state.storage?.getStore()?.claims;\n\n if (requestClaims !== undefined) {\n return requestClaims as TData;\n }\n\n if (typeof document === \"undefined\") {\n return state.currentClaims as TData | undefined;\n }\n\n if (state.browserClaims === undefined) {\n state.browserClaims = readClaimsFromDocument();\n }\n\n return state.browserClaims as TData | undefined;\n}\n\nexport function __resetAuthForTesting(): void {\n authConfig = {\n forbiddenTo: \"/forbidden\",\n redirectTo: \"/login\",\n serializeClaims: defaultSerializeSessionClaims,\n };\n const state = authRuntimeState();\n state.browserClaims = undefined;\n state.currentClaims = undefined;\n const requestState = state.storage?.getStore();\n if (requestState !== undefined) {\n requestState.claims = undefined;\n }\n}\n\nfunction authorizeRequirement(\n available: readonly string[] | undefined,\n requirement: AuthRequirement,\n reason: \"missing-permission\" | \"missing-role\",\n mode: AuthRequirementMode = \"any\",\n): AuthorizationResult {\n const required = Array.isArray(requirement) ? requirement : [requirement];\n const authorized = mode === \"all\" ? hasAll(available, required) : hasAny(available, required);\n\n return authorized ? { authorized: true } : { authorized: false, reason };\n}\n\nfunction authRedirectTo(options: AuthGuardOptions): string {\n return options.redirectTo ?? authConfig.redirectTo;\n}\n\nfunction authForbiddenTo(options: AuthGuardOptions): string {\n return options.forbiddenTo ?? authConfig.forbiddenTo;\n}\n\nfunction hasAll(\n available: readonly string[] | undefined,\n required: readonly string[] | undefined,\n): boolean {\n if (required === undefined || required.length === 0) {\n return true;\n }\n\n if (available === undefined || available.length === 0) {\n return false;\n }\n\n const values = new Set(available);\n\n return required.every((value) => values.has(value));\n}\n\nfunction hasAny(\n available: readonly string[] | undefined,\n required: readonly string[] | undefined,\n): boolean {\n if (required === undefined || required.length === 0) {\n return true;\n }\n\n if (available === undefined || available.length === 0) {\n return false;\n }\n\n const values = new Set(available);\n\n return required.some((value) => values.has(value));\n}\n\nfunction setSessionClaims(data: unknown): void {\n const claims = normalizeSessionClaims(authConfig.serializeClaims(data));\n const state = authRuntimeState();\n const requestState = state.storage?.getStore();\n\n if (requestState !== undefined) {\n requestState.claims = claims;\n return;\n }\n\n state.currentClaims = claims;\n}\n\nfunction readClaimsFromDocument(): AuthSessionClaims | undefined {\n const node = document.getElementById(__MREACT_AUTH_SESSION_SCRIPT_ID);\n\n if (node?.textContent === undefined || node.textContent === \"\") {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(node.textContent) as unknown;\n return normalizeSessionClaims(parsed);\n } catch {\n return undefined;\n }\n}\n\nfunction defaultSerializeSessionClaims(data: unknown): AuthSessionClaims | undefined {\n const claims = normalizeSessionClaims(data);\n\n if (claims === undefined) {\n return undefined;\n }\n\n const safeClaims: AuthSessionClaims = {};\n\n if (claims.permissions !== undefined) {\n safeClaims.permissions = claims.permissions;\n }\n\n if (claims.roles !== undefined) {\n safeClaims.roles = claims.roles;\n }\n\n return Object.keys(safeClaims).length === 0 ? undefined : safeClaims;\n}\n\nfunction normalizeSessionClaims(value: unknown): AuthSessionClaims | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const claims = value as AuthSessionClaims;\n const roles = normalizeStringArray(claims.roles);\n const permissions = normalizeStringArray(claims.permissions);\n\n if (\n (claims.roles !== undefined && roles === undefined) ||\n (claims.permissions !== undefined && permissions === undefined)\n ) {\n return undefined;\n }\n\n return {\n ...claims,\n ...(permissions === undefined ? {} : { permissions }),\n ...(roles === undefined ? {} : { roles }),\n };\n}\n\nfunction normalizeStringArray(value: unknown): readonly string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return Array.isArray(value) && value.every((item) => typeof item === \"string\")\n ? value\n : undefined;\n}\n\nfunction authRuntimeState(): AuthRuntimeState {\n return getGlobalRuntimeState(authRuntimeStateKey, () => ({}));\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createMemorySessionStore,\n createSession,\n destroySession as destroyRouterSession,\n getSession,\n rotateSession as rotateRouterSession,\n type SessionCookieOptions,\n type SessionRecord,\n type SessionStore,\n} from \"@reckona/mreact-router/session\";\nimport { getGlobalRuntimeState } from \"@reckona/mreact-reactive-core/runtime-state\";\nimport { redirect } from \"@reckona/mreact-router\";\n\nexport {\n createMemorySessionStore,\n createSession,\n destroyRouterSession as destroySession,\n getSession,\n rotateRouterSession as rotateSession,\n};\nexport type { SessionCookieOptions, SessionRecord, SessionStore };\n\nexport const __MREACT_AUTH_SESSION_SCRIPT_ID = \"__mreact_auth_session\";\n\nexport interface AuthSessionClaims {\n [claim: string]: unknown;\n permissions?: readonly string[] | undefined;\n roles?: readonly string[] | undefined;\n}\n\nexport interface AuthGuardOptions {\n forbiddenTo?: string | undefined;\n mode?: AuthRequirementMode | undefined;\n redirectTo?: string | undefined;\n}\n\nexport interface AuthConfig {\n forbiddenTo?: string | undefined;\n redirectTo?: string | undefined;\n serializeClaims?: AuthClaimsSerializer | undefined;\n}\n\ninterface ResolvedAuthConfig {\n forbiddenTo: string;\n redirectTo: string;\n serializeClaims: AuthClaimsSerializer;\n}\n\nexport type AuthRequirement = string | readonly string[];\nexport type AuthRequirementMode = \"all\" | \"any\";\nexport type AuthClaimsSerializer = (data: unknown) => AuthSessionClaims | undefined;\n\nexport interface AuthorizationPolicy {\n permissions?: readonly string[] | undefined;\n roles?: readonly string[] | undefined;\n}\n\nexport type AuthorizationResult =\n | {\n authorized: true;\n }\n | {\n authorized: false;\n reason: \"missing-permission\" | \"missing-role\";\n };\n\nexport type TryAuthResult<TData> =\n | {\n authorized: true;\n session: SessionRecord<TData>;\n }\n | {\n authorized: false;\n reason: \"missing-permission\" | \"missing-role\" | \"missing-session\";\n };\n\nconst authRuntimeStateKey = \"__mreactAuthRuntimeState\";\n\ninterface AuthRuntimeRequestState {\n claims?: AuthSessionClaims | undefined;\n}\n\ninterface AuthRuntimeState {\n browserClaims?: AuthSessionClaims | undefined;\n currentClaims?: AuthSessionClaims | undefined;\n storage?:\n | {\n getStore(): AuthRuntimeRequestState | undefined;\n }\n | undefined;\n}\n\nlet authConfig: ResolvedAuthConfig = {\n forbiddenTo: \"/forbidden\",\n redirectTo: \"/login\",\n serializeClaims: defaultSerializeSessionClaims,\n};\n\nexport function configureAuth(config: AuthConfig): void {\n authConfig = {\n forbiddenTo: config.forbiddenTo ?? authConfig.forbiddenTo,\n redirectTo: config.redirectTo ?? authConfig.redirectTo,\n serializeClaims: config.serializeClaims ?? authConfig.serializeClaims,\n };\n}\n\nexport async function getCurrentSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const session = await getSession(request, store, options);\n\n setSessionClaims(session?.data);\n\n return session;\n}\n\nexport async function requireSession<TData>(\n request: Request,\n store: SessionStore<TData>,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n redirect(authRedirectTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function requireRole<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n role: AuthRequirement,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await requireSession(request, store, options);\n const result = authorizeRequirement(session.data.roles, role, \"missing-role\", options.mode);\n\n if (!result.authorized) {\n redirect(authForbiddenTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function requirePermission<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n permission: AuthRequirement,\n options: AuthGuardOptions = {},\n): Promise<SessionRecord<TData>> {\n const session = await requireSession(request, store, options);\n const result = authorizeRequirement(\n session.data.permissions,\n permission,\n \"missing-permission\",\n options.mode,\n );\n\n if (!result.authorized) {\n redirect(authForbiddenTo(options), { status: 303 });\n }\n\n return session;\n}\n\nexport async function tryRequireRole<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n role: AuthRequirement,\n options: Pick<AuthGuardOptions, \"mode\"> = {},\n): Promise<TryAuthResult<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n return { authorized: false, reason: \"missing-session\" };\n }\n\n const result = authorizeRequirement(session.data.roles, role, \"missing-role\", options.mode);\n\n return result.authorized ? { authorized: true, session } : result;\n}\n\nexport async function tryRequirePermission<TData extends AuthSessionClaims>(\n request: Request,\n store: SessionStore<TData>,\n permission: AuthRequirement,\n options: Pick<AuthGuardOptions, \"mode\"> = {},\n): Promise<TryAuthResult<TData>> {\n const session = await getCurrentSession(request, store);\n\n if (session === undefined) {\n return { authorized: false, reason: \"missing-session\" };\n }\n\n const result = authorizeRequirement(\n session.data.permissions,\n permission,\n \"missing-permission\",\n options.mode,\n );\n\n return result.authorized ? { authorized: true, session } : result;\n}\n\nexport function authorizeSession<TData extends AuthSessionClaims>(\n data: TData,\n policy: AuthorizationPolicy,\n): AuthorizationResult {\n if (!hasAll(data.roles, policy.roles)) {\n return {\n authorized: false,\n reason: \"missing-role\",\n };\n }\n\n if (!hasAll(data.permissions, policy.permissions)) {\n return {\n authorized: false,\n reason: \"missing-permission\",\n };\n }\n\n return { authorized: true };\n}\n\nexport async function refreshSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<SessionRecord<TData> | undefined> {\n const session = await rotateRouterSession(request, response, store, options);\n\n setSessionClaims(session?.data);\n\n return session;\n}\n\nexport async function revokeCurrentSession<TData>(\n request: Request,\n response: Response,\n store: SessionStore<TData>,\n options: SessionCookieOptions = {},\n): Promise<void> {\n await destroyRouterSession(request, response, store, options);\n setSessionClaims(undefined);\n}\n\nexport function getSessionClaims<TData extends AuthSessionClaims = AuthSessionClaims>():\n | TData\n | undefined {\n const state = authRuntimeState();\n const requestClaims = state.storage?.getStore()?.claims;\n\n if (requestClaims !== undefined) {\n return requestClaims as TData;\n }\n\n if (typeof document === \"undefined\") {\n return state.currentClaims as TData | undefined;\n }\n\n if (state.browserClaims === undefined) {\n state.browserClaims = readClaimsFromDocument();\n }\n\n return state.browserClaims as TData | undefined;\n}\n\nexport function __resetAuthForTesting(): void {\n authConfig = {\n forbiddenTo: \"/forbidden\",\n redirectTo: \"/login\",\n serializeClaims: defaultSerializeSessionClaims,\n };\n const state = authRuntimeState();\n state.browserClaims = undefined;\n state.currentClaims = undefined;\n const requestState = state.storage?.getStore();\n if (requestState !== undefined) {\n requestState.claims = undefined;\n }\n}\n\nfunction authorizeRequirement(\n available: readonly string[] | undefined,\n requirement: AuthRequirement,\n reason: \"missing-permission\" | \"missing-role\",\n mode: AuthRequirementMode = \"any\",\n): AuthorizationResult {\n const required = Array.isArray(requirement) ? requirement : [requirement];\n const authorized = mode === \"all\" ? hasAll(available, required) : hasAny(available, required);\n\n return authorized ? { authorized: true } : { authorized: false, reason };\n}\n\nfunction authRedirectTo(options: AuthGuardOptions): string {\n return options.redirectTo ?? authConfig.redirectTo;\n}\n\nfunction authForbiddenTo(options: AuthGuardOptions): string {\n return options.forbiddenTo ?? authConfig.forbiddenTo;\n}\n\nfunction hasAll(\n available: readonly string[] | undefined,\n required: readonly string[] | undefined,\n): boolean {\n if (required === undefined || required.length === 0) {\n return true;\n }\n\n if (available === undefined || available.length === 0) {\n return false;\n }\n\n const values = new Set(available);\n\n return required.every((value) => values.has(value));\n}\n\nfunction hasAny(\n available: readonly string[] | undefined,\n required: readonly string[] | undefined,\n): boolean {\n if (required === undefined || required.length === 0) {\n return true;\n }\n\n if (available === undefined || available.length === 0) {\n return false;\n }\n\n const values = new Set(available);\n\n return required.some((value) => values.has(value));\n}\n\nfunction setSessionClaims(data: unknown): void {\n const claims = normalizeSessionClaims(authConfig.serializeClaims(data));\n const state = authRuntimeState();\n const requestState = state.storage?.getStore();\n\n if (requestState !== undefined) {\n requestState.claims = claims;\n return;\n }\n\n state.currentClaims = claims;\n}\n\nfunction readClaimsFromDocument(): AuthSessionClaims | undefined {\n const node = document.getElementById(__MREACT_AUTH_SESSION_SCRIPT_ID);\n\n if (node?.textContent === undefined || node.textContent === \"\") {\n return undefined;\n }\n\n try {\n const parsed = JSON.parse(node.textContent) as unknown;\n return normalizeSessionClaims(parsed);\n } catch {\n return undefined;\n }\n}\n\nfunction defaultSerializeSessionClaims(data: unknown): AuthSessionClaims | undefined {\n if (typeof data !== \"object\" || data === null) {\n return undefined;\n }\n\n const claims = data as AuthSessionClaims;\n const roles = normalizeStringArray(claims.roles);\n const permissions = normalizeStringArray(claims.permissions);\n\n if (\n (claims.roles !== undefined && roles === undefined) ||\n (claims.permissions !== undefined && permissions === undefined)\n ) {\n return undefined;\n }\n\n const safeClaims: AuthSessionClaims = {};\n\n if (permissions !== undefined) {\n safeClaims.permissions = permissions;\n }\n\n if (roles !== undefined) {\n safeClaims.roles = roles;\n }\n\n return Object.keys(safeClaims).length === 0 ? undefined : safeClaims;\n}\n\nfunction normalizeSessionClaims(value: unknown): AuthSessionClaims | undefined {\n if (typeof value !== \"object\" || value === null) {\n return undefined;\n }\n\n const claims = value as AuthSessionClaims;\n const roles = normalizeStringArray(claims.roles);\n const permissions = normalizeStringArray(claims.permissions);\n\n if (\n (claims.roles !== undefined && roles === undefined) ||\n (claims.permissions !== undefined && permissions === undefined)\n ) {\n return undefined;\n }\n\n return {\n ...claims,\n ...(permissions === undefined ? {} : { permissions }),\n ...(roles === undefined ? {} : { roles }),\n };\n}\n\nfunction normalizeStringArray(value: unknown): readonly string[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n return Array.isArray(value) && value.every((item) => typeof item === \"string\")\n ? value\n : undefined;\n}\n\nfunction authRuntimeState(): AuthRuntimeState {\n return getGlobalRuntimeState(authRuntimeStateKey, () => ({}));\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reckona/mreact-auth",
3
- "version": "0.0.85",
3
+ "version": "0.0.87",
4
4
  "description": "Session and authorization helpers for mreact app router applications.",
5
5
  "keywords": [
6
6
  "auth",
@@ -41,7 +41,7 @@
41
41
  "access": "public"
42
42
  },
43
43
  "dependencies": {
44
- "@reckona/mreact-reactive-core": "0.0.85",
45
- "@reckona/mreact-router": "0.0.85"
44
+ "@reckona/mreact-reactive-core": "0.0.87",
45
+ "@reckona/mreact-router": "0.0.87"
46
46
  }
47
47
  }
package/src/index.ts CHANGED
@@ -369,20 +369,29 @@ function readClaimsFromDocument(): AuthSessionClaims | undefined {
369
369
  }
370
370
 
371
371
  function defaultSerializeSessionClaims(data: unknown): AuthSessionClaims | undefined {
372
- const claims = normalizeSessionClaims(data);
372
+ if (typeof data !== "object" || data === null) {
373
+ return undefined;
374
+ }
375
+
376
+ const claims = data as AuthSessionClaims;
377
+ const roles = normalizeStringArray(claims.roles);
378
+ const permissions = normalizeStringArray(claims.permissions);
373
379
 
374
- if (claims === undefined) {
380
+ if (
381
+ (claims.roles !== undefined && roles === undefined) ||
382
+ (claims.permissions !== undefined && permissions === undefined)
383
+ ) {
375
384
  return undefined;
376
385
  }
377
386
 
378
387
  const safeClaims: AuthSessionClaims = {};
379
388
 
380
- if (claims.permissions !== undefined) {
381
- safeClaims.permissions = claims.permissions;
389
+ if (permissions !== undefined) {
390
+ safeClaims.permissions = permissions;
382
391
  }
383
392
 
384
- if (claims.roles !== undefined) {
385
- safeClaims.roles = claims.roles;
393
+ if (roles !== undefined) {
394
+ safeClaims.roles = roles;
386
395
  }
387
396
 
388
397
  return Object.keys(safeClaims).length === 0 ? undefined : safeClaims;