@navios/openapi-fastify 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/LICENSE +8 -0
- package/README.md +311 -0
- package/dist/src/index.d.mts +6 -0
- package/dist/src/index.d.mts.map +1 -0
- package/dist/src/openapi-fastify.plugin.d.mts +74 -0
- package/dist/src/openapi-fastify.plugin.d.mts.map +1 -0
- package/dist/src/schemas/index.d.mts +2 -0
- package/dist/src/schemas/index.d.mts.map +1 -0
- package/dist/src/schemas/openapi-fastify-options.schema.d.mts +113 -0
- package/dist/src/schemas/openapi-fastify-options.schema.d.mts.map +1 -0
- package/dist/src/utils/apply-global-prefix.util.d.mts +26 -0
- package/dist/src/utils/apply-global-prefix.util.d.mts.map +1 -0
- package/dist/src/utils/index.d.mts +2 -0
- package/dist/src/utils/index.d.mts.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/tsdown.config.d.mts +3 -0
- package/dist/tsdown.config.d.mts.map +1 -0
- package/dist/vitest.config.d.mts +3 -0
- package/dist/vitest.config.d.mts.map +1 -0
- package/lib/index.cjs +233 -0
- package/lib/index.cjs.map +1 -0
- package/lib/index.d.cts +214 -0
- package/lib/index.d.cts.map +1 -0
- package/lib/index.d.mts +214 -0
- package/lib/index.d.mts.map +1 -0
- package/lib/index.mjs +185 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +48 -0
- package/project.json +66 -0
- package/src/index.mts +41 -0
- package/src/openapi-fastify.plugin.mts +167 -0
- package/src/schemas/index.mts +10 -0
- package/src/schemas/openapi-fastify-options.schema.mts +129 -0
- package/src/utils/apply-global-prefix.util.mts +52 -0
- package/src/utils/index.mts +1 -0
- package/tsconfig.json +14 -0
- package/tsconfig.lib.json +8 -0
- package/tsconfig.spec.json +7 -0
- package/tsdown.config.mts +35 -0
- package/vitest.config.mts +11 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
NaviosPlugin,
|
|
3
|
+
PluginContext,
|
|
4
|
+
PluginDefinition,
|
|
5
|
+
} from '@navios/core'
|
|
6
|
+
import type { OpenApiGeneratorOptions } from '@navios/openapi'
|
|
7
|
+
import type { FastifyInstance } from 'fastify'
|
|
8
|
+
|
|
9
|
+
import { OpenApiGeneratorService } from '@navios/openapi'
|
|
10
|
+
|
|
11
|
+
import { getHtmlDocument } from '@scalar/core/libs/html-rendering'
|
|
12
|
+
import { stringify as yamlStringify } from 'yaml'
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
FastifyOpenApiPluginOptionsBase,
|
|
16
|
+
ScalarOptions,
|
|
17
|
+
ScalarTheme,
|
|
18
|
+
} from './schemas/index.mjs'
|
|
19
|
+
|
|
20
|
+
import { fastifyOpenApiPluginOptionsSchema } from './schemas/index.mjs'
|
|
21
|
+
import { applyGlobalPrefix } from './utils/index.mjs'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Combined options for the Fastify OpenAPI plugin.
|
|
25
|
+
* Extends OpenApiGeneratorOptions with Fastify-specific settings.
|
|
26
|
+
*/
|
|
27
|
+
export interface FastifyOpenApiPluginOptions
|
|
28
|
+
extends OpenApiGeneratorOptions, Partial<FastifyOpenApiPluginOptionsBase> {}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Class-based OpenAPI Fastify plugin that integrates with Navios plugin system.
|
|
32
|
+
*
|
|
33
|
+
* This plugin:
|
|
34
|
+
* - Scans all registered modules for endpoints
|
|
35
|
+
* - Generates an OpenAPI 3.1 document
|
|
36
|
+
* - Serves the document as JSON and optionally YAML
|
|
37
|
+
* - Provides Scalar UI for interactive documentation
|
|
38
|
+
*/
|
|
39
|
+
export class OpenApiFastifyPlugin implements NaviosPlugin<FastifyOpenApiPluginOptions> {
|
|
40
|
+
readonly name = 'openapi-fastify'
|
|
41
|
+
|
|
42
|
+
async register(
|
|
43
|
+
context: PluginContext,
|
|
44
|
+
options: FastifyOpenApiPluginOptions,
|
|
45
|
+
): Promise<void> {
|
|
46
|
+
const fastify = context.server as FastifyInstance
|
|
47
|
+
|
|
48
|
+
// Parse and validate options with defaults
|
|
49
|
+
const parsedOptions = fastifyOpenApiPluginOptionsSchema.parse(options)
|
|
50
|
+
|
|
51
|
+
// Get the generator service from the container
|
|
52
|
+
const generator = await context.container.get(OpenApiGeneratorService)
|
|
53
|
+
|
|
54
|
+
// Generate OpenAPI document from discovered endpoints
|
|
55
|
+
const document = generator.generate(context.modules, options)
|
|
56
|
+
|
|
57
|
+
// Apply global prefix to servers if not already set
|
|
58
|
+
const documentWithServers = applyGlobalPrefix(
|
|
59
|
+
document,
|
|
60
|
+
context.globalPrefix,
|
|
61
|
+
options,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
// Register JSON endpoint
|
|
65
|
+
const jsonPath = parsedOptions.jsonPath
|
|
66
|
+
fastify.get(jsonPath, async (_request, reply) => {
|
|
67
|
+
return reply.send(documentWithServers)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
// Register YAML endpoint (disabled by default)
|
|
71
|
+
if (!parsedOptions.disableYaml) {
|
|
72
|
+
const yamlPath = parsedOptions.yamlPath
|
|
73
|
+
fastify.get(yamlPath, async (_request, reply) => {
|
|
74
|
+
reply.type('text/yaml')
|
|
75
|
+
return reply.send(yamlStringify(documentWithServers))
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Register Scalar UI (unless disabled)
|
|
80
|
+
if (!parsedOptions.disableScalar) {
|
|
81
|
+
const docsPath = parsedOptions.docsPath
|
|
82
|
+
const scalarOptions = options.scalar ?? {}
|
|
83
|
+
|
|
84
|
+
// Generate HTML document using @scalar/core
|
|
85
|
+
const html = this.generateScalarHtml(jsonPath, scalarOptions)
|
|
86
|
+
|
|
87
|
+
fastify.get(docsPath, async (_request, reply) => {
|
|
88
|
+
reply.type('text/html')
|
|
89
|
+
return reply.send(html)
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Generates the Scalar API Reference HTML document.
|
|
96
|
+
*
|
|
97
|
+
* @param specUrl - URL to the OpenAPI JSON specification
|
|
98
|
+
* @param options - Scalar UI configuration options
|
|
99
|
+
* @returns Complete HTML document string
|
|
100
|
+
*/
|
|
101
|
+
private generateScalarHtml(specUrl: string, options: ScalarOptions): string {
|
|
102
|
+
return getHtmlDocument({
|
|
103
|
+
url: specUrl,
|
|
104
|
+
theme: options.theme ?? 'default',
|
|
105
|
+
favicon: options.favicon,
|
|
106
|
+
customCss: options.customCss,
|
|
107
|
+
hideDownloadButton: options.hideDownloadButton,
|
|
108
|
+
hideSearch: options.hideSearch,
|
|
109
|
+
metaData: options.metaData,
|
|
110
|
+
cdn: options.cdn,
|
|
111
|
+
pageTitle: options.metaData?.title ?? 'API Reference',
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Creates a plugin definition for the OpenAPI Fastify plugin.
|
|
118
|
+
*
|
|
119
|
+
* @param options - Plugin configuration options
|
|
120
|
+
* @returns Plugin definition to pass to `app.usePlugin()`
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* import { NaviosFactory } from '@navios/core'
|
|
125
|
+
* import { defineFastifyEnvironment } from '@navios/adapter-fastify'
|
|
126
|
+
* import { defineOpenApiPlugin } from '@navios/openapi-fastify'
|
|
127
|
+
*
|
|
128
|
+
* const app = await NaviosFactory.create(AppModule, {
|
|
129
|
+
* adapter: defineFastifyEnvironment(),
|
|
130
|
+
* })
|
|
131
|
+
*
|
|
132
|
+
* app.usePlugin(defineOpenApiPlugin({
|
|
133
|
+
* info: {
|
|
134
|
+
* title: 'My API',
|
|
135
|
+
* version: '1.0.0',
|
|
136
|
+
* description: 'API documentation',
|
|
137
|
+
* },
|
|
138
|
+
* servers: [
|
|
139
|
+
* { url: 'http://localhost:3000', description: 'Development' },
|
|
140
|
+
* ],
|
|
141
|
+
* securitySchemes: {
|
|
142
|
+
* bearerAuth: {
|
|
143
|
+
* type: 'http',
|
|
144
|
+
* scheme: 'bearer',
|
|
145
|
+
* bearerFormat: 'JWT',
|
|
146
|
+
* },
|
|
147
|
+
* },
|
|
148
|
+
* scalar: {
|
|
149
|
+
* theme: 'purple',
|
|
150
|
+
* },
|
|
151
|
+
* }))
|
|
152
|
+
*
|
|
153
|
+
* await app.listen({ port: 3000 })
|
|
154
|
+
* // API docs available at http://localhost:3000/docs
|
|
155
|
+
* ```
|
|
156
|
+
*/
|
|
157
|
+
export function defineOpenApiPlugin(
|
|
158
|
+
options: FastifyOpenApiPluginOptions,
|
|
159
|
+
): PluginDefinition<FastifyOpenApiPluginOptions> {
|
|
160
|
+
return {
|
|
161
|
+
plugin: new OpenApiFastifyPlugin(),
|
|
162
|
+
options,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Re-export types for convenience
|
|
167
|
+
export type { ScalarOptions, ScalarTheme }
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export {
|
|
2
|
+
fastifyOpenApiPluginOptionsSchema,
|
|
3
|
+
scalarMetaDataSchema,
|
|
4
|
+
scalarOptionsSchema,
|
|
5
|
+
scalarThemeSchema,
|
|
6
|
+
type FastifyOpenApiPluginOptionsBase,
|
|
7
|
+
type ScalarMetaData,
|
|
8
|
+
type ScalarOptions,
|
|
9
|
+
type ScalarTheme,
|
|
10
|
+
} from './openapi-fastify-options.schema.mjs'
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for Scalar UI theme options
|
|
5
|
+
*/
|
|
6
|
+
export const scalarThemeSchema = z.enum([
|
|
7
|
+
'default',
|
|
8
|
+
'alternate',
|
|
9
|
+
'moon',
|
|
10
|
+
'purple',
|
|
11
|
+
'solarized',
|
|
12
|
+
'bluePlanet',
|
|
13
|
+
'saturn',
|
|
14
|
+
'kepler',
|
|
15
|
+
'mars',
|
|
16
|
+
'deepSpace',
|
|
17
|
+
'laserwave',
|
|
18
|
+
'elysiajs',
|
|
19
|
+
'fastify',
|
|
20
|
+
'none',
|
|
21
|
+
])
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Zod schema for Scalar UI metadata
|
|
25
|
+
*/
|
|
26
|
+
export const scalarMetaDataSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
title: z.string().optional(),
|
|
29
|
+
description: z.string().optional(),
|
|
30
|
+
ogDescription: z.string().optional(),
|
|
31
|
+
ogTitle: z.string().optional(),
|
|
32
|
+
ogImage: z.string().optional(),
|
|
33
|
+
twitterCard: z.string().optional(),
|
|
34
|
+
})
|
|
35
|
+
.optional()
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Zod schema for Scalar UI configuration options
|
|
39
|
+
*/
|
|
40
|
+
export const scalarOptionsSchema = z.object({
|
|
41
|
+
/**
|
|
42
|
+
* Theme for Scalar UI
|
|
43
|
+
* @default 'default'
|
|
44
|
+
*/
|
|
45
|
+
theme: scalarThemeSchema.optional(),
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Custom favicon URL
|
|
49
|
+
*/
|
|
50
|
+
favicon: z.string().optional(),
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Custom logo URL
|
|
54
|
+
*/
|
|
55
|
+
logo: z.string().optional(),
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Hide the "Download OpenAPI Spec" button
|
|
59
|
+
* @default false
|
|
60
|
+
*/
|
|
61
|
+
hideDownloadButton: z.boolean().optional(),
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Hide the "Search" input
|
|
65
|
+
* @default false
|
|
66
|
+
*/
|
|
67
|
+
hideSearch: z.boolean().optional(),
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Custom CSS to inject
|
|
71
|
+
*/
|
|
72
|
+
customCss: z.string().optional(),
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Meta data for the HTML page
|
|
76
|
+
*/
|
|
77
|
+
metaData: scalarMetaDataSchema,
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* CDN URL for Scalar API Reference
|
|
81
|
+
* @default 'https://cdn.jsdelivr.net/npm/@scalar/api-reference'
|
|
82
|
+
*/
|
|
83
|
+
cdn: z.string().optional(),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Zod schema for Fastify OpenAPI plugin options
|
|
88
|
+
*/
|
|
89
|
+
export const fastifyOpenApiPluginOptionsSchema = z.object({
|
|
90
|
+
/**
|
|
91
|
+
* Path to serve OpenAPI JSON
|
|
92
|
+
* @default '/openapi.json'
|
|
93
|
+
*/
|
|
94
|
+
jsonPath: z.string().optional().default('/openapi.json'),
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Path to serve OpenAPI YAML
|
|
98
|
+
* @default '/openapi.yaml'
|
|
99
|
+
*/
|
|
100
|
+
yamlPath: z.string().optional().default('/openapi.yaml'),
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Path to serve Scalar UI
|
|
104
|
+
* @default '/docs'
|
|
105
|
+
*/
|
|
106
|
+
docsPath: z.string().optional().default('/docs'),
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Scalar UI configuration
|
|
110
|
+
*/
|
|
111
|
+
scalar: scalarOptionsSchema.optional(),
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Disable Scalar UI (only serve JSON/YAML)
|
|
115
|
+
* @default false
|
|
116
|
+
*/
|
|
117
|
+
disableScalar: z.boolean().optional().default(false),
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Disable YAML endpoint
|
|
121
|
+
* @default true
|
|
122
|
+
*/
|
|
123
|
+
disableYaml: z.boolean().optional().default(true),
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
export type ScalarTheme = z.infer<typeof scalarThemeSchema>
|
|
127
|
+
export type ScalarMetaData = z.infer<typeof scalarMetaDataSchema>
|
|
128
|
+
export type ScalarOptions = z.infer<typeof scalarOptionsSchema>
|
|
129
|
+
export type FastifyOpenApiPluginOptionsBase = z.infer<typeof fastifyOpenApiPluginOptionsSchema>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { OpenApiGeneratorOptions } from '@navios/openapi'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* OpenAPI document shape (minimal interface for typing)
|
|
5
|
+
*/
|
|
6
|
+
export interface OpenAPIDocument {
|
|
7
|
+
openapi: string
|
|
8
|
+
info: {
|
|
9
|
+
title: string
|
|
10
|
+
version: string
|
|
11
|
+
}
|
|
12
|
+
paths?: Record<string, unknown>
|
|
13
|
+
servers?: Array<{
|
|
14
|
+
url: string
|
|
15
|
+
description?: string
|
|
16
|
+
}>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Applies global prefix to OpenAPI servers if needed.
|
|
21
|
+
*
|
|
22
|
+
* @param document - The OpenAPI document to modify
|
|
23
|
+
* @param globalPrefix - The global route prefix (e.g., '/api/v1')
|
|
24
|
+
* @param options - Plugin options that may contain server configuration
|
|
25
|
+
* @returns The document with servers array updated if applicable
|
|
26
|
+
*/
|
|
27
|
+
export function applyGlobalPrefix<T extends OpenAPIDocument>(
|
|
28
|
+
document: T,
|
|
29
|
+
globalPrefix: string,
|
|
30
|
+
options: OpenApiGeneratorOptions,
|
|
31
|
+
): T {
|
|
32
|
+
// If servers are already defined, don't modify
|
|
33
|
+
if (options.servers && options.servers.length > 0) {
|
|
34
|
+
return document
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// If no global prefix, return as-is
|
|
38
|
+
if (!globalPrefix) {
|
|
39
|
+
return document
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Add a default server with the global prefix
|
|
43
|
+
return {
|
|
44
|
+
...document,
|
|
45
|
+
servers: [
|
|
46
|
+
{
|
|
47
|
+
url: globalPrefix,
|
|
48
|
+
description: 'API with global prefix',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { applyGlobalPrefix, type OpenAPIDocument } from './apply-global-prefix.util.mjs'
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "Node18",
|
|
5
|
+
"outDir": "dist"
|
|
6
|
+
},
|
|
7
|
+
"references": [
|
|
8
|
+
{ "path": "./tsconfig.lib.json" },
|
|
9
|
+
{ "path": "../core" },
|
|
10
|
+
{ "path": "../di" },
|
|
11
|
+
{ "path": "../openapi" },
|
|
12
|
+
{ "path": "../adapter-fastify" }
|
|
13
|
+
]
|
|
14
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { withFilter } from 'rolldown/filter'
|
|
2
|
+
import { defineConfig } from 'tsdown'
|
|
3
|
+
import swc from 'unplugin-swc'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
entry: ['src/index.mts'],
|
|
7
|
+
outDir: 'lib',
|
|
8
|
+
format: ['esm', 'cjs'],
|
|
9
|
+
clean: true,
|
|
10
|
+
tsconfig: 'tsconfig.lib.json',
|
|
11
|
+
treeshake: true,
|
|
12
|
+
sourcemap: true,
|
|
13
|
+
platform: 'node',
|
|
14
|
+
external: ['@navios/core', '@navios/openapi', '@navios/adapter-fastify', 'fastify'],
|
|
15
|
+
dts: true,
|
|
16
|
+
target: 'es2022',
|
|
17
|
+
plugins: [
|
|
18
|
+
withFilter(
|
|
19
|
+
swc.rolldown({
|
|
20
|
+
jsc: {
|
|
21
|
+
target: 'es2022',
|
|
22
|
+
parser: {
|
|
23
|
+
syntax: 'typescript',
|
|
24
|
+
decorators: true,
|
|
25
|
+
},
|
|
26
|
+
transform: {
|
|
27
|
+
decoratorVersion: '2022-03',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
// Only run this transform if the file contains a decorator.
|
|
32
|
+
{ transform: { code: '@' } },
|
|
33
|
+
),
|
|
34
|
+
],
|
|
35
|
+
})
|