serverstruct 1.0.0 → 1.2.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/.claude/settings.local.json +8 -0
- package/OPENAPI.md +286 -0
- package/OTEL.md +208 -0
- package/README.md +224 -81
- package/dist/index.cjs +193 -24
- package/dist/index.d.cts +175 -23
- package/dist/index.d.mts +175 -23
- package/dist/index.mjs +188 -24
- package/dist/openapi.cjs +242 -0
- package/dist/openapi.d.cts +241 -0
- package/dist/openapi.d.mts +241 -0
- package/dist/openapi.mjs +231 -0
- package/dist/openapi.scalar.cjs +13 -0
- package/dist/openapi.scalar.d.cts +8 -0
- package/dist/openapi.scalar.d.mts +8 -0
- package/dist/openapi.scalar.mjs +13 -0
- package/package.json +46 -10
- package/tsdown.config.mts +11 -0
package/dist/index.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { H3, serve } from "h3";
|
|
2
1
|
import { Box, factory } from "getbox";
|
|
2
|
+
import { H3, defineHandler, defineMiddleware, serve } from "h3";
|
|
3
3
|
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
/**
|
|
6
|
-
* Creates an h3 application
|
|
6
|
+
* Creates an h3 application.
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* @param setup - Function that configures the app. Receives a fresh H3 instance
|
|
9
|
+
* and Box instance. Can add routes to the provided app, or create
|
|
10
|
+
* and return a new H3 instance.
|
|
11
11
|
* @param box - Optional Box instance. If not provided, creates a new one.
|
|
12
|
-
* @returns Object with `app` (H3 instance) and `serve` method.
|
|
12
|
+
* @returns Object with `app` (H3 instance), `box` (Box instance), and `serve` method.
|
|
13
13
|
*
|
|
14
14
|
* @example
|
|
15
15
|
* ```typescript
|
|
@@ -30,28 +30,33 @@ import { Box, factory } from "getbox";
|
|
|
30
30
|
* await app.serve({ port: 3000 });
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
|
-
function application(
|
|
33
|
+
function application(setup, box = new Box()) {
|
|
34
34
|
const defaultApp = new H3();
|
|
35
|
-
const app =
|
|
35
|
+
const app = setup(defaultApp, box) || defaultApp;
|
|
36
36
|
return {
|
|
37
37
|
app,
|
|
38
|
+
box,
|
|
38
39
|
serve: (options) => serve(app, options)
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
/**
|
|
42
|
-
* Creates
|
|
43
|
+
* Creates an h3 app constructor.
|
|
43
44
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* @param fn - Function that configures the controller.
|
|
48
|
-
* @returns A Constructor that can be resolved via `box.new(controller)`.
|
|
45
|
+
* @param setup - Function that configures the app.
|
|
46
|
+
* @returns A Constructor that produces an h3 app.
|
|
49
47
|
*
|
|
50
48
|
* @example
|
|
51
49
|
* ```typescript
|
|
50
|
+
* import { application, controller } from "serverstruct";
|
|
51
|
+
*
|
|
52
|
+
* class Database {
|
|
53
|
+
* getUsers() { return ["Alice", "Bob"]; }
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
52
56
|
* // Define a controller
|
|
53
57
|
* const usersController = controller((app, box) => {
|
|
54
|
-
*
|
|
58
|
+
* const db = box.get(Database);
|
|
59
|
+
* app.get("/", () => db.getUsers());
|
|
55
60
|
* });
|
|
56
61
|
*
|
|
57
62
|
* // Use it in your app
|
|
@@ -59,23 +64,182 @@ function application(fn, box = new Box()) {
|
|
|
59
64
|
* app.mount("/users", box.new(usersController));
|
|
60
65
|
* });
|
|
61
66
|
* ```
|
|
67
|
+
*/
|
|
68
|
+
function controller(setup) {
|
|
69
|
+
return factory((box) => application(setup, box).app);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Creates a handler constructor.
|
|
73
|
+
*
|
|
74
|
+
* @param setup - Handler function that receives the event and Box instance.
|
|
75
|
+
* @returns A Constructor that produces an h3 handler.
|
|
62
76
|
*
|
|
63
77
|
* @example
|
|
64
78
|
* ```typescript
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
79
|
+
* import { application, handler } from "serverstruct";
|
|
80
|
+
*
|
|
81
|
+
* class UserService {
|
|
82
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
68
83
|
* }
|
|
69
84
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
85
|
+
* // Define a handler
|
|
86
|
+
* const getUserHandler = handler((event, box) => {
|
|
87
|
+
* const userService = box.get(UserService);
|
|
88
|
+
* const id = event.context.params?.id;
|
|
89
|
+
* return userService.getUser(id);
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Use it in your app
|
|
93
|
+
* const app = application((app, box) => {
|
|
94
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
95
|
+
* });
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
function handler(setup) {
|
|
99
|
+
return factory((box) => defineHandler((event) => setup(event, box)));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Creates an event handler constructor from a setup function.
|
|
103
|
+
*
|
|
104
|
+
* @param setup - Function that receives Box instance and returns an event handler object.
|
|
105
|
+
* @returns A Constructor that produces an h3 event handler.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* import { application, eventHandler } from "serverstruct";
|
|
110
|
+
*
|
|
111
|
+
* class UserService {
|
|
112
|
+
* getUser(id: string) { return { id, name: "Alice" }; }
|
|
113
|
+
* }
|
|
114
|
+
*
|
|
115
|
+
* // Define an event handler
|
|
116
|
+
* const getUserHandler = eventHandler((box) => ({
|
|
117
|
+
* handler(event) {
|
|
118
|
+
* const userService = box.get(UserService);
|
|
119
|
+
* const id = event.context.params?.id;
|
|
120
|
+
* return userService.getUser(id);
|
|
121
|
+
* },
|
|
122
|
+
* meta: { auth: true }
|
|
123
|
+
* }));
|
|
124
|
+
*
|
|
125
|
+
* // Use it in your app
|
|
126
|
+
* const app = application((app, box) => {
|
|
127
|
+
* app.get("/users/:id", box.get(getUserHandler));
|
|
128
|
+
* });
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
function eventHandler(setup) {
|
|
132
|
+
return factory((box) => defineHandler(setup(box)));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Creates a middleware constructor.
|
|
136
|
+
*
|
|
137
|
+
* @param setup - Middleware function that receives the event, next function, and Box instance.
|
|
138
|
+
* @returns A Constructor that produces an h3 middleware.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```typescript
|
|
142
|
+
* import { application, middleware } from "serverstruct";
|
|
143
|
+
*
|
|
144
|
+
* class AuthService {
|
|
145
|
+
* validateToken(token: string) { return token === "valid"; }
|
|
146
|
+
* }
|
|
147
|
+
*
|
|
148
|
+
* // Define a middleware
|
|
149
|
+
* const authMiddleware = middleware((event, next, box) => {
|
|
150
|
+
* const authService = box.get(AuthService);
|
|
151
|
+
* const token = event.headers.get("authorization");
|
|
152
|
+
* if (!token || !authService.validateToken(token)) {
|
|
153
|
+
* throw new Error("Unauthorized");
|
|
154
|
+
* }
|
|
155
|
+
* });
|
|
156
|
+
*
|
|
157
|
+
* // Use it in your app
|
|
158
|
+
* const app = application((app, box) => {
|
|
159
|
+
* app.use(box.get(authMiddleware));
|
|
160
|
+
* app.get("/", () => "Hello world!");
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
function middleware(setup) {
|
|
165
|
+
return factory((box) => defineMiddleware((event, next) => setup(event, next, box)));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A request-scoped context store for associating values with H3 events.
|
|
169
|
+
*
|
|
170
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
171
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
172
|
+
* garbage collected with their events.
|
|
173
|
+
*
|
|
174
|
+
* @example
|
|
175
|
+
* ```typescript
|
|
176
|
+
* import { application, Context } from "serverstruct";
|
|
177
|
+
*
|
|
178
|
+
* const userContext = new Context<User>();
|
|
179
|
+
*
|
|
180
|
+
* const app = application((app) => {
|
|
181
|
+
* app.use((event) => {
|
|
182
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
183
|
+
* });
|
|
184
|
+
* app.get("/user", (event) => {
|
|
185
|
+
* const user = userContext.get(event);
|
|
186
|
+
* return user;
|
|
187
|
+
* });
|
|
188
|
+
* });
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
var Context = class {
|
|
192
|
+
#map = /* @__PURE__ */ new WeakMap();
|
|
193
|
+
/**
|
|
194
|
+
* Sets a value for the given event.
|
|
195
|
+
*/
|
|
196
|
+
set(event, value) {
|
|
197
|
+
this.#map.set(event, value);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Gets the value for the given event.
|
|
201
|
+
* @throws Error if no value is set for the event.
|
|
202
|
+
*/
|
|
203
|
+
get(event) {
|
|
204
|
+
if (this.#map.has(event)) return this.#map.get(event);
|
|
205
|
+
throw new Error("context not found");
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Gets the value for the given event, or undefined if not set.
|
|
209
|
+
*/
|
|
210
|
+
lookup(event) {
|
|
211
|
+
return this.#map.get(event);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
/**
|
|
215
|
+
* Creates a request-scoped context store for associating values with H3 events.
|
|
216
|
+
*
|
|
217
|
+
* Each request gets its own isolated context that is automatically cleaned up
|
|
218
|
+
* when the request completes. Uses a WeakMap internally to ensure values are
|
|
219
|
+
* garbage collected with their events.
|
|
220
|
+
*
|
|
221
|
+
* @returns A Context instance.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* ```typescript
|
|
225
|
+
* import { application, context } from "serverstruct";
|
|
226
|
+
*
|
|
227
|
+
* const userContext = context<User>();
|
|
228
|
+
*
|
|
229
|
+
* const app = application((app) => {
|
|
230
|
+
* app.use((event) => {
|
|
231
|
+
* userContext.set(event, { id: "123", name: "Alice" });
|
|
232
|
+
* });
|
|
233
|
+
* app.get("/user", (event) => {
|
|
234
|
+
* const user = userContext.get(event);
|
|
235
|
+
* return user;
|
|
236
|
+
* });
|
|
73
237
|
* });
|
|
74
238
|
* ```
|
|
75
239
|
*/
|
|
76
|
-
function
|
|
77
|
-
return
|
|
240
|
+
function context() {
|
|
241
|
+
return new Context();
|
|
78
242
|
}
|
|
79
243
|
|
|
80
244
|
//#endregion
|
|
81
|
-
export { application, controller };
|
|
245
|
+
export { Context, application, context, controller, eventHandler, handler, middleware };
|
package/dist/openapi.cjs
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
let h3 = require("h3");
|
|
2
|
+
let zod_openapi_api = require("zod-openapi/api");
|
|
3
|
+
let zod_openapi = require("zod-openapi");
|
|
4
|
+
|
|
5
|
+
//#region src/openapi.ts
|
|
6
|
+
function createContext(operation) {
|
|
7
|
+
const paramsSchema = operation.requestParams?.path;
|
|
8
|
+
const querySchema = operation.requestParams?.query;
|
|
9
|
+
const headersSchema = operation.requestParams?.header;
|
|
10
|
+
const bodyRawSchema = operation.requestBody?.content?.["application/json"]?.schema;
|
|
11
|
+
const bodySchema = (0, zod_openapi_api.isAnyZodType)(bodyRawSchema) ? bodyRawSchema : void 0;
|
|
12
|
+
return {
|
|
13
|
+
schemas: {
|
|
14
|
+
params: paramsSchema,
|
|
15
|
+
query: querySchema,
|
|
16
|
+
headers: headersSchema,
|
|
17
|
+
body: bodySchema
|
|
18
|
+
},
|
|
19
|
+
params: (event) => paramsSchema ? (0, h3.getValidatedRouterParams)(event, paramsSchema) : Promise.resolve((0, h3.getRouterParams)(event)),
|
|
20
|
+
query: (event) => querySchema ? (0, h3.getValidatedQuery)(event, querySchema) : Promise.resolve((0, h3.getQuery)(event)),
|
|
21
|
+
body: (event) => bodySchema ? (0, h3.readValidatedBody)(event, bodySchema) : (0, h3.readBody)(event),
|
|
22
|
+
reply: (event, status, data, headers) => {
|
|
23
|
+
event.res.status = status;
|
|
24
|
+
if (headers) for (const [key, value] of Object.entries(headers)) event.res.headers.set(key, String(value));
|
|
25
|
+
return data;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const HTTP_METHODS = [
|
|
30
|
+
"get",
|
|
31
|
+
"post",
|
|
32
|
+
"put",
|
|
33
|
+
"delete",
|
|
34
|
+
"patch"
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Collects OpenAPI operation definitions for document generation.
|
|
38
|
+
*
|
|
39
|
+
* Register operations by HTTP method and path. The accumulated `paths`
|
|
40
|
+
* object can be passed to `createDocument()` to generate the OpenAPI spec.
|
|
41
|
+
*
|
|
42
|
+
* Each registration returns a typed {@link RouterContext} for use in route handlers.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```ts
|
|
46
|
+
* // Singleton via getbox DI
|
|
47
|
+
* const paths = box.get(OpenApiPaths);
|
|
48
|
+
*
|
|
49
|
+
* const getPost = paths.get("/posts/{id}", { ... });
|
|
50
|
+
*
|
|
51
|
+
* // Generate OpenAPI document
|
|
52
|
+
* createDocument({ openapi: "3.1.0", info: { ... }, paths: paths.paths });
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
var OpenApiPaths = class {
|
|
56
|
+
paths = {};
|
|
57
|
+
get(path, operation) {
|
|
58
|
+
return this.register(path, "get", operation);
|
|
59
|
+
}
|
|
60
|
+
post(path, operation) {
|
|
61
|
+
return this.register(path, "post", operation);
|
|
62
|
+
}
|
|
63
|
+
put(path, operation) {
|
|
64
|
+
return this.register(path, "put", operation);
|
|
65
|
+
}
|
|
66
|
+
delete(path, operation) {
|
|
67
|
+
return this.register(path, "delete", operation);
|
|
68
|
+
}
|
|
69
|
+
patch(path, operation) {
|
|
70
|
+
return this.register(path, "patch", operation);
|
|
71
|
+
}
|
|
72
|
+
/** Register an operation for all standard HTTP methods (get, post, put, delete, patch). */
|
|
73
|
+
all(path, operation) {
|
|
74
|
+
return this.on(HTTP_METHODS, path, operation);
|
|
75
|
+
}
|
|
76
|
+
/** Register an operation for specific HTTP methods. */
|
|
77
|
+
on(methods, path, operation) {
|
|
78
|
+
const item = {};
|
|
79
|
+
for (const method of methods) item[method] = operation;
|
|
80
|
+
this.paths[path] = {
|
|
81
|
+
...this.paths[path],
|
|
82
|
+
...item
|
|
83
|
+
};
|
|
84
|
+
return createContext(operation);
|
|
85
|
+
}
|
|
86
|
+
register(path, method, operation) {
|
|
87
|
+
this.paths[path] = {
|
|
88
|
+
...this.paths[path],
|
|
89
|
+
[method]: operation
|
|
90
|
+
};
|
|
91
|
+
return createContext(operation);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Combines OpenAPI path registration with H3 route registration.
|
|
96
|
+
*
|
|
97
|
+
* Each method registers the operation in {@link OpenApiPaths} (converting the
|
|
98
|
+
* H3 path syntax to OpenAPI format) and simultaneously registers the route
|
|
99
|
+
* handler on the H3 app. The handler receives the typed {@link RouterContext}.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* const router = createRouter(app, box.get(OpenApiPaths));
|
|
104
|
+
*
|
|
105
|
+
* router.get("/posts/:id", {
|
|
106
|
+
* operationId: "getPost",
|
|
107
|
+
* requestBody: jsonRequest(inputSchema),
|
|
108
|
+
* responses: {
|
|
109
|
+
* 200: jsonResponse(outputSchema, { description: "Success" }),
|
|
110
|
+
* },
|
|
111
|
+
* }, async (event, ctx) => {
|
|
112
|
+
* const body = await ctx.body(event);
|
|
113
|
+
* return ctx.reply(event, 200, { message: "ok" });
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
var OpenApiRouter = class {
|
|
118
|
+
constructor(app, paths) {
|
|
119
|
+
this.app = app;
|
|
120
|
+
this.paths = paths;
|
|
121
|
+
}
|
|
122
|
+
get(path, operation, handler, opts) {
|
|
123
|
+
const ctx = this.paths.get(toOpenApiPath(path), operation);
|
|
124
|
+
this.app.get(path, (event) => handler(event, ctx), opts);
|
|
125
|
+
return this;
|
|
126
|
+
}
|
|
127
|
+
post(path, operation, handler, opts) {
|
|
128
|
+
const ctx = this.paths.post(toOpenApiPath(path), operation);
|
|
129
|
+
this.app.post(path, (event) => handler(event, ctx), opts);
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
put(path, operation, handler, opts) {
|
|
133
|
+
const ctx = this.paths.put(toOpenApiPath(path), operation);
|
|
134
|
+
this.app.put(path, (event) => handler(event, ctx), opts);
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
delete(path, operation, handler, opts) {
|
|
138
|
+
const ctx = this.paths.delete(toOpenApiPath(path), operation);
|
|
139
|
+
this.app.delete(path, (event) => handler(event, ctx), opts);
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
patch(path, operation, handler, opts) {
|
|
143
|
+
const ctx = this.paths.patch(toOpenApiPath(path), operation);
|
|
144
|
+
this.app.patch(path, (event) => handler(event, ctx), opts);
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
/** Register a route and operation for all standard HTTP methods. */
|
|
148
|
+
all(path, operation, handler, opts) {
|
|
149
|
+
const ctx = this.paths.all(toOpenApiPath(path), operation);
|
|
150
|
+
this.app.all(path, (event) => handler(event, ctx), opts);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
/** Register a route and operation for specific HTTP methods. */
|
|
154
|
+
on(methods, path, operation, handler, opts) {
|
|
155
|
+
const ctx = this.paths.on(methods, toOpenApiPath(path), operation);
|
|
156
|
+
for (const method of methods) this.app.on(method, path, (event) => handler(event, ctx), opts);
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
/** Create an {@link OpenApiRouter} that combines H3 route registration with OpenAPI path collection. */
|
|
161
|
+
function createRouter(app, paths) {
|
|
162
|
+
return new OpenApiRouter(app, paths);
|
|
163
|
+
}
|
|
164
|
+
/** Builder for OpenAPI metadata passed to `.meta()` on Zod schemas. */
|
|
165
|
+
const metadata = (meta) => meta;
|
|
166
|
+
/**
|
|
167
|
+
* Build a typed `requestBody` object with `application/json` content.
|
|
168
|
+
*
|
|
169
|
+
* Additional media type options (e.g. `example`) can be passed via `opts.content`.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* jsonRequest(inputSchema)
|
|
174
|
+
* jsonRequest(inputSchema, { description: "Create a post", content: { example: { title: "Hello" } } })
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
function jsonRequest(schema, opts) {
|
|
178
|
+
const { content, ...rest } = opts || {};
|
|
179
|
+
return {
|
|
180
|
+
required: true,
|
|
181
|
+
...rest,
|
|
182
|
+
content: { "application/json": {
|
|
183
|
+
schema,
|
|
184
|
+
...content
|
|
185
|
+
} }
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Build a typed response object with `application/json` content.
|
|
190
|
+
*
|
|
191
|
+
* Additional media type options (e.g. `example`) can be passed via `opts.content`.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```ts
|
|
195
|
+
* jsonResponse(outputSchema, { description: "Success" })
|
|
196
|
+
* jsonResponse(outputSchema, {
|
|
197
|
+
* description: "Success",
|
|
198
|
+
* headers: z.object({ "x-request-id": z.string() }).meta({}),
|
|
199
|
+
* })
|
|
200
|
+
* ```
|
|
201
|
+
*/
|
|
202
|
+
function jsonResponse(schema, opts) {
|
|
203
|
+
const { content, headers, ...rest } = opts;
|
|
204
|
+
return {
|
|
205
|
+
...rest,
|
|
206
|
+
headers,
|
|
207
|
+
content: { "application/json": {
|
|
208
|
+
schema,
|
|
209
|
+
...content
|
|
210
|
+
} }
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Convert H3 path syntax to OpenAPI path syntax.
|
|
215
|
+
*
|
|
216
|
+
* - `/:name` → `/{name}`
|
|
217
|
+
* - `/*` → `/{param}`
|
|
218
|
+
* - `/**` → `/{path}`
|
|
219
|
+
*/
|
|
220
|
+
function toOpenApiPath(route) {
|
|
221
|
+
if (!route.startsWith("/")) route = "/" + route;
|
|
222
|
+
return route.split("/").map((segment) => {
|
|
223
|
+
if (segment.startsWith(":")) return `{${segment.slice(1)}}`;
|
|
224
|
+
else if (segment === "*") return "{param}";
|
|
225
|
+
else if (segment === "**") return "{path}";
|
|
226
|
+
else return segment;
|
|
227
|
+
}).join("/");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
//#endregion
|
|
231
|
+
exports.OpenApiPaths = OpenApiPaths;
|
|
232
|
+
exports.OpenApiRouter = OpenApiRouter;
|
|
233
|
+
Object.defineProperty(exports, 'createDocument', {
|
|
234
|
+
enumerable: true,
|
|
235
|
+
get: function () {
|
|
236
|
+
return zod_openapi.createDocument;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
exports.createRouter = createRouter;
|
|
240
|
+
exports.jsonRequest = jsonRequest;
|
|
241
|
+
exports.jsonResponse = jsonResponse;
|
|
242
|
+
exports.metadata = metadata;
|