mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
Feature/consolidate setup (#3092)
* start consolidating * add start-cli flash-os * combine install and setup and refactor all * use http * undo mock * fix translation * translations * use dialogservice wrapper * better ST messaging on setup * only warn on update if breakages (#3097) * finish setup wizard and ui language-keyboard feature * fix typo * wip: localization * remove start-tunnel readme * switch to posix strings for language internal * revert mock * translate backend strings * fix missing about text * help text for args * feat: add "Add new gateway" option (#3098) * feat: add "Add new gateway" option * Update web/projects/ui/src/app/routes/portal/components/form/controls/select.component.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * add translation --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Matt Hill <mattnine@protonmail.com> * fix dns selection * keyboard keymap also * ability to shutdown after install * revert mock * working setup flow + manifest localization * (mostly) redundant localization on frontend * version bump * omit live medium from disk list and better space management * ignore missing package archive on 035 migration * fix device migration * add i18n helper to sdk * fix install over 0.3.5.1 * fix grub config --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com> Co-authored-by: Alex Inkin <alexander@inkin.ru> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type AddCategoryParams = { id: string; name: string }
|
||||
export type AddCategoryParams = { id: string; name: LocaleString }
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type Alerts = {
|
||||
install: string | null
|
||||
uninstall: string | null
|
||||
restore: string | null
|
||||
start: string | null
|
||||
stop: string | null
|
||||
install: LocaleString | null
|
||||
uninstall: LocaleString | null
|
||||
restore: LocaleString | null
|
||||
start: LocaleString | null
|
||||
stop: LocaleString | null
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import type { EncryptedWire } from "./EncryptedWire"
|
||||
|
||||
export type AttachParams = {
|
||||
startOsPassword: EncryptedWire | null
|
||||
password: EncryptedWire | null
|
||||
guid: string
|
||||
kiosk?: boolean
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type Category = { name: string }
|
||||
export type Category = { name: LocaleString }
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DataUrl } from "./DataUrl"
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type CurrentDependencyInfo = {
|
||||
title: string | null
|
||||
title: LocaleString | null
|
||||
icon: DataUrl | null
|
||||
versionRange: string
|
||||
} & ({ kind: "exists" } | { kind: "running"; healthChecks: string[] })
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DataUrl } from "./DataUrl"
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type DependencyMetadata = {
|
||||
title: string | null
|
||||
title: LocaleString | null
|
||||
icon: DataUrl | null
|
||||
description: string | null
|
||||
description: LocaleString | null
|
||||
optional: boolean
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
|
||||
export type Description = { short: string; long: string }
|
||||
export type Description = { short: LocaleString; long: LocaleString }
|
||||
|
||||
9
sdk/base/lib/osBindings/KeyboardOptions.ts
Normal file
9
sdk/base/lib/osBindings/KeyboardOptions.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type KeyboardOptions = {
|
||||
layout: string
|
||||
keymap: string | null
|
||||
model: string | null
|
||||
variant: string | null
|
||||
options: Array<string>
|
||||
}
|
||||
3
sdk/base/lib/osBindings/LocaleString.ts
Normal file
3
sdk/base/lib/osBindings/LocaleString.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type LocaleString = string | Record<string, string>
|
||||
@@ -6,6 +6,7 @@ import type { GitHash } from "./GitHash"
|
||||
import type { HardwareRequirements } from "./HardwareRequirements"
|
||||
import type { ImageConfig } from "./ImageConfig"
|
||||
import type { ImageId } from "./ImageId"
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { Version } from "./Version"
|
||||
import type { VolumeId } from "./VolumeId"
|
||||
@@ -15,7 +16,7 @@ export type Manifest = {
|
||||
title: string
|
||||
version: Version
|
||||
satisfies: Array<Version>
|
||||
releaseNotes: string
|
||||
releaseNotes: LocaleString
|
||||
canMigrateTo: string
|
||||
canMigrateFrom: string
|
||||
license: string
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
import type { PathOrUrl } from "./PathOrUrl"
|
||||
|
||||
export type Metadata = { title: string; icon: PathOrUrl }
|
||||
export type Metadata = { title: LocaleString; icon: PathOrUrl }
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { DependencyMetadata } from "./DependencyMetadata"
|
||||
import type { Description } from "./Description"
|
||||
import type { GitHash } from "./GitHash"
|
||||
import type { HardwareRequirements } from "./HardwareRequirements"
|
||||
import type { LocaleString } from "./LocaleString"
|
||||
import type { MerkleArchiveCommitment } from "./MerkleArchiveCommitment"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { RegistryAsset } from "./RegistryAsset"
|
||||
@@ -15,7 +16,7 @@ export type PackageVersionInfo = {
|
||||
title: string
|
||||
icon: DataUrl
|
||||
description: Description
|
||||
releaseNotes: string
|
||||
releaseNotes: LocaleString
|
||||
gitHash: GitHash | null
|
||||
license: string
|
||||
wrapperRepo: string
|
||||
|
||||
3
sdk/base/lib/osBindings/Pem.ts
Normal file
3
sdk/base/lib/osBindings/Pem.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Pem = string
|
||||
@@ -1,5 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Governor } from "./Governor"
|
||||
import type { KeyboardOptions } from "./KeyboardOptions"
|
||||
import type { LshwDevice } from "./LshwDevice"
|
||||
import type { NetworkInfo } from "./NetworkInfo"
|
||||
import type { ServerStatus } from "./ServerStatus"
|
||||
@@ -27,4 +28,6 @@ export type ServerInfo = {
|
||||
ram: number
|
||||
devices: Array<LshwDevice>
|
||||
kiosk: boolean | null
|
||||
language: string | null
|
||||
keyboard: KeyboardOptions | null
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { EncryptedWire } from "./EncryptedWire"
|
||||
import type { RecoverySource } from "./RecoverySource"
|
||||
|
||||
export type SetupExecuteParams = {
|
||||
startOsLogicalname: string
|
||||
startOsPassword: EncryptedWire
|
||||
guid: string
|
||||
password: EncryptedWire
|
||||
recoverySource: RecoverySource<EncryptedWire> | null
|
||||
kiosk?: boolean
|
||||
}
|
||||
|
||||
3
sdk/base/lib/osBindings/SetupInfo.ts
Normal file
3
sdk/base/lib/osBindings/SetupInfo.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SetupInfo = { guid: string | null; attach: boolean }
|
||||
@@ -1,8 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Pem } from "./Pem"
|
||||
|
||||
export type SetupResult = {
|
||||
torAddresses: Array<string>
|
||||
hostname: string
|
||||
lanAddress: string
|
||||
rootCa: string
|
||||
rootCa: Pem
|
||||
needsRestart: boolean
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { SetupInfo } from "./SetupInfo"
|
||||
import type { SetupProgress } from "./SetupProgress"
|
||||
import type { SetupResult } from "./SetupResult"
|
||||
|
||||
export type SetupStatusRes =
|
||||
| ({ status: "complete" } & SetupResult)
|
||||
| { status: "needs-install" }
|
||||
| ({ status: "incomplete" } & SetupInfo)
|
||||
| ({ status: "running" } & SetupProgress)
|
||||
| ({ status: "complete" } & SetupResult)
|
||||
|
||||
@@ -121,9 +121,11 @@ export { InstallingState } from "./InstallingState"
|
||||
export { InstallParams } from "./InstallParams"
|
||||
export { IpHostname } from "./IpHostname"
|
||||
export { IpInfo } from "./IpInfo"
|
||||
export { KeyboardOptions } from "./KeyboardOptions"
|
||||
export { ListPackageSignersParams } from "./ListPackageSignersParams"
|
||||
export { ListServiceInterfacesParams } from "./ListServiceInterfacesParams"
|
||||
export { ListVersionSignersParams } from "./ListVersionSignersParams"
|
||||
export { LocaleString } from "./LocaleString"
|
||||
export { LoginParams } from "./LoginParams"
|
||||
export { LshwDevice } from "./LshwDevice"
|
||||
export { LshwDisplay } from "./LshwDisplay"
|
||||
@@ -161,6 +163,7 @@ export { PackageState } from "./PackageState"
|
||||
export { PackageVersionInfo } from "./PackageVersionInfo"
|
||||
export { PasswordType } from "./PasswordType"
|
||||
export { PathOrUrl } from "./PathOrUrl"
|
||||
export { Pem } from "./Pem"
|
||||
export { Percentage } from "./Percentage"
|
||||
export { Progress } from "./Progress"
|
||||
export { ProgressUnits } from "./ProgressUnits"
|
||||
@@ -199,6 +202,7 @@ export { SetMainStatusStatus } from "./SetMainStatusStatus"
|
||||
export { SetMainStatus } from "./SetMainStatus"
|
||||
export { SetNameParams } from "./SetNameParams"
|
||||
export { SetupExecuteParams } from "./SetupExecuteParams"
|
||||
export { SetupInfo } from "./SetupInfo"
|
||||
export { SetupProgress } from "./SetupProgress"
|
||||
export { SetupResult } from "./SetupResult"
|
||||
export { SetupStatusRes } from "./SetupStatusRes"
|
||||
|
||||
@@ -48,9 +48,9 @@ export type SDKManifest = {
|
||||
readonly docsUrl: string
|
||||
readonly description: {
|
||||
/** Short description to display on the marketplace list page. Max length 80 chars. */
|
||||
readonly short: string
|
||||
readonly short: T.LocaleString
|
||||
/** Long description to display on the marketplace details page for this service. Max length 500 chars. */
|
||||
readonly long: string
|
||||
readonly long: T.LocaleString
|
||||
}
|
||||
/**
|
||||
* override the StartOS version this package was made for
|
||||
@@ -96,17 +96,17 @@ export type SDKManifest = {
|
||||
|
||||
readonly alerts?: {
|
||||
/** An warning alert requiring user confirmation before proceeding with initial installation of this service. */
|
||||
readonly install?: string | null
|
||||
readonly install?: T.LocaleString | null
|
||||
/** An warning alert requiring user confirmation before updating this service. */
|
||||
readonly update?: string | null
|
||||
readonly update?: T.LocaleString | null
|
||||
/** An warning alert requiring user confirmation before uninstalling this service. */
|
||||
readonly uninstall?: string | null
|
||||
readonly uninstall?: T.LocaleString | null
|
||||
/** An warning alert requiring user confirmation before restoring this service from backup. */
|
||||
readonly restore?: string | null
|
||||
readonly restore?: T.LocaleString | null
|
||||
/** An warning alert requiring user confirmation before starting this service. */
|
||||
readonly start?: string | null
|
||||
readonly start?: T.LocaleString | null
|
||||
/** An warning alert requiring user confirmation before stopping this service. */
|
||||
readonly stop?: string | null
|
||||
readonly stop?: T.LocaleString | null
|
||||
}
|
||||
/**
|
||||
* @description A mapping of service dependencies to be displayed to users when viewing the Marketplace
|
||||
|
||||
@@ -355,10 +355,13 @@ export class GetServiceInterface<Mapped = ServiceInterfaceFilled | null> {
|
||||
const watch = this.watch(abort.signal)
|
||||
const res = await watch.next()
|
||||
if (this.effects.constRetry) {
|
||||
watch.next().then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
watch
|
||||
.next()
|
||||
.then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
.catch()
|
||||
}
|
||||
return res.value
|
||||
}
|
||||
|
||||
@@ -55,10 +55,13 @@ export class GetServiceInterfaces<Mapped = ServiceInterfaceFilled[]> {
|
||||
const watch = this.watch(abort.signal)
|
||||
const res = await watch.next()
|
||||
if (this.effects.constRetry) {
|
||||
watch.next().then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
watch
|
||||
.next()
|
||||
.then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
.catch()
|
||||
}
|
||||
return res.value
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ import {
|
||||
import { getOwnServiceInterfaces } from "../../base/lib/util/getServiceInterfaces"
|
||||
import { Volumes, createVolumes } from "./util/Volume"
|
||||
|
||||
export const OSVersion = testTypeVersion("0.4.0-alpha.17")
|
||||
export const OSVersion = testTypeVersion("0.4.0-alpha.18")
|
||||
|
||||
// prettier-ignore
|
||||
type AnyNeverCond<T extends any[], Then, Else> =
|
||||
|
||||
74
sdk/package/lib/i18n/index.ts
Normal file
74
sdk/package/lib/i18n/index.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Internationalization (i18n) utilities for StartOS packages.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // In package's i18n/index.ts:
|
||||
* import { setupI18n } from '@start9labs/start-sdk'
|
||||
* import defaultDict, { DEFAULT_LANG } from './dictionaries/default'
|
||||
* import translations from './dictionaries/translations'
|
||||
*
|
||||
* export const i18n = setupI18n(defaultDict, translations, DEFAULT_LANG)
|
||||
* ```
|
||||
*/
|
||||
|
||||
type ParamValue = string | number | Date
|
||||
|
||||
/**
|
||||
* Creates a typed i18n function for a package.
|
||||
*
|
||||
* @param defaultDict - The default language dictionary mapping strings to numeric indices
|
||||
* @param translations - Translation dictionaries for each supported locale
|
||||
* @param defaultLang - The default language code (e.g., 'en_US')
|
||||
* @returns A typed i18n function that accepts dictionary keys and optional parameters
|
||||
*/
|
||||
export function setupI18n<
|
||||
Dict extends Record<string, number>,
|
||||
Translations extends Record<string, Record<number, string>>,
|
||||
>(defaultDict: Dict, translations: Translations, defaultLang: string) {
|
||||
const lang = process.env.LANG?.replace(/\.UTF-8$/, "") || defaultLang
|
||||
|
||||
// Convert locale format from en_US to en-US for Intl APIs
|
||||
const intlLocale = lang.replace("_", "-")
|
||||
|
||||
function getTranslation(): Record<number, string> | null {
|
||||
if (lang === defaultLang) return null
|
||||
|
||||
const availableLangs = Object.keys(translations) as (keyof Translations)[]
|
||||
|
||||
const match =
|
||||
availableLangs.find((l) => l === lang) ??
|
||||
availableLangs.find((l) => String(l).startsWith(lang.split("_")[0] + "_"))
|
||||
|
||||
return match ? (translations[match] as Record<number, string>) : null
|
||||
}
|
||||
|
||||
const translation = getTranslation()
|
||||
|
||||
function formatValue(value: ParamValue): string {
|
||||
if (typeof value === "number") {
|
||||
return new Intl.NumberFormat(intlLocale).format(value)
|
||||
}
|
||||
if (value instanceof Date) {
|
||||
return new Intl.DateTimeFormat(intlLocale).format(value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
return function i18n(
|
||||
key: keyof Dict,
|
||||
params?: Record<string, ParamValue>,
|
||||
): string {
|
||||
let result = translation
|
||||
? translation[defaultDict[key as string]]
|
||||
: (key as string)
|
||||
|
||||
if (params) {
|
||||
for (const [paramName, value] of Object.entries(params)) {
|
||||
result = result.replace(`\${${paramName}}`, formatValue(value))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ export {
|
||||
matches,
|
||||
utils,
|
||||
}
|
||||
export { setupI18n } from "./i18n"
|
||||
export * as T from "./types"
|
||||
export { Daemons } from "./mainFn/Daemons"
|
||||
export { SubContainer } from "./util/SubContainer"
|
||||
|
||||
@@ -19,10 +19,13 @@ export class GetServiceManifest<Mapped = Manifest> {
|
||||
const watch = this.watch(abort.signal)
|
||||
const res = await watch.next()
|
||||
if (this.effects.constRetry) {
|
||||
watch.next().then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
watch
|
||||
.next()
|
||||
.then(() => {
|
||||
abort.abort()
|
||||
this.effects.constRetry && this.effects.constRetry()
|
||||
})
|
||||
.catch()
|
||||
}
|
||||
return res.value
|
||||
}
|
||||
|
||||
@@ -230,10 +230,13 @@ export class FileHelper<A> {
|
||||
eq,
|
||||
]
|
||||
this.consts.push(record)
|
||||
watch.next().then(() => {
|
||||
this.consts = this.consts.filter((r) => r !== record)
|
||||
effects.constRetry && effects.constRetry()
|
||||
})
|
||||
watch
|
||||
.next()
|
||||
.then(() => {
|
||||
this.consts = this.consts.filter((r) => r !== record)
|
||||
effects.constRetry && effects.constRetry()
|
||||
})
|
||||
.catch()
|
||||
}
|
||||
return res.value
|
||||
}
|
||||
@@ -263,6 +266,7 @@ export class FileHelper<A> {
|
||||
})
|
||||
.catch((e) => console.error(asError(e)))
|
||||
if (!prev || !eq(prev.value, newRes)) {
|
||||
console.error("yielding", JSON.stringify({ prev: prev, newRes }))
|
||||
yield newRes
|
||||
}
|
||||
prev = { value: newRes }
|
||||
|
||||
@@ -7,7 +7,7 @@ export type VersionOptions<Version extends string> = {
|
||||
/** The exver-compliant version number */
|
||||
version: Version & ValidateExVer<Version>
|
||||
/** The release notes for this version */
|
||||
releaseNotes: string
|
||||
releaseNotes: T.LocaleString
|
||||
/** Data migrations for this version */
|
||||
migrations: {
|
||||
/**
|
||||
|
||||
4
sdk/package/package-lock.json
generated
4
sdk/package/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.47",
|
||||
"version": "0.4.0-beta.48",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.47",
|
||||
"version": "0.4.0-beta.48",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.47",
|
||||
"version": "0.4.0-beta.48",
|
||||
"description": "Software development kit to facilitate packaging services for StartOS",
|
||||
"main": "./package/lib/index.js",
|
||||
"types": "./package/lib/index.d.ts",
|
||||
|
||||
Reference in New Issue
Block a user