shokupan 0.13.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.
- package/dist/{analyzer-BOtveWL-.cjs → analyzer-BZSVGTmP.cjs} +5 -4
- package/dist/analyzer-BZSVGTmP.cjs.map +1 -0
- package/dist/{analyzer-B0fMzeIo.js → analyzer-Faojwm7c.js} +5 -4
- package/dist/analyzer-Faojwm7c.js.map +1 -0
- package/dist/{analyzer.impl-CUDO6vpn.cjs → analyzer.impl-5aCqtook.cjs} +28 -11
- package/dist/analyzer.impl-5aCqtook.cjs.map +1 -0
- package/dist/{analyzer.impl-DmHe92Oi.js → analyzer.impl-COdN69gL.js} +28 -11
- package/dist/analyzer.impl-COdN69gL.js.map +1 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js +184 -0
- package/dist/ast-analyzer-worker-C3jrQ8VR.js.map +1 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs +184 -0
- package/dist/ast-analyzer-worker-D_uYkqmY.cjs.map +1 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/context.d.ts +39 -4
- package/dist/decorators/di.d.ts +31 -0
- package/dist/decorators/hooks.d.ts +28 -0
- package/dist/decorators/http.d.ts +60 -0
- package/dist/decorators/index.d.ts +8 -0
- package/dist/decorators/mcp.d.ts +48 -0
- package/dist/decorators/util/container.d.ts +36 -0
- package/dist/decorators/websocket.d.ts +172 -0
- package/dist/index-BP7v0Hiv.cjs +12216 -0
- package/dist/index-BP7v0Hiv.cjs.map +1 -0
- package/dist/index-CUNBeZKj.js +12176 -0
- package/dist/index-CUNBeZKj.js.map +1 -0
- package/dist/index.cjs +137 -10518
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +137 -10477
- package/dist/index.js.map +1 -1
- package/dist/{json-parser-COdZ0fqY.cjs → json-parser-BA0mUgMF.cjs} +3 -3
- package/dist/json-parser-BA0mUgMF.cjs.map +1 -0
- package/dist/{json-parser-B3dnQmCC.js → json-parser-BFM-SnBR.js} +3 -3
- package/dist/json-parser-BFM-SnBR.js.map +1 -0
- package/dist/knex-DDPXR-sQ.js +218 -0
- package/dist/knex-DDPXR-sQ.js.map +1 -0
- package/dist/knex-DghF-jjm.cjs +240 -0
- package/dist/knex-DghF-jjm.cjs.map +1 -0
- package/dist/level-BU87Jbus.js +184 -0
- package/dist/level-BU87Jbus.js.map +1 -0
- package/dist/level-DNFl2n-m.cjs +184 -0
- package/dist/level-DNFl2n-m.cjs.map +1 -0
- package/dist/plugins/application/api-explorer/static/explorer-client.mjs +54 -28
- package/dist/plugins/application/asyncapi/plugin.d.ts +1 -0
- package/dist/plugins/application/asyncapi/static/asyncapi-client.mjs +22 -11
- package/dist/plugins/application/dashboard/fetch-interceptor.d.ts +3 -1
- package/dist/plugins/application/dashboard/metrics-collector.d.ts +5 -3
- package/dist/plugins/application/dashboard/plugin.d.ts +36 -3
- package/dist/plugins/application/dashboard/static/requests.js +517 -53
- package/dist/plugins/application/dashboard/static/tabs.js +2 -2
- package/dist/plugins/application/error-view/index.d.ts +25 -0
- package/dist/plugins/application/error-view/reason-phrases.d.ts +1 -0
- package/dist/plugins/application/openapi/analyzer.d.ts +3 -1
- package/dist/plugins/application/openapi/analyzer.impl.d.ts +4 -2
- package/dist/router.d.ts +56 -21
- package/dist/shokupan.d.ts +25 -11
- package/dist/sqlite-CLrcTkti.js +180 -0
- package/dist/sqlite-CLrcTkti.js.map +1 -0
- package/dist/sqlite-n7FQ6Ja6.cjs +180 -0
- package/dist/sqlite-n7FQ6Ja6.cjs.map +1 -0
- package/dist/surreal-6QONU6xa.cjs +210 -0
- package/dist/surreal-6QONU6xa.cjs.map +1 -0
- package/dist/surreal-w7DeGVI-.js +188 -0
- package/dist/surreal-w7DeGVI-.js.map +1 -0
- package/dist/util/adapter/datastore/knex.d.ts +29 -0
- package/dist/util/adapter/datastore/level.d.ts +26 -0
- package/dist/util/adapter/datastore/sqlite.d.ts +24 -0
- package/dist/util/adapter/datastore/surreal.d.ts +29 -0
- package/dist/util/adapter/datastore.d.ts +59 -0
- package/dist/util/adapter/h3.d.ts +8 -0
- package/dist/util/adapter/index.d.ts +1 -0
- package/dist/util/ast-analyzer-worker.d.ts +77 -0
- package/dist/util/ast-worker-thread.d.ts +1 -0
- package/dist/util/cookie-parser.d.ts +6 -0
- package/dist/util/env-loader.d.ts +7 -0
- package/dist/util/html.d.ts +15 -0
- package/dist/util/ide.d.ts +9 -0
- package/dist/util/logger.d.ts +25 -0
- package/dist/util/query-string.d.ts +8 -0
- package/dist/util/response-transformer.d.ts +87 -0
- package/dist/util/symbol.d.ts +1 -0
- package/dist/util/types.d.ts +116 -42
- package/dist/websocket.d.ts +163 -0
- package/package.json +27 -1
- package/dist/analyzer-B0fMzeIo.js.map +0 -1
- package/dist/analyzer-BOtveWL-.cjs.map +0 -1
- package/dist/analyzer.impl-CUDO6vpn.cjs.map +0 -1
- package/dist/analyzer.impl-DmHe92Oi.js.map +0 -1
- package/dist/json-parser-B3dnQmCC.js.map +0 -1
- package/dist/json-parser-COdZ0fqY.cjs.map +0 -1
- package/dist/plugins/application/error-view/views/error.d.ts +0 -2
- package/dist/plugins/application/error-view/views/status.d.ts +0 -2
- package/dist/util/decorators.d.ts +0 -134
- package/dist/util/di.d.ts +0 -13
- /package/dist/{util → decorators/util}/metadata.d.ts +0 -0
- /package/dist/{util → decorators/util}/stack.d.ts +0 -0
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { Worker } from "worker_threads";
|
|
4
|
+
class ASTAnalyzerWorker extends EventEmitter {
|
|
5
|
+
state = "idle";
|
|
6
|
+
result = null;
|
|
7
|
+
error = null;
|
|
8
|
+
worker = null;
|
|
9
|
+
analysisPromise = null;
|
|
10
|
+
rootDir;
|
|
11
|
+
entrypoint;
|
|
12
|
+
timeout;
|
|
13
|
+
startTime = 0;
|
|
14
|
+
constructor(rootDir, entrypoint, timeout = 3e4) {
|
|
15
|
+
super();
|
|
16
|
+
this.rootDir = rootDir;
|
|
17
|
+
this.entrypoint = entrypoint;
|
|
18
|
+
this.timeout = timeout;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the current state of the analyzer.
|
|
22
|
+
*/
|
|
23
|
+
getState() {
|
|
24
|
+
return this.state;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Get the cached result if analysis completed successfully.
|
|
28
|
+
*/
|
|
29
|
+
getResult() {
|
|
30
|
+
return this.result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the error if analysis failed.
|
|
34
|
+
*/
|
|
35
|
+
getError() {
|
|
36
|
+
return this.error;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Check if analysis is currently running.
|
|
40
|
+
*/
|
|
41
|
+
isAnalyzing() {
|
|
42
|
+
return this.state === "analyzing";
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Check if analysis has completed successfully.
|
|
46
|
+
*/
|
|
47
|
+
isCompleted() {
|
|
48
|
+
return this.state === "completed";
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if analysis has failed.
|
|
52
|
+
*/
|
|
53
|
+
isFailed() {
|
|
54
|
+
return this.state === "failed";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Get analysis duration in milliseconds (if completed or failed).
|
|
58
|
+
*/
|
|
59
|
+
getDuration() {
|
|
60
|
+
if (this.state === "idle" || this.state === "analyzing") {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return Date.now() - this.startTime;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Start AST analysis in a worker thread.
|
|
67
|
+
* Returns immediately and emits events as analysis progresses.
|
|
68
|
+
*/
|
|
69
|
+
async analyze() {
|
|
70
|
+
if (this.analysisPromise) {
|
|
71
|
+
return this.analysisPromise;
|
|
72
|
+
}
|
|
73
|
+
if (this.state === "completed" && this.result) {
|
|
74
|
+
return Promise.resolve(this.result);
|
|
75
|
+
}
|
|
76
|
+
if (this.state === "failed") {
|
|
77
|
+
this.state = "idle";
|
|
78
|
+
this.error = null;
|
|
79
|
+
}
|
|
80
|
+
this.analysisPromise = new Promise((resolve, reject) => {
|
|
81
|
+
this.state = "analyzing";
|
|
82
|
+
this.startTime = Date.now();
|
|
83
|
+
this.emit("started");
|
|
84
|
+
const workerPath = path.join(__dirname, "ast-worker-thread.js");
|
|
85
|
+
this.worker = new Worker(workerPath, {
|
|
86
|
+
workerData: {
|
|
87
|
+
rootDir: this.rootDir,
|
|
88
|
+
entrypoint: this.entrypoint
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const timeoutId = setTimeout(() => {
|
|
92
|
+
if (this.worker) {
|
|
93
|
+
this.worker.terminate();
|
|
94
|
+
this.worker = null;
|
|
95
|
+
}
|
|
96
|
+
const timeoutError = new Error(`AST analysis timed out after ${this.timeout}ms`);
|
|
97
|
+
this.state = "failed";
|
|
98
|
+
this.error = timeoutError;
|
|
99
|
+
this.emit("failed", timeoutError);
|
|
100
|
+
reject(timeoutError);
|
|
101
|
+
}, this.timeout);
|
|
102
|
+
this.worker.on("message", (message) => {
|
|
103
|
+
if (message.type === "progress") {
|
|
104
|
+
this.emit("progress", message.message);
|
|
105
|
+
} else if (message.type === "result") {
|
|
106
|
+
clearTimeout(timeoutId);
|
|
107
|
+
this.state = "completed";
|
|
108
|
+
this.result = message.data;
|
|
109
|
+
this.emit("completed", this.result);
|
|
110
|
+
resolve(this.result);
|
|
111
|
+
if (this.worker) {
|
|
112
|
+
this.worker.terminate();
|
|
113
|
+
this.worker = null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
this.worker.on("error", (err) => {
|
|
118
|
+
clearTimeout(timeoutId);
|
|
119
|
+
this.state = "failed";
|
|
120
|
+
this.error = err;
|
|
121
|
+
this.emit("failed", err);
|
|
122
|
+
reject(err);
|
|
123
|
+
if (this.worker) {
|
|
124
|
+
this.worker.terminate();
|
|
125
|
+
this.worker = null;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
this.worker.on("exit", (code) => {
|
|
129
|
+
if (code !== 0 && this.state === "analyzing") {
|
|
130
|
+
clearTimeout(timeoutId);
|
|
131
|
+
const exitError = new Error(`Worker exited with code ${code}`);
|
|
132
|
+
this.state = "failed";
|
|
133
|
+
this.error = exitError;
|
|
134
|
+
this.emit("failed", exitError);
|
|
135
|
+
reject(exitError);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
return this.analysisPromise;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Wait for analysis to complete (if it's running) or return immediately if already done.
|
|
143
|
+
*/
|
|
144
|
+
async waitForCompletion() {
|
|
145
|
+
if (this.state === "completed" && this.result) {
|
|
146
|
+
return this.result;
|
|
147
|
+
}
|
|
148
|
+
if (this.state === "failed" && this.error) {
|
|
149
|
+
throw this.error;
|
|
150
|
+
}
|
|
151
|
+
if (this.state === "analyzing" && this.analysisPromise) {
|
|
152
|
+
return this.analysisPromise;
|
|
153
|
+
}
|
|
154
|
+
return this.analyze();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Terminate the worker thread if running.
|
|
158
|
+
*/
|
|
159
|
+
terminate() {
|
|
160
|
+
if (this.worker) {
|
|
161
|
+
this.worker.terminate();
|
|
162
|
+
this.worker = null;
|
|
163
|
+
}
|
|
164
|
+
if (this.state === "analyzing") {
|
|
165
|
+
this.state = "idle";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
let globalAnalyzer = null;
|
|
170
|
+
function getGlobalAnalyzer(rootDir, entrypoint, timeout) {
|
|
171
|
+
if (!globalAnalyzer) {
|
|
172
|
+
globalAnalyzer = new ASTAnalyzerWorker(
|
|
173
|
+
rootDir || process.cwd(),
|
|
174
|
+
entrypoint,
|
|
175
|
+
timeout
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return globalAnalyzer;
|
|
179
|
+
}
|
|
180
|
+
export {
|
|
181
|
+
ASTAnalyzerWorker,
|
|
182
|
+
getGlobalAnalyzer
|
|
183
|
+
};
|
|
184
|
+
//# sourceMappingURL=ast-analyzer-worker-C3jrQ8VR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-analyzer-worker-C3jrQ8VR.js","sources":["../src/util/ast-analyzer-worker.ts"],"sourcesContent":["import { EventEmitter } from 'events';\nimport path from 'path';\nimport { Worker } from 'worker_threads';\n\nexport type ASTAnalyzerState = 'idle' | 'analyzing' | 'completed' | 'failed';\n\nexport interface ASTAnalyzerResult {\n applications: any[];\n}\n\nexport interface ASTAnalyzerEvents {\n 'started': () => void;\n 'completed': (result: ASTAnalyzerResult) => void;\n 'failed': (error: Error) => void;\n 'progress': (message: string) => void;\n}\n\n/**\n * Worker-based AST analyzer that runs TypeScript analysis in a separate thread.\n * This prevents blocking the main event loop during intensive AST parsing.\n */\nexport class ASTAnalyzerWorker extends EventEmitter {\n private state: ASTAnalyzerState = 'idle';\n private result: ASTAnalyzerResult | null = null;\n private error: Error | null = null;\n private worker: Worker | null = null;\n private analysisPromise: Promise<ASTAnalyzerResult> | null = null;\n private rootDir: string;\n private entrypoint?: string;\n private timeout: number;\n private startTime: number = 0;\n\n constructor(rootDir: string, entrypoint?: string, timeout: number = 30000) {\n super();\n this.rootDir = rootDir;\n this.entrypoint = entrypoint;\n this.timeout = timeout;\n }\n\n /**\n * Get the current state of the analyzer.\n */\n public getState(): ASTAnalyzerState {\n return this.state;\n }\n\n /**\n * Get the cached result if analysis completed successfully.\n */\n public getResult(): ASTAnalyzerResult | null {\n return this.result;\n }\n\n /**\n * Get the error if analysis failed.\n */\n public getError(): Error | null {\n return this.error;\n }\n\n /**\n * Check if analysis is currently running.\n */\n public isAnalyzing(): boolean {\n return this.state === 'analyzing';\n }\n\n /**\n * Check if analysis has completed successfully.\n */\n public isCompleted(): boolean {\n return this.state === 'completed';\n }\n\n /**\n * Check if analysis has failed.\n */\n public isFailed(): boolean {\n return this.state === 'failed';\n }\n\n /**\n * Get analysis duration in milliseconds (if completed or failed).\n */\n public getDuration(): number | null {\n if (this.state === 'idle' || this.state === 'analyzing') {\n return null;\n }\n return Date.now() - this.startTime;\n }\n\n /**\n * Start AST analysis in a worker thread.\n * Returns immediately and emits events as analysis progresses.\n */\n public async analyze(): Promise<ASTAnalyzerResult> {\n // If already analyzing, return the existing promise\n if (this.analysisPromise) {\n return this.analysisPromise;\n }\n\n // If already completed, return cached result\n if (this.state === 'completed' && this.result) {\n return Promise.resolve(this.result);\n }\n\n // If previously failed, reset state for retry\n if (this.state === 'failed') {\n this.state = 'idle';\n this.error = null;\n }\n\n this.analysisPromise = new Promise<ASTAnalyzerResult>((resolve, reject) => {\n this.state = 'analyzing';\n this.startTime = Date.now();\n this.emit('started');\n\n // Create worker thread\n const workerPath = path.join(__dirname, 'ast-worker-thread.js');\n this.worker = new Worker(workerPath, {\n workerData: {\n rootDir: this.rootDir,\n entrypoint: this.entrypoint\n }\n });\n\n // Set timeout\n const timeoutId = setTimeout(() => {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n const timeoutError = new Error(`AST analysis timed out after ${this.timeout}ms`);\n this.state = 'failed';\n this.error = timeoutError;\n this.emit('failed', timeoutError);\n reject(timeoutError);\n }, this.timeout);\n\n // Handle worker messages\n this.worker.on('message', (message: any) => {\n if (message.type === 'progress') {\n this.emit('progress', message.message);\n } else if (message.type === 'result') {\n clearTimeout(timeoutId);\n this.state = 'completed';\n this.result = message.data;\n this.emit('completed', this.result!);\n resolve(this.result!);\n\n // Clean up worker\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n }\n });\n\n // Handle worker errors\n this.worker.on('error', (err: Error) => {\n clearTimeout(timeoutId);\n this.state = 'failed';\n this.error = err;\n this.emit('failed', err);\n reject(err);\n\n // Clean up worker\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n });\n\n // Handle worker exit\n this.worker.on('exit', (code) => {\n if (code !== 0 && this.state === 'analyzing') {\n clearTimeout(timeoutId);\n const exitError = new Error(`Worker exited with code ${code}`);\n this.state = 'failed';\n this.error = exitError;\n this.emit('failed', exitError);\n reject(exitError);\n }\n });\n });\n\n return this.analysisPromise;\n }\n\n /**\n * Wait for analysis to complete (if it's running) or return immediately if already done.\n */\n public async waitForCompletion(): Promise<ASTAnalyzerResult> {\n if (this.state === 'completed' && this.result) {\n return this.result;\n }\n\n if (this.state === 'failed' && this.error) {\n throw this.error;\n }\n\n if (this.state === 'analyzing' && this.analysisPromise) {\n return this.analysisPromise;\n }\n\n // Not started yet, start it\n return this.analyze();\n }\n\n /**\n * Terminate the worker thread if running.\n */\n public terminate(): void {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n if (this.state === 'analyzing') {\n this.state = 'idle';\n }\n }\n}\n\n// Singleton instance for shared use across plugins\nlet globalAnalyzer: ASTAnalyzerWorker | null = null;\n\n/**\n * Get or create the global AST analyzer instance.\n * This ensures all plugins share the same analysis results.\n */\nexport function getGlobalAnalyzer(rootDir?: string, entrypoint?: string, timeout?: number): ASTAnalyzerWorker {\n if (!globalAnalyzer) {\n globalAnalyzer = new ASTAnalyzerWorker(\n rootDir || process.cwd(),\n entrypoint,\n timeout\n );\n }\n return globalAnalyzer;\n}\n\n/**\n * Reset the global analyzer instance (useful for testing).\n */\nexport function resetGlobalAnalyzer(): void {\n if (globalAnalyzer) {\n globalAnalyzer.terminate();\n globalAnalyzer = null;\n }\n}\n"],"names":[],"mappings":";;;AAqBO,MAAM,0BAA0B,aAAa;AAAA,EACxC,QAA0B;AAAA,EAC1B,SAAmC;AAAA,EACnC,QAAsB;AAAA,EACtB,SAAwB;AAAA,EACxB,kBAAqD;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA,YAAoB;AAAA,EAE5B,YAAY,SAAiB,YAAqB,UAAkB,KAAO;AACvE,UAAA;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,UAAU;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKO,WAA6B;AAChC,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKO,YAAsC;AACzC,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKO,WAAyB;AAC5B,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKO,cAAuB;AAC1B,WAAO,KAAK,UAAU;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKO,cAAuB;AAC1B,WAAO,KAAK,UAAU;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKO,WAAoB;AACvB,WAAO,KAAK,UAAU;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKO,cAA6B;AAChC,QAAI,KAAK,UAAU,UAAU,KAAK,UAAU,aAAa;AACrD,aAAO;AAAA,IACX;AACA,WAAO,KAAK,QAAQ,KAAK;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAa,UAAsC;AAE/C,QAAI,KAAK,iBAAiB;AACtB,aAAO,KAAK;AAAA,IAChB;AAGA,QAAI,KAAK,UAAU,eAAe,KAAK,QAAQ;AAC3C,aAAO,QAAQ,QAAQ,KAAK,MAAM;AAAA,IACtC;AAGA,QAAI,KAAK,UAAU,UAAU;AACzB,WAAK,QAAQ;AACb,WAAK,QAAQ;AAAA,IACjB;AAEA,SAAK,kBAAkB,IAAI,QAA2B,CAAC,SAAS,WAAW;AACvE,WAAK,QAAQ;AACb,WAAK,YAAY,KAAK,IAAA;AACtB,WAAK,KAAK,SAAS;AAGnB,YAAM,aAAa,KAAK,KAAK,WAAW,sBAAsB;AAC9D,WAAK,SAAS,IAAI,OAAO,YAAY;AAAA,QACjC,YAAY;AAAA,UACR,SAAS,KAAK;AAAA,UACd,YAAY,KAAK;AAAA,QAAA;AAAA,MACrB,CACH;AAGD,YAAM,YAAY,WAAW,MAAM;AAC/B,YAAI,KAAK,QAAQ;AACb,eAAK,OAAO,UAAA;AACZ,eAAK,SAAS;AAAA,QAClB;AACA,cAAM,eAAe,IAAI,MAAM,gCAAgC,KAAK,OAAO,IAAI;AAC/E,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,KAAK,UAAU,YAAY;AAChC,eAAO,YAAY;AAAA,MACvB,GAAG,KAAK,OAAO;AAGf,WAAK,OAAO,GAAG,WAAW,CAAC,YAAiB;AACxC,YAAI,QAAQ,SAAS,YAAY;AAC7B,eAAK,KAAK,YAAY,QAAQ,OAAO;AAAA,QACzC,WAAW,QAAQ,SAAS,UAAU;AAClC,uBAAa,SAAS;AACtB,eAAK,QAAQ;AACb,eAAK,SAAS,QAAQ;AACtB,eAAK,KAAK,aAAa,KAAK,MAAO;AACnC,kBAAQ,KAAK,MAAO;AAGpB,cAAI,KAAK,QAAQ;AACb,iBAAK,OAAO,UAAA;AACZ,iBAAK,SAAS;AAAA,UAClB;AAAA,QACJ;AAAA,MACJ,CAAC;AAGD,WAAK,OAAO,GAAG,SAAS,CAAC,QAAe;AACpC,qBAAa,SAAS;AACtB,aAAK,QAAQ;AACb,aAAK,QAAQ;AACb,aAAK,KAAK,UAAU,GAAG;AACvB,eAAO,GAAG;AAGV,YAAI,KAAK,QAAQ;AACb,eAAK,OAAO,UAAA;AACZ,eAAK,SAAS;AAAA,QAClB;AAAA,MACJ,CAAC;AAGD,WAAK,OAAO,GAAG,QAAQ,CAAC,SAAS;AAC7B,YAAI,SAAS,KAAK,KAAK,UAAU,aAAa;AAC1C,uBAAa,SAAS;AACtB,gBAAM,YAAY,IAAI,MAAM,2BAA2B,IAAI,EAAE;AAC7D,eAAK,QAAQ;AACb,eAAK,QAAQ;AACb,eAAK,KAAK,UAAU,SAAS;AAC7B,iBAAO,SAAS;AAAA,QACpB;AAAA,MACJ,CAAC;AAAA,IACL,CAAC;AAED,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,oBAAgD;AACzD,QAAI,KAAK,UAAU,eAAe,KAAK,QAAQ;AAC3C,aAAO,KAAK;AAAA,IAChB;AAEA,QAAI,KAAK,UAAU,YAAY,KAAK,OAAO;AACvC,YAAM,KAAK;AAAA,IACf;AAEA,QAAI,KAAK,UAAU,eAAe,KAAK,iBAAiB;AACpD,aAAO,KAAK;AAAA,IAChB;AAGA,WAAO,KAAK,QAAA;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKO,YAAkB;AACrB,QAAI,KAAK,QAAQ;AACb,WAAK,OAAO,UAAA;AACZ,WAAK,SAAS;AAAA,IAClB;AACA,QAAI,KAAK,UAAU,aAAa;AAC5B,WAAK,QAAQ;AAAA,IACjB;AAAA,EACJ;AACJ;AAGA,IAAI,iBAA2C;AAMxC,SAAS,kBAAkB,SAAkB,YAAqB,SAAqC;AAC1G,MAAI,CAAC,gBAAgB;AACjB,qBAAiB,IAAI;AAAA,MACjB,WAAW,QAAQ,IAAA;AAAA,MACnB;AAAA,MACA;AAAA,IAAA;AAAA,EAER;AACA,SAAO;AACX;"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const events = require("events");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const worker_threads = require("worker_threads");
|
|
6
|
+
class ASTAnalyzerWorker extends events.EventEmitter {
|
|
7
|
+
state = "idle";
|
|
8
|
+
result = null;
|
|
9
|
+
error = null;
|
|
10
|
+
worker = null;
|
|
11
|
+
analysisPromise = null;
|
|
12
|
+
rootDir;
|
|
13
|
+
entrypoint;
|
|
14
|
+
timeout;
|
|
15
|
+
startTime = 0;
|
|
16
|
+
constructor(rootDir, entrypoint, timeout = 3e4) {
|
|
17
|
+
super();
|
|
18
|
+
this.rootDir = rootDir;
|
|
19
|
+
this.entrypoint = entrypoint;
|
|
20
|
+
this.timeout = timeout;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get the current state of the analyzer.
|
|
24
|
+
*/
|
|
25
|
+
getState() {
|
|
26
|
+
return this.state;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get the cached result if analysis completed successfully.
|
|
30
|
+
*/
|
|
31
|
+
getResult() {
|
|
32
|
+
return this.result;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get the error if analysis failed.
|
|
36
|
+
*/
|
|
37
|
+
getError() {
|
|
38
|
+
return this.error;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if analysis is currently running.
|
|
42
|
+
*/
|
|
43
|
+
isAnalyzing() {
|
|
44
|
+
return this.state === "analyzing";
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Check if analysis has completed successfully.
|
|
48
|
+
*/
|
|
49
|
+
isCompleted() {
|
|
50
|
+
return this.state === "completed";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Check if analysis has failed.
|
|
54
|
+
*/
|
|
55
|
+
isFailed() {
|
|
56
|
+
return this.state === "failed";
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Get analysis duration in milliseconds (if completed or failed).
|
|
60
|
+
*/
|
|
61
|
+
getDuration() {
|
|
62
|
+
if (this.state === "idle" || this.state === "analyzing") {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return Date.now() - this.startTime;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Start AST analysis in a worker thread.
|
|
69
|
+
* Returns immediately and emits events as analysis progresses.
|
|
70
|
+
*/
|
|
71
|
+
async analyze() {
|
|
72
|
+
if (this.analysisPromise) {
|
|
73
|
+
return this.analysisPromise;
|
|
74
|
+
}
|
|
75
|
+
if (this.state === "completed" && this.result) {
|
|
76
|
+
return Promise.resolve(this.result);
|
|
77
|
+
}
|
|
78
|
+
if (this.state === "failed") {
|
|
79
|
+
this.state = "idle";
|
|
80
|
+
this.error = null;
|
|
81
|
+
}
|
|
82
|
+
this.analysisPromise = new Promise((resolve, reject) => {
|
|
83
|
+
this.state = "analyzing";
|
|
84
|
+
this.startTime = Date.now();
|
|
85
|
+
this.emit("started");
|
|
86
|
+
const workerPath = path.join(__dirname, "ast-worker-thread.js");
|
|
87
|
+
this.worker = new worker_threads.Worker(workerPath, {
|
|
88
|
+
workerData: {
|
|
89
|
+
rootDir: this.rootDir,
|
|
90
|
+
entrypoint: this.entrypoint
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const timeoutId = setTimeout(() => {
|
|
94
|
+
if (this.worker) {
|
|
95
|
+
this.worker.terminate();
|
|
96
|
+
this.worker = null;
|
|
97
|
+
}
|
|
98
|
+
const timeoutError = new Error(`AST analysis timed out after ${this.timeout}ms`);
|
|
99
|
+
this.state = "failed";
|
|
100
|
+
this.error = timeoutError;
|
|
101
|
+
this.emit("failed", timeoutError);
|
|
102
|
+
reject(timeoutError);
|
|
103
|
+
}, this.timeout);
|
|
104
|
+
this.worker.on("message", (message) => {
|
|
105
|
+
if (message.type === "progress") {
|
|
106
|
+
this.emit("progress", message.message);
|
|
107
|
+
} else if (message.type === "result") {
|
|
108
|
+
clearTimeout(timeoutId);
|
|
109
|
+
this.state = "completed";
|
|
110
|
+
this.result = message.data;
|
|
111
|
+
this.emit("completed", this.result);
|
|
112
|
+
resolve(this.result);
|
|
113
|
+
if (this.worker) {
|
|
114
|
+
this.worker.terminate();
|
|
115
|
+
this.worker = null;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
this.worker.on("error", (err) => {
|
|
120
|
+
clearTimeout(timeoutId);
|
|
121
|
+
this.state = "failed";
|
|
122
|
+
this.error = err;
|
|
123
|
+
this.emit("failed", err);
|
|
124
|
+
reject(err);
|
|
125
|
+
if (this.worker) {
|
|
126
|
+
this.worker.terminate();
|
|
127
|
+
this.worker = null;
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
this.worker.on("exit", (code) => {
|
|
131
|
+
if (code !== 0 && this.state === "analyzing") {
|
|
132
|
+
clearTimeout(timeoutId);
|
|
133
|
+
const exitError = new Error(`Worker exited with code ${code}`);
|
|
134
|
+
this.state = "failed";
|
|
135
|
+
this.error = exitError;
|
|
136
|
+
this.emit("failed", exitError);
|
|
137
|
+
reject(exitError);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
return this.analysisPromise;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Wait for analysis to complete (if it's running) or return immediately if already done.
|
|
145
|
+
*/
|
|
146
|
+
async waitForCompletion() {
|
|
147
|
+
if (this.state === "completed" && this.result) {
|
|
148
|
+
return this.result;
|
|
149
|
+
}
|
|
150
|
+
if (this.state === "failed" && this.error) {
|
|
151
|
+
throw this.error;
|
|
152
|
+
}
|
|
153
|
+
if (this.state === "analyzing" && this.analysisPromise) {
|
|
154
|
+
return this.analysisPromise;
|
|
155
|
+
}
|
|
156
|
+
return this.analyze();
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Terminate the worker thread if running.
|
|
160
|
+
*/
|
|
161
|
+
terminate() {
|
|
162
|
+
if (this.worker) {
|
|
163
|
+
this.worker.terminate();
|
|
164
|
+
this.worker = null;
|
|
165
|
+
}
|
|
166
|
+
if (this.state === "analyzing") {
|
|
167
|
+
this.state = "idle";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
let globalAnalyzer = null;
|
|
172
|
+
function getGlobalAnalyzer(rootDir, entrypoint, timeout) {
|
|
173
|
+
if (!globalAnalyzer) {
|
|
174
|
+
globalAnalyzer = new ASTAnalyzerWorker(
|
|
175
|
+
rootDir || process.cwd(),
|
|
176
|
+
entrypoint,
|
|
177
|
+
timeout
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
return globalAnalyzer;
|
|
181
|
+
}
|
|
182
|
+
exports.ASTAnalyzerWorker = ASTAnalyzerWorker;
|
|
183
|
+
exports.getGlobalAnalyzer = getGlobalAnalyzer;
|
|
184
|
+
//# sourceMappingURL=ast-analyzer-worker-D_uYkqmY.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-analyzer-worker-D_uYkqmY.cjs","sources":["../src/util/ast-analyzer-worker.ts"],"sourcesContent":["import { EventEmitter } from 'events';\nimport path from 'path';\nimport { Worker } from 'worker_threads';\n\nexport type ASTAnalyzerState = 'idle' | 'analyzing' | 'completed' | 'failed';\n\nexport interface ASTAnalyzerResult {\n applications: any[];\n}\n\nexport interface ASTAnalyzerEvents {\n 'started': () => void;\n 'completed': (result: ASTAnalyzerResult) => void;\n 'failed': (error: Error) => void;\n 'progress': (message: string) => void;\n}\n\n/**\n * Worker-based AST analyzer that runs TypeScript analysis in a separate thread.\n * This prevents blocking the main event loop during intensive AST parsing.\n */\nexport class ASTAnalyzerWorker extends EventEmitter {\n private state: ASTAnalyzerState = 'idle';\n private result: ASTAnalyzerResult | null = null;\n private error: Error | null = null;\n private worker: Worker | null = null;\n private analysisPromise: Promise<ASTAnalyzerResult> | null = null;\n private rootDir: string;\n private entrypoint?: string;\n private timeout: number;\n private startTime: number = 0;\n\n constructor(rootDir: string, entrypoint?: string, timeout: number = 30000) {\n super();\n this.rootDir = rootDir;\n this.entrypoint = entrypoint;\n this.timeout = timeout;\n }\n\n /**\n * Get the current state of the analyzer.\n */\n public getState(): ASTAnalyzerState {\n return this.state;\n }\n\n /**\n * Get the cached result if analysis completed successfully.\n */\n public getResult(): ASTAnalyzerResult | null {\n return this.result;\n }\n\n /**\n * Get the error if analysis failed.\n */\n public getError(): Error | null {\n return this.error;\n }\n\n /**\n * Check if analysis is currently running.\n */\n public isAnalyzing(): boolean {\n return this.state === 'analyzing';\n }\n\n /**\n * Check if analysis has completed successfully.\n */\n public isCompleted(): boolean {\n return this.state === 'completed';\n }\n\n /**\n * Check if analysis has failed.\n */\n public isFailed(): boolean {\n return this.state === 'failed';\n }\n\n /**\n * Get analysis duration in milliseconds (if completed or failed).\n */\n public getDuration(): number | null {\n if (this.state === 'idle' || this.state === 'analyzing') {\n return null;\n }\n return Date.now() - this.startTime;\n }\n\n /**\n * Start AST analysis in a worker thread.\n * Returns immediately and emits events as analysis progresses.\n */\n public async analyze(): Promise<ASTAnalyzerResult> {\n // If already analyzing, return the existing promise\n if (this.analysisPromise) {\n return this.analysisPromise;\n }\n\n // If already completed, return cached result\n if (this.state === 'completed' && this.result) {\n return Promise.resolve(this.result);\n }\n\n // If previously failed, reset state for retry\n if (this.state === 'failed') {\n this.state = 'idle';\n this.error = null;\n }\n\n this.analysisPromise = new Promise<ASTAnalyzerResult>((resolve, reject) => {\n this.state = 'analyzing';\n this.startTime = Date.now();\n this.emit('started');\n\n // Create worker thread\n const workerPath = path.join(__dirname, 'ast-worker-thread.js');\n this.worker = new Worker(workerPath, {\n workerData: {\n rootDir: this.rootDir,\n entrypoint: this.entrypoint\n }\n });\n\n // Set timeout\n const timeoutId = setTimeout(() => {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n const timeoutError = new Error(`AST analysis timed out after ${this.timeout}ms`);\n this.state = 'failed';\n this.error = timeoutError;\n this.emit('failed', timeoutError);\n reject(timeoutError);\n }, this.timeout);\n\n // Handle worker messages\n this.worker.on('message', (message: any) => {\n if (message.type === 'progress') {\n this.emit('progress', message.message);\n } else if (message.type === 'result') {\n clearTimeout(timeoutId);\n this.state = 'completed';\n this.result = message.data;\n this.emit('completed', this.result!);\n resolve(this.result!);\n\n // Clean up worker\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n }\n });\n\n // Handle worker errors\n this.worker.on('error', (err: Error) => {\n clearTimeout(timeoutId);\n this.state = 'failed';\n this.error = err;\n this.emit('failed', err);\n reject(err);\n\n // Clean up worker\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n });\n\n // Handle worker exit\n this.worker.on('exit', (code) => {\n if (code !== 0 && this.state === 'analyzing') {\n clearTimeout(timeoutId);\n const exitError = new Error(`Worker exited with code ${code}`);\n this.state = 'failed';\n this.error = exitError;\n this.emit('failed', exitError);\n reject(exitError);\n }\n });\n });\n\n return this.analysisPromise;\n }\n\n /**\n * Wait for analysis to complete (if it's running) or return immediately if already done.\n */\n public async waitForCompletion(): Promise<ASTAnalyzerResult> {\n if (this.state === 'completed' && this.result) {\n return this.result;\n }\n\n if (this.state === 'failed' && this.error) {\n throw this.error;\n }\n\n if (this.state === 'analyzing' && this.analysisPromise) {\n return this.analysisPromise;\n }\n\n // Not started yet, start it\n return this.analyze();\n }\n\n /**\n * Terminate the worker thread if running.\n */\n public terminate(): void {\n if (this.worker) {\n this.worker.terminate();\n this.worker = null;\n }\n if (this.state === 'analyzing') {\n this.state = 'idle';\n }\n }\n}\n\n// Singleton instance for shared use across plugins\nlet globalAnalyzer: ASTAnalyzerWorker | null = null;\n\n/**\n * Get or create the global AST analyzer instance.\n * This ensures all plugins share the same analysis results.\n */\nexport function getGlobalAnalyzer(rootDir?: string, entrypoint?: string, timeout?: number): ASTAnalyzerWorker {\n if (!globalAnalyzer) {\n globalAnalyzer = new ASTAnalyzerWorker(\n rootDir || process.cwd(),\n entrypoint,\n timeout\n );\n }\n return globalAnalyzer;\n}\n\n/**\n * Reset the global analyzer instance (useful for testing).\n */\nexport function resetGlobalAnalyzer(): void {\n if (globalAnalyzer) {\n globalAnalyzer.terminate();\n globalAnalyzer = null;\n }\n}\n"],"names":["EventEmitter","Worker"],"mappings":"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"}
|
package/dist/cli.cjs
CHANGED
|
@@ -4,7 +4,7 @@ const p = require("@clack/prompts");
|
|
|
4
4
|
const fs = require("node:fs");
|
|
5
5
|
const path = require("node:path");
|
|
6
6
|
const promises = require("node:timers/promises");
|
|
7
|
-
const analyzer = require("./analyzer-
|
|
7
|
+
const analyzer = require("./analyzer-BZSVGTmP.cjs");
|
|
8
8
|
function _interopNamespaceDefault(e) {
|
|
9
9
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
|
10
10
|
if (e) {
|
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as p from "@clack/prompts";
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { setTimeout } from "node:timers/promises";
|
|
6
|
-
import { OpenAPIAnalyzer } from "./analyzer-
|
|
6
|
+
import { OpenAPIAnalyzer } from "./analyzer-Faojwm7c.js";
|
|
7
7
|
const templates = {
|
|
8
8
|
controller: (name) => `import { Controller, Get, Ctx } from 'shokupan';
|
|
9
9
|
import { ShokupanContext } from 'shokupan';
|
package/dist/context.d.ts
CHANGED
|
@@ -5,6 +5,15 @@ import { ShokupanRequest } from './util/request';
|
|
|
5
5
|
import { ShokupanResponse } from './util/response';
|
|
6
6
|
import { $bodyParsed, $bodyParseError, $bodyType, $cachedBody, $cachedCookies, $cachedHost, $cachedHostname, $cachedOrigin, $cachedProtocol, $cachedQuery, $debug, $finalResponse, $io, $rawBody, $requestId, $routeMatched, $socket, $url, $ws } from './util/symbol';
|
|
7
7
|
import { CookieOptions, HeadersInit, JSXRenderer, SSEStreamErrorHandler, SSEStreamHelper, StreamErrorHandler, StreamHelper, TextStreamErrorHandler, TextStreamHelper } from './util/types';
|
|
8
|
+
/**
|
|
9
|
+
* Inline WebSocket handlers for ctx.upgrade()
|
|
10
|
+
*/
|
|
11
|
+
export interface InlineWebSocketHandlers<T = any> {
|
|
12
|
+
open?: (ctx: ShokupanContext<T>, ws: ServerWebSocket<any>) => void | Promise<void>;
|
|
13
|
+
message?: (ctx: ShokupanContext<T>, ws: ServerWebSocket<any>, message: string | Buffer) => void | Promise<void>;
|
|
14
|
+
close?: (ctx: ShokupanContext<T>, ws: ServerWebSocket<any>, code?: number, reason?: string) => void | Promise<void>;
|
|
15
|
+
error?: (ctx: ShokupanContext<T>, ws: ServerWebSocket<any>, error: Error) => void | Promise<void>;
|
|
16
|
+
}
|
|
8
17
|
export interface HandlerStackItem {
|
|
9
18
|
name: string;
|
|
10
19
|
file: string;
|
|
@@ -93,6 +102,10 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
|
|
|
93
102
|
[$debug]?: DebugCollector;
|
|
94
103
|
[$finalResponse]?: Response;
|
|
95
104
|
[$rawBody]?: string | ArrayBuffer | Uint8Array;
|
|
105
|
+
/**
|
|
106
|
+
* Application logger instance
|
|
107
|
+
*/
|
|
108
|
+
get logger(): import('./util/logger').Logger;
|
|
96
109
|
private [$url]?;
|
|
97
110
|
private [$cachedBody]?;
|
|
98
111
|
private [$bodyType]?;
|
|
@@ -211,12 +224,26 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
|
|
|
211
224
|
isUpgraded: boolean;
|
|
212
225
|
/**
|
|
213
226
|
* Upgrades the request to a WebSocket connection.
|
|
214
|
-
*
|
|
227
|
+
*
|
|
228
|
+
* @param options Upgrade options or inline WebSocket handlers
|
|
215
229
|
* @returns true if upgraded, false otherwise
|
|
216
|
-
|
|
217
|
-
|
|
230
|
+
*
|
|
231
|
+
* This method will link the WebSocket connection to the context object,
|
|
232
|
+
* allowing you to access the connection in your handlers.
|
|
233
|
+
*
|
|
234
|
+
* @example Inline handlers
|
|
235
|
+
* ```ts
|
|
236
|
+
* app.get('/ws', (ctx) => {
|
|
237
|
+
* ctx.upgrade({
|
|
238
|
+
* open: (ctx, ws) => ws.send("Connected"),
|
|
239
|
+
* message: (ctx, ws, msg) => ws.send(msg),
|
|
240
|
+
* close: (ctx, ws) => console.log("Disconnected")
|
|
241
|
+
* });
|
|
242
|
+
* });
|
|
243
|
+
* ```
|
|
244
|
+
*/
|
|
245
|
+
upgrade(options?: Parameters<Server<State>["upgrade"]>[1] | InlineWebSocketHandlers<State> & {
|
|
218
246
|
data?: any;
|
|
219
|
-
headers?: HeadersInit;
|
|
220
247
|
}): boolean;
|
|
221
248
|
/**
|
|
222
249
|
* Set a cookie
|
|
@@ -241,6 +268,14 @@ export declare class ShokupanContext<State extends Record<string, any> = Record<
|
|
|
241
268
|
* Errors are deferred until the body is actually accessed in the handler.
|
|
242
269
|
*/
|
|
243
270
|
parseBody(): Promise<void>;
|
|
271
|
+
/**
|
|
272
|
+
* Respond with automatic content negotiation
|
|
273
|
+
* Uses Accept header to determine the best response format
|
|
274
|
+
* @param data Data to respond with
|
|
275
|
+
* @param status HTTP status code
|
|
276
|
+
* @param headers Additional headers
|
|
277
|
+
*/
|
|
278
|
+
respond(data: any, status?: number, headers?: HeadersInit): Promise<Response>;
|
|
244
279
|
/**
|
|
245
280
|
* Send a response
|
|
246
281
|
* @param body Response body
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { RateLimitOptions } from '../plugins/middleware/rate-limit';
|
|
2
|
+
import { AsyncAPISpec, GuardAPISpec, MethodAPISpec, Middleware } from '../util/types';
|
|
3
|
+
/**
|
|
4
|
+
* Registers this class as a **Singleton** service.
|
|
5
|
+
* A single instance will be created and shared across the process.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Injectable(scope: 'singleton'): ClassDecorator;
|
|
8
|
+
/**
|
|
9
|
+
* Registers this class as an **Instanced** (Transient) service.
|
|
10
|
+
* A new instance will be created every time dependency is resolved.
|
|
11
|
+
*/
|
|
12
|
+
export declare function Injectable(scope: 'instanced'): ClassDecorator;
|
|
13
|
+
/**
|
|
14
|
+
* Property/Parameter Decorator: Injects a service.
|
|
15
|
+
* Used on class properties or constructor parameters.
|
|
16
|
+
*/
|
|
17
|
+
export declare function Inject(token: any): PropertyDecorator & ParameterDecorator;
|
|
18
|
+
/**
|
|
19
|
+
* Decorator: Applies middleware OR injects dependencies.
|
|
20
|
+
* - Class/Method: Middleware
|
|
21
|
+
* - Property/Parameter: Dependency Injection
|
|
22
|
+
*/
|
|
23
|
+
export declare function Use(tokenOrMiddleware?: any | Middleware, ...moreMiddleware: Middleware[]): any;
|
|
24
|
+
/**
|
|
25
|
+
* Decorator: Overrides the OpenAPI specification for a route.
|
|
26
|
+
*/
|
|
27
|
+
export declare function Spec(spec: MethodAPISpec | GuardAPISpec | AsyncAPISpec): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Decorator: Applies a rate limit to a class or method.
|
|
30
|
+
*/
|
|
31
|
+
export declare function RateLimit(options: RateLimitOptions): any;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decorator: Hook that runs before a request is processed by the controller handler.
|
|
3
|
+
*/
|
|
4
|
+
export declare const OnRequestStart: () => (target: any, propertyKey: string) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Decorator: Hook that runs after a request is successfully processed.
|
|
7
|
+
*/
|
|
8
|
+
export declare const OnRequestEnd: () => (target: any, propertyKey: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Decorator: Hook that runs when an error occurs during request processing.
|
|
11
|
+
*/
|
|
12
|
+
export declare const OnRequestError: () => (target: any, propertyKey: string) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Decorator: Hook that runs when the response starts sending (headers).
|
|
15
|
+
*/
|
|
16
|
+
export declare const OnResponseStart: () => (target: any, propertyKey: string) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Decorator: Hook that runs after the response has finished sending.
|
|
19
|
+
*/
|
|
20
|
+
export declare const OnResponseEnd: () => (target: any, propertyKey: string) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Decorator: Hook that runs before validation.
|
|
23
|
+
*/
|
|
24
|
+
export declare const BeforeValidate: () => (target: any, propertyKey: string) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Decorator: Hook that runs after validation.
|
|
27
|
+
*/
|
|
28
|
+
export declare const AfterValidate: () => (target: any, propertyKey: string) => void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class Decorator: Defines the base path for a controller.
|
|
3
|
+
*/
|
|
4
|
+
export declare function Controller(path?: string): (target: any) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Decorator: Binds a method to the GET HTTP verb.
|
|
7
|
+
*/
|
|
8
|
+
export declare const Get: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
9
|
+
/**
|
|
10
|
+
* Decorator: Binds a method to the POST HTTP verb.
|
|
11
|
+
*/
|
|
12
|
+
export declare const Post: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Decorator: Binds a method to the PUT HTTP verb.
|
|
15
|
+
*/
|
|
16
|
+
export declare const Put: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Decorator: Binds a method to the DELETE HTTP verb.
|
|
19
|
+
*/
|
|
20
|
+
export declare const Delete: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Decorator: Binds a method to the PATCH HTTP verb.
|
|
23
|
+
*/
|
|
24
|
+
export declare const Patch: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
25
|
+
/**
|
|
26
|
+
* Decorator: Binds a method to the OPTIONS HTTP verb.
|
|
27
|
+
*/
|
|
28
|
+
export declare const Options: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Decorator: Binds a method to the HEAD HTTP verb.
|
|
31
|
+
*/
|
|
32
|
+
export declare const Head: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
33
|
+
/**
|
|
34
|
+
* Decorator: Binds a method to ANY HTTP verb.
|
|
35
|
+
*/
|
|
36
|
+
export declare const All: (path?: string) => (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Decorator: Binds a parameter to the request body.
|
|
39
|
+
*/
|
|
40
|
+
export declare const Body: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|
|
41
|
+
/**
|
|
42
|
+
* Decorator: Binds a parameter to the request parameters.
|
|
43
|
+
*/
|
|
44
|
+
export declare const Param: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Decorator: Binds a parameter to the request query string.
|
|
47
|
+
*/
|
|
48
|
+
export declare const Query: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|
|
49
|
+
/**
|
|
50
|
+
* Decorator: Binds a parameter to the request headers.
|
|
51
|
+
*/
|
|
52
|
+
export declare const Headers: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|
|
53
|
+
/**
|
|
54
|
+
* Decorator: Binds a parameter to the request object.
|
|
55
|
+
*/
|
|
56
|
+
export declare const Req: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|
|
57
|
+
/**
|
|
58
|
+
* Decorator: Binds a parameter to the request context.
|
|
59
|
+
*/
|
|
60
|
+
export declare const Ctx: (name?: string) => (target: any, propertyKey: string, parameterIndex: number) => void;
|