@jini-ai/platform 0.6.15-rc.1 → 0.6.15
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/CHANGELOG.md +26 -0
- package/README.md +5 -1
- package/dist/blob-storage.js +10 -9
- package/dist/child-environment.js +1 -1
- package/dist/command.js +4 -1
- package/dist/core/effective-port.d.ts +6 -0
- package/dist/core/effective-port.js +8 -0
- package/dist/download.js +25 -24
- package/dist/fetch-with-timeout.d.ts +44 -1
- package/dist/fetch-with-timeout.js +60 -1
- package/dist/fs/atomic-write.js +5 -2
- package/dist/fs/boot-identity.d.ts +0 -4
- package/dist/fs/boot-identity.js +9 -3
- package/dist/fs/directory-registry.js +2 -2
- package/dist/fs/directory-running-lock.js +9 -4
- package/dist/fs/directory-sync.js +2 -3
- package/dist/fs/directory-workspace.js +11 -14
- package/dist/fs/durable-json.js +22 -16
- package/dist/fs/errno.d.ts +9 -0
- package/dist/fs/errno.js +21 -0
- package/dist/fs/file-lock.js +17 -19
- package/dist/fs/guarded-reader.js +15 -9
- package/dist/fs/user-data-directories.js +5 -7
- package/dist/fs.js +2 -1
- package/dist/http/guarded/client.js +2 -1
- package/dist/http.js +2 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/mail/adapter-module.d.ts +18 -0
- package/dist/mail/adapter-module.js +13 -1
- package/dist/mail/builtin-providers.js +4 -2
- package/dist/mail/feedback.js +1 -1
- package/dist/mail/index.d.ts +1 -0
- package/dist/mail/index.js +1 -0
- package/dist/mail/prepare-sender-email.js +7 -1
- package/dist/mail/provider.js +18 -9
- package/dist/mail/rate-limit.js +3 -1
- package/dist/net/endpoint-policy.js +15 -7
- package/dist/object-store/local-fs.js +3 -1
- package/dist/process.js +10 -9
- package/dist/proxy-env.js +22 -14
- package/dist/secrets/credential-sets/provider-matches.js +14 -3
- package/dist/secrets/credential-sets/vault.meta.js +6 -2
- package/dist/secrets/credential-sets/vault.repo.memory.js +3 -5
- package/dist/secrets/credential-sets/vault.service.js +22 -17
- package/dist/secrets/credential-sets/vault.types.d.ts +6 -0
- package/dist/secrets/credential-sets/vault.types.js +7 -0
- package/dist/secrets/credential-token.js +9 -2
- package/dist/secrets/keyring.env.js +2 -4
- package/dist/shell.js +2 -1
- package/dist/terminal.js +4 -7
- package/dist/toolchain.js +4 -9
- package/dist/web/first-distinct.d.ts +11 -0
- package/dist/web/first-distinct.js +16 -0
- package/dist/web/html-document.js +35 -39
- package/dist/web/html-to-markdown.js +20 -9
- package/dist/web/web-page.js +28 -25
- package/dist/windows-system-tools.d.ts +15 -0
- package/dist/windows-system-tools.js +16 -0
- package/package.json +2 -2
|
@@ -12,18 +12,25 @@ const MAX_DEPTH = 300;
|
|
|
12
12
|
function isElement(node) {
|
|
13
13
|
return "tagName" in node;
|
|
14
14
|
}
|
|
15
|
+
/** A node's children for {@link plainText}; skipped elements and leaves contribute none. */
|
|
16
|
+
function scannableChildren(node) {
|
|
17
|
+
if (!("childNodes" in node) || (isElement(node) && SKIPPED.has(node.tagName)))
|
|
18
|
+
return [];
|
|
19
|
+
return node.childNodes;
|
|
20
|
+
}
|
|
15
21
|
/** Iterative so a degraded, very deep subtree cannot overflow the stack either. O(subtree nodes). */
|
|
16
22
|
function plainText(root) {
|
|
17
23
|
const pending = [root];
|
|
18
24
|
const parts = [];
|
|
19
25
|
while (pending.length) {
|
|
20
26
|
const node = pending.pop();
|
|
21
|
-
if (node.nodeName === "#text" && "value" in node)
|
|
27
|
+
if (node.nodeName === "#text" && "value" in node) {
|
|
22
28
|
parts.push(node.value);
|
|
23
|
-
|
|
24
|
-
for (let i = node.childNodes.length - 1; i >= 0; i--)
|
|
25
|
-
pending.push(node.childNodes[i]);
|
|
29
|
+
continue;
|
|
26
30
|
}
|
|
31
|
+
const children = scannableChildren(node);
|
|
32
|
+
for (let i = children.length - 1; i >= 0; i--)
|
|
33
|
+
pending.push(children[i]);
|
|
27
34
|
}
|
|
28
35
|
return parts.join("").replace(/\s+/g, " ");
|
|
29
36
|
}
|
|
@@ -112,9 +119,11 @@ function takeEdgeWhitespace({ node, last }, _options = {}) {
|
|
|
112
119
|
const edge = edgeText({ node, last });
|
|
113
120
|
if (!edge)
|
|
114
121
|
return "";
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
122
|
+
const value = edge.value;
|
|
123
|
+
// trimStart/trimEnd strip exactly the characters `\s` matches.
|
|
124
|
+
const kept = last ? value.trimEnd() : value.trimStart();
|
|
125
|
+
edge.value = kept;
|
|
126
|
+
return last ? value.slice(kept.length) : value.slice(0, value.length - kept.length);
|
|
118
127
|
}
|
|
119
128
|
/** The first/last leaf of the subtree when it is a text node. */
|
|
120
129
|
function edgeText({ node, last }, _options = {}) {
|
|
@@ -141,9 +150,11 @@ function hastText(root) {
|
|
|
141
150
|
while (pending.length) {
|
|
142
151
|
const node = pending.pop();
|
|
143
152
|
// HAST text nodes always carry a value.
|
|
144
|
-
if (node.type === "text")
|
|
153
|
+
if (node.type === "text") {
|
|
145
154
|
parts.push(node.value);
|
|
146
|
-
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (node.children)
|
|
147
158
|
for (let i = node.children.length - 1; i >= 0; i--)
|
|
148
159
|
pending.push(node.children[i]);
|
|
149
160
|
}
|
package/dist/web/web-page.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { boundHtml } from "./html-resource.js";
|
|
2
|
+
import { firstDistinct } from "./first-distinct.js";
|
|
2
3
|
import { ToolInputError } from "@jini-ai/core";
|
|
3
4
|
import { EgressRefusedError } from "../http/guarded/errors.js";
|
|
4
5
|
import { htmlToText, readHtmlDocument, stripActiveHtml, MAX_LINKS, MAX_IMAGES } from "./html-document.js";
|
|
@@ -145,28 +146,25 @@ const EMPTY_FACTS = { links: [], linksTruncated: false, images: [], imagesTrunca
|
|
|
145
146
|
/** A sitemap's `<loc>` entries become links so an importer can enumerate pages from one call. */
|
|
146
147
|
function sitemapFacts(xml, pageUrl) {
|
|
147
148
|
const host = new URL(pageUrl).hostname.replace(/^www\./, "");
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
url = new URL(match[1].replace(/&/g, "&"), pageUrl);
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
if ((url.protocol !== "http:" && url.protocol !== "https:") || seen.has(url.href))
|
|
160
|
-
continue;
|
|
161
|
-
seen.add(url.href);
|
|
162
|
-
if (links.length === MAX_LINKS) {
|
|
163
|
-
linksTruncated = true;
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
links.push({ href: url.href, text: "", internal: url.hostname.replace(/^www\./, "") === host });
|
|
167
|
-
}
|
|
149
|
+
const { picked, truncated: linksTruncated } = firstDistinct({
|
|
150
|
+
items: [...xml.matchAll(/<loc>\s*([^<\s]+)\s*<\/loc>/gi)],
|
|
151
|
+
max: MAX_LINKS,
|
|
152
|
+
keyOf: (match) => sitemapHref(match[1], pageUrl),
|
|
153
|
+
});
|
|
154
|
+
const links = picked.map(([href]) => ({ href, text: "", internal: new URL(href).hostname.replace(/^www\./, "") === host }));
|
|
168
155
|
return { ...EMPTY_FACTS, links, linksTruncated };
|
|
169
156
|
}
|
|
157
|
+
/** The absolute http(s) href of one `<loc>` value, or undefined when it is unparsable or another scheme. */
|
|
158
|
+
function sitemapHref(loc, pageUrl) {
|
|
159
|
+
let url;
|
|
160
|
+
try {
|
|
161
|
+
url = new URL(loc.replace(/&/g, "&"), pageUrl);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
return url.protocol === "http:" || url.protocol === "https:" ? url.href : undefined;
|
|
167
|
+
}
|
|
170
168
|
function render(format, body, isHtml, pageUrl, ports) {
|
|
171
169
|
if (!isHtml || format === "raw")
|
|
172
170
|
return body;
|
|
@@ -364,9 +362,9 @@ function projectRendered({ input, ports, url, page }) {
|
|
|
364
362
|
}
|
|
365
363
|
/** Any clipped or dropped fact, image, data or text marks the whole rendered result truncated. */
|
|
366
364
|
function renderedFlags({ page, result, images, factsTruncated, textTruncated }) {
|
|
367
|
-
const imagesTruncated = images.truncated
|
|
368
|
-
const truncated = imagesTruncated
|
|
369
|
-
|
|
365
|
+
const imagesTruncated = [images.truncated, page.imagesTruncated, result.imagesTruncated, images.byUrl.size > MAX_IMAGES].some(Boolean);
|
|
366
|
+
const truncated = [imagesTruncated, factsTruncated, page.title.length > MAX_RENDERED_TITLE, result.truncated,
|
|
367
|
+
result.linksTruncated, page.dataTruncated, textTruncated].some(Boolean);
|
|
370
368
|
return { imagesTruncated, truncated };
|
|
371
369
|
}
|
|
372
370
|
/** Browser image facts come first, so their alt text wins over the parsed DOM's for the same src. */
|
|
@@ -391,8 +389,13 @@ function boundRenderedFacts({ result }, _optional = {}) {
|
|
|
391
389
|
const stylesheets = result.stylesheets.filter(href => href.length <= MAX_URL_LENGTH);
|
|
392
390
|
const meta = Object.fromEntries(Object.entries(result.meta).filter(([key]) => key.length <= MAX_RENDERED_META_KEY));
|
|
393
391
|
const linksDropped = links.length < result.links.length;
|
|
394
|
-
const truncated =
|
|
395
|
-
|
|
392
|
+
const truncated = [
|
|
393
|
+
linksDropped,
|
|
394
|
+
stylesheets.length < result.stylesheets.length,
|
|
395
|
+
Object.keys(meta).length < Object.keys(result.meta).length,
|
|
396
|
+
(result.description?.length ?? 0) > MAX_RENDERED_DESCRIPTION,
|
|
397
|
+
(result.lang?.length ?? 0) > MAX_RENDERED_LANG,
|
|
398
|
+
].some(Boolean);
|
|
396
399
|
return { links, stylesheets, meta, linksDropped, truncated };
|
|
397
400
|
}
|
|
398
401
|
/** `none` empties content; `summary` and text format use the browser's visible text instead of the projection. */
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Absolute path of a Windows system tool under `%SystemRoot%\System32`. A bare name such as
|
|
3
|
+
* `reg.exe` is resolved by the child-process search, which on Windows consults the current
|
|
4
|
+
* directory before PATH, so a same-named file in a project folder could run instead of the OS tool.
|
|
5
|
+
* Falls back to `C:\Windows` when the environment does not name the system root.
|
|
6
|
+
* @complexity O(1).
|
|
7
|
+
*/
|
|
8
|
+
export declare function windowsSystemTool({ relativePath }: {
|
|
9
|
+
relativePath: readonly string[];
|
|
10
|
+
}, { env }?: {
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
}): string;
|
|
13
|
+
/** Windows PowerShell 5.1, which ships with every supported Windows release. */
|
|
14
|
+
export declare function windowsPowerShell(): string;
|
|
15
|
+
//# sourceMappingURL=windows-system-tools.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { win32 } from "node:path";
|
|
2
|
+
/**
|
|
3
|
+
* Absolute path of a Windows system tool under `%SystemRoot%\System32`. A bare name such as
|
|
4
|
+
* `reg.exe` is resolved by the child-process search, which on Windows consults the current
|
|
5
|
+
* directory before PATH, so a same-named file in a project folder could run instead of the OS tool.
|
|
6
|
+
* Falls back to `C:\Windows` when the environment does not name the system root.
|
|
7
|
+
* @complexity O(1).
|
|
8
|
+
*/
|
|
9
|
+
export function windowsSystemTool({ relativePath }, { env = process.env } = {}) {
|
|
10
|
+
return win32.join(env.SystemRoot ?? env.windir ?? "C:\\Windows", "System32", ...relativePath);
|
|
11
|
+
}
|
|
12
|
+
/** Windows PowerShell 5.1, which ships with every supported Windows release. */
|
|
13
|
+
export function windowsPowerShell() {
|
|
14
|
+
return windowsSystemTool({ relativePath: ["WindowsPowerShell", "v1.0", "powershell.exe"] });
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=windows-system-tools.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jini-ai/platform",
|
|
3
|
-
"version": "0.6.15
|
|
3
|
+
"version": "0.6.15",
|
|
4
4
|
"description": "Generic OS/platform primitives: process exec and lifecycle, filesystem containment, HTTP readiness polling, toolchain discovery, blob storage, AWS signing, and an SSRF-safe asset cache.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -206,7 +206,7 @@
|
|
|
206
206
|
"!dist/**/*.map"
|
|
207
207
|
],
|
|
208
208
|
"dependencies": {
|
|
209
|
-
"@jini-ai/core": "^0.6.
|
|
209
|
+
"@jini-ai/core": "^0.6.13"
|
|
210
210
|
},
|
|
211
211
|
"publishConfig": {
|
|
212
212
|
"access": "public",
|