Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion configuration
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# IMPORTANT: When these are updated, you must also update the versions
# in src/command/check/check.ts
# Binary dependencies
export DENO=v2.7.14
export DENO=v2.9.8
# TODO figure out where 0.1.41 apple silicon libs are available
export DENO_DOM=v0.1.41-alpha-artifacts
export PANDOC=3.10
Expand Down
4 changes: 2 additions & 2 deletions dev-docs/runtime-migration/HANDOFF.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ These were throwaway and are recreated by the plans when needed:
`REVIEW-2026-10-15.md` is the principal review of the first draft (13 structural findings, per-plan defects, the landing strategy, the decisions taken in its section 6).
Every plan was then reworked against it: six new PRs (00a, 00b, 00c, 02b, 14b, 20b, 27b), PR 21 folded into 25, PR 07 and PR 39 rewritten and renamed, `SPIKES.md` added, `_TEMPLATE.md` vocabulary updated, `00-assessment.md` given an errata section.
`README.md` carries the new table, dependency graph, conventions and baseline.
The plans are now executable in the README order; PR 02 (#15135) and 02c (#15153) are merged, 02d (the ratchet also counts `Deno` reached through optional chaining and `globalThis`) is in progress, and the next to run are 00a, then 00b.
The plans are now executable in the README order; PR 02 (#15135), 02c (#15153) and 02d (#15218) are merged; 00a is in progress as the Deno 2.9.8 security bump (#15152), and 00b runs next.

## Reconciliation pass (bucket B of `TRIAGE-2026-10-16.md`): done on 2026-10-16

Expand Down Expand Up @@ -78,7 +78,7 @@ Two notes for whoever continues: the B1 commit carries the maintainer's author i
2. Read `README.md`, then `00-assessment.md` sections 10 and 11, then `_TEMPLATE.md`.
3. The section 9 decisions are taken (`REVIEW-2026-10-15.md` section 6); the test runner is decided by Spike V in `SPIKES.md` before PR 31.
4. Apply the local corrections of `TRIAGE-2026-10-16.md` bucket C (one task per plan file, in parallel where the triage marks it), then the re-read of 02, 25, 26, 27, 29, 33, 35, 36 the triage's step 4 asks for (02, 25, 26, 27 and 29 done 2026-10-16, 33, 35 and 36 done 2026-10-17: step 4 is complete).
5. PR 02 and 02c are merged, 02d is in progress; open the remaining plans as PRs against `main` in the README order: 00a and 00b, then 03–06 in parallel, then 07.
5. PR 02, 02c and 02d are merged, and 00a is in progress; open the remaining plans as PRs against `main` in the README order: 00b, then 03–06 in parallel, then 07.
Each plan names its branch, executor and verification commands.
For the per-worktree session ritual (window model, trust, fresh conversation, concurrency ceiling), check
`local/multi-worktree-workflow.md` if it exists — it is a maintainer-local, untracked note.
Expand Down
10 changes: 7 additions & 3 deletions dev-docs/runtime-migration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ The rows below are the ones that still need a named person or an external answer
| PR 19 Task 1, PR 27b | both replace the whole body of `platform.ts`: keep the `v8Branch` export (`_TEMPLATE.md`, "`platform.ts`"); PR 27b computes it from `process.versions.v8` | coordinator | step 0 of each |
| PR 02c (from #15202, which turned `main` red) | Decided 2026-10-27: PR runs fail on any increase that leaves a count above their own `tools/runtime-boundary-baseline.json` (exactly what the push check on `main` will compare), instead of only warning; an increase that still fits because `main` sits below its baseline is a notice; 02c's "everything else is a warning for the maintainer" and its "exit 1 if any error, else 0" no longer hold. Per-line findings stay warnings saying the contributor has nothing to change, plus one `::error` saying a maintainer pushes the baseline update before merging; the remedy is unchanged (update the branch with `main`, `--update-baseline --accept-increase`, push to the PR). Rejected: an acceptance label (the merged tree still carries the old baseline, so `main` fails anyway) and warn-only with a merge checklist (the human step is what failed). A plan whose expected delta raises a count runs `--accept-increase` in its PR (PRs 01 and 05 already do) | maintainer | step 0 of any plan that raises a count |
| PR 30 | tagged `v8-<branch>/` directories are left behind like the untagged `.kv` files; remove `v8Branch` and its contract-test line together with its last consumer. What "damaged" means for the JSON index (unparsable or truncated file): keep the miss-with-warning versus fail-naming-the-folder split or not. The Deno KV damage tests (`tests/unit/kv-damage.test.ts` and the damaged-store cases in `sass-cache.test.ts` and `project-cache.test.ts`, from the #15119 fix) build real SQLite damage: they are replaced or deleted here, because PR 32 runs the full unit suite on Node, where neither `Deno.openKv` nor its damage exists, and "`sass-cache.test.ts` stays green" is restated accordingly | maintainer (damage semantics), coordinator (the rest) | PR 30 step 0 |
| PR 00b, vendor script steps | Deno 2.9 rejects permission flags on a non-global `deno install` (denoland/deno#36489), and the vendor scripts keep going after a failed entrypoint, so `--allow-all` vendors nothing. Every `deno install` line the plan adds uses `--allow-import`, as the current vendor scripts do since #15152; its `deno run` and `deno bundle` lines keep `--allow-all` | executor | step 0 of PR 00b |
| PR 01 | The `assert` → `with` half landed with #15152 (TypeScript 6 in Deno 2.9 rejects `assert`, TS2880), and it changed the IDE bundles: esbuild now wraps the JSON module as ESM (same data, same `.default`). Skip those edits and the "bundles unchanged" check; the PR keeps only the bslib ordering | executor | step 0 of PR 01 |
| PR 15 Task 2 | The replacement `port.ts` listing has `4160, // sieve` and a private `isPortSafe`. Since #15152 the list has `4190` (the Fetch standard's bad port, which Deno 2.9's `fetch` refuses) and `isPortSafe` is exported for `tests/unit/core/port.test.ts`. Retain port `4190` and the exported `isPortSafe`, and ensure `tests/unit/core/port.test.ts` still passes. | executor | step 0 of PR 15 |
| PRs 15, 16, 23 and 31, sanitizer checks | Deno 2.9 disables test sanitizers by default, and `tests/test.ts` does not enable them. Enabling them causes every test to fail because the harness leaks an open file and a timer; these leaks also occur on Deno 2.7.14. Fix the harness leaks and re-enable sanitizers before relying on the plans' "no sanitizer failures" checks or PR 31's "Leak guarantees". | maintainer | before PR 15 runs |

## Shared rules and tables

Expand Down Expand Up @@ -201,11 +205,11 @@ Every PR that changes a count lands after 02c; preparing it earlier is fine.
|---|---|---|---|---|---|---|
| 02 | [02-runtime-boundary-check.md](02-runtime-boundary-check.md) | CI ratchet counting `Deno.*` and direct std imports in five scopes (`src`, `src-js`, `resources`, `package/src`, `tests`); `tests/asserts.ts`; lands first | none | Sonnet | S | merged |
| 02c | [02c-ratchet-pr-delta-and-guidance.md](02c-ratchet-pr-delta-and-guidance.md) | PR runs compare with the base branch; findings name a working replacement or ask the maintainer to accept; `--accept-increase` | 02 | Sonnet | S | merged |
| 02d | [02d-ratchet-counts-indirect-deno.md](02d-ratchet-counts-indirect-deno.md) | The ratchet also counts `Deno?.x`, `globalThis["Deno"]` and a bare `globalThis.Deno` | 02c | Sonnet | S | in progress |
| 00a | [00a-deno-bump.md](00a-deno-bump.md) | Deno 2.7.14 → newest 2.9.x everywhere the version appears | 02 | Sonnet | S | planned |
| 02d | [02d-ratchet-counts-indirect-deno.md](02d-ratchet-counts-indirect-deno.md) | The ratchet also counts `Deno?.x`, `globalThis["Deno"]` and a bare `globalThis.Deno` | 02c | Sonnet | S | merged |
| 00a | [00a-deno-bump.md](00a-deno-bump.md) | Deno 2.7.14 → newest 2.9.x everywhere the version appears | 02 | Sonnet | S | in progress |
| 00b | [00b-lockfile-and-bundle-gate.md](00b-lockfile-and-bundle-gate.md) | Committed `deno.lock` with `--frozen` (six entrypoints); `tools/check-test-imports.ts` keeps the unlocked tests inside that graph; three-OS bundle gate (cold cache, external-specifier grep, five renders) | 02, 00a | Opus | M | planned |
| 00c | [00c-quarto-run-deprecation-notice.md](00c-quarto-run-deprecation-notice.md) | One-time notice when `quarto run` or a pre/post-render `.ts` script runs on Deno; `QUARTO_RUN_DENO_NOTICE=0` | 02 | Sonnet | S | planned |
| 01 | [01-quick-fixes-from-spike.md](01-quick-fixes-from-spike.md) | `assert`→`with` on two JSON imports; deterministic bslib Sass ordering | 02 | Sonnet | S | planned |
| 01 | [01-quick-fixes-from-spike.md](01-quick-fixes-from-spike.md) | Deterministic bslib Sass ordering (the `assert`→`with` half landed with 00a) | 02 | Sonnet | S | planned |
| 03 | [03-deps-skypack-to-npm.md](03-deps-skypack-to-npm.md) | Replace every `cdn.skypack.dev` import-map entry with `npm:`; CommonJS bundling proof | 02, 00b | Sonnet | M | planned |
| 04 | [04-deps-deno-land-x-small.md](04-deps-deno-land-x-small.md) | Replace semver, media_types, xmlp, xml, cache, events; cookie jar on tough-cookie | 02, 00b | Opus | M | planned |
| 05 | [05-deps-deno-dom-jsr.md](05-deps-deno-dom-jsr.md) | deno_dom from `deno.land/x` to `jsr:@b-fuze/deno-dom` 0.1.56; `parseHtml` timing baseline on the native plugin | 02, 00b | Opus | M | planned |
Expand Down
2 changes: 1 addition & 1 deletion dev-docs/upgrade-dependencies.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Change version numbers in `./configuration` to correspond to new versions.

Update hardcoded version strings in `src/command/check/check.ts` (`versionConstraints` array, ~line 249) so that they match the new versions in `configuration`. The `configuration` file warns about this in a comment.
Update hardcoded version strings in `src/command/check/check.ts` (the `versionConstraints` array in `checkVersions`) so that they match the new versions in `configuration`. The `configuration` file warns about this in a comment, and `tests/smoke/check/check-versions-no-mismatch.test.ts` fails until they match.

## Verify installer signing & notarization before merging (bundled binaries)

Expand Down
2 changes: 2 additions & 0 deletions news/changelog-1.11.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All changes included in 1.11:
## Dependencies

- ([#15043](https://github.com/quarto-dev/quarto-cli/issues/15043)): Update the OJS runtime to acorn 8.17, Observable Inspector 5.0.1, and Observable Inputs 0.10.6. `FileAttachment(...).mimeType` now reports `text/javascript` instead of `application/javascript` for `.js` and `.mjs` files.
- ([#15152](https://github.com/quarto-dev/quarto-cli/issues/15152)): Update `deno` to v2.9.8 to stop trusting the compromised eMudhra / emSign certificate authorities, whose exposed private keys allow network attackers to impersonate HTTPS sites, protecting HTTPS requests made by Quarto commands and TypeScript scripts from these attacks.

## Accessibility

Expand Down Expand Up @@ -204,5 +205,6 @@ All changes included in 1.11:
- ([#15126](https://github.com/quarto-dev/quarto-cli/issues/15126)): Translate the `revealjs-menu-button-label` language key in French. (author: @D3ller)
- ([#15126](https://github.com/quarto-dev/quarto-cli/issues/15126)): Translate the `revealjs-menu-button-label` language key in Greek. (author: @sogav21)
- ([#15140](https://github.com/quarto-dev/quarto-cli/pull/15140)): Add support for definition lists written as a `definition-list` div holding a nested bullet list, the definition list syntax of Quarto 2.
- ([#15157](https://github.com/quarto-dev/quarto-cli/issues/15157)): Fix `quarto preview` and other commands sometimes starting a local server on port 4190, which browsers refuse to connect to.
- ([#15180](https://github.com/quarto-dev/quarto-cli/pull/15180)): Fix older Quarto versions failing to render with `RangeError: could not deserialize value` once a Quarto built on a newer Deno has used the same cache. Also fix a project cache that already has entries failing to clear with `Path must be a string`.
- ([#15198](https://github.com/quarto-dev/quarto-cli/issues/15198)): Fix `quarto add`, `quarto use template`, `quarto use brand` and `quarto install tinytex` failing to unzip on Windows when a Group Policy blocks running `.bat` files from the temporary folder, and when a path contains an apostrophe.
2 changes: 1 addition & 1 deletion package/scripts/vendoring/vendor.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ IF EXIST "!DENO_DIR!" (
PUSHD "!QUARTO_SRC_PATH!"

FOR %%E IN (quarto.ts vendor_deps.ts ..\tests\test-deps.ts ..\package\scripts\deno_std\deno_std.ts) DO (
CALL !DENO_BIN_PATH! install --allow-all --no-config --entrypoint %%E --importmap="!QUARTO_SRC_PATH!\import_map.json" || (
CALL !DENO_BIN_PATH! install --allow-import --no-config --entrypoint %%E --importmap="!QUARTO_SRC_PATH!\import_map.json" || (
ECHO Warning: Failed to vendor %%E, continuing...
)
)
Expand Down
2 changes: 1 addition & 1 deletion package/scripts/vendoring/vendor.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fi
pushd "${QUARTO_SRC_PATH}"
set +e
for entrypoint in quarto.ts vendor_deps.ts ../tests/test-deps.ts ../package/scripts/deno_std/deno_std.ts; do
$DENO_BIN_PATH install --allow-all --no-config --entrypoint $entrypoint "--importmap=$QUARTO_SRC_PATH/import_map.json"
$DENO_BIN_PATH install --allow-import --no-config --entrypoint $entrypoint "--importmap=$QUARTO_SRC_PATH/import_map.json"
done
set -e
popd
2 changes: 1 addition & 1 deletion src/command/check/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ async function checkVersions(conf: CheckConfiguration) {
const versionConstraints: [string | undefined, string, string][] = [
[pandocVersion, "3.10.0", "Pandoc"],
[sassVersion, "1.101.0", "Dart Sass"],
[denoVersion, "2.7.14", "Deno"],
[denoVersion, "2.9.8", "Deno"],
[typstVersion, "0.15.1", "Typst"],
];
const checkData: [string | undefined, string, string][] = versionConstraints
Expand Down
2 changes: 1 addition & 1 deletion src/core/lib/yaml-intelligence/parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export async function getTreeSitter(): Promise<any> {

const treeSitterYamlJson = (await import(
"../../../resources/editor/tools/yaml/tree-sitter-yaml.json",
{ assert: { type: "json" } }
{ with: { type: "json" } }
)).default as { data: number[] };

const YAML = await Parser.Language.load(
Expand Down
2 changes: 1 addition & 1 deletion src/core/lib/yaml-intelligence/yaml-intelligence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1208,7 +1208,7 @@ async function init(
const ideInit = async () => {
const resourceModule = (await import(
"../../../resources/editor/tools/yaml/yaml-intelligence-resources.json",
{ assert: { type: "json" } }
{ with: { type: "json" } }
)).default as Record<string, unknown>;

await getTreeSitter();
Expand Down
11 changes: 11 additions & 0 deletions src/core/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,17 @@ export function logError(e: unknown, defaultShowStack = true) {
// print error name if requested
let message = err.printName ? `${err.name}: ${err.message}` : err.message;

// runtime errors such as Deno's "fetch failed" carry the reason in `cause`
const seen = new Set<unknown>([err]);
for (
let cause = err.cause;
cause instanceof Error && !seen.has(cause);
cause = cause.cause
) {
seen.add(cause);
message = `${message}: ${cause.message}`;
}

if (e instanceof InternalError) {
// always print stack information of internal errors
message = message +
Expand Down
4 changes: 2 additions & 2 deletions src/core/port.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ import { kLocalhost } from "./port-consts.ts";
const kMinPort = 3000;
const kMaxPort = 8000;

function isPortSafe(port: number): boolean {
export function isPortSafe(port: number): boolean {
// cf https://superuser.com/a/188070
// and netwerk/base/nsIOService.cpp in Firefox's source
//
// excludes port numbers that Chrome or Firefox consider unsafe
return ![
3659, // apple-sasl / PasswordServer
4045, // lockd
4160, // sieve
4190, // sieve
5060, // sip
5061, // sips
6000, // X11
Expand Down
7 changes: 5 additions & 2 deletions src/publish/posit-connect-cloud/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ export class PositConnectCloudClient {
);
}

public async uploadBundle(uploadUrl: string, bundleData: Uint8Array) {
public async uploadBundle(
uploadUrl: string,
bundleData: Uint8Array<ArrayBuffer>,
) {
publishDebug(
`Uploading bundle (${bundleData.length} bytes)`,
);
Expand Down Expand Up @@ -290,7 +293,7 @@ export class PositConnectCloudClient {
method: string,
url: string,
headers: Record<string, string>,
body?: string | Uint8Array,
body?: string | Uint8Array<ArrayBuffer>,
): Promise<Response> {
await this.ensureValidToken_();
const buildHeaders = () => ({
Expand Down
55 changes: 25 additions & 30 deletions src/resources/editor/tools/vs-code.mjs

Large diffs are not rendered by default.

55 changes: 25 additions & 30 deletions src/resources/editor/tools/yaml/web-worker.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions tests/docs/search/issue-9905/navbar/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/search/issue-9905/sidebar/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/site-navigation/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/drafts-default/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/drafts-env/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/drafts-gone/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/drafts-preprocessor/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/drafts-visible/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/drafts/no-drafts/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/issue-3686/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 2 additions & 0 deletions tests/docs/websites/issue-5756/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.quarto/

**/*.quarto_ipynb
2 changes: 1 addition & 1 deletion tests/smoke/axe/axe-transport-failclosed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function unanswerable(browser: ScanBrowser): Promise<unknown> {
* rather than passing it.
*/
async function settled(p: Promise<unknown>): Promise<string> {
let timer: number | undefined;
let timer: ReturnType<typeof setTimeout> | undefined;
try {
await Promise.race([
p,
Expand Down
81 changes: 81 additions & 0 deletions tests/unit/core/log-error.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* log-error.test.ts
*
* Copyright (C) 2026 Posit Software, PBC
*/

import { test } from "../../test.ts";
import { printsMessage } from "../../verify.ts";
import { logError } from "../../../src/core/log.ts";

// Deno's fetch rejects with TypeError("fetch failed") and keeps the reason
// (TLS, DNS, connection) only in `cause`.
test({
name: "logError prints the cause of a failed fetch",
type: "unit",
context: {},
// deno-lint-ignore require-await
execute: async () => {
logError(
new TypeError("fetch failed", {
cause: new Error(
"error sending request for url (https://example.com/): client error (Connect): invalid peer certificate: certificate expired",
),
}),
);
},
verify: [
printsMessage({
level: "ERROR",
regex: /fetch failed: error sending request .*certificate expired/,
}),
],
});

test({
name: "logError prints every cause in a chain",
type: "unit",
context: {},
// deno-lint-ignore require-await
execute: async () => {
logError(
new Error("outer", {
cause: new Error("middle", { cause: new Error("inner") }),
}),
);
},
verify: [
printsMessage({ level: "ERROR", regex: /outer: middle: inner/ }),
],
});

test({
name: "logError stops at a self-referencing cause",
type: "unit",
context: {},
// deno-lint-ignore require-await
execute: async () => {
const err = new Error("self");
err.cause = err;
logError(err);
},
verify: [
printsMessage({ level: "ERROR", regex: /^self$/m }),
],
});

test({
name: "logError stops at a cause cycle",
type: "unit",
context: {},
// deno-lint-ignore require-await
execute: async () => {
const first = new Error("first");
const second = new Error("second", { cause: first });
first.cause = second;
logError(first);
},
verify: [
printsMessage({ level: "ERROR", regex: /^first: second$/m }),
],
});
45 changes: 45 additions & 0 deletions tests/unit/core/port.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* port.test.ts
*
* Copyright (C) 2026 Posit Software, PBC
*/

import { unitTest } from "../../test.ts";
import { assert } from "../../asserts.ts";
import { isPortSafe } from "../../../src/core/port.ts";

// Quarto fetches from the servers it starts on ports from findOpenPort
// (e.g. waiting for headless Chrome in src/core/cri/launch.ts). Deno's fetch
// refuses the Fetch standard's "bad ports", so every port isPortSafe accepts
// must be one Deno's fetch will request.
unitTest(
"isPortSafe accepts no port that Deno's fetch blocks",
async () => {
const candidates: number[] = [];
for (let port = 3000; port < 8000; ++port) {
if (isPortSafe(port)) candidates.push(port);
}
const blocked: number[] = [];
const kBatch = 500;
for (let i = 0; i < candidates.length; i += kBatch) {
await Promise.all(
candidates.slice(i, i + kBatch).map(async (port) => {
try {
const response = await fetch(`http://127.0.0.1:${port}/`, {
signal: AbortSignal.timeout(250),
});
await response.body?.cancel();
} catch (e) {
if (String(e).includes(`port ${port} are blocked`)) {
blocked.push(port);
}
}
}),
);
}
assert(
blocked.length === 0,
`isPortSafe accepts ports Deno's fetch blocks: ${blocked.join(", ")}`,
);
},
);
Loading
Loading