diff --git a/src/content/changelogs-next/2025-01-28-nodejs-compat-improvements.mdx b/src/content/changelogs-next/2025-01-28-nodejs-compat-improvements.mdx new file mode 100644 index 00000000000000..7b9bc9595c70a1 --- /dev/null +++ b/src/content/changelogs-next/2025-01-28-nodejs-compat-improvements.mdx @@ -0,0 +1,91 @@ +--- +title: Support for Node.js DNS, Net, and Timer APIs in Workers +description: Node.js APIs from the node:dns, node:net, and node:timers modules are now available when using nodejs_compat. +products: + - workers +date: 2025-01-28T13:00:00Z +--- + +import { Render, PackageManagers, TypeScriptExample } from "~/components"; + +When using a Worker with the [`nodejs_compat`](/workers/runtime-apis/nodejs/) compatibility flag enabled, you can now use the following Node.js APIs: + +- [`node:net`](/workers/runtime-apis/nodejs/net/) +- [`node:dns`](/workers/runtime-apis/nodejs/dns/) +- [`node:timers`](/workers/runtime-apis/nodejs/timers/) + +#### node:net + +This makes it possible to connect to databases such as [MySQL](https://www.mysql.com/), [PostgreSQL](https://www.postgresql.org/), +[Redis](https://redis.io/), or [MongoDB](https://github.com/mongodb/mongo). Though for production use, we recommend that you connect +using TLS, which can be done with the [`cloudflare:sockets`](/workers/runtime-apis/tcp-sockets/#connect) +module, or prefereably by using [Hyperdrive](/hyperdrive), which includes +[connection pooling](/hyperdrive/configuration/how-hyperdrive-works/#connection-pooling) +and [query caching](/hyperdrive/configuration/how-hyperdrive-works/#query-caching). + + +```ts +import net from "node:net"; + +const exampleIP = "127.0.0.1"; + +export default { + async fetch(req): Promise { + const socket = new net.Socket(); + socket.connect(4000, exampleIP, function () { + console.log("Connected"); + }); + + socket.write("Hello, Server!"); + socket.end(); + + return new Response("Wrote to server", { status: 200 }); + }, +} satisfies ExportedHandler; +```` + + +Additionally, you can now use other APIs incliding [`net.BlockList`](https://nodejs.org/api/net.html#class-netblocklist) and +[`net.SocketAddress`](https://nodejs.org/api/net.html#class-netsocketaddress). + +Note that [`net.Server`](https://nodejs.org/api/net.html#class-netserver) is not supported. + +#### node:dns + +You can use [`node:dns`](https://nodejs.org/api/dns.html) for name resolution via [DNS over HTTPS](/1.1.1.1/encryption/dns-over-https/) using +[Cloudflare DNS](https://www.cloudflare.com/application-services/products/dns/) at 1.1.1.1. + + +```ts +import dns from "node:dns"; + +dns.lookup("example.org", (_err: any, address: string, ipFamily: number) => + console.log(`address: ${address} family: IPv${ipFamily}`)); +```` + + + +All `node:dns` functions are available, except `lookup`, `lookupService`, and `resolve` which throw "Not implemented" errors when called. + +#### node:timers + +You can use [`node:timers`](https://nodejs.org/api/timers.html) to schedule functions to be called at some future period of time. + +This includes [`setTimeout`](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args) for calling a function after a delay, +[`setInterval`](https://nodejs.org/api/timers.html#setintervalcallback-delay-args) for calling a function repeatedly, +and [`setImmediate`](https://nodejs.org/api/timers.html#setimmediatecallback-args) for calling a function in the next iteration of the event loop. + + +```ts +import timers from "node:timers"; + +console.log("first"); +timers.setTimeout(() => { + console.log("last"); +}, 10); + +timers.setTimeout(() => { + console.log("next"); +}); +``` + diff --git a/src/content/docs/workers/runtime-apis/nodejs/assert.mdx b/src/content/docs/workers/runtime-apis/nodejs/assert.mdx index 2f2fd14973dca0..27073dff3bdb86 100644 --- a/src/content/docs/workers/runtime-apis/nodejs/assert.mdx +++ b/src/content/docs/workers/runtime-apis/nodejs/assert.mdx @@ -1,39 +1,35 @@ --- pcx_content_type: configuration title: assert - --- -import { Render } from "~/components" +import { Render } from "~/components"; The `assert` module in Node.js provides a number of useful assertions that are useful when building tests. ```js -import { - strictEqual, - deepStrictEqual, - ok, - doesNotReject, -} from 'node:assert'; +import { strictEqual, deepStrictEqual, ok, doesNotReject } from "node:assert"; strictEqual(1, 1); // ok! strictEqual(1, "1"); // fails! throws AssertionError -deepStrictEqual({ a: { b: 1 }}, { a: { b: 1 }});// ok! -deepStrictEqual({ a: { b: 1 }}, { a: { b: 2 }});// fails! throws AssertionError +deepStrictEqual({ a: { b: 1 } }, { a: { b: 1 } }); // ok! +deepStrictEqual({ a: { b: 1 } }, { a: { b: 2 } }); // fails! throws AssertionError ok(true); // ok! ok(false); // fails! throws AssertionError await doesNotReject(async () => {}); // ok! -await doesNotReject(async () => { throw new Error('boom') }); // fails! throws AssertionError +await doesNotReject(async () => { + throw new Error("boom"); +}); // fails! throws AssertionError ``` :::note -In the Workers implementation of `assert`, all assertions run in, what Node.js calls, the strict assertion mode. In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example, `deepEqual()` will behave like `deepStrictEqual()`. +In the Workers implementation of `assert`, all assertions run in, what Node.js calls, the strict assertion mode. In strict assertion mode, non-strict methods behave like their corresponding strict methods. For example, `deepEqual()` will behave like `deepStrictEqual()`. ::: Refer to the [Node.js documentation for `assert`](https://nodejs.org/dist/latest-v19.x/docs/api/assert.html) for more information. diff --git a/src/content/docs/workers/runtime-apis/nodejs/dns.mdx b/src/content/docs/workers/runtime-apis/nodejs/dns.mdx new file mode 100644 index 00000000000000..53b18f69aa3e88 --- /dev/null +++ b/src/content/docs/workers/runtime-apis/nodejs/dns.mdx @@ -0,0 +1,28 @@ +--- +pcx_content_type: configuration +title: dns +--- + +import { Render, TypeScriptExample } from "~/components"; + + + +You can use [`node:dns`](https://nodejs.org/api/dns.html) for name resolution via [DNS over HTTPS](/1.1.1.1/encryption/dns-over-https/) using +[Cloudflare DNS](https://www.cloudflare.com/application-services/products/dns/) at 1.1.1.1. + + +```ts +import dns from "node:dns"; + +dns.lookup("example.org", (_err: any, address: string, ipFamily: number) => + console.log(`address: ${address} family: IPv${ipFamily}`)); +``` + + +:::note + +DNS requests will execute a subrequest, counts for your [Worker's subrequest limit](/workers/platform/limits/#subrequests). + +::: + +The full `node:dns` API is documented in the [Node.js documentation for `node:dns`](https://nodejs.org/api/dns.html). diff --git a/src/content/docs/workers/runtime-apis/nodejs/net.mdx b/src/content/docs/workers/runtime-apis/nodejs/net.mdx new file mode 100644 index 00000000000000..f25af8183c10cc --- /dev/null +++ b/src/content/docs/workers/runtime-apis/nodejs/net.mdx @@ -0,0 +1,50 @@ +--- +pcx_content_type: configuration +title: net +--- + +import { Render, TypeScriptExample } from "~/components"; + + + +You can use [`node:net`](https://nodejs.org/api/net.html) to create a direct connection to servers via a TCP sockets +with [`net.Socket`](https://nodejs.org/api/net.html#class-netsocket). + +This makes it possible to connect to databases such as [MySQL](https://www.mysql.com/), [PostgreSQL](https://www.postgresql.org/), +[Redis](https://redis.io/), or [MongoDB](https://github.com/mongodb/mongo). Though for production use, we recommend that you connect +using TLS, which can be done with the [`cloudflare:sockets`](/workers/runtime-apis/tcp-sockets/#connect) +module, or prefereably by using [Hyperdrive](/hyperdrive), which includes +[connection pooling](/hyperdrive/configuration/how-hyperdrive-works/#connection-pooling) +and [query caching](/hyperdrive/configuration/how-hyperdrive-works/#query-caching). + +These functions use [`connect`](/workers/runtime-apis/tcp-sockets/#connect) functionality from the built-in `cloudflare:sockets` module. + + +```ts +import net from "node:net"; + +const exampleIP = "127.0.0.1"; + +export default { + async fetch(req): Promise { + const socket = new net.Socket(); + socket.connect(4000, exampleIP, function () { + console.log("Connected"); + }); + + socket.write("Hello, Server!"); + socket.end(); + + return new Response("Wrote to server", { status: 200 }); + }, +} satisfies ExportedHandler; + +``` + + +Additionally, other APIs such as [`net.BlockList`](https://nodejs.org/api/net.html#class-netblocklist) +and [`net.SocketAddress`](https://nodejs.org/api/net.html#class-netsocketaddress) are available. + +Note that the [`net.Server`](https://nodejs.org/api/net.html#class-netserver) class is not supported by Workers. + +The full `node:net` API is documented in the [Node.js documentation for `node:net`](https://nodejs.org/api/net.html). diff --git a/src/content/docs/workers/runtime-apis/nodejs/path.mdx b/src/content/docs/workers/runtime-apis/nodejs/path.mdx index a1c0f4a6030236..259940aed82c90 100644 --- a/src/content/docs/workers/runtime-apis/nodejs/path.mdx +++ b/src/content/docs/workers/runtime-apis/nodejs/path.mdx @@ -1,24 +1,18 @@ --- pcx_content_type: configuration title: path - --- -import { Render } from "~/components" +import { Render } from "~/components"; The [`node:path`](https://nodejs.org/api/path.html) module provides utilities for working with file and directory paths. The `node:path` module can be accessed using: ```js -import path from "node:path" -path.join('/foo', 'bar', 'baz/asdf', 'quux', '..'); +import path from "node:path"; +path.join("/foo", "bar", "baz/asdf", "quux", ".."); // Returns: '/foo/bar/baz/asdf' ``` -:::note - -In the Workers implementation of `path`, the [path.win32](https://nodejs.org/api/path.html#windows-vs-posix) variants of the path API are not implemented, and will throw an exception. -::: - Refer to the [Node.js documentation for `path`](https://nodejs.org/api/path.html) for more information. diff --git a/src/content/docs/workers/runtime-apis/nodejs/timers.mdx b/src/content/docs/workers/runtime-apis/nodejs/timers.mdx new file mode 100644 index 00000000000000..6fddbfb4c456dc --- /dev/null +++ b/src/content/docs/workers/runtime-apis/nodejs/timers.mdx @@ -0,0 +1,43 @@ +--- +pcx_content_type: configuration +title: timers +--- + +import { Render, TypeScriptExample } from "~/components"; + + + +Use [`node:timers`](https://nodejs.org/api/timers.html) APIs to schedule functions to be executed later. + +This includes [`setTimeout`](https://nodejs.org/api/timers.html#settimeoutcallback-delay-args) for calling a function after a delay, +[`setInterval`](https://nodejs.org/api/timers.html#clearintervaltimeout) for calling a function repeatedly, +and [`setImmediate`](https://nodejs.org/api/timers.html#setimmediatecallback-args) for calling a function in the next iteration of the event loop. + + +```ts +import timers from "node:timers"; + +console.log("first"); +timers.setTimeout(() => { + console.log("last"); +}, 10); + +timers.setTimeout(() => { + console.log("next"); +}); +``` + + +:::note +Due to [security-based restrictions on timers](/workers/reference/security-model/#step-1-disallow-timers-and-multi-threading) in Workers, +timers are limited to returning the time of the last I/O. This means that while setTimeout, setInterval, and setImmediate will defer your function execution +until after other events have run, they will not delay them for the full time specified. +::: + +:::note +When called from a global level (on [`globalThis`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/globalThis)), +functions such as `clearTimeout` and `setTimeout` will respect web standards rather than Node.js-specific functionality. For complete Node.js +compatibility, you must call functions from the `node:timers` module. +::: + +The full `node:timers` API is documented in the [Node.js documentation for `node:timers`](https://nodejs.org/api/timers.html).