@xyo-network/dapp-kit-browser
v2.1.4
Published
Browser lifecycle owners and application-port transport for headless XL1 dApps
Readme
@xyo-network/dapp-kit-browser
Browser lifecycle owners and browser application-port adapters for headless dApp-kit launches.
The initial slice owns read-only application sessions in either a page or a dedicated worker. It composes browser-kit's page-hide and worker shutdown adapters, then exposes only application ports, status, and stop. It does not expose the neutral session, actor system, provider system, or locator.
Effectful application ports are rejected until dapp-kit has a transactional,
crash-durable browser effect journal. This package does not use memory or
localStorage as a durability substitute.
The package adapts a real MessagePort to the shared application-port peers in
@xyo-network/dapp-kit-port. Those peers bind every frame to
the authenticated attachment, plan, system incarnation, host session, request,
port, operation, and deadline. Hosts dispatch an explicit operation registry;
actor/provider locators are never reflected across the boundary. Unary calls
support cancellation acknowledgement. Streams use bounded receiver credit,
monotonic at-least-once delivery, exact duplicate checks, durable cursors, and
resume.
The browser package re-exports the shared
connectWebSocketApplicationPort() client for same-origin network attachments.
The connection handshake validates the expected dApp, plan, protocol version,
and grant lifetime before exposing a client; closing or losing the socket
detaches only that UI session.
The shared package's structural Node tests exercise paired endpoints, stale-incarnation rejection, cancellation ordering, detach cleanup, bounded credit, durable resume, and the real Node WebSocket server/client boundary. The local runner's opt-in Chromium suite additionally bundles this package's actual WebSocket client into an admitted static site and proves attach, request, reload, and detach without page ownership of the runtime.
This package does not yet claim:
- forced-worker-termination conformance;
- service-worker support;
- a wallet or XL1 browser-system integration; or
- React or any other UI framework integration.
Anonymous SDK/S3 projection reads
createS3DatalakeObjectLoader() adapts one explicitly selected public SDK/S3
store to the core PublishedProjectionObjectLoader contract. It composes core
DatalakeObjectReader with the SDK's public payloadPath() layout and payload
verification. No new package or additional datalake service is required.
import { loadPublishedProjection } from '@xyo-network/dapp-kit'
import { createS3DatalakeObjectLoader } from '@xyo-network/dapp-kit-browser'
const pageLifetime = new AbortController()
const load = createS3DatalakeObjectLoader({
baseUrl: 'https://objects.example.org/lifehash/public/',
immutableKeyPrefixes: ['generations/'],
maximumObjectBytes: 4 * 1024 * 1024,
requestTimeoutMs: 15_000,
signal: pageLifetime.signal,
storeId: 'lifehash-public',
})
const projection = await loadPublishedProjection({
headStoreId: 'lifehash-public',
load,
})
// The page/worker owner calls pageLifetime.abort() when this reader is retired.The base URL addresses the public bucket/prefix root. Non-immutable keys read
records/<key>; immutable keys read references/<key> followed by
content/<SDK payloadPath(hash)>. The declared immutable prefixes must match
the server binding, be nonoverlapping, and end in /. Keys are canonical
URL-safe ASCII paths without traversal or URL escapes. Base URLs require HTTPS
or explicit localhost, 127.0.0.1, or [::1] HTTP for local work; credentials,
query strings and fragments are rejected.
Every fetch uses credentials: 'omit', redirect: 'error', cache: 'default'
and referrerPolicy: 'no-referrer'. An optional fetchImpl can supply the host's
fetch implementation without changing that request contract. The requested
store ID must exactly match the configured ID before any fetch. No private
endpoint discovery, alternate-store fallback, wallet, cookie or access token
is acquired. A missing record/reference returns undefined; a missing,
corrupted or differently bound referenced payload rejects the read.
Records and references must expose a nonempty provider ETag. In the default
metadata-header format, mutable records additionally require
x-amz-meta-dapp-kit-store-id equal to the configured store ID. Select
recordFormat: 'bound-body' on both ends when custom S3 headers are unavailable.
References always verify store identity in their bodies. Any present store
header must match. Configure the website origin and expose ETag (plus the
store header when using the default mutable format).
The loader never invents an ETag when CORS hides it. The endpoint must permit anonymous reads of this public scope; the metadata check is not an access policy. Provider IAM must keep private projection and connector scopes private. Anonymous listing is intentionally unsupported.
The default raw object limit is 4 MiB, with 64 KiB reference documents and
encoded payload reads bounded to twice the raw limit plus 64 KiB. The default
15-second requestTimeoutMs covers a complete logical read, including
reference/body retrieval and immutable verification. Streaming bytes are
bounded even when Content-Length is missing or false. Cancellation also bounds
an injected fetch or stalled stream that fails to settle. No automatic retries
are performed, and transport errors omit provider messages.
The optional signal is a page/worker lifetime signal, not a startup deadline.
Aborting it prevents all future uses of this loader. Use requestTimeoutMs for
individual reads; there is no separately owned client to close.
The focused loader suite passes 31 tests in Node and the same 31 in Chromium, covering coherent head/generation/object reads, anonymous request options, scope rejection, missing/corrupt payloads, limits and cancellation. These tests use injected HTTP responses and the real SDK/core verification code; they do not qualify hosted CORS or a rendered application journey. The complete browser package's Node suite passes 36 tests. See portable storage for the distinct SDK/S3 application rehearsal and remaining provider gates.
Public hosts without custom S3 metadata
Select recordFormat: 'bound-body' on both the S3 binding and anonymous loader
for a new namespace on an R2 custom domain. Mutable bodies then bind store/key
identity independently of custom HTTP headers; ETag must still be exposed.
See the shared contract for wire,
cache, compatibility and qualification requirements.
