# Bundle source (/docs/guide/core-concepts/bundle-source) A **source** is the location on the device where bundles are stored. There are two types of source. One is the read-only builtin (`builtin`) source shipped inside the app package, and the other is the remote (`remote`) source that updates over the air from a remote server. ## Builtin vs remote [#builtin-vs-remote] Webview Bundle splits bundle sources into builtin (`builtin`) and remote (`remote`). * **`builtin`** — a bundle shipped *inside* the app package. It is read-only and serves as the fallback on first launch, before anything has been downloaded. * **`remote`** — a bundle downloaded from a remote server. It is writable and updates over the air without an app store release. When a bundle exists in both sources, **remote wins**. A source determines the version by checking the current version in the remote manifest first, and falls back to builtin when the bundle is not in remote. *** This separation makes updates safe. A shipped builtin version is always available to fall back to, and a downloaded remote version naturally replaces the builtin version once it passes verification and installs. See [Over-The-Air](/docs/guide/core-concepts/over-the-air) for the download and verification flow. ## Disk layout [#disk-layout] Inside the source directory, each bundle has its own folder, and the manifest lives at the root. ```text {source_dir}/ ├── {name}/ │ └── {name}_{version}.wvb └── manifest.json ``` For example, when the `app` bundle has two versions installed, `1.0.0` and `1.1.0`, the disk layout looks like this. ```text {source_dir}/ ├── app/ │ ├── app_1.0.0.wvb │ └── app_1.1.0.wvb └── manifest.json ``` The file path is always `{source_dir}/{name}/{name}_{version}.wvb`. The builtin bundle and the remote bundle are separate sources, so each is tracked by its own manifest. Bundle names and versions become path components, so they are restricted to ASCII `[A-Za-z0-9._-]`. ## Manifest [#manifest] `manifest.json` lives at the root of the source directory. For each bundle, it records the versions that exist, their metadata, and which version is current. ```json title="manifest.json" { "manifestVersion": 1, "entries": { "app": { "versions": { "1.0.0": {}, "1.1.0": {} }, "currentVersion": "1.0.0" } } } ``` The fields are as follows. | Field | Type | Description | | -------------------------------- | ----------------- | -------------------------------------------------------- | | `manifestVersion` | integer | Manifest schema version. Always `1`. | | `entries` | object | Map of bundle entries | | `entries.{name}.versions` | object | Map of per-version metadata | | `entries.{name}.currentVersion` | string (optional) | The active version served for this bundle. | | `entries.{name}.previousVersion` | string (optional) | The version that was active just before the current one. | Each version's metadata is an object whose fields are all optional. The metadata is usually populated from the remote server's response headers when the bundle is downloaded. | Field | Type | Description | | -------------- | ------ | --------------------------------------------------------------- | | `etag` | string | The server's `ETag` value for the downloaded bundle. | | `integrity` | string | Integrity hash, in `:` form (e.g. `sha256:n4bQ…`). | | `signature` | string | Base64 signature over the integrity string. | | `lastModified` | string | The server's `Last-Modified` value. | ### Current version and previous version [#current-version-and-previous-version] `currentVersion` is the version the source serves right now. It may be absent when several versions are staged but none is active yet. Staging a version records it under `versions` without changing `currentVersion`. `previousVersion` is the version that was current just before the most recent activation. A source keeps it for two reasons. First, it lets you roll back to a build confirmed to work. Second, it keeps the previous file on disk so an in-flight request that already opened that file can finish reading cleanly while the new version becomes current. Only the current and previous versions are kept; older versions are cleaned up. # Communicate between native and webview (/docs/guide/core-concepts/communicate-between-native-and-webview) To use native features from web code in the webview, you communicate with the native side. Webview Bundle provides a bridge for this. ## Call the bridge [#call-the-bridge] In the webview, call native features with `invoke(name, params)` from the unified bridge package `@wvb/bridge`. A handler registered on the native side processes the call and returns a result. The delivery mechanism per platform and framework is as follows. * **Electron** — Electron IPC * **Tauri** — Tauri command * **Android** — WebView message listener (`WebViewCompat.addWebMessageListener`) * **iOS** — `WKScriptMessageHandler` For details on using the bridge API, see the [Bridges](/docs/guide/frontend/bridges) guide. # Glue to native (/docs/guide/core-concepts/glue-to-native) Webview Bundle is designed to avoid being tied to any specific native platform or framework. Write your familiar web application code once, and a single core lets you integrate it the same way across multiple platforms and frameworks. ## A core written in Rust [#a-core-written-in-rust] The core crate (`wvb`) is written in Rust and designed to run across multiple platforms. The core crate provides the following: * Read and write the `.wvb` bundle format * Manage bundle sources (builtin and remote) * Download bundles from a remote * Remote updater * Protocol handling (serve bundles over a custom scheme, with `GET`, `HEAD`, and range request support) * Integrity and signature verification ## Multi-platform and multi-environment support [#multi-platform-and-multi-environment-support] To support multiple platforms and environments, the `wvb` crate ships with bindings. Each binding exposes the API of the `wvb` core crate as-is, so you use the same API across different platforms and environments. * **Node.js** * Uses a native addon built with [napi.rs](https://napi.rs/) that binds the Rust code to [N-API](https://nodejs.org/api/n-api.html). * The N-API version is 8; for compatible Node.js versions, see the [Node.js docs](https://nodejs.org/api/n-api.html#node-api-version-matrix). * **Android/iOS** * Uses [uniffi](https://github.com/mozilla/uniffi-rs) to generate Kotlin/Swift bindings from the Rust code. * The generated bindings are published as part of the [Android](https://github.com/webview-bundle/webview-bundle-android) and [iOS](https://github.com/webview-bundle/webview-bundle-ios) libraries, respectively. * **Deno** * Uses the [Deno FFI](https://docs.deno.com/runtime/fundamentals/ffi/) API to load the library dynamically. See the full API reference [here](/docs/references). ## Glue to native [#glue-to-native] The core intercepts the webview's network requests, reads resources from the bundle, and responds. On Android, for example, you override `WebViewClient.shouldInterceptRequest` to hand the request to the core's protocol handler. ```kotlin class WebViewBundleClient( private val owner: WebViewBundle, ) : WebViewClient() { override fun shouldInterceptRequest( view: WebView, request: WebResourceRequest, ): WebResourceResponse? = owner.handleRequest(request) } ``` The integration package for each platform and framework handles this glue for you, so in most cases you never write intercept code yourself. See the **Native** section for details. # Over-the-air (/docs/guide/core-concepts/over-the-air) Download new webview bundles remotely. Ship updated app code through the Webview Bundle remote server without redeploying the native app. ## Update lifecycle [#update-lifecycle] After you build your app code and package it into the Webview Bundle format, it goes through five steps before it reaches the device. 1. Pack the build output into the `.wvb` format. 2. Upload the packed webview bundle file to the remote server. You can attach an integrity hash and a signature. 3. Deploy the uploaded version so clients can fetch its update info. 4. The client checks for a new version, then downloads it. 5. Verify the downloaded data, then install it into the remote source. Steps 1 through 3 run as CLI commands. ```sh wvb pack # Package the `.wvb` file wvb upload --version 1.2.0 # Upload version 1.2.0 to the remote server wvb deploy --version 1.2.0 # Deploy 1.2.0 as the current version ``` Or integrate it in a more convenient way for the platform/framework you use. See the guide in the **Native** section. ## Updating on the client [#updating-on-the-client] Control how the client downloads the remote bundle and installs it into the remote [bundle source](/docs/guide/core-concepts/bundle-source). The available APIs are: * **updater.getUpdate** : Queries the remote's current version info (a HEAD request) and compares it against the installed version. It does not download anything; it returns whether an update is available along with the version info. * **updater.download** : Downloads the new version's bundle, verifies it, then stages it on disk. It is not activated at this step yet. * **updater.install** : Activates the downloaded version as the current version. That version is served from installation onward. Because download and install are separate, you can apply a new bundle at whatever timing fits your app's business requirements. *** Here is how to use the API from the Rust core crate. ```rust use std::sync::Arc; use wvb::updater::Updater; let updater = Updater::new(source, remote, None); let update = updater.get_update("app").await?; if update.is_available { let info = updater.download("app", None).await?; updater.install("app", info.version).await?; // The new version bundle is available from here on } ``` See the guide docs for how to use the update API on each platform/framework. ### Integrity [#integrity] An integrity hash lets the client confirm that the bundle it downloaded matches the data of the bundle deployed on the remote. The supported algorithms (SHA-2) are `sha256` (default), `sha384`, and `sha512`, serialized in the `":"` format. ```text sha256:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ``` The client recomputes the hash from the downloaded bundle data and checks that it matches the integrity hash the remote reported. Verification runs before installation, and installation fails if they do not match. There are three verification policies. * `strict` : An integrity hash must be present; it fails if the hash is missing or does not match. * `optional` (default) : Verifies the hash if present, and skips it if absent. * `none` : Does not verify integrity. ### Signature [#signature] A signature proves that the bundle was deployed by the holder of the private key. An integrity hash only guarantees that the data matches a specific hash, but a signature also confirms the authenticity of the deployer. The signature is generated over the integrity string, so you must enable integrity together to use signatures. The supported algorithms are: * ECDSA (P-256, P-384) * Ed25519 * RSA (PKCS#1 v1.5, PSS) Signature verification is optional. Configure a signature verifier with a public key on the client, and it checks the downloaded bundle's signature against the integrity string, aborting installation if verification fails. ## Remote [#remote] The remote is an HTTP server from which clients download bundles and metadata. Configure it with an endpoint URL. It provides listing bundles, querying current version metadata (HEAD), and downloading the current version and specific versions. Version, integrity, and signature values are passed in the response headers. ### Providers [#providers] Builtin providers let you skip running a bundle server yourself. * **AWS** — `@wvb/remote-aws` * **Cloudflare** — `@wvb/remote-cloudflare` You can also build your own provider by implementing the remote HTTP protocol. See the [Remote](/docs/guide/remote) docs for details. ### Channels [#channels] A channel is a label that distinguishes deployments (for example, `stable`, `beta`). The client receives the current version of the channel it specifies, and receives the default deployment when it specifies no channel. In Rust, you specify the channel on `UpdaterConfig`. ```rust use wvb::updater::{Updater, UpdaterConfig}; let config = UpdaterConfig::new().channel("beta"); let updater = Updater::new(source, remote, Some(config)); ``` The channel is passed to the remote request as the `?channel=beta` query parameter. # Handling protocols (/docs/guide/core-concepts/protocol-handling) Webview Bundle provides a protocol handler that responds to HTTP requests with the matching resource inside a bundle. On each platform and framework, this protocol handler serves webview requests by returning resources from a Webview Bundle as standard HTTP responses. ## Bundle protocol [#bundle-protocol] The bundle protocol loads the file at the requested path from the Webview Bundle mapped to the request URI, then returns it as an HTTP response. For example, given the request URI `app://app.wvb/index.html`, the handler resolves the bundle name to `app` and the file path within the bundle to `/index.html`, then returns the HTTP response. ```text app://app.wvb/index.html -> bundle "app", file "/index.html" app://myapp.wvb/assets/logo.png -> bundle "myapp", file "/assets/logo.png" ``` Path resolution fills in `index.html` like a static file server. When the path ends with a slash, or the last segment has no `.`, the handler fills in `index.html` and looks up that file in the bundle. ```text / -> /index.html # path ends with a slash /about -> /about/index.html # last segment has no "." /a.js -> /a.js # last segment has a ".", so it is served as-is ``` When the bundle is not found, the handler fails with a `BundleNotFound` error and responds with 500 (Internal Server Error). When the bundle exists but the file is not found inside it, the handler responds with 404 (Not Found). ### Methods, headers, responses [#methods-headers-responses] Only `GET` and `HEAD` are served; any other method returns 405 (Method Not Allowed). `HEAD` returns the headers with an empty body. When serving a file, the handler adds the `Content-Type` and `Content-Length` header values recorded in the index entry by default. Any other headers you added are also included in the response. ```text GET app://app.wvb/assets/app.js -> 200 OK cache-control: public, max-age=31536000 # value you set on the index entry content-type: application/javascript # value recorded in the index entry content-length: 84213 # decompressed size ``` ### Range requests [#range-requests] Webviews rely on range requests to seek media and resume large downloads. When the `Range` header is present, the handler returns 206 (Partial Content) with `Accept-Ranges: bytes` and `Content-Range`. ```text GET app://app.wvb/media/clip.mp4 Range: bytes=0-1023 -> 206 Partial Content accept-ranges: bytes content-range: bytes 0-1023/5242880 content-length: 1024 ``` * Each returned range is capped at `1000 * 1024` bytes (about 1 MB); a requested range larger than this is truncated. * Multiple ranges are returned as a `multipart/byteranges` response. * An unsatisfiable range returns 416 (Range Not Satisfiable) with `Content-Range: bytes */`. ```text Range: bytes=99999999- -> 416 Range Not Satisfiable content-range: bytes */5242880 ``` Ranges are computed against the decompressed content. Offsets therefore match the files the build produced. ## Local protocol [#local-protocol] Instead of fetching resources from a Webview Bundle file (`.wvb`), the local protocol lets you proxy resources from localhost. This is useful during development. For example, to run hot reload from a [Vite](https://vite.dev/) dev server (such as `http://localhost:5173`), configure Electron as follows. ```ts title="main.ts" import { localProtocol, wvb } from '@wvb/electron'; const instance = wvb({ protocols: [ localProtocol('myscheme', { hosts: { 'myapp.wvb': 'http://localhost:5173', }, }), ], }); ``` You can then load the webview from the `myscheme://myapp.wvb` URL. *** For details on using protocols on each platform and framework, see the "Native" section. # Webview Bundle (.wvb) (/docs/guide/core-concepts/webview-bundle) A webview bundle packs many web resources into a single `.wvb` file. Packing a web app puts its assets — HTML, JS, CSS, images — into this one file. The native host intercepts the webview's requests and answers them by reading assets from the file. Each asset is stored with a checksum, so the host serves integrity-checked assets with no network. ## Data structure [#data-structure] A .wvb file has three sections — Header, Index, and Data — and each ends with an xxHash-32 checksum. A `.wvb` file has three sections: a header, an index, and data. Each section ends with an xxHash-32 checksum that verifies its integrity. ### Header [#header] The header is the first 17 bytes of the file and holds the format metadata. * **Magic number (8 bytes)** — a fixed value that identifies the webview bundle format. It is `0xF09F8C90F09F8E81`, which is "🌐🎁" in UTF-8, written big-endian. * **Version (1 byte)** — the format version. The current value is v1 (`0x01`). * **Index size (4 bytes)** — the size of the index section in bytes, stored as a big-endian u32. * **Checksum (4 bytes)** — an xxHash-32 hash that verifies the preceding 13 bytes. ### Index [#index] The index maps each request path one-to-one to the location of its data. The host looks a request path up in the index to find that asset's byte range, then reads the range to answer the request. A request path is looked up in the index to get an offset and length, then those bytes are read from the data section. * The index occupies the size declared in the header and is encoded big-endian. * It maps a path (key) to an entry (value), serialized in sorted key order so the output is deterministic. * Each entry holds: * **Offset and length** — the byte range to read the file's data from the data section. * **Content type and content length** — the asset's MIME type and its original size before compression. * **HTTP headers** — headers to send when serving the asset over the protocol. (Optional) * The last 4 bytes are an xxHash-32 checksum that verifies the index. ### Data [#data] The data section stores each entry's file bytes in order. The host reads a single asset by seeking to the offset and length it got from the index. The data section stores each entry's compressed bytes back to back, and the index records the offset and length of each. For example, if the `/index.js` entry is recorded with offset `0` and length `768`, the host reads bytes `0` through `768` from the data section. * Each entry is compressed with the [LZ4 block format](https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md). * The last 4 bytes are an xxHash-32 checksum that verifies the data. ## Design decisions [#design-decisions] ### Why a new format instead of `.zip` [#why-a-new-format-instead-of-zip] `.zip` keeps its file listing (the central directory) at the end of the file, so finding an asset means reading the end first. It also carries none of the information — like content type or headers — needed to answer an HTTP request. The webview bundle format is built for one job: serving assets to a webview. * **The index comes first.** One lookup turns a path into a data location, with no scan of the file. * **Every entry stores HTTP metadata.** The host sends the content type and headers straight back as the HTTP response. * **The byte layout is fixed.** Reading only the needed range by offset and length makes HTTP range requests and streaming straightforward. * **A cheap checksum verifies it.** The header, index, and data are each verified with xxHash-32. ### Why LZ4 [#why-lz4] Decompression runs every time the host answers the webview, so decompression speed matters more than compression ratio. * **Decompression is very fast.** It does not delay first paint. * **It uses little CPU.** It does not block the UI thread. * **Each entry compresses independently.** The [LZ4 block format](https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md) decompresses each asset on its own, so the host reads only the assets it needs by random access. # Checking the sources (/docs/guide/frontend/bridges/checking-sources) Read installed bundles from the web app with the source bridge — current version, all versions, builtin vs remote. The `source` bridge reads the native bundle source from your web app. Use it to show the active version, list what is installed, and tell builtin bundles apart from remote (over-the-air) ones. ## Read the current version [#read-the-current-version] `loadVersion` returns the active version and its type, or `null` if the bundle is not loaded. ```ts title="src/version.ts" import { source } from '@wvb/bridge'; const current = await source.loadVersion('app'); // { type: 'builtin' | 'remote', version: '1.2.0' } | null ``` ## List installed bundles [#list-installed-bundles] `listBundles` returns every bundle the host knows about. Each item carries its `type` and the manifest item, including whether it is `current`. ```ts import { source } from '@wvb/bridge'; const bundles = await source.listBundles(); for (const { type, item } of bundles) { console.log(item.name, item.version, type, item.current); } ``` ## Use cases [#use-cases] * Render an "about" or diagnostics screen with the running version. * Detect whether the user is on a builtin fallback or a downloaded remote bundle. * Read `loadBuiltinMetadata` / `loadRemoteMetadata` to surface integrity or last-modified details. # Overview (/docs/guide/frontend/bridges) The web-side @wvb/bridge package that calls the native host over an auto-detected transport. `@wvb/bridge` is the web-side package. JavaScript inside the webview imports it to call the native host that manages your bundle source, remote, and updater. It auto-detects the transport per platform, so the same web code runs on Electron, Tauri, Android, and iOS. ```ts import { source, remote, updater } from '@wvb/bridge'; ``` ## Three surfaces [#three-surfaces] * `source` — inspect and manage the native bundle source: list bundles, load and switch versions, resolve files. * `remote` — talk to the configured remote through the host: list, inspect, and download bundles. * `updater` — drive the over-the-air update flow: check for an update, download it, install it. Each surface is typed and builds on the low-level `invoke()`. See the [bridge reference](/docs/references/api/bridge) for the full API. ## When to reach for it [#when-to-reach-for-it] Reach for `@wvb/bridge` when your web code needs to know or change which bundle is served — checking the active source, pulling a newer bundle from the remote, or running an OTA update from inside the app. # Testing (/docs/guide/frontend/bridges/testing) Test web code that calls the bridge without a native host — mock invoke calls and the platform with mockBridge. Test web code that calls the bridge without a native host. The `@wvb/bridge/testing` subpath mocks bridge calls so your code resolves against fixtures instead of a real platform. ## Mock a bridge [#mock-a-bridge] `mockBridge(options?)` creates a disposable bridge you register handlers on. Chain `.mockInvoke(command, handler)` once per dotted command key; the handler receives the method's params positionally and returns the value the call resolves to (or a promise of it). ```ts title="load-version.test.ts" import { expect, test } from 'vitest'; import { source } from '@wvb/bridge'; import { mockBridge } from '@wvb/bridge/testing'; test('loads the current version', async () => { using bridge = mockBridge({ platform: 'android' }); bridge.mockInvoke('source.loadVersion', bundleName => ({ type: 'remote', version: '1.0.0', })); await expect(source.loadVersion('app')).resolves.toEqual({ type: 'remote', version: '1.0.0', }); }); ``` Pass `{ platform }` to mock the platform at the same time: ```ts using bridge = mockBridge({ platform: 'ios' }).mockInvoke('source.loadVersion', () => ({ type: 'remote', version: '1.0.0', })); ``` `using` disposes the bridge at the end of the block, clearing every mock it registered. Without it, call `bridge.clear()` yourself so the stubs do not leak into the next test. ## Mock the platform [#mock-the-platform] `mockPlatform(type)` overrides platform detection on its own, for code that branches on `platform.type` (`platform.isIos`, `platform.isElectron`, …). It returns a disposable that restores the previous platform when the scope exits. `type` is one of `'electron'`, `'tauri'`, `'android'`, `'ios'`, or `'deno'`. ```ts import { platform } from '@wvb/bridge'; import { mockPlatform } from '@wvb/bridge/testing'; test('detects the iOS platform', () => { using _platform = mockPlatform('ios'); expect(platform.isIos).toBe(true); }); ``` ## Stub a single command [#stub-a-single-command] `mockInvoke(command, handler)` registers one command without a bridge instance — the primitive `mockBridge` builds on. It returns a disposable handle; reset every ambient mock with `clearInvokeMocks()`, for example in `afterEach`. ```ts using _mock = mockInvoke('source.loadVersion', () => ({ type: 'remote', version: '1.0.0' })); ``` # Update remote bundles (/docs/guide/frontend/bridges/update-remote-bundles) Drive an over-the-air update from the web app with the updater bridge — check, download, install, and reload. The `updater` bridge drives an over-the-air update from web code inside the webview: check for a newer bundle, download it, install it, then reload. ## Update flow [#update-flow] `getUpdate` reports whether a newer version is available. `download` stages it (verify and write to the native source store), `install` activates it, and a reload serves it. ```ts title="src/update.ts" import { updater } from '@wvb/bridge'; async function checkForUpdate(bundleName: string) { const update = await updater.getUpdate(bundleName); if (!update.isAvailable) { return; } await updater.download(bundleName); await updater.install(bundleName, update.version); // Reload so the webview serves the newly installed bundle. window.location.reload(); } ``` `getUpdate` resolves to a `BundleUpdateInfo`: `version` is what the remote offers, `localVersion` is what is installed. Check `isAvailable` before staging. ## Configure the updater first [#configure-the-updater-first] The bridge only forwards these calls to the native host — the updater and its remote live on the native side. See your platform's guide to wire them up. If no updater is configured on the host, `updater` calls reject with a `BridgeError` whose `code` is `BridgeErrorCode.UpdaterNotInitialized`. # Deploy (/docs/guide/frontend/deploy) Promote an already-uploaded version to current so clients pick it up over the air. Uploading stores a version on the remote. Deploying makes it the **current** version — the one clients download over the air. Deploy is a separate, fast step: no repack, no re-upload. Deploy after [uploading](/docs/guide/frontend/upload), or pass `--deploy` to `wvb upload` to do both at once. ## Deploy a version [#deploy-a-version] Point the remote at a version that is already uploaded: ```sh wvb deploy app --version 1.2.0 ``` `app` is the bundle name (falls back to your config or `package.json`). The version is the `--version` (`-V`) flag — there is no positional version. ## Channels [#channels] Deploy to a named channel to keep separate release tracks (`stable`, `beta`, `internal`, …). Clients on that channel receive the version you deploy there. ```sh wvb deploy app --version 1.2.0 --channel beta ``` Omit `--channel` to deploy to the default channel. ## Rollback [#rollback] There is no dedicated rollback command. To roll back, deploy a previously uploaded version — it becomes current again: ```sh wvb deploy app --version 1.1.0 ``` Any version already on the remote can be re-deployed, so keep known-good versions uploaded. # Development (/docs/guide/frontend/development) Run your framework's dev server and point the native Local Protocol at it so the webview loads your live, hot-reloading UI. During development you don't want to pack a `.wvb` on every change. Instead, run your framework's dev server and point the native **Local Protocol** at it, so the webview loads your live, hot-reloading UI. ## Run your dev server [#run-your-dev-server] Start your framework's dev server as you normally would: ```sh vite dev ``` Note the URL it prints (for example `http://localhost:5173`) — the native side proxies to it. ## Point the Local Protocol at it [#point-the-local-protocol-at-it] The native app registers two schemes: * A **Bundle Protocol** that serves files from the packed `.wvb` bundle. * A **Local Protocol** that proxies requests to your dev server. You pick which one the webview loads based on whether the app is running in development or production: * **Development** — load the Local Protocol URL (e.g. `app-local://app.wvb`). Requests forward to your dev server, so hot reload works. * **Production** — load the Bundle Protocol URL (e.g. `app://app.wvb`). Files come straight from the bundle. The exact scheme names, the host-to-dev-server mapping, and the dev-vs-prod switch are native-side config. Set them up on your platform's Local development page: ## Preview a packed bundle [#preview-a-packed-bundle] To check the production build — the packed `.wvb`, not the dev server — before shipping, serve it over HTTP with [`wvb serve`](/docs/references/cli/serve): ```sh wvb serve ./build/app.wvb ``` This unpacks one bundle and serves it at `http://localhost:4312`, matching how the webview loads it at runtime. # Packing (/docs/guide/frontend/packing) Pack a built web app into a single .wvb bundle with wvb pack. Packing turns a built web app into one `.wvb` file — the unit your app ships to its webview or uploads for over-the-air updates. ## Pack a bundle [#pack-a-bundle] Run `wvb pack` against your build output directory. It reads every file under the source directory and writes a single compressed `.wvb` archive. ```sh wvb pack # uses config defaults wvb pack ./dist # explicit source directory wvb pack ./dist --outfile ./build/app.wvb # explicit output path ``` The source directory defaults to `pack.srcDir` (or `./dist`), and the output path defaults to `pack.outFile`. The `.wvb` extension is appended when you omit it. See [`wvb pack`](/docs/references/cli/pack) for every flag. ## Name and version [#name-and-version] The bundle name comes from your `package.json` `name` field with any scope prefix stripped. It sets the default output path, `.wvb/.wvb`. The version comes from your `package.json` `version` field. Packing does not embed it in the filename — the version is stamped when you upload the bundle or install it as a builtin. ## Configure defaults [#configure-defaults] Set `pack` defaults in your `wvb.config` file so the command runs with no arguments. ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig({ pack: { srcDir: './dist', outFile: '.wvb/app', }, }); ``` `outFile` is a single output path — there is no separate `outDir`. A flag passed on the command line always overrides the config value. See [Configuration](/docs/references/configuration) for the full `pack` schema. ## Ship as builtin [#ship-as-builtin] A packed `.wvb` can ship inside your native app as a builtin bundle, served when the app is offline or before it fetches a newer bundle over the air. `wvb builtin` collects bundles into an output directory (default `.wvb/builtin/bundles`), laid out as `/_.wvb` alongside a `manifest.json`. # Upload to remote (/docs/guide/frontend/upload) Stage a packed .wvb version on the remote so you can deploy it later. `wvb upload` sends a packed `.wvb` to your configured remote. Uploading *stages* a version — it does not make it current. ## Upload a version [#upload-a-version] ```sh wvb upload app --version 1.2.0 ``` By default `wvb upload` packs `pack.srcDir`, computes an integrity hash, signs the bundle (when signing is configured), then uploads through `remote.uploader`. On success it prints the bundle endpoint. To upload a bundle you already built, skip packing and point at the file: ```sh wvb upload app --version 1.2.0 --no-pack --file ./build/app.wvb ``` Pass `--force` to overwrite a version that already exists on the remote. ## Stage vs deploy [#stage-vs-deploy] `--deploy` defaults to `false`, so an upload only stages the version. Clients keep receiving the previously deployed version until you activate this one. * **Upload** stores the version on the remote. * **Deploy** flips which version clients download. `--channel` applies only with `--deploy`. To upload and activate in one step, add `--deploy` (and `--channel beta` to target a channel). ## Requirements [#requirements] Uploading requires `remote.uploader` in your config. The optional `--deploy` step also needs `remote.deployer`. See [Remote configuration](/docs/references/configuration/remote). # Start with an example (/docs/guide/getting-started/example) Use `create-wvb` to scaffold an example project with your preferred tool. ```sh npx create-wvb@latest ``` ```sh pnpx create-wvb@latest ``` ```sh yarn dlx create-wvb@latest ``` ## Example list [#example-list] Find the available examples in the table below. | Example | Description | | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | | [electron-builder-app](https://github.com/webview-bundle/webview-bundle/tree/main/examples/electron-builder-app) | Electron app packaged with electron-builder | | [electron-forge-app](https://github.com/webview-bundle/webview-bundle/tree/main/examples/electron-forge-app) | Electron app packaged with Electron Forge | # Introduction (/docs/guide/getting-started) *** ## Overview [#overview] Webview Bundle is an offline-first distributing system for web applications on webview-based frameworks and platforms. Instead of loading your web app over the network and rendering it in the webview, you pack it into a webview bundle file (`.wvb`) and render it from local resources. You can also set up a remote, download bundles from it, and update your app's code over the air — with no native release. Webview Bundle supports the platforms that host a webview — [Electron](https://electronjs.org), [Tauri](https://tauri.app), Android, iOS, and [Deno Desktop](https://deno.com/blog/v2.9#deno-desktop) (experimental) — and provides a [bridge](/docs/guide/core-concepts/communicate-between-native-and-webview) for communicating with the webview. ## Features [#features] ### Web inside native [#web-inside-native] With Webview Bundle, you embed familiar frontend code in a native app and ship an application that runs offline. You pack the web app into the webview bundle (`.wvb`) format and include it in the native app bundle. On the native side, the host intercepts the webview's requests and answers them by reading resources from the bundle file. Because it serves local data instead of going over the network, the web app works offline. ### Over-the-air (OTA) [#over-the-air-ota] Webview Bundle provides over-the-air (OTA) updates to keep the bundle inside the native app current. You create a [remote](/docs/guide/core-concepts/over-the-air) provider, upload the bundles you want to ship, and download new bundles from the frontend or the native side whenever you choose. An over-the-air update needs no native release and no app restart, so the app stays current without disrupting the user. Electron, for example, downloads tens of megabytes and restarts the app to apply an update; Webview Bundle skips that. ### Multi-platform support [#multi-platform-support] The Webview Bundle core is written in Rust and builds for many platforms. * Node.js — a [native add-on](https://nodejs.org/api/n-api.html) built with [napi.rs](https://napi.rs/). * Android and iOS — Kotlin and Swift bindings generated with [UniFFI](https://github.com/mozilla/uniffi-rs). * Deno — a dynamic library linked through the [Deno FFI](https://docs.deno.com/runtime/fundamentals/ffi/) API. # Platform and framework support (/docs/guide/getting-started/platform-and-framework-support) The platforms and frameworks that run Webview Bundle. Webview Bundle supports several native platforms and frameworks. ## Support status [#support-status] | Platform | Compatible versions | Status | | ------------ | ----------------------------- | ------------ | | Electron | Electron >= 15 | Stable | | Tauri | Tauri v2 / Windows >= 10 | Stable | | Android | Android minSdk >= 24 | Stable | | iOS | iOS 16 / macOS 12.0 / Swift 6 | Stable | | Deno Desktop | Deno >= 2.9.0 | Experimental | If you need support for more platforms or frameworks, please file a request in the [GitHub discussions](https://github.com/webview-bundle/webview-bundle/discussions). # Prerequisites (/docs/guide/getting-started/prerequisites) Install a few dependencies before you start a project. ## Node.js [#nodejs] Install [Node.js](https://nodejs.org/en) to use the Webview Bundle command line. * Minimum required version: 18 * Recommended version: LTS ## Android [#android] Android app development requires the Android SDK. (Or install [Android Studio](https://developer.android.com/studio).) The minimum required tool versions are: * JDK 17 * Minimum Android SDK version: 24 ## iOS [#ios] iOS app development requires [Xcode](https://developer.apple.com/xcode/). The minimum required tool versions are: * Swift v5 * iOS 16 ## Deno [#deno] Install Deno if you use [Deno Desktop](/docs/guide/native/deno). *** For the dependencies each platform requires, see the guide for each framework. # Builtin bundles (/docs/guide/native/android/builtin) Install builtin Webview Bundles into an Android app module with wvb builtin so the Source serves them offline. `wvb builtin` installs the bundles your Android app ships into the module's `assets/bundles/`, where the [Source](/docs/guide/native/android) reads them on first launch — before any over-the-air update. ## Install into the app module [#install-into-the-app-module] Run the CLI with the `--android` preset. Bare `--android` auto-detects the `com.android.application` module; pass `--android=` to point at it explicitly. ```sh # Auto-detect the app module and install into src/main/assets/bundles wvb builtin --android # Or target an explicit module wvb builtin --android=./app ``` The bundles come from `builtin.target` in your config — a remote endpoint by default, or local workspaces. Use `--endpoint` and `--channel` to override the remote target. See [`wvb builtin`](/docs/references/cli/builtin) for every flag. The preset writes into `/src/main/assets/bundles/`: a `manifest.json` plus one `/_.wvb` file per bundle. ```text app/src/main/assets/bundles/ ├── manifest.json └── app/ └── app_0.1.0.wvb ``` Keep `.wvb` assets uncompressed so the APK does not re-compress them: add `noCompress += "wvb"` to the `androidResources` block in your module's `build.gradle.kts`. The CLI warns when it is missing. ## How the Source loads them [#how-the-source-loads-them] The native Source reads files, not asset streams, so the library copies `assets/bundles/` into the app's `filesDir` on each install or update. This is controlled by `SourceOptions.builtinAssetsDir`: ```kotlin import dev.wvb.SourceOptions WebViewBundleConfig( protocols = listOf(WebViewBundleProtocol.bundle()), source = SourceOptions( builtinAssetsDir = "bundles", // APK assets/; null disables extraction ), ) ``` The extracted copy under `/wvb/builtin` is read-only; over-the-air downloads land in the writable `/wvb/remote`. # Setup (/docs/guide/native/android) Serve and update Webview Bundles inside an Android WebView with the webview-bundle-android Kotlin library. The `webview-bundle-android` library wires the Webview Bundle Rust core into an Android `WebView`. Give it a `WebView`; it intercepts requests over ordinary `https://.wvb/` URLs, serves files from a bundle you ship in the APK, and pulls newer bundles over the air (OTA) from a remote without an app-store release. ## Requirements [#requirements] | Item | Value | | ----------------- | ------------------------------------------------------------------ | | `minSdk` | 24 (Android 7.0) | | JVM target | 17 (Java and Kotlin source/target 17) | | AndroidX | Required (`android.useAndroidX=true`, needed by `androidx.webkit`) | | System WebView | Must support `WEB_MESSAGE_LISTENER` (modern WebView / Chrome 88+) | | Library namespace | `dev.wvb` | The bridge attaches through `WebViewCompat.addWebMessageListener`. On a device whose System WebView is too old for `WEB_MESSAGE_LISTENER`, the bridge is not attached and the library logs a warning — serving still works, only the JavaScript bridge is unavailable. Runtime dependencies are pulled in transitively: JNA (`net.java.dev.jna:jna`, loads the native `libwvb_ffi.so`), `kotlinx-coroutines-core`, and `androidx.webkit`. Consumer R8/ProGuard rules ship with the library, so you do not add keep rules for the FFI yourself. Add the dependency: ```kotlin title="build.gradle.kts" dependencies { implementation("dev.wvb:webview-bundle-android:") } ``` See [Platform support](/docs/guide/getting-started/platform-and-framework-support) for the status of every platform. ## Quick start [#quick-start] Obtain the process-wide `WebViewBundle` singleton with `WebViewBundle.getInstance`, install it onto your `WebView`, then load a bundle URL. The bundle name is the first label of the host, so `https://app.wvb/` serves the bundle named `app`. ```kotlin title="MainActivity.kt" import android.os.Bundle import android.webkit.WebSettings import android.webkit.WebView import androidx.appcompat.app.AppCompatActivity import dev.wvb.WebViewBundle import dev.wvb.WebViewBundleConfig import dev.wvb.WebViewBundleProtocol class MainActivity : AppCompatActivity() { private lateinit var webView: WebView private lateinit var handle: AutoCloseable override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val wvb = WebViewBundle.getInstance( this, WebViewBundleConfig( protocols = listOf(WebViewBundleProtocol.bundle()), ), ) webView = WebView(this) webView.settings.apply { javaScriptEnabled = true domStorageEnabled = true mixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW allowFileAccess = false allowContentAccess = false } handle = wvb.install(webView) { } webView.loadUrl("https://app.wvb/") setContentView(webView) } override fun onDestroy() { handle.close() webView.destroy() super.onDestroy() } } ``` `getInstance` honors `config` only on the first call per process; later calls return the existing instance and ignore the passed config. `getInstance` also has shorthand aliases: ```kotlin WebViewBundle.getInstance(context, config) // canonical WebViewBundle(context, config) // invoke operator webViewBundle(context, config) // top-level fun wvb(context, config) // short alias ``` The manifest needs the internet permission. For local development against a cleartext dev server or remote, also enable `usesCleartextTraffic`. ```xml title="AndroidManifest.xml" ``` `usesCleartextTraffic="true"` is for local development only. Production bundles are served over `https://` from inside the app and remote endpoints should use TLS, so leave cleartext disabled in release builds. ## How serving works [#how-serving-works] No custom URL scheme is registered. `install()` sets a `WebViewClient` whose `shouldInterceptRequest` inspects ordinary `http`/`https` requests and serves matching ones from the bundle source. For each request, the handler lowercases the host and walks your registered protocols in order; the first matcher to accept the host wins. The bundle protocol takes the bundle name from the first host label and returns the file at the request path. No match returns `null` and the `WebView` loads from the network. If a handler throws, the library synthesizes a `500 text/plain` response and calls the optional `onError` callback. See [Protocol handling](/docs/guide/core-concepts/protocol-handling) for how a request path maps to a file inside a `.wvb`. `install()` also attaches the native bridge as `window.wvbAndroid` on the main frame. Use the install options to register extra native handlers, wrap your own `WebViewClient`, or skip the bridge: ```kotlin val handle = wvb.install(webView) { delegate = myWebViewClient // your callbacks are preserved disableBridge = false // set true to skip window.wvbAndroid bridge = { handler("greet") { params -> "hello" } } } ``` If you want the serving seam without the bridge at all, use the low-level client directly: ```kotlin webView.webViewClient = wvb.createWebViewClient(delegate = myWebViewClient) ``` ## Builtin bundles [#builtin-bundles] Ship the bundle your app starts with inside the APK under `assets/bundles/` — a `manifest.json` plus the `.wvb` files it references. ```text app/src/main/assets/bundles/ ├── manifest.json └── app/ └── app_0.1.0.wvb ``` The native source reads files, not asset streams, so the library copies `assets/bundles/` into the app's `filesDir`. This is controlled by `SourceOptions`: ```kotlin import dev.wvb.SourceOptions WebViewBundleConfig( protocols = listOf(WebViewBundleProtocol.bundle()), source = SourceOptions( builtinAssetsDir = "bundles", // APK assets/; null disables extraction // builtinDir defaults to /wvb/builtin (read-only) // remoteDir defaults to /wvb/remote (writable) ), ) ``` Re-extraction happens on each APK install or update and is additive — removed assets are not deleted. The `manifest.json` declares the bundle entries and current version, and may carry `integrity` and `signature` values: ```json title="manifest.json" { "manifestVersion": 1, "bundles": { "app": { "currentVersion": "0.1.0", "versions": { "0.1.0": { "integrity": "sha256:n4bQgYhMfWWaL...", "signature": "..." } } } } } ``` See [Bundle sources](/docs/guide/core-concepts/bundle-source) for the manifest format. ## Protocols [#protocols] A protocol decides which hosts a `WebView` request is served from. Register protocols in `WebViewBundleConfig.protocols`; they are evaluated in order and the first matching one wins, so **register `bundle()` last** because it matches every host. `WebViewBundleProtocol.bundle()` serves entries from the bundle source for every host, using the first host label as the bundle name. Pass a passthrough block to send named hosts to the network instead: ```kotlin WebViewBundleProtocol.bundle { passthrough("api.example.com") passthroughDomain("analytics.example.com") passthrough { host -> host.endsWith(".cdn.example.com") } } ``` `WebViewBundleProtocol.local(hosts)` is a development proxy. It maps a full request host to a local base URL so you keep your bundler's hot reload while developing. On the Android emulator, `10.0.2.2` reaches the host machine's loopback: ```kotlin WebViewBundleProtocol.local( mapOf("app.wvb" to "http://10.0.2.2:3000"), ) ``` A typical dev configuration registers `local()` for the hosts you proxy and `bundle()` last as the fallback: ```kotlin WebViewBundleConfig( protocols = listOf( WebViewBundleProtocol.local(mapOf("app.wvb" to "http://10.0.2.2:3000")), WebViewBundleProtocol.bundle(), ), ) ``` ## OTA updates [#ota-updates] Pass a `WebViewBundleUpdaterConfig` as `WebViewBundleConfig.updater`. The library then builds a remote client and an updater, exposed as `wvb.remote` and `wvb.updater` (both `null` when no updater config is provided). ```kotlin title="MainActivity.kt" import android.util.Base64 import dev.wvb.IntegrityPolicy import dev.wvb.SignatureAlgorithm import dev.wvb.SignatureVerifierOptions import dev.wvb.SignatureVerifyingKey import dev.wvb.VerifyingKeyFormat import dev.wvb.WebViewBundleConfig import dev.wvb.WebViewBundleProtocol import dev.wvb.WebViewBundleRemoteConfig import dev.wvb.WebViewBundleUpdaterConfig val wvb = WebViewBundle.getInstance( this, WebViewBundleConfig( protocols = listOf(WebViewBundleProtocol.bundle()), updater = WebViewBundleUpdaterConfig( remote = WebViewBundleRemoteConfig(endpoint = "http://10.0.2.2:4313"), channel = "stable", integrityPolicy = IntegrityPolicy.STRICT, signatureVerifier = SignatureVerifierOptions( algorithm = SignatureAlgorithm.ED25519, key = SignatureVerifyingKey( format = VerifyingKeyFormat.SPKI_DER, pem = null, der = Base64.decode("MCowBQYDK2VwAyEA...", Base64.NO_WRAP), ), ), ), onError = { error -> /* log */ }, ), ) ``` `IntegrityPolicy.STRICT` rejects a bundle whose digest does not match; `OPTIONAL` verifies when present and skips when absent; `NONE` skips the check. The integrity string uses SHA-2 (`sha256`, `sha384`, or `sha512`). The signature verifier proves who published the bundle. Not every algorithm and key-format pair is valid: | `SignatureAlgorithm` | Valid `VerifyingKeyFormat` | | ------------------------------------ | ----------------------------------------------------- | | `ECDSA_SECP256R1`, `ECDSA_SECP384R1` | `SEC1`, `SPKI_DER`, `SPKI_PEM` | | `ED25519` | `SPKI_DER`, `SPKI_PEM`, `RAW` (32-byte key via `der`) | | `RSA_PKCS1_V15`, `RSA_PSS` | `PKCS1_DER`, `PKCS1_PEM`, `SPKI_DER`, `SPKI_PEM` | An unsupported pair throws `Exception.Signature` when the updater is built. `pem` is read for `*_PEM` formats; `der` for DER, `SEC1`, and `RAW`. On the Android emulator, a remote running on the host machine is reachable at `http://10.0.2.2:4313` (the local remote's default port). The `channel` value is sent to the remote as a query parameter so it can serve a specific release channel. ### Driving updates from Kotlin [#driving-updates-from-kotlin] The updater runs a three-step cycle. Each call is a `suspend` function, so call it from a coroutine. ```kotlin import kotlinx.coroutines.launch lifecycleScope.launch { val update = wvb.updater?.getUpdate("app") // check the remote, no download if (update != null && update.isAvailable) { wvb.updater?.downloadUpdate("app") // download latest, persist to remote dir wvb.updater?.install("app", update.version) // verify, activate, prune old versions } } ``` `getUpdate` reports whether a newer version exists without downloading. `downloadUpdate` fetches and stores the bundle (the latest version when you pass no version). `install` verifies integrity and signature on the staged bundle, makes it current, and prunes stale versions. ### Driving updates from web JavaScript [#driving-updates-from-web-javascript] The same cycle is available to your web app through the `window.wvbAndroid` bridge. The built-in updater commands are `updaterGetUpdate`, `updaterDownload`, and `updaterInstall`; they throw `updater_not_initialized` when no updater config was provided. ```ts declare const wvbAndroid: { postMessage(message: string): void; }; // The bridge posts { name, params, success, error } and replies via callbacks. // A small wrapper that resolves a Promise per command: function invoke(name: string, params?: unknown): Promise { return new Promise((resolve, reject) => { // ... wire success/error callbacks, then: wvbAndroid.postMessage(JSON.stringify({ name, params })); }); } const update = await invoke('updaterGetUpdate', { name: 'app' }); await invoke('updaterDownload', { name: 'app' }); await invoke('updaterInstall', { name: 'app', version: '0.2.0' }); ``` For the remote HTTP contract, integrity, and signatures across platforms, see [Remote bundles](/docs/guide/core-concepts/over-the-air) and the guide to [building a remote](/docs/guide/remote). # Local development (/docs/guide/native/android/local-development) Route a bundle host to your dev server with a Local protocol so the Android WebView loads your live dev build. Register a Local protocol to map a bundle host to your bundler's dev server. The `WebView` then loads your live dev build with hot reload intact, while unmapped hosts still fall through to the shipped bundle. ## Map the bundle host to your dev server [#map-the-bundle-host-to-your-dev-server] `WebViewBundleProtocol.local(hosts)` maps a full request host to a local base URL. Register it before `bundle()`, which matches every host, so the fallback stays last. ```kotlin title="MainActivity.kt" import dev.wvb.WebViewBundleConfig import dev.wvb.WebViewBundleProtocol WebViewBundleConfig( protocols = listOf( WebViewBundleProtocol.local(mapOf("app.wvb" to "http://10.0.2.2:3000")), WebViewBundleProtocol.bundle(), ), ) ``` Requests to `app.wvb` now proxy to `http://10.0.2.2:3000`; every other host serves from the bundle source. ## Reach the host machine from the emulator [#reach-the-host-machine-from-the-emulator] On the Android emulator, `10.0.2.2` reaches the host machine's loopback, so a dev server on `localhost:3000` is `http://10.0.2.2:3000`. A cleartext `http://` server needs `usesCleartextTraffic` enabled in the manifest. ```xml title="AndroidManifest.xml" ``` `usesCleartextTraffic="true"` is for local development only. Leave it disabled in release builds. # Building (/docs/guide/native/deno/building) Compile a Deno Desktop app into a self-contained binary that embeds the native cdylib and your builtin bundles. Compile a Deno Desktop app into a distributable binary with `deno desktop`, embedding the `@wvb/deno` native library and your builtin bundles so it runs offline with no separate install. A single compiled binary targets one platform. Vendor and compile once per target triple you ship. ## Vendor the native library [#vendor-the-native-library] `@wvb/deno` loads a prebuilt Rust `cdylib` over FFI. Download it into your project for the target you are building: ```sh deno run -A jsr:@wvb/deno/install --out vendor/wvb --target aarch64-apple-darwin ``` The library is saved under the plain platform name — `libwvb_deno.dylib`, `libwvb_deno.so`, or `wvb_deno.dll` — and its SHA-256 checksum is verified before it is written. See the [Deno Desktop setup](/docs/guide/native/deno) for the supported target triples. ## Compile a distributable binary [#compile-a-distributable-binary] Embed the vendored `cdylib` and your packed `bundles` directory with `deno desktop --include`, then resolve the library from `import.meta.url` at runtime: ```sh deno desktop --allow-ffi --include vendor/wvb/libwvb_deno.dylib --include bundles main.ts ``` ```ts title="main.ts" import { webviewBundle, bundleProtocol } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ lib: new URL('./vendor/wvb/libwvb_deno.dylib', import.meta.url), protocols: [bundleProtocol('app')], }); ``` The app reads builtin bundles from the included `bundles` directory next to its entry module, so the compiled binary serves them without network access. # Builtin bundles (/docs/guide/native/deno/builtin) Ship bundles inside a Deno Desktop app by installing them into the builtin directory the BundleSource reads. Builtin bundles ship inside the app so the window loads offline on first launch, before any bundle has been downloaded over the air. The `BundleSource` reads them from its `builtinDir`; `wvb builtin` writes the installed set into that directory. ## Point the source at a builtin directory [#point-the-source-at-a-builtin-directory] `webviewBundle` builds its `BundleSource` from `source`. Set `builtinDir` to the directory you install into. It defaults to `bundles` next to your entry module. ```ts title="main.ts" import { webviewBundle, bundleProtocol } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], source: { builtinDir: './bundles' }, }); ``` ## Install with wvb builtin [#install-with-wvb-builtin] Run `wvb builtin` and point `--out` at that same directory. It writes a `manifest.json` plus one `/_.wvb` file per bundle. ```sh wvb builtin --out ./bundles ``` Whether bundles come from a remote endpoint or from local workspaces is set by `builtin.target` in your [config](/docs/references/configuration), not by a CLI flag. It defaults to a remote target. See [`wvb builtin`](/docs/references/cli/builtin) for every flag and both target shapes. # Setup (/docs/guide/native/deno) Serve and update Webview Bundle archives in a Deno desktop webview through a Deno.serve request handler. Experimental Deno Desktop renders a native webview with `Deno.BrowserWindow` and serves it over `Deno.serve`. Webview Bundle becomes that server's handler, so the window loads your packed `.wvb` assets offline instead of fetching them over the network. ```ts title="main.ts" import { webviewBundle, bundleProtocol } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], }); const server = Deno.serve(wvb.fetch); const win = new Deno.BrowserWindow({ url: `http://localhost:${server.addr.port}` }); await win.closed; ``` `@wvb/deno-desktop` is the integration layer; `@wvb/deno` is the FFI peer of [`@wvb/node`](/docs/references/api/node) that drives the shared Rust core. ## How it fits together [#how-it-fits-together] The window points at a single local origin served by `Deno.serve`, so the integration is **single-origin**: it allows exactly one protocol. See [Platform integration](/docs/guide/core-concepts/glue-to-native) for how the core reaches each platform and [Protocol handling](/docs/guide/core-concepts/protocol-handling) for the protocol model. ## @wvb/deno-desktop [#wvbdeno-desktop] Call `webviewBundle(config)` — aliased as `wvb`, backed by the `WebviewBundle` class — to build a `BundleSource` (plus an optional `Remote` and `Updater`) and get back a `Deno.serve`-compatible `fetch` handler. Add an `updater` to pull newer bundles from a remote: ```ts title="main.ts" import { webviewBundle, bundleProtocol } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], updater: { remote: { endpoint: 'https://bundles.example.com' }, }, }); const server = Deno.serve(wvb.fetch); const win = new Deno.BrowserWindow({ url: `http://localhost:${server.addr.port}` }); await win.closed; ``` ### Bindings [#bindings] Call `registerBindings(win, wvb)` to expose native commands to your web app. It registers one `Deno.BrowserWindow` binding named `wvbInvoke`, reachable from the page as `window.bindings.wvbInvoke`, that dispatches every `@wvb/bridge` command in the `source.*`, `remote.*`, and `updater.*` groups. ```ts title="main.ts" import { webviewBundle, bundleProtocol, registerBindings } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], }); const server = Deno.serve(wvb.fetch); const win = new Deno.BrowserWindow({ url: `http://localhost:${server.addr.port}` }); registerBindings(win, wvb); // wires window.bindings.wvbInvoke await win.closed; ``` The binding never throws across the FFI boundary. Each call resolves to an `InvokeResult` envelope: ```ts type InvokeResult = | { ok: true; value: unknown } | { ok: false; error: { code?: string; message: string } }; ``` The `@wvb/bridge` client unwraps this envelope once it detects the `deno` platform, so web code keeps calling `invoke()`, `source.*`, `remote.*`, and `updater.*` exactly as on other platforms: ```ts title="app.ts (in the webview)" import { updater } from '@wvb/bridge'; const update = await updater.getUpdate('my-app'); if (update.isAvailable) { await updater.download('my-app'); await updater.install('my-app', update.version); } ``` ## @wvb/deno [#wvbdeno] `@wvb/deno` is the FFI peer of [`@wvb/node`](/docs/references/api/node). It loads a prebuilt Rust `cdylib` through `Deno.dlopen` and exposes the same core classes: `BundleProtocol`, `LocalProtocol`, `Remote`, `BundleSource`, and `Updater`. Each class is `Disposable` — free it explicitly with `free()`, or let a `using` declaration call `[Symbol.dispose]` at scope exit: ```ts title="dispose.ts" import { BundleProtocol } from '@wvb/deno'; // `lib` and `source` come from the load + BundleSource steps below. // Explicit cleanup. const protocol = new BundleProtocol(lib, source); const res = await protocol.handle('get', 'app://my-app/index.html'); protocol.free(); // Or scope-bound cleanup with `using`. { using scoped = new BundleProtocol(lib, source); await scoped.handle('get', 'app://my-app/index.html'); } // [Symbol.dispose]() runs here ``` ### Load the native library [#load-the-native-library] Load the `cdylib` from an explicit path, or download a SHA-256-verified prebuilt via [`@denosaurs/plug`](https://jsr.io/@denosaurs/plug): ```ts title="load.ts" import { loadLib, loadLibViaPlug } from '@wvb/deno'; // 1. Load a library already on disk. const lib = loadLib('./vendor/wvb/libwvb_deno.dylib'); // 2. Download a sha256-verified prebuilt at runtime. const libViaPlug = await loadLibViaPlug(); ``` Point `loadLib` at a file with the `WVB_DENO_LIB` environment variable instead of hard-coding the path: ```sh WVB_DENO_LIB=./vendor/wvb/libwvb_deno.dylib deno run -A main.ts ``` Or vendor the library ahead of time with the installer subcommand: ```sh deno run -A jsr:@wvb/deno/install --out vendor/wvb ``` `@wvb/deno/install` downloads the cdylib from GitHub Releases and verifies its SHA-256 checksum by default. Supported targets: | Target triple | | --------------------------- | | `aarch64-apple-darwin` | | `x86_64-apple-darwin` | | `aarch64-unknown-linux-gnu` | | `x86_64-unknown-linux-gnu` | | `x86_64-pc-windows-msvc` | Vendor a specific target with `--target`: ```sh deno run -A jsr:@wvb/deno/install --out vendor/wvb --target x86_64-unknown-linux-gnu ``` For the full class and method reference, see the [Deno API reference](/docs/references/api/deno). ## Limitations [#limitations] Two gaps apply to the Deno bindings today. **Custom verifier callbacks are not supported.** The `Updater` accepts only the **declarative** `signatureVerifier` — a `SignatureVerifierOptions` with an `algorithm` and a `key`: ```ts title="updater.ts" const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], updater: { remote: { endpoint: 'https://bundles.example.com' }, integrityPolicy: 'strict', signatureVerifier: { algorithm: 'ed25519', key: { format: 'raw', data: publicKeyBytes }, }, }, }); ``` The custom `integrityChecker` / `signatureVerifier` function callbacks available in `@wvb/node` cannot cross the FFI boundary. **`HttpOptions.defaultHeaders` is not supported** on the Deno `Remote`. Other `HttpOptions` fields still apply: ```ts title="http.ts" const wvb = await webviewBundle({ protocols: [bundleProtocol('app')], updater: { remote: { endpoint: 'https://bundles.example.com', http: { userAgent: 'my-app/1.0', timeout: 120_000 }, }, }, }); ``` For how integrity and signatures work across platforms, see [Remote bundles](/docs/guide/core-concepts/over-the-air). # Local development (/docs/guide/native/deno/local-development) Proxy the Deno desktop webview to your dev server for live reload with localProtocol. Experimental In development, swap `bundleProtocol` for `localProtocol`. It proxies the webview to your dev server, so edits reload live instead of loading packed `.wvb` assets. ## Proxy to your dev server [#proxy-to-your-dev-server] `localProtocol(scheme, { hosts })` maps the served host to your dev server's base URL. Point it at Vite (or whatever serves your frontend) and reuse the same single-origin `webviewBundle` wiring as production. ```ts title="main.ts" import { webviewBundle, localProtocol } from '@wvb/deno-desktop'; const wvb = await webviewBundle({ protocols: [ localProtocol('app', { hosts: { app: 'http://localhost:5173' }, }), ], }); const server = Deno.serve(wvb.fetch); const win = new Deno.BrowserWindow({ url: `http://localhost:${server.addr.port}` }); await win.closed; ``` ## Switch back for production [#switch-back-for-production] Swap `localProtocol` back for `bundleProtocol` to serve packed `.wvb` assets offline. See [Setup](/docs/guide/native/deno) for the production wiring. # Electron Builder (/docs/guide/native/electron/builder) Install builtin .wvb bundles at package time and keep the native @wvb/node addon in your electron-builder app. `@wvb/electron-builder` integrates Webview Bundle with [electron-builder](https://www.electron.build/) packaging. It hooks electron-builder's `afterPack` step to install your builtin `.wvb` bundles into the packaged app's resources, so the bundles `@wvb/electron` serves at runtime ship with the app. You still configure electron-builder to keep the native `@wvb/node` addon out of the ASAR archive. Read the [Electron guide](/docs/guide/native/electron) first for the runtime setup, and see [Electron Forge](/docs/guide/native/electron/forge) for the Forge equivalent. ## What it does [#what-it-does] At package time the plugin resolves your Webview Bundle config, installs the builtin bundles (downloaded from a `remote` target or packed from local workspaces via `@wvb/cli`), stages them under `/.wvb/builtin/bundles/-`, then copies them into the packaged app's `Resources/` directory. That is exactly where `@wvb/electron` reads builtin bundles from when packaged (`process.resourcesPath/bundles`), so the runtime picks them up with no extra wiring. The plugin requires `electron-builder` 24+ (declared as an optional peer dependency) and pulls in `@wvb/cli` and `@wvb/config` to resolve and pack bundles. ## Configure the plugin [#configure-the-plugin] Wrap your electron-builder config with `withWebviewBundle(...)` (alias `withWvb`). It composes the `afterPack` hook for you while preserving any existing function-valued `afterPack`. ```ts title="electron-builder.config.ts" import { withWebviewBundle } from '@wvb/electron-builder'; export default withWebviewBundle({ appId: 'com.example.app', asar: true, mac: { target: 'dmg' }, }); ``` Pass plugin options as a second argument: ```ts title="electron-builder.config.ts" import { withWebviewBundle } from '@wvb/electron-builder'; export default withWebviewBundle( { appId: 'com.example.app', asar: true, }, { bundlesDir: 'bundles', channel: 'beta', } ); ``` If you prefer to wire the hook yourself, use the raw factory `webviewBundleAfterPack(options?)` (alias `wvbAfterPack`), which returns an electron-builder `afterPack` function. The package also exports `resolveResourcesPath(ctx)`, which returns the packaged app's resources directory for a given build context. ### Options [#options] Both `@wvb/electron-builder` and `@wvb/electron-forge` share these options: | Option | Type | Default | Meaning | | ------------------------- | ------------------- | ----------- | --------------------------------------------------------------------------------- | | `root` | `string` | (resolved) | project root used to discover config and bundles | | `builtin` | `BuiltinConfig` | from config | inline builtin config, overriding the config file | | `bundlesDir` | `string` | `'bundles'` | destination directory name under the packaged `Resources` | | `configFile` | `string \| boolean` | `true` | `true` auto-discovers and merges; a path loads explicitly; `false` is inline only | | `channel` | `string` | — | release channel to install bundles from (e.g. `"beta"`) | | `throwWhenBuiltinIsEmpty` | `boolean` | `true` | throw if zero bundles end up installed | When `builtin.target` is not set, the plugin defaults to a `remote` target using the resolved remote endpoint. `bundlesDir` must be a relative path with no `..` segments. See [configuration](/docs/references/configuration) for the underlying `builtin` and `remote` config, and [Building a remote](/docs/guide/remote) for the install source. ## Keep the native addon out of the ASAR [#keep-the-native-addon-out-of-the-asar] `@wvb/electron` depends on `@wvb/node`, a native N-API addon (a `.node` binary). When `asar: true`, electron-builder packs `node_modules` into the ASAR archive, and native binaries cannot be loaded from inside ASAR. Use `asarUnpack` to unpack the addon so it loads at runtime: ```json title="electron-builder config" { "asar": true, "asarUnpack": ["**/node_modules/@wvb/node/**"] } ``` The plugin handles installing the builtin bundles, so you do not need `extraResources` for them. If you stage `.wvb` files yourself instead of using the plugin, ship the directory as an extra resource so it lands in `Resources/bundles`: ```json title="electron-builder config" { "extraResources": [{ "from": "bundles", "to": "bundles" }] } ``` If the app works in development but throws a missing-module error for `@wvb/node` once packaged, the native addon was packed into the ASAR. Add the `asarUnpack` glob above and repackage. # Builtin bundles (/docs/guide/native/electron/builtin) Ship read-only .wvb bundles inside your Electron package as an offline fallback. Builtin bundles are the `.wvb` files you ship inside your Electron package. They are read-only and always present, so your app has something to serve when it starts offline or before it has fetched a newer bundle over the air. Downloaded updates take priority over builtin bundles at runtime — see [Bundle sources](/docs/guide/core-concepts/bundle-source). ## Where builtin bundles land [#where-builtin-bundles-land] `@wvb/electron` reads builtin bundles from `source.builtinDir`, which defaults to `process.resourcesPath/bundles` in a packaged app — the `resources/bundles` directory. Each bundle is laid out as `/_.wvb` next to a `manifest.json`. ## Install with `wvb builtin` [#install-with-wvb-builtin] `wvb builtin` installs bundles into an output directory. The source is set by `builtin.target` in your [config](/docs/references/configuration): a `remote` target downloads them from your update server, a `local` target packs them from local workspaces. ```sh # Install from the configured target into a bundles directory wvb builtin --out bundles # Or pull from a remote endpoint explicitly wvb builtin --endpoint https://updates.example.com --out bundles ``` Point `--out` at the directory you ship with your app. See [`wvb builtin`](/docs/references/cli/builtin) for every flag. ## Install at package time [#install-at-package-time] The Forge and Builder integrations install builtin bundles for you during packaging and copy them into the packaged app's `resources/bundles`, so you never stage `.wvb` files by hand. # Electron Forge (/docs/guide/native/electron/forge) Ship packed .wvb builtins as an extra resource and unpack the native @wvb/node addon from the ASAR with the @wvb/electron-forge plugin. `@wvb/electron-forge` is an Electron Forge plugin that wires Webview Bundle into your packaging step. It installs your packed `.wvb` builtins into the packaged app's resources and helps keep the native `@wvb/node` addon available at runtime, so you do not stage bundle files by hand. Use it alongside the main [Electron guide](/docs/guide/native/electron), which covers serving bundles through a custom protocol and updating them over the air. ## What the plugin does [#what-the-plugin-does] The plugin extends Forge's `PluginBase` and hooks `packageAfterCopy`. At package time it resolves your Webview Bundle config, installs the builtin `.wvb` bundles (downloaded from a `remote` target or packed from local workspaces via `@wvb/cli`), stages them under `/.wvb/builtin/bundles`, and copies them into the packaged app's resources next to the copied app directory. That destination is exactly where `@wvb/electron` reads builtin bundles from at runtime. See the package source for the exact surface: [`@wvb/electron-forge`](https://github.com/webview-bundle/webview-bundle/tree/main/packages/electron-forge). ## Add it to forge.config.ts [#add-it-to-forgeconfigts] Register the plugin in your Forge config alongside your other plugins. The plugin class is `WebviewBundlePlugin` (also exported as the default export and aliased `WvbPlugin`). ```ts title="forge.config.ts" import type { ForgeConfig } from '@electron-forge/shared-types'; import { WebviewBundlePlugin } from '@wvb/electron-forge'; const config: ForgeConfig = { plugins: [new WebviewBundlePlugin({ bundlesDir: 'bundles', channel: 'beta' })], }; export default config; ``` The plugin reads its options from `WebviewBundlePluginConfig`: | Option | Type | Default | Meaning | | ------------------------- | ------------------- | ----------- | --------------------------------------------------------------------------------- | | `bundlesDir` | `string` | `'bundles'` | destination dir name under the packaged app's resources | | `configFile` | `string \| boolean` | `true` | `true` auto-discovers and merges; a path loads explicitly; `false` is inline only | | `channel` | `string` | — | release channel to install bundles from | | `throwWhenBuiltinIsEmpty` | `boolean` | `true` | throw if zero bundles are installed | It also accepts inline `root` and `builtin` config picked from the shared [Webview Bundle config](/docs/references/configuration). When `builtin.target` is unset, the plugin defaults to a `remote` target using your resolved remote endpoint. ## Native binary and extra resource [#native-binary-and-extra-resource] Even without the plugin, two things must reach the packaged app: the builtin `bundles` directory and the native `@wvb/node` addon. The plugin handles the bundles; the native addon is unpacked from the ASAR archive with Forge's `AutoUnpackNativesPlugin`. ```ts title="forge.config.ts" import { AutoUnpackNativesPlugin } from '@electron-forge/plugin-auto-unpack-natives'; import { WebviewBundlePlugin } from '@wvb/electron-forge'; const config: ForgeConfig = { packagerConfig: { asar: true, extraResource: ['bundles'], // ship the builtin bundles }, plugins: [ // …vite plugin… new AutoUnpackNativesPlugin({}), // unpack @wvb/node's .node binary from the ASAR new WebviewBundlePlugin({}), ], }; ``` `extraResource: ['bundles']` ships the builtin bundles into the packaged app's resources. `AutoUnpackNativesPlugin` unpacks the `@wvb/node` native `.node` binary out of the ASAR so it can be loaded at runtime. Run [`wvb pack`](/docs/references/cli/pack) to produce the `.wvb` files that land in that `bundles` directory. ## Keep node\_modules so the native module is bundled [#keep-node_modules-so-the-native-module-is-bundled] The Forge Vite plugin can exclude `node_modules` from the package, which drops the native `@wvb/node` module. If you hit a missing `@wvb/node` binary at runtime, override `packagerConfig.ignore` so `node_modules` is kept. ```ts title="forge.config.ts" const config: ForgeConfig = { packagerConfig: { asar: true, extraResource: ['bundles'], // Keep node_modules so the native @wvb/node addon is bundled. ignore: [/^\/(?!node_modules|\.vite|package\.json)/], }, }; ``` If your app starts in development but the window is blank when packaged, the `bundles` resource or the native `@wvb/node` binary was most likely left out. Verify `extraResource`, `AutoUnpackNativesPlugin`, and the `packagerConfig.ignore` override above. # Setup (/docs/guide/native/electron) Serve your Electron UI from a .wvb bundle through a custom protocol, with dev-server proxying and over-the-air updates. `@wvb/electron` wires Webview Bundle into Electron in three moves: serve your UI from a `.wvb` bundle through a custom protocol, proxy to a dev server while developing, and (optionally) update bundles over the air. ## Install [#install] `@wvb/electron` requires Electron 15+ and pulls in `@wvb/node` (prebuilt N-API binaries — no Rust toolchain). `@wvb/cli` packs bundles at build time. ```sh npm install @wvb/electron npm install -D @wvb/cli ``` ```sh pnpm add @wvb/electron pnpm add -D @wvb/cli ``` ```sh yarn add @wvb/electron yarn add -D @wvb/cli ``` ## Register the protocol in the main process [#register-the-protocol-in-the-main-process] Call `wvb(...)` (alias of `webviewBundle(...)`) before any window loads. It registers your schemes as privileged, builds the source, and wires the protocol handlers and IPC. ```ts title="src/main.ts" import path from 'node:path'; import { app, BrowserWindow } from 'electron'; import { bundleProtocol, localProtocol, wvb } from '@wvb/electron'; const instance = wvb({ source: { builtinDir: path.join(process.resourcesPath, 'bundles'), }, protocols: [ // Dev: proxy `app-local://app.wvb/...` to the Vite dev server for hot reload. localProtocol('app-local', { hosts: { 'app.wvb': MAIN_WINDOW_VITE_DEV_SERVER_URL }, }), // Prod: serve `app://.wvb/...` straight from the bundle. bundleProtocol('app', { onError: e => console.error('[wvb]', e) }), ], }); async function createWindow() { await instance.whenProtocolRegistered(); const win = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }); await win.loadURL('app://app.wvb'); } app.whenReady().then(createWindow); ``` URL shape is `://.wvb/` — `app://app.wvb/index.html` resolves to bundle `app`, file `/index.html`. * **`bundleProtocol(scheme, options?)`** serves files directly from bundles in the source. * **`localProtocol(scheme, { hosts })`** proxies matching hosts to a dev server. `hosts` is required — a `Record` (or a function returning one) mapping host to URL. Choose which URL to load based on `app.isPackaged`: ```ts await win.loadURL(app.isPackaged ? 'app://app.wvb' : 'app-local://app.wvb'); ``` `whenProtocolRegistered()` resolves after every protocol is registered and `app.whenReady()` fires — always await it before navigating. Override per-protocol privileges with the `privileges` option: ```ts bundleProtocol('app', { privileges: { stream: true }, // merged over the defaults below }); ``` Each scheme is registered as privileged with these defaults: `standard`, `secure`, `bypassCSP`, `allowServiceWorkers`, `supportFetchAPI`, `corsEnabled`, `codeCache` all `true`; `stream` `false`. See [Protocol handling](/docs/guide/core-concepts/protocol-handling) for the full model. ## Add the preload script [#add-the-preload-script] The preload exposes a safe transport (`window.wvbElectron.invoke`) that the bridge uses for source, remote, and updater calls. ```ts title="src/preload.ts" import { preload } from '@wvb/electron/preload'; preload(); ``` Point `webPreferences.preload` at the compiled preload and keep `contextIsolation: true` with `nodeIntegration: false`. ## Call the API from the renderer [#call-the-api-from-the-renderer] Import the bridge in renderer code to drive updates from the UI — for example, a "Check for updates" button. It forwards to the main process over IPC, so it works only when the preload is loaded. ```ts title="src/renderer.ts" import { source, remote, updater } from '@wvb/bridge'; // What is installed locally right now? const current = await source.loadVersion('app'); // Is a newer version deployed on the remote? const update = await updater.getUpdate('app'); if (update) { const downloaded = await updater.download('app'); // download + verify + stage await updater.install('app', downloaded.version); // activate // Reload the window to pick up the new bundle — your app's responsibility. } ``` `source`, `remote`, and `updater` come from `@wvb/bridge`, which auto-detects the Electron transport installed by `@wvb/electron/preload`. Result shapes for `getUpdate`/`download` are in the [Node API reference](/docs/references/api/node). The same surfaces are reachable in the main process on the instance returned by `wvb(...)`: ```ts instance.source; // BundleSource instance.remote; // Remote | null (null unless `updater` is configured) instance.updater; // Updater | null (null unless `updater` is configured) await instance.whenProtocolRegistered(); ``` ## Configure over-the-air updates [#configure-over-the-air-updates] Add an `updater` block pointing at your remote. Its presence is what enables `instance.remote` and `instance.updater`; omit it and the renderer's `remote.*` / `updater.*` calls fail with a "not initialized" bridge error. ```ts wvb({ source: { builtinDir: path.join(process.resourcesPath, 'bundles') }, updater: { remote: { endpoint: 'https://updates.example.com' }, channel: 'stable', // integrity and signature verification also live here: // integrityPolicy, integrityChecker, signatureVerifier }, protocols: [bundleProtocol('app')], }); ``` Pin a signing key to verify *who* published an update: ```ts updater: { remote: { endpoint: 'https://updates.example.com' }, signatureVerifier: { algorithm: 'ed25519', key: '/* raw 32-byte or PEM public key */', }, }, ``` `SignatureAlgorithm` is one of `ecdsaSecp256R1`, `ecdsaSecp384R1`, `ed25519`, `rsaPkcs1V15`, `rsaPss`. See [Remote bundles](/docs/guide/core-concepts/over-the-air) for integrity and signature details, and [Building a remote](/docs/guide/remote) for standing a server up — including a local one for testing. ## Where bundles live [#where-bundles-live] `source` accepts `builtinDir` (shipped, read-only) and `remoteDir` (downloaded updates), both with Electron-aware defaults: | Option | Default | | ------------ | --------------------------------------------------------------------------- | | `builtinDir` | `process.resourcesPath/bundles` when packaged, else `process.cwd()/bundles` | | `remoteDir` | `app.getPath('userData')/bundles` | Downloaded versions take priority over builtin ones, so an installed update is served automatically after `updater.download(...)` and `updater.install(...)`. See [Bundle sources](/docs/guide/core-concepts/bundle-source) for resolution details. ## Pack and ship bundles [#pack-and-ship-bundles] Build your web app, then pack the output into the directory you set as `builtinDir`: ```sh # Build your renderer first (e.g. `vite build`), then: npx wvb pack ./dist --outfile bundles/app/app_1.0.0.wvb ``` Ship the `bundles` directory with your app so the protocol can serve it at runtime. How you stage those files into the package depends on your packaging tool — see [Packaging](#packaging). ## Packaging [#packaging] Packaging an Electron app that uses `@wvb/electron` needs two things to land in the final build: the builtin `bundles` directory has to ship with the app, and the native `@wvb/node` binary has to stay out of the ASAR archive so it can load at runtime. Dedicated integrations handle both and install builtin bundles at package time, so you never stage `.wvb` files by hand. ## Troubleshooting [#troubleshooting] * **Blank window or `ERR_FAILED`** — confirm `wvb(...)` runs and `whenProtocolRegistered()` resolves before `loadURL`, and the URL's bundle name matches the packed file (`app://app.wvb` → bundle `app`). * **Renderer cannot reach the bridge API** — the preload is not loaded. Check `webPreferences.preload` and that it calls `preload()`. * **`remote_not_initialized` / `updater_not_initialized`** — a `remote.*` / `updater.*` call was made but no `updater` block was passed to `wvb(...)`. Add the [over-the-air updates](#configure-over-the-air-updates) config. * **Works in dev, fails when packaged** — the `bundles` resource or the native `@wvb/node` binary was not included in the package. See [Packaging](#packaging). # Local development (/docs/guide/native/electron/local-development) Proxy your bundle host to the Vite dev server for hot reload, and switch protocols on app.isPackaged. In development you want hot reload, not a packed `.wvb`. Register a `localProtocol` on your bundle scheme so the webview loads the same URL while requests proxy to your framework dev server. ## Proxy to the dev server [#proxy-to-the-dev-server] `localProtocol(scheme, { hosts })` forwards each mapped host to a running dev server, so edits reload live over the same `app://app.wvb` URL you use in production. `hosts` maps `.wvb` to the dev server origin. ## Switch on `app.isPackaged` [#switch-on-appispackaged] Register `localProtocol` in development and `bundleProtocol` in production, both on the same scheme. The renderer URL never changes — only the handler behind it does. ```ts title="src/main.ts" import path from 'node:path'; import { app, BrowserWindow } from 'electron'; import { bundleProtocol, localProtocol, wvb } from '@wvb/electron'; const DEV_SERVER_URL = 'http://localhost:5173'; const instance = wvb({ source: { builtinDir: path.join(process.resourcesPath, 'bundles'), }, protocols: app.isPackaged ? // Prod: serve `app://app.wvb/...` from the packed bundle. [bundleProtocol('app')] : // Dev: proxy `app://app.wvb/...` to the Vite dev server for hot reload. [localProtocol('app', { hosts: { 'app.wvb': DEV_SERVER_URL } })], }); async function createWindow() { await instance.whenProtocolRegistered(); const win = new BrowserWindow({ width: 800, height: 600 }); await win.loadURL('app://app.wvb'); } app.whenReady().then(createWindow); ``` Only one handler can own a scheme at a time, so build the `protocols` array conditionally rather than registering both. Always `await instance.whenProtocolRegistered()` before `loadURL`. ## Multiple hosts [#multiple-hosts] `hosts` takes any number of entries — map each window's bundle host to its own dev server, then load each by host. ```ts localProtocol('app', { hosts: { 'app.wvb': 'http://localhost:5173', 'admin.wvb': 'http://localhost:5174', }, }); // win.loadURL('app://app.wvb'); // adminWin.loadURL('app://admin.wvb'); ``` In production, `bundleProtocol('app')` serves both from the `app` and `admin` bundles in your source. # Builtin bundles (/docs/guide/native/ios/builtin) Install builtin .wvb bundles into an iOS app's resources with wvb builtin so the Source serves them offline. The iOS Source reads builtin bundles from `/bundles` — the app bundle's read-only `bundles` folder. Install them there with `wvb builtin`, then ship the folder as a folder reference. ## Install [#install] `wvb builtin` pulls bundles from the target set in your config (`builtin.target`, remote by default) and writes a `manifest.json` plus one `/_.wvb` file per bundle. ```sh # Tuist project: auto-detect the project and wire the folder reference wvb builtin --ios # Otherwise: install into a folder you add to the app target wvb builtin --out path/to/App/bundles ``` The folder reference must land at `bundles/` in the app's resources, so name the output folder `bundles`. ## Ship it as a folder reference [#ship-it-as-a-folder-reference] The Source loads the directory as-is, so add it to the app target as a **folder reference** (blue folder in Xcode) — a group would flatten the `/_.wvb` layout the manifest points at. The `--ios` preset does this for you by adding a `folderReference` to `Project.swift` (Tuist projects). To read from a different location, set `builtinDir` on `WebViewBundleConfig.source`. See the [Sources section](/docs/guide/native/ios#sources) of the iOS setup guide. ## Remote or local [#remote-or-local] The install source is config-driven, not a flag: `builtin.target` is a discriminated union of `remote` (the default) and `local`. `--endpoint`, `--channel`, `--concurrency`, and `--progress` apply to the remote target only. See [wvb builtin](/docs/references/cli/builtin) for every option. # Setup (/docs/guide/native/ios) Serve and update Webview Bundle archives in a WKWebView using the webview-bundle-ios Swift package. The `webview-bundle-ios` Swift package serves `.wvb` bundles to a `WKWebView` through a custom URL scheme and keeps them current with over-the-air (OTA) updates. Register a scheme, point a `WKWebView` at `app://app.wvb`, and the package answers every request from the bundle on disk — offline-first, with the updater pulling newer bundles in the background without an App Store release. ## Requirements [#requirements] | Requirement | Value | | --------------- | ---------------------------------------------------------- | | Minimum OS | iOS 16, macOS 12 (`platforms: [.macOS(.v12), .iOS(.v16)]`) | | Swift tools | 6.1, language mode 6 | | SwiftPM product | `WebViewBundle` | The package binds the Rust core through a UniFFI-generated module named `WebViewBundleLibrary`, both exposed under the `WebViewBundle` module. See [Platform integration](/docs/guide/core-concepts/glue-to-native) for how the shared core reaches each platform. Add the package as a dependency: ```swift title="Package.swift" dependencies: [ .package(url: "https://github.com/webview-bundle/webview-bundle-ios", from: "0.1.0"), ], targets: [ .target(name: "App", dependencies: [ .product(name: "WebViewBundle", package: "webview-bundle-ios"), ]), ] ``` In an Xcode app project, add the same URL through **File → Add Package Dependencies…** instead. ## Quick start [#quick-start] Configure once, register the scheme on a `WKWebViewConfiguration`, load the entry URL. Use a **custom scheme** — `http` and `https` are reserved and rejected at init. ```swift title="ContentView.swift" import SwiftUI import WebKit import WebViewBundle let instance = try WebViewBundle.configure( WebViewBundleConfig( protocols: [.bundle(scheme: "app")], updater: WebViewBundleUpdaterConfig( remote: WebViewBundleRemoteConfig(endpoint: "https://bundles.example.com"), integrityPolicy: .strict, signatureVerifier: SignatureVerifierOptions( algorithm: .ed25519, key: SignatureVerifyingKey(format: .spkiDer, pem: nil, der: publicKeyDer) ) ) ) ) let config = WKWebViewConfiguration() instance.install(on: config) // registers the app:// scheme handler + JS bridge let webView = WKWebView(frame: .zero, configuration: config) webView.load(URLRequest(url: URL(string: "app://app.wvb")!)) ``` `configure(_:)` builds the instance once and caches it process-wide. The entry URL `app://app.wvb` selects the bundle named `app`. To skip manual configuration, take a ready-made `WKWebView`: ```swift let webView = instance.makeWebView() // or: instance.makeConfiguration() webView.load(URLRequest(url: URL(string: "app://app.wvb")!)) ``` Read the configured singleton anywhere — `shared` traps if read before `configure(_:)`, `safeShared` does not: ```swift let wvb = WebViewBundle.shared // precondition-fails if not yet configured let maybe = WebViewBundle.safeShared // nil if not yet configured ``` ## How serving works [#how-serving-works] Each scheme gets a `WKURLSchemeHandler` registered via `setURLSchemeHandler(_:forURLScheme:)`; the handler maps each request to the Rust core, which answers from the bundle on disk. * **Bundle name = first label of the request host.** `app://app.wvb/index.html` resolves to bundle `app`, path `/index.html`. * **Reserved schemes are rejected at init** (registering a handler for one raises an uncatchable exception): `http`, `https`, `file`, `ftp`, `ftps`, `ws`, `wss`, `about`, `blob`, `data`, `javascript`. * **A scheme must match `^[a-z][a-z0-9+.-]*$`** and be unique. Empty, malformed, duplicate, or reserved schemes throw `WebViewBundleError`: ```swift do { _ = try WebViewBundle.configure( WebViewBundleConfig(protocols: [.bundle(scheme: "https")])) } catch WebViewBundleError.reservedScheme(let scheme) { print("\(scheme) is reserved") // .emptyScheme / .invalidScheme / .duplicateScheme also exist } ``` Two protocol kinds exist — `.bundle` serves bundle entries, `.local` proxies to a local HTTP server (matching the full request host against the `hosts` map). See [Protocol handling](/docs/guide/core-concepts/protocol-handling) for the model. ```swift WebViewBundleConfig(protocols: [ .bundle(scheme: "app"), .local(scheme: "dev", hosts: ["myapp": "http://localhost:8080"]), ]) ``` ## The bridge [#the-bridge] `install(on:)` also wires a JavaScript-to-native bridge. The web app posts to `window.webkit.messageHandlers.wvbIos`; the bridge accepts **main-frame messages only** (subframe and iframe messages are dropped) and exposes the source, remote, and updater commands. ```ts title="web app" window.webkit.messageHandlers.wvbIos.postMessage({ name: 'updaterGetUpdate', params: { bundleName: 'app' }, }); ``` ## Sources [#sources] Each app reads from two sources. See [Bundle sources](/docs/guide/core-concepts/bundle-source) for the full model. * **Builtin** — read-only bundles shipped inside the app. Default dir is the app bundle's `/bundles` folder; ship it as a folder reference so files land there. * **Remote** — the writable directory for downloaded updates. Default lives under Application Support, namespaced by the app's bundle identifier. Override either path through `SourceOptions` on `WebViewBundleConfig.source`: ```swift WebViewBundleConfig( source: SourceOptions( builtinDir: Foundation.Bundle.main.resourcePath.map { "\($0)/bundles" }, remoteDir: nil, // nil => default Application Support dir builtinManifestFilepath: nil, remoteManifestFilepath: nil ), protocols: [.bundle(scheme: "app")] ) ``` Inside the `WebViewBundle` module, unqualified `Bundle` resolves to the FFI bundle class, not `Foundation.Bundle`. Write `Foundation.Bundle` explicitly when you mean the app bundle. ## OTA updates [#ota-updates] Set `WebViewBundleConfig.updater` and the package builds a `Remote` and an `Updater` for you, reachable as `instance.remote` and `instance.updater`. ```swift let updaterConfig = WebViewBundleUpdaterConfig( remote: WebViewBundleRemoteConfig(endpoint: "https://bundles.example.com"), channel: "stable", integrityPolicy: .strict, signatureVerifier: SignatureVerifierOptions( algorithm: .ed25519, key: SignatureVerifyingKey(format: .spkiDer, pem: nil, der: publicKeyDer) ) ) ``` `integrityPolicy` is `.strict`, `.optional`, or `.none`. Integrity values are SHA-2 digests serialized as `sha256:`. The `signatureVerifier` proves who published a bundle: | Field | Values | | --------------------- | --------------------------------------------------------------------------- | | `algorithm` | `.ecdsaSecp256r1`, `.ecdsaSecp384r1`, `.ed25519`, `.rsaPkcs1V15`, `.rsaPss` | | `key.format` | `.spkiDer`, `.spkiPem`, `.pkcs1Der`, `.pkcs1Pem`, `.sec1`, `.raw` | | `key.pem` / `key.der` | `pem` for text keys, `der` for binary keys | Drive the update cycle through the updater: ```swift guard let updater = instance.updater else { return } let info = try await updater.getUpdate(bundleName: "app") // check; no download if info.isAvailable { _ = try await updater.downloadUpdate(bundleName: "app", version: info.version) try await updater.install(bundleName: "app", version: info.version) } ``` `getUpdate` checks the remote for a newer version without downloading. `downloadUpdate` downloads and persists a version (latest when `version` is `nil`). `install` activates a staged version, verifies integrity and signature when configured, then prunes stale versions. Reload to render the new bundle: ```swift try await updater.install(bundleName: "app", version: info.version) await webView.evaluateJavaScript("location.reload()") ``` A failed signature surfaces as the FFI error `Error.Signature(message:)`. For the remote HTTP contract, integrity, and signing details, see [Remote bundles](/docs/guide/core-concepts/over-the-air) and [Building a remote](/docs/guide/remote). # Local development (/docs/guide/native/ios/local-development) Register a local protocol so WKWebView loads your dev server over the bundle scheme, and switch on In development you want `WKWebView` to load your running dev server, not a packed `.wvb`. Register a `.local` protocol on your bundle scheme so the same `app://app.wvb` URL proxies to the dev server and edits reload live. ## Proxy the dev server [#proxy-the-dev-server] `.local(scheme:hosts:)` forwards each mapped host to a running dev server. The `hosts` key is matched against the **entire** request host, so map `app.wvb` — the full host you load — to the dev server origin. Build the `protocols` array conditionally on the same scheme: `.local` in `#if DEBUG`, `.bundle` in release. The loaded URL never changes — only the handler behind it does. ```swift title="ContentView.swift" import WebKit import WebViewBundle #if DEBUG let protocols: [WebViewBundleProtocol] = [ // Dev: proxy `app://app.wvb/...` to the Vite dev server for hot reload. .local(scheme: "app", hosts: ["app.wvb": "http://localhost:5173"]), ] #else let protocols: [WebViewBundleProtocol] = [ // Prod: serve `app://app.wvb/...` from the packed bundle. .bundle(scheme: "app"), ] #endif let instance = try WebViewBundle.configure(WebViewBundleConfig(protocols: protocols)) let config = WKWebViewConfiguration() instance.install(on: config) let webView = WKWebView(frame: .zero, configuration: config) webView.load(URLRequest(url: URL(string: "app://app.wvb")!)) ``` ## App Transport Security [#app-transport-security] If your dev server is plain `http://localhost`, iOS App Transport Security may block the cleartext request. Add an `NSAllowsLocalNetworking` exception under `NSAppTransportSecurity` in your app's `Info.plist` for development builds. # Builtin bundles (/docs/guide/native/tauri/builtin) Install builtin .wvb bundles into a Tauri app at build time with wvb builtin and ship them as Tauri resources. Ship one or more `.wvb` bundles inside your Tauri app so the webview loads offline, before any over-the-air update. Install them at build time with `wvb builtin`, then ship the directory as a Tauri resource. ## Install bundles at build time [#install-bundles-at-build-time] `wvb builtin` writes a `manifest.json` plus one `/_.wvb` file per bundle into `--out`. Point it at the directory you ship as a resource: ```sh wvb builtin --out src-tauri/bundles ``` The source is chosen by `builtin.target` in your [config](/docs/references/configuration) — a `remote` target downloads from an endpoint, a `local` target packs bundles from your workspaces. See the [`wvb builtin` reference](/docs/references/cli/builtin) for every flag. ## Ship the directory as a resource [#ship-the-directory-as-a-resource] List the bundles directory under `bundle.resources` so Tauri packs it into the app: ```json title="src-tauri/tauri.conf.json" { "bundle": { "resources": ["bundles/**/*"] } } ``` ## Where bundles resolve at runtime [#where-bundles-resolve-at-runtime] By default the plugin serves builtin bundles from a `bundles` directory in the app's resource directory. Override the location on the `Source`: ```rust title="src-tauri/src/lib.rs" use wvb_tauri::Source; // Static path, resolved through Tauri's path API. Source::new().builtin_dir("$RESOURCE/bundles"); // Or compute it from the AppHandle. Source::new().builtin_dir_fn(|app| Ok(app.path().resource_dir()?.join("bundles"))); ``` On Android, builtin bundles ship inside the APK as `asset://` resources that the filesystem cannot read directly. The plugin extracts them from the APK on first request, so the app must also register `tauri_plugin_fs::init()`. See [Tauri mobile](/docs/guide/native/tauri/mobile). # Setup (/docs/guide/native/tauri) Add the wvb-tauri plugin to a Tauri v2 app so the webview is served from a .wvb bundle, with dev proxying and over-the-air updates. `wvb-tauri` is the Webview Bundle integration for Tauri v2. Register it as a plugin and your app serves its webview from a local `.wvb` bundle through a custom URL scheme, proxies a dev server while you build, and downloads newer bundles over the air (OTA). The same plugin runs on desktop and on Tauri mobile (Android and iOS). Tauri uses the Rust crate `wvb-tauri` (crates.io). There is no `@wvb/tauri` npm package — the frontend talks to the plugin through Tauri's standard command bridge, which needs no extra package beyond `@tauri-apps/api`. ## Install [#install] ```toml title="src-tauri/Cargo.toml" [dependencies] wvb-tauri = "0.1" tauri = { version = "2", features = [] } ``` To drive updates from the frontend, install Tauri's JS API in your web app: ```sh npm install @tauri-apps/api ``` ```sh pnpm add @tauri-apps/api ``` ```sh yarn add @tauri-apps/api ``` ## Register the plugin [#register-the-plugin] Build a `Config` with `Config::new()`, then chain a bundle **source**, one or more **protocols**, and optionally a **remote** for updates: ```rust title="src-tauri/src/lib.rs" use tauri::Manager; use wvb_tauri::{Config, Protocol, Source}; #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { tauri::Builder::default() .plugin(wvb_tauri::init( Config::new() .source(Source::new().builtin_dir_fn(|app| { Ok(app.path().resource_dir()?.join("bundles")) })) // Serve `bundle://.wvb/...` straight from packed bundles. .protocol(Protocol::bundle("bundle")) // In development, proxy `local://example.com/...` to the dev server. .protocol(Protocol::local("local").host("example.com", "http://localhost:1420")), )) .run(tauri::generate_context!()) .expect("error while running tauri application"); } ``` `Protocol::bundle(scheme)` serves files from a packed bundle, deriving the bundle name from the request host — `bundle://app.wvb/index.html` resolves to bundle `app`, file `/index.html`. `Protocol::local(scheme)` proxies a host to a localhost dev server so the same scheme works with hot reload. Map several hosts at once with `.hosts(...)`: ```rust use std::collections::HashMap; Protocol::local("local").hosts(HashMap::from([ ("example.com".to_string(), "http://localhost:1420".to_string()), ("api.example.com".to_string(), "http://localhost:8080".to_string()), ])); ``` `Source` resolves where bundles live. Use static path strings or `AppHandle` closures: ```rust use wvb_tauri::Source; // Static path strings (resolved through Tauri's path API): Source::new().builtin_dir("$RESOURCE/bundles").remote_dir("$APPLOCALDATA/bundles"); // Or compute the path at runtime from the AppHandle: Source::new().builtin_dir_fn(|app| Ok(app.path().resource_dir()?.join("bundles"))); ``` When unset, the builtin dir defaults to `bundles` in the app's resource directory and the remote dir to `bundles` in app local data. Each `.protocol(...)` call registers its own asynchronous URI scheme. See [Protocol handling](/docs/guide/core-concepts/protocol-handling) for how the schemes resolve requests. ## Point a window at the custom scheme [#point-a-window-at-the-custom-scheme] Boot the main window straight into the bundle scheme: ```json title="src-tauri/tauri.conf.json" { "app": { "windows": [ { "url": "bundle://app.wvb" } ] } } ``` If you call plugin commands from the frontend, grant permissions in a capability file. The namespace is `wvb-tauri`, and `wvb-tauri:default` allows all source, remote, and updater commands: ```json title="src-tauri/capabilities/default.json" { "identifier": "default", "windows": ["main"], "permissions": ["core:default", "wvb-tauri:default"] } ``` To restrict access, replace `wvb-tauri:default` with the individual `wvb-tauri:allow-*` permissions you need: ```json title="src-tauri/capabilities/default.json" { "identifier": "default", "windows": ["main"], "permissions": [ "core:default", "wvb-tauri:allow-updater-get-update", "wvb-tauri:allow-updater-download", "wvb-tauri:allow-updater-install" ] } ``` ## Pack and ship bundles [#pack-and-ship-bundles] Build your frontend, pack it into a `.wvb`, and place the result in your source directory: ```sh # build your frontend first (e.g. `vite build`), then: npx wvb pack ./dist --outfile src-tauri/bundles/app/app_1.0.0.wvb ``` Ship the directory with the build by listing it in resources: ```json title="src-tauri/tauri.conf.json" { "bundle": { "resources": ["bundles/**/*"] } } ``` For the full packing workflow and flags, see the [CLI reference](/docs/references/cli) and [Bundle sources](/docs/guide/core-concepts/bundle-source). ## Drive updates from the frontend [#drive-updates-from-the-frontend] Add a `Remote` to enable OTA downloads: ```rust title="src-tauri/src/lib.rs" use wvb_tauri::{Config, Protocol, Remote, Source}; Config::new() .source(Source::new().builtin_dir_fn(|app| Ok(app.path().resource_dir()?.join("bundles")))) .protocol(Protocol::bundle("bundle")) .remote(Remote::new("https://updates.example.com")); ``` Tune the HTTP client with `Http` (defaults: request timeout `120_000` ms), and watch progress with `.on_download`: ```rust use wvb_tauri::{Http, Remote}; Remote::new("https://updates.example.com") .http(Http::new().timeout(30_000).user_agent("my-app/1.0".into())) .on_download(|downloaded, total, _name| { if let Some(total) = total { println!("{downloaded}/{total} bytes"); } }); ``` Plugin commands are reachable as `plugin:wvb-tauri|`. Arguments use camelCase on the JS side (`bundle_name` becomes `bundleName`). The core OTA flow uses three updater commands: | Command | Arguments | Returns | | -------------------- | ------------------------ | ------------------------------------------- | | `updater_get_update` | `bundleName` | `BundleUpdateInfo` (availability + version) | | `updater_download` | `bundleName`, `version?` | `RemoteBundleInfo` (downloaded metadata) | | `updater_install` | `bundleName`, `version` | `null` (activates the downloaded version) | ```ts title="src/update.ts" import { invoke } from '@tauri-apps/api/core'; interface BundleUpdateInfo { name: string; version: string; localVersion?: string; isAvailable: boolean; } interface RemoteBundleInfo { name: string; version: string; integrity?: string; signature?: string; } export async function checkAndUpdate(bundleName: string) { const update = await invoke('plugin:wvb-tauri|updater_get_update', { bundleName, }); if (!update.isAvailable) return; const info = await invoke('plugin:wvb-tauri|updater_download', { bundleName }); await invoke('plugin:wvb-tauri|updater_install', { bundleName, version: info.version, }); // reload the webview to pick up the new bundle window.location.reload(); } ``` The plugin also exposes `source_*` commands for managing local bundles and `remote_*` commands for listing and staging remote bundles: | Command | Arguments | Returns | | ----------------------- | ------------------------ | ---------------------------------------------- | | `source_list_bundles` | — | local bundle list | | `source_load_version` | `bundleName` | active local version, if any | | `source_update_version` | `bundleName`, `version` | `null` (activate a staged version) | | `remote_list_bundles` | `channel?` | remote bundle list | | `remote_get_info` | `bundleName`, `channel?` | current remote metadata | | `remote_download` | `bundleName`, `channel?` | `RemoteBundleInfo` (stages without activating) | `remote_download` stages a version without activating it; activate later with `source_update_version`: ```ts import { invoke } from '@tauri-apps/api/core'; // Stage a remote bundle now, activate on next launch. const info = await invoke<{ version: string }>('plugin:wvb-tauri|remote_download', { bundleName: 'app', }); await invoke('plugin:wvb-tauri|source_update_version', { bundleName: 'app', version: info.version, }); ``` The full command set (twelve `source_*`, four `remote_*`, and four `updater_*` commands) is defined in [`packages/tauri/src/commands.rs`](https://github.com/webview-bundle/webview-bundle/blob/main/packages/tauri/src/commands.rs). See [Remote bundles](/docs/guide/core-concepts/over-the-air) for how integrity and signature verification fit into the download flow, and [Remote config](/docs/references/configuration/remote) for the server side. The `remote_*` commands require a `Remote` on the config; the `updater_*` commands additionally require an `Updater`. Calling them without that configuration returns an error whose `code` field is `remote_not_initialized` or `updater_not_initialized`. Branch on the `code` field in the frontend: ```ts import { invoke } from '@tauri-apps/api/core'; try { await invoke('plugin:wvb-tauri|updater_get_update', { bundleName: 'app' }); } catch (err) { const { code } = err as { message: string; code?: string }; if (code === 'updater_not_initialized') { // no Updater configured — skip the OTA check } } ``` ## Verify signatures and pin integrity [#verify-signatures-and-pin-integrity] Add an `Updater` with a `SignatureVerifier` to require a publisher signature on downloaded bundles. The verifier is built lazily from a closure: ```rust title="src-tauri/src/lib.rs" use wvb_tauri::{Config, Ed25519Verifier, IntegrityPolicy, Protocol, Remote, Source, Updater}; const PUBLIC_KEY_PEM: &str = include_str!("../keys/public.pem"); Config::new() .source(Source::new()) .protocol(Protocol::bundle("bundle")) .remote(Remote::new("https://updates.example.com")) .updater( Updater::new() .channel("stable") .integrity_policy(IntegrityPolicy::Strict) .signature_verifier(|| Ok(Ed25519Verifier::from_pem(PUBLIC_KEY_PEM)?.into())), ); ``` `IntegrityPolicy` is `Strict` (must be present and match), `Optional` (default — verify if present), or `None` (skip). Verifier types: `EcdsaSecp256r1Verifier`, `EcdsaSecp384r1Verifier`, `Ed25519Verifier`, `RsaPkcs1V15Verifier`, `RsaPssVerifier`. An `Updater` requires a `Remote`; without one, no updater is built. ## Reach the plugin from Rust [#reach-the-plugin-from-rust] From any `App`, `AppHandle`, or `Window`, the `WebviewBundleExtra` trait adds `webview_bundle()` (aliased `wvb()`), returning the managed state. `.source()` is always available; `.remote()` and `.updater()` return `Option`: ```rust use wvb_tauri::WebviewBundleExtra; let wvb = app.wvb(); let _source = wvb.source(); if let Some(_updater) = wvb.updater() { // updater is present only when both `.remote(...)` and `.updater(...)` are configured } ``` This is the same state the frontend commands operate on, so you can mix Rust-side and frontend-driven update logic. ## Tauri mobile [#tauri-mobile] On **iOS**, builtin bundles live in a real filesystem resource directory — no extra setup beyond the desktop configuration. On **Android**, builtin bundles ship inside the APK as `asset://` resources the filesystem cannot read directly, so an app that ships builtin bundles must also register the Tauri filesystem plugin: ```rust title="src-tauri/src/lib.rs" tauri::Builder::default() .plugin(tauri_plugin_fs::init()) .plugin(wvb_tauri::init(/* ... */)); ``` The plugin then extracts each bundle from the APK on first request and caches it in app local data. Remote-only apps (no builtin bundles) need no extra Android setup. See the [Android](/docs/guide/native/android) and [iOS](/docs/guide/native/ios) guides for platform specifics, and [Platform support](/docs/guide/getting-started/platform-and-framework-support) for current status. ## Troubleshooting [#troubleshooting] * **Request returns HTTP 500 from the scheme** — the protocol handler failed. Confirm the bundle exists in the source directory and the host maps to a real bundle name (`bundle://app.wvb/...` → bundle `app`). * **`remote_not_initialized` / `updater_not_initialized`** — you called a `remote_*` or `updater_*` command without `.remote(...)` (and `.updater(...)`) on the `Config`. Branch on `error.code`. * **Command rejected by the ACL** — add `wvb-tauri:default` (or the specific `wvb-tauri:allow-*` permission) to a capability targeting the calling window. * **Bundle not found at runtime** — confirm the `bundles` directory is in `tauri.conf.json` resources and `Source` resolves to it. On Android, confirm `tauri_plugin_fs::init()` is registered when shipping builtin bundles. # Local development (/docs/guide/native/tauri/local-development) Proxy the wvb custom scheme to your Tauri/Vite dev server so the webview loads live, and switch between dev and packed bundles. In development you want the webview to load from your running dev server, not from a packed `.wvb`. Register a `local` protocol so the custom scheme proxies to Tauri's Vite dev server and keeps hot reload. ## Proxy the dev server [#proxy-the-dev-server] Register `Protocol::local` next to `Protocol::bundle`, mapping a scheme host to Tauri's Vite dev server (default `http://localhost:1420`): ```rust title="src-tauri/src/lib.rs" use wvb_tauri::{Config, Protocol, Source}; Config::new() .source(Source::new().builtin_dir_fn(|app| Ok(app.path().resource_dir()?.join("bundles")))) // Production: serve files from the packed bundle. .protocol(Protocol::bundle("bundle")) // Development: proxy the same host to the running dev server. .protocol(Protocol::local("local").host("example.com", "http://localhost:1420")); ``` `Protocol::local(scheme)` forwards `local://example.com/...` to the dev server, so edits reload live. Map several hosts with more `.host(...)` calls or a single `.hosts(...)`. ## Switch dev and prod [#switch-dev-and-prod] Point the window at the `local` scheme while developing and at the `bundle` scheme when you ship: ```json title="src-tauri/tauri.conf.json" { "app": { "windows": [ { "url": "local://example.com" } ] } } ``` Swap the window `url` to `bundle://app.wvb` for production builds, or pick it at runtime with `cfg!(debug_assertions)` so the switch is automatic. # For mobile (/docs/guide/native/tauri/mobile) What changes when you run the wvb-tauri plugin on Tauri mobile (iOS and Android), and where builtin bundles live. The same `wvb-tauri` plugin runs on desktop and on Tauri mobile. Register it exactly as in [Setup](/docs/guide/native/tauri) — the differences below are only about where builtin bundles live on each platform. ## iOS [#ios] Builtin bundles live in a real filesystem resource directory. No extra setup beyond the desktop configuration. ## Android [#android] Builtin bundles ship inside the APK as `asset://` resources, which the filesystem cannot read directly. An app that ships builtin bundles must also register the Tauri filesystem plugin: ```rust title="src-tauri/src/lib.rs" tauri::Builder::default() .plugin(tauri_plugin_fs::init()) .plugin(wvb_tauri::init(/* ... */)); ``` The plugin extracts each bundle from the APK on first request and caches it in app local data. Remote-only apps (no builtin bundles) need no extra Android setup. # Download current bundle (/docs/guide/remote/http-spec/endpoints/get-current) Download the current deployed version of a bundle as raw .wvb bytes, optionally selecting a channel. Download the current deployed version of a bundle. The server streams the `.wvb` archive as the response body and carries the bundle's metadata in `Webview-Bundle-*` headers. This is the call the [updater](/docs/references/api/node/updater) makes to fetch a new version after a check reports one is available. ```http GET /bundles/{name} ``` Pass `?channel=` to download the current version for a specific channel instead of the default deployment. ## Parameters [#parameters] | Name | In | Type | Required | Description | | --------- | ----- | ------ | -------- | ----------------------------------------------------------- | | `name` | path | string | yes | Bundle name to download. | | `channel` | query | string | no | Channel to select. Omit to download the default deployment. | ## Responses [#responses] | Status | Description | | ------ | ----------------------------------------------------- | | `200` | The bundle was found; the body is the `.wvb` archive. | | `404` | The named bundle is not deployed. | For the `404` shape and how the client maps other non-2xx responses, see [Errors](/docs/guide/remote/http-spec/errors). ### Response headers [#response-headers] A `200` response carries the same bundle metadata headers as [HEAD /bundles/{name}](/docs/guide/remote/http-spec/endpoints/head-current). The client reads them case-insensitively; the canonical casing is shown here. | Header | Required | Description | | -------------------------- | -------- | ------------------------------------ | | `Webview-Bundle-Name` | yes | Bundle name. | | `Webview-Bundle-Version` | yes | Bundle version. | | `Webview-Bundle-Integrity` | no | Integrity string `":"`. | | `Webview-Bundle-Signature` | no | Base64 signature. | | `ETag` | no | Standard validator. | | `Last-Modified` | no | Standard validator. | The client rejects a `200` response that omits `Webview-Bundle-Name` or `Webview-Bundle-Version`. The response body is the raw `.wvb` archive bytes, served with `Content-Type: application/webview-bundle`. ## Example [#example] Download the current version and dump the response headers: ```sh curl -s http://localhost:4313/bundles/app -o app.wvb -D - ``` ```http HTTP/1.1 200 OK Content-Type: application/webview-bundle Webview-Bundle-Name: app Webview-Bundle-Version: 1.2.0 Webview-Bundle-Integrity: sha256:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ``` Select a channel's current version with `?channel=`: ```sh curl -s 'http://localhost:4313/bundles/app?channel=beta' -o app-beta.wvb ``` A bundle that is not deployed returns `404`: ```sh curl -sI http://localhost:4313/bundles/unknown ``` ```http HTTP/1.1 404 Not Found ``` # Download a specific version (/docs/guide/remote/http-spec/endpoints/get-version) Download a named bundle at an exact version, gated by the server's other-version download policy. Download a bundle at an exact version rather than the deployed current one. Unlike the other download routes, this operation does not accept a channel: the version is named directly in the path. ```http GET /bundles/{name}/{version} ``` A server only serves this route when it allows other-version downloads. Providers expose that as the `allowOtherVersions` option, which defaults to `false`; when it is disabled, the request returns `403` even though the version exists. ## Parameters [#parameters] | Name | In | Type | Required | Description | | ----------- | ---- | ------ | -------- | -------------------------- | | `{name}` | path | string | yes | Bundle name to download. | | `{version}` | path | string | yes | Exact version to download. | This route does not accept a `channel` query parameter. ## Responses [#responses] | Status | Description | | ------ | -------------------------------------------- | | `200` | The bundle bytes, with metadata headers. | | `403` | The server disables other-version downloads. | | `404` | The named bundle or version is not deployed. | The client maps `403` to a "forbidden" error and `404` to a "bundle not found" error. See [Errors](/docs/guide/remote/http-spec/errors) for the full mapping and the JSON error body shape. ### Response headers [#response-headers] | Header | Required | Description | | -------------------------- | -------- | ------------------------------------ | | `Webview-Bundle-Name` | yes | Bundle name. | | `Webview-Bundle-Version` | yes | Bundle version. | | `Webview-Bundle-Integrity` | no | Integrity string `":"`. | | `Webview-Bundle-Signature` | no | Base64 signature. | | `ETag` | no | Standard validator. | | `Last-Modified` | no | Standard validator. | The client rejects a response that omits `Webview-Bundle-Name` or `Webview-Bundle-Version`. The `200` body is the raw `.wvb` bytes, served with `Content-Type: application/webview-bundle`. This route never selects a channel. To download the current version, with or without a channel, use [GET /bundles/{name}](/docs/guide/remote/http-spec/endpoints/get-current). ## Example [#example] Download version `1.2.0` of the `app` bundle. ```sh $ curl -s http://localhost:4313/bundles/app/1.2.0 -o app-1.2.0.wvb -D - ``` ```http HTTP/1.1 200 OK Content-Type: application/webview-bundle Webview-Bundle-Name: app Webview-Bundle-Version: 1.2.0 Webview-Bundle-Integrity: sha256:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ``` When the server disables other-version downloads, the same request returns `403`: ```sh $ curl -sI http://localhost:4313/bundles/app/1.2.0 HTTP/1.1 403 Forbidden ``` A version that is not deployed returns `404`: ```sh $ curl -sI http://localhost:4313/bundles/app/9.9.9 HTTP/1.1 404 Not Found ``` # Get current metadata (/docs/guide/remote/http-spec/endpoints/head-current) HEAD /bundles/{name} returns the current deployed version's metadata as response headers, with no body. `HEAD /bundles/{name}` returns the metadata of a bundle's current deployed version as response headers, with no body. The updater calls it to check whether a newer version is available before downloading anything. ```http HEAD /bundles/{name} ``` ## Parameters [#parameters] | Name | In | Type | Required | Description | | --------- | ----- | ------ | -------- | ----------------------------------------------------------------------- | | `name` | path | string | yes | The bundle name to inspect. | | `channel` | query | string | no | Selects a channel's deployment. Omit it to read the default deployment. | ## Responses [#responses] | Status | Description | | ------ | ------------------------------------------------------------ | | `204` | The bundle is deployed. Metadata is returned in the headers. | | `404` | The named bundle is not deployed. | Success is `204 No Content`: the response carries metadata headers only and never a body. A `404` means the named bundle has no current deployment. See [Errors](/docs/guide/remote/http-spec/errors) for the error body shape and other status codes. ### Response headers [#response-headers] | Header | Required | Description | | -------------------------- | -------- | --------------------------------------------------- | | `Webview-Bundle-Name` | yes | The bundle name. | | `Webview-Bundle-Version` | yes | The current deployed version. | | `Webview-Bundle-Integrity` | no | Integrity string in the form `":"`. | | `Webview-Bundle-Signature` | no | Base64-encoded signature over the integrity string. | | `ETag` | no | Standard validator. | | `Last-Modified` | no | Standard validator. | The client reads these headers case-insensitively and rejects a response that omits `Webview-Bundle-Name` or `Webview-Bundle-Version`. This route returns metadata only. To fetch the bundle bytes, use [GET /bundles/{name} ](/docs/guide/remote/http-spec/endpoints/get-current). ## Example [#example] ```sh $ curl -sI 'http://localhost:4313/bundles/app' ``` ```http HTTP/1.1 204 No Content Webview-Bundle-Name: app Webview-Bundle-Version: 1.2.0 Webview-Bundle-Integrity: sha256:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= ETag: "abc123" Last-Modified: Tue, 01 Jul 2026 00:00:00 GMT ``` Read a specific channel's current version with `?channel=`: ```sh $ curl -sI 'http://localhost:4313/bundles/app?channel=beta' ``` # List bundles (/docs/guide/remote/http-spec/endpoints/list-bundles) GET /bundles returns the bundles a remote currently has deployed, optionally scoped to a channel. Return the bundles a remote currently has deployed. The client and updater call this first to discover which bundles exist and what version each is deployed at, before reading metadata or downloading bytes. ```http GET /bundles ``` ## Parameters [#parameters] | Name | In | Type | Required | Description | | --------- | ----- | ------ | -------- | ------------------------------------------------------------------------------- | | `channel` | query | string | No | Select a channel's deployments. When omitted, the default deployment is listed. | ## Responses [#responses] | Status | Description | | ------ | ----------------------------------------------- | | `200` | A JSON array of the currently deployed bundles. | For 4xx responses, see [Errors](/docs/guide/remote/http-spec/errors). ### Response headers [#response-headers] | Header | Required | Description | | -------------- | -------- | ----------------------------------------- | | `Content-Type` | Yes | `application/json` for the list response. | ### Response body [#response-body] The body is a JSON array. Each item describes one deployed bundle by `name` and `version`. Bundles that are not deployed are excluded. ```json [ { "name": string, "version": string } ] ``` | Field | Type | Description | | --------- | ------ | ------------------------------- | | `name` | string | The bundle name. | | `version` | string | The currently deployed version. | ## Example [#example] ```sh curl -s http://localhost:4313/bundles ``` ```http HTTP/1.1 200 OK Content-Type: application/json [ { "name": "app", "version": "1.2.0" }, { "name": "admin", "version": "0.4.1" } ] ``` Scope the list to a channel with `?channel=`: ```sh curl -s 'http://localhost:4313/bundles?channel=beta' ``` This operation is the entry point of the remote HTTP contract. To read a bundle's current metadata or download its bytes, see the [Remote HTTP Spec](/docs/guide/remote/http-spec) overview. # Errors (/docs/guide/remote/http-spec/errors) The status codes a remote returns for non-2xx responses and how the client maps them. The remote signals failures with HTTP status codes. The client handles two of them specially and treats the rest as generic HTTP errors. | Status | Meaning | Client error message | | ------------- | ------------------------------------------------------------------- | -------------------------------------- | | `403` | Other-version downloads are disabled (`allowOtherVersions` is off). | `remote forbidden` | | `404` | The requested bundle or version is not deployed. | `remote bundle not found` | | other non-2xx | Any other failure. | `remote http error with status ` | For `403` and `404` the client does not read the response body. For any other non-2xx status it reads a JSON body of the shape below and surfaces `message` on the error. ```json { "message": "why the request failed" } ``` These surface as ordinary JavaScript `Error`s — the message equals the text above, with no typed error class or status field. Tell `403` from `404` by the message string. ## Invalid responses [#invalid-responses] A `2xx` response is still rejected when required metadata is missing. If `Webview-Bundle-Name` or `Webview-Bundle-Version` is absent from a bundle download, the client fails with `invalid remote bundle` rather than installing it. ## Upload conflicts [#upload-conflicts] Publishing is separate from the download contract above. Uploading a version that already exists throws `BundleAlreadyUploadedError`; pass `--force` (or `force: true`) to overwrite it. See [Upload to remote](/docs/guide/frontend/upload). # Overview (/docs/guide/remote/http-spec) Any server that implements this HTTP contract can act as a remote. The [providers](/docs/guide/remote/providers/local) implement it for you; read this only when you build your own. A client reads bundles in three steps: 1. [`GET /bundles`](/docs/guide/remote/http-spec/endpoints/list-bundles) — list the deployed bundles. 2. [`HEAD /bundles/{name}`](/docs/guide/remote/http-spec/endpoints/head-current) — read the current version's metadata to check for an update. 3. [`GET /bundles/{name}`](/docs/guide/remote/http-spec/endpoints/get-current) — download the current version's bytes. [`GET /bundles/{name}/{version}`](/docs/guide/remote/http-spec/endpoints/get-version) downloads an exact version. ## Metadata headers [#metadata-headers] Bundle responses carry metadata in `Webview-Bundle-*` headers, not the body. `Webview-Bundle-Name` and `Webview-Bundle-Version` are required — the client rejects a response missing either. `Webview-Bundle-Integrity` and `Webview-Bundle-Signature` are optional. Bundle bytes are served as `application/webview-bundle`. ## Channels [#channels] A channel selects a separate deployment track. The list, metadata, and current-download routes accept an optional `?channel=` query; omit it to target the default deployment. The exact-version route takes no channel. ## Endpoints [#endpoints] For non-2xx responses, see [Errors](/docs/guide/remote/http-spec/errors). # Overview (/docs/guide/remote) A remote is the HTTP server your app downloads new bundles from over the air. You publish a packed `.wvb` to it, mark a version as current, and clients fetch that version without a native app release. ## Publish and download [#publish-and-download] Publishing is a two-step model, both run from the [CLI](/docs/guide/remote/using-cli): 1. **Upload** stores a packed version on the remote. 2. **Deploy** marks which version is current — the one clients receive. Clients then check for and download the deployed version through the updater. See [Over-the-air](/docs/guide/core-concepts/over-the-air) for the client-side flow, and [Remote configuration](/docs/references/configuration/remote) for the `remote` block that wires it up. ## Run a remote [#run-a-remote] There are two ways to run a remote. **Use a provider.** A provider gives you a server to deploy and an `uploader`/`deployer` pair to drop into your config — no HTTP contract to implement. **Build your own.** Any server that implements the remote HTTP contract works. See the [HTTP spec](/docs/guide/remote/http-spec). # AWS (/docs/guide/remote/providers/aws) Serve bundles from S3 behind CloudFront, with optional KMS signing. The AWS provider serves bundles from an S3 bucket behind a CloudFront distribution. Two Lambda\@Edge functions implement the remote HTTP contract at the edge. ## Provision the server [#provision-the-server] `@wvb/remote-aws-provider-pulumi` provisions the whole stack — bucket, distribution, and edge functions — as a [Pulumi](https://www.pulumi.com) component: ```sh npm install @wvb/remote-aws-provider-pulumi ``` ```ts title="index.ts" import { WebviewBundleRemoteProvider } from '@wvb/remote-aws-provider-pulumi'; const remote = new WebviewBundleRemoteProvider('wvb', { bucketName: 'my-bundles', // allowOtherVersions: true, // also serve GET /bundles/{name}/{version} }); export const endpoint = remote.cloudfrontDistributionDomainName; ``` The request handler itself is `@wvb/remote-aws-provider` (`webviewBundleRemote`), which the component deploys for you. To wire the edge functions manually, see the [package reference](/docs/references/api/remotes/remote-aws-provider). ## Publish to it [#publish-to-it] `@wvb/remote-aws` provides the `uploader` and `deployer` — and an optional AWS KMS `signature` signer — for your config: ```sh npm install -D @wvb/remote-aws ``` ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; import { awsRemote } from '@wvb/remote-aws'; export default defineConfig({ remote: { endpoint: 'https://d111111abcdef8.cloudfront.net', integrity: { algorithm: 'sha256' }, ...awsRemote({ bucket: 'my-bundles', // deployer: { invalidation: { distributionId: 'E1234567890ABC' } }, // signature: { keyId: 'arn:aws:kms:…', algorithm: 'ECDSA_SHA_256' }, }), }, }); ``` `awsRemote()` returns `{ uploader, deployer, signature? }`. Credentials and region come from the standard AWS SDK chain; override them with the `aws` option. See the [AWS client reference](/docs/references/api/remotes/remote-aws) for every option. The server option is `bucketName`; the client option is `bucket`. Both must point at the same bucket. Lambda\@Edge always runs in `us-east-1`, independent of the bucket's region. # Cloudflare (/docs/guide/remote/providers/cloudflare) Serve bundles from R2 behind a Cloudflare Worker. The Cloudflare provider serves bundles from an R2 bucket through a Worker, using a KV namespace to record which version is deployed. ## Provision the server [#provision-the-server] `@wvb/remote-cloudflare-provider-pulumi` provisions the Worker, R2 bucket, and KV namespace as a [Pulumi](https://www.pulumi.com) component: ```sh npm install @wvb/remote-cloudflare-provider-pulumi ``` ```ts title="index.ts" import { WebviewBundleRemoteProvider } from '@wvb/remote-cloudflare-provider-pulumi'; const remote = new WebviewBundleRemoteProvider('wvb', { accountId: '', }); export const bucketName = remote.bucketName; export const kvNamespaceId = remote.kvNamespaceId; ``` To write the Worker yourself, `@wvb/remote-cloudflare-provider` exports a [Hono](https://hono.dev) app. Bind an R2 bucket as `BUCKET` and a KV namespace as `KV`, then map them into the handler: ```ts title="src/worker.ts" import { wvbRemote } from '@wvb/remote-cloudflare-provider'; const app = wvbRemote(); export default { fetch(req: Request, env: { KV: KVNamespace; BUCKET: R2Bucket }) { return app.fetch(req, { kv: env.KV, r2: env.BUCKET }); }, }; ``` ## Publish to it [#publish-to-it] `@wvb/remote-cloudflare` provides the `uploader` and `deployer` for your config: ```sh npm install -D @wvb/remote-cloudflare ``` ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; import { cloudflareRemote } from '@wvb/remote-cloudflare'; export default defineConfig({ remote: { endpoint: 'https://updates.example.com', ...cloudflareRemote({ accountId: '', bucket: 'webview-bundle', kvNamespaceId: '', }), }, }); ``` The uploader writes to R2 over the S3-compatible API, so pass R2 access keys through its `s3ClientConfig.credentials`; the deployer updates KV with a Cloudflare API token. See the [Cloudflare client reference](/docs/references/api/remotes/remote-cloudflare) for the full config. The Worker reads an R2 binding named `BUCKET` and a KV binding named `KV`. Match those names in your `wrangler.jsonc`. # Local (/docs/guide/remote/providers/local) Serve bundles from a local directory for development and testing. The local provider runs a remote on your machine, backed by a directory. Use it to exercise the full upload → deploy → download loop offline before wiring in a hosted provider. ## Run the server [#run-the-server] The quickest way needs no code — the CLI ships the server: ```sh wvb remote local ``` This serves `~/.wvb/local` on `http://localhost:4313`. See [`wvb remote local`](/docs/references/cli/remote) for its flags (`--base-dir`, `--port`, `--allow-other-versions`). To embed the server yourself, `@wvb/remote-local-provider` exports a [Hono](https://hono.dev) app. Serve it with any Hono adapter: ```sh npm install @wvb/remote-local-provider @hono/node-server ``` ```ts title="server.ts" import { serve } from '@hono/node-server'; import { wvbRemote } from '@wvb/remote-local-provider'; const app = wvbRemote({ baseDir: '~/.wvb/local' }); serve({ fetch: app.fetch, port: 4313 }); ``` | Option | Type | Default | Description | | -------------------- | --------- | -------------- | --------------------------------------------------------- | | `baseDir` | `string` | `~/.wvb/local` | Directory that stores bundles and deployments. | | `allowOtherVersions` | `boolean` | `false` | Serve exact versions via `GET /bundles/{name}/{version}`. | ## Publish to it [#publish-to-it] `@wvb/remote-local` provides the `uploader` and `deployer` for your config, writing to the same directory the server reads. ```sh npm install -D @wvb/remote-local ``` ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; import { localRemote } from '@wvb/remote-local'; export default defineConfig({ remote: { endpoint: 'http://localhost:4313', ...localRemote({ baseDir: '~/.wvb/local' }), }, }); ``` `localRemote()` returns `{ uploader, deployer }`. Spread it into `remote` so `wvb upload` and `wvb deploy` write bundles the local server can serve. Point the server and the client at the same `baseDir`. The [CLI walkthrough](/docs/guide/remote/using-cli) uses this provider end to end. # Using the CLI (/docs/guide/remote/using-cli) Run a local remote, publish a version, and download it — the whole update loop from the terminal. The `wvb` CLI drives the entire remote workflow: run a local server, publish bundles, and download them back. This walkthrough exercises the full loop on your machine before you deploy a hosted [provider](/docs/guide/remote/providers/local). ## Configure the remote [#configure-the-remote] Point your config at a remote and give it the local `uploader`/`deployer`: ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; import { localRemote } from '@wvb/remote-local'; export default defineConfig({ remote: { endpoint: 'http://localhost:4313', integrity: { algorithm: 'sha256' }, ...localRemote({ baseDir: '.wvb/local' }), }, }); ``` `endpoint` is where downloads read from; `uploader` and `deployer` are how `wvb upload` and `wvb deploy` publish. See [Remote configuration](/docs/references/configuration/remote) for every field. ## Run a local remote [#run-a-local-remote] Start a server backed by the same directory, and leave it running in its own terminal: ```sh wvb remote local --base-dir .wvb/local ``` It serves `http://localhost:4313`. See [`wvb remote local`](/docs/references/cli/remote) for its flags. ## Publish a version [#publish-a-version] Pack, upload, and deploy in one command: ```sh wvb upload app --version 1.0.0 --deploy ``` Without `--deploy`, the version is only staged; run [`wvb deploy app --version 1.0.0`](/docs/references/cli/remote-deploy) to make it current. Add `--channel beta` to publish to a channel. ## Inspect and download [#inspect-and-download] Check what the remote serves: ```sh wvb remote current app # current version and its metadata wvb remote list # every bundle on the remote wvb download app # download the current .wvb to disk ``` ## Install in the app [#install-in-the-app] Downloading with the CLI verifies what the remote serves; your app installs updates through the updater, not the CLI. Point its remote at the same endpoint (`http://localhost:4313`) and run the check → download → install flow. See [Over-the-air](/docs/guide/core-concepts/over-the-air) for the client API and your platform's guide in the **Native** section for wiring it up. # BridgeErrorCode (/docs/references/api/bridge/bridge-error-code) BridgeErrorCode — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/error.ts#L9) ## Properties [#properties] *** ## Type [#type] ```ts type BridgeErrorCode = (typeof BridgeErrorCode)[keyof typeof BridgeErrorCode]; ``` # BridgeErrorData (/docs/references/api/bridge/bridge-error-data) Bridge error data that respond from native. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bridge error data that respond from native. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/error.ts#L4) ## Properties [#properties] # BridgeError (/docs/references/api/bridge/bridge-error) Error thrown by @wvb/bridge when an invoke() command rejects, regardless of platform. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Error thrown by `@wvb/bridge` when an `invoke()` command rejects, regardless of platform. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/error.ts#L28) **Extends:** `Error` ## Constructor [#constructor] ```ts new BridgeError(data: BridgeErrorData); ``` ## Properties [#properties] ## Methods [#methods] # BundleManifestMetadata (/docs/references/api/bridge/bundle-manifest-metadata) Bundle manifest metadata. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle manifest metadata. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L12) ## Properties [#properties] # BundleSourceType (/docs/references/api/bridge/bundle-source-type) BundleSourceType — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} * builtin: Built-in bundle which is included in the application. * remote: Remote bundle which is downloaded from a remote server. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L7) ## Type [#type] ```ts type BundleSourceType = 'builtin' | 'remote'; ``` # BundleSourceVersion (/docs/references/api/bridge/bundle-source-version) Bundle source version. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle source version. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L50) ## Properties [#properties] # BundleUpdateInfo (/docs/references/api/bridge/bundle-update-info) Information of an available bundle update. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Information of an available bundle update. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/updater.ts#L9) ## Properties [#properties] # @wvb/bridge (/docs/references/api/bridge) WebView bridge {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # InvokeParams (/docs/references/api/bridge/invoke-params) InvokeParams — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/invoke.ts#L15) ## Index Signature [#index-signature] ```ts [key: string | number]: any; ``` # invoke (/docs/references/api/bridge/invoke) Invokes a native bridge command and resolves its result. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Invokes a native bridge command and resolves its result. Before using the bridge, make sure native supports webview-bundle. Throws a [`BridgeError`](/docs/references/api/bridge/bridge-error) on failure. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/invoke.ts#L27) ```ts function invoke(name: string, params?: InvokeParams): Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise` # isBridgeErrorData (/docs/references/api/bridge/is-bridge-error-data) isBridgeErrorData — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/error.ts#L62) ```ts function isBridgeErrorData(value: unknown): value is BridgeErrorData; ``` ## Parameters [#parameters] ## Returns [#returns] `value is BridgeErrorData` # isBridgeError (/docs/references/api/bridge/is-bridge-error) isBridgeError — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/error.ts#L58) ```ts function isBridgeError(e: unknown): e is BridgeError; ``` ## Parameters [#parameters] ## Returns [#returns] `e is BridgeError` # ListBundleItem (/docs/references/api/bridge/list-bundle-item) List item of bundles. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} List item of bundles. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L40) ## Properties [#properties] # ListBundleManifestItem (/docs/references/api/bridge/list-bundle-manifest-item) List item of bundle manifests. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} List item of bundle manifests. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L26) ## Properties [#properties] # ListRemoteBundleInfo (/docs/references/api/bridge/list-remote-bundle-info) List item of remote bundles. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} List item of remote bundles. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/remote.ts#L4) ## Properties [#properties] # PlatformType (/docs/references/api/bridge/platform-type) PlatformType — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/platform.ts#L5) ## Type [#type] ```ts type PlatformType = 'electron' | 'tauri' | 'deno' | 'android' | 'ios'; ``` # platform (/docs/references/api/bridge/platform) platform — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/platform.ts#L74) ## Properties [#properties] # RemoteApi (/docs/references/api/bridge/remote-api) RemoteApi — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/remote.ts#L43) ## Methods [#methods] # RemoteBundleInfo (/docs/references/api/bridge/remote-bundle-info) Information of a remote bundle. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Information of a remote bundle. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/remote.ts#L16) ## Properties [#properties] # remote (/docs/references/api/bridge/remote) remote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/remote.ts#L50) **Type:** [`RemoteApi`](/docs/references/api/bridge/remote-api) See [`RemoteApi`](/docs/references/api/bridge/remote-api) for the full member list. # SourceApi (/docs/references/api/bridge/source-api) SourceApi — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L117) ## Methods [#methods] # source (/docs/references/api/bridge/source) source — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/source.ts#L132) **Type:** [`SourceApi`](/docs/references/api/bridge/source-api) See [`SourceApi`](/docs/references/api/bridge/source-api) for the full member list. # UpdaterApi (/docs/references/api/bridge/updater-api) UpdaterApi — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/updater.ts#L40) ## Methods [#methods] # updater (/docs/references/api/bridge/updater) updater — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/bridge/src/updater.ts#L47) **Type:** [`UpdaterApi`](/docs/references/api/bridge/updater-api) See [`UpdaterApi`](/docs/references/api/bridge/updater-api) for the full member list. # defineConfig (/docs/references/api/cli/define-config) defineConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Overload 1 [#overload-1] ```ts function defineConfig(config: Config): Config; ``` ## Parameters [#parameters] ## Returns [#returns] `Config` ## Overload 2 [#overload-2] ```ts function defineConfig(config: Promise): Promise; ``` ## Parameters [#parameters-1] ## Returns [#returns-1] `Promise` ## Overload 3 [#overload-3] ```ts function defineConfig(config: ConfigInputFnObj): ConfigInputFnObj; ``` ## Parameters [#parameters-2] ## Returns [#returns-2] `ConfigInputFnObj` ## Overload 4 [#overload-4] ```ts function defineConfig(config: ConfigInputFnPromise): ConfigInputFnPromise; ``` ## Parameters [#parameters-3] ## Returns [#returns-3] `ConfigInputFnPromise` ## Overload 5 [#overload-5] ```ts function defineConfig(config: ConfigInputFn): ConfigInputFn; ``` ## Parameters [#parameters-4] ## Returns [#returns-4] `ConfigInputFn` ## Overload 6 [#overload-6] ```ts function defineConfig(config: ConfigInput): ConfigInput; ``` ## Parameters [#parameters-5] ## Returns [#returns-5] `ConfigInput` # @wvb/cli (/docs/references/api/cli) API reference for @wvb/cli. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] # InlineConfig (/docs/references/api/cli/inline-config) InlineConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/cli/src/config.ts#L174) **Extends:** `Config` ## Properties [#properties] # loadConfigFile (/docs/references/api/cli/load-config-file) loadConfigFile — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/cli/src/config.ts#L26) ```ts function loadConfigFile(filePath?: string, cwd: string = ...): Promise<{ config: Config; configFile: string; configFileDependencies: string[] } | null>; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise<{ config: Config; configFile: string; configFileDependencies: string[] } | null>` # resolveConfig (/docs/references/api/cli/resolve-config) resolveConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/cli/src/config.ts#L189) ```ts function resolveConfig(inlineConfig: InlineConfig): Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise` # ResolvedConfig (/docs/references/api/cli/resolved-config) ResolvedConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/cli/src/config.ts#L178) **Extends:** `Readonly & { configFile: string | undefined; configFileDependencies: string[] | undefined; inlineConfig: InlineConfig; packageJson: PackageJson | undefined; root: string }>` ## Properties [#properties] # BuiltinBundleMatches (/docs/references/api/config/builtin-bundle-matches) BuiltinBundleMatches — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L5) ## Type [#type] ```ts type BuiltinBundleMatches = | string | RegExp | (string | RegExp)[] | ((info: { name: string; version: string }) => boolean | Promise); ``` # BuiltinConfig (/docs/references/api/config/builtin-config) BuiltinConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L54) ## Properties [#properties] # BuiltinDownloadConfig (/docs/references/api/config/builtin-download-config) BuiltinDownloadConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L11) ## Properties [#properties] # BuiltinLocalTargetConfig (/docs/references/api/config/builtin-local-target-config) Install builtin bundles from a local target. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Install builtin bundles from a local target. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L29) ## Properties [#properties] # BuiltinRemoteTargetConfig (/docs/references/api/config/builtin-remote-target-config) Install builtin bundles from a remote target. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Install builtin bundles from a remote target. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L22) **Extends:** `Pick` ## Properties [#properties] # BuiltinTarget (/docs/references/api/config/builtin-target) BuiltinTarget — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/builtin.ts#L50) ## Type [#type] ```ts type BuiltinTarget = | ({ type: 'remote' } & BuiltinRemoteTargetConfig) | ({ type: 'local' } & BuiltinLocalTargetConfig); ``` # BundleInfoResolverParams (/docs/references/api/config/bundle-info-resolver-params) BundleInfoResolverParams — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/common.ts#L3) ## Properties [#properties] # BundleNameResolver (/docs/references/api/config/bundle-name-resolver) Bundle name resolver to determine the name of the bundle to be used in remote or builtin. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle name resolver to determine the name of the bundle to be used in remote or builtin. From "package.json", will use the "name" field from "package.json", if not specified, will be throw error. If "name" is with a scope prefix, it will be removed. Or, specify a custom bundle name string or a function that returns a bundle name string. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/common.ts#L47) ## Type [#type] ```ts type BundleNameResolver = | { from: 'package.json' } | string | ((params: BundleInfoResolverParams) => string | Promise); ``` # ConfigInputFnObj (/docs/references/api/config/config-input-fn-obj) ConfigInputFnObj — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L6) ## Type [#type] ```ts type ConfigInputFnObj = () => Config; ``` # ConfigInputFnPromise (/docs/references/api/config/config-input-fn-promise) ConfigInputFnPromise — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L7) ## Type [#type] ```ts type ConfigInputFnPromise = () => Promise; ``` # ConfigInputFn (/docs/references/api/config/config-input-fn) ConfigInputFn — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L8) ## Type [#type] ```ts type ConfigInputFn = () => Config | Promise; ``` # ConfigInput (/docs/references/api/config/config-input) ConfigInput — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L10) ## Type [#type] ```ts type ConfigInput = | Config | Promise | ConfigInputFnObj | ConfigInputFnPromise | ConfigInputFn; ``` # Config (/docs/references/api/config/config) Config — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L27) ## Properties [#properties] # defineConfig (/docs/references/api/config/define-config) defineConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/config.ts#L17) ## Overload 1 [#overload-1] ```ts function defineConfig(config: Config): Config; ``` ## Parameters [#parameters] ## Returns [#returns] `Config` ## Overload 2 [#overload-2] ```ts function defineConfig(config: Promise): Promise; ``` ## Parameters [#parameters-1] ## Returns [#returns-1] `Promise` ## Overload 3 [#overload-3] ```ts function defineConfig(config: ConfigInputFnObj): ConfigInputFnObj; ``` ## Parameters [#parameters-2] ## Returns [#returns-2] `ConfigInputFnObj` ## Overload 4 [#overload-4] ```ts function defineConfig(config: ConfigInputFnPromise): ConfigInputFnPromise; ``` ## Parameters [#parameters-3] ## Returns [#returns-3] `ConfigInputFnPromise` ## Overload 5 [#overload-5] ```ts function defineConfig(config: ConfigInputFn): ConfigInputFn; ``` ## Parameters [#parameters-4] ## Returns [#returns-4] `ConfigInputFn` ## Overload 6 [#overload-6] ```ts function defineConfig(config: ConfigInput): ConfigInput; ``` ## Parameters [#parameters-5] ## Returns [#returns-5] `ConfigInput` # HeadersConfig (/docs/references/api/config/headers-config) HeadersConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/pack.ts#L2) ## Type [#type] ```ts type HeadersConfig = | Record | [string, HeadersInit][] | ((file: string) => HeadersInit | null | undefined | Promise); ``` # IgnoreConfig (/docs/references/api/config/ignore-config) IgnoreConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/pack.ts#L1) ## Type [#type] ```ts type IgnoreConfig = (string | RegExp)[] | ((file: string) => boolean | Promise); ``` # @wvb/config (/docs/references/api/config) Configuration for webview bundle {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] # PackConfig (/docs/references/api/config/pack-config) Webview Bundle pack config. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Webview Bundle pack config. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/pack.ts#L10) ## Properties [#properties] ## Examples [#examples] ### headers [#headers] ```ts { * "*.html": { * "cache-control": "max-age=3600", * }, * "*.js": ["cache-control", "max-age=0"] * } ``` # ServeConfig (/docs/references/api/config/serve-config) ServeConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/serve.ts#L1) ## Properties [#properties] # VersionResolver (/docs/references/api/config/version-resolver) Version resolver to determine the version of the bundle to be used in remote or builtin. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Version resolver to determine the version of the bundle to be used in remote or builtin. From "package.json", will use the "version" field from "package.json", if not specified, will be throw error. From "git", will use the "HEAD" commit hash. Or, specify a custom version string or a function that returns a version string. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/config/src/common.ts#L30) ## Type [#type] ```ts type VersionResolver = | { from: 'package.json' } | { from: 'git' } | string | ((params: BundleInfoResolverParams) => string | Promise); ``` # BundleManifestMetadata (/docs/references/api/deno/bundle-manifest-metadata) Cache-validation / integrity metadata for a bundle version. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Cache-validation / integrity metadata for a bundle version. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L15) ## Properties [#properties] # BundleProtocol (/docs/references/api/deno/bundle-protocol) Serves files from a BundleSource as HTTP responses — GET/HEAD, content-type, HTTP Range (206), and index.html directory-index fallback. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Serves files from a [`BundleSource`](/docs/references/api/deno/bundle-source) as HTTP responses — GET/HEAD, content-type, HTTP Range (206), and `index.html` directory-index fallback. Resolves the bundle name from the request URI host (`bundle://app/index.html` → bundle `app`). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/protocol.ts#L30) ## Constructor [#constructor] ```ts new BundleProtocol(source: BundleSource); ``` ## Methods [#methods] # BundleSourceConfig (/docs/references/api/deno/bundle-source-config) BundleSourceConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L4) ## Properties [#properties] # BundleSourceType (/docs/references/api/deno/bundle-source-type) Which source a bundle version comes from. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Which source a bundle version comes from. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L12) ## Type [#type] ```ts type BundleSourceType = 'builtin' | 'remote'; ``` # BundleSourceVersion (/docs/references/api/deno/bundle-source-version) The current version of a bundle and which source provides it. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} The current version of a bundle and which source provides it. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L23) ## Properties [#properties] # BundleSource (/docs/references/api/deno/bundle-source) A bundle source over a builtinDir (read-only) and remoteDir (writable). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A bundle source over a `builtinDir` (read-only) and `remoteDir` (writable). Pass it to [`BundleProtocol`](/docs/references/api/deno/bundle-protocol). Free it with `using` or `.free()` once no longer needed (the protocol keeps its own reference, so the source may be freed after the protocol is created). The data methods mirror `@wvb/node`'s `BundleSource` so `@wvb/deno-desktop` can serve the `@wvb/bridge` `source.*` commands. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L45) ## Constructor [#constructor] ```ts new BundleSource(config: BundleSourceConfig); ``` ## Methods [#methods] # BundleUpdateInfo (/docs/references/api/deno/bundle-update-info) Information about an available update. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Information about an available update. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L64) ## Properties [#properties] # HttpMethod (/docs/references/api/deno/http-method) HTTP method accepted by a protocol handler (case-insensitive on the wire). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} HTTP method accepted by a protocol handler (case-insensitive on the wire). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/protocol.ts#L7) ## Type [#type] ```ts type HttpMethod = 'get' | 'head' | 'options' | 'post' | 'put' | 'patch' | 'delete'; ``` # HttpOptions (/docs/references/api/deno/http-options) HTTP client options (mirrors @wvb/node's HttpOptions; defaultHeaders not yet supported). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} HTTP client options (mirrors `@wvb/node`'s `HttpOptions`; `defaultHeaders` not yet supported). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L5) ## Properties [#properties] # HttpResponse (/docs/references/api/deno/http-response) A served HTTP response (mirrors @wvb/node's HttpResponse, with Uint8Array for the body). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A served HTTP response (mirrors `@wvb/node`'s `HttpResponse`, with `Uint8Array` for the body). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/ffi.ts#L265) ## Properties [#properties] # @wvb/deno (/docs/references/api/deno) API reference for @wvb/deno. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] # IntegrityPolicy (/docs/references/api/deno/integrity-policy) Integrity verification policy. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Integrity verification policy. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L8) ## Type [#type] ```ts type IntegrityPolicy = 'strict' | 'optional' | 'none'; ``` # ListBundleItem (/docs/references/api/deno/list-bundle-item) A bundle version from BundleSource.listBundles (flat shape, matching @wvb/node). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A bundle version from `BundleSource.listBundles` (flat shape, matching `@wvb/node`). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/source.ts#L29) ## Properties [#properties] # ListRemoteBundleInfo (/docs/references/api/deno/list-remote-bundle-info) Bundle info from list operations. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle info from list operations. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L22) ## Properties [#properties] # LoadLibViaPlugOptions (/docs/references/api/deno/load-lib-via-plug-options) LoadLibViaPlugOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/ffi.ts#L162) ## Properties [#properties] # loadLibViaPlug (/docs/references/api/deno/load-lib-via-plug) Download the platform cdylib from a release via @denosaurs/plug, verify it, cache it, and load it. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Download the platform cdylib from a release via `@denosaurs/plug`, verify it, cache it, and load it. For `deno run` / library use where the dylib isn't bundled. NOT for self-contained `deno desktop` builds — there, vendor + `--include` the dylib and use [`loadLib`](/docs/references/api/deno/load-lib). Requires `--allow-net --allow-read --allow-write --allow-env --allow-ffi`. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/ffi.ts#L178) ```ts function loadLibViaPlug(options: LoadLibViaPlugOptions = {}): Promise>; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise>` # loadLib (/docs/references/api/deno/load-lib) Load the native library from an explicit path and cache it {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Load the native library from an explicit path and cache it [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/ffi.ts#L157) ```ts function loadLib(libPath: string | URL): DynamicLibrary; ``` ## Parameters [#parameters] ## Returns [#returns] `DynamicLibrary` # LocalProtocol (/docs/references/api/deno/local-protocol) Proxies requests for custom hosts to localhost URLs (for dev servers with hot reload). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Proxies requests for custom hosts to localhost URLs (for dev servers with hot reload). Maps a custom host to a base URL — e.g. `{ app: 'http://localhost:5173' }` serves `app://app/index.html` from the dev server. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/protocol.ts#L62) ## Constructor [#constructor] ```ts new LocalProtocol(hosts: Record); ``` ## Methods [#methods] # platformLibFileName (/docs/references/api/deno/platform-lib-file-name) Platform cdylib filename: libwvb_deno.dylib (macOS) / libwvb_deno.so (Linux) / wvb_deno.dll (Windows). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Platform cdylib filename: `libwvb_deno.dylib` (macOS) / `libwvb_deno.so` (Linux) / `wvb_deno.dll` (Windows). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/ffi.ts#L136) ```ts function platformLibFileName(os: any = Deno.build.os): string; ``` ## Parameters [#parameters] ## Returns [#returns] `string` # RemoteBundleInfo (/docs/references/api/deno/remote-bundle-info) Complete bundle info from the remote server. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Complete bundle info from the remote server. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L28) ## Properties [#properties] # RemoteDownload (/docs/references/api/deno/remote-download) Result of a remote bundle download: info + raw .wvb bytes. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Result of a remote bundle download: info + raw `.wvb` bytes. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L38) ## Properties [#properties] # RemoteOptions (/docs/references/api/deno/remote-options) RemoteOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L17) ## Properties [#properties] # Remote (/docs/references/api/deno/remote) HTTP client for a remote bundle server — list, get metadata, and download bundles. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} HTTP client for a remote bundle server — list, get metadata, and download bundles. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/remote.ts#L46) ## Constructor [#constructor] ```ts new Remote(endpoint: string, options?: RemoteOptions); ``` ## Properties [#properties] ## Methods [#methods] # SignatureAlgorithm (/docs/references/api/deno/signature-algorithm) Digital signature algorithm for bundle verification (mirrors @wvb/node). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Digital signature algorithm for bundle verification (mirrors `@wvb/node`). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L11) ## Type [#type] ```ts type SignatureAlgorithm = | 'ecdsaSecp256R1' | 'ecdsaSecp384R1' | 'ed25519' | 'rsaPkcs1V15' | 'rsaPss'; ``` # SignatureVerifierOptions (/docs/references/api/deno/signature-verifier-options) Declarative signature verifier: an algorithm + the public key to verify bundle signatures with. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Declarative signature verifier: an algorithm + the public key to verify bundle signatures with. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L30) ## Properties [#properties] # SignatureVerifyingKeyOptions (/docs/references/api/deno/signature-verifying-key-options) Public key configuration: data is the PEM text for PEM formats, or the key bytes otherwise. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Public key configuration: `data` is the PEM text for PEM formats, or the key bytes otherwise. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L24) ## Properties [#properties] # toResponse (/docs/references/api/deno/to-response) Convert an HttpResponse to a web Response (for use inside a Deno.serve handler). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Convert an [`HttpResponse`](/docs/references/api/deno/http-response) to a web `Response` (for use inside a `Deno.serve` handler). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/protocol.ts#L90) ```ts function toResponse(res: HttpResponse): Response; ``` ## Parameters [#parameters] ## Returns [#returns] `Response` # UpdaterOptions (/docs/references/api/deno/updater-options) UpdaterOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L35) ## Properties [#properties] # Updater (/docs/references/api/deno/updater) Coordinates updates between a BundleSource and a Remote: check, download to the remote dir, and activate. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Coordinates updates between a [`BundleSource`](/docs/references/api/deno/bundle-source) and a [`Remote`](/docs/references/api/deno/remote): check, download to the remote dir, and activate. Supports `channel`, `integrityPolicy`, and a declarative `signatureVerifier`. The custom-function callback options of `@wvb/node` (`integrityChecker`, custom `signatureVerifier`) are not yet supported over FFI. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L83) ## Constructor [#constructor] ```ts new Updater(source: BundleSource, remote: Remote, options?: UpdaterOptions); ``` ## Methods [#methods] # VerifyingKeyFormat (/docs/references/api/deno/verifying-key-format) Format of the public key. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Format of the public key. Binary formats (`spkiDer`/`pkcs1Der`/`sec1`/`raw`) take `Uint8Array` data; the PEM formats take the PEM text. `pkcs1*` is RSA-only, `sec1` is ECDSA-only, `raw` is Ed25519-only (32 bytes). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno/lib/updater.ts#L21) ## Type [#type] ```ts type VerifyingKeyFormat = 'spkiDer' | 'spkiPem' | 'pkcs1Der' | 'pkcs1Pem' | 'sec1' | 'raw'; ``` # appDataDir (/docs/references/api/deno-desktop/app-data-dir) The OS application-data base directory where downloaded bundles persist: macOS ~/Library/Application Support, Windows %APPDATA%, Linux $XDG_DATA_HOME (or ~/.… {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} The OS application-data base directory where downloaded bundles persist: macOS `~/Library/Application Support`, Windows `%APPDATA%`, Linux `$XDG_DATA_HOME` (or `~/.local/share`). Override with the `WVB_APP_DATA_DIR` env var. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/source.ts#L48) ```ts function appDataDir(): string; ``` ## Returns [#returns] `string` # BridgeErrorCode (/docs/references/api/deno-desktop/bridge-error-code) BridgeErrorCode — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L24) ## Properties [#properties] # BridgeErrorData (/docs/references/api/deno-desktop/bridge-error-data) Error payload returned to @wvb/bridge (becomes a BridgeError there, preserving code). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Error payload returned to `@wvb/bridge` (becomes a `BridgeError` there, preserving `code`). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L12) ## Properties [#properties] # BundleProtocolConfig (/docs/references/api/deno-desktop/bundle-protocol-config) BundleProtocolConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L60) **Extends:** `ProtocolOptions` ## Methods [#methods] # bundleProtocol (/docs/references/api/deno-desktop/bundle-protocol) Serve a builtin bundle (named scheme) at the HTTP root. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Serve a builtin bundle (named `scheme`) at the HTTP root. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L63) ```ts function bundleProtocol(scheme: string, config: BundleProtocolConfig = {}): Protocol; ``` ## Parameters [#parameters] ## Returns [#returns] `Protocol` # bundleSource (/docs/references/api/deno-desktop/bundle-source) bundleSource — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/source.ts#L25) ```ts function bundleSource(options: SourceOptions = {}): BundleSource; ``` ## Parameters [#parameters] ## Returns [#returns] `BundleSource` # DenoBrowserWindow (/docs/references/api/deno-desktop/deno-browser-window) A Deno.BrowserWindow (only the binding methods we use; the full type ships with Deno desktop). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A `Deno.BrowserWindow` (only the binding methods we use; the full type ships with Deno desktop). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L134) ## Methods [#methods] # dispatch (/docs/references/api/deno-desktop/dispatch) Run one @wvb/bridge command and return its JSON-serializable result envelope (never throws). {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Run one `@wvb/bridge` command and return its JSON-serializable result envelope (never throws). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L110) ```ts function dispatch(wvb: WebviewBundle, name: string, params?: Params): Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise` # handlerNames (/docs/references/api/deno-desktop/handler-names) Names of every command this host can serve. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Names of every command this host can serve. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L107) **Type:** `readonly string[]` # HttpResponse (/docs/references/api/deno-desktop/http-response) HttpResponse — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Type [#type] ```ts type HttpResponse = any; ``` # @wvb/deno-desktop (/docs/references/api/deno-desktop) API reference for @wvb/deno-desktop. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # INVOKE_BINDING (/docs/references/api/deno-desktop/invoke-binding) The single binding name the @wvb/bridge deno transport calls. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} The single binding name the `@wvb/bridge` `deno` transport calls. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L9) **Type:** `"wvbInvoke"` # InvokeResult (/docs/references/api/deno-desktop/invoke-result) Result envelope. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Result envelope. Deno desktop delivers a thrown handler error as `{ name, message, stack }` (dropping our `code`), so handlers never throw across the binding — they return this instead and `@wvb/bridge` unwraps it (mirrors @wvb/electron's preload). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L22) ## Type [#type] ```ts type InvokeResult = { ok: true; value: unknown } | { error: BridgeErrorData; ok: false }; ``` # LocalProtocolConfig (/docs/references/api/deno-desktop/local-protocol-config) LocalProtocolConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L90) **Extends:** `ProtocolOptions` ## Properties [#properties] ## Methods [#methods] # localProtocol (/docs/references/api/deno-desktop/local-protocol) Proxy to a local dev server (hot reload), mapping scheme host → URL. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Proxy to a local dev server (hot reload), mapping `scheme` host → URL. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L95) ```ts function localProtocol(scheme: string, config: LocalProtocolConfig): Protocol; ``` ## Parameters [#parameters] ## Returns [#returns] `Protocol` # ProtocolHandlerBuildContext (/docs/references/api/deno-desktop/protocol-handler-build-context) ProtocolHandlerBuildContext — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L16) ## Properties [#properties] # ProtocolHandlerBuild (/docs/references/api/deno-desktop/protocol-handler-build) ProtocolHandlerBuild — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L19) ## Type [#type] ```ts type ProtocolHandlerBuild = ( ctx: ProtocolHandlerBuildContext ) => ProtocolHandler | Promise; ``` # ProtocolHandler (/docs/references/api/deno-desktop/protocol-handler) ProtocolHandler — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L12) ## Methods [#methods] # ProtocolOptions (/docs/references/api/deno-desktop/protocol-options) ProtocolOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L23) ## Methods [#methods] # Protocol (/docs/references/api/deno-desktop/protocol) Protocol — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/protocol.ts#L27) ## Properties [#properties] # registerBindings (/docs/references/api/deno-desktop/register-bindings) Register the @wvb/bridge transport on a Deno desktop window: a single wvbInvoke(name, params) binding that dispatches to wvb. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Register the `@wvb/bridge` transport on a Deno desktop window: a single `wvbInvoke(name, params)` binding that dispatches to `wvb`. Call after creating the window and the app, e.g. ```ts const win = new Deno.BrowserWindow(); const app = webviewBundle({ source: { appName: 'myapp' }, protocols: [bundleProtocol('app')] }); registerBindings(win, app); Deno.serve(app.fetch); ``` [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/bindings.ts#L150) ```ts function registerBindings(win: DenoBrowserWindow, wvb: WebviewBundle): void; ``` ## Parameters [#parameters] ## Returns [#returns] `void` # RemoteOptions (/docs/references/api/deno-desktop/remote-options) RemoteOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/remote.ts#L4) **Extends:** `HttpResponse` # remote (/docs/references/api/deno-desktop/remote) remote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/remote.ts#L6) ```ts function remote(endpoint: string, options?: RemoteOptions): Remote; ``` ## Parameters [#parameters] ## Returns [#returns] `Remote` # SourceOptions (/docs/references/api/deno-desktop/source-options) SourceOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/source.ts#L10) **Extends:** `Omit` ## Properties [#properties] ## Index Signature [#index-signature] ```ts [key: string]: BundleSourceConfig; [key: number]: BundleSourceConfig; [key: symbol]: BundleSourceConfig; ``` # WebviewBundleConfig (/docs/references/api/deno-desktop/webview-bundle-config) WebviewBundleConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L14) ## Properties [#properties] # WebviewBundle (/docs/references/api/deno-desktop/webview-bundle-interface) WebviewBundle — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L48) ## Properties [#properties] ## Methods [#methods] # WebviewBundleRemoteConfig (/docs/references/api/deno-desktop/webview-bundle-remote-config) WebviewBundleRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L6) **Extends:** `RemoteOptions` ## Properties [#properties] # WebviewBundleUpdaterConfig (/docs/references/api/deno-desktop/webview-bundle-updater-config) WebviewBundleUpdaterConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L10) **Extends:** `HttpResponse` ## Properties [#properties] # webviewBundle (/docs/references/api/deno-desktop/webview-bundle) webviewBundle — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L98) ```ts function webviewBundle(config: WebviewBundleConfig): WebviewBundle; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundle` # wvb (/docs/references/api/deno-desktop/wvb) wvb — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/deno-desktop/lib/webview-bundle.ts#L102) **Type:** [`typeof webviewBundle`](/docs/references/api/deno-desktop/webview-bundle) See [`typeof webviewBundle`](/docs/references/api/deno-desktop/webview-bundle) for the full member list. # bundleProtocol (/docs/references/api/electron/bundle-protocol) bundleProtocol — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/protocol.ts#L122) ```ts function bundleProtocol(scheme: string, config: BundleProtocolConfig = {}): Protocol; ``` ## Parameters [#parameters] ## Returns [#returns] `Protocol` # @wvb/electron (/docs/references/api/electron) Webview Bundle API for Electron {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Variables [#variables] # localProtocol (/docs/references/api/electron/local-protocol) localProtocol — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/protocol.ts#L100) ```ts function localProtocol(scheme: string, config: LocalProtocolConfig): Protocol; ``` ## Parameters [#parameters] ## Returns [#returns] `Protocol` # ProtocolHandler (/docs/references/api/electron/protocol-handler) ProtocolHandler — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/protocol.ts#L13) ## Methods [#methods] # ProtocolOptions (/docs/references/api/electron/protocol-options) ProtocolOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/protocol.ts#L17) ## Properties [#properties] ## Methods [#methods] # Protocol (/docs/references/api/electron/protocol) Protocol — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/protocol.ts#L30) ## Properties [#properties] # RemoteOptions (/docs/references/api/electron/remote-options) RemoteOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/remote.ts#L3) **Extends:** `RemoteOptions` ## Properties [#properties] ## Methods [#methods] # SourceOptions (/docs/references/api/electron/source-options) SourceOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/source.ts#L5) **Extends:** `Omit` ## Properties [#properties] # WebviewBundleConfig (/docs/references/api/electron/webview-bundle-config) WebviewBundleConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/webview-bundle.ts#L15) ## Properties [#properties] # WebviewBundle (/docs/references/api/electron/webview-bundle-interface) WebviewBundle — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/webview-bundle.ts#L21) ## Properties [#properties] ## Methods [#methods] # WebviewBundleRemoteConfig (/docs/references/api/electron/webview-bundle-remote-config) WebviewBundleRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/webview-bundle.ts#L7) **Extends:** `RemoteOptions` ## Properties [#properties] ## Methods [#methods] # webviewBundle (/docs/references/api/electron/webview-bundle) webviewBundle — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/webview-bundle.ts#L63) ```ts function webviewBundle(config: WebviewBundleConfig): WebviewBundle; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundle` # wvb (/docs/references/api/electron/wvb) wvb — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron/src/webview-bundle.ts#L69) **Type:** [`typeof webviewBundle`](/docs/references/api/electron/webview-bundle) See [`typeof webviewBundle`](/docs/references/api/electron/webview-bundle) for the full member list. # AfterPackContext (/docs/references/api/electron-builder/after-pack-context) Electron builder's after pack context type. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Electron builder's after pack context type. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/config.ts#L6) ## Properties [#properties] # AfterPackHook (/docs/references/api/electron-builder/after-pack-hook) An electron-builder afterPack lifecycle hook. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} An electron-builder `afterPack` lifecycle hook. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/config.ts#L26) ## Type [#type] ```ts type AfterPackHook = (context: AfterPackContext) => void | Promise; ``` # @wvb/electron-builder (/docs/references/api/electron-builder) electron-builder integration for webview bundle {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # resolveResourcesPath (/docs/references/api/electron-builder/resolve-resources-path) Resolve the packaged app's Resources directory from an electron-builder afterPack context. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Resolve the packaged app's `Resources` directory from an electron-builder `afterPack` context. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/setup.ts#L23) ```ts function resolveResourcesPath(context: AfterPackContext): string; ``` ## Parameters [#parameters] ## Returns [#returns] `string` # webviewBundleAfterPack (/docs/references/api/electron-builder/webview-bundle-after-pack) Build an electron-builder afterPack hook that installs builtin Webview Bundles — downloaded from the remote and/or packed from local workspaces as configured… {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Build an electron-builder `afterPack` hook that installs builtin Webview Bundles — downloaded from the remote and/or packed from local workspaces as configured in your webview-bundle config — and embeds them into the packaged app's `Resources/`, where `@wvb/electron` looks for them at runtime. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/setup.ts#L38) ```ts function webviewBundleAfterPack( options: WebviewBundleOptions = {} ): (context: AfterPackContext) => Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `(context: AfterPackContext) => Promise` # WebviewBundleOptions (/docs/references/api/electron-builder/webview-bundle-options) Webview bundle options. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Webview bundle options. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/config.ts#L31) **Extends:** `Pick` ## Properties [#properties] # withWebviewBundle (/docs/references/api/electron-builder/with-webview-bundle) Wrap an electron-builder configuration so it installs builtin Webview Bundles at package time. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Wrap an electron-builder configuration so it installs builtin Webview Bundles at package time. ```ts // electron-builder.config.ts import { withWebViewBundle } from '@wvb/electron-builder'; export default withWebViewBundle({ appId: 'com.example.app', asar: true, mac: { target: 'dmg' }, }); ``` [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/setup.ts#L125) ```ts function withWebviewBundle(config: C, options: WebviewBundleOptions = {}): C; ``` ## Parameters [#parameters] ## Returns [#returns] `C` # withWvb (/docs/references/api/electron-builder/with-wvb) withWvb — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/setup.ts#L153) **Type:** [`typeof withWebviewBundle`](/docs/references/api/electron-builder/with-webview-bundle) See [`typeof withWebviewBundle`](/docs/references/api/electron-builder/with-webview-bundle) for the full member list. # wvbAfterPack (/docs/references/api/electron-builder/wvb-after-pack) wvbAfterPack — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-builder/src/setup.ts#L109) **Type:** [`typeof webviewBundleAfterPack`](/docs/references/api/electron-builder/webview-bundle-after-pack) See [`typeof webviewBundleAfterPack`](/docs/references/api/electron-builder/webview-bundle-after-pack) for the full member list. # @wvb/electron-forge (/docs/references/api/electron-forge) Electron forge plugin for webview bundle {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Interfaces [#interfaces] ## Variables [#variables] # WebviewBundlePluginConfig (/docs/references/api/electron-forge/webview-bundle-plugin-config) WebviewBundlePluginConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-forge/src/config.ts#L3) **Extends:** `Pick` ## Properties [#properties] # WebviewBundlePlugin (/docs/references/api/electron-forge/webview-bundle-plugin) WebviewBundlePlugin — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-forge/src/plugin.ts#L27) **Extends:** `default` ## Constructor [#constructor] ```ts new WebviewBundlePlugin(config: WebviewBundlePluginConfig = {}); ``` ## Properties [#properties] ## Methods [#methods] # WvbPlugin (/docs/references/api/electron-forge/wvb-plugin) WvbPlugin — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/electron-forge/src/plugin.ts#L116) **Type:** [`typeof WebviewBundlePlugin`](/docs/references/api/electron-forge/webview-bundle-plugin) See [`typeof WebviewBundlePlugin`](/docs/references/api/electron-forge/webview-bundle-plugin) for the full member list. # BuildHeaderOptions (/docs/references/api/node/build-header-options) Options for bundle header generation. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Options for bundle header generation. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1040) ## Properties [#properties] # BuildIndexOptions (/docs/references/api/node/build-index-options) Options for bundle index generation. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Options for bundle index generation. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1049) ## Properties [#properties] # BuildOptions (/docs/references/api/node/build-options) Options for building a bundle. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Options for building a bundle. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1060) ## Properties [#properties] # BundleBuilder (/docs/references/api/node/bundle-builder) Builder for creating bundle files. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Builder for creating bundle files. Allows you to add files, set options, and generate a complete bundle. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L80) ## Constructor [#constructor] ```ts new BundleBuilder(version?: "v1" | null); ``` ## Properties [#properties] ## Methods [#methods] ## Examples [#examples] ```typescript const builder = new BundleBuilder(); // Add files builder.insertEntry('/index.html', Buffer.from('...')); builder.insertEntry('/app.js', Buffer.from("console.log('hello');")); // Build the bundle const bundle = builder.build(); // Write to file await writeBundle(bundle, 'app.wvb'); ``` ### constructor [#constructor-1] ```typescript const builder = new BundleBuilder(); ``` ### build [#build] ```typescript const bundle = builder.build(); await writeBundle(bundle, 'output.wvb'); ``` ### containsEntry [#containsentry] ```typescript if (builder.containsEntry('/index.html')) { console.log('index.html already added'); } ``` ### entryPaths [#entrypaths] ```typescript const paths = builder.entryPaths(); console.log(paths); // ["/index.html", "/app.js"] ``` ### insertEntry [#insertentry] ```typescript // Auto-detect MIME type builder.insertEntry('/index.html', Buffer.from('')); // Specify MIME type builder.insertEntry('/data.bin', buffer, 'application/octet-stream'); // With custom headers builder.insertEntry('/style.css', cssBuffer, 'text/css', { 'Cache-Control': 'max-age=3600', }); ``` ### removeEntry [#removeentry] ```typescript builder.removeEntry('/old-file.js'); ``` # BundleDescriptor (/docs/references/api/node/bundle-descriptor) Bundle metadata including header and index information. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle metadata including header and index information. A descriptor contains only the metadata without loading the actual file data, making it efficient for inspecting bundle contents. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L195) ## Constructor [#constructor] ```ts new BundleDescriptor(); ``` ## Methods [#methods] ## Examples [#examples] ```typescript const bundle = await readBundle('app.wvb'); const descriptor = bundle.descriptor(); const header = descriptor.header(); const index = descriptor.index(); ``` # BundleManifestData (/docs/references/api/node/bundle-manifest-data) Complete manifest data structure. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Complete manifest data structure. The manifest tracks all bundle versions and metadata. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1074) ## Properties [#properties] # BundleManifestEntry (/docs/references/api/node/bundle-manifest-entry) Entry for a single bundle in the manifest. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Entry for a single bundle in the manifest. Contains all versions and the current active version. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1087) ## Properties [#properties] # BundleManifestMetadata (/docs/references/api/node/bundle-manifest-metadata) Metadata for a bundle version in the manifest. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Metadata for a bundle version in the manifest. Contains cache validation and integrity information. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1102) ## Properties [#properties] # BundleManifestVersion (/docs/references/api/node/bundle-manifest-version) Manifest format version. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Manifest format version. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1114) ## Members [#members] # BundleProtocol (/docs/references/api/node/bundle-protocol) Protocol handler for serving files from bundle sources. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Protocol handler for serving files from bundle sources. Serves web resources from `.wvb` bundle files, supporting: * GET and HEAD HTTP methods * HTTP Range requests for streaming * Content-Type and custom HTTP headers [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L265) ## Constructor [#constructor] ```ts new BundleProtocol(source: BundleSource); ``` ## Methods [#methods] ## Examples [#examples] ```typescript const source = new BundleSource({ builtinDir: './bundles/builtin', remoteDir: './bundles/remote', }); const protocol = new BundleProtocol(source); // Handle a request const response = await protocol.handle('get', 'bundle://app/index.html'); console.log(`Status: ${response.status}`); console.log(`Content-Type: ${response.headers['content-type']}`); ``` ### constructor [#constructor-1] ```typescript const source = new BundleSource({ builtinDir: './bundles', remoteDir: './remote', }); const protocol = new BundleProtocol(source); ``` ### handle [#handle] ```typescript // GET request const response = await protocol.handle('get', 'bundle://app/index.html'); if (response.status === 200) { console.log(response.body.toString('utf-8')); } ``` ```typescript // Range request for streaming const response = await protocol.handle('get', 'bundle://app/video.mp4', { Range: 'bytes=0-1023' }); console.log(`Status: ${response.status}`); // 206 Partial Content ``` # BundleSourceConfig (/docs/references/api/node/bundle-source-config) Configuration for creating a bundle source. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Configuration for creating a bundle source. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1135) ## Properties [#properties] ## Examples [#examples] ```typescript const config = { builtinDir: './bundles/builtin', remoteDir: './bundles/remote', }; const source = new BundleSource(config); ``` # BundleSourceKind (/docs/references/api/node/bundle-source-kind) The type of bundle source: builtin or remote. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} The type of bundle source: builtin or remote. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1147) ## Type [#type] ```ts type BundleSourceKind = 'builtin' | 'remote'; ``` # BundleSourceVersion (/docs/references/api/node/bundle-source-version) Bundle version with source kind information. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle version with source kind information. Indicates which source (builtin or remote) provides a bundle version. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1160) ## Properties [#properties] # BundleSource (/docs/references/api/node/bundle-source) Bundle source for managing multiple bundle versions. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle source for managing multiple bundle versions. A source manages bundles in two directories: * **builtin**: Bundles shipped with the app (read-only, fallback) * **remote**: Downloaded bundles (takes priority) The source automatically handles version selection, with remote bundles taking priority over builtin ones. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L337) ## Constructor [#constructor] ```ts new BundleSource(config: BundleSourceConfig); ``` ## Methods [#methods] ## Examples [#examples] ```typescript const source = new BundleSource({ builtinDir: './bundles/builtin', remoteDir: './bundles/remote', }); // List all bundles const bundles = await source.listBundles(); // Load current version const version = await source.loadVersion('app'); // Fetch bundle const bundle = await source.fetch('app'); ``` ### constructor [#constructor-1] ```typescript const source = new BundleSource({ builtinDir: './builtin', remoteDir: './remote', }); ``` ### fetchBundle [#fetchbundle] ```typescript const bundle = await source.fetchBundle('app'); const html = bundle.getData('/index.html'); ``` ### fetchDescriptor [#fetchdescriptor] ```typescript const descriptor = await source.fetchDescriptor('app'); const index = descriptor.index(); console.log(`Files: ${Object.keys(index.entries()).length}`); ``` ### listBundles [#listbundles] ```typescript const bundles = await source.listBundles(); for (const bundle of bundles) { console.log(`${bundle.name}@${bundle.version} (${bundle.type})`); } ``` ### loadDescriptor [#loaddescriptor] ```typescript const loaded = await source.loadDescriptor('app'); const html = await loaded.getData('/index.html'); ``` ### loadVersion [#loadversion] ```typescript const version = await source.loadVersion('app'); if (version) { console.log(`Current version: ${version.version} (${version.type})`); } ``` ### resolveFilepath [#resolvefilepath] ```typescript const path = await source.resolveFilepath('app'); console.log(`Bundle at: ${path}`); ``` ### updateRemoteVersion [#updateremoteversion] ```typescript await source.updateRemoteVersion('app', '1.2.0'); ``` ### writeRemoteBundle [#writeremotebundle] ```typescript await source.writeRemoteBundle('app', '1.2.0', bundle, { integrity: 'sha3-384-...', etag: 'abc123', }); ``` # BundleUpdateInfo (/docs/references/api/node/bundle-update-info) Information about a bundle update. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Information about a bundle update. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1186) ## Properties [#properties] ## Examples [#examples] ```typescript const updateInfo = await updater.getUpdate('app'); if (updateInfo.isAvailable) { console.log(`Update available: ${updateInfo.localVersion} → ${updateInfo.version}`); await updater.download('app'); } ``` # Bundle (/docs/references/api/node/bundle) A complete bundle including metadata and file data. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A complete bundle including metadata and file data. Represents a `.wvb` bundle file loaded entirely into memory. Use this when you need to access multiple files or build new bundles. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L21) ## Constructor [#constructor] ```ts new Bundle(); ``` ## Methods [#methods] ## Examples [#examples] ```typescript // Read a bundle from file const bundle = await readBundle('app.wvb'); // Access files const html = bundle.getData('/index.html'); if (html) { console.log(html.toString('utf-8')); } ``` ### descriptor [#descriptor] ```typescript const descriptor = bundle.descriptor(); const index = descriptor.index(); ``` ### getData [#getdata] ```typescript const data = bundle.getData('/index.html'); if (data) { console.log(data.toString('utf-8')); } ``` # Header (/docs/references/api/node/header) Bundle header containing format metadata. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle header containing format metadata. The header is the first 17 bytes of a `.wvb` file and includes: * Magic number (🌐🎁) * Format version * Index size * Header checksum [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L576) ## Constructor [#constructor] ```ts new Header(); ``` ## Methods [#methods] ## Examples [#examples] ### version [#version] ```typescript const header = bundle.descriptor().header(); console.log(header.version()); // 'v1' ``` # HttpMethod (/docs/references/api/node/http-method) HttpMethod — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1197) ## Type [#type] ```ts type HttpMethod = | 'get' | 'head' | 'options' | 'post' | 'put' | 'patch' | 'delete' | 'trace' | 'connect'; ``` # HttpOptions (/docs/references/api/node/http-options) HttpOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1207) ## Properties [#properties] # HttpResponse (/docs/references/api/node/http-response) HttpResponse — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1220) ## Properties [#properties] # Index (/docs/references/api/node/index-class) Bundle index mapping file paths to their metadata. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle index mapping file paths to their metadata. The index is stored as binary data in the bundle file and maps file paths to their metadata (offset, length, content-type, headers, etc.). [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L611) ## Constructor [#constructor] ```ts new Index(); ``` ## Methods [#methods] ## Examples [#examples] ### containsPath [#containspath] ```typescript if (index.containsPath('/app.js')) { console.log('app.js is in the bundle'); } ``` ### entries [#entries] ```typescript const index = bundle.descriptor().index(); const entries = index.entries(); for (const [path, entry] of Object.entries(entries)) { console.log(`${path}: ${entry.contentType}`); } ``` ### getEntry [#getentry] ```typescript const entry = index.getEntry('/index.html'); if (entry) { console.log(`Content-Type: ${entry.contentType}`); } ``` # IndexEntry (/docs/references/api/node/index-entry) Metadata for a single file in the bundle. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Metadata for a single file in the bundle. Contains information about file location, size, MIME type, and HTTP headers. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1238) ## Properties [#properties] # @wvb/node (/docs/references/api/node) Webview bundle API for Node.js {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Functions [#functions] ## Interfaces [#interfaces] ## Enumerations [#enumerations] ## Type Aliases [#type-aliases] # IntegrityAlgorithm (/docs/references/api/node/integrity-algorithm) Hash algorithm for bundle integrity verification. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Hash algorithm for bundle integrity verification. Supports SHA-2 family hash algorithms for cryptographic verification following the Subresource Integrity specification. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1261) ## Type [#type] ```ts type IntegrityAlgorithm = 'sha256' | 'sha384' | 'sha512'; ``` ## Examples [#examples] ```typescript // Integrity strings use these algorithms: // "sha256-abc123..." - SHA-256 // "sha384-def456..." - SHA-384 (recommended) // "sha512-ghi789..." - SHA-512 ``` # IntegrityPolicy (/docs/references/api/node/integrity-policy) Policy for enforcing integrity verification during bundle operations. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Policy for enforcing integrity verification during bundle operations. Controls when integrity hashes are required and how missing hashes are handled. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1288) ## Type [#type] ```ts type IntegrityPolicy = 'strict' | 'optional' | 'none'; ``` ## Examples [#examples] ```typescript import { Updater } from '@wvb/node'; // Require integrity for all bundles const updater = new Updater(source, remote, { integrityPolicy: 'strict', }); // Optional integrity (warn if missing) const updater2 = new Updater(source, remote, { integrityPolicy: 'optional', }); ``` # ListBundleItem (/docs/references/api/node/list-bundle-item) Information about a bundle from list operations. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Information about a bundle from list operations. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1304) ## Properties [#properties] # ListRemoteBundleInfo (/docs/references/api/node/list-remote-bundle-info) Bundle information from list operations. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle information from list operations. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1318) ## Properties [#properties] # LoadedDescriptor (/docs/references/api/node/loaded-descriptor) A descriptor loaded (and cached) by a BundleSource. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} A descriptor loaded (and cached) by a [`BundleSource`](/docs/references/api/node/bundle-source). Holds the parsed header/index together with the filepath it was loaded from, so reading entry data always targets the exact bundle version that produced this descriptor — even if the source's active version is swapped concurrently. The instance owns a reference-counted handle to the cached descriptor. When the JavaScript object is garbage-collected, the handle is released automatically; the underlying descriptor stays alive only while the source cache (see `BundleSource.loadDescriptor`) or another `LoadedDescriptor` references it. No manual disposal is required and no memory is leaked. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L671) ## Constructor [#constructor] ```ts new LoadedDescriptor(); ``` ## Methods [#methods] ## Examples [#examples] ### descriptor [#descriptor] ```typescript const loaded = await source.loadDescriptor('app'); const index = loaded.descriptor().index(); console.log(index.containsPath('/index.html')); ``` ### getData [#getdata] ```typescript const loaded = await source.loadDescriptor('app'); const html = await loaded.getData('/index.html'); if (html) { console.log(html.toString('utf-8')); } ``` # LocalProtocol (/docs/references/api/node/local-protocol) Protocol handler that proxies requests to localhost servers. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Protocol handler that proxies requests to localhost servers. Forwards requests to local development servers for hot-reloading workflows. Features response caching and 304 Not Modified support. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L735) ## Constructor [#constructor] ```ts new LocalProtocol(hosts: Record); ``` ## Methods [#methods] ## Examples [#examples] ```typescript const protocol = new LocalProtocol({ myapp: 'http://localhost:3000', api: 'http://localhost:8080', }); // This proxies to http://localhost:3000/index.html const response = await protocol.handle('get', 'app://myapp/index.html'); ``` ### constructor [#constructor-1] ```typescript const protocol = new LocalProtocol({ myapp: 'http://localhost:3000', api: 'http://localhost:8080', }); ``` ### handle [#handle] ```typescript // Proxies to http://localhost:3000/api/data?foo=bar const response = await protocol.handle('get', 'app://myapp/api/data?foo=bar'); console.log(response.status); ``` ```typescript // POST with headers const response = await protocol.handle('post', 'app://api/submit', { 'Content-Type': 'application/json', }); ``` # readBundleFromBuffer (/docs/references/api/node/read-bundle-from-buffer) Reads a bundle from a buffer synchronously. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Reads a bundle from a buffer synchronously. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1352) ```ts function readBundleFromBuffer(buffer: Buffer): Bundle; ``` ## Parameters [#parameters] ## Returns [#returns] `Bundle` — Parsed bundle ## Examples [#examples] ```typescript import { readFileSync } from 'fs'; const buffer = readFileSync('app.wvb'); const bundle = readBundleFromBuffer(buffer); ``` # readBundle (/docs/references/api/node/read-bundle) Reads a bundle from a file asynchronously. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Reads a bundle from a file asynchronously. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1336) ```ts function readBundle(filepath: string): Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise` — Parsed bundle ## Examples [#examples] ```typescript const bundle = await readBundle('app.wvb'); const html = bundle.getData('/index.html'); ``` # RemoteBundleInfo (/docs/references/api/node/remote-bundle-info) Complete bundle information from remote server. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Complete bundle information from remote server. Contains version, cache validation, and integrity data. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1366) ## Properties [#properties] # RemoteOnDownloadData (/docs/references/api/node/remote-on-download-data) Download progress data. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Download progress data. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1382) ## Properties [#properties] # RemoteOptions (/docs/references/api/node/remote-options) Options for creating a remote client. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Options for creating a remote client. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1405) ## Properties [#properties] ## Methods [#methods] ## Examples [#examples] ```typescript const options = { http: { timeout: 30000 }, onDownload: data => { console.log(`Downloaded ${data.downloadedBytes}/${data.totalBytes}`); }, }; const remote = new Remote('https://updates.example.com', options); ``` # Remote (/docs/references/api/node/remote) HTTP client for downloading bundles from a remote server. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} HTTP client for downloading bundles from a remote server. The remote client implements the bundle HTTP protocol, allowing you to: * List available bundles * Get bundle metadata * Download specific versions * Track download progress [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L802) ## Constructor [#constructor] ```ts new Remote(endpoint: string, options?: RemoteOptions | null); ``` ## Methods [#methods] ## Examples [#examples] ```typescript const remote = new Remote('https://updates.example.com'); // List all bundles const bundles = await remote.listBundles(); // Get current version info const info = await remote.getInfo('app'); console.log(`Latest version: ${info.version}`); // Download bundle const [bundleInfo, bundle, data] = await remote.download('app'); ``` ### constructor [#constructor-1] ```typescript const remote = new Remote('https://updates.example.com'); ``` ```typescript // With options const remote = new Remote('https://updates.example.com', { http: { timeout: 60000 }, onDownload: data => { const percent = (data.downloadedBytes / data.totalBytes) * 100; console.log(`Progress: ${percent.toFixed(1)}%`); }, }); ``` ### download [#download] ```typescript const [info, bundle, data] = await remote.download('app'); console.log(`Downloaded ${info.name}@${info.version}`); console.log(`Size: ${data.length} bytes`); // Save to file await writeBundle(bundle, 'app.wvb'); ``` ### downloadVersion [#downloadversion] ```typescript const [info, bundle, data] = await remote.downloadVersion('app', '1.0.0'); console.log(`Downloaded specific version: ${info.version}`); ``` ### getInfo [#getinfo] ```typescript const info = await remote.getInfo('app'); console.log(`Current version: ${info.version}`); if (info.integrity) { console.log(`Integrity: ${info.integrity}`); } ``` ### listBundles [#listbundles] ```typescript const bundles = await remote.listBundles(); for (const bundle of bundles) { console.log(`${bundle.name}@${bundle.version}`); } ``` # SignatureAlgorithm (/docs/references/api/node/signature-algorithm) Digital signature algorithm for bundle verification. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Digital signature algorithm for bundle verification. Supports multiple signature schemes for cryptographic verification of bundle authenticity. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1430) ## Type [#type] ```ts type SignatureAlgorithm = | 'ecdsaSecp256R1' | 'ecdsaSecp384R1' | 'ed25519' | 'rsaPkcs1V15' | 'rsaPss'; ``` ## Examples [#examples] ```typescript import { Updater } from '@wvb/node'; const updater = new Updater(source, remote, { signatureVerifier: { algorithm: 'ed25519', key: { format: 'spkiPem', data: publicKeyPem, }, }, }); ``` # SignatureVerifierOptions (/docs/references/api/node/signature-verifier-options) Configuration for signature verification. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Configuration for signature verification. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1458) ## Properties [#properties] ## Examples [#examples] ```typescript const verifierOptions = { algorithm: 'ed25519', key: { format: 'spkiPem', data: publicKeyPem, }, }; ``` # SignatureVerifyingKeyOptions (/docs/references/api/node/signature-verifying-key-options) Public key configuration for signature verification. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Public key configuration for signature verification. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1484) ## Properties [#properties] ## Examples [#examples] ```typescript // PEM format (string) const pemKey = { format: 'spkiPem', data: publicKeyPem, }; // DER format (binary) const derKey = { format: 'spkiDer', data: new Uint8Array(derKeyBytes), }; ``` # UpdaterOptions (/docs/references/api/node/updater-options) Configuration options for the updater. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Configuration options for the updater. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1527) ## Properties [#properties] ## Methods [#methods] ## Examples [#examples] ```typescript const updater = new Updater(source, remote, { channel: 'stable', integrityPolicy: 'strict', signatureVerifier: { algorithm: 'ed25519', key: { format: 'spkiPem', data: publicKeyPem, }, }, }); ``` ```typescript // Custom verification functions const updater = new Updater(source, remote, { integrityChecker: async (data, integrity) => { // Custom integrity verification return true; }, signatureVerifier: async (data, signature) => { // Custom signature verification return true; }, }); ``` # Updater (/docs/references/api/node/updater) Bundle updater for managing updates from a remote server. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Bundle updater for managing updates from a remote server. The updater coordinates between a local bundle source and remote server, handling update checks, downloads, integrity verification, and signature validation. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L935) ## Constructor [#constructor] ```ts new Updater(source: BundleSource, remote: Remote, options?: UpdaterOptions | null); ``` ## Methods [#methods] ## Examples [#examples] ```typescript import { Updater, BundleSource, Remote } from '@wvb/node'; const source = new BundleSource({ builtinDir: './bundles/builtin', remoteDir: './bundles/remote', }); const remote = new Remote('https://updates.example.com'); const updater = new Updater(source, remote, { channel: 'stable', integrityPolicy: 'strict', signatureVerifier: { algorithm: 'ed25519', key: { format: 'spkiPem', data: publicKeyPem, }, }, }); // Check for updates const updateInfo = await updater.getUpdate('app'); if (updateInfo.isAvailable) { console.log(`Update available: ${updateInfo.version}`); await updater.download('app'); await updater.install('app', updateInfo.version); } ``` ### constructor [#constructor-1] ```typescript const updater = new Updater(source, remote, { channel: 'stable', integrityPolicy: 'strict', }); ``` ### download [#download] ```typescript // Download latest version const info = await updater.download('app'); console.log(`Downloaded ${info.name} v${info.version}`); ``` ```typescript // Download specific version const info = await updater.download('app', '1.2.3'); console.log(`Downloaded ${info.name} v${info.version}`); ``` ### getUpdate [#getupdate] ```typescript const updateInfo = await updater.getUpdate('app'); if (updateInfo.isAvailable) { console.log(`Update available: ${updateInfo.localVersion} → ${updateInfo.version}`); } else { console.log('Already up to date'); } ``` ### install [#install] ```typescript await updater.download('app', '1.2.0'); // ...later, active the latest version: await updater.install('app', '1.2.0'); ``` ### listRemotes [#listremotes] ```typescript const remotes = await updater.listRemotes(); for (const bundle of remotes) { console.log(`${bundle.name}: ${bundle.version}`); } ``` # VerifyingKeyFormat (/docs/references/api/node/verifying-key-format) Format of the public key used for signature verification. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Format of the public key used for signature verification. Different algorithms support different key formats. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1565) ## Type [#type] ```ts type VerifyingKeyFormat = 'spkiDer' | 'spkiPem' | 'pkcs1Der' | 'pkcs1Pem' | 'sec1' | 'raw'; ``` ## Examples [#examples] ```typescript import fs from 'fs'; // PEM format (text) const pemKey = fs.readFileSync('./public-key.pem', 'utf8'); const config1 = { format: 'spkiPem', data: pemKey, }; // DER format (binary) const derKey = fs.readFileSync('./public-key.der'); const config2 = { format: 'spkiDer', data: derKey, }; // Raw bytes (Ed25519 only) const rawKey = new Uint8Array(32); const config3 = { format: 'raw', data: rawKey, }; ``` # Version (/docs/references/api/node/version) Version — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1578) ## Type [#type] ```ts type Version = 'v1'; ``` # writeBundleIntoBuffer (/docs/references/api/node/write-bundle-into-buffer) Writes a bundle to a buffer synchronously. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Writes a bundle to a buffer synchronously. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1611) ```ts function writeBundleIntoBuffer(bundle: Bundle): Buffer; ``` ## Parameters [#parameters] ## Returns [#returns] `Buffer` — Bundle data as a buffer ## Examples [#examples] ```typescript const bundle = builder.build(); const buffer = writeBundleIntoBuffer(bundle); console.log(`Bundle size: ${buffer.length} bytes`); ``` # writeBundle (/docs/references/api/node/write-bundle) Writes a bundle to a file asynchronously. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} Writes a bundle to a file asynchronously. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/node/index.d.ts#L1596) ```ts function writeBundle(bundle: Bundle, filepath: string): Promise; ``` ## Parameters [#parameters] ## Returns [#returns] `Promise` — Number of bytes written ## Examples [#examples] ```typescript const builder = new BundleBuilder(); builder.insertEntry('/index.html', Buffer.from('')); const bundle = builder.build(); await writeBundle(bundle, 'output.wvb'); ``` # AwsKmsSignatureSignerConfig (/docs/references/api/remotes/remote-aws/aws-kms-signature-signer-config) AwsKmsSignatureSignerConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/signature.ts#L6) **Extends:** `AwsKmsClientConfigLike` ## Properties [#properties] # awsKmsSignatureSigner (/docs/references/api/remotes/remote-aws/aws-kms-signature-signer) awsKmsSignatureSigner — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/signature.ts#L11) ```ts function awsKmsSignatureSigner(config: AwsKmsSignatureSignerConfig): SignatureSignFn; ``` ## Parameters [#parameters] ## Returns [#returns] `SignatureSignFn` # AwsRemoteConfig (/docs/references/api/remotes/remote-aws/aws-remote-config) AwsRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/index.ts#L15) ## Properties [#properties] # AwsRemoteDeployerConfig (/docs/references/api/remotes/remote-aws/aws-remote-deployer-config) AwsRemoteDeployerConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/deployer.ts#L16) **Extends:** `AwsS3ClientConfigLike`, `AwsCloudFrontClientConfigLike` ## Properties [#properties] # awsRemoteDeployer (/docs/references/api/remotes/remote-aws/aws-remote-deployer) awsRemoteDeployer — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/deployer.ts#L148) ```ts function awsRemoteDeployer(config: AwsRemoteDeployerConfig): BaseRemoteDeployer; ``` ## Parameters [#parameters] ## Returns [#returns] `BaseRemoteDeployer` # AwsRemote (/docs/references/api/remotes/remote-aws/aws-remote-interface) AwsRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/index.ts#L23) ## Properties [#properties] # awsRemote (/docs/references/api/remotes/remote-aws/aws-remote) AWS remote configuration. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} AWS remote configuration. [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/index.ts#L32) ```ts function awsRemote(config: AwsRemoteConfig): AwsRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `AwsRemote` # AwsS3RemoteUploaderConfig (/docs/references/api/remotes/remote-aws/aws-s3-remote-uploader-config) AwsS3RemoteUploaderConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/uploader.ts#L12) **Extends:** `AwsS3ClientConfigLike` ## Properties [#properties] # awsS3RemoteUploader (/docs/references/api/remotes/remote-aws/aws-s3-remote-uploader) awsS3RemoteUploader — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/uploader.ts#L76) ```ts function awsS3RemoteUploader(config: AwsS3RemoteUploaderConfig): BaseRemoteUploader; ``` ## Parameters [#parameters] ## Returns [#returns] `BaseRemoteUploader` # BundleAlreadyUploadedError (/docs/references/api/remotes/remote-aws/bundle-already-uploaded-error) BundleAlreadyUploadedError — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/errors.ts#L1) **Extends:** `Error` ## Constructor [#constructor] ```ts new BundleAlreadyUploadedError(bundleName: string, version: string); ``` ## Properties [#properties] # @wvb/remote-aws (/docs/references/api/remotes/remote-aws) Webview Bundle remote configuration for AWS {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Functions [#functions] ## Interfaces [#interfaces] # isBundleAlreadyUploadedError (/docs/references/api/remotes/remote-aws/is-bundle-already-uploaded-error) isBundleAlreadyUploadedError — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws/src/errors.ts#L15) ```ts function isBundleAlreadyUploadedError(e: unknown): e is BundleAlreadyUploadedError; ``` ## Parameters [#parameters] ## Returns [#returns] `e is BundleAlreadyUploadedError` # @wvb/remote-aws-provider (/docs/references/api/remotes/remote-aws-provider) Webview Bundle remote provider for AWS {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # WebviewBundleRemoteConfig (/docs/references/api/remotes/remote-aws-provider/webview-bundle-remote-config) WebviewBundleRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider/src/remote.ts#L10) ## Properties [#properties] # WebviewBundleRemote (/docs/references/api/remotes/remote-aws-provider/webview-bundle-remote-type-alias) WebviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider/src/remote.ts#L8) ## Type [#type] ```ts type WebviewBundleRemote = Hono<{ Bindings: Bindings; Variables: Context }>; ``` # webviewBundleRemote (/docs/references/api/remotes/remote-aws-provider/webview-bundle-remote) webviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider/src/remote.ts#L18) ```ts function webviewBundleRemote(config: WebviewBundleRemoteConfig): WebviewBundleRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundleRemote` # wvbRemote (/docs/references/api/remotes/remote-aws-provider/wvb-remote) wvbRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider/src/remote.ts#L81) ```ts const wvbRemote: (config: WebviewBundleRemoteConfig) => WebviewBundleRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundleRemote` # @wvb/remote-aws-provider-pulumi (/docs/references/api/remotes/remote-aws-provider-pulumi) Webview Bundle remote pulumi configuration for AWS {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Interfaces [#interfaces] ## Variables [#variables] # WebviewBundleRemoteProviderConfig (/docs/references/api/remotes/remote-aws-provider-pulumi/webview-bundle-remote-provider-config) WebviewBundleRemoteProviderConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider-pulumi/src/provider.ts#L26) ## Properties [#properties] # WebviewBundleRemoteProvider (/docs/references/api/remotes/remote-aws-provider-pulumi/webview-bundle-remote-provider) WebviewBundleRemoteProvider — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider-pulumi/src/provider.ts#L47) **Extends:** `ComponentResource` ## Constructor [#constructor] ```ts new WebviewBundleRemoteProvider(name: string, config: WebviewBundleRemoteProviderConfig = {}, opts?: ComponentResourceOptions); ``` ## Properties [#properties] # WvbRemoteProvider (/docs/references/api/remotes/remote-aws-provider-pulumi/wvb-remote-provider) WvbRemoteProvider — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/aws-provider-pulumi/src/provider.ts#L372) **Type:** [`typeof WebviewBundleRemoteProvider`](/docs/references/api/remotes/remote-aws-provider-pulumi/webview-bundle-remote-provider) See [`typeof WebviewBundleRemoteProvider`](/docs/references/api/remotes/remote-aws-provider-pulumi/webview-bundle-remote-provider) for the full member list. # BundleAlreadyUploadedError (/docs/references/api/remotes/remote-cloudflare/bundle-already-uploaded-error) BundleAlreadyUploadedError — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} **Extends:** `Error` ## Constructor [#constructor] ```ts new BundleAlreadyUploadedError(bundleName: string, version: string); ``` ## Properties [#properties] # CloudflareRemoteConfig (/docs/references/api/remotes/remote-cloudflare/cloudflare-remote-config) CloudflareRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare/src/index.ts#L9) **Extends:** `CloudflareClientConfigLike`, `Pick` ## Properties [#properties] # CloudflareRemote (/docs/references/api/remotes/remote-cloudflare/cloudflare-remote-interface) CloudflareRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare/src/index.ts#L19) ## Properties [#properties] # cloudflareRemote (/docs/references/api/remotes/remote-cloudflare/cloudflare-remote) cloudflareRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare/src/index.ts#L24) ```ts function cloudflareRemote(config: CloudflareRemoteConfig): CloudflareRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `CloudflareRemote` # @wvb/remote-cloudflare (/docs/references/api/remotes/remote-cloudflare) Webview Bundle remote configuration for Cloudflare {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Functions [#functions] ## Interfaces [#interfaces] # isBundleAlreadyUploadedError (/docs/references/api/remotes/remote-cloudflare/is-bundle-already-uploaded-error) isBundleAlreadyUploadedError — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ```ts function isBundleAlreadyUploadedError(e: unknown): e is BundleAlreadyUploadedError; ``` ## Parameters [#parameters] ## Returns [#returns] `e is BundleAlreadyUploadedError` # Context (/docs/references/api/remotes/remote-cloudflare-provider/context) Context — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider/src/context.ts#L1) ## Properties [#properties] # @wvb/remote-cloudflare-provider (/docs/references/api/remotes/remote-cloudflare-provider) Webview Bundle remote provider for Cloudflare {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # WebviewBundleRemoteOptions (/docs/references/api/remotes/remote-cloudflare-provider/webview-bundle-remote-options) WebviewBundleRemoteOptions — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider/src/remote.ts#L10) ## Properties [#properties] # WebviewBundleRemote (/docs/references/api/remotes/remote-cloudflare-provider/webview-bundle-remote-type-alias) WebviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider/src/remote.ts#L8) ## Type [#type] ```ts type WebviewBundleRemote = Hono<{ Bindings: Context }>; ``` # webviewBundleRemote (/docs/references/api/remotes/remote-cloudflare-provider/webview-bundle-remote) webviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider/src/remote.ts#L15) ```ts function webviewBundleRemote(options: WebviewBundleRemoteOptions = {}): WebviewBundleRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundleRemote` # wvbRemote (/docs/references/api/remotes/remote-cloudflare-provider/wvb-remote) wvbRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider/src/remote.ts#L65) ```ts const wvbRemote: (options: WebviewBundleRemoteOptions = {}) => WebviewBundleRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `WebviewBundleRemote` # @wvb/remote-cloudflare-provider-pulumi (/docs/references/api/remotes/remote-cloudflare-provider-pulumi) Webview Bundle remote pulumi configuration for Cloudflare {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Classes [#classes] ## Interfaces [#interfaces] ## Variables [#variables] # WebviewBundleRemoteProviderConfig (/docs/references/api/remotes/remote-cloudflare-provider-pulumi/webview-bundle-remote-provider-config) WebviewBundleRemoteProviderConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider-pulumi/src/provider.ts#L16) ## Properties [#properties] # WebviewBundleRemoteProvider (/docs/references/api/remotes/remote-cloudflare-provider-pulumi/webview-bundle-remote-provider) WebviewBundleRemoteProvider — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider-pulumi/src/provider.ts#L26) **Extends:** `ComponentResource` ## Constructor [#constructor] ```ts new WebviewBundleRemoteProvider(name: string, config: WebviewBundleRemoteProviderConfig, opts?: ComponentResourceOptions); ``` ## Properties [#properties] # WvbRemoteProvider (/docs/references/api/remotes/remote-cloudflare-provider-pulumi/wvb-remote-provider) WvbRemoteProvider — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/cloudflare-provider-pulumi/src/provider.ts#L164) **Type:** [`typeof WebviewBundleRemoteProvider`](/docs/references/api/remotes/remote-cloudflare-provider-pulumi/webview-bundle-remote-provider) See [`typeof WebviewBundleRemoteProvider`](/docs/references/api/remotes/remote-cloudflare-provider-pulumi/webview-bundle-remote-provider) for the full member list. # @wvb/remote-local (/docs/references/api/remotes/remote-local) Webview Bundle remote config for local simulation {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] # LocalRemoteConfig (/docs/references/api/remotes/remote-local/local-remote-config) LocalRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local/src/config.ts#L7) ## Properties [#properties] # LocalRemote (/docs/references/api/remotes/remote-local/local-remote-interface) LocalRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local/src/config.ts#L14) ## Properties [#properties] # localRemote (/docs/references/api/remotes/remote-local/local-remote) localRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local/src/config.ts#L19) ```ts function localRemote(config: LocalRemoteConfig): LocalRemote; ``` ## Parameters [#parameters] ## Returns [#returns] `LocalRemote` # @wvb/remote-local-provider (/docs/references/api/remotes/remote-local-provider) Webview Bundle remote provider for local simulation {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} ## Functions [#functions] ## Interfaces [#interfaces] ## Type Aliases [#type-aliases] ## Variables [#variables] # WebviewBundleRemoteConfig (/docs/references/api/remotes/remote-local-provider/webview-bundle-remote-config) WebviewBundleRemoteConfig — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local-provider/src/remote.ts#L24) ## Properties [#properties] # WebviewBundleRemote (/docs/references/api/remotes/remote-local-provider/webview-bundle-remote-type-alias) WebviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local-provider/src/remote.ts#L22) ## Type [#type] ```ts type WebviewBundleRemote = Hono; ``` # webviewBundleRemote (/docs/references/api/remotes/remote-local-provider/webview-bundle-remote) webviewBundleRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local-provider/src/remote.ts#L34) ```ts function webviewBundleRemote( __namedParameters: WebviewBundleRemoteConfig ): Hono; ``` ## Parameters [#parameters] ## Returns [#returns] `Hono` # wvbRemote (/docs/references/api/remotes/remote-local-provider/wvb-remote) wvbRemote — API reference. {/* This page is auto-generated from TypeScript + JSDoc by scripts/generate-references.ts — do not edit by hand. */} [View source ↗](https://github.com/webview-bundle/webview-bundle/blob/262b4d90c5f036ab9d52086913752b990875ac84/packages/remote/local-provider/src/remote.ts#L118) ```ts const wvbRemote: (__namedParameters: WebviewBundleRemoteConfig) => Hono; ``` ## Parameters [#parameters] ## Returns [#returns] `Hono` # wvb builtin (/docs/references/cli/builtin) Install builtin webview bundles into your app from a remote or local target. `wvb builtin` installs bundles into an output directory so your app can ship them as builtin fallbacks. When the app starts offline, or before it has fetched a newer bundle over the air, it serves these builtin bundles. The command pulls from the source defined by `builtin.target` in your [config](/docs/references/configuration), which defaults to a remote target. The command writes a `manifest.json` describing the installed set, plus one file per bundle laid out as `/_.wvb`. For how builtin and remote sources work together, see [Bundle sources](/docs/guide/core-concepts/bundle-source). ## Usage [#usage] ```sh # Install from the configured target into the default directory wvb builtin # Install from a remote endpoint into an explicit directory wvb builtin --endpoint https://updates.example.com --out .wvb/builtin/bundles # Filter which bundles get installed wvb builtin --include 'app*' --exclude 'internal*' # Install into the detected Android module wvb builtin --android # Dry run: report what would be installed without writing wvb builtin --no-write ``` ## Options [#options] | Option | Aliases | Default | Description | | --------------- | ------- | ---------------------- | --------------------------------------------------------------------------------------- | | `--out` | `-O` | `.wvb/builtin/bundles` | Output directory. A mobile preset changes this to the platform module directory. | | `--endpoint` | `-E` | `remote.endpoint` | Remote endpoint to pull from. Remote target only. | | `--channel` | — | — | Release channel to install from. Remote target only. | | `--include` | — | — | Glob include patterns over the target bundles. Repeatable. | | `--exclude` | — | — | Glob exclude patterns over the target bundles. Repeatable. | | `--clean` | — | `true` | Clear the output directory before installing. Pass `--no-clean` to keep existing files. | | `--concurrency` | — | CPU count, capped at 8 | Number of parallel downloads. Remote target only. | | `--android` | — | — | Mobile preset. Bare auto-detects the app module; `--android=` sets it explicitly. | | `--ios` | — | — | Mobile preset. Bare auto-detects the project; `--ios=` sets it explicitly. | | `--write` | — | `true` | Write the installed files. Pass `--no-write` for a dry run. | | `--progress` | — | `true` | Show a download progress bar. Remote target only. | | `--config` | `-C` | (auto-discovery) | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | Boolean flags accept `--flag`, `--flag=true|false`, and a `--no-flag` negation, so `--no-write` and `--no-clean` turn off the `--write` and `--clean` defaults. ## Mobile presets [#mobile-presets] `--android` and `--ios` install bundles into a platform project instead of a plain directory. Each can be passed bare to auto-detect the target, or as `--android=` / `--ios=` to point at an explicit module or project directory. The `--ios` preset adds a `folderReference` to `Project.swift`, which applies to Tuist projects. You cannot pass both `--android` and `--ios` in the same run. ## Notes [#notes] * The target type comes from `builtin.target` in your [config](/docs/references/configuration), a discriminated union of `remote` and `local`. It defaults to a remote target. * `--endpoint`, `--channel`, `--concurrency`, and `--progress` apply to the remote target only. * A successful run writes a `manifest.json` and one `/_.wvb` file per installed bundle. # Environment Variables (/docs/references/cli/environment) This page is a work in progress. # Overview (/docs/references/cli) The wvb command-line tool packs your web assets into .wvb bundles and drives the full upload, deploy, and download workflow. The `wvb` command-line tool packs your built web assets into `.wvb` bundles and drives the full remote update workflow: upload, deploy, download, and inspect bundles on a remote server. It ships in the `@wvb/cli` package and exposes two equivalent binaries, `wvb` and `webview-bundle`. Install it as a dev dependency: ```sh npm install -D @wvb/cli npx wvb --help ``` ```sh pnpm add -D @wvb/cli pnpm wvb --help ``` ```sh yarn add -D @wvb/cli yarn wvb --help ``` Most commands read their defaults from a [`wvb.config`](/docs/references/configuration) file discovered in the working directory, so a typical project runs `wvb pack` or `wvb upload` with no arguments at all. Each command has its own page with the full option reference. To call the same logic from JavaScript, see the [programmatic API](/docs/references/cli/programmatic). ## Global flags [#global-flags] Three flags apply to every command. They control output formatting and logging only. | Flag | Values / type | Default | Env | Description | | --------------- | ----------------------------------------- | ------- | ----------- | -------------------------------------------------------------- | | `--color` | `off` \| `on` \| `auto` | `auto` | `COLOR` | Color mode for output. `auto` enables color on a TTY or in CI. | | `--log-level` | `debug` \| `info` \| `warning` \| `error` | `info` | `LOG_LEVEL` | Minimum log level to print. | | `--log-verbose` | boolean | `false` | — | Verbose logging with timestamps and categories. | `--config` (`-C`) and `--cwd` are **not** global. They are declared per command and are present on most of them. `extract` accepts `--cwd` but has no `--config`, and `remote local` accepts neither. Where present, `--config ` points at a specific config file and `--cwd ` changes the directory used to resolve paths. Boolean flags accept `--flag`, `--flag=true|false`, and a `--no-flag` negation. For example, `--no-write` and `--no-pack` turn off the `--write` and `--pack` defaults. ## Config file discovery [#config-file-discovery] Commands load defaults from a `wvb.config` file in the working directory. Pass `--config ` to point at a specific file; otherwise `wvb` searches for the first matching file in this order: ```text wvb.config.js wvb.config.cjs wvb.config.mjs wvb.config.ts wvb.config.cts wvb.config.mts webview-bundle.config.js webview-bundle.config.cjs webview-bundle.config.mjs webview-bundle.config.ts webview-bundle.config.cts webview-bundle.config.mts wvb.config.json wvb.config.jsonc ``` Both the `wvb.config` and `webview-bundle.config` base names support the `.js`, `.cjs`, `.mjs`, `.ts`, `.cts`, and `.mts` extensions. The `.json` and `.jsonc` extensions are supported for the `wvb.config` base name only. See [Configuration](/docs/references/configuration) for the full schema. ## Commands [#commands] # Installation (/docs/references/cli/installation) Install the @wvb/cli package and run the wvb command-line tool. The command-line tool ships in the [`@wvb/cli`](/docs/references/api/cli) package. It exposes two equivalent binaries, `wvb` and `webview-bundle` — use whichever reads better in your scripts. ## Requirements [#requirements] * **Node.js 18.14.1 or later.** Node 19 is supported from 19.7.0; Node 20 and newer work without restriction. * The package is ESM-only. It runs from any project regardless of whether your own code is ESM or CommonJS. ## Install [#install] Add `@wvb/cli` as a dev dependency — it is a build-time tool, not a runtime dependency of your app. ```sh npm install -D @wvb/cli ``` ```sh pnpm add -D @wvb/cli ``` ```sh yarn add -D @wvb/cli ``` ## Run [#run] Invoke the binary through your package manager so it resolves from `node_modules`: ```sh npx wvb --help ``` ```sh pnpm wvb --help ``` ```sh yarn wvb --help ``` Add commands to your `package.json` scripts for repeatable builds: ```json title="package.json" { "scripts": { "bundle": "wvb pack", "bundle:deploy": "wvb upload && wvb deploy" } } ``` Prefer a project-local install over a global one. It pins the CLI version alongside your other dev dependencies, so every machine and CI run uses the same version. ## Verify [#verify] Print the installed version to confirm the binary resolves: ```sh npx wvb --version ``` ## Next steps [#next-steps] * Create a [`wvb.config`](/docs/references/configuration) file so commands run with no arguments. * Browse every command on the [CLI overview](/docs/references/cli). * Call the same logic from JavaScript with the [programmatic API](/docs/references/cli/programmatic). # wvb pack (/docs/references/cli/pack) Pack a directory of built web assets into a single compressed, integrity-checked .wvb archive. `wvb pack` packs a directory of built web assets (HTML, JS, CSS, media) into a single `.wvb` archive. The archive is compressed and checksummed. It is the unit your app ships and serves to its webview, or uploads to a remote for over-the-air (OTA) updates. Most projects run `wvb pack` with no arguments. The source directory, output path, and other defaults come from the [`wvb.config`](/docs/references/configuration) file discovered in the working directory. ## Usage [#usage] ```sh wvb pack [SRC_DIR] ``` Pack the default source directory, then pack an explicit directory to a chosen output path: ```sh wvb pack # uses config defaults wvb pack ./dist wvb pack ./dist --outfile ./build/app.wvb ``` Exclude files with repeatable `--ignore` globs: ```sh wvb pack ./dist --ignore '*.map' --ignore 'node_modules/**' ``` Attach response headers to matching files with `--header`, which takes three values per use: ```sh wvb pack ./dist --header '*.html' 'cache-control' 'max-age=3600' ``` Do a dry run that reports what would be packed without writing the archive: ```sh wvb pack ./dist --no-write ``` ## Options [#options] | Option | Aliases | Default | Description | | ------------- | ------------------ | ------------------------- | --------------------------------------------------------------------------- | | `SRC_DIR` | — | `pack.srcDir` ?? `./dist` | Source directory to pack. | | `--outfile` | `--out-file`, `-O` | `.wvb/` | Output path. `.wvb` is appended if missing. | | `--ignore` | — | — | Glob of files to exclude. Repeatable. | | `--header` | `-H` | — | Set headers on matching files: `--header `. Repeatable. | | `--no-write` | — | writes by default | Run the pack without writing the archive (dry run). | | `--overwrite` | — | `true` | Overwrite an existing output file. | These flags also accept the common per-command `--config` (`-C`) and `--cwd` options. See the [CLI overview](/docs/references/cli) for how config discovery and global flags work. `pack` has no `--outdir` flag. The output directory is determined by `--outfile`; the default resolves to `.wvb/`, where the name comes from the nearest `package.json` with its scope stripped. Boolean flags accept `--flag`, `--flag=true|false`, and a `--no-flag` negation. For example, `--no-write` turns off the default `--write` behavior, and `--no-overwrite` keeps an existing output file in place. ## Configuration [#configuration] Set `pack` defaults in your [`wvb.config`](/docs/references/configuration) file so the command runs cleanly with no arguments. The config field for the output path is `outFile` (a single path; `.wvb` is appended automatically), and `overwrite` defaults to `true`. A flag passed on the command line always wins over the config value. # Programmatically Usage (/docs/references/cli/programmatic) Embed the wvb CLI in scripts and CI with @wvb/cli/api, and load the wvb config file from your own code. Every `wvb` command is also a function. The `@wvb/cli` package ships a programmatic API at `@wvb/cli/api` that exposes the same packing, extracting, serving, uploading, and local-remote logic the CLI runs, so you can drive Webview Bundle from build scripts, test harnesses, or CI without shelling out. The main `@wvb/cli` entry separately exposes the config helpers — `defineConfig`, `loadConfigFile`, and `resolveConfig` — so your tooling can read and resolve a `wvb.config` file the same way the CLI does. Install `@wvb/cli` as a dependency of the script or workspace that needs it. ```sh npm install --save-dev @wvb/cli ``` ```sh pnpm add -D @wvb/cli ``` ```sh yarn add -D @wvb/cli ``` Prefer the API over spawning the `wvb` binary when you need return values (the packed `Bundle`, a running server handle) or want to keep everything inside one Node process. For the command-line surface, see the [CLI reference](/docs/references/cli). ## The `/api` exports [#the-api-exports] Import the functions from `@wvb/cli/api`. Each function takes a single options object and returns a promise. Failures throw an `ApiError`. | Function | Signature | | -------------- | ---------------------------------------------------------------------- | | `pack` | `pack(params: PackParams): Promise` | | `extract` | `extract(params: ExtractParams): Promise` | | `serve` | `serve(params: ServeParams): Promise` | | `remoteUpload` | `remoteUpload(params: RemoteUploadParams): Promise` | | `builtin` | `builtin(params: BuiltinParams): Promise` | | `localRemote` | `localRemote(params: LocalRemoteParams): Promise` | The `/api` surface is intentionally CLI-adjacent, not a full client. There are no `deploy` or `download` functions here — those commands live only on the CLI, which talks to a remote through the `Remote` class from [`@wvb/node`](/docs/references/api/node). ### pack [#pack] Pack a source directory into a `.wvb` archive. The `.wvb` extension is appended to `outFile` automatically if you leave it off. ```ts import { pack } from '@wvb/cli/api'; const result = await pack({ srcDir: './dist', outFile: './.wvb/app', // becomes ./.wvb/app.wvb write: true, // default true; set false to pack in memory only overwrite: true, // default true }); console.log(result.outFilePath); // absolute path to the written .wvb console.log(result.bundle); // the in-memory Bundle ``` `PackParams` accepts `srcDir`, `outFile`, optional `ignores` and `headers` (the same shapes as the config file), `write` (default `true`), `overwrite` (default `true`), `cwd` (default `process.cwd()`), `logLevel` (default `'info'`), and an optional `logger`. The returned `PackResult` has `outFilePath` and `bundle` (a `Bundle` from `@wvb/node`). ### extract [#extract] Read a `.wvb` file and write its entries to a directory. ```ts import { extract } from '@wvb/cli/api'; const bundle = await extract({ file: './.wvb/app.wvb', outDir: './extracted', // defaults to .wvb/ when omitted clean: true, // default false; remove outDir first }); ``` `ExtractParams` accepts `file` (required), optional `outDir`, `cwd`, `write` (default `true`), `clean` (default `false`), and a `logger`. It returns the parsed `Bundle`. ### serve [#serve] Start a localhost server that serves a bundle to a webview. Directory paths resolve to `index.html`. ```ts import { serve } from '@wvb/cli/api'; const instance = await serve({ file: './.wvb/app.wvb', port: 4312, // default 4312 silent: false, // default false; true disables request logging }); // ... later await instance.shutdown(); ``` `ServeParams` accepts `file` (required), optional `hostname`, `port` (default `4312`), `silent` (default `false`), `cwd`, `logger`, and `colorEnabled`. It returns a `ServeInstance` with the raw `server` and a `shutdown()` method. ### remoteUpload [#remoteupload] Upload a packed bundle to a remote. Pass a file path or an in-memory `Bundle`, plus an `uploader` from your remote configuration. ```ts import { pack, remoteUpload } from '@wvb/cli/api'; import { loadConfigFile } from '@wvb/cli'; const config = await loadConfigFile(); const { bundle } = await pack({ srcDir: './dist', outFile: './.wvb/app' }); await remoteUpload({ file: bundle, bundleName: 'app', version: '1.2.0', uploader: config.remote.uploader, integrity: true, // default true }); ``` `RemoteUploadParams` accepts `file` (a path or `Bundle`), `bundleName`, `version`, and `uploader` (a `BaseRemoteUploader`). Optional fields are `force`, `integrity` (default `true`; pass an integrity config to customize), `signature`, `logger`, and `cwd`. Integrity uses SHA-2 (`sha256` by default). The signature, when provided, signs the integrity string bytes — see [Remote bundles](/docs/guide/core-concepts/over-the-air) for how integrity and signatures fit together. ### builtin [#builtin] Install builtin bundles into your app from a remote or local target. ```ts import { builtin } from '@wvb/cli/api'; const result = await builtin({ target: { type: 'remote' }, // discriminated union: 'remote' | 'local' dir: './.wvb/builtin/bundles', clean: true, // default true }); console.log(result.manifest); ``` `BuiltinParams` accepts `target` (a `BuiltinTarget` discriminated union keyed by `type`), optional `dir` (default `'.wvb/builtin/bundles'`), `include`/`exclude` match lists, `channel`, `clean` (default `true`), `cwd`, `write` (default `true`), `logLevel`, `logger`, `progress`, and the mobile presets `android` and `ios`. It returns a `BuiltinResult` whose `manifest` describes the installed bundles. ### localRemote [#localremote] Start a local remote server for development. This mirrors the `wvb remote local` command and dynamically imports the optional peer dependency `@wvb/remote-local-provider`, so make sure that package is installed. ```ts import { localRemote } from '@wvb/cli/api'; const instance = await localRemote({ baseDir: '~/.wvb/local', port: 4313, // default 4313 allowOtherVersions: false, }); // ... later await instance.shutdown(); ``` `LocalRemoteParams` accepts optional `baseDir` (the provider resolves `~/.wvb/local` by default), `hostname`, `port` (default `4313`), `silent` (default `false`), `allowOtherVersions`, `logger`, and `colorEnabled`. It returns a `LocalRemoteInstance` with the raw `server` and `shutdown()`. `@wvb/remote-local-provider` is an optional peer dependency. If it is not installed, `localRemote` throws when it tries to import it. Add it alongside `@wvb/cli` when you use local remotes. ## Config helpers from the main entry [#config-helpers-from-the-main-entry] The default `@wvb/cli` entry (not `/api`) re-exports the config tooling. It surfaces `defineConfig` from [`@wvb/config`](/docs/references/configuration), plus `loadConfigFile` and `resolveConfig`, and the `InlineConfig` and `ResolvedConfig` types. ```ts import { defineConfig, loadConfigFile, resolveConfig, type InlineConfig, type ResolvedConfig, } from '@wvb/cli'; // Discover and load wvb.config.* from the current directory. const config: ResolvedConfig = await loadConfigFile(); // Or load an explicit file and merge inline overrides on top. const inline: InlineConfig = { root: process.cwd() }; const merged = await resolveConfig(inline); ``` `loadConfigFile` finds and bundles the config file, then resolves it. `resolveConfig` merges a file config under your inline config, sets `root` (default `process.cwd()`), attaches the nearest `package.json`, and returns a readonly `ResolvedConfig`. Use `defineConfig` inside the config file itself to get full type inference. ## Config discovery [#config-discovery] When you call `loadConfigFile` without an explicit path — and when the CLI runs without `--config` — Webview Bundle searches the working directory for the first matching file in this order: ```text wvb.config.js wvb.config.cjs wvb.config.mjs wvb.config.ts wvb.config.cts wvb.config.mts webview-bundle.config.js webview-bundle.config.cjs webview-bundle.config.mjs webview-bundle.config.ts webview-bundle.config.cts webview-bundle.config.mts wvb.config.json wvb.config.jsonc ``` Both base names — `wvb.config.*` and `webview-bundle.config.*` — support the `.js`, `.cjs`, `.mjs`, `.ts`, `.cts`, and `.mts` extensions. The `.json` and `.jsonc` extensions are supported only for the `wvb.config` base name. Pass `--config`, `-C` (or call `loadConfigFile` with an explicit path) to bypass discovery. Config files are bundled with `rolldown` before they run, so TypeScript and ESM/CJS files load without a separate build step. Bare and `npm:` specifiers and Node builtins stay external. Under Deno, config files are always treated as ESM — the loader skips the package-type and extension sniffing it uses on Node. Deno Desktop support is experimental; see the [Deno guide](/docs/guide/native/deno). # wvb deploy (/docs/references/cli/remote-deploy) Mark an already-uploaded bundle version as the current one that clients receive. `wvb deploy` promotes a bundle version that is already on the remote to be the current version. Clients that download the bundle then receive that version. Uploading a bundle stores it on the remote but does not make it current — deploy is the step that flips the switch. Run it after [`wvb upload`](/docs/references/cli/remote-upload), or pass `--deploy` to `upload` to combine both steps in one command. ## Usage [#usage] ```sh wvb deploy app --version 1.2.0 wvb deploy app --version 1.2.0 --channel beta wvb deploy # uses config / package.json defaults ``` The bundle name is the positional `BUNDLE` argument and falls back to the resolved name from your config or `package.json`. The version is the `--version` (`-V`) flag — there is no positional version argument. ## Options [#options] | Option | Aliases | Default | Description | | ----------- | ------- | -------------------------------- | -------------------------------------- | | `BUNDLE` | — | resolved from config | Bundle name to deploy. | | `--version` | `-V` | config or `package.json` version | Version to mark as current. | | `--channel` | — | — | Release channel to deploy to. | | `--config` | `-C` | config auto-discovery | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | The global flags `--color`, `--log-level`, and `--log-verbose` also apply. See the [CLI overview](/docs/references/cli) for details. ## Requirements [#requirements] `deploy` requires `remote.deployer` in your [config](/docs/references/configuration/remote). The deployer is the component that records which version is current on the remote, so you cannot deploy to a remote without one. The version is the `--version` (`-V`) flag, not a positional argument. If you omit it, deploy uses the version resolved from your config or the nearest `package.json`. # wvb download (/docs/references/cli/remote-download) Download a bundle from a remote server to disk, or fetch and print its metadata. `wvb download` fetches a bundle from a remote server and, by default, saves it to disk as a `.wvb` file. Pass a bundle name and an optional version; omit it to download the version that is currently deployed. This is the read side of the publishing workflow that `wvb upload` and `wvb deploy` drive, and it is handy for verifying what a remote actually serves. ## Usage [#usage] ```sh wvb download app --endpoint https://updates.example.com wvb download app 1.2.0 --out ./bundles/app.wvb --overwrite wvb download app --no-write ``` The first example downloads the current deployed version of `app` to `app.wvb` in the working directory. The second downloads a specific version (`1.2.0`) to an explicit path, overwriting any existing file. The third fetches the bundle and prints its information without writing anything to disk. The bundle name and the endpoint both fall back to your [`wvb.config`](/docs/references/configuration/remote) file, so inside a configured project you can usually run `wvb download` with no flags to pull the current version. ## Options [#options] | Option | Aliases | Default | Description | | ------------- | ------- | ------------------- | ----------------------------------------------------------------------------- | | `BUNDLE` | — | from config | Bundle name (positional). Resolves from config when omitted. | | `VERSION` | — | current deployed | Specific version (positional). Omit to download the current deployed version. | | `--out` | `-O` | `.wvb` | Output file path. | | `--endpoint` | `-E` | `remote.endpoint` | Remote endpoint to download from. | | `--channel` | — | — | Release channel. | | `--write` | — | `true` | Write the bundle to disk. Pass `--no-write` to fetch and print info only. | | `--overwrite` | — | `false` | Overwrite an existing output file. | | `--progress` | — | `true` | Show a download progress bar. Pass `--no-progress` to disable. | | `--config` | `-C` | auto-discovery | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | Boolean flags accept `--flag`, `--flag=true|false`, and a `--no-flag` negation. The three global flags (`--color`, `--log-level`, `--log-verbose`) apply here too; see the [CLI overview](/docs/references/cli). With a version positional, `wvb download` requests that exact version; without one, it downloads the current deployed version for the given channel. Serving a non-current version requires the remote to allow other versions. `--no-write` fetches the bundle and prints its information without saving a file. Use it to inspect what a remote serves without touching disk. To see metadata without downloading the bundle body at all, use [`wvb remote current`](/docs/references/cli/remote) instead. # wvb upload (/docs/references/cli/remote-upload) Pack, hash, sign, and upload a bundle to the configured remote, with an optional deploy step. `wvb upload` publishes a bundle to your remote server. By default it runs the full pipeline in order — pack, then integrity, then signature, then upload — so a single command turns your built assets into a signed, integrity-checked bundle on the remote. The upload step requires `remote.uploader` in your [config](/docs/references/configuration/remote); the optional deploy step at the end also requires `remote.deployer`. ```sh wvb upload # uses config defaults wvb upload app --version 1.2.0 wvb upload app --version 1.2.0 --deploy --channel beta wvb upload --no-pack --file ./build/app.wvb --force ``` ## Options [#options] | Option | Aliases | Default | Description | | ------------------ | ------- | -------------------------------- | ------------------------------------------------------------------- | | `BUNDLE` | — | from config / `--file` name | Bundle name. Positional argument. | | `--version` | `-V` | config or `package.json` version | Version to publish. | | `--file` | `-F` | resolved output path | Path to the `.wvb` to upload. | | `--force` | — | `false` | Overwrite if the version already exists on the remote. | | `--deploy` | — | `false` | Deploy the version after uploading. | | `--channel` | — | — | Channel to deploy to. Used with `--deploy`. | | `--pack` | `-P` | `true` | Pack from `pack.srcDir` before uploading. Pass `--no-pack` to skip. | | `--skip-integrity` | — | `false` | Skip computing the integrity hash. | | `--skip-signature` | — | `false` | Skip signing the bundle. | | `--config` | `-C` | config auto-discovery | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | The version is the `--version` (`-V`) flag, not a positional argument. The first positional is the bundle name. `--deploy` defaults to `false`, so an upload publishes the version without making it current — clients keep receiving the previously deployed version until you deploy this one. ## Pipeline [#pipeline] `wvb upload` runs these stages in order: 1. **Pack** — packs `pack.srcDir` into a `.wvb` archive. Skip with `--no-pack` and pass an existing bundle through `--file`. 2. **Integrity** — computes the integrity hash. Skip with `--skip-integrity`. 3. **Signature** — signs the bundle. Skip with `--skip-signature`. 4. **Upload** — sends the bundle to the remote through `remote.uploader`. 5. **Deploy** (optional) — runs only with `--deploy`, marking the uploaded version current through `remote.deployer`. On success the command prints the bundle endpoint. ## Requirements [#requirements] * `remote.uploader` must be configured for the upload step. See [Remote, integrity & signature config](/docs/references/configuration/remote). * `remote.deployer` is additionally required when you pass `--deploy`. To deploy a version separately later, use [`wvb deploy`](/docs/references/cli/remote-deploy). For the publishing model and a local-testing walkthrough, see [Building a remote](/docs/guide/remote). # wvb remote (/docs/references/cli/remote) Inspect and test a remote — show the current deployed bundle, list available bundles, and run a local update server. The `wvb remote` command group inspects and tests a remote update server. Use it to see which version is currently deployed, list every bundle the remote knows about, and run a local server that mirrors the production HTTP contract so you can exercise the full update loop offline. It groups three subcommands: * [`wvb remote current`](#wvb-remote-current-bundle) — show the current deployed version and its metadata. * [`wvb remote list`](#wvb-remote-list) — list every bundle available on the remote (alias `wvb remote ls`). * [`wvb remote local`](#wvb-remote-local) — start a local update server backed by a directory. The first two read `remote.endpoint` from your [config](/docs/references/configuration/remote) by default, so you can drop the `--endpoint` flag once a remote is configured. For the publishing model and a local-testing walkthrough, see [Building a remote](/docs/guide/remote). ## wvb remote current \[BUNDLE] [#wvb-remote-current-bundle] Show the current deployed version and its metadata for a bundle, without downloading the bundle itself. The output includes the version, ETag, integrity, signature, and last-modified values reported by the remote. ```sh wvb remote current app --endpoint https://updates.example.com wvb remote current app --channel beta wvb remote current # uses config defaults ``` | Option | Aliases | Default | Description | | ------------ | ------- | --------------------- | -------------------------------------------- | | `BUNDLE` | — | resolved from config | Bundle name. Falls back to the package name. | | `--endpoint` | `-E` | `remote.endpoint` | Remote endpoint to query. | | `--channel` | — | — | Release channel. | | `--config` | `-C` | config auto-discovery | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | ## wvb remote list [#wvb-remote-list] List every bundle available on the remote. The command also has the alias `wvb remote ls`. Output is JSON, so it pipes cleanly into other tools. ```sh wvb remote list --endpoint https://updates.example.com wvb remote ls --channel beta wvb remote list | jq '.[].name' ``` | Option | Aliases | Default | Description | | ------------ | ------- | --------------------- | -------------------------------------- | | `--endpoint` | `-E` | `remote.endpoint` | Remote endpoint to query. | | `--channel` | — | — | Release channel. | | `--config` | `-C` | config auto-discovery | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | ## wvb remote local [#wvb-remote-local] Start a local update server backed by a directory. It implements the same HTTP contract as a production remote, so you can test the full update loop offline before wiring in a hosted [provider](/docs/guide/remote/providers/local). The server defaults to serving `~/.wvb/local` on port `4313`. ```sh wvb remote local # http://localhost:4313, serving ~/.wvb/local wvb remote local --base-dir ./.wvb/local --port 4313 wvb remote local --allow-other-versions --hostname 0.0.0.0 ``` | Option | Aliases | Default | Env | Description | | ------------------------ | ------- | -------------- | ---------- | ------------------------------------------ | | `--base-dir` | — | `~/.wvb/local` | — | Directory to serve. | | `--allow-other-versions` | — | `false` | — | Allow serving versions other than current. | | `--hostname` | `-H` | `localhost` | `HOSTNAME` | Bind hostname. | | `--port` | `-P` | `4313` | `PORT` | Port to listen on. | | `--silent` | — | `false` | — | Disable request logging. | `remote local` requires the optional `@wvb/remote-local-provider` package, which the command imports on demand. Unlike the other subcommands, it does not read `--config` or `--cwd`. The server stops cleanly on `SIGINT` or `SIGTERM`. By default the local server only serves the version marked current for each bundle. Pass `--allow-other-versions` to also serve specific older versions, which is useful for testing rollbacks and version pinning. # wvb serve (/docs/references/cli/serve) Serve a single .wvb bundle's files over HTTP to preview a packed bundle in a browser. `wvb serve` starts a local HTTP server that unpacks one `.wvb` bundle and serves its files, so you can open a packed bundle in a browser and check it before shipping. Directory paths resolve to `index.html`, matching how a webview loads the bundle at runtime. By default the server listens on `http://localhost:4312`. It handles `SIGINT` and `SIGTERM` for a graceful shutdown, so `Ctrl+C` stops it cleanly. `wvb serve` previews the contents of a single bundle. To test the full over-the-air (OTA) update loop against an HTTP remote, run a local update server with [`wvb remote local`](/docs/references/cli/remote) instead. See [Building a remote](/docs/guide/remote) for the end-to-end walkthrough. ## Usage [#usage] ```sh wvb serve # serve the bundle resolved from config wvb serve ./build/app.wvb # http://localhost:4312 wvb serve ./build/app.wvb --port 8080 --hostname 0.0.0.0 wvb serve ./build/app.wvb --silent # disable request logging ``` If you omit `FILE`, `wvb serve` falls back to `serve.file` in your [config](/docs/references/configuration), and then to the resolved pack output path. A typical project that has run `wvb pack` can preview with a bare `wvb serve`. ## Options [#options] | Option | Aliases | Default | Description | | ------------ | ------- | --------------- | --------------------------------------------------------------------------- | | `FILE` | — | from config | Bundle to serve. Falls back to `serve.file`, then the resolved pack output. | | `--hostname` | `-H` | `localhost` | Bind hostname. Reads the `HOSTNAME` env var. | | `--port` | `-P` | `4312` | Port to listen on. Reads the `PORT` env var. Must be between 1 and 65535. | | `--silent` | — | `false` | Disable the request-logging middleware. | | `--config` | `-C` | — | Path to the config file. | | `--cwd` | — | `process.cwd()` | Working directory for resolving paths. | Boolean flags accept `--silent`, `--silent=true|false`, and the `--no-silent` negation. The global `--color`, `--log-level`, and `--log-verbose` flags apply here as well; see the [CLI overview](/docs/references/cli). ## Notes [#notes] * The server resolves directory requests to `index.html`, so client-side routes that map to a directory load the bundle's entry document. * `--hostname 0.0.0.0` binds all interfaces, which is useful for previewing the bundle from another device on your network. * To call the same logic from JavaScript, use the `serve` function in the [programmatic API](/docs/references/cli/programmatic). # wvb extract (/docs/references/cli/unpack) Unpack a .wvb archive's files back onto disk to inspect what a bundle contains. `wvb extract` reads a `.wvb` archive and writes its files back onto disk. Use it to inspect what a bundle ships, diff two bundles, or recover the assets that went into one. ## Usage [#usage] Pass the bundle file to extract. The command writes the unpacked files under an output directory, defaulting to `.wvb/`. ```sh wvb extract ./build/app.wvb wvb extract ./build/app.wvb --outdir ./unpacked wvb extract ./build/app.wvb --outdir ./unpacked --clean ``` Pass `--no-write` to run the extraction without touching disk, which is useful for verifying that a bundle reads cleanly: ```sh wvb extract ./build/app.wvb --no-write ``` ## Options [#options] | Option | Aliases | Default | Description | | ---------- | ------- | ------------------------------ | ---------------------------------------------------------------- | | `FILE` | — | required | Bundle file to extract. | | `--outdir` | `-O` | `.wvb/` | Destination directory for the unpacked files. | | `--clean` | — | `false` | Remove the output directory first if it exists. | | `--write` | — | `true` | Pass `--no-write` to simulate the extract without writing files. | | `--cwd` | — | `process.cwd()` | Working directory used to resolve paths. | `wvb extract` has no `--config` flag. It reads only the bundle file you pass and the flags above; it does not load a `wvb.config` file. It does accept `--cwd` to resolve relative paths. The global `--color`, `--log-level`, and `--log-verbose` flags apply here as they do on every command. Boolean flags accept `--flag`, `--flag=true|false`, and a `--no-flag` negation, so `--no-write` turns off the default `--write` behavior. # builtin (/docs/references/configuration/builtin) The builtin section of wvb.config — install bundles that ship inside your app from a remote or local workspaces. `builtin` (`BuiltinConfig`) sets the defaults for [`wvb builtin`](/docs/references/cli/builtin), which installs bundles that ship inside your app — either downloaded from a remote or collected from local workspaces. ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig({ builtin: { outDir: '.wvb/builtin/bundles', target: { type: 'remote' }, include: ['app*'], exclude: [/^internal-/], clean: true, }, }); ``` | Field | Type | Default | | --------- | -------------------------------------------------------------------- | ---------------------- | | `outDir` | `string` | `.wvb/builtin/bundles` | | `target` | `BuiltinTarget` | `{ type: 'remote' }` | | `include` | `string \| RegExp \| Array \| ((info) => boolean)` | — | | `exclude` | `string \| RegExp \| Array \| ((info) => boolean)` | — | | `clean` | `boolean` | `true` | `include` and `exclude` filter the candidate bundles. Each accepts a glob string, a regular expression, an array of either, or a predicate `(info: { name: string; version: string }) => boolean` (optionally async). With `clean` enabled, the output directory is cleared before install. ## target [#target] `target` is a discriminated union on `type`. Choose `remote` to download bundles from a server, or `local` to collect them from workspaces in your repository. ```ts // Remote target — download from a server target: { type: 'remote', endpoint: 'https://updates.example.com', download: { concurrency: 4, // http: { /* HttpOptions from @wvb/node */ }, }, } // Local target — collect from workspaces target: { type: 'local', workspaces: ['packages/*'], bundleName: { from: 'package.json' }, version: { from: 'package.json' }, packBeforeInstall: true, } ``` For the `remote` target, `endpoint` and `download` are optional. The only concurrency knob is `download.concurrency`; `download.http` accepts the `HttpOptions` type from [`@wvb/node`](/docs/references/api/node). | `remote` field | Type | Default | | ---------------------- | ------------- | ------- | | `endpoint` | `string` | — | | `download.concurrency` | `number` | — | | `download.http` | `HttpOptions` | — | For the `local` target, `workspaces` is required — it is the only required field anywhere in the config. The `integrity` and `signature` options share the same shapes as the remote section; see [Remote, integrity & signature](/docs/references/configuration/remote). | `local` field | Type | Default | | ------------------- | --------------------------------------------------- | -------- | | `workspaces` | `string[] \| (() => string[] \| Promise)` | required | | `bundleName` | `BundleNameResolver` | — | | `version` | `VersionResolver` | — | | `integrity` | `boolean \| IntegrityMakeConfig` | — | | `signature` | `SignatureSignConfig` | — | | `packBeforeInstall` | `boolean` | `true` | # Configuration (/docs/references/configuration) The wvb.config file that the CLI and the programmatic API read for pack, remote, serve, and builtin options. A single `wvb.config` file drives every Webview Bundle workflow. Both the `wvb` CLI and the programmatic API (`@wvb/cli/api`) load it, so one config keeps packing, serving, remote publishing, and builtin installs consistent. Author it with `defineConfig` from `@wvb/config` to get full type-checking and editor autocompletion. Each top-level section has its own page: ## The config file [#the-config-file] Place the config in your project root. The CLI auto-discovers the first matching file in the working directory, in this order: ```text wvb.config.js wvb.config.cjs wvb.config.mjs wvb.config.ts wvb.config.cts wvb.config.mts webview-bundle.config.js webview-bundle.config.cjs webview-bundle.config.mjs webview-bundle.config.ts webview-bundle.config.cts webview-bundle.config.mts wvb.config.json wvb.config.jsonc ``` Both base names `wvb.config.*` and `webview-bundle.config.*` are supported with the `.js`, `.cjs`, `.mjs`, `.ts`, `.cts`, and `.mts` extensions. The `.json` and `.jsonc` forms are only recognized for the `wvb.config` base name. Pass `--config` (alias `-C`) to any command to point at a specific file instead of relying on discovery. ```sh wvb pack --config ./configs/wvb.prod.ts ``` ### defineConfig [#defineconfig] Wrap your config with `defineConfig` from `@wvb/config`. It is an identity function at runtime — its only job is to attach types. It accepts an object, a promise that resolves to a config, or a synchronous or asynchronous function that returns one, so you can compute values at load time. ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig({ root: process.cwd(), pack: { srcDir: './dist', }, serve: { port: 4312, }, }); ``` ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig(async () => { const endpoint = process.env.WVB_ENDPOINT; return { remote: { endpoint, }, }; }); ``` Install the package as a dev dependency: `npm install -D @wvb/config`. ## Top-level fields [#top-level-fields] The config object has five optional fields. Nothing else is read at the top level. | Field | Type | Default | | --------- | --------------------------------------------------------- | --------------- | | `root` | `string` | `process.cwd()` | | `pack` | [`PackConfig`](/docs/references/configuration/pack) | — | | `remote` | [`RemoteConfig`](/docs/references/configuration/remote) | — | | `serve` | [`ServeConfig`](/docs/references/configuration/serve) | — | | `builtin` | [`BuiltinConfig`](/docs/references/configuration/builtin) | — | `root` sets the project root used to resolve relative paths. It may be absolute or relative to the config file. Each section field is documented on its own page linked above. # pack (/docs/references/configuration/pack) The pack section of wvb.config — source directory, output path, ignore rules, and per-file headers. `pack` (`PackConfig`) sets the defaults for [`wvb pack`](/docs/references/cli/pack). CLI flags override these per invocation. ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig({ pack: { srcDir: './dist', outFile: '.wvb/app', overwrite: true, ignore: ['*.map', /\.DS_Store$/], headers: { '*.html': { 'cache-control': 'max-age=0' }, '*.js': { 'cache-control': 'max-age=31536000' }, }, }, }); ``` | Field | Type | Default | | ----------- | ------------------------------------------------------------------------------------ | ------------- | | `srcDir` | `string` | `./dist` | | `outFile` | `string` | `.wvb/` | | `overwrite` | `boolean` | `true` | | `ignore` | `Array \| ((file: string) => boolean \| Promise)` | — | | `headers` | `Record \| Array<[glob, HeadersInit]> \| ((file) => HeadersInit)` | — | `outFile` is a single output path. The `.wvb` extension is appended automatically when you omit it, and the path resolves relative to `root` unless it is absolute. The default `.wvb/` derives `` from your `package.json` name with any scope prefix stripped. The field is `outFile`, a complete path. There is no `outFileName` or `outDir` on `pack` — write the full output path, including any subdirectory, in `outFile`. `ignore` accepts an array of globs and regular expressions, or a predicate that returns a boolean (optionally async). `headers` attaches HTTP headers to matching files and accepts three shapes: ```ts // 1. Record keyed by glob headers: { '*.html': { 'cache-control': 'max-age=3600' }, } // 2. Array of [glob, HeadersInit] tuples headers: [ ['*.html', { 'cache-control': 'max-age=3600' }], ['*.png', [['cache-control', 'max-age=0']]], // HeadersInit also accepts [name, value] pairs ] // 3. Function returning headers per file headers: (file) => (file.endsWith('.html') ? { 'cache-control': 'max-age=0' } : undefined) ``` # remote (/docs/references/configuration/remote) Configure the remote block of wvb.config, plus the publish-side integrity and signature options. The `remote` block of `wvb.config.ts` tells the `wvb` CLI how to publish a bundle: where the remote server lives, how to name and version each bundle, and which provider uploads and deploys it. Two adjacent options harden the result — `integrity` computes a content hash, and `signature` signs that hash with your private key so clients can verify who published the bundle. This page documents those three options and ends with a complete, copy-pasteable config. For the rest of the config file (top-level fields, `pack`, `serve`, `builtin`), see [The wvb.config file](/docs/references/configuration). For the runtime side — how a client downloads, verifies, and activates these bundles over the air — see [Remote bundles](/docs/guide/core-concepts/over-the-air). ## remote [#remote] `remote` is a `RemoteConfig` object. Every field is optional; the `uploader` and `deployer` you supply come from a provider package. | Field | Type | Default | Description | | ------------------ | -------------------------------------- | -------------------------- | ----------------------------------------------------------------- | | `endpoint` | `string` | — | Base URL of the remote server. | | `bundleName` | `BundleNameResolver` | `{ from: 'package.json' }` | How to resolve the bundle name. | | `version` | `VersionResolver` | `{ from: 'package.json' }` | How to resolve the version to publish. | | `packBeforeUpload` | `boolean` | `true` | Pack the bundle before uploading. | | `uploader` | `BaseRemoteUploader` | — | Uploads the `.wvb` to the server (from a provider). | | `deployer` | `BaseRemoteDeployer` | — | Marks a version deployed (from a provider). | | `integrity` | `boolean \| IntegrityMakeConfig \| fn` | — | Compute an integrity hash on upload. See [integrity](#integrity). | | `signature` | `SignatureSignConfig \| fn` | — | Sign the integrity hash on upload. See [signature](#signature). | `RemoteConfig` has no `channel` or `allowOtherVersions` field. A channel is a deploy-time argument (`wvb deploy --channel `), not a property of the config object. ### Resolvers [#resolvers] `bundleName` and `version` accept a literal string, a resolver object, or a function. The function form receives `{ packageJson, dir, file }` and returns a string (or a `Promise` of one). ```ts title="wvb.config.ts" remote: { // Bundle name: 'package.json' (name field, scope stripped) or a string or a function. bundleName: { from: 'package.json' }, // Version: 'package.json' (version field), 'git' (HEAD commit hash), a string, or a function. version: { from: 'git' }, } ``` | Resolver | Accepted forms | | ------------ | ------------------------------------------------------------------------------------------------------ | | `bundleName` | `{ from: 'package.json' }` \| `string` \| `(params) => string \| Promise` | | `version` | `{ from: 'package.json' }` \| `{ from: 'git' }` \| `string` \| `(params) => string \| Promise` | `{ from: 'package.json' }` reads the `name`/`version` field and throws when it is missing. `{ from: 'git' }` (version only) uses the current `HEAD` commit hash. ### Providers [#providers] `uploader` and `deployer` are not built into `@wvb/config` — they come from a provider package. Each provider exports a factory that returns `{ uploader, deployer }` (AWS also returns a `signature` signer) ready to spread into `remote`. ## integrity [#integrity] Integrity computes a cryptographic hash of the bundle bytes and stores it alongside the bundle. Clients recompute the hash on download and reject a bundle whose hash does not match — proof the bytes were not corrupted or tampered with in transit. The hash uses **SHA-2**. `integrity` accepts three forms: ```ts title="wvb.config.ts" // 1. Boolean — enable with the default algorithm (sha256). integrity: true, // 2. Pick the algorithm. integrity: { algorithm: 'sha384' }, // 'sha256' | 'sha384' | 'sha512' // 3. Custom function — return the full ":" string yourself. integrity: async ({ data }) => `sha256:${await myHash(data)}`, ``` | Form | Type | Notes | | ------------- | -------------------------------------------------- | ---------------------------------- | | Boolean | `boolean` | `true` uses the default algorithm. | | Config object | `{ algorithm?: 'sha256' \| 'sha384' \| 'sha512' }` | Default `algorithm` is `'sha256'`. | | Function | `(params: { data: Buffer }) => Promise` | Returns the serialized string. | The serialized output is `":"` — the algorithm name, a colon, then the base64-encoded digest, for example `sha256:n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=`. ## signature [#signature] A signature proves *who* published a bundle. It signs the bytes of the integrity string (the `":"` value above) with your private key, and the client verifies the result with the matching public key. Because the signed message is the integrity string, signature verification requires an integrity value to be present. `signature` is a `SignatureSignConfig` — a discriminated union on `algorithm` — or a custom signing function. This is the **publish (sign) side**, shipped in `@wvb/config`. | `algorithm` | Required fields | Optional fields | | ------------------ | --------------------------------------------- | --------------- | | `'ecdsa'` | `curve` (`'p256'` \| `'p384'`), `hash`, `key` | — | | `'ed25519'` | `key` | — | | `'rsa-pkcs1-v1.5'` | `hash`, `key` | — | | `'rsa-pss'` | `hash`, `key` | `saltLength` | `hash` is one of `'sha256' | 'sha384' | 'sha512'`. The `key` is a `SignatureSigningKeyConfig`: | `format` | `data` type | | -------------------------------- | ------------ | | `'jwk'` | `JsonWebKey` | | `'raw'` \| `'pkcs8'` \| `'spki'` | `Buffer` | ```ts title="wvb.config.ts" // ECDSA signature: { algorithm: 'ecdsa', curve: 'p256', // 'p256' | 'p384' hash: 'sha256', key: { format: 'pkcs8', data: privateKeyDerBuffer }, }, // Ed25519 signature: { algorithm: 'ed25519', key: { format: 'pkcs8', data: privateKeyDerBuffer }, }, // RSA-PSS (or 'rsa-pkcs1-v1.5') signature: { algorithm: 'rsa-pss', hash: 'sha256', saltLength: 32, // rsa-pss only; defaults from the hash when omitted key: { format: 'pkcs8', data: privateKeyDerBuffer }, }, // Custom signer — receives the integrity-string bytes, returns a base64 signature. signature: async ({ message }) => myExternalSigner(message), ``` Clients verify with the matching **public** key, and the verify side accepts different key formats than the sign side — SPKI, PKCS#1 (RSA only), SEC1 (ECDSA only), and raw 32-byte (Ed25519 only), but not JWK. See [Remote bundles](/docs/guide/core-concepts/over-the-air) for verification and the [Node API reference](/docs/references/api/node) for the client-side helpers. ## Complete example [#complete-example] A full `wvb.config.ts` that publishes through the AWS provider, hashes with SHA-384, and signs with Ed25519. Swap `awsRemote` for `localRemote` or `cloudflareRemote` to target a different provider. ```ts title="wvb.config.ts" import { readFileSync } from 'node:fs'; import { defineConfig } from '@wvb/config'; import { awsRemote } from '@wvb/remote-aws'; export default defineConfig(() => { const provider = awsRemote({ bucket: 'my-app-bundles', aws: { region: 'us-east-1' }, }); return { remote: { endpoint: 'https://updates.example.com', bundleName: { from: 'package.json' }, version: { from: 'git' }, uploader: provider.uploader, deployer: provider.deployer, integrity: { algorithm: 'sha384' }, signature: { algorithm: 'ed25519', key: { format: 'pkcs8', data: readFileSync('./keys/signing-key.pkcs8.der'), }, }, }, }; }); ``` To publish, run `wvb upload` to push the `.wvb` (which packs first when `packBeforeUpload` is `true`), then `wvb deploy --version ` to mark a version live. See the [CLI reference](/docs/references/cli) for the full command set and the [remote guide](/docs/guide/remote) for building and testing a remote end to end. # serve (/docs/references/configuration/serve) The serve section of wvb.config — the local file, port, and log output for the preview server. `serve` (`ServeConfig`) sets the defaults for [`wvb serve`](/docs/references/cli/serve), the local server that serves a packed bundle for development. ```ts title="wvb.config.ts" import { defineConfig } from '@wvb/config'; export default defineConfig({ serve: { file: './.wvb/app.wvb', port: 4312, silent: false, }, }); ``` | Field | Type | Default | | -------- | --------- | ----------------------- | | `file` | `string` | the `pack.outFile` path | | `port` | `number` | `4312` | | `silent` | `boolean` | — | `file` falls back to the resolved `pack.outFile` path when omitted. Set `silent` to disable request-log output. `serve` has no `hostname` field. To bind a different host, pass `--hostname` (alias `-H`) to `wvb serve` on the command line. # Overview (/docs/references) API references for the Rust core, the Node and Deno bindings, and the web-side bridge. Most app developers never touch these APIs directly. To ship Webview Bundle in an app, reach for the platform integration packages and follow the platform guides — they wrap the core for you. These references are for advanced and embedding use: hosting the core yourself, driving the Node or Deno bindings, or calling the native host from inside the webview. Building an app? Start with the [platform integration guide](/docs/guide/core-concepts/glue-to-native) and pick your platform: [Electron](/docs/guide/native/electron), [Tauri](/docs/guide/native/tauri), [Android](/docs/guide/native/android), [iOS](/docs/guide/native/ios), or [Deno Desktop](/docs/guide/native/deno). ## API references [#api-references] ## Web-side bridge [#web-side-bridge] The bridge (`@wvb/bridge`) runs inside the webview and lets your web app call the native host. It exposes a single `invoke()` function plus typed `source`, `remote`, and `updater` helpers, so the same code works across Electron, Tauri, Android, and iOS — the per-platform transport is abstracted away. See the [Bridge reference](/docs/references/api/bridge) for the full API. ```ts import { invoke, updater } from '@wvb/bridge'; // Typed domain helper const update = await updater.getUpdate('my-app'); if (update.isAvailable) { await updater.download('my-app'); await updater.install('my-app', update.version); } // Or call a command directly const bundles = await invoke('sourceListBundles'); ``` The native side hosts `@wvb/node` and answers these calls. For how the bridge fits into each platform, see the [platform integration guide](/docs/guide/core-concepts/glue-to-native). ## Other platforms [#other-platforms] The Tauri and mobile integrations expose their own APIs, documented alongside their guides: * Tauri ships as the Rust crate `wvb-tauri` — see the [Tauri guide](/docs/guide/native/tauri). * Android (Kotlin) and iOS (Swift) bindings are covered in the [Android guide](/docs/guide/native/android) and the [iOS guide](/docs/guide/native/ios).