@rebasepro/server 0.0.1-canary.4829d6e

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 (127) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +77 -0
  3. package/dist/api/ast-schema-editor.d.ts +21 -0
  4. package/dist/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
  5. package/dist/api/errors.d.ts +53 -0
  6. package/dist/api/index.d.ts +7 -0
  7. package/dist/api/logs-routes.d.ts +37 -0
  8. package/dist/api/openapi-generator.d.ts +16 -0
  9. package/dist/api/rest/api-generator.d.ts +68 -0
  10. package/dist/api/rest/index.d.ts +1 -0
  11. package/dist/api/rest/query-parser.d.ts +6 -0
  12. package/dist/api/schema-editor-routes.d.ts +3 -0
  13. package/dist/api/types.d.ts +56 -0
  14. package/dist/auth/adapter-middleware.d.ts +43 -0
  15. package/dist/auth/admin-roles-route.d.ts +18 -0
  16. package/dist/auth/admin-user-ops.d.ts +80 -0
  17. package/dist/auth/admin-users-route.d.ts +28 -0
  18. package/dist/auth/api-keys/api-key-middleware.d.ts +39 -0
  19. package/dist/auth/api-keys/api-key-permission-guard.d.ts +32 -0
  20. package/dist/auth/api-keys/api-key-routes.d.ts +20 -0
  21. package/dist/auth/api-keys/api-key-store.d.ts +35 -0
  22. package/dist/auth/api-keys/api-key-types.d.ts +96 -0
  23. package/dist/auth/api-keys/index.d.ts +17 -0
  24. package/dist/auth/apple-oauth.d.ts +30 -0
  25. package/dist/auth/auth-hooks.d.ts +242 -0
  26. package/dist/auth/bitbucket-oauth.d.ts +11 -0
  27. package/dist/auth/builtin-auth-adapter.d.ts +55 -0
  28. package/dist/auth/cookie-utils.d.ts +32 -0
  29. package/dist/auth/crypto-utils.d.ts +16 -0
  30. package/dist/auth/custom-auth-adapter.d.ts +39 -0
  31. package/dist/auth/discord-oauth.d.ts +14 -0
  32. package/dist/auth/facebook-oauth.d.ts +14 -0
  33. package/dist/auth/github-oauth.d.ts +15 -0
  34. package/dist/auth/gitlab-oauth.d.ts +13 -0
  35. package/dist/auth/google-oauth.d.ts +47 -0
  36. package/dist/auth/index.d.ts +38 -0
  37. package/dist/auth/interfaces.d.ts +431 -0
  38. package/dist/auth/jwt.d.ts +67 -0
  39. package/dist/auth/linkedin-oauth.d.ts +18 -0
  40. package/dist/auth/magic-link-routes.d.ts +32 -0
  41. package/dist/auth/mfa-crypto.d.ts +23 -0
  42. package/dist/auth/mfa-routes.d.ts +7 -0
  43. package/dist/auth/mfa.d.ts +49 -0
  44. package/dist/auth/microsoft-oauth.d.ts +16 -0
  45. package/dist/auth/middleware.d.ts +158 -0
  46. package/dist/auth/password.d.ts +22 -0
  47. package/dist/auth/rate-limiter.d.ts +50 -0
  48. package/dist/auth/reset-password-admin.d.ts +29 -0
  49. package/dist/auth/rls-scope.d.ts +31 -0
  50. package/dist/auth/routes.d.ts +66 -0
  51. package/dist/auth/session-routes.d.ts +29 -0
  52. package/dist/auth/slack-oauth.d.ts +12 -0
  53. package/dist/auth/spotify-oauth.d.ts +12 -0
  54. package/dist/auth/twitter-oauth.d.ts +18 -0
  55. package/dist/backup/backup-common.d.ts +31 -0
  56. package/dist/backup/backup-routes.d.ts +22 -0
  57. package/dist/backup/index.d.ts +7 -0
  58. package/dist/collections/BackendCollectionRegistry.d.ts +13 -0
  59. package/dist/collections/loader.d.ts +39 -0
  60. package/dist/cron/cron-loader.d.ts +18 -0
  61. package/dist/cron/cron-routes.d.ts +14 -0
  62. package/dist/cron/cron-scheduler.d.ts +106 -0
  63. package/dist/cron/cron-store.d.ts +32 -0
  64. package/dist/cron/define-cron.d.ts +28 -0
  65. package/dist/cron/index.d.ts +7 -0
  66. package/dist/db/interfaces.d.ts +18 -0
  67. package/dist/dynamic-import-Dvh-K5fl.js +22 -0
  68. package/dist/dynamic-import-Dvh-K5fl.js.map +1 -0
  69. package/dist/email/index.d.ts +6 -0
  70. package/dist/email/smtp-email-service.d.ts +30 -0
  71. package/dist/email/templates.d.ts +50 -0
  72. package/dist/email/types.d.ts +126 -0
  73. package/dist/env.d.ts +102 -0
  74. package/dist/functions/define-function.d.ts +55 -0
  75. package/dist/functions/function-loader.d.ts +18 -0
  76. package/dist/functions/function-routes.d.ts +10 -0
  77. package/dist/functions/index.d.ts +5 -0
  78. package/dist/history/history-routes.d.ts +23 -0
  79. package/dist/history/index.d.ts +1 -0
  80. package/dist/index.d.ts +38 -0
  81. package/dist/index.es.js +18458 -0
  82. package/dist/index.es.js.map +1 -0
  83. package/dist/index.umd.js +48745 -0
  84. package/dist/index.umd.js.map +1 -0
  85. package/dist/init/docs.d.ts +4 -0
  86. package/dist/init/health.d.ts +2 -0
  87. package/dist/init/middlewares.d.ts +10 -0
  88. package/dist/init/shutdown.d.ts +65 -0
  89. package/dist/init/storage.d.ts +5 -0
  90. package/dist/init.d.ts +375 -0
  91. package/dist/jwt-BwIn8xmk.js +4200 -0
  92. package/dist/jwt-BwIn8xmk.js.map +1 -0
  93. package/dist/logger-BYU66ENZ.js +94 -0
  94. package/dist/logger-BYU66ENZ.js.map +1 -0
  95. package/dist/ms-DnYXB-Wd.js +162 -0
  96. package/dist/ms-DnYXB-Wd.js.map +1 -0
  97. package/dist/openapi-generator-Z9oYWLf_.js +586 -0
  98. package/dist/openapi-generator-Z9oYWLf_.js.map +1 -0
  99. package/dist/schema-editor-routes-D3ef8zu1.js +219 -0
  100. package/dist/schema-editor-routes-D3ef8zu1.js.map +1 -0
  101. package/dist/serve-spa.d.ts +36 -0
  102. package/dist/services/driver-registry.d.ts +78 -0
  103. package/dist/services/routed-realtime-service.d.ts +43 -0
  104. package/dist/services/webhook-service.d.ts +29 -0
  105. package/dist/singleton.d.ts +51 -0
  106. package/dist/src-B4OLmNVa.js +437 -0
  107. package/dist/src-B4OLmNVa.js.map +1 -0
  108. package/dist/src-B9tjYmqP.js +24598 -0
  109. package/dist/src-B9tjYmqP.js.map +1 -0
  110. package/dist/storage/GCSStorageController.d.ts +43 -0
  111. package/dist/storage/LocalStorageController.d.ts +46 -0
  112. package/dist/storage/S3StorageController.d.ts +40 -0
  113. package/dist/storage/image-transform.d.ts +50 -0
  114. package/dist/storage/index.d.ts +31 -0
  115. package/dist/storage/routes.d.ts +70 -0
  116. package/dist/storage/storage-registry.d.ts +78 -0
  117. package/dist/storage/tus-handler.d.ts +53 -0
  118. package/dist/storage/types.d.ts +128 -0
  119. package/dist/types/index.d.ts +11 -0
  120. package/dist/utils/dev-port.d.ts +45 -0
  121. package/dist/utils/dynamic-import.d.ts +25 -0
  122. package/dist/utils/logger.d.ts +31 -0
  123. package/dist/utils/logging.d.ts +9 -0
  124. package/dist/utils/request-id.d.ts +4 -0
  125. package/dist/utils/request-logger.d.ts +19 -0
  126. package/dist/utils/sql.d.ts +27 -0
  127. package/package.json +115 -0
@@ -0,0 +1,586 @@
1
+ import { createRequire as __createRequire } from "module";
2
+ import "process";
3
+ __createRequire(import.meta.url);
4
+ //#region src/api/openapi-generator.ts
5
+ function generateOpenApiSpec(collections, options = {}) {
6
+ const basePath = options.basePath ?? "/api";
7
+ const requireAuth = options.requireAuth ?? true;
8
+ const spec = {
9
+ openapi: "3.0.3",
10
+ info: {
11
+ title: "Rebase API",
12
+ version: "1.0.0",
13
+ description: "Auto-generated REST API from Rebase collection definitions. This is the same API consumed by the `@rebasepro/client` SDK."
14
+ },
15
+ servers: [{
16
+ url: basePath,
17
+ description: "API Server"
18
+ }],
19
+ paths: {},
20
+ components: {
21
+ schemas: {
22
+ ErrorResponse: {
23
+ type: "object",
24
+ properties: { error: {
25
+ type: "object",
26
+ required: ["message", "code"],
27
+ properties: {
28
+ message: { type: "string" },
29
+ code: { type: "string" },
30
+ details: {}
31
+ }
32
+ } }
33
+ },
34
+ PaginationMeta: {
35
+ type: "object",
36
+ properties: {
37
+ total: {
38
+ type: "integer",
39
+ description: "Total number of matching records"
40
+ },
41
+ limit: {
42
+ type: "integer",
43
+ description: "Page size used for this query"
44
+ },
45
+ offset: {
46
+ type: "integer",
47
+ description: "Number of records skipped"
48
+ },
49
+ hasMore: {
50
+ type: "boolean",
51
+ description: "Whether more records exist beyond this page"
52
+ }
53
+ }
54
+ }
55
+ },
56
+ securitySchemes: {}
57
+ },
58
+ tags: []
59
+ };
60
+ if (requireAuth) {
61
+ spec.components.securitySchemes = {
62
+ bearerAuth: {
63
+ type: "http",
64
+ scheme: "bearer",
65
+ bearerFormat: "JWT",
66
+ description: "JWT access token obtained from `POST /auth/login` or `POST /auth/register`. Can also be a static service key for server-to-server authentication."
67
+ },
68
+ queryToken: {
69
+ type: "apiKey",
70
+ in: "query",
71
+ name: "token",
72
+ description: "Alternative: pass the JWT or service key as a `token` query parameter."
73
+ }
74
+ };
75
+ spec.security = [{ bearerAuth: [] }, { queryToken: [] }];
76
+ }
77
+ const paths = spec.paths;
78
+ const schemas = spec.components.schemas;
79
+ const tags = spec.tags;
80
+ for (const collection of collections || []) {
81
+ const schemaName = toPascalCase(collection.singularName || collection.name);
82
+ const slug = collection.slug;
83
+ tags.push({
84
+ name: collection.name,
85
+ description: collection.description || `CRUD operations for ${collection.name}`
86
+ });
87
+ schemas[schemaName] = buildCollectionSchema(collection);
88
+ schemas[`${schemaName}Input`] = buildCollectionInputSchema(collection);
89
+ const dataPath = `/data/${slug}`;
90
+ paths[dataPath] = {
91
+ get: {
92
+ tags: [collection.name],
93
+ summary: `List ${collection.name}`,
94
+ operationId: `list${schemaName}`,
95
+ parameters: [
96
+ {
97
+ name: "limit",
98
+ in: "query",
99
+ schema: {
100
+ type: "integer",
101
+ default: 20,
102
+ maximum: 100
103
+ },
104
+ description: "Maximum number of records to return"
105
+ },
106
+ {
107
+ name: "offset",
108
+ in: "query",
109
+ schema: {
110
+ type: "integer",
111
+ default: 0
112
+ },
113
+ description: "Number of records to skip"
114
+ },
115
+ {
116
+ name: "page",
117
+ in: "query",
118
+ schema: {
119
+ type: "integer",
120
+ minimum: 1
121
+ },
122
+ description: "Page number (alternative to offset). Calculates offset as (page-1)*limit"
123
+ },
124
+ {
125
+ name: "orderBy",
126
+ in: "query",
127
+ schema: { type: "string" },
128
+ description: "Sort field and direction. Accepts `field:asc` or `field:desc`, or a JSON array `[{\"field\":\"name\",\"direction\":\"asc\"}]`",
129
+ example: "created_at:desc"
130
+ },
131
+ {
132
+ name: "where",
133
+ in: "query",
134
+ schema: { type: "string" },
135
+ description: "JSON object filter. Example: `{\"status\":[\"==\",\"active\"]}`"
136
+ },
137
+ {
138
+ name: "include",
139
+ in: "query",
140
+ schema: { type: "string" },
141
+ description: "Comma-separated list of relations to include (eager-load). Use `*` for all relations.",
142
+ example: "author,tags"
143
+ },
144
+ {
145
+ name: "fields",
146
+ in: "query",
147
+ schema: { type: "string" },
148
+ description: "Comma-separated list of fields to return (field selection)",
149
+ example: "id,name,created_at"
150
+ },
151
+ {
152
+ name: "searchString",
153
+ in: "query",
154
+ schema: { type: "string" },
155
+ description: "Full-text search query"
156
+ },
157
+ ...buildFilterParameters(collection)
158
+ ],
159
+ responses: {
160
+ 200: {
161
+ description: "Paginated list of entities",
162
+ content: { "application/json": { schema: {
163
+ type: "object",
164
+ properties: {
165
+ data: {
166
+ type: "array",
167
+ items: { $ref: `#/components/schemas/${schemaName}` }
168
+ },
169
+ meta: { $ref: "#/components/schemas/PaginationMeta" }
170
+ }
171
+ } } }
172
+ },
173
+ ...errorResponses(requireAuth)
174
+ }
175
+ },
176
+ post: {
177
+ tags: [collection.name],
178
+ summary: `Create ${collection.singularName || collection.name}`,
179
+ operationId: `create${schemaName}`,
180
+ requestBody: {
181
+ required: true,
182
+ content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}Input` } } }
183
+ },
184
+ responses: {
185
+ 201: {
186
+ description: "Created entity",
187
+ content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
188
+ },
189
+ ...errorResponses(requireAuth)
190
+ }
191
+ }
192
+ };
193
+ const entityPath = `/data/${slug}/{id}`;
194
+ paths[entityPath] = {
195
+ get: {
196
+ tags: [collection.name],
197
+ summary: `Get ${collection.singularName || collection.name} by ID`,
198
+ operationId: `get${schemaName}ById`,
199
+ parameters: [{
200
+ name: "id",
201
+ in: "path",
202
+ required: true,
203
+ schema: { type: "string" },
204
+ description: "Entity ID"
205
+ }, {
206
+ name: "include",
207
+ in: "query",
208
+ schema: { type: "string" },
209
+ description: "Comma-separated list of relations to include",
210
+ example: "author,tags"
211
+ }],
212
+ responses: {
213
+ 200: {
214
+ description: "Entity found",
215
+ content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
216
+ },
217
+ 404: {
218
+ description: "Entity not found",
219
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
220
+ },
221
+ ...errorResponses(requireAuth)
222
+ }
223
+ },
224
+ put: {
225
+ tags: [collection.name],
226
+ summary: `Update ${collection.singularName || collection.name}`,
227
+ operationId: `update${schemaName}`,
228
+ parameters: [{
229
+ name: "id",
230
+ in: "path",
231
+ required: true,
232
+ schema: { type: "string" },
233
+ description: "Entity ID"
234
+ }],
235
+ requestBody: {
236
+ required: true,
237
+ content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}Input` } } }
238
+ },
239
+ responses: {
240
+ 200: {
241
+ description: "Updated entity",
242
+ content: { "application/json": { schema: { $ref: `#/components/schemas/${schemaName}` } } }
243
+ },
244
+ 404: {
245
+ description: "Entity not found",
246
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
247
+ },
248
+ ...errorResponses(requireAuth)
249
+ }
250
+ },
251
+ delete: {
252
+ tags: [collection.name],
253
+ summary: `Delete ${collection.singularName || collection.name}`,
254
+ operationId: `delete${schemaName}`,
255
+ parameters: [{
256
+ name: "id",
257
+ in: "path",
258
+ required: true,
259
+ schema: { type: "string" },
260
+ description: "Entity ID"
261
+ }],
262
+ responses: {
263
+ 204: { description: "Deleted successfully" },
264
+ 404: {
265
+ description: "Entity not found",
266
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
267
+ },
268
+ ...errorResponses(requireAuth)
269
+ }
270
+ }
271
+ };
272
+ const relations = collection.relations;
273
+ if (relations && relations.length > 0) for (const relation of relations) {
274
+ const relationName = relation.relationName;
275
+ if (!relationName) continue;
276
+ let targetName;
277
+ try {
278
+ const targetCollection = relation.target();
279
+ targetName = targetCollection.singularName || targetCollection.name;
280
+ } catch {
281
+ targetName = relationName;
282
+ }
283
+ const targetSchema = toPascalCase(targetName);
284
+ const subPath = `/data/${slug}/{parentId}/${relationName}`;
285
+ paths[subPath] = { get: {
286
+ tags: [collection.name],
287
+ summary: `List ${relationName} for a ${collection.singularName || collection.name}`,
288
+ operationId: `list${schemaName}${toPascalCase(relationName)}`,
289
+ parameters: [
290
+ {
291
+ name: "parentId",
292
+ in: "path",
293
+ required: true,
294
+ schema: { type: "string" },
295
+ description: `${collection.singularName || collection.name} ID`
296
+ },
297
+ {
298
+ name: "limit",
299
+ in: "query",
300
+ schema: {
301
+ type: "integer",
302
+ default: 20
303
+ }
304
+ },
305
+ {
306
+ name: "offset",
307
+ in: "query",
308
+ schema: {
309
+ type: "integer",
310
+ default: 0
311
+ }
312
+ },
313
+ {
314
+ name: "orderBy",
315
+ in: "query",
316
+ schema: { type: "string" }
317
+ },
318
+ {
319
+ name: "searchString",
320
+ in: "query",
321
+ schema: { type: "string" }
322
+ }
323
+ ],
324
+ responses: {
325
+ 200: {
326
+ description: `List of related ${relationName}`,
327
+ content: { "application/json": { schema: {
328
+ type: "object",
329
+ properties: {
330
+ data: {
331
+ type: "array",
332
+ items: schemas[targetSchema] ? { $ref: `#/components/schemas/${targetSchema}` } : { type: "object" }
333
+ },
334
+ meta: { $ref: "#/components/schemas/PaginationMeta" }
335
+ }
336
+ } } }
337
+ },
338
+ ...errorResponses(requireAuth)
339
+ }
340
+ } };
341
+ }
342
+ }
343
+ return spec;
344
+ }
345
+ /**
346
+ * Build the component schema for a collection (output / read shape).
347
+ * All fields are included (including relation foreign keys).
348
+ */
349
+ function buildCollectionSchema(collection) {
350
+ const properties = { id: {
351
+ type: "string",
352
+ description: "Unique identifier"
353
+ } };
354
+ const required = ["id"];
355
+ for (const [key, property] of Object.entries(collection.properties)) {
356
+ if (property.type === "relation") continue;
357
+ properties[key] = convertPropertyToSchema(property);
358
+ if (property.validation?.required) required.push(key);
359
+ }
360
+ return {
361
+ type: "object",
362
+ required: required.length > 0 ? required : void 0,
363
+ properties
364
+ };
365
+ }
366
+ /**
367
+ * Build an input schema (for POST/PUT) — excludes auto-generated fields.
368
+ */
369
+ function buildCollectionInputSchema(collection) {
370
+ const properties = {};
371
+ const required = [];
372
+ for (const [key, property] of Object.entries(collection.properties)) {
373
+ if (property.type === "relation") continue;
374
+ if (property.type === "date" && property.autoValue) continue;
375
+ if ("isId" in property && property.isId && property.isId !== "manual" && property.isId !== true) continue;
376
+ properties[key] = convertPropertyToSchema(property);
377
+ if (property.validation?.required) required.push(key);
378
+ }
379
+ properties["id"] = {
380
+ type: "string",
381
+ description: "Optional: client-assigned ID. If omitted, the server generates one."
382
+ };
383
+ return {
384
+ type: "object",
385
+ required: required.length > 0 ? required : void 0,
386
+ properties
387
+ };
388
+ }
389
+ /**
390
+ * Convert a Rebase Property to an OpenAPI 3.0 schema object.
391
+ */
392
+ function convertPropertyToSchema(property) {
393
+ const base = {};
394
+ if (property.name) base.description = property.name;
395
+ switch (property.type) {
396
+ case "string": {
397
+ const sp = property;
398
+ base.type = "string";
399
+ if (sp.enum) {
400
+ const enumValues = resolveEnumValues(sp.enum);
401
+ if (enumValues.length > 0) base.enum = enumValues;
402
+ }
403
+ if (sp.validation) {
404
+ if (sp.validation.min !== void 0) base.minLength = sp.validation.min;
405
+ if (sp.validation.max !== void 0) base.maxLength = sp.validation.max;
406
+ if (sp.validation.length !== void 0) {
407
+ base.minLength = sp.validation.length;
408
+ base.maxLength = sp.validation.length;
409
+ }
410
+ if (sp.validation.matches !== void 0) base.pattern = String(sp.validation.matches);
411
+ }
412
+ if (sp.email) base.format = "email";
413
+ if (sp.ui?.url) base.format = "uri";
414
+ if (sp.storage) base.format = "uri";
415
+ if (sp.ui?.markdown) base.description = (base.description || "") + " (Markdown)";
416
+ return base;
417
+ }
418
+ case "number": {
419
+ const np = property;
420
+ base.type = np.validation?.integer || np.columnType === "integer" || np.columnType === "serial" || np.columnType === "bigserial" || np.columnType === "bigint" ? "integer" : "number";
421
+ if (np.enum) {
422
+ const enumValues = resolveEnumValues(np.enum);
423
+ if (enumValues.length > 0) base.enum = enumValues;
424
+ }
425
+ if (np.validation) {
426
+ if (np.validation.min !== void 0) base.minimum = np.validation.min;
427
+ if (np.validation.max !== void 0) base.maximum = np.validation.max;
428
+ if (np.validation.moreThan !== void 0) {
429
+ base.minimum = np.validation.moreThan;
430
+ base.exclusiveMinimum = true;
431
+ }
432
+ if (np.validation.lessThan !== void 0) {
433
+ base.maximum = np.validation.lessThan;
434
+ base.exclusiveMaximum = true;
435
+ }
436
+ }
437
+ return base;
438
+ }
439
+ case "boolean":
440
+ base.type = "boolean";
441
+ return base;
442
+ case "date":
443
+ base.type = "string";
444
+ if (property.mode === "date") base.format = "date";
445
+ else base.format = "date-time";
446
+ if (property.autoValue) {
447
+ base.readOnly = true;
448
+ base.description = (base.description || "") + (property.autoValue === "on_create" ? " (Auto-set on creation)" : " (Auto-updated)");
449
+ }
450
+ return base;
451
+ case "geopoint":
452
+ base.type = "object";
453
+ base.properties = {
454
+ latitude: { type: "number" },
455
+ longitude: { type: "number" }
456
+ };
457
+ base.required = ["latitude", "longitude"];
458
+ return base;
459
+ case "reference":
460
+ base.type = "string";
461
+ base.description = (base.description || "") + " (Reference ID)";
462
+ return base;
463
+ case "array": {
464
+ const ap = property;
465
+ base.type = "array";
466
+ if (ap.oneOf) {
467
+ const typeField = ap.oneOf.typeField || "type";
468
+ const valueField = ap.oneOf.valueField || "value";
469
+ const variants = [];
470
+ for (const [variantKey, variantProp] of Object.entries(ap.oneOf.properties)) variants.push({
471
+ type: "object",
472
+ properties: {
473
+ [typeField]: {
474
+ type: "string",
475
+ enum: [variantKey]
476
+ },
477
+ [valueField]: convertPropertyToSchema(variantProp)
478
+ },
479
+ required: [typeField, valueField]
480
+ });
481
+ base.items = { oneOf: variants };
482
+ } else if (ap.of) if (Array.isArray(ap.of)) base.items = { oneOf: ap.of.map((p) => convertPropertyToSchema(p)) };
483
+ else base.items = convertPropertyToSchema(ap.of);
484
+ else base.items = {};
485
+ if (ap.validation) {
486
+ if (ap.validation.min !== void 0) base.minItems = ap.validation.min;
487
+ if (ap.validation.max !== void 0) base.maxItems = ap.validation.max;
488
+ }
489
+ return base;
490
+ }
491
+ case "map": {
492
+ const mp = property;
493
+ base.type = "object";
494
+ if (mp.properties) {
495
+ const props = {};
496
+ const req = [];
497
+ for (const [key, subProp] of Object.entries(mp.properties)) {
498
+ props[key] = convertPropertyToSchema(subProp);
499
+ if (subProp.validation?.required) req.push(key);
500
+ }
501
+ base.properties = props;
502
+ if (req.length > 0) base.required = req;
503
+ } else if (mp.keyValue) base.additionalProperties = true;
504
+ return base;
505
+ }
506
+ case "vector": {
507
+ const vp = property;
508
+ base.type = "array";
509
+ base.items = { type: "number" };
510
+ base.description = (base.description || "") + ` (Vector(${vp.dimensions}))`;
511
+ return base;
512
+ }
513
+ case "binary":
514
+ base.type = "string";
515
+ base.description = (base.description || "") + " (Binary/Base64)";
516
+ return base;
517
+ default:
518
+ base.type = "string";
519
+ return base;
520
+ }
521
+ }
522
+ /**
523
+ * Resolve EnumValues (array or record) into a flat array of enum values.
524
+ */
525
+ function resolveEnumValues(enumDef) {
526
+ if (Array.isArray(enumDef)) return enumDef.map((e) => typeof e === "object" && e !== null && "id" in e ? e.id : e);
527
+ return Object.keys(enumDef).map((k) => {
528
+ const num = Number(k);
529
+ return isNaN(num) ? k : num;
530
+ });
531
+ }
532
+ /**
533
+ * Build PostgREST-style filter parameters for a collection.
534
+ * These are additional query parameters like `?status=eq.active&price=gte.100`.
535
+ */
536
+ function buildFilterParameters(collection) {
537
+ const params = [];
538
+ for (const [key, property] of Object.entries(collection.properties)) {
539
+ if (property.type === "relation" || property.type === "map" || property.type === "array" || property.type === "geopoint") continue;
540
+ params.push({
541
+ name: key,
542
+ in: "query",
543
+ required: false,
544
+ schema: { type: "string" },
545
+ description: `Filter by \`${key}\`. Supports PostgREST operators: \`eq.value\`, \`neq.value\`, \`gt.value\`, \`gte.value\`, \`lt.value\`, \`lte.value\`, \`in.(a,b,c)\`, \`nin.(a,b,c)\`, \`cs.value\` (array-contains), \`csa.(a,b)\` (array-contains-any). Plain values imply equality.`,
546
+ example: property.type === "string" ? "eq.active" : property.type === "number" ? "gte.100" : void 0
547
+ });
548
+ }
549
+ return params;
550
+ }
551
+ /**
552
+ * Standard error responses included on every endpoint.
553
+ */
554
+ function errorResponses(requireAuth) {
555
+ const responses = {
556
+ 400: {
557
+ description: "Bad request",
558
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
559
+ },
560
+ 500: {
561
+ description: "Internal server error",
562
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
563
+ }
564
+ };
565
+ if (requireAuth) {
566
+ responses[401] = {
567
+ description: "Authentication required or invalid token",
568
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
569
+ };
570
+ responses[403] = {
571
+ description: "Insufficient permissions",
572
+ content: { "application/json": { schema: { $ref: "#/components/schemas/ErrorResponse" } } }
573
+ };
574
+ }
575
+ return responses;
576
+ }
577
+ /**
578
+ * Convert a string to PascalCase for schema names.
579
+ */
580
+ function toPascalCase(str) {
581
+ return str.replace(/[^a-zA-Z0-9]+/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join("");
582
+ }
583
+ //#endregion
584
+ export { generateOpenApiSpec };
585
+
586
+ //# sourceMappingURL=openapi-generator-Z9oYWLf_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openapi-generator-Z9oYWLf_.js","names":[],"sources":["../src/api/openapi-generator.ts"],"sourcesContent":["import { CollectionConfig, Property, StringProperty, NumberProperty, ArrayProperty, MapProperty, Relation, VectorProperty } from \"@rebasepro/types\";\n\n/**\n * OpenAPI 3.0.3 specification generator.\n *\n * Produces a spec that exactly mirrors the REST API consumed by the\n * Rebase SDK client (`@rebasepro/client`).\n *\n * Routes are mounted at `{basePath}/data/{slug}` by `initializeRebaseBackend`.\n */\n\nexport interface OpenApiGeneratorOptions {\n /** Base path for the API (e.g. \"/api\"). Defaults to \"/api\". */\n basePath?: string;\n /** Whether auth is enabled on data routes. Defaults to true. */\n requireAuth?: boolean;\n}\n\nexport function generateOpenApiSpec(\n collections: CollectionConfig[],\n options: OpenApiGeneratorOptions = {}\n): Record<string, unknown> {\n const basePath = options.basePath ?? \"/api\";\n const requireAuth = options.requireAuth ?? true;\n\n const spec: Record<string, unknown> = {\n openapi: \"3.0.3\",\n info: {\n title: \"Rebase API\",\n version: \"1.0.0\",\n description:\n \"Auto-generated REST API from Rebase collection definitions. \" +\n \"This is the same API consumed by the `@rebasepro/client` SDK.\"\n },\n servers: [\n {\n url: basePath,\n description: \"API Server\"\n }\n ],\n paths: {} as Record<string, unknown>,\n components: {\n schemas: {\n ErrorResponse: {\n type: \"object\",\n properties: {\n error: {\n type: \"object\",\n required: [\"message\", \"code\"],\n properties: {\n message: { type: \"string\" },\n code: { type: \"string\" },\n details: {}\n }\n }\n }\n },\n PaginationMeta: {\n type: \"object\",\n properties: {\n total: { type: \"integer\",\ndescription: \"Total number of matching records\" },\n limit: { type: \"integer\",\ndescription: \"Page size used for this query\" },\n offset: { type: \"integer\",\ndescription: \"Number of records skipped\" },\n hasMore: { type: \"boolean\",\ndescription: \"Whether more records exist beyond this page\" }\n }\n }\n } as Record<string, unknown>,\n securitySchemes: {} as Record<string, unknown>\n },\n tags: [] as Array<{ name: string; description?: string }>\n };\n\n // ── Security Schemes ─────────────────────────────────────────────────\n if (requireAuth) {\n (spec.components as Record<string, unknown>).securitySchemes = {\n bearerAuth: {\n type: \"http\",\n scheme: \"bearer\",\n bearerFormat: \"JWT\",\n description:\n \"JWT access token obtained from `POST /auth/login` or `POST /auth/register`. \" +\n \"Can also be a static service key for server-to-server authentication.\"\n },\n queryToken: {\n type: \"apiKey\",\n in: \"query\",\n name: \"token\",\n description: \"Alternative: pass the JWT or service key as a `token` query parameter.\"\n }\n };\n (spec as Record<string, unknown>).security = [\n { bearerAuth: [] },\n { queryToken: [] }\n ];\n }\n\n const paths = spec.paths as Record<string, unknown>;\n const schemas = (spec.components as Record<string, unknown>).schemas as Record<string, unknown>;\n const tags = spec.tags as Array<{ name: string; description?: string }>;\n\n // ── Collection routes ────────────────────────────────────────────────\n for (const collection of (collections || [])) {\n const schemaName = toPascalCase(collection.singularName || collection.name);\n const slug = collection.slug;\n\n tags.push({\n name: collection.name,\n description: collection.description || `CRUD operations for ${collection.name}`\n });\n\n // Build component schema for this collection\n schemas[schemaName] = buildCollectionSchema(collection);\n\n // Build an \"input\" schema (no read-only/auto fields like autoValue dates)\n schemas[`${schemaName}Input`] = buildCollectionInputSchema(collection);\n\n const dataPath = `/data/${slug}`;\n\n // ── GET /data/{slug} — List entities ──────────────────────────\n paths[dataPath] = {\n get: {\n tags: [collection.name],\n summary: `List ${collection.name}`,\n operationId: `list${schemaName}`,\n parameters: [\n { name: \"limit\",\nin: \"query\",\nschema: { type: \"integer\",\ndefault: 20,\nmaximum: 100 },\ndescription: \"Maximum number of records to return\" },\n { name: \"offset\",\nin: \"query\",\nschema: { type: \"integer\",\ndefault: 0 },\ndescription: \"Number of records to skip\" },\n { name: \"page\",\nin: \"query\",\nschema: { type: \"integer\",\nminimum: 1 },\ndescription: \"Page number (alternative to offset). Calculates offset as (page-1)*limit\" },\n {\n name: \"orderBy\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"Sort field and direction. Accepts `field:asc` or `field:desc`, or a JSON array `[{\\\"field\\\":\\\"name\\\",\\\"direction\\\":\\\"asc\\\"}]`\",\n example: \"created_at:desc\"\n },\n {\n name: \"where\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"JSON object filter. Example: `{\\\"status\\\":[\\\"==\\\",\\\"active\\\"]}`\"\n },\n {\n name: \"include\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"Comma-separated list of relations to include (eager-load). Use `*` for all relations.\",\n example: \"author,tags\"\n },\n {\n name: \"fields\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"Comma-separated list of fields to return (field selection)\",\n example: \"id,name,created_at\"\n },\n {\n name: \"searchString\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"Full-text search query\"\n },\n ...buildFilterParameters(collection)\n ],\n responses: {\n 200: {\n description: \"Paginated list of entities\",\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n properties: {\n data: {\n type: \"array\",\n items: { $ref: `#/components/schemas/${schemaName}` }\n },\n meta: { $ref: \"#/components/schemas/PaginationMeta\" }\n }\n }\n }\n }\n },\n ...errorResponses(requireAuth)\n }\n },\n post: {\n tags: [collection.name],\n summary: `Create ${collection.singularName || collection.name}`,\n operationId: `create${schemaName}`,\n requestBody: {\n required: true,\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schemaName}Input` }\n }\n }\n },\n responses: {\n 201: {\n description: \"Created entity\",\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schemaName}` }\n }\n }\n },\n ...errorResponses(requireAuth)\n }\n }\n };\n\n // ── GET/PUT/DELETE /data/{slug}/{id} ──────────────────────────\n const entityPath = `/data/${slug}/{id}`;\n paths[entityPath] = {\n get: {\n tags: [collection.name],\n summary: `Get ${collection.singularName || collection.name} by ID`,\n operationId: `get${schemaName}ById`,\n parameters: [\n { name: \"id\",\nin: \"path\",\nrequired: true,\nschema: { type: \"string\" },\ndescription: \"Entity ID\" },\n {\n name: \"include\",\n in: \"query\",\n schema: { type: \"string\" },\n description: \"Comma-separated list of relations to include\",\n example: \"author,tags\"\n }\n ],\n responses: {\n 200: {\n description: \"Entity found\",\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schemaName}` }\n }\n }\n },\n 404: { description: \"Entity not found\",\ncontent: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } } },\n ...errorResponses(requireAuth)\n }\n },\n put: {\n tags: [collection.name],\n summary: `Update ${collection.singularName || collection.name}`,\n operationId: `update${schemaName}`,\n parameters: [\n { name: \"id\",\nin: \"path\",\nrequired: true,\nschema: { type: \"string\" },\ndescription: \"Entity ID\" }\n ],\n requestBody: {\n required: true,\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schemaName}Input` }\n }\n }\n },\n responses: {\n 200: {\n description: \"Updated entity\",\n content: {\n \"application/json\": {\n schema: { $ref: `#/components/schemas/${schemaName}` }\n }\n }\n },\n 404: { description: \"Entity not found\",\ncontent: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } } },\n ...errorResponses(requireAuth)\n }\n },\n delete: {\n tags: [collection.name],\n summary: `Delete ${collection.singularName || collection.name}`,\n operationId: `delete${schemaName}`,\n parameters: [\n { name: \"id\",\nin: \"path\",\nrequired: true,\nschema: { type: \"string\" },\ndescription: \"Entity ID\" }\n ],\n responses: {\n 204: { description: \"Deleted successfully\" },\n 404: { description: \"Entity not found\",\ncontent: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } } },\n ...errorResponses(requireAuth)\n }\n }\n };\n\n // ── Subcollection routes ──────────────────────────────────────\n const relations = collection.relations;\n if (relations && relations.length > 0) {\n for (const relation of relations) {\n const relationName = relation.relationName;\n if (!relationName) continue;\n\n let targetName: string;\n try {\n const targetCollection = relation.target();\n targetName = targetCollection.singularName || targetCollection.name;\n } catch {\n targetName = relationName;\n }\n const targetSchema = toPascalCase(targetName);\n\n const subPath = `/data/${slug}/{parentId}/${relationName}`;\n\n // Only add if the schema exists (target collection is also registered)\n paths[subPath] = {\n get: {\n tags: [collection.name],\n summary: `List ${relationName} for a ${collection.singularName || collection.name}`,\n operationId: `list${schemaName}${toPascalCase(relationName)}`,\n parameters: [\n { name: \"parentId\",\nin: \"path\",\nrequired: true,\nschema: { type: \"string\" },\ndescription: `${collection.singularName || collection.name} ID` },\n { name: \"limit\",\nin: \"query\",\nschema: { type: \"integer\",\ndefault: 20 } },\n { name: \"offset\",\nin: \"query\",\nschema: { type: \"integer\",\ndefault: 0 } },\n { name: \"orderBy\",\nin: \"query\",\nschema: { type: \"string\" } },\n { name: \"searchString\",\nin: \"query\",\nschema: { type: \"string\" } }\n ],\n responses: {\n 200: {\n description: `List of related ${relationName}`,\n content: {\n \"application/json\": {\n schema: {\n type: \"object\",\n properties: {\n data: {\n type: \"array\",\n items: schemas[targetSchema]\n ? { $ref: `#/components/schemas/${targetSchema}` }\n : { type: \"object\" }\n },\n meta: { $ref: \"#/components/schemas/PaginationMeta\" }\n }\n }\n }\n }\n },\n ...errorResponses(requireAuth)\n }\n }\n };\n }\n }\n }\n\n return spec;\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\n/**\n * Build the component schema for a collection (output / read shape).\n * All fields are included (including relation foreign keys).\n */\nfunction buildCollectionSchema(collection: CollectionConfig): Record<string, unknown> {\n const properties: Record<string, unknown> = {\n id: { type: \"string\",\ndescription: \"Unique identifier\" }\n };\n const required: string[] = [\"id\"];\n\n for (const [key, property] of Object.entries(collection.properties)) {\n // Skip relation properties — they are virtual and not part of the REST payload\n if (property.type === \"relation\") continue;\n\n properties[key] = convertPropertyToSchema(property);\n\n if (property.validation?.required) {\n required.push(key);\n }\n }\n\n return {\n type: \"object\",\n required: required.length > 0 ? required : undefined,\n properties\n };\n}\n\n/**\n * Build an input schema (for POST/PUT) — excludes auto-generated fields.\n */\nfunction buildCollectionInputSchema(collection: CollectionConfig): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [key, property] of Object.entries(collection.properties)) {\n if (property.type === \"relation\") continue;\n\n // Skip auto-value date fields from the input schema\n if (property.type === \"date\" && property.autoValue) continue;\n\n // Skip auto-generated ID fields\n if (\"isId\" in property && property.isId && property.isId !== \"manual\" && property.isId !== true) continue;\n\n properties[key] = convertPropertyToSchema(property);\n\n if (property.validation?.required) {\n required.push(key);\n }\n }\n\n // Allow explicit ID for create (optional)\n properties[\"id\"] = {\n type: \"string\",\n description: \"Optional: client-assigned ID. If omitted, the server generates one.\"\n };\n\n return {\n type: \"object\",\n required: required.length > 0 ? required : undefined,\n properties\n };\n}\n\n/**\n * Convert a Rebase Property to an OpenAPI 3.0 schema object.\n */\nfunction convertPropertyToSchema(property: Property): Record<string, unknown> {\n const base: Record<string, unknown> = {};\n\n if (property.name) {\n base.description = property.name;\n }\n\n switch (property.type) {\n case \"string\": {\n const sp = property as StringProperty;\n base.type = \"string\";\n\n if (sp.enum) {\n const enumValues = resolveEnumValues(sp.enum);\n if (enumValues.length > 0) {\n base.enum = enumValues;\n }\n }\n\n if (sp.validation) {\n if (sp.validation.min !== undefined) base.minLength = sp.validation.min;\n if (sp.validation.max !== undefined) base.maxLength = sp.validation.max;\n if (sp.validation.length !== undefined) {\n base.minLength = sp.validation.length;\n base.maxLength = sp.validation.length;\n }\n if (sp.validation.matches !== undefined) {\n base.pattern = String(sp.validation.matches);\n }\n }\n\n if (sp.email) base.format = \"email\";\n if (sp.ui?.url) base.format = \"uri\";\n if (sp.storage) base.format = \"uri\";\n if (sp.ui?.markdown) base.description = (base.description || \"\") + \" (Markdown)\";\n\n return base;\n }\n\n case \"number\": {\n const np = property as NumberProperty;\n const isInteger = np.validation?.integer || np.columnType === \"integer\" || np.columnType === \"serial\" || np.columnType === \"bigserial\" || np.columnType === \"bigint\";\n base.type = isInteger ? \"integer\" : \"number\";\n\n if (np.enum) {\n const enumValues = resolveEnumValues(np.enum);\n if (enumValues.length > 0) {\n base.enum = enumValues;\n }\n }\n\n if (np.validation) {\n if (np.validation.min !== undefined) base.minimum = np.validation.min;\n if (np.validation.max !== undefined) base.maximum = np.validation.max;\n if (np.validation.moreThan !== undefined) {\n base.minimum = np.validation.moreThan;\n base.exclusiveMinimum = true;\n }\n if (np.validation.lessThan !== undefined) {\n base.maximum = np.validation.lessThan;\n base.exclusiveMaximum = true;\n }\n }\n\n return base;\n }\n\n case \"boolean\":\n base.type = \"boolean\";\n return base;\n\n case \"date\": {\n base.type = \"string\";\n if (property.mode === \"date\") {\n base.format = \"date\";\n } else {\n base.format = \"date-time\";\n }\n if (property.autoValue) {\n base.readOnly = true;\n base.description = (base.description || \"\") +\n (property.autoValue === \"on_create\" ? \" (Auto-set on creation)\" : \" (Auto-updated)\");\n }\n return base;\n }\n\n case \"geopoint\":\n base.type = \"object\";\n base.properties = {\n latitude: { type: \"number\" },\n longitude: { type: \"number\" }\n };\n base.required = [\"latitude\", \"longitude\"];\n return base;\n\n case \"reference\":\n base.type = \"string\";\n base.description = (base.description || \"\") + \" (Reference ID)\";\n return base;\n\n case \"array\": {\n const ap = property as ArrayProperty;\n base.type = \"array\";\n\n if (ap.oneOf) {\n // Discriminated union (e.g., content blocks)\n const typeField = ap.oneOf.typeField || \"type\";\n const valueField = ap.oneOf.valueField || \"value\";\n const variants: Record<string, unknown>[] = [];\n\n for (const [variantKey, variantProp] of Object.entries(ap.oneOf.properties)) {\n variants.push({\n type: \"object\",\n properties: {\n [typeField]: { type: \"string\",\nenum: [variantKey] },\n [valueField]: convertPropertyToSchema(variantProp)\n },\n required: [typeField, valueField]\n });\n }\n\n base.items = { oneOf: variants };\n } else if (ap.of) {\n if (Array.isArray(ap.of)) {\n base.items = { oneOf: ap.of.map(p => convertPropertyToSchema(p)) };\n } else {\n base.items = convertPropertyToSchema(ap.of);\n }\n } else {\n base.items = {};\n }\n\n if (ap.validation) {\n if (ap.validation.min !== undefined) base.minItems = ap.validation.min;\n if (ap.validation.max !== undefined) base.maxItems = ap.validation.max;\n }\n\n return base;\n }\n\n case \"map\": {\n const mp = property as MapProperty;\n base.type = \"object\";\n\n if (mp.properties) {\n const props: Record<string, unknown> = {};\n const req: string[] = [];\n\n for (const [key, subProp] of Object.entries(mp.properties)) {\n props[key] = convertPropertyToSchema(subProp);\n if (subProp.validation?.required) {\n req.push(key);\n }\n }\n\n base.properties = props;\n if (req.length > 0) base.required = req;\n } else if (mp.keyValue) {\n base.additionalProperties = true;\n }\n\n return base;\n }\n\n case \"vector\": {\n const vp = property as VectorProperty;\n base.type = \"array\";\n base.items = { type: \"number\" };\n base.description = (base.description || \"\") + ` (Vector(${vp.dimensions}))`;\n return base;\n }\n case \"binary\": {\n base.type = \"string\";\n base.description = (base.description || \"\") + \" (Binary/Base64)\";\n return base;\n }\n default:\n base.type = \"string\";\n return base;\n }\n}\n\n/**\n * Resolve EnumValues (array or record) into a flat array of enum values.\n */\nfunction resolveEnumValues(enumDef: Record<string | number, unknown> | Array<{ id: string | number }>): Array<string | number> {\n if (Array.isArray(enumDef)) {\n return enumDef.map(e => (typeof e === \"object\" && e !== null && \"id\" in e) ? e.id : e as string | number);\n }\n return Object.keys(enumDef).map(k => {\n // Preserve numeric keys as numbers\n const num = Number(k);\n return isNaN(num) ? k : num;\n });\n}\n\n/**\n * Build PostgREST-style filter parameters for a collection.\n * These are additional query parameters like `?status=eq.active&price=gte.100`.\n */\nfunction buildFilterParameters(collection: CollectionConfig): Array<Record<string, unknown>> {\n const params: Array<Record<string, unknown>> = [];\n\n for (const [key, property] of Object.entries(collection.properties)) {\n if (property.type === \"relation\" || property.type === \"map\" || property.type === \"array\" || property.type === \"geopoint\") {\n continue;\n }\n\n params.push({\n name: key,\n in: \"query\",\n required: false,\n schema: { type: \"string\" },\n description:\n `Filter by \\`${key}\\`. Supports PostgREST operators: ` +\n \"`eq.value`, `neq.value`, `gt.value`, `gte.value`, `lt.value`, `lte.value`, \" +\n \"`in.(a,b,c)`, `nin.(a,b,c)`, `cs.value` (array-contains), `csa.(a,b)` (array-contains-any). \" +\n \"Plain values imply equality.\",\n example: property.type === \"string\" ? \"eq.active\" : property.type === \"number\" ? \"gte.100\" : undefined\n });\n }\n\n return params;\n}\n\n/**\n * Standard error responses included on every endpoint.\n */\nfunction errorResponses(requireAuth: boolean): Record<string, unknown> {\n const responses: Record<string, unknown> = {\n 400: {\n description: \"Bad request\",\n content: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } }\n },\n 500: {\n description: \"Internal server error\",\n content: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } }\n }\n };\n\n if (requireAuth) {\n responses[401] = {\n description: \"Authentication required or invalid token\",\n content: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } }\n };\n responses[403] = {\n description: \"Insufficient permissions\",\n content: { \"application/json\": { schema: { $ref: \"#/components/schemas/ErrorResponse\" } } }\n };\n }\n\n return responses;\n}\n\n/**\n * Convert a string to PascalCase for schema names.\n */\nfunction toPascalCase(str: string): string {\n return str\n .replace(/[^a-zA-Z0-9]+/g, \" \")\n .split(\" \")\n .filter(Boolean)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\"\");\n}\n"],"mappings":"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"}