@markwharton/pwa-core 1.7.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,369 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const vitest_1 = require("vitest");
37
- // Mock fetch globally
38
- const mockFetch = vitest_1.vi.fn();
39
- global.fetch = mockFetch;
40
- (0, vitest_1.describe)('API client', () => {
41
- (0, vitest_1.beforeEach)(() => {
42
- vitest_1.vi.resetModules();
43
- mockFetch.mockReset();
44
- });
45
- (0, vitest_1.describe)('initApiClient', () => {
46
- (0, vitest_1.it)('sets token getter', async () => {
47
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
48
- initApiClient({ getToken: () => 'test-token' });
49
- mockFetch.mockResolvedValue({
50
- ok: true,
51
- text: () => Promise.resolve('{"data": "test"}')
52
- });
53
- await apiCall('/api/test');
54
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/test', vitest_1.expect.objectContaining({
55
- headers: vitest_1.expect.objectContaining({
56
- Authorization: 'Bearer test-token'
57
- })
58
- }));
59
- });
60
- (0, vitest_1.it)('sets onUnauthorized callback', async () => {
61
- const onUnauthorized = vitest_1.vi.fn();
62
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
63
- initApiClient({ getToken: () => 'token', onUnauthorized });
64
- mockFetch.mockResolvedValue({
65
- ok: false,
66
- status: 401,
67
- json: () => Promise.resolve({ error: 'Unauthorized' })
68
- });
69
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toThrow();
70
- (0, vitest_1.expect)(onUnauthorized).toHaveBeenCalled();
71
- });
72
- (0, vitest_1.it)('sets custom timeout', async () => {
73
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
74
- initApiClient({ getToken: () => 'token', timeout: 5000 });
75
- mockFetch.mockResolvedValue({
76
- ok: true,
77
- text: () => Promise.resolve('{}')
78
- });
79
- await apiCall('/api/test');
80
- // Verify signal was passed to fetch
81
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/test', vitest_1.expect.objectContaining({
82
- signal: vitest_1.expect.any(AbortSignal)
83
- }));
84
- });
85
- });
86
- (0, vitest_1.describe)('apiCall', () => {
87
- (0, vitest_1.it)('makes authenticated request', async () => {
88
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
89
- initApiClient({ getToken: () => 'my-token' });
90
- mockFetch.mockResolvedValue({
91
- ok: true,
92
- text: () => Promise.resolve('{"result": "success"}')
93
- });
94
- const result = await apiCall('/api/endpoint');
95
- (0, vitest_1.expect)(result).toEqual({ result: 'success' });
96
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/endpoint', vitest_1.expect.objectContaining({
97
- headers: vitest_1.expect.objectContaining({
98
- 'Content-Type': 'application/json',
99
- Authorization: 'Bearer my-token'
100
- })
101
- }));
102
- });
103
- (0, vitest_1.it)('handles request without token', async () => {
104
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
105
- initApiClient({ getToken: () => null });
106
- mockFetch.mockResolvedValue({
107
- ok: true,
108
- text: () => Promise.resolve('{}')
109
- });
110
- await apiCall('/api/public');
111
- const headers = mockFetch.mock.calls[0][1].headers;
112
- (0, vitest_1.expect)(headers.Authorization).toBeUndefined();
113
- });
114
- (0, vitest_1.it)('throws ApiError on non-ok response', async () => {
115
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
116
- const { ApiError: LocalApiError } = await Promise.resolve().then(() => __importStar(require('../../client/apiError')));
117
- initApiClient({ getToken: () => 'token' });
118
- mockFetch.mockResolvedValue({
119
- ok: false,
120
- status: 400,
121
- json: () => Promise.resolve({ error: 'Invalid input' })
122
- });
123
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toThrow(LocalApiError);
124
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toMatchObject({
125
- status: 400,
126
- message: 'Invalid input'
127
- });
128
- });
129
- (0, vitest_1.it)('handles empty response body', async () => {
130
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
131
- initApiClient({ getToken: () => 'token' });
132
- mockFetch.mockResolvedValue({
133
- ok: true,
134
- text: () => Promise.resolve('')
135
- });
136
- const result = await apiCall('/api/delete');
137
- (0, vitest_1.expect)(result).toEqual({});
138
- });
139
- (0, vitest_1.it)('handles JSON parse error in error response', async () => {
140
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
141
- initApiClient({ getToken: () => 'token' });
142
- mockFetch.mockResolvedValue({
143
- ok: false,
144
- status: 500,
145
- json: () => Promise.reject(new Error('Invalid JSON'))
146
- });
147
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toMatchObject({
148
- status: 500,
149
- message: 'Request failed'
150
- });
151
- });
152
- (0, vitest_1.it)('uses default error message when error field is missing', async () => {
153
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
154
- initApiClient({ getToken: () => 'token' });
155
- mockFetch.mockResolvedValue({
156
- ok: false,
157
- status: 400,
158
- json: () => Promise.resolve({ message: 'not the error field' })
159
- });
160
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toMatchObject({
161
- status: 400,
162
- message: 'Request failed'
163
- });
164
- });
165
- (0, vitest_1.it)('handles request timeout', async () => {
166
- const { initApiClient, apiCall } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
167
- initApiClient({ getToken: () => 'token' });
168
- const abortError = new Error('Aborted');
169
- abortError.name = 'AbortError';
170
- mockFetch.mockRejectedValue(abortError);
171
- await (0, vitest_1.expect)(apiCall('/api/test')).rejects.toMatchObject({
172
- status: 0,
173
- message: 'Request timeout'
174
- });
175
- });
176
- });
177
- (0, vitest_1.describe)('HTTP method helpers', () => {
178
- (0, vitest_1.beforeEach)(async () => {
179
- const { initApiClient } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
180
- initApiClient({ getToken: () => 'token' });
181
- mockFetch.mockResolvedValue({
182
- ok: true,
183
- text: () => Promise.resolve('{"data": "test"}')
184
- });
185
- });
186
- (0, vitest_1.it)('apiGet uses GET method', async () => {
187
- const { apiGet } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
188
- await apiGet('/api/resource');
189
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
190
- method: 'GET'
191
- }));
192
- });
193
- (0, vitest_1.it)('apiPost uses POST method with body', async () => {
194
- const { apiPost } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
195
- await apiPost('/api/resource', { name: 'test' });
196
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
197
- method: 'POST',
198
- body: '{"name":"test"}'
199
- }));
200
- });
201
- (0, vitest_1.it)('apiPost works without body', async () => {
202
- const { apiPost } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
203
- await apiPost('/api/resource');
204
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
205
- method: 'POST',
206
- body: undefined
207
- }));
208
- });
209
- (0, vitest_1.it)('apiPut uses PUT method with body', async () => {
210
- const { apiPut } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
211
- await apiPut('/api/resource', { name: 'updated' });
212
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
213
- method: 'PUT',
214
- body: '{"name":"updated"}'
215
- }));
216
- });
217
- (0, vitest_1.it)('apiPut works without body', async () => {
218
- const { apiPut } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
219
- await apiPut('/api/resource');
220
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
221
- method: 'PUT',
222
- body: undefined
223
- }));
224
- });
225
- (0, vitest_1.it)('apiPatch uses PATCH method with body', async () => {
226
- const { apiPatch } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
227
- await apiPatch('/api/resource', { field: 'value' });
228
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
229
- method: 'PATCH',
230
- body: '{"field":"value"}'
231
- }));
232
- });
233
- (0, vitest_1.it)('apiPatch works without body', async () => {
234
- const { apiPatch } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
235
- await apiPatch('/api/resource');
236
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
237
- method: 'PATCH',
238
- body: undefined
239
- }));
240
- });
241
- (0, vitest_1.it)('apiDelete uses DELETE method', async () => {
242
- const { apiDelete } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
243
- await apiDelete('/api/resource');
244
- (0, vitest_1.expect)(mockFetch).toHaveBeenCalledWith('/api/resource', vitest_1.expect.objectContaining({
245
- method: 'DELETE'
246
- }));
247
- });
248
- });
249
- (0, vitest_1.describe)('apiCallSafe', () => {
250
- (0, vitest_1.it)('returns ok response with data', async () => {
251
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
252
- initApiClient({ getToken: () => 'token' });
253
- mockFetch.mockResolvedValue({
254
- ok: true,
255
- status: 200,
256
- text: () => Promise.resolve('{"user": "john"}')
257
- });
258
- const result = await apiCallSafe('/api/user');
259
- (0, vitest_1.expect)(result.ok).toBe(true);
260
- (0, vitest_1.expect)(result.status).toBe(200);
261
- (0, vitest_1.expect)(result.data).toEqual({ user: 'john' });
262
- });
263
- (0, vitest_1.it)('preserves actual status code', async () => {
264
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
265
- initApiClient({ getToken: () => 'token' });
266
- mockFetch.mockResolvedValue({
267
- ok: true,
268
- status: 201,
269
- text: () => Promise.resolve('{"id": "123"}')
270
- });
271
- const result = await apiCallSafe('/api/create');
272
- (0, vitest_1.expect)(result.status).toBe(201);
273
- });
274
- (0, vitest_1.it)('returns error response for non-ok status', async () => {
275
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
276
- initApiClient({ getToken: () => 'token' });
277
- mockFetch.mockResolvedValue({
278
- ok: false,
279
- status: 404,
280
- json: () => Promise.resolve({ error: 'Not found' })
281
- });
282
- const result = await apiCallSafe('/api/missing');
283
- (0, vitest_1.expect)(result.ok).toBe(false);
284
- (0, vitest_1.expect)(result.status).toBe(404);
285
- (0, vitest_1.expect)(result.error).toBe('Not found');
286
- });
287
- (0, vitest_1.it)('handles network errors', async () => {
288
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
289
- initApiClient({ getToken: () => 'token' });
290
- mockFetch.mockRejectedValue(new Error('Network failure'));
291
- const result = await apiCallSafe('/api/test');
292
- (0, vitest_1.expect)(result.ok).toBe(false);
293
- (0, vitest_1.expect)(result.status).toBe(0);
294
- (0, vitest_1.expect)(result.error).toBe('Network error');
295
- });
296
- (0, vitest_1.it)('calls onUnauthorized for 401', async () => {
297
- const onUnauthorized = vitest_1.vi.fn();
298
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
299
- initApiClient({ getToken: () => 'token', onUnauthorized });
300
- mockFetch.mockResolvedValue({
301
- ok: false,
302
- status: 401,
303
- json: () => Promise.resolve({ error: 'Token expired' })
304
- });
305
- await apiCallSafe('/api/protected');
306
- (0, vitest_1.expect)(onUnauthorized).toHaveBeenCalled();
307
- });
308
- (0, vitest_1.it)('handles empty success response', async () => {
309
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
310
- initApiClient({ getToken: () => 'token' });
311
- mockFetch.mockResolvedValue({
312
- ok: true,
313
- status: 204,
314
- text: () => Promise.resolve('')
315
- });
316
- const result = await apiCallSafe('/api/delete');
317
- (0, vitest_1.expect)(result.ok).toBe(true);
318
- (0, vitest_1.expect)(result.status).toBe(204);
319
- (0, vitest_1.expect)(result.data).toBeUndefined();
320
- });
321
- (0, vitest_1.it)('handles request without token', async () => {
322
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
323
- initApiClient({ getToken: () => null });
324
- mockFetch.mockResolvedValue({
325
- ok: true,
326
- status: 200,
327
- text: () => Promise.resolve('{}')
328
- });
329
- await apiCallSafe('/api/public');
330
- const headers = mockFetch.mock.calls[0][1].headers;
331
- (0, vitest_1.expect)(headers.Authorization).toBeUndefined();
332
- });
333
- (0, vitest_1.it)('uses default error message when error field is missing', async () => {
334
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
335
- initApiClient({ getToken: () => 'token' });
336
- mockFetch.mockResolvedValue({
337
- ok: false,
338
- status: 400,
339
- json: () => Promise.resolve({ details: 'not the error field' })
340
- });
341
- const result = await apiCallSafe('/api/test');
342
- (0, vitest_1.expect)(result.ok).toBe(false);
343
- (0, vitest_1.expect)(result.error).toBe('Request failed');
344
- });
345
- (0, vitest_1.it)('handles JSON parse error in error response', async () => {
346
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
347
- initApiClient({ getToken: () => 'token' });
348
- mockFetch.mockResolvedValue({
349
- ok: false,
350
- status: 500,
351
- json: () => Promise.reject(new Error('Invalid JSON'))
352
- });
353
- const result = await apiCallSafe('/api/test');
354
- (0, vitest_1.expect)(result.ok).toBe(false);
355
- (0, vitest_1.expect)(result.error).toBe('Request failed');
356
- });
357
- (0, vitest_1.it)('handles request timeout', async () => {
358
- const { initApiClient, apiCallSafe } = await Promise.resolve().then(() => __importStar(require('../../client/api')));
359
- initApiClient({ getToken: () => 'token' });
360
- const abortError = new Error('Aborted');
361
- abortError.name = 'AbortError';
362
- mockFetch.mockRejectedValue(abortError);
363
- const result = await apiCallSafe('/api/test');
364
- (0, vitest_1.expect)(result.ok).toBe(false);
365
- (0, vitest_1.expect)(result.status).toBe(0);
366
- (0, vitest_1.expect)(result.error).toBe('Request timeout');
367
- });
368
- });
369
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,91 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const apiError_1 = require("../../client/apiError");
5
- (0, vitest_1.describe)('ApiError', () => {
6
- (0, vitest_1.describe)('constructor', () => {
7
- (0, vitest_1.it)('sets status, message, and name', () => {
8
- const error = new apiError_1.ApiError(404, 'Not found');
9
- (0, vitest_1.expect)(error.status).toBe(404);
10
- (0, vitest_1.expect)(error.message).toBe('Not found');
11
- (0, vitest_1.expect)(error.name).toBe('ApiError');
12
- });
13
- (0, vitest_1.it)('sets optional details', () => {
14
- const error = new apiError_1.ApiError(400, 'Validation failed', 'Field "email" is required');
15
- (0, vitest_1.expect)(error.details).toBe('Field "email" is required');
16
- });
17
- (0, vitest_1.it)('extends Error', () => {
18
- const error = new apiError_1.ApiError(500, 'Server error');
19
- (0, vitest_1.expect)(error).toBeInstanceOf(Error);
20
- });
21
- });
22
- (0, vitest_1.describe)('isUnauthorized', () => {
23
- (0, vitest_1.it)('returns true for 401 status', () => {
24
- const error = new apiError_1.ApiError(401, 'Unauthorized');
25
- (0, vitest_1.expect)(error.isUnauthorized()).toBe(true);
26
- });
27
- (0, vitest_1.it)('returns false for other statuses', () => {
28
- (0, vitest_1.expect)(new apiError_1.ApiError(400, 'Bad request').isUnauthorized()).toBe(false);
29
- (0, vitest_1.expect)(new apiError_1.ApiError(403, 'Forbidden').isUnauthorized()).toBe(false);
30
- (0, vitest_1.expect)(new apiError_1.ApiError(404, 'Not found').isUnauthorized()).toBe(false);
31
- (0, vitest_1.expect)(new apiError_1.ApiError(500, 'Server error').isUnauthorized()).toBe(false);
32
- });
33
- });
34
- (0, vitest_1.describe)('isNotFound', () => {
35
- (0, vitest_1.it)('returns true for 404 status', () => {
36
- const error = new apiError_1.ApiError(404, 'Not found');
37
- (0, vitest_1.expect)(error.isNotFound()).toBe(true);
38
- });
39
- (0, vitest_1.it)('returns false for other statuses', () => {
40
- (0, vitest_1.expect)(new apiError_1.ApiError(400, 'Bad request').isNotFound()).toBe(false);
41
- (0, vitest_1.expect)(new apiError_1.ApiError(401, 'Unauthorized').isNotFound()).toBe(false);
42
- (0, vitest_1.expect)(new apiError_1.ApiError(403, 'Forbidden').isNotFound()).toBe(false);
43
- (0, vitest_1.expect)(new apiError_1.ApiError(500, 'Server error').isNotFound()).toBe(false);
44
- });
45
- });
46
- (0, vitest_1.describe)('isBadRequest', () => {
47
- (0, vitest_1.it)('returns true for 400 status', () => {
48
- const error = new apiError_1.ApiError(400, 'Bad request');
49
- (0, vitest_1.expect)(error.isBadRequest()).toBe(true);
50
- });
51
- (0, vitest_1.it)('returns false for other statuses', () => {
52
- (0, vitest_1.expect)(new apiError_1.ApiError(401, 'Unauthorized').isBadRequest()).toBe(false);
53
- (0, vitest_1.expect)(new apiError_1.ApiError(403, 'Forbidden').isBadRequest()).toBe(false);
54
- (0, vitest_1.expect)(new apiError_1.ApiError(404, 'Not found').isBadRequest()).toBe(false);
55
- (0, vitest_1.expect)(new apiError_1.ApiError(500, 'Server error').isBadRequest()).toBe(false);
56
- });
57
- });
58
- (0, vitest_1.describe)('isClientError', () => {
59
- (0, vitest_1.it)('returns true for 4xx statuses', () => {
60
- (0, vitest_1.expect)(new apiError_1.ApiError(400, 'Bad request').isClientError()).toBe(true);
61
- (0, vitest_1.expect)(new apiError_1.ApiError(401, 'Unauthorized').isClientError()).toBe(true);
62
- (0, vitest_1.expect)(new apiError_1.ApiError(403, 'Forbidden').isClientError()).toBe(true);
63
- (0, vitest_1.expect)(new apiError_1.ApiError(404, 'Not found').isClientError()).toBe(true);
64
- (0, vitest_1.expect)(new apiError_1.ApiError(422, 'Unprocessable').isClientError()).toBe(true);
65
- (0, vitest_1.expect)(new apiError_1.ApiError(429, 'Too many requests').isClientError()).toBe(true);
66
- (0, vitest_1.expect)(new apiError_1.ApiError(499, 'Client closed').isClientError()).toBe(true);
67
- });
68
- (0, vitest_1.it)('returns false for non-4xx statuses', () => {
69
- (0, vitest_1.expect)(new apiError_1.ApiError(200, 'OK').isClientError()).toBe(false);
70
- (0, vitest_1.expect)(new apiError_1.ApiError(301, 'Moved').isClientError()).toBe(false);
71
- (0, vitest_1.expect)(new apiError_1.ApiError(500, 'Server error').isClientError()).toBe(false);
72
- (0, vitest_1.expect)(new apiError_1.ApiError(0, 'Network error').isClientError()).toBe(false);
73
- });
74
- });
75
- (0, vitest_1.describe)('isServerError', () => {
76
- (0, vitest_1.it)('returns true for 5xx statuses', () => {
77
- (0, vitest_1.expect)(new apiError_1.ApiError(500, 'Internal server error').isServerError()).toBe(true);
78
- (0, vitest_1.expect)(new apiError_1.ApiError(501, 'Not implemented').isServerError()).toBe(true);
79
- (0, vitest_1.expect)(new apiError_1.ApiError(502, 'Bad gateway').isServerError()).toBe(true);
80
- (0, vitest_1.expect)(new apiError_1.ApiError(503, 'Service unavailable').isServerError()).toBe(true);
81
- (0, vitest_1.expect)(new apiError_1.ApiError(504, 'Gateway timeout').isServerError()).toBe(true);
82
- (0, vitest_1.expect)(new apiError_1.ApiError(599, 'Network timeout').isServerError()).toBe(true);
83
- });
84
- (0, vitest_1.it)('returns false for non-5xx statuses', () => {
85
- (0, vitest_1.expect)(new apiError_1.ApiError(200, 'OK').isServerError()).toBe(false);
86
- (0, vitest_1.expect)(new apiError_1.ApiError(400, 'Bad request').isServerError()).toBe(false);
87
- (0, vitest_1.expect)(new apiError_1.ApiError(404, 'Not found').isServerError()).toBe(false);
88
- (0, vitest_1.expect)(new apiError_1.ApiError(0, 'Network error').isServerError()).toBe(false);
89
- });
90
- });
91
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,112 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const responses_1 = require("../../http/responses");
5
- const status_1 = require("../../http/status");
6
- (0, vitest_1.describe)('HTTP response helpers', () => {
7
- (0, vitest_1.describe)('badRequestResponse', () => {
8
- (0, vitest_1.it)('returns 400 status with error message', () => {
9
- const response = (0, responses_1.badRequestResponse)('Invalid input');
10
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.BAD_REQUEST);
11
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Invalid input' });
12
- });
13
- });
14
- (0, vitest_1.describe)('unauthorizedResponse', () => {
15
- (0, vitest_1.it)('returns 401 status with default message', () => {
16
- const response = (0, responses_1.unauthorizedResponse)();
17
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.UNAUTHORIZED);
18
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Unauthorized' });
19
- });
20
- (0, vitest_1.it)('returns 401 status with custom message', () => {
21
- const response = (0, responses_1.unauthorizedResponse)('Token expired');
22
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.UNAUTHORIZED);
23
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Token expired' });
24
- });
25
- });
26
- (0, vitest_1.describe)('forbiddenResponse', () => {
27
- (0, vitest_1.it)('returns 403 status with default message', () => {
28
- const response = (0, responses_1.forbiddenResponse)();
29
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.FORBIDDEN);
30
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Forbidden' });
31
- });
32
- (0, vitest_1.it)('returns 403 status with custom message', () => {
33
- const response = (0, responses_1.forbiddenResponse)('Admin access required');
34
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.FORBIDDEN);
35
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Admin access required' });
36
- });
37
- });
38
- (0, vitest_1.describe)('notFoundResponse', () => {
39
- (0, vitest_1.it)('returns 404 status with resource name', () => {
40
- const response = (0, responses_1.notFoundResponse)('User');
41
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.NOT_FOUND);
42
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'User not found' });
43
- });
44
- });
45
- (0, vitest_1.describe)('conflictResponse', () => {
46
- (0, vitest_1.it)('returns 409 status with error message', () => {
47
- const response = (0, responses_1.conflictResponse)('Resource already exists');
48
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.CONFLICT);
49
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Resource already exists' });
50
- });
51
- });
52
- (0, vitest_1.describe)('handleFunctionError', () => {
53
- (0, vitest_1.it)('logs error and returns 500 response', () => {
54
- const mockContext = {
55
- error: vitest_1.vi.fn()
56
- };
57
- const error = new Error('Database connection failed');
58
- const response = (0, responses_1.handleFunctionError)(error, mockContext);
59
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.INTERNAL_ERROR);
60
- (0, vitest_1.expect)(response.jsonBody).toEqual({ error: 'Internal server error' });
61
- (0, vitest_1.expect)(mockContext.error).toHaveBeenCalledWith('Function error: Database connection failed');
62
- });
63
- (0, vitest_1.it)('handles non-Error objects', () => {
64
- const mockContext = {
65
- error: vitest_1.vi.fn()
66
- };
67
- const response = (0, responses_1.handleFunctionError)('string error', mockContext);
68
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.INTERNAL_ERROR);
69
- (0, vitest_1.expect)(mockContext.error).toHaveBeenCalledWith('Function error: Unknown error');
70
- });
71
- (0, vitest_1.it)('handles null/undefined errors', () => {
72
- const mockContext = {
73
- error: vitest_1.vi.fn()
74
- };
75
- const response = (0, responses_1.handleFunctionError)(null, mockContext);
76
- (0, vitest_1.expect)(response.status).toBe(status_1.HTTP_STATUS.INTERNAL_ERROR);
77
- (0, vitest_1.expect)(mockContext.error).toHaveBeenCalledWith('Function error: Unknown error');
78
- });
79
- });
80
- (0, vitest_1.describe)('isNotFoundError', () => {
81
- (0, vitest_1.it)('returns true for 404 error', () => {
82
- const error = Object.assign(new Error('Not found'), { statusCode: 404 });
83
- (0, vitest_1.expect)((0, responses_1.isNotFoundError)(error)).toBe(true);
84
- });
85
- (0, vitest_1.it)('returns false for other status codes', () => {
86
- const error = Object.assign(new Error('Conflict'), { statusCode: 409 });
87
- (0, vitest_1.expect)((0, responses_1.isNotFoundError)(error)).toBe(false);
88
- });
89
- (0, vitest_1.it)('returns false for non-Error objects', () => {
90
- (0, vitest_1.expect)((0, responses_1.isNotFoundError)({ statusCode: 404 })).toBe(false);
91
- });
92
- (0, vitest_1.it)('returns false for errors without statusCode', () => {
93
- (0, vitest_1.expect)((0, responses_1.isNotFoundError)(new Error('Not found'))).toBe(false);
94
- });
95
- });
96
- (0, vitest_1.describe)('isConflictError', () => {
97
- (0, vitest_1.it)('returns true for 409 error', () => {
98
- const error = Object.assign(new Error('Conflict'), { statusCode: 409 });
99
- (0, vitest_1.expect)((0, responses_1.isConflictError)(error)).toBe(true);
100
- });
101
- (0, vitest_1.it)('returns false for other status codes', () => {
102
- const error = Object.assign(new Error('Not found'), { statusCode: 404 });
103
- (0, vitest_1.expect)((0, responses_1.isConflictError)(error)).toBe(false);
104
- });
105
- (0, vitest_1.it)('returns false for non-Error objects', () => {
106
- (0, vitest_1.expect)((0, responses_1.isConflictError)({ statusCode: 409 })).toBe(false);
107
- });
108
- (0, vitest_1.it)('returns false for errors without statusCode', () => {
109
- (0, vitest_1.expect)((0, responses_1.isConflictError)(new Error('Conflict'))).toBe(false);
110
- });
111
- });
112
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,27 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const vitest_1 = require("vitest");
4
- const status_1 = require("../../http/status");
5
- (0, vitest_1.describe)('HTTP_STATUS', () => {
6
- (0, vitest_1.it)('has correct status codes', () => {
7
- (0, vitest_1.expect)(status_1.HTTP_STATUS.OK).toBe(200);
8
- (0, vitest_1.expect)(status_1.HTTP_STATUS.CREATED).toBe(201);
9
- (0, vitest_1.expect)(status_1.HTTP_STATUS.NO_CONTENT).toBe(204);
10
- (0, vitest_1.expect)(status_1.HTTP_STATUS.BAD_REQUEST).toBe(400);
11
- (0, vitest_1.expect)(status_1.HTTP_STATUS.UNAUTHORIZED).toBe(401);
12
- (0, vitest_1.expect)(status_1.HTTP_STATUS.FORBIDDEN).toBe(403);
13
- (0, vitest_1.expect)(status_1.HTTP_STATUS.NOT_FOUND).toBe(404);
14
- (0, vitest_1.expect)(status_1.HTTP_STATUS.CONFLICT).toBe(409);
15
- (0, vitest_1.expect)(status_1.HTTP_STATUS.GONE).toBe(410);
16
- (0, vitest_1.expect)(status_1.HTTP_STATUS.INTERNAL_ERROR).toBe(500);
17
- (0, vitest_1.expect)(status_1.HTTP_STATUS.SERVICE_UNAVAILABLE).toBe(503);
18
- });
19
- (0, vitest_1.it)('is immutable (const assertion)', () => {
20
- // TypeScript const assertion makes the object readonly
21
- // This test verifies the values haven't been accidentally modified
22
- const statusCodes = Object.values(status_1.HTTP_STATUS);
23
- (0, vitest_1.expect)(statusCodes).toContain(200);
24
- (0, vitest_1.expect)(statusCodes).toContain(404);
25
- (0, vitest_1.expect)(statusCodes).toContain(500);
26
- });
27
- });
@@ -1 +0,0 @@
1
- export {};