lambder 2.0.18 → 3.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 (67) hide show
  1. package/Readme.md +162 -41
  2. package/dist/Lambder.d.ts +154 -46
  3. package/dist/Lambder.js +312 -166
  4. package/dist/LambderCaller.js +6 -3
  5. package/dist/LambderContext.d.ts +20 -9
  6. package/dist/LambderContext.js +57 -17
  7. package/dist/LambderCors.d.ts +12 -0
  8. package/dist/LambderCors.js +30 -0
  9. package/dist/LambderHtml.d.ts +33 -0
  10. package/dist/LambderHtml.js +62 -0
  11. package/dist/LambderMSW.d.ts +16 -1
  12. package/dist/LambderMSW.js +5 -9
  13. package/dist/LambderPublicFiles.d.ts +47 -0
  14. package/dist/LambderPublicFiles.js +108 -0
  15. package/dist/LambderResolver.d.ts +30 -31
  16. package/dist/LambderResolver.js +29 -43
  17. package/dist/LambderResponse.d.ts +71 -0
  18. package/dist/LambderResponse.js +196 -0
  19. package/dist/LambderResponseBuilder.d.ts +58 -33
  20. package/dist/LambderResponseBuilder.js +114 -167
  21. package/dist/LambderRouting.d.ts +23 -0
  22. package/dist/LambderRouting.js +67 -0
  23. package/dist/LambderSessionController.d.ts +13 -1
  24. package/dist/LambderSessionController.js +33 -10
  25. package/dist/LambderSessionManager.d.ts +3 -1
  26. package/dist/LambderSessionManager.js +15 -6
  27. package/dist/LambderTemplatingEngine.d.ts +87 -0
  28. package/dist/LambderTemplatingEngine.js +156 -0
  29. package/dist/index.d.ts +14 -2
  30. package/dist/index.js +10 -1
  31. package/dist/node-polyfills.d.ts +4 -2
  32. package/dist/node-polyfills.js +28 -0
  33. package/package.json +7 -5
  34. package/.eslintrc.cjs +0 -26
  35. package/.vscode/settings.json +0 -26
  36. package/deploy +0 -22
  37. package/dist/LambderUtils.d.ts +0 -10
  38. package/dist/LambderUtils.js +0 -70
  39. package/docs/DYNAMODB_SETUP.md +0 -96
  40. package/docs/LAMBDER_MSW.md +0 -409
  41. package/docs/TYPE_SAFE_QUICK_START.md +0 -77
  42. package/examples/msw-testing-example.ts +0 -280
  43. package/examples/secure-session-example.ts +0 -207
  44. package/examples/zod-chained-api-example.ts +0 -63
  45. package/src/Lambder.ts +0 -430
  46. package/src/LambderApiContract.ts +0 -20
  47. package/src/LambderCaller.ts +0 -238
  48. package/src/LambderContext.ts +0 -78
  49. package/src/LambderMSW.ts +0 -180
  50. package/src/LambderResolver.ts +0 -101
  51. package/src/LambderResponseBuilder.ts +0 -332
  52. package/src/LambderSessionController.ts +0 -114
  53. package/src/LambderSessionManager.ts +0 -217
  54. package/src/LambderUtils.ts +0 -75
  55. package/src/index.ts +0 -17
  56. package/src/node-polyfills.ts +0 -27
  57. package/tests/error-handling.test.ts +0 -585
  58. package/tests/file-serving.test.ts +0 -194
  59. package/tests/fixtures/public/index.html +0 -1
  60. package/tests/fixtures/public/main.css +0 -1
  61. package/tests/hooks.test.ts +0 -561
  62. package/tests/output-type-runtime.test.ts +0 -381
  63. package/tests/redirect.test.ts +0 -88
  64. package/tests/routes.test.ts +0 -543
  65. package/tests/session.test.ts +0 -1083
  66. package/tests/use-plugin.test.ts +0 -460
  67. package/tsconfig.json +0 -24
@@ -1,409 +0,0 @@
1
- # LambderMSW - Mock Service Worker Integration
2
-
3
- LambderMSW provides seamless integration with [MSW (Mock Service Worker)](https://mswjs.io/) for testing your Lambder APIs. It allows you to mock API endpoints with full type safety when using TypeScript API contracts.
4
-
5
- ## Installation
6
-
7
- First, install MSW as a dev dependency:
8
-
9
- ```bash
10
- npm install msw --save-dev
11
- # or
12
- yarn add msw --dev
13
- ```
14
-
15
- ## Basic Setup
16
-
17
- ```typescript
18
- import { LambderMSW } from 'lambder';
19
- import { setupServer } from 'msw/node';
20
-
21
- // Create an MSW instance
22
- const lambderMSW = new LambderMSW({
23
- apiPath: '/secure', // Must match your Lambder backend apiPath
24
- });
25
-
26
- // Create mock handlers
27
- const handlers = [
28
- lambderMSW.mockApi('getUserById', async (payload) => {
29
- return {
30
- id: payload.userId,
31
- name: 'John Doe',
32
- email: 'john@example.com'
33
- };
34
- })
35
- ];
36
-
37
- // Setup MSW server
38
- const server = setupServer(...handlers);
39
-
40
- // Start server before tests
41
- beforeAll(() => server.listen());
42
- afterEach(() => server.resetHandlers());
43
- afterAll(() => server.close());
44
- ```
45
-
46
- ## Type-Safe Mocking
47
-
48
- When using TypeScript API contracts, LambderMSW provides full type safety:
49
-
50
- ```typescript
51
- // backend/index.ts (define your APIs with Lambder)
52
- import { z } from 'zod';
53
- import Lambder from 'lambder';
54
-
55
- const lambder = new Lambder({ apiPath: '/secure', publicPath: './public' })
56
- .addApi('getUserById', {
57
- input: z.object({ userId: z.string() }),
58
- output: z.object({ id: z.string(), name: z.string(), email: z.string() })
59
- }, async (ctx, resolver) => {
60
- // Implementation...
61
- return resolver.api({ id: ctx.apiPayload.userId, name: 'John', email: 'john@example.com' });
62
- })
63
- .addApi('createUser', {
64
- input: z.object({ name: z.string(), email: z.string() }),
65
- output: z.object({ id: z.string(), name: z.string(), email: z.string() })
66
- }, async (ctx, resolver) => {
67
- // Implementation...
68
- return resolver.api({ id: '123', ...ctx.apiPayload });
69
- });
70
-
71
- // Export the inferred contract type
72
- export type ApiContractType = typeof lambder.ApiContract;
73
-
74
- // test/setup.ts
75
- import { LambderMSW } from 'lambder';
76
- import type { ApiContractType } from '../backend';
77
-
78
- const lambderMSW = new LambderMSW<ApiContractType>({
79
- apiPath: '/secure',
80
- apiVersion: '1.0.0'
81
- });
82
-
83
- // Now mockApi is fully typed! ✨
84
- const handler = lambderMSW.mockApi('getUserById', async (payload) => {
85
- // payload is automatically typed as { userId: string }
86
- // Return value is type-checked against output type
87
- return {
88
- id: payload.userId,
89
- name: 'John Doe',
90
- email: 'john@example.com'
91
- };
92
- });
93
- ```
94
-
95
- ## API Reference
96
-
97
- ### `new LambderMSW(options)`
98
-
99
- Creates a new LambderMSW instance.
100
-
101
- **Parameters:**
102
- - `apiPath` (string): The API endpoint path (must match your Lambder backend)
103
- - `apiVersion` (string, optional): API version to include in responses
104
-
105
- ### `mockApi(apiName, handler, options?)`
106
-
107
- Mock an API endpoint with a custom handler.
108
-
109
- **Parameters:**
110
- - `apiName` (string): Name of the API to mock
111
- - `handler` (function): Async or sync function that returns the mock payload
112
- - Input: API payload from the request
113
- - Output: The mocked response payload
114
- - `options` (object, optional):
115
- - `versionExpired` (boolean): Simulate version expired error
116
- - `sessionExpired` (boolean): Simulate session expired error
117
- - `notAuthorized` (boolean): Simulate not authorized error
118
- - `message` (any): Custom message to include in response
119
- - `errorMessage` (any): Error message to include in response
120
- - `logList` (array): Array of log entries
121
- - `delay` (number): Artificial delay in milliseconds to simulate network latency
122
-
123
- **Returns:** MSW RequestHandler
124
-
125
- **Example:**
126
- ```typescript
127
- lambderMSW.mockApi('getCompanyPage', async (payload) => {
128
- return {
129
- companyName: payload.companyName,
130
- description: 'Mock company description',
131
- employees: 100
132
- };
133
- }, {
134
- delay: 500, // Simulate 500ms network delay
135
- message: 'Data fetched successfully'
136
- });
137
- ```
138
-
139
- ### `mockSessionExpired(apiName)`
140
-
141
- Mock an API that returns a session expired error.
142
-
143
- **Parameters:**
144
- - `apiName` (string): Name of the API to mock
145
-
146
- **Example:**
147
- ```typescript
148
- lambderMSW.mockSessionExpired('getProtectedData');
149
- ```
150
-
151
- ### `mockVersionExpired(apiName)`
152
-
153
- Mock an API that returns a version expired error.
154
-
155
- **Parameters:**
156
- - `apiName` (string): Name of the API to mock
157
-
158
- **Example:**
159
- ```typescript
160
- lambderMSW.mockVersionExpired('getUserProfile');
161
- ```
162
-
163
- ### `mockNotAuthorized(apiName)`
164
-
165
- Mock an API that returns a not authorized error.
166
-
167
- **Parameters:**
168
- - `apiName` (string): Name of the API to mock
169
-
170
- **Example:**
171
- ```typescript
172
- lambderMSW.mockNotAuthorized('deleteUser');
173
- ```
174
-
175
- ### `mockError(apiName, errorMessage)`
176
-
177
- Mock an API that returns a custom error message.
178
-
179
- **Parameters:**
180
- - `apiName` (string): Name of the API to mock
181
- - `errorMessage` (string): The error message to return
182
-
183
- **Example:**
184
- ```typescript
185
- lambderMSW.mockError('submitOrder', 'Payment processing failed');
186
- ```
187
-
188
- ### `mockWithMessage(apiName, handler, message)`
189
-
190
- Mock an API with a custom success message.
191
-
192
- **Parameters:**
193
- - `apiName` (string): Name of the API to mock
194
- - `handler` (function): Handler function that returns the mock payload
195
- - `message` (any): Custom message to include in response
196
-
197
- **Example:**
198
- ```typescript
199
- lambderMSW.mockWithMessage('updateProfile', async (payload) => {
200
- return { userId: payload.userId, updated: true };
201
- }, 'Profile updated successfully');
202
- ```
203
-
204
- ## Complete Testing Example
205
-
206
- ```typescript
207
- // test/api.test.ts
208
- import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
209
- import { setupServer } from 'msw/node';
210
- import { LambderMSW, LambderCaller } from 'lambder';
211
- import type { ApiContractType } from '../backend'; // Type-only import from your backend
212
-
213
- // Setup MSW
214
- const lambderMSW = new LambderMSW<ApiContractType>({
215
- apiPath: '/secure',
216
- apiVersion: '1.0.0'
217
- });
218
-
219
- const handlers = [
220
- lambderMSW.mockApi('getUserById', async (payload) => {
221
- if (payload.userId === '123') {
222
- return {
223
- id: '123',
224
- name: 'John Doe',
225
- email: 'john@example.com'
226
- };
227
- }
228
- return null;
229
- }),
230
-
231
- lambderMSW.mockApi('createUser', async (payload) => {
232
- return {
233
- id: Math.random().toString(),
234
- name: payload.name,
235
- email: payload.email
236
- };
237
- }, { delay: 100 }), // Simulate 100ms delay
238
-
239
- lambderMSW.mockSessionExpired('getProtectedData'),
240
-
241
- lambderMSW.mockError('failingApi', 'Something went wrong')
242
- ];
243
-
244
- const server = setupServer(...handlers);
245
-
246
- beforeAll(() => server.listen());
247
- afterEach(() => server.resetHandlers());
248
- afterAll(() => server.close());
249
-
250
- // Setup LambderCaller
251
- const lambderCaller = new LambderCaller<ApiContractType>({
252
- apiPath: '/secure',
253
- isCorsEnabled: false
254
- });
255
-
256
- describe('User APIs', () => {
257
- it('should fetch user by id', async () => {
258
- const result = await lambderCaller.api('getUserById', { userId: '123' });
259
-
260
- expect(result).toEqual({
261
- id: '123',
262
- name: 'John Doe',
263
- email: 'john@example.com'
264
- });
265
- });
266
-
267
- it('should create a new user', async () => {
268
- const result = await lambderCaller.api('createUser', {
269
- name: 'Jane Smith',
270
- email: 'jane@example.com'
271
- });
272
-
273
- expect(result?.name).toBe('Jane Smith');
274
- expect(result?.email).toBe('jane@example.com');
275
- expect(result?.id).toBeDefined();
276
- });
277
-
278
- it('should handle session expired', async () => {
279
- try {
280
- await lambderCaller.api('getProtectedData', {});
281
- // Should not reach here
282
- expect(true).toBe(false);
283
- } catch (error: any) {
284
- expect(error.sessionExpired).toBe(true);
285
- }
286
- });
287
-
288
- it('should handle errors', async () => {
289
- try {
290
- await lambderCaller.api('failingApi', {});
291
- // Should not reach here
292
- expect(true).toBe(false);
293
- } catch (error: any) {
294
- expect(error.errorMessage).toBe('Something went wrong');
295
- }
296
- });
297
- });
298
- ```
299
-
300
- ## Browser Testing
301
-
302
- LambderMSW also works in browser environments with MSW's browser integration:
303
-
304
- ```typescript
305
- // test/browser-setup.ts
306
- import { setupWorker } from 'msw/browser';
307
- import { LambderMSW } from 'lambder';
308
- import type { ApiContractType } from '../backend'; // Type-only import from your backend
309
-
310
- const lambderMSW = new LambderMSW<ApiContractType>({
311
- apiPath: '/secure'
312
- });
313
-
314
- const handlers = [
315
- lambderMSW.mockApi('getUserById', async (payload) => {
316
- return {
317
- id: payload.userId,
318
- name: 'John Doe',
319
- email: 'john@example.com'
320
- };
321
- })
322
- ];
323
-
324
- const worker = setupWorker(...handlers);
325
-
326
- // Start the worker
327
- worker.start();
328
- ```
329
-
330
- ## Advanced Usage
331
-
332
- ### Dynamic Mock Responses
333
-
334
- ```typescript
335
- lambderMSW.mockApi('searchUsers', async (payload) => {
336
- const { query, limit } = payload;
337
-
338
- // Return different responses based on input
339
- if (query === 'admin') {
340
- return [{
341
- id: '1',
342
- name: 'Admin User',
343
- role: 'admin'
344
- }];
345
- }
346
-
347
- return Array.from({ length: limit }, (_, i) => ({
348
- id: `${i}`,
349
- name: `User ${i}`,
350
- role: 'user'
351
- }));
352
- });
353
- ```
354
-
355
- ### Override Handlers Per Test
356
-
357
- ```typescript
358
- it('should handle specific user', async () => {
359
- // Override the default handler for this test
360
- server.use(
361
- lambderMSW.mockApi('getUserById', async (payload) => {
362
- return {
363
- id: payload.userId,
364
- name: 'Special User',
365
- email: 'special@example.com'
366
- };
367
- })
368
- );
369
-
370
- const result = await lambderCaller.api('getUserById', { userId: '999' });
371
- expect(result?.name).toBe('Special User');
372
- });
373
- ```
374
-
375
- ## Benefits
376
-
377
- - Full TypeScript support with API contracts
378
- - Intuitive methods matching Lambder's API structure
379
- - Test isolation without real backend dependencies
380
- - Simulate real-world scenarios (delays, errors, etc.)
381
-
382
- ## Troubleshooting
383
-
384
- ### MSW Not Found Error
385
-
386
- If you see "MSW (Mock Service Worker) is required", make sure MSW is installed:
387
-
388
- ```bash
389
- npm install msw --save-dev
390
- ```
391
-
392
- ### Handler Not Matching
393
-
394
- LambderMSW matches handlers based on the `apiName` in the request body. Make sure:
395
- 1. Your `apiPath` matches between backend, frontend, and mocks
396
- 2. The API name string matches exactly
397
- 3. Handlers are registered before making requests
398
-
399
- ### Console Warnings
400
-
401
- LambderMSW logs matching information to console for debugging. To see these logs:
402
- - Check browser console for "LambderMSW called for:" messages
403
- - Verify "Matched!" appears when handler should execute
404
-
405
- ## See Also
406
-
407
- - [MSW Documentation](https://mswjs.io/)
408
- - [Type-Safe Quick Start](./TYPE_SAFE_QUICK_START.md)
409
- - [Lambder Main Documentation](../Readme.md)
@@ -1,77 +0,0 @@
1
- # Type-Safe API Quick Start (v2.0)
2
-
3
- ## In 3 Simple Steps
4
-
5
- ### 1. Define & Implement APIs (Backend)
6
-
7
- Use Zod schemas to define your API contract inline. Lambder will automatically validate inputs at runtime and infer types for compile-time safety.
8
-
9
- ```typescript
10
- import { z } from "zod";
11
- import Lambder from "lambder";
12
-
13
- // Initialize
14
- const lambder = new Lambder({
15
- publicPath: "./public",
16
- apiPath: "/api"
17
- })
18
- // Chain APIs
19
- .addApi("getUser", {
20
- input: z.object({ userId: z.string() }),
21
- output: z.object({ id: z.string(), name: z.string() })
22
- }, async (ctx, resolver) => {
23
- // ctx.apiPayload is typed as { userId: string }
24
- // Runtime validation is already performed!
25
- return resolver.api({
26
- id: ctx.apiPayload.userId,
27
- name: "John Doe"
28
- });
29
- });
30
-
31
- // Export the inferred contract type
32
- export type ApiContractType = typeof lambder.ApiContract;
33
-
34
- export const handler = lambder.getHandler();
35
- ```
36
-
37
- ### 2. Use in Frontend
38
-
39
- Import the type (not the code) and use `LambderCaller`.
40
-
41
- ```typescript
42
- import { LambderCaller } from "lambder";
43
- import type { ApiContractType } from "./backend"; // Type-only import
44
-
45
- const lambderCaller = new LambderCaller<ApiContractType>({
46
- apiPath: "/api"
47
- });
48
-
49
- // Fully typed!
50
- // TypeScript knows 'getUser' takes { userId: string } and returns { id: string, name: string }
51
- const user = await lambderCaller.api("getUser", { userId: "123" });
52
- ```
53
-
54
- ### 3. Modular APIs (Optional)
55
-
56
- For larger apps, split your APIs into modules using `.use()`.
57
-
58
- ```typescript
59
- // api.user.ts
60
- import { z } from "zod";
61
- import Lambder from "lambder";
62
-
63
- export const userApi = <T>(l: Lambder<T>) => {
64
- return l.addApi("login", {
65
- input: z.object({ email: z.string() }),
66
- output: z.boolean()
67
- }, async (ctx, resolver) => {
68
- return resolver.api(true);
69
- });
70
- };
71
-
72
- // index.ts
73
- import { userApi } from "./api.user";
74
-
75
- const lambder = new Lambder({ publicPath: './public' })
76
- .use(userApi); // Types are preserved!
77
- ```