typespec-hono 0.1.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/LICENSE +21 -0
- package/README.md +333 -0
- package/dist/src/app.d.ts +61 -0
- package/dist/src/app.js +609 -0
- package/dist/src/base-path.d.ts +16 -0
- package/dist/src/base-path.js +47 -0
- package/dist/src/emitter.d.ts +24 -0
- package/dist/src/emitter.js +108 -0
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +12 -0
- package/dist/src/lib.d.ts +71 -0
- package/dist/src/lib.js +123 -0
- package/dist/src/runtime.d.ts +174 -0
- package/dist/src/runtime.js +63 -0
- package/dist/src/security.d.ts +29 -0
- package/dist/src/security.js +48 -0
- package/dist/src/tsp-index.d.ts +9 -0
- package/dist/src/tsp-index.js +9 -0
- package/lib/main.tsp +3 -0
- package/package.json +90 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type HttpOperation } from "@typespec/http";
|
|
2
|
+
import type { Program } from "@typespec/compiler";
|
|
3
|
+
import type { SecurityRequirement } from "./runtime.js";
|
|
4
|
+
/**
|
|
5
|
+
* What the DOCUMENT says a caller must satisfy, in the shape the document says it.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ **The scheme was being thrown away, and only "is a caller needed" survived.** `@useAuth(BearerAuth)`
|
|
8
|
+
* reaches OpenAPI as `security: [{ "BearerAuth": [] }]`, and this emitter reduced that to
|
|
9
|
+
* `deps.context(c, "required")`. A gate was emitted ONLY when the scheme carried scopes — so for
|
|
10
|
+
* bearer, api-key and basic, which is the common case, nothing carried which scheme at all. An
|
|
11
|
+
* application whose `context` read a cookie would happily serve a route the document says needs a
|
|
12
|
+
* bearer token, and nothing anywhere would notice.
|
|
13
|
+
*
|
|
14
|
+
* ⚠️ **Passed through, never enforced here.** Which credentials satisfy a scheme is the application's
|
|
15
|
+
* business and could not be anything else; which schemes an operation ACCEPTS is a contract fact and
|
|
16
|
+
* is now generated. That is the same split as `context` and `respond`, applied to the half that was
|
|
17
|
+
* missing.
|
|
18
|
+
*/
|
|
19
|
+
export type { SecurityRequirement } from "./runtime.js";
|
|
20
|
+
/**
|
|
21
|
+
* The requirements an operation declares. Satisfying **any one** of them authorises the caller —
|
|
22
|
+
* which is what an array of `security` objects means in OpenAPI, and why this is a list of lists
|
|
23
|
+
* rather than a flat set of scopes.
|
|
24
|
+
*
|
|
25
|
+
* Empty when the operation declares `@useAuth(NoAuth)` or no authentication at all.
|
|
26
|
+
*/
|
|
27
|
+
export declare function securityFor(program: Program, operation: HttpOperation): SecurityRequirement[];
|
|
28
|
+
/** The requirements as a TypeScript literal, for the generated call site. */
|
|
29
|
+
export declare function renderSecurity(requirements: readonly SecurityRequirement[]): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { getAuthenticationForOperation } from "@typespec/http";
|
|
2
|
+
/**
|
|
3
|
+
* The requirements an operation declares. Satisfying **any one** of them authorises the caller —
|
|
4
|
+
* which is what an array of `security` objects means in OpenAPI, and why this is a list of lists
|
|
5
|
+
* rather than a flat set of scopes.
|
|
6
|
+
*
|
|
7
|
+
* Empty when the operation declares `@useAuth(NoAuth)` or no authentication at all.
|
|
8
|
+
*/
|
|
9
|
+
export function securityFor(program, operation) {
|
|
10
|
+
const authentication = getAuthenticationForOperation(program, operation.operation);
|
|
11
|
+
const requirements = [];
|
|
12
|
+
for (const option of authentication?.options ?? []) {
|
|
13
|
+
const requirement = {};
|
|
14
|
+
let anonymous = false;
|
|
15
|
+
for (const scheme of option.schemes) {
|
|
16
|
+
/**
|
|
17
|
+
* ⚠️ **`NoAuth` inside an option means that option needs nothing**, which is how a spec says
|
|
18
|
+
* "authentication is optional here". It is not a scheme to demand, and emitting it as one
|
|
19
|
+
* would refuse every anonymous caller the document permits.
|
|
20
|
+
*/
|
|
21
|
+
if (scheme.type === "noAuth") {
|
|
22
|
+
anonymous = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Scopes belong to the flows of an OAuth2 scheme; every other kind has none. Read from the
|
|
27
|
+
* scheme rather than assumed, and de-duplicated because two flows may name the same scope.
|
|
28
|
+
*/
|
|
29
|
+
const scopes = scheme.type === "oauth2"
|
|
30
|
+
? [...new Set(scheme.flows.flatMap((flow) => flow.scopes.map((scope) => scope.value)))]
|
|
31
|
+
: [];
|
|
32
|
+
requirement[scheme.id] = scopes;
|
|
33
|
+
}
|
|
34
|
+
if (anonymous && Object.keys(requirement).length === 0)
|
|
35
|
+
continue;
|
|
36
|
+
if (Object.keys(requirement).length > 0)
|
|
37
|
+
requirements.push(requirement);
|
|
38
|
+
}
|
|
39
|
+
return requirements;
|
|
40
|
+
}
|
|
41
|
+
/** The requirements as a TypeScript literal, for the generated call site. */
|
|
42
|
+
export function renderSecurity(requirements) {
|
|
43
|
+
return `[${requirements
|
|
44
|
+
.map((requirement) => `{ ${Object.entries(requirement)
|
|
45
|
+
.map(([scheme, scopes]) => `${JSON.stringify(scheme)}: [${scopes.map((s) => JSON.stringify(s)).join(", ")}]`)
|
|
46
|
+
.join(", ")} }`)
|
|
47
|
+
.join(", ")}]`;
|
|
48
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What TypeSpec's compiler loads for this library.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ **There is deliberately no `$decorators` export**, here or in `typespec-http-zod`. Four once
|
|
5
|
+
* existed and every one let a spec state something `@typespec/openapi3` could not publish, so the
|
|
6
|
+
* emitted validator enforced a rule no caller reading the contract could see. A decorator is not a
|
|
7
|
+
* convenience; it is a second contract.
|
|
8
|
+
*/
|
|
9
|
+
export { $lib } from "./lib.js";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What TypeSpec's compiler loads for this library.
|
|
3
|
+
*
|
|
4
|
+
* ⚠️ **There is deliberately no `$decorators` export**, here or in `typespec-http-zod`. Four once
|
|
5
|
+
* existed and every one let a spec state something `@typespec/openapi3` could not publish, so the
|
|
6
|
+
* emitted validator enforced a rule no caller reading the contract could see. A decorator is not a
|
|
7
|
+
* convenience; it is a second contract.
|
|
8
|
+
*/
|
|
9
|
+
export { $lib } from "./lib.js";
|
package/lib/main.tsp
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typespec-hono",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeSpec emitter: generate a Hono server, and the Zod validators it enforces, from an HTTP service definition — agreeing with the OpenAPI document @typespec/openapi3 publishes from the same source.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cloudflare-workers",
|
|
7
|
+
"codegen",
|
|
8
|
+
"hono",
|
|
9
|
+
"openapi",
|
|
10
|
+
"typespec",
|
|
11
|
+
"typespec-emitter",
|
|
12
|
+
"zod"
|
|
13
|
+
],
|
|
14
|
+
"homepage": "https://github.com/bison-digital/typespec-hono#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/bison-digital/typespec-hono/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/bison-digital/typespec-hono.git"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"lib/*.tsp",
|
|
25
|
+
"dist/**",
|
|
26
|
+
"!dist/test/**"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "dist/src/index.js",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"typespec": "./lib/main.tsp",
|
|
33
|
+
"types": "./dist/src/index.d.ts",
|
|
34
|
+
"default": "./dist/src/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./runtime": {
|
|
37
|
+
"types": "./dist/src/runtime.d.ts",
|
|
38
|
+
"default": "./dist/src/runtime.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"publishConfig": {
|
|
42
|
+
"access": "public",
|
|
43
|
+
"provenance": true
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"typespec-http-zod": "^0.1.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@hono/zod-openapi": "^1.4.0",
|
|
50
|
+
"@hono/zod-validator": "^0.8.0",
|
|
51
|
+
"@types/node": "^26.0.0",
|
|
52
|
+
"@typespec/compiler": "1.15.0",
|
|
53
|
+
"@typespec/events": "0.85.0",
|
|
54
|
+
"@typespec/http": "1.15.0",
|
|
55
|
+
"@typespec/http-specs": "0.1.0-alpha.41",
|
|
56
|
+
"@typespec/openapi": "1.15.0",
|
|
57
|
+
"@typespec/openapi3": "1.15.0",
|
|
58
|
+
"@typespec/rest": "0.85.0",
|
|
59
|
+
"@typespec/sse": "0.85.0",
|
|
60
|
+
"@typespec/streams": "0.85.0",
|
|
61
|
+
"@typespec/versioning": "0.85.0",
|
|
62
|
+
"@typespec/xml": "0.85.0",
|
|
63
|
+
"hono": "^4.12.26",
|
|
64
|
+
"oxfmt": "^0.63.0",
|
|
65
|
+
"oxlint": "^1.78.0",
|
|
66
|
+
"typescript": "~7.0.2",
|
|
67
|
+
"typespec-hono": "link:.",
|
|
68
|
+
"vitest": "^4.1.9",
|
|
69
|
+
"zod": "^4.4.3"
|
|
70
|
+
},
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"@hono/zod-validator": "^0.8.0",
|
|
73
|
+
"@typespec/compiler": "^1.15.0",
|
|
74
|
+
"@typespec/http": "^1.15.0",
|
|
75
|
+
"hono": "^4.12.0",
|
|
76
|
+
"zod": "^4.0.0"
|
|
77
|
+
},
|
|
78
|
+
"engines": {
|
|
79
|
+
"node": ">=22.0.0"
|
|
80
|
+
},
|
|
81
|
+
"tspMain": "lib/main.tsp",
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsc -p tsconfig.build.json",
|
|
84
|
+
"test": "tsc -p tsconfig.build.json && vitest run",
|
|
85
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
86
|
+
"lint": "oxlint src/ test/",
|
|
87
|
+
"format": "oxfmt",
|
|
88
|
+
"format:check": "oxfmt --check"
|
|
89
|
+
}
|
|
90
|
+
}
|