@vibe-x/dsh-html-workbench 0.2.0 → 0.3.1
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 +16 -2
- package/assets/workbench.html +318 -3
- package/dsh.plugin.json +1 -1
- package/lib/client.js +514 -7
- package/package.json +1 -1
- package/scripts/workbench.py +1091 -37
- package/src/client.js +480 -6
- package/src/host.js +586 -41
- package/src/index.js +74 -5
package/src/index.js
CHANGED
|
@@ -8,12 +8,76 @@
|
|
|
8
8
|
* resolved relative to THIS module (`import.meta.url`) — never hard-coded to a
|
|
9
9
|
* specific machine — and handed to the shared body as `config.script`.
|
|
10
10
|
*/
|
|
11
|
-
import { readFileSync } from 'node:fs'
|
|
12
|
-
import {
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
12
|
+
import { tmpdir } from 'node:os'
|
|
13
|
+
import { dirname, join, resolve } from 'node:path'
|
|
13
14
|
import { fileURLToPath } from 'node:url'
|
|
14
15
|
|
|
15
16
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
16
17
|
const scriptPath = resolve(here, '..', 'scripts', 'workbench.py')
|
|
18
|
+
// The panel shows this next to the diagnostics so a pasted report says WHICH
|
|
19
|
+
// build produced it — without it, every bug report needs a follow-up question.
|
|
20
|
+
const version = JSON.parse(readFileSync(resolve(here, '..', 'package.json'), 'utf8')).version
|
|
21
|
+
|
|
22
|
+
// Must match RUNTIME_DIR_NAME in scripts/workbench.py, so the host's first guess
|
|
23
|
+
// and the service's own in-process fallback land in the SAME folder instead of
|
|
24
|
+
// scattering two differently named directories through the user's workspace.
|
|
25
|
+
const RUNTIME_DIR_NAME = '.html-workbench'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Whether this process can really create files in `dir` (mkdir + write + delete).
|
|
29
|
+
*
|
|
30
|
+
* A writable-looking DACL proves nothing: DSH runs the Python service as a
|
|
31
|
+
* sandboxed child whose restricted token may write only the session workspace and
|
|
32
|
+
* a private temp directory it hands the child through TEMP/TMP — never the
|
|
33
|
+
* ambient %TEMP% root the parent sees. Probing by an actual create is the only
|
|
34
|
+
* test that reflects what a child can do, and the probe must fail fast (see
|
|
35
|
+
* `make_temp_file` in workbench.py for why `tempfile.mkstemp` is unusable here).
|
|
36
|
+
*
|
|
37
|
+
* A successful probe leaves the directory behind, so it is marked ignored right
|
|
38
|
+
* away: the runtime root normally sits in the user's own repository, and probing
|
|
39
|
+
* must not be what dirties their `git status` (see `self_ignore` in workbench.py,
|
|
40
|
+
* which does the same for the directory the service settles on).
|
|
41
|
+
*/
|
|
42
|
+
const probeWritableDir = (dir) => {
|
|
43
|
+
try {
|
|
44
|
+
mkdirSync(dir, { recursive: true })
|
|
45
|
+
const probe = join(dir, '.wb-write-probe-' + process.pid)
|
|
46
|
+
writeFileSync(probe, '')
|
|
47
|
+
rmSync(probe, { force: true })
|
|
48
|
+
if (!existsSync(join(dir, '.gitignore'))) {
|
|
49
|
+
writeFileSync(join(dir, '.gitignore'), '# Created by html-workbench: disposable logs and cache.\n*\n')
|
|
50
|
+
}
|
|
51
|
+
return true
|
|
52
|
+
} catch (e) {
|
|
53
|
+
return false
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Choose the runtime directory to ASK the service for.
|
|
59
|
+
*
|
|
60
|
+
* The workspace comes first: it is the one tree the sandbox reliably grants and it
|
|
61
|
+
* keeps the re-downloadable GrapesJS cache across restarts. The historical temp
|
|
62
|
+
* location stays as a fallback for deployments with no writable cwd.
|
|
63
|
+
*
|
|
64
|
+
* This is a request, not a guarantee — the probe runs with the parent's rights,
|
|
65
|
+
* which are wider than the child's. The service re-probes in-process, falls back
|
|
66
|
+
* on its own, and reports the directories it really used, so a wrong guess here
|
|
67
|
+
* costs a different folder, never a failed start.
|
|
68
|
+
*/
|
|
69
|
+
const resolveRuntimeDir = () => {
|
|
70
|
+
const candidates = [
|
|
71
|
+
process.cwd() ? join(process.cwd(), RUNTIME_DIR_NAME) : null,
|
|
72
|
+
join(tmpdir(), RUNTIME_DIR_NAME),
|
|
73
|
+
]
|
|
74
|
+
for (const candidate of candidates) {
|
|
75
|
+
if (candidate && probeWritableDir(candidate)) return candidate
|
|
76
|
+
}
|
|
77
|
+
return candidates[0] || join(tmpdir(), RUNTIME_DIR_NAME)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const runtimeDir = resolveRuntimeDir()
|
|
17
81
|
|
|
18
82
|
// The body is a `return { ... }` statement; wrap it in a function and call it.
|
|
19
83
|
// eslint-disable-next-line no-new-func
|
|
@@ -22,6 +86,11 @@ const plugin = makePlugin()
|
|
|
22
86
|
|
|
23
87
|
export const name = 'html-workbench'
|
|
24
88
|
export const inject = plugin.inject ?? []
|
|
25
|
-
// Inject
|
|
26
|
-
//
|
|
27
|
-
export const apply = (ctx, config) => plugin.apply(ctx, {
|
|
89
|
+
// Inject paths resolved by Node rather than assuming POSIX separators. A
|
|
90
|
+
// deployment-provided config may still override every value.
|
|
91
|
+
export const apply = (ctx, config) => plugin.apply(ctx, {
|
|
92
|
+
script: scriptPath,
|
|
93
|
+
runtimeDir,
|
|
94
|
+
version,
|
|
95
|
+
...(config || {}),
|
|
96
|
+
})
|