v0.0.9.2
Build Service / BuildPackage (push) Has been cancelled

This commit is contained in:
2026-05-24 19:10:21 -04:00
parent b308d0ceaa
commit 70b8aab0f3
10 changed files with 169 additions and 45 deletions
+2
View File
@@ -13,6 +13,7 @@ import { resetPassword } from './resetPassword'
import { resetSpacedState } from './resetSpacedState'
import { resetSubspacesState } from './resetSubspacesState'
import { setBitcoinRpc } from './setBitcoinRpc'
import { setSubsProver } from './setSubsProver'
import { showCredentials } from './showCredentials'
import { showDbCredentials } from './showDbCredentials'
import { showPassword } from './showPassword'
@@ -35,5 +36,6 @@ export const actions = sdk.Actions.of()
.addAction(resetExplorerState)
.addAction(enableSubspaces)
.addAction(disableSubspaces)
.addAction(setSubsProver)
.addAction(resetSubspacesState)
.addAction(configureCertrelay)
+61
View File
@@ -0,0 +1,61 @@
import { storeJson } from '../fileModels/storeJson'
import { i18n } from '../i18n'
import { sdk } from '../sdk'
const { InputSpec, Value } = sdk
const inputSpec = InputSpec.of({
enabled: Value.toggle({
name: i18n('Run Subspaces Prover'),
description: i18n(
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.',
),
warning: null,
footnote: null,
default: false,
}),
})
export const setSubsProver = sdk.Action.withInput(
// id
'set-subs-prover',
// metadata
async ({ effects }) => ({
name: i18n('Enable / Disable Subspaces Prover'),
description: i18n(
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.',
),
warning: null,
allowedStatuses: 'any',
group: null,
visibility: 'enabled',
}),
// input
inputSpec,
// prefill — current value
async ({ effects }) => {
const enabled = await storeJson.read((s) => s.enableSubsProver).once()
return { enabled: enabled === true }
},
// run
async ({ effects, input }) => {
await storeJson.merge(effects, { enableSubsProver: input.enabled })
return {
version: '1',
title: i18n('Success'),
message: input.enabled
? i18n(
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.',
)
: i18n(
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.',
),
result: null,
}
},
)
+1
View File
@@ -27,6 +27,7 @@ const shape = z.object({
.catch(null),
enableExplorer: z.boolean().nullable().catch(null),
enableSubspaces: z.boolean().nullable().catch(null),
enableSubsProver: z.boolean().nullable().catch(null),
certrelaySelfUrl: z.string().nullable().catch(null),
certrelayBootstrap: z.boolean().nullable().catch(null),
certrelayHealthcheckHandle: z.string().nullable().catch(null),
+13
View File
@@ -128,6 +128,19 @@ const dict = {
133,
'Certrelay configuration saved. The service is restarting to apply the new settings.':
134,
'Enable / Disable Subspaces Prover': 135,
'Independently start or stop the subs-prover daemon, separate from the overall Subspaces toggle. Saving restarts the service.':
136,
'Run Subspaces Prover': 137,
'When on, the subs-prover daemon starts (only while Subspaces itself is enabled). It runs lengthy timing tests on boot and can take a long time to become ready. Off by default. The Subspaces Prover interface (port 8888) stays registered either way.':
138,
'Subspaces Prover enabled. The service is restarting; the prover starts after the other Subspaces daemons and may take a while to become ready.':
139,
'Subspaces Prover disabled. The service is restarting; the prover daemon will not start. Its interface (8888) remains registered.':
140,
'Subs API': 141,
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.':
142,
// interfaces.ts
'Space-CLI Web UI': 12,
+11 -7
View File
@@ -2,12 +2,16 @@ import { storeJson } from '../fileModels/storeJson'
import { sdk } from '../sdk'
export const taskSeedEnableSubspaces = sdk.setupOnInit(async (effects) => {
const existing = await storeJson.read((s) => s.enableSubspaces).once()
if (existing !== null && existing !== undefined) return
const store = await storeJson.read().once()
await storeJson.merge(
effects,
{ enableSubspaces: false },
{ allowWriteAfterConst: true },
)
const patch: { enableSubspaces?: boolean; enableSubsProver?: boolean } = {}
if (store?.enableSubspaces === null || store?.enableSubspaces === undefined)
patch.enableSubspaces = false
// subs-prover is independently gated and defaults OFF.
if (store?.enableSubsProver === null || store?.enableSubsProver === undefined)
patch.enableSubsProver = false
if (Object.keys(patch).length > 0) {
await storeJson.merge(effects, patch, { allowWriteAfterConst: true })
}
})
+21 -1
View File
@@ -68,7 +68,27 @@ export const setInterfaces = sdk.setupInterfaces(async ({ effects }) => {
query: {},
})
const subspacesReceipt = await subspacesMultiOrigin.export([subspaces])
// The subs daemon ("subsd — HTTP REST API server for subs operations") serves
// its REST API on the same port. Expose it as a distinct `api` interface,
// separate from the prover (8888) and registry (8081) interfaces.
const subsApi = sdk.createInterface(effects, {
name: i18n('Subs API'),
id: 'subs-api',
description: i18n(
'REST API of the subs daemon (subsd) for Subspaces operations. Distinct from the Subspaces Prover and Subspaces Registry. Only useful while Subspaces is enabled.',
),
type: 'api',
masked: false,
schemeOverride: null,
username: null,
path: '',
query: {},
})
const subspacesReceipt = await subspacesMultiOrigin.export([
subspaces,
subsApi,
])
const proverMulti = sdk.MultiHost.of(effects, 'subspaces-prover-multi')
const proverMultiOrigin = await proverMulti.bindPort(SUBSPACES_PROVER_PORT, {
+42 -28
View File
@@ -56,6 +56,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
const { password: APP_PASSWORD, btcAuth, dbAuth, spacedAuth } = store
const enableExplorer = store.enableExplorer === true
const enableSubspaces = store.enableSubspaces === true
// subs-prover is independently gated and defaults OFF (null/undefined => false).
const enableSubsProver = store.enableSubsProver === true
const spacedEnv = {
SPACED_CHAIN,
@@ -262,8 +264,8 @@ export const main = sdk.setupMain(async ({ effects }) => {
// Appends the Subspaces chain (fetch → build → wallet ensure → subs-prover →
// subs daemon) to any existing chain. `as any` because the chain's TS type
// depends on prior IDs and we can't easily express the union here.
const withSubspaces = (chain: any): any =>
chain
const withSubspaces = (chain: any): any => {
let c = chain
.addOneshot('subspaces-dirs', {
subcontainer: subspacesSub,
exec: {
@@ -278,32 +280,6 @@ export const main = sdk.setupMain(async ({ effects }) => {
},
requires: [],
})
.addDaemon('subs-prover', {
subcontainer: subspacesSub,
exec: {
command: [
'sh',
'-c',
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
],
env: proverEnv,
// Run as root: the horologger/subs image declares USER subs, but our
// /data volume + subdirs are root-owned, so the non-root user can't
// traverse/write them. Root sidesteps the ownership mismatch.
user: 'root',
},
ready: {
display: i18n('Subspaces Prover'),
fn: () =>
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
successMessage: i18n('subs-prover is ready'),
errorMessage: i18n('subs-prover is not ready'),
}),
gracePeriod: 60_000,
trigger: sdk.trigger.cooldownTrigger(30_000),
},
requires: ['subspaces-dirs'],
})
.addDaemon('subs-registry', {
subcontainer: subspacesSub,
exec: {
@@ -349,6 +325,44 @@ export const main = sdk.setupMain(async ({ effects }) => {
requires: ['subspaces-dirs', 'spaced', 'subs-registry'],
})
// subs-prover is opt-in and DISABLED BY DEFAULT (toggle via the "Enable
// Subspaces Prover" action). Its interface (8888) stays registered either
// way (see interfaces.ts), but the daemon only starts when enabled. It's
// added LAST and depends on every other subspaces daemon; it runs lengthy
// timing tests on boot and NOTHING depends on it, so its slow startup never
// blocks anything else.
if (enableSubsProver) {
c = c.addDaemon('subs-prover', {
subcontainer: subspacesSub,
exec: {
command: [
'sh',
'-c',
`cd ${SUBSPACES_PROVER_DIR} && exec ${SUBSPACES_PROVER_BIN} --server --server-port ${SUBSPACES_PROVER_PORT}`,
],
env: proverEnv,
// Run as root: the horologger/subs image declares USER subs, but our
// /data volume + subdirs are root-owned, so the non-root user can't
// traverse/write them. Root sidesteps the ownership mismatch.
user: 'root',
},
ready: {
display: i18n('Subspaces Prover'),
fn: () =>
sdk.healthCheck.checkPortListening(effects, SUBSPACES_PROVER_PORT, {
successMessage: i18n('subs-prover is ready'),
errorMessage: i18n('subs-prover is not ready'),
}),
gracePeriod: 60_000,
trigger: sdk.trigger.cooldownTrigger(30_000),
},
requires: ['subspaces-dirs', 'subs-registry', 'subs'],
})
}
return c
}
if (!enableExplorer) {
// Spaces-only mode: spaced + gotty terminal. No PostgreSQL, no indexer.
// User can flip the toggle via the Enable Embedded Explorer action;
+2 -2
View File
@@ -1,7 +1,7 @@
import { VersionGraph } from '@start9labs/start-sdk'
import { v_0_0_9_1 } from './v0.0.9.1'
import { v_0_0_9_2 } from './v0.0.9.2'
export const versionGraph = VersionGraph.of({
current: v_0_0_9_1,
current: v_0_0_9_2,
other: [],
})
@@ -1,9 +1,11 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_0_0_9_1 = VersionInfo.of({
version: '0.0.9:1',
export const v_0_0_9_2 = VersionInfo.of({
version: '0.0.9:2',
releaseNotes: {
en_US: `- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface.
en_US: `- Added a dedicated "Subs API" interface (type api) on the subs daemon's port (7777), distinct from the Subspaces Prover (8888) and Subspaces Registry (8081) interfaces. The subs daemon is "subsd — an HTTP REST API server"; this surfaces that REST API as its own dashboard entry.
- New "Enable / Disable Subspaces Prover" action independently gates just the subs-prover daemon (store.enableSubsProver), **disabled by default**. When off, subs-prover does not start (it runs lengthy boot-time timing tests), but its interface on 8888 stays registered. It is added last and nothing depends on it, so its slow startup never blocks subs, the registry, or certrelay.
- Embedded Certrelay (prebuilt \`horologger/certrelay:v0.2.3\` image, static musl binaries). Always on — runs the \`certrelay\` server on port 7778 from service start, as its own StartOS interface. It serves cryptographic proofs binding Bitcoin-anchored handles to owner keys, talking to the local spaced over loopback using the store.spacedAuth credentials. The bundled \`fabric\` CLI is copied to /data/bin/fabric so it's runnable from the Space-CLI Web UI. New "Configure Certrelay" action sets CERTRELAY_SELF_URL, CERTRELAY_BOOTSTRAP, and CERTRELAY_HEALTHCHECK_HANDLE (stored in store.json; saving restarts the service). Set CERTRELAY_SELF_URL to the publicly visible URL StartOS exposes for the Certrelay interface.
- Removed the build-from-source chains for the Go indexer and the SvelteKit explorer, and dropped their builder images (\`golang:1.23-alpine\`, \`node:20-alpine\`). This shrinks the .s9pk and removes the multi-minute first-enable compile. The indexer + explorer-UI daemons are now stubbed with TODOs in startos/main.ts pending prebuilt images (indexer image not yet produced; explorer image to be provided). Enabling the embedded explorer currently starts PostgreSQL only. All explorer-indexer actions (show-db-credentials, reset-db-state, reset-indexer-state, reset-explorer-state) are retained.
- Embedded Subspaces support (prebuilt \`horologger/subs:v0.1.0\` image). Opt-in via the new "Enable Subspaces" action; "Disable Subspaces" stops it. No compile step — enabling starts three prebuilt daemons, each on its own StartOS interface: **subs** (Web UI, 7777), **subs-prover** (RISC Zero prover, no GPU, 8888), and **registry-server** (handle registry, 8081). subs loads the existing \`default\` spaces wallet at startup (it does not create one). Runtime data persists at /data/subspaces/data across restarts and toggles. New "Reset Subspaces State" action wipes local data. Adds a fifth manifest image (\`horologger/subs:v0.1.0\`, ~84 MB) — switched from building \`spacesops/subs\` from source with \`rust:1-slim\` to shrink the .s9pk and eliminate the multi-minute first-enable compile.
- Five distinct interfaces now appear in the dashboard: **Space-CLI Web UI** (gotty terminal, 8080), **Explorer Web UI** (3000, opt-in), **Subspaces Web UI** (7777, opt-in), **Subspaces Prover** (8888, opt-in), **Subspaces Registry** (8081, opt-in). Internal "Web UI" references renamed to **Space-CLI Web UI** for clarity.