diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..88337de58 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,22 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Dev Server", + "type": "shell", + "command": "deno task start", + "group": "serve", + "isBackground": true + }, + { + "label": "Dev Server", + "type": "shell", + "command": "deno task start", + "isBackground": true, + "problemMatcher": [ + "$deno" + ], + "group": "serve" + } + ] +} diff --git a/_components/Base.tsx b/_components/Base.tsx index 80fba6d9f..d3265a217 100644 --- a/_components/Base.tsx +++ b/_components/Base.tsx @@ -7,7 +7,10 @@ export default function Base( return ( <>
- +
{children}
diff --git a/_components/Navigation.tsx b/_components/Navigation.tsx index fb5eccad0..723ba4bb6 100644 --- a/_components/Navigation.tsx +++ b/_components/Navigation.tsx @@ -43,7 +43,7 @@ function getSectionData(data: Lume.Data, currentUrl: string) { const childItems = categoryPanel.categories; childItems.push({ - name: `View all ${categoryPanel.total_symbols} symbols`, + name: `All ${categoryPanel.total_symbols} symbols`, href: categoryPanel.all_symbols_href, active: currentUrl.includes("all_symbols"), }); diff --git a/_components/SidebarNav.tsx b/_components/SidebarNav.tsx index 913794d3a..c3efcdff3 100644 --- a/_components/SidebarNav.tsx +++ b/_components/SidebarNav.tsx @@ -1,28 +1,242 @@ +// deno-lint-ignore-file no-explicit-any export default function (data: Lume.Data) { const sectionData = data.sectionData; const currentUrl = data.currentUrl.replace(/\/$/, ""); const isReference = currentUrl.startsWith("/api/"); - const isDenoAPI = currentUrl.startsWith("/api/deno/"); + + // Access global API categories data + const apiCategories = data.apiCategories; if (isReference) { + // Note: Per-category symbol counts are not available in the generated API data structure + // The categories_panel only provides total symbol counts, not per-category breakdowns + // For API reference, we want to add section headings for the three API types + + const apiSections = [ + { + title: "Deno APIs", + key: "deno", + isCurrentSection: currentUrl.startsWith("/api/deno"), + items: currentUrl.startsWith("/api/deno") ? sectionData : undefined, + extraItems: [ + { href: "/api/deno", title: "Deno specific APIs" }, + { + href: "/api/deno/all_symbols", + title: "All symbols", + }, + ], + }, + { + title: "Web APIs", + key: "web", + isCurrentSection: currentUrl.startsWith("/api/web"), + items: currentUrl.startsWith("/api/web") ? sectionData : undefined, + extraItems: [ + { href: "/api/web", title: "Web Platform Support" }, + { + href: "/api/web/all_symbols", + title: "All symbols", + }, + ], + }, + { + title: "Node APIs", + key: "node", + isCurrentSection: currentUrl.startsWith("/api/node"), + items: currentUrl.startsWith("/api/node") ? sectionData : undefined, + extraItems: [ + { href: "/api/node", title: "Node support in deno" }, + { + href: "/api/node/all_symbols", + title: "All symbols", + }, + ], + }, + ]; + return ( <> - {sectionData.map((nav: any) => ( -
- {(isReference && data.children.props.data.toc_ctx) && ( - - )} + {(() => { + const tocCtx = getTocCtx(data); + return isReference && tocCtx + ? ( + + ) + : null; + })()} ); } diff --git a/_includes/layout.tsx b/_includes/layout.tsx index 9dcaccc71..a25b2ac11 100644 --- a/_includes/layout.tsx +++ b/_includes/layout.tsx @@ -10,8 +10,7 @@ export default function Layout(data: Lume.Data) { const isServicesPage = data.url.startsWith("/deploy") || data.url.startsWith("/subhosting") || data.url.startsWith("/services"); - const hasSubNav = data.page?.data?.SidebarNav?.length || - data.url.startsWith("/api"); + const hasSubNav = isServicesPage; return ( diff --git a/api/deno/index.md b/api/deno/index.md new file mode 100644 index 000000000..e4d20320a --- /dev/null +++ b/api/deno/index.md @@ -0,0 +1,901 @@ +--- +title: "Deno Namespace APIs" +description: "A guide to Deno's built-in runtime APIs. Learn about file system operations, network functionality, permissions management, and other core capabilities available through the global Deno namespace." +layout: doc.tsx +oldUrl: +- /runtime/manual/runtime/ +- /runtime/manual/runtime/builtin_apis/ +- /runtime/manual/runtime/permission_apis/ +- /runtime/manual/runtime/import_meta_api/ +- /runtime/manual/runtime/ffi_api/ +- /runtime/manual/runtime/program_lifecycle/ +- /runtime/reference/deno_namespace_apis/ +--- + +The global `Deno` namespace contains APIs that are not web standard, including +APIs for reading from files, opening TCP sockets, serving HTTP, and executing +subprocesses, etc. + +## API Documentation + +This section provides comprehensive documentation for all Deno-specific APIs +available through the global `Deno` namespace. You can +[browse all symbols](/api/deno/all_symbols) to view the complete list of +available APIs or search by category. Click on any function or interface to see +detailed documentation with examples + +Below we highlight some of the most important Deno APIs to know. + +## File System + +The Deno runtime comes with +[various functions for working with files and directories](/api/deno/file-system). +You will need to use --allow-read and --allow-write permissions to gain access +to the file system. + +Refer to the links below for code examples of how to use the file system +functions. + +- [Reading files in streams](/examples/file_server_tutorial/) +- [Reading a text file (`Deno.readTextFile`)](/examples/reading_files/) +- [Writing a text file (`Deno.writeTextFile`)](/examples/writing_files/) + +## Network + +The Deno runtime comes with +[built-in functions for dealing with connections to network ports](/api/deno/network). + +Refer to the links below for code examples for common functions. + +- [Connect to the hostname and port (`Deno.connect`)](/api/deno/~/Deno.connect) +- [Announcing on the local transport address (`Deno.listen`)](/api/deno/~/Deno.listen) + +For practical examples of networking functionality: + +- [HTTP Server: Hello world](/examples/http_server/) +- [HTTP Server: Routing](/examples/http_server_routing/) +- [TCP Echo Server](/examples/tcp_echo_server/) +- [WebSockets example](/examples/http_server_websocket/) +- [Build a chat app with WebSockets tutorial](/examples/chat_app_tutorial/) + +## Subprocesses + +The Deno runtime comes with +[built-in functions for spinning up subprocesses](/api/deno/subprocess). + +Refer to the links below for code samples of how to create a subprocess. + +- [Creating a subprocess (`Deno.Command`)](/examples/subprocess_tutorial/) +- [Collecting output from subprocesses](/examples/subprocesses_output/) + +## Errors + +The Deno runtime comes with [20 error classes](/api/deno/errors) that can be +raised in response to a number of conditions. + +Some examples are: + +```sh +Deno.errors.NotFound; +Deno.errors.WriteZero; +``` + +They can be used as below: + +```ts +try { + const file = await Deno.open("./some/file.txt"); +} catch (error) { + if (error instanceof Deno.errors.NotFound) { + console.error("the file was not found"); + } else { + // otherwise re-throw + throw error; + } +} +``` + +## HTTP Server + +Deno has two HTTP Server APIs: + +- [`Deno.serve`](/api/deno/~/Deno.serve): native, _higher-level_, supports + HTTP/1.1 and HTTP2, this is the preferred API to write HTTP servers in Deno. +- [`Deno.serveHttp`](/api/deno/~/Deno.serveHttp): native, _low-level_, supports + HTTP/1.1 and HTTP2. + +To start an HTTP server on a given port, use the `Deno.serve` function. This +function takes a handler function that will be called for each incoming request, +and is expected to return a response (or a promise resolving to a response). For +example: + +```ts +Deno.serve((_req) => { + return new Response("Hello, World!"); +}); +``` + +By default `Deno.serve` will listen on port `8000`, but this can be changed by +passing in a port number in options bag as the first or second argument. + +You can +[read more about how to use the HTTP server APIs](/runtime/fundamentals/http_server/). + +For practical examples of HTTP servers: + +- [Simple file server tutorial](/examples/file_server_tutorial/) +- [HTTP server serving files](/examples/http_server_files/) +- [HTTP server with streaming](/examples/http_server_streaming/) +- [HTTP server WebSockets](/examples/http_server_websocket/) + +## Permissions + +Permissions are granted from the CLI when running the `deno` command. User code +will often assume its own set of required permissions, but there is no guarantee +during execution that the set of **granted** permissions will align with this. + +In some cases, ensuring a fault-tolerant program requires a way to interact with +the permission system at runtime. + +### Permission descriptors + +On the CLI, read permission for `/foo/bar` is represented as +`--allow-read=/foo/bar`. In runtime JS, it is represented as the following: + +```ts +const desc = { name: "read", path: "/foo/bar" } as const; +``` + +Other examples: + +```ts +// Global write permission. +const desc1 = { name: "write" } as const; + +// Write permission to `$PWD/foo/bar`. +const desc2 = { name: "write", path: "foo/bar" } as const; + +// Global net permission. +const desc3 = { name: "net" } as const; + +// Net permission to 127.0.0.1:8000. +const desc4 = { name: "net", host: "127.0.0.1:8000" } as const; + +// High-resolution time permission. +const desc5 = { name: "hrtime" } as const; +``` + +See [`PermissionDescriptor`](/api/deno/~/Deno.PermissionDescriptor) in API +reference for more details. Synchronous API counterparts (ex. +`Deno.permissions.querySync`) exist for all the APIs described below. + +### Query permissions + +Check, by descriptor, if a permission is granted or not. + +```ts +// deno run --allow-read=/foo main.ts + +const desc1 = { name: "read", path: "/foo" } as const; +console.log(await Deno.permissions.query(desc1)); +// PermissionStatus { state: "granted", partial: false } + +const desc2 = { name: "read", path: "/foo/bar" } as const; +console.log(await Deno.permissions.query(desc2)); +// PermissionStatus { state: "granted", partial: false } + +const desc3 = { name: "read", path: "/bar" } as const; +console.log(await Deno.permissions.query(desc3)); +// PermissionStatus { state: "prompt", partial: false } +``` + +If `--deny-read` flag was used to restrict some of the filepaths, the result +will contain `partial: true` describing that not all subpaths have permissions +granted: + +```ts +// deno run --allow-read=/foo --deny-read=/foo/bar main.ts + +const desc1 = { name: "read", path: "/foo" } as const; +console.log(await Deno.permissions.query(desc1)); +// PermissionStatus { state: "granted", partial: true } + +const desc2 = { name: "read", path: "/foo/bar" } as const; +console.log(await Deno.permissions.query(desc2)); +// PermissionStatus { state: "denied", partial: false } + +const desc3 = { name: "read", path: "/bar" } as const; +console.log(await Deno.permissions.query(desc3)); +// PermissionStatus { state: "prompt", partial: false } +``` + +### Permission states + +A permission state can be either "granted", "prompt" or "denied". Permissions +which have been granted from the CLI will query to `{ state: "granted" }`. Those +which have not been granted query to `{ state: "prompt" }` by default, while +`{ state: "denied" }` reserved for those which have been explicitly refused. +This will come up in [Request permissions](#request-permissions). + +### Permission strength + +The intuitive understanding behind the result of the second query in +[Query permissions](#query-permissions) is that read access was granted to +`/foo` and `/foo/bar` is within `/foo` so `/foo/bar` is allowed to be read. This +hold true, unless the CLI-granted permission is _partial_ to the queried +permissions (as an effect of using a `--deny-*` flag). + +We can also say that `desc1` is +_[stronger than](https://www.w3.org/TR/permissions/#ref-for-permissiondescriptor-stronger-than)_ +`desc2`. This means that for any set of CLI-granted permissions: + +1. If `desc1` queries to `{ state: "granted", partial: false }` then so must + `desc2`. +2. If `desc2` queries to `{ state: "denied", partial: false }` then so must + `desc1`. + +More examples: + +```ts +const desc1 = { name: "write" } as const; +// is stronger than +const desc2 = { name: "write", path: "/foo" } as const; + +const desc3 = { name: "net", host: "127.0.0.1" } as const; +// is stronger than +const desc4 = { name: "net", host: "127.0.0.1:8000" } as const; +``` + +### Request permissions + +Request an ungranted permission from the user via CLI prompt. + +```ts +// deno run main.ts + +const desc1 = { name: "read", path: "/foo" } as const; +const status1 = await Deno.permissions.request(desc1); +// ⚠️ Deno requests read access to "/foo". Grant? [y/n (y = yes allow, n = no deny)] y +console.log(status1); +// PermissionStatus { state: "granted", partial: false } + +const desc2 = { name: "read", path: "/bar" } as const; +const status2 = await Deno.permissions.request(desc2); +// ⚠️ Deno requests read access to "/bar". Grant? [y/n (y = yes allow, n = no deny)] n +console.log(status2); +// PermissionStatus { state: "denied", partial: false } +``` + +If the current permission state is "prompt", a prompt will appear on the user's +terminal asking them if they would like to grant the request. The request for +`desc1` was granted so its new status is returned and execution will continue as +if `--allow-read=/foo` was specified on the CLI. The request for `desc2` was +denied so its permission state is downgraded from "prompt" to "denied". + +If the current permission state is already either "granted" or "denied", the +request will behave like a query and just return the current status. This +prevents prompts both for already granted permissions and previously denied +requests. + +### Revoke permissions + +Downgrade a permission from "granted" to "prompt". + +```ts +// deno run --allow-read=/foo main.ts + +const desc = { name: "read", path: "/foo" } as const; +console.log(await Deno.permissions.revoke(desc)); +// PermissionStatus { state: "prompt", partial: false } +``` + +What happens when you try to revoke a permission which is _partial_ to one +granted on the CLI? + +```ts +// deno run --allow-read=/foo main.ts + +const desc = { name: "read", path: "/foo/bar" } as const; +console.log(await Deno.permissions.revoke(desc)); +// PermissionStatus { state: "prompt", partial: false } +const cliDesc = { name: "read", path: "/foo" } as const; +console.log(await Deno.permissions.revoke(cliDesc)); +// PermissionStatus { state: "prompt", partial: false } +``` + +The CLI-granted permission, which implies the revoked permission, was also +revoked. + +To understand this behavior, imagine that Deno stores an internal set of +_explicitly granted permission descriptors_. Specifying `--allow-read=/foo,/bar` +on the CLI initializes this set to: + +```ts +[ + { name: "read", path: "/foo" }, + { name: "read", path: "/bar" }, +]; +``` + +Granting a runtime request for `{ name: "write", path: "/foo" }` updates the set +to: + +```ts +[ + { name: "read", path: "/foo" }, + { name: "read", path: "/bar" }, + { name: "write", path: "/foo" }, +]; +``` + +Deno's permission revocation algorithm works by removing every element from this +set which is _stronger than_ the argument permission descriptor. + +Deno does not allow "fragmented" permission states, where some strong permission +is granted with exclusions of weak permissions implied by it. Such a system +would prove increasingly complex and unpredictable as you factor in a wider +variety of use cases and the `"denied"` state. This is a calculated trade-off of +granularity for security. + +## import.meta + +Deno supports a number of properties and methods on the +[`import.meta`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import.meta) +API. It can be used to get information about the module, such as the module's +URL. + +### import.meta.url + +Returns the URL of the current module. + +```ts title="main.ts" +console.log(import.meta.url); +``` + +```sh +$ deno run main.ts +file:///dev/main.ts + +$ deno run https:/example.com/main.ts +https://example.com/main.ts +``` + +### import.meta.main + +Returns whether the current module is the entry point to your program. + +```ts title="main.ts" +import "./other.ts"; + +console.log(`Is ${import.meta.url} the main module?`, import.meta.main); +``` + +```ts title="other.ts" +console.log(`Is ${import.meta.url} the main module?`, import.meta.main); +``` + +```sh +$ deno run main.ts +Is file:///dev/other.ts the main module? false +Is file:///dev/main.ts the main module? true +``` + +### import.meta.filename + +_This property is only available for local modules (module that have +`file:///...` specifier) and returns `undefined` for remote modules._ + +Returns the fully resolved path to the current module. The value contains OS +specific path separators. + +```ts title="main.ts" +console.log(import.meta.filename); +``` + +On Unix: + +```sh +$ deno run main.ts +/dev/main.ts + +$ deno run https://example.com/main.ts +undefined +``` + +On Windows: + +```sh +$ deno run main.ts +C:\dev\main.ts + +$ deno run https://example.com/main.ts +undefined +``` + +### import.meta.dirname + +_This property is only available for local modules (module that have +`file:///...` specifier) and returns `undefined` for remote modules._ + +Returns the fully resolved path to the directory containing the current module. +The value contains OS specific path separators. + +```ts title="main.ts" +console.log(import.meta.dirname); +``` + +On Unix: + +```sh +$ deno run main.ts +/dev/ + +$ deno run https://example.com/main.ts +undefined +``` + +On Windows: + +```sh +$ deno run main.ts +C:\dev\ + +$ deno run https://example.com/main.ts +undefined +``` + +### import.meta.resolve + +Resolve specifiers relative to the current module. + +```ts +const worker = new Worker(import.meta.resolve("./worker.ts")); +``` + +The `import.meta.resolve` API takes into account the currently applied import +map, which gives you the ability to resolve "bare" specifiers as well. + +With such import map loaded... + +```json +{ + "imports": { + "fresh": "https://deno.land/x/fresh@1.0.1/dev.ts" + } +} +``` + +...you can now resolve: + +```js title="resolve.js" +console.log(import.meta.resolve("fresh")); +``` + +```sh +$ deno run resolve.js +https://deno.land/x/fresh@1.0.1/dev.ts +``` + +## FFI + +The FFI (foreign function interface) API allows users to call libraries written +in native languages that support the C ABIs (C/C++, Rust, Zig, V, etc.) using +`Deno.dlopen`. + +Here's an example showing how to call a Rust function from Deno: + +```rust +// add.rs +#[no_mangle] +pub extern "C" fn add(a: isize, b: isize) -> isize { + a + b +} +``` + +Compile it to a C dynamic library (`libadd.so` on Linux): + +```sh +rustc --crate-type cdylib add.rs +``` + +In C you can write it as: + +```c +// add.c +int add(int a, int b) { + return a + b; +} +``` + +And compile it: + +```sh +// unix +cc -c -o add.o add.c +cc -shared -W -o libadd.so add.o +// Windows +cl /LD add.c /link /EXPORT:add +``` + +Calling the library from Deno: + +```typescript +// ffi.ts + +// Determine library extension based on +// your OS. +let libSuffix = ""; +switch (Deno.build.os) { + case "windows": + libSuffix = "dll"; + break; + case "darwin": + libSuffix = "dylib"; + break; + default: + libSuffix = "so"; + break; +} + +const libName = `./libadd.${libSuffix}`; +// Open library and define exported symbols +const dylib = Deno.dlopen( + libName, + { + "add": { parameters: ["isize", "isize"], result: "isize" }, + } as const, +); + +// Call the symbol `add` +const result = dylib.symbols.add(35, 34); // 69 + +console.log(`Result from external addition of 35 and 34: ${result}`); +``` + +Run with `--allow-ffi` and `--unstable` flag: + +```sh +deno run --allow-ffi --unstable ffi.ts +``` + +### Non-blocking FFI + +There are many use cases where users might want to run CPU-bound FFI functions +in the background without blocking other tasks on the main thread. + +As of Deno 1.15, symbols can be marked `nonblocking` in `Deno.dlopen`. These +function calls will run on a dedicated blocking thread and will return a +`Promise` resolving to the desired `result`. + +Example of executing expensive FFI calls with Deno: + +```c +// sleep.c +#ifdef _WIN32 +#include +#else +#include +#endif + +int sleep(unsigned int ms) { + #ifdef _WIN32 + Sleep(ms); + #else + struct timespec ts; + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&ts, NULL); + #endif +} +``` + +Calling it from Deno: + +```typescript +// nonblocking_ffi.ts +const library = Deno.dlopen( + "./sleep.so", + { + sleep: { + parameters: ["usize"], + result: "void", + nonblocking: true, + }, + } as const, +); + +library.symbols.sleep(500).then(() => console.log("After")); +console.log("Before"); +``` + +Result: + +```sh +$ deno run --allow-ffi --unstable unblocking_ffi.ts +Before +After +``` + +### Callbacks + +Deno FFI API supports creating C callbacks from JavaScript functions for calling +back into Deno from dynamic libraries. An example of how callbacks are created +and used is as follows: + +```typescript +// callback_ffi.ts +const library = Deno.dlopen( + "./callback.so", + { + set_status_callback: { + parameters: ["function"], + result: "void", + }, + start_long_operation: { + parameters: [], + result: "void", + }, + check_status: { + parameters: [], + result: "void", + }, + } as const, +); + +const callback = new Deno.UnsafeCallback( + { + parameters: ["u8"], + result: "void", + } as const, + (success: number) => {}, +); + +// Pass the callback pointer to dynamic library +library.symbols.set_status_callback(callback.pointer); +// Start some long operation that does not block the thread +library.symbols.start_long_operation(); + +// Later, trigger the library to check if the operation is done. +// If it is, this call will trigger the callback. +library.symbols.check_status(); +``` + +If an `UnsafeCallback`'s callback function throws an error, the error will get +propagated up to the function that triggered the callback to be called (above, +that would be `check_status()`) and can be caught there. If a callback returning +a value throws then Deno will return 0 (null pointer for pointers) as the +result. + +`UnsafeCallback` is not deallocated by default as it can cause use-after-free +bugs. To properly dispose of an `UnsafeCallback` its `close()` method must be +called. + +```typescript +const callback = new Deno.UnsafeCallback( + { parameters: [], result: "void" } as const, + () => {}, +); + +// After callback is no longer needed +callback.close(); +// It is no longer safe to pass the callback as a parameter. +``` + +It is also possible for native libraries to setup interrupt handlers and to have +those directly trigger the callback. However, this is not recommended and may +cause unexpected side-effects and undefined behaviour. Preferably any interrupt +handlers would only set a flag that can later be polled similarly to how +`check_status()` is used above. + +### Supported types + +Here's a list of types supported currently by the Deno FFI API. + +| FFI Type | Deno | C | Rust | +| ---------------------- | -------------------- | ------------------------ | ------------------------- | +| `i8` | `number` | `char` / `signed char` | `i8` | +| `u8` | `number` | `unsigned char` | `u8` | +| `i16` | `number` | `short int` | `i16` | +| `u16` | `number` | `unsigned short int` | `u16` | +| `i32` | `number` | `int` / `signed int` | `i32` | +| `u32` | `number` | `unsigned int` | `u32` | +| `i64` | `bigint` | `long long int` | `i64` | +| `u64` | `bigint` | `unsigned long long int` | `u64` | +| `usize` | `bigint` | `size_t` | `usize` | +| `isize` | `bigint` | `size_t` | `isize` | +| `f32` | `number` | `float` | `f32` | +| `f64` | `number` | `double` | `f64` | +| `void`[1] | `undefined` | `void` | `()` | +| `pointer` | `{} \| null` | `void *` | `*mut c_void` | +| `buffer`[2] | `TypedArray \| null` | `uint8_t *` | `*mut u8` | +| `function`[3] | `{} \| null` | `void (*fun)()` | `Option` | +| `{ struct: [...] }`[4] | `TypedArray` | `struct MyStruct` | `MyStruct` | + +As of Deno 1.25, the `pointer` type has been split into a `pointer` and a +`buffer` type to ensure users take advantage of optimizations for Typed Arrays, +and as of Deno 1.31 the JavaScript representation of `pointer` has become an +opaque pointer object or `null` for null pointers. + +- [1] `void` type can only be used as a result type. +- [2] `buffer` type accepts TypedArrays as parameter, but it always returns a + pointer object or `null` when used as result type like the `pointer` type. +- [3] `function` type works exactly the same as the `pointer` type as a + parameter and result type. +- [4] `struct` type is for passing and returning C structs by value (copy). The + `struct` array must enumerate each of the struct's fields' type in order. The + structs are padded automatically: Packed structs can be defined by using an + appropriate amount of `u8` fields to avoid padding. Only TypedArrays are + supported as structs, and structs are always returned as `Uint8Array`s. + +### deno_bindgen + +[`deno_bindgen`](https://github.com/denoland/deno_bindgen) is the official tool +to simplify glue code generation of Deno FFI libraries written in Rust. + +It is similar to [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) in +the Rust Wasm ecosystem. + +Here's an example showing its usage: + +```rust +// mul.rs +use deno_bindgen::deno_bindgen; + +#[deno_bindgen] +struct Input { + a: i32, + b: i32, +} + +#[deno_bindgen] +fn mul(input: Input) -> i32 { + input.a * input.b +} +``` + +Run `deno_bindgen` to generate bindings. You can now directly import them into +Deno: + +```ts +// mul.ts +import { mul } from "./bindings/bindings.ts"; +mul({ a: 10, b: 2 }); // 20 +``` + +Any issues related to `deno_bindgen` should be reported at + + +## Program Lifecycle + +Deno supports browser compatible lifecycle events: + +- [`load`](https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event#:~:text=The%20load%20event%20is%20fired,for%20resources%20to%20finish%20loading.): + fired when the whole page has loaded, including all dependent resources such + as stylesheets and images. +- [`beforeunload`](https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event#:~:text=The%20beforeunload%20event%20is%20fired,want%20to%20leave%20the%20page.): + fired when the event loop has no more work to do and is about to exit. + Scheduling more asynchronous work (like timers or network requests) will cause + the program to continue. +- [`unload`](https://developer.mozilla.org/en-US/docs/Web/API/Window/unload_event): + fired when the document or a child resource is being unloaded. +- [`unhandledrejection`](https://developer.mozilla.org/en-US/docs/Web/API/Window/unhandledrejection_event): + fired when a promise that has no rejection handler is rejected, ie. a promise + that has no `.catch()` handler or a second argument to `.then()`. +- [`rejectionhandled`](https://developer.mozilla.org/en-US/docs/Web/API/Window/rejectionhandled_event): + fired when a `.catch()` handler is added to a a promise that has already + rejected. This event is fired only if there's `unhandledrejection` listener + installed that prevents propagation of the event (which would result in the + program terminating with an error). + +You can use these events to provide setup and cleanup code in your program. + +Listeners for `load` events can be asynchronous and will be awaited, this event +cannot be canceled. Listeners for `beforeunload` need to be synchronous and can +be cancelled to keep the program running. Listeners for `unload` events need to +be synchronous and cannot be cancelled. + +## main.ts + +```ts title="main.ts" +import "./imported.ts"; + +const handler = (e: Event): void => { + console.log(`got ${e.type} event in event handler (main)`); +}; + +globalThis.addEventListener("load", handler); + +globalThis.addEventListener("beforeunload", handler); + +globalThis.addEventListener("unload", handler); + +globalThis.onload = (e: Event): void => { + console.log(`got ${e.type} event in onload function (main)`); +}; + +globalThis.onbeforeunload = (e: Event): void => { + console.log(`got ${e.type} event in onbeforeunload function (main)`); +}; + +globalThis.onunload = (e: Event): void => { + console.log(`got ${e.type} event in onunload function (main)`); +}; + +console.log("log from main script"); +``` + +```ts title="imported.ts" +const handler = (e: Event): void => { + console.log(`got ${e.type} event in event handler (imported)`); +}; + +globalThis.addEventListener("load", handler); +globalThis.addEventListener("beforeunload", handler); +globalThis.addEventListener("unload", handler); + +globalThis.onload = (e: Event): void => { + console.log(`got ${e.type} event in onload function (imported)`); +}; + +globalThis.onbeforeunload = (e: Event): void => { + console.log(`got ${e.type} event in onbeforeunload function (imported)`); +}; + +globalThis.onunload = (e: Event): void => { + console.log(`got ${e.type} event in onunload function (imported)`); +}; + +console.log("log from imported script"); +``` + +A couple notes on this example: + +- `addEventListener` and `onload`/`onunload` are prefixed with `globalThis`, but + you could also use `self` or no prefix at all. + [It is not recommended to use `window` as a prefix](https://docs.deno.com/lint/rules/no-window-prefix). +- You can use `addEventListener` and/or `onload`/`onunload` to define handlers + for events. There is a major difference between them, let's run the example: + +```shell +$ deno run main.ts +log from imported script +log from main script +got load event in event handler (imported) +got load event in event handler (main) +got load event in onload function (main) +got onbeforeunload event in event handler (imported) +got onbeforeunload event in event handler (main) +got onbeforeunload event in onbeforeunload function (main) +got unload event in event handler (imported) +got unload event in event handler (main) +got unload event in onunload function (main) +``` + +All listeners added using `addEventListener` were run, but `onload`, +`onbeforeunload` and `onunload` defined in `main.ts` overrode handlers defined +in `imported.ts`. + +In other words, you can use `addEventListener` to register multiple `"load"` or +`"unload"` event handlers, but only the last defined `onload`, `onbeforeunload`, +`onunload` event handlers will be executed. It is preferable to use +`addEventListener` when possible for this reason. + +### beforeunload + +```js +// beforeunload.js +let count = 0; + +console.log(count); + +globalThis.addEventListener("beforeunload", (e) => { + console.log("About to exit..."); + count++; +}); + +globalThis.addEventListener("unload", (e) => { + console.log("Exiting"); +}); + +count++; +``` diff --git a/api/node/index.md b/api/node/index.md new file mode 100644 index 000000000..1f9f8bff8 --- /dev/null +++ b/api/node/index.md @@ -0,0 +1,155 @@ +--- +title: "Node.js Built-in APIs" +description: "Complete reference for Node.js built-in modules and globals supported in Deno. Explore Node.js APIs including fs, http, crypto, process, buffer, and more with compatibility information." +layout: doc.tsx +oldUrl: + - /runtime/manual/node/compatibility/ + - /runtime/manual/npm_nodejs/compatibility_mode/ +--- + +Deno provides comprehensive support for Node.js built-in modules and globals, +enabling seamless migration of Node.js applications and libraries. These APIs +follow Node.js specifications and provide familiar functionality for developers +transitioning from Node.js. + + + +## Key Features + +- **Built-in Module Support**: Access Node.js modules using `node:` prefix + (e.g., `import fs from "node:fs"`) +- **Global Objects**: Node.js global objects available in npm package scope +- **Compatibility Layer**: Seamless interoperability with existing Node.js code +- **Performance**: Native implementations optimized for Deno runtime + +## Core Modules + +### File System + +- **`node:fs`** - File system operations (read, write, watch, stats) +- **`node:fs/promises`** - Promise-based file system API +- **`node:path`** - Cross-platform path utilities + +### Network & HTTP + +- **`node:http`** - HTTP server and client functionality +- **`node:https`** - HTTPS server and client with TLS support +- **`node:http2`** - HTTP/2 server and client implementation +- **`node:net`** - TCP networking utilities +- **`node:dns`** - DNS resolution and lookup functions + +### Process & System + +- **`node:process`** - Process information and control +- **`node:os`** - Operating system utilities and information +- **`node:child_process`** - Spawn and manage child processes +- **`node:cluster`** - Multi-process clustering support + +### Crypto & Security + +- **`node:crypto`** - Cryptographic functionality (hashing, encryption, + certificates) +- **`node:tls`** - TLS/SSL secure communication layer + +### Data & Streams + +- **`node:stream`** - Stream interfaces (readable, writable, transform) +- **`node:buffer`** - Binary data handling with Buffer class +- **`node:zlib`** - Data compression and decompression +- **`node:string_decoder`** - Decode buffers to strings + +### Utilities + +- **`node:util`** - Utility functions (promisify, inspect, types) +- **`node:events`** - Event emitter pattern implementation +- **`node:url`** - URL parsing and formatting utilities +- **`node:querystring`** - Query string utilities +- **`node:assert`** - Assertion testing support + +### Development & Testing + +- **`node:vm`** - Virtual machine contexts for code execution +- **`node:repl`** - Read-Eval-Print Loop functionality +- **`node:inspector`** - V8 inspector integration for debugging + +## Global Objects + +Node.js global objects are available in the npm package scope and can be +imported from relevant `node:` modules: + +- **`Buffer`** - Binary data manipulation +- **`process`** - Process information and environment +- **`global`** - Global namespace object +- **`__dirname`** / **`__filename`** - Module path information +- **Web Standards** - `fetch`, `URL`, `TextEncoder`, `crypto`, and more + +## Usage Examples + +### Basic Module Import + +```javascript +import fs from "node:fs"; +import { readFile } from "node:fs/promises"; +import path from "node:path"; + +// Synchronous file reading +const data = fs.readFileSync("file.txt", "utf8"); + +// Asynchronous file reading +const content = await readFile("file.txt", "utf8"); + +// Path manipulation +const fullPath = path.join("/users", "documents", "file.txt"); +``` + +### HTTP Server + +```javascript +import http from "node:http"; + +const server = http.createServer((req, res) => { + res.writeHead(200, { "Content-Type": "text/plain" }); + res.end("Hello from Node.js API in Deno!"); +}); + +server.listen(3000, () => { + console.log("Server running on port 3000"); +}); +``` + +### Crypto Operations + +```javascript +import crypto from "node:crypto"; + +// Generate hash +const hash = crypto.createHash("sha256"); +hash.update("Hello World"); +const digest = hash.digest("hex"); + +// Generate random bytes +const randomBytes = crypto.randomBytes(16); +``` + +## Compatibility + +Node compatibility is an ongoing project. Most core Node.js APIs are supported +with high fidelity. For detailed compatibility information: + +- View our [Node.js compatibility guide](/runtime/reference/node_apis/) +- Check [Node.js test results](https://node-test-viewer.deno.dev/) for specific + test coverage +- [Report compatibility issues](https://github.com/denoland/deno/issues) on + GitHub + +## Migration from Node.js + +When migrating from Node.js to Deno: + +1. **Update imports**: Use `node:` prefix for built-in modules +2. **Check compatibility**: Verify your dependencies work with Deno +3. **Use npm specifiers**: Import npm packages with `npm:` prefix +4. **Review permissions**: Configure Deno's permission system as needed + +For more guidance, see our +[migration guide](/runtime/reference/migration_guide/). diff --git a/api/web/index.md b/api/web/index.md new file mode 100644 index 000000000..356b46655 --- /dev/null +++ b/api/web/index.md @@ -0,0 +1,615 @@ +--- +title: "Web Platform APIs" +description: "A guide to the Web Platform APIs available in Deno. Learn about fetch, events, workers, storage, and other web standard APIs, including implementation details and deviations from browser specifications." +layout: doc.tsx +oldUrl: + - /runtime/manual/runtime/navigator_api/ + - /runtime/manual/runtime/web_platform_apis/ + - /runtime/manual/runtime/location_api/ + - /runtime/manual/runtime/web_storage_api/ + - /runtime/manual/runtime/workers/ +--- + +Deno implements many of the standard Web Platform APIs that are available in +modern browsers. This means if you've built for the web, you're likely already +familiar with many of Deno's APIs. Learning Deno also means investing in your +knowledge of the web platform. + +This section provides comprehensive documentation for all Deno's supported Web +APIs You can [browse all symbols](/api/web/all_symbols) to view the complete +list or search by category. Click on any function or interface to see detailed +documentation with examples + +## Core Web APIs + +Deno supports a comprehensive set of web standard APIs: + +### Network & Communication + +- **[`fetch`](/api/web/~/fetch)** - HTTP requests following the WHATWG fetch + specification +- **[WebSocket](/api/web/~/WebSocket)** - Full-duplex communication over TCP +- **[Server-Sent Events](/api/web/~/EventSource)** - Server-to-client event + streaming +- **[BroadcastChannel](/api/web/~/BroadcastChannel)** - Cross-context messaging + +### Storage & State + +- **[Web Storage](/api/web/~/Storage)** - localStorage and sessionStorage APIs +- **[Cache API](/api/web/~/Cache)** - HTTP response caching interface +- **[IndexedDB](/api/web/~/IDBDatabase)** - Client-side database storage + +### Workers & Concurrency + +- **[Web Workers](/api/web/~/Worker)** - Background thread execution +- **[SharedArrayBuffer](/api/web/~/SharedArrayBuffer)** - Shared memory between + workers + +### Streams & Data + +- **[Streams API](/api/web/~/ReadableStream)** - Composable streaming data + interfaces +- **[Compression](/api/web/~/CompressionStream)** - Built-in gzip/deflate + compression +- **[File API](/api/web/~/File)** - File and Blob manipulation + +### Events & DOM + +- **[Event API](/api/web/~/Event)** - Standard event handling patterns +- **[CustomEvent](/api/web/~/CustomEvent)** - Custom event creation and dispatch +- **[EventTarget](/api/web/~/EventTarget)** - Event listener management + +### Encoding & Crypto + +- **[TextEncoder/TextDecoder](/api/web/~/TextEncoder)** - UTF-8 text + encoding/decoding +- **[Web Crypto](/api/web/~/SubtleCrypto)** - Cryptographic operations +- **[URL API](/api/web/~/URL)** - URL parsing and manipulation + +### Timers & Performance + +- **[Performance API](/api/web/~/Performance)** - High-resolution timing +- **[Timers](/api/web/~/setTimeout)** - setTimeout, setInterval, and + setImmediate + +## Key Benefits + +- **Standards Compliance**: APIs follow WHATWG and W3C specifications +- **Cross-Platform**: Code works consistently across Deno, browsers, and other + runtimes +- **No Polyfills**: Native implementations provide optimal performance +- **Future-Proof**: Built on evolving web standards + +## Usage Examples + +### Making HTTP Requests + +```javascript +const response = await fetch("https://api.github.com/users/denoland"); +const data = await response.json(); +console.log(data); +``` + +### Using Web Workers + +```javascript +// main.js +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", +}); + +worker.postMessage({ task: "process_data", data: [1, 2, 3] }); +worker.onmessage = (e) => console.log("Result:", e.data); +``` + +```javascript +// worker.js +self.onmessage = (e) => { + const { task, data } = e.data; + const result = data.map((x) => x * 2); + self.postMessage(result); +}; +``` + +### Local Storage + +```javascript +// Persist data across sessions +localStorage.setItem("user_preference", "dark_mode"); +const preference = localStorage.getItem("user_preference"); +``` + +## Compatibility Notes + +To check if a Web Platform API is available in Deno, refer to the interface +documentation on +[MDN](https://developer.mozilla.org/en-US/docs/Web/API#interfaces) and its +Browser Compatibility table. + +Most APIs are implemented according to their specifications, with some +Deno-specific adaptations for server environments. Notable differences are +documented below. + +## fetch + +The [`fetch`](/api/web/~/fetch) API can be used to make HTTP requests. It is +implemented as specified in the +[WHATWG `fetch` spec](https://fetch.spec.whatwg.org/). + +### Spec deviations + +- The Deno user agent does not have a cookie jar. As such, the `set-cookie` + header on a response is not processed, or filtered from the visible response + headers. +- Deno does not follow the same-origin policy, because the Deno user agent + currently does not have the concept of origins, and it does not have a cookie + jar. This means Deno does not need to protect against leaking authenticated + data cross origin. Because of this Deno does not implement the following + sections of the WHATWG `fetch` specification: + - Section `3.1. 'Origin' header`. + - Section `3.2. CORS protocol`. + - Section `3.5. CORB`. + - Section `3.6. 'Cross-Origin-Resource-Policy' header`. + - `Atomic HTTP redirect handling`. + - The `opaqueredirect` response type. +- A `fetch` with a `redirect` mode of `manual` will return a `basic` response + rather than an `opaqueredirect` response. +- The specification is vague on how + [`file:` URLs are to be handled](https://fetch.spec.whatwg.org/#scheme-fetch). + Firefox is the only mainstream browser that implements fetching `file:` URLs, + and even then it doesn't work by default. As of Deno 1.16, Deno supports + fetching local files. See the next section for details. +- The `request` and `response` header guards are implemented, but unlike + browsers do not have any constraints on which header names are allowed. +- The `referrer`, `referrerPolicy`, `mode`, `credentials`, `cache`, `integrity`, + `keepalive`, and `window` properties and their relevant behaviours in + `RequestInit` are not implemented. The relevant fields are not present on the + `Request` object. +- Request body upload streaming is supported (on HTTP/1.1 and HTTP/2). Unlike + the current fetch proposal, the implementation supports duplex streaming. +- The `set-cookie` header is not concatenated when iterated over in the + `headers` iterator. This behaviour is in the + [process of being specified](https://github.com/whatwg/fetch/pull/1346). + +### Fetching local files + +Deno supports fetching `file:` URLs. This makes it easier to write code that +uses the same code path on a server as local, as well as easier to author code +that works both with the Deno CLI and Deno Deploy. + +Deno only supports absolute file URLs, this means that `fetch("./some.json")` +will not work. It should be noted though that if [`--location`](#location) is +specified, relative URLs use the `--location` as the base, but a `file:` URL +cannot be passed as the `--location`. + +To be able to fetch a resource, relative to the current module, which would work +if the module is local or remote, you should to use `import.meta.url` as the +base. For example: + +```js +const response = await fetch(new URL("./config.json", import.meta.url)); +const config = await response.json(); +``` + +Notes on fetching local files: + +- Permissions are applied to reading resources, so an appropriate `--allow-read` + permission is needed to be able to read a local file. +- Fetching locally only supports the `GET` method, and will reject the promise + with any other method. +- A file that does not exist simply rejects the promise with a vague + `TypeError`. This is to avoid the potential of fingerprinting attacks. +- No headers are set on the response. Therefore it is up to the consumer to + determine things like the content type or content length. +- Response bodies are streamed from the Rust side, so large files are available + in chunks, and can be cancelled. + +## CustomEvent and EventTarget + +The [DOM Event API](/api/web/~/Event) can be used to dispatch and listen to +events happening in an application. It is implemented as specified in the +[WHATWG DOM spec](https://dom.spec.whatwg.org/#events). + +### Event API Deviations + +- Events do not bubble, because Deno does not have a DOM hierarchy, so there is + no tree for Events to bubble/capture through. +- `timeStamp` property is always set to `0`. + +## Typings + +The TypeScript definitions for the implemented web APIs can be found in the +[`lib.deno.shared_globals.d.ts`](https://github.com/denoland/deno/blob/main/cli/tsc/dts/lib.deno.shared_globals.d.ts) +and +[`lib.deno.window.d.ts`](https://github.com/denoland/deno/blob/main/cli/tsc/dts/lib.deno.window.d.ts) +files. + +Definitions that are specific to workers can be found in the +[`lib.deno.worker.d.ts`](https://github.com/denoland/deno/blob/main/cli/tsc/dts/lib.deno.worker.d.ts) +file. + +## Location + +Deno supports the [`location`](/api/web/~/Location) global from the web. + +### Location flag + +There is no "web page" whose URL we can use for a location in a Deno process. We +instead allow users to emulate a document location by specifying one on the CLI +using the `--location` flag. It can be a `http` or `https` URL. + +```ts +// deno run --location https://example.com/path main.ts + +console.log(location.href); +// "https://example.com/path" +``` + +You must pass `--location ` for this to work. If you don't, any access to +the `location` global will throw an error. + +```ts +// deno run main.ts + +console.log(location.href); +// error: Uncaught ReferenceError: Access to "location", run again with --location . +``` + +Setting `location` or any of its fields will normally cause navigation in +browsers. This is not applicable in Deno, so it will throw in this situation. + +```ts +// deno run --location https://example.com/path main.ts + +location.pathname = "./foo"; +// error: Uncaught NotSupportedError: Cannot set "location.pathname". +``` + +### Extended usage + +On the web, resource resolution (excluding modules) typically uses the value of +`location.href` as the root on which to base any relative URLs. This affects +some web APIs adopted by Deno. + +#### Fetch API + +```ts +// deno run --location https://api.github.com/ --allow-net main.ts + +const response = await fetch("./orgs/denoland"); +// Fetches "https://api.github.com/orgs/denoland". +``` + +The `fetch()` call above would throw if the `--location` flag was not passed, +since there is no web-analogous location to base it onto. + +#### Worker modules + +```ts +// deno run --location https://example.com/index.html --allow-net main.ts + +const worker = new Worker("./workers/hello.ts", { type: "module" }); +// Fetches worker module at "https://example.com/workers/hello.ts". +``` + +:::note + +For the above use cases, it is preferable to pass URLs in full rather than +relying on `--location`. You can manually base a relative URL using the `URL` +constructor if needed. + +::: + +The `--location` flag is intended for those who have a specific purpose in mind +for emulating a document location and are aware that this will only work at +application-level. However, you may also use it to silence errors from a +dependency which is frivolously accessing the `location` global. + +## Web Storage + +The [Web Storage API](/api/web/storage) provides an API for storing string keys +and values. Persisting data works similar to a browser, and has a 10MB storage +limit. The global `sessionStorage` object only persists data for the current +execution context, while `localStorage` persists data from execution to +execution. + +In a browser, `localStorage` persists data uniquely per origin (effectively the +protocol plus hostname plus port). As of Deno 1.16, Deno has a set of rules to +determine what is a unique storage location: + +- When using the `--location` flag, the origin for the location is used to + uniquely store the data. That means a location of `http://example.com/a.ts` + and `http://example.com/b.ts` and `http://example.com:80/` would all share the + same storage, but `https://example.com/` would be different. +- If there is no location specifier, but there is a `--config` configuration + file specified, the absolute path to that configuration file is used. That + means `deno run --config deno.jsonc a.ts` and + `deno run --config deno.jsonc b.ts` would share the same storage, but + `deno run --config tsconfig.json a.ts` would be different. +- If there is no configuration or location specifier, Deno uses the absolute + path to the main module to determine what storage is shared. The Deno REPL + generates a "synthetic" main module that is based off the current working + directory where `deno` is started from. This means that multiple invocations + of the REPL from the same path will share the persisted `localStorage` data. + +To set, get and remove items from `localStorage`, you can use the following: + +```ts +// Set an item in localStorage +localStorage.setItem("myDemo", "Deno App"); + +// Read an item from localStorage +const cat = localStorage.getItem("myDemo"); + +// Remove an item from localStorage +localStorage.removeItem("myDemo"); + +// Remove all items from localStorage +localStorage.clear(); +``` + +## Web Workers + +Deno supports the [`Web Worker API`](/api/web/workers). + +Workers can be used to run code on multiple threads. Each instance of `Worker` +is run on a separate thread, dedicated only to that worker. + +Currently Deno supports only `module` type workers; thus it's essential to pass +the `type: "module"` option when creating a new worker. + +Use of relative module specifiers in the main worker are only supported with +`--location ` passed on the CLI. This is not recommended for portability. +You can instead use the `URL` constructor and `import.meta.url` to easily create +a specifier for some nearby script. Dedicated workers, however, have a location +and this capability by default. + +```ts +// Good +new Worker(import.meta.resolve("./worker.js"), { type: "module" }); + +// Bad +new Worker(import.meta.resolve("./worker.js")); +new Worker(import.meta.resolve("./worker.js"), { type: "classic" }); +new Worker("./worker.js", { type: "module" }); +``` + +As with regular modules, you can use top-level `await` in worker modules. +However, you should be careful to always register the message handler before the +first `await`, since messages can be lost otherwise. This is not a bug in Deno, +it's just an unfortunate interaction of features, and it also happens in all +browsers that support module workers. + +```ts +import { delay } from "jsr:@std/async@1/delay"; + +// First await: waits for a second, then continues running the module. +await delay(1000); + +// The message handler is only set after that 1s delay, so some of the messages +// that reached the worker during that second might have been fired when no +// handler was registered. +self.onmessage = (evt) => { + console.log(evt.data); +}; +``` + +### Instantiation permissions + +Creating a new `Worker` instance is similar to a dynamic import; therefore Deno +requires appropriate permission for this action. + +For workers using local modules; `--allow-read` permission is required: + +```ts title="main.ts" +new Worker(import.meta.resolve("./worker.ts"), { type: "module" }); +``` + +```ts title="worker.ts" +console.log("hello world"); +self.close(); +``` + +```shell +$ deno run main.ts +error: Uncaught PermissionDenied: read access to "./worker.ts", run again with the --allow-read flag + +$ deno run --allow-read main.ts +hello world +``` + +For workers using remote modules; `--allow-net` permission is required: + +```ts title="main.ts" +new Worker("https://example.com/worker.ts", { type: "module" }); +``` + +```ts title="worker.ts" +// This file is hosted at https://example.com/worker.ts +console.log("hello world"); +self.close(); +``` + +```shell +$ deno run main.ts +error: Uncaught PermissionDenied: net access to "https://example.com/worker.ts", run again with the --allow-net flag + +$ deno run --allow-net main.ts +hello world +``` + +### Using Deno in a worker + +```js title="main.js" +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", +}); + +worker.postMessage({ filename: "./log.txt" }); +``` + +```js title="worker.js" +self.onmessage = async (e) => { + const { filename } = e.data; + const text = await Deno.readTextFile(filename); + console.log(text); + self.close(); +}; +``` + +```text title="log.txt" +hello world +``` + +```shell +$ deno run --allow-read main.js +hello world +``` + +### Specifying worker permissions + +:::caution + +This is an unstable Deno feature. Learn more about +[unstable features](/runtime/fundamentals/stability_and_releases/#unstable-apis). + +::: + +The permissions available for the worker are analogous to the CLI permission +flags, meaning every permission enabled there can be disabled at the level of +the Worker API. You can find a more detailed description of each of the +permission options in the +[security documentation](/runtime/fundamentals/security/). + +By default a worker will inherit permissions from the thread it was created in, +however in order to allow users to limit the access of this worker we provide +the `deno.permissions` option in the worker API. + +For permissions that support granular access you can pass in a list of the +desired resources the worker will have access to, and for those who only have +the on/off option you can pass true/false respectively: + +```ts +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", + deno: { + permissions: { + net: [ + "deno.land", + ], + read: [ + new URL("./file_1.txt", import.meta.url), + new URL("./file_2.txt", import.meta.url), + ], + write: false, + }, + }, +}); +``` + +Granular access permissions receive both absolute and relative routes as +arguments, however take into account that relative routes will be resolved +relative to the file the worker is instantiated in, not the path the worker file +is currently in: + +```ts +const worker = new Worker( + new URL("./worker/worker.js", import.meta.url).href, + { + type: "module", + deno: { + permissions: { + read: [ + "/home/user/Documents/deno/worker/file_1.txt", + "./worker/file_2.txt", + ], + }, + }, + }, +); +``` + +Both `deno.permissions` and its children support the option `"inherit"`, which +implies it will borrow its parent permissions: + +```ts +// This worker will inherit its parent permissions +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", + deno: { + permissions: "inherit", + }, +}); +``` + +```ts +// This worker will inherit only the net permissions of its parent +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", + deno: { + permissions: { + env: false, + hrtime: false, + net: "inherit", + ffi: false, + read: false, + run: false, + write: false, + }, + }, +}); +``` + +Not specifying the `deno.permissions` option or one of its children will cause +the worker to inherit by default: + +```ts +// This worker will inherit its parent permissions +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", +}); +``` + +```ts +// This worker will inherit all the permissions of its parent BUT net +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", + deno: { + permissions: { + net: false, + }, + }, +}); +``` + +You can disable the permissions of the worker all together by passing `"none"` +to the `deno.permissions` option: + +```ts +// This worker will not have any permissions enabled +const worker = new Worker(import.meta.resolve("./worker.js"), { + type: "module", + deno: { + permissions: "none", + }, +}); +``` + +## Deviations of other APIs from spec + +### Cache API + +Only the following APIs are implemented: + +- [CacheStorage::open()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/open) +- [CacheStorage::has()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/has) +- [CacheStorage::delete()](https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage/delete) +- [Cache::match()](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match) +- [Cache::put()](https://developer.mozilla.org/en-US/docs/Web/API/Cache/put) +- [Cache::delete()](https://developer.mozilla.org/en-US/docs/Web/API/Cache/delete) + +A few things that are different compared to browsers: + +1. You cannot pass relative paths to the APIs. The request can be an instance of + Request or URL or a url string. +2. `match()` & `delete()` don't support query options yet. diff --git a/examples/tutorials/connecting_to_databases.md b/examples/tutorials/connecting_to_databases.md index 2d9fcabba..03705e4ad 100644 --- a/examples/tutorials/connecting_to_databases.md +++ b/examples/tutorials/connecting_to_databases.md @@ -132,7 +132,7 @@ db.close(); ### Connect to SQLite with the FFI Module [@db/sqlite](https://jsr.io/@db/sqlite) provides JavaScript bindings to the -SQLite3 C API, using [Deno FFI](/runtime/reference/deno_namespace_apis/#ffi). +SQLite3 C API, using [Deno FFI](/api/deno/#ffi). ```ts import { Database } from "jsr:@db/sqlite@0.12"; diff --git a/oldurls.json b/oldurls.json index d45da950c..337214ab7 100644 --- a/oldurls.json +++ b/oldurls.json @@ -75,8 +75,6 @@ "/examples/web-workers": "/examples/web_workers", "/examples/writing-files": "/examples/writing_files", "/examples/writing-tests": "/examples/writing_tests", - "/api/deno/": "/api/deno/~/Deno", - "/api/web/": "/api/web/all_symbols", "/runtime/contributing/profiling/": "/runtime/contributing#profiling", "/runtime/manual/advanced/jsx_dom/jsdom": "/runtime/reference/jsx/", "/examples/stubs": "/examples/stubbing_tutorial", diff --git a/reference/_components/Breadcrumbs.tsx b/reference/_components/Breadcrumbs.tsx index 7ffabdfd1..2a4d6c57d 100644 --- a/reference/_components/Breadcrumbs.tsx +++ b/reference/_components/Breadcrumbs.tsx @@ -1,7 +1,12 @@ import type { BreadcrumbCtx } from "@deno/doc"; export default function ( - { comp, parts }: { comp: any; parts: BreadcrumbCtx[] }, + // deno-lint-ignore no-explicit-any + { comp, parts, hasSubNav }: { + comp: any; + parts: BreadcrumbCtx[]; + hasSubNav?: boolean; + }, ) { const pathParts: BreadcrumbCtx[] = []; const symbolParts: BreadcrumbCtx[] = []; @@ -14,8 +19,12 @@ export default function ( } } + const topClass = hasSubNav ? "top-header-plus-subnav" : "top-header"; + return ( -