@markwharton/pwa-core 1.8.0 → 2.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.
Files changed (103) hide show
  1. package/dist/{client/api.d.ts → client.d.ts} +85 -9
  2. package/dist/{client/api.js → client.js} +159 -56
  3. package/dist/index.d.ts +10 -2
  4. package/dist/index.js +14 -6
  5. package/dist/server.d.ts +283 -0
  6. package/dist/server.js +476 -0
  7. package/dist/shared.d.ts +150 -0
  8. package/dist/shared.js +124 -0
  9. package/package.json +11 -12
  10. package/dist/__tests__/auth/apiKey.test.d.ts +0 -1
  11. package/dist/__tests__/auth/apiKey.test.js +0 -80
  12. package/dist/__tests__/auth/token.test.d.ts +0 -1
  13. package/dist/__tests__/auth/token.test.js +0 -212
  14. package/dist/__tests__/auth/types.test.d.ts +0 -1
  15. package/dist/__tests__/auth/types.test.js +0 -77
  16. package/dist/__tests__/client/api.test.d.ts +0 -1
  17. package/dist/__tests__/client/api.test.js +0 -369
  18. package/dist/__tests__/client/apiError.test.d.ts +0 -1
  19. package/dist/__tests__/client/apiError.test.js +0 -91
  20. package/dist/__tests__/http/responses.test.d.ts +0 -1
  21. package/dist/__tests__/http/responses.test.js +0 -112
  22. package/dist/__tests__/http/status.test.d.ts +0 -1
  23. package/dist/__tests__/http/status.test.js +0 -27
  24. package/dist/__tests__/server/auth/apiKey.test.d.ts +0 -1
  25. package/dist/__tests__/server/auth/apiKey.test.js +0 -80
  26. package/dist/__tests__/server/auth/token.test.d.ts +0 -1
  27. package/dist/__tests__/server/auth/token.test.js +0 -299
  28. package/dist/__tests__/server/http/responses.test.d.ts +0 -1
  29. package/dist/__tests__/server/http/responses.test.js +0 -112
  30. package/dist/__tests__/server/storage/client.test.d.ts +0 -1
  31. package/dist/__tests__/server/storage/client.test.js +0 -173
  32. package/dist/__tests__/server/storage/keys.test.d.ts +0 -1
  33. package/dist/__tests__/server/storage/keys.test.js +0 -47
  34. package/dist/__tests__/shared/auth/types.test.d.ts +0 -1
  35. package/dist/__tests__/shared/auth/types.test.js +0 -77
  36. package/dist/__tests__/shared/http/status.test.d.ts +0 -1
  37. package/dist/__tests__/shared/http/status.test.js +0 -29
  38. package/dist/__tests__/storage/client.test.d.ts +0 -1
  39. package/dist/__tests__/storage/client.test.js +0 -173
  40. package/dist/__tests__/storage/keys.test.d.ts +0 -1
  41. package/dist/__tests__/storage/keys.test.js +0 -47
  42. package/dist/__tests__/types.test.d.ts +0 -1
  43. package/dist/__tests__/types.test.js +0 -56
  44. package/dist/auth/apiKey.d.ts +0 -44
  45. package/dist/auth/apiKey.js +0 -59
  46. package/dist/auth/index.d.ts +0 -3
  47. package/dist/auth/index.js +0 -22
  48. package/dist/auth/token.d.ts +0 -56
  49. package/dist/auth/token.js +0 -104
  50. package/dist/auth/types.d.ts +0 -63
  51. package/dist/auth/types.js +0 -41
  52. package/dist/client/apiError.d.ts +0 -48
  53. package/dist/client/apiError.js +0 -65
  54. package/dist/client/index.d.ts +0 -3
  55. package/dist/client/index.js +0 -14
  56. package/dist/client/types.d.ts +0 -12
  57. package/dist/client/types.js +0 -5
  58. package/dist/http/index.d.ts +0 -3
  59. package/dist/http/index.js +0 -14
  60. package/dist/http/responses.d.ts +0 -82
  61. package/dist/http/responses.js +0 -132
  62. package/dist/http/status.d.ts +0 -17
  63. package/dist/http/status.js +0 -19
  64. package/dist/http/types.d.ts +0 -10
  65. package/dist/http/types.js +0 -5
  66. package/dist/server/auth/apiKey.d.ts +0 -44
  67. package/dist/server/auth/apiKey.js +0 -59
  68. package/dist/server/auth/index.d.ts +0 -3
  69. package/dist/server/auth/index.js +0 -19
  70. package/dist/server/auth/token.d.ts +0 -102
  71. package/dist/server/auth/token.js +0 -158
  72. package/dist/server/http/index.d.ts +0 -1
  73. package/dist/server/http/index.js +0 -12
  74. package/dist/server/http/responses.d.ts +0 -82
  75. package/dist/server/http/responses.js +0 -132
  76. package/dist/server/index.d.ts +0 -4
  77. package/dist/server/index.js +0 -37
  78. package/dist/server/storage/client.d.ts +0 -48
  79. package/dist/server/storage/client.js +0 -107
  80. package/dist/server/storage/index.d.ts +0 -2
  81. package/dist/server/storage/index.js +0 -11
  82. package/dist/server/storage/keys.d.ts +0 -8
  83. package/dist/server/storage/keys.js +0 -14
  84. package/dist/shared/auth/index.d.ts +0 -2
  85. package/dist/shared/auth/index.js +0 -7
  86. package/dist/shared/auth/types.d.ts +0 -63
  87. package/dist/shared/auth/types.js +0 -41
  88. package/dist/shared/http/index.d.ts +0 -3
  89. package/dist/shared/http/index.js +0 -5
  90. package/dist/shared/http/status.d.ts +0 -19
  91. package/dist/shared/http/status.js +0 -21
  92. package/dist/shared/http/types.d.ts +0 -10
  93. package/dist/shared/http/types.js +0 -5
  94. package/dist/shared/index.d.ts +0 -5
  95. package/dist/shared/index.js +0 -10
  96. package/dist/storage/client.d.ts +0 -48
  97. package/dist/storage/client.js +0 -107
  98. package/dist/storage/index.d.ts +0 -2
  99. package/dist/storage/index.js +0 -11
  100. package/dist/storage/keys.d.ts +0 -8
  101. package/dist/storage/keys.js +0 -14
  102. package/dist/types.d.ts +0 -48
  103. package/dist/types.js +0 -41
@@ -1,132 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.badRequestResponse = badRequestResponse;
4
- exports.unauthorizedResponse = unauthorizedResponse;
5
- exports.forbiddenResponse = forbiddenResponse;
6
- exports.notFoundResponse = notFoundResponse;
7
- exports.conflictResponse = conflictResponse;
8
- exports.handleFunctionError = handleFunctionError;
9
- exports.isNotFoundError = isNotFoundError;
10
- exports.isConflictError = isConflictError;
11
- const status_1 = require("./status");
12
- /**
13
- * Creates a 400 Bad Request response.
14
- * @param message - The error message to return
15
- * @returns Azure Functions HttpResponseInit object
16
- * @example
17
- * if (!body.email) return badRequestResponse('Email is required');
18
- */
19
- function badRequestResponse(message) {
20
- return {
21
- status: status_1.HTTP_STATUS.BAD_REQUEST,
22
- jsonBody: { error: message }
23
- };
24
- }
25
- /**
26
- * Creates a 401 Unauthorized response.
27
- * @param message - The error message (default: 'Unauthorized')
28
- * @returns Azure Functions HttpResponseInit object
29
- * @example
30
- * if (!token) return unauthorizedResponse();
31
- */
32
- function unauthorizedResponse(message = 'Unauthorized') {
33
- return {
34
- status: status_1.HTTP_STATUS.UNAUTHORIZED,
35
- jsonBody: { error: message }
36
- };
37
- }
38
- /**
39
- * Creates a 403 Forbidden response.
40
- * @param message - The error message (default: 'Forbidden')
41
- * @returns Azure Functions HttpResponseInit object
42
- * @example
43
- * if (!isAdmin(payload)) return forbiddenResponse('Admin access required');
44
- */
45
- function forbiddenResponse(message = 'Forbidden') {
46
- return {
47
- status: status_1.HTTP_STATUS.FORBIDDEN,
48
- jsonBody: { error: message }
49
- };
50
- }
51
- /**
52
- * Creates a 404 Not Found response.
53
- * @param resource - The name of the resource that wasn't found
54
- * @returns Azure Functions HttpResponseInit object
55
- * @example
56
- * if (!user) return notFoundResponse('User');
57
- * // Returns: { error: 'User not found' }
58
- */
59
- function notFoundResponse(resource) {
60
- return {
61
- status: status_1.HTTP_STATUS.NOT_FOUND,
62
- jsonBody: { error: `${resource} not found` }
63
- };
64
- }
65
- /**
66
- * Creates a 409 Conflict response.
67
- * @param message - The conflict error message
68
- * @returns Azure Functions HttpResponseInit object
69
- * @example
70
- * if (existingUser) return conflictResponse('Email already registered');
71
- */
72
- function conflictResponse(message) {
73
- return {
74
- status: status_1.HTTP_STATUS.CONFLICT,
75
- jsonBody: { error: message }
76
- };
77
- }
78
- /**
79
- * Handles unexpected errors safely by logging details and returning a generic message.
80
- * Use in catch blocks to avoid exposing internal error details to clients.
81
- * @param error - The caught error
82
- * @param context - Azure Functions InvocationContext for logging
83
- * @returns Azure Functions HttpResponseInit with 500 status
84
- * @example
85
- * try {
86
- * await riskyOperation();
87
- * } catch (error) {
88
- * return handleFunctionError(error, context);
89
- * }
90
- */
91
- function handleFunctionError(error, context) {
92
- const message = error instanceof Error ? error.message : 'Unknown error';
93
- context.error(`Function error: ${message}`);
94
- return {
95
- status: status_1.HTTP_STATUS.INTERNAL_ERROR,
96
- jsonBody: { error: 'Internal server error' }
97
- };
98
- }
99
- /**
100
- * Checks if an error is an Azure Table Storage "not found" error.
101
- * @param error - The caught error
102
- * @returns True if error has statusCode 404
103
- * @example
104
- * try {
105
- * await tableClient.getEntity(pk, rk);
106
- * } catch (error) {
107
- * if (isNotFoundError(error)) return notFoundResponse('Entity');
108
- * throw error;
109
- * }
110
- */
111
- function isNotFoundError(error) {
112
- return (error instanceof Error &&
113
- 'statusCode' in error &&
114
- error.statusCode === 404);
115
- }
116
- /**
117
- * Checks if an error is an Azure Table Storage "conflict" error.
118
- * @param error - The caught error
119
- * @returns True if error has statusCode 409
120
- * @example
121
- * try {
122
- * await tableClient.createEntity(entity);
123
- * } catch (error) {
124
- * if (isConflictError(error)) return conflictResponse('Entity already exists');
125
- * throw error;
126
- * }
127
- */
128
- function isConflictError(error) {
129
- return (error instanceof Error &&
130
- 'statusCode' in error &&
131
- error.statusCode === 409);
132
- }
@@ -1,17 +0,0 @@
1
- /**
2
- * HTTP status codes - use instead of magic numbers
3
- */
4
- export declare const HTTP_STATUS: {
5
- readonly OK: 200;
6
- readonly CREATED: 201;
7
- readonly NO_CONTENT: 204;
8
- readonly BAD_REQUEST: 400;
9
- readonly UNAUTHORIZED: 401;
10
- readonly FORBIDDEN: 403;
11
- readonly NOT_FOUND: 404;
12
- readonly CONFLICT: 409;
13
- readonly GONE: 410;
14
- readonly INTERNAL_ERROR: 500;
15
- readonly SERVICE_UNAVAILABLE: 503;
16
- };
17
- export type HttpStatus = typeof HTTP_STATUS[keyof typeof HTTP_STATUS];
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HTTP_STATUS = void 0;
4
- /**
5
- * HTTP status codes - use instead of magic numbers
6
- */
7
- exports.HTTP_STATUS = {
8
- OK: 200,
9
- CREATED: 201,
10
- NO_CONTENT: 204,
11
- BAD_REQUEST: 400,
12
- UNAUTHORIZED: 401,
13
- FORBIDDEN: 403,
14
- NOT_FOUND: 404,
15
- CONFLICT: 409,
16
- GONE: 410,
17
- INTERNAL_ERROR: 500,
18
- SERVICE_UNAVAILABLE: 503
19
- };
@@ -1,10 +0,0 @@
1
- /**
2
- * HTTP module type definitions
3
- */
4
- /**
5
- * Standard error response structure
6
- */
7
- export interface ErrorResponse {
8
- error: string;
9
- details?: string;
10
- }
@@ -1,5 +0,0 @@
1
- "use strict";
2
- /**
3
- * HTTP module type definitions
4
- */
5
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,44 +0,0 @@
1
- import { Result } from '../../types';
2
- /**
3
- * API Key utilities for machine-to-machine authentication
4
- */
5
- /**
6
- * Extracts API key from the X-API-Key header.
7
- * @param request - Request object with headers.get() method
8
- * @returns The API key string, or null if not present
9
- * @example
10
- * const apiKey = extractApiKey(request);
11
- */
12
- export declare function extractApiKey(request: {
13
- headers: {
14
- get(name: string): string | null;
15
- };
16
- }): string | null;
17
- /**
18
- * Hashes an API key using SHA-256 for secure storage.
19
- * Store this hash in your database, never the raw key.
20
- * @param apiKey - The raw API key to hash
21
- * @returns The SHA-256 hash as a hex string
22
- * @example
23
- * const hash = hashApiKey(rawKey);
24
- * await db.save({ apiKeyHash: hash });
25
- */
26
- export declare function hashApiKey(apiKey: string): string;
27
- /**
28
- * Validates an API key against a stored hash.
29
- * @param apiKey - The API key from the request
30
- * @param storedHash - The hash stored in your database
31
- * @returns Result with ok=true if valid, or error message if invalid
32
- * @example
33
- * const result = validateApiKey(apiKey, user.apiKeyHash);
34
- * if (!result.ok) return httpUnauthorized();
35
- */
36
- export declare function validateApiKey(apiKey: string, storedHash: string): Result<void>;
37
- /**
38
- * Generates a cryptographically secure API key.
39
- * @returns A random 64-character hex string (32 bytes)
40
- * @example
41
- * const apiKey = generateApiKey();
42
- * // Return to user once, store hash in database
43
- */
44
- export declare function generateApiKey(): string;
@@ -1,59 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.extractApiKey = extractApiKey;
4
- exports.hashApiKey = hashApiKey;
5
- exports.validateApiKey = validateApiKey;
6
- exports.generateApiKey = generateApiKey;
7
- const crypto_1 = require("crypto");
8
- const types_1 = require("../../types");
9
- /**
10
- * API Key utilities for machine-to-machine authentication
11
- */
12
- /**
13
- * Extracts API key from the X-API-Key header.
14
- * @param request - Request object with headers.get() method
15
- * @returns The API key string, or null if not present
16
- * @example
17
- * const apiKey = extractApiKey(request);
18
- */
19
- function extractApiKey(request) {
20
- return request.headers.get('X-API-Key');
21
- }
22
- /**
23
- * Hashes an API key using SHA-256 for secure storage.
24
- * Store this hash in your database, never the raw key.
25
- * @param apiKey - The raw API key to hash
26
- * @returns The SHA-256 hash as a hex string
27
- * @example
28
- * const hash = hashApiKey(rawKey);
29
- * await db.save({ apiKeyHash: hash });
30
- */
31
- function hashApiKey(apiKey) {
32
- return (0, crypto_1.createHash)('sha256').update(apiKey).digest('hex');
33
- }
34
- /**
35
- * Validates an API key against a stored hash.
36
- * @param apiKey - The API key from the request
37
- * @param storedHash - The hash stored in your database
38
- * @returns Result with ok=true if valid, or error message if invalid
39
- * @example
40
- * const result = validateApiKey(apiKey, user.apiKeyHash);
41
- * if (!result.ok) return httpUnauthorized();
42
- */
43
- function validateApiKey(apiKey, storedHash) {
44
- const keyHash = hashApiKey(apiKey);
45
- if (keyHash === storedHash) {
46
- return (0, types_1.okVoid)();
47
- }
48
- return (0, types_1.err)('Invalid API key');
49
- }
50
- /**
51
- * Generates a cryptographically secure API key.
52
- * @returns A random 64-character hex string (32 bytes)
53
- * @example
54
- * const apiKey = generateApiKey();
55
- * // Return to user once, store hash in database
56
- */
57
- function generateApiKey() {
58
- return (0, crypto_1.randomBytes)(32).toString('hex');
59
- }
@@ -1,3 +0,0 @@
1
- export { initAuth, getJwtSecret, extractToken, validateToken, generateToken, generateLongLivedToken, requireAuth, requireAdmin, DEFAULT_TOKEN_EXPIRY, DEFAULT_TOKEN_EXPIRY_SECONDS } from './token';
2
- export type { AuthSuccess, AuthFailure, AuthResult } from './token';
3
- export { extractApiKey, hashApiKey, validateApiKey, generateApiKey } from './apiKey';
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateApiKey = exports.validateApiKey = exports.hashApiKey = exports.extractApiKey = exports.DEFAULT_TOKEN_EXPIRY_SECONDS = exports.DEFAULT_TOKEN_EXPIRY = exports.requireAdmin = exports.requireAuth = exports.generateLongLivedToken = exports.generateToken = exports.validateToken = exports.extractToken = exports.getJwtSecret = exports.initAuth = void 0;
4
- var token_1 = require("./token");
5
- Object.defineProperty(exports, "initAuth", { enumerable: true, get: function () { return token_1.initAuth; } });
6
- Object.defineProperty(exports, "getJwtSecret", { enumerable: true, get: function () { return token_1.getJwtSecret; } });
7
- Object.defineProperty(exports, "extractToken", { enumerable: true, get: function () { return token_1.extractToken; } });
8
- Object.defineProperty(exports, "validateToken", { enumerable: true, get: function () { return token_1.validateToken; } });
9
- Object.defineProperty(exports, "generateToken", { enumerable: true, get: function () { return token_1.generateToken; } });
10
- Object.defineProperty(exports, "generateLongLivedToken", { enumerable: true, get: function () { return token_1.generateLongLivedToken; } });
11
- Object.defineProperty(exports, "requireAuth", { enumerable: true, get: function () { return token_1.requireAuth; } });
12
- Object.defineProperty(exports, "requireAdmin", { enumerable: true, get: function () { return token_1.requireAdmin; } });
13
- Object.defineProperty(exports, "DEFAULT_TOKEN_EXPIRY", { enumerable: true, get: function () { return token_1.DEFAULT_TOKEN_EXPIRY; } });
14
- Object.defineProperty(exports, "DEFAULT_TOKEN_EXPIRY_SECONDS", { enumerable: true, get: function () { return token_1.DEFAULT_TOKEN_EXPIRY_SECONDS; } });
15
- var apiKey_1 = require("./apiKey");
16
- Object.defineProperty(exports, "extractApiKey", { enumerable: true, get: function () { return apiKey_1.extractApiKey; } });
17
- Object.defineProperty(exports, "hashApiKey", { enumerable: true, get: function () { return apiKey_1.hashApiKey; } });
18
- Object.defineProperty(exports, "validateApiKey", { enumerable: true, get: function () { return apiKey_1.validateApiKey; } });
19
- Object.defineProperty(exports, "generateApiKey", { enumerable: true, get: function () { return apiKey_1.generateApiKey; } });
@@ -1,102 +0,0 @@
1
- import { HttpResponseInit } from '@azure/functions';
2
- import { Result } from '../../types';
3
- import { BaseJwtPayload, RoleTokenPayload } from '../../shared/auth/types';
4
- /**
5
- * Initializes the JWT authentication system. Call once at application startup.
6
- * @param secret - The JWT secret key (from environment variable)
7
- * @param minLength - Minimum required secret length (default: 32)
8
- * @throws Error if secret is missing or too short
9
- * @example
10
- * initAuth(process.env.JWT_SECRET);
11
- */
12
- export declare function initAuth(secret: string | undefined, minLength?: number): void;
13
- /**
14
- * Gets the configured JWT secret.
15
- * @returns The JWT secret string
16
- * @throws Error if initAuth() has not been called
17
- */
18
- export declare function getJwtSecret(): string;
19
- /**
20
- * Extracts the Bearer token from an Authorization header.
21
- * @param authHeader - The Authorization header value
22
- * @returns The token string, or null if not a valid Bearer token
23
- * @example
24
- * const token = extractToken(request.headers.get('Authorization'));
25
- */
26
- export declare function extractToken(authHeader: string | null): string | null;
27
- /**
28
- * Validates and decodes a JWT token.
29
- * @typeParam T - The expected payload type (extends object)
30
- * @param token - The JWT token string to validate
31
- * @returns Result with decoded payload on success, or error message on failure
32
- * @example
33
- * const result = validateToken<UserPayload>(token);
34
- * if (result.ok) {
35
- * console.log(result.data.username);
36
- * }
37
- */
38
- export declare function validateToken<T extends object>(token: string): Result<T>;
39
- /**
40
- * Generates a signed JWT token with the given payload.
41
- * @typeParam T - The payload type (extends object)
42
- * @param payload - The data to encode in the token
43
- * @param expiresIn - Token expiration time (default: '7d')
44
- * @returns The signed JWT token string
45
- * @example
46
- * const token = generateToken({ userId: '123', role: 'admin' }, '1h');
47
- */
48
- export declare function generateToken<T extends object>(payload: T, expiresIn?: string): string;
49
- /**
50
- * Generates a long-lived JWT token for machine/API access.
51
- * @typeParam T - The payload type (extends object)
52
- * @param payload - The data to encode in the token
53
- * @param expiresInDays - Token expiration in days (default: 3650 ≈ 10 years)
54
- * @returns The signed JWT token string
55
- * @example
56
- * const apiToken = generateLongLivedToken({ machineId: 'server-1' });
57
- */
58
- export declare function generateLongLivedToken<T extends object>(payload: T, expiresInDays?: number): string;
59
- /**
60
- * Successful auth result with typed payload.
61
- */
62
- export interface AuthSuccess<T extends BaseJwtPayload> {
63
- authorized: true;
64
- payload: T;
65
- }
66
- /**
67
- * Failed auth result with HTTP response.
68
- */
69
- export interface AuthFailure {
70
- authorized: false;
71
- response: HttpResponseInit;
72
- }
73
- /**
74
- * Discriminated union for auth results.
75
- * Use `auth.authorized` to narrow the type.
76
- */
77
- export type AuthResult<T extends BaseJwtPayload> = AuthSuccess<T> | AuthFailure;
78
- /** Default token expiry string for generateToken (7 days) */
79
- export declare const DEFAULT_TOKEN_EXPIRY = "7d";
80
- /** Default token expiry in seconds (7 days = 604800 seconds) */
81
- export declare const DEFAULT_TOKEN_EXPIRY_SECONDS: number;
82
- /**
83
- * Validates auth header and returns typed payload or error response.
84
- * @typeParam T - The expected payload type (extends BaseJwtPayload)
85
- * @param authHeader - The Authorization header value
86
- * @returns AuthResult with payload on success, or HTTP response on failure
87
- * @example
88
- * const auth = requireAuth<UsernameTokenPayload>(request.headers.get('Authorization'));
89
- * if (!auth.authorized) return auth.response;
90
- * console.log(auth.payload.username);
91
- */
92
- export declare function requireAuth<T extends BaseJwtPayload>(authHeader: string | null): AuthResult<T>;
93
- /**
94
- * Requires admin role. Use with RoleTokenPayload.
95
- * @param authHeader - The Authorization header value
96
- * @returns AuthResult with RoleTokenPayload on success, or HTTP response on failure
97
- * @example
98
- * const auth = requireAdmin(request.headers.get('Authorization'));
99
- * if (!auth.authorized) return auth.response;
100
- * // User is admin
101
- */
102
- export declare function requireAdmin(authHeader: string | null): AuthResult<RoleTokenPayload>;
@@ -1,158 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DEFAULT_TOKEN_EXPIRY_SECONDS = exports.DEFAULT_TOKEN_EXPIRY = void 0;
7
- exports.initAuth = initAuth;
8
- exports.getJwtSecret = getJwtSecret;
9
- exports.extractToken = extractToken;
10
- exports.validateToken = validateToken;
11
- exports.generateToken = generateToken;
12
- exports.generateLongLivedToken = generateLongLivedToken;
13
- exports.requireAuth = requireAuth;
14
- exports.requireAdmin = requireAdmin;
15
- const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
16
- const types_1 = require("../../types");
17
- const types_2 = require("../../shared/auth/types");
18
- const responses_1 = require("../http/responses");
19
- /**
20
- * JWT token utilities - works with any payload structure
21
- * Use BaseJwtPayload or extend it for type safety
22
- */
23
- let jwtSecret = null;
24
- /**
25
- * Initializes the JWT authentication system. Call once at application startup.
26
- * @param secret - The JWT secret key (from environment variable)
27
- * @param minLength - Minimum required secret length (default: 32)
28
- * @throws Error if secret is missing or too short
29
- * @example
30
- * initAuth(process.env.JWT_SECRET);
31
- */
32
- function initAuth(secret, minLength = 32) {
33
- if (!secret || secret.length < minLength) {
34
- throw new Error(`JWT_SECRET must be at least ${minLength} characters`);
35
- }
36
- jwtSecret = secret;
37
- }
38
- /**
39
- * Gets the configured JWT secret.
40
- * @returns The JWT secret string
41
- * @throws Error if initAuth() has not been called
42
- */
43
- function getJwtSecret() {
44
- if (!jwtSecret) {
45
- throw new Error('Auth not initialized. Call initAuth() first.');
46
- }
47
- return jwtSecret;
48
- }
49
- /**
50
- * Extracts the Bearer token from an Authorization header.
51
- * @param authHeader - The Authorization header value
52
- * @returns The token string, or null if not a valid Bearer token
53
- * @example
54
- * const token = extractToken(request.headers.get('Authorization'));
55
- */
56
- function extractToken(authHeader) {
57
- if (!authHeader?.startsWith('Bearer ')) {
58
- return null;
59
- }
60
- return authHeader.slice(7);
61
- }
62
- /**
63
- * Validates and decodes a JWT token.
64
- * @typeParam T - The expected payload type (extends object)
65
- * @param token - The JWT token string to validate
66
- * @returns Result with decoded payload on success, or error message on failure
67
- * @example
68
- * const result = validateToken<UserPayload>(token);
69
- * if (result.ok) {
70
- * console.log(result.data.username);
71
- * }
72
- */
73
- function validateToken(token) {
74
- try {
75
- const payload = jsonwebtoken_1.default.verify(token, getJwtSecret());
76
- if (typeof payload === 'object' && payload !== null) {
77
- return (0, types_1.ok)(payload);
78
- }
79
- return (0, types_1.err)('Invalid token payload');
80
- }
81
- catch (error) {
82
- const message = error instanceof Error ? error.message : 'Token validation failed';
83
- return (0, types_1.err)(message);
84
- }
85
- }
86
- /**
87
- * Generates a signed JWT token with the given payload.
88
- * @typeParam T - The payload type (extends object)
89
- * @param payload - The data to encode in the token
90
- * @param expiresIn - Token expiration time (default: '7d')
91
- * @returns The signed JWT token string
92
- * @example
93
- * const token = generateToken({ userId: '123', role: 'admin' }, '1h');
94
- */
95
- function generateToken(payload, expiresIn = '7d') {
96
- return jsonwebtoken_1.default.sign(payload, getJwtSecret(), { expiresIn });
97
- }
98
- /**
99
- * Generates a long-lived JWT token for machine/API access.
100
- * @typeParam T - The payload type (extends object)
101
- * @param payload - The data to encode in the token
102
- * @param expiresInDays - Token expiration in days (default: 3650 ≈ 10 years)
103
- * @returns The signed JWT token string
104
- * @example
105
- * const apiToken = generateLongLivedToken({ machineId: 'server-1' });
106
- */
107
- function generateLongLivedToken(payload, expiresInDays = 3650) {
108
- return jsonwebtoken_1.default.sign(payload, getJwtSecret(), { expiresIn: `${expiresInDays}d` });
109
- }
110
- // ============================================================================
111
- // Token Expiry Constants
112
- // ============================================================================
113
- /** Default token expiry string for generateToken (7 days) */
114
- exports.DEFAULT_TOKEN_EXPIRY = '7d';
115
- /** Default token expiry in seconds (7 days = 604800 seconds) */
116
- exports.DEFAULT_TOKEN_EXPIRY_SECONDS = 7 * 24 * 60 * 60;
117
- // ============================================================================
118
- // Auth Helpers
119
- // ============================================================================
120
- /**
121
- * Validates auth header and returns typed payload or error response.
122
- * @typeParam T - The expected payload type (extends BaseJwtPayload)
123
- * @param authHeader - The Authorization header value
124
- * @returns AuthResult with payload on success, or HTTP response on failure
125
- * @example
126
- * const auth = requireAuth<UsernameTokenPayload>(request.headers.get('Authorization'));
127
- * if (!auth.authorized) return auth.response;
128
- * console.log(auth.payload.username);
129
- */
130
- function requireAuth(authHeader) {
131
- const token = extractToken(authHeader);
132
- if (!token) {
133
- return { authorized: false, response: (0, responses_1.unauthorizedResponse)() };
134
- }
135
- const result = validateToken(token);
136
- if (!result.ok) {
137
- return { authorized: false, response: (0, responses_1.unauthorizedResponse)(result.error) };
138
- }
139
- return { authorized: true, payload: result.data };
140
- }
141
- /**
142
- * Requires admin role. Use with RoleTokenPayload.
143
- * @param authHeader - The Authorization header value
144
- * @returns AuthResult with RoleTokenPayload on success, or HTTP response on failure
145
- * @example
146
- * const auth = requireAdmin(request.headers.get('Authorization'));
147
- * if (!auth.authorized) return auth.response;
148
- * // User is admin
149
- */
150
- function requireAdmin(authHeader) {
151
- const auth = requireAuth(authHeader);
152
- if (!auth.authorized)
153
- return auth;
154
- if (!(0, types_2.isAdmin)(auth.payload)) {
155
- return { authorized: false, response: (0, responses_1.forbiddenResponse)('Admin access required') };
156
- }
157
- return auth;
158
- }
@@ -1 +0,0 @@
1
- export { badRequestResponse, unauthorizedResponse, forbiddenResponse, notFoundResponse, conflictResponse, handleFunctionError, isNotFoundError, isConflictError } from './responses';
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isConflictError = exports.isNotFoundError = exports.handleFunctionError = exports.conflictResponse = exports.notFoundResponse = exports.forbiddenResponse = exports.unauthorizedResponse = exports.badRequestResponse = void 0;
4
- var responses_1 = require("./responses");
5
- Object.defineProperty(exports, "badRequestResponse", { enumerable: true, get: function () { return responses_1.badRequestResponse; } });
6
- Object.defineProperty(exports, "unauthorizedResponse", { enumerable: true, get: function () { return responses_1.unauthorizedResponse; } });
7
- Object.defineProperty(exports, "forbiddenResponse", { enumerable: true, get: function () { return responses_1.forbiddenResponse; } });
8
- Object.defineProperty(exports, "notFoundResponse", { enumerable: true, get: function () { return responses_1.notFoundResponse; } });
9
- Object.defineProperty(exports, "conflictResponse", { enumerable: true, get: function () { return responses_1.conflictResponse; } });
10
- Object.defineProperty(exports, "handleFunctionError", { enumerable: true, get: function () { return responses_1.handleFunctionError; } });
11
- Object.defineProperty(exports, "isNotFoundError", { enumerable: true, get: function () { return responses_1.isNotFoundError; } });
12
- Object.defineProperty(exports, "isConflictError", { enumerable: true, get: function () { return responses_1.isConflictError; } });
@@ -1,82 +0,0 @@
1
- import { HttpResponseInit, InvocationContext } from '@azure/functions';
2
- /**
3
- * Creates a 400 Bad Request response.
4
- * @param message - The error message to return
5
- * @returns Azure Functions HttpResponseInit object
6
- * @example
7
- * if (!body.email) return badRequestResponse('Email is required');
8
- */
9
- export declare function badRequestResponse(message: string): HttpResponseInit;
10
- /**
11
- * Creates a 401 Unauthorized response.
12
- * @param message - The error message (default: 'Unauthorized')
13
- * @returns Azure Functions HttpResponseInit object
14
- * @example
15
- * if (!token) return unauthorizedResponse();
16
- */
17
- export declare function unauthorizedResponse(message?: string): HttpResponseInit;
18
- /**
19
- * Creates a 403 Forbidden response.
20
- * @param message - The error message (default: 'Forbidden')
21
- * @returns Azure Functions HttpResponseInit object
22
- * @example
23
- * if (!isAdmin(payload)) return forbiddenResponse('Admin access required');
24
- */
25
- export declare function forbiddenResponse(message?: string): HttpResponseInit;
26
- /**
27
- * Creates a 404 Not Found response.
28
- * @param resource - The name of the resource that wasn't found
29
- * @returns Azure Functions HttpResponseInit object
30
- * @example
31
- * if (!user) return notFoundResponse('User');
32
- * // Returns: { error: 'User not found' }
33
- */
34
- export declare function notFoundResponse(resource: string): HttpResponseInit;
35
- /**
36
- * Creates a 409 Conflict response.
37
- * @param message - The conflict error message
38
- * @returns Azure Functions HttpResponseInit object
39
- * @example
40
- * if (existingUser) return conflictResponse('Email already registered');
41
- */
42
- export declare function conflictResponse(message: string): HttpResponseInit;
43
- /**
44
- * Handles unexpected errors safely by logging details and returning a generic message.
45
- * Use in catch blocks to avoid exposing internal error details to clients.
46
- * @param error - The caught error
47
- * @param context - Azure Functions InvocationContext for logging
48
- * @returns Azure Functions HttpResponseInit with 500 status
49
- * @example
50
- * try {
51
- * await riskyOperation();
52
- * } catch (error) {
53
- * return handleFunctionError(error, context);
54
- * }
55
- */
56
- export declare function handleFunctionError(error: unknown, context: InvocationContext): HttpResponseInit;
57
- /**
58
- * Checks if an error is an Azure Table Storage "not found" error.
59
- * @param error - The caught error
60
- * @returns True if error has statusCode 404
61
- * @example
62
- * try {
63
- * await tableClient.getEntity(pk, rk);
64
- * } catch (error) {
65
- * if (isNotFoundError(error)) return notFoundResponse('Entity');
66
- * throw error;
67
- * }
68
- */
69
- export declare function isNotFoundError(error: unknown): boolean;
70
- /**
71
- * Checks if an error is an Azure Table Storage "conflict" error.
72
- * @param error - The caught error
73
- * @returns True if error has statusCode 409
74
- * @example
75
- * try {
76
- * await tableClient.createEntity(entity);
77
- * } catch (error) {
78
- * if (isConflictError(error)) return conflictResponse('Entity already exists');
79
- * throw error;
80
- * }
81
- */
82
- export declare function isConflictError(error: unknown): boolean;