@jesscss/plugin-js 2.0.0-alpha.7 → 2.0.0-alpha.8
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 +48 -3
- package/lib/index.cjs +33 -2
- package/lib/index.d.ts +7 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +33 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,6 +1,51 @@
|
|
|
1
1
|
# @jesscss/plugin-js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**Import bridge for JavaScript/TypeScript modules in stylesheets — a seed of the
|
|
4
|
+
JavaScript-execution / CSS-in-JS story.**
|
|
4
5
|
|
|
5
|
-
This
|
|
6
|
-
|
|
6
|
+
This plugin lets a stylesheet pull in JavaScript/TypeScript modules
|
|
7
|
+
(`.js`, `.mjs`, `.cjs`, `.ts`, `.mts`, `.cts`) — the mechanism behind `@use` /
|
|
8
|
+
`@-from` script imports and legacy Less `@plugin` loading. When installed, it is
|
|
9
|
+
auto-loaded by `jess`.
|
|
10
|
+
|
|
11
|
+
## Sandboxed execution
|
|
12
|
+
|
|
13
|
+
`plugin-js` does **not** run untrusted module code in your Node process. Before
|
|
14
|
+
executing anything, it checks for a usable **Deno** runtime (`deno --version`)
|
|
15
|
+
and runs the module in a Deno subprocess behind a permission broker:
|
|
16
|
+
|
|
17
|
+
- **read** is limited to `node_modules` (and an optional `jsReadRoot`),
|
|
18
|
+
- **net** is denied unless you opt in (`allowHttp`, optionally scoped to
|
|
19
|
+
`allowNetHosts`),
|
|
20
|
+
- **env / write / run / ffi / sys** are denied outright.
|
|
21
|
+
|
|
22
|
+
Values cross the boundary through a small typed bridge (dimensions, colors,
|
|
23
|
+
quoted strings, lists, detached rules, …). Built-in `@jesscss/fns` modules are
|
|
24
|
+
trusted and imported directly, without the worker. If no Deno binary is found,
|
|
25
|
+
the plugin fails with a clear message instead of falling back to unsandboxed
|
|
26
|
+
execution.
|
|
27
|
+
|
|
28
|
+
## Why it exists — the convergence angle
|
|
29
|
+
|
|
30
|
+
One of the four tools [Jess](https://github.com/jesscss/jess) aims to converge is
|
|
31
|
+
**CSS-in-JS**: running real JavaScript inside stylesheets so styles can be
|
|
32
|
+
dynamic without leaving CSS files. This plugin — together with
|
|
33
|
+
[`@jesscss/plugin-node-modules`](../jess-plugin-node-modules), which resolves the
|
|
34
|
+
packages — is a seed of that story.
|
|
35
|
+
|
|
36
|
+
That convergence is **roadmap — being proven through the alpha, not claimed as
|
|
37
|
+
done.** Legacy Less `@plugin` is supported for compatibility but deprecated in
|
|
38
|
+
favor of `@-from` / `@-use`.
|
|
39
|
+
|
|
40
|
+
## Status
|
|
41
|
+
|
|
42
|
+
**Alpha.** Part of Jess, the ground-up rewrite of Less.js (Jess *is* Less.js
|
|
43
|
+
v5). Requires a Deno runtime for script execution. The programmatic
|
|
44
|
+
plugin/compiler API is **not yet stabilized** — the `jess` / `lessc` CLIs are the
|
|
45
|
+
public surface for the alpha. Watch the [docs site](https://jesscss.github.io/)
|
|
46
|
+
for the API once it settles.
|
|
47
|
+
|
|
48
|
+
- Project overview & positioning: <https://github.com/jesscss/jess#readme>
|
|
49
|
+
- Docs: <https://jesscss.github.io/> (currently pre-alpha content)
|
|
50
|
+
- Issues: <https://github.com/jesscss/jess/issues>
|
|
51
|
+
- License: MIT
|
package/lib/index.cjs
CHANGED
|
@@ -144,6 +144,33 @@ const RUNTIME_MISSING_MESSAGE = [
|
|
|
144
144
|
const BOOT_TIMEOUT_MS = 8e3;
|
|
145
145
|
const REQUEST_TIMEOUT_MS = 1e4;
|
|
146
146
|
const IDLE_SHUTDOWN_MS = 5e3;
|
|
147
|
+
/**
|
|
148
|
+
* Environment variables that inject a Node.js debugger/inspector bootloader
|
|
149
|
+
* into child processes (VS Code / Cursor "Auto Attach", `node --inspect`, etc.).
|
|
150
|
+
*
|
|
151
|
+
* These must never leak into the sandboxed Deno worker: the injected bootloader
|
|
152
|
+
* tries to read the environment, the Jess Deno sandbox denies `env` permission,
|
|
153
|
+
* and the worker never signals ready — producing a spurious
|
|
154
|
+
* "Timed out waiting for Deno worker startup" failure. Deno does not use any of
|
|
155
|
+
* these vars, so stripping them is safe.
|
|
156
|
+
*/
|
|
157
|
+
const DEBUG_ENV_KEY_RE = /^(NODE_OPTIONS|NODE_INSPECT|VSCODE_INSPECTOR_OPTIONS)/i;
|
|
158
|
+
const DEBUG_ENV_VALUE_RE = /js-debug|bootloader/i;
|
|
159
|
+
/**
|
|
160
|
+
* Returns a copy of `env` with Node debugger/inspector-attach variables removed,
|
|
161
|
+
* so a spawned Deno subprocess starts regardless of the parent's debug env.
|
|
162
|
+
* The Deno permission sandbox is untouched; this only stops leaking the debugger
|
|
163
|
+
* into it.
|
|
164
|
+
*/
|
|
165
|
+
const sanitizeSpawnEnv = (env = process.env) => {
|
|
166
|
+
const clean = {};
|
|
167
|
+
for (const [key, value] of Object.entries(env)) {
|
|
168
|
+
if (DEBUG_ENV_KEY_RE.test(key)) continue;
|
|
169
|
+
if (typeof value === "string" && DEBUG_ENV_VALUE_RE.test(value)) continue;
|
|
170
|
+
clean[key] = value;
|
|
171
|
+
}
|
|
172
|
+
return clean;
|
|
173
|
+
};
|
|
147
174
|
const isPathInside = (candidatePath, rootPath) => {
|
|
148
175
|
const rel = node_path.relative(rootPath, candidatePath);
|
|
149
176
|
return rel === "" || !rel.startsWith("..") && !node_path.isAbsolute(rel);
|
|
@@ -227,7 +254,10 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
227
254
|
this.idleTimer.unref?.();
|
|
228
255
|
}
|
|
229
256
|
ensureRuntimeAvailable() {
|
|
230
|
-
if ((0, node_child_process.spawnSync)(this.opts.denoCommand ?? "deno", ["--version"], {
|
|
257
|
+
if ((0, node_child_process.spawnSync)(this.opts.denoCommand ?? "deno", ["--version"], {
|
|
258
|
+
stdio: "ignore",
|
|
259
|
+
env: sanitizeSpawnEnv(process.env)
|
|
260
|
+
}).status !== 0) throw new Error(RUNTIME_MISSING_MESSAGE);
|
|
231
261
|
}
|
|
232
262
|
ensureRuntime() {
|
|
233
263
|
if (this.runtimeState.status === "ready") {
|
|
@@ -354,7 +384,7 @@ var JsPlugin = class JsPlugin extends _jesscss_core.AbstractPlugin {
|
|
|
354
384
|
"pipe"
|
|
355
385
|
],
|
|
356
386
|
env: {
|
|
357
|
-
...process.env,
|
|
387
|
+
...sanitizeSpawnEnv(process.env),
|
|
358
388
|
DENO_PERMISSION_BROKER_PATH: socketPath
|
|
359
389
|
}
|
|
360
390
|
});
|
|
@@ -587,3 +617,4 @@ exports.JESS_PLUGIN_JS_GLOBAL = JESS_PLUGIN_JS_GLOBAL;
|
|
|
587
617
|
exports.JsPlugin = JsPlugin;
|
|
588
618
|
exports.__toESM = __toESM;
|
|
589
619
|
exports.default = jsPlugin;
|
|
620
|
+
exports.sanitizeSpawnEnv = sanitizeSpawnEnv;
|
package/lib/index.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface JsPluginOptions extends JavaScriptSandboxConfig {
|
|
|
14
14
|
*/
|
|
15
15
|
runtimeApi?: 'module' | 'less';
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Returns a copy of `env` with Node debugger/inspector-attach variables removed,
|
|
19
|
+
* so a spawned Deno subprocess starts regardless of the parent's debug env.
|
|
20
|
+
* The Deno permission sandbox is untouched; this only stops leaking the debugger
|
|
21
|
+
* into it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const sanitizeSpawnEnv: (env?: NodeJS.ProcessEnv) => NodeJS.ProcessEnv;
|
|
17
24
|
export declare class JsPlugin extends AbstractPlugin {
|
|
18
25
|
opts: JsPluginOptions;
|
|
19
26
|
private static cleanupRegistered;
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACf,MAAM,eAAe,CAAC;AAQvB,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,eAAgB,SAAQ,uBAAuB;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAChC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,cAAc,EACf,MAAM,eAAe,CAAC;AAQvB,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,WAAW,eAAgB,SAAQ,uBAAuB;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;CAChC;AAmCD;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAC3B,MAAK,MAAM,CAAC,UAAwB,KACnC,MAAM,CAAC,UAYT,CAAC;AA0FF,qBAAa,QAAS,SAAQ,cAAc;IAoBvB,IAAI,EAAE,eAAe;IAnBxC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAS;IACzC,OAAO,CAAC,MAAM,CAAC,aAAa,CAAuB;IACnD,IAAI,SAAQ;IACZ,mBAAmB,WAAiC;IACpD,OAAO,CAAC,YAAY,CAAoC;IACxD,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,YAAY,CAAyB;IAC7C,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,MAAM,CAA6C;IAC3D,OAAO,CAAC,YAAY,CAAM;IAC1B,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,OAAO,CAIV;IAEL,OAAO,CAAC,SAAS,CAA6B;gBAE3B,IAAI,GAAE,eAAoB;IAM7C,OAAO;IAIP,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAkBrC,OAAO,CAAC,cAAc;IAOtB,OAAO,CAAC,oBAAoB;IAY5B,OAAO,CAAC,sBAAsB;IAW9B,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,mBAAmB;YA0Bb,WAAW;IA8CzB,OAAO,CAAC,WAAW;YAwFL,YAAY;IAW1B,OAAO,CAAC,cAAc;IAiCtB,OAAO,CAAC,gBAAgB;YAQV,UAAU;IAwBxB,OAAO,CAAC,QAAQ;IA0BhB,OAAO;IAMP,OAAO,CAAC,iBAAiB;IAgBnB,MAAM,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IA+CpE;;;;;OAKG;IACG,gBAAgB,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;KAAE,CAAC;CA6BnI;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,iCAAiC,CAAC;AAOpE,QAAA,MAAM,QAAQ,UAAY,eAAe,aAEtB,CAAC;AAEpB,eAAe,QAAQ,CAAC"}
|
package/lib/index.js
CHANGED
|
@@ -115,6 +115,33 @@ const RUNTIME_MISSING_MESSAGE = [
|
|
|
115
115
|
const BOOT_TIMEOUT_MS = 8e3;
|
|
116
116
|
const REQUEST_TIMEOUT_MS = 1e4;
|
|
117
117
|
const IDLE_SHUTDOWN_MS = 5e3;
|
|
118
|
+
/**
|
|
119
|
+
* Environment variables that inject a Node.js debugger/inspector bootloader
|
|
120
|
+
* into child processes (VS Code / Cursor "Auto Attach", `node --inspect`, etc.).
|
|
121
|
+
*
|
|
122
|
+
* These must never leak into the sandboxed Deno worker: the injected bootloader
|
|
123
|
+
* tries to read the environment, the Jess Deno sandbox denies `env` permission,
|
|
124
|
+
* and the worker never signals ready — producing a spurious
|
|
125
|
+
* "Timed out waiting for Deno worker startup" failure. Deno does not use any of
|
|
126
|
+
* these vars, so stripping them is safe.
|
|
127
|
+
*/
|
|
128
|
+
const DEBUG_ENV_KEY_RE = /^(NODE_OPTIONS|NODE_INSPECT|VSCODE_INSPECTOR_OPTIONS)/i;
|
|
129
|
+
const DEBUG_ENV_VALUE_RE = /js-debug|bootloader/i;
|
|
130
|
+
/**
|
|
131
|
+
* Returns a copy of `env` with Node debugger/inspector-attach variables removed,
|
|
132
|
+
* so a spawned Deno subprocess starts regardless of the parent's debug env.
|
|
133
|
+
* The Deno permission sandbox is untouched; this only stops leaking the debugger
|
|
134
|
+
* into it.
|
|
135
|
+
*/
|
|
136
|
+
const sanitizeSpawnEnv = (env = process.env) => {
|
|
137
|
+
const clean = {};
|
|
138
|
+
for (const [key, value] of Object.entries(env)) {
|
|
139
|
+
if (DEBUG_ENV_KEY_RE.test(key)) continue;
|
|
140
|
+
if (typeof value === "string" && DEBUG_ENV_VALUE_RE.test(value)) continue;
|
|
141
|
+
clean[key] = value;
|
|
142
|
+
}
|
|
143
|
+
return clean;
|
|
144
|
+
};
|
|
118
145
|
const isPathInside = (candidatePath, rootPath) => {
|
|
119
146
|
const rel = path.relative(rootPath, candidatePath);
|
|
120
147
|
return rel === "" || !rel.startsWith("..") && !path.isAbsolute(rel);
|
|
@@ -198,7 +225,10 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
198
225
|
this.idleTimer.unref?.();
|
|
199
226
|
}
|
|
200
227
|
ensureRuntimeAvailable() {
|
|
201
|
-
if (spawnSync(this.opts.denoCommand ?? "deno", ["--version"], {
|
|
228
|
+
if (spawnSync(this.opts.denoCommand ?? "deno", ["--version"], {
|
|
229
|
+
stdio: "ignore",
|
|
230
|
+
env: sanitizeSpawnEnv(process.env)
|
|
231
|
+
}).status !== 0) throw new Error(RUNTIME_MISSING_MESSAGE);
|
|
202
232
|
}
|
|
203
233
|
ensureRuntime() {
|
|
204
234
|
if (this.runtimeState.status === "ready") {
|
|
@@ -325,7 +355,7 @@ var JsPlugin = class JsPlugin extends AbstractPlugin {
|
|
|
325
355
|
"pipe"
|
|
326
356
|
],
|
|
327
357
|
env: {
|
|
328
|
-
...process.env,
|
|
358
|
+
...sanitizeSpawnEnv(process.env),
|
|
329
359
|
DENO_PERMISSION_BROKER_PATH: socketPath
|
|
330
360
|
}
|
|
331
361
|
});
|
|
@@ -554,4 +584,4 @@ const jsPlugin = ((opts) => {
|
|
|
554
584
|
return new JsPlugin(opts);
|
|
555
585
|
});
|
|
556
586
|
//#endregion
|
|
557
|
-
export { JESS_PLUGIN_JS_GLOBAL, JsPlugin, jsPlugin as default };
|
|
587
|
+
export { JESS_PLUGIN_JS_GLOBAL, JsPlugin, jsPlugin as default, sanitizeSpawnEnv };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jesscss/plugin-js",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.8",
|
|
4
4
|
"description": "Jess plugin for JavaScript/TypeScript module imports with Deno runtime checks",
|
|
5
5
|
"main": "lib/index.cjs",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"deno": "^2.6.8",
|
|
21
|
-
"@jesscss/core": "2.0.0-alpha.
|
|
21
|
+
"@jesscss/core": "2.0.0-alpha.8"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.0.0",
|