@flink-app/flink 0.14.3 → 2.0.0-alpha.100
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/CHANGELOG.md +1051 -0
- package/SCHEMA_EXTRACTION_ANALYSIS.md +494 -0
- package/SIMPLE_AST_FEASIBILITY.md +570 -0
- package/bin/flink.ts +13 -2
- package/cli/build.ts +24 -44
- package/cli/clean.ts +13 -25
- package/cli/cli-utils.ts +190 -17
- package/cli/dev.ts +252 -0
- package/cli/loadEnvFiles.ts +116 -0
- package/cli/run.ts +45 -62
- package/dist/bin/flink.js +61 -2
- package/dist/cli/build.js +20 -25
- package/dist/cli/clean.js +12 -10
- package/dist/cli/cli-utils.d.ts +34 -3
- package/dist/cli/cli-utils.js +193 -12
- package/dist/cli/dev.d.ts +2 -0
- package/dist/cli/dev.js +279 -0
- package/dist/cli/loadEnvFiles.d.ts +30 -0
- package/dist/cli/loadEnvFiles.js +113 -0
- package/dist/cli/run.js +47 -46
- package/dist/src/DependencyTracker.d.ts +44 -0
- package/dist/src/DependencyTracker.js +239 -0
- package/dist/src/FlinkApp.d.ts +163 -10
- package/dist/src/FlinkApp.js +847 -184
- package/dist/src/FlinkContext.d.ts +41 -0
- package/dist/src/FlinkErrors.d.ts +19 -6
- package/dist/src/FlinkErrors.js +36 -42
- package/dist/src/FlinkHttpHandler.d.ts +219 -26
- package/dist/src/FlinkHttpHandler.js +37 -1
- package/dist/src/FlinkJob.d.ts +10 -0
- package/dist/src/FlinkLog.d.ts +82 -18
- package/dist/src/FlinkLog.js +165 -13
- package/dist/src/FlinkLogFactory.d.ts +288 -0
- package/dist/src/FlinkLogFactory.js +619 -0
- package/dist/src/FlinkRepo.d.ts +10 -2
- package/dist/src/FlinkRepo.js +11 -1
- package/dist/src/FlinkRequestContext.d.ts +63 -0
- package/dist/src/FlinkRequestContext.js +74 -0
- package/dist/src/FlinkResponse.d.ts +6 -0
- package/dist/src/FlinkService.d.ts +38 -0
- package/dist/src/FlinkService.js +46 -0
- package/dist/src/LeaderElection.d.ts +45 -0
- package/dist/src/LeaderElection.js +269 -0
- package/dist/src/SchemaCache.d.ts +84 -0
- package/dist/src/SchemaCache.js +289 -0
- package/dist/src/TypeScriptCompiler.d.ts +161 -51
- package/dist/src/TypeScriptCompiler.js +1253 -617
- package/dist/src/TypeScriptUtils.js +4 -0
- package/dist/src/ai/AgentRunner.d.ts +39 -0
- package/dist/src/ai/AgentRunner.js +760 -0
- package/dist/src/ai/ConversationAgent.d.ts +279 -0
- package/dist/src/ai/ConversationAgent.js +404 -0
- package/dist/src/ai/ConversationFlinkAgent.d.ts +278 -0
- package/dist/src/ai/ConversationFlinkAgent.js +404 -0
- package/dist/src/ai/FlinkAgent.d.ts +690 -0
- package/dist/src/ai/FlinkAgent.js +729 -0
- package/dist/src/ai/FlinkTool.d.ts +135 -0
- package/dist/src/ai/FlinkTool.js +2 -0
- package/dist/src/ai/InMemoryConversationAgent.d.ts +121 -0
- package/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/dist/src/ai/LLMAdapter.d.ts +148 -0
- package/dist/src/ai/LLMAdapter.js +2 -0
- package/dist/src/ai/PersistentFlinkAgent.d.ts +278 -0
- package/dist/src/ai/PersistentFlinkAgent.js +403 -0
- package/dist/src/ai/SubAgentExecutor.d.ts +38 -0
- package/dist/src/ai/SubAgentExecutor.js +223 -0
- package/dist/src/ai/ToolExecutor.d.ts +64 -0
- package/dist/src/ai/ToolExecutor.js +497 -0
- package/dist/src/ai/agentInstructions.d.ts +68 -0
- package/dist/src/ai/agentInstructions.js +286 -0
- package/dist/src/ai/index.d.ts +8 -0
- package/dist/src/ai/index.js +26 -0
- package/dist/src/ai/instructionFileLoader.d.ts +44 -0
- package/dist/src/ai/instructionFileLoader.js +179 -0
- package/dist/src/auth/FlinkAuthPlugin.d.ts +1 -1
- package/dist/src/handlers/StreamWriterFactory.d.ts +20 -0
- package/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/dist/src/index.d.ts +14 -0
- package/dist/src/index.js +17 -0
- package/dist/src/loadPluginSchemas.d.ts +45 -0
- package/dist/src/loadPluginSchemas.js +143 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.d.ts +40 -0
- package/dist/src/schema-extraction/ComplexTypeDetection.js +75 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.d.ts +321 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.js +925 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.d.ts +1 -0
- package/dist/src/schema-extraction/TypeScriptSourceParser.spec.js +233 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.d.ts +57 -0
- package/dist/src/schema-extraction/TypeScriptTokenizer.js +177 -0
- package/dist/src/schema-extraction/index.d.ts +2 -0
- package/dist/src/schema-extraction/index.js +20 -0
- package/dist/src/schema-extraction/types.d.ts +31 -0
- package/dist/src/schema-extraction/types.js +2 -0
- package/dist/src/utils/loadFlinkConfig.d.ts +53 -0
- package/dist/src/utils/loadFlinkConfig.js +77 -0
- package/dist/src/utils.d.ts +30 -0
- package/dist/src/utils.js +52 -0
- package/dist/src/workers/SchemaGeneratorWorker.d.ts +1 -0
- package/dist/src/workers/SchemaGeneratorWorker.js +49 -0
- package/dist/src/workers/WorkerPool.d.ts +60 -0
- package/dist/src/workers/WorkerPool.js +306 -0
- package/examples/logging-hierarchical-example.ts +125 -0
- package/package.json +29 -4
- package/readme.md +499 -0
- package/spec/AgentDescendantDetection.spec.ts +335 -0
- package/spec/AgentDuplicateDetection.spec.ts +112 -0
- package/spec/AgentObserver.spec.ts +266 -0
- package/spec/AgentRunner.spec.ts +1062 -0
- package/spec/AsyncLocalStorageContext.spec.ts +223 -0
- package/spec/ConversationHooks.spec.ts +257 -0
- package/spec/FlinkAgent.spec.ts +681 -0
- package/spec/FlinkApp.htmlResponse.spec.ts +260 -0
- package/spec/FlinkApp.onError.invocation.spec.ts +151 -0
- package/spec/FlinkApp.onError.spec.ts +1 -2
- package/spec/FlinkApp.query.spec.ts +107 -0
- package/spec/FlinkApp.routeOrdering.spec.ts +61 -0
- package/spec/FlinkApp.undefinedResponse.spec.ts +123 -0
- package/spec/FlinkApp.validationMode.spec.ts +155 -0
- package/spec/FlinkJob.spec.ts +171 -0
- package/spec/FlinkLogFactory.spec.ts +337 -0
- package/spec/FlinkRepo.spec.ts +1 -1
- package/spec/LeaderElection.spec.ts +174 -0
- package/spec/StreamingIntegration.spec.ts +139 -0
- package/spec/ToolExecutor.spec.ts +465 -0
- package/spec/TypeScriptCompiler.spec.ts +1 -1
- package/spec/TypeScriptSourceParser.spec.ts +1215 -0
- package/spec/TypeScriptTokenizer.spec.ts +366 -0
- package/spec/ai/ContextCompaction.spec.ts +405 -0
- package/spec/ai/ConversationAgent.spec.ts +520 -0
- package/spec/ai/InMemoryConversationAgent.spec.ts +144 -0
- package/spec/ai/agentInstructions.spec.ts +358 -0
- package/spec/fixtures/agent-instructions/TestAgent.ts +24 -0
- package/spec/fixtures/agent-instructions/simple.md +3 -0
- package/spec/fixtures/agent-instructions/template.md +18 -0
- package/spec/fixtures/agent-instructions/yaml-format.yaml +9 -0
- package/spec/mock-project/dist/.tsbuildinfo +1 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar.js +56 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCar2.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema2.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithArraySchema3.js +52 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithLiteralSchema2.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/GetCarWithSchemaInFile2.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler.js +53 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/ManuallyAddedHandler2.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchCar.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOnboardingSession.js +75 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchOrderWithComplexTypes.js +57 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchProductWithIntersection.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PatchUserWithUnion.js +58 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogin.js +55 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PostLogout.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/handlers/PutCar.js +54 -0
- package/spec/mock-project/dist/spec/mock-project/src/index.js +83 -0
- package/spec/mock-project/dist/spec/mock-project/src/repos/CarRepo.js +26 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/Car.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/DefaultExportSchema.js +2 -0
- package/spec/mock-project/dist/spec/mock-project/src/schemas/FileWithTwoSchemas.js +2 -0
- package/spec/mock-project/dist/src/FlinkApp.js +1000 -0
- package/spec/mock-project/dist/src/FlinkContext.js +2 -0
- package/spec/mock-project/dist/src/FlinkErrors.js +143 -0
- package/spec/mock-project/dist/src/FlinkHttpHandler.js +47 -0
- package/spec/mock-project/dist/src/FlinkJob.js +2 -0
- package/spec/mock-project/dist/src/FlinkLog.js +119 -0
- package/spec/mock-project/dist/src/FlinkLogFactory.js +617 -0
- package/spec/mock-project/dist/src/FlinkPlugin.js +2 -0
- package/spec/mock-project/dist/src/FlinkRepo.js +224 -0
- package/spec/mock-project/dist/src/FlinkRequestContext.js +74 -0
- package/spec/mock-project/dist/src/FlinkResponse.js +2 -0
- package/spec/mock-project/dist/src/ai/AgentExecutor.js +279 -0
- package/spec/mock-project/dist/src/ai/AgentRunner.js +632 -0
- package/spec/mock-project/dist/src/ai/ConversationAgent.js +402 -0
- package/spec/mock-project/dist/src/ai/ConversationFlinkAgent.js +422 -0
- package/spec/mock-project/dist/src/ai/FlinkAgent.js +699 -0
- package/spec/mock-project/dist/src/ai/FlinkTool.js +2 -0
- package/spec/mock-project/dist/src/ai/InMemoryConversationAgent.js +209 -0
- package/spec/mock-project/dist/src/ai/LLMAdapter.js +2 -0
- package/spec/mock-project/dist/src/ai/SubAgentExecutor.js +223 -0
- package/spec/mock-project/dist/src/ai/ToolExecutor.js +412 -0
- package/spec/mock-project/dist/src/ai/agentInstructions.js +246 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthPlugin.js +2 -0
- package/spec/mock-project/dist/src/auth/FlinkAuthUser.js +2 -0
- package/spec/mock-project/dist/src/handlers/GetCar.js +26 -52
- package/spec/mock-project/dist/src/handlers/GetCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCar2.js +32 -54
- package/spec/mock-project/dist/src/handlers/GetCar2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js +26 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js +28 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js +29 -48
- package/spec/mock-project/dist/src/handlers/GetCarWithArraySchema3.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js +26 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js +28 -50
- package/spec/mock-project/dist/src/handlers/GetCarWithLiteralSchema2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js +27 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js +29 -53
- package/spec/mock-project/dist/src/handlers/GetCarWithSchemaInFile2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js +16 -49
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js +25 -50
- package/spec/mock-project/dist/src/handlers/ManuallyAddedHandler2.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchCar.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js +44 -70
- package/spec/mock-project/dist/src/handlers/PatchOnboardingSession.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js +27 -53
- package/spec/mock-project/dist/src/handlers/PatchOrderWithComplexTypes.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchProductWithIntersection.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js +28 -54
- package/spec/mock-project/dist/src/handlers/PatchUserWithUnion.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogin.js +25 -51
- package/spec/mock-project/dist/src/handlers/PostLogin.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PostLogout.js +24 -50
- package/spec/mock-project/dist/src/handlers/PostLogout.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/PutCar.js +24 -50
- package/spec/mock-project/dist/src/handlers/PutCar.js.map +1 -0
- package/spec/mock-project/dist/src/handlers/StreamWriterFactory.js +83 -0
- package/spec/mock-project/dist/src/index.js +52 -76
- package/spec/mock-project/dist/src/index.js.map +1 -0
- package/spec/mock-project/dist/src/mock-data-generator.js +9 -0
- package/spec/mock-project/dist/src/repos/CarRepo.js +12 -24
- package/spec/mock-project/dist/src/repos/CarRepo.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/Car.js +3 -1
- package/spec/mock-project/dist/src/schemas/Car.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js +3 -1
- package/spec/mock-project/dist/src/schemas/DefaultExportSchema.js.map +1 -0
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js +3 -1
- package/spec/mock-project/dist/src/schemas/FileWithTwoSchemas.js.map +1 -0
- package/spec/mock-project/dist/src/utils.js +290 -0
- package/spec/mock-project/tsconfig.json +6 -1
- package/spec/schema-generation-nested-objects.spec.ts +97 -0
- package/spec/testHelpers.ts +49 -0
- package/spec/utils.caseConversion.spec.ts +78 -0
- package/spec/utils.spec.ts +13 -13
- package/src/DependencyTracker.ts +166 -0
- package/src/FlinkApp.ts +919 -155
- package/src/FlinkContext.ts +43 -0
- package/src/FlinkErrors.ts +32 -12
- package/src/FlinkHttpHandler.ts +246 -28
- package/src/FlinkJob.ts +11 -0
- package/src/FlinkLog.ts +119 -12
- package/src/FlinkLogFactory.ts +699 -0
- package/src/FlinkRepo.ts +10 -3
- package/src/FlinkRequestContext.ts +95 -0
- package/src/FlinkResponse.ts +6 -0
- package/src/FlinkService.ts +49 -0
- package/src/LeaderElection.ts +203 -0
- package/src/SchemaCache.ts +232 -0
- package/src/TypeScriptCompiler.ts +1347 -610
- package/src/TypeScriptUtils.ts +5 -0
- package/src/ai/AgentRunner.ts +646 -0
- package/src/ai/ConversationAgent.ts +413 -0
- package/src/ai/FlinkAgent.ts +1069 -0
- package/src/ai/FlinkTool.ts +165 -0
- package/src/ai/InMemoryConversationAgent.ts +149 -0
- package/src/ai/LLMAdapter.ts +126 -0
- package/src/ai/ToolExecutor.ts +485 -0
- package/src/ai/agentInstructions.ts +245 -0
- package/src/ai/index.ts +8 -0
- package/src/ai/instructionFileLoader.ts +156 -0
- package/src/auth/FlinkAuthPlugin.ts +2 -1
- package/src/handlers/StreamWriterFactory.ts +84 -0
- package/src/index.ts +14 -0
- package/src/loadPluginSchemas.ts +141 -0
- package/src/schema-extraction/TypeScriptSourceParser.ts +1058 -0
- package/src/schema-extraction/TypeScriptTokenizer.ts +205 -0
- package/src/schema-extraction/index.ts +2 -0
- package/src/schema-extraction/types.ts +34 -0
- package/src/utils/loadFlinkConfig.ts +89 -0
- package/src/utils.ts +52 -0
- package/tsconfig.json +6 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { FlinkApp } from "../src/FlinkApp";
|
|
2
|
+
import { FlinkContext } from "../src/FlinkContext";
|
|
3
|
+
import { GetHandler, Handler, HttpMethod } from "../src/FlinkHttpHandler";
|
|
4
|
+
|
|
5
|
+
const request = require("supertest");
|
|
6
|
+
|
|
7
|
+
interface TestContext extends FlinkContext {}
|
|
8
|
+
|
|
9
|
+
describe("HTML response handler (html: true in RouteProps)", () => {
|
|
10
|
+
let app: FlinkApp<TestContext>;
|
|
11
|
+
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
if (app && app.started) {
|
|
14
|
+
await app.stop();
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should return text/html content type", async () => {
|
|
19
|
+
const handler: GetHandler<TestContext, string> = async () => {
|
|
20
|
+
return { data: "<h1>Hello</h1>" };
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
app = new FlinkApp<TestContext>({ name: "test-html-ct", port: 4100 });
|
|
24
|
+
await app.start();
|
|
25
|
+
|
|
26
|
+
app.addHandler({
|
|
27
|
+
default: handler,
|
|
28
|
+
Route: { method: HttpMethod.get, path: "/html", responseType: "html" },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const response = await request(app.expressApp).get("/html");
|
|
32
|
+
|
|
33
|
+
expect(response.status).toBe(200);
|
|
34
|
+
expect(response.headers["content-type"]).toMatch(/text\/html/);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return the raw HTML string as the body, not a JSON envelope", async () => {
|
|
38
|
+
const html = "<!DOCTYPE html><html><body><h1>Hello</h1></body></html>";
|
|
39
|
+
|
|
40
|
+
const handler: GetHandler<TestContext, string> = async () => {
|
|
41
|
+
return { data: html };
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
app = new FlinkApp<TestContext>({ name: "test-html-body", port: 4101 });
|
|
45
|
+
await app.start();
|
|
46
|
+
|
|
47
|
+
app.addHandler({
|
|
48
|
+
default: handler,
|
|
49
|
+
Route: { method: HttpMethod.get, path: "/html", responseType: "html" },
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const response = await request(app.expressApp).get("/html");
|
|
53
|
+
|
|
54
|
+
expect(response.text).toBe(html);
|
|
55
|
+
// Must NOT be a JSON envelope
|
|
56
|
+
expect(response.body).not.toEqual(jasmine.objectContaining({ data: jasmine.anything() }));
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("should respect a custom status code", async () => {
|
|
60
|
+
const handler: GetHandler<TestContext, string> = async () => {
|
|
61
|
+
return { status: 404, data: "<h1>Not Found</h1>" };
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
app = new FlinkApp<TestContext>({ name: "test-html-status", port: 4102 });
|
|
65
|
+
await app.start();
|
|
66
|
+
|
|
67
|
+
app.addHandler({
|
|
68
|
+
default: handler,
|
|
69
|
+
Route: { method: HttpMethod.get, path: "/html", responseType: "html" },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const response = await request(app.expressApp).get("/html");
|
|
73
|
+
|
|
74
|
+
expect(response.status).toBe(404);
|
|
75
|
+
expect(response.text).toBe("<h1>Not Found</h1>");
|
|
76
|
+
expect(response.headers["content-type"]).toMatch(/text\/html/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("should not affect regular JSON handlers on the same app", async () => {
|
|
80
|
+
const jsonHandler: GetHandler<TestContext, any> = async () => {
|
|
81
|
+
return { status: 200, data: { ok: true } };
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const htmlHandler: GetHandler<TestContext, string> = async () => {
|
|
85
|
+
return { data: "<p>HTML</p>" };
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
app = new FlinkApp<TestContext>({ name: "test-html-coexist", port: 4103 });
|
|
89
|
+
await app.start();
|
|
90
|
+
|
|
91
|
+
app.addHandler({
|
|
92
|
+
default: jsonHandler,
|
|
93
|
+
Route: { method: HttpMethod.get, path: "/json" },
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
app.addHandler({
|
|
97
|
+
default: htmlHandler,
|
|
98
|
+
Route: { method: HttpMethod.get, path: "/html", responseType: "html" },
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const jsonRes = await request(app.expressApp).get("/json");
|
|
102
|
+
expect(jsonRes.status).toBe(200);
|
|
103
|
+
expect(jsonRes.headers["content-type"]).toMatch(/application\/json/);
|
|
104
|
+
expect(jsonRes.body.data).toEqual({ ok: true });
|
|
105
|
+
|
|
106
|
+
const htmlRes = await request(app.expressApp).get("/html");
|
|
107
|
+
expect(htmlRes.status).toBe(200);
|
|
108
|
+
expect(htmlRes.headers["content-type"]).toMatch(/text\/html/);
|
|
109
|
+
expect(htmlRes.text).toBe("<p>HTML</p>");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should handle POST html handlers", async () => {
|
|
113
|
+
const handler: Handler<TestContext, { name: string }, string> = async ({ req }) => {
|
|
114
|
+
return { data: `<h1>Hello ${req.body.name}</h1>` };
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
app = new FlinkApp<TestContext>({ name: "test-html-post", port: 4104 });
|
|
118
|
+
await app.start();
|
|
119
|
+
|
|
120
|
+
app.addHandler({
|
|
121
|
+
default: handler,
|
|
122
|
+
Route: { method: HttpMethod.post, path: "/html", responseType: "html" },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const response = await request(app.expressApp).post("/html").send({ name: "World" });
|
|
126
|
+
|
|
127
|
+
expect(response.status).toBe(200);
|
|
128
|
+
expect(response.headers["content-type"]).toMatch(/text\/html/);
|
|
129
|
+
expect(response.text).toBe("<h1>Hello World</h1>");
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe("Binary Buffer response handler (responseType: image/png)", () => {
|
|
134
|
+
let app: FlinkApp<TestContext>;
|
|
135
|
+
|
|
136
|
+
afterEach(async () => {
|
|
137
|
+
if (app && app.started) {
|
|
138
|
+
await app.stop();
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should return image/png content type for Buffer response", async () => {
|
|
143
|
+
// Minimal valid 1x1 red PNG (67 bytes)
|
|
144
|
+
const pngBuffer = Buffer.from(
|
|
145
|
+
"89504e470d0a1a0a0000000d49484452000000010000000108020000009001" +
|
|
146
|
+
"2e00000000c4944415478016360f8cfc00000000200016934e360000000049454e44ae426082",
|
|
147
|
+
"hex"
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const handler: GetHandler<TestContext, Buffer> = async () => {
|
|
151
|
+
return { data: pngBuffer };
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
app = new FlinkApp<TestContext>({ name: "test-png-ct", port: 4110 });
|
|
155
|
+
await app.start();
|
|
156
|
+
|
|
157
|
+
app.addHandler({
|
|
158
|
+
default: handler,
|
|
159
|
+
Route: { method: HttpMethod.get, path: "/image", responseType: "image/png" },
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const response = await request(app.expressApp).get("/image");
|
|
163
|
+
|
|
164
|
+
expect(response.status).toBe(200);
|
|
165
|
+
expect(response.headers["content-type"]).toMatch(/image\/png/);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it("should return the exact buffer bytes as the response body", async () => {
|
|
169
|
+
const pngBuffer = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
170
|
+
|
|
171
|
+
const handler: GetHandler<TestContext, Buffer> = async () => {
|
|
172
|
+
return { data: pngBuffer };
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
app = new FlinkApp<TestContext>({ name: "test-png-body", port: 4111 });
|
|
176
|
+
await app.start();
|
|
177
|
+
|
|
178
|
+
app.addHandler({
|
|
179
|
+
default: handler,
|
|
180
|
+
Route: { method: HttpMethod.get, path: "/image", responseType: "image/png" },
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const response = await request(app.expressApp)
|
|
184
|
+
.get("/image")
|
|
185
|
+
.buffer(true)
|
|
186
|
+
.parse((res: any, callback: any) => {
|
|
187
|
+
const chunks: Buffer[] = [];
|
|
188
|
+
res.on("data", (chunk: Buffer) => chunks.push(chunk));
|
|
189
|
+
res.on("end", () => callback(null, Buffer.concat(chunks)));
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
expect(response.status).toBe(200);
|
|
193
|
+
expect(Buffer.compare(response.body, pngBuffer)).toBe(0);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it("should respect a custom status code for binary responses", async () => {
|
|
197
|
+
const handler: GetHandler<TestContext, Buffer> = async () => {
|
|
198
|
+
return { status: 404, data: Buffer.from("not found") };
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
app = new FlinkApp<TestContext>({ name: "test-png-status", port: 4112 });
|
|
202
|
+
await app.start();
|
|
203
|
+
|
|
204
|
+
app.addHandler({
|
|
205
|
+
default: handler,
|
|
206
|
+
Route: { method: HttpMethod.get, path: "/image", responseType: "image/png" },
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const response = await request(app.expressApp).get("/image");
|
|
210
|
+
|
|
211
|
+
expect(response.status).toBe(404);
|
|
212
|
+
expect(response.headers["content-type"]).toMatch(/image\/png/);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("should support image/jpeg content type", async () => {
|
|
216
|
+
const jpegBuffer = Buffer.from([0xff, 0xd8, 0xff, 0xe0]);
|
|
217
|
+
|
|
218
|
+
const handler: GetHandler<TestContext, Buffer> = async () => {
|
|
219
|
+
return { data: jpegBuffer };
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
app = new FlinkApp<TestContext>({ name: "test-jpeg-ct", port: 4113 });
|
|
223
|
+
await app.start();
|
|
224
|
+
|
|
225
|
+
app.addHandler({
|
|
226
|
+
default: handler,
|
|
227
|
+
Route: { method: HttpMethod.get, path: "/photo", responseType: "image/jpeg" },
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const response = await request(app.expressApp).get("/photo");
|
|
231
|
+
|
|
232
|
+
expect(response.status).toBe(200);
|
|
233
|
+
expect(response.headers["content-type"]).toMatch(/image\/jpeg/);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should support application/octet-stream for generic binary data", async () => {
|
|
237
|
+
const binaryData = Buffer.from([0x00, 0x01, 0x02, 0x03, 0xff]);
|
|
238
|
+
|
|
239
|
+
const handler: GetHandler<TestContext, Buffer> = async () => {
|
|
240
|
+
return { data: binaryData };
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
app = new FlinkApp<TestContext>({ name: "test-octet", port: 4114 });
|
|
244
|
+
await app.start();
|
|
245
|
+
|
|
246
|
+
app.addHandler({
|
|
247
|
+
default: handler,
|
|
248
|
+
Route: {
|
|
249
|
+
method: HttpMethod.get,
|
|
250
|
+
path: "/binary",
|
|
251
|
+
responseType: "application/octet-stream",
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const response = await request(app.expressApp).get("/binary");
|
|
256
|
+
|
|
257
|
+
expect(response.status).toBe(200);
|
|
258
|
+
expect(response.headers["content-type"]).toMatch(/application\/octet-stream/);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { FlinkApp } from "../src/FlinkApp";
|
|
2
|
+
import { FlinkContext } from "../src/FlinkContext";
|
|
3
|
+
import { FlinkError } from "../src/FlinkErrors";
|
|
4
|
+
import { GetHandler, Handler, HttpMethod } from "../src/FlinkHttpHandler";
|
|
5
|
+
import { FlinkResponse } from "../src/FlinkResponse";
|
|
6
|
+
|
|
7
|
+
const request = require("supertest");
|
|
8
|
+
|
|
9
|
+
interface TestContext extends FlinkContext {}
|
|
10
|
+
|
|
11
|
+
const reqSchema = {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
name: { type: "string" },
|
|
15
|
+
},
|
|
16
|
+
required: ["name"],
|
|
17
|
+
additionalProperties: false,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const resSchema = {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
id: { type: "string" },
|
|
24
|
+
},
|
|
25
|
+
required: ["id"],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("FlinkApp onError invocation", () => {
|
|
29
|
+
let app: FlinkApp<TestContext>;
|
|
30
|
+
let calls: { error: FlinkResponse<FlinkError>; context: any }[];
|
|
31
|
+
|
|
32
|
+
const onError = (error: FlinkResponse<FlinkError>, context: any) => {
|
|
33
|
+
calls.push({ error, context });
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
calls = [];
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
afterEach(async () => {
|
|
41
|
+
if (app && app.started) {
|
|
42
|
+
await app.stop();
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should invoke onError for request validation 400s", async () => {
|
|
47
|
+
const handler: Handler<TestContext, any, any> = async () => {
|
|
48
|
+
return { data: { id: "ok" } };
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
app = new FlinkApp<TestContext>({ name: "test-onerror-req", port: 4210, onError });
|
|
52
|
+
await app.start();
|
|
53
|
+
|
|
54
|
+
app.addHandler({
|
|
55
|
+
default: handler,
|
|
56
|
+
Route: { method: HttpMethod.post, path: "/test", reqSchema },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const response = await request(app.expressApp).post("/test").send({ wrong: "field" });
|
|
60
|
+
|
|
61
|
+
expect(response.status).toBe(400);
|
|
62
|
+
expect(calls.length).toBe(1);
|
|
63
|
+
expect(calls[0].error.status).toBe(400);
|
|
64
|
+
expect(calls[0].error.error?.title).toBe("Bad request");
|
|
65
|
+
expect(calls[0].context.method).toBe(HttpMethod.post);
|
|
66
|
+
expect(calls[0].context.path).toBe("/test");
|
|
67
|
+
expect(calls[0].context.reqId).toBeDefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should invoke onError for response validation 500s (invalid shape)", async () => {
|
|
71
|
+
const handler: GetHandler<TestContext, any> = async () => {
|
|
72
|
+
return { data: { wrongField: 123 } }; // missing required "id"
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
app = new FlinkApp<TestContext>({ name: "test-onerror-res", port: 4211, onError });
|
|
76
|
+
await app.start();
|
|
77
|
+
|
|
78
|
+
app.addHandler({
|
|
79
|
+
default: handler,
|
|
80
|
+
Route: { method: HttpMethod.get, path: "/test", resSchema },
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const response = await request(app.expressApp).get("/test");
|
|
84
|
+
|
|
85
|
+
expect(response.status).toBe(500);
|
|
86
|
+
expect(calls.length).toBe(1);
|
|
87
|
+
expect(calls[0].error.status).toBe(500);
|
|
88
|
+
expect(calls[0].error.error?.title).toBe("Bad response");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should invoke onError for response validation 500s (no data)", async () => {
|
|
92
|
+
const handler: GetHandler<TestContext, any> = async () => {
|
|
93
|
+
return { status: 200 } as any; // no data
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
app = new FlinkApp<TestContext>({ name: "test-onerror-nodata", port: 4212, onError });
|
|
97
|
+
await app.start();
|
|
98
|
+
|
|
99
|
+
app.addHandler({
|
|
100
|
+
default: handler,
|
|
101
|
+
Route: { method: HttpMethod.get, path: "/test", resSchema },
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const response = await request(app.expressApp).get("/test");
|
|
105
|
+
|
|
106
|
+
expect(response.status).toBe(500);
|
|
107
|
+
expect(calls.length).toBe(1);
|
|
108
|
+
expect(calls[0].error.status).toBe(500);
|
|
109
|
+
expect(calls[0].error.error?.title).toBe("Bad response");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should still invoke onError for handler-thrown errors", async () => {
|
|
113
|
+
const handler: GetHandler<TestContext, any> = async () => {
|
|
114
|
+
throw new Error("boom");
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
app = new FlinkApp<TestContext>({ name: "test-onerror-throw", port: 4213, onError });
|
|
118
|
+
await app.start();
|
|
119
|
+
|
|
120
|
+
app.addHandler({
|
|
121
|
+
default: handler,
|
|
122
|
+
Route: { method: HttpMethod.get, path: "/test" },
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const response = await request(app.expressApp).get("/test");
|
|
126
|
+
|
|
127
|
+
expect(response.status).toBe(500);
|
|
128
|
+
expect(calls.length).toBe(1);
|
|
129
|
+
expect(calls[0].error.status).toBe(500);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should pass the app context (ctx) to the callback", async () => {
|
|
133
|
+
const handler: GetHandler<TestContext, any> = async () => {
|
|
134
|
+
throw new Error("boom");
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
app = new FlinkApp<TestContext>({ name: "test-onerror-ctx", port: 4214, onError });
|
|
138
|
+
await app.start();
|
|
139
|
+
|
|
140
|
+
app.addHandler({
|
|
141
|
+
default: handler,
|
|
142
|
+
Route: { method: HttpMethod.get, path: "/test" },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await request(app.expressApp).get("/test");
|
|
146
|
+
|
|
147
|
+
expect(calls.length).toBe(1);
|
|
148
|
+
expect(calls[0].context.ctx).toBeDefined();
|
|
149
|
+
expect(calls[0].context.ctx).toBe(app.ctx);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { FlinkApp } from "../src/FlinkApp";
|
|
2
2
|
import { FlinkContext } from "../src/FlinkContext";
|
|
3
|
-
import { FlinkResponse } from "../src/FlinkResponse";
|
|
4
3
|
import { FlinkError } from "../src/FlinkErrors";
|
|
5
|
-
import { badRequest, internalServerError, notFound } from "../src/FlinkErrors";
|
|
6
4
|
import { HttpMethod } from "../src/FlinkHttpHandler";
|
|
5
|
+
import { FlinkResponse } from "../src/FlinkResponse";
|
|
7
6
|
|
|
8
7
|
interface TestContext extends FlinkContext {}
|
|
9
8
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { FlinkApp } from "../src/FlinkApp";
|
|
2
|
+
import { FlinkContext } from "../src/FlinkContext";
|
|
3
|
+
import { GetHandler, HttpMethod } from "../src/FlinkHttpHandler";
|
|
4
|
+
|
|
5
|
+
const request = require("supertest");
|
|
6
|
+
|
|
7
|
+
interface TestContext extends FlinkContext {}
|
|
8
|
+
|
|
9
|
+
describe("Query parameter normalization", () => {
|
|
10
|
+
let app: FlinkApp<TestContext>;
|
|
11
|
+
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
if (app && app.started) {
|
|
14
|
+
await app.stop();
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should normalize query params to strings", async () => {
|
|
19
|
+
const handler: GetHandler<TestContext, any> = async ({ req }) => {
|
|
20
|
+
return { status: 200, data: { query: req.query } };
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
app = new FlinkApp<TestContext>({ name: "test-query-norm", port: 4000 });
|
|
24
|
+
await app.start();
|
|
25
|
+
|
|
26
|
+
app.addHandler({
|
|
27
|
+
default: handler,
|
|
28
|
+
Route: { method: HttpMethod.get, path: "/test" },
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const response = await request(app.expressApp).get("/test?name=John&age=25");
|
|
32
|
+
|
|
33
|
+
expect(response.status).toBe(200);
|
|
34
|
+
expect(response.body.data.query.name).toBe("John");
|
|
35
|
+
expect(response.body.data.query.age).toBe("25");
|
|
36
|
+
expect(typeof response.body.data.query.name).toBe("string");
|
|
37
|
+
expect(typeof response.body.data.query.age).toBe("string");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it("should normalize array query params to string arrays", async () => {
|
|
41
|
+
const handler: GetHandler<TestContext, any> = async ({ req }) => {
|
|
42
|
+
return { status: 200, data: { query: req.query } };
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
app = new FlinkApp<TestContext>({ name: "test-query-array", port: 4001 });
|
|
46
|
+
await app.start();
|
|
47
|
+
|
|
48
|
+
app.addHandler({
|
|
49
|
+
default: handler,
|
|
50
|
+
Route: { method: HttpMethod.get, path: "/test-array" },
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const response = await request(app.expressApp).get("/test-array?tag=a&tag=b&tag=c");
|
|
54
|
+
|
|
55
|
+
expect(response.status).toBe(200);
|
|
56
|
+
expect(Array.isArray(response.body.data.query.tag)).toBe(true);
|
|
57
|
+
expect(response.body.data.query.tag).toEqual(["a", "b", "c"]);
|
|
58
|
+
response.body.data.query.tag.forEach((tag: string) => {
|
|
59
|
+
expect(typeof tag).toBe("string");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should normalize numeric values to strings", async () => {
|
|
64
|
+
const handler: GetHandler<TestContext, any> = async ({ req }) => {
|
|
65
|
+
return { status: 200, data: { query: req.query } };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
app = new FlinkApp<TestContext>({ name: "test-query-numbers", port: 4002 });
|
|
69
|
+
await app.start();
|
|
70
|
+
|
|
71
|
+
app.addHandler({
|
|
72
|
+
default: handler,
|
|
73
|
+
Route: { method: HttpMethod.get, path: "/test-numbers" },
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const response = await request(app.expressApp).get("/test-numbers?count=100&price=99.99");
|
|
77
|
+
|
|
78
|
+
expect(response.status).toBe(200);
|
|
79
|
+
expect(response.body.data.query.count).toBe("100");
|
|
80
|
+
expect(response.body.data.query.price).toBe("99.99");
|
|
81
|
+
expect(typeof response.body.data.query.count).toBe("string");
|
|
82
|
+
expect(typeof response.body.data.query.price).toBe("string");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should allow handlers to parse strings as needed", async () => {
|
|
86
|
+
const handler: GetHandler<TestContext, any> = async ({ req }) => {
|
|
87
|
+
const page = Number(req.query.page) || 1;
|
|
88
|
+
const active = req.query.active === "true";
|
|
89
|
+
|
|
90
|
+
return { status: 200, data: { page, active } };
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
app = new FlinkApp<TestContext>({ name: "test-query-parsing", port: 4003 });
|
|
94
|
+
await app.start();
|
|
95
|
+
|
|
96
|
+
app.addHandler({
|
|
97
|
+
default: handler,
|
|
98
|
+
Route: { method: HttpMethod.get, path: "/test-parsing" },
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const response = await request(app.expressApp).get("/test-parsing?page=2&active=true");
|
|
102
|
+
|
|
103
|
+
expect(response.status).toBe(200);
|
|
104
|
+
expect(response.body.data.page).toBe(2);
|
|
105
|
+
expect(response.body.data.active).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { FlinkApp, autoRegisteredHandlers } from "../src/FlinkApp";
|
|
2
|
+
import { FlinkContext } from "../src/FlinkContext";
|
|
3
|
+
import { GetHandler, HttpMethod } from "../src/FlinkHttpHandler";
|
|
4
|
+
|
|
5
|
+
const request = require("supertest");
|
|
6
|
+
|
|
7
|
+
interface TestContext extends FlinkContext {}
|
|
8
|
+
|
|
9
|
+
describe("Route ordering", () => {
|
|
10
|
+
let app: FlinkApp<TestContext>;
|
|
11
|
+
|
|
12
|
+
afterEach(async () => {
|
|
13
|
+
// Clean up auto-registered handlers between tests
|
|
14
|
+
autoRegisteredHandlers.length = 0;
|
|
15
|
+
|
|
16
|
+
if (app && app.started) {
|
|
17
|
+
await app.stop();
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("should match static segment before parameterized segment when parameterized handler is registered first", async () => {
|
|
22
|
+
const byTagsHandler: GetHandler<TestContext, any> = async () => {
|
|
23
|
+
return { status: 200, data: { route: "by-tags" } };
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const byIdHandler: GetHandler<TestContext, any> = async ({ req }) => {
|
|
27
|
+
return { status: 200, data: { route: "by-id", id: req.params.id } };
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Register parameterized route first (simulates bad file discovery order)
|
|
31
|
+
autoRegisteredHandlers.push({
|
|
32
|
+
handler: {
|
|
33
|
+
default: byIdHandler,
|
|
34
|
+
Route: { method: HttpMethod.get, path: "/jobs/:id" },
|
|
35
|
+
},
|
|
36
|
+
assumedHttpMethod: HttpMethod.get,
|
|
37
|
+
__file: "GetJobById.ts",
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
autoRegisteredHandlers.push({
|
|
41
|
+
handler: {
|
|
42
|
+
default: byTagsHandler,
|
|
43
|
+
Route: { method: HttpMethod.get, path: "/jobs/by-tags" },
|
|
44
|
+
},
|
|
45
|
+
assumedHttpMethod: HttpMethod.get,
|
|
46
|
+
__file: "GetJobsByTags.ts",
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
app = new FlinkApp<TestContext>({ name: "test-route-order", port: 4050 });
|
|
50
|
+
await app.start();
|
|
51
|
+
|
|
52
|
+
const byTagsRes = await request(app.expressApp).get("/jobs/by-tags");
|
|
53
|
+
expect(byTagsRes.status).toBe(200);
|
|
54
|
+
expect(byTagsRes.body.data.route).toBe("by-tags");
|
|
55
|
+
|
|
56
|
+
const byIdRes = await request(app.expressApp).get("/jobs/abc123");
|
|
57
|
+
expect(byIdRes.status).toBe(200);
|
|
58
|
+
expect(byIdRes.body.data.route).toBe("by-id");
|
|
59
|
+
expect(byIdRes.body.data.id).toBe("abc123");
|
|
60
|
+
});
|
|
61
|
+
});
|