adorn-api 1.1.11 → 1.1.13
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/README.md +18 -0
- package/dist/adapter/express/types.d.ts +3 -46
- package/dist/adapter/fastify/coercion.d.ts +12 -0
- package/dist/adapter/fastify/coercion.js +289 -0
- package/dist/adapter/fastify/controllers.d.ts +7 -0
- package/dist/adapter/fastify/controllers.js +201 -0
- package/dist/adapter/fastify/index.d.ts +14 -0
- package/dist/adapter/fastify/index.js +67 -0
- package/dist/adapter/fastify/multipart.d.ts +26 -0
- package/dist/adapter/fastify/multipart.js +75 -0
- package/dist/adapter/fastify/openapi.d.ts +10 -0
- package/dist/adapter/fastify/openapi.js +76 -0
- package/dist/adapter/fastify/response-serializer.d.ts +2 -0
- package/dist/adapter/fastify/response-serializer.js +162 -0
- package/dist/adapter/fastify/types.d.ts +100 -0
- package/dist/adapter/fastify/types.js +2 -0
- package/dist/adapter/metal-orm/index.d.ts +1 -1
- package/dist/adapter/metal-orm/types.d.ts +23 -0
- package/dist/adapter/native/coercion.d.ts +12 -0
- package/dist/adapter/native/coercion.js +289 -0
- package/dist/adapter/native/controllers.d.ts +17 -0
- package/dist/adapter/native/controllers.js +215 -0
- package/dist/adapter/native/index.d.ts +14 -0
- package/dist/adapter/native/index.js +127 -0
- package/dist/adapter/native/openapi.d.ts +7 -0
- package/dist/adapter/native/openapi.js +82 -0
- package/dist/adapter/native/response-serializer.d.ts +5 -0
- package/dist/adapter/native/response-serializer.js +160 -0
- package/dist/adapter/native/router.d.ts +25 -0
- package/dist/adapter/native/router.js +68 -0
- package/dist/adapter/native/types.d.ts +77 -0
- package/dist/adapter/native/types.js +2 -0
- package/dist/core/auth.d.ts +11 -12
- package/dist/core/auth.js +2 -2
- package/dist/core/logger.d.ts +3 -4
- package/dist/core/logger.js +2 -2
- package/dist/core/streaming.d.ts +10 -10
- package/dist/core/streaming.js +31 -19
- package/dist/core/types.d.ts +102 -0
- package/dist/index.d.ts +6 -1
- package/dist/index.js +16 -1
- package/examples/fastify/app.ts +16 -0
- package/examples/fastify/index.ts +21 -0
- package/package.json +24 -18
- package/src/adapter/express/controllers.ts +249 -249
- package/src/adapter/express/types.ts +121 -160
- package/src/adapter/fastify/coercion.ts +369 -0
- package/src/adapter/fastify/controllers.ts +255 -0
- package/src/adapter/fastify/index.ts +53 -0
- package/src/adapter/fastify/multipart.ts +94 -0
- package/src/adapter/fastify/openapi.ts +93 -0
- package/src/adapter/fastify/response-serializer.ts +179 -0
- package/src/adapter/fastify/types.ts +119 -0
- package/src/adapter/metal-orm/index.ts +3 -0
- package/src/adapter/metal-orm/types.ts +25 -0
- package/src/adapter/native/coercion.ts +369 -0
- package/src/adapter/native/controllers.ts +271 -0
- package/src/adapter/native/index.ts +116 -0
- package/src/adapter/native/openapi.ts +109 -0
- package/src/adapter/native/response-serializer.ts +177 -0
- package/src/adapter/native/router.ts +90 -0
- package/src/adapter/native/types.ts +96 -0
- package/src/core/auth.ts +314 -315
- package/src/core/health.ts +234 -235
- package/src/core/logger.ts +245 -247
- package/src/core/streaming.ts +342 -330
- package/src/core/types.ts +115 -0
- package/src/index.ts +46 -16
- package/tests/e2e/fastify.e2e.test.ts +174 -0
- package/tests/native.test.ts +191 -0
- package/tests/typecheck/query-params.typecheck.ts +42 -0
- package/tests/unit/openapi-parameters.test.ts +97 -97
- package/tsconfig.json +14 -13
- package/tsconfig.typecheck.json +8 -0
- package/vitest.config.ts +47 -7
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
import { describe, expect, it, beforeEach } from "vitest";
|
|
2
|
-
import { t } from "../../src/core/schema";
|
|
3
|
-
import { registerController
|
|
4
|
-
import { buildOpenApi } from "../../src/core/openapi";
|
|
5
|
-
import { createInputCoercer } from "../../src/adapter/express/coercion";
|
|
6
|
-
|
|
7
|
-
describe("OpenAPI query parameter serialization", () => {
|
|
8
|
-
class QueryArrayController {}
|
|
9
|
-
|
|
10
|
-
beforeEach(() => {
|
|
11
|
-
registerController({
|
|
12
|
-
basePath: "/items",
|
|
13
|
-
controller: QueryArrayController,
|
|
14
|
-
routes: [
|
|
15
|
-
{
|
|
16
|
-
httpMethod: "get",
|
|
17
|
-
path: "/",
|
|
18
|
-
handlerName: "list",
|
|
19
|
-
query: {
|
|
20
|
-
schema: {
|
|
21
|
-
kind: "object",
|
|
22
|
-
properties: {
|
|
23
|
-
ids: t.array(t.string()),
|
|
24
|
-
nums: t.array(t.integer()),
|
|
25
|
-
tags: t.array(t.string(), { examples: [["a", "b"]] })
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
},
|
|
29
|
-
responses: [{ status: 200 }]
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
});
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("query array<string> generates style=form + explode=true", () => {
|
|
36
|
-
const doc = buildOpenApi({
|
|
37
|
-
info: { title: "test", version: "1.0.0" },
|
|
38
|
-
controllers: [QueryArrayController]
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
42
|
-
const idsParam = params.find((p: any) => p.name === "ids");
|
|
43
|
-
|
|
44
|
-
expect(idsParam).toBeDefined();
|
|
45
|
-
expect(idsParam.style).toBe("form");
|
|
46
|
-
expect(idsParam.explode).toBe(true);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it("query array<integer> generates style=form + explode=true", () => {
|
|
50
|
-
const doc = buildOpenApi({
|
|
51
|
-
info: { title: "test", version: "1.0.0" },
|
|
52
|
-
controllers: [QueryArrayController]
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
56
|
-
const numsParam = params.find((p: any) => p.name === "nums");
|
|
57
|
-
|
|
58
|
-
expect(numsParam).toBeDefined();
|
|
59
|
-
expect(numsParam.style).toBe("form");
|
|
60
|
-
expect(numsParam.explode).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it("projects example from schema.examples to parameter.example", () => {
|
|
64
|
-
const doc = buildOpenApi({
|
|
65
|
-
info: { title: "test", version: "1.0.0" },
|
|
66
|
-
controllers: [QueryArrayController]
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
70
|
-
const tagsParam = params.find((p: any) => p.name === "tags");
|
|
71
|
-
|
|
72
|
-
expect(tagsParam).toBeDefined();
|
|
73
|
-
expect(tagsParam.example).toEqual(["a", "b"]);
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe("Query array coercion – CSV support", () => {
|
|
78
|
-
it("?ids=1&ids=2 -> [1,2] via repeated keys", () => {
|
|
79
|
-
const coerce = createInputCoercer(
|
|
80
|
-
{ schema: { kind: "object", properties: { ids: t.array(t.integer()) } } },
|
|
81
|
-
{ mode: "safe", location: "query" }
|
|
82
|
-
)!;
|
|
83
|
-
|
|
84
|
-
const result = coerce({ ids: ["1", "2"] });
|
|
85
|
-
expect(result.ids).toEqual([1, 2]);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it("?ids=1,2 -> [1,2] via CSV string", () => {
|
|
89
|
-
const coerce = createInputCoercer(
|
|
90
|
-
{ schema: { kind: "object", properties: { ids: t.array(t.integer()) } } },
|
|
91
|
-
{ mode: "safe", location: "query" }
|
|
92
|
-
)!;
|
|
93
|
-
|
|
94
|
-
const result = coerce({ ids: "1,2" });
|
|
95
|
-
expect(result.ids).toEqual([1, 2]);
|
|
96
|
-
});
|
|
97
|
-
});
|
|
1
|
+
import { describe, expect, it, beforeEach } from "vitest";
|
|
2
|
+
import { t } from "../../src/core/schema";
|
|
3
|
+
import { registerController } from "../../src/core/metadata";
|
|
4
|
+
import { buildOpenApi } from "../../src/core/openapi";
|
|
5
|
+
import { createInputCoercer } from "../../src/adapter/express/coercion";
|
|
6
|
+
|
|
7
|
+
describe("OpenAPI query parameter serialization", () => {
|
|
8
|
+
class QueryArrayController {}
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
registerController({
|
|
12
|
+
basePath: "/items",
|
|
13
|
+
controller: QueryArrayController,
|
|
14
|
+
routes: [
|
|
15
|
+
{
|
|
16
|
+
httpMethod: "get",
|
|
17
|
+
path: "/",
|
|
18
|
+
handlerName: "list",
|
|
19
|
+
query: {
|
|
20
|
+
schema: {
|
|
21
|
+
kind: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
ids: t.array(t.string()),
|
|
24
|
+
nums: t.array(t.integer()),
|
|
25
|
+
tags: t.array(t.string(), { examples: [["a", "b"]] })
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
responses: [{ status: 200 }]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("query array<string> generates style=form + explode=true", () => {
|
|
36
|
+
const doc = buildOpenApi({
|
|
37
|
+
info: { title: "test", version: "1.0.0" },
|
|
38
|
+
controllers: [QueryArrayController]
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
42
|
+
const idsParam = params.find((p: any) => p.name === "ids");
|
|
43
|
+
|
|
44
|
+
expect(idsParam).toBeDefined();
|
|
45
|
+
expect(idsParam.style).toBe("form");
|
|
46
|
+
expect(idsParam.explode).toBe(true);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("query array<integer> generates style=form + explode=true", () => {
|
|
50
|
+
const doc = buildOpenApi({
|
|
51
|
+
info: { title: "test", version: "1.0.0" },
|
|
52
|
+
controllers: [QueryArrayController]
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
56
|
+
const numsParam = params.find((p: any) => p.name === "nums");
|
|
57
|
+
|
|
58
|
+
expect(numsParam).toBeDefined();
|
|
59
|
+
expect(numsParam.style).toBe("form");
|
|
60
|
+
expect(numsParam.explode).toBe(true);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("projects example from schema.examples to parameter.example", () => {
|
|
64
|
+
const doc = buildOpenApi({
|
|
65
|
+
info: { title: "test", version: "1.0.0" },
|
|
66
|
+
controllers: [QueryArrayController]
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const params = (doc.paths["/items"] as any).get.parameters as any[];
|
|
70
|
+
const tagsParam = params.find((p: any) => p.name === "tags");
|
|
71
|
+
|
|
72
|
+
expect(tagsParam).toBeDefined();
|
|
73
|
+
expect(tagsParam.example).toEqual(["a", "b"]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("Query array coercion – CSV support", () => {
|
|
78
|
+
it("?ids=1&ids=2 -> [1,2] via repeated keys", () => {
|
|
79
|
+
const coerce = createInputCoercer(
|
|
80
|
+
{ schema: { kind: "object", properties: { ids: t.array(t.integer()) } } },
|
|
81
|
+
{ mode: "safe", location: "query" }
|
|
82
|
+
)!;
|
|
83
|
+
|
|
84
|
+
const result = coerce({ ids: ["1", "2"] });
|
|
85
|
+
expect(result.ids).toEqual([1, 2]);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("?ids=1,2 -> [1,2] via CSV string", () => {
|
|
89
|
+
const coerce = createInputCoercer(
|
|
90
|
+
{ schema: { kind: "object", properties: { ids: t.array(t.integer()) } } },
|
|
91
|
+
{ mode: "safe", location: "query" }
|
|
92
|
+
)!;
|
|
93
|
+
|
|
94
|
+
const result = coerce({ ids: "1,2" });
|
|
95
|
+
expect(result.ids).toEqual([1, 2]);
|
|
96
|
+
});
|
|
97
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2022",
|
|
4
4
|
"module": "CommonJS",
|
|
5
5
|
"moduleResolution": "Node",
|
|
6
|
+
"ignoreDeprecations": "6.0",
|
|
6
7
|
"rootDir": "src",
|
|
7
|
-
"outDir": "dist",
|
|
8
|
-
"declaration": true,
|
|
9
|
-
"strict": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"esModuleInterop": true,
|
|
13
|
-
"useDefineForClassFields": true,
|
|
14
|
-
"experimentalDecorators": false,
|
|
15
|
-
"emitDecoratorMetadata": false
|
|
16
|
-
},
|
|
17
|
-
"include": ["src"]
|
|
18
|
-
}
|
|
8
|
+
"outDir": "dist",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"forceConsistentCasingInFileNames": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"useDefineForClassFields": true,
|
|
15
|
+
"experimentalDecorators": false,
|
|
16
|
+
"emitDecoratorMetadata": false
|
|
17
|
+
},
|
|
18
|
+
"include": ["src"]
|
|
19
|
+
}
|
package/vitest.config.ts
CHANGED
|
@@ -1,14 +1,54 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import * as ts from "typescript";
|
|
1
4
|
import { defineConfig } from "vitest/config";
|
|
2
5
|
|
|
6
|
+
function transpileSourcePlugin() {
|
|
7
|
+
return {
|
|
8
|
+
name: "transpile-source",
|
|
9
|
+
enforce: "pre",
|
|
10
|
+
load(id: string) {
|
|
11
|
+
const cleanId = id.split(/[?#]/)[0];
|
|
12
|
+
const normalizedId = cleanId.split(path.sep).join("/");
|
|
13
|
+
if (
|
|
14
|
+
!normalizedId.includes("/src/") &&
|
|
15
|
+
!normalizedId.includes("/examples/") &&
|
|
16
|
+
!normalizedId.includes("/tests/")
|
|
17
|
+
) {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
if (!normalizedId.endsWith(".ts") && !normalizedId.endsWith(".tsx")) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const code = fs.readFileSync(cleanId, "utf8");
|
|
25
|
+
const result = ts.transpileModule(code, {
|
|
26
|
+
compilerOptions: {
|
|
27
|
+
target: ts.ScriptTarget.ES2022,
|
|
28
|
+
module: ts.ModuleKind.ESNext,
|
|
29
|
+
moduleResolution: ts.ModuleResolutionKind.Node,
|
|
30
|
+
experimentalDecorators: false,
|
|
31
|
+
emitDecoratorMetadata: false,
|
|
32
|
+
useDefineForClassFields: true,
|
|
33
|
+
esModuleInterop: true,
|
|
34
|
+
sourceMap: true
|
|
35
|
+
},
|
|
36
|
+
fileName: cleanId
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
code: result.outputText,
|
|
41
|
+
map: result.sourceMapText ? JSON.parse(result.sourceMapText) : undefined
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
3
47
|
export default defineConfig({
|
|
48
|
+
plugins: [transpileSourcePlugin()],
|
|
4
49
|
test: {
|
|
5
50
|
environment: "node",
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
poolOptions: {
|
|
9
|
-
forks: {
|
|
10
|
-
singleFork: true
|
|
11
|
-
}
|
|
12
|
-
}
|
|
51
|
+
pool: "threads",
|
|
52
|
+
include: ["src/**/*.test.ts", "tests/**/*.test.ts"]
|
|
13
53
|
}
|
|
14
54
|
});
|