@trim21/personal-pi-extensions 0.0.367 → 0.0.372
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/bwrap/core.ts +14 -3
- package/src/web/fetch.ts +16 -0
package/package.json
CHANGED
package/src/bwrap/core.ts
CHANGED
|
@@ -252,6 +252,12 @@ export function createBwrapBashOperations(
|
|
|
252
252
|
});
|
|
253
253
|
if (signal?.aborted) throw new Error("aborted");
|
|
254
254
|
|
|
255
|
+
// 干净环境:不继承父进程 env/PATH,由 bash -lc 从 /etc/profile 与用户 profile 重建
|
|
256
|
+
const home = process.env.HOME;
|
|
257
|
+
if (home === undefined) {
|
|
258
|
+
throw new Error("HOME is not set; refusing to run bash in a clean environment");
|
|
259
|
+
}
|
|
260
|
+
|
|
255
261
|
const seccompFd = resolved.network ? undefined : getSeccompFd();
|
|
256
262
|
const baseArgs = [
|
|
257
263
|
"--ro-bind",
|
|
@@ -266,8 +272,8 @@ export function createBwrapBashOperations(
|
|
|
266
272
|
const child = spawn(
|
|
267
273
|
findBwrap(resolved.bwrapPath),
|
|
268
274
|
seccompFd === undefined
|
|
269
|
-
? [...baseArgs, "--", "bash", "-
|
|
270
|
-
: [...baseArgs, "--seccomp", "3", "--", "bash", "-
|
|
275
|
+
? [...baseArgs, "--", "bash", "-lc", command]
|
|
276
|
+
: [...baseArgs, "--seccomp", "3", "--", "bash", "-lc", command],
|
|
271
277
|
{
|
|
272
278
|
cwd,
|
|
273
279
|
detached: true,
|
|
@@ -275,7 +281,12 @@ export function createBwrapBashOperations(
|
|
|
275
281
|
seccompFd === undefined
|
|
276
282
|
? ["ignore", "pipe", "pipe"]
|
|
277
283
|
: ["ignore", "pipe", "pipe", seccompFd],
|
|
278
|
-
env:
|
|
284
|
+
env: {
|
|
285
|
+
HOME: home,
|
|
286
|
+
SHELL: "/bin/bash",
|
|
287
|
+
TERM: "dumb",
|
|
288
|
+
LANG: "C.UTF-8",
|
|
289
|
+
},
|
|
279
290
|
},
|
|
280
291
|
);
|
|
281
292
|
|
package/src/web/fetch.ts
CHANGED
|
@@ -170,12 +170,28 @@ function classifyContentType(contentType: string): "html" | "text" | null {
|
|
|
170
170
|
interface ParsedDocument {
|
|
171
171
|
title: string | null;
|
|
172
172
|
body: { textContent: string | null } | null;
|
|
173
|
+
querySelectorAll(selector: string): readonly {
|
|
174
|
+
id: string | null;
|
|
175
|
+
removeAttribute(name: string): void;
|
|
176
|
+
}[];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* React 19 流式 SSR 把尚未 hydrate 的正文放在 <div hidden id="S:N"> 里暂存,
|
|
181
|
+
* 客户端接管后才移除 hidden。静态抓取时先解除,否则 readability 会把它当
|
|
182
|
+
* 隐藏内容丢弃,只留下 Suspense fallback(如 "Loading...")。
|
|
183
|
+
*/
|
|
184
|
+
function unshadowReactStreaming(document: ParsedDocument): void {
|
|
185
|
+
for (const el of document.querySelectorAll("[hidden]")) {
|
|
186
|
+
if (/^S:\d+$/.test(el.id ?? "")) el.removeAttribute("hidden");
|
|
187
|
+
}
|
|
173
188
|
}
|
|
174
189
|
|
|
175
190
|
/** 从 HTML 提取标题 + 正文 markdown(readability 主内容 → turndown) */
|
|
176
191
|
export function extractMarkdown(html: string, sourceUrl: string): FetchedPage {
|
|
177
192
|
const parsed = parseHTML(html) as { document: ParsedDocument };
|
|
178
193
|
const document = parsed.document;
|
|
194
|
+
unshadowReactStreaming(document);
|
|
179
195
|
// tsconfig 无 DOM lib;Readability 构造参数声明为 DOM Document,运行时只用到
|
|
180
196
|
// linkedom document 的兼容方法,cast 桥接即可
|
|
181
197
|
const article = new Readability(parsed.document).parse();
|