@adhd/apigen-plugin-openapi 0.2.2 → 0.2.3

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 CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.2.3 (2026-09-24)
2
+
3
+ This was a version bump only for apigen-plugin-openapi to align it with other projects, there were no code changes.
4
+
1
5
  ## 0.2.2 (2026-08-07)
2
6
 
3
7
 
package/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require("ts-morph");require("node:fs");require("node:path");require("ts-json-schema-generator");function m(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function j(e,t,n={}){const r=e.split("/");if(r.length<2||r.some(l=>l.length===0))throw new Error(`syntheticOp: id "${e}" must be "<namespace>/<path...>" with non-empty segments`);const[o,...i]=r,c=o.replace(/^_+/,""),p=n.kind??"action",s={id:e,host:t.host,namespace:m(c),path:i.map(m),kind:p,async:n.async??!1,streaming:n.streaming??!1,safe:n.safe??p==="query",input:n.input??{},output:n.output??{},envelope:n.envelope??{},typeText:n.typeText??null};return n.hasCtx!==void 0&&(s.hasCtx=n.hasCtx),n.transports!==void 0&&(s.transports=n.transports),s}const O={"decimal.js":"Decimal"};function w(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(O).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${w(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));const d=new Set(["string","number","boolean","integer"]);function q(e){if(typeof e!="object"||e===null)return!1;const t=e;if(t.$ref!==void 0||t.oneOf||t.anyOf||t.allOf)return!1;const{type:n}=t;return typeof n=="string"?d.has(n):Array.isArray(n)?n.every(r=>d.has(r)||r==="null"):Array.isArray(t.enum)&&t.enum.length>0?t.enum.every(r=>["string","number","boolean"].includes(typeof r)):!1}function A(e){if(!e||typeof e!="object")return!1;const t=e.properties;return t===void 0||typeof t!="object"||t===null?!1:Object.values(t).every(q)}const P={"decimal.js":"Decimal"};function k(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(P).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${k(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));function y(e){return e.words.join("-")}function h(e){return e.words.map(_).join("")}function g(e){return e.words.join("_")}function S(e,t={}){var n,r;const o=[e.namespace,...e.path],i=e.safe||A(e.input)?"GET":"POST",c=((r=(n=t.http)==null?void 0:n.verb)==null?void 0:r[e.id])??i,p="/"+o.map(a=>y(a)).join("/"),s=o.map(a=>g(a)).join("_"),l=o.map(a=>g(a)).slice(0,-1).join("."),f=h(o[o.length-2]??o[0]),u=h(o[o.length-1]),v=o.map(a=>y(a));return{http:{verb:c,route:p},mcp:{name:s},grpc:{package:l,service:f,method:u},cli:{path:v}}}function _(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function $(e,t={}){const n=t.title??"API",r=t.version??"0.0.0",o={};for(const i of e){const c=S(i),{verb:p,route:s}=c.http,l=p.toLowerCase(),f={operationId:i.id,summary:i.id,responses:{200:x(i.output)}};if(p==="GET")f.parameters=E(i.input);else{const u=i.input;typeof u=="object"&&u!==null&&Object.keys(u).length>0&&(f.requestBody={required:!0,content:{"application/json":{schema:u}}})}o[s]===void 0&&(o[s]={}),o[s][l]=f}return{openapi:"3.1.0",info:{title:n,version:r},paths:o}}function x(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function E(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(([r,o])=>({name:r,in:"query",required:t.includes(r),schema:o}))}function T(e,t={}){return[{...j("_meta/openapi",e,{kind:"query",safe:!0,output:{type:"object"},transports:["http"]}),handler:n=>$(e.operations,{title:t.title,version:t.version})}]}const b={id:"openapi",description:"Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",language:"ts",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 T(e,t)}}}};exports.default=b;exports.openapiPlugin=b;
1
+ "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require("node:fs");const v=require("node:module");require("node:path");var c=typeof document<"u"?document.currentScript:null;function m(e){return{raw:e,words:e.split(/(?=[A-Z])|[-_]/).map(t=>t.toLowerCase()).filter(Boolean)}}function O(e,t,n={}){const o=e.split("/");if(o.length<2||o.some(f=>f.length===0))throw new Error(`syntheticOp: id "${e}" must be "<namespace>/<path...>" with non-empty segments`);const[r,...i]=o,l=r.replace(/^_+/,""),a=n.kind??"action",s={id:e,host:t.host,namespace:m(l),path:i.map(m),kind:a,async:n.async??!1,streaming:n.streaming??!1,safe:n.safe??a==="query",input:n.input??{},output:n.output??{},envelope:n.envelope??{},typeText:n.typeText??null};return n.hasCtx!==void 0&&(s.hasCtx=n.hasCtx),n.transports!==void 0&&(s.transports=n.transports),s}v.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:c&&c.tagName.toUpperCase()==="SCRIPT"&&c.src||new URL("index.js",document.baseURI).href);const q={"decimal.js":"Decimal"};function _(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(q).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${_(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));v.createRequire(typeof document>"u"?require("url").pathToFileURL(__filename).href:c&&c.tagName.toUpperCase()==="SCRIPT"&&c.src||new URL("index.js",document.baseURI).href);const y=new Set(["string","number","boolean","integer"]);function R(e){if(typeof e!="object"||e===null)return!1;const t=e;if(t.$ref!==void 0||t.oneOf||t.anyOf||t.allOf)return!1;const{type:n}=t;return typeof n=="string"?y.has(n):Array.isArray(n)?n.every(o=>y.has(o)||o==="null"):Array.isArray(t.enum)&&t.enum.length>0?t.enum.every(o=>["string","number","boolean"].includes(typeof o)):!1}function A(e){if(!e||typeof e!="object")return!1;const t=e.properties;return t===void 0||typeof t!="object"||t===null?!1:Object.values(t).every(R)}const S={"decimal.js":"Decimal"};function C(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}Object.entries(S).map(([e,t])=>({pattern:new RegExp(`import\\(["'][^"']*${C(e)}[^"']*["']\\)\\.\\w+`,"g"),key:t}));function h(e){return e.words.join("-")}function g(e){return e.words.map(T).join("")}function b(e){return e.words.join("_")}function P(e,t={}){var n,o;const r=[e.namespace,...e.path],i=e.safe||A(e.input)?"GET":"POST",l=((o=(n=t.http)==null?void 0:n.verb)==null?void 0:o[e.id])??i,a="/"+r.map(p=>h(p)).join("/"),s=r.map(p=>b(p)).join("_"),f=r.map(p=>b(p)).slice(0,-1).join("."),d=g(r[r.length-2]??r[0]),u=g(r[r.length-1]),w=r.map(p=>h(p));return{http:{verb:l,route:a},mcp:{name:s},grpc:{package:f,service:d,method:u},cli:{path:w}}}function T(e){return e.length===0?e:e[0].toUpperCase()+e.slice(1)}function x(e,t={}){const n=t.title??"API",o=t.version??"0.0.0",r={};for(const i of e){const l=P(i),{verb:a,route:s}=l.http,f=a.toLowerCase(),d={operationId:i.id,summary:i.id,responses:{200:I(i.output)}};if(a==="GET")d.parameters=U(i.input);else{const u=i.input;typeof u=="object"&&u!==null&&Object.keys(u).length>0&&(d.requestBody={required:!0,content:{"application/json":{schema:u}}})}r[s]===void 0&&(r[s]={}),r[s][f]=d}return{openapi:"3.1.0",info:{title:n,version:o},paths:r}}function I(e){return typeof e=="object"&&e!==null&&Object.keys(e).length>0?{description:"Success",content:{"application/json":{schema:e}}}:{description:"Success"}}function U(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(([o,r])=>({name:o,in:"query",required:t.includes(o),schema:r}))}function k(e,t={}){return[{...O("_meta/openapi",e,{kind:"query",safe:!0,output:{type:"object"},transports:["http"]}),handler:n=>x(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",language:"ts",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 k(e,t)}}}};exports.default=j;exports.openapiPlugin=j;
package/index.mjs CHANGED
@@ -1,7 +1,6 @@
1
- import "ts-morph";
2
1
  import "node:fs";
2
+ import { createRequire as b } from "node:module";
3
3
  import "node:path";
4
- import "ts-json-schema-generator";
5
4
  function m(e) {
6
5
  return {
7
6
  raw: e,
@@ -9,16 +8,16 @@ function m(e) {
9
8
  };
10
9
  }
11
10
  function j(e, t, n = {}) {
12
- const i = e.split("/");
13
- if (i.length < 2 || i.some((l) => l.length === 0))
11
+ const r = e.split("/");
12
+ if (r.length < 2 || r.some((l) => l.length === 0))
14
13
  throw new Error(
15
14
  `syntheticOp: id "${e}" must be "<namespace>/<path...>" with non-empty segments`
16
15
  );
17
- const [o, ...r] = i, c = o.replace(/^_+/, ""), p = n.kind ?? "action", s = {
16
+ const [o, ...i] = r, c = o.replace(/^_+/, ""), p = n.kind ?? "action", s = {
18
17
  id: e,
19
18
  host: t.host,
20
19
  namespace: m(c),
21
- path: r.map(m),
20
+ path: i.map(m),
22
21
  kind: p,
23
22
  async: n.async ?? !1,
24
23
  streaming: n.streaming ?? !1,
@@ -30,13 +29,14 @@ function j(e, t, n = {}) {
30
29
  };
31
30
  return n.hasCtx !== void 0 && (s.hasCtx = n.hasCtx), n.transports !== void 0 && (s.transports = n.transports), s;
32
31
  }
33
- const v = {
32
+ b(import.meta.url);
33
+ const O = {
34
34
  "decimal.js": "Decimal"
35
35
  };
36
- function O(e) {
36
+ function w(e) {
37
37
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
38
38
  }
39
- Object.entries(v).map(([e, t]) => ({
39
+ Object.entries(O).map(([e, t]) => ({
40
40
  // Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
41
41
  // The module specifier appears inside an absolute path, so we allow any
42
42
  // characters between the quote and the specifier, and between the specifier
@@ -44,36 +44,37 @@ Object.entries(v).map(([e, t]) => ({
44
44
  // …) is matched generically (`\w+`) rather than anchored to one spelling —
45
45
  // see the doc comment above for why.
46
46
  pattern: new RegExp(
47
- `import\\(["'][^"']*${O(e)}[^"']*["']\\)\\.\\w+`,
47
+ `import\\(["'][^"']*${w(e)}[^"']*["']\\)\\.\\w+`,
48
48
  "g"
49
49
  ),
50
50
  key: t
51
51
  }));
52
+ b(import.meta.url);
52
53
  const d = /* @__PURE__ */ new Set(["string", "number", "boolean", "integer"]);
53
- function w(e) {
54
+ function A(e) {
54
55
  if (typeof e != "object" || e === null)
55
56
  return !1;
56
57
  const t = e;
57
58
  if (t.$ref !== void 0 || t.oneOf || t.anyOf || t.allOf)
58
59
  return !1;
59
60
  const { type: n } = t;
60
- return typeof n == "string" ? d.has(n) : Array.isArray(n) ? n.every((i) => d.has(i) || i === "null") : Array.isArray(t.enum) && t.enum.length > 0 ? t.enum.every((i) => ["string", "number", "boolean"].includes(typeof i)) : !1;
61
+ return typeof n == "string" ? d.has(n) : Array.isArray(n) ? n.every((r) => d.has(r) || r === "null") : Array.isArray(t.enum) && t.enum.length > 0 ? t.enum.every((r) => ["string", "number", "boolean"].includes(typeof r)) : !1;
61
62
  }
62
- function A(e) {
63
+ function q(e) {
63
64
  if (!e || typeof e != "object")
64
65
  return !1;
65
66
  const t = e.properties;
66
67
  return t === void 0 || typeof t != "object" || t === null ? !1 : Object.values(t).every(
67
- w
68
+ A
68
69
  );
69
70
  }
70
- const q = {
71
+ const k = {
71
72
  "decimal.js": "Decimal"
72
73
  };
73
- function k(e) {
74
+ function x(e) {
74
75
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
75
76
  }
76
- Object.entries(q).map(([e, t]) => ({
77
+ Object.entries(k).map(([e, t]) => ({
77
78
  // Matches: import("...{modSpec}...").<anyMemberName> (single or double quotes)
78
79
  // The module specifier appears inside an absolute path, so we allow any
79
80
  // characters between the quote and the specifier, and between the specifier
@@ -81,7 +82,7 @@ Object.entries(q).map(([e, t]) => ({
81
82
  // …) is matched generically (`\w+`) rather than anchored to one spelling —
82
83
  // see the doc comment above for why.
83
84
  pattern: new RegExp(
84
- `import\\(["'][^"']*${k(e)}[^"']*["']\\)\\.\\w+`,
85
+ `import\\(["'][^"']*${x(e)}[^"']*["']\\)\\.\\w+`,
85
86
  "g"
86
87
  ),
87
88
  key: t
@@ -90,38 +91,38 @@ function y(e) {
90
91
  return e.words.join("-");
91
92
  }
92
93
  function h(e) {
93
- return e.words.map(P).join("");
94
+ return e.words.map($).join("");
94
95
  }
95
96
  function g(e) {
96
97
  return e.words.join("_");
97
98
  }
98
- function x(e, t = {}) {
99
- var n, i;
100
- const o = [e.namespace, ...e.path], r = e.safe || A(e.input) ? "GET" : "POST", c = ((i = (n = t.http) == null ? void 0 : n.verb) == null ? void 0 : i[e.id]) ?? r, p = "/" + o.map((a) => y(a)).join("/"), s = o.map((a) => g(a)).join("_"), l = o.map((a) => g(a)).slice(0, -1).join("."), f = h(o[o.length - 2] ?? o[0]), u = h(o[o.length - 1]), b = o.map((a) => y(a));
99
+ function _(e, t = {}) {
100
+ var n, r;
101
+ const o = [e.namespace, ...e.path], i = e.safe || q(e.input) ? "GET" : "POST", c = ((r = (n = t.http) == null ? void 0 : n.verb) == null ? void 0 : r[e.id]) ?? i, p = "/" + o.map((a) => y(a)).join("/"), s = o.map((a) => g(a)).join("_"), l = o.map((a) => g(a)).slice(0, -1).join("."), f = h(o[o.length - 2] ?? o[0]), u = h(o[o.length - 1]), v = o.map((a) => y(a));
101
102
  return {
102
103
  http: { verb: c, route: p },
103
104
  mcp: { name: s },
104
105
  grpc: { package: l, service: f, method: u },
105
- cli: { path: b }
106
+ cli: { path: v }
106
107
  };
107
108
  }
108
- function P(e) {
109
+ function $(e) {
109
110
  return e.length === 0 ? e : e[0].toUpperCase() + e.slice(1);
110
111
  }
111
- function $(e, t = {}) {
112
- const n = t.title ?? "API", i = t.version ?? "0.0.0", o = {};
113
- for (const r of e) {
114
- const c = x(r), { verb: p, route: s } = c.http, l = p.toLowerCase(), f = {
115
- operationId: r.id,
116
- summary: r.id,
112
+ function E(e, t = {}) {
113
+ const n = t.title ?? "API", r = t.version ?? "0.0.0", o = {};
114
+ for (const i of e) {
115
+ const c = _(i), { verb: p, route: s } = c.http, l = p.toLowerCase(), f = {
116
+ operationId: i.id,
117
+ summary: i.id,
117
118
  responses: {
118
- 200: E(r.output)
119
+ 200: P(i.output)
119
120
  }
120
121
  };
121
122
  if (p === "GET")
122
- f.parameters = C(r.input);
123
+ f.parameters = C(i.input);
123
124
  else {
124
- const u = r.input;
125
+ const u = i.input;
125
126
  typeof u == "object" && u !== null && Object.keys(u).length > 0 && (f.requestBody = {
126
127
  required: !0,
127
128
  content: {
@@ -135,11 +136,11 @@ function $(e, t = {}) {
135
136
  }
136
137
  return {
137
138
  openapi: "3.1.0",
138
- info: { title: n, version: i },
139
+ info: { title: n, version: r },
139
140
  paths: o
140
141
  };
141
142
  }
142
- function E(e) {
143
+ function P(e) {
143
144
  return typeof e == "object" && e !== null && Object.keys(e).length > 0 ? {
144
145
  description: "Success",
145
146
  content: {
@@ -151,10 +152,10 @@ function C(e) {
151
152
  if (typeof e != "object" || e === null || typeof e.properties != "object" || e.properties === null)
152
153
  return [];
153
154
  const t = Array.isArray(e.required) ? e.required : [], n = e.properties;
154
- return Object.entries(n).map(([i, o]) => ({
155
- name: i,
155
+ return Object.entries(n).map(([r, o]) => ({
156
+ name: r,
156
157
  in: "query",
157
- required: t.includes(i),
158
+ required: t.includes(r),
158
159
  schema: o
159
160
  }));
160
161
  }
@@ -172,14 +173,14 @@ function S(e, t = {}) {
172
173
  transports: ["http"]
173
174
  }),
174
175
  // Handler: derive the doc from the descriptor at request time.
175
- handler: (n) => $(e.operations, {
176
+ handler: (n) => E(e.operations, {
176
177
  title: t.title,
177
178
  version: t.version
178
179
  })
179
180
  }
180
181
  ];
181
182
  }
182
- const B = {
183
+ const G = {
183
184
  id: "openapi",
184
185
  description: "Mount plugin: serves the OpenAPI 3.1 doc at GET /meta/openapi",
185
186
  language: "ts",
@@ -203,6 +204,6 @@ const B = {
203
204
  }
204
205
  };
205
206
  export {
206
- B as default,
207
- B as openapiPlugin
207
+ G as default,
208
+ G as openapiPlugin
208
209
  };
package/package.json CHANGED
@@ -1,14 +1,32 @@
1
1
  {
2
2
  "name": "@adhd/apigen-plugin-openapi",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "main": "./index.js",
5
5
  "dependencies": {
6
- "@adhd/apigen-core-client": "^0.3.0",
7
- "@adhd/apigen-codegen-openapi": "^0.2.2"
6
+ "@adhd/apigen-core-client": "^0.3.1",
7
+ "@adhd/apigen-codegen-openapi": "^0.2.3"
8
8
  },
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
12
  "module": "./index.mjs",
13
- "types": "./index.d.ts"
13
+ "types": "./index.d.ts",
14
+ "description": "apigen plugin that live-mounts TypeScript as an OpenAPI document",
15
+ "keywords": [
16
+ "openapi",
17
+ "apigen",
18
+ "typescript",
19
+ "plugin",
20
+ "codegen"
21
+ ],
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/PseudoSky/adhd.git",
26
+ "directory": "packages/apigen/apigen-plugin-openapi"
27
+ },
28
+ "homepage": "https://github.com/PseudoSky/adhd/tree/main/packages/apigen/apigen-plugin-openapi#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/PseudoSky/adhd/issues"
31
+ }
14
32
  }