@markwharton/pwa-core 4.0.0 → 4.0.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.
package/dist/server.d.ts CHANGED
@@ -90,15 +90,15 @@ export declare const DEFAULT_TOKEN_EXPIRY_SECONDS: number;
90
90
  */
91
91
  export declare function requireAuth<T extends BaseJwtPayload>(authHeader: string | null): Result<T>;
92
92
  /**
93
- * Requires admin role. Use with RoleTokenPayload.
93
+ * Requires admin role. Generic like requireAuth — callers can extend RoleTokenPayload.
94
94
  * @param authHeader - The Authorization header value
95
- * @returns Result with RoleTokenPayload on success, or error with status on failure
95
+ * @returns Result with payload on success, or error with status on failure
96
96
  * @example
97
97
  * const auth = requireAdmin(request.headers.get('Authorization'));
98
98
  * if (!auth.ok) return resultToResponse(auth);
99
99
  * // User is admin
100
100
  */
101
- export declare function requireAdmin(authHeader: string | null): Result<RoleTokenPayload>;
101
+ export declare function requireAdmin<T extends RoleTokenPayload = RoleTokenPayload>(authHeader: string | null): Result<T>;
102
102
  /**
103
103
  * Extracts API key from the X-API-Key header.
104
104
  * @param request - Request object with headers.get() method
@@ -444,6 +444,9 @@ export interface SessionAuthConfig {
444
444
  /** Additional email validation. Called after built-in domain/admin checks reject.
445
445
  * Can only widen access, never narrow it. Supports async for database lookups. */
446
446
  isEmailAllowed?: (email: string) => boolean | Promise<boolean>;
447
+ /** Transform base SessionUser into an app-specific user type.
448
+ * Called after session validation succeeds. Enables generic session functions. */
449
+ resolveUser?: (user: SessionUser) => Promise<SessionUser> | SessionUser;
447
450
  /** Base URL for magic links and SWA preview URL validation */
448
451
  appBaseUrl?: string;
449
452
  /** Required callback to send magic link emails */
@@ -482,6 +485,9 @@ export declare function initSessionAuthFromEnv(config: {
482
485
  /** Additional email validation. Called after built-in domain/admin checks reject.
483
486
  * Can only widen access, never narrow it. */
484
487
  isEmailAllowed?: (email: string) => boolean | Promise<boolean>;
488
+ /** Transform base SessionUser into an app-specific user type.
489
+ * Called after session validation succeeds. Enables generic session functions. */
490
+ resolveUser?: (user: SessionUser) => Promise<SessionUser> | SessionUser;
485
491
  }): void;
486
492
  /**
487
493
  * Parses cookies from a request's Cookie header.
@@ -580,12 +586,12 @@ export declare function verifyMagicLink(token: string): Promise<Result<{
580
586
  * const result = await validateSession(request);
581
587
  * if (!result.ok) return unauthorizedResponse();
582
588
  */
583
- export declare function validateSession(request: {
589
+ export declare function validateSession<T extends SessionUser = SessionUser>(request: {
584
590
  headers: {
585
591
  get(name: string): string | null;
586
592
  };
587
593
  }): Promise<Result<{
588
- user: SessionUser;
594
+ user: T;
589
595
  session: SessionInfo;
590
596
  refreshedCookie?: string;
591
597
  }>>;
@@ -598,12 +604,12 @@ export declare function validateSession(request: {
598
604
  * if (!result.ok) return resultToResponse(result);
599
605
  * const { user, headers } = result.data!;
600
606
  */
601
- export declare function getSessionUser(request: {
607
+ export declare function getSessionUser<T extends SessionUser = SessionUser>(request: {
602
608
  headers: {
603
609
  get(name: string): string | null;
604
610
  };
605
611
  }): Promise<Result<{
606
- user: SessionUser;
612
+ user: T;
607
613
  headers?: Record<string, string>;
608
614
  }>>;
609
615
  /**
@@ -631,8 +637,8 @@ export declare function destroySession(request: {
631
637
  * })
632
638
  * });
633
639
  */
634
- export declare function withSessionAuth(handler: (request: HttpRequest, context: InvocationContext, auth: {
635
- user: SessionUser;
640
+ export declare function withSessionAuth<T extends SessionUser = SessionUser>(handler: (request: HttpRequest, context: InvocationContext, auth: {
641
+ user: T;
636
642
  headers?: Record<string, string>;
637
643
  }) => Promise<HttpResponseInit>): (request: HttpRequest, context: InvocationContext) => Promise<HttpResponseInit>;
638
644
  /**
@@ -647,8 +653,8 @@ export declare function withSessionAuth(handler: (request: HttpRequest, context:
647
653
  * })
648
654
  * });
649
655
  */
650
- export declare function withSessionAdminAuth(handler: (request: HttpRequest, context: InvocationContext, auth: {
651
- user: SessionUser;
656
+ export declare function withSessionAdminAuth<T extends SessionUser = SessionUser>(handler: (request: HttpRequest, context: InvocationContext, auth: {
657
+ user: T;
652
658
  headers?: Record<string, string>;
653
659
  }) => Promise<HttpResponseInit>): (request: HttpRequest, context: InvocationContext) => Promise<HttpResponseInit>;
654
660
  /**
package/dist/server.js CHANGED
@@ -245,9 +245,9 @@ function requireAuth(authHeader) {
245
245
  return (0, shared_1.ok)(result.data);
246
246
  }
247
247
  /**
248
- * Requires admin role. Use with RoleTokenPayload.
248
+ * Requires admin role. Generic like requireAuth — callers can extend RoleTokenPayload.
249
249
  * @param authHeader - The Authorization header value
250
- * @returns Result with RoleTokenPayload on success, or error with status on failure
250
+ * @returns Result with payload on success, or error with status on failure
251
251
  * @example
252
252
  * const auth = requireAdmin(request.headers.get('Authorization'));
253
253
  * if (!auth.ok) return resultToResponse(auth);
@@ -818,6 +818,7 @@ function initSessionAuthFromEnv(config) {
818
818
  ? adminEmailsStr.split(',').map(e => e.trim().toLowerCase())
819
819
  : undefined,
820
820
  isEmailAllowed: config.isEmailAllowed,
821
+ resolveUser: config.resolveUser,
821
822
  sendEmail: config.sendEmail,
822
823
  });
823
824
  }
@@ -1156,13 +1157,17 @@ async function validateSession(request) {
1156
1157
  const userEntity = await getEntityIfExists(usersClient, USER_PARTITION, sessionEntity.email.toLowerCase());
1157
1158
  if (!userEntity)
1158
1159
  return (0, shared_1.err)('User not found', shared_1.HTTP_STATUS.UNAUTHORIZED);
1159
- const user = {
1160
+ const baseUser = {
1160
1161
  id: userEntity.id,
1161
1162
  email: userEntity.email,
1162
1163
  isAdmin: userEntity.isAdmin,
1163
1164
  createdAt: userEntity.createdAt,
1164
1165
  lastLoginAt: userEntity.lastLoginAt
1165
1166
  };
1167
+ // Resolve to app-specific user type if callback is configured
1168
+ const user = (config.resolveUser
1169
+ ? await config.resolveUser(baseUser)
1170
+ : baseUser);
1166
1171
  const session = {
1167
1172
  id: sessionEntity.id,
1168
1173
  userId: sessionEntity.userId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markwharton/pwa-core",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "Shared patterns for Azure PWA projects",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",