@scalar/client-side-rendering 0.1.12 → 0.2.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 +24 -0
- package/dist/html-rendering.d.ts +19 -2
- package/dist/html-rendering.d.ts.map +1 -1
- package/dist/html-rendering.js +29 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @scalar/client-side-rendering
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#9422](https://github.com/scalar/scalar/pull/9422): Add a `nonce` option for Content Security Policy support.
|
|
8
|
+
|
|
9
|
+
When you pass a `nonce`, the rendered HTML stamps it onto the inline `<script>` and the CDN `<script>` tag (and Scalar's own `<style>` tags, plus a matching `<meta property="csp-nonce">`). This lets the API Reference run under a strict `script-src` with no `unsafe-inline` and no `unsafe-eval`.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
ApiReference({
|
|
13
|
+
url: '/openapi.json',
|
|
14
|
+
// Match this value in your `script-src` CSP directive.
|
|
15
|
+
nonce: 'r4nd0m',
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Note: `style-src` still needs `'unsafe-inline'`. The reference renders inline `style="…"` attributes, which a CSP nonce can never authorize (nonces only apply to `<script>`, `<style>` and `<link>` elements), so a nonce-only `style-src` is not possible. The win is a fully strict `script-src`.
|
|
20
|
+
|
|
21
|
+
## 0.1.13
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#9326](https://github.com/scalar/scalar/pull/9326): Export `DEFAULT_CDN` so consumers (e.g. `@scalar/astro`) can share the canonical fallback URL instead of duplicating it. Also widens `getConfiguration` to accept `Partial<HtmlRenderingConfiguration>`, removing the need for a `Record<string, unknown>` cast at the boundary.
|
|
26
|
+
|
|
3
27
|
## 0.1.12
|
|
4
28
|
|
|
5
29
|
## 0.1.11
|
package/dist/html-rendering.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { AnyApiReferenceConfiguration, HtmlRenderingConfiguration } from '@scalar/types/api-reference';
|
|
2
2
|
export type { AnyApiReferenceConfiguration, HtmlRenderingConfiguration };
|
|
3
|
+
/** Default CDN URL for the @scalar/api-reference standalone bundle. */
|
|
4
|
+
export declare const DEFAULT_CDN = "https://cdn.jsdelivr.net/npm/@scalar/api-reference";
|
|
3
5
|
/**
|
|
4
6
|
* Render the Scalar API Reference as a complete HTML document using the CDN.
|
|
5
7
|
*
|
|
@@ -15,13 +17,28 @@ export declare function renderApiReference(options: {
|
|
|
15
17
|
pageTitle?: string;
|
|
16
18
|
/** CDN URL for the standalone bundle. Defaults to jsDelivr. */
|
|
17
19
|
cdn?: string;
|
|
20
|
+
/**
|
|
21
|
+
* A Content Security Policy (CSP) nonce to apply to the generated inline `<script>` and `<style>`
|
|
22
|
+
* tags (and the CDN `<script>` tag).
|
|
23
|
+
*
|
|
24
|
+
* When set, a `<meta property="csp-nonce">` tag is also emitted so the standalone bundle can apply
|
|
25
|
+
* the same nonce to the stylesheet it injects at runtime. This lets the API Reference run under a
|
|
26
|
+
* strict `script-src` with no `unsafe-inline` and no `unsafe-eval`.
|
|
27
|
+
*
|
|
28
|
+
* Note: `style-src` still needs `'unsafe-inline'`, because the reference renders inline
|
|
29
|
+
* `style="..."` attributes that a CSP nonce cannot authorize.
|
|
30
|
+
*/
|
|
31
|
+
nonce?: string;
|
|
18
32
|
}, customTheme?: string): string;
|
|
19
33
|
/**
|
|
20
34
|
* The script tags to load the @scalar/api-reference package from the CDN.
|
|
35
|
+
*
|
|
36
|
+
* When a `nonce` is provided it is applied to both script tags so they are allowed under a strict
|
|
37
|
+
* `script-src` Content Security Policy.
|
|
21
38
|
*/
|
|
22
|
-
export declare function getScriptTags(configuration: Record<string, unknown>, cdn?: string): string;
|
|
39
|
+
export declare function getScriptTags(configuration: Record<string, unknown>, cdn?: string, nonce?: string): string;
|
|
23
40
|
/**
|
|
24
41
|
* The configuration to pass to the @scalar/api-reference package.
|
|
25
42
|
*/
|
|
26
|
-
export declare const getConfiguration: (givenConfiguration: Record<string, unknown>) => Record<string, unknown>;
|
|
43
|
+
export declare const getConfiguration: (givenConfiguration: Partial<HtmlRenderingConfiguration> | Record<string, unknown>) => Record<string, unknown>;
|
|
27
44
|
//# sourceMappingURL=html-rendering.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-rendering.d.ts","sourceRoot":"","sources":["../src/html-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AAE3G,YAAY,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"html-rendering.d.ts","sourceRoot":"","sources":["../src/html-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AAE3G,YAAY,EAAE,4BAA4B,EAAE,0BAA0B,EAAE,CAAA;AAExE,uEAAuE;AACvE,eAAO,MAAM,WAAW,uDAAuD,CAAA;AAoE/E;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE;IACP,uCAAuC;IACvC,MAAM,EAAE,4BAA4B,CAAA;IACpC,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ;;;;;;;;;;OAUG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,EACD,WAAW,SAAK,GACf,MAAM,CA8BR;AASD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CA0C1G;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,GAC3B,oBAAoB,OAAO,CAAC,0BAA0B,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAChF,MAAM,CAAC,MAAM,EAAE,OAAO,CAcxB,CAAA"}
|
package/dist/html-rendering.js
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
/** Default CDN URL for the @scalar/api-reference standalone bundle. */
|
|
2
|
+
export const DEFAULT_CDN = 'https://cdn.jsdelivr.net/npm/@scalar/api-reference';
|
|
2
3
|
/**
|
|
3
4
|
* Escape HTML special characters in user-provided strings.
|
|
4
5
|
*/
|
|
5
6
|
const escapeHtml = (str) => {
|
|
6
7
|
return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
7
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* Escape a value for use inside a double-quoted HTML attribute.
|
|
11
|
+
*
|
|
12
|
+
* On top of the regular HTML escaping we also encode double quotes so the value cannot break out of
|
|
13
|
+
* the attribute. Used for the CSP nonce, which is attacker-influenced in some setups.
|
|
14
|
+
*/
|
|
15
|
+
const escapeHtmlAttribute = (str) => escapeHtml(str).replace(/"/g, '"');
|
|
16
|
+
/**
|
|
17
|
+
* Build a ` nonce="..."` attribute (with a leading space) when a nonce is provided, otherwise an
|
|
18
|
+
* empty string. Returned ready to be interpolated into a tag.
|
|
19
|
+
*/
|
|
20
|
+
const nonceAttribute = (nonce) => (nonce ? ` nonce="${escapeHtmlAttribute(nonce)}"` : '');
|
|
8
21
|
/**
|
|
9
22
|
* Helper function to add consistent indentation to multiline strings
|
|
10
23
|
* @param str The string to indent
|
|
@@ -26,7 +39,7 @@ const addIndent = (str, spaces = 2, initialIndent = false) => {
|
|
|
26
39
|
/**
|
|
27
40
|
* Generate the style tag with custom theme if needed
|
|
28
41
|
*/
|
|
29
|
-
const getStyles = (configuration, customTheme) => {
|
|
42
|
+
const getStyles = (configuration, customTheme, nonce) => {
|
|
30
43
|
const styles = [];
|
|
31
44
|
if (configuration.customCss) {
|
|
32
45
|
styles.push('/* Custom CSS */');
|
|
@@ -40,7 +53,7 @@ const getStyles = (configuration, customTheme) => {
|
|
|
40
53
|
return '';
|
|
41
54
|
}
|
|
42
55
|
return `
|
|
43
|
-
<style type="text/css">
|
|
56
|
+
<style type="text/css"${nonceAttribute(nonce)}>
|
|
44
57
|
${addIndent(styles.join('\n\n'), 6)}
|
|
45
58
|
</style>`;
|
|
46
59
|
};
|
|
@@ -53,7 +66,7 @@ const getStyles = (configuration, customTheme) => {
|
|
|
53
66
|
* For server-side rendering with hydration, use the server module instead.
|
|
54
67
|
*/
|
|
55
68
|
export function renderApiReference(options, customTheme = '') {
|
|
56
|
-
const { config: givenConfig, pageTitle, cdn } = options;
|
|
69
|
+
const { config: givenConfig, pageTitle, cdn, nonce } = options;
|
|
57
70
|
const title = escapeHtml(pageTitle ?? 'Scalar API Reference');
|
|
58
71
|
const unwrapped = Array.isArray(givenConfig) ? givenConfig[0] : givenConfig;
|
|
59
72
|
const { customCss, theme, ...rest } = (unwrapped ?? {});
|
|
@@ -62,6 +75,9 @@ export function renderApiReference(options, customTheme = '') {
|
|
|
62
75
|
...(theme ? { theme } : {}),
|
|
63
76
|
...(customCss !== undefined ? { customCss } : {}),
|
|
64
77
|
});
|
|
78
|
+
// Expose the nonce to the standalone bundle so it can apply it to the stylesheet it injects at
|
|
79
|
+
// runtime (the bundle reads `meta[property=csp-nonce]` when built with `useStrictCSP`).
|
|
80
|
+
const cspNonceMeta = nonce ? `\n <meta property="csp-nonce" content="${escapeHtmlAttribute(nonce)}" />` : '';
|
|
65
81
|
return `<!doctype html>
|
|
66
82
|
<html>
|
|
67
83
|
<head>
|
|
@@ -69,10 +85,10 @@ export function renderApiReference(options, customTheme = '') {
|
|
|
69
85
|
<meta charset="utf-8" />
|
|
70
86
|
<meta
|
|
71
87
|
name="viewport"
|
|
72
|
-
content="width=device-width, initial-scale=1" />${getStyles(configuration, customTheme)}
|
|
88
|
+
content="width=device-width, initial-scale=1" />${cspNonceMeta}${getStyles(configuration, customTheme, nonce)}
|
|
73
89
|
</head>
|
|
74
90
|
<body>
|
|
75
|
-
<div id="app"></div>${getScriptTags(configuration, cdn)}
|
|
91
|
+
<div id="app"></div>${getScriptTags(configuration, cdn, nonce)}
|
|
76
92
|
</body>
|
|
77
93
|
</html>`;
|
|
78
94
|
}
|
|
@@ -84,8 +100,11 @@ const serializeArrayWithFunctions = (arr) => {
|
|
|
84
100
|
};
|
|
85
101
|
/**
|
|
86
102
|
* The script tags to load the @scalar/api-reference package from the CDN.
|
|
103
|
+
*
|
|
104
|
+
* When a `nonce` is provided it is applied to both script tags so they are allowed under a strict
|
|
105
|
+
* `script-src` Content Security Policy.
|
|
87
106
|
*/
|
|
88
|
-
export function getScriptTags(configuration, cdn) {
|
|
107
|
+
export function getScriptTags(configuration, cdn, nonce) {
|
|
89
108
|
const restConfig = { ...configuration };
|
|
90
109
|
const functionProps = [];
|
|
91
110
|
for (const [key, value] of Object.entries(configuration)) {
|
|
@@ -113,12 +132,13 @@ export function getScriptTags(configuration, cdn) {
|
|
|
113
132
|
configString = `${jsonWithoutClosingBrace},\n ${functionProps.join(',\n ')}\n }`;
|
|
114
133
|
}
|
|
115
134
|
}
|
|
135
|
+
const nonceAttr = nonceAttribute(nonce);
|
|
116
136
|
return `
|
|
117
137
|
<!-- Load the Script -->
|
|
118
|
-
<script src="${cdn ?? DEFAULT_CDN}"></script>
|
|
138
|
+
<script src="${cdn ?? DEFAULT_CDN}"${nonceAttr}></script>
|
|
119
139
|
|
|
120
140
|
<!-- Initialize the Scalar API Reference -->
|
|
121
|
-
<script type="text/javascript">
|
|
141
|
+
<script type="text/javascript"${nonceAttr}>
|
|
122
142
|
Scalar.createApiReference('#app', ${configString})
|
|
123
143
|
</script>`;
|
|
124
144
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { type AnyApiReferenceConfiguration, type HtmlRenderingConfiguration, getConfiguration, getScriptTags, renderApiReference, } from './html-rendering.js';
|
|
1
|
+
export { type AnyApiReferenceConfiguration, DEFAULT_CDN, type HtmlRenderingConfiguration, getConfiguration, getScriptTags, renderApiReference, } from './html-rendering.js';
|
|
2
2
|
//# sourceMappingURL=index.d.ts.map
|
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,EACL,KAAK,4BAA4B,EACjC,KAAK,0BAA0B,EAC/B,gBAAgB,EAChB,aAAa,EACb,kBAAkB,GACnB,MAAM,kBAAkB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,4BAA4B,EACjC,WAAW,EACX,KAAK,0BAA0B,EAC/B,gBAAgB,EAChB,aAAa,EACb,kBAAkB,GACnB,MAAM,kBAAkB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { getConfiguration, getScriptTags, renderApiReference, } from './html-rendering.js';
|
|
1
|
+
export { DEFAULT_CDN, getConfiguration, getScriptTags, renderApiReference, } from './html-rendering.js';
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"directory": "packages/client-side-rendering"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [],
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.2.0",
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=22"
|
|
17
17
|
},
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"CHANGELOG.md"
|
|
29
29
|
],
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@scalar/schemas": "0.
|
|
32
|
-
"@scalar/
|
|
33
|
-
"@scalar/
|
|
31
|
+
"@scalar/schemas": "0.4.0",
|
|
32
|
+
"@scalar/types": "0.13.0",
|
|
33
|
+
"@scalar/validation": "0.6.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"vite": "8.0.0"
|