@adhd/apigen-plugin-openapi 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/index.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export type { OpenapiOptions } from './lib/plugin';
2
+ export { openapiPlugin } from './lib/plugin';
3
+ export { default } from './lib/plugin';
package/index.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});function m(e){return e.words.join("-")}function g(e){return e.words.map(P).join("")}function b(e){return e.words.join("_")}function v(e,t={}){var d,h;const n=[e.namespace,...e.path],s=e.safe?"GET":"POST",r=((h=(d=t.http)==null?void 0:d.verb)==null?void 0:h[e.id])??s,o="/"+n.map(i=>m(i)).join("/"),l=n.map(i=>b(i)).join("_"),p=n.map(i=>b(i)).slice(0,-1).join("."),u=g(n[n.length-2]??n[0]),c=g(n[n.length-1]),a=n.map(i=>m(i));return{http:{verb:r,route:o},mcp:{name:l},grpc:{package:p,service:u,method:c},cli:{path:a}}}function P(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function O(e,t={}){const n=t.title??"API",s=t.version??"0.0.0",r={};for(const o of e){const l=v(o),{verb:f,route:p}=l.http,u=f.toLowerCase(),c={operationId:o.id,summary:o.id,responses:{200:S(o.output)}};if(o.safe)c.parameters=q(o.input);else{const a=o.input;typeof a=="object"&&a!==null&&Object.keys(a).length>0&&(c.requestBody={required:!0,content:{"application/json":{schema:a}}})}r[p]===void 0&&(r[p]={}),r[p][u]=c}return{openapi:"3.1.0",info:{title:n,version:s},paths:r}}function S(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function q(e){if(typeof e!="object"||e===null||typeof e.properties!="object"||e.properties===null)return[];const t=Array.isArray(e.required)?e.required:[],n=e.properties;return Object.entries(n).map(([s,r])=>({name:s,in:"query",required:t.includes(s),schema:r}))}function y(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function A(e,t={}){return[{id:"_meta/openapi",host:e.host,namespace:y("meta"),path:[y("openapi")],kind:"query",async:!1,streaming:!1,safe:!0,input:{},output:{type:"object"},envelope:{},typeText:null,transports:["http"],handler:n=>O(e.operations,{title:t.title,version:t.version})}]}const j={id:"openapi",description:"Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",optionsSchema:{type:"object",properties:{title:{type:"string",description:"OpenAPI info.title"},version:{type:"string",description:"OpenAPI info.version"}},additionalProperties:!1},capabilities:{mount:{operations(e,t){return A(e,t)}}}};exports.default=j;exports.openapiPlugin=j;
package/index.mjs ADDED
@@ -0,0 +1,128 @@
1
+ function m(e) {
2
+ return e.words.join("-");
3
+ }
4
+ function y(e) {
5
+ return e.words.map(v).join("");
6
+ }
7
+ function b(e) {
8
+ return e.words.join("_");
9
+ }
10
+ function j(e, t = {}) {
11
+ var f, h;
12
+ const n = [e.namespace, ...e.path], s = e.safe ? "GET" : "POST", r = ((h = (f = t.http) == null ? void 0 : f.verb) == null ? void 0 : h[e.id]) ?? s, o = "/" + n.map((i) => m(i)).join("/"), l = n.map((i) => b(i)).join("_"), a = n.map((i) => b(i)).slice(0, -1).join("."), u = y(n[n.length - 2] ?? n[0]), c = y(n[n.length - 1]), p = n.map((i) => m(i));
13
+ return {
14
+ http: { verb: r, route: o },
15
+ mcp: { name: l },
16
+ grpc: { package: a, service: u, method: c },
17
+ cli: { path: p }
18
+ };
19
+ }
20
+ function v(e) {
21
+ return e.length === 0 ? e : e[0].toUpperCase() + e.slice(1);
22
+ }
23
+ function P(e, t = {}) {
24
+ const n = t.title ?? "API", s = t.version ?? "0.0.0", r = {};
25
+ for (const o of e) {
26
+ const l = j(o), { verb: d, route: a } = l.http, u = d.toLowerCase(), c = {
27
+ operationId: o.id,
28
+ summary: o.id,
29
+ responses: {
30
+ 200: O(o.output)
31
+ }
32
+ };
33
+ if (o.safe)
34
+ c.parameters = q(o.input);
35
+ else {
36
+ const p = o.input;
37
+ typeof p == "object" && p !== null && Object.keys(p).length > 0 && (c.requestBody = {
38
+ required: !0,
39
+ content: {
40
+ "application/json": {
41
+ schema: p
42
+ }
43
+ }
44
+ });
45
+ }
46
+ r[a] === void 0 && (r[a] = {}), r[a][u] = c;
47
+ }
48
+ return {
49
+ openapi: "3.1.0",
50
+ info: { title: n, version: s },
51
+ paths: r
52
+ };
53
+ }
54
+ function O(e) {
55
+ return typeof e == "object" && e !== null && Object.keys(e).length > 0 ? {
56
+ description: "Success",
57
+ content: {
58
+ "application/json": { schema: e }
59
+ }
60
+ } : { description: "Success" };
61
+ }
62
+ function q(e) {
63
+ if (typeof e != "object" || e === null || typeof e.properties != "object" || e.properties === null)
64
+ return [];
65
+ const t = Array.isArray(e.required) ? e.required : [], n = e.properties;
66
+ return Object.entries(n).map(([s, r]) => ({
67
+ name: s,
68
+ in: "query",
69
+ required: t.includes(s),
70
+ schema: r
71
+ }));
72
+ }
73
+ function g(e) {
74
+ return { raw: e, words: e.split(/(?=[A-Z])|[-_]/).map((t) => t.toLowerCase()).filter(Boolean) };
75
+ }
76
+ function A(e, t = {}) {
77
+ return [
78
+ {
79
+ // Canonical id — the `_meta` prefix is a convention for meta-endpoints.
80
+ id: "_meta/openapi",
81
+ host: e.host,
82
+ namespace: g("meta"),
83
+ path: [g("openapi")],
84
+ // query + safe → GET /meta/openapi (SPEC §5)
85
+ kind: "query",
86
+ async: !1,
87
+ streaming: !1,
88
+ safe: !0,
89
+ // Input: no domain params — this is a zero-arg metadata endpoint.
90
+ input: {},
91
+ // Output: an object (the full OpenAPI doc shape; not narrowed further
92
+ // here because the exact schema varies with the descriptor content).
93
+ output: { type: "object" },
94
+ envelope: {},
95
+ typeText: null,
96
+ // Expose only on HTTP — the doc is a tooling artefact (SPEC §7.2b).
97
+ transports: ["http"],
98
+ // Handler: derive the doc from the descriptor at request time.
99
+ handler: (n) => P(e.operations, {
100
+ title: t.title,
101
+ version: t.version
102
+ })
103
+ }
104
+ ];
105
+ }
106
+ const S = {
107
+ id: "openapi",
108
+ description: "Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",
109
+ optionsSchema: {
110
+ type: "object",
111
+ properties: {
112
+ title: { type: "string", description: "OpenAPI info.title" },
113
+ version: { type: "string", description: "OpenAPI info.version" }
114
+ },
115
+ additionalProperties: !1
116
+ },
117
+ capabilities: {
118
+ mount: {
119
+ operations(e, t) {
120
+ return A(e, t);
121
+ }
122
+ }
123
+ }
124
+ };
125
+ export {
126
+ S as default,
127
+ S as openapiPlugin
128
+ };
@@ -0,0 +1,23 @@
1
+ import { Plugin } from '@adhd/apigen-core';
2
+
3
+ /** Options accepted by the openapi mount plugin. */
4
+ export interface OpenapiOptions {
5
+ /**
6
+ * The API title placed in the generated OpenAPI doc's `info.title`.
7
+ * @default 'API'
8
+ */
9
+ title?: string;
10
+ /**
11
+ * The API version placed in the generated OpenAPI doc's `info.version`.
12
+ * @default '0.0.0'
13
+ */
14
+ version?: string;
15
+ }
16
+ /**
17
+ * v2 openapi mount plugin (SPEC §7.1 / §7.2b).
18
+ *
19
+ * Contributes `GET /meta/openapi` → the OpenAPI 3.1 document derived from
20
+ * the canonical descriptor at request time.
21
+ */
22
+ export declare const openapiPlugin: Plugin<OpenapiOptions>;
23
+ export default openapiPlugin;
package/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@adhd/apigen-plugin-openapi",
3
+ "version": "0.1.0",
4
+ "main": "./index.js",
5
+ "dependencies": {
6
+ "@adhd/apigen-core": "^0.1.0",
7
+ "@adhd/apigen-codegen-openapi": "^0.1.0"
8
+ },
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "module": "./index.mjs",
13
+ "types": "./index.d.ts"
14
+ }