@riktajs/swagger 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +258 -0
  2. package/dist/constants.d.ts +56 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +61 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/decorators/api-body.decorator.d.ts +33 -0
  7. package/dist/decorators/api-body.decorator.d.ts.map +1 -0
  8. package/dist/decorators/api-body.decorator.js +40 -0
  9. package/dist/decorators/api-body.decorator.js.map +1 -0
  10. package/dist/decorators/api-exclude.decorator.d.ts +71 -0
  11. package/dist/decorators/api-exclude.decorator.d.ts.map +1 -0
  12. package/dist/decorators/api-exclude.decorator.js +95 -0
  13. package/dist/decorators/api-exclude.decorator.js.map +1 -0
  14. package/dist/decorators/api-header.decorator.d.ts +25 -0
  15. package/dist/decorators/api-header.decorator.d.ts.map +1 -0
  16. package/dist/decorators/api-header.decorator.js +33 -0
  17. package/dist/decorators/api-header.decorator.js.map +1 -0
  18. package/dist/decorators/api-operation.decorator.d.ts +32 -0
  19. package/dist/decorators/api-operation.decorator.d.ts.map +1 -0
  20. package/dist/decorators/api-operation.decorator.js +39 -0
  21. package/dist/decorators/api-operation.decorator.js.map +1 -0
  22. package/dist/decorators/api-param.decorator.d.ts +28 -0
  23. package/dist/decorators/api-param.decorator.d.ts.map +1 -0
  24. package/dist/decorators/api-param.decorator.js +36 -0
  25. package/dist/decorators/api-param.decorator.js.map +1 -0
  26. package/dist/decorators/api-property.decorator.d.ts +69 -0
  27. package/dist/decorators/api-property.decorator.d.ts.map +1 -0
  28. package/dist/decorators/api-property.decorator.js +76 -0
  29. package/dist/decorators/api-property.decorator.js.map +1 -0
  30. package/dist/decorators/api-query.decorator.d.ts +30 -0
  31. package/dist/decorators/api-query.decorator.d.ts.map +1 -0
  32. package/dist/decorators/api-query.decorator.js +38 -0
  33. package/dist/decorators/api-query.decorator.js.map +1 -0
  34. package/dist/decorators/api-response.decorator.d.ts +70 -0
  35. package/dist/decorators/api-response.decorator.d.ts.map +1 -0
  36. package/dist/decorators/api-response.decorator.js +100 -0
  37. package/dist/decorators/api-response.decorator.js.map +1 -0
  38. package/dist/decorators/api-security.decorator.d.ts +88 -0
  39. package/dist/decorators/api-security.decorator.d.ts.map +1 -0
  40. package/dist/decorators/api-security.decorator.js +119 -0
  41. package/dist/decorators/api-security.decorator.js.map +1 -0
  42. package/dist/decorators/api-tags.decorator.d.ts +31 -0
  43. package/dist/decorators/api-tags.decorator.d.ts.map +1 -0
  44. package/dist/decorators/api-tags.decorator.js +52 -0
  45. package/dist/decorators/api-tags.decorator.js.map +1 -0
  46. package/dist/decorators/index.d.ts +16 -0
  47. package/dist/decorators/index.d.ts.map +1 -0
  48. package/dist/decorators/index.js +24 -0
  49. package/dist/decorators/index.js.map +1 -0
  50. package/dist/index.d.ts +62 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +68 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/openapi/generator.d.ts +98 -0
  55. package/dist/openapi/generator.d.ts.map +1 -0
  56. package/dist/openapi/generator.js +493 -0
  57. package/dist/openapi/generator.js.map +1 -0
  58. package/dist/openapi/index.d.ts +8 -0
  59. package/dist/openapi/index.d.ts.map +1 -0
  60. package/dist/openapi/index.js +11 -0
  61. package/dist/openapi/index.js.map +1 -0
  62. package/dist/openapi/zod-to-openapi.d.ts +52 -0
  63. package/dist/openapi/zod-to-openapi.d.ts.map +1 -0
  64. package/dist/openapi/zod-to-openapi.js +172 -0
  65. package/dist/openapi/zod-to-openapi.js.map +1 -0
  66. package/dist/plugin/index.d.ts +7 -0
  67. package/dist/plugin/index.d.ts.map +1 -0
  68. package/dist/plugin/index.js +7 -0
  69. package/dist/plugin/index.js.map +1 -0
  70. package/dist/plugin/swagger.plugin.d.ts +157 -0
  71. package/dist/plugin/swagger.plugin.d.ts.map +1 -0
  72. package/dist/plugin/swagger.plugin.js +235 -0
  73. package/dist/plugin/swagger.plugin.js.map +1 -0
  74. package/dist/types.d.ts +511 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +2 -0
  77. package/dist/types.js.map +1 -0
  78. package/package.json +61 -0
@@ -0,0 +1,172 @@
1
+ import { zodToJsonSchema } from 'zod-to-json-schema';
2
+ /**
3
+ * Type guard to check if a value is a Zod schema
4
+ * Uses duck typing to detect Zod schemas without requiring the full library
5
+ */
6
+ export function isZodSchema(value) {
7
+ return (value !== null &&
8
+ typeof value === 'object' &&
9
+ '_def' in value &&
10
+ 'safeParse' in value &&
11
+ typeof value.safeParse === 'function');
12
+ }
13
+ /**
14
+ * Convert JSON Schema 7 to OpenAPI 3.0 compatible schema
15
+ *
16
+ * Main differences:
17
+ * - OpenAPI uses `nullable: true` instead of `type: ['string', 'null']`
18
+ * - OpenAPI 3.0 doesn't support `$schema`, `$id`, etc.
19
+ * - Some JSON Schema features need to be simplified
20
+ */
21
+ function jsonSchemaToOpenApi(jsonSchema) {
22
+ if (typeof jsonSchema === 'boolean') {
23
+ return jsonSchema ? {} : { not: {} };
24
+ }
25
+ const result = {};
26
+ const schema = jsonSchema;
27
+ // Handle type with null (convert to nullable)
28
+ if (Array.isArray(schema.type)) {
29
+ const types = schema.type;
30
+ const nullIndex = types.indexOf('null');
31
+ if (nullIndex !== -1) {
32
+ result.nullable = true;
33
+ const nonNullTypes = types.filter(t => t !== 'null');
34
+ if (nonNullTypes.length === 1) {
35
+ result.type = nonNullTypes[0];
36
+ }
37
+ else if (nonNullTypes.length > 1) {
38
+ // Multiple non-null types - use oneOf
39
+ result.oneOf = nonNullTypes.map(t => ({ type: t }));
40
+ }
41
+ }
42
+ else if (types.length === 1) {
43
+ result.type = types[0];
44
+ }
45
+ }
46
+ else if (schema.type) {
47
+ result.type = schema.type;
48
+ }
49
+ // Copy simple properties
50
+ const simpleProps = [
51
+ 'format', 'description', 'default', 'example', 'enum',
52
+ 'minimum', 'maximum', 'exclusiveMinimum', 'exclusiveMaximum',
53
+ 'minLength', 'maxLength', 'pattern',
54
+ 'minItems', 'maxItems', 'uniqueItems',
55
+ 'minProperties', 'maxProperties',
56
+ 'required', 'readOnly', 'writeOnly', 'deprecated',
57
+ ];
58
+ for (const prop of simpleProps) {
59
+ if (schema[prop] !== undefined) {
60
+ result[prop] = schema[prop];
61
+ }
62
+ }
63
+ // Handle items (for arrays)
64
+ if (schema.items) {
65
+ if (Array.isArray(schema.items)) {
66
+ // Tuple - OpenAPI 3.0 doesn't support tuple validation well
67
+ result.items = { oneOf: schema.items.map(jsonSchemaToOpenApi) };
68
+ }
69
+ else {
70
+ result.items = jsonSchemaToOpenApi(schema.items);
71
+ }
72
+ }
73
+ // Handle properties (for objects)
74
+ if (schema.properties) {
75
+ result.properties = {};
76
+ for (const [key, value] of Object.entries(schema.properties)) {
77
+ result.properties[key] = jsonSchemaToOpenApi(value);
78
+ }
79
+ }
80
+ // Handle additionalProperties
81
+ if (schema.additionalProperties !== undefined) {
82
+ if (typeof schema.additionalProperties === 'boolean') {
83
+ result.additionalProperties = schema.additionalProperties;
84
+ }
85
+ else {
86
+ result.additionalProperties = jsonSchemaToOpenApi(schema.additionalProperties);
87
+ }
88
+ }
89
+ // Handle allOf, oneOf, anyOf
90
+ if (schema.allOf) {
91
+ result.allOf = schema.allOf.map(jsonSchemaToOpenApi);
92
+ }
93
+ if (schema.oneOf) {
94
+ result.oneOf = schema.oneOf.map(jsonSchemaToOpenApi);
95
+ }
96
+ if (schema.anyOf) {
97
+ result.anyOf = schema.anyOf.map(jsonSchemaToOpenApi);
98
+ }
99
+ // Handle not
100
+ if (schema.not) {
101
+ result.not = jsonSchemaToOpenApi(schema.not);
102
+ }
103
+ // Handle const (convert to enum with single value)
104
+ if (schema.const !== undefined) {
105
+ result.enum = [schema.const];
106
+ }
107
+ return result;
108
+ }
109
+ /**
110
+ * Convert a Zod schema to an OpenAPI 3.0 schema object
111
+ *
112
+ * Uses `zod-to-json-schema` for the heavy lifting, then converts
113
+ * JSON Schema 7 to OpenAPI 3.0 compatible format.
114
+ *
115
+ * Supports all Zod types including:
116
+ * - Primitives: string, number, boolean, bigint
117
+ * - Complex: object, array, tuple, record
118
+ * - Modifiers: optional, nullable, default
119
+ * - Validators: min, max, email, uuid, url, etc.
120
+ * - Enums: enum, nativeEnum
121
+ * - Unions and intersections
122
+ * - Literals
123
+ * - Effects (transform, refine)
124
+ *
125
+ * @param schema - The Zod schema to convert
126
+ * @returns OpenAPI schema object
127
+ *
128
+ * @example
129
+ * ```typescript
130
+ * const UserSchema = z.object({
131
+ * id: z.string().uuid(),
132
+ * email: z.string().email(),
133
+ * age: z.number().int().min(0).optional(),
134
+ * });
135
+ *
136
+ * const openApiSchema = zodToOpenApi(UserSchema);
137
+ * // {
138
+ * // type: 'object',
139
+ * // properties: {
140
+ * // id: { type: 'string', format: 'uuid' },
141
+ * // email: { type: 'string', format: 'email' },
142
+ * // age: { type: 'integer', minimum: 0 }
143
+ * // },
144
+ * // required: ['id', 'email']
145
+ * // }
146
+ * ```
147
+ */
148
+ export function zodToOpenApi(schema) {
149
+ // Convert to JSON Schema using zod-to-json-schema
150
+ const jsonSchema = zodToJsonSchema(schema, {
151
+ target: 'openApi3',
152
+ $refStrategy: 'none', // Inline all references
153
+ });
154
+ // Convert JSON Schema to OpenAPI format
155
+ // The result from zodToJsonSchema may include $schema and definitions
156
+ // which are not part of JsonSchema7Type but are compatible
157
+ return jsonSchemaToOpenApi(jsonSchema);
158
+ }
159
+ /**
160
+ * Convert a Zod schema to OpenAPI schema, or pass through if already an OpenAPI schema
161
+ */
162
+ export function toOpenApiSchema(schemaOrOpenApi) {
163
+ if (!schemaOrOpenApi) {
164
+ return undefined;
165
+ }
166
+ if (isZodSchema(schemaOrOpenApi)) {
167
+ return zodToOpenApi(schemaOrOpenApi);
168
+ }
169
+ // Already an OpenAPI schema object
170
+ return schemaOrOpenApi;
171
+ }
172
+ //# sourceMappingURL=zod-to-openapi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zod-to-openapi.js","sourceRoot":"","sources":["../../src/openapi/zod-to-openapi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAwB,MAAM,oBAAoB,CAAC;AAG3E;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,CACL,KAAK,KAAK,IAAI;QACd,OAAO,KAAK,KAAK,QAAQ;QACzB,MAAM,IAAI,KAAK;QACf,WAAW,IAAI,KAAK;QACpB,OAAQ,KAAgC,CAAC,SAAS,KAAK,UAAU,CAClE,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,mBAAmB,CAAC,UAA2B;IACtD,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACvC,CAAC;IAED,MAAM,MAAM,GAAwB,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,UAAqC,CAAC;IAErD,8CAA8C;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAgB,CAAC;QACtC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACxC,IAAI,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC;YACvB,MAAM,YAAY,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC;YACrD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9B,MAAM,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC,CAAgC,CAAC;YAC/D,CAAC;iBAAM,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACnC,sCAAsC;gBACtC,MAAM,CAAC,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAgC,EAAE,CAAC,CAAC,CAAC;YACrF,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAgC,CAAC;QACxD,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QACvB,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAmC,CAAC;IAC3D,CAAC;IAED,yBAAyB;IACzB,MAAM,WAAW,GAAG;QAClB,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM;QACrD,SAAS,EAAE,SAAS,EAAE,kBAAkB,EAAE,kBAAkB;QAC5D,WAAW,EAAE,WAAW,EAAE,SAAS;QACnC,UAAU,EAAE,UAAU,EAAE,aAAa;QACrC,eAAe,EAAE,eAAe;QAChC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY;KACzC,CAAC;IAEX,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9B,MAAkC,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,4BAA4B;IAC5B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YAChC,4DAA4D;YAC5D,MAAM,CAAC,KAAK,GAAG,EAAE,KAAK,EAAG,MAAM,CAAC,KAA2B,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACzF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,GAAG,mBAAmB,CAAC,MAAM,CAAC,KAAwB,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,UAA6C,CAAC,EAAE,CAAC;YAChG,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,MAAM,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;QAC9C,IAAI,OAAO,MAAM,CAAC,oBAAoB,KAAK,SAAS,EAAE,CAAC;YACrD,MAAM,CAAC,oBAAoB,GAAG,MAAM,CAAC,oBAAoB,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,oBAAoB,GAAG,mBAAmB,CAAC,MAAM,CAAC,oBAAuC,CAAC,CAAC;QACpG,CAAC;IACH,CAAC;IAED,6BAA6B;IAC7B,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,GAAI,MAAM,CAAC,KAA2B,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,GAAI,MAAM,CAAC,KAA2B,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC9E,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,GAAI,MAAM,CAAC,KAA2B,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IAC9E,CAAC;IAED,aAAa;IACb,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,GAAG,mBAAmB,CAAC,MAAM,CAAC,GAAsB,CAAC,CAAC;IAClE,CAAC;IAED,mDAAmD;IACnD,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,UAAU,YAAY,CAAC,MAAe;IAC1C,kDAAkD;IAClD,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,EAAE;QACzC,MAAM,EAAE,UAAU;QAClB,YAAY,EAAE,MAAM,EAAE,wBAAwB;KAC/C,CAAC,CAAC;IAEH,wCAAwC;IACxC,sEAAsE;IACtE,2DAA2D;IAC3D,OAAO,mBAAmB,CAAC,UAA6B,CAAC,CAAC;AAC5D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAC7B,eAA0D;IAE1D,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,WAAW,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,OAAO,YAAY,CAAC,eAAe,CAAC,CAAC;IACvC,CAAC;IAED,mCAAmC;IACnC,OAAO,eAAsC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Swagger Plugin barrel export
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { swaggerPlugin, registerSwagger, createSwaggerConfig, type SwaggerPluginOptions, } from './swagger.plugin.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Swagger Plugin barrel export
3
+ *
4
+ * @packageDocumentation
5
+ */
6
+ export { swaggerPlugin, registerSwagger, createSwaggerConfig, } from './swagger.plugin.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugin/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,aAAa,EACb,eAAe,EACf,mBAAmB,GAEpB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,157 @@
1
+ import type { FastifyInstance, FastifyPluginAsync } from 'fastify';
2
+ import { type FastifySwaggerUiOptions } from '@fastify/swagger-ui';
3
+ import type { SwaggerConfig, OpenApiDocument, OpenApiInfoObject } from '../types.js';
4
+ type Constructor<T = unknown> = new (...args: any[]) => T;
5
+ /**
6
+ * Swagger plugin options
7
+ */
8
+ export interface SwaggerPluginOptions {
9
+ /**
10
+ * Swagger/OpenAPI configuration
11
+ */
12
+ config?: SwaggerConfig;
13
+ /**
14
+ * API Info (title, version, description, etc.)
15
+ * Can also be provided via config.info
16
+ */
17
+ info?: OpenApiInfoObject;
18
+ /**
19
+ * Controllers to document (optional - will auto-discover from registry if not provided)
20
+ */
21
+ controllers?: Constructor[];
22
+ /**
23
+ * Path to serve the OpenAPI JSON specification
24
+ * @default '/docs/json'
25
+ */
26
+ jsonPath?: string;
27
+ /**
28
+ * Path to serve the Swagger UI
29
+ * @default '/docs'
30
+ */
31
+ uiPath?: string;
32
+ /**
33
+ * Whether to expose the Swagger UI
34
+ * @default true
35
+ */
36
+ exposeUI?: boolean;
37
+ /**
38
+ * Whether to expose the OpenAPI JSON specification
39
+ * @default true
40
+ */
41
+ exposeSpec?: boolean;
42
+ /**
43
+ * Logo configuration for Swagger UI
44
+ */
45
+ logo?: {
46
+ url: string;
47
+ altText?: string;
48
+ backgroundColor?: string;
49
+ };
50
+ /**
51
+ * Swagger UI theme
52
+ * @default 'default'
53
+ */
54
+ theme?: 'default' | 'dark';
55
+ /**
56
+ * Transform the OpenAPI specification before serving
57
+ */
58
+ transform?: (spec: OpenApiDocument) => OpenApiDocument | Promise<OpenApiDocument>;
59
+ }
60
+ declare module 'fastify' {
61
+ interface FastifyInstance {
62
+ openApiSpec?: OpenApiDocument;
63
+ }
64
+ }
65
+ /**
66
+ * Swagger plugin for Fastify/Rikta
67
+ *
68
+ * Automatically generates OpenAPI documentation from Rikta controllers
69
+ * and serves Swagger UI for interactive API exploration.
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * import { RiktaFactory } from '@riktajs/core';
74
+ * import { swaggerPlugin } from '@riktajs/swagger';
75
+ *
76
+ * const app = await RiktaFactory.create();
77
+ *
78
+ * await app.register(swaggerPlugin, {
79
+ * info: {
80
+ * title: 'My API',
81
+ * version: '1.0.0',
82
+ * description: 'API documentation for My App',
83
+ * },
84
+ * config: {
85
+ * servers: [
86
+ * { url: 'http://localhost:3000', description: 'Development' },
87
+ * ],
88
+ * },
89
+ * });
90
+ *
91
+ * // Swagger UI available at /docs
92
+ * // OpenAPI JSON at /docs/json
93
+ * ```
94
+ */
95
+ export declare const swaggerPlugin: FastifyPluginAsync<SwaggerPluginOptions>;
96
+ /**
97
+ * Register swagger plugin with a Rikta application
98
+ *
99
+ * Helper function that provides a simpler API for registering the plugin.
100
+ *
101
+ * @param app - Fastify instance
102
+ * @param options - Swagger plugin options
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * import { RiktaFactory } from '@riktajs/core';
107
+ * import { registerSwagger } from '@riktajs/swagger';
108
+ *
109
+ * const app = await RiktaFactory.create();
110
+ *
111
+ * await registerSwagger(app, {
112
+ * info: {
113
+ * title: 'My API',
114
+ * version: '1.0.0',
115
+ * },
116
+ * });
117
+ * ```
118
+ */
119
+ export declare function registerSwagger(app: FastifyInstance, options?: SwaggerPluginOptions): Promise<void>;
120
+ /**
121
+ * Create a standalone Swagger configuration for manual use
122
+ *
123
+ * Use this when you need more control over the Swagger setup,
124
+ * or when integrating with an existing Fastify application.
125
+ *
126
+ * @param options - Swagger plugin options
127
+ * @returns Object containing swagger and swaggerUI options and specification
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * import fastify from 'fastify';
132
+ * import fastifySwagger from '@fastify/swagger';
133
+ * import fastifySwaggerUI from '@fastify/swagger-ui';
134
+ * import { createSwaggerConfig } from '@riktajs/swagger';
135
+ *
136
+ * const app = fastify();
137
+ * const { swaggerOptions, swaggerUIOptions, specification } = createSwaggerConfig({
138
+ * info: { title: 'My API', version: '1.0.0' },
139
+ * controllers: [UserController, ProductController],
140
+ * });
141
+ *
142
+ * await app.register(fastifySwagger, swaggerOptions);
143
+ * await app.register(fastifySwaggerUI, swaggerUIOptions);
144
+ * ```
145
+ */
146
+ export declare function createSwaggerConfig(options?: SwaggerPluginOptions): {
147
+ swaggerOptions: {
148
+ mode: 'static';
149
+ specification: {
150
+ document: OpenApiDocument;
151
+ };
152
+ };
153
+ swaggerUIOptions: FastifySwaggerUiOptions;
154
+ specification: OpenApiDocument;
155
+ };
156
+ export {};
157
+ //# sourceMappingURL=swagger.plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swagger.plugin.d.ts","sourceRoot":"","sources":["../../src/plugin/swagger.plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAGnE,OAAyB,EAAE,KAAK,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAGrF,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrF,KAAK,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IAEvB;;;OAGG;IACH,IAAI,CAAC,EAAE,iBAAiB,CAAC;IAEzB;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC;IAE5B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;;OAGG;IACH,KAAK,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAE3B;;OAEG;IACH,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACnF;AA4HD,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,eAAe;QACvB,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,aAAa,EAAE,kBAAkB,CAAC,oBAAoB,CAOlE,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,eAAe,EACpB,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,oBAAyB,GAAG;IACvE,cAAc,EAAE;QACd,IAAI,EAAE,QAAQ,CAAC;QACf,aAAa,EAAE;YAAE,QAAQ,EAAE,eAAe,CAAA;SAAE,CAAC;KAC9C,CAAC;IACF,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,aAAa,EAAE,eAAe,CAAC;CAChC,CA+CA"}
@@ -0,0 +1,235 @@
1
+ import fp from 'fastify-plugin';
2
+ import fastifySwagger from '@fastify/swagger';
3
+ import fastifySwaggerUI from '@fastify/swagger-ui';
4
+ import { OpenApiGenerator } from '../openapi/generator.js';
5
+ import { registry } from '@riktajs/core';
6
+ /**
7
+ * Default plugin options
8
+ */
9
+ const DEFAULT_OPTIONS = {
10
+ jsonPath: '/docs/json',
11
+ uiPath: '/docs',
12
+ exposeUI: true,
13
+ exposeSpec: true,
14
+ };
15
+ /**
16
+ * Swagger plugin implementation
17
+ *
18
+ * Registers @fastify/swagger and @fastify/swagger-ui with automatic
19
+ * OpenAPI specification generation from Rikta controllers.
20
+ */
21
+ async function swaggerPluginImpl(fastify, options) {
22
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
23
+ const { jsonPath, uiPath, exposeUI, exposeSpec, controllers, config, info, transform } = mergedOptions;
24
+ // Build info object from options or config
25
+ const apiInfo = info || config?.info || {
26
+ title: 'API Documentation',
27
+ version: '1.0.0',
28
+ };
29
+ // Create OpenAPI generator
30
+ const generator = new OpenApiGenerator({
31
+ ...config,
32
+ info: apiInfo,
33
+ });
34
+ // Get controllers to document
35
+ const controllersToDocument = controllers || registry.getControllers();
36
+ // Add controllers to generator
37
+ for (const controller of controllersToDocument) {
38
+ generator.addController(controller);
39
+ }
40
+ // Add security schemes from config
41
+ if (config?.securitySchemes) {
42
+ for (const [name, scheme] of Object.entries(config.securitySchemes)) {
43
+ generator.addSecurityScheme(name, scheme);
44
+ }
45
+ }
46
+ // Generate OpenAPI specification
47
+ let spec = generator.generate();
48
+ // Apply transform if provided
49
+ if (transform) {
50
+ spec = await transform(spec);
51
+ }
52
+ // Register @fastify/swagger with static specification
53
+ await fastify.register(fastifySwagger, {
54
+ mode: 'static',
55
+ specification: {
56
+ document: spec, // Type assertion needed due to fastify-swagger types
57
+ },
58
+ });
59
+ // Register @fastify/swagger-ui if enabled
60
+ if (exposeUI) {
61
+ const uiOptions = {
62
+ routePrefix: uiPath,
63
+ uiConfig: {
64
+ docExpansion: 'list',
65
+ deepLinking: true,
66
+ displayRequestDuration: true,
67
+ filter: true,
68
+ syntaxHighlight: {
69
+ activate: true,
70
+ theme: mergedOptions.theme === 'dark' ? 'monokai' : 'agate',
71
+ },
72
+ },
73
+ staticCSP: true,
74
+ transformStaticCSP: (header) => header,
75
+ };
76
+ // Add logo if provided
77
+ if (mergedOptions.logo) {
78
+ uiOptions.logo = {
79
+ type: 'image/png',
80
+ content: mergedOptions.logo.url,
81
+ href: mergedOptions.logo.url,
82
+ };
83
+ }
84
+ await fastify.register(fastifySwaggerUI, uiOptions);
85
+ }
86
+ // Add JSON spec route if enabled
87
+ // @fastify/swagger-ui registers routes at {uiPath}/json when UI is enabled
88
+ // So we only add custom route if:
89
+ // 1. UI is disabled (no swagger-ui default route exists)
90
+ // 2. jsonPath differs from swagger-ui default path
91
+ const defaultSwaggerUIJsonPath = `${uiPath}/json`;
92
+ const shouldRegisterCustomJsonRoute = exposeSpec && (!exposeUI ||
93
+ (jsonPath !== defaultSwaggerUIJsonPath && jsonPath !== '/docs/json'));
94
+ if (shouldRegisterCustomJsonRoute) {
95
+ fastify.get(jsonPath, {
96
+ schema: {
97
+ hide: true,
98
+ },
99
+ }, async () => {
100
+ return spec;
101
+ });
102
+ }
103
+ // Store spec on fastify instance for later access
104
+ fastify.decorate('openApiSpec', spec);
105
+ }
106
+ /**
107
+ * Swagger plugin for Fastify/Rikta
108
+ *
109
+ * Automatically generates OpenAPI documentation from Rikta controllers
110
+ * and serves Swagger UI for interactive API exploration.
111
+ *
112
+ * @example
113
+ * ```typescript
114
+ * import { RiktaFactory } from '@riktajs/core';
115
+ * import { swaggerPlugin } from '@riktajs/swagger';
116
+ *
117
+ * const app = await RiktaFactory.create();
118
+ *
119
+ * await app.register(swaggerPlugin, {
120
+ * info: {
121
+ * title: 'My API',
122
+ * version: '1.0.0',
123
+ * description: 'API documentation for My App',
124
+ * },
125
+ * config: {
126
+ * servers: [
127
+ * { url: 'http://localhost:3000', description: 'Development' },
128
+ * ],
129
+ * },
130
+ * });
131
+ *
132
+ * // Swagger UI available at /docs
133
+ * // OpenAPI JSON at /docs/json
134
+ * ```
135
+ */
136
+ export const swaggerPlugin = fp(swaggerPluginImpl, {
137
+ fastify: '>=4.0.0',
138
+ name: '@riktajs/swagger',
139
+ dependencies: [],
140
+ });
141
+ /**
142
+ * Register swagger plugin with a Rikta application
143
+ *
144
+ * Helper function that provides a simpler API for registering the plugin.
145
+ *
146
+ * @param app - Fastify instance
147
+ * @param options - Swagger plugin options
148
+ *
149
+ * @example
150
+ * ```typescript
151
+ * import { RiktaFactory } from '@riktajs/core';
152
+ * import { registerSwagger } from '@riktajs/swagger';
153
+ *
154
+ * const app = await RiktaFactory.create();
155
+ *
156
+ * await registerSwagger(app, {
157
+ * info: {
158
+ * title: 'My API',
159
+ * version: '1.0.0',
160
+ * },
161
+ * });
162
+ * ```
163
+ */
164
+ export async function registerSwagger(app, options = {}) {
165
+ await app.register(swaggerPlugin, options);
166
+ }
167
+ /**
168
+ * Create a standalone Swagger configuration for manual use
169
+ *
170
+ * Use this when you need more control over the Swagger setup,
171
+ * or when integrating with an existing Fastify application.
172
+ *
173
+ * @param options - Swagger plugin options
174
+ * @returns Object containing swagger and swaggerUI options and specification
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * import fastify from 'fastify';
179
+ * import fastifySwagger from '@fastify/swagger';
180
+ * import fastifySwaggerUI from '@fastify/swagger-ui';
181
+ * import { createSwaggerConfig } from '@riktajs/swagger';
182
+ *
183
+ * const app = fastify();
184
+ * const { swaggerOptions, swaggerUIOptions, specification } = createSwaggerConfig({
185
+ * info: { title: 'My API', version: '1.0.0' },
186
+ * controllers: [UserController, ProductController],
187
+ * });
188
+ *
189
+ * await app.register(fastifySwagger, swaggerOptions);
190
+ * await app.register(fastifySwaggerUI, swaggerUIOptions);
191
+ * ```
192
+ */
193
+ export function createSwaggerConfig(options = {}) {
194
+ const mergedOptions = { ...DEFAULT_OPTIONS, ...options };
195
+ const { uiPath, controllers, config, info } = mergedOptions;
196
+ // Build info object
197
+ const apiInfo = info || config?.info || {
198
+ title: 'API Documentation',
199
+ version: '1.0.0',
200
+ };
201
+ // Create generator
202
+ const generator = new OpenApiGenerator({
203
+ ...config,
204
+ info: apiInfo,
205
+ });
206
+ // Add controllers
207
+ const controllersToDocument = controllers || registry.getControllers();
208
+ for (const controller of controllersToDocument) {
209
+ generator.addController(controller);
210
+ }
211
+ // Add security schemes
212
+ if (config?.securitySchemes) {
213
+ for (const [name, scheme] of Object.entries(config.securitySchemes)) {
214
+ generator.addSecurityScheme(name, scheme);
215
+ }
216
+ }
217
+ const specification = generator.generate();
218
+ return {
219
+ swaggerOptions: {
220
+ mode: 'static',
221
+ specification: { document: specification },
222
+ },
223
+ swaggerUIOptions: {
224
+ routePrefix: uiPath,
225
+ uiConfig: {
226
+ docExpansion: 'list',
227
+ deepLinking: true,
228
+ displayRequestDuration: true,
229
+ filter: true,
230
+ },
231
+ },
232
+ specification,
233
+ };
234
+ }
235
+ //# sourceMappingURL=swagger.plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swagger.plugin.js","sourceRoot":"","sources":["../../src/plugin/swagger.plugin.ts"],"names":[],"mappings":"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"}