@tinvar/renderer 0.4.19 → 0.4.21
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/package.json +1 -1
- package/src/dev-guard.js +30 -14
- package/src/dev-server.js +22 -2
package/package.json
CHANGED
package/src/dev-guard.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// The one check dev mode makes before anything of it is loaded: that this is
|
|
2
|
-
//
|
|
2
|
+
// a developer's machine. Its own module, importing nothing, so the refusal happens
|
|
3
3
|
// before Vite -- or any dependency of the app -- has run a line.
|
|
4
4
|
|
|
5
5
|
/** The variables any of which, saying `production`, rule the dev server out. Mirrors Tinvar\Support\DevMode. */
|
|
@@ -7,27 +7,43 @@ export const PRODUCTION_MARKERS = ['NODE_ENV', 'TINVAR_ENV', 'APP_ENV'];
|
|
|
7
7
|
|
|
8
8
|
export class DevServerRefused extends Error {}
|
|
9
9
|
|
|
10
|
+
/** The TINVAR_ENV values that say this is a developer's or a test's machine. Mirrors Tinvar\Support\DevMode::DEVELOPMENT. */
|
|
11
|
+
export const DEVELOPMENT = ['local', 'development', 'testing'];
|
|
12
|
+
|
|
10
13
|
/**
|
|
11
|
-
* Refuses, loudly,
|
|
14
|
+
* Refuses, loudly, everywhere but a machine that says it is a developer's.
|
|
12
15
|
*
|
|
13
16
|
* The dev server runs unsandboxed, serves source over HTTP and shows stacks
|
|
14
|
-
* to whoever loads a failing page.
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
+
* to whoever loads a failing page. So, as Tinvar\Support\DevMode reads it
|
|
18
|
+
* (ADR 0213): TINVAR_ENV must say local, development or testing, and no
|
|
19
|
+
* NODE_ENV, TINVAR_ENV or APP_ENV may say production, nor TINVAR_ENV,
|
|
20
|
+
* APP_ENV or TINVAR_PROFILE staging. An environment that says nothing may
|
|
21
|
+
* be a server's, and is refused too.
|
|
17
22
|
*
|
|
18
23
|
* @param {Record<string, string | undefined>} env
|
|
19
24
|
*/
|
|
20
25
|
export function assertDevelopment(env = process.env) {
|
|
26
|
+
const read = (name) =>
|
|
27
|
+
String(env[name] ?? '')
|
|
28
|
+
.trim()
|
|
29
|
+
.toLowerCase();
|
|
30
|
+
let why = null;
|
|
21
31
|
for (const name of PRODUCTION_MARKERS) {
|
|
22
|
-
if (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.toLowerCase() === 'production'
|
|
26
|
-
) {
|
|
27
|
-
throw new DevServerRefused(
|
|
28
|
-
`The dev server is refused: ${name}=production. It runs without the renderer's sandbox and serves ` +
|
|
29
|
-
'source to the browser, so it never runs in production. Use the built renderer there.',
|
|
30
|
-
);
|
|
32
|
+
if (read(name) === 'production') {
|
|
33
|
+
why = `${name}=production`;
|
|
34
|
+
break;
|
|
31
35
|
}
|
|
32
36
|
}
|
|
37
|
+
for (const name of ['TINVAR_ENV', 'APP_ENV', 'TINVAR_PROFILE']) {
|
|
38
|
+
if (why === null && ['production', 'staging'].includes(read(name))) why = `${name}=${read(name)}`;
|
|
39
|
+
}
|
|
40
|
+
if (why === null && !DEVELOPMENT.includes(read('TINVAR_ENV'))) {
|
|
41
|
+
why = 'TINVAR_ENV is not local, development or testing';
|
|
42
|
+
}
|
|
43
|
+
if (why !== null) {
|
|
44
|
+
throw new DevServerRefused(
|
|
45
|
+
`The dev server is refused: ${why}. It runs without the renderer's sandbox and serves source to the ` +
|
|
46
|
+
"browser, so it runs only on a developer's machine: set TINVAR_ENV=local there. Use the built renderer anywhere else.",
|
|
47
|
+
);
|
|
48
|
+
}
|
|
33
49
|
}
|
package/src/dev-server.js
CHANGED
|
@@ -42,6 +42,11 @@ export const DEV_BASE = '/_vite/';
|
|
|
42
42
|
/** Addresses the dev server may listen on: this machine's, and nothing else. */
|
|
43
43
|
const LOOPBACK = new Set(['127.0.0.1', '::1']);
|
|
44
44
|
|
|
45
|
+
/** $path with the characters a glob reads escaped, so it matches itself alone. */
|
|
46
|
+
function globEscape(path) {
|
|
47
|
+
return path.replace(/[\\*?[\]{}()!+@]/g, '\\$&');
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
/** The app's Vite config file. */
|
|
46
51
|
function configFileOf(appRoot) {
|
|
47
52
|
for (const name of ['vite.config.ts', 'vite.config.mts', 'vite.config.js', 'vite.config.mjs']) {
|
|
@@ -128,8 +133,23 @@ export async function createDevServer({
|
|
|
128
133
|
...(publicHosts.length > 0 ? { allowedHosts: [...publicHosts] } : {}),
|
|
129
134
|
fs: {
|
|
130
135
|
// Vite's own refusals, and the secrets an app keeps beside its code:
|
|
131
|
-
// a key file, a database, the PHP dependencies.
|
|
132
|
-
|
|
136
|
+
// a key file, a database, the PHP dependencies. And, since a
|
|
137
|
+
// tunnel's visitor reaches whatever is served under the base (ADR
|
|
138
|
+
// 0214): the app's database/ directory whatever its files are named
|
|
139
|
+
// (APP_LOG, APP_MAIL_LOG, the sign-up and reset links in them),
|
|
140
|
+
// every log, and the secrets/ compose reads the app key from.
|
|
141
|
+
deny: [
|
|
142
|
+
'.env',
|
|
143
|
+
'.env.*',
|
|
144
|
+
'*.{crt,pem}',
|
|
145
|
+
'**/.git/**',
|
|
146
|
+
'**/*.key',
|
|
147
|
+
'**/*.sqlite*',
|
|
148
|
+
'**/vendor/**',
|
|
149
|
+
'**/*.log',
|
|
150
|
+
`${globEscape(appRoot)}/database/**`,
|
|
151
|
+
`${globEscape(appRoot)}/secrets/**`,
|
|
152
|
+
],
|
|
133
153
|
},
|
|
134
154
|
},
|
|
135
155
|
});
|