react-cheminfo 0.61.0 → 0.62.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/README.md
CHANGED
|
@@ -1229,9 +1229,11 @@ A prerendered site can also be deployed as a server, with its API and its MCP
|
|
|
1229
1229
|
tools beside the pages. `staticSite` from `react-cheminfo/server` serves the
|
|
1230
1230
|
build by the rules the static hosts follow: `/titration` is `titration.html`
|
|
1231
1231
|
with no redirect, an unknown address is `404.html` and never the home page,
|
|
1232
|
-
pages are revalidated on every visit and `assets/` is kept for a year,
|
|
1233
|
-
|
|
1234
|
-
|
|
1232
|
+
pages are revalidated on every visit and `assets/` is kept for a year, every
|
|
1233
|
+
answer carries `Access-Control-Allow-Origin: *` (a page framed by a chat's
|
|
1234
|
+
sandboxed view fetches all its files cross-origin), the `TRACKING_SCRIPT`
|
|
1235
|
+
snippet is in every page, and `/health` answers the deploy script. Only a file
|
|
1236
|
+
the build wrote is ever served.
|
|
1235
1237
|
|
|
1236
1238
|
```ts
|
|
1237
1239
|
import { fastify } from 'fastify';
|
|
@@ -28,8 +28,9 @@ export interface StaticSiteOptions {
|
|
|
28
28
|
* family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
|
|
29
29
|
* file per address and no fallback page, `/titration` answered without a
|
|
30
30
|
* redirect, pages checked on every visit and hashed bundles kept for a year,
|
|
31
|
-
* the analytics snippet in every page,
|
|
32
|
-
* not have, and `/health` for the
|
|
31
|
+
* every response open to any origin, the analytics snippet in every page,
|
|
32
|
+
* `404.html` for an address the site does not have, and `/health` for the
|
|
33
|
+
* deploy script.
|
|
33
34
|
*
|
|
34
35
|
* Register it next to the API; a build missing (a server started before the
|
|
35
36
|
* frontend was built) leaves the API alone:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staticSite.d.ts","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAC;AAMjB,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;
|
|
1
|
+
{"version":3,"file":"staticSite.d.ts","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,eAAe,EAIhB,MAAM,SAAS,CAAC;AAMjB,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC9B;AAwBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,IAAI,CAAC,CAyDf"}
|
package/lib/server/staticSite.js
CHANGED
|
@@ -6,6 +6,12 @@ import { isHashedBundle, listSiteFiles, resolveAddress } from "./siteFiles.js";
|
|
|
6
6
|
const PAGE_CACHE = 'no-cache';
|
|
7
7
|
/** A bundle is named by its content, so it never changes under its name. */
|
|
8
8
|
const BUNDLE_CACHE = 'public, max-age=31536000, immutable';
|
|
9
|
+
/**
|
|
10
|
+
* Every file of a build is public, and a page framed by a sandboxed view runs
|
|
11
|
+
* under an opaque origin, where everything it fetches from its own site is
|
|
12
|
+
* cross-origin: the static hosts open every response, and so does this server.
|
|
13
|
+
*/
|
|
14
|
+
const ALLOW_ORIGIN = 'access-control-allow-origin';
|
|
9
15
|
/** Kept out of the API's documentation (`@fastify/swagger` reads `hide`). */
|
|
10
16
|
const HIDDEN = { hide: true };
|
|
11
17
|
/**
|
|
@@ -13,8 +19,9 @@ const HIDDEN = { hide: true };
|
|
|
13
19
|
* family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
|
|
14
20
|
* file per address and no fallback page, `/titration` answered without a
|
|
15
21
|
* redirect, pages checked on every visit and hashed bundles kept for a year,
|
|
16
|
-
* the analytics snippet in every page,
|
|
17
|
-
* not have, and `/health` for the
|
|
22
|
+
* every response open to any origin, the analytics snippet in every page,
|
|
23
|
+
* `404.html` for an address the site does not have, and `/health` for the
|
|
24
|
+
* deploy script.
|
|
18
25
|
*
|
|
19
26
|
* Register it next to the API; a build missing (a server started before the
|
|
20
27
|
* frontend was built) leaves the API alone:
|
|
@@ -26,7 +33,7 @@ const HIDDEN = { hide: true };
|
|
|
26
33
|
export async function staticSite(fastify, options) {
|
|
27
34
|
const { trackingScript, redirects = {}, reserved = ['/v1/'] } = options;
|
|
28
35
|
const root = resolve(options.root);
|
|
29
|
-
fastify.get('/health', { logLevel: 'silent', schema: HIDDEN }, (_request, reply) => reply.send({ status: 'ok' }));
|
|
36
|
+
fastify.get('/health', { logLevel: 'silent', schema: HIDDEN }, (_request, reply) => reply.header(ALLOW_ORIGIN, '*').send({ status: 'ok' }));
|
|
30
37
|
const files = await listSiteFiles(root);
|
|
31
38
|
if (files === undefined) {
|
|
32
39
|
fastify.log.warn({ root }, 'no built site: serving the API alone');
|
|
@@ -42,15 +49,7 @@ export async function staticSite(fastify, options) {
|
|
|
42
49
|
cacheControl: false,
|
|
43
50
|
setHeaders: (reply, path) => {
|
|
44
51
|
const file = relative(root, path).split(sep).join('/');
|
|
45
|
-
|
|
46
|
-
reply.header('cache-control', BUNDLE_CACHE);
|
|
47
|
-
// A page framed by a sandboxed view may run under an opaque origin,
|
|
48
|
-
// and a module bundle is then fetched cross-origin.
|
|
49
|
-
reply.header('access-control-allow-origin', '*');
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
reply.header('cache-control', PAGE_CACHE);
|
|
53
|
-
}
|
|
52
|
+
reply.header('cache-control', isHashedBundle(file) ? BUNDLE_CACHE : PAGE_CACHE);
|
|
54
53
|
},
|
|
55
54
|
});
|
|
56
55
|
const answer = (request, reply) => {
|
|
@@ -59,6 +58,7 @@ export async function staticSite(fastify, options) {
|
|
|
59
58
|
if (reserved.some((prefix) => pathname.startsWith(prefix))) {
|
|
60
59
|
return reply.callNotFound();
|
|
61
60
|
}
|
|
61
|
+
reply.header(ALLOW_ORIGIN, '*');
|
|
62
62
|
const destination = redirects[pathname] ?? redirects[pathname.replace(/\/$/, '')];
|
|
63
63
|
if (destination !== undefined) {
|
|
64
64
|
return reply.redirect(`${destination}${search}`, 301);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staticSite.js","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AASzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAErE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAiC/E,+EAA+E;AAC/E,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,4EAA4E;AAC5E,MAAM,YAAY,GAAG,qCAAqC,CAAC;AAE3D,6EAA6E;AAC7E,MAAM,MAAM,GAAsC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAEjE
|
|
1
|
+
{"version":3,"file":"staticSite.js","sourceRoot":"","sources":["../../src/server/staticSite.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-cheminfo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.62.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "React components, hooks and framework-free helpers shared by the cheminfo sites: site chrome, citations, sharing, routing, pedagogy, charts, and the structure, orbital and 3D molecule viewers",
|
|
6
6
|
"author": "Luc Patiny",
|
package/src/server/staticSite.ts
CHANGED
|
@@ -49,6 +49,13 @@ const PAGE_CACHE = 'no-cache';
|
|
|
49
49
|
/** A bundle is named by its content, so it never changes under its name. */
|
|
50
50
|
const BUNDLE_CACHE = 'public, max-age=31536000, immutable';
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Every file of a build is public, and a page framed by a sandboxed view runs
|
|
54
|
+
* under an opaque origin, where everything it fetches from its own site is
|
|
55
|
+
* cross-origin: the static hosts open every response, and so does this server.
|
|
56
|
+
*/
|
|
57
|
+
const ALLOW_ORIGIN = 'access-control-allow-origin';
|
|
58
|
+
|
|
52
59
|
/** Kept out of the API's documentation (`@fastify/swagger` reads `hide`). */
|
|
53
60
|
const HIDDEN: FastifySchema & { hide: boolean } = { hide: true };
|
|
54
61
|
|
|
@@ -57,8 +64,9 @@ const HIDDEN: FastifySchema & { hide: boolean } = { hide: true };
|
|
|
57
64
|
* family follows (static-web-server's `sws.toml`, Cloudflare Pages): a real
|
|
58
65
|
* file per address and no fallback page, `/titration` answered without a
|
|
59
66
|
* redirect, pages checked on every visit and hashed bundles kept for a year,
|
|
60
|
-
* the analytics snippet in every page,
|
|
61
|
-
* not have, and `/health` for the
|
|
67
|
+
* every response open to any origin, the analytics snippet in every page,
|
|
68
|
+
* `404.html` for an address the site does not have, and `/health` for the
|
|
69
|
+
* deploy script.
|
|
62
70
|
*
|
|
63
71
|
* Register it next to the API; a build missing (a server started before the
|
|
64
72
|
* frontend was built) leaves the API alone:
|
|
@@ -77,7 +85,7 @@ export async function staticSite(
|
|
|
77
85
|
fastify.get(
|
|
78
86
|
'/health',
|
|
79
87
|
{ logLevel: 'silent', schema: HIDDEN },
|
|
80
|
-
(_request, reply) => reply.send({ status: 'ok' }),
|
|
88
|
+
(_request, reply) => reply.header(ALLOW_ORIGIN, '*').send({ status: 'ok' }),
|
|
81
89
|
);
|
|
82
90
|
|
|
83
91
|
const files = await listSiteFiles(root);
|
|
@@ -96,14 +104,10 @@ export async function staticSite(
|
|
|
96
104
|
cacheControl: false,
|
|
97
105
|
setHeaders: (reply, path) => {
|
|
98
106
|
const file = relative(root, path).split(sep).join('/');
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
reply.header('access-control-allow-origin', '*');
|
|
104
|
-
} else {
|
|
105
|
-
reply.header('cache-control', PAGE_CACHE);
|
|
106
|
-
}
|
|
107
|
+
reply.header(
|
|
108
|
+
'cache-control',
|
|
109
|
+
isHashedBundle(file) ? BUNDLE_CACHE : PAGE_CACHE,
|
|
110
|
+
);
|
|
107
111
|
},
|
|
108
112
|
});
|
|
109
113
|
|
|
@@ -113,6 +117,7 @@ export async function staticSite(
|
|
|
113
117
|
if (reserved.some((prefix) => pathname.startsWith(prefix))) {
|
|
114
118
|
return reply.callNotFound();
|
|
115
119
|
}
|
|
120
|
+
reply.header(ALLOW_ORIGIN, '*');
|
|
116
121
|
const destination =
|
|
117
122
|
redirects[pathname] ?? redirects[pathname.replace(/\/$/, '')];
|
|
118
123
|
if (destination !== undefined) {
|