@jini-ai/platform 0.6.15-rc.2 → 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.
Files changed (56) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +4 -2
  3. package/dist/blob-storage.js +10 -9
  4. package/dist/child-environment.js +1 -1
  5. package/dist/command.js +4 -1
  6. package/dist/core/effective-port.d.ts +6 -0
  7. package/dist/core/effective-port.js +8 -0
  8. package/dist/download.js +25 -24
  9. package/dist/fetch-with-timeout.d.ts +26 -6
  10. package/dist/fetch-with-timeout.js +50 -10
  11. package/dist/fs/atomic-write.js +5 -2
  12. package/dist/fs/boot-identity.d.ts +0 -4
  13. package/dist/fs/boot-identity.js +9 -3
  14. package/dist/fs/directory-registry.js +2 -2
  15. package/dist/fs/directory-running-lock.js +9 -4
  16. package/dist/fs/directory-sync.js +2 -3
  17. package/dist/fs/directory-workspace.js +11 -14
  18. package/dist/fs/durable-json.js +22 -16
  19. package/dist/fs/errno.d.ts +9 -0
  20. package/dist/fs/errno.js +21 -0
  21. package/dist/fs/file-lock.js +17 -19
  22. package/dist/fs/guarded-reader.js +15 -9
  23. package/dist/fs/user-data-directories.js +5 -7
  24. package/dist/fs.js +2 -1
  25. package/dist/http/guarded/client.js +2 -1
  26. package/dist/http.js +2 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/mail/builtin-providers.js +4 -2
  30. package/dist/mail/feedback.js +1 -1
  31. package/dist/mail/prepare-sender-email.js +7 -1
  32. package/dist/mail/provider.js +14 -8
  33. package/dist/mail/rate-limit.js +3 -1
  34. package/dist/net/endpoint-policy.js +15 -7
  35. package/dist/object-store/local-fs.js +3 -1
  36. package/dist/process.js +10 -9
  37. package/dist/proxy-env.js +22 -14
  38. package/dist/secrets/credential-sets/provider-matches.js +14 -3
  39. package/dist/secrets/credential-sets/vault.meta.js +6 -2
  40. package/dist/secrets/credential-sets/vault.repo.memory.js +3 -5
  41. package/dist/secrets/credential-sets/vault.service.js +22 -17
  42. package/dist/secrets/credential-sets/vault.types.d.ts +6 -0
  43. package/dist/secrets/credential-sets/vault.types.js +7 -0
  44. package/dist/secrets/credential-token.js +9 -2
  45. package/dist/secrets/keyring.env.js +2 -4
  46. package/dist/shell.js +2 -1
  47. package/dist/terminal.js +4 -7
  48. package/dist/toolchain.js +4 -9
  49. package/dist/web/first-distinct.d.ts +11 -0
  50. package/dist/web/first-distinct.js +16 -0
  51. package/dist/web/html-document.js +35 -39
  52. package/dist/web/html-to-markdown.js +20 -9
  53. package/dist/web/web-page.js +28 -25
  54. package/dist/windows-system-tools.d.ts +15 -0
  55. package/dist/windows-system-tools.js +16 -0
  56. package/package.json +2 -2
@@ -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 seen = new Set();
149
- const links = [];
150
- let linksTruncated = false;
151
- for (const match of xml.matchAll(/<loc>\s*([^<\s]+)\s*<\/loc>/gi)) {
152
- let url;
153
- try {
154
- url = new URL(match[1].replace(/&amp;/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(/&amp;/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 || page.imagesTruncated || result.imagesTruncated || images.byUrl.size > MAX_IMAGES;
368
- const truncated = imagesTruncated || factsTruncated || page.title.length > MAX_RENDERED_TITLE || result.truncated
369
- || result.linksTruncated || page.dataTruncated || textTruncated;
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 = linksDropped || stylesheets.length < result.stylesheets.length || Object.keys(meta).length < Object.keys(result.meta).length
395
- || (result.description?.length ?? 0) > MAX_RENDERED_DESCRIPTION || (result.lang?.length ?? 0) > MAX_RENDERED_LANG;
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-rc.2",
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.15-rc.2"
209
+ "@jini-ai/core": "^0.6.13"
210
210
  },
211
211
  "publishConfig": {
212
212
  "access": "public",