mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
task fix and keyboard fix (#3130)
* task fix and keyboard fix
* fixes for build scripts
* passthrough feature
* feat: inline domain health checks and improve address UX
- addPublicDomain returns DNS query + port check results (AddPublicDomainRes)
so frontend skips separate API calls after adding a domain
- addPrivateDomain returns check_dns result for the gateway
- Support multiple ports per domain in validation modal (deduplicated)
- Run port checks concurrently via futures::future::join_all
- Add note to add-domain dialog showing other interfaces on same host
- Add addXForwardedHeaders to knownProtocols in SDK Host.ts
- Add plugin filter kind, pluginId filter, matchesAny, and docs to
getServiceInterface.ts
- Add PassthroughInfo type and passthroughs field to NetworkInfo
- Pluralize "port forwarding rules" in i18n dictionaries
* feat: add shared host note to private domain dialog with i18n
* fix: scope public domain to single binding and return single port check
Accept internalPort in AddPublicDomainParams to target a specific
binding. Disable the domain on all other bindings. Return a single
CheckPortRes instead of Vec. Revert multi-port UI to singular port
display from 0f8a66b35.
* better shared hostname approach, and improve look-feel of addresses tables
* fix starttls
* preserve usb as top efi boot option
* fix race condition in wan ip check
* sdk beta.56
* various bug, improve smtp
* multiple bugs, better outbound gateway UX
* remove non option from smtp for better package compat
* bump sdk
---------
Co-authored-by: Aiden McClelland <me@drbonez.dev>
This commit is contained in:
@@ -141,6 +141,7 @@ export class StartSdk<Manifest extends T.SDKManifest> {
|
||||
| 'getSystemSmtp'
|
||||
| 'getOutboundGateway'
|
||||
| 'getContainerIp'
|
||||
| 'getStatus'
|
||||
| 'getDataVersion'
|
||||
| 'setDataVersion'
|
||||
| 'getServiceManifest'
|
||||
@@ -164,7 +165,6 @@ export class StartSdk<Manifest extends T.SDKManifest> {
|
||||
getSslKey: (effects, ...args) => effects.getSslKey(...args),
|
||||
shutdown: (effects, ...args) => effects.shutdown(...args),
|
||||
getDependencies: (effects, ...args) => effects.getDependencies(...args),
|
||||
getStatus: (effects, ...args) => effects.getStatus(...args),
|
||||
setHealth: (effects, ...args) => effects.setHealth(...args),
|
||||
}
|
||||
|
||||
@@ -342,6 +342,104 @@ export class StartSdk<Manifest extends T.SDKManifest> {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the service's current status with reactive subscription support.
|
||||
*
|
||||
* Returns an object with multiple read strategies: `const()` for a value
|
||||
* that retries on change, `once()` for a single read, `watch()` for an async
|
||||
* generator, `onChange()` for a callback, and `waitFor()` to block until a predicate is met.
|
||||
*
|
||||
* @param effects - The effects context
|
||||
* @param options - Optional filtering options (e.g. `packageId`)
|
||||
*/
|
||||
getStatus: (
|
||||
effects: T.Effects,
|
||||
options: Omit<Parameters<T.Effects['getStatus']>[0], 'callback'> = {},
|
||||
) => {
|
||||
async function* watch(abort?: AbortSignal) {
|
||||
const resolveCell = { resolve: () => {} }
|
||||
effects.onLeaveContext(() => {
|
||||
resolveCell.resolve()
|
||||
})
|
||||
abort?.addEventListener('abort', () => resolveCell.resolve())
|
||||
while (effects.isInContext && !abort?.aborted) {
|
||||
let callback: () => void = () => {}
|
||||
const waitForNext = new Promise<void>((resolve) => {
|
||||
callback = resolve
|
||||
resolveCell.resolve = resolve
|
||||
})
|
||||
yield await effects.getStatus({ ...options, callback })
|
||||
await waitForNext
|
||||
}
|
||||
}
|
||||
return {
|
||||
const: () =>
|
||||
effects.getStatus({
|
||||
...options,
|
||||
callback:
|
||||
effects.constRetry &&
|
||||
(() => effects.constRetry && effects.constRetry()),
|
||||
}),
|
||||
once: () => effects.getStatus(options),
|
||||
watch: (abort?: AbortSignal) => {
|
||||
const ctrl = new AbortController()
|
||||
abort?.addEventListener('abort', () => ctrl.abort())
|
||||
return DropGenerator.of(watch(ctrl.signal), () => ctrl.abort())
|
||||
},
|
||||
onChange: (
|
||||
callback: (
|
||||
value: T.StatusInfo | null,
|
||||
error?: Error,
|
||||
) => { cancel: boolean } | Promise<{ cancel: boolean }>,
|
||||
) => {
|
||||
;(async () => {
|
||||
const ctrl = new AbortController()
|
||||
for await (const value of watch(ctrl.signal)) {
|
||||
try {
|
||||
const res = await callback(value)
|
||||
if (res.cancel) {
|
||||
ctrl.abort()
|
||||
break
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
'callback function threw an error @ getStatus.onChange',
|
||||
e,
|
||||
)
|
||||
}
|
||||
}
|
||||
})()
|
||||
.catch((e) => callback(null, e))
|
||||
.catch((e) =>
|
||||
console.error(
|
||||
'callback function threw an error @ getStatus.onChange',
|
||||
e,
|
||||
),
|
||||
)
|
||||
},
|
||||
waitFor: async (pred: (value: T.StatusInfo | null) => boolean) => {
|
||||
const resolveCell = { resolve: () => {} }
|
||||
effects.onLeaveContext(() => {
|
||||
resolveCell.resolve()
|
||||
})
|
||||
while (effects.isInContext) {
|
||||
let callback: () => void = () => {}
|
||||
const waitForNext = new Promise<void>((resolve) => {
|
||||
callback = resolve
|
||||
resolveCell.resolve = resolve
|
||||
})
|
||||
const res = await effects.getStatus({ ...options, callback })
|
||||
if (pred(res)) {
|
||||
resolveCell.resolve()
|
||||
return res
|
||||
}
|
||||
await waitForNext
|
||||
}
|
||||
return null
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
MultiHost: {
|
||||
/**
|
||||
* Create a new MultiHost instance for binding ports and exporting interfaces.
|
||||
|
||||
Reference in New Issue
Block a user