@scalar/hono-api-reference 0.11.16 → 0.12.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/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/scalar.d.ts +46 -2
- package/dist/scalar.d.ts.map +1 -1
- package/dist/scalar.js +46 -1
- package/dist/scalar.test.js +68 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,OAAO,EACL,MAAM;AACN;;GAEG;AACH,MAAM,IAAI,YAAY,GACvB,CAAA;AAED,YAAY,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAEjC,OAAO,EACL,MAAM;AACN;;GAEG;AACH,MAAM,IAAI,YAAY,GACvB,CAAA;AAED,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClD,YAAY,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA"}
|
package/dist/scalar.d.ts
CHANGED
|
@@ -1,9 +1,53 @@
|
|
|
1
1
|
import type { Context, Env, MiddlewareHandler } from 'hono';
|
|
2
|
+
import { Hono } from 'hono';
|
|
2
3
|
import type { ApiReferenceConfiguration } from './types.js';
|
|
3
4
|
type Configuration<E extends Env> = Partial<ApiReferenceConfiguration> | ((c: Context<E>) => Partial<ApiReferenceConfiguration> | Promise<Partial<ApiReferenceConfiguration>>);
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* An OpenAPI document.
|
|
7
|
+
*
|
|
8
|
+
* Typed loosely as an object on purpose, so it accepts both plain document objects and the typed
|
|
9
|
+
* return values of generators like Zod OpenAPI Hono's `getOpenAPI31Document()`, whose interfaces do
|
|
10
|
+
* not carry an index signature.
|
|
6
11
|
*/
|
|
7
|
-
|
|
12
|
+
type OpenApiDocument = object;
|
|
13
|
+
/**
|
|
14
|
+
* The configuration for `Scalar.serve`.
|
|
15
|
+
*
|
|
16
|
+
* On top of the universal API Reference configuration, this takes the OpenAPI `document` to render
|
|
17
|
+
* and expose. Because `Scalar.serve` sources the document itself, `content` and `url` are managed for
|
|
18
|
+
* you and are not accepted here.
|
|
19
|
+
*/
|
|
20
|
+
export type ServeConfiguration<E extends Env> = Omit<Partial<ApiReferenceConfiguration>, 'content' | 'url'> & {
|
|
21
|
+
/**
|
|
22
|
+
* The OpenAPI document to render and serve.
|
|
23
|
+
*
|
|
24
|
+
* Pass the document directly, or a function that returns it. The function receives the Hono
|
|
25
|
+
* `Context`, so it can read `c.env` or `c.req` and build the document per request. This is also how
|
|
26
|
+
* you wire up an `OpenAPIHono` app:
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* app.route('/scalar', Scalar.serve({
|
|
31
|
+
* document: () => app.getOpenAPI31Document({ openapi: '3.1.0', info: { title: 'Example', version: 'v1' } }),
|
|
32
|
+
* }))
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
document: OpenApiDocument | ((c: Context<E>) => OpenApiDocument | Promise<OpenApiDocument>);
|
|
36
|
+
/**
|
|
37
|
+
* Path, relative to the mount point, where the OpenAPI document is served as JSON.
|
|
38
|
+
*
|
|
39
|
+
* @default '/openapi.json'
|
|
40
|
+
*/
|
|
41
|
+
documentPath?: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Render the Scalar API Reference in a Hono app.
|
|
45
|
+
*
|
|
46
|
+
* Use `Scalar(...)` as a middleware to render the reference on a route, or `Scalar.serve(...)` to
|
|
47
|
+
* serve the reference and its OpenAPI document together from a single mount.
|
|
48
|
+
*/
|
|
49
|
+
export declare const Scalar: (<E extends Env>(configOrResolver: Configuration<E>) => MiddlewareHandler<E>) & {
|
|
50
|
+
serve: <E extends Env>(options: ServeConfiguration<E>) => Hono<E>;
|
|
51
|
+
};
|
|
8
52
|
export {};
|
|
9
53
|
//# sourceMappingURL=scalar.d.ts.map
|
package/dist/scalar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalar.d.ts","sourceRoot":"","sources":["../src/scalar.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"scalar.d.ts","sourceRoot":"","sources":["../src/scalar.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,SAAS,CAAA;AAgExD,KAAK,aAAa,CAAC,CAAC,SAAS,GAAG,IAC5B,OAAO,CAAC,yBAAyB,CAAC,GAClC,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,yBAAyB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAA;AA2BzG;;;;;;GAMG;AACH,KAAK,eAAe,GAAG,MAAM,CAAA;AAE7B;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,CAAC,CAAC,SAAS,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,EAAE,SAAS,GAAG,KAAK,CAAC,GAAG;IAC5G;;;;;;;;;;;;;OAaG;IACH,QAAQ,EAAE,eAAe,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAA;IAC3F;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAA;AAgDD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,IAlHO,CAAC,SAAS,GAAG,oBAAoB,aAAa,CAAC,CAAC,CAAC,KAAG,iBAAiB,CAAC,CAAC,CAAC;YA+E7E,CAAC,SAAS,GAAG,WAAW,kBAAkB,CAAC,CAAC,CAAC,KAAG,IAAI,CAAC,CAAC,CAAC;CAmCC,CAAA"}
|
package/dist/scalar.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { renderApiReference } from '@scalar/client-side-rendering';
|
|
2
|
+
import { Hono } from 'hono';
|
|
2
3
|
/**
|
|
3
4
|
* The default configuration for the API Reference.
|
|
4
5
|
*/
|
|
@@ -62,7 +63,7 @@ const customTheme = `
|
|
|
62
63
|
/**
|
|
63
64
|
* The Hono middleware for the Scalar API Reference.
|
|
64
65
|
*/
|
|
65
|
-
|
|
66
|
+
const scalarMiddleware = (configOrResolver) => {
|
|
66
67
|
return async (c) => {
|
|
67
68
|
let resolvedConfig = {};
|
|
68
69
|
if (typeof configOrResolver === 'function') {
|
|
@@ -81,3 +82,47 @@ export const Scalar = (configOrResolver) => {
|
|
|
81
82
|
return c.html(renderApiReference({ config, pageTitle, cdn, nonce }, customTheme));
|
|
82
83
|
};
|
|
83
84
|
};
|
|
85
|
+
/**
|
|
86
|
+
* Serve the API Reference and its OpenAPI document together as a mountable Hono app.
|
|
87
|
+
*
|
|
88
|
+
* Unlike the `Scalar` middleware — which only renders the reference and expects the document to live
|
|
89
|
+
* somewhere else — this exposes both from a single call, so you do not have to wire up a separate
|
|
90
|
+
* document route and keep its `url` in sync.
|
|
91
|
+
*
|
|
92
|
+
* Mount it with `app.route(...)`:
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* import { Scalar } from '@scalar/hono-api-reference'
|
|
97
|
+
*
|
|
98
|
+
* // Serves the reference at `/scalar` and the document at `/scalar/openapi.json`
|
|
99
|
+
* app.route('/scalar', Scalar.serve({ document: myOpenApiDocument }))
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
const scalarServe = (options) => {
|
|
103
|
+
const { document, documentPath = '/openapi.json', ...rest } = options;
|
|
104
|
+
const app = new Hono();
|
|
105
|
+
const resolveDocument = (c) => typeof document === 'function' ? document(c) : document;
|
|
106
|
+
// Expose the OpenAPI document as JSON, so a single call powers both the reference and its source.
|
|
107
|
+
app.get(documentPath, async (c) => c.json(await resolveDocument(c)));
|
|
108
|
+
// Render the reference, pointing it at the document we expose above.
|
|
109
|
+
app.get('/', (c) => {
|
|
110
|
+
// Build a root-absolute URL to the document from the current request path. This keeps the
|
|
111
|
+
// reference working wherever it is mounted, and whether or not the request has a trailing slash.
|
|
112
|
+
const url = `${c.req.path.replace(/\/+$/, '')}${documentPath}`;
|
|
113
|
+
const { cdn, pageTitle, nonce, ...config } = {
|
|
114
|
+
...DEFAULT_CONFIGURATION,
|
|
115
|
+
...rest,
|
|
116
|
+
url,
|
|
117
|
+
};
|
|
118
|
+
return c.html(renderApiReference({ config, pageTitle, cdn, nonce }, customTheme));
|
|
119
|
+
});
|
|
120
|
+
return app;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Render the Scalar API Reference in a Hono app.
|
|
124
|
+
*
|
|
125
|
+
* Use `Scalar(...)` as a middleware to render the reference on a route, or `Scalar.serve(...)` to
|
|
126
|
+
* serve the reference and its OpenAPI document together from a single mount.
|
|
127
|
+
*/
|
|
128
|
+
export const Scalar = Object.assign(scalarMiddleware, { serve: scalarServe });
|
package/dist/scalar.test.js
CHANGED
|
@@ -206,4 +206,72 @@ describe('Scalar', () => {
|
|
|
206
206
|
expect(text).toContain('Test API');
|
|
207
207
|
expect(text).toContain('deepSpace');
|
|
208
208
|
});
|
|
209
|
+
describe('serve', () => {
|
|
210
|
+
const document = {
|
|
211
|
+
openapi: '3.1.0',
|
|
212
|
+
info: { title: 'Serve API', version: '1.0.0' },
|
|
213
|
+
paths: {},
|
|
214
|
+
};
|
|
215
|
+
it('serves the OpenAPI document as JSON at the mount point', async () => {
|
|
216
|
+
const app = new Hono();
|
|
217
|
+
app.route('/scalar', Scalar.serve({ document }));
|
|
218
|
+
const response = await app.request('/scalar/openapi.json');
|
|
219
|
+
expect(response.status).toBe(200);
|
|
220
|
+
expect(response.headers.get('content-type')).toContain('application/json');
|
|
221
|
+
expect(await response.json()).toEqual(document);
|
|
222
|
+
});
|
|
223
|
+
it('renders the reference at the mount point, pointing at the served document', async () => {
|
|
224
|
+
const app = new Hono();
|
|
225
|
+
app.route('/scalar', Scalar.serve({ document }));
|
|
226
|
+
const response = await app.request('/scalar');
|
|
227
|
+
expect(response.status).toBe(200);
|
|
228
|
+
expect(response.headers.get('content-type')).toContain('text/html');
|
|
229
|
+
const text = await response.text();
|
|
230
|
+
expect(text).toContain('<title>Scalar API Reference</title>');
|
|
231
|
+
// The reference points at the document we serve alongside it
|
|
232
|
+
expect(text).toContain('/scalar/openapi.json');
|
|
233
|
+
// The document is referenced by URL, not inlined
|
|
234
|
+
expect(text).not.toContain('Serve API');
|
|
235
|
+
});
|
|
236
|
+
it('serves the document at a custom documentPath', async () => {
|
|
237
|
+
const app = new Hono();
|
|
238
|
+
app.route('/scalar', Scalar.serve({ document, documentPath: '/spec.json' }));
|
|
239
|
+
const json = await app.request('/scalar/spec.json');
|
|
240
|
+
expect(json.status).toBe(200);
|
|
241
|
+
expect(await json.json()).toEqual(document);
|
|
242
|
+
const html = await (await app.request('/scalar')).text();
|
|
243
|
+
expect(html).toContain('/scalar/spec.json');
|
|
244
|
+
});
|
|
245
|
+
it('resolves the document from a function with access to the context', async () => {
|
|
246
|
+
const app = new Hono();
|
|
247
|
+
app.route('/scalar', Scalar.serve({
|
|
248
|
+
document: (c) => ({ ...document, info: { ...document.info, title: c.req.path } }),
|
|
249
|
+
}));
|
|
250
|
+
const response = await app.request('/scalar/openapi.json');
|
|
251
|
+
expect(await response.json()).toMatchObject({ info: { title: '/scalar/openapi.json' } });
|
|
252
|
+
});
|
|
253
|
+
it('passes through reference options like pageTitle and theme', async () => {
|
|
254
|
+
const app = new Hono();
|
|
255
|
+
app.route('/scalar', Scalar.serve({ document, pageTitle: 'Serve Title', theme: 'kepler' }));
|
|
256
|
+
const text = await (await app.request('/scalar')).text();
|
|
257
|
+
expect(text).toContain('<title>Serve Title</title>');
|
|
258
|
+
// A theme was provided, so the custom Hono theme CSS is not injected
|
|
259
|
+
expect(text).not.toContain('--scalar-color-1: rgba(255, 255, 245, .86);');
|
|
260
|
+
});
|
|
261
|
+
it('includes the hono integration marker and the custom theme by default', async () => {
|
|
262
|
+
const app = new Hono();
|
|
263
|
+
app.route('/scalar', Scalar.serve({ document }));
|
|
264
|
+
const text = await (await app.request('/scalar')).text();
|
|
265
|
+
expect(text).toContain('_integration": "hono"');
|
|
266
|
+
expect(text).toContain('--scalar-color-1: rgba(255, 255, 245, .86);');
|
|
267
|
+
});
|
|
268
|
+
it('works when mounted at the root', async () => {
|
|
269
|
+
const app = new Hono();
|
|
270
|
+
app.route('/', Scalar.serve({ document }));
|
|
271
|
+
const html = await (await app.request('/')).text();
|
|
272
|
+
expect(html).toContain('/openapi.json');
|
|
273
|
+
const json = await app.request('/openapi.json');
|
|
274
|
+
expect(await json.json()).toEqual(document);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
209
277
|
});
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"url": "git+https://github.com/scalar/scalar.git",
|
|
11
11
|
"directory": "integrations/hono"
|
|
12
12
|
},
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.12.0",
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=22"
|
|
16
16
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"documentation": "https://scalar.com/products/api-references/integrations/hono"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@scalar/client-side-rendering": "0.3.
|
|
47
|
+
"@scalar/client-side-rendering": "0.3.10"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@hono/node-server": "^1.19.10",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"hono": "^4.12.7",
|
|
53
53
|
"vite": "8.1.5",
|
|
54
54
|
"vitest": "4.1.10",
|
|
55
|
-
"@scalar/openapi-to-markdown": "0.5.
|
|
55
|
+
"@scalar/openapi-to-markdown": "0.5.43"
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"hono": "^4.12.5"
|