rootless-config 1.7.3 → 1.8.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/package.json +3 -2
- package/src/cli/commands/activate.js +8 -3
- package/src/index.js +2 -1
- package/src/serve/index.js +74 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rootless-config",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "Store project config files outside the project root, auto-deploy them where tools expect them.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
},
|
|
9
9
|
"main": "./src/index.js",
|
|
10
10
|
"exports": {
|
|
11
|
-
".": "./src/index.js"
|
|
11
|
+
".": "./src/index.js",
|
|
12
|
+
"./serve": "./src/serve/index.js"
|
|
12
13
|
},
|
|
13
14
|
"files": [
|
|
14
15
|
"bin",
|
|
@@ -142,10 +142,15 @@ export default {
|
|
|
142
142
|
return
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
-
// Если stdout пайпится (Invoke-Expression) — выводим
|
|
146
|
-
//
|
|
145
|
+
// Если stdout пайпится (Invoke-Expression) — выводим одну строку PS,
|
|
146
|
+
// которая декодирует base64 и исполняет весь блок целиком.
|
|
147
|
+
// Это обходит проблему PS-пайпа (строки идут по одной → незакрытые блоки).
|
|
148
|
+
// Правильный вызов: rootless activate | Invoke-Expression
|
|
147
149
|
if (!process.stdout.isTTY) {
|
|
148
|
-
|
|
150
|
+
const encoded = Buffer.from(HOOK_BODY, 'utf8').toString('base64')
|
|
151
|
+
process.stdout.write(
|
|
152
|
+
`[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${encoded}')) | Invoke-Expression\n`
|
|
153
|
+
)
|
|
149
154
|
} else {
|
|
150
155
|
logger.info('')
|
|
151
156
|
logger.info('To activate the CURRENT session, run:')
|
package/src/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { createWatcher } from './watch/watcher.js'
|
|
|
5
5
|
import { createDirtySet } from './watch/dirtySet.js'
|
|
6
6
|
import { runIncrementalRegeneration } from './watch/incrementalRegeneration.js'
|
|
7
7
|
import { resolveContainerPath } from './core/pathResolver.js'
|
|
8
|
+
import { resolveStaticFile, getServeDirs } from './serve/index.js'
|
|
8
9
|
|
|
9
10
|
async function prepare(options = {}) {
|
|
10
11
|
return preparePipeline(options)
|
|
@@ -36,4 +37,4 @@ async function watch(options = {}) {
|
|
|
36
37
|
}
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
export { prepare, watch, clean }
|
|
40
|
+
export { prepare, watch, clean, resolveStaticFile, getServeDirs }
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*-------- Public serve API — for use in Tandem Sites and other dev servers --------*/
|
|
2
|
+
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import { stat, readFile } from 'node:fs/promises'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Resolves a URL path to a real file on disk.
|
|
8
|
+
*
|
|
9
|
+
* Search order (first match wins):
|
|
10
|
+
* [1] projectRoot — real files/folders in project root
|
|
11
|
+
* [2] .root/assets/ — files migrated to rootless container
|
|
12
|
+
* [3] .root/env/ — .env files in rootless container
|
|
13
|
+
*
|
|
14
|
+
* Also tries index.html / index.htm for directory requests.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} requestPath — e.g. '/viewer/app/code/app.js' or '/'
|
|
17
|
+
* @param {string} projectRoot — absolute path to the project root
|
|
18
|
+
* @returns {Promise<string|null>} absolute path to the file, or null if not found
|
|
19
|
+
*/
|
|
20
|
+
async function resolveStaticFile(requestPath, projectRoot) {
|
|
21
|
+
const containerPath = path.join(projectRoot, '.root')
|
|
22
|
+
const assetsDir = path.join(containerPath, 'assets')
|
|
23
|
+
const envDir = path.join(containerPath, 'env')
|
|
24
|
+
const searchDirs = [projectRoot, assetsDir, envDir]
|
|
25
|
+
|
|
26
|
+
const rel = decodeURIComponent(requestPath).replace(/^\//, '') || ''
|
|
27
|
+
|
|
28
|
+
for (const dir of searchDirs) {
|
|
29
|
+
// Block access to .root internals when searching from projectRoot
|
|
30
|
+
if (dir === projectRoot && rel.startsWith('.root')) continue
|
|
31
|
+
|
|
32
|
+
const candidates = rel === ''
|
|
33
|
+
? [
|
|
34
|
+
path.join(dir, 'index.html'),
|
|
35
|
+
path.join(dir, 'index.htm'),
|
|
36
|
+
]
|
|
37
|
+
: [
|
|
38
|
+
path.join(dir, rel),
|
|
39
|
+
path.join(dir, rel, 'index.html'),
|
|
40
|
+
path.join(dir, rel, 'index.htm'),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
for (const candidate of candidates) {
|
|
44
|
+
try {
|
|
45
|
+
if ((await stat(candidate)).isFile()) return candidate
|
|
46
|
+
} catch {
|
|
47
|
+
// not found, try next
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns the ordered list of directories that rootless serves from.
|
|
57
|
+
* Useful for configuring a static server manually.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} projectRoot
|
|
60
|
+
* @returns {{ projectRoot: string, assetsDir: string, envDir: string, searchDirs: string[] }}
|
|
61
|
+
*/
|
|
62
|
+
function getServeDirs(projectRoot) {
|
|
63
|
+
const containerPath = path.join(projectRoot, '.root')
|
|
64
|
+
const assetsDir = path.join(containerPath, 'assets')
|
|
65
|
+
const envDir = path.join(containerPath, 'env')
|
|
66
|
+
return {
|
|
67
|
+
projectRoot,
|
|
68
|
+
assetsDir,
|
|
69
|
+
envDir,
|
|
70
|
+
searchDirs: [projectRoot, assetsDir, envDir],
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export { resolveStaticFile, getServeDirs }
|