lambder 1.0.124 → 1.0.126

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.
@@ -0,0 +1,224 @@
1
+ /**
2
+ * Type Safety Tests
3
+ *
4
+ * This file tests that the type system works correctly.
5
+ * If this file compiles without errors, the types are working!
6
+ */
7
+
8
+ import Lambder from '../src/Lambder.js';
9
+ import LambderCaller from '../src/LambderCaller.js';
10
+ import type { ApiContract } from '../src/index.js';
11
+
12
+ // Test contract
13
+ type TestApiContract = {
14
+ getUser: { input: { userId: string }, output: { id: string, name: string } },
15
+ createUser: { input: { name: string, email: string }, output: { id: string, name: string, email: string } },
16
+ listUsers: { input: void, output: Array<{ id: string, name: string }> },
17
+ deleteUser: { input: { userId: string }, output: boolean }
18
+ }
19
+
20
+ // ============================================================================
21
+ // Test 1: LambderCaller Type Safety
22
+ // ============================================================================
23
+
24
+ function testCallerTypes() {
25
+ const caller = new LambderCaller<TestApiContract>({
26
+ apiPath: '/api',
27
+ isCorsEnabled: false
28
+ });
29
+
30
+ async function test() {
31
+ // ✅ Should work: Correct types
32
+ const user1 = await caller.api('getUser', { userId: '123' });
33
+ const user2 = await caller.api('createUser', { name: 'Alice', email: 'alice@example.com' });
34
+ const users = await caller.api('listUsers', undefined);
35
+ const deleted = await caller.api('deleteUser', { userId: '123' });
36
+
37
+ // Type assertions to verify return types
38
+ if (user1) {
39
+ const name: string = user1.name; // Should work
40
+ const id: string = user1.id; // Should work
41
+ }
42
+
43
+ if (user2) {
44
+ const email: string = user2.email; // Should work
45
+ }
46
+
47
+ if (users) {
48
+ const firstUser = users[0];
49
+ if (firstUser) {
50
+ const name: string = firstUser.name; // Should work
51
+ }
52
+ }
53
+
54
+ if (deleted !== null && deleted !== undefined) {
55
+ const result: boolean = deleted; // Should work
56
+ }
57
+
58
+ // ❌ These should cause TypeScript errors (commented out to allow compilation):
59
+
60
+ // Wrong property name
61
+ // await caller.api('getUser', { id: '123' }); // Error: should be userId
62
+
63
+ // Missing required property
64
+ // await caller.api('createUser', { name: 'Bob' }); // Error: missing email
65
+
66
+ // Wrong type
67
+ // await caller.api('getUser', { userId: 123 }); // Error: userId should be string
68
+
69
+ // Non-existent API
70
+ // await caller.api('nonExistent', {}); // Error: API doesn't exist
71
+
72
+ // Wrong payload for void input
73
+ // await caller.api('listUsers', { something: true }); // Error: should be undefined
74
+ }
75
+ }
76
+
77
+ // ============================================================================
78
+ // Test 2: Lambder Type Safety
79
+ // ============================================================================
80
+
81
+ function testLambderTypes() {
82
+ const lambder = new Lambder<TestApiContract>({
83
+ publicPath: './public',
84
+ apiPath: '/api'
85
+ });
86
+
87
+ // ✅ Should work: Typed API
88
+ lambder.addApi('getUser', async (ctx, resolver) => {
89
+ // ctx.apiPayload should be typed as { userId: string }
90
+ const userId: string = ctx.apiPayload.userId; // Should work
91
+
92
+ // Return correct type
93
+ return resolver.api({ id: userId, name: 'Test' });
94
+ });
95
+
96
+ // ✅ Should work: Typed session API
97
+ lambder.addSessionApi('createUser', async (ctx, resolver) => {
98
+ // ctx.apiPayload should be typed as { name: string, email: string }
99
+ const name: string = ctx.apiPayload.name;
100
+ const email: string = ctx.apiPayload.email;
101
+
102
+ return resolver.api({ id: '1', name, email });
103
+ });
104
+
105
+ // ✅ Should work: Void input API
106
+ lambder.addApi('listUsers', async (ctx, resolver) => {
107
+ // ctx.apiPayload should be void/undefined
108
+ return resolver.api([
109
+ { id: '1', name: 'User 1' },
110
+ { id: '2', name: 'User 2' }
111
+ ]);
112
+ });
113
+
114
+ // ✅ Should work: RegExp (untyped)
115
+ lambder.addApi(/^admin\./, async (ctx, resolver) => {
116
+ // ctx.apiPayload is any (untyped)
117
+ return resolver.api({});
118
+ });
119
+
120
+ // ❌ These should cause TypeScript errors (commented out):
121
+
122
+ // Accessing wrong property
123
+ // lambder.addApi('getUser', async (ctx, resolver) => {
124
+ // const id = ctx.apiPayload.id; // Error: should be userId
125
+ // return resolver.api({ id, name: 'Test' });
126
+ // });
127
+
128
+ // Returning wrong type
129
+ // lambder.addApi('getUser', async (ctx, resolver) => {
130
+ // return resolver.api({ id: '1' }); // Error: missing name property
131
+ // });
132
+ }
133
+
134
+ // ============================================================================
135
+ // Test 3: Backward Compatibility (No Contract)
136
+ // ============================================================================
137
+
138
+ function testBackwardCompatibility() {
139
+ // Without contract type - should work as before (untyped)
140
+ const caller = new LambderCaller({
141
+ apiPath: '/api',
142
+ isCorsEnabled: false
143
+ });
144
+
145
+ const lambder = new Lambder({
146
+ publicPath: './public',
147
+ apiPath: '/api'
148
+ });
149
+
150
+ async function test() {
151
+ // Should work - untyped
152
+ const result = await caller.api('anyApi', { anything: true });
153
+
154
+ lambder.addApi('anyApi', async (ctx, resolver) => {
155
+ // ctx.apiPayload is any
156
+ return resolver.api({ anything: ctx.apiPayload });
157
+ });
158
+ }
159
+ }
160
+
161
+ // ============================================================================
162
+ // Test 4: apiRaw Method
163
+ // ============================================================================
164
+
165
+ function testApiRaw() {
166
+ const caller = new LambderCaller<TestApiContract>({
167
+ apiPath: '/api',
168
+ isCorsEnabled: false
169
+ });
170
+
171
+ async function test() {
172
+ // apiRaw should also be typed
173
+ const response = await caller.apiRaw('getUser', { userId: '123' });
174
+
175
+ if (response) {
176
+ // response.payload should be typed
177
+ const user = response.payload;
178
+ if (user) {
179
+ const name: string = user.name; // Should work
180
+ const id: string = user.id; // Should work
181
+ }
182
+ }
183
+ }
184
+ }
185
+
186
+ // ============================================================================
187
+ // Test 5: Complex Types
188
+ // ============================================================================
189
+
190
+ type ComplexApiContract = {
191
+ update: {
192
+ input: { id: string } & Partial<{ name: string, email: string }>,
193
+ output: { id: string, name: string, email: string }
194
+ },
195
+ search: {
196
+ input: { query: string, filters?: { role?: string, active?: boolean } },
197
+ output: Array<{ id: string, name: string }>
198
+ }
199
+ }
200
+
201
+ function testComplexTypes() {
202
+ const caller = new LambderCaller<ComplexApiContract>({
203
+ apiPath: '/api',
204
+ isCorsEnabled: false
205
+ });
206
+
207
+ async function test() {
208
+ // Should work with partial update
209
+ await caller.api('update', { id: '1', name: 'New Name' });
210
+ await caller.api('update', { id: '1', email: 'new@email.com' });
211
+ await caller.api('update', { id: '1' }); // Only id
212
+
213
+ // Should work with optional nested object
214
+ await caller.api('search', { query: 'test' });
215
+ await caller.api('search', { query: 'test', filters: { role: 'admin' } });
216
+ await caller.api('search', { query: 'test', filters: { role: 'admin', active: true } });
217
+ }
218
+ }
219
+
220
+ // ============================================================================
221
+ // If this file compiles without errors, the type system is working! ✅
222
+ // ============================================================================
223
+
224
+ export { };