@ebay-dt/bonfire-node
v0.1.0
Published
Node.js adapters for Bonfire.
Downloads
813
Keywords
Readme
@ebay-dt/bonfire-node
Node.js adapters for Bonfire. It provides an injectable GitHub CLI client for identity lookup and web/device-login startup, safe prototype catalog discovery, and development-only local prototype lifecycle services from an explicit repository root.
The client invokes gh with argument arrays, captures both output streams,
returns a safe device URL, and classifies missing, unauthenticated, and unknown
failures without exposing command output or credentials. Configure the GitHub
hostname per application; the adapter does not assume a particular host.
PrototypeCatalog scans the conventional src/app/(prototypes) root, reads
validated metadata.json documents, skips invalid entries safely, and returns
path-free summaries. Pass an explicit repositoryRoot; catalog operations do
not use ambient working-directory discovery.
The Next.js integration creates the GitHub CLI client and catalog automatically.
Applications can provide a GitHubCliClientLike implementation to
createBonfireNext for controlled testing.
Lifecycle runtime context
Lifecycle services use explicit repository and prototype roots, with origin
and main as the default remote and primary branch. Repository mutations are
serialized by one HMR-safe, process-global gate per canonical repository path.
A competing mutation returns repository-busy immediately rather than waiting.
The gate covers the supported local Node process only; coordination across
multiple processes or machines is not provided.
Deployment provider
Deployment is an optional development capability. Configure the generic provider only in a server-only host module with a complete HTTP endpoint; never expose the endpoint or provider to browser code:
import { createDeploymentProvider } from "@ebay-dt/bonfire-node";
const deploymentProvider = createDeploymentProvider({
endpoint: process.env.BONFIRE_DEPLOYMENT_ENDPOINT!,
timeoutMs: 120_000,
});The provider sends exactly { applicationId, login }. Bonfire supplies the
application ID from trusted application configuration and the login from the
verified authenticated identity; instances never provide owner/branch values.
The application ID must exactly match the application's DT deployment-service
registration; Bonfire does not validate that registration locally. A mismatch
is returned as a safe deployment failure rather than exposing provider details.
The documented success response is returned with HTTP 201 and contains
repository, ref, commitSha, sourceFileCount, project, deployed,
deploymentId, url, and readyState. readyState is one of BLOCKED,
BUILDING, CANCELED, ERROR, INITIALIZING, QUEUED, or READY. HTTP 201
means deployment creation succeeded, not that the preview is ready. A failure
response contains repository, optional ref, commitSha, project, and
stage, plus deployed: false, statusCode, and details; those diagnostics
are validated and then intentionally hidden behind a safe provider error.
The provider preserves the deployment ID and reported ready state, but Bonfire does not poll for later status. Provider failures are reduced to safe typed lifecycle errors; response diagnostics, credentials, Vercel credentials, and deployment-target selection remain outside Bonfire in the deployment service. If the deployment service exposes a registration-specific status, hosts may map it to a generic message such as “Deployment is not configured for this application.” They should not infer that classification from an arbitrary failure or forward provider response bodies, endpoint details, repository or branch data, or filesystem diagnostics to the browser. The provider validates the endpoint, response, HTTPS preview URL, and timeout without exposing service details to the browser.
Prototype shape and duplication
Duplicate sources must contain valid metadata.json plus regular,
nonsymlink page.tsx, app.tsx, and app.module.css files. Sources with the
legacy page.module.css shape or missing canonical files are rejected; missing
implementation files are never synthesized. A source components/ directory
is optional and validated recursively. Destination metadata, tsconfig.json,
and css-modules.d.ts are regenerated, while canonical implementation and
component files are copied byte-for-byte.
Preparing prototype-local files
A trusted server host may provide one preparePrototypeFiles callback when
constructing LocalPrototypeLifecycle. It receives a validated, normalized,
read-only request for the new destination and may write files only inside that
destination:
import { writeFile } from "node:fs/promises";
import { join } from "node:path";
import { LocalPrototypeLifecycle } from "@ebay-dt/bonfire-node";
const lifecycle = new LocalPrototypeLifecycle({
repositoryRoot,
preparePrototypeFiles: async (request) => {
await writeFile(join(request.prototypePath, "instructions.md"), "...");
},
});The callback runs once after scaffold or duplication and before the initial path-scoped commit. Bonfire validates the destination afterward, includes valid callback files in the commit, and removes the newly owned destination if preparation or validation fails. A commit or push failure preserves the completed destination. The default callback is a no-op.
LocalPrototypeLifecycle.getDirtyState validates the authenticated owner and
prototype reference, then returns a clean or dirty observation based only on
Git status within that prototype path. LocalPrototypeLifecycle.save creates a
local, path-scoped checkpoint without pushing; .discard restores tracked
files and removes untracked files within that path. LocalPrototypeLifecycle.create,
.duplicate, .edit, and .delete return typed results and serialize repository
mutations through one process-local operation gate. Edit updates only title,
description, and updatedAt while preserving the existing ref/URL. Delete
removes the complete owned prototype directory, including uncommitted files,
after ownership and path validation. These operations prepare the authenticated
identity branch when automatic switching is enabled;
BF_DISABLE_AUTO_BRANCH_SWITCH=true disables every automatic switch and leaves
the current branch untouched. Git remains behind the Node-owned repository
adapter, and simple-git is not part of the public API.
This is a server-only host extension: it must not perform repository-wide projection, package installation, skills or MCP setup, or write outside the prototype destination. Host-specific form fields and metadata require separate contracts.
Dirty observation is available from the separate @ebay-dt/bonfire-node/watcher
subpath. It shares one configured Chokidar watcher across prototype subscribers,
debounces filesystem events, and reports only clean/dirty transitions. The
watcher subpath is intentionally separate so importing @ebay-dt/bonfire-node does
not load Chokidar.
Agent launch preferences
PrototypeAgentService stores a user's selected Claude Code terminal at
<prototypeRoot>/<login>/preferences.json, using the explicit runtime context
provided by the host. This is a local preference file, not prototype source:
consuming applications must add their prototype-root preference pattern to
.gitignore, for example:
/src/app/(prototypes)/*/preferences.jsonThe service writes the file atomically and only after authenticated ownership
and command preflight have succeeded. Cursor launching requires cursor on the
Bonfire server process's inherited PATH. Claude Code launching requires
claude and, on macOS, osascript on that PATH; the service checks these
commands without executing them. GUI-launched Node processes may have a
different PATH from an interactive shell, so restart Bonfire after changing
shell profiles.
Claude Code supports the explicit terminal values terminal (Terminal.app),
iterm (iTerm2), and warp (Warp). Unsupported platforms, missing commands,
missing preferences, ownership failures, and launch failures are returned as
safe typed results; raw process output and absolute paths are never public
results. No skill, clipboard fallback, or copy/paste setup flow is involved.
Production hosts must not construct the service or expose its local preference
store.
From the repository root, use Turbo filters so package dependencies are prepared in dependency order:
pnpm exec turbo run lint --filter=@ebay-dt/bonfire-node
pnpm exec turbo run check --filter=@ebay-dt/bonfire-node
pnpm exec turbo run test --filter=@ebay-dt/bonfire-node
pnpm exec turbo run build --filter=@ebay-dt/bonfire-node