@xyo-network/dapp-kit-local
v3.2.6
Published
Importable local deployment reconciler for headless XL1 dApps
Readme
@xyo-network/dapp-kit-local
Importable, headless local deployment reconciliation for dapp-kit projects.
startDefaultLocalDappRun() is the V1 composition surface. It installs admitted
product hosts, constructs only supported resource adapters, records lifecycle
state, emits redacted component logs, starts declared static ingress after host
readiness, and returns one foreground owner. dev retains repository state;
test defaults to an isolated temporary state root that is removed after the
terminal record and logs have been captured.
The package owns whole deployment-resource and host sessions. It does not own actor supervision, provider location, XL1 protocol implementations, or a CLI parser. Resource and host implementations are installed explicitly into closed registries and are selected by the exact IDs and versions retained in a deployment lock.
installPlannedLocalDappHosts() installs only host artifacts selected by the
immutable deployment plan. Artifact admission verifies their executable file,
actor/provider descriptor, and product host-factory inventories before the
function exposes LocalHostAdapterRegistry entries. Those adapters forward the
exact lock, abort signal, and borrowed resource capabilities; they do not infer
recovery, status, or application-port behavior from descriptor metadata.
createLocalDappLogSink() serializes bounded canonical JSONL independently per
component and can forward the same redacted entry to a foreground renderer.
Every entry retains component, host, plan, system-incarnation, severity, and
stable event-code fields. Secret-shaped keys, credential-bearing URLs, and
authorization strings are redacted before either destination sees the entry.
planLocalDappProject() validates a repository, admits built Node host
artifacts without executing them, resolves one named deployment against an
explicit environment catalog, compiles the neutral plan, and optionally writes
the reproducible lock. Declared static sites are built by invoking one exact
package script through the repository's pinned package manager without a shell,
then admitted through a confined, symlink-free file inventory and independent
manifest/content hashes. The admitted manifest is cached under .xl1/cache and
its identities enter the deployment lock. Planning never provisions a resource
or constructs an actor.
createDefaultLocalEnvironmentCatalog() returns the closed, versioned V1
catalog used by the CLI when no override is supplied. It resolves only
managed-local XL1, Aries datalake, filesystem journal/projection/checkpoint,
and ephemeral identity requests. It contains no runtime ports, secrets,
service-relative managed resources, external endpoints, or placeholder
side-channel/external-source adapters.
Filesystem-backed sessions require Node >=26.9/native FFI and either Darwin arm64/APFS or Linux glibc x64/arm64/ext4 with trusted current-process procfs. They acquire one persistent base owner before readiness; related acquired resource sessions borrow separate scopes and retain it until the final session stops. Stop revokes new store operations, drains accepted work, deletes only ephemeral descendant state, and releases its owner reference. Retained state and the base directory remain. Independent competing/nested bases and redirected unsafe resource paths fail closed.
Quiesce all old filesystem processes before upgrading; old path-only adapters
do not participate in the new locks. Old .dapp-kit-owner markers require an explicit quiescent migration: stop every
old owner, verify no old binary can restart, then remove its marker before opening
the new adapter. New code never steals or deletes that marker. Windows, musl/Alpine, other filesystems and hostile same-UID namespace changes
are unqualified. Linux container state needs a qualified ext4 volume; overlapping
independent mount aliases require one shared configured owner.
This narrows adapter availability and adds lifecycle/syscall costs.
runLocalDappVerifications() invokes only manifest-declared package-script
names through the repository's exact package manager. Each result retains its
declared evidence class. Scripts receive one private JSON context path with
lock/plan identity and credential-free endpoint metadata; arbitrary parent
environment values are not inherited. A failed script remains failed evidence
and is never promoted into another evidence class. Package-manager preflight
has its own packageManagerTimeoutMs budget (default 5 seconds), while
verificationTimeoutMs bounds each selected script. Termination and output
pipe draining have separate budgets (defaults: 1 second cleanup, then 250 ms
pipe drain); these are not one total operation deadline. Timer inputs above the
platform timer maximum are rejected. A cold or stalled package-manager probe
can now fail at its configured bound instead of waiting indefinitely.
On supported POSIX hosts, cleanup freezes a live owned launcher, captures current
same-owner ancestry, and stops/terminates descendants before the launcher even
when a child has moved to another process group. It observes metadata only,
without command arguments or environment values. This requires process-inspection
permission. Lost ancestry, denied inspection, or incomplete termination produces
local-verification.cleanup-unconfirmed, rather than ordinary failed-but-cleaned
evidence. Cached PID metadata is not later orphan-kill authority. Windows and
arbitrary detached/reparented daemons have no qualified tree-containment promise.
DefaultLocalDappRun.deferStateCleanup() returns an idempotent async release
for a hold on isolated run-state deletion. Terminal notification still resolves
so verification can receive cancellation; deletion waits for the final hold.
The CLI retains that isolated context/run-record root on unconfirmed cleanup,
even when ordinary failure retention is disabled. Provider-owned ephemeral
resource disposal and repository contents have their own lifecycles and are not
covered by this retention hold. Direct structural run implementations/mocks must
supply the new method; late retention/holds cannot undo removal already begun.
Extra inspection is on failure cleanup, and uncertainty can leave diagnostic
state requiring explicit operator follow-up.
startRecordedLocalDappRun() wraps the reusable reconciler with the validated
noncanonical run-record store. It records every lifecycle phase, exact host
session IDs, allocated ports, and the terminal issue code while leaving the
deployment lock unchanged. The injected store may use retained repository state
for dev or an isolated temporary state root for test.
The reconciler's optional startIngress phase runs only after every host is
ready and before deployment readiness is published. Each returned site/ingress
session is adopted immediately, participates in terminal-failure detection,
and stops before host and resource sessions during reverse teardown.
startLocalStaticSiteServer() serves only the admitted file inventory from one
loopback origin and verifies file size/hash again on every response. It composes
the canonical status/readiness/health facade with the complete WebSocket
application-port ingress. Browser attachments require a short-lived random
same-origin session held only in an HttpOnly, SameSite=Strict cookie; the
token is not returned to JavaScript, embedded in endpoint URLs, or printed.
Reloading rotates the session and detaches the prior port client. Stopping or
closing the site owns only site/ingress resources and never stops the dApp host.
startPlannedLocalStaticSites() turns admitted static artifacts into owned
post-host ingress sessions and credential-free verification endpoints. V1
requires exactly one application-port host for a site-bearing deployment; a
missing or multi-host binding fails explicitly until the manifest gains an
unambiguous multi-host routing contract.
startPlannedLocalProjectionIngress() exposes the selected portable
projection-store through a runner-owned, loopback-only, read-only HTTP server
when the locked projection profile is public-served. The endpoint maps object
keys directly beneath one origin, preserves safe cache validators and public
CORS, rejects queries and write methods, never exposes the checkpoint store,
and stops as an ingress session before the host and resource. The default local
runner starts this endpoint even when the dApp declares no static UI, so a
headless public indexer remains externally verifiable without product-owned
HTTP lifecycle code.
pnpm test:local-browser bundles the shared browser client into a reference
static site and runs it in real Chromium. The suite proves bootstrap, cookie
authority, unary port traffic, health, reload, and detach-to-zero without
transferring runtime ownership to the page.
LocalFilesystemResourceAdapter supplies confined runner-owned capabilities for
effect journals, projection roots, and checkpoint roots. It reuses the Node
package's crash-durable journal and portable object store, rejects concurrent
ownership, preserves retained state, and removes only its own ephemeral
resource root. Filesystem roots remain private to the resource session; hosts
and projection ingress receive only the object-store capability.
createDefaultLocalResourceAdapterRegistry() installs exactly the managed
local adapters implemented by this package for the resources retained in a
deployment lock. External networks/stores, managed service resources,
side-channels, and external sources fail before provisioning; the runner never
substitutes a local fake for an unresolved capability.
The registry also exposes narrow deterministic test seams for identity entropy
and the local XL1 genesis reward address. pnpm test:local-system separately
proves a clean external host artifact over managed XL1, combined XL1/Aries
resource ownership, and both directly assembled and admitted-artifact
passive-public UC-02 claims ports over an owned real XL1, Aries, journal,
identity, and host graph. The clean admitted UC-02 repository also declares a
static site: planning builds and admits it, the default owner starts it after
host readiness, and the test replays publish/by-id through an authenticated
loopback WebSocket attachment before named verification and reverse teardown.
The UC-02 cases use the same derived child-zero wallet for both test seams.
Production callers must still obtain funding authority explicitly; the registry
does not infer it from an arbitrary identity binding.
LocalXl1ResourceAdapter owns the published xl1 CLI as a foreground child,
binds its loopback RPC endpoint from the deployment lock, configures the exact
expected chain ID, proves readiness through typed XL1 viewers, and performs
bounded TERM/KILL teardown. The current in-memory CLI adapter explicitly
rejects retained chain state instead of overstating durability.
startLocalHostedAppProcess() supplies the same foreground ownership boundary
for a consumer-selected application host. It allocates loopback ingress, passes
the selected port to exact argument/environment factories, waits on a bounded
HTTP or injected readiness probe, captures bounded child output for failures,
and performs TERM/KILL teardown. The caller retains provider choice: a test may
own a framework development server or a pinned vercel dev process without
making dapp-kit install, authenticate, or silently acquire a provider CLI.
LocalIdentityResourceAdapter creates an explicitly requested ephemeral local
XL1 wallet from in-memory entropy at the canonical
m/44'/60'/0'/0/<childIndex> path. The capability exposes the wallet only to
the owning run, never serializes a mnemonic or private key, and can fund the
managed local XL1 genesis account when the network resource declares the
identity as a dependency.
LocalDatalakeResourceAdapter owns the published Aries local datalake daemon,
keeps its generated control credential inside a deployment-scoped
ARIES_HOME, and exposes only an authenticated payload client plus non-secret
endpoint metadata. It applies the locked public/capability read policy, proves
readiness with a content-addressed insert/read-back, removes ephemeral state,
and preserves retained state across owned daemon restarts. It imports the
public clients from @ariestools/datalake-cli and invokes the packaged
aries CLI instead of copying private server internals into dapp-kit.
