@naisys/supervisor 3.0.0-beta.6

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 (57) hide show
  1. package/bin/naisys-supervisor +2 -0
  2. package/client-dist/android-chrome-192x192.png +0 -0
  3. package/client-dist/android-chrome-512x512.png +0 -0
  4. package/client-dist/apple-touch-icon.png +0 -0
  5. package/client-dist/assets/index-BBrK4ItN.js +177 -0
  6. package/client-dist/assets/index-CKg0vgt5.css +1 -0
  7. package/client-dist/assets/naisys-logo-CzoPnn5I.webp +0 -0
  8. package/client-dist/favicon-16x16.png +0 -0
  9. package/client-dist/favicon-32x32.png +0 -0
  10. package/client-dist/favicon.ico +0 -0
  11. package/client-dist/index.html +49 -0
  12. package/client-dist/site.webmanifest +22 -0
  13. package/dist/api-reference.js +52 -0
  14. package/dist/auth-middleware.js +116 -0
  15. package/dist/database/hubDb.js +26 -0
  16. package/dist/database/supervisorDb.js +18 -0
  17. package/dist/error-helpers.js +13 -0
  18. package/dist/hateoas.js +61 -0
  19. package/dist/logger.js +11 -0
  20. package/dist/route-helpers.js +7 -0
  21. package/dist/routes/admin.js +209 -0
  22. package/dist/routes/agentChat.js +194 -0
  23. package/dist/routes/agentConfig.js +265 -0
  24. package/dist/routes/agentLifecycle.js +350 -0
  25. package/dist/routes/agentMail.js +171 -0
  26. package/dist/routes/agentRuns.js +90 -0
  27. package/dist/routes/agents.js +236 -0
  28. package/dist/routes/api.js +52 -0
  29. package/dist/routes/attachments.js +18 -0
  30. package/dist/routes/auth.js +103 -0
  31. package/dist/routes/costs.js +51 -0
  32. package/dist/routes/hosts.js +296 -0
  33. package/dist/routes/models.js +152 -0
  34. package/dist/routes/root.js +56 -0
  35. package/dist/routes/schemas.js +31 -0
  36. package/dist/routes/status.js +20 -0
  37. package/dist/routes/users.js +420 -0
  38. package/dist/routes/variables.js +103 -0
  39. package/dist/schema-registry.js +23 -0
  40. package/dist/services/agentConfigService.js +182 -0
  41. package/dist/services/agentHostStatusService.js +178 -0
  42. package/dist/services/agentService.js +291 -0
  43. package/dist/services/attachmentProxyService.js +130 -0
  44. package/dist/services/browserSocketService.js +78 -0
  45. package/dist/services/chatService.js +201 -0
  46. package/dist/services/configExportService.js +61 -0
  47. package/dist/services/costsService.js +127 -0
  48. package/dist/services/hostService.js +156 -0
  49. package/dist/services/hubConnectionService.js +333 -0
  50. package/dist/services/logFileService.js +11 -0
  51. package/dist/services/mailService.js +154 -0
  52. package/dist/services/modelService.js +92 -0
  53. package/dist/services/runsService.js +164 -0
  54. package/dist/services/userService.js +147 -0
  55. package/dist/services/variableService.js +23 -0
  56. package/dist/supervisorServer.js +221 -0
  57. package/package.json +79 -0
@@ -0,0 +1,420 @@
1
+ import { ChangePasswordSchema, CreateAgentUserSchema, CreateUserSchema, GrantPermissionSchema, PermissionEnum, UpdateUserSchema, } from "@naisys/supervisor-shared";
2
+ import { z } from "zod/v4";
3
+ import { authCache, requirePermission } from "../auth-middleware.js";
4
+ import { conflict, notFound } from "../error-helpers.js";
5
+ import { API_PREFIX, collectionLink, paginationLinks, schemaLink, selfLink, } from "../hateoas.js";
6
+ import { getHubAgentById, getHubAgentByUuid, } from "../services/agentService.js";
7
+ import * as userService from "../services/userService.js";
8
+ function userItemLinks(username, agentUsername) {
9
+ const links = [
10
+ selfLink(`/users/${username}`),
11
+ collectionLink("users"),
12
+ schemaLink("UpdateUser"),
13
+ ];
14
+ if (agentUsername != null) {
15
+ links.push({
16
+ rel: "agent",
17
+ href: `${API_PREFIX}/agents/${agentUsername}`,
18
+ title: "View Agent",
19
+ });
20
+ }
21
+ return links;
22
+ }
23
+ function userActions(username, isSelf, isAdmin) {
24
+ const href = `${API_PREFIX}/users/${username}`;
25
+ const actions = [];
26
+ // Admins can edit any user (username + password)
27
+ if (isAdmin) {
28
+ actions.push({
29
+ rel: "update",
30
+ href,
31
+ method: "PUT",
32
+ title: "Update",
33
+ schema: `${API_PREFIX}/schemas/UpdateUser`,
34
+ body: { username: "" },
35
+ });
36
+ }
37
+ // Any authenticated user can change their own password
38
+ if (isSelf) {
39
+ actions.push({
40
+ rel: "change-password",
41
+ href: `${API_PREFIX}/users/me/password`,
42
+ method: "POST",
43
+ title: "Change Password",
44
+ schema: `${API_PREFIX}/schemas/ChangePassword`,
45
+ body: { password: "" },
46
+ });
47
+ }
48
+ if (isAdmin) {
49
+ actions.push({
50
+ rel: "grant-permission",
51
+ href: `${href}/permissions`,
52
+ method: "POST",
53
+ title: "Grant Permission",
54
+ schema: `${API_PREFIX}/schemas/GrantPermission`,
55
+ body: { permission: "" },
56
+ });
57
+ actions.push({
58
+ rel: "rotate-key",
59
+ href: `${href}/rotate-key`,
60
+ method: "POST",
61
+ title: "Rotate API Key",
62
+ });
63
+ if (!isSelf) {
64
+ actions.push({
65
+ rel: "delete",
66
+ href,
67
+ method: "DELETE",
68
+ title: "Delete",
69
+ });
70
+ }
71
+ }
72
+ return actions;
73
+ }
74
+ function permissionActions(username, permission, isSelf, isAdmin) {
75
+ if (!isAdmin)
76
+ return [];
77
+ const actions = [];
78
+ // Cannot revoke own supervisor_admin
79
+ if (!(isSelf && permission === "supervisor_admin")) {
80
+ actions.push({
81
+ rel: "revoke",
82
+ href: `${API_PREFIX}/users/${username}/permissions/${permission}`,
83
+ method: "DELETE",
84
+ title: "Revoke",
85
+ });
86
+ }
87
+ return actions;
88
+ }
89
+ function formatUser(user, currentUserId, currentUserPermissions, options) {
90
+ if (!user)
91
+ return null;
92
+ const isSelf = user.id === currentUserId;
93
+ const isAdmin = currentUserPermissions.includes("supervisor_admin");
94
+ return {
95
+ id: user.id,
96
+ username: user.username,
97
+ isAgent: user.isAgent,
98
+ createdAt: user.createdAt.toISOString(),
99
+ updatedAt: user.updatedAt.toISOString(),
100
+ apiKey: isAdmin ? (options?.apiKey ?? null) : undefined,
101
+ permissions: user.permissions.map((p) => ({
102
+ permission: p.permission,
103
+ grantedAt: p.grantedAt.toISOString(),
104
+ grantedBy: p.grantedBy,
105
+ _actions: permissionActions(user.username, p.permission, isSelf, isAdmin),
106
+ })),
107
+ _links: userItemLinks(user.username, options?.agentUsername),
108
+ _actions: userActions(user.username, isSelf, isAdmin),
109
+ };
110
+ }
111
+ function formatListUser(user) {
112
+ return {
113
+ id: user.id,
114
+ uuid: user.uuid,
115
+ username: user.username,
116
+ isAgent: user.isAgent,
117
+ createdAt: user.createdAt.toISOString(),
118
+ permissionCount: user.permissions.length,
119
+ };
120
+ }
121
+ export default function userRoutes(fastify, _options) {
122
+ const app = fastify.withTypeProvider();
123
+ const adminPreHandler = [requirePermission("supervisor_admin")];
124
+ const requireAdminOrSelf = async (request, reply) => {
125
+ if (!request.supervisorUser) {
126
+ reply.status(401).send({
127
+ statusCode: 401,
128
+ error: "Unauthorized",
129
+ message: "Authentication required",
130
+ });
131
+ return;
132
+ }
133
+ const isAdmin = request.supervisorUser.permissions.includes("supervisor_admin");
134
+ const isSelf = request.params.username === request.supervisorUser.username;
135
+ if (!isAdmin && !isSelf) {
136
+ reply.status(403).send({
137
+ statusCode: 403,
138
+ error: "Forbidden",
139
+ message: "Permission 'supervisor_admin' required",
140
+ });
141
+ return;
142
+ }
143
+ };
144
+ // LIST USERS
145
+ app.get("/", {
146
+ preHandler: adminPreHandler,
147
+ schema: {
148
+ description: "List all users with pagination",
149
+ tags: ["Users"],
150
+ querystring: z.object({
151
+ page: z.coerce.number().int().min(1).default(1),
152
+ pageSize: z.coerce.number().int().min(1).max(100).default(20),
153
+ search: z.string().optional(),
154
+ }),
155
+ security: [{ cookieAuth: [] }],
156
+ },
157
+ }, async (request) => {
158
+ const { page, pageSize, search } = request.query;
159
+ const result = await userService.listUsers({ page, pageSize, search });
160
+ const actions = [
161
+ {
162
+ rel: "create",
163
+ href: `${API_PREFIX}/users`,
164
+ method: "POST",
165
+ title: "Create User",
166
+ schema: `${API_PREFIX}/schemas/CreateUser`,
167
+ body: { username: "", password: "" },
168
+ },
169
+ {
170
+ rel: "create-from-agent",
171
+ href: `${API_PREFIX}/users/from-agent`,
172
+ method: "POST",
173
+ title: "Import User from Agent",
174
+ schema: `${API_PREFIX}/schemas/CreateAgentUser`,
175
+ body: { agentId: 0 },
176
+ },
177
+ ];
178
+ return {
179
+ items: result.items.map(formatListUser),
180
+ total: result.total,
181
+ pageSize: result.pageSize,
182
+ _links: paginationLinks("users", page, pageSize, result.total, {
183
+ search,
184
+ }),
185
+ _linkTemplates: [
186
+ { rel: "item", hrefTemplate: `${API_PREFIX}/users/{username}` },
187
+ ],
188
+ _actions: actions,
189
+ };
190
+ });
191
+ // CHANGE OWN PASSWORD (must be registered before /:username routes)
192
+ app.post("/me/password", {
193
+ schema: {
194
+ description: "Change the current user's password",
195
+ tags: ["Users"],
196
+ body: ChangePasswordSchema,
197
+ security: [{ cookieAuth: [] }],
198
+ },
199
+ }, async (request, reply) => {
200
+ if (!request.supervisorUser) {
201
+ reply.status(401).send({
202
+ statusCode: 401,
203
+ error: "Unauthorized",
204
+ message: "Authentication required",
205
+ });
206
+ return;
207
+ }
208
+ await userService.updateUser(request.supervisorUser.id, {
209
+ password: request.body.password,
210
+ });
211
+ authCache.clear();
212
+ return { success: true, message: "Password changed" };
213
+ });
214
+ // CREATE USER
215
+ app.post("/", {
216
+ preHandler: adminPreHandler,
217
+ schema: {
218
+ description: "Create a new user",
219
+ tags: ["Users"],
220
+ body: CreateUserSchema,
221
+ security: [{ cookieAuth: [] }],
222
+ },
223
+ }, async (request, reply) => {
224
+ try {
225
+ const user = await userService.createUserWithPassword(request.body);
226
+ reply.code(201);
227
+ return {
228
+ success: true,
229
+ message: "User created",
230
+ id: user.id,
231
+ username: user.username,
232
+ };
233
+ }
234
+ catch (err) {
235
+ if (err instanceof Error && err.message.includes("Unique constraint")) {
236
+ return conflict(reply, "Username already exists");
237
+ }
238
+ throw err;
239
+ }
240
+ });
241
+ // CREATE AGENT USER (from hub agent)
242
+ app.post("/from-agent", {
243
+ preHandler: adminPreHandler,
244
+ schema: {
245
+ description: "Create a supervisor user from an existing hub agent",
246
+ tags: ["Users"],
247
+ body: CreateAgentUserSchema,
248
+ security: [{ cookieAuth: [] }],
249
+ },
250
+ }, async (request, reply) => {
251
+ const { agentId } = request.body;
252
+ const hubAgent = await getHubAgentById(agentId);
253
+ if (!hubAgent) {
254
+ return notFound(reply, "Agent not found");
255
+ }
256
+ const existingByUuid = await userService.getUserByUuid(hubAgent.uuid);
257
+ if (existingByUuid) {
258
+ return conflict(reply, "A user with this agent's UUID already exists");
259
+ }
260
+ const existingByUsername = await userService.getUserByUsername(hubAgent.username);
261
+ if (existingByUsername) {
262
+ return conflict(reply, "Username already exists");
263
+ }
264
+ const user = await userService.createUserForAgent(hubAgent.username, hubAgent.uuid);
265
+ reply.code(201);
266
+ return {
267
+ success: true,
268
+ message: "Agent user created",
269
+ id: user.id,
270
+ username: user.username,
271
+ };
272
+ });
273
+ const usernameParams = z.object({ username: z.string() });
274
+ // GET USER (admin or self)
275
+ app.get("/:username", {
276
+ preHandler: [requireAdminOrSelf],
277
+ schema: {
278
+ description: "Get user details",
279
+ tags: ["Users"],
280
+ params: usernameParams,
281
+ security: [{ cookieAuth: [] }],
282
+ },
283
+ }, async (request, reply) => {
284
+ const user = await userService.getUserByUsernameWithPermissions(request.params.username);
285
+ if (!user) {
286
+ return notFound(reply, "User not found");
287
+ }
288
+ let agentUsername = null;
289
+ if (user.isAgent && user.uuid) {
290
+ const hubAgent = await getHubAgentByUuid(user.uuid);
291
+ agentUsername = hubAgent?.username ?? null;
292
+ }
293
+ const apiKey = await userService.getUserApiKey(user.id);
294
+ return formatUser(user, request.supervisorUser.id, request.supervisorUser.permissions, { agentUsername, apiKey });
295
+ });
296
+ // UPDATE USER (admin can update any field; non-admin can only change own password)
297
+ app.put("/:username", {
298
+ preHandler: [requireAdminOrSelf],
299
+ schema: {
300
+ description: "Update a user",
301
+ tags: ["Users"],
302
+ params: usernameParams,
303
+ body: UpdateUserSchema,
304
+ security: [{ cookieAuth: [] }],
305
+ },
306
+ }, async (request, reply) => {
307
+ const targetUser = await userService.getUserByUsernameWithPermissions(request.params.username);
308
+ if (!targetUser) {
309
+ return notFound(reply, "User not found");
310
+ }
311
+ const isAdmin = request.supervisorUser.permissions.includes("supervisor_admin");
312
+ // Non-admins can only change their own password
313
+ const body = isAdmin ? request.body : { password: request.body.password };
314
+ try {
315
+ await userService.updateUser(targetUser.id, body);
316
+ authCache.clear();
317
+ return { success: true, message: "User updated" };
318
+ }
319
+ catch (err) {
320
+ if (err instanceof Error && err.message.includes("Unique constraint")) {
321
+ return conflict(reply, "Username already exists");
322
+ }
323
+ throw err;
324
+ }
325
+ });
326
+ // DELETE USER
327
+ app.delete("/:username", {
328
+ preHandler: adminPreHandler,
329
+ schema: {
330
+ description: "Delete a user",
331
+ tags: ["Users"],
332
+ params: usernameParams,
333
+ security: [{ cookieAuth: [] }],
334
+ },
335
+ }, async (request, reply) => {
336
+ if (request.params.username === request.supervisorUser.username) {
337
+ return conflict(reply, "Cannot delete yourself");
338
+ }
339
+ const targetUser = await userService.getUserByUsernameWithPermissions(request.params.username);
340
+ if (!targetUser) {
341
+ return notFound(reply, "User not found");
342
+ }
343
+ await userService.deleteUser(targetUser.id);
344
+ authCache.clear();
345
+ return { success: true, message: "User deleted" };
346
+ });
347
+ // ROTATE API KEY
348
+ app.post("/:username/rotate-key", {
349
+ preHandler: adminPreHandler,
350
+ schema: {
351
+ description: "Rotate a user's API key",
352
+ tags: ["Users"],
353
+ params: usernameParams,
354
+ security: [{ cookieAuth: [] }],
355
+ },
356
+ }, async (request, reply) => {
357
+ const targetUser = await userService.getUserByUsernameWithPermissions(request.params.username);
358
+ if (!targetUser) {
359
+ return notFound(reply, "User not found");
360
+ }
361
+ await userService.rotateUserApiKey(targetUser.id);
362
+ authCache.clear();
363
+ return { success: true, message: "API key rotated" };
364
+ });
365
+ // GRANT PERMISSION
366
+ app.post("/:username/permissions", {
367
+ preHandler: adminPreHandler,
368
+ schema: {
369
+ description: "Grant a permission to a user",
370
+ tags: ["Users"],
371
+ params: usernameParams,
372
+ body: GrantPermissionSchema,
373
+ security: [{ cookieAuth: [] }],
374
+ },
375
+ }, async (request, reply) => {
376
+ const targetUser = await userService.getUserByUsernameWithPermissions(request.params.username);
377
+ if (!targetUser) {
378
+ return notFound(reply, "User not found");
379
+ }
380
+ try {
381
+ await userService.grantPermission(targetUser.id, request.body.permission, request.supervisorUser.id);
382
+ authCache.clear();
383
+ return { success: true, message: "Permission granted" };
384
+ }
385
+ catch (err) {
386
+ if (err instanceof Error && err.message.includes("Unique constraint")) {
387
+ return conflict(reply, "Permission already granted");
388
+ }
389
+ throw err;
390
+ }
391
+ });
392
+ // REVOKE PERMISSION
393
+ app.delete("/:username/permissions/:permission", {
394
+ preHandler: adminPreHandler,
395
+ schema: {
396
+ description: "Revoke a permission from a user",
397
+ tags: ["Users"],
398
+ params: z.object({
399
+ username: z.string(),
400
+ permission: PermissionEnum,
401
+ }),
402
+ security: [{ cookieAuth: [] }],
403
+ },
404
+ }, async (request, reply) => {
405
+ const { username, permission } = request.params;
406
+ // Cannot revoke own supervisor_admin
407
+ if (username === request.supervisorUser.username &&
408
+ permission === "supervisor_admin") {
409
+ return conflict(reply, "Cannot revoke your own supervisor_admin permission");
410
+ }
411
+ const targetUser = await userService.getUserByUsernameWithPermissions(username);
412
+ if (!targetUser) {
413
+ return notFound(reply, "User not found");
414
+ }
415
+ await userService.revokePermission(targetUser.id, permission);
416
+ authCache.clear();
417
+ return { success: true, message: "Permission revoked" };
418
+ });
419
+ }
420
+ //# sourceMappingURL=users.js.map
@@ -0,0 +1,103 @@
1
+ import { DeleteVariableParamsSchema, DeleteVariableResponseSchema, ErrorResponseSchema, SaveVariableRequestSchema, SaveVariableResponseSchema, VariablesResponseSchema, } from "@naisys/supervisor-shared";
2
+ import { hasPermission, requirePermission } from "../auth-middleware.js";
3
+ import { API_PREFIX } from "../hateoas.js";
4
+ import { sendVariablesChanged } from "../services/hubConnectionService.js";
5
+ import { deleteVariable, getVariables, saveVariable, } from "../services/variableService.js";
6
+ function variableActions(hasManagePermission) {
7
+ const actions = [];
8
+ if (hasManagePermission) {
9
+ actions.push({
10
+ rel: "save",
11
+ href: `${API_PREFIX}/variables/:key`,
12
+ method: "PUT",
13
+ title: "Save Variable",
14
+ schema: `${API_PREFIX}/schemas/SaveVariable`,
15
+ body: { value: "", exportToShell: false },
16
+ }, {
17
+ rel: "delete",
18
+ href: `${API_PREFIX}/variables/:key`,
19
+ method: "DELETE",
20
+ title: "Delete Variable",
21
+ });
22
+ }
23
+ return actions;
24
+ }
25
+ export default function variablesRoutes(fastify, _options) {
26
+ // GET / — list all variables
27
+ fastify.get("/", {
28
+ preHandler: [requirePermission("manage_variables")],
29
+ schema: {
30
+ description: "List all variables",
31
+ tags: ["Variables"],
32
+ response: {
33
+ 200: VariablesResponseSchema,
34
+ 500: ErrorResponseSchema,
35
+ },
36
+ },
37
+ }, async (request, _reply) => {
38
+ const items = await getVariables();
39
+ const hasManagePermission = hasPermission(request.supervisorUser, "manage_variables");
40
+ const actions = variableActions(hasManagePermission);
41
+ return {
42
+ items: items.map((v) => ({
43
+ key: v.key,
44
+ value: v.value,
45
+ exportToShell: v.export_to_shell,
46
+ })),
47
+ _actions: actions.length > 0 ? actions : undefined,
48
+ };
49
+ });
50
+ // PUT /:key — upsert a variable
51
+ fastify.put("/:key", {
52
+ preHandler: [requirePermission("manage_variables")],
53
+ schema: {
54
+ description: "Create or update a variable",
55
+ tags: ["Variables"],
56
+ params: DeleteVariableParamsSchema,
57
+ body: SaveVariableRequestSchema,
58
+ response: {
59
+ 200: SaveVariableResponseSchema,
60
+ 400: ErrorResponseSchema,
61
+ 500: ErrorResponseSchema,
62
+ },
63
+ },
64
+ }, async (request, reply) => {
65
+ try {
66
+ const { key } = request.params;
67
+ const { value, exportToShell } = request.body;
68
+ const result = await saveVariable(key, value, exportToShell, request.supervisorUser.uuid);
69
+ sendVariablesChanged();
70
+ return result;
71
+ }
72
+ catch (error) {
73
+ const message = error instanceof Error ? error.message : "Failed to save variable";
74
+ return reply.code(500).send({ success: false, message });
75
+ }
76
+ });
77
+ // DELETE /:key — delete a variable
78
+ fastify.delete("/:key", {
79
+ preHandler: [requirePermission("manage_variables")],
80
+ schema: {
81
+ description: "Delete a variable",
82
+ tags: ["Variables"],
83
+ params: DeleteVariableParamsSchema,
84
+ response: {
85
+ 200: DeleteVariableResponseSchema,
86
+ 400: ErrorResponseSchema,
87
+ 500: ErrorResponseSchema,
88
+ },
89
+ },
90
+ }, async (request, reply) => {
91
+ try {
92
+ const { key } = request.params;
93
+ const result = await deleteVariable(key);
94
+ sendVariablesChanged();
95
+ return result;
96
+ }
97
+ catch (error) {
98
+ const message = error instanceof Error ? error.message : "Failed to delete variable";
99
+ return reply.code(500).send({ success: false, message });
100
+ }
101
+ });
102
+ }
103
+ //# sourceMappingURL=variables.js.map
@@ -0,0 +1,23 @@
1
+ import { AgentStartRequestSchema, ChangePasswordSchema, CreateAgentConfigRequestSchema, CreateUserSchema, GrantPermissionSchema, LoginRequestSchema, SaveImageModelRequestSchema, SaveLlmModelRequestSchema, SaveVariableRequestSchema, SendChatRequestSchema, SendMailRequestSchema, SetLeadAgentRequestSchema, UpdateAgentConfigRequestSchema, UpdateUserSchema, } from "@naisys/supervisor-shared";
2
+ import { z } from "zod/v4";
3
+ export const schemaRegistry = {
4
+ CreateAgent: CreateAgentConfigRequestSchema,
5
+ UpdateAgentConfig: UpdateAgentConfigRequestSchema,
6
+ StartAgent: AgentStartRequestSchema,
7
+ SetLeadAgent: SetLeadAgentRequestSchema,
8
+ SendChat: SendChatRequestSchema,
9
+ SendMail: SendMailRequestSchema,
10
+ ChangePassword: ChangePasswordSchema,
11
+ CreateUser: CreateUserSchema,
12
+ UpdateUser: UpdateUserSchema,
13
+ GrantPermission: GrantPermissionSchema,
14
+ LoginRequest: LoginRequestSchema,
15
+ SaveLlmModel: SaveLlmModelRequestSchema,
16
+ SaveImageModel: SaveImageModelRequestSchema,
17
+ SaveVariable: SaveVariableRequestSchema,
18
+ };
19
+ // Register schemas with Zod global registry for OpenAPI components/schemas population
20
+ for (const [name, schema] of Object.entries(schemaRegistry)) {
21
+ z.globalRegistry.add(schema, { id: name });
22
+ }
23
+ //# sourceMappingURL=schema-registry.js.map