@arnilo/prism-tools 0.0.0-stage → 0.13.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/CHANGELOG.md +418 -0
- package/LICENSE +21 -0
- package/README.md +44 -2
- package/browser/README.md +98 -0
- package/browser/skills/browser-automation/SKILL.md +14 -0
- package/browser/src/actions/cdp.ts +131 -0
- package/browser/src/actions/dialog.ts +25 -0
- package/browser/src/actions/download_release.ts +22 -0
- package/browser/src/actions/index.ts +37 -0
- package/browser/src/actions/locator.ts +70 -0
- package/browser/src/actions/navigate.ts +23 -0
- package/browser/src/actions/screenshot.ts +27 -0
- package/browser/src/actions/scroll.ts +24 -0
- package/browser/src/actions/select_page.ts +21 -0
- package/browser/src/actions/types.ts +114 -0
- package/browser/src/actions/upload.ts +44 -0
- package/browser/src/actions/wait.ts +45 -0
- package/browser/src/browser.ts +197 -0
- package/browser/src/cdp.ts +178 -0
- package/browser/src/checkpoint.ts +189 -0
- package/browser/src/config.ts +72 -0
- package/browser/src/downloads.ts +253 -0
- package/browser/src/errors.ts +31 -0
- package/browser/src/evaluate.ts +101 -0
- package/browser/src/index.ts +129 -0
- package/browser/src/limits.ts +271 -0
- package/browser/src/manager.ts +730 -0
- package/browser/src/network.ts +263 -0
- package/browser/src/observe.ts +178 -0
- package/browser/src/policy.ts +133 -0
- package/browser/src/screenshot.ts +107 -0
- package/browser/src/shared-sandbox.ts +53 -0
- package/browser/src/snapshot.ts +99 -0
- package/browser/src/targets.ts +165 -0
- package/browser/src/tools.ts +480 -0
- package/browser/src/types.ts +316 -0
- package/browser/src/uploads.ts +174 -0
- package/coding/README.md +337 -0
- package/coding/src/agent/acp-operations.ts +146 -0
- package/coding/src/agent/artifacts.ts +38 -0
- package/coding/src/agent/ask-user-decision.ts +623 -0
- package/coding/src/agent/atomic-write.ts +23 -0
- package/coding/src/agent/bounded-file.ts +21 -0
- package/coding/src/agent/checks.ts +301 -0
- package/coding/src/agent/coding-checkpoint.ts +828 -0
- package/coding/src/agent/delete.ts +237 -0
- package/coding/src/agent/diagnostics-tool.ts +163 -0
- package/coding/src/agent/diagnostics.ts +262 -0
- package/coding/src/agent/edit-diff.ts +382 -0
- package/coding/src/agent/edit.ts +322 -0
- package/coding/src/agent/effects.ts +102 -0
- package/coding/src/agent/env.ts +28 -0
- package/coding/src/agent/execution-policy.ts +89 -0
- package/coding/src/agent/file-mutation-queue.ts +72 -0
- package/coding/src/agent/forge/github.ts +603 -0
- package/coding/src/agent/forge/index.ts +16 -0
- package/coding/src/agent/forge/types.ts +185 -0
- package/coding/src/agent/git-aware-repository.ts +305 -0
- package/coding/src/agent/git-exec.ts +326 -0
- package/coding/src/agent/git-status.ts +177 -0
- package/coding/src/agent/git-tools.ts +360 -0
- package/coding/src/agent/git.ts +1074 -0
- package/coding/src/agent/glob-match.ts +146 -0
- package/coding/src/agent/glob.ts +182 -0
- package/coding/src/agent/goal-verify.ts +385 -0
- package/coding/src/agent/grep-worker.ts +74 -0
- package/coding/src/agent/grep.ts +459 -0
- package/coding/src/agent/identity.ts +48 -0
- package/coding/src/agent/index.ts +676 -0
- package/coding/src/agent/language/client.ts +429 -0
- package/coding/src/agent/language/framing.ts +190 -0
- package/coding/src/agent/language/index.ts +23 -0
- package/coding/src/agent/language/intelligence.ts +682 -0
- package/coding/src/agent/language/types.ts +187 -0
- package/coding/src/agent/lifecycle-events.ts +121 -0
- package/coding/src/agent/lifecycle.ts +166 -0
- package/coding/src/agent/limits.ts +214 -0
- package/coding/src/agent/move.ts +178 -0
- package/coding/src/agent/mutation-path.ts +52 -0
- package/coding/src/agent/output-accumulator.ts +304 -0
- package/coding/src/agent/path-utils.ts +120 -0
- package/coding/src/agent/process/index.ts +58 -0
- package/coding/src/agent/process/recovery.ts +508 -0
- package/coding/src/agent/process/sessions-host.ts +222 -0
- package/coding/src/agent/process/sessions-monitor.ts +141 -0
- package/coding/src/agent/process/sessions-recovery.ts +241 -0
- package/coding/src/agent/process/sessions-spawn.ts +613 -0
- package/coding/src/agent/process/sessions-teardown.ts +281 -0
- package/coding/src/agent/process/sessions.ts +30 -0
- package/coding/src/agent/process/types.ts +358 -0
- package/coding/src/agent/read-path-set.ts +126 -0
- package/coding/src/agent/read.ts +713 -0
- package/coding/src/agent/repository/glob.ts +147 -0
- package/coding/src/agent/repository/indexed-search.ts +480 -0
- package/coding/src/agent/repository/list.ts +131 -0
- package/coding/src/agent/repository/operations.ts +22 -0
- package/coding/src/agent/repository/path.ts +98 -0
- package/coding/src/agent/repository/search.ts +277 -0
- package/coding/src/agent/repository/types.ts +243 -0
- package/coding/src/agent/repository/walk.ts +126 -0
- package/coding/src/agent/repository.ts +12 -0
- package/coding/src/agent/shell-background.ts +264 -0
- package/coding/src/agent/shell-output.ts +75 -0
- package/coding/src/agent/shell.ts +526 -0
- package/coding/src/agent/todo.ts +399 -0
- package/coding/src/agent/truncate.ts +251 -0
- package/coding/src/agent/write.ts +170 -0
- package/coding/src/ask-user-host.ts +48 -0
- package/coding/src/config.ts +278 -0
- package/coding/src/hard-deny.ts +97 -0
- package/coding/src/index.ts +318 -0
- package/coding/src/principal-guard.ts +84 -0
- package/coding/src/sandbox.ts +92 -0
- package/coding/src/security/approval.ts +144 -0
- package/coding/src/security/command-rules.ts +57 -0
- package/coding/src/security/docker-cli.ts +222 -0
- package/coding/src/security/docker-sandbox.ts +1205 -0
- package/coding/src/security/e2b-sandbox.ts +853 -0
- package/coding/src/security/egress/dns-pin.ts +88 -0
- package/coding/src/security/egress/index.ts +32 -0
- package/coding/src/security/egress/limits.ts +57 -0
- package/coding/src/security/egress/policy.ts +137 -0
- package/coding/src/security/egress/proxy.ts +599 -0
- package/coding/src/security/egress/types.ts +30 -0
- package/coding/src/security/index.ts +199 -0
- package/coding/src/security/native-sandbox.ts +639 -0
- package/coding/src/security/path-containment.ts +55 -0
- package/coding/src/security/sandbox-coding-operations.ts +392 -0
- package/coding/src/security/sandbox-fs-operations.ts +644 -0
- package/coding/src/security/sandbox-limits.ts +147 -0
- package/coding/src/security/sandbox-tar.ts +308 -0
- package/coding/src/security/sandbox.ts +179 -0
- package/coding/src/security/semaphore.ts +55 -0
- package/coding/src/targets.ts +110 -0
- package/coding/src/workspace/diff.ts +78 -0
- package/coding/src/workspace/errors.ts +29 -0
- package/coding/src/workspace/index.ts +5 -0
- package/coding/src/workspace/merge.ts +151 -0
- package/coding/src/workspace/routing.ts +76 -0
- package/coding/src/workspace/service.ts +584 -0
- package/computer-use/README.md +105 -0
- package/computer-use/skills/computer-use-linux/SKILL.md +17 -0
- package/computer-use/src/classify.ts +53 -0
- package/computer-use/src/command.ts +29 -0
- package/computer-use/src/config.ts +69 -0
- package/computer-use/src/create.ts +170 -0
- package/computer-use/src/devices.ts +247 -0
- package/computer-use/src/env.ts +28 -0
- package/computer-use/src/index.ts +157 -0
- package/computer-use/src/skill.ts +21 -0
- package/openapi/README.md +97 -0
- package/openapi/src/compile.ts +386 -0
- package/openapi/src/config.ts +73 -0
- package/openapi/src/errors.ts +16 -0
- package/openapi/src/execute.ts +241 -0
- package/openapi/src/index.ts +124 -0
- package/openapi/src/limits.ts +63 -0
- package/openapi/src/specs.ts +86 -0
- package/openapi/src/tools.ts +60 -0
- package/openapi/src/types.ts +61 -0
- package/package.json +171 -4
- package/research/README.md +72 -0
- package/research/skills/research-report/SKILL.md +12 -0
- package/research/skills/research-scoping/SKILL.md +10 -0
- package/research/skills/research-synthesis/SKILL.md +10 -0
- package/research/skills/source-triage/SKILL.md +10 -0
- package/research/src/check.ts +71 -0
- package/research/src/config.ts +41 -0
- package/research/src/index.ts +147 -0
- package/research/src/ledger.ts +157 -0
- package/research/src/urls.ts +21 -0
- package/web/README.md +287 -0
- package/web/skills/web-research/SKILL.md +17 -0
- package/web/src/brave.ts +66 -0
- package/web/src/cache.ts +151 -0
- package/web/src/config.ts +210 -0
- package/web/src/controls.ts +128 -0
- package/web/src/domains.ts +114 -0
- package/web/src/exa.ts +60 -0
- package/web/src/firecrawl.ts +160 -0
- package/web/src/index.ts +387 -0
- package/web/src/kagi.ts +73 -0
- package/web/src/limits.ts +55 -0
- package/web/src/native/convert.ts +84 -0
- package/web/src/native/fetch.ts +226 -0
- package/web/src/normalize.ts +131 -0
- package/web/src/obscura/cdp.ts +201 -0
- package/web/src/obscura/classify.ts +35 -0
- package/web/src/obscura/cli.ts +254 -0
- package/web/src/obscura/errors.ts +8 -0
- package/web/src/obscura/index.ts +59 -0
- package/web/src/obscura/limits.ts +92 -0
- package/web/src/obscura/mcp.ts +104 -0
- package/web/src/obscura/playwright.ts +133 -0
- package/web/src/obscura/process.ts +235 -0
- package/web/src/obscura/search-profile.ts +73 -0
- package/web/src/obscura/types.ts +48 -0
- package/web/src/obscura/web.ts +419 -0
- package/web/src/prompt-fetch.ts +88 -0
- package/web/src/render.ts +75 -0
- package/web/src/searxng.ts +78 -0
- package/web/src/slice.ts +139 -0
- package/web/src/tavily.ts +77 -0
- package/web/src/tools.ts +182 -0
- package/web/src/transport.ts +310 -0
- package/web/src/types.ts +199 -0
- package/work/README.md +77 -0
- package/work/THIRD_PARTY_NOTICES +24 -0
- package/work/docling/ocr.py +150 -0
- package/work/sandbox/Dockerfile +36 -0
- package/work/sandbox/soffice.sh +12 -0
- package/work/src/command.ts +29 -0
- package/work/src/config.ts +138 -0
- package/work/src/connectors/cli.ts +343 -0
- package/work/src/connectors/drafts.ts +647 -0
- package/work/src/connectors/errors.ts +8 -0
- package/work/src/connectors/file-bytes.ts +149 -0
- package/work/src/connectors/google-workspace-http.ts +399 -0
- package/work/src/connectors/google-workspace.ts +465 -0
- package/work/src/connectors/gws-tools.ts +378 -0
- package/work/src/connectors/http.ts +123 -0
- package/work/src/connectors/idempotency.ts +235 -0
- package/work/src/connectors/identity.ts +34 -0
- package/work/src/connectors/index.ts +93 -0
- package/work/src/connectors/limits.ts +50 -0
- package/work/src/connectors/m365-tools.ts +308 -0
- package/work/src/connectors/microsoft365-http.ts +428 -0
- package/work/src/connectors/microsoft365.ts +402 -0
- package/work/src/connectors/normalize.ts +120 -0
- package/work/src/connectors/tool-helpers.ts +398 -0
- package/work/src/connectors/tools.ts +42 -0
- package/work/src/connectors/types.ts +399 -0
- package/work/src/diagrams/canonicalize.ts +166 -0
- package/work/src/diagrams/caps.ts +52 -0
- package/work/src/diagrams/embed.ts +340 -0
- package/work/src/diagrams/errors.ts +76 -0
- package/work/src/diagrams/index.ts +81 -0
- package/work/src/diagrams/messages.ts +150 -0
- package/work/src/diagrams/origin.ts +52 -0
- package/work/src/diagrams/telemetry.ts +34 -0
- package/work/src/diagrams/xml.ts +267 -0
- package/work/src/document-extraction/index.ts +563 -0
- package/work/src/document-reader/ambient.d.ts +2 -0
- package/work/src/document-reader/errors.ts +7 -0
- package/work/src/document-reader/index.ts +181 -0
- package/work/src/document-reader/mistral-ocr.ts +318 -0
- package/work/src/document-reader/parsers.ts +171 -0
- package/work/src/documents/caps.ts +135 -0
- package/work/src/documents/diff.ts +269 -0
- package/work/src/documents/errors.ts +44 -0
- package/work/src/documents/fidelity.ts +98 -0
- package/work/src/documents/generate.ts +96 -0
- package/work/src/documents/hash.ts +8 -0
- package/work/src/documents/index.ts +14 -0
- package/work/src/documents/model-schema.ts +639 -0
- package/work/src/documents/parse.ts +252 -0
- package/work/src/documents/patch-history.ts +81 -0
- package/work/src/documents/patch.ts +476 -0
- package/work/src/documents/preview-html.ts +245 -0
- package/work/src/documents/preview.ts +227 -0
- package/work/src/documents/telemetry.ts +36 -0
- package/work/src/documents/translate/docx.ts +292 -0
- package/work/src/documents/translate/pptx.ts +304 -0
- package/work/src/documents/translate/xlsx.ts +137 -0
- package/work/src/documents/types.ts +188 -0
- package/work/src/index.ts +311 -0
- package/work/src/runtime/worker-pool-entry.ts +102 -0
- package/work/src/runtime/worker-pool.ts +267 -0
- package/work/src/sandbox/composition.ts +212 -0
- package/work/src/sandbox/image.ts +6 -0
- package/work/src/sandbox/index.ts +14 -0
- package/work/src/sheets/caps.ts +68 -0
- package/work/src/sheets/csv.ts +351 -0
- package/work/src/sheets/decimal.ts +388 -0
- package/work/src/sheets/errors.ts +52 -0
- package/work/src/sheets/index.ts +62 -0
- package/work/src/sheets/inference.ts +378 -0
- package/work/src/sheets/telemetry.ts +34 -0
- package/work/src/sheets/types.ts +162 -0
- package/work/src/sheets/xlsx.ts +388 -0
- package/work/src/skills/index.ts +8 -0
- package/work/src/skills/load.ts +43 -0
- package/work/src/tools/filesystem.ts +21 -0
- package/work/src/tools/index.ts +1 -0
- package/work/src/tools/local-filesystem.ts +33 -0
- package/work/src/tools/office.ts +311 -0
- package/work/vendor/hermes-agent/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_comments.py +289 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_common.py +94 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_create.py +177 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_edit.py +250 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_read.py +149 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_revisions.py +147 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_template.py +70 -0
- package/work/vendor/hermes-agent/skills/productivity/docx/scripts/docx_validate.py +156 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/SKILL.md +125 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/_raster.py +76 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_marker.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/extract_pymupdf.py +101 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_create.py +130 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_fill_form.py +97 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_form_layout.py +168 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_make_form.py +145 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_merge.py +50 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_meta.py +115 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_page_image.py +99 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_read.py +153 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_secure.py +71 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_split.py +84 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_stamp.py +143 -0
- package/work/vendor/hermes-agent/skills/productivity/pdf/scripts/pdf_watermark.py +51 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/SKILL.md +220 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_create.py +214 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_edit.py +436 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_from_template.py +88 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_read.py +131 -0
- package/work/vendor/hermes-agent/skills/productivity/powerpoint/scripts/pptx_render.py +93 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/LICENSE +21 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/SKILL.md +196 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/csv_to_xlsx.py +104 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_create.py +259 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_edit.py +263 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_read.py +160 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_recalc.py +111 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_restructure.py +337 -0
- package/work/vendor/hermes-agent/skills/productivity/xlsx/scripts/xlsx_to_csv.py +69 -0
- package/work/vendor-lock.json +11 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
2
|
+
import { BrowserError } from "../errors.js";
|
|
3
|
+
import type { BrowserActRequest, BrowserActResult } from "../types.js";
|
|
4
|
+
import type { ActionContext, RunSession } from "./types.js";
|
|
5
|
+
|
|
6
|
+
export async function wait(
|
|
7
|
+
ctx: ActionContext,
|
|
8
|
+
session: RunSession,
|
|
9
|
+
request: BrowserActRequest,
|
|
10
|
+
signal: AbortSignal | undefined,
|
|
11
|
+
): Promise<BrowserActResult> {
|
|
12
|
+
ctx.chargeAction(session);
|
|
13
|
+
const page = ctx.resolvePage(session, request.pageId);
|
|
14
|
+
const timeout = clampTimeout(request.timeoutMs, ctx.limits.waitTimeoutMs);
|
|
15
|
+
if (typeof request.url === "string" && request.url) {
|
|
16
|
+
ctx.assertInputBytes(request.url);
|
|
17
|
+
if (!page.page.waitForURL) {
|
|
18
|
+
throw new BrowserError("ERR_PRISM_BROWSER", "Page does not support waitForURL");
|
|
19
|
+
}
|
|
20
|
+
await page.page.waitForURL(request.url, { timeout });
|
|
21
|
+
} else if (typeof request.text === "string" && request.text) {
|
|
22
|
+
ctx.assertInputBytes(request.text);
|
|
23
|
+
const locator = page.page.getByText(request.text, { exact: false });
|
|
24
|
+
const start = Date.now();
|
|
25
|
+
while (Date.now() - start < timeout) {
|
|
26
|
+
ctx.throwIfAborted(signal);
|
|
27
|
+
if ((await locator.count()) > 0) break;
|
|
28
|
+
await sleep(50);
|
|
29
|
+
}
|
|
30
|
+
if ((await locator.count()) === 0) {
|
|
31
|
+
throw new BrowserError("ERR_PRISM_BROWSER", `wait text not found within ${timeout}ms`);
|
|
32
|
+
}
|
|
33
|
+
} else {
|
|
34
|
+
await sleep(Math.min(timeout, ctx.limits.waitTimeoutMs));
|
|
35
|
+
}
|
|
36
|
+
return ctx.resultFor(session, "wait", page);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function clampTimeout(value: number | undefined, hard: number): number {
|
|
40
|
+
if (value === undefined) return hard;
|
|
41
|
+
if (!Number.isSafeInteger(value) || value < 1 || value > hard) {
|
|
42
|
+
throw new BrowserError("ERR_PRISM_BROWSER_LIMIT", `timeoutMs must be 1..${hard}`);
|
|
43
|
+
}
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
export {
|
|
2
|
+
type CdpExceptionDetails,
|
|
3
|
+
type CdpMode,
|
|
4
|
+
type CdpRemoteObject,
|
|
5
|
+
type CdpRuntimeEvaluateResponse,
|
|
6
|
+
cdpAvailable,
|
|
7
|
+
cdpEmulationClearDeviceMetrics,
|
|
8
|
+
cdpEmulationSetDeviceMetrics,
|
|
9
|
+
cdpEmulationSetUserAgent,
|
|
10
|
+
cdpNetworkEmulateConditions,
|
|
11
|
+
cdpNetworkEnable,
|
|
12
|
+
cdpNetworkSetBlockedUrls,
|
|
13
|
+
cdpRuntimeEnable,
|
|
14
|
+
cdpRuntimeEvaluate,
|
|
15
|
+
createPageCdpSession,
|
|
16
|
+
resolveCdpMode,
|
|
17
|
+
} from "./cdp.js";
|
|
18
|
+
export {
|
|
19
|
+
type BrowserCheckpoint,
|
|
20
|
+
type BrowserCheckpointInput,
|
|
21
|
+
type BrowserCheckpointLedger,
|
|
22
|
+
type BrowserCheckpointLimitOptions,
|
|
23
|
+
type BrowserCheckpointLimits,
|
|
24
|
+
createBrowserCheckpointLedger,
|
|
25
|
+
DEFAULT_MAX_CHECKPOINT_URL_BYTES,
|
|
26
|
+
DEFAULT_MAX_CHECKPOINTS_PER_RUN,
|
|
27
|
+
DEFAULT_MAX_DOMAIN_STATE_HASH_BYTES,
|
|
28
|
+
DEFAULT_MAX_HOST_DATA_REF_BYTES,
|
|
29
|
+
HARD_MAX_CHECKPOINT_URL_BYTES,
|
|
30
|
+
HARD_MAX_CHECKPOINTS_PER_RUN,
|
|
31
|
+
HARD_MAX_DOMAIN_STATE_HASH_BYTES,
|
|
32
|
+
HARD_MAX_HOST_DATA_REF_BYTES,
|
|
33
|
+
resolveBrowserCheckpointLimits,
|
|
34
|
+
} from "./checkpoint.js";
|
|
35
|
+
export {
|
|
36
|
+
type BrowserDownloadOptions,
|
|
37
|
+
cleanupDownloads,
|
|
38
|
+
createDownloadBudget,
|
|
39
|
+
type DownloadBudget,
|
|
40
|
+
type DownloadMetadata,
|
|
41
|
+
quarantineDownload,
|
|
42
|
+
releaseDownload,
|
|
43
|
+
sanitizeDownloadName,
|
|
44
|
+
} from "./downloads.js";
|
|
45
|
+
export { BrowserError, type BrowserErrorCode } from "./errors.js";
|
|
46
|
+
export { boundedJson, type EvaluateBounds, type EvaluateOutcome, evaluateInPage } from "./evaluate.js";
|
|
47
|
+
export {
|
|
48
|
+
type BrowserLimitOptions,
|
|
49
|
+
DEFAULT_ACTION_TIMEOUT_MS,
|
|
50
|
+
DEFAULT_BROWSER_LIMITS,
|
|
51
|
+
DEFAULT_CLOSE_GRACE_MS,
|
|
52
|
+
DEFAULT_IDLE_RUN_TTL_MS,
|
|
53
|
+
DEFAULT_MAX_ACTION_INPUT_BYTES,
|
|
54
|
+
DEFAULT_MAX_ACTIONS,
|
|
55
|
+
DEFAULT_MAX_BLOCKED_URL_PATTERNS,
|
|
56
|
+
DEFAULT_MAX_CONSOLE_ENTRIES,
|
|
57
|
+
DEFAULT_MAX_DIALOGS,
|
|
58
|
+
DEFAULT_MAX_DOWNLOAD_AGGREGATE_BYTES,
|
|
59
|
+
DEFAULT_MAX_DOWNLOAD_BYTES,
|
|
60
|
+
DEFAULT_MAX_DOWNLOADS,
|
|
61
|
+
DEFAULT_MAX_EVALUATE_RESULT_BYTES,
|
|
62
|
+
DEFAULT_MAX_LISTENERS,
|
|
63
|
+
DEFAULT_MAX_NETWORK_REQUESTS,
|
|
64
|
+
DEFAULT_MAX_PAGES,
|
|
65
|
+
DEFAULT_MAX_POPUPS,
|
|
66
|
+
DEFAULT_MAX_QUEUED_ACTIONS,
|
|
67
|
+
DEFAULT_MAX_REDIRECTS_PER_REQUEST,
|
|
68
|
+
DEFAULT_MAX_SCREENSHOT_BYTES,
|
|
69
|
+
DEFAULT_MAX_SCREENSHOT_MEGAPIXELS,
|
|
70
|
+
DEFAULT_MAX_SCREENSHOTS,
|
|
71
|
+
DEFAULT_MAX_SNAPSHOT_BYTES,
|
|
72
|
+
DEFAULT_MAX_SNAPSHOT_DEPTH,
|
|
73
|
+
DEFAULT_MAX_SNAPSHOT_REFS,
|
|
74
|
+
DEFAULT_MAX_UPLOAD_AGGREGATE_BYTES,
|
|
75
|
+
DEFAULT_MAX_UPLOAD_BYTES,
|
|
76
|
+
DEFAULT_MAX_UPLOADS,
|
|
77
|
+
DEFAULT_MAX_WEBSOCKETS,
|
|
78
|
+
DEFAULT_NAVIGATION_TIMEOUT_MS,
|
|
79
|
+
DEFAULT_RUN_WALL_TIME_MS,
|
|
80
|
+
DEFAULT_WAIT_TIMEOUT_MS,
|
|
81
|
+
HARD_ACTION_TIMEOUT_MS,
|
|
82
|
+
HARD_BROWSER_LIMITS,
|
|
83
|
+
HARD_CLOSE_GRACE_MS,
|
|
84
|
+
HARD_IDLE_RUN_TTL_MS,
|
|
85
|
+
HARD_MAX_ACTION_INPUT_BYTES,
|
|
86
|
+
HARD_MAX_ACTIONS,
|
|
87
|
+
HARD_MAX_BLOCKED_URL_PATTERNS,
|
|
88
|
+
HARD_MAX_CONSOLE_ENTRIES,
|
|
89
|
+
HARD_MAX_DEVICE_SCALE_FACTOR,
|
|
90
|
+
HARD_MAX_DIALOGS,
|
|
91
|
+
HARD_MAX_DOWNLOAD_AGGREGATE_BYTES,
|
|
92
|
+
HARD_MAX_DOWNLOAD_BYTES,
|
|
93
|
+
HARD_MAX_DOWNLOADS,
|
|
94
|
+
HARD_MAX_EMULATE_DIMENSION,
|
|
95
|
+
HARD_MAX_EMULATE_UA_BYTES,
|
|
96
|
+
HARD_MAX_EVALUATE_RESULT_BYTES,
|
|
97
|
+
HARD_MAX_LISTENERS,
|
|
98
|
+
HARD_MAX_NETWORK_REQUESTS,
|
|
99
|
+
HARD_MAX_PAGES,
|
|
100
|
+
HARD_MAX_POPUPS,
|
|
101
|
+
HARD_MAX_QUEUED_ACTIONS,
|
|
102
|
+
HARD_MAX_REDIRECTS_PER_REQUEST,
|
|
103
|
+
HARD_MAX_SCREENSHOT_BYTES,
|
|
104
|
+
HARD_MAX_SCREENSHOT_MEGAPIXELS,
|
|
105
|
+
HARD_MAX_SCREENSHOTS,
|
|
106
|
+
HARD_MAX_SNAPSHOT_BYTES,
|
|
107
|
+
HARD_MAX_SNAPSHOT_DEPTH,
|
|
108
|
+
HARD_MAX_SNAPSHOT_REFS,
|
|
109
|
+
HARD_MAX_THROTTLE_KBPS,
|
|
110
|
+
HARD_MAX_THROTTLE_LATENCY_MS,
|
|
111
|
+
HARD_MAX_UPLOAD_AGGREGATE_BYTES,
|
|
112
|
+
HARD_MAX_UPLOAD_BYTES,
|
|
113
|
+
HARD_MAX_UPLOADS,
|
|
114
|
+
HARD_MAX_WEBSOCKETS,
|
|
115
|
+
HARD_NAVIGATION_TIMEOUT_MS,
|
|
116
|
+
HARD_RUN_WALL_TIME_MS,
|
|
117
|
+
HARD_WAIT_TIMEOUT_MS,
|
|
118
|
+
type ResolvedBrowserLimits,
|
|
119
|
+
resolveBrowserLimits,
|
|
120
|
+
} from "./limits.js";
|
|
121
|
+
export { type BrowserManager, type CreateBrowserManagerOptions, createBrowserManager } from "./manager.js";
|
|
122
|
+
export {
|
|
123
|
+
assertBrowserUrlAllowed,
|
|
124
|
+
type BrowserNetworkPolicy,
|
|
125
|
+
type BrowserUrlDecision,
|
|
126
|
+
classifyBrowserUrl,
|
|
127
|
+
classifyHost,
|
|
128
|
+
createNetworkBudget,
|
|
129
|
+
installNetworkRouting,
|
|
130
|
+
type NetworkBudget,
|
|
131
|
+
} from "./network.js";
|
|
132
|
+
export { createObservationRing, installCdpObservation, type ObservationRing } from "./observe.js";
|
|
133
|
+
export {
|
|
134
|
+
type BrowserEffectClass,
|
|
135
|
+
type BrowserOperationClass,
|
|
136
|
+
type BrowserRisk,
|
|
137
|
+
classifyBrowserOperation,
|
|
138
|
+
classifyBrowserToolEffect,
|
|
139
|
+
isSideEffectAction,
|
|
140
|
+
} from "./policy.js";
|
|
141
|
+
export {
|
|
142
|
+
type CaptureScreenshotOptions,
|
|
143
|
+
captureBoundedScreenshot,
|
|
144
|
+
createScreenshotBudget,
|
|
145
|
+
type ScreenshotBudget,
|
|
146
|
+
type ScreenshotResult,
|
|
147
|
+
} from "./screenshot.js";
|
|
148
|
+
export {
|
|
149
|
+
createSharedSandboxBrowserOptions,
|
|
150
|
+
type SharedSandboxBrowserAlignment,
|
|
151
|
+
type SharedSandboxBrowserOptions,
|
|
152
|
+
} from "./shared-sandbox.js";
|
|
153
|
+
export { captureAriaSnapshot, createSnapshotId, type LiveSnapshot, toSnapshotResult } from "./snapshot.js";
|
|
154
|
+
export {
|
|
155
|
+
assertValidRef,
|
|
156
|
+
normalizeTarget,
|
|
157
|
+
parseSnapshotRefs,
|
|
158
|
+
requireUniqueLocator,
|
|
159
|
+
resolveTargetLocator,
|
|
160
|
+
} from "./targets.js";
|
|
161
|
+
export { type BrowserToolsOptions, createBrowserTools, getBrowserManagerFromTools } from "./tools.js";
|
|
162
|
+
export type {
|
|
163
|
+
BrowserActionName,
|
|
164
|
+
BrowserActRequest,
|
|
165
|
+
BrowserActResult,
|
|
166
|
+
BrowserCdpOptions,
|
|
167
|
+
BrowserDownloadInfo,
|
|
168
|
+
BrowserEvaluateRequest,
|
|
169
|
+
BrowserEvaluateResult,
|
|
170
|
+
BrowserObserveResult,
|
|
171
|
+
BrowserOpenResult,
|
|
172
|
+
BrowserPageInfo,
|
|
173
|
+
BrowserSnapshotResult,
|
|
174
|
+
BrowserTarget,
|
|
175
|
+
CdpConsoleEntry,
|
|
176
|
+
CdpNetworkEntry,
|
|
177
|
+
PlaywrightBrowser,
|
|
178
|
+
PlaywrightBrowserContext,
|
|
179
|
+
PlaywrightCdpSession,
|
|
180
|
+
PlaywrightDialog,
|
|
181
|
+
PlaywrightDownload,
|
|
182
|
+
PlaywrightLocator,
|
|
183
|
+
PlaywrightPage,
|
|
184
|
+
PlaywrightRequest,
|
|
185
|
+
PlaywrightRoute,
|
|
186
|
+
SnapshotRefInfo,
|
|
187
|
+
} from "./types.js";
|
|
188
|
+
export {
|
|
189
|
+
type ApprovedUploadFile,
|
|
190
|
+
approveUploadPaths,
|
|
191
|
+
type BrowserUploadOptions,
|
|
192
|
+
createUploadBudget,
|
|
193
|
+
resolveUploadCandidate,
|
|
194
|
+
type UploadBudget,
|
|
195
|
+
} from "./uploads.js";
|
|
196
|
+
|
|
197
|
+
export const packageName = "@arnilo/prism-tools/browser";
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chrome DevTools Protocol session layer (0.1.4, plan 016 Task 4).
|
|
3
|
+
* Rides playwright-core's existing CDP transport (context.newCDPSession(page)) —
|
|
4
|
+
* zero new dependencies, host-supplied Chromium browser only, Prism never
|
|
5
|
+
* launches or downloads browsers. Domain allowlist: Runtime, Network, Emulation.
|
|
6
|
+
* No cookies/tracing/IndexedDB/worker-attach domains in 0.1.4.
|
|
7
|
+
*/
|
|
8
|
+
import { BrowserError } from "./errors.js";
|
|
9
|
+
import type { BrowserCdpOptions, PlaywrightBrowser, PlaywrightBrowserContext, PlaywrightCdpSession, PlaywrightPage } from "./types.js";
|
|
10
|
+
|
|
11
|
+
export type CdpMode = "auto" | "on" | "off";
|
|
12
|
+
|
|
13
|
+
export function resolveCdpMode(options?: BrowserCdpOptions): CdpMode {
|
|
14
|
+
return options?.mode ?? "auto";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Chromium-only capability signal. Playwright exposes page-level CDP sessions
|
|
19
|
+
* only for Chromium; belt-and-braces: version() strings prefixed firefox-/webkit-
|
|
20
|
+
* are treated as non-CDP even if a host layered newCDPSession on them.
|
|
21
|
+
*/
|
|
22
|
+
export function cdpAvailable(browser: PlaywrightBrowser, context: PlaywrightBrowserContext): boolean {
|
|
23
|
+
if (typeof context.newCDPSession !== "function") return false;
|
|
24
|
+
const version = browser.version?.() ?? "";
|
|
25
|
+
if (/^(firefox|webkit)-/u.test(version)) return false;
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Create a page-level CDP session or throw ERR_PRISM_BROWSER_CDP_UNAVAILABLE. */
|
|
30
|
+
export async function createPageCdpSession(
|
|
31
|
+
browser: PlaywrightBrowser,
|
|
32
|
+
context: PlaywrightBrowserContext,
|
|
33
|
+
page: PlaywrightPage,
|
|
34
|
+
): Promise<PlaywrightCdpSession> {
|
|
35
|
+
if (!cdpAvailable(browser, context)) {
|
|
36
|
+
throw new BrowserError(
|
|
37
|
+
"ERR_PRISM_BROWSER_CDP_UNAVAILABLE",
|
|
38
|
+
"CDP requires a Chromium-based host browser whose contexts expose newCDPSession(page)",
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const session = await context.newCDPSession!(page);
|
|
43
|
+
if (!session || typeof session.send !== "function") {
|
|
44
|
+
throw new BrowserError("ERR_PRISM_BROWSER_CDP_UNAVAILABLE", "Host newCDPSession did not return a usable CDP session");
|
|
45
|
+
}
|
|
46
|
+
return session;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof BrowserError) throw error;
|
|
49
|
+
throw new BrowserError(
|
|
50
|
+
"ERR_PRISM_BROWSER_CDP_UNAVAILABLE",
|
|
51
|
+
`CDP session creation failed: ${error instanceof Error ? error.message.slice(0, 256) : String(error).slice(0, 256)}`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Bounded JSON-serializable value carried by a CDP RemoteObject. */
|
|
57
|
+
export interface CdpRemoteObject {
|
|
58
|
+
readonly type?: string;
|
|
59
|
+
readonly subtype?: string;
|
|
60
|
+
readonly value?: unknown;
|
|
61
|
+
readonly description?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface CdpExceptionDetails {
|
|
65
|
+
readonly text?: string;
|
|
66
|
+
readonly url?: string;
|
|
67
|
+
readonly lineNumber?: number;
|
|
68
|
+
readonly columnNumber?: number;
|
|
69
|
+
readonly exception?: CdpRemoteObject;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface CdpRuntimeEvaluateResponse {
|
|
73
|
+
readonly result?: CdpRemoteObject;
|
|
74
|
+
readonly exceptionDetails?: CdpExceptionDetails;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export async function cdpRuntimeEvaluate(
|
|
78
|
+
session: PlaywrightCdpSession,
|
|
79
|
+
params: {
|
|
80
|
+
expression: string;
|
|
81
|
+
awaitPromise?: boolean;
|
|
82
|
+
returnByValue?: boolean;
|
|
83
|
+
userGesture?: boolean;
|
|
84
|
+
timeout?: number;
|
|
85
|
+
},
|
|
86
|
+
): Promise<CdpRuntimeEvaluateResponse> {
|
|
87
|
+
try {
|
|
88
|
+
return await session.send<CdpRuntimeEvaluateResponse>("Runtime.evaluate", {
|
|
89
|
+
expression: params.expression,
|
|
90
|
+
awaitPromise: params.awaitPromise === true,
|
|
91
|
+
returnByValue: params.returnByValue === true,
|
|
92
|
+
userGesture: params.userGesture === true,
|
|
93
|
+
...(params.timeout !== undefined ? { timeout: params.timeout } : {}),
|
|
94
|
+
});
|
|
95
|
+
} catch (error) {
|
|
96
|
+
throw cdpSendError(error);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function cdpRuntimeEnable(session: PlaywrightCdpSession): Promise<void> {
|
|
101
|
+
try {
|
|
102
|
+
await session.send("Runtime.enable");
|
|
103
|
+
} catch (error) {
|
|
104
|
+
throw cdpSendError(error);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export async function cdpNetworkEnable(session: PlaywrightCdpSession): Promise<void> {
|
|
109
|
+
try {
|
|
110
|
+
await session.send("Network.enable");
|
|
111
|
+
} catch (error) {
|
|
112
|
+
throw cdpSendError(error);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export async function cdpNetworkSetBlockedUrls(session: PlaywrightCdpSession, urls: readonly string[]): Promise<void> {
|
|
117
|
+
try {
|
|
118
|
+
await session.send("Network.setBlockedURLs", { urls: [...urls] });
|
|
119
|
+
} catch (error) {
|
|
120
|
+
throw cdpSendError(error);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function cdpNetworkEmulateConditions(
|
|
125
|
+
session: PlaywrightCdpSession,
|
|
126
|
+
params: { offline: boolean; latencyMs: number; downloadThroughputBps: number; uploadThroughputBps: number },
|
|
127
|
+
): Promise<void> {
|
|
128
|
+
try {
|
|
129
|
+
await session.send("Network.emulateNetworkConditions", {
|
|
130
|
+
offline: params.offline,
|
|
131
|
+
latency: params.latencyMs,
|
|
132
|
+
downloadThroughput: params.downloadThroughputBps,
|
|
133
|
+
uploadThroughput: params.uploadThroughputBps,
|
|
134
|
+
});
|
|
135
|
+
} catch (error) {
|
|
136
|
+
throw cdpSendError(error);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export async function cdpEmulationSetDeviceMetrics(
|
|
141
|
+
session: PlaywrightCdpSession,
|
|
142
|
+
params: { width: number; height: number; mobile: boolean; deviceScaleFactor: number },
|
|
143
|
+
): Promise<void> {
|
|
144
|
+
try {
|
|
145
|
+
await session.send("Emulation.setDeviceMetricsOverride", {
|
|
146
|
+
width: params.width,
|
|
147
|
+
height: params.height,
|
|
148
|
+
mobile: params.mobile,
|
|
149
|
+
deviceScaleFactor: params.deviceScaleFactor,
|
|
150
|
+
});
|
|
151
|
+
} catch (error) {
|
|
152
|
+
throw cdpSendError(error);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export async function cdpEmulationSetUserAgent(session: PlaywrightCdpSession, userAgent: string): Promise<void> {
|
|
157
|
+
try {
|
|
158
|
+
await session.send("Emulation.setUserAgentOverride", { userAgent });
|
|
159
|
+
} catch (error) {
|
|
160
|
+
throw cdpSendError(error);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function cdpEmulationClearDeviceMetrics(session: PlaywrightCdpSession): Promise<void> {
|
|
165
|
+
try {
|
|
166
|
+
await session.send("Emulation.clearDeviceMetricsOverride");
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw cdpSendError(error);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function cdpSendError(error: unknown): BrowserError {
|
|
173
|
+
if (error instanceof BrowserError) return error;
|
|
174
|
+
return new BrowserError(
|
|
175
|
+
"ERR_PRISM_BROWSER_CDP",
|
|
176
|
+
`CDP send failed: ${error instanceof Error ? error.message.slice(0, 256) : String(error).slice(0, 256)}`,
|
|
177
|
+
);
|
|
178
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verified-state browser checkpoints (Task 6).
|
|
3
|
+
*
|
|
4
|
+
* A checkpoint records verified navigation state — URL, a domain-state hash,
|
|
5
|
+
* and host-owned data refs — never serialized browser internals (cookies,
|
|
6
|
+
* storage, contexts), which are fragile and secret-bearing. After any resume or
|
|
7
|
+
* interruption the ledger requires a reload + verify before the first mutating
|
|
8
|
+
* action, so side effects never replay on stale/unverified state (fail closed).
|
|
9
|
+
* Checkpoints are run-scoped; a conversation thread composes through the run it
|
|
10
|
+
* owns, reusing the manager's existing sandbox/egress/approval/limit policy.
|
|
11
|
+
*/
|
|
12
|
+
import { BrowserError } from "./errors.js";
|
|
13
|
+
|
|
14
|
+
/** Checkpoint URL: 8 KiB default / 16 KiB hard. */
|
|
15
|
+
export const DEFAULT_MAX_CHECKPOINT_URL_BYTES = 8 * 1024;
|
|
16
|
+
export const HARD_MAX_CHECKPOINT_URL_BYTES = 16 * 1024;
|
|
17
|
+
/** Domain state hash: 256 B default / 1 KiB hard. */
|
|
18
|
+
export const DEFAULT_MAX_DOMAIN_STATE_HASH_BYTES = 256;
|
|
19
|
+
export const HARD_MAX_DOMAIN_STATE_HASH_BYTES = 1024;
|
|
20
|
+
/** Host data ref (ref only, never a body): 2 KiB default / 8 KiB hard. */
|
|
21
|
+
export const DEFAULT_MAX_HOST_DATA_REF_BYTES = 2 * 1024;
|
|
22
|
+
export const HARD_MAX_HOST_DATA_REF_BYTES = 8 * 1024;
|
|
23
|
+
/** Checkpoints retained per run: 16 default / 64 hard (oldest evicted). */
|
|
24
|
+
export const DEFAULT_MAX_CHECKPOINTS_PER_RUN = 16;
|
|
25
|
+
export const HARD_MAX_CHECKPOINTS_PER_RUN = 64;
|
|
26
|
+
|
|
27
|
+
export interface BrowserCheckpoint {
|
|
28
|
+
readonly checkpointId: string;
|
|
29
|
+
readonly runId: string;
|
|
30
|
+
readonly url: string;
|
|
31
|
+
readonly domainStateHash: string;
|
|
32
|
+
/** Host-owned data reference only — never a serialized browser internal or body. */
|
|
33
|
+
readonly hostDataRef?: string;
|
|
34
|
+
readonly createdAt: string;
|
|
35
|
+
readonly verified: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface BrowserCheckpointLimits {
|
|
39
|
+
readonly maxUrlBytes: number;
|
|
40
|
+
readonly maxDomainStateHashBytes: number;
|
|
41
|
+
readonly maxHostDataRefBytes: number;
|
|
42
|
+
readonly maxCheckpointsPerRun: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface BrowserCheckpointLimitOptions {
|
|
46
|
+
readonly maxUrlBytes?: number;
|
|
47
|
+
readonly maxDomainStateHashBytes?: number;
|
|
48
|
+
readonly maxHostDataRefBytes?: number;
|
|
49
|
+
readonly maxCheckpointsPerRun?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface BrowserCheckpointInput {
|
|
53
|
+
readonly runId: string;
|
|
54
|
+
readonly url: string;
|
|
55
|
+
readonly domainStateHash: string;
|
|
56
|
+
readonly hostDataRef?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface BrowserCheckpointLedger {
|
|
60
|
+
readonly limits: BrowserCheckpointLimits;
|
|
61
|
+
/** Record verified state during normal operation. */
|
|
62
|
+
checkpoint(input: BrowserCheckpointInput): BrowserCheckpoint;
|
|
63
|
+
list(runId: string): readonly BrowserCheckpoint[];
|
|
64
|
+
/** Mark a run's state stale after resume/interruption; verify required before side effect. */
|
|
65
|
+
markResumed(runId: string): void;
|
|
66
|
+
/** Reload + verify completed; clears the verify gate and records a fresh verified checkpoint. */
|
|
67
|
+
verify(input: BrowserCheckpointInput): BrowserCheckpoint;
|
|
68
|
+
/** Fail closed unless the run holds verified state (reload+verify before any mutating action). */
|
|
69
|
+
assertVerifiedBeforeSideEffect(runId: string): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function validateBytes(name: string, value: string | undefined, max: number, required: boolean): string | undefined {
|
|
73
|
+
if (value === undefined) {
|
|
74
|
+
if (required) throw new BrowserError("ERR_PRISM_BROWSER_INPUT", `${name} is required`);
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
78
|
+
throw new BrowserError("ERR_PRISM_BROWSER_INPUT", `${name} must be a non-empty string`);
|
|
79
|
+
}
|
|
80
|
+
if (Buffer.byteLength(value, "utf8") > max) {
|
|
81
|
+
throw new BrowserError("ERR_PRISM_BROWSER_LIMIT", `${name} exceeds ${max} bytes`);
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function validateCount(name: string, value: number | undefined, def: number, hard: number): number {
|
|
87
|
+
const resolved = value ?? def;
|
|
88
|
+
if (!Number.isSafeInteger(resolved) || resolved < 1 || resolved > hard) {
|
|
89
|
+
throw new BrowserError("ERR_PRISM_BROWSER_LIMIT", `${name} must be a positive safe integer at most ${hard}`);
|
|
90
|
+
}
|
|
91
|
+
return resolved;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function resolveBrowserCheckpointLimits(input: BrowserCheckpointLimitOptions = {}): BrowserCheckpointLimits {
|
|
95
|
+
return {
|
|
96
|
+
maxUrlBytes: validateCount("maxUrlBytes", input.maxUrlBytes, DEFAULT_MAX_CHECKPOINT_URL_BYTES, HARD_MAX_CHECKPOINT_URL_BYTES),
|
|
97
|
+
maxDomainStateHashBytes: validateCount(
|
|
98
|
+
"maxDomainStateHashBytes",
|
|
99
|
+
input.maxDomainStateHashBytes,
|
|
100
|
+
DEFAULT_MAX_DOMAIN_STATE_HASH_BYTES,
|
|
101
|
+
HARD_MAX_DOMAIN_STATE_HASH_BYTES,
|
|
102
|
+
),
|
|
103
|
+
maxHostDataRefBytes: validateCount(
|
|
104
|
+
"maxHostDataRefBytes",
|
|
105
|
+
input.maxHostDataRefBytes,
|
|
106
|
+
DEFAULT_MAX_HOST_DATA_REF_BYTES,
|
|
107
|
+
HARD_MAX_HOST_DATA_REF_BYTES,
|
|
108
|
+
),
|
|
109
|
+
maxCheckpointsPerRun: validateCount(
|
|
110
|
+
"maxCheckpointsPerRun",
|
|
111
|
+
input.maxCheckpointsPerRun,
|
|
112
|
+
DEFAULT_MAX_CHECKPOINTS_PER_RUN,
|
|
113
|
+
HARD_MAX_CHECKPOINTS_PER_RUN,
|
|
114
|
+
),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface RunCheckpointState {
|
|
119
|
+
readonly checkpoints: BrowserCheckpoint[];
|
|
120
|
+
needsVerify: boolean;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let checkpointSeq = 0;
|
|
124
|
+
function nextCheckpointId(): string {
|
|
125
|
+
checkpointSeq += 1;
|
|
126
|
+
return `bcp_${checkpointSeq}`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function createBrowserCheckpointLedger(options: BrowserCheckpointLimitOptions = {}): BrowserCheckpointLedger {
|
|
130
|
+
const limits = resolveBrowserCheckpointLimits(options);
|
|
131
|
+
const runs = new Map<string, RunCheckpointState>();
|
|
132
|
+
|
|
133
|
+
function record(input: BrowserCheckpointInput): BrowserCheckpoint {
|
|
134
|
+
const runId = validateBytes("runId", input.runId, 256, true)!;
|
|
135
|
+
const url = validateBytes("url", input.url, limits.maxUrlBytes, true)!;
|
|
136
|
+
const domainStateHash = validateBytes("domainStateHash", input.domainStateHash, limits.maxDomainStateHashBytes, true)!;
|
|
137
|
+
const hostDataRef = validateBytes("hostDataRef", input.hostDataRef, limits.maxHostDataRefBytes, false);
|
|
138
|
+
const checkpoint: BrowserCheckpoint = {
|
|
139
|
+
checkpointId: nextCheckpointId(),
|
|
140
|
+
runId,
|
|
141
|
+
url,
|
|
142
|
+
domainStateHash,
|
|
143
|
+
...(hostDataRef ? { hostDataRef } : {}),
|
|
144
|
+
createdAt: new Date().toISOString(),
|
|
145
|
+
verified: true,
|
|
146
|
+
};
|
|
147
|
+
let state = runs.get(runId);
|
|
148
|
+
if (!state) {
|
|
149
|
+
state = { checkpoints: [], needsVerify: false };
|
|
150
|
+
runs.set(runId, state);
|
|
151
|
+
}
|
|
152
|
+
state.checkpoints.push(checkpoint);
|
|
153
|
+
// Bounded retention: evict oldest beyond the per-run cap.
|
|
154
|
+
while (state.checkpoints.length > limits.maxCheckpointsPerRun) {
|
|
155
|
+
state.checkpoints.shift();
|
|
156
|
+
}
|
|
157
|
+
return checkpoint;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
limits,
|
|
162
|
+
checkpoint: (input) => record(input),
|
|
163
|
+
list: (runId) => runs.get(runId)?.checkpoints ?? [],
|
|
164
|
+
markResumed(runId) {
|
|
165
|
+
validateBytes("runId", runId, 256, true);
|
|
166
|
+
let state = runs.get(runId);
|
|
167
|
+
if (!state) {
|
|
168
|
+
// Resuming an unknown run is unverified state — fail closed until verify.
|
|
169
|
+
state = { checkpoints: [], needsVerify: true };
|
|
170
|
+
runs.set(runId, state);
|
|
171
|
+
} else {
|
|
172
|
+
state.needsVerify = true;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
verify(input) {
|
|
176
|
+
const checkpoint = record(input);
|
|
177
|
+
const state = runs.get(checkpoint.runId)!;
|
|
178
|
+
state.needsVerify = false;
|
|
179
|
+
return checkpoint;
|
|
180
|
+
},
|
|
181
|
+
assertVerifiedBeforeSideEffect(runId) {
|
|
182
|
+
validateBytes("runId", runId, 256, true);
|
|
183
|
+
const state = runs.get(runId);
|
|
184
|
+
if (!state || state.needsVerify || state.checkpoints.length === 0) {
|
|
185
|
+
throw new BrowserError("ERR_PRISM_BROWSER_STATE", "browser side effect requires reload + verify after resume/interruption");
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { JsonSchema } from "@arnilo/prism";
|
|
2
|
+
|
|
3
|
+
/** Host attestation that real egress is forced through an isolated proxy/firewall. */
|
|
4
|
+
export interface ToolsBrowserProxyConfig {
|
|
5
|
+
readonly proxyEndpoint: string;
|
|
6
|
+
readonly denyDirectEgress: true;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Validated `packageConfig` for `@arnilo/prism-tools/browser`. */
|
|
10
|
+
export interface ToolsBrowserConfig {
|
|
11
|
+
/** Launch a headless Chromium through `playwright-core` (default `true`). */
|
|
12
|
+
readonly headless?: boolean;
|
|
13
|
+
/** Absolute path to a host-pinned browser binary passed to `chromium.launch`. */
|
|
14
|
+
readonly executablePath?: string;
|
|
15
|
+
/** Playwright channel (for example `"chromium"` or `"chrome"`) passed to `chromium.launch`. */
|
|
16
|
+
readonly channel?: string;
|
|
17
|
+
/**
|
|
18
|
+
* Origin allowlist. When set, navigation and subrequests to any other origin are hard-denied.
|
|
19
|
+
* Omit to leave origin decisions to `containedProxy` and the default scheme/host denies.
|
|
20
|
+
*/
|
|
21
|
+
readonly allowOrigins?: readonly string[];
|
|
22
|
+
/** Host contained-proxy attestation; without it every external request is denied (fail closed). */
|
|
23
|
+
readonly containedProxy?: ToolsBrowserProxyConfig;
|
|
24
|
+
/** Allow loopback destinations (default `false`). */
|
|
25
|
+
readonly allowLoopback?: boolean;
|
|
26
|
+
/** Allow private/link-local/ULA destinations (default `false`). */
|
|
27
|
+
readonly allowPrivateHosts?: boolean;
|
|
28
|
+
/** Absolute roots uploads may read from (realpath-contained; symlink escapes rejected). */
|
|
29
|
+
readonly uploadRoots?: readonly string[];
|
|
30
|
+
/** Absolute quarantine directory; enables download support when set. */
|
|
31
|
+
readonly quarantine?: string;
|
|
32
|
+
/** CDP capability gating: `"auto"` (default), `"on"`, or `"off"`. */
|
|
33
|
+
readonly cdp?: "auto" | "on" | "off";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const originList: JsonSchema = {
|
|
37
|
+
type: "array",
|
|
38
|
+
items: { type: "string", minLength: 1, maxLength: 4096 },
|
|
39
|
+
maxItems: 64,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const pathList: JsonSchema = {
|
|
43
|
+
type: "array",
|
|
44
|
+
items: { type: "string", minLength: 1, maxLength: 4096 },
|
|
45
|
+
maxItems: 64,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** The config schema. Every undeclared key fails closed. */
|
|
49
|
+
export const toolsBrowserConfigSchema: JsonSchema = {
|
|
50
|
+
type: "object",
|
|
51
|
+
additionalProperties: false,
|
|
52
|
+
properties: {
|
|
53
|
+
headless: { type: "boolean", default: true },
|
|
54
|
+
executablePath: { type: "string", minLength: 1, maxLength: 4096 },
|
|
55
|
+
channel: { type: "string", minLength: 1, maxLength: 128 },
|
|
56
|
+
allowOrigins: originList,
|
|
57
|
+
containedProxy: {
|
|
58
|
+
type: "object",
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
required: ["proxyEndpoint", "denyDirectEgress"],
|
|
61
|
+
properties: {
|
|
62
|
+
proxyEndpoint: { type: "string", minLength: 1, maxLength: 4096 },
|
|
63
|
+
denyDirectEgress: { type: "boolean", enum: [true] },
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
allowLoopback: { type: "boolean", default: false },
|
|
67
|
+
allowPrivateHosts: { type: "boolean", default: false },
|
|
68
|
+
uploadRoots: pathList,
|
|
69
|
+
quarantine: { type: "string", minLength: 1, maxLength: 4096 },
|
|
70
|
+
cdp: { type: "string", enum: ["auto", "on", "off"], default: "auto" },
|
|
71
|
+
},
|
|
72
|
+
};
|