@markwharton/pwa-core 1.2.0 → 1.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.
Files changed (83) hide show
  1. package/dist/__tests__/auth/apiKey.test.d.ts +1 -0
  2. package/dist/__tests__/auth/apiKey.test.js +80 -0
  3. package/dist/__tests__/auth/token.test.d.ts +1 -0
  4. package/dist/__tests__/auth/token.test.js +212 -0
  5. package/dist/__tests__/auth/types.test.d.ts +1 -0
  6. package/dist/__tests__/auth/types.test.js +77 -0
  7. package/dist/__tests__/client/api.test.d.ts +1 -0
  8. package/dist/__tests__/client/api.test.js +334 -0
  9. package/dist/__tests__/client/apiError.test.d.ts +1 -0
  10. package/dist/__tests__/client/apiError.test.js +58 -0
  11. package/dist/__tests__/http/responses.test.d.ts +1 -0
  12. package/dist/__tests__/http/responses.test.js +112 -0
  13. package/dist/__tests__/http/status.test.d.ts +1 -0
  14. package/dist/__tests__/http/status.test.js +27 -0
  15. package/dist/__tests__/server/auth/apiKey.test.d.ts +1 -0
  16. package/dist/__tests__/server/auth/apiKey.test.js +80 -0
  17. package/dist/__tests__/server/auth/token.test.d.ts +1 -0
  18. package/dist/__tests__/server/auth/token.test.js +212 -0
  19. package/dist/__tests__/server/http/responses.test.d.ts +1 -0
  20. package/dist/__tests__/server/http/responses.test.js +112 -0
  21. package/dist/__tests__/server/storage/client.test.d.ts +1 -0
  22. package/dist/__tests__/server/storage/client.test.js +173 -0
  23. package/dist/__tests__/server/storage/keys.test.d.ts +1 -0
  24. package/dist/__tests__/server/storage/keys.test.js +47 -0
  25. package/dist/__tests__/shared/auth/types.test.d.ts +1 -0
  26. package/dist/__tests__/shared/auth/types.test.js +77 -0
  27. package/dist/__tests__/shared/http/status.test.d.ts +1 -0
  28. package/dist/__tests__/shared/http/status.test.js +27 -0
  29. package/dist/__tests__/storage/client.test.d.ts +1 -0
  30. package/dist/__tests__/storage/client.test.js +173 -0
  31. package/dist/__tests__/storage/keys.test.d.ts +1 -0
  32. package/dist/__tests__/storage/keys.test.js +47 -0
  33. package/dist/__tests__/types.test.d.ts +1 -0
  34. package/dist/__tests__/types.test.js +56 -0
  35. package/dist/auth/apiKey.d.ts +24 -7
  36. package/dist/auth/apiKey.js +24 -7
  37. package/dist/auth/token.d.ts +37 -10
  38. package/dist/auth/token.js +37 -10
  39. package/dist/auth/types.d.ts +21 -3
  40. package/dist/auth/types.js +21 -3
  41. package/dist/client/api.d.ts +70 -9
  42. package/dist/client/api.js +70 -9
  43. package/dist/client/apiError.d.ts +22 -5
  44. package/dist/client/apiError.js +22 -5
  45. package/dist/http/responses.d.ts +57 -8
  46. package/dist/http/responses.js +57 -8
  47. package/dist/index.d.ts +2 -4
  48. package/dist/index.js +6 -5
  49. package/dist/server/auth/apiKey.d.ts +44 -0
  50. package/dist/server/auth/apiKey.js +59 -0
  51. package/dist/server/auth/index.d.ts +2 -0
  52. package/dist/server/auth/index.js +15 -0
  53. package/dist/server/auth/token.d.ts +56 -0
  54. package/dist/server/auth/token.js +104 -0
  55. package/dist/server/http/index.d.ts +1 -0
  56. package/dist/server/http/index.js +12 -0
  57. package/dist/server/http/responses.d.ts +82 -0
  58. package/dist/server/http/responses.js +132 -0
  59. package/dist/server/index.d.ts +3 -0
  60. package/dist/server/index.js +33 -0
  61. package/dist/server/storage/client.d.ts +48 -0
  62. package/dist/server/storage/client.js +107 -0
  63. package/dist/server/storage/index.d.ts +2 -0
  64. package/dist/server/storage/index.js +11 -0
  65. package/dist/server/storage/keys.d.ts +8 -0
  66. package/dist/server/storage/keys.js +14 -0
  67. package/dist/shared/auth/index.d.ts +2 -0
  68. package/dist/shared/auth/index.js +7 -0
  69. package/dist/shared/auth/types.d.ts +63 -0
  70. package/dist/shared/auth/types.js +41 -0
  71. package/dist/shared/http/index.d.ts +3 -0
  72. package/dist/shared/http/index.js +5 -0
  73. package/dist/shared/http/status.d.ts +17 -0
  74. package/dist/shared/http/status.js +19 -0
  75. package/dist/shared/http/types.d.ts +10 -0
  76. package/dist/shared/http/types.js +5 -0
  77. package/dist/shared/index.d.ts +5 -0
  78. package/dist/shared/index.js +10 -0
  79. package/dist/storage/client.d.ts +29 -6
  80. package/dist/storage/client.js +29 -6
  81. package/dist/types.d.ts +16 -3
  82. package/dist/types.js +16 -3
  83. package/package.json +9 -13
@@ -1,37 +1,98 @@
1
1
  import { ApiResponse } from './types';
2
2
  /**
3
- * Initialize the API client
3
+ * Initializes the API client with token retrieval and optional 401 handler.
4
+ * Call once at application startup.
5
+ * @param config - Client configuration
6
+ * @param config.getToken - Function that returns the current auth token (or null)
7
+ * @param config.onUnauthorized - Optional callback for 401 responses (e.g., redirect to login)
8
+ * @example
9
+ * initApiClient({
10
+ * getToken: () => localStorage.getItem('token'),
11
+ * onUnauthorized: () => window.location.href = '/login'
12
+ * });
4
13
  */
5
14
  export declare function initApiClient(config: {
6
15
  getToken: () => string | null;
7
16
  onUnauthorized?: () => void;
8
17
  }): void;
9
18
  /**
10
- * Make an authenticated API call
19
+ * Makes an authenticated API call. Throws ApiError on non-2xx responses.
20
+ * @typeParam T - The expected response data type
21
+ * @param url - The API endpoint URL
22
+ * @param options - Optional fetch options (method, body, headers)
23
+ * @returns The parsed JSON response
24
+ * @throws ApiError on non-2xx HTTP status
25
+ * @example
26
+ * const user = await apiCall<User>('/api/users/123');
11
27
  */
12
28
  export declare function apiCall<T>(url: string, options?: RequestInit): Promise<T>;
13
29
  /**
14
- * GET request helper
30
+ * Makes an authenticated GET request.
31
+ * @typeParam T - The expected response data type
32
+ * @param url - The API endpoint URL
33
+ * @returns The parsed JSON response
34
+ * @throws ApiError on non-2xx HTTP status
35
+ * @example
36
+ * const users = await apiGet<User[]>('/api/users');
15
37
  */
16
38
  export declare function apiGet<T>(url: string): Promise<T>;
17
39
  /**
18
- * POST request helper
40
+ * Makes an authenticated POST request.
41
+ * @typeParam T - The expected response data type
42
+ * @param url - The API endpoint URL
43
+ * @param body - Optional request body (will be JSON stringified)
44
+ * @returns The parsed JSON response
45
+ * @throws ApiError on non-2xx HTTP status
46
+ * @example
47
+ * const user = await apiPost<User>('/api/users', { name: 'John' });
19
48
  */
20
49
  export declare function apiPost<T>(url: string, body?: unknown): Promise<T>;
21
50
  /**
22
- * PUT request helper
51
+ * Makes an authenticated PUT request.
52
+ * @typeParam T - The expected response data type
53
+ * @param url - The API endpoint URL
54
+ * @param body - Optional request body (will be JSON stringified)
55
+ * @returns The parsed JSON response
56
+ * @throws ApiError on non-2xx HTTP status
57
+ * @example
58
+ * const user = await apiPut<User>('/api/users/123', { name: 'Jane' });
23
59
  */
24
60
  export declare function apiPut<T>(url: string, body?: unknown): Promise<T>;
25
61
  /**
26
- * PATCH request helper
62
+ * Makes an authenticated PATCH request.
63
+ * @typeParam T - The expected response data type
64
+ * @param url - The API endpoint URL
65
+ * @param body - Optional request body (will be JSON stringified)
66
+ * @returns The parsed JSON response
67
+ * @throws ApiError on non-2xx HTTP status
68
+ * @example
69
+ * const user = await apiPatch<User>('/api/users/123', { status: 'active' });
27
70
  */
28
71
  export declare function apiPatch<T>(url: string, body?: unknown): Promise<T>;
29
72
  /**
30
- * DELETE request helper
73
+ * Makes an authenticated DELETE request.
74
+ * @typeParam T - The expected response data type
75
+ * @param url - The API endpoint URL
76
+ * @returns The parsed JSON response
77
+ * @throws ApiError on non-2xx HTTP status
78
+ * @example
79
+ * await apiDelete('/api/users/123');
31
80
  */
32
81
  export declare function apiDelete<T>(url: string): Promise<T>;
33
82
  /**
34
- * Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
35
- * Preserves actual HTTP status code on success
83
+ * Makes an authenticated API call with Result-style error handling.
84
+ * Unlike apiCall, this never throws - errors are returned in the response.
85
+ * Preserves actual HTTP status code on success (not always 200).
86
+ * @typeParam T - The expected response data type
87
+ * @param url - The API endpoint URL
88
+ * @param options - Optional fetch options (method, body, headers)
89
+ * @returns ApiResponse with ok, status, data (on success), or error (on failure)
90
+ * @example
91
+ * const response = await apiCallSafe<User>('/api/users/123');
92
+ * if (response.ok) {
93
+ * console.log(response.data);
94
+ * } else {
95
+ * console.error(response.error);
96
+ * }
36
97
  */
37
98
  export declare function apiCallSafe<T>(url: string, options?: RequestInit): Promise<ApiResponse<T>>;
@@ -17,14 +17,30 @@ let getToken = null;
17
17
  // Callback for 401 responses (e.g., redirect to login)
18
18
  let onUnauthorized = null;
19
19
  /**
20
- * Initialize the API client
20
+ * Initializes the API client with token retrieval and optional 401 handler.
21
+ * Call once at application startup.
22
+ * @param config - Client configuration
23
+ * @param config.getToken - Function that returns the current auth token (or null)
24
+ * @param config.onUnauthorized - Optional callback for 401 responses (e.g., redirect to login)
25
+ * @example
26
+ * initApiClient({
27
+ * getToken: () => localStorage.getItem('token'),
28
+ * onUnauthorized: () => window.location.href = '/login'
29
+ * });
21
30
  */
22
31
  function initApiClient(config) {
23
32
  getToken = config.getToken;
24
33
  onUnauthorized = config.onUnauthorized ?? null;
25
34
  }
26
35
  /**
27
- * Make an authenticated API call
36
+ * Makes an authenticated API call. Throws ApiError on non-2xx responses.
37
+ * @typeParam T - The expected response data type
38
+ * @param url - The API endpoint URL
39
+ * @param options - Optional fetch options (method, body, headers)
40
+ * @returns The parsed JSON response
41
+ * @throws ApiError on non-2xx HTTP status
42
+ * @example
43
+ * const user = await apiCall<User>('/api/users/123');
28
44
  */
29
45
  async function apiCall(url, options = {}) {
30
46
  const token = getToken?.();
@@ -61,13 +77,26 @@ async function apiCall(url, options = {}) {
61
77
  return JSON.parse(text);
62
78
  }
63
79
  /**
64
- * GET request helper
80
+ * Makes an authenticated GET request.
81
+ * @typeParam T - The expected response data type
82
+ * @param url - The API endpoint URL
83
+ * @returns The parsed JSON response
84
+ * @throws ApiError on non-2xx HTTP status
85
+ * @example
86
+ * const users = await apiGet<User[]>('/api/users');
65
87
  */
66
88
  async function apiGet(url) {
67
89
  return apiCall(url, { method: 'GET' });
68
90
  }
69
91
  /**
70
- * POST request helper
92
+ * Makes an authenticated POST request.
93
+ * @typeParam T - The expected response data type
94
+ * @param url - The API endpoint URL
95
+ * @param body - Optional request body (will be JSON stringified)
96
+ * @returns The parsed JSON response
97
+ * @throws ApiError on non-2xx HTTP status
98
+ * @example
99
+ * const user = await apiPost<User>('/api/users', { name: 'John' });
71
100
  */
72
101
  async function apiPost(url, body) {
73
102
  return apiCall(url, {
@@ -76,7 +105,14 @@ async function apiPost(url, body) {
76
105
  });
77
106
  }
78
107
  /**
79
- * PUT request helper
108
+ * Makes an authenticated PUT request.
109
+ * @typeParam T - The expected response data type
110
+ * @param url - The API endpoint URL
111
+ * @param body - Optional request body (will be JSON stringified)
112
+ * @returns The parsed JSON response
113
+ * @throws ApiError on non-2xx HTTP status
114
+ * @example
115
+ * const user = await apiPut<User>('/api/users/123', { name: 'Jane' });
80
116
  */
81
117
  async function apiPut(url, body) {
82
118
  return apiCall(url, {
@@ -85,7 +121,14 @@ async function apiPut(url, body) {
85
121
  });
86
122
  }
87
123
  /**
88
- * PATCH request helper
124
+ * Makes an authenticated PATCH request.
125
+ * @typeParam T - The expected response data type
126
+ * @param url - The API endpoint URL
127
+ * @param body - Optional request body (will be JSON stringified)
128
+ * @returns The parsed JSON response
129
+ * @throws ApiError on non-2xx HTTP status
130
+ * @example
131
+ * const user = await apiPatch<User>('/api/users/123', { status: 'active' });
89
132
  */
90
133
  async function apiPatch(url, body) {
91
134
  return apiCall(url, {
@@ -94,14 +137,32 @@ async function apiPatch(url, body) {
94
137
  });
95
138
  }
96
139
  /**
97
- * DELETE request helper
140
+ * Makes an authenticated DELETE request.
141
+ * @typeParam T - The expected response data type
142
+ * @param url - The API endpoint URL
143
+ * @returns The parsed JSON response
144
+ * @throws ApiError on non-2xx HTTP status
145
+ * @example
146
+ * await apiDelete('/api/users/123');
98
147
  */
99
148
  async function apiDelete(url) {
100
149
  return apiCall(url, { method: 'DELETE' });
101
150
  }
102
151
  /**
103
- * Alternative: Response wrapper style (like financial-tracker's authJsonFetch)
104
- * Preserves actual HTTP status code on success
152
+ * Makes an authenticated API call with Result-style error handling.
153
+ * Unlike apiCall, this never throws - errors are returned in the response.
154
+ * Preserves actual HTTP status code on success (not always 200).
155
+ * @typeParam T - The expected response data type
156
+ * @param url - The API endpoint URL
157
+ * @param options - Optional fetch options (method, body, headers)
158
+ * @returns ApiResponse with ok, status, data (on success), or error (on failure)
159
+ * @example
160
+ * const response = await apiCallSafe<User>('/api/users/123');
161
+ * if (response.ok) {
162
+ * console.log(response.data);
163
+ * } else {
164
+ * console.error(response.error);
165
+ * }
105
166
  */
106
167
  async function apiCallSafe(url, options = {}) {
107
168
  const token = getToken?.();
@@ -1,21 +1,38 @@
1
1
  /**
2
- * Custom error class for API errors
3
- * Preserves status code and error message from server
2
+ * Custom error class for API errors.
3
+ * Preserves HTTP status code and error message from the server.
4
+ * @example
5
+ * try {
6
+ * await apiGet('/users/123');
7
+ * } catch (error) {
8
+ * if (error instanceof ApiError && error.isNotFound()) {
9
+ * console.log('User not found');
10
+ * }
11
+ * }
4
12
  */
5
13
  export declare class ApiError extends Error {
6
14
  status: number;
7
15
  details?: string | undefined;
16
+ /**
17
+ * Creates a new ApiError instance.
18
+ * @param status - The HTTP status code
19
+ * @param message - The error message
20
+ * @param details - Optional additional error details
21
+ */
8
22
  constructor(status: number, message: string, details?: string | undefined);
9
23
  /**
10
- * Check if this is an authentication error
24
+ * Checks if this is a 401 Unauthorized error.
25
+ * @returns True if status is 401
11
26
  */
12
27
  isUnauthorized(): boolean;
13
28
  /**
14
- * Check if this is a not found error
29
+ * Checks if this is a 404 Not Found error.
30
+ * @returns True if status is 404
15
31
  */
16
32
  isNotFound(): boolean;
17
33
  /**
18
- * Check if this is a validation error
34
+ * Checks if this is a 400 Bad Request error.
35
+ * @returns True if status is 400
19
36
  */
20
37
  isBadRequest(): boolean;
21
38
  }
@@ -2,10 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ApiError = void 0;
4
4
  /**
5
- * Custom error class for API errors
6
- * Preserves status code and error message from server
5
+ * Custom error class for API errors.
6
+ * Preserves HTTP status code and error message from the server.
7
+ * @example
8
+ * try {
9
+ * await apiGet('/users/123');
10
+ * } catch (error) {
11
+ * if (error instanceof ApiError && error.isNotFound()) {
12
+ * console.log('User not found');
13
+ * }
14
+ * }
7
15
  */
8
16
  class ApiError extends Error {
17
+ /**
18
+ * Creates a new ApiError instance.
19
+ * @param status - The HTTP status code
20
+ * @param message - The error message
21
+ * @param details - Optional additional error details
22
+ */
9
23
  constructor(status, message, details) {
10
24
  super(message);
11
25
  this.status = status;
@@ -13,19 +27,22 @@ class ApiError extends Error {
13
27
  this.name = 'ApiError';
14
28
  }
15
29
  /**
16
- * Check if this is an authentication error
30
+ * Checks if this is a 401 Unauthorized error.
31
+ * @returns True if status is 401
17
32
  */
18
33
  isUnauthorized() {
19
34
  return this.status === 401;
20
35
  }
21
36
  /**
22
- * Check if this is a not found error
37
+ * Checks if this is a 404 Not Found error.
38
+ * @returns True if status is 404
23
39
  */
24
40
  isNotFound() {
25
41
  return this.status === 404;
26
42
  }
27
43
  /**
28
- * Check if this is a validation error
44
+ * Checks if this is a 400 Bad Request error.
45
+ * @returns True if status is 400
29
46
  */
30
47
  isBadRequest() {
31
48
  return this.status === 400;
@@ -1,33 +1,82 @@
1
1
  import { HttpResponseInit, InvocationContext } from '@azure/functions';
2
2
  /**
3
- * Create a 400 Bad Request response
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');
4
8
  */
5
9
  export declare function badRequestResponse(message: string): HttpResponseInit;
6
10
  /**
7
- * Create a 401 Unauthorized response
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();
8
16
  */
9
17
  export declare function unauthorizedResponse(message?: string): HttpResponseInit;
10
18
  /**
11
- * Create a 403 Forbidden response
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');
12
24
  */
13
25
  export declare function forbiddenResponse(message?: string): HttpResponseInit;
14
26
  /**
15
- * Create a 404 Not Found response
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' }
16
33
  */
17
34
  export declare function notFoundResponse(resource: string): HttpResponseInit;
18
35
  /**
19
- * Create a 409 Conflict response
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');
20
41
  */
21
42
  export declare function conflictResponse(message: string): HttpResponseInit;
22
43
  /**
23
- * Handle unexpected errors safely (logs details, returns generic message)
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
+ * }
24
55
  */
25
56
  export declare function handleFunctionError(error: unknown, context: InvocationContext): HttpResponseInit;
26
57
  /**
27
- * Check if an Azure Table Storage error is "not found"
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
+ * }
28
68
  */
29
69
  export declare function isNotFoundError(error: unknown): boolean;
30
70
  /**
31
- * Check if an Azure Table Storage error is "conflict"
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
+ * }
32
81
  */
33
82
  export declare function isConflictError(error: unknown): boolean;
@@ -10,7 +10,11 @@ exports.isNotFoundError = isNotFoundError;
10
10
  exports.isConflictError = isConflictError;
11
11
  const status_1 = require("./status");
12
12
  /**
13
- * Create a 400 Bad Request response
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');
14
18
  */
15
19
  function badRequestResponse(message) {
16
20
  return {
@@ -19,7 +23,11 @@ function badRequestResponse(message) {
19
23
  };
20
24
  }
21
25
  /**
22
- * Create a 401 Unauthorized response
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();
23
31
  */
24
32
  function unauthorizedResponse(message = 'Unauthorized') {
25
33
  return {
@@ -28,7 +36,11 @@ function unauthorizedResponse(message = 'Unauthorized') {
28
36
  };
29
37
  }
30
38
  /**
31
- * Create a 403 Forbidden response
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');
32
44
  */
33
45
  function forbiddenResponse(message = 'Forbidden') {
34
46
  return {
@@ -37,7 +49,12 @@ function forbiddenResponse(message = 'Forbidden') {
37
49
  };
38
50
  }
39
51
  /**
40
- * Create a 404 Not Found response
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' }
41
58
  */
42
59
  function notFoundResponse(resource) {
43
60
  return {
@@ -46,7 +63,11 @@ function notFoundResponse(resource) {
46
63
  };
47
64
  }
48
65
  /**
49
- * Create a 409 Conflict response
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');
50
71
  */
51
72
  function conflictResponse(message) {
52
73
  return {
@@ -55,7 +76,17 @@ function conflictResponse(message) {
55
76
  };
56
77
  }
57
78
  /**
58
- * Handle unexpected errors safely (logs details, returns generic message)
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
+ * }
59
90
  */
60
91
  function handleFunctionError(error, context) {
61
92
  const message = error instanceof Error ? error.message : 'Unknown error';
@@ -66,7 +97,16 @@ function handleFunctionError(error, context) {
66
97
  };
67
98
  }
68
99
  /**
69
- * Check if an Azure Table Storage error is "not found"
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
+ * }
70
110
  */
71
111
  function isNotFoundError(error) {
72
112
  return (error instanceof Error &&
@@ -74,7 +114,16 @@ function isNotFoundError(error) {
74
114
  error.statusCode === 404);
75
115
  }
76
116
  /**
77
- * Check if an Azure Table Storage error is "conflict"
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
+ * }
78
127
  */
79
128
  function isConflictError(error) {
80
129
  return (error instanceof Error &&
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
1
  export * from './types';
2
- export * from './auth';
3
- export * from './http';
4
- export * from './storage';
5
- export * from './client';
2
+ export * from './server';
3
+ export * from './shared';
package/dist/index.js CHANGED
@@ -14,9 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- // Main entry point - re-export everything
17
+ // Core types (universal)
18
18
  __exportStar(require("./types"), exports);
19
- __exportStar(require("./auth"), exports);
20
- __exportStar(require("./http"), exports);
21
- __exportStar(require("./storage"), exports);
22
- __exportStar(require("./client"), exports);
19
+ // Server utilities (for convenience, but prefer ./server)
20
+ __exportStar(require("./server"), exports);
21
+ // Shared utilities
22
+ __exportStar(require("./shared"), exports);
23
+ // Note: Client utilities available via ./client subpath
@@ -0,0 +1,44 @@
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;
@@ -0,0 +1,59 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export { initAuth, getJwtSecret, extractToken, validateToken, generateToken, generateLongLivedToken } from './token';
2
+ export { extractApiKey, hashApiKey, validateApiKey, generateApiKey } from './apiKey';