Issue #13 uses Token Host Builder in wrapper mode around the hand-written
FocPlatformRegistry and platform API. The generated Token Host app is the
demo scaffold for upload UI, manifest metadata, sponsored transaction UX, and
upload adapter wiring. It is not the authoritative storage lifecycle.
apps/tokenhost-foc-platform/schema.json: current Token Host Schema input.apps/tokenhost-foc-platform/ui-overrides/app/page.tsx: custom generated home page used by Token Host Builder.tokenhost/foc-platform-wrapper.config.json: FOC Platform wrapper metadata that current Token Host Builder cannot yet emit natively.artifacts/tokenhost/foc-platform-wrapper-manifest.json: deterministic wrapper manifest generated bypnpm build:tokenhost.src/admin/reconciliation.mjsandsrc/api/platform-admin-api.mjs: read-only admin/reconciliation projection and routes exposed to wrapper metadata until Token Host Builder emits native FOC Platform admin pages.src/demo/tokenhost-wrapper.mjs: small client adapter for Token Host-style request/status/object/usage screens pluscreateTokenHostRegistryDirectReadAdapterfor direct registry read pages.test/tokenhost-demo.test.mjs: schema/config, manifest, and API flow smoke tests.test/tokenhost-direct-reads.test.mjs: direct registry read adapter smoke tests for object, account, dataset, coordinator, relayer, admin, and stale active-cursor restart behavior.
Set these paths for your local checkouts:
export FOC_PLATFORM_DIR=/path/to/foc-platform
export TOKENHOST_BUILDER_DIR=/path/to/tokenhost-builderRun the builder flow with:
pnpm --dir "$TOKENHOST_BUILDER_DIR" install
pnpm --dir "$TOKENHOST_BUILDER_DIR" build
pnpm --dir "$TOKENHOST_BUILDER_DIR" th validate "$FOC_PLATFORM_DIR/apps/tokenhost-foc-platform/schema.json"
rm -rf /tmp/foc-platform-tokenhost-demo
TH_UPLOAD_RUNNER=remote \
TH_UPLOAD_PROVIDER=filecoin_onchain_cloud \
TH_UPLOAD_REMOTE_ENDPOINT_URL=/storage/tokenhost/upload \
TH_UPLOAD_REMOTE_STATUS_URL=/storage/tokenhost/upload/status \
pnpm --dir "$TOKENHOST_BUILDER_DIR" th build "$FOC_PLATFORM_DIR/apps/tokenhost-foc-platform/schema.json" \
--chain filecoin_calibration \
--tx-mode sponsored \
--relay-base-url /__tokenhost/relay \
--out /tmp/foc-platform-tokenhost-demoth validate reported schema hash
sha256:b1113f6e1338d1fd54421441ce079fa1432334c2dc2e71785c8f3f2a19d1b4c5.
Observed output included:
manifest.jsonschema.jsoncontracts/App.solcompiled/App.jsonsources.tgzcompiled.tgzui-bundle/ui-site/netlify.tomlnetlify/functions/tokenhost-upload-start.mjsnetlify/functions/tokenhost-upload-status.mjsnetlify/functions/tokenhost-upload-worker-background.mjsNETLIFY-UPLOADS.md
The generated Next export included /, /UploadRequest, /StorageObject, and
/tag; / came from the custom ui-overrides home page. The generated
manifest exposed sponsored transaction metadata and Filecoin upload adapter
metadata:
{
"extensions": {
"tx": {
"mode": "sponsored",
"sponsored": { "relayBaseUrl": "/__tokenhost/relay" }
},
"uploads": {
"enabled": true,
"endpointUrl": "/storage/tokenhost/upload",
"statusUrl": "/storage/tokenhost/upload/status",
"provider": "filecoin_onchain_cloud",
"runnerMode": "remote"
}
},
"ui": {
"bundleHash": "sha256:<builder-emitted-ui-bundle-digest>"
}
}The build manifest still uses a placeholder local deployment until th deploy
runs against a real chain and funded key. Do not treat the build-only manifest
as Calibration deployment evidence.
The wrapper config maps the generated app to the platform API:
- generated Token Host byte upload adapter:
POST /storage/tokenhost/upload - generated Token Host upload adapter status:
GET /storage/tokenhost/upload/status - create upload:
POST /storage/upload-requestsorPOST /storage/upload - submit bytes:
POST /storage/uploads/:objectId/bytes - status:
GET /storage/uploads/:objectId/statusorGET /storage/uploads/:objectId - object:
GET /storage/objects/:objectId - usage:
GET /storage/usage/:accountIdorGET /usage - admin object browser:
GET /admin/storage/objectsandGET /admin/storage/objects/:objectId - admin usage:
GET /admin/storage/usage - admin dataset/provider attribution:
GET /admin/storage/datasets - admin coordinator status:
GET /admin/storage/coordinators - admin reconciliation:
GET /admin/storage/reconciliation
pnpm build:tokenhost also emits registry.directReads into
artifacts/tokenhost/foc-platform-wrapper-manifest.json. Generated or wrapper
provided admin/read UIs should use that metadata to discover the Calibration
chain, registry address source, ABI artifact, max page size, list methods,
detail methods, dataset key tuple shape, and bounded readBatch/multicall
capability. The repo-local adapter can be passed as the admin implementation
to createPlatformAdminApi when a server wrapper wants the existing admin
routes backed by direct contract views instead of fixture/projection state.
FocPlatformRegistry remains authoritative for lifecycle, receipts, usage,
relayer accountability, coordinator controls, and reconciliation. Generic Token
Host CRUD output may help generate UI and upload scaffolding, but it must not
replace section 6.7 semantics until a custom FOC module proves equivalence.
The current admin routes are wrapper/read-model projections and require an
explicit operator authorization hook in any server wrapper. The direct-onchain
admin path must instead bind Token Host wrapper reads to the FOC-specific
registry list/detail surface:
- use bounded ID/key enumeration in the same spirit as Token Host Builder
listIdsC(cursorIdExclusive, limit, includeDeleted=false)pages, while preserving the FOC registry's exact cursor model; - use object-id cursors for
listStorageObjectIdsandlistAccountObjectIds; - use offset pagination for
listAccountIds,listCoordinatorAddresses,listRelayerAddresses, andlistDatasetKeys; - fetch details through
getStorageObject,getAccountUsage,getCopyReceipts,receiptPayer,getDatasetRecord,coordinatorPolicies, andisRelayer; - batch bounded detail reads with registry
readBatchor builder-compatible multicall helpers where available; - keep generated CRUD state as UI scaffolding only, not as the current-state authority for FOC Platform rows.
FOC active-object cursors intentionally differ from generic builder short-page
semantics when stale tombstone traversal exceeds the scan budget: the registry
reverts with ActiveCursorTraversalLimitExceeded, and wrapper/dashboard code
should restart from the head cursor rather than interpreting that path as a
real end-of-list.
The generated byte-upload endpoint speaks Token Host Builder's upload adapter
contract: it accepts file bytes with X-TokenHost-Upload-* headers and returns
{ ok: true, upload: { url, size, provider, runnerMode, metadata } }. The
adapter then creates a section 6.7 upload request and submits the bytes through
the registry adapter. In this wrapper phase upload.url points at the platform
object read endpoint, not a public CDN retrieval URL.
The generated upload adapter status endpoint
GET /storage/tokenhost/upload/status returns Token Host upload-runner
metadata. The separate object-status alias
GET /storage/uploads/status?objectId=:objectId maps to the same registry read
as the canonical section 6.7 object status route,
GET /storage/uploads/:objectId/status.
These upstream Token Host Builder issues remain open:
tokenhost/tokenhost-builder#79: nativeapp.focPlatformschema and manifest extension.tokenhost/tokenhost-builder#80: registry lifecycle generation or tested wrapper mode.tokenhost/tokenhost-builder#81: generated FOC Platform admin and reconciliation surfaces.tokenhost/tokenhost-builder#82: receipt-aware upload runner path.
Until those land, FOC metadata lives in tokenhost/foc-platform-wrapper.config.json
and the wrapper manifest. The generated upload runner is prototype/demo
scaffolding, not proof of section 6.7-compatible receipts.
Run:
pnpm build:tokenhost
pnpm test:tokenhostThe focused smoke test drives a Token Host-style flow through the platform API:
- submit a generated Token Host byte upload through
/storage/tokenhost/upload, - create an upload request,
- submit bytes through the platform upload endpoint,
- read upload status,
- read object receipt state,
- read account usage.