惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
N
News and Events Feed by Topic
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
The Cloudflare Blog
H
Heimdal Security Blog
Schneier on Security
Schneier on Security
Engineering at Meta
Engineering at Meta
Google Online Security Blog
Google Online Security Blog
宝玉的分享
宝玉的分享
AI
AI
The GitHub Blog
The GitHub Blog
MongoDB | Blog
MongoDB | Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
The Last Watchdog
The Last Watchdog
T
Troy Hunt's Blog
S
Security @ Cisco Blogs
H
Hacker News: Front Page
F
Fortinet All Blogs
博客园_首页
S
Secure Thoughts
N
News and Events Feed by Topic
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
Spread Privacy
Spread Privacy
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Hugging Face - Blog
Hugging Face - Blog
Hacker News: Ask HN
Hacker News: Ask HN
C
CXSECURITY Database RSS Feed - CXSecurity.com
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
L
LINUX DO - 最新话题
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Schneier on Security
Know Your Adversary
Know Your Adversary
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Scott Helme
Scott Helme
P
Privacy & Cybersecurity Law Blog
S
Securelist
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
O
OpenAI News
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
PCI Perspectives
PCI Perspectives
L
LangChain Blog
雷峰网
雷峰网
Security Archives - TechRepublic
Security Archives - TechRepublic
V2EX - 技术
V2EX - 技术

Deno

Deno 2.8 | Deno Claw Patrol: an open-source security firewall for agents | Deno Fresh 2.3: Zero JS by default, View Transitions, and Temporal support | Deno Deno 2.7: Temporal API, Windows ARM, and npm overrides | Deno Build a dinosaur runner game with Deno, pt. 6 | Deno Build a dinosaur runner game with Deno, pt. 5 | Deno Deno Deploy is Generally Available | Deno Introducing Deno Sandbox | Deno Build a dinosaur runner game with Deno, pt. 4 | Deno Build a dinosaur runner game with Deno, pt. 3 | Deno Build a dinosaur runner game with Deno, pt. 2 | Deno React / Next.js Denial-of-Service Vulnerability: Deno Deploy users protected | Deno Deno 2.6: dx is the new npx | Deno Build a dinosaur runner game with Deno, pt. 1 | Deno React Server Functions / Next.js Vulnerability: Deno Deploy users protected | Deno My highlights from the new Deno Deploy | Deno Deno's Other Open Source Projects | Deno How Deno protects against npm exploits | Deno Help Us Raise $200k to Free JavaScript from Oracle | Deno Deno 2.5: Permissions in the config file | Deno Fresh 2.0 Graduates to Beta, Adds Vite Support | Deno Deno 2.4: deno bundle is back | Deno JavaScript™ Trademark Update | Deno What's coming to JavaScript | Deno A brief history of JavaScript | Deno Reports of Deno's Demise Have Been Greatly Exaggerated | Deno An Update on Fresh | Deno How Plaid migrated 100 services to a new database platform 5x faster with Deno | Deno Deno 2.3: Improved deno compile, local npm packages, and more | Deno Add JSR packages with pnpm and Yarn | Deno Zero-config Debugging with Deno and OpenTelemetry | Deno Exploring Art with TypeScript, Jupyter, Polars, and Observable Plot | Deno Deno v Oracle Update 3: Fighting the JavaScript Trademark | Deno Build a custom RAG AI agent in TypeScript and Jupyter | Deno How to get deep traces in your Node.js backend with OTel and Deno | Deno toranoana.deno #20 登録受付中(2025年3月14日) | Deno Node just added TypeScript support. What does that mean for Deno? | Deno The Dino 🦕, the Llama 🦙, and the Whale 🐋 | Deno Publish a lint rule, get a prize | Deno Deno 2.2: OpenTelemetry, Lint Plugins, node:sqlite | Deno If you're not using npm specifiers, you're doing it wrong | Deno How Deno's documentation is evolving | Deno Oracle justified its JavaScript trademark with Node.js—now it wants that ignored | Deno Introducing the JSR open governance board | Deno Intro to Wasm in Deno | Deno Announcing OpenAI on JSR | Deno Deno in 2024 | Deno Goodbye WinterCG, welcome WinterTC | Deno Build a SolidJS app with Deno | Deno Run your Next.js SSR app on Deno Deploy | Deno Solve Advent of Code 2024 with Deno and Win Prizes! | Deno Deno v. Oracle: Canceling the JavaScript Trademark | Deno Deno 2.1: Wasm Imports and other enhancements | Deno Build a Typesafe API with tRPC and Deno | Deno Self-contained Executable Programs with Deno Compile | Deno Build a Database App with Drizzle ORM and Deno | Deno Introducing your new JavaScript package manager: Deno | Deno Announcing Growthbook on JSR | Deno Build an Astro site with Deno | Deno How to convert CommonJS to ESM | Deno Announcing Deno 2 | Deno The Final Touches: What’s New In v2.0.0-rc.10 | Deno Announcing Stable V8 Bindings for Rust | Deno Deno 2.0 Release Candidate | Deno Secure, efficient private npm registries with Cloudsmith and Deno | Deno Painting the Plane as We Fly It: Designing JSR | Deno Introducing Web Cache API support on Deno Deploy | Deno Deno 1.46: The Last 1.x Release | Deno Protect your cloud spend with new Deno Deploy spend limits | Deno What we got wrong about HTTP imports | Deno Benchmarking AWS Lambda Cold Starts Across JavaScript Runtimes | Deno Announcing Supabase on JSR | Deno Deno 1.45: Workspace and Monorepo Support | Deno Introducing KV Backup for Deno Subhosting | Deno A Gentle Intro to TypeScript | Deno Announcing Hono on JSR | Deno How We Made the Deno Language Server Ten Times Faster | Deno How the Guardian uses Deno to audit accessibility and performance across their 2.7 million articles | Deno Introducing More Flexible Domain Association for Deno Subhosting | Deno The stabilization process of the Standard Library has begun | Deno Deno 1.44: Private npm registries, improved Node.js compat, and performance boosts | Deno How we built a secure, performant, multi-tenant cloud platform to run untrusted code | Deno The Deno Standard Library is now available on JSR | Deno How to document your JavaScript package | Deno Your Low Code Solution Needs an Escape Hatch | Deno Deno 1.43: Improved Language Server performance | Deno How Slack used Deno to save months of engineering effort in launching their new platform | Deno JSR Is Not Another Package Manager | Deno Announcing the Hookdeck SDK on JSR | Deno Announcing the Neon Serverless Driver on JSR | Deno An intro to TSConfig for JavaScript Developers | Deno How we built JSR | Deno How Netlify used Deno Subhosting to build a successful edge functions product | Deno Introducing Simpler Project Creation in Deno Deploy | Deno Deno 1.42: Better dependency management with JSR | Deno Introducing deployctl, the command line interface for Deno Deploy | Deno Introducing JSR - the JavaScript Registry | Deno How to add Monaco to a Next.js app and securely run untrusted user code | Deno Survey Results and Roadmap | Deno Deno 1.41: smaller deno compile binaries | Deno
Deno 1.17 Release Notes | Deno
2021-12-16 · via Deno

Deno 1.17 has been tagged and released with the following features and changes:

  • Import assertions and JSON modules
  • Improvements to the Web Cryptography API
  • --no-check=remote flag
  • Unstable support for ALPN in Deno.connectTls()
  • Unref timers
  • Updates to abort reasons in AbortSignal
  • Updates to the Deno Language Server
  • Updates to deno test
  • Updates to the file watcher
  • Updates to the REPL
  • Updates to the FFI API
  • TypeScript 4.5
  • Updates to the standard library

If you already have Deno installed, you can upgrade to 1.17 by running:

If you are installing Deno for the first time, you can use one of the methods listed below:


curl -fsSL https://deno.land/x/install/install.sh | sh


iwr https://deno.land/x/install/install.ps1 -useb | iex


brew install deno


scoop install deno


choco install deno

New features and changes

Import assertions and JSON modules

Deno v1.17 ships with full support for import assertions and JSON modules.

Import assertions is a Stage 3 proposal that shipped in V8 earlier this year. The main use case of this proposal is to allow imports of JSON modules; which without import assertions could pose a security vulnerability.

Prior to this release the only way to read JSON file was to use fetch() or Deno.readTextFile() in combination with JSON.parse(). Starting with this release you can import JSON files directly into your module graph:




const response = await fetch("https://example.com/data.json");
const jsonData = await response.json();
console.log(jsonData);


const text = await Deno.readTextFile("./data.json");
const jsonData = JSON.parse(text);
console.log(jsonData);




import jsonData from "https://exmaple.com/data.json" with { type: "json" };
console.log(jsonData);


import jsonData from "./data.json" with { type: "json" };
console.log(jsonData);

You can also import JSON modules dynamically using import():

const jsonData = await import("./data.json", { assert: { type: "json" } });
console.log(jsonData);

An advantage of using import declarations for JSON modules is that you don’t need to provide permissions to import them; dynamic imports are subject to regular permissions checks.

Improvements to the Web Cryptography API

This release once again adds new features to the Web Cryptography API. With these additions, the API is now nearing feature parity with browsers.

Added in v1.17:

  • crypto.subtle.importKey:
    • support importing RSA keys in SPKI format
    • support importing RSA keys in JWK format
    • support importing AES keys in JWK format
    • support importing EC keys in PKCS#8 format
    • support importing EC keys in SPKI format
    • support importing EC keys in JWK format
  • crypto.subtle.exportKey:
    • support exporting RSA keys in JWK format
    • support exporting AES keys in JWK format
  • crypto.subtle.unwrapKey:
    • support for unwrapping using RSA-OAEP
    • support for unwrapping using AES-GCM

The last few features (elliptic curve key imports and exports, and more AES encryption/decryption formats) are still in development, but are coming along nicely and will likely be available in the next release.

See progress here: denoland/deno#11690

Thanks to Yacine Hmito, Sean Michael Wykes and Divy Srivastava for contributing these improvements.

--no-check=remote flag

One of the common challenges with Deno is that sometimes remote dependencies don’t type check properly even though they have the correct runtime behavior. When type checking your local code this can cause diagnostics to be issued and your program not to run even when you have no control over the remote dependencies.

The --no-check=remote option was added to help with this. When this flag is passed, the program will be type checked as a whole, but any diagnostics that are coming from a remote module will be discarded. If there are no local diagnostics, your program will run.

Pass the option on the command line:

> deno run --no-check=remote server.ts

We encourage you to experiment with this flag and report feedback. We think this mode might be a good default type checking configuration for future releases of Deno.

Unstable support for negotiating ALPN for Deno.connectTls()

ALPN is a TLS extension that allows a client to negotiate a communication protocol with a server. This is used when using HTTP/2 for example, to negotiate if the server supports HTTP/2.

Up to now Deno did not support manually negotiating ALPN. This release adds that capability. If you are interested in this functionality, we’d love to hear your feedback.

An example:

const conn = await Deno.connectTls({
  hostname: "example.com",
  port: 443,
  alpnProtocols: ["h2", "http/1.1"],
});
const { alpnProtocol } = await conn.handshake();
if (alpnProtocol !== null) {
  console.log("Negotiated protocol:", alpnProtocol);
} else {
  console.log("No protocol negotiated");
}

Thanks to Yury Selivanov for contributing this feature.

Unref timers

This release adds two new unstable APIs:

  • Deno.unrefTimer(id: number)
  • Deno.refTimer(id: number)

These APIs can be used to change the behavior of timers (setTimeout and setInterval) to block or not block the event loop from exiting.

By default all timers block the event loop from exiting until they are cleared.

In the following example the program will finish after printing hello from timeout after 5 seconds.

setTimeout(() => {
  console.log("hello from timeout");
}, 5000);

console.log("hello world!");

However sometimes it’s not desired for timers to prevent the event loop from exiting. An example of this behavior is periodic collection of telemetry data:


setInterval(() => {
  const data = collectSomeData();
  fetch("https://example.com/telemetry", { method: "POST", body: data })
    .catch(() => {});
}, 5000);


await longRunningTask();

In the above example, we want our program to exit once longRunningTask finishes. To achieve this behavior we can “unref” the interval:


const intervalId = setInterval(() => {
  const data = collectSomeData();
  fetch("https://example.com/telemetry", { body: data }).catch(() => {});
}, 5000);


Deno.unrefTimer(intervalId);


await longRunningTask();

Updates to abort reasons in AbortSignal

The last release added support for aborting AbortSignals with specific abort reasons. These reasons are now correctly propagated through these APIs:

  • Deno.readFile() and Deno.readTextFile()
  • Deno.writeFile() and Deno.writeTextFile()
  • All of the WHATWG streams APIs (ReadableStream, TransformStream, WritableStream, and friends).
  • WebSocketStream
  • fetch, Request, and Response

In addition we now support the new throwIfAborted() method on AbortSignal that can be used to synchronously throw an error if the signal has already been aborted.

const controller = new AbortController();
const signal = controller.signal;

try {
  signal.throwIfAborted();
} catch (err) {
  unreachable(); 
}

controller.abort("Hello World");

try {
  signal.throwIfAborted();
  unreachable(); 
} catch (err) {
  assertEquals(err, "Hello World");
}

Thanks to Andreu Botella for contributing these changes.

Updates to the Deno Language Server

The Deno Language Server adds support for a revised module registry suggestion protocol. This will allow large package registries (like NPM) to provide partial result sets, intelligent incremental search, and documentation details about packages and modules as part of the editing experience. Adding the new capabilities to deno.land/x and deno.land/std will happen soon after 1.17 ships.

Another behind the scenes improvement is that the values from the package registries will respect the cache headers supplied. Previously, the results from a registry were cached indefinitely and required users to clear the cache manually to get new or changed results.

To take advantage of these features, ensure that your editor’s Deno configuration includes supported registries in the deno.suggest.imports.hosts are configured. For example:

{
  "deno.suggest.imports.hosts": {
    "https://deno.land": true,
    "https://cdn.nest.land": true,
    "https://crux.land": true
  }
}

While not related directly to the Deno 1.17 release, vscode_deno is being updated to enable known package registries which support the registry protocol by default. This will increase visibility of this feature, making it easier for people to find code to run under Deno.

With the new features of the registry protocol, we hope to work with the likes of esm.sh, Skypack and JSPM to provide intelligent registries to make it easy to consume code from the wider JavaScript and TypeScript ecosystem.

If you want to add support for import completions to your own registry, you can read more about the registry protocol here.

Also, the Deno Language Server reaches a level of maturity, adding a couple of outstanding features, including goto type definition support and workspace symbol searching.

Updates to deno test

Deno ships with a built-in test runner. You can register tests using Deno.test() API. Until now there were two available overloads of the API - “shorthand” and “definition” based. The shorthand works well for simple tests, while the definition gives the most control, allowing for example tests to be ignored:

import { assertEquals } from "https://deno.land/std@0.118.0/testing/asserts.ts";

Deno.test("My test description", (): void => {
  assertEquals("hello", "hello");
});

Deno.test({
  name: "example test",
  ignore: Deno.build.os == "windows",
  fn(): void {
    assertEquals("world", "world");
  },
});

It becomes quite cumbersome if you need to ignore/focus a single test that was written using “shorthand” overload. You would need to rewrite whole test to use the “definition” overload. To alleviate this problem and provide more flexibility in writing tests we’ve added four more overloads to the Deno.test() API.

import { assertEquals } from "https://deno.land/std@0.118.0/testing/asserts.ts";

Deno.test(function myTestName(): void {
  assertEquals("hello", "hello");
});

Deno.test("My test description", { permissions: { read: true } }, (): void => {
  assertEquals("hello", "hello");
});

Deno.test(
  { name: "My test description", permissions: { read: true } },
  (): void => {
    assertEquals("hello", "hello");
  },
);

Deno.test({ permissions: { read: true } }, function myTestName(): void {
  assertEquals("hello", "hello");
});

You can now mix both forms, and provide a partial “definition” as the first or second argument.

Another update is for users using unstable test steps API. The final test report output will now include number of test steps with distinction for passed/ignored/failed steps. The test step API is scheduled to be stabilized in v1.18

Deno.test("nested failure", async (t) => {
  const success = await t.step("step 1", async (t) => {
    let success = await t.step("inner 1", () => {
      throw new Error("Failed.");
    });
    if (success) throw new Error("Expected failure");

    success = await t.step("inner 2", () => {});
    if (!success) throw new Error("Expected success");
  });

  if (success) throw new Error("Expected failure");
});
$ deno test --unstable test.ts
running 1 test from file:///dev/test.ts
test nested failure ...
  test step 1 ...
    test inner 1 ... FAILED (11ms)
      Error: Failed.
          at file:///dev/test.ts:4:13
          at testStepSanitizer (deno:runtime/js/40_testing.js:187:13)
          at asyncOpSanitizer (deno:runtime/js/40_testing.js:68:15)
          at resourceSanitizer (deno:runtime/js/40_testing.js:138:13)
          at exitSanitizer (deno:runtime/js/40_testing.js:170:15)
          at TestContext.step (deno:runtime/js/40_testing.js:800:19)
          at file:///dev/test.ts:3:27
          at testStepSanitizer (deno:runtime/js/40_testing.js:187:13)
          at asyncOpSanitizer (deno:runtime/js/40_testing.js:68:15)
          at resourceSanitizer (deno:runtime/js/40_testing.js:138:13)
    test inner 2 ... ok (11ms)
  FAILED (32ms)
FAILED (44ms)

failures:

nested failure
Error: 1 test step failed.
    at runTest (deno:runtime/js/40_testing.js:432:11)
    at async Object.runTests (deno:runtime/js/40_testing.js:541:22)

failures:

    nested failure

test result: FAILED. 0 passed (1 step); 1 failed (2 steps); 0 ignored; 0 measured; 0 filtered out (66ms)

Updates to the file watcher

Deno ships with a built-in file watcher that can be activated using the --watch flag.

The file watcher automatically discovers files to watch based on the files contained in module graph (for the deno run subcommand) or file paths passed as arguments (for subcommands like deno lint or deno fmt).

In this release the --watch flag for deno run accepts an optional list of external files that should also be watched for changes.

$ deno run --watch=data/external.txt script.ts

Thanks to Jasper van den End for contributing this feature.

A small quality of life improvement to the watcher is automatic clearing of terminal screen on restart:

Updates to the REPL

Module specifier completions

The REPL (deno repl) now provides completions for relative specifiers on the file system and absolute specifiers from the deno.land registry.

These completions can be requested by pressing the <TAB> key while typing a module specifier.

Node.js compatibility mode

The REPL can now be run in Node.js compatibility mode; allowing access to Node’s global variables (eg. process), import CommonJS modules with require() and providing ESM resolution compatible with Node.js. To enter REPL in compatibility mode use deno repl --compat --unstable.

$ deno repl --compat --unstable
Deno 1.17.0
exit using ctrl+d or close()
> console.log(process)
process {
  _events: {},
  _eventsCount: 0,
  _maxListeners: undefined,
  ...
}

Ignore certificate errors

This release adds the --unsafely-ignore-certificate-errors flag to the deno repl subcommand that allows disabling TLS certificate verification.

Note that this is a dangerous setting. You should not use this flag to silence certificate errors. Disabling TLS certificate verification (ignoring certificate errors) makes TLS pointless because it allows MITM attacks. Data sent over a TLS connection is not confidential if the certificate has not been verified and trusted.

Read more in Deno 1.13 Release Notes blog post.

Thanks to VishnuJin for contributing this feature.

Updates to the FFI API

Following improvements to the FFI API in v1.15 this release adds two new APIs for working with pointers across languages boundary: Deno.UnsafePointer and Deno.UnsafePointerView. Additionally buffer parameter type was renamed to pointer.

Example:


static BUFFER: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];

#[no_mangle]
pub extern "C" fn return_buffer() -> *const u8 {
  BUFFER.as_ptr()
}

#[no_mangle]
pub extern "C" fn is_null_ptr(ptr: *const u8) -> u8 {
  ptr.is_null() as u8
}

const [libPrefix, libSuffix] = {
  darwin: ["lib", "dylib"],
  linux: ["lib", "so"],
  windows: ["", "dll"],
}[Deno.build.os];
const libPath = `${targetDir}/${libPrefix}test_ffi.${libSuffix}`;

const dylib = Deno.dlopen(libPath, {
  "return_buffer": { parameters: [], result: "pointer" },
  "is_null_ptr": { parameters: ["pointer"], result: "u8" },
});

const ptr = dylib.symbols.return_buffer();
dylib.symbols.print_buffer(ptr, 8);
const ptrView = new Deno.UnsafePointerView(ptr);
const into = new Uint8Array(6);
const into2 = new Uint8Array(3);
const into2ptr = Deno.UnsafePointer.of(into2);
const into2ptrView = new Deno.UnsafePointerView(into2ptr);
const into3 = new Uint8Array(3);
ptrView.copyInto(into);
console.log([...into]);
ptrView.copyInto(into2, 3);
console.log([...into2]);
into2ptrView.copyInto(into3);
console.log([...into3]);
const string = new Uint8Array([
  ...new TextEncoder().encode("Hello from pointer!"),
  0,
]);
const stringPtr = Deno.UnsafePointer.of(string);
const stringPtrview = new Deno.UnsafePointerView(stringPtr);
console.log(stringPtrview.getCString());
console.log(stringPtrview.getCString(11));
console.log(Boolean(dylib.symbols.is_null_ptr(ptr)));
console.log(Boolean(dylib.symbols.is_null_ptr(null)));
console.log(Boolean(dylib.symbols.is_null_ptr(Deno.UnsafePointer.of(into))));
$ deno run --allow-ffi --allow-read --unstable test_ffi.js
[1, 2, 3, 4, 5, 6, 7, 8]
[ 1, 2, 3, 4, 5, 6 ]
[ 4, 5, 6 ]
[ 4, 5, 6 ]
Hello from pointer!
pointer!
false
true
false

We are already seeing interesting projects using these new APIs, eg. native bindings to SQLite C API: https://deno.land/x/sqlite3

FFI requires the --allow-ffi and the --unstable flags. Beware that enabling FFI will effectively disable all security protections in Deno.

Thank you to Elias Sjögreen for contributing this feature.

TypeScript 4.5

Deno 1.17 ships with the latest stable version of TypeScript. This was part of what unlocked the ability to support import assertions. Also, a new way to import types is supported:

Previously it was recommended to import items only be used in the type position this way:

import { A } from "https://example.com/mod.ts";
import type { B } from "https://example.com/mod.ts";

But now these can be combined into a single import statement:

import { A, type B } from "https://example.com/mod.ts";

Also, TypeScript 4.5 added support for .mts and .d.mts extensions as well as first class support for .mjs files, which are properly handled in Deno 1.17.

For more information on new features in TypeScript see TypeScript’s 4.5 blog post

Updates to the standard library

This release includes a number of new features and breaking changes to the standard library. We are hard at work at cleaning up the standard library to get it into a state where it can stabilized.

Breaking changes

In version 0.118.0 of deno_std following APIs undergone breaking changes:

  • ws module was removed - instead use Deno.upgradeWebSocket() API
  • assertThrowsAsync from testing/asserts.ts was removed - instead use assertRejects API from the same module
  • http/server_legacy.ts was removed - a legacy implementation of HTTP server, instead use http/server.ts
  • copy API was removed from fs/mod.ts - instead import this API directly from fs/copy.ts
  • onSignal was removed from signals module - instead use Deno.addSignalListener() API
  • findLast and findLastIndex were removed from collections module
  • http server module no longer accepts string address, use { host: string, port: number } interface instead

New HTTP server options

Previously the serve function in the std/http module would swallow all errors produced by the HTTP handler function. This release changes that behavior, so that the server will log all errors produced by handlers using console.error. You can customize the behavior by passing a custom onError function to the serve options.

import { Server } from "https://deno.land/std@0.118.0/http/server.ts";

const port = 4505;
const handler = (request: Request) => {
  const body = `Your user-agent is:\n\n${
    request.headers.get(
      "user-agent",
    ) ?? "Unknown"
  }`;

  return new Response(body, { status: 200 });
};

const onError = (_error: unknown) => {
  return new Response("custom error page", { status: 500 });
};

const server = new Server({ port, handler, onError });

Additions to std/collections

std/collections is a playground for us to experiment with more advanced functions for iterating over arrays and iterables. This release adds aggregateGroups. It applies the given aggregator to each group in the given grouping, returning the results together with the respective group keys:

import { aggregateGroups } from "https://deno.land/std@0.118.0/collections/mod.ts";
import { assertEquals } from "https://deno.land/std@0.118.0/testing/asserts.ts";
const foodProperties = {
  "Curry": ["spicy", "vegan"],
  "Omelette": ["creamy", "vegetarian"],
};
const descriptions = aggregateGroups(
  foodProperties,
  (current, key, first, acc) => {
    if (first) {
      return `${key} is ${current}`;
    }
    return `${acc} and ${current}`;
  },
);
assertEquals(descriptions, {
  "Curry": "Curry is spicy and vegan",
  "Omelette": "Omelette is creamy and vegetarian",
});

Byte formatting using std/fmt/bytes

A new std/fmt/bytes module has been added to the standard library. It provides a function for formatting bytes in a human readable format:

import { prettyBytes } from "https://deno.land/std@0.118.0/fmt/bytes.ts";
import { assertEquals } from "https://deno.land/std@0.118.0/testing/asserts.ts";

assertEquals(prettyBytes(1024), "1.02 kB");
assertEquals(prettyBytes(1024, { binary: true }), "1 kiB");

This API is a port of the popular pretty-bytes npm package.