@bsb/registry 1.0.4 → 1.1.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 (38) hide show
  1. package/README.md +1 -1
  2. package/lib/.bsb/clients/service-bsb-registry.d.ts +348 -982
  3. package/lib/.bsb/clients/service-bsb-registry.d.ts.map +1 -1
  4. package/lib/.bsb/clients/service-bsb-registry.js +287 -291
  5. package/lib/.bsb/clients/service-bsb-registry.js.map +1 -1
  6. package/lib/plugins/service-bsb-registry/auth.d.ts +2 -2
  7. package/lib/plugins/service-bsb-registry/auth.d.ts.map +1 -1
  8. package/lib/plugins/service-bsb-registry/auth.js +5 -9
  9. package/lib/plugins/service-bsb-registry/auth.js.map +1 -1
  10. package/lib/plugins/service-bsb-registry/db/file.d.ts +2 -2
  11. package/lib/plugins/service-bsb-registry/db/file.d.ts.map +1 -1
  12. package/lib/plugins/service-bsb-registry/db/file.js +3 -40
  13. package/lib/plugins/service-bsb-registry/db/file.js.map +1 -1
  14. package/lib/plugins/service-bsb-registry/db/index.d.ts +1 -1
  15. package/lib/plugins/service-bsb-registry/db/index.d.ts.map +1 -1
  16. package/lib/plugins/service-bsb-registry/db/index.js +3 -6
  17. package/lib/plugins/service-bsb-registry/db/index.js.map +1 -1
  18. package/lib/plugins/service-bsb-registry/index.d.ts +377 -1020
  19. package/lib/plugins/service-bsb-registry/index.d.ts.map +1 -1
  20. package/lib/plugins/service-bsb-registry/index.js +58 -95
  21. package/lib/plugins/service-bsb-registry/index.js.map +1 -1
  22. package/lib/plugins/service-bsb-registry/types.d.ts +197 -517
  23. package/lib/plugins/service-bsb-registry/types.d.ts.map +1 -1
  24. package/lib/plugins/service-bsb-registry/types.js +164 -167
  25. package/lib/plugins/service-bsb-registry/types.js.map +1 -1
  26. package/lib/plugins/service-bsb-registry-ui/http-server.d.ts +2 -2
  27. package/lib/plugins/service-bsb-registry-ui/http-server.d.ts.map +1 -1
  28. package/lib/plugins/service-bsb-registry-ui/http-server.js +229 -181
  29. package/lib/plugins/service-bsb-registry-ui/http-server.js.map +1 -1
  30. package/lib/plugins/service-bsb-registry-ui/index.d.ts +27 -27
  31. package/lib/plugins/service-bsb-registry-ui/index.d.ts.map +1 -1
  32. package/lib/plugins/service-bsb-registry-ui/index.js +22 -26
  33. package/lib/plugins/service-bsb-registry-ui/index.js.map +1 -1
  34. package/lib/schemas/service-bsb-registry-ui.json +1 -46
  35. package/lib/schemas/service-bsb-registry-ui.plugin.json +2 -47
  36. package/lib/schemas/service-bsb-registry.json +1903 -1693
  37. package/lib/schemas/service-bsb-registry.plugin.json +1 -47
  38. package/package.json +4 -7
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Registry UI & API HTTP Server (Event-Driven with Handlebars)
4
3
  *
@@ -6,56 +5,49 @@
6
5
  * using content negotiation (Accept header).
7
6
  * Communicates with registry core via typed BsbRegistryClient.
8
7
  */
9
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- var desc = Object.getOwnPropertyDescriptor(m, k);
12
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
- desc = { enumerable: true, get: function() { return m[k]; } };
14
- }
15
- Object.defineProperty(o, k2, desc);
16
- }) : (function(o, m, k, k2) {
17
- if (k2 === undefined) k2 = k;
18
- o[k2] = m[k];
19
- }));
20
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
- Object.defineProperty(o, "default", { enumerable: true, value: v });
22
- }) : function(o, v) {
23
- o["default"] = v;
24
- });
25
- var __importStar = (this && this.__importStar) || (function () {
26
- var ownKeys = function(o) {
27
- ownKeys = Object.getOwnPropertyNames || function (o) {
28
- var ar = [];
29
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
- return ar;
31
- };
32
- return ownKeys(o);
33
- };
34
- return function (mod) {
35
- if (mod && mod.__esModule) return mod;
36
- var result = {};
37
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
- __setModuleDefault(result, mod);
39
- return result;
8
+ import * as path from 'path';
9
+ import * as fs from 'node:fs';
10
+ import * as fsp from 'node:fs/promises';
11
+ import { pipeline } from 'node:stream/promises';
12
+ import Fastify from 'fastify';
13
+ import fastifyCors from '@fastify/cors';
14
+ import fastifyMultipart from '@fastify/multipart';
15
+ import fastifyStatic from '@fastify/static';
16
+ import fastifyView from '@fastify/view';
17
+ import handlebars from 'handlebars';
18
+ import { marked } from 'marked';
19
+ import * as av from '@anyvali/js';
20
+ function objectSchema(shape) {
21
+ return av.object(shape, { unknownKeys: 'strip' });
22
+ }
23
+ function createValidator(schema, options) {
24
+ return {
25
+ safeParse(input) {
26
+ const normalized = options?.normalize ? options.normalize(input) : input;
27
+ const result = schema.safeParse(normalized);
28
+ if (!result.success) {
29
+ return result;
30
+ }
31
+ const extraIssues = options?.extraIssues?.(result.data) ?? [];
32
+ if (extraIssues.length > 0) {
33
+ return {
34
+ success: false,
35
+ issues: extraIssues,
36
+ };
37
+ }
38
+ return result;
39
+ },
40
40
  };
41
- })();
42
- var __importDefault = (this && this.__importDefault) || function (mod) {
43
- return (mod && mod.__esModule) ? mod : { "default": mod };
44
- };
45
- Object.defineProperty(exports, "__esModule", { value: true });
46
- exports.RegistryUIServer = void 0;
47
- const path = __importStar(require("path"));
48
- const fs = __importStar(require("node:fs"));
49
- const fsp = __importStar(require("node:fs/promises"));
50
- const promises_1 = require("node:stream/promises");
51
- const fastify_1 = __importDefault(require("fastify"));
52
- const cors_1 = __importDefault(require("@fastify/cors"));
53
- const multipart_1 = __importDefault(require("@fastify/multipart"));
54
- const static_1 = __importDefault(require("@fastify/static"));
55
- const view_1 = __importDefault(require("@fastify/view"));
56
- const handlebars_1 = __importDefault(require("handlebars"));
57
- const marked_1 = require("marked");
58
- const zod_1 = require("zod");
41
+ }
42
+ function mapObjectInput(input, transform) {
43
+ if (typeof input !== 'object' || input === null || Array.isArray(input)) {
44
+ return input;
45
+ }
46
+ return transform({ ...input });
47
+ }
48
+ function emptyStringToUndefined(value) {
49
+ return value === '' ? undefined : value;
50
+ }
59
51
  // ============================================================================
60
52
  // Zod Validation Schemas — all external input validated at the boundary
61
53
  // ============================================================================
@@ -70,149 +62,206 @@ const semverPattern = /^\d{1,5}\.\d{1,5}\.\d{1,5}(-[a-zA-Z0-9.]+)?$/;
70
62
  const majorMinorPattern = /^\d{1,5}\.\d{1,5}$/;
71
63
  // Package name: npm-style scoped or unscoped
72
64
  const packageNamePattern = /^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+$/;
73
- const slugField = zod_1.z.string().min(1).max(100).regex(slugPattern, 'Only alphanumeric, dash, underscore, dot, @, /');
74
- const semverField = zod_1.z.string().min(5).max(50).regex(semverPattern, 'Must be semver (e.g. 1.0.0)');
75
- const languageEnum = zod_1.z.enum(['nodejs', 'csharp', 'go', 'java', 'python']);
76
- const categoryEnum = zod_1.z.enum(['service', 'observable', 'events', 'config']);
77
- const visibilityEnum = zod_1.z.enum(['public', 'private']);
78
- const safeString = (max) => zod_1.z.string().max(max).regex(safeAscii, 'ASCII printable characters only');
79
- const safeStringRequired = (min, max) => zod_1.z.string().min(min).max(max).regex(safeAscii, 'ASCII printable characters only');
80
- const optionalNonEmpty = (schema) => zod_1.z.preprocess((value) => value === '' ? undefined : value, schema.optional());
65
+ const slugField = av.string().minLength(1).maxLength(100).pattern(slugPattern.source);
66
+ const semverField = av.string().minLength(5).maxLength(50).pattern(semverPattern.source);
67
+ const languageEnum = av.enum_(['nodejs', 'csharp', 'go', 'java', 'python']);
68
+ const categoryEnum = av.enum_(['service', 'observable', 'events', 'config']);
69
+ const visibilityEnum = av.enum_(['public', 'private']);
70
+ const safeString = (max) => av.string().maxLength(max).pattern(safeAscii.source);
71
+ const safeStringRequired = (min, max) => av.string().minLength(min).maxLength(max).pattern(safeAscii.source);
81
72
  // ---- Route param schemas ----
82
- const OrgParamsSchema = zod_1.z.object({
73
+ const OrgParamsSchema = createValidator(objectSchema({
83
74
  org: slugField,
84
- });
85
- const PluginDetailParamsSchema = zod_1.z.object({
75
+ }));
76
+ const PluginDetailParamsSchema = createValidator(objectSchema({
86
77
  org: slugField,
87
78
  name: slugField,
88
- });
89
- const PluginVersionParamsSchema = zod_1.z.object({
79
+ }));
80
+ const PluginVersionParamsSchema = createValidator(objectSchema({
90
81
  org: slugField,
91
82
  name: slugField,
92
83
  version: semverField,
93
- });
94
- const PluginTypesParamsSchema = zod_1.z.object({
84
+ }));
85
+ const PluginTypesParamsSchema = createValidator(objectSchema({
95
86
  org: slugField,
96
87
  name: slugField,
97
88
  version: semverField,
98
89
  language: languageEnum,
99
- });
90
+ }));
100
91
  const packageLookupIdPattern = /^[A-Za-z0-9@._\-/:]+$/;
101
- const PackageLookupParamsSchema = zod_1.z.object({
92
+ const PackageLookupParamsSchema = createValidator(objectSchema({
102
93
  language: languageEnum,
103
- '*': zod_1.z.preprocess((value) => {
104
- if (typeof value !== 'string')
94
+ '*': av.string().minLength(1).maxLength(300).pattern(packageLookupIdPattern.source),
95
+ }), {
96
+ normalize: (input) => mapObjectInput(input, (value) => {
97
+ const packageId = value['*'];
98
+ if (typeof packageId !== 'string') {
105
99
  return value;
100
+ }
106
101
  try {
107
- return decodeURIComponent(value).trim();
102
+ return {
103
+ ...value,
104
+ '*': decodeURIComponent(packageId).trim(),
105
+ };
108
106
  }
109
107
  catch {
110
- return '__INVALID_PACKAGE_ID__';
108
+ return {
109
+ ...value,
110
+ '*': '__INVALID_PACKAGE_ID__',
111
+ };
111
112
  }
112
- }, zod_1.z.string().min(1).max(300).regex(packageLookupIdPattern, 'Invalid package identifier')),
113
+ }),
113
114
  });
114
115
  // ---- Query string schemas ----
115
- // Note: z.coerce handles string-to-number conversion for query params
116
- const BrowseQuerySchema = zod_1.z.object({
117
- page: zod_1.z.coerce.number().int().min(1).max(10000).optional(),
118
- query: optionalNonEmpty(safeString(200)),
119
- category: optionalNonEmpty(categoryEnum),
120
- language: optionalNonEmpty(languageEnum),
121
- limit: zod_1.z.coerce.number().int().min(1).max(100).optional(),
122
- offset: zod_1.z.coerce.number().int().min(0).max(100000).optional(),
123
- }).passthrough(); // ignore unexpected query params (referrer tracking etc.)
124
- const VersionsQuerySchema = zod_1.z.object({
125
- majorMinor: zod_1.z.string().max(11).regex(majorMinorPattern, 'Must be major.minor (e.g. 1.0)').optional(),
126
- }).passthrough();
127
- const MatchQuerySchema = zod_1.z.object({
128
- version: zod_1.z.string().min(1).max(20).regex(safeAscii, 'ASCII only'),
129
- }).passthrough();
130
- const DocsQuerySchema = zod_1.z.object({
131
- index: zod_1.z.coerce.number().int().min(0).max(100).optional(),
132
- }).passthrough();
116
+ const BrowseQuerySchema = createValidator(objectSchema({
117
+ page: av.optional(av.int32().coerce({ from: 'string' }).min(1).max(10000)),
118
+ query: av.optional(safeString(200)),
119
+ category: av.optional(categoryEnum),
120
+ language: av.optional(languageEnum),
121
+ limit: av.optional(av.int32().coerce({ from: 'string' }).min(1).max(100)),
122
+ offset: av.optional(av.int32().coerce({ from: 'string' }).min(0).max(100000)),
123
+ }), {
124
+ normalize: (input) => mapObjectInput(input, (value) => ({
125
+ ...value,
126
+ query: emptyStringToUndefined(value.query),
127
+ category: emptyStringToUndefined(value.category),
128
+ language: emptyStringToUndefined(value.language),
129
+ })),
130
+ });
131
+ const VersionsQuerySchema = createValidator(objectSchema({
132
+ majorMinor: av.optional(av.string().maxLength(11).pattern(majorMinorPattern.source)),
133
+ }));
134
+ const MatchQuerySchema = createValidator(objectSchema({
135
+ version: av.string().minLength(1).maxLength(20).pattern(safeAscii.source),
136
+ }));
137
+ const DocsQuerySchema = createValidator(objectSchema({
138
+ index: av.optional(av.int32().coerce({ from: 'string' }).min(0).max(100)),
139
+ }));
133
140
  // ---- EventSchemaExport validation (parsed from the JSON string clients send) ----
134
- const EventExportEntryZod = zod_1.z.object({
135
- type: zod_1.z.enum(['fire-and-forget', 'returnable', 'broadcast']),
136
- category: zod_1.z.enum([
141
+ const AnyValiDocumentSchema = av.record(av.unknown());
142
+ const EventExportEntrySchema = objectSchema({
143
+ type: av.enum_(['fire-and-forget', 'returnable', 'broadcast']),
144
+ category: av.enum_([
137
145
  'emitEvents', 'onEvents',
138
146
  'emitReturnableEvents', 'onReturnableEvents',
139
147
  'emitBroadcast', 'onBroadcast',
140
148
  ]),
141
- description: zod_1.z.string().max(1000).optional(),
142
- defaultTimeout: zod_1.z.number().int().min(0).max(300).optional(),
143
- inputSchema: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
144
- outputSchema: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).nullable(),
145
- }).passthrough();
146
- const EventSchemaExportZod = zod_1.z.object({
149
+ description: av.optional(av.string().maxLength(1000)),
150
+ defaultTimeout: av.optional(av.int32().min(0).max(300)),
151
+ inputSchema: AnyValiDocumentSchema,
152
+ outputSchema: av.nullable(AnyValiDocumentSchema),
153
+ });
154
+ const EventSchemaExportObjectSchema = objectSchema({
147
155
  pluginName: safeStringRequired(1, 200),
148
156
  version: semverField,
149
- events: zod_1.z.record(zod_1.z.string(), EventExportEntryZod).default({}),
150
- capabilities: zod_1.z.unknown().optional(),
151
- dependencies: zod_1.z.array(zod_1.z.object({
152
- id: zod_1.z.string().min(1).max(200),
157
+ events: av.record(EventExportEntrySchema).default({}),
158
+ capabilities: av.optional(av.unknown()),
159
+ dependencies: av.optional(av.array(objectSchema({
160
+ id: av.string().minLength(1).maxLength(200),
153
161
  version: safeStringRequired(1, 50),
154
- })).max(100).optional(),
155
- }).passthrough();
162
+ })).maxItems(100)),
163
+ });
156
164
  // ---- Publish body schema ----
157
- const AuthorSchema = zod_1.z.union([
165
+ const AuthorSchema = av.union([
158
166
  safeString(200),
159
- zod_1.z.object({
167
+ objectSchema({
160
168
  name: safeStringRequired(1, 200),
161
- email: zod_1.z.string().max(200).email().optional(),
162
- url: zod_1.z.string().max(500).url().optional(),
163
- }).strict(),
169
+ email: av.optional(av.string().maxLength(200).format('email')),
170
+ url: av.optional(av.string().maxLength(500).format('url')),
171
+ }),
164
172
  ]);
165
- const PublishBodySchema = zod_1.z.object({
166
- org: zod_1.z.string().min(1).max(100).regex(slugPattern, 'Invalid org name'),
167
- name: zod_1.z.string().min(1).max(100).regex(packageNamePattern, 'Invalid plugin name'),
173
+ const PublishBodyObjectSchema = objectSchema({
174
+ org: av.string().minLength(1).maxLength(100).pattern(slugPattern.source),
175
+ name: av.string().minLength(1).maxLength(100).pattern(packageNamePattern.source),
168
176
  version: semverField,
169
177
  language: languageEnum,
170
- metadata: zod_1.z.object({
178
+ metadata: objectSchema({
171
179
  displayName: safeStringRequired(1, 200),
172
- description: zod_1.z.string().min(1).max(1000),
180
+ description: av.string().minLength(1).maxLength(1000),
173
181
  category: categoryEnum,
174
- tags: zod_1.z.array(safeString(50)).max(30),
175
- author: AuthorSchema.optional(),
176
- license: safeString(50).optional(),
177
- homepage: zod_1.z.string().max(500).url().optional(),
178
- repository: zod_1.z.string().max(500).url().optional(),
179
- }).strict(),
180
- eventSchema: EventSchemaExportZod, // parsed object, validated at HTTP boundary
181
- capabilities: zod_1.z.unknown().optional(),
182
- configSchema: zod_1.z.object({
183
- type: zod_1.z.literal('object'),
184
- properties: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
185
- required: zod_1.z.array(zod_1.z.string()).optional(),
186
- description: zod_1.z.string().optional(),
187
- }).passthrough().optional(),
188
- typeDefinitions: zod_1.z.object({
189
- nodejs: zod_1.z.string().max(5_000_000).optional(),
190
- csharp: zod_1.z.string().max(5_000_000).optional(),
191
- go: zod_1.z.string().max(5_000_000).optional(),
192
- java: zod_1.z.string().max(5_000_000).optional(),
193
- }).strict().optional(),
194
- documentation: zod_1.z.array(zod_1.z.string().max(1_000_000)).min(1).max(20),
195
- dependencies: zod_1.z.array(zod_1.z.object({
196
- id: zod_1.z.string().min(1).max(200).regex(slugPattern, 'Invalid plugin ID'),
182
+ tags: av.array(safeString(50)).maxItems(30),
183
+ author: av.optional(AuthorSchema),
184
+ license: av.optional(safeString(50)),
185
+ homepage: av.optional(av.string().maxLength(500).format('url')),
186
+ repository: av.optional(av.string().maxLength(500).format('url')),
187
+ }),
188
+ eventSchema: EventSchemaExportObjectSchema,
189
+ capabilities: av.optional(av.unknown()),
190
+ configSchema: av.optional(AnyValiDocumentSchema),
191
+ typeDefinitions: av.optional(objectSchema({
192
+ nodejs: av.optional(av.string().maxLength(5_000_000)),
193
+ csharp: av.optional(av.string().maxLength(5_000_000)),
194
+ go: av.optional(av.string().maxLength(5_000_000)),
195
+ java: av.optional(av.string().maxLength(5_000_000)),
196
+ })),
197
+ documentation: av.array(av.string().maxLength(1_000_000)).minItems(1).maxItems(20),
198
+ dependencies: av.optional(av.array(objectSchema({
199
+ id: av.string().minLength(1).maxLength(200).pattern(slugPattern.source),
197
200
  version: safeStringRequired(1, 50),
198
- }).strict()).max(100).optional(),
199
- package: zod_1.z.object({
200
- nodejs: safeString(200).optional(),
201
- csharp: safeString(200).optional(),
202
- go: safeString(200).optional(),
203
- java: safeString(200).optional(),
204
- python: safeString(200).optional(),
205
- }).strict().optional(),
206
- runtime: zod_1.z.object({
207
- nodejs: safeString(50).optional(),
208
- dotnet: safeString(50).optional(),
209
- go: safeString(50).optional(),
210
- java: safeString(50).optional(),
211
- python: safeString(50).optional(),
212
- }).strict().optional(),
213
- visibility: visibilityEnum.optional(),
214
- }).strict();
215
- class RegistryUIServer {
201
+ })).maxItems(100)),
202
+ package: av.optional(objectSchema({
203
+ nodejs: av.optional(safeString(200)),
204
+ csharp: av.optional(safeString(200)),
205
+ go: av.optional(safeString(200)),
206
+ java: av.optional(safeString(200)),
207
+ python: av.optional(safeString(200)),
208
+ })),
209
+ runtime: av.optional(objectSchema({
210
+ nodejs: av.optional(safeString(50)),
211
+ dotnet: av.optional(safeString(50)),
212
+ go: av.optional(safeString(50)),
213
+ java: av.optional(safeString(50)),
214
+ python: av.optional(safeString(50)),
215
+ })),
216
+ visibility: av.optional(visibilityEnum),
217
+ });
218
+ function validateAnyValiDocument(value, path) {
219
+ if (!value || typeof value !== 'object') {
220
+ return [{
221
+ code: 'invalid_type',
222
+ message: 'Expected AnyVali document object',
223
+ path,
224
+ expected: 'object',
225
+ received: typeof value,
226
+ }];
227
+ }
228
+ try {
229
+ av.importSchema(value);
230
+ return [];
231
+ }
232
+ catch (error) {
233
+ const issues = error instanceof av.ValidationError
234
+ ? error.issues
235
+ : [{
236
+ code: 'invalid_schema',
237
+ message: error instanceof Error ? error.message : 'Invalid AnyVali document',
238
+ path: [],
239
+ }];
240
+ return issues.map((issue) => ({
241
+ ...issue,
242
+ path: [...path, ...issue.path],
243
+ }));
244
+ }
245
+ }
246
+ function validateEventSchemaExportDocuments(value, path = []) {
247
+ const nestedIssues = [];
248
+ for (const [eventName, eventDef] of Object.entries(value.events)) {
249
+ nestedIssues.push(...validateAnyValiDocument(eventDef.inputSchema, [...path, 'events', eventName, 'inputSchema']));
250
+ if (eventDef.outputSchema !== null) {
251
+ nestedIssues.push(...validateAnyValiDocument(eventDef.outputSchema, [...path, 'events', eventName, 'outputSchema']));
252
+ }
253
+ }
254
+ return nestedIssues;
255
+ }
256
+ const PublishBodySchema = createValidator(PublishBodyObjectSchema, {
257
+ extraIssues: (value) => [
258
+ ...validateEventSchemaExportDocuments(value.eventSchema, ['eventSchema']),
259
+ ...(value.configSchema !== undefined
260
+ ? validateAnyValiDocument(value.configSchema, ['configSchema'])
261
+ : []),
262
+ ],
263
+ });
264
+ export class RegistryUIServer {
216
265
  app;
217
266
  port;
218
267
  host;
@@ -234,7 +283,7 @@ class RegistryUIServer {
234
283
  this.badgesFile = path.resolve(badgesFile);
235
284
  this.maxImageUploadBytes = maxImageUploadMb * 1024 * 1024;
236
285
  this.imageIndexPath = path.join(this.uploadDir, 'images.json');
237
- this.app = (0, fastify_1.default)({
286
+ this.app = Fastify({
238
287
  logger: false,
239
288
  disableRequestLogging: true,
240
289
  bodyLimit: 10 * 1024 * 1024, // 10MB max request body
@@ -308,7 +357,7 @@ class RegistryUIServer {
308
357
  registerHandlebarsHelpers() {
309
358
  const helpers = this.getHandlebarsHelpers();
310
359
  for (const [name, fn] of Object.entries(helpers)) {
311
- handlebars_1.default.registerHelper(name, fn);
360
+ handlebars.registerHelper(name, fn);
312
361
  }
313
362
  }
314
363
  async init(obs, plugin) {
@@ -320,7 +369,7 @@ class RegistryUIServer {
320
369
  this.pluginCwd = plugin.pluginCwd;
321
370
  // Register CORS
322
371
  const corsSpan = obs.startSpan('register.cors');
323
- await this.app.register(cors_1.default, {
372
+ await this.app.register(fastifyCors, {
324
373
  origin: '*',
325
374
  methods: ['GET', 'POST', 'OPTIONS'],
326
375
  allowedHeaders: ['Content-Type', 'Authorization', 'Accept'],
@@ -328,7 +377,7 @@ class RegistryUIServer {
328
377
  corsSpan.end();
329
378
  // Register multipart upload handling for plugin images
330
379
  const multipartSpan = obs.startSpan('register.multipart');
331
- await this.app.register(multipart_1.default, {
380
+ await this.app.register(fastifyMultipart, {
332
381
  limits: {
333
382
  fileSize: this.maxImageUploadBytes,
334
383
  files: 1,
@@ -342,13 +391,13 @@ class RegistryUIServer {
342
391
  // Register static file serving
343
392
  const staticSpan = obs.startSpan('register.static');
344
393
  const staticPath = path.join(plugin.pluginCwd, 'static');
345
- await this.app.register(static_1.default, {
394
+ await this.app.register(fastifyStatic, {
346
395
  root: staticPath,
347
396
  prefix: '/static/',
348
397
  index: false,
349
398
  });
350
399
  await fsp.mkdir(this.uploadDir, { recursive: true });
351
- await this.app.register(static_1.default, {
400
+ await this.app.register(fastifyStatic, {
352
401
  root: this.uploadDir,
353
402
  prefix: '/images/',
354
403
  decorateReply: false,
@@ -360,9 +409,9 @@ class RegistryUIServer {
360
409
  const viewSpan = obs.startSpan('register.handlebars');
361
410
  const templatesPath = path.join(plugin.pluginCwd, 'templates');
362
411
  obs.log.debug('Registering Handlebars templates from {path}', { path: templatesPath });
363
- await this.app.register(view_1.default, {
412
+ await this.app.register(fastifyView, {
364
413
  engine: {
365
- handlebars: handlebars_1.default,
414
+ handlebars,
366
415
  },
367
416
  root: templatesPath,
368
417
  layout: 'layouts/main.hbs',
@@ -546,24 +595,24 @@ class RegistryUIServer {
546
595
  return request.headers.accept?.includes('application/json') === true;
547
596
  }
548
597
  /**
549
- * Validate input against a Zod schema. Returns parsed data on success,
598
+ * Validate input against an AnyVali-backed schema. Returns parsed data on success,
550
599
  * or sends a 400 response and returns null on failure.
551
600
  */
552
601
  validateInput(schema, data, reply) {
553
602
  const result = schema.safeParse(data);
554
- if (!result.success) {
555
- const issues = result.error.issues.map((issue) => ({
556
- path: issue.path.join('.'),
557
- message: issue.message,
558
- }));
559
- reply.code(400).send({
560
- error: 'Validation Error',
561
- code: 'INVALID_INPUT',
562
- details: issues,
563
- });
564
- return null;
603
+ if (result.success) {
604
+ return result.data;
565
605
  }
566
- return result.data;
606
+ const issues = result.issues.map((issue) => ({
607
+ path: issue.path.join('.'),
608
+ message: issue.message,
609
+ }));
610
+ reply.code(400).send({
611
+ error: 'Validation Error',
612
+ code: 'INVALID_INPUT',
613
+ details: issues,
614
+ });
615
+ return null;
567
616
  }
568
617
  /** Render an error page (HTML) or send JSON error depending on Accept header */
569
618
  async renderError(request, reply, statusCode, title, message) {
@@ -981,13 +1030,13 @@ a.s:hover{background:#333;border-color:#FB8C00}
981
1030
  * External links open in a new tab. Raw HTML in the source is escaped.
982
1031
  */
983
1032
  renderMarkdown(md) {
984
- const renderer = new marked_1.marked.Renderer();
1033
+ const renderer = new marked.Renderer();
985
1034
  // Open external links in new tab with noopener
986
1035
  renderer.link = ({ href, title, text }) => {
987
1036
  const titleAttr = title ? ` title="${title}"` : '';
988
1037
  return `<a href="${href}"${titleAttr} target="_blank" rel="noopener noreferrer">${text}</a>`;
989
1038
  };
990
- return marked_1.marked.parse(md, {
1039
+ return marked.parse(md, {
991
1040
  renderer,
992
1041
  gfm: true,
993
1042
  breaks: false,
@@ -1718,7 +1767,7 @@ a.s:hover{background:#333;border-color:#FB8C00}
1718
1767
  const safeFileName = `${params.org}__${params.name}${ext}`;
1719
1768
  const outputPath = path.join(this.uploadDir, safeFileName);
1720
1769
  await fsp.mkdir(this.uploadDir, { recursive: true });
1721
- await (0, promises_1.pipeline)(filePart.file, fs.createWriteStream(outputPath));
1770
+ await pipeline(filePart.file, fs.createWriteStream(outputPath));
1722
1771
  if (filePart.file.truncated) {
1723
1772
  await fsp.unlink(outputPath).catch(() => { });
1724
1773
  reply.code(413).send({
@@ -1833,5 +1882,4 @@ a.s:hover{background:#333;border-color:#FB8C00}
1833
1882
  this.app.close();
1834
1883
  }
1835
1884
  }
1836
- exports.RegistryUIServer = RegistryUIServer;
1837
1885
  //# sourceMappingURL=http-server.js.map