@scalar/fastify-api-reference 1.61.0 → 1.62.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.
- package/CHANGELOG.md +8 -0
- package/dist/fastifyApiReference.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +165 -1
- package/dist/utils/getJavaScriptFile.d.ts +11 -1
- package/dist/utils/getJavaScriptFile.d.ts.map +1 -1
- package/package.json +6 -7
- package/dist/fastifyApiReference.js +0 -215
- package/dist/js/standalone.js +0 -2385
- package/dist/types.js +0 -1
- package/dist/utils/getJavaScriptFile.js +0 -20
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Return the standalone build of `@scalar/api-reference` as a string.
|
|
3
|
+
*
|
|
4
|
+
* This implementation reads the script from disk and is what runs during
|
|
5
|
+
* development (the playground executes the source directly via `tsx`) and in
|
|
6
|
+
* tests, where `@scalar/api-reference` is available as a workspace dependency.
|
|
7
|
+
*
|
|
8
|
+
* For the published package, the Vite build replaces this module with the
|
|
9
|
+
* script inlined as a string (see `vite.config.ts`). That is what makes the
|
|
10
|
+
* plugin bundler-safe: the output is self-contained and no longer reads the
|
|
11
|
+
* file at runtime, so it survives whatever bundler the consuming application
|
|
12
|
+
* uses (for example when bundling a Fastify app into a Docker image).
|
|
3
13
|
*/
|
|
4
14
|
export declare function getJavaScriptFile(): string;
|
|
5
15
|
//# sourceMappingURL=getJavaScriptFile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getJavaScriptFile.d.ts","sourceRoot":"","sources":["../../src/utils/getJavaScriptFile.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"getJavaScriptFile.d.ts","sourceRoot":"","sources":["../../src/utils/getJavaScriptFile.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C"}
|
package/package.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"openapi",
|
|
18
18
|
"swagger"
|
|
19
19
|
],
|
|
20
|
-
"version": "1.
|
|
20
|
+
"version": "1.62.1",
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=22"
|
|
23
23
|
},
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"fastify-plugin": "^4.5.1",
|
|
56
56
|
"github-slugger": "2.0.0",
|
|
57
|
-
"@scalar/
|
|
57
|
+
"@scalar/openapi-parser": "0.28.8",
|
|
58
58
|
"@scalar/openapi-types": "0.9.1",
|
|
59
|
-
"@scalar/
|
|
59
|
+
"@scalar/client-side-rendering": "0.3.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@fastify/basic-auth": "^5.1.1",
|
|
@@ -66,12 +66,11 @@
|
|
|
66
66
|
"vite": "8.0.0",
|
|
67
67
|
"vitest": "4.1.0",
|
|
68
68
|
"yaml": "^2.8.3",
|
|
69
|
-
"@scalar/api-reference": "1.
|
|
70
|
-
"@scalar/helpers": "0.
|
|
69
|
+
"@scalar/api-reference": "1.62.1",
|
|
70
|
+
"@scalar/helpers": "0.9.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
|
-
"build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json
|
|
74
|
-
"copy:standalone": "shx mkdir -p ./dist/js && shx cp ../../packages/api-reference/dist/browser/standalone.js ./dist/js/standalone.js",
|
|
73
|
+
"build": "pnpm types:check && vite build && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
75
74
|
"dev": "tsx watch playground/index.ts",
|
|
76
75
|
"docker:build": "docker build --build-arg BASE_IMAGE=scalar-base -t fastify-api-reference -f Dockerfile .",
|
|
77
76
|
"docker:run": "docker run -p 5053:5053 fastify-api-reference",
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
/// <reference types="@fastify/swagger" />
|
|
2
|
-
import { renderApiReference } from '@scalar/client-side-rendering';
|
|
3
|
-
import { normalize, toJson, toYaml } from '@scalar/openapi-parser';
|
|
4
|
-
import fp from 'fastify-plugin';
|
|
5
|
-
import { slug } from 'github-slugger';
|
|
6
|
-
import { getJavaScriptFile } from './utils/getJavaScriptFile.js';
|
|
7
|
-
/**
|
|
8
|
-
* Path to the bundled Scalar JavaScript file
|
|
9
|
-
*/
|
|
10
|
-
const RELATIVE_JAVASCRIPT_PATH = 'js/scalar.js';
|
|
11
|
-
/**
|
|
12
|
-
* This Schema is used to hide the route from the documentation.
|
|
13
|
-
*
|
|
14
|
-
* We don't know whether `@fastify/swagger` is registered, but it doesn't hurt to add a schema anyway.
|
|
15
|
-
*
|
|
16
|
-
* @see https://github.com/fastify/fastify-swagger#hide-a-route
|
|
17
|
-
*/
|
|
18
|
-
// Typed as FastifySchema so route inference uses FastifySchema (not the narrow
|
|
19
|
-
// literal { hide: boolean }), keeping hook handler types compatible across
|
|
20
|
-
// Fastify v4 and v5 even when @fastify/swagger augments FastifySchema with `hide`.
|
|
21
|
-
const schemaToHideRoute = {
|
|
22
|
-
hide: true,
|
|
23
|
-
};
|
|
24
|
-
const getRoutePrefix = (routePrefix) => {
|
|
25
|
-
const prefix = routePrefix ?? '/reference';
|
|
26
|
-
// Remove trailing slash if present
|
|
27
|
-
return prefix.endsWith('/') ? prefix.slice(0, -1) : prefix;
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Get the endpoints for the OpenAPI specification.
|
|
31
|
-
*/
|
|
32
|
-
const getOpenApiDocumentEndpoints = (openApiDocumentEndpoints) => {
|
|
33
|
-
const { json = '/openapi.json', yaml = '/openapi.yaml' } = openApiDocumentEndpoints ?? {};
|
|
34
|
-
return { json, yaml };
|
|
35
|
-
};
|
|
36
|
-
/**
|
|
37
|
-
* Get the URL for the Scalar JavaScript file.
|
|
38
|
-
*/
|
|
39
|
-
const getJavaScriptUrl = (routePrefix) => `${getRoutePrefix(routePrefix)}/${RELATIVE_JAVASCRIPT_PATH}`.replace(/\/\//g, '/');
|
|
40
|
-
/**
|
|
41
|
-
* The default configuration for Fastify
|
|
42
|
-
*/
|
|
43
|
-
const DEFAULT_CONFIGURATION = {
|
|
44
|
-
_integration: 'fastify',
|
|
45
|
-
};
|
|
46
|
-
const fastifyApiReference = fp((fastify, options, next) => {
|
|
47
|
-
const { configuration: givenConfiguration } = options;
|
|
48
|
-
// Merge the defaults
|
|
49
|
-
let configuration = {
|
|
50
|
-
...DEFAULT_CONFIGURATION,
|
|
51
|
-
...givenConfiguration,
|
|
52
|
-
};
|
|
53
|
-
const specSource = (() => {
|
|
54
|
-
const { content, url } = configuration ?? {};
|
|
55
|
-
if (content) {
|
|
56
|
-
return {
|
|
57
|
-
type: 'content',
|
|
58
|
-
get: () => {
|
|
59
|
-
if (typeof content === 'function') {
|
|
60
|
-
return content();
|
|
61
|
-
}
|
|
62
|
-
return content;
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
if (url) {
|
|
67
|
-
return {
|
|
68
|
-
type: 'url',
|
|
69
|
-
get: () => url,
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
// Even if @fastify/swagger is loaded, when the `decorator` option is set, the `swagger` function is not available.
|
|
73
|
-
if (fastify.hasPlugin('@fastify/swagger') && typeof fastify.swagger === 'function') {
|
|
74
|
-
return {
|
|
75
|
-
type: 'swagger',
|
|
76
|
-
get: () => fastify.swagger(),
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
return void 0;
|
|
80
|
-
})();
|
|
81
|
-
// If no OpenAPI specification is passed and @fastify/swagger isn't loaded, show a warning.
|
|
82
|
-
if (!specSource && !configuration.sources) {
|
|
83
|
-
fastify.log.warn("[@scalar/fastify-api-reference] You didn't provide a `content`, `url`, `sources` or @fastify/swagger could not be found. Please provide one of these options.");
|
|
84
|
-
return next();
|
|
85
|
-
}
|
|
86
|
-
// Read the JavaScript file once.
|
|
87
|
-
const fileContent = getJavaScriptFile();
|
|
88
|
-
const hooks = {};
|
|
89
|
-
if (options.hooks) {
|
|
90
|
-
const additionalHooks = ['onRequest', 'preHandler'];
|
|
91
|
-
for (const hook of additionalHooks) {
|
|
92
|
-
if (options.hooks[hook]) {
|
|
93
|
-
hooks[hook] = options.hooks[hook];
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const getSpecFilenameSlug = (spec) => {
|
|
98
|
-
// Same GitHub Slugger and default file name as in `@scalar/api-reference`, when generating the download
|
|
99
|
-
return slug(spec?.specification?.info?.title ?? 'spec');
|
|
100
|
-
};
|
|
101
|
-
// Only expose the endpoints if specSource is available
|
|
102
|
-
if (specSource) {
|
|
103
|
-
const openApiSpecUrlJson = `${getRoutePrefix(options.routePrefix)}${getOpenApiDocumentEndpoints(options.openApiDocumentEndpoints).json}`;
|
|
104
|
-
fastify.route({
|
|
105
|
-
method: 'GET',
|
|
106
|
-
url: openApiSpecUrlJson,
|
|
107
|
-
schema: schemaToHideRoute,
|
|
108
|
-
...hooks,
|
|
109
|
-
...(options.logLevel && { logLevel: options.logLevel }),
|
|
110
|
-
handler(_, reply) {
|
|
111
|
-
const spec = normalize(specSource.get());
|
|
112
|
-
const filename = getSpecFilenameSlug(spec);
|
|
113
|
-
const json = JSON.parse(toJson(spec)); // parsing minifies the JSON
|
|
114
|
-
return reply
|
|
115
|
-
.header('Content-Type', 'application/json')
|
|
116
|
-
.header('Content-Disposition', `filename=${filename}.json`)
|
|
117
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
118
|
-
.header('Access-Control-Allow-Methods', '*')
|
|
119
|
-
.send(json);
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
const openApiSpecUrlYaml = `${getRoutePrefix(options.routePrefix)}${getOpenApiDocumentEndpoints(options.openApiDocumentEndpoints).yaml}`;
|
|
123
|
-
fastify.route({
|
|
124
|
-
method: 'GET',
|
|
125
|
-
url: openApiSpecUrlYaml,
|
|
126
|
-
schema: schemaToHideRoute,
|
|
127
|
-
...hooks,
|
|
128
|
-
...(options.logLevel && { logLevel: options.logLevel }),
|
|
129
|
-
handler(_, reply) {
|
|
130
|
-
const spec = normalize(specSource.get());
|
|
131
|
-
const filename = getSpecFilenameSlug(spec);
|
|
132
|
-
const yaml = toYaml(spec);
|
|
133
|
-
return reply
|
|
134
|
-
.header('Content-Type', 'application/yaml')
|
|
135
|
-
.header('Content-Disposition', `filename=${filename}.yaml`)
|
|
136
|
-
.header('Access-Control-Allow-Origin', '*')
|
|
137
|
-
.header('Access-Control-Allow-Methods', '*')
|
|
138
|
-
.send(yaml);
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
// Redirect route without a trailing slash to force a trailing slash:
|
|
143
|
-
// We need this so the request to the JS file is relative.
|
|
144
|
-
// With ignoreTrailingSlash: true, fastify responds to both routes anyway.
|
|
145
|
-
const ignoreTrailingSlash =
|
|
146
|
-
// @ts-expect-error We're still on Fastify 4, this is introduced in Fastify 5
|
|
147
|
-
fastify.initialConfig?.routerOptions?.ignoreTrailingSlash === true ||
|
|
148
|
-
fastify.initialConfig?.ignoreTrailingSlash === true;
|
|
149
|
-
if (!ignoreTrailingSlash && getRoutePrefix(options.routePrefix)) {
|
|
150
|
-
fastify.route({
|
|
151
|
-
method: 'GET',
|
|
152
|
-
url: getRoutePrefix(options.routePrefix),
|
|
153
|
-
schema: schemaToHideRoute,
|
|
154
|
-
...hooks,
|
|
155
|
-
...(options.logLevel && { logLevel: options.logLevel }),
|
|
156
|
-
handler(request, reply) {
|
|
157
|
-
// we are in a route without a trailing slash so redirect directly to the one with a trailing slash
|
|
158
|
-
const currentUrl = new URL(request.url, `${request.protocol}://${request.hostname}`);
|
|
159
|
-
return reply.redirect(`${currentUrl.pathname}/`, 301);
|
|
160
|
-
},
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
// If no theme is passed, use the default theme.
|
|
164
|
-
fastify.route({
|
|
165
|
-
method: 'GET',
|
|
166
|
-
url: `${getRoutePrefix(options.routePrefix)}/`,
|
|
167
|
-
// We don't know whether @fastify/swagger is registered, but it doesn't hurt to add a schema anyway.
|
|
168
|
-
schema: schemaToHideRoute,
|
|
169
|
-
...hooks,
|
|
170
|
-
...(options.logLevel && { logLevel: options.logLevel }),
|
|
171
|
-
handler(request, reply) {
|
|
172
|
-
// Redirect if it's the route without a slash
|
|
173
|
-
const currentUrl = new URL(request.url, `${request.protocol}://${request.hostname}`);
|
|
174
|
-
if (!currentUrl.pathname.endsWith('/')) {
|
|
175
|
-
return reply.redirect(`${currentUrl.pathname}/`, 301);
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Regardless of where we source the spec from, provide it as a URL, to have the
|
|
179
|
-
* download button point to the exposed endpoint.
|
|
180
|
-
* If the URL is explicitly passed, defer to that URL instead.
|
|
181
|
-
*/
|
|
182
|
-
if (specSource && specSource.type !== 'url') {
|
|
183
|
-
configuration = {
|
|
184
|
-
...configuration,
|
|
185
|
-
// Use a relative URL in case we're proxied
|
|
186
|
-
url: `.${getOpenApiDocumentEndpoints(options.openApiDocumentEndpoints).json}`,
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
// Respond with the HTML document
|
|
190
|
-
const { cdn, pageTitle, nonce, ...config } = configuration;
|
|
191
|
-
return reply.header('Content-Type', 'text/html; charset=utf-8').send(renderApiReference({
|
|
192
|
-
config,
|
|
193
|
-
// We're using the bundled JS here by default, but the user can pass a CDN URL.
|
|
194
|
-
cdn: cdn ?? RELATIVE_JAVASCRIPT_PATH,
|
|
195
|
-
pageTitle,
|
|
196
|
-
nonce,
|
|
197
|
-
}));
|
|
198
|
-
},
|
|
199
|
-
});
|
|
200
|
-
fastify.route({
|
|
201
|
-
method: 'GET',
|
|
202
|
-
url: getJavaScriptUrl(options.routePrefix),
|
|
203
|
-
// We don't know whether @fastify/swagger is registered, but it doesn't hurt to add a schema anyway.
|
|
204
|
-
schema: schemaToHideRoute,
|
|
205
|
-
...hooks,
|
|
206
|
-
...(options.logLevel && { logLevel: options.logLevel }),
|
|
207
|
-
handler(_, reply) {
|
|
208
|
-
return reply.header('Content-Type', 'application/javascript; charset=utf-8').send(fileContent);
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
next();
|
|
212
|
-
}, {
|
|
213
|
-
name: '@scalar/fastify-api-reference',
|
|
214
|
-
});
|
|
215
|
-
export default fastifyApiReference;
|