Upgrade to SpacesOps v1.0.1 and fix v1.0.1:1 startup on StartOS.

Bump the image to spacesops/spacesops:v1.0.1, always inject NODE_EXTRA_CA_CERTS from sdk.getSslCertificate so the upstream entrypoint no longer crashes on unset _SCRIPT_DIR, and document the same-host HTTPS behavior in the README.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-23 12:07:38 -04:00
co-authored by Cursor
parent 147f51d710
commit feb32a1456
12 changed files with 230 additions and 43 deletions
+10 -5
View File
@@ -39,7 +39,7 @@ auto-connects to it — see [Installation and First-Run Flow](#installation-and-
| Field | Value | | Field | Value |
| --- | --- | | --- | --- |
| Image | `docker.io/spacesops/spacesops:v1.0.0` | | Image | `docker.io/spacesops/spacesops:v1.0.1` |
| Base | `node:20-alpine` | | Base | `node:20-alpine` |
| Architectures | `x86_64` (linux/amd64), `aarch64` (linux/arm64) | | Architectures | `x86_64` (linux/amd64), `aarch64` (linux/arm64) |
| Entrypoint | The image's `/app/docker-entrypoint.sh` is **kept**. StartOS runs `/app/docker-entrypoint.sh node server.js` as the daemon. | | Entrypoint | The image's `/app/docker-entrypoint.sh` is **kept**. StartOS runs `/app/docker-entrypoint.sh node server.js` as the daemon. |
@@ -139,7 +139,7 @@ volume is **not** part of this package's backup.
and sync Spaces before (or alongside) SpacesOps; the service restarts until and sync Spaces before (or alongside) SpacesOps; the service restarts until
those credentials are available. those credentials are available.
2. **The admin password is fixed and well-known.** Admin Basic Auth is hardcoded 2. **The admin password is fixed and well-known.** Admin Basic Auth is hardcoded
in the v1.0.0 image as `admin` / `Whatever!` with **no environment override**. in the v1.0.1 image as `admin` / `Whatever!` with **no environment override**.
It cannot be changed without rebuilding the image. **Keep this service private It cannot be changed without rebuilding the image. **Keep this service private
(Tor-only) and never expose its admin routes to the public internet** — the (Tor-only) and never expose its admin routes to the public internet** — the
admin area can run SQL and manage tenants. See **Show Admin Credentials**. admin area can run SQL and manage tenants. See **Show Admin Credentials**.
@@ -151,7 +151,11 @@ volume is **not** part of this package's backup.
5. **The SUBS backend is not auto-wired to the Spaces subs daemon in v1.** The 5. **The SUBS backend is not auto-wired to the Spaces subs daemon in v1.** The
Spaces service's subs daemon listens on 7777 with a different API/auth than Spaces service's subs daemon listens on 7777 with a different API/auth than
the SUBS endpoint (port 7244) SpacesOps expects, so SUBS must be configured the SUBS endpoint (port 7244) SpacesOps expects, so SUBS must be configured
manually if used. manually if used. StartOS always sets `NODE_EXTRA_CA_CERTS` to the StartOS
root CA (fetched via `sdk.getSslCertificate` for the SUBS `*.startos`
hostname when configured, otherwise `spaces.startos`) so outbound HTTPS to
same-host StartOS services succeeds and the v1.0.1 image entrypoint does not
crash on its broken `_SCRIPT_DIR` default.
## What Is Unchanged from Upstream ## What Is Unchanged from Upstream
@@ -166,8 +170,8 @@ volume is **not** part of this package's backup.
```yaml ```yaml
package_id: spacesops package_id: spacesops
upstream_version: 1.0.0 upstream_version: 1.0.1
image: docker.io/spacesops/spacesops:v1.0.0 image: docker.io/spacesops/spacesops:v1.0.1
architectures: [x86_64, aarch64] architectures: [x86_64, aarch64]
volumes: volumes:
main: /data main: /data
@@ -196,6 +200,7 @@ optional_env_vars: # only set when configured via configure-platform
- SUBS_URI_VALUE - SUBS_URI_VALUE
- SUBS_RPC_USER - SUBS_RPC_USER
- SUBS_RPC_PASSWORD - SUBS_RPC_PASSWORD
- NODE_EXTRA_CA_CERTS # /data/.startos/startos-root-ca.crt (always set)
admin_credentials: admin_credentials:
username: admin username: admin
password: Whatever! # FIXED, baked into image, cannot be changed password: Whatever! # FIXED, baked into image, cannot be changed
+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1024mm"
height="500mm"
viewBox="0 0 1024 500"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="spaceswallet.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.15"
inkscape:cx="2150"
inkscape:cy="110"
inkscape:window-width="1312"
inkscape:window-height="874"
inkscape:window-x="184"
inkscape:window-y="29"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="473.026"
y="159.67598"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="473.026"
y="159.67598">@</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="96.926056"
y="312.17776"
id="text1-3"><tspan
sodipodi:role="line"
id="tspan1-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.111px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="96.926056"
y="312.17776">SpacesWallet</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+8 -8
View File
@@ -8,7 +8,7 @@
version="1.1" version="1.1"
id="svg1" id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)" inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="spacesops.svg" sodipodi:docname="icon.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@@ -25,7 +25,7 @@
inkscape:document-units="mm" inkscape:document-units="mm"
inkscape:zoom="0.5" inkscape:zoom="0.5"
inkscape:cx="365" inkscape:cx="365"
inkscape:cy="260" inkscape:cy="452"
inkscape:window-width="1312" inkscape:window-width="1312"
inkscape:window-height="995" inkscape:window-height="995"
inkscape:window-x="550" inkscape:window-x="550"
@@ -40,14 +40,14 @@
id="layer1"> id="layer1">
<text <text
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:139.331px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:19.7477;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="-1.9590863" x="10.27656"
y="82.934502" y="75.009308"
id="text1"><tspan id="text1"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan1" id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:139.331px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:19.7477" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="-1.9590863" x="10.27656"
y="82.934502">@</tspan></text> y="75.009308">@</tspan></text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

+7 -7
View File
@@ -25,7 +25,7 @@
inkscape:document-units="mm" inkscape:document-units="mm"
inkscape:zoom="0.5" inkscape:zoom="0.5"
inkscape:cx="365" inkscape:cx="365"
inkscape:cy="260" inkscape:cy="452"
inkscape:window-width="1312" inkscape:window-width="1312"
inkscape:window-height="995" inkscape:window-height="995"
inkscape:window-x="550" inkscape:window-x="550"
@@ -40,14 +40,14 @@
id="layer1"> id="layer1">
<text <text
xml:space="preserve" xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:139.331px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:19.7477;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="-1.9590863" x="10.27656"
y="82.934502" y="75.009308"
id="text1"><tspan id="text1"><tspan
sodipodi:role="line" sodipodi:role="line"
id="tspan1" id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:139.331px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:19.7477" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="-1.9590863" x="10.27656"
y="82.934502">@</tspan></text> y="75.009308">@</tspan></text>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

+64
View File
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="1024mm"
height="500mm"
viewBox="0 0 1024 500"
version="1.1"
id="svg1"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
sodipodi:docname="spaceswallet.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.15"
inkscape:cx="2150"
inkscape:cy="1643.3333"
inkscape:window-width="1312"
inkscape:window-height="874"
inkscape:window-x="184"
inkscape:window-y="29"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="473.026"
y="159.67598"
id="text1"><tspan
sodipodi:role="line"
id="tspan1"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="473.026"
y="159.67598">@</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:108.156px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291;stroke-linecap:round;stroke-miterlimit:3;paint-order:fill markers stroke"
x="96.926056"
y="312.17776"
id="text1-3"><tspan
sodipodi:role="line"
id="tspan1-9"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:141.111px;font-family:Outfit;-inkscape-font-specification:'Outfit, @wght=400';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;font-variation-settings:'wght' 400;fill:#903369;fill-opacity:1;stroke:none;stroke-width:15.3291"
x="96.926056"
y="312.17776">SpacesWallet</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+22
View File
@@ -1,3 +1,4 @@
import { mkdir, writeFile } from 'fs/promises'
import { storeJson } from './fileModels/storeJson' import { storeJson } from './fileModels/storeJson'
import { i18n } from './i18n' import { i18n } from './i18n'
import { sdk } from './sdk' import { sdk } from './sdk'
@@ -8,6 +9,10 @@ import {
SPACED_RPC_URL, SPACED_RPC_URL,
SPACED_WALLETLOAD_NAME, SPACED_WALLETLOAD_NAME,
spacesDataDir, spacesDataDir,
startOsHostnameFromUrl,
nodeExtraCaCertContainerPath,
nodeExtraCaCertVolumeSubpath,
SPACES_PACKAGE_ID,
uiPort, uiPort,
} from './utils' } from './utils'
@@ -106,6 +111,23 @@ export const main = sdk.setupMain(async ({ effects }) => {
if (store.subsUser) env.SUBS_RPC_USER = store.subsUser if (store.subsUser) env.SUBS_RPC_USER = store.subsUser
if (store.subsPassword) env.SUBS_RPC_PASSWORD = store.subsPassword if (store.subsPassword) env.SUBS_RPC_PASSWORD = store.subsPassword
// v1.0.1's entrypoint sources setup-spacesops-env.sh with set -u. That file
// exports NODE_EXTRA_CA_CERTS using ${_SCRIPT_DIR}, but _SCRIPT_DIR is set on
// a separate non-export line the entrypoint never evals — startup crashes
// unless NODE_EXTRA_CA_CERTS is already set. Fetch the StartOS root CA for
// outbound *.startos HTTPS (SUBS_URI host when configured, else Spaces).
const caHostname =
(store.subsUrl && startOsHostnameFromUrl(store.subsUrl)) ||
`${SPACES_PACKAGE_ID}.startos`
const certs = await sdk.getSslCertificate(effects, [caHostname]).const()
const [rootCa] = certs.slice(-1)
await mkdir(sdk.volumes.main.subpath('.startos'), { recursive: true })
await writeFile(
sdk.volumes.main.subpath(nodeExtraCaCertVolumeSubpath),
rootCa,
)
env.NODE_EXTRA_CA_CERTS = nodeExtraCaCertContainerPath
return sdk.Daemons.of(effects).addDaemon('spacesops', { return sdk.Daemons.of(effects).addDaemon('spacesops', {
subcontainer: sub, subcontainer: sub,
exec: { exec: {
+1 -1
View File
@@ -14,7 +14,7 @@ export const manifest = setupManifest({
volumes: ['main'], volumes: ['main'],
images: { images: {
spacesops: { spacesops: {
source: { dockerTag: 'spacesops/spacesops:v1.0.0' }, source: { dockerTag: 'spacesops/spacesops:v1.0.1' },
arch: ['x86_64', 'aarch64'], arch: ['x86_64', 'aarch64'],
}, },
}, },
+23 -2
View File
@@ -20,13 +20,34 @@ export const SPACES_PACKAGE_ID = 'spaces'
export const SPACED_RPC_URL = 'http://spaces.startos:7225' export const SPACED_RPC_URL = 'http://spaces.startos:7225'
export const SPACED_WALLETLOAD_NAME = 'main' export const SPACED_WALLETLOAD_NAME = 'main'
// Admin Basic Auth is baked into the v1.0.0 image with NO env override. It // Admin Basic Auth is baked into the v1.0.1 image with NO env override. It
// cannot be changed without rebuilding the image. Surfaced (with a warning) // cannot be changed without rebuilding the image. Surfaced (with a warning)
// via the "Show Admin Credentials" action. // via the "Show Admin Credentials" action.
export const ADMIN_USER = 'admin' export const ADMIN_USER = 'admin'
export const ADMIN_PASSWORD = 'Whatever!' export const ADMIN_PASSWORD = 'Whatever!'
// Optional-config defaults (see the "Configure Platform" action). // Where StartOS writes the StartOS root CA for outbound *.startos HTTPS (see
// main.ts). Always injected as NODE_EXTRA_CA_CERTS — required on v1.0.1+ where
// the image entrypoint's setup-spacesops-env.sh references _SCRIPT_DIR without
// defining it under set -u.
export const nodeExtraCaCertVolumeSubpath = '.startos/startos-root-ca.crt'
export const nodeExtraCaCertContainerPath = `${dataDir}/.startos/startos-root-ca.crt`
// Legacy aliases (same file path after rename).
export const subsCaCertVolumeSubpath = nodeExtraCaCertVolumeSubpath
export const subsCaCertContainerPath = nodeExtraCaCertContainerPath
// Returns the hostname when url targets another StartOS service on this server
// (e.g. https://spaces.startos:7777), otherwise null.
export function startOsHostnameFromUrl(url: string): string | null {
try {
const hostname = new URL(url).hostname
return hostname.endsWith('.startos') ? hostname : null
} catch {
return null
}
}
export const DEFAULT_OPERATOR_RELAY = 'wss://relay.primal.net' export const DEFAULT_OPERATOR_RELAY = 'wss://relay.primal.net'
export const DEFAULT_PLATFORM_MODE = 'prod' export const DEFAULT_PLATFORM_MODE = 'prod'
export const DEFAULT_COINGECKO_TOKEN_COINS = 'bitcoin' export const DEFAULT_COINGECKO_TOKEN_COINS = 'bitcoin'
+4 -3
View File
@@ -1,7 +1,8 @@
import { VersionGraph } from '@start9labs/start-sdk' import { VersionGraph } from '@start9labs/start-sdk'
import { v_1_0_0_0 } from './v1.0.0.0' import { v_1_0_1_0 } from './v1.0.1.0'
import { v_1_0_1_1 } from './v1.0.1.1'
export const versionGraph = VersionGraph.of({ export const versionGraph = VersionGraph.of({
current: v_1_0_0_0, current: v_1_0_1_1,
other: [], other: [v_1_0_1_0],
}) })
-17
View File
@@ -1,17 +0,0 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_1_0_0_0 = VersionInfo.of({
version: '1.0.0:0',
releaseNotes: {
en_US: `Initial StartOS package for SpacesOps (upstream v1.0.0).
- Runs the SpacesOps web platform (Express + SQLite) from the prebuilt spacesops/spacesops:v1.0.0 image on x86_64 and aarch64.
- Depends on the Spaces service and auto-connects to its spaced JSON-RPC at spaces.startos:7225 by reading the Spaces RPC credentials from the mounted Spaces volume.
- Generates a Nostr operator keypair and a strong session secret on first install. "Show Operator Credentials" and "Import Operator Key" actions manage the keypair.
- "Show Admin Credentials" surfaces the fixed, well-known admin login baked into the image, with a warning to keep the service private.
- "Configure Platform" optionally sets the Nostr relay, theme mode, CoinGecko pricing, and SUBS backend.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})
+14
View File
@@ -0,0 +1,14 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_1_0_1_0 = VersionInfo.of({
version: '1.0.1:0',
releaseNotes: {
en_US: `Upstream upgrade to SpacesOps v1.0.1.
- Bumps the image to spacesops/spacesops:v1.0.1 on x86_64 and aarch64.
- No StartOS-side configuration, action, or migration changes; existing operator keypair, session secret, and Configure-Platform settings are preserved.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})
+13
View File
@@ -0,0 +1,13 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
export const v_1_0_1_1 = VersionInfo.of({
version: '1.0.1:1',
releaseNotes: {
en_US: `- Always sets NODE_EXTRA_CA_CERTS before the v1.0.1 image entrypoint runs, fetching the StartOS root CA via sdk.getSslCertificate (SUBS *.startos hostname when configured, otherwise spaces.startos). Fixes startup crash where setup-spacesops-env.sh references unset _SCRIPT_DIR under set -u.
- Enables outbound HTTPS to same-host StartOS services from SpacesOps.`,
},
migrations: {
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})