Skip to content

fix(sdk): let a select or union render with no option preselected - #3871

Merged
dr-bonez merged 1 commit into
masterfrom
fix/sdk-select-no-default
Sep 2, 2026
Merged

fix(sdk): let a select or union render with no option preselected#3871
dr-bonez merged 1 commit into
masterfrom
fix/sdk-select-no-default

Conversation

@MattDHill

@MattDHill MattDHill commented Aug 30, 2026

Copy link
Copy Markdown
Member

Value.select and Value.union typed default as a required, non-nullable key, so a packager could not express "the user must choose" — every such field had to name a winner up front.

Everything downstream already supported the null case:

  • ValueSpecSelect.default and ValueSpecUnion.default are already string | null (inputSpecTypes.ts)
  • the UI builds a select as formBuilder.control(spec.default, [Validators.required]) (form.service.ts), so a null default renders unselected and blocks submission until the user picks; getUnionObject falls through to an empty sub-form
  • the builder's own doc comment already documented @type { (keyof Values & string) | null } and @example default: null

Only the public signature disagreed. This widens it on select, dynamicSelect, union and all three dynamicUnion overloads, and corrects the two doc comments that described the old contract.

Packages already need this and are casting around it — lnbits-startos/startos/actions/lightningImplementation.ts writes default: undefined as any to get an unselected Lightning-backend picker.

Every other builder — text, textarea, number, color, datetime, triState — already accepts a null default. select and union were the outliers; toggle and multiselect are correct as-is (binary, and an empty array already means "nothing selected").

Verification

npm run check clean across all projects; make web-format-check clean.

@MattDHill
MattDHill force-pushed the fix/sdk-select-no-default branch 2 times, most recently from e7ae612 to 0d19ab2 Compare August 30, 2026 22:31
@MattDHill
MattDHill requested a review from dr-bonez August 30, 2026 22:33
MattDHill added a commit to Start9Labs/mempool-startos that referenced this pull request Aug 31, 2026
…nfigured

`store.json.indexer` has no default, and the select that sets it declared
`default: 'fulcrum'` — so the form rendered as though Fulcrum were already
chosen. Closing it without saving persisted nothing, and the task that would
have forced the choice was gated on `kind === 'install'`, so an install that
updated into the feature was never asked at all.

With the choice unmade, `setupDependencies` declared no indexer and
`watchHosts` omitted the `ELECTRUM` section, while `MEMPOOL.BACKEND` stayed
pinned to `'electrum'`. Upstream's own defaults then applied — `127.0.0.1:3306`
with TLS on, which is this package's MariaDB — and the backend reconnected to
it once a second indefinitely. Both health checks stayed green throughout;
address lookups were silently dead. A demo box had logged 578,380 aborted
MariaDB connections this way.

- The select offers `none` and preselects nothing, so a choice has to be made.
- The task is raised whenever the choice is unmade, which reaches installs
  already in this state on their next start.
- `watchHosts` writes `MEMPOOL.BACKEND` alongside `ELECTRUM` — `electrum` when
  an address resolved, `none` otherwise — so the backend is never left on
  upstream's defaults. `BACKEND` is relaxed from a literal to that pair.
- `store.json.indexer` gains `'none'`: absent means unmade, `'none'` means
  declined.

No migration — `watchHosts` repairs `BACKEND` on every init and the task
reaches every affected install, so both halves heal on the next start.

`default: null` needs the SDK signature widened
(Start9Labs/start-technologies#3871); the cast goes when that ships.

Verified on demo.local, upgrading 3.3.1:23 → 3.3.1:24 in the broken state:
the task appeared on an *update* and blocked startup; `BACKEND` flipped to
`none` with `POLL_RATE_MS` intact; selecting Fulcrum resolved
`ELECTRUM 10.0.3.1:51537 TLS_ENABLED false`, added `fulcrum` to
`currentDependencies`, and cleared the task; the service came up with both
health checks green and logged `Connected to Electrum Server at
10.0.3.1:51537 (["Fulcrum 2.1.2","1.4"])`. Zero Electrum errors and zero
aborted MariaDB connections since. An address lookup through the published
port was not exercised — the port was not reachable from the test shell.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
MattDHill added a commit to Start9Labs/mempool-startos that referenced this pull request Aug 31, 2026
…nfigured (#83)

`store.json.indexer` has no default, and the select that sets it declared
`default: 'fulcrum'` — so the form rendered as though Fulcrum were already
chosen. Closing it without saving persisted nothing, and the task that would
have forced the choice was gated on `kind === 'install'`, so an install that
updated into the feature was never asked at all.

With the choice unmade, `setupDependencies` declared no indexer and
`watchHosts` omitted the `ELECTRUM` section, while `MEMPOOL.BACKEND` stayed
pinned to `'electrum'`. Upstream's own defaults then applied — `127.0.0.1:3306`
with TLS on, which is this package's MariaDB — and the backend reconnected to
it once a second indefinitely. Both health checks stayed green throughout;
address lookups were silently dead. A demo box had logged 578,380 aborted
MariaDB connections this way.

- The select offers `none` and preselects nothing, so a choice has to be made.
- The task is raised whenever the choice is unmade, which reaches installs
  already in this state on their next start.
- `watchHosts` writes `MEMPOOL.BACKEND` alongside `ELECTRUM` — `electrum` when
  an address resolved, `none` otherwise — so the backend is never left on
  upstream's defaults. `BACKEND` is relaxed from a literal to that pair.
- `store.json.indexer` gains `'none'`: absent means unmade, `'none'` means
  declined.

No migration — `watchHosts` repairs `BACKEND` on every init and the task
reaches every affected install, so both halves heal on the next start.

`default: null` needs the SDK signature widened
(Start9Labs/start-technologies#3871); the cast goes when that ships.

Verified on demo.local, upgrading 3.3.1:23 → 3.3.1:24 in the broken state:
the task appeared on an *update* and blocked startup; `BACKEND` flipped to
`none` with `POLL_RATE_MS` intact; selecting Fulcrum resolved
`ELECTRUM 10.0.3.1:51537 TLS_ENABLED false`, added `fulcrum` to
`currentDependencies`, and cleared the task; the service came up with both
health checks green and logged `Connected to Electrum Server at
10.0.3.1:51537 (["Fulcrum 2.1.2","1.4"])`. Zero Electrum errors and zero
aborted MariaDB connections since. An address lookup through the published
port was not exercised — the port was not reachable from the test shell.

Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
dr-bonez
dr-bonez previously approved these changes Sep 2, 2026
`Value.select` and `Value.union` typed `default` as a required, non-nullable
key, so a packager could not express "the user must choose" — every such field
had to name a winner up front. A preselected option is indistinguishable from
one the user picked, so the choice gets made silently and they never learn they
had one.

Everything downstream already supported it. `ValueSpecSelect.default` and
`ValueSpecUnion.default` are `string | null`; the UI builds a select control as
`formBuilder.control(spec.default, [Validators.required])`, so a null default
renders unselected and blocks submission until a choice is made, and
`getUnionObject` falls through to an empty sub-form. The builder's own doc
comment already documented `@type { (keyof Values & string) | null }` and
`@example default: null`. Only the public signature disagreed.

Every other builder — text, textarea, number, color, datetime, triState —
already accepts a null default; select and union were the outliers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dr-bonez
dr-bonez merged commit 080bcef into master Sep 2, 2026
17 checks passed
@dr-bonez
dr-bonez deleted the fix/sdk-select-no-default branch September 2, 2026 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants