@geekmidas/cli 0.12.0 → 0.14.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 (82) hide show
  1. package/dist/bundler-BjholBlA.cjs +131 -0
  2. package/dist/bundler-BjholBlA.cjs.map +1 -0
  3. package/dist/bundler-DWctKN1z.mjs +130 -0
  4. package/dist/bundler-DWctKN1z.mjs.map +1 -0
  5. package/dist/config.d.cts +1 -1
  6. package/dist/config.d.mts +1 -1
  7. package/dist/dokploy-api-B7KxOQr3.cjs +3 -0
  8. package/dist/dokploy-api-C7F9VykY.cjs +317 -0
  9. package/dist/dokploy-api-C7F9VykY.cjs.map +1 -0
  10. package/dist/dokploy-api-CaETb2L6.mjs +305 -0
  11. package/dist/dokploy-api-CaETb2L6.mjs.map +1 -0
  12. package/dist/dokploy-api-DHvfmWbi.mjs +3 -0
  13. package/dist/{encryption-Dyf_r1h-.cjs → encryption-D7Efcdi9.cjs} +1 -1
  14. package/dist/{encryption-Dyf_r1h-.cjs.map → encryption-D7Efcdi9.cjs.map} +1 -1
  15. package/dist/{encryption-C8H-38Yy.mjs → encryption-h4Nb6W-M.mjs} +1 -1
  16. package/dist/{encryption-C8H-38Yy.mjs.map → encryption-h4Nb6W-M.mjs.map} +1 -1
  17. package/dist/index.cjs +1520 -1136
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.mjs +1520 -1136
  20. package/dist/index.mjs.map +1 -1
  21. package/dist/{openapi-Bt_1FDpT.cjs → openapi-C89hhkZC.cjs} +3 -3
  22. package/dist/{openapi-Bt_1FDpT.cjs.map → openapi-C89hhkZC.cjs.map} +1 -1
  23. package/dist/{openapi-BfFlOBCG.mjs → openapi-CZVcfxk-.mjs} +3 -3
  24. package/dist/{openapi-BfFlOBCG.mjs.map → openapi-CZVcfxk-.mjs.map} +1 -1
  25. package/dist/{openapi-react-query-B6XTeGqS.mjs → openapi-react-query-CM2_qlW9.mjs} +1 -1
  26. package/dist/{openapi-react-query-B6XTeGqS.mjs.map → openapi-react-query-CM2_qlW9.mjs.map} +1 -1
  27. package/dist/{openapi-react-query-B-sNWHFU.cjs → openapi-react-query-iKjfLzff.cjs} +1 -1
  28. package/dist/{openapi-react-query-B-sNWHFU.cjs.map → openapi-react-query-iKjfLzff.cjs.map} +1 -1
  29. package/dist/openapi-react-query.cjs +1 -1
  30. package/dist/openapi-react-query.mjs +1 -1
  31. package/dist/openapi.cjs +1 -1
  32. package/dist/openapi.d.cts +1 -1
  33. package/dist/openapi.d.mts +1 -1
  34. package/dist/openapi.mjs +1 -1
  35. package/dist/{storage-C9PU_30f.mjs → storage-BaOP55oq.mjs} +48 -2
  36. package/dist/storage-BaOP55oq.mjs.map +1 -0
  37. package/dist/{storage-BXoJvmv2.cjs → storage-Bn3K9Ccu.cjs} +59 -1
  38. package/dist/storage-Bn3K9Ccu.cjs.map +1 -0
  39. package/dist/storage-UfyTn7Zm.cjs +7 -0
  40. package/dist/storage-nkGIjeXt.mjs +3 -0
  41. package/dist/{types-BR0M2v_c.d.mts → types-BgaMXsUa.d.cts} +3 -1
  42. package/dist/{types-BR0M2v_c.d.mts.map → types-BgaMXsUa.d.cts.map} +1 -1
  43. package/dist/{types-BhkZc-vm.d.cts → types-iFk5ms7y.d.mts} +3 -1
  44. package/dist/{types-BhkZc-vm.d.cts.map → types-iFk5ms7y.d.mts.map} +1 -1
  45. package/package.json +4 -4
  46. package/src/auth/__tests__/credentials.spec.ts +127 -0
  47. package/src/auth/__tests__/index.spec.ts +69 -0
  48. package/src/auth/credentials.ts +33 -0
  49. package/src/auth/index.ts +57 -50
  50. package/src/build/__tests__/bundler.spec.ts +444 -0
  51. package/src/build/__tests__/endpoint-analyzer.spec.ts +623 -0
  52. package/src/build/__tests__/handler-templates.spec.ts +272 -0
  53. package/src/build/bundler.ts +126 -8
  54. package/src/build/index.ts +31 -0
  55. package/src/build/types.ts +6 -0
  56. package/src/deploy/__tests__/dokploy-api.spec.ts +698 -0
  57. package/src/deploy/__tests__/dokploy.spec.ts +196 -6
  58. package/src/deploy/__tests__/index.spec.ts +339 -0
  59. package/src/deploy/__tests__/init.spec.ts +147 -16
  60. package/src/deploy/docker.ts +32 -3
  61. package/src/deploy/dokploy-api.ts +581 -0
  62. package/src/deploy/dokploy.ts +66 -93
  63. package/src/deploy/index.ts +587 -32
  64. package/src/deploy/init.ts +192 -249
  65. package/src/deploy/types.ts +19 -1
  66. package/src/dev/__tests__/index.spec.ts +95 -0
  67. package/src/docker/__tests__/templates.spec.ts +144 -0
  68. package/src/docker/index.ts +96 -6
  69. package/src/docker/templates.ts +114 -27
  70. package/src/generators/EndpointGenerator.ts +2 -2
  71. package/src/index.ts +34 -13
  72. package/src/secrets/__tests__/storage.spec.ts +208 -0
  73. package/src/secrets/storage.ts +73 -0
  74. package/src/types.ts +2 -0
  75. package/dist/bundler-DRXCw_YR.mjs +0 -70
  76. package/dist/bundler-DRXCw_YR.mjs.map +0 -1
  77. package/dist/bundler-WsEvH_b2.cjs +0 -71
  78. package/dist/bundler-WsEvH_b2.cjs.map +0 -1
  79. package/dist/storage-BUYQJgz7.cjs +0 -4
  80. package/dist/storage-BXoJvmv2.cjs.map +0 -1
  81. package/dist/storage-C9PU_30f.mjs.map +0 -1
  82. package/dist/storage-DLJAYxzJ.mjs +0 -3
@@ -0,0 +1,623 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ analyzeEndpointFeatures,
4
+ determineEndpointTier,
5
+ type EndpointAnalysis,
6
+ type EndpointFeatures,
7
+ summarizeAnalysis,
8
+ } from '../endpoint-analyzer';
9
+
10
+ describe('endpoint-analyzer', () => {
11
+ describe('analyzeEndpointFeatures', () => {
12
+ it('should detect auth when authorizer is set', () => {
13
+ const endpoint = {
14
+ authorizer: () => true,
15
+ services: [],
16
+ databaseService: undefined,
17
+ input: {},
18
+ audits: [],
19
+ events: [],
20
+ rateLimit: undefined,
21
+ rlsConfig: undefined,
22
+ rlsBypass: false,
23
+ outputSchema: undefined,
24
+ };
25
+
26
+ const features = analyzeEndpointFeatures(endpoint as any);
27
+ expect(features.hasAuth).toBe(true);
28
+ });
29
+
30
+ it('should detect services when services array is not empty', () => {
31
+ const endpoint = {
32
+ authorizer: undefined,
33
+ services: [{ serviceName: 'db' }],
34
+ databaseService: undefined,
35
+ input: {},
36
+ audits: [],
37
+ events: [],
38
+ rateLimit: undefined,
39
+ rlsConfig: undefined,
40
+ rlsBypass: false,
41
+ outputSchema: undefined,
42
+ };
43
+
44
+ const features = analyzeEndpointFeatures(endpoint as any);
45
+ expect(features.hasServices).toBe(true);
46
+ });
47
+
48
+ it('should detect database service when set', () => {
49
+ const endpoint = {
50
+ authorizer: undefined,
51
+ services: [],
52
+ databaseService: { serviceName: 'database' },
53
+ input: {},
54
+ audits: [],
55
+ events: [],
56
+ rateLimit: undefined,
57
+ rlsConfig: undefined,
58
+ rlsBypass: false,
59
+ outputSchema: undefined,
60
+ };
61
+
62
+ const features = analyzeEndpointFeatures(endpoint as any);
63
+ expect(features.hasDatabase).toBe(true);
64
+ });
65
+
66
+ it('should detect body validation', () => {
67
+ const endpoint = {
68
+ authorizer: undefined,
69
+ services: [],
70
+ databaseService: undefined,
71
+ input: { body: { parse: () => {} } },
72
+ audits: [],
73
+ events: [],
74
+ rateLimit: undefined,
75
+ rlsConfig: undefined,
76
+ rlsBypass: false,
77
+ outputSchema: undefined,
78
+ };
79
+
80
+ const features = analyzeEndpointFeatures(endpoint as any);
81
+ expect(features.hasBodyValidation).toBe(true);
82
+ });
83
+
84
+ it('should detect query validation', () => {
85
+ const endpoint = {
86
+ authorizer: undefined,
87
+ services: [],
88
+ databaseService: undefined,
89
+ input: { query: { parse: () => {} } },
90
+ audits: [],
91
+ events: [],
92
+ rateLimit: undefined,
93
+ rlsConfig: undefined,
94
+ rlsBypass: false,
95
+ outputSchema: undefined,
96
+ };
97
+
98
+ const features = analyzeEndpointFeatures(endpoint as any);
99
+ expect(features.hasQueryValidation).toBe(true);
100
+ });
101
+
102
+ it('should detect param validation', () => {
103
+ const endpoint = {
104
+ authorizer: undefined,
105
+ services: [],
106
+ databaseService: undefined,
107
+ input: { params: { parse: () => {} } },
108
+ audits: [],
109
+ events: [],
110
+ rateLimit: undefined,
111
+ rlsConfig: undefined,
112
+ rlsBypass: false,
113
+ outputSchema: undefined,
114
+ };
115
+
116
+ const features = analyzeEndpointFeatures(endpoint as any);
117
+ expect(features.hasParamValidation).toBe(true);
118
+ });
119
+
120
+ it('should detect audits when audits array is not empty', () => {
121
+ const endpoint = {
122
+ authorizer: undefined,
123
+ services: [],
124
+ databaseService: undefined,
125
+ input: {},
126
+ audits: [{ type: 'user.created' }],
127
+ events: [],
128
+ rateLimit: undefined,
129
+ rlsConfig: undefined,
130
+ rlsBypass: false,
131
+ outputSchema: undefined,
132
+ };
133
+
134
+ const features = analyzeEndpointFeatures(endpoint as any);
135
+ expect(features.hasAudits).toBe(true);
136
+ });
137
+
138
+ it('should detect events when events array is not empty', () => {
139
+ const endpoint = {
140
+ authorizer: undefined,
141
+ services: [],
142
+ databaseService: undefined,
143
+ input: {},
144
+ audits: [],
145
+ events: [{ type: 'user.created' }],
146
+ rateLimit: undefined,
147
+ rlsConfig: undefined,
148
+ rlsBypass: false,
149
+ outputSchema: undefined,
150
+ };
151
+
152
+ const features = analyzeEndpointFeatures(endpoint as any);
153
+ expect(features.hasEvents).toBe(true);
154
+ });
155
+
156
+ it('should detect rate limiting', () => {
157
+ const endpoint = {
158
+ authorizer: undefined,
159
+ services: [],
160
+ databaseService: undefined,
161
+ input: {},
162
+ audits: [],
163
+ events: [],
164
+ rateLimit: { limit: 100, windowMs: 60000 },
165
+ rlsConfig: undefined,
166
+ rlsBypass: false,
167
+ outputSchema: undefined,
168
+ };
169
+
170
+ const features = analyzeEndpointFeatures(endpoint as any);
171
+ expect(features.hasRateLimit).toBe(true);
172
+ });
173
+
174
+ it('should detect RLS when rlsConfig is set and not bypassed', () => {
175
+ const endpoint = {
176
+ authorizer: undefined,
177
+ services: [],
178
+ databaseService: undefined,
179
+ input: {},
180
+ audits: [],
181
+ events: [],
182
+ rateLimit: undefined,
183
+ rlsConfig: { role: 'authenticated' },
184
+ rlsBypass: false,
185
+ outputSchema: undefined,
186
+ };
187
+
188
+ const features = analyzeEndpointFeatures(endpoint as any);
189
+ expect(features.hasRls).toBe(true);
190
+ });
191
+
192
+ it('should not detect RLS when bypassed', () => {
193
+ const endpoint = {
194
+ authorizer: undefined,
195
+ services: [],
196
+ databaseService: undefined,
197
+ input: {},
198
+ audits: [],
199
+ events: [],
200
+ rateLimit: undefined,
201
+ rlsConfig: { role: 'authenticated' },
202
+ rlsBypass: true,
203
+ outputSchema: undefined,
204
+ };
205
+
206
+ const features = analyzeEndpointFeatures(endpoint as any);
207
+ expect(features.hasRls).toBe(false);
208
+ });
209
+
210
+ it('should detect output validation', () => {
211
+ const endpoint = {
212
+ authorizer: undefined,
213
+ services: [],
214
+ databaseService: undefined,
215
+ input: {},
216
+ audits: [],
217
+ events: [],
218
+ rateLimit: undefined,
219
+ rlsConfig: undefined,
220
+ rlsBypass: false,
221
+ outputSchema: { parse: () => {} },
222
+ };
223
+
224
+ const features = analyzeEndpointFeatures(endpoint as any);
225
+ expect(features.hasOutputValidation).toBe(true);
226
+ });
227
+
228
+ it('should handle minimal endpoint with no features', () => {
229
+ const endpoint = {
230
+ authorizer: undefined,
231
+ services: [],
232
+ databaseService: undefined,
233
+ input: {},
234
+ audits: [],
235
+ events: [],
236
+ rateLimit: undefined,
237
+ rlsConfig: undefined,
238
+ rlsBypass: false,
239
+ outputSchema: undefined,
240
+ };
241
+
242
+ const features = analyzeEndpointFeatures(endpoint as any);
243
+ expect(features).toEqual({
244
+ hasAuth: false,
245
+ hasServices: false,
246
+ hasDatabase: false,
247
+ hasBodyValidation: false,
248
+ hasQueryValidation: false,
249
+ hasParamValidation: false,
250
+ hasAudits: false,
251
+ hasEvents: false,
252
+ hasRateLimit: false,
253
+ hasRls: false,
254
+ hasOutputValidation: false,
255
+ });
256
+ });
257
+ });
258
+
259
+ describe('determineEndpointTier', () => {
260
+ it('should return minimal for endpoint with no features', () => {
261
+ const features: EndpointFeatures = {
262
+ hasAuth: false,
263
+ hasServices: false,
264
+ hasDatabase: false,
265
+ hasBodyValidation: false,
266
+ hasQueryValidation: false,
267
+ hasParamValidation: false,
268
+ hasAudits: false,
269
+ hasEvents: false,
270
+ hasRateLimit: false,
271
+ hasRls: false,
272
+ hasOutputValidation: false,
273
+ };
274
+
275
+ expect(determineEndpointTier(features)).toBe('minimal');
276
+ });
277
+
278
+ it('should return minimal for endpoint with only validation', () => {
279
+ const features: EndpointFeatures = {
280
+ hasAuth: false,
281
+ hasServices: false,
282
+ hasDatabase: false,
283
+ hasBodyValidation: true,
284
+ hasQueryValidation: true,
285
+ hasParamValidation: true,
286
+ hasAudits: false,
287
+ hasEvents: false,
288
+ hasRateLimit: false,
289
+ hasRls: false,
290
+ hasOutputValidation: true,
291
+ };
292
+
293
+ expect(determineEndpointTier(features)).toBe('minimal');
294
+ });
295
+
296
+ it('should return standard for endpoint with auth', () => {
297
+ const features: EndpointFeatures = {
298
+ hasAuth: true,
299
+ hasServices: false,
300
+ hasDatabase: false,
301
+ hasBodyValidation: false,
302
+ hasQueryValidation: false,
303
+ hasParamValidation: false,
304
+ hasAudits: false,
305
+ hasEvents: false,
306
+ hasRateLimit: false,
307
+ hasRls: false,
308
+ hasOutputValidation: false,
309
+ };
310
+
311
+ expect(determineEndpointTier(features)).toBe('standard');
312
+ });
313
+
314
+ it('should return standard for endpoint with services', () => {
315
+ const features: EndpointFeatures = {
316
+ hasAuth: false,
317
+ hasServices: true,
318
+ hasDatabase: false,
319
+ hasBodyValidation: false,
320
+ hasQueryValidation: false,
321
+ hasParamValidation: false,
322
+ hasAudits: false,
323
+ hasEvents: false,
324
+ hasRateLimit: false,
325
+ hasRls: false,
326
+ hasOutputValidation: false,
327
+ };
328
+
329
+ expect(determineEndpointTier(features)).toBe('standard');
330
+ });
331
+
332
+ it('should return standard for endpoint with database', () => {
333
+ const features: EndpointFeatures = {
334
+ hasAuth: false,
335
+ hasServices: false,
336
+ hasDatabase: true,
337
+ hasBodyValidation: false,
338
+ hasQueryValidation: false,
339
+ hasParamValidation: false,
340
+ hasAudits: false,
341
+ hasEvents: false,
342
+ hasRateLimit: false,
343
+ hasRls: false,
344
+ hasOutputValidation: false,
345
+ };
346
+
347
+ expect(determineEndpointTier(features)).toBe('standard');
348
+ });
349
+
350
+ it('should return standard for endpoint with events', () => {
351
+ const features: EndpointFeatures = {
352
+ hasAuth: false,
353
+ hasServices: false,
354
+ hasDatabase: false,
355
+ hasBodyValidation: false,
356
+ hasQueryValidation: false,
357
+ hasParamValidation: false,
358
+ hasAudits: false,
359
+ hasEvents: true,
360
+ hasRateLimit: false,
361
+ hasRls: false,
362
+ hasOutputValidation: false,
363
+ };
364
+
365
+ expect(determineEndpointTier(features)).toBe('standard');
366
+ });
367
+
368
+ it('should return full for endpoint with audits', () => {
369
+ const features: EndpointFeatures = {
370
+ hasAuth: false,
371
+ hasServices: false,
372
+ hasDatabase: false,
373
+ hasBodyValidation: false,
374
+ hasQueryValidation: false,
375
+ hasParamValidation: false,
376
+ hasAudits: true,
377
+ hasEvents: false,
378
+ hasRateLimit: false,
379
+ hasRls: false,
380
+ hasOutputValidation: false,
381
+ };
382
+
383
+ expect(determineEndpointTier(features)).toBe('full');
384
+ });
385
+
386
+ it('should return full for endpoint with rate limiting', () => {
387
+ const features: EndpointFeatures = {
388
+ hasAuth: false,
389
+ hasServices: false,
390
+ hasDatabase: false,
391
+ hasBodyValidation: false,
392
+ hasQueryValidation: false,
393
+ hasParamValidation: false,
394
+ hasAudits: false,
395
+ hasEvents: false,
396
+ hasRateLimit: true,
397
+ hasRls: false,
398
+ hasOutputValidation: false,
399
+ };
400
+
401
+ expect(determineEndpointTier(features)).toBe('full');
402
+ });
403
+
404
+ it('should return full for endpoint with RLS', () => {
405
+ const features: EndpointFeatures = {
406
+ hasAuth: false,
407
+ hasServices: false,
408
+ hasDatabase: false,
409
+ hasBodyValidation: false,
410
+ hasQueryValidation: false,
411
+ hasParamValidation: false,
412
+ hasAudits: false,
413
+ hasEvents: false,
414
+ hasRateLimit: false,
415
+ hasRls: true,
416
+ hasOutputValidation: false,
417
+ };
418
+
419
+ expect(determineEndpointTier(features)).toBe('full');
420
+ });
421
+
422
+ it('should return full even with auth and services when has audits', () => {
423
+ const features: EndpointFeatures = {
424
+ hasAuth: true,
425
+ hasServices: true,
426
+ hasDatabase: true,
427
+ hasBodyValidation: true,
428
+ hasQueryValidation: true,
429
+ hasParamValidation: true,
430
+ hasAudits: true,
431
+ hasEvents: true,
432
+ hasRateLimit: false,
433
+ hasRls: false,
434
+ hasOutputValidation: true,
435
+ };
436
+
437
+ expect(determineEndpointTier(features)).toBe('full');
438
+ });
439
+ });
440
+
441
+ describe('summarizeAnalysis', () => {
442
+ it('should summarize empty analyses', () => {
443
+ const result = summarizeAnalysis([]);
444
+ expect(result).toEqual({
445
+ total: 0,
446
+ byTier: {
447
+ minimal: 0,
448
+ standard: 0,
449
+ full: 0,
450
+ },
451
+ byFeature: {
452
+ hasAuth: 0,
453
+ hasServices: 0,
454
+ hasDatabase: 0,
455
+ hasBodyValidation: 0,
456
+ hasQueryValidation: 0,
457
+ hasParamValidation: 0,
458
+ hasAudits: 0,
459
+ hasEvents: 0,
460
+ hasRateLimit: 0,
461
+ hasRls: 0,
462
+ hasOutputValidation: 0,
463
+ },
464
+ });
465
+ });
466
+
467
+ it('should count endpoints by tier', () => {
468
+ const analyses: EndpointAnalysis[] = [
469
+ {
470
+ route: '/health',
471
+ method: 'GET',
472
+ exportName: 'healthEndpoint',
473
+ tier: 'minimal',
474
+ serviceNames: [],
475
+ features: {
476
+ hasAuth: false,
477
+ hasServices: false,
478
+ hasDatabase: false,
479
+ hasBodyValidation: false,
480
+ hasQueryValidation: false,
481
+ hasParamValidation: false,
482
+ hasAudits: false,
483
+ hasEvents: false,
484
+ hasRateLimit: false,
485
+ hasRls: false,
486
+ hasOutputValidation: false,
487
+ },
488
+ },
489
+ {
490
+ route: '/users',
491
+ method: 'GET',
492
+ exportName: 'listUsersEndpoint',
493
+ tier: 'standard',
494
+ serviceNames: ['database'],
495
+ features: {
496
+ hasAuth: true,
497
+ hasServices: true,
498
+ hasDatabase: true,
499
+ hasBodyValidation: false,
500
+ hasQueryValidation: true,
501
+ hasParamValidation: false,
502
+ hasAudits: false,
503
+ hasEvents: false,
504
+ hasRateLimit: false,
505
+ hasRls: false,
506
+ hasOutputValidation: false,
507
+ },
508
+ },
509
+ {
510
+ route: '/users',
511
+ method: 'POST',
512
+ exportName: 'createUserEndpoint',
513
+ tier: 'full',
514
+ serviceNames: ['database'],
515
+ features: {
516
+ hasAuth: true,
517
+ hasServices: true,
518
+ hasDatabase: true,
519
+ hasBodyValidation: true,
520
+ hasQueryValidation: false,
521
+ hasParamValidation: false,
522
+ hasAudits: true,
523
+ hasEvents: true,
524
+ hasRateLimit: true,
525
+ hasRls: false,
526
+ hasOutputValidation: true,
527
+ },
528
+ },
529
+ ];
530
+
531
+ const result = summarizeAnalysis(analyses);
532
+
533
+ expect(result.total).toBe(3);
534
+ expect(result.byTier).toEqual({
535
+ minimal: 1,
536
+ standard: 1,
537
+ full: 1,
538
+ });
539
+ expect(result.byFeature.hasAuth).toBe(2);
540
+ expect(result.byFeature.hasServices).toBe(2);
541
+ expect(result.byFeature.hasDatabase).toBe(2);
542
+ expect(result.byFeature.hasBodyValidation).toBe(1);
543
+ expect(result.byFeature.hasQueryValidation).toBe(1);
544
+ expect(result.byFeature.hasAudits).toBe(1);
545
+ expect(result.byFeature.hasEvents).toBe(1);
546
+ expect(result.byFeature.hasRateLimit).toBe(1);
547
+ });
548
+
549
+ it('should count multiple endpoints of same tier', () => {
550
+ const analyses: EndpointAnalysis[] = [
551
+ {
552
+ route: '/health',
553
+ method: 'GET',
554
+ exportName: 'healthEndpoint',
555
+ tier: 'minimal',
556
+ serviceNames: [],
557
+ features: {
558
+ hasAuth: false,
559
+ hasServices: false,
560
+ hasDatabase: false,
561
+ hasBodyValidation: false,
562
+ hasQueryValidation: false,
563
+ hasParamValidation: false,
564
+ hasAudits: false,
565
+ hasEvents: false,
566
+ hasRateLimit: false,
567
+ hasRls: false,
568
+ hasOutputValidation: false,
569
+ },
570
+ },
571
+ {
572
+ route: '/ping',
573
+ method: 'GET',
574
+ exportName: 'pingEndpoint',
575
+ tier: 'minimal',
576
+ serviceNames: [],
577
+ features: {
578
+ hasAuth: false,
579
+ hasServices: false,
580
+ hasDatabase: false,
581
+ hasBodyValidation: false,
582
+ hasQueryValidation: false,
583
+ hasParamValidation: false,
584
+ hasAudits: false,
585
+ hasEvents: false,
586
+ hasRateLimit: false,
587
+ hasRls: false,
588
+ hasOutputValidation: false,
589
+ },
590
+ },
591
+ {
592
+ route: '/version',
593
+ method: 'GET',
594
+ exportName: 'versionEndpoint',
595
+ tier: 'minimal',
596
+ serviceNames: [],
597
+ features: {
598
+ hasAuth: false,
599
+ hasServices: false,
600
+ hasDatabase: false,
601
+ hasBodyValidation: false,
602
+ hasQueryValidation: false,
603
+ hasParamValidation: false,
604
+ hasAudits: false,
605
+ hasEvents: false,
606
+ hasRateLimit: false,
607
+ hasRls: false,
608
+ hasOutputValidation: false,
609
+ },
610
+ },
611
+ ];
612
+
613
+ const result = summarizeAnalysis(analyses);
614
+
615
+ expect(result.total).toBe(3);
616
+ expect(result.byTier).toEqual({
617
+ minimal: 3,
618
+ standard: 0,
619
+ full: 0,
620
+ });
621
+ });
622
+ });
623
+ });