docpouch-client 0.9.1 → 1.0.3

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,613 @@
1
+ import express from 'express';
2
+ import { createServer, type Server as HttpServer } from 'http';
3
+ import { Server as SocketIOServer } from 'socket.io';
4
+ import type { AddressInfo } from 'net';
5
+ import crypto from 'crypto';
6
+
7
+ export interface MockSession {
8
+ userId: string;
9
+ isAdmin: boolean;
10
+ userName: string;
11
+ }
12
+
13
+ export interface MockUser {
14
+ _id: string;
15
+ name: string;
16
+ password: string;
17
+ email?: string;
18
+ department: string;
19
+ group: string;
20
+ isAdmin: boolean;
21
+ }
22
+
23
+ export interface MockDocument {
24
+ _id: string;
25
+ owner: string;
26
+ title: string;
27
+ description?: string;
28
+ type: number;
29
+ subType: number;
30
+ content: any;
31
+ shareWithGroup: boolean;
32
+ shareWithDepartment: boolean;
33
+ public: boolean;
34
+ }
35
+
36
+ export interface MockStructure {
37
+ _id: string;
38
+ name: string;
39
+ description: string;
40
+ fields: { name: string; type: string; items?: string }[];
41
+ }
42
+
43
+ export interface MockType {
44
+ _id: string;
45
+ type: number;
46
+ subType: number;
47
+ name: string;
48
+ description?: string;
49
+ defaultStructureID?: string;
50
+ }
51
+
52
+ export interface MockServer {
53
+ server: HttpServer;
54
+ io: SocketIOServer;
55
+ port: number;
56
+ url: string;
57
+ users: Map<string, MockUser>;
58
+ documents: Map<string, MockDocument>;
59
+ structures: Map<string, MockStructure>;
60
+ types: Map<string, MockType>;
61
+ sessions: Map<string, MockSession>;
62
+ oidcClients: Map<string, any>;
63
+ registrationToken: string;
64
+ reset: () => void;
65
+ waitForPong: (timeout?: number) => Promise<any>;
66
+ }
67
+
68
+ function generateId(): string {
69
+ return Array.from(crypto.getRandomValues(new Uint8Array(12)))
70
+ .map(b => b.toString(36).padStart(2, '0'))
71
+ .join('');
72
+ }
73
+
74
+ export function createMockServer(): Promise<MockServer> {
75
+ const app = express();
76
+ const server = createServer(app);
77
+ const io = new SocketIOServer(server, {
78
+ cors: { origin: '*' }
79
+ });
80
+
81
+ const users = new Map<string, MockUser>();
82
+ const documents = new Map<string, MockDocument>();
83
+ const structures = new Map<string, MockStructure>();
84
+ const types = new Map<string, MockType>();
85
+ const sessions = new Map<string, MockSession>();
86
+
87
+ function seedData() {
88
+ const adminId = generateId();
89
+ users.set(adminId, {
90
+ _id: adminId,
91
+ name: 'admin',
92
+ password: 'admin',
93
+ email: 'admin@example.com',
94
+ department: 'administration',
95
+ group: 'auto-created',
96
+ isAdmin: true,
97
+ });
98
+
99
+ const userId = generateId();
100
+ users.set(userId, {
101
+ _id: userId,
102
+ name: 'testuser',
103
+ password: 'testpass',
104
+ email: 'test@example.com',
105
+ department: 'engineering',
106
+ group: 'alpha',
107
+ isAdmin: false,
108
+ });
109
+ }
110
+
111
+ function reset() {
112
+ users.clear();
113
+ documents.clear();
114
+ structures.clear();
115
+ types.clear();
116
+ sessions.clear();
117
+ seedData();
118
+ }
119
+
120
+ seedData();
121
+
122
+ app.use(express.json());
123
+ app.use(express.urlencoded({ extended: true }));
124
+
125
+ function authMiddleware(req: any, res: any, next: any) {
126
+ const authHeader = req.headers.authorization;
127
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
128
+ return res.status(401).json({ error: 'No token provided' });
129
+ }
130
+ const token = authHeader.slice(7);
131
+ const session = sessions.get(token);
132
+ if (!session) {
133
+ return res.status(401).json({ error: 'Invalid token' });
134
+ }
135
+ req.session = session;
136
+ next();
137
+ }
138
+
139
+ function adminMiddleware(req: any, res: any, next: any) {
140
+ if (!req.session.isAdmin) {
141
+ return res.status(401).json({ error: 'Admin access required' });
142
+ }
143
+ next();
144
+ }
145
+
146
+ function getTokenSession(token: string): MockSession | undefined {
147
+ return sessions.get(token);
148
+ }
149
+
150
+ // Socket.IO auth middleware
151
+ io.use((socket, next) => {
152
+ const token = socket.handshake.auth.token;
153
+ if (!token) {
154
+ return next(new Error('No token provided'));
155
+ }
156
+ const session = getTokenSession(token);
157
+ if (!session) {
158
+ return next(new Error('Invalid token'));
159
+ }
160
+ (socket as any).session = session;
161
+ next();
162
+ });
163
+
164
+ let pongResolve: ((data: any) => void) | null = null;
165
+
166
+ io.on('connection', (socket) => {
167
+ socket.on('heartbeatPong', (data) => {
168
+ if (pongResolve) {
169
+ pongResolve(data);
170
+ pongResolve = null;
171
+ }
172
+ });
173
+ });
174
+
175
+ // Auth endpoints
176
+ app.post('/users/login', (req: any, res: any) => {
177
+ const { name, password } = req.body;
178
+ const user = Array.from(users.values()).find(u => u.name === name);
179
+ if (!user) {
180
+ return res.status(404).json({ error: 'User not found' });
181
+ }
182
+ if (user.password !== password) {
183
+ return res.status(401).json({ error: 'Invalid credentials' });
184
+ }
185
+ const token = generateId() + generateId();
186
+ sessions.set(token, {
187
+ userId: user._id,
188
+ isAdmin: user.isAdmin,
189
+ userName: user.name,
190
+ });
191
+ res.json({
192
+ _id: user._id,
193
+ token,
194
+ isAdmin: user.isAdmin,
195
+ userName: user.name,
196
+ });
197
+ });
198
+
199
+ // User endpoints
200
+ app.get('/users/list', authMiddleware, (req: any, res: any) => {
201
+ const userList = Array.from(users.values()).map(u => ({
202
+ _id: u._id,
203
+ name: u.name,
204
+ email: u.email,
205
+ department: u.department,
206
+ group: u.group,
207
+ isAdmin: u.isAdmin,
208
+ }));
209
+ res.json(userList);
210
+ });
211
+
212
+ app.post('/users/create', authMiddleware, adminMiddleware, (req: any, res: any) => {
213
+ const { name, password, email, department, group, isAdmin } = req.body;
214
+ const _id = generateId();
215
+ const newUser: MockUser = {
216
+ _id,
217
+ name,
218
+ password,
219
+ email,
220
+ department,
221
+ group,
222
+ isAdmin: isAdmin || false,
223
+ };
224
+ users.set(_id, newUser);
225
+ io.emit('newUser', { _id, name, email, department, group });
226
+ res.json({
227
+ _id,
228
+ username: name,
229
+ email,
230
+ department,
231
+ group,
232
+ isAdmin: newUser.isAdmin,
233
+ });
234
+ });
235
+
236
+ app.patch('/users/update/:userID', authMiddleware, (req: any, res: any) => {
237
+ const { userID } = req.params;
238
+ const user = users.get(userID);
239
+ if (!user) {
240
+ return res.status(404).json({ error: 'User not found' });
241
+ }
242
+ if (!req.session.isAdmin && req.session.userId !== userID) {
243
+ return res.status(401).json({ error: 'Not authorized to update this user' });
244
+ }
245
+ const updates = req.body;
246
+ if (updates.name !== undefined) user.name = updates.name;
247
+ if (updates.password !== undefined) user.password = updates.password;
248
+ if (updates.email !== undefined) user.email = updates.email;
249
+ if (updates.department !== undefined) user.department = updates.department;
250
+ if (updates.group !== undefined) user.group = updates.group;
251
+ if (updates.isAdmin !== undefined && req.session.isAdmin) user.isAdmin = updates.isAdmin;
252
+ users.set(userID, user);
253
+ io.emit('changedUser', { _id: userID, ...updates });
254
+ res.json({ success: true });
255
+ });
256
+
257
+ app.delete('/users/remove/:userID', authMiddleware, adminMiddleware, (req: any, res: any) => {
258
+ const { userID } = req.params;
259
+ if (!users.has(userID)) {
260
+ return res.status(404).json({ error: 'User not found' });
261
+ }
262
+ users.delete(userID);
263
+ Array.from(documents.entries()).filter(([_, d]) => d.owner === userID).forEach(([id]) => documents.delete(id));
264
+ io.emit('removedUser', { removedID: userID });
265
+ res.json({ success: true });
266
+ });
267
+
268
+ // Document endpoints
269
+ app.post('/docs/create', authMiddleware, (req: any, res: any) => {
270
+ const owner = req.session.userId;
271
+ const _id = generateId();
272
+ const doc: MockDocument = {
273
+ _id,
274
+ owner,
275
+ title: req.body.title,
276
+ description: req.body.description,
277
+ type: req.body.type,
278
+ subType: req.body.subType,
279
+ content: req.body.content,
280
+ shareWithGroup: req.body.shareWithGroup || false,
281
+ shareWithDepartment: req.body.shareWithDepartment || false,
282
+ public: req.body.public || false,
283
+ };
284
+ documents.set(_id, doc);
285
+ io.emit('newDocument', { ...doc });
286
+ res.json(doc);
287
+ });
288
+
289
+ app.get('/docs/list', authMiddleware, (req: any, res: any) => {
290
+ const docList = Array.from(documents.values())
291
+ .filter(d => canRead(req.session, d))
292
+ .map(({ content, ...rest }) => rest);
293
+ res.json(docList);
294
+ });
295
+
296
+ app.post('/docs/fetch', authMiddleware, (req: any, res: any) => {
297
+ const query = req.body;
298
+ const results = Array.from(documents.values())
299
+ .filter(d => canRead(req.session, d))
300
+ .filter(d => {
301
+ if (query._id && d._id !== query._id) return false;
302
+ if (query.owner && d.owner !== query.owner) return false;
303
+ if (query.type !== undefined && d.type !== query.type) return false;
304
+ if (query.subType !== undefined && d.subType !== query.subType) return false;
305
+ if (query.title !== undefined && d.title !== query.title) return false;
306
+ if (query.description !== undefined && d.description !== query.description) return false;
307
+ if (query.shareWithGroup !== undefined && d.shareWithGroup !== query.shareWithGroup) return false;
308
+ if (query.shareWithDepartment !== undefined && d.shareWithDepartment !== query.shareWithDepartment) return false;
309
+ if (query.public !== undefined && d.public !== query.public) return false;
310
+ return true;
311
+ });
312
+ res.json(results);
313
+ });
314
+
315
+ app.patch('/docs/update/:documentID', authMiddleware, (req: any, res: any) => {
316
+ const { documentID } = req.params;
317
+ const doc = documents.get(documentID);
318
+ if (!doc) {
319
+ return res.status(404).json({ error: 'Document not found' });
320
+ }
321
+ if (!req.session.isAdmin && doc.owner !== req.session.userId) {
322
+ const canEdit = doc.shareWithGroup || doc.shareWithDepartment || doc.public;
323
+ if (!canEdit) {
324
+ return res.status(401).json({ error: 'Not authorized to update this document' });
325
+ }
326
+ }
327
+ const updates = req.body;
328
+ if (updates.title !== undefined) doc.title = updates.title;
329
+ if (updates.description !== undefined) doc.description = updates.description;
330
+ if (updates.type !== undefined) doc.type = updates.type;
331
+ if (updates.subType !== undefined) doc.subType = updates.subType;
332
+ if (updates.content !== undefined) doc.content = updates.content;
333
+ if (updates.shareWithGroup !== undefined && doc.owner === req.session.userId) doc.shareWithGroup = updates.shareWithGroup;
334
+ if (updates.shareWithDepartment !== undefined && doc.owner === req.session.userId) doc.shareWithDepartment = updates.shareWithDepartment;
335
+ if (updates.public !== undefined && doc.owner === req.session.userId) doc.public = updates.public;
336
+ documents.set(documentID, doc);
337
+ io.emit('changedDocument', { _id: documentID, ...updates });
338
+ res.json({ success: true });
339
+ });
340
+
341
+ app.delete('/docs/remove/:documentID', authMiddleware, (req: any, res: any) => {
342
+ const { documentID } = req.params;
343
+ const doc = documents.get(documentID);
344
+ if (!doc) {
345
+ return res.status(404).json({ error: 'Document not found' });
346
+ }
347
+ if (!req.session.isAdmin && doc.owner !== req.session.userId) {
348
+ return res.status(401).json({ error: 'Not authorized to delete this document' });
349
+ }
350
+ documents.delete(documentID);
351
+ io.emit('removedDocument', { removedID: documentID });
352
+ res.json({ success: true });
353
+ });
354
+
355
+ // Structure endpoints
356
+ app.post('/structures/create', authMiddleware, adminMiddleware, (req: any, res: any) => {
357
+ const _id = generateId();
358
+ const structure: MockStructure = {
359
+ _id,
360
+ name: req.body.name,
361
+ description: req.body.description || '',
362
+ fields: req.body.fields || [],
363
+ };
364
+ structures.set(_id, structure);
365
+ io.emit('newStructure', { ...structure });
366
+ res.json(structure);
367
+ });
368
+
369
+ app.get('/structures/list', authMiddleware, (req: any, res: any) => {
370
+ const list = Array.from(structures.values());
371
+ res.json(list);
372
+ });
373
+
374
+ app.patch('/structures/update/:structureID', authMiddleware, adminMiddleware, (req: any, res: any) => {
375
+ const { structureID } = req.params;
376
+ const structure = structures.get(structureID);
377
+ if (!structure) {
378
+ return res.status(404).json({ error: 'Structure not found' });
379
+ }
380
+ const updates = req.body;
381
+ if (updates.name !== undefined) structure.name = updates.name;
382
+ if (updates.description !== undefined) structure.description = updates.description;
383
+ if (updates.fields !== undefined) structure.fields = updates.fields;
384
+ structures.set(structureID, structure);
385
+ io.emit('changedStructure', { _id: structureID, ...updates });
386
+ res.json({ success: true });
387
+ });
388
+
389
+ app.delete('/structures/remove/:structureID', authMiddleware, adminMiddleware, (req: any, res: any) => {
390
+ const { structureID } = req.params;
391
+ if (!structures.has(structureID)) {
392
+ return res.status(404).json({ error: 'Structure not found' });
393
+ }
394
+ structures.delete(structureID);
395
+ io.emit('removedStructure', { removedID: structureID });
396
+ res.json({ success: true });
397
+ });
398
+
399
+ // Type endpoints
400
+ app.post('/types/write', authMiddleware, adminMiddleware, (req: any, res: any) => {
401
+ let docType: MockType;
402
+ if (req.body._id && types.has(req.body._id)) {
403
+ docType = types.get(req.body._id)!;
404
+ if (req.body.type !== undefined) docType.type = req.body.type;
405
+ if (req.body.subType !== undefined) docType.subType = req.body.subType;
406
+ if (req.body.name !== undefined) docType.name = req.body.name;
407
+ if (req.body.description !== undefined) docType.description = req.body.description;
408
+ if (req.body.defaultStructureID !== undefined) docType.defaultStructureID = req.body.defaultStructureID;
409
+ types.set(req.body._id, docType);
410
+ io.emit('changedType', { ...docType });
411
+ } else {
412
+ const _id = req.body._id || generateId();
413
+ docType = {
414
+ _id,
415
+ type: req.body.type,
416
+ subType: req.body.subType,
417
+ name: req.body.name,
418
+ description: req.body.description,
419
+ defaultStructureID: req.body.defaultStructureID,
420
+ };
421
+ types.set(_id, docType);
422
+ io.emit('newType', { ...docType });
423
+ }
424
+ res.json(docType);
425
+ });
426
+
427
+ app.get('/types/list', authMiddleware, (req: any, res: any) => {
428
+ const list = Array.from(types.values());
429
+ res.json(list);
430
+ });
431
+
432
+ app.delete('/types/remove/:typeID', authMiddleware, adminMiddleware, (req: any, res: any) => {
433
+ const { typeID } = req.params;
434
+ if (!types.has(typeID)) {
435
+ return res.status(404).json({ error: 'Type not found' });
436
+ }
437
+ types.delete(typeID);
438
+ io.emit('removedType', { removedID: typeID });
439
+ res.json({ success: true });
440
+ });
441
+
442
+ // OIDC Dynamic Client Registration
443
+ const oidcClients = new Map<string, any>();
444
+
445
+ const registrationToken = 'mock-reg-token-' + generateId();
446
+
447
+ app.post('/oidc/reg', (req: any, res: any) => {
448
+ const authHeader = req.headers.authorization;
449
+ if (!authHeader || authHeader !== `Bearer ${registrationToken}`) {
450
+ return res.status(401).json({ error: 'Invalid or missing registration access token' });
451
+ }
452
+ const clientId = generateId();
453
+ const clientSecret = generateId() + generateId();
454
+ const client: any = {
455
+ client_id: clientId,
456
+ client_secret: clientSecret,
457
+ client_secret_expires_at: 0,
458
+ client_id_issued_at: Math.floor(Date.now() / 1000),
459
+ registration_access_token: 'reg-access-' + generateId(),
460
+ registration_client_uri: `http://localhost:${port}/oidc/reg/${clientId}`,
461
+ client_name: req.body.client_name,
462
+ redirect_uris: req.body.redirect_uris || [],
463
+ grant_types: req.body.grant_types || ['authorization_code'],
464
+ response_types: req.body.response_types || ['code'],
465
+ scope: req.body.scope || 'openid',
466
+ token_endpoint_auth_method: req.body.token_endpoint_auth_method || 'client_secret_basic',
467
+ };
468
+ oidcClients.set(clientId, client);
469
+ res.status(201).json(client);
470
+ });
471
+
472
+ app.get('/oidc/reg/:clientId', (req: any, res: any) => {
473
+ const authHeader = req.headers.authorization;
474
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
475
+ return res.status(401).json({ error: 'Invalid or missing registration access token' });
476
+ }
477
+ const client = oidcClients.get(req.params.clientId);
478
+ if (!client) {
479
+ return res.status(404).json({ error: 'Client not found' });
480
+ }
481
+ res.json(client);
482
+ });
483
+
484
+ app.put('/oidc/reg/:clientId', (req: any, res: any) => {
485
+ const authHeader = req.headers.authorization;
486
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
487
+ return res.status(401).json({ error: 'Invalid or missing registration access token' });
488
+ }
489
+ const client = oidcClients.get(req.params.clientId);
490
+ if (!client) {
491
+ return res.status(404).json({ error: 'Client not found' });
492
+ }
493
+ Object.assign(client, req.body);
494
+ res.json(client);
495
+ });
496
+
497
+ app.delete('/oidc/reg/:clientId', (req: any, res: any) => {
498
+ const authHeader = req.headers.authorization;
499
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
500
+ return res.status(401).json({ error: 'Invalid or missing registration access token' });
501
+ }
502
+ const client = oidcClients.get(req.params.clientId);
503
+ if (!client) {
504
+ return res.status(404).json({ error: 'Client not found' });
505
+ }
506
+ oidcClients.delete(req.params.clientId);
507
+ res.status(204).send();
508
+ });
509
+
510
+ // Version check
511
+ app.get('/version/check', (_req: any, res: any) => {
512
+ res.json({
513
+ hasUpdate: false,
514
+ currentVersion: '1.7.1',
515
+ latestVersion: '1.7.1',
516
+ });
517
+ });
518
+
519
+ // OIDC endpoints
520
+ app.get('/.well-known/openid-configuration', (req: any, res: any) => {
521
+ res.json({
522
+ issuer: `http://localhost:${port}`,
523
+ authorization_endpoint: `http://localhost:${port}/mock-oidc/authorize`,
524
+ token_endpoint: `http://localhost:${port}/mock-oidc/token`,
525
+ jwks_uri: `http://localhost:${port}/mock-oidc/jwks`,
526
+ response_types_supported: ['code'],
527
+ subject_types_supported: ['public'],
528
+ id_token_signing_alg_values_supported: ['RS256'],
529
+ });
530
+ });
531
+
532
+ let port: number;
533
+
534
+ const oidcCodes = new Map<string, string>();
535
+
536
+ app.post('/mock-oidc/token', (req: any, res: any) => {
537
+ const { grant_type, code, code_verifier, refresh_token } = req.body;
538
+ if (grant_type === 'authorization_code') {
539
+ if (!code || !oidcCodes.has(code) || !code_verifier) {
540
+ return res.status(400).json({ error: 'Invalid code or code_verifier' });
541
+ }
542
+ oidcCodes.delete(code);
543
+ return res.json({
544
+ access_token: 'mock-oidc-access-token-' + generateId(),
545
+ refresh_token: 'mock-oidc-refresh-token-' + generateId(),
546
+ id_token: 'mock-oidc-id-token-' + generateId(),
547
+ expires_in: 3600,
548
+ token_type: 'Bearer',
549
+ scope: 'openid profile',
550
+ });
551
+ }
552
+ if (grant_type === 'refresh_token') {
553
+ return res.json({
554
+ access_token: 'mock-oidc-access-token-' + generateId(),
555
+ refresh_token: refresh_token,
556
+ id_token: 'mock-oidc-id-token-' + generateId(),
557
+ expires_in: 3600,
558
+ token_type: 'Bearer',
559
+ scope: 'openid profile',
560
+ });
561
+ }
562
+ res.status(400).json({ error: 'Unsupported grant_type' });
563
+ });
564
+
565
+ app.get('/mock-oidc/authorize', (req: any, res: any) => {
566
+ const code = generateId();
567
+ const codeVerifier = req.query.code_challenge || 'mock-verifier';
568
+ oidcCodes.set(code, codeVerifier as string);
569
+ const redirectUri = req.query.redirect_uri;
570
+ const state = req.query.state;
571
+ const redirectUrl = `${redirectUri}?code=${code}&state=${state}`;
572
+ res.redirect(redirectUrl);
573
+ });
574
+
575
+ return new Promise((resolve) => {
576
+ server.listen(0, () => {
577
+ port = (server.address() as AddressInfo).port;
578
+ const waitForPong = (timeout = 3000): Promise<any> =>
579
+ new Promise((resolve, reject) => {
580
+ pongResolve = resolve;
581
+ setTimeout(() => {
582
+ if (pongResolve) {
583
+ pongResolve = null;
584
+ reject(new Error('Pong timeout'));
585
+ }
586
+ }, timeout);
587
+ });
588
+
589
+ resolve({
590
+ server,
591
+ io,
592
+ port,
593
+ url: `http://localhost:${port}`,
594
+ users,
595
+ documents,
596
+ structures,
597
+ types,
598
+ sessions,
599
+ oidcClients,
600
+ registrationToken,
601
+ reset,
602
+ waitForPong,
603
+ });
604
+ });
605
+ });
606
+ }
607
+
608
+ function canRead(session: any, doc: MockDocument): boolean {
609
+ if (session.isAdmin) return true;
610
+ if (doc.owner === session.userId) return true;
611
+ if (doc.public) return true;
612
+ return false;
613
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src"
5
+ },
6
+ "include": ["src/**/*.ts", "src/**/*.tsx"]
7
+ }
package/tsconfig.json CHANGED
@@ -2,24 +2,26 @@
2
2
  "compilerOptions": {
3
3
  "target": "ES2020",
4
4
  "module": "Node16",
5
- "lib": ["ES6", "DOM"],
5
+ "lib": [
6
+ "ES2017",
7
+ "DOM"
8
+ ],
6
9
  "moduleResolution": "Node16",
7
10
  "strict": true,
8
11
  "esModuleInterop": true,
9
12
  "skipLibCheck": true,
10
13
  "forceConsistentCasingInFileNames": true,
11
14
  "outDir": "./dist",
12
- "rootDir": "./src",
15
+ "rootDir": ".",
13
16
  "declaration": true,
14
17
  "emitDeclarationOnly": false,
15
18
  "resolveJsonModule": true,
16
19
  "isolatedModules": true,
17
20
  "allowSyntheticDefaultImports": true
18
21
  },
19
- "include": ["**/*.ts", "**/*.tsx"],
20
- "exclude": [
21
- "node_modules",
22
- "**/*.test.ts",
23
- "./dist/**/*"
22
+ "include": [
23
+ "src/**/*.ts",
24
+ "src/**/*.tsx",
25
+ "tests/**/*.ts"
24
26
  ]
25
27
  }