zudoku 0.26.0 → 0.26.1

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.
Files changed (169) hide show
  1. package/dist/config/config.d.ts +1 -0
  2. package/dist/config/loader.js +1 -1
  3. package/dist/config/loader.js.map +1 -1
  4. package/dist/config/validators/common.d.ts +11 -0
  5. package/dist/config/validators/common.js +1 -0
  6. package/dist/config/validators/common.js.map +1 -1
  7. package/dist/config/validators/validate.d.ts +5 -0
  8. package/dist/lib/authentication/providers/auth0.js +1 -1
  9. package/dist/lib/authentication/providers/auth0.js.map +1 -1
  10. package/dist/lib/authentication/providers/openid.d.ts +1 -1
  11. package/dist/lib/authentication/providers/openid.js +10 -6
  12. package/dist/lib/authentication/providers/openid.js.map +1 -1
  13. package/dist/lib/components/Autocomplete.d.ts +12 -0
  14. package/dist/lib/components/Autocomplete.js +47 -0
  15. package/dist/lib/components/Autocomplete.js.map +1 -0
  16. package/dist/lib/components/Header.js +3 -3
  17. package/dist/lib/components/Header.js.map +1 -1
  18. package/dist/lib/components/index.js +2 -2
  19. package/dist/lib/components/index.js.map +1 -1
  20. package/dist/lib/plugins/markdown/MdxPage.js +8 -2
  21. package/dist/lib/plugins/markdown/MdxPage.js.map +1 -1
  22. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.d.ts +3 -1
  23. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js +3 -2
  24. package/dist/lib/plugins/openapi/PlaygroundDialogWrapper.js.map +1 -1
  25. package/dist/lib/plugins/openapi/Sidecar.js +1 -1
  26. package/dist/lib/plugins/openapi/Sidecar.js.map +1 -1
  27. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.d.ts +6 -0
  28. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js +12 -0
  29. package/dist/lib/plugins/openapi/playground/ExamplesDropdown.js.map +1 -0
  30. package/dist/lib/plugins/openapi/playground/Headers.js +66 -4
  31. package/dist/lib/plugins/openapi/playground/Headers.js.map +1 -1
  32. package/dist/lib/plugins/openapi/playground/Playground.d.ts +5 -1
  33. package/dist/lib/plugins/openapi/playground/Playground.js +36 -11
  34. package/dist/lib/plugins/openapi/playground/Playground.js.map +1 -1
  35. package/dist/lib/plugins/openapi/playground/QueryParams.js +20 -30
  36. package/dist/lib/plugins/openapi/playground/QueryParams.js.map +1 -1
  37. package/dist/lib/plugins/openapi/post-processors/removeExtensions.d.ts +2 -1
  38. package/dist/lib/plugins/openapi/post-processors/removeExtensions.js +5 -3
  39. package/dist/lib/plugins/openapi/post-processors/removeExtensions.js.map +1 -1
  40. package/dist/lib/plugins/openapi/post-processors/removeExtensions.test.js +49 -0
  41. package/dist/lib/plugins/openapi/post-processors/removeExtensions.test.js.map +1 -1
  42. package/dist/lib/plugins/openapi/post-processors/removeParameters.d.ts +10 -0
  43. package/dist/lib/plugins/openapi/post-processors/removeParameters.js +66 -0
  44. package/dist/lib/plugins/openapi/post-processors/removeParameters.js.map +1 -0
  45. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.d.ts +1 -0
  46. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.js +131 -0
  47. package/dist/lib/plugins/openapi/post-processors/removeParameters.test.js.map +1 -0
  48. package/dist/lib/ui/Command.d.ts +9 -1
  49. package/dist/lib/ui/Command.js +5 -1
  50. package/dist/lib/ui/Command.js.map +1 -1
  51. package/dist/lib/util/joinUrl.d.ts +1 -0
  52. package/dist/lib/util/joinUrl.js +40 -0
  53. package/dist/lib/util/joinUrl.js.map +1 -0
  54. package/dist/vite/build.js +10 -10
  55. package/dist/vite/build.js.map +1 -1
  56. package/dist/vite/config.js +4 -1
  57. package/dist/vite/config.js.map +1 -1
  58. package/dist/vite/dev-server.js +4 -1
  59. package/dist/vite/dev-server.js.map +1 -1
  60. package/dist/vite/plugin-api.d.ts +1 -1
  61. package/dist/vite/plugin-api.js +23 -5
  62. package/dist/vite/plugin-api.js.map +1 -1
  63. package/dist/vite/plugin-auth.js +4 -1
  64. package/dist/vite/plugin-auth.js.map +1 -1
  65. package/dist/vite/plugin-mdx.js +9 -4
  66. package/dist/vite/plugin-mdx.js.map +1 -1
  67. package/dist/vite/prerender.d.ts +2 -2
  68. package/dist/vite/prerender.js +4 -4
  69. package/dist/vite/prerender.js.map +1 -1
  70. package/dist/zuplo/enrich-with-zuplo.d.ts +5 -0
  71. package/dist/zuplo/enrich-with-zuplo.js +184 -0
  72. package/dist/zuplo/enrich-with-zuplo.js.map +1 -0
  73. package/dist/zuplo/env.d.ts +1 -0
  74. package/dist/zuplo/env.js +3 -0
  75. package/dist/zuplo/env.js.map +1 -1
  76. package/dist/zuplo/policy-types.d.ts +33 -0
  77. package/dist/zuplo/policy-types.js +8 -0
  78. package/dist/zuplo/policy-types.js.map +1 -0
  79. package/dist/zuplo/with-zuplo-processors.d.ts +3 -0
  80. package/dist/zuplo/with-zuplo-processors.js +26 -0
  81. package/dist/zuplo/with-zuplo-processors.js.map +1 -0
  82. package/dist/zuplo/with-zuplo.d.ts +1 -2
  83. package/dist/zuplo/with-zuplo.js +6 -27
  84. package/dist/zuplo/with-zuplo.js.map +1 -1
  85. package/lib/{AnchorLink-_Vu02ceN.js → AnchorLink-bObQitZv.js} +2 -2
  86. package/lib/{AnchorLink-_Vu02ceN.js.map → AnchorLink-bObQitZv.js.map} +1 -1
  87. package/lib/{AuthenticationPlugin-DNXBcsVN.js → AuthenticationPlugin-C9SwOxkc.js} +3 -3
  88. package/lib/{AuthenticationPlugin-DNXBcsVN.js.map → AuthenticationPlugin-C9SwOxkc.js.map} +1 -1
  89. package/lib/{Markdown-BrfrjEk_.js → Markdown-DFN6p0J-.js} +2 -2
  90. package/lib/{Markdown-BrfrjEk_.js.map → Markdown-DFN6p0J-.js.map} +1 -1
  91. package/lib/{MdxPage-LNZLj_A5.js → MdxPage-D9c4z09Q.js} +63 -58
  92. package/lib/MdxPage-D9c4z09Q.js.map +1 -0
  93. package/lib/{OperationList-PCwzTp1r.js → OperationList-DGJWDx1G.js} +875 -871
  94. package/lib/{OperationList-PCwzTp1r.js.map → OperationList-DGJWDx1G.js.map} +1 -1
  95. package/lib/{Route-Pzk6qwIk.js → Route-VdmEyOD0.js} +3 -3
  96. package/lib/{Route-Pzk6qwIk.js.map → Route-VdmEyOD0.js.map} +1 -1
  97. package/lib/{Select-DkOpAG0c.js → Select-D3O7wISy.js} +3 -3
  98. package/lib/{Select-DkOpAG0c.js.map → Select-D3O7wISy.js.map} +1 -1
  99. package/lib/{SlotletProvider-DPbx9KdU.js → SlotletProvider-_3zzX_g_.js} +4 -4
  100. package/lib/{SlotletProvider-DPbx9KdU.js.map → SlotletProvider-_3zzX_g_.js.map} +1 -1
  101. package/lib/{Button-oroWHXAy.js → Spinner-BlzrEEk1.js} +15 -12
  102. package/lib/Spinner-BlzrEEk1.js.map +1 -0
  103. package/lib/{ZudokuContext-D3ayHjP-.js → ZudokuContext-DeQZEp-x.js} +2 -2
  104. package/lib/{ZudokuContext-D3ayHjP-.js.map → ZudokuContext-DeQZEp-x.js.map} +1 -1
  105. package/lib/{chunk-SYFQ2XB5-KWlHsT7t.js → chunk-SYFQ2XB5-BF5IDYrB.js} +6 -5
  106. package/lib/{chunk-SYFQ2XB5-KWlHsT7t.js.map → chunk-SYFQ2XB5-BF5IDYrB.js.map} +1 -1
  107. package/lib/{hook-DUyACbIK.js → hook-BRQEDRbn.js} +2 -2
  108. package/lib/{hook-DUyACbIK.js.map → hook-BRQEDRbn.js.map} +1 -1
  109. package/lib/index-B7mqiOei.js +509 -0
  110. package/lib/index-B7mqiOei.js.map +1 -0
  111. package/lib/index-CXRrqOIl.js +1750 -0
  112. package/lib/index-CXRrqOIl.js.map +1 -0
  113. package/lib/joinUrl-BTy9bvoK.js +20 -0
  114. package/lib/joinUrl-BTy9bvoK.js.map +1 -0
  115. package/lib/post-processors/removeExtensions.js +7 -7
  116. package/lib/post-processors/removeExtensions.js.map +1 -1
  117. package/lib/post-processors/removeParameters.js +48 -0
  118. package/lib/post-processors/removeParameters.js.map +1 -0
  119. package/lib/ui/ActionButton.js +10 -11
  120. package/lib/ui/ActionButton.js.map +1 -1
  121. package/lib/ui/Command.js +125 -13
  122. package/lib/ui/Command.js.map +1 -1
  123. package/lib/{useExposedProps-BBHR7aLM.js → useExposedProps-CetwhZpP.js} +2 -2
  124. package/lib/{useExposedProps-BBHR7aLM.js.map → useExposedProps-CetwhZpP.js.map} +1 -1
  125. package/lib/zudoku.auth-auth0.js +7 -9
  126. package/lib/zudoku.auth-auth0.js.map +1 -1
  127. package/lib/zudoku.auth-clerk.js +1 -1
  128. package/lib/zudoku.auth-openid.js +223 -219
  129. package/lib/zudoku.auth-openid.js.map +1 -1
  130. package/lib/zudoku.components.js +219 -219
  131. package/lib/zudoku.components.js.map +1 -1
  132. package/lib/zudoku.plugin-api-catalog.js +3 -3
  133. package/lib/zudoku.plugin-api-keys.js +5 -5
  134. package/lib/zudoku.plugin-custom-pages.js +2 -2
  135. package/lib/zudoku.plugin-markdown.js +1 -1
  136. package/lib/zudoku.plugin-openapi.js +4 -4
  137. package/lib/zudoku.plugin-redirect.js +1 -1
  138. package/package.json +1 -1
  139. package/src/app/main.css +50 -50
  140. package/src/lib/authentication/providers/auth0.tsx +1 -4
  141. package/src/lib/authentication/providers/openid.tsx +12 -5
  142. package/src/lib/components/Autocomplete.tsx +111 -0
  143. package/src/lib/components/Header.tsx +3 -3
  144. package/src/lib/components/index.ts +2 -2
  145. package/src/lib/plugins/markdown/MdxPage.tsx +9 -1
  146. package/src/lib/plugins/openapi/PlaygroundDialogWrapper.tsx +5 -0
  147. package/src/lib/plugins/openapi/Sidecar.tsx +1 -0
  148. package/src/lib/plugins/openapi/playground/ExamplesDropdown.tsx +51 -0
  149. package/src/lib/plugins/openapi/playground/Headers.tsx +138 -41
  150. package/src/lib/plugins/openapi/playground/Playground.tsx +156 -62
  151. package/src/lib/plugins/openapi/playground/QueryParams.tsx +89 -122
  152. package/src/lib/plugins/openapi/post-processors/removeExtensions.test.ts +58 -0
  153. package/src/lib/plugins/openapi/post-processors/removeExtensions.ts +7 -4
  154. package/src/lib/plugins/openapi/post-processors/removeParameters.test.ts +148 -0
  155. package/src/lib/plugins/openapi/post-processors/removeParameters.ts +101 -0
  156. package/src/lib/ui/Command.tsx +20 -0
  157. package/src/lib/util/joinUrl.ts +57 -0
  158. package/dist/lib/plugins/openapi/playground/EnumSelector.d.ts +0 -8
  159. package/dist/lib/plugins/openapi/playground/EnumSelector.js +0 -21
  160. package/dist/lib/plugins/openapi/playground/EnumSelector.js.map +0 -1
  161. package/lib/Button-oroWHXAy.js.map +0 -1
  162. package/lib/Command-D5DE0DD7.js +0 -611
  163. package/lib/Command-D5DE0DD7.js.map +0 -1
  164. package/lib/MdxPage-LNZLj_A5.js.map +0 -1
  165. package/lib/Spinner-C5gHXrVz.js +0 -7
  166. package/lib/Spinner-C5gHXrVz.js.map +0 -1
  167. package/lib/index-CaILD1AV.js +0 -1292
  168. package/lib/index-CaILD1AV.js.map +0 -1
  169. package/src/lib/plugins/openapi/playground/EnumSelector.tsx +0 -86
@@ -1,4 +1,3 @@
1
- import { EraserIcon } from "lucide-react";
2
1
  import {
3
2
  Control,
4
3
  Controller,
@@ -7,16 +6,10 @@ import {
7
6
  } from "react-hook-form";
8
7
  import { Card } from "zudoku/ui/Card.js";
9
8
  import { Checkbox } from "zudoku/ui/Checkbox.js";
10
- import { Button } from "../../../ui/Button.js";
9
+ import { Autocomplete } from "../../../components/Autocomplete.js";
11
10
  import { Input } from "../../../ui/Input.js";
12
- import { cn } from "../../../util/cn.js";
13
- import { EnumSelector } from "./EnumSelector.js";
14
11
  import { InlineInput } from "./InlineInput.js";
15
- import {
16
- NO_IDENTITY,
17
- type PlaygroundForm,
18
- type QueryParam,
19
- } from "./Playground.js";
12
+ import { type PlaygroundForm, type QueryParam } from "./Playground.js";
20
13
 
21
14
  export const QueryParams = ({
22
15
  control,
@@ -33,127 +26,101 @@ export const QueryParams = ({
33
26
 
34
27
  const requiredFields = queryParams.map((param) => Boolean(param.isRequired));
35
28
 
36
- const selectedIdentity = form.watch("identity");
37
- const hasSelectedIdentity = selectedIdentity !== NO_IDENTITY;
38
-
39
29
  return (
40
30
  <Card className="rounded-lg">
41
- <table className="w-full">
42
- <tbody>
43
- {fields
44
- .filter(
45
- // TODO remove this hack for Accu or make it more generic
46
- (field) => !(hasSelectedIdentity && field.name === "apikey"),
47
- )
48
- .map((field, i) => {
49
- const currentParam = queryParams.find(
50
- (param) => param.name === field.name,
51
- );
52
- return (
53
- <tr key={field.id} className="hover:bg-accent/40">
54
- <td className="w-5/12 flex items-center ps-3">
55
- <Controller
56
- control={control}
57
- name={`queryParams.${i}.active`}
58
- render={({ field }) => (
59
- <Checkbox
60
- variant="outline"
61
- id={`queryParams.${i}.active`}
62
- checked={field.value}
63
- onCheckedChange={field.onChange}
64
- />
65
- )}
66
- />
67
- <Controller
68
- control={control}
69
- render={({ field }) => (
70
- <InlineInput asChild>
71
- <label
72
- className="flex items-center cursor-pointer gap-1"
73
- htmlFor={`queryParams.${i}.active`}
74
- title={
75
- requiredFields[i] ? "Required field" : undefined
76
- }
77
- >
78
- {field.value}
79
- {requiredFields[i] && <sup>&nbsp;*</sup>}
80
- </label>
81
- </InlineInput>
82
- )}
83
- name={`queryParams.${i}.name`}
31
+ <div className="w-full ">
32
+ {fields.map((field, i) => {
33
+ const currentParam = queryParams.find(
34
+ (param) => param.name === field.name,
35
+ );
36
+ return (
37
+ <div
38
+ key={field.id}
39
+ className="hover:bg-accent/40 grid grid-cols-[min-content_1fr_1fr] gap-2 items-center px-3"
40
+ >
41
+ <Controller
42
+ control={control}
43
+ name={`queryParams.${i}.active`}
44
+ render={({ field }) => (
45
+ <Checkbox
46
+ variant="outline"
47
+ id={`queryParams.${i}.active`}
48
+ className="mr-2"
49
+ checked={field.value}
50
+ onCheckedChange={field.onChange}
51
+ />
52
+ )}
53
+ />
54
+ <Controller
55
+ control={control}
56
+ render={({ field }) =>
57
+ !requiredFields[i] ? (
58
+ <Autocomplete
59
+ value={field.value}
60
+ options={queryParams.map((param) => param.name)}
61
+ onChange={(e) => {
62
+ field.onChange(e);
63
+ }}
64
+ className="border-0 font-mono text-xs bg-transparent hover:bg-transparent"
84
65
  />
85
- </td>
86
- <td className="w-7/12">
87
- <div className="flex justify-between items-center">
88
- <Controller
89
- control={control}
90
- render={({ field }) => {
91
- const hasEnum =
92
- currentParam?.enum && currentParam.enum.length > 0;
66
+ ) : (
67
+ <InlineInput asChild>
68
+ <label
69
+ className="flex items-center cursor-pointer gap-1"
70
+ htmlFor={`queryParams.${i}.active`}
71
+ title={requiredFields[i] ? "Required field" : undefined}
72
+ >
73
+ {field.value}
74
+ {requiredFields[i] && <sup>&nbsp;*</sup>}
75
+ </label>
76
+ </InlineInput>
77
+ )
78
+ }
79
+ name={`queryParams.${i}.name`}
80
+ />
93
81
 
94
- if (!hasEnum) {
95
- return (
96
- <Input
97
- {...field}
98
- onChange={(e) => {
99
- field.onChange(e.target.value);
100
- if (e.target.value.length > 0) {
101
- form.setValue(
102
- `queryParams.${i}.active`,
103
- true,
104
- );
105
- }
106
- }}
107
- placeholder="Enter value"
108
- className="w-full border-0 shadow-none text-xs font-mono hover:bg-accent"
109
- />
110
- );
111
- }
82
+ <div className="flex justify-between items-center">
83
+ <Controller
84
+ control={control}
85
+ render={({ field }) => {
86
+ const hasEnum =
87
+ currentParam?.enum && currentParam.enum.length > 0;
112
88
 
113
- const enumValues = currentParam.enum ?? [];
89
+ if (!hasEnum) {
90
+ return (
91
+ <Input
92
+ {...field}
93
+ onChange={(e) => {
94
+ field.onChange(e.target.value);
95
+ if (e.target.value.length > 0) {
96
+ form.setValue(`queryParams.${i}.active`, true);
97
+ }
98
+ }}
99
+ placeholder="Enter value"
100
+ className="w-full border-0 shadow-none text-xs font-mono"
101
+ />
102
+ );
103
+ }
114
104
 
115
- return (
116
- <EnumSelector
117
- value={field.value}
118
- enumValues={enumValues}
119
- onChange={field.onChange}
120
- onValueSelected={() => {
121
- form.setValue(`queryParams.${i}.active`, true);
122
- }}
123
- />
124
- );
105
+ return (
106
+ <Autocomplete
107
+ value={field.value}
108
+ options={currentParam.enum ?? []}
109
+ onChange={(e) => {
110
+ field.onChange(e);
111
+ form.setValue(`queryParams.${i}.active`, true);
125
112
  }}
126
- name={`queryParams.${i}.value`}
127
- />
128
- <Controller
129
- control={control}
130
- render={({ field }) => (
131
- <Button
132
- size="icon"
133
- type="button"
134
- variant="ghost"
135
- aria-label="Clear value"
136
- className={cn(
137
- "ms-2 mr-1",
138
- field.value.length === 0
139
- ? "opacity-0 pointer-events-none"
140
- : "opacity-100",
141
- )}
142
- title="Clear value"
143
- onClick={() => field.onChange("")}
144
- >
145
- <EraserIcon size={16} />
146
- </Button>
147
- )}
148
- name={`queryParams.${i}.value`}
113
+ className="font-mono text-xs border-0 ring-1 ring-ring"
149
114
  />
150
- </div>
151
- </td>
152
- </tr>
153
- );
154
- })}
155
- </tbody>
156
- </table>
115
+ );
116
+ }}
117
+ name={`queryParams.${i}.value`}
118
+ />
119
+ </div>
120
+ </div>
121
+ );
122
+ })}
123
+ </div>
157
124
  </Card>
158
125
  );
159
126
  };
@@ -4,28 +4,34 @@ import { removeExtensions } from "./removeExtensions.js";
4
4
  const baseDoc = {
5
5
  openapi: "3.1.0",
6
6
  "x-root-ext": "remove me",
7
+ "x-zuplo-ext": "remove me too",
7
8
  info: {
8
9
  title: "Test API",
9
10
  version: "1.0.0",
10
11
  "x-info-ext": "remove me",
12
+ "x-zuplo-info": "remove me too",
11
13
  },
12
14
  paths: {
13
15
  "/test": {
14
16
  "x-path-ext": "remove me",
17
+ "x-zuplo-path": "remove me too",
15
18
  parameters: [
16
19
  {
17
20
  name: "param1",
18
21
  in: "query",
19
22
  schema: { type: "string" },
20
23
  "x-param-ext": "remove me",
24
+ "x-zuplo-param": "remove me too",
21
25
  },
22
26
  ],
23
27
  get: {
24
28
  "x-operation-ext": "remove me",
29
+ "x-zuplo-route": "remove me too",
25
30
  responses: {
26
31
  "200": {
27
32
  description: "OK",
28
33
  "x-response-ext": "remove me",
34
+ "x-zuplo-response": "remove me too",
29
35
  },
30
36
  },
31
37
  parameters: [
@@ -34,6 +40,7 @@ const baseDoc = {
34
40
  in: "header",
35
41
  schema: { type: "string" },
36
42
  "x-op-param-ext": "remove me",
43
+ "x-zuplo-param": "remove me too",
37
44
  },
38
45
  ],
39
46
  },
@@ -43,6 +50,7 @@ const baseDoc = {
43
50
  {
44
51
  name: "example",
45
52
  "x-tag-ext": "remove me",
53
+ "x-zuplo-tag": "remove me too",
46
54
  },
47
55
  ],
48
56
  components: {
@@ -52,6 +60,7 @@ const baseDoc = {
52
60
  name: "api_key",
53
61
  in: "header",
54
62
  "x-security-ext": "remove me",
63
+ "x-zuplo-security": "remove me too",
55
64
  },
56
65
  },
57
66
  },
@@ -141,4 +150,53 @@ describe("removeExtensions", () => {
141
150
 
142
151
  expect(processed).toEqual(docWithoutExtensions);
143
152
  });
153
+
154
+ it("removes extensions based on shouldRemove callback", () => {
155
+ const processed = removeExtensions({
156
+ shouldRemove: (key) => key.startsWith("x-zuplo"),
157
+ })(baseDoc);
158
+
159
+ // Should remove x-zuplo extensions
160
+ const removedExtensions = [
161
+ "x-zuplo-ext",
162
+ "info.x-zuplo-info",
163
+ "paths./test.x-zuplo-path",
164
+ "paths./test.parameters.0.x-zuplo-param",
165
+ "paths./test.get.x-zuplo-route",
166
+ "paths./test.get.responses.200.x-zuplo-response",
167
+ "paths./test.get.parameters.0.x-zuplo-param",
168
+ "tags.0.x-zuplo-tag",
169
+ "components.securitySchemes.ApiKeyAuth.x-zuplo-security",
170
+ ];
171
+
172
+ // Should keep other x- extensions
173
+ const keptExtensions = [
174
+ "x-root-ext",
175
+ "info.x-info-ext",
176
+ "paths./test.x-path-ext",
177
+ "paths./test.parameters.0.x-param-ext",
178
+ "paths./test.get.x-operation-ext",
179
+ "paths./test.get.responses.200.x-response-ext",
180
+ "paths./test.get.parameters.0.x-op-param-ext",
181
+ "tags.0.x-tag-ext",
182
+ "components.securitySchemes.ApiKeyAuth.x-security-ext",
183
+ ];
184
+
185
+ removedExtensions.forEach((ext) => {
186
+ expect(processed).not.toHaveProperty(ext.split("."));
187
+ });
188
+
189
+ keptExtensions.forEach((ext) => {
190
+ expect(processed).toHaveProperty(ext.split("."));
191
+ });
192
+
193
+ // Assert that non-x- fields remain unchanged
194
+ expect(processed).toHaveProperty("openapi", "3.1.0");
195
+ expect(processed).toHaveProperty("info.title", "Test API");
196
+ expect(processed).toHaveProperty(
197
+ "paths./test.get.responses.200.description",
198
+ "OK",
199
+ );
200
+ expect(processed).toHaveProperty("tags.0.name", "example");
201
+ });
144
202
  });
@@ -2,21 +2,24 @@ import { type RecordAny, traverse } from "./traverse.js";
2
2
 
3
3
  interface RemoveExtensionsOptions {
4
4
  keys?: string[];
5
+ shouldRemove?: (key: string) => boolean;
5
6
  }
6
7
 
7
8
  // Remove all `x-` prefixed key/value pairs, or filter by names if provided
8
9
  export const removeExtensions =
9
- ({ keys }: RemoveExtensionsOptions = {}) =>
10
+ ({ keys, shouldRemove }: RemoveExtensionsOptions = {}) =>
10
11
  (doc: RecordAny): RecordAny =>
11
12
  traverse(doc, (spec) => {
12
13
  const result: RecordAny = {};
13
14
 
14
15
  for (const [key, value] of Object.entries(spec)) {
15
16
  const isExtension = key.startsWith("x-");
16
- const shouldRemove =
17
- isExtension && (keys === undefined || keys.includes(key));
17
+ const shouldBeRemoved =
18
+ isExtension &&
19
+ (keys === undefined || keys.includes(key)) &&
20
+ (!shouldRemove || shouldRemove(key));
18
21
 
19
- if (shouldRemove) continue;
22
+ if (shouldBeRemoved) continue;
20
23
 
21
24
  result[key] = value;
22
25
  }
@@ -0,0 +1,148 @@
1
+ import { type OpenAPIV3_1 } from "openapi-types";
2
+ import { describe, expect, it } from "vitest";
3
+ import { removeParameters } from "./removeParameters.js";
4
+
5
+ const baseDoc: OpenAPIV3_1.Document = {
6
+ openapi: "3.1.0",
7
+ info: {
8
+ title: "Test API",
9
+ version: "1.0.0",
10
+ },
11
+ components: {
12
+ parameters: {
13
+ commonParam: {
14
+ name: "commonParam",
15
+ in: "query",
16
+ schema: { type: "string" },
17
+ },
18
+ headerParam: {
19
+ name: "headerParam",
20
+ in: "header",
21
+ schema: { type: "string" },
22
+ },
23
+ },
24
+ },
25
+ paths: {
26
+ "/test": {
27
+ parameters: [
28
+ {
29
+ name: "pathParam",
30
+ in: "path",
31
+ schema: { type: "string" },
32
+ required: true,
33
+ },
34
+ {
35
+ name: "pathHeader",
36
+ in: "header",
37
+ schema: { type: "string" },
38
+ required: true,
39
+ },
40
+ ],
41
+ get: {
42
+ parameters: [
43
+ {
44
+ name: "opParam",
45
+ in: "query",
46
+ schema: { type: "string" },
47
+ required: true,
48
+ },
49
+ {
50
+ name: "opHeader",
51
+ in: "header",
52
+ schema: { type: "string" },
53
+ required: true,
54
+ },
55
+ ],
56
+ responses: {
57
+ "200": {
58
+ description: "OK",
59
+ },
60
+ },
61
+ },
62
+ },
63
+ },
64
+ };
65
+
66
+ describe("removeParameters", () => {
67
+ it("removes parameters by name", () => {
68
+ const processed = removeParameters({
69
+ names: ["pathParam", "opParam"],
70
+ })(baseDoc);
71
+
72
+ expect(processed.paths["/test"].parameters).toHaveLength(1);
73
+ expect(processed.paths["/test"].parameters[0].name).toBe("pathHeader");
74
+ expect(processed.paths["/test"].get.parameters).toHaveLength(1);
75
+ expect(processed.paths["/test"].get.parameters[0].name).toBe("opHeader");
76
+ });
77
+
78
+ it("removes parameters by location", () => {
79
+ const processed = removeParameters({
80
+ in: ["header"],
81
+ })(baseDoc);
82
+
83
+ expect(processed.paths["/test"].parameters).toHaveLength(1);
84
+ expect(processed.paths["/test"].parameters[0].in).toBe("path");
85
+ expect(processed.paths["/test"].get.parameters).toHaveLength(1);
86
+ expect(processed.paths["/test"].get.parameters[0].in).toBe("query");
87
+ });
88
+
89
+ it("removes parameters using shouldRemove callback", () => {
90
+ const processed = removeParameters({
91
+ shouldRemove: ({ parameter }) =>
92
+ parameter.in === "header" && parameter.name.includes("op"),
93
+ })(baseDoc);
94
+
95
+ expect(processed.paths["/test"].parameters).toHaveLength(2);
96
+ expect(processed.paths["/test"].get.parameters).toHaveLength(1);
97
+ expect(processed.paths["/test"].get.parameters[0].name).toBe("opParam");
98
+ });
99
+
100
+ it("combines multiple removal criteria", () => {
101
+ const processed = removeParameters({
102
+ in: ["query", "header"],
103
+ shouldRemove: ({ parameter }) => parameter.name === "pathHeader",
104
+ })(baseDoc);
105
+
106
+ expect(processed.paths["/test"].parameters).toHaveLength(1);
107
+ expect(processed.paths["/test"].parameters[0].name).toBe("pathParam");
108
+ expect(processed.paths["/test"].get.parameters).toHaveLength(0);
109
+ });
110
+
111
+ it("handles missing parameters arrays", () => {
112
+ const docWithoutParams = {
113
+ openapi: "3.1.0",
114
+ paths: {
115
+ "/test": {
116
+ get: {
117
+ summary: "Test endpoint",
118
+ },
119
+ },
120
+ },
121
+ };
122
+
123
+ const processed = removeParameters({
124
+ names: ["someParam"],
125
+ })(docWithoutParams);
126
+
127
+ expect(processed).toEqual(docWithoutParams);
128
+ });
129
+
130
+ it("preserves non-parameter properties", () => {
131
+ const processed = removeParameters({
132
+ names: ["globalParam"],
133
+ })(baseDoc);
134
+
135
+ expect(processed.openapi).toBe("3.1.0");
136
+ expect(processed.paths["/test"].get).toBeDefined();
137
+ });
138
+
139
+ it("removes parameters from components", () => {
140
+ const processed = removeParameters({
141
+ in: ["header"],
142
+ })(baseDoc);
143
+
144
+ expect(Object.keys(processed.components.parameters)).toHaveLength(1);
145
+ expect(processed.components.parameters.commonParam).toBeDefined();
146
+ expect(processed.components.parameters.headerParam).toBeUndefined();
147
+ });
148
+ });
@@ -0,0 +1,101 @@
1
+ import { type RecordAny, traverse } from "./traverse.js";
2
+
3
+ interface RemoveParametersOptions {
4
+ // Names of parameters to remove
5
+ names?: string[];
6
+ // Specific locations to remove parameters from ('query', 'header', 'path', 'cookie')
7
+ in?: string[];
8
+ // Custom filter function
9
+ shouldRemove?: ({ parameter }: { parameter: RecordAny }) => boolean;
10
+ }
11
+
12
+ export const removeParameters =
13
+ ({ names, in: locations, shouldRemove }: RemoveParametersOptions = {}) =>
14
+ (doc: RecordAny): RecordAny =>
15
+ traverse(doc, (spec) => {
16
+ // Helper function to filter parameters
17
+ const filterParameters = (parameters: RecordAny[]) =>
18
+ parameters.filter((p) => {
19
+ if (names?.includes(p.name)) return false;
20
+ if (locations?.includes(p.in)) return false;
21
+ if (shouldRemove?.({ parameter: p })) return false;
22
+ return true;
23
+ });
24
+
25
+ // Handle components.parameters
26
+ if (spec.components?.parameters) {
27
+ spec = {
28
+ ...spec,
29
+ components: {
30
+ ...spec.components,
31
+ parameters: Object.fromEntries(
32
+ Object.entries(spec.components.parameters).filter(
33
+ ([_, param]) => {
34
+ const p = param as RecordAny;
35
+ if (p.$ref) return true; // Skip references
36
+ return (
37
+ !names?.includes(p.name) &&
38
+ !locations?.includes(p.in) &&
39
+ !shouldRemove?.({ parameter: p })
40
+ );
41
+ },
42
+ ),
43
+ ),
44
+ },
45
+ };
46
+ }
47
+
48
+ // Handle paths
49
+ if (spec.paths) {
50
+ const updatedPaths: RecordAny = {};
51
+
52
+ for (const [path, pathItem] of Object.entries(spec.paths)) {
53
+ if (typeof pathItem !== "object" || pathItem === null) {
54
+ updatedPaths[path] = pathItem;
55
+ continue;
56
+ }
57
+
58
+ let updatedPathItem = { ...pathItem };
59
+
60
+ // Handle path-level parameters
61
+ if (
62
+ "parameters" in updatedPathItem &&
63
+ Array.isArray(updatedPathItem.parameters)
64
+ ) {
65
+ updatedPathItem.parameters = filterParameters(
66
+ updatedPathItem.parameters,
67
+ );
68
+ }
69
+
70
+ // Handle operation-level parameters
71
+ for (const method of Object.keys(updatedPathItem)) {
72
+ const pathItemWithMethods = updatedPathItem as Record<
73
+ string,
74
+ RecordAny
75
+ >;
76
+
77
+ if (
78
+ method === "parameters" ||
79
+ typeof pathItemWithMethods[method] !== "object"
80
+ ) {
81
+ continue;
82
+ }
83
+
84
+ const operation = pathItemWithMethods[method];
85
+ if (Array.isArray(operation.parameters)) {
86
+ pathItemWithMethods[method] = {
87
+ ...operation,
88
+ parameters: filterParameters(operation.parameters),
89
+ };
90
+ updatedPathItem = pathItemWithMethods;
91
+ }
92
+ }
93
+
94
+ updatedPaths[path] = updatedPathItem;
95
+ }
96
+
97
+ spec = { ...spec, paths: updatedPaths };
98
+ }
99
+
100
+ return spec;
101
+ });
@@ -52,6 +52,25 @@ const CommandInput = React.forwardRef<
52
52
 
53
53
  CommandInput.displayName = CommandPrimitive.Input.displayName;
54
54
 
55
+ const CommandInlineInput = React.forwardRef<
56
+ React.ElementRef<typeof CommandPrimitive.Input>,
57
+ React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
58
+ >(({ className, ...props }, ref) => (
59
+ // eslint-disable-next-line react/no-unknown-property
60
+ <div className="flex items-center" cmdk-input-wrapper="">
61
+ <CommandPrimitive.Input
62
+ ref={ref}
63
+ className={cn(
64
+ "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
65
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
66
+ className,
67
+ )}
68
+ {...props}
69
+ />
70
+ </div>
71
+ ));
72
+
73
+ CommandInlineInput.displayName = CommandPrimitive.Input.displayName;
55
74
  const CommandList = React.forwardRef<
56
75
  React.ElementRef<typeof CommandPrimitive.List>,
57
76
  React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
@@ -143,6 +162,7 @@ export {
143
162
  CommandDialog,
144
163
  CommandEmpty,
145
164
  CommandGroup,
165
+ CommandInlineInput,
146
166
  CommandInput,
147
167
  CommandItem,
148
168
  CommandList,