Enbox Browser
Research Preview — Enbox is under active development. APIs may change without notice.
| Browser entrypoint for Enbox application APIs, auth, wallet connect, and DWeb features |
|---|
Install
bun add @enbox/browser
Usage
@enbox/browser re-exports the high-level API, browser-safe auth surface,
wallet connect handler, and DWeb helpers:
import { createApplication } from '@enbox/browser';
import { NotesStore } from './features/notes/store.js';
const application = createApplication({
stores: { notes: NotesStore },
wallet: { appName: 'Notes' },
connection: { monitor: { autoRefresh: {} } },
});
await application.initialize();
// Invoke directly from a user action so the wallet popup opens.
async function connect(): Promise<void> {
const snapshot = await application.connection.connect();
if (snapshot.phase !== 'connected') {
throw snapshot.error ?? new Error('Connection was not established.');
}
const notes = application.store(NotesStore);
// Subscribe to notes' resources or run its domain commands.
}
Keep one application for the browser lifetime. It derives the manifest from
feature modules and owns the connection, session-scoped resources, commands,
and cleanup. application.connection.disconnect() signs out;
application.dispose() permanently tears down the owner. React binds the same
runtime through EnboxProvider application={application}.
For a custom host, supply connectHandler instead of wallet, or supply a
connection: manifest => nativeConnection factory that owns all native
configuration. The headless @enbox/api constructor requires that factory;
the browser constructor supplies browser defaults around the same runtime.
Native connection, record, and context primitives remain available for custom
flows. defineStore's observe() factory owns all native view types through
one subscription and cleanup mechanism.
Wallet sign-in without a data session
Call authenticateViaPopup() directly from a user action to request an owner
authentication proof. Supply the wallet URL and a service-issued
authentication: { version: 1, audience, challenge } request. The result is
{ connectedDid, authentication }, or undefined when denied; no DWN delegate
session is created. The service verifies the returned proof against its exact
pending request and consumes the challenge once before establishing login.
Supply onAuthenticationRequest to register that exact generated request with
the service before wallet delivery; the callback must resolve successfully
before approval can proceed. A registration failure closes the popup.
Service-side verification requires an independent expected: { audience, challenge } from configuration and its issued transaction, together with the
stored full request. Unknown or already-used challenges must be rejected.
Owner authentication requires an HTTPS origin, including local development.
Proofs expire 300 seconds after signing; the response envelope's separate
600-second lifetime does not extend that deadline. An expired proof fails
login even if the wallet already approved grants in combined mode.
connectViaPopup() also accepts authentication to combine sign-in with its
explicit DWN permission request. The existing application/connection-store
APIs continue to manage data sessions. The Connect proof is an Enbox wallet
primitive; OAuth/OIDC token issuance belongs to the receiving service.
Authentication capability discovery/negotiation is not implemented. Use combined mode only with known-capable wallets: older wallets can grant the requested data access and then return no owner proof, which fails login. Likewise, a final signing failure can leave previously written grants in place. Callers must reconcile or revoke that partial outcome before retrying; a rejected combined operation is not evidence of a DWN rollback.
Browser runtime
Every browser dapp must register an application-owned service worker that calls
activatePolyfills(). The page owns the connection store, record views, and
WebSockets; the worker owns DRL fetch interception and the offline shell. Keep
the default Level/IndexedDB storage stack.
Before initializing the connection store, await prepareBrowser(workerUrl, { registrationOptions: { type: 'module' } }) for a module worker, or pass an
existing registration from this page's navigator.serviceWorker when a PWA
tool owns registration. The helper waits for that worker to control the page
and activates page polyfills, with a timeout and abort signal. The application
owns update activation. Worker-side activatePolyfills() claims clients during
activation, but leaves waiting workers in place. Complete pending application
work before your update handler requests skipWaiting() and reloads the page.
Current browser-conditioned packages work in page and worker builds without
Enbox-specific Node-global, process, or IIFE shims. Follow the
browser dapp guide for the canonical Vite, worker,
startup, live-data, hosting, and verification setup. The rationale lives in
Browser dapp architecture.
Project resources
| Resource | Description |
|---|---|
| AGENTS.md | Contributor workflow and repository rules |
| License | Apache License, Version 2.0 |