shokupan 0.10.4 → 0.11.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 (54) hide show
  1. package/dist/{analyzer-CKLGLFtx.cjs → analyzer-BAhvpNY_.cjs} +2 -7
  2. package/dist/{analyzer-CKLGLFtx.cjs.map → analyzer-BAhvpNY_.cjs.map} +1 -1
  3. package/dist/{analyzer-BqIe1p0R.js → analyzer-CnKnQ5KV.js} +3 -8
  4. package/dist/{analyzer-BqIe1p0R.js.map → analyzer-CnKnQ5KV.js.map} +1 -1
  5. package/dist/{analyzer.impl-D9Yi1Hax.cjs → analyzer.impl-CfpMu4-g.cjs} +586 -40
  6. package/dist/analyzer.impl-CfpMu4-g.cjs.map +1 -0
  7. package/dist/{analyzer.impl-CV6W1Eq7.js → analyzer.impl-DCiqlXI5.js} +586 -40
  8. package/dist/analyzer.impl-DCiqlXI5.js.map +1 -0
  9. package/dist/cli.cjs +206 -18
  10. package/dist/cli.cjs.map +1 -1
  11. package/dist/cli.js +206 -18
  12. package/dist/cli.js.map +1 -1
  13. package/dist/context.d.ts +6 -1
  14. package/dist/index.cjs +2405 -1008
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +2402 -1006
  17. package/dist/index.js.map +1 -1
  18. package/dist/plugins/application/api-explorer/static/explorer-client.mjs +423 -30
  19. package/dist/plugins/application/api-explorer/static/style.css +351 -10
  20. package/dist/plugins/application/api-explorer/static/theme.css +7 -2
  21. package/dist/plugins/application/asyncapi/generator.d.ts +4 -0
  22. package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +154 -22
  23. package/dist/plugins/application/asyncapi/static/style.css +24 -8
  24. package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +107 -0
  25. package/dist/plugins/application/dashboard/metrics-collector.d.ts +38 -2
  26. package/dist/plugins/application/dashboard/plugin.d.ts +44 -1
  27. package/dist/plugins/application/dashboard/static/charts.js +127 -62
  28. package/dist/plugins/application/dashboard/static/client.js +160 -0
  29. package/dist/plugins/application/dashboard/static/graph.mjs +167 -56
  30. package/dist/plugins/application/dashboard/static/reactflow.css +20 -10
  31. package/dist/plugins/application/dashboard/static/registry.js +112 -8
  32. package/dist/plugins/application/dashboard/static/requests.js +868 -58
  33. package/dist/plugins/application/dashboard/static/styles.css +186 -14
  34. package/dist/plugins/application/dashboard/static/tabs.js +44 -9
  35. package/dist/plugins/application/dashboard/static/theme.css +7 -2
  36. package/dist/plugins/application/openapi/analyzer.impl.d.ts +61 -1
  37. package/dist/plugins/application/openapi/openapi.d.ts +3 -0
  38. package/dist/plugins/application/shared/ast-utils.d.ts +7 -0
  39. package/dist/router.d.ts +55 -16
  40. package/dist/shokupan.d.ts +7 -2
  41. package/dist/util/adapter/adapters.d.ts +19 -0
  42. package/dist/util/adapter/filesystem.d.ts +20 -0
  43. package/dist/util/controller-scanner.d.ts +4 -0
  44. package/dist/util/cpu-monitor.d.ts +2 -0
  45. package/dist/util/middleware-tracker.d.ts +10 -0
  46. package/dist/util/types.d.ts +37 -0
  47. package/package.json +5 -5
  48. package/dist/analyzer.impl-CV6W1Eq7.js.map +0 -1
  49. package/dist/analyzer.impl-D9Yi1Hax.cjs.map +0 -1
  50. package/dist/http-server-BEMPIs33.cjs +0 -85
  51. package/dist/http-server-BEMPIs33.cjs.map +0 -1
  52. package/dist/http-server-CCeagTyU.js +0 -68
  53. package/dist/http-server-CCeagTyU.js.map +0 -1
  54. package/dist/plugins/application/dashboard/static/poll.js +0 -146
@@ -14,7 +14,7 @@ html {
14
14
  body {
15
15
  display: flex;
16
16
  flex-direction: column;
17
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
17
+ font-family: var(--shokupan-font);
18
18
  background-color: var(--bg-primary);
19
19
  color: var(--text-primary);
20
20
  height: 100vh;
@@ -26,7 +26,6 @@ header {
26
26
  background-color: var(--bg-header);
27
27
  padding: 0 1rem;
28
28
  display: flex;
29
- justify-content: space-between;
30
29
  align-items: center;
31
30
  }
32
31
 
@@ -56,6 +55,15 @@ select {
56
55
  flex-direction: column;
57
56
  align-items: center;
58
57
  overflow: hidden;
58
+ width: 100%;
59
+ }
60
+
61
+ .contents {
62
+ width: 100%;
63
+ display: flex;
64
+ height: 100%;
65
+ overflow-y: auto;
66
+ justify-content: center;
59
67
  }
60
68
 
61
69
  .metrics-grid {
@@ -116,7 +124,6 @@ select {
116
124
  border: 1px solid var(--card-border);
117
125
  border-radius: 1rem;
118
126
  padding: 1.5rem;
119
- margin-bottom: 2rem;
120
127
  overflow: hidden;
121
128
  }
122
129
 
@@ -125,14 +132,13 @@ select {
125
132
  display: flex;
126
133
  gap: 1rem;
127
134
  border-bottom: 1px solid var(--card-border);
128
- margin-bottom: 2rem;
129
135
  }
130
136
 
131
137
  .tab-btn {
132
138
  background: none;
133
139
  border: none;
134
140
  color: var(--text-secondary);
135
- padding: 1rem;
141
+ padding: .5rem;
136
142
  cursor: pointer;
137
143
  font-size: 1rem;
138
144
  border-bottom: 2px solid transparent;
@@ -154,31 +160,197 @@ select {
154
160
 
155
161
  .tab-content {
156
162
  display: none;
157
- flex-direction: column;
158
163
  flex: 1;
159
- overflow: auto;
160
- width: -webkit-fill-available;
161
- /* width: 1200px; */
162
- max-width: 1200px;
163
- margin: 0 2rem;
164
+ flex-direction: column;
165
+ width: 100%
164
166
  }
165
167
 
166
168
  .tab-content.active {
167
- display: flex;
169
+ display: block;
168
170
  }
169
171
 
170
172
 
171
173
  /* Graph */
172
174
  #cy {
173
- width: 100%;
175
+ width: calc(100% - 4rem);
174
176
  height: 600px;
175
177
  background-color: var(--bg-secondary);
176
- border-radius: 1rem;
178
+ border-radius: 4px;
177
179
  border: 1px solid var(--card-border);
180
+ overflow: hidden
178
181
  }
179
182
 
180
183
  .card-container {
181
184
  display: grid;
182
185
  gap: 1rem;
183
186
  grid-template-columns: 1fr;
187
+ }
188
+
189
+ #tab-overview {
190
+ /* width: 100%; */
191
+ /* max-width: 1200px; */
192
+ max-width: 900px;
193
+ margin: 2rem
194
+ }
195
+
196
+ .button-group {
197
+ display: inline-flex;
198
+ background: var(--bg-secondary);
199
+ padding: 4px;
200
+ border-radius: 8px;
201
+ border: 1px solid var(--card-border);
202
+ }
203
+
204
+ .view-btn {
205
+ background: transparent;
206
+ border: none;
207
+ color: var(--text-secondary);
208
+ padding: 6px 12px;
209
+ border-radius: 6px;
210
+ font-size: 0.9rem;
211
+ cursor: pointer;
212
+ transition: all 0.2s;
213
+ }
214
+
215
+ .view-btn:hover {
216
+ color: var(--text-primary);
217
+ }
218
+
219
+ .view-btn.active {
220
+ background: var(--bg-primary);
221
+ color: var(--accent);
222
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
223
+ font-weight: 500;
224
+ }
225
+
226
+ .app-view {
227
+ display: none;
228
+ flex: 1;
229
+ width: 100%;
230
+ }
231
+
232
+ .app-view.active {
233
+ display: flex;
234
+ flex-direction: column;
235
+ }
236
+
237
+ .traffic-view {
238
+ display: none;
239
+ flex: 1;
240
+ width: 100%;
241
+ }
242
+
243
+ .traffic-view.active {
244
+ display: flex;
245
+ flex-direction: column;
246
+ }
247
+
248
+ .btn-action {
249
+ background: var(--bg-primary);
250
+ border: 1px solid var(--card-border);
251
+ color: var(--text-primary);
252
+ padding: 4px 8px;
253
+ border-radius: 4px;
254
+ font-size: 0.8rem;
255
+ cursor: pointer;
256
+ transition: all 0.2s;
257
+ display: flex;
258
+ align-items: center;
259
+ gap: 4px;
260
+ }
261
+
262
+ .btn-action:hover {
263
+ background: var(--bg-secondary);
264
+ border-color: var(--accent);
265
+ }
266
+
267
+ /* Network Tab Styles */
268
+
269
+ /* Tabulator Overrides for DevTools look */
270
+ .tabulator {
271
+ border: none !important;
272
+ background-color: var(--bg-secondary) !important;
273
+ }
274
+
275
+ .tabulator-header {
276
+ background-color: var(--bg-header) !important;
277
+ border-bottom: 1px solid var(--border-color) !important;
278
+ color: var(--text-secondary) !important;
279
+ font-weight: 500 !important;
280
+ }
281
+
282
+ .tabulator-col {
283
+ background-color: transparent !important;
284
+ border-right: 1px solid var(--border-color) !important;
285
+ }
286
+
287
+ .tabulator-row {
288
+ background-color: var(--bg-secondary) !important;
289
+ border-bottom: 1px solid var(--border-color) !important;
290
+ color: var(--text-primary) !important;
291
+ }
292
+
293
+ .tabulator-row:hover {
294
+ background-color: var(--bg-primary) !important;
295
+ cursor: pointer;
296
+ }
297
+
298
+ .tabulator-row.tabulator-selected {
299
+ background-color: #2e3440 !important;
300
+ color: #fff !important;
301
+ }
302
+
303
+ /* Tabs */
304
+ .tab-item {
305
+ transition: all 0.2s;
306
+ }
307
+
308
+ .tab-item:hover {
309
+ background-color: rgba(255, 255, 255, 0.05);
310
+ }
311
+
312
+ .tab-item.active {
313
+ background-color: rgba(59, 130, 246, 0.1);
314
+ }
315
+
316
+ /* Details Panel */
317
+ details>summary {
318
+ list-style: none;
319
+ }
320
+
321
+ details>summary::-webkit-details-marker {
322
+ display: none;
323
+ }
324
+
325
+ details>summary::before {
326
+ content: '▶';
327
+ font-size: 0.8em;
328
+ margin-right: 6px;
329
+ display: inline-block;
330
+ transition: transform 0.2s;
331
+ }
332
+
333
+ details[open]>summary::before {
334
+ transform: rotate(90deg);
335
+ }
336
+
337
+ /* Slightly lighter than bg-secondary */
338
+ /* border-left: 2px solid var(--accent) !important; */
339
+ /* Slightly lighter than bg-secondary */
340
+
341
+ /* Filter Bar */
342
+ #network-filter-bar input:focus,
343
+ #network-filter-bar select:focus {
344
+ border-color: var(--accent);
345
+ outline: none;
346
+ }
347
+
348
+ #tab-network {
349
+ height: 100%;
350
+ overflow: hidden;
351
+ flex-direction: column;
352
+ }
353
+
354
+ #tab-network.active {
355
+ display: flex !important;
184
356
  }
@@ -14,20 +14,55 @@ function switchTab(tabId) {
14
14
  if (tabId === 'overview') {
15
15
  if (typeof fetchTopStats === 'function') fetchTopStats();
16
16
  }
17
- else if (tabId === 'graph') {
18
- initGraph();
17
+ else if (tabId === 'application') {
18
+ const activeView = document.querySelector('.app-view.active');
19
+ if (!activeView || activeView.id === 'app-view-registry') {
20
+ switchApplicationView('registry');
21
+ } else {
22
+ switchApplicationView('graph');
23
+ }
19
24
  }
20
- else if (tabId === 'requests') {
25
+ else if (tabId === 'network') {
21
26
  if (typeof fetchRequests === 'function') fetchRequests();
27
+ // Redraw table if it exists to fix layout issues when unhiding
28
+ setTimeout(() => {
29
+ if (window.requestsTable) window.requestsTable.redraw();
30
+ }, 50);
22
31
  }
23
- else if (tabId === 'failures') {
24
- fetchFailures();
25
- }
26
- else if (tabId === 'middleware') {
27
- fetchMiddleware();
32
+ }
33
+
34
+
35
+ function switchApplicationView(viewId) {
36
+ console.log('Switching application view to:', viewId);
37
+
38
+ // Update buttons
39
+ const container = document.getElementById('tab-application');
40
+ if (!container) return;
41
+
42
+ container.querySelectorAll('.view-btn').forEach(btn => btn.classList.remove('active'));
43
+ // Find button
44
+ const btn = Array.from(container.querySelectorAll('.view-btn')).find(b => b.getAttribute('onclick') === `switchApplicationView('${viewId}')`);
45
+ if (btn) btn.classList.add('active');
46
+
47
+ // Update content
48
+ container.querySelectorAll('.app-view').forEach(view => {
49
+ view.classList.remove('active');
50
+ view.style.display = 'none';
51
+ });
52
+
53
+ const activeView = document.getElementById('app-view-' + viewId);
54
+ if (activeView) {
55
+ activeView.classList.add('active');
56
+ activeView.style.display = 'block';
28
57
  }
29
- else if (tabId === 'registry') {
58
+
59
+ if (viewId === 'registry') {
30
60
  if (typeof fetchRegistry === 'function') fetchRegistry();
61
+ } else if (viewId === 'graph') {
62
+ // Build graph if needed
63
+ setTimeout(() => {
64
+ if (typeof initGraph === 'function') initGraph();
65
+ }, 50);
31
66
  }
32
67
  }
33
68
 
@@ -13,8 +13,8 @@
13
13
  --palette-dark-header: rgb(39, 27, 19);
14
14
  /* Proofing Drawer */
15
15
 
16
- /* Universal defaults (tokens) */
17
- --shokupan-font: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
16
+ --shokupan-font: "Vend Sans", 'Open Sans', 'Helvetica Neue', sans-serif;
17
+ --shokupan-font-mono: "Google Sans Code", monospace;
18
18
 
19
19
  /* Theme Variables - Enforced Dark Mode */
20
20
  --bg-primary: var(--palette-dark-bg);
@@ -42,6 +42,11 @@
42
42
  --button-text: #1A1614;
43
43
  }
44
44
 
45
+ * {
46
+ box-sizing: border-box;
47
+ font-optical-sizing: auto;
48
+ }
49
+
45
50
  ::-webkit-scrollbar {
46
51
  width: 8px;
47
52
  height: 8px;
@@ -14,6 +14,7 @@ export interface RouteInfo {
14
14
  };
15
15
  responseType?: string;
16
16
  responseSchema?: any;
17
+ hasUnknownFields?: boolean;
17
18
  summary?: string;
18
19
  description?: string;
19
20
  tags?: string[];
@@ -33,7 +34,7 @@ export interface RouteInfo {
33
34
  highlights?: {
34
35
  startLine: number;
35
36
  endLine: number;
36
- type: 'emit' | 'return-success' | 'return-warning';
37
+ type: 'emit' | 'return-success' | 'return-warning' | 'dynamic-path';
37
38
  }[];
38
39
  };
39
40
  }
@@ -56,6 +57,7 @@ export interface ApplicationInstance {
56
57
  controllerPrefix?: string;
57
58
  routes: RouteInfo[];
58
59
  mounted: MountInfo[];
60
+ middleware: MiddlewareInfo[];
59
61
  }
60
62
  interface MountInfo {
61
63
  prefix: string;
@@ -68,6 +70,31 @@ interface MountInfo {
68
70
  endLine: number;
69
71
  };
70
72
  }
73
+ /**
74
+ * Middleware information extracted from AST
75
+ */
76
+ export interface MiddlewareInfo {
77
+ name: string;
78
+ file: string;
79
+ startLine: number;
80
+ endLine: number;
81
+ handlerSource?: string;
82
+ responseTypes?: Record<string, any>;
83
+ headers?: string[];
84
+ scope: 'global' | 'router' | 'route';
85
+ sourceContext?: {
86
+ file: string;
87
+ startLine: number;
88
+ endLine: number;
89
+ snippet?: string;
90
+ snippetStartLine?: number;
91
+ highlights?: {
92
+ startLine: number;
93
+ endLine: number;
94
+ type: 'emit' | 'return-success' | 'return-warning';
95
+ }[];
96
+ };
97
+ }
71
98
  /**
72
99
  * Main analyzer class
73
100
  */
@@ -77,6 +104,7 @@ export declare class OpenAPIAnalyzer {
77
104
  private applications;
78
105
  private program?;
79
106
  private entrypoint?;
107
+ private imports;
80
108
  constructor(rootDir: string, entrypoint?: string);
81
109
  /**
82
110
  * Main analysis entry point
@@ -99,6 +127,10 @@ export declare class OpenAPIAnalyzer {
99
127
  * Process source maps to reconstruct TypeScript
100
128
  */
101
129
  private processSourceMaps;
130
+ /**
131
+ * Collect all imports from source files for later resolution
132
+ */
133
+ private collectImports;
102
134
  /**
103
135
  * Parse TypeScript files and create AST
104
136
  */
@@ -123,6 +155,10 @@ export declare class OpenAPIAnalyzer {
123
155
  * Extract routes from a specific file
124
156
  */
125
157
  private extractRoutesFromFile;
158
+ /**
159
+ * Resolve string value from expression (literals, concatenation, templates, constants)
160
+ */
161
+ private resolveStringValue;
126
162
  /**
127
163
  * Extract route information from a route call (e.g., app.get('/path', handler))
128
164
  */
@@ -135,6 +171,14 @@ export declare class OpenAPIAnalyzer {
135
171
  * Convert an Expression node to an OpenAPI schema (best effort)
136
172
  */
137
173
  private convertExpressionToSchema;
174
+ /**
175
+ * Deduplicate schemas by comparing their JSON representations
176
+ */
177
+ private deduplicateSchemas;
178
+ /**
179
+ * Check if a schema contains fields with unknown types
180
+ */
181
+ private hasUnknownFields;
138
182
  /**
139
183
  * Check if an expression is a call to ctx.body()
140
184
  */
@@ -143,10 +187,26 @@ export declare class OpenAPIAnalyzer {
143
187
  * Convert a TypeScript TypeNode to an OpenAPI schema
144
188
  */
145
189
  private convertTypeNodeToSchema;
190
+ /**
191
+ * Convert a TypeScript Type (from type checker) to an OpenAPI schema
192
+ */
193
+ private convertTypeToSchema;
146
194
  /**
147
195
  * Extract mount information from mount call
148
196
  */
149
197
  private extractMountFromCall;
198
+ /**
199
+ * Extract middleware information from .use() call
200
+ */
201
+ private extractMiddlewareFromCall;
202
+ /**
203
+ * Analyze middleware function to extract response types and headers
204
+ */
205
+ private analyzeMiddleware;
206
+ /**
207
+ * Resolve an imported middleware identifier and analyze its definition
208
+ */
209
+ private resolveImportedMiddlewareDefinition;
150
210
  /**
151
211
  * Check if a reference is to an external dependency
152
212
  */
@@ -1,5 +1,8 @@
1
1
  import { ShokupanRouter } from '../../../router';
2
2
  import { OpenAPIOptions } from '../../../util/types';
3
+ /**
4
+ * Gets deduped AST routes if available.
5
+ */
3
6
  /**
4
7
  * Statically generate an OpenAPI spec from a ShokupanRouter instance.
5
8
  *
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Gets deduped AST routes if available.
3
+ */
4
+ export declare function getAstRoutes(applications: any[], options?: {
5
+ includePrefix?: boolean;
6
+ pathTransform?: (p: string) => string;
7
+ }): Promise<any[]>;