Repository navigation
v0.1.2
settings.describe() is not always a promise — in both halves, and the host one never worked.
settings.describe() was called with .then(...) unconditionally, but that one name has
two implementations: the typert WIRE form returns a Promise, while the DIRECT form —
SettingsController.describe() in @deepseek-ai/dsh-api-settings-controller — is
synchronous and returns the view object itself, and can throw instead
(settings service is absent: mount @deepseek-ai/dsh-settings).
The resulting TypeError: settings.describe(...).then is not a function is raised
synchronously, so it escaped before the .catch at the end of the loader's chain.
This plugin's apply() is async with no internal try/catch, so the throw rejected apply — and a
failed apply fails the Cordis fiber: the plugin never activates and its five switches silently never
appear.
The HOST half was worse. Its migration (ctx.inject(['settings'], …)) reads the HOST service —
SettingsForms from @deepseek-ai/dsh-settings — whose describe() is synchronous and returns the
descriptor array, not a {ok, value} envelope. settings.describe().then(...) therefore threw on
the spot, and because the throw happens at the .then access it escaped the .catch(() => {}) at
the end of that chain: the dock-flash → dsh-flash-proxy settings migration has never run once. Now
normalized, and it accepts both shapes.
Both call sites now normalize through _describeAsync(), which accepts a Promise, a plain view, or a
throw, so the loader's existing .catch handles it instead of the plugin dying.
Hardening, in the same release. apply() had no internal try/catch, so any throw inside it
rejected the async apply — and a failed apply fails the Cordis fiber: the plugin never activates
and its switch silently never appears. The body is unchanged and now lives in _applyInner; the public
apply reports the failure (apply failed (non-fatal)) and returns, exactly as dock-flash's has always
done.
Patch: no published surface changed.