@markwharton/pwa-core 3.4.2 → 4.0.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.
package/dist/server.d.ts CHANGED
@@ -23,12 +23,11 @@ export declare function initAuth(config: {
23
23
  /**
24
24
  * Initializes JWT authentication from environment variables.
25
25
  * Reads JWT_SECRET from process.env.
26
- * @param minLength - Minimum required secret length (default: 32)
27
26
  * @throws Error if JWT_SECRET is missing or too short
28
27
  * @example
29
28
  * initAuthFromEnv(); // Uses process.env.JWT_SECRET
30
29
  */
31
- export declare function initAuthFromEnv(minLength?: number): void;
30
+ export declare function initAuthFromEnv(): void;
32
31
  /**
33
32
  * Gets the configured JWT secret.
34
33
  * @returns The JWT secret string
@@ -75,50 +74,31 @@ export declare function generateToken<T extends object>(payload: T, expiresIn?:
75
74
  * const apiToken = generateLongLivedToken({ machineId: 'server-1' });
76
75
  */
77
76
  export declare function generateLongLivedToken<T extends object>(payload: T, expiresInDays?: number): string;
78
- /**
79
- * Successful auth result with typed payload.
80
- */
81
- export interface AuthSuccess<T extends BaseJwtPayload> {
82
- authorized: true;
83
- payload: T;
84
- }
85
- /**
86
- * Failed auth result with HTTP response.
87
- */
88
- export interface AuthFailure {
89
- authorized: false;
90
- response: HttpResponseInit;
91
- }
92
- /**
93
- * Discriminated union for auth results.
94
- * Use `auth.authorized` to narrow the type.
95
- */
96
- export type AuthResult<T extends BaseJwtPayload> = AuthSuccess<T> | AuthFailure;
97
77
  /** Default token expiry string for generateToken (7 days) */
98
78
  export declare const DEFAULT_TOKEN_EXPIRY = "7d";
99
79
  /** Default token expiry in seconds (7 days = 604800 seconds) */
100
80
  export declare const DEFAULT_TOKEN_EXPIRY_SECONDS: number;
101
81
  /**
102
- * Validates auth header and returns typed payload or error response.
82
+ * Validates auth header and returns typed payload or error result.
103
83
  * @typeParam T - The expected payload type (extends BaseJwtPayload)
104
84
  * @param authHeader - The Authorization header value
105
- * @returns AuthResult with payload on success, or HTTP response on failure
85
+ * @returns Result with payload on success, or error with status on failure
106
86
  * @example
107
87
  * const auth = requireAuth<UsernameTokenPayload>(request.headers.get('Authorization'));
108
- * if (!auth.authorized) return auth.response;
109
- * console.log(auth.payload.username);
88
+ * if (!auth.ok) return resultToResponse(auth);
89
+ * console.log(auth.data.username);
110
90
  */
111
- export declare function requireAuth<T extends BaseJwtPayload>(authHeader: string | null): AuthResult<T>;
91
+ export declare function requireAuth<T extends BaseJwtPayload>(authHeader: string | null): Result<T>;
112
92
  /**
113
93
  * Requires admin role. Use with RoleTokenPayload.
114
94
  * @param authHeader - The Authorization header value
115
- * @returns AuthResult with RoleTokenPayload on success, or HTTP response on failure
95
+ * @returns Result with RoleTokenPayload on success, or error with status on failure
116
96
  * @example
117
97
  * const auth = requireAdmin(request.headers.get('Authorization'));
118
- * if (!auth.authorized) return auth.response;
98
+ * if (!auth.ok) return resultToResponse(auth);
119
99
  * // User is admin
120
100
  */
121
- export declare function requireAdmin(authHeader: string | null): AuthResult<RoleTokenPayload>;
101
+ export declare function requireAdmin(authHeader: string | null): Result<RoleTokenPayload>;
122
102
  /**
123
103
  * Extracts API key from the X-API-Key header.
124
104
  * @param request - Request object with headers.get() method
@@ -259,12 +239,14 @@ export declare function initErrorHandling(config?: {
259
239
  * Initializes error handling from environment variables.
260
240
  * Currently a no-op but provides consistent API for future error config
261
241
  * (e.g., ERROR_LOG_LEVEL, ERROR_INCLUDE_STACK).
262
- * @param callback - Optional callback invoked when handleFunctionError is called (fire-and-forget)
242
+ * @param config - Optional config with onError callback invoked when handleFunctionError is called (fire-and-forget)
263
243
  * @example
264
244
  * initErrorHandlingFromEnv(); // Uses process.env automatically
265
- * initErrorHandlingFromEnv((op, msg) => sendAlert(op, msg));
245
+ * initErrorHandlingFromEnv({ onError: (op, msg) => sendAlert(op, msg) });
266
246
  */
267
- export declare function initErrorHandlingFromEnv(callback?: ErrorCallback): void;
247
+ export declare function initErrorHandlingFromEnv(config?: {
248
+ onError?: ErrorCallback;
249
+ }): void;
268
250
  /**
269
251
  * Handles unexpected errors safely by logging details and returning a generic message.
270
252
  * Use in catch blocks to avoid exposing internal error details to clients.
@@ -397,15 +379,16 @@ export declare function upsertEntity<T extends {
397
379
  }>(client: TableClient, entity: T): Promise<void>;
398
380
  /**
399
381
  * Deletes an entity from Azure Table Storage.
400
- * Returns true on success, false on error (swallows errors).
382
+ * Returns ok(true) if deleted, ok(false) if not found (not an error), err() on real failures.
401
383
  * @param client - The TableClient instance
402
384
  * @param partitionKey - The partition key
403
385
  * @param rowKey - The row key
404
- * @returns True if deleted successfully, false on error
386
+ * @returns Result with true if deleted, false if not found, or error on failure
405
387
  * @example
406
- * const deleted = await deleteEntity(client, 'session', sessionId);
388
+ * const result = await deleteEntity(client, 'session', sessionId);
389
+ * if (!result.ok) console.error(result.error);
407
390
  */
408
- export declare function deleteEntity(client: TableClient, partitionKey: string, rowKey: string): Promise<boolean>;
391
+ export declare function deleteEntity(client: TableClient, partitionKey: string, rowKey: string): Promise<Result<boolean>>;
409
392
  /**
410
393
  * Lists all entities in a partition.
411
394
  * @typeParam T - The entity type
@@ -458,7 +441,8 @@ export interface SessionAuthConfig {
458
441
  allowedDomain?: string;
459
442
  /** Emails that get isAdmin=true */
460
443
  adminEmails?: string[];
461
- /** Custom email validation callback (overrides default allowedEmails/allowedDomain check). Supports async for database lookups. */
444
+ /** Additional email validation. Called after built-in domain/admin checks reject.
445
+ * Can only widen access, never narrow it. Supports async for database lookups. */
462
446
  isEmailAllowed?: (email: string) => boolean | Promise<boolean>;
463
447
  /** Base URL for magic links and SWA preview URL validation */
464
448
  appBaseUrl?: string;
@@ -480,16 +464,25 @@ export declare function initSessionAuth(config: SessionAuthConfig): void;
480
464
  /**
481
465
  * Initializes session auth from environment variables.
482
466
  * Reads: SESSION_COOKIE_NAME, APP_BASE_URL, ALLOWED_EMAILS, ALLOWED_DOMAIN, ADMIN_EMAILS.
483
- * @param sendEmail - Required callback to send magic link emails
484
- * @param overrides - Optional config overrides (e.g., isEmailAllowed callback)
467
+ * Only callbacks go in the config object data comes from env vars.
468
+ * Use initSessionAuth() directly for full control.
469
+ * @param config - Required config with sendEmail callback and optional isEmailAllowed
485
470
  * @throws Error if sendEmail is not provided
486
471
  * @example
487
- * initSessionAuthFromEnv(async (to, magicLink) => {
488
- * await resend.emails.send({ to, html: `<a href="${magicLink}">Sign In</a>` });
489
- * return true;
490
- * }, { isEmailAllowed: async (email) => lookupInDatabase(email) });
472
+ * initSessionAuthFromEnv({
473
+ * sendEmail: async (to, magicLink) => {
474
+ * await resend.emails.send({ to, html: `<a href="${magicLink}">Sign In</a>` });
475
+ * return true;
476
+ * },
477
+ * isEmailAllowed: async (email) => lookupInDatabase(email),
478
+ * });
491
479
  */
492
- export declare function initSessionAuthFromEnv(sendEmail: (to: string, magicLink: string) => Promise<boolean>, overrides?: Partial<Omit<SessionAuthConfig, 'sendEmail'>>): void;
480
+ export declare function initSessionAuthFromEnv(config: {
481
+ sendEmail: (to: string, magicLink: string) => Promise<boolean>;
482
+ /** Additional email validation. Called after built-in domain/admin checks reject.
483
+ * Can only widen access, never narrow it. */
484
+ isEmailAllowed?: (email: string) => boolean | Promise<boolean>;
485
+ }): void;
493
486
  /**
494
487
  * Parses cookies from a request's Cookie header.
495
488
  * @param request - Request object with headers.get() method
@@ -582,37 +575,37 @@ export declare function verifyMagicLink(token: string): Promise<Result<{
582
575
  * Validates a session cookie and returns the user and session info.
583
576
  * Performs sliding window refresh if the session is close to expiry.
584
577
  * @param request - Request object with headers.get() method
585
- * @returns User, session, and optional refreshed cookie, or null if invalid
578
+ * @returns Result with user, session, and optional refreshed cookie
586
579
  * @example
587
580
  * const result = await validateSession(request);
588
- * if (!result) return unauthorizedResponse();
581
+ * if (!result.ok) return unauthorizedResponse();
589
582
  */
590
583
  export declare function validateSession(request: {
591
584
  headers: {
592
585
  get(name: string): string | null;
593
586
  };
594
- }): Promise<{
587
+ }): Promise<Result<{
595
588
  user: SessionUser;
596
589
  session: SessionInfo;
597
590
  refreshedCookie?: string;
598
- } | null>;
591
+ }>>;
599
592
  /**
600
593
  * Convenience function: validates session and returns user with optional refresh headers.
601
594
  * @param request - Request object with headers.get() method
602
- * @returns User and optional Set-Cookie headers, or null if not authenticated
595
+ * @returns Result with user and optional Set-Cookie headers
603
596
  * @example
604
597
  * const result = await getSessionUser(request);
605
- * if (!result) return unauthorizedResponse();
606
- * return { headers: result.headers, jsonBody: { user: result.user } };
598
+ * if (!result.ok) return resultToResponse(result);
599
+ * const { user, headers } = result.data!;
607
600
  */
608
601
  export declare function getSessionUser(request: {
609
602
  headers: {
610
603
  get(name: string): string | null;
611
604
  };
612
- }): Promise<{
605
+ }): Promise<Result<{
613
606
  user: SessionUser;
614
607
  headers?: Record<string, string>;
615
- } | null>;
608
+ }>>;
616
609
  /**
617
610
  * Destroys the current session and returns a logout cookie string.
618
611
  * @param request - Request object with headers.get() method
@@ -676,4 +669,41 @@ export declare function deleteExpiredSessions(): Promise<number>;
676
669
  * context.log(`Cleaned up ${deleted} expired magic links`);
677
670
  */
678
671
  export declare function deleteExpiredMagicLinks(): Promise<number>;
672
+ /**
673
+ * Checks if any environment variables contain Key Vault references.
674
+ * Useful for skipping resolution in development environments.
675
+ * @returns True if any env vars match the @Microsoft.KeyVault pattern
676
+ * @example
677
+ * if (hasKeyVaultReferences()) {
678
+ * await resolveKeyVaultReferences();
679
+ * }
680
+ */
681
+ export declare function hasKeyVaultReferences(): boolean;
682
+ /**
683
+ * Resolves all @Microsoft.KeyVault(SecretUri=...) references in process.env.
684
+ * Replaces env var values in-place with the resolved secret values.
685
+ * Uses DefaultAzureCredential for authentication (managed identity in Azure, az cli locally).
686
+ *
687
+ * Requires @azure/keyvault-secrets as a peer dependency.
688
+ *
689
+ * @returns Number of secrets resolved
690
+ * @throws Error if any secret resolution fails (fail-fast)
691
+ * @example
692
+ * // In sessionAuthInit.ts (before any other initialization):
693
+ * if (hasKeyVaultReferences()) {
694
+ * const count = await resolveKeyVaultReferences();
695
+ * console.log(`Resolved ${count} Key Vault secrets`);
696
+ * }
697
+ */
698
+ export declare function resolveKeyVaultReferences(): Promise<number>;
699
+ /**
700
+ * Convert a failed Result to an HttpResponseInit.
701
+ * Use after checking `!result.ok` to return the error as an HTTP response.
702
+ * @param result - A failed Result (ok=false)
703
+ * @returns HttpResponseInit with the error status and message
704
+ * @example
705
+ * const auth = requireAuth<UsernameTokenPayload>(authHeader);
706
+ * if (!auth.ok) return resultToResponse(auth);
707
+ */
708
+ export declare function resultToResponse(result: Result<unknown>): HttpResponseInit;
679
709
  export { Result, ok, okVoid, err, getErrorMessage, BaseJwtPayload, UserTokenPayload, UsernameTokenPayload, RoleTokenPayload, hasUsername, hasRole, isAdmin, HTTP_STATUS, HttpStatus, ErrorResponse, SessionUser, SessionInfo, MagicLinkRequest, SessionAuthResponse } from './shared';