@btst/stack 1.6.0 → 1.7.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.
Files changed (41) hide show
  1. package/dist/api/index.cjs +7 -1
  2. package/dist/api/index.d.cts +2 -2
  3. package/dist/api/index.d.mts +2 -2
  4. package/dist/api/index.d.ts +2 -2
  5. package/dist/api/index.mjs +7 -1
  6. package/dist/client/index.d.cts +1 -1
  7. package/dist/client/index.d.mts +1 -1
  8. package/dist/client/index.d.ts +1 -1
  9. package/dist/index.d.cts +1 -1
  10. package/dist/index.d.mts +1 -1
  11. package/dist/index.d.ts +1 -1
  12. package/dist/packages/better-stack/src/plugins/open-api/api/generator.cjs +300 -0
  13. package/dist/packages/better-stack/src/plugins/open-api/api/generator.mjs +284 -0
  14. package/dist/packages/better-stack/src/plugins/open-api/api/plugin.cjs +115 -0
  15. package/dist/packages/better-stack/src/plugins/open-api/api/plugin.mjs +113 -0
  16. package/dist/packages/better-stack/src/plugins/open-api/db.cjs +7 -0
  17. package/dist/packages/better-stack/src/plugins/open-api/db.mjs +5 -0
  18. package/dist/packages/better-stack/src/plugins/open-api/logo.cjs +8 -0
  19. package/dist/packages/better-stack/src/plugins/open-api/logo.mjs +6 -0
  20. package/dist/plugins/api/index.d.cts +2 -2
  21. package/dist/plugins/api/index.d.mts +2 -2
  22. package/dist/plugins/api/index.d.ts +2 -2
  23. package/dist/plugins/client/index.d.cts +2 -2
  24. package/dist/plugins/client/index.d.mts +2 -2
  25. package/dist/plugins/client/index.d.ts +2 -2
  26. package/dist/plugins/open-api/api/index.cjs +9 -0
  27. package/dist/plugins/open-api/api/index.d.cts +95 -0
  28. package/dist/plugins/open-api/api/index.d.mts +95 -0
  29. package/dist/plugins/open-api/api/index.d.ts +95 -0
  30. package/dist/plugins/open-api/api/index.mjs +2 -0
  31. package/dist/shared/{stack.ByOugz9d.d.cts → stack.CSce37mX.d.cts} +15 -2
  32. package/dist/shared/{stack.ByOugz9d.d.mts → stack.CSce37mX.d.mts} +15 -2
  33. package/dist/shared/{stack.ByOugz9d.d.ts → stack.CSce37mX.d.ts} +15 -2
  34. package/package.json +14 -1
  35. package/src/api/index.ts +14 -2
  36. package/src/plugins/open-api/api/generator.ts +433 -0
  37. package/src/plugins/open-api/api/index.ts +8 -0
  38. package/src/plugins/open-api/api/plugin.ts +243 -0
  39. package/src/plugins/open-api/db.ts +7 -0
  40. package/src/plugins/open-api/logo.ts +7 -0
  41. package/src/types.ts +15 -1
@@ -11,8 +11,14 @@ function betterStack(config) {
11
11
  for (const [pluginKey, plugin] of Object.entries(plugins)) {
12
12
  betterDbSchema = betterDbSchema.use(plugin.dbPlugin);
13
13
  }
14
+ const adapterInstance = adapter(betterDbSchema);
15
+ const context = {
16
+ plugins,
17
+ basePath,
18
+ adapter: adapterInstance
19
+ };
14
20
  for (const [pluginKey, plugin] of Object.entries(plugins)) {
15
- const pluginRoutes = plugin.routes(adapter(betterDbSchema));
21
+ const pluginRoutes = plugin.routes(adapterInstance, context);
16
22
  for (const [routeKey, endpoint] of Object.entries(pluginRoutes)) {
17
23
  const compositeKey = `${pluginKey}_${routeKey}`;
18
24
  allRoutes[compositeKey] = endpoint;
@@ -1,5 +1,5 @@
1
- import { d as PrefixedPluginRoutes, e as BackendLibConfig, f as BackendLib } from '../shared/stack.ByOugz9d.cjs';
2
- export { B as BackendPlugin } from '../shared/stack.ByOugz9d.cjs';
1
+ import { e as PrefixedPluginRoutes, f as BackendLibConfig, g as BackendLib } from '../shared/stack.CSce37mX.cjs';
2
+ export { B as BackendPlugin, a as BetterStackContext } from '../shared/stack.CSce37mX.cjs';
3
3
  export { toNodeHandler } from 'better-call/node';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
@@ -1,5 +1,5 @@
1
- import { d as PrefixedPluginRoutes, e as BackendLibConfig, f as BackendLib } from '../shared/stack.ByOugz9d.mjs';
2
- export { B as BackendPlugin } from '../shared/stack.ByOugz9d.mjs';
1
+ import { e as PrefixedPluginRoutes, f as BackendLibConfig, g as BackendLib } from '../shared/stack.CSce37mX.mjs';
2
+ export { B as BackendPlugin, a as BetterStackContext } from '../shared/stack.CSce37mX.mjs';
3
3
  export { toNodeHandler } from 'better-call/node';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
@@ -1,5 +1,5 @@
1
- import { d as PrefixedPluginRoutes, e as BackendLibConfig, f as BackendLib } from '../shared/stack.ByOugz9d.js';
2
- export { B as BackendPlugin } from '../shared/stack.ByOugz9d.js';
1
+ import { e as PrefixedPluginRoutes, f as BackendLibConfig, g as BackendLib } from '../shared/stack.CSce37mX.js';
2
+ export { B as BackendPlugin, a as BetterStackContext } from '../shared/stack.CSce37mX.js';
3
3
  export { toNodeHandler } from 'better-call/node';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
@@ -9,8 +9,14 @@ function betterStack(config) {
9
9
  for (const [pluginKey, plugin] of Object.entries(plugins)) {
10
10
  betterDbSchema = betterDbSchema.use(plugin.dbPlugin);
11
11
  }
12
+ const adapterInstance = adapter(betterDbSchema);
13
+ const context = {
14
+ plugins,
15
+ basePath,
16
+ adapter: adapterInstance
17
+ };
12
18
  for (const [pluginKey, plugin] of Object.entries(plugins)) {
13
- const pluginRoutes = plugin.routes(adapter(betterDbSchema));
19
+ const pluginRoutes = plugin.routes(adapterInstance, context);
14
20
  for (const [routeKey, endpoint] of Object.entries(pluginRoutes)) {
15
21
  const compositeKey = `${pluginKey}_${routeKey}`;
16
22
  allRoutes[compositeKey] = endpoint;
@@ -1,4 +1,4 @@
1
- import { S as Sitemap, C as ClientPlugin, a as PluginRoutes, b as ClientLibConfig, c as ClientLib } from '../shared/stack.ByOugz9d.cjs';
1
+ import { S as Sitemap, C as ClientPlugin, b as PluginRoutes, c as ClientLibConfig, d as ClientLib } from '../shared/stack.CSce37mX.cjs';
2
2
  import '@btst/yar';
3
3
  import '@btst/db';
4
4
  import 'better-call';
@@ -1,4 +1,4 @@
1
- import { S as Sitemap, C as ClientPlugin, a as PluginRoutes, b as ClientLibConfig, c as ClientLib } from '../shared/stack.ByOugz9d.mjs';
1
+ import { S as Sitemap, C as ClientPlugin, b as PluginRoutes, c as ClientLibConfig, d as ClientLib } from '../shared/stack.CSce37mX.mjs';
2
2
  import '@btst/yar';
3
3
  import '@btst/db';
4
4
  import 'better-call';
@@ -1,4 +1,4 @@
1
- import { S as Sitemap, C as ClientPlugin, a as PluginRoutes, b as ClientLibConfig, c as ClientLib } from '../shared/stack.ByOugz9d.js';
1
+ import { S as Sitemap, C as ClientPlugin, b as PluginRoutes, c as ClientLibConfig, d as ClientLib } from '../shared/stack.CSce37mX.js';
2
2
  import '@btst/yar';
3
3
  import '@btst/db';
4
4
  import 'better-call';
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { betterStack } from './api/index.cjs';
2
2
  export { toNodeHandler } from 'better-call/node';
3
- export { f as BackendLib, e as BackendLibConfig, B as BackendPlugin } from './shared/stack.ByOugz9d.cjs';
3
+ export { g as BackendLib, f as BackendLibConfig, B as BackendPlugin, a as BetterStackContext } from './shared/stack.CSce37mX.cjs';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
6
6
  import 'better-call';
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { betterStack } from './api/index.mjs';
2
2
  export { toNodeHandler } from 'better-call/node';
3
- export { f as BackendLib, e as BackendLibConfig, B as BackendPlugin } from './shared/stack.ByOugz9d.mjs';
3
+ export { g as BackendLib, f as BackendLibConfig, B as BackendPlugin, a as BetterStackContext } from './shared/stack.CSce37mX.mjs';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
6
6
  import 'better-call';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { betterStack } from './api/index.js';
2
2
  export { toNodeHandler } from 'better-call/node';
3
- export { f as BackendLib, e as BackendLibConfig, B as BackendPlugin } from './shared/stack.ByOugz9d.js';
3
+ export { g as BackendLib, f as BackendLibConfig, B as BackendPlugin, a as BetterStackContext } from './shared/stack.CSce37mX.js';
4
4
  import '@btst/yar';
5
5
  import '@btst/db';
6
6
  import 'better-call';
@@ -0,0 +1,300 @@
1
+ 'use strict';
2
+
3
+ const z = require('zod');
4
+
5
+ function _interopNamespaceCompat(e) {
6
+ if (e && typeof e === 'object' && 'default' in e) return e;
7
+ const n = Object.create(null);
8
+ if (e) {
9
+ for (const k in e) {
10
+ n[k] = e[k];
11
+ }
12
+ }
13
+ n.default = e;
14
+ return n;
15
+ }
16
+
17
+ const z__namespace = /*#__PURE__*/_interopNamespaceCompat(z);
18
+
19
+ function toOpenApiPath(path) {
20
+ return path.split("/").map((part) => part.startsWith(":") ? `{${part.slice(1)}}` : part).join("/");
21
+ }
22
+ function getTypeFromZodType(zodType) {
23
+ if (zodType instanceof z__namespace.ZodString) return "string";
24
+ if (zodType instanceof z__namespace.ZodNumber) return "number";
25
+ if (zodType instanceof z__namespace.ZodBoolean) return "boolean";
26
+ if (zodType instanceof z__namespace.ZodArray) return "array";
27
+ if (zodType instanceof z__namespace.ZodObject) return "object";
28
+ const type = zodType.type;
29
+ if (type === "string") return "string";
30
+ if (type === "number") return "number";
31
+ if (type === "boolean") return "boolean";
32
+ if (type === "array") return "array";
33
+ if (type === "object") return "object";
34
+ return "string";
35
+ }
36
+ function processZodType(zodType) {
37
+ if (zodType instanceof z__namespace.ZodOptional) {
38
+ const innerType = zodType._def?.innerType || zodType.unwrap?.();
39
+ if (innerType) {
40
+ return processZodType(innerType);
41
+ }
42
+ }
43
+ if (zodType instanceof z__namespace.ZodNullable) {
44
+ const innerType = zodType._def?.innerType || zodType.unwrap?.();
45
+ if (innerType) {
46
+ const innerSchema = processZodType(innerType);
47
+ return {
48
+ ...innerSchema,
49
+ nullable: true
50
+ };
51
+ }
52
+ }
53
+ if (zodType instanceof z__namespace.ZodDefault) {
54
+ const innerType = zodType._def?.innerType;
55
+ const defaultValue = zodType._def?.defaultValue?.();
56
+ if (innerType) {
57
+ const innerSchema = processZodType(innerType);
58
+ if (defaultValue !== void 0) {
59
+ return {
60
+ ...innerSchema,
61
+ default: defaultValue
62
+ };
63
+ }
64
+ return innerSchema;
65
+ }
66
+ }
67
+ if (zodType instanceof z__namespace.ZodObject) {
68
+ const shape = zodType.shape || zodType._def?.shape?.();
69
+ if (shape) {
70
+ const properties = {};
71
+ const required = [];
72
+ for (const [key, value] of Object.entries(shape)) {
73
+ if (value instanceof z__namespace.ZodType) {
74
+ properties[key] = processZodType(value);
75
+ if (!(value instanceof z__namespace.ZodOptional)) {
76
+ required.push(key);
77
+ }
78
+ }
79
+ }
80
+ return {
81
+ type: "object",
82
+ properties,
83
+ ...required.length > 0 ? { required } : {}
84
+ };
85
+ }
86
+ }
87
+ if (zodType instanceof z__namespace.ZodArray) {
88
+ const elementType = zodType._def?.type || zodType.element;
89
+ return {
90
+ type: "array",
91
+ items: elementType ? processZodType(elementType) : { type: "string" }
92
+ };
93
+ }
94
+ if (zodType instanceof z__namespace.ZodEnum) {
95
+ const values = zodType._def?.values || zodType.options;
96
+ return {
97
+ type: "string",
98
+ enum: values
99
+ };
100
+ }
101
+ if (zodType instanceof z__namespace.ZodLiteral) {
102
+ const value = zodType._def?.value || zodType.value;
103
+ let type;
104
+ if (value === null) {
105
+ type = "null";
106
+ } else if (value === void 0) {
107
+ return { nullable: true };
108
+ } else {
109
+ type = typeof value;
110
+ }
111
+ return {
112
+ type,
113
+ const: value
114
+ };
115
+ }
116
+ if (zodType instanceof z__namespace.ZodUnion) {
117
+ const options = zodType._def?.options || zodType.options;
118
+ if (options && Array.isArray(options)) {
119
+ return {
120
+ oneOf: options.map((opt) => processZodType(opt))
121
+ };
122
+ }
123
+ }
124
+ if (zodType._def?.coerce) {
125
+ const innerType = zodType._def?.innerType;
126
+ if (innerType) {
127
+ return processZodType(innerType);
128
+ }
129
+ }
130
+ return {
131
+ type: getTypeFromZodType(zodType)
132
+ };
133
+ }
134
+ function getParameters(options) {
135
+ const parameters = [];
136
+ if (options.query instanceof z__namespace.ZodObject) {
137
+ const shape = options.query.shape || options.query._def?.shape?.();
138
+ if (shape) {
139
+ for (const [key, value] of Object.entries(shape)) {
140
+ if (value instanceof z__namespace.ZodType) {
141
+ parameters.push({
142
+ name: key,
143
+ in: "query",
144
+ required: !(value instanceof z__namespace.ZodOptional),
145
+ schema: processZodType(value)
146
+ });
147
+ }
148
+ }
149
+ }
150
+ }
151
+ if (options.params instanceof z__namespace.ZodObject) {
152
+ const shape = options.params.shape || options.params._def?.shape?.();
153
+ if (shape) {
154
+ for (const [key, value] of Object.entries(shape)) {
155
+ if (value instanceof z__namespace.ZodType) {
156
+ parameters.push({
157
+ name: key,
158
+ in: "path",
159
+ required: true,
160
+ schema: processZodType(value)
161
+ });
162
+ }
163
+ }
164
+ }
165
+ }
166
+ return parameters;
167
+ }
168
+ function getRequestBody(options) {
169
+ if (!options.body) return void 0;
170
+ if (options.body instanceof z__namespace.ZodType) {
171
+ const schema = processZodType(options.body);
172
+ const isOptional = options.body instanceof z__namespace.ZodOptional;
173
+ return {
174
+ required: !isOptional,
175
+ content: {
176
+ "application/json": {
177
+ schema
178
+ }
179
+ }
180
+ };
181
+ }
182
+ return void 0;
183
+ }
184
+ function createErrorSchema() {
185
+ return {
186
+ type: "object",
187
+ properties: {
188
+ message: { type: "string" }
189
+ },
190
+ required: ["message"]
191
+ };
192
+ }
193
+ function getErrorResponses() {
194
+ return {
195
+ "400": {
196
+ description: "Bad Request",
197
+ content: { "application/json": { schema: createErrorSchema() } }
198
+ },
199
+ "401": {
200
+ description: "Unauthorized",
201
+ content: { "application/json": { schema: createErrorSchema() } }
202
+ },
203
+ "403": {
204
+ description: "Forbidden",
205
+ content: { "application/json": { schema: createErrorSchema() } }
206
+ },
207
+ "404": {
208
+ description: "Not Found",
209
+ content: { "application/json": { schema: createErrorSchema() } }
210
+ },
211
+ "500": {
212
+ description: "Internal Server Error",
213
+ content: { "application/json": { schema: createErrorSchema() } }
214
+ }
215
+ };
216
+ }
217
+ function generateOpenAPISchema(context, options) {
218
+ const paths = {};
219
+ const tags = [];
220
+ for (const [pluginKey, plugin] of Object.entries(context.plugins)) {
221
+ if (pluginKey === "openApi" || plugin.name === "open-api") {
222
+ continue;
223
+ }
224
+ const pluginRoutes = plugin.routes(context.adapter, context);
225
+ const tagName = pluginKey.charAt(0).toUpperCase() + pluginKey.slice(1);
226
+ tags.push({
227
+ name: tagName,
228
+ description: `${tagName} plugin endpoints`
229
+ });
230
+ for (const [routeKey, endpoint] of Object.entries(pluginRoutes)) {
231
+ const ep = endpoint;
232
+ const path = ep.path;
233
+ const endpointOptions = ep.options || {};
234
+ const method = (endpointOptions.method || "GET").toLowerCase();
235
+ if (!path) continue;
236
+ const openApiPath = toOpenApiPath(path);
237
+ if (!paths[openApiPath]) {
238
+ paths[openApiPath] = {};
239
+ }
240
+ const operation = {
241
+ tags: [tagName],
242
+ operationId: `${pluginKey}_${routeKey}`,
243
+ summary: endpointOptions.metadata?.openapi?.summary,
244
+ description: endpointOptions.metadata?.openapi?.description,
245
+ parameters: getParameters(endpointOptions),
246
+ responses: {
247
+ "200": {
248
+ description: "Successful response",
249
+ content: {
250
+ "application/json": {
251
+ schema: { type: "object" }
252
+ }
253
+ }
254
+ },
255
+ ...getErrorResponses()
256
+ }
257
+ };
258
+ if (["post", "put", "patch"].includes(method)) {
259
+ const requestBody = getRequestBody(endpointOptions);
260
+ if (requestBody) {
261
+ operation.requestBody = requestBody;
262
+ }
263
+ }
264
+ paths[openApiPath][method] = operation;
265
+ }
266
+ }
267
+ return {
268
+ openapi: "3.1.0",
269
+ info: {
270
+ title: options?.title || "Better Stack API",
271
+ description: options?.description || "API Reference for your Better Stack application",
272
+ version: options?.version || "1.0.0"
273
+ },
274
+ servers: [
275
+ {
276
+ url: context.basePath,
277
+ description: "API Server"
278
+ }
279
+ ],
280
+ tags,
281
+ paths,
282
+ components: {
283
+ securitySchemes: {
284
+ bearerAuth: {
285
+ type: "http",
286
+ scheme: "bearer",
287
+ description: "Bearer token authentication"
288
+ },
289
+ cookieAuth: {
290
+ type: "apiKey",
291
+ in: "cookie",
292
+ name: "session",
293
+ description: "Session cookie authentication"
294
+ }
295
+ }
296
+ }
297
+ };
298
+ }
299
+
300
+ exports.generateOpenAPISchema = generateOpenAPISchema;
@@ -0,0 +1,284 @@
1
+ import * as z from 'zod';
2
+
3
+ function toOpenApiPath(path) {
4
+ return path.split("/").map((part) => part.startsWith(":") ? `{${part.slice(1)}}` : part).join("/");
5
+ }
6
+ function getTypeFromZodType(zodType) {
7
+ if (zodType instanceof z.ZodString) return "string";
8
+ if (zodType instanceof z.ZodNumber) return "number";
9
+ if (zodType instanceof z.ZodBoolean) return "boolean";
10
+ if (zodType instanceof z.ZodArray) return "array";
11
+ if (zodType instanceof z.ZodObject) return "object";
12
+ const type = zodType.type;
13
+ if (type === "string") return "string";
14
+ if (type === "number") return "number";
15
+ if (type === "boolean") return "boolean";
16
+ if (type === "array") return "array";
17
+ if (type === "object") return "object";
18
+ return "string";
19
+ }
20
+ function processZodType(zodType) {
21
+ if (zodType instanceof z.ZodOptional) {
22
+ const innerType = zodType._def?.innerType || zodType.unwrap?.();
23
+ if (innerType) {
24
+ return processZodType(innerType);
25
+ }
26
+ }
27
+ if (zodType instanceof z.ZodNullable) {
28
+ const innerType = zodType._def?.innerType || zodType.unwrap?.();
29
+ if (innerType) {
30
+ const innerSchema = processZodType(innerType);
31
+ return {
32
+ ...innerSchema,
33
+ nullable: true
34
+ };
35
+ }
36
+ }
37
+ if (zodType instanceof z.ZodDefault) {
38
+ const innerType = zodType._def?.innerType;
39
+ const defaultValue = zodType._def?.defaultValue?.();
40
+ if (innerType) {
41
+ const innerSchema = processZodType(innerType);
42
+ if (defaultValue !== void 0) {
43
+ return {
44
+ ...innerSchema,
45
+ default: defaultValue
46
+ };
47
+ }
48
+ return innerSchema;
49
+ }
50
+ }
51
+ if (zodType instanceof z.ZodObject) {
52
+ const shape = zodType.shape || zodType._def?.shape?.();
53
+ if (shape) {
54
+ const properties = {};
55
+ const required = [];
56
+ for (const [key, value] of Object.entries(shape)) {
57
+ if (value instanceof z.ZodType) {
58
+ properties[key] = processZodType(value);
59
+ if (!(value instanceof z.ZodOptional)) {
60
+ required.push(key);
61
+ }
62
+ }
63
+ }
64
+ return {
65
+ type: "object",
66
+ properties,
67
+ ...required.length > 0 ? { required } : {}
68
+ };
69
+ }
70
+ }
71
+ if (zodType instanceof z.ZodArray) {
72
+ const elementType = zodType._def?.type || zodType.element;
73
+ return {
74
+ type: "array",
75
+ items: elementType ? processZodType(elementType) : { type: "string" }
76
+ };
77
+ }
78
+ if (zodType instanceof z.ZodEnum) {
79
+ const values = zodType._def?.values || zodType.options;
80
+ return {
81
+ type: "string",
82
+ enum: values
83
+ };
84
+ }
85
+ if (zodType instanceof z.ZodLiteral) {
86
+ const value = zodType._def?.value || zodType.value;
87
+ let type;
88
+ if (value === null) {
89
+ type = "null";
90
+ } else if (value === void 0) {
91
+ return { nullable: true };
92
+ } else {
93
+ type = typeof value;
94
+ }
95
+ return {
96
+ type,
97
+ const: value
98
+ };
99
+ }
100
+ if (zodType instanceof z.ZodUnion) {
101
+ const options = zodType._def?.options || zodType.options;
102
+ if (options && Array.isArray(options)) {
103
+ return {
104
+ oneOf: options.map((opt) => processZodType(opt))
105
+ };
106
+ }
107
+ }
108
+ if (zodType._def?.coerce) {
109
+ const innerType = zodType._def?.innerType;
110
+ if (innerType) {
111
+ return processZodType(innerType);
112
+ }
113
+ }
114
+ return {
115
+ type: getTypeFromZodType(zodType)
116
+ };
117
+ }
118
+ function getParameters(options) {
119
+ const parameters = [];
120
+ if (options.query instanceof z.ZodObject) {
121
+ const shape = options.query.shape || options.query._def?.shape?.();
122
+ if (shape) {
123
+ for (const [key, value] of Object.entries(shape)) {
124
+ if (value instanceof z.ZodType) {
125
+ parameters.push({
126
+ name: key,
127
+ in: "query",
128
+ required: !(value instanceof z.ZodOptional),
129
+ schema: processZodType(value)
130
+ });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ if (options.params instanceof z.ZodObject) {
136
+ const shape = options.params.shape || options.params._def?.shape?.();
137
+ if (shape) {
138
+ for (const [key, value] of Object.entries(shape)) {
139
+ if (value instanceof z.ZodType) {
140
+ parameters.push({
141
+ name: key,
142
+ in: "path",
143
+ required: true,
144
+ schema: processZodType(value)
145
+ });
146
+ }
147
+ }
148
+ }
149
+ }
150
+ return parameters;
151
+ }
152
+ function getRequestBody(options) {
153
+ if (!options.body) return void 0;
154
+ if (options.body instanceof z.ZodType) {
155
+ const schema = processZodType(options.body);
156
+ const isOptional = options.body instanceof z.ZodOptional;
157
+ return {
158
+ required: !isOptional,
159
+ content: {
160
+ "application/json": {
161
+ schema
162
+ }
163
+ }
164
+ };
165
+ }
166
+ return void 0;
167
+ }
168
+ function createErrorSchema() {
169
+ return {
170
+ type: "object",
171
+ properties: {
172
+ message: { type: "string" }
173
+ },
174
+ required: ["message"]
175
+ };
176
+ }
177
+ function getErrorResponses() {
178
+ return {
179
+ "400": {
180
+ description: "Bad Request",
181
+ content: { "application/json": { schema: createErrorSchema() } }
182
+ },
183
+ "401": {
184
+ description: "Unauthorized",
185
+ content: { "application/json": { schema: createErrorSchema() } }
186
+ },
187
+ "403": {
188
+ description: "Forbidden",
189
+ content: { "application/json": { schema: createErrorSchema() } }
190
+ },
191
+ "404": {
192
+ description: "Not Found",
193
+ content: { "application/json": { schema: createErrorSchema() } }
194
+ },
195
+ "500": {
196
+ description: "Internal Server Error",
197
+ content: { "application/json": { schema: createErrorSchema() } }
198
+ }
199
+ };
200
+ }
201
+ function generateOpenAPISchema(context, options) {
202
+ const paths = {};
203
+ const tags = [];
204
+ for (const [pluginKey, plugin] of Object.entries(context.plugins)) {
205
+ if (pluginKey === "openApi" || plugin.name === "open-api") {
206
+ continue;
207
+ }
208
+ const pluginRoutes = plugin.routes(context.adapter, context);
209
+ const tagName = pluginKey.charAt(0).toUpperCase() + pluginKey.slice(1);
210
+ tags.push({
211
+ name: tagName,
212
+ description: `${tagName} plugin endpoints`
213
+ });
214
+ for (const [routeKey, endpoint] of Object.entries(pluginRoutes)) {
215
+ const ep = endpoint;
216
+ const path = ep.path;
217
+ const endpointOptions = ep.options || {};
218
+ const method = (endpointOptions.method || "GET").toLowerCase();
219
+ if (!path) continue;
220
+ const openApiPath = toOpenApiPath(path);
221
+ if (!paths[openApiPath]) {
222
+ paths[openApiPath] = {};
223
+ }
224
+ const operation = {
225
+ tags: [tagName],
226
+ operationId: `${pluginKey}_${routeKey}`,
227
+ summary: endpointOptions.metadata?.openapi?.summary,
228
+ description: endpointOptions.metadata?.openapi?.description,
229
+ parameters: getParameters(endpointOptions),
230
+ responses: {
231
+ "200": {
232
+ description: "Successful response",
233
+ content: {
234
+ "application/json": {
235
+ schema: { type: "object" }
236
+ }
237
+ }
238
+ },
239
+ ...getErrorResponses()
240
+ }
241
+ };
242
+ if (["post", "put", "patch"].includes(method)) {
243
+ const requestBody = getRequestBody(endpointOptions);
244
+ if (requestBody) {
245
+ operation.requestBody = requestBody;
246
+ }
247
+ }
248
+ paths[openApiPath][method] = operation;
249
+ }
250
+ }
251
+ return {
252
+ openapi: "3.1.0",
253
+ info: {
254
+ title: options?.title || "Better Stack API",
255
+ description: options?.description || "API Reference for your Better Stack application",
256
+ version: options?.version || "1.0.0"
257
+ },
258
+ servers: [
259
+ {
260
+ url: context.basePath,
261
+ description: "API Server"
262
+ }
263
+ ],
264
+ tags,
265
+ paths,
266
+ components: {
267
+ securitySchemes: {
268
+ bearerAuth: {
269
+ type: "http",
270
+ scheme: "bearer",
271
+ description: "Bearer token authentication"
272
+ },
273
+ cookieAuth: {
274
+ type: "apiKey",
275
+ in: "cookie",
276
+ name: "session",
277
+ description: "Session cookie authentication"
278
+ }
279
+ }
280
+ }
281
+ };
282
+ }
283
+
284
+ export { generateOpenAPISchema };