mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Refactor/sdk init (#2947)
* fixes for main * refactor package initialization * fixes from testing * more fixes * beta.21 * do not use instanceof * closes #2921 * beta22 * allow disabling kiosk * migration * fix /etc/shadow * actionRequest -> task * beta.23
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { ExtendedVersion, VersionRange } from "./exver"
|
||||
import {
|
||||
ActionId,
|
||||
ActionInput,
|
||||
@@ -12,7 +13,7 @@ import {
|
||||
Host,
|
||||
ExportServiceInterfaceParams,
|
||||
ServiceInterface,
|
||||
RequestActionParams,
|
||||
CreateTaskParams,
|
||||
MainStatus,
|
||||
} from "./osBindings"
|
||||
import {
|
||||
@@ -50,10 +51,8 @@ export type Effects = {
|
||||
actionId: ActionId
|
||||
input?: Input
|
||||
}): Promise<ActionResult | null>
|
||||
request<Input extends Record<string, unknown>>(
|
||||
options: RequestActionParams,
|
||||
): Promise<null>
|
||||
clearRequests(
|
||||
createTask(options: CreateTaskParams): Promise<null>
|
||||
clearTasks(
|
||||
options: { only: string[] } | { except: string[] },
|
||||
): Promise<null>
|
||||
}
|
||||
@@ -168,7 +167,7 @@ export type Effects = {
|
||||
}) => Promise<string>
|
||||
|
||||
/** sets the version that this service's data has been migrated to */
|
||||
setDataVersion(options: { version: string }): Promise<null>
|
||||
setDataVersion(options: { version: string | null }): Promise<null>
|
||||
/** returns the version that this service's data has been migrated to */
|
||||
getDataVersion(): Promise<string | null>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as T from "../types"
|
||||
import * as IST from "../actions/input/inputSpecTypes"
|
||||
import { Action } from "./setupActions"
|
||||
import { Action, ActionInfo } from "./setupActions"
|
||||
import { ExtractInputSpecType } from "./input/builder/inputSpec"
|
||||
|
||||
export type RunActionInput<Input> =
|
||||
@@ -45,45 +45,41 @@ export const runAction = async <
|
||||
})
|
||||
}
|
||||
}
|
||||
type GetActionInputType<A extends Action<T.ActionId, any>> =
|
||||
type GetActionInputType<A extends ActionInfo<T.ActionId, any>> =
|
||||
A extends Action<T.ActionId, infer I> ? ExtractInputSpecType<I> : never
|
||||
|
||||
type ActionRequestBase = {
|
||||
type TaskBase = {
|
||||
reason?: string
|
||||
replayId?: string
|
||||
}
|
||||
type ActionRequestInput<T extends Action<T.ActionId, any>> = {
|
||||
type TaskInput<T extends ActionInfo<T.ActionId, any>> = {
|
||||
kind: "partial"
|
||||
value: T.DeepPartial<GetActionInputType<T>>
|
||||
}
|
||||
export type ActionRequestOptions<T extends Action<T.ActionId, any>> =
|
||||
ActionRequestBase &
|
||||
(
|
||||
| {
|
||||
when?: Exclude<
|
||||
T.ActionRequestTrigger,
|
||||
{ condition: "input-not-matches" }
|
||||
>
|
||||
input?: ActionRequestInput<T>
|
||||
}
|
||||
| {
|
||||
when: T.ActionRequestTrigger & { condition: "input-not-matches" }
|
||||
input: ActionRequestInput<T>
|
||||
}
|
||||
)
|
||||
export type TaskOptions<T extends ActionInfo<T.ActionId, any>> = TaskBase &
|
||||
(
|
||||
| {
|
||||
when?: Exclude<T.TaskTrigger, { condition: "input-not-matches" }>
|
||||
input?: TaskInput<T>
|
||||
}
|
||||
| {
|
||||
when: T.TaskTrigger & { condition: "input-not-matches" }
|
||||
input: TaskInput<T>
|
||||
}
|
||||
)
|
||||
|
||||
const _validate: T.ActionRequest = {} as ActionRequestOptions<any> & {
|
||||
const _validate: T.Task = {} as TaskOptions<any> & {
|
||||
actionId: string
|
||||
packageId: string
|
||||
severity: T.ActionSeverity
|
||||
severity: T.TaskSeverity
|
||||
}
|
||||
|
||||
export const requestAction = <T extends Action<T.ActionId, any>>(options: {
|
||||
export const createTask = <T extends ActionInfo<T.ActionId, any>>(options: {
|
||||
effects: T.Effects
|
||||
packageId: T.PackageId
|
||||
action: T
|
||||
severity: T.ActionSeverity
|
||||
options?: ActionRequestOptions<T>
|
||||
severity: T.TaskSeverity
|
||||
options?: TaskOptions<T>
|
||||
}) => {
|
||||
const request = options.options || {}
|
||||
const actionId = options.action.id
|
||||
@@ -96,5 +92,5 @@ export const requestAction = <T extends Action<T.ActionId, any>>(options: {
|
||||
replayId: request.replayId || `${options.packageId}:${actionId}`,
|
||||
}
|
||||
delete req.action
|
||||
return options.effects.action.request(req)
|
||||
return options.effects.action.createTask(req)
|
||||
}
|
||||
|
||||
@@ -919,36 +919,6 @@ export class Value<Type> {
|
||||
aVariants.validator,
|
||||
)
|
||||
}
|
||||
static filteredUnion<
|
||||
VariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: InputSpec<any>
|
||||
}
|
||||
},
|
||||
>(
|
||||
getDisabledFn: LazyBuild<string[] | false | string>,
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: keyof VariantValues & string
|
||||
},
|
||||
aVariants: Variants<VariantValues>,
|
||||
) {
|
||||
return new Value<typeof aVariants.validator._TYPE>(
|
||||
async (options) => ({
|
||||
type: "union" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...a,
|
||||
variants: await aVariants.build(options as any),
|
||||
disabled: (await getDisabledFn(options)) || false,
|
||||
immutable: false,
|
||||
}),
|
||||
aVariants.validator,
|
||||
)
|
||||
}
|
||||
static dynamicUnion<
|
||||
VariantValues extends {
|
||||
[K in string]: {
|
||||
|
||||
@@ -45,15 +45,16 @@ export const customSmtp = InputSpec.of<InputSpecOf<SmtpValue>>({
|
||||
/**
|
||||
* For service inputSpec. Gives users 3 options for SMTP: (1) disabled, (2) use system SMTP settings, (3) use custom SMTP settings
|
||||
*/
|
||||
export const smtpInputSpec = Value.filteredUnion(
|
||||
export const smtpInputSpec = Value.dynamicUnion(
|
||||
async ({ effects }) => {
|
||||
const smtp = await new GetSystemSmtp(effects).once()
|
||||
return smtp ? [] : ["system"]
|
||||
},
|
||||
{
|
||||
name: "SMTP",
|
||||
description: "Optionally provide an SMTP server for sending emails",
|
||||
default: "disabled",
|
||||
const disabled = smtp ? [] : ["system"]
|
||||
return {
|
||||
name: "SMTP",
|
||||
description: "Optionally provide an SMTP server for sending emails",
|
||||
default: "disabled",
|
||||
disabled,
|
||||
}
|
||||
},
|
||||
Variants.of({
|
||||
disabled: { name: "Disabled", spec: InputSpec.of({}) },
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
} from "./input/builder/inputSpec"
|
||||
import * as T from "../types"
|
||||
import { once } from "../util"
|
||||
import { InitScript } from "../inits"
|
||||
|
||||
export type Run<
|
||||
A extends Record<string, any> | InputSpec<Record<string, any>>,
|
||||
@@ -40,10 +41,20 @@ function mapMaybeFn<T, U>(
|
||||
}
|
||||
}
|
||||
|
||||
export class Action<
|
||||
export interface ActionInfo<
|
||||
Id extends T.ActionId,
|
||||
InputSpecType extends Record<string, any> | InputSpec<any>,
|
||||
> {
|
||||
readonly id: Id
|
||||
readonly _INPUT: InputSpecType
|
||||
}
|
||||
|
||||
export class Action<
|
||||
Id extends T.ActionId,
|
||||
InputSpecType extends Record<string, any> | InputSpec<any>,
|
||||
> implements ActionInfo<Id, InputSpecType>
|
||||
{
|
||||
readonly _INPUT: InputSpecType = null as any as InputSpecType
|
||||
private constructor(
|
||||
readonly id: Id,
|
||||
private readonly metadataFn: MaybeFn<T.ActionMetadata>,
|
||||
@@ -111,7 +122,8 @@ export class Action<
|
||||
|
||||
export class Actions<
|
||||
AllActions extends Record<T.ActionId, Action<T.ActionId, any>>,
|
||||
> {
|
||||
> implements InitScript
|
||||
{
|
||||
private constructor(private readonly actions: AllActions) {}
|
||||
static of(): Actions<{}> {
|
||||
return new Actions({})
|
||||
@@ -121,13 +133,26 @@ export class Actions<
|
||||
): Actions<AllActions & { [id in A["id"]]: A }> {
|
||||
return new Actions({ ...this.actions, [action.id]: action })
|
||||
}
|
||||
async update(options: { effects: T.Effects }): Promise<null> {
|
||||
async init(effects: T.Effects): Promise<void> {
|
||||
for (let action of Object.values(this.actions)) {
|
||||
await action.exportMetadata(options)
|
||||
const fn = async () => {
|
||||
let res: (value?: undefined) => void = () => {}
|
||||
const complete = new Promise((resolve) => {
|
||||
res = resolve
|
||||
})
|
||||
const e: T.Effects = effects.child(action.id)
|
||||
e.constRetry = once(() =>
|
||||
complete.then(() => fn()).catch(console.error),
|
||||
)
|
||||
try {
|
||||
await action.exportMetadata({ effects: e })
|
||||
} finally {
|
||||
res()
|
||||
}
|
||||
}
|
||||
await fn()
|
||||
}
|
||||
await options.effects.action.clear({ except: Object.keys(this.actions) })
|
||||
|
||||
return null
|
||||
await effects.action.clear({ except: Object.keys(this.actions) })
|
||||
}
|
||||
get<Id extends T.ActionId>(actionId: Id): AllActions[Id] {
|
||||
return this.actions[actionId]
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
import * as T from "../types"
|
||||
import * as child_process from "child_process"
|
||||
import { asError } from "../util"
|
||||
|
||||
export const DEFAULT_OPTIONS: T.SyncOptions = {
|
||||
delete: true,
|
||||
exclude: [],
|
||||
}
|
||||
export type BackupSync<Volumes extends string> = {
|
||||
dataPath: `/media/startos/volumes/${Volumes}/${string}`
|
||||
backupPath: `/media/startos/backup/${string}`
|
||||
options?: Partial<T.SyncOptions>
|
||||
backupOptions?: Partial<T.SyncOptions>
|
||||
restoreOptions?: Partial<T.SyncOptions>
|
||||
}
|
||||
/**
|
||||
* This utility simplifies the volume backup process.
|
||||
* ```ts
|
||||
* export const { createBackup, restoreBackup } = Backups.volumes("main").build();
|
||||
* ```
|
||||
*
|
||||
* Changing the options of the rsync, (ie excludes) use either
|
||||
* ```ts
|
||||
* Backups.volumes("main").set_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
|
||||
* // or
|
||||
* Backups.with_options({exclude: ['bigdata/']}).volumes('excludedVolume').build()
|
||||
* ```
|
||||
*
|
||||
* Using the more fine control, using the addSets for more control
|
||||
* ```ts
|
||||
* Backups.addSets({
|
||||
* srcVolume: 'main', srcPath:'smallData/', dstPath: 'main/smallData/', dstVolume: : Backups.BACKUP
|
||||
* }, {
|
||||
* srcVolume: 'main', srcPath:'bigData/', dstPath: 'main/bigData/', dstVolume: : Backups.BACKUP, options: {exclude:['bigData/excludeThis']}}
|
||||
* ).build()q
|
||||
* ```
|
||||
*/
|
||||
export class Backups<M extends T.Manifest> {
|
||||
private constructor(
|
||||
private options = DEFAULT_OPTIONS,
|
||||
private restoreOptions: Partial<T.SyncOptions> = {},
|
||||
private backupOptions: Partial<T.SyncOptions> = {},
|
||||
private backupSet = [] as BackupSync<M["volumes"][number]>[],
|
||||
) {}
|
||||
|
||||
static withVolumes<M extends T.Manifest = never>(
|
||||
...volumeNames: Array<M["volumes"][number]>
|
||||
): Backups<M> {
|
||||
return Backups.withSyncs(
|
||||
...volumeNames.map((srcVolume) => ({
|
||||
dataPath: `/media/startos/volumes/${srcVolume}/` as const,
|
||||
backupPath: `/media/startos/backup/${srcVolume}/` as const,
|
||||
})),
|
||||
)
|
||||
}
|
||||
|
||||
static withSyncs<M extends T.Manifest = never>(
|
||||
...syncs: BackupSync<M["volumes"][number]>[]
|
||||
) {
|
||||
return syncs.reduce((acc, x) => acc.addSync(x), new Backups<M>())
|
||||
}
|
||||
|
||||
static withOptions<M extends T.Manifest = never>(
|
||||
options?: Partial<T.SyncOptions>,
|
||||
) {
|
||||
return new Backups<M>({ ...DEFAULT_OPTIONS, ...options })
|
||||
}
|
||||
|
||||
setOptions(options?: Partial<T.SyncOptions>) {
|
||||
this.options = {
|
||||
...this.options,
|
||||
...options,
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setBackupOptions(options?: Partial<T.SyncOptions>) {
|
||||
this.backupOptions = {
|
||||
...this.backupOptions,
|
||||
...options,
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
setRestoreOptions(options?: Partial<T.SyncOptions>) {
|
||||
this.restoreOptions = {
|
||||
...this.restoreOptions,
|
||||
...options,
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
mountVolume(
|
||||
volume: M["volumes"][number],
|
||||
options?: Partial<{
|
||||
options: T.SyncOptions
|
||||
backupOptions: T.SyncOptions
|
||||
restoreOptions: T.SyncOptions
|
||||
}>,
|
||||
) {
|
||||
return this.addSync({
|
||||
dataPath: `/media/startos/volumes/${volume}/` as const,
|
||||
backupPath: `/media/startos/backup/${volume}/` as const,
|
||||
...options,
|
||||
})
|
||||
}
|
||||
addSync(sync: BackupSync<M["volumes"][0]>) {
|
||||
this.backupSet.push({
|
||||
...sync,
|
||||
options: { ...this.options, ...sync.options },
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
async createBackup() {
|
||||
for (const item of this.backupSet) {
|
||||
const rsyncResults = await runRsync({
|
||||
srcPath: item.dataPath,
|
||||
dstPath: item.backupPath,
|
||||
options: {
|
||||
...this.options,
|
||||
...this.backupOptions,
|
||||
...item.options,
|
||||
...item.backupOptions,
|
||||
},
|
||||
})
|
||||
await rsyncResults.wait()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
async restoreBackup() {
|
||||
for (const item of this.backupSet) {
|
||||
const rsyncResults = await runRsync({
|
||||
srcPath: item.backupPath,
|
||||
dstPath: item.dataPath,
|
||||
options: {
|
||||
...this.options,
|
||||
...this.backupOptions,
|
||||
...item.options,
|
||||
...item.backupOptions,
|
||||
},
|
||||
})
|
||||
await rsyncResults.wait()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async function runRsync(rsyncOptions: {
|
||||
srcPath: string
|
||||
dstPath: string
|
||||
options: T.SyncOptions
|
||||
}): Promise<{
|
||||
id: () => Promise<string>
|
||||
wait: () => Promise<null>
|
||||
progress: () => Promise<number>
|
||||
}> {
|
||||
const { srcPath, dstPath, options } = rsyncOptions
|
||||
|
||||
const command = "rsync"
|
||||
const args: string[] = []
|
||||
if (options.delete) {
|
||||
args.push("--delete")
|
||||
}
|
||||
for (const exclude of options.exclude) {
|
||||
args.push(`--exclude=${exclude}`)
|
||||
}
|
||||
args.push("-actAXH")
|
||||
args.push("--info=progress2")
|
||||
args.push("--no-inc-recursive")
|
||||
args.push(srcPath)
|
||||
args.push(dstPath)
|
||||
const spawned = child_process.spawn(command, args, { detached: true })
|
||||
let percentage = 0.0
|
||||
spawned.stdout.on("data", (data: unknown) => {
|
||||
const lines = String(data).replace("\r", "\n").split("\n")
|
||||
for (const line of lines) {
|
||||
const parsed = /$([0-9.]+)%/.exec(line)?.[1]
|
||||
if (!parsed) continue
|
||||
percentage = Number.parseFloat(parsed)
|
||||
}
|
||||
})
|
||||
|
||||
spawned.stderr.on("data", (data: unknown) => {
|
||||
console.error(`Backups.runAsync`, asError(data))
|
||||
})
|
||||
|
||||
const id = async () => {
|
||||
const pid = spawned.pid
|
||||
if (pid === undefined) {
|
||||
throw new Error("rsync process has no pid")
|
||||
}
|
||||
return String(pid)
|
||||
}
|
||||
const waitPromise = new Promise<null>((resolve, reject) => {
|
||||
spawned.on("exit", (code: any) => {
|
||||
if (code === 0) {
|
||||
resolve(null)
|
||||
} else {
|
||||
reject(new Error(`rsync exited with code ${code}`))
|
||||
}
|
||||
})
|
||||
})
|
||||
const wait = () => waitPromise
|
||||
const progress = () => Promise.resolve(percentage)
|
||||
return { id, wait, progress }
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Backups } from "./Backups"
|
||||
import * as T from "../types"
|
||||
import { _ } from "../util"
|
||||
|
||||
export type SetupBackupsParams<M extends T.Manifest> =
|
||||
| M["volumes"][number][]
|
||||
| ((_: { effects: T.Effects }) => Promise<Backups<M>>)
|
||||
|
||||
type SetupBackupsRes = {
|
||||
createBackup: T.ExpectedExports.createBackup
|
||||
restoreBackup: T.ExpectedExports.restoreBackup
|
||||
}
|
||||
|
||||
export function setupBackups<M extends T.Manifest>(
|
||||
options: SetupBackupsParams<M>,
|
||||
) {
|
||||
let backupsFactory: (_: { effects: T.Effects }) => Promise<Backups<M>>
|
||||
if (options instanceof Function) {
|
||||
backupsFactory = options
|
||||
} else {
|
||||
backupsFactory = async () => Backups.withVolumes(...options)
|
||||
}
|
||||
const answer: {
|
||||
createBackup: T.ExpectedExports.createBackup
|
||||
restoreBackup: T.ExpectedExports.restoreBackup
|
||||
} = {
|
||||
get createBackup() {
|
||||
return (async (options) => {
|
||||
return (await backupsFactory(options)).createBackup()
|
||||
}) as T.ExpectedExports.createBackup
|
||||
},
|
||||
get restoreBackup() {
|
||||
return (async (options) => {
|
||||
return (await backupsFactory(options)).restoreBackup()
|
||||
}) as T.ExpectedExports.restoreBackup
|
||||
},
|
||||
}
|
||||
return answer
|
||||
}
|
||||
@@ -6,7 +6,7 @@ export type CheckDependencies<DependencyId extends PackageId = PackageId> = {
|
||||
installedSatisfied: (packageId: DependencyId) => boolean
|
||||
installedVersionSatisfied: (packageId: DependencyId) => boolean
|
||||
runningSatisfied: (packageId: DependencyId) => boolean
|
||||
actionsSatisfied: (packageId: DependencyId) => boolean
|
||||
tasksSatisfied: (packageId: DependencyId) => boolean
|
||||
healthCheckSatisfied: (
|
||||
packageId: DependencyId,
|
||||
healthCheckId: HealthCheckId,
|
||||
@@ -16,7 +16,7 @@ export type CheckDependencies<DependencyId extends PackageId = PackageId> = {
|
||||
throwIfInstalledNotSatisfied: (packageId: DependencyId) => null
|
||||
throwIfInstalledVersionNotSatisfied: (packageId: DependencyId) => null
|
||||
throwIfRunningNotSatisfied: (packageId: DependencyId) => null
|
||||
throwIfActionsNotSatisfied: (packageId: DependencyId) => null
|
||||
throwIfTasksNotSatisfied: (packageId: DependencyId) => null
|
||||
throwIfHealthNotSatisfied: (
|
||||
packageId: DependencyId,
|
||||
healthCheckId?: HealthCheckId,
|
||||
@@ -65,9 +65,9 @@ export async function checkDependencies<
|
||||
const dep = find(packageId)
|
||||
return dep.requirement.kind !== "running" || dep.result.isRunning
|
||||
}
|
||||
const actionsSatisfied = (packageId: DependencyId) =>
|
||||
Object.entries(find(packageId).result.requestedActions).filter(
|
||||
([_, req]) => req.active && req.request.severity === "critical",
|
||||
const tasksSatisfied = (packageId: DependencyId) =>
|
||||
Object.entries(find(packageId).result.tasks).filter(
|
||||
([_, t]) => t.active && t.task.severity === "critical",
|
||||
).length === 0
|
||||
const healthCheckSatisfied = (
|
||||
packageId: DependencyId,
|
||||
@@ -90,7 +90,7 @@ export async function checkDependencies<
|
||||
installedSatisfied(packageId) &&
|
||||
installedVersionSatisfied(packageId) &&
|
||||
runningSatisfied(packageId) &&
|
||||
actionsSatisfied(packageId) &&
|
||||
tasksSatisfied(packageId) &&
|
||||
healthCheckSatisfied(packageId)
|
||||
const satisfied = (packageId?: DependencyId) =>
|
||||
packageId
|
||||
@@ -129,10 +129,10 @@ export async function checkDependencies<
|
||||
}
|
||||
return null
|
||||
}
|
||||
const throwIfActionsNotSatisfied = (packageId: DependencyId) => {
|
||||
const throwIfTasksNotSatisfied = (packageId: DependencyId) => {
|
||||
const dep = find(packageId)
|
||||
const reqs = Object.entries(dep.result.requestedActions)
|
||||
.filter(([_, req]) => req.active && req.request.severity === "critical")
|
||||
const reqs = Object.entries(dep.result.tasks)
|
||||
.filter(([_, t]) => t.active && t.task.severity === "critical")
|
||||
.map(([id, _]) => id)
|
||||
if (reqs.length) {
|
||||
throw new Error(
|
||||
@@ -172,7 +172,7 @@ export async function checkDependencies<
|
||||
throwIfInstalledNotSatisfied(packageId)
|
||||
throwIfInstalledVersionNotSatisfied(packageId)
|
||||
throwIfRunningNotSatisfied(packageId)
|
||||
throwIfActionsNotSatisfied(packageId)
|
||||
throwIfTasksNotSatisfied(packageId)
|
||||
throwIfHealthNotSatisfied(packageId)
|
||||
return null
|
||||
}
|
||||
@@ -199,13 +199,13 @@ export async function checkDependencies<
|
||||
installedSatisfied,
|
||||
installedVersionSatisfied,
|
||||
runningSatisfied,
|
||||
actionsSatisfied,
|
||||
tasksSatisfied,
|
||||
healthCheckSatisfied,
|
||||
satisfied,
|
||||
throwIfInstalledNotSatisfied,
|
||||
throwIfInstalledVersionNotSatisfied,
|
||||
throwIfRunningNotSatisfied,
|
||||
throwIfActionsNotSatisfied,
|
||||
throwIfTasksNotSatisfied,
|
||||
throwIfHealthNotSatisfied,
|
||||
throwIfNotSatisfied,
|
||||
}
|
||||
|
||||
@@ -37,16 +37,10 @@ export function setupDependencies<Manifest extends T.SDKManifest>(
|
||||
fn: (options: {
|
||||
effects: T.Effects
|
||||
}) => Promise<CurrentDependenciesResult<Manifest>>,
|
||||
): (options: { effects: T.Effects }) => Promise<null> {
|
||||
const cell = { updater: async (_: { effects: T.Effects }) => null }
|
||||
cell.updater = async (options: { effects: T.Effects }) => {
|
||||
const childEffects = options.effects.child("setupDependencies")
|
||||
childEffects.constRetry = once(() => {
|
||||
cell.updater({ effects: options.effects })
|
||||
})
|
||||
|
||||
const dependencyType = await fn({ effects: childEffects })
|
||||
return await options.effects.setDependencies({
|
||||
): (effects: T.Effects) => Promise<null> {
|
||||
return async (effects: T.Effects) => {
|
||||
const dependencyType = await fn({ effects })
|
||||
return await effects.setDependencies({
|
||||
dependencies: Object.entries(dependencyType)
|
||||
.map(([k, v]) => [k, v as DependencyRequirement] as const)
|
||||
.map(
|
||||
@@ -59,5 +53,4 @@ export function setupDependencies<Manifest extends T.SDKManifest>(
|
||||
),
|
||||
})
|
||||
}
|
||||
return cell.updater
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export * as IST from "./actions/input/inputSpecTypes"
|
||||
export * as types from "./types"
|
||||
export * as T from "./types"
|
||||
export * as yaml from "yaml"
|
||||
export * as inits from "./inits"
|
||||
export * as matches from "ts-matches"
|
||||
|
||||
export * as utils from "./util"
|
||||
|
||||
2
sdk/base/lib/inits/index.ts
Normal file
2
sdk/base/lib/inits/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./setupInit"
|
||||
export * from "./setupUninit"
|
||||
91
sdk/base/lib/inits/setupInit.ts
Normal file
91
sdk/base/lib/inits/setupInit.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
import { VersionRange } from "../../../base/lib/exver"
|
||||
import * as T from "../../../base/lib/types"
|
||||
import { once } from "../util"
|
||||
|
||||
export type InitKind = "install" | "update" | "restore" | null
|
||||
|
||||
export type InitFn<Kind extends InitKind = InitKind> = (
|
||||
effects: T.Effects,
|
||||
kind: Kind,
|
||||
) => Promise<void | null | undefined>
|
||||
|
||||
export interface InitScript<Kind extends InitKind = InitKind> {
|
||||
init(effects: T.Effects, kind: Kind): Promise<void>
|
||||
}
|
||||
|
||||
export type InitScriptOrFn<Kind extends InitKind = InitKind> =
|
||||
| InitScript<Kind>
|
||||
| InitFn<Kind>
|
||||
|
||||
export function setupInit(...inits: InitScriptOrFn[]): T.ExpectedExports.init {
|
||||
return async (opts) => {
|
||||
for (const idx in inits) {
|
||||
const init = inits[idx]
|
||||
const fn = async () => {
|
||||
let res: (value?: undefined) => void = () => {}
|
||||
const complete = new Promise((resolve) => {
|
||||
res = resolve
|
||||
})
|
||||
const e: T.Effects = opts.effects.child(`init_${idx}`)
|
||||
e.constRetry = once(() =>
|
||||
complete.then(() => fn()).catch(console.error),
|
||||
)
|
||||
try {
|
||||
if ("init" in init) await init.init(e, opts.kind)
|
||||
else await init(e, opts.kind)
|
||||
} finally {
|
||||
res()
|
||||
}
|
||||
}
|
||||
await fn()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function setupOnInit(onInit: InitScriptOrFn): InitScript {
|
||||
return "init" in onInit
|
||||
? onInit
|
||||
: {
|
||||
init: async (effects, kind) => {
|
||||
await onInit(effects, kind)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function setupOnInstall(
|
||||
onInstall: InitScriptOrFn<"install">,
|
||||
): InitScript {
|
||||
return {
|
||||
init: async (effects, kind) => {
|
||||
if (kind === "install") {
|
||||
if ("init" in onInstall) await onInstall.init(effects, kind)
|
||||
else await onInstall(effects, kind)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function setupOnUpdate(onUpdate: InitScriptOrFn<"update">): InitScript {
|
||||
return {
|
||||
init: async (effects, kind) => {
|
||||
if (kind === "update") {
|
||||
if ("init" in onUpdate) await onUpdate.init(effects, kind)
|
||||
else await onUpdate(effects, kind)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function setupOnInstallOrUpdate(
|
||||
onInstallOrUpdate: InitScriptOrFn<"install" | "update">,
|
||||
): InitScript {
|
||||
return {
|
||||
init: async (effects, kind) => {
|
||||
if (kind === "install" || kind === "update") {
|
||||
if ("init" in onInstallOrUpdate)
|
||||
await onInstallOrUpdate.init(effects, kind)
|
||||
else await onInstallOrUpdate(effects, kind)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
25
sdk/base/lib/inits/setupUninit.ts
Normal file
25
sdk/base/lib/inits/setupUninit.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ExtendedVersion, VersionRange } from "../../../base/lib/exver"
|
||||
import * as T from "../../../base/lib/types"
|
||||
|
||||
export type UninitFn = (
|
||||
effects: T.Effects,
|
||||
target: VersionRange | ExtendedVersion | null,
|
||||
) => Promise<void | null | undefined>
|
||||
|
||||
export interface UninitScript {
|
||||
uninit(
|
||||
effects: T.Effects,
|
||||
target: VersionRange | ExtendedVersion | null,
|
||||
): Promise<void>
|
||||
}
|
||||
|
||||
export function setupUninit(
|
||||
...uninits: (UninitScript | UninitFn)[]
|
||||
): T.ExpectedExports.uninit {
|
||||
return async (opts) => {
|
||||
for (const uninit of uninits) {
|
||||
if ("uninit" in uninit) await uninit.uninit(opts.effects, opts.target)
|
||||
else await uninit(opts.effects, opts.target)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,12 @@ export class Origin {
|
||||
readonly sslScheme: string | null,
|
||||
) {}
|
||||
|
||||
build({ username, path, search, schemeOverride }: BuildOptions): AddressInfo {
|
||||
build({
|
||||
username,
|
||||
path,
|
||||
query: search,
|
||||
schemeOverride,
|
||||
}: BuildOptions): AddressInfo {
|
||||
const qpEntries = Object.entries(search)
|
||||
.map(
|
||||
([key, val]) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`,
|
||||
@@ -50,7 +55,7 @@ export class Origin {
|
||||
type,
|
||||
username,
|
||||
path,
|
||||
search,
|
||||
query: search,
|
||||
schemeOverride,
|
||||
masked,
|
||||
} = serviceInterface.options
|
||||
@@ -58,7 +63,7 @@ export class Origin {
|
||||
const addressInfo = this.build({
|
||||
username,
|
||||
path,
|
||||
search,
|
||||
query: search,
|
||||
schemeOverride,
|
||||
})
|
||||
|
||||
@@ -82,5 +87,5 @@ type BuildOptions = {
|
||||
schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
|
||||
username: string | null
|
||||
path: string
|
||||
search: Record<string, string>
|
||||
query: Record<string, string>
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export class ServiceInterfaceBuilder {
|
||||
type: ServiceInterfaceType
|
||||
username: string | null
|
||||
path: string
|
||||
search: Record<string, string>
|
||||
query: Record<string, string>
|
||||
schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
|
||||
masked: boolean
|
||||
},
|
||||
|
||||
@@ -10,46 +10,34 @@ export type UpdateServiceInterfacesReceipt = {
|
||||
export type ServiceInterfacesReceipt = Array<T.AddressInfo[] & AddressReceipt>
|
||||
export type SetServiceInterfaces<Output extends ServiceInterfacesReceipt> =
|
||||
(opts: { effects: T.Effects }) => Promise<Output>
|
||||
export type UpdateServiceInterfaces<Output extends ServiceInterfacesReceipt> =
|
||||
(opts: {
|
||||
effects: T.Effects
|
||||
}) => Promise<Output & UpdateServiceInterfacesReceipt>
|
||||
export type UpdateServiceInterfaces = (effects: T.Effects) => Promise<null>
|
||||
export type SetupServiceInterfaces = <Output extends ServiceInterfacesReceipt>(
|
||||
fn: SetServiceInterfaces<Output>,
|
||||
) => UpdateServiceInterfaces<Output>
|
||||
) => UpdateServiceInterfaces
|
||||
export const NO_INTERFACE_CHANGES = {} as UpdateServiceInterfacesReceipt
|
||||
export const setupServiceInterfaces: SetupServiceInterfaces = <
|
||||
Output extends ServiceInterfacesReceipt,
|
||||
>(
|
||||
fn: SetServiceInterfaces<Output>,
|
||||
) => {
|
||||
const cell = {
|
||||
updater: (async (options: { effects: T.Effects }) =>
|
||||
[] as any as Output) as UpdateServiceInterfaces<Output>,
|
||||
}
|
||||
cell.updater = (async (options: { effects: T.Effects }) => {
|
||||
const childEffects = options.effects.child("setupInterfaces")
|
||||
childEffects.constRetry = once(() => {
|
||||
cell.updater({ effects: options.effects })
|
||||
})
|
||||
return (async (effects: T.Effects) => {
|
||||
const bindings: T.BindId[] = []
|
||||
const interfaces: T.ServiceInterfaceId[] = []
|
||||
const res = await fn({
|
||||
await fn({
|
||||
effects: {
|
||||
...childEffects,
|
||||
...effects,
|
||||
bind: (params: T.BindParams) => {
|
||||
bindings.push({ id: params.id, internalPort: params.internalPort })
|
||||
return childEffects.bind(params)
|
||||
return effects.bind(params)
|
||||
},
|
||||
exportServiceInterface: (params: T.ExportServiceInterfaceParams) => {
|
||||
interfaces.push(params.id)
|
||||
return childEffects.exportServiceInterface(params)
|
||||
return effects.exportServiceInterface(params)
|
||||
},
|
||||
},
|
||||
})
|
||||
await options.effects.clearBindings({ except: bindings })
|
||||
await options.effects.clearServiceInterfaces({ except: interfaces })
|
||||
return res
|
||||
}) as UpdateServiceInterfaces<Output>
|
||||
return cell.updater
|
||||
await effects.clearBindings({ except: bindings })
|
||||
await effects.clearServiceInterfaces({ except: interfaces })
|
||||
return null
|
||||
}) as UpdateServiceInterfaces
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionId } from "./ActionId"
|
||||
import type { ActionRequestInput } from "./ActionRequestInput"
|
||||
import type { ActionRequestTrigger } from "./ActionRequestTrigger"
|
||||
import type { ActionSeverity } from "./ActionSeverity"
|
||||
import type { PackageId } from "./PackageId"
|
||||
|
||||
export type ActionRequest = {
|
||||
packageId: PackageId
|
||||
actionId: ActionId
|
||||
severity: ActionSeverity
|
||||
reason?: string
|
||||
when?: ActionRequestTrigger
|
||||
input?: ActionRequestInput
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionRequest } from "./ActionRequest"
|
||||
|
||||
export type ActionRequestEntry = { request: ActionRequest; active: boolean }
|
||||
@@ -1,7 +0,0 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionRequestCondition } from "./ActionRequestCondition"
|
||||
|
||||
export type ActionRequestTrigger = {
|
||||
once: boolean
|
||||
condition: ActionRequestCondition
|
||||
}
|
||||
@@ -4,4 +4,5 @@ import type { EncryptedWire } from "./EncryptedWire"
|
||||
export type AttachParams = {
|
||||
startOsPassword: EncryptedWire | null
|
||||
guid: string
|
||||
kiosk?: boolean
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionRequestEntry } from "./ActionRequestEntry"
|
||||
import type { HealthCheckId } from "./HealthCheckId"
|
||||
import type { NamedHealthCheckResult } from "./NamedHealthCheckResult"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { ReplayId } from "./ReplayId"
|
||||
import type { TaskEntry } from "./TaskEntry"
|
||||
import type { Version } from "./Version"
|
||||
|
||||
export type CheckDependenciesResult = {
|
||||
@@ -12,6 +12,6 @@ export type CheckDependenciesResult = {
|
||||
installedVersion: Version | null
|
||||
satisfies: Array<Version>
|
||||
isRunning: boolean
|
||||
requestedActions: { [key: ReplayId]: ActionRequestEntry }
|
||||
tasks: { [key: ReplayId]: TaskEntry }
|
||||
healthChecks: { [key: HealthCheckId]: NamedHealthCheckResult }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ClearActionRequestsParams =
|
||||
| { only: string[] }
|
||||
| { except: string[] }
|
||||
export type ClearTasksParams = { only: string[] } | { except: string[] }
|
||||
@@ -1,17 +1,17 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionId } from "./ActionId"
|
||||
import type { ActionRequestInput } from "./ActionRequestInput"
|
||||
import type { ActionRequestTrigger } from "./ActionRequestTrigger"
|
||||
import type { ActionSeverity } from "./ActionSeverity"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { ReplayId } from "./ReplayId"
|
||||
import type { TaskInput } from "./TaskInput"
|
||||
import type { TaskSeverity } from "./TaskSeverity"
|
||||
import type { TaskTrigger } from "./TaskTrigger"
|
||||
|
||||
export type RequestActionParams = {
|
||||
export type CreateTaskParams = {
|
||||
replayId: ReplayId
|
||||
packageId: PackageId
|
||||
actionId: ActionId
|
||||
severity: ActionSeverity
|
||||
severity: TaskSeverity
|
||||
reason?: string
|
||||
when?: ActionRequestTrigger
|
||||
input?: ActionRequestInput
|
||||
when?: TaskTrigger
|
||||
input?: TaskInput
|
||||
}
|
||||
@@ -12,7 +12,6 @@ export type MainStatus =
|
||||
}
|
||||
| { main: "stopped" }
|
||||
| { main: "restarting" }
|
||||
| { main: "restoring" }
|
||||
| { main: "stopping" }
|
||||
| {
|
||||
main: "starting"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionId } from "./ActionId"
|
||||
import type { ActionMetadata } from "./ActionMetadata"
|
||||
import type { ActionRequestEntry } from "./ActionRequestEntry"
|
||||
import type { CurrentDependencies } from "./CurrentDependencies"
|
||||
import type { DataUrl } from "./DataUrl"
|
||||
import type { Hosts } from "./Hosts"
|
||||
@@ -9,11 +8,11 @@ import type { MainStatus } from "./MainStatus"
|
||||
import type { PackageState } from "./PackageState"
|
||||
import type { ServiceInterface } from "./ServiceInterface"
|
||||
import type { ServiceInterfaceId } from "./ServiceInterfaceId"
|
||||
import type { Version } from "./Version"
|
||||
import type { TaskEntry } from "./TaskEntry"
|
||||
|
||||
export type PackageDataEntry = {
|
||||
stateInfo: PackageState
|
||||
dataVersion: Version | null
|
||||
dataVersion: string | null
|
||||
status: MainStatus
|
||||
registry: string | null
|
||||
developerKey: string
|
||||
@@ -21,7 +20,7 @@ export type PackageDataEntry = {
|
||||
lastBackup: string | null
|
||||
currentDependencies: CurrentDependencies
|
||||
actions: { [key: ActionId]: ActionMetadata }
|
||||
requestedActions: { [key: string]: ActionRequestEntry }
|
||||
tasks: { [key: string]: TaskEntry }
|
||||
serviceInterfaces: { [key: ServiceInterfaceId]: ServiceInterface }
|
||||
hosts: Hosts
|
||||
storeExposedDependents: string[]
|
||||
|
||||
@@ -26,4 +26,5 @@ export type ServerInfo = {
|
||||
smtp: SmtpValue | null
|
||||
ram: number
|
||||
devices: Array<LshwDevice>
|
||||
kiosk: boolean | null
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ export type SetupExecuteParams = {
|
||||
startOsLogicalname: string
|
||||
startOsPassword: EncryptedWire
|
||||
recoverySource: RecoverySource<EncryptedWire> | null
|
||||
kiosk?: boolean
|
||||
}
|
||||
|
||||
15
sdk/base/lib/osBindings/Task.ts
Normal file
15
sdk/base/lib/osBindings/Task.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { ActionId } from "./ActionId"
|
||||
import type { PackageId } from "./PackageId"
|
||||
import type { TaskInput } from "./TaskInput"
|
||||
import type { TaskSeverity } from "./TaskSeverity"
|
||||
import type { TaskTrigger } from "./TaskTrigger"
|
||||
|
||||
export type Task = {
|
||||
packageId: PackageId
|
||||
actionId: ActionId
|
||||
severity: TaskSeverity
|
||||
reason?: string
|
||||
when?: TaskTrigger
|
||||
input?: TaskInput
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ActionSeverity = "critical" | "important"
|
||||
export type TaskCondition = "input-not-matches"
|
||||
4
sdk/base/lib/osBindings/TaskEntry.ts
Normal file
4
sdk/base/lib/osBindings/TaskEntry.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Task } from "./Task"
|
||||
|
||||
export type TaskEntry = { task: Task; active: boolean }
|
||||
@@ -1,6 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ActionRequestInput = {
|
||||
kind: "partial"
|
||||
value: Record<string, unknown>
|
||||
}
|
||||
export type TaskInput = { kind: "partial"; value: Record<string, unknown> }
|
||||
@@ -1,3 +1,3 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ActionRequestCondition = "input-not-matches"
|
||||
export type TaskSeverity = "optional" | "important" | "critical"
|
||||
4
sdk/base/lib/osBindings/TaskTrigger.ts
Normal file
4
sdk/base/lib/osBindings/TaskTrigger.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { TaskCondition } from "./TaskCondition"
|
||||
|
||||
export type TaskTrigger = { once: boolean; condition: TaskCondition }
|
||||
@@ -4,17 +4,11 @@ export { AcmeSettings } from "./AcmeSettings"
|
||||
export { ActionId } from "./ActionId"
|
||||
export { ActionInput } from "./ActionInput"
|
||||
export { ActionMetadata } from "./ActionMetadata"
|
||||
export { ActionRequestCondition } from "./ActionRequestCondition"
|
||||
export { ActionRequestEntry } from "./ActionRequestEntry"
|
||||
export { ActionRequestInput } from "./ActionRequestInput"
|
||||
export { ActionRequestTrigger } from "./ActionRequestTrigger"
|
||||
export { ActionRequest } from "./ActionRequest"
|
||||
export { ActionResultMember } from "./ActionResultMember"
|
||||
export { ActionResult } from "./ActionResult"
|
||||
export { ActionResultV0 } from "./ActionResultV0"
|
||||
export { ActionResultV1 } from "./ActionResultV1"
|
||||
export { ActionResultValue } from "./ActionResultValue"
|
||||
export { ActionSeverity } from "./ActionSeverity"
|
||||
export { ActionVisibility } from "./ActionVisibility"
|
||||
export { AddAdminParams } from "./AddAdminParams"
|
||||
export { AddAssetParams } from "./AddAssetParams"
|
||||
@@ -51,14 +45,15 @@ export { Celsius } from "./Celsius"
|
||||
export { CheckDependenciesParam } from "./CheckDependenciesParam"
|
||||
export { CheckDependenciesResult } from "./CheckDependenciesResult"
|
||||
export { Cifs } from "./Cifs"
|
||||
export { ClearActionRequestsParams } from "./ClearActionRequestsParams"
|
||||
export { ClearActionsParams } from "./ClearActionsParams"
|
||||
export { ClearBindingsParams } from "./ClearBindingsParams"
|
||||
export { ClearCallbacksParams } from "./ClearCallbacksParams"
|
||||
export { ClearServiceInterfacesParams } from "./ClearServiceInterfacesParams"
|
||||
export { ClearTasksParams } from "./ClearTasksParams"
|
||||
export { CliSetIconParams } from "./CliSetIconParams"
|
||||
export { ContactInfo } from "./ContactInfo"
|
||||
export { CreateSubcontainerFsParams } from "./CreateSubcontainerFsParams"
|
||||
export { CreateTaskParams } from "./CreateTaskParams"
|
||||
export { CurrentDependencies } from "./CurrentDependencies"
|
||||
export { CurrentDependencyInfo } from "./CurrentDependencyInfo"
|
||||
export { DataUrl } from "./DataUrl"
|
||||
@@ -173,7 +168,6 @@ export { RemovePackageFromCategoryParams } from "./RemovePackageFromCategoryPara
|
||||
export { RemovePackageParams } from "./RemovePackageParams"
|
||||
export { RemoveVersionParams } from "./RemoveVersionParams"
|
||||
export { ReplayId } from "./ReplayId"
|
||||
export { RequestActionParams } from "./RequestActionParams"
|
||||
export { RequestCommitment } from "./RequestCommitment"
|
||||
export { RunActionParams } from "./RunActionParams"
|
||||
export { Security } from "./Security"
|
||||
@@ -201,6 +195,12 @@ export { SignAssetParams } from "./SignAssetParams"
|
||||
export { SignerInfo } from "./SignerInfo"
|
||||
export { SmtpValue } from "./SmtpValue"
|
||||
export { StartStop } from "./StartStop"
|
||||
export { TaskCondition } from "./TaskCondition"
|
||||
export { TaskEntry } from "./TaskEntry"
|
||||
export { TaskInput } from "./TaskInput"
|
||||
export { TaskSeverity } from "./TaskSeverity"
|
||||
export { TaskTrigger } from "./TaskTrigger"
|
||||
export { Task } from "./Task"
|
||||
export { TestSmtpParams } from "./TestSmtpParams"
|
||||
export { UnsetInboundParams } from "./UnsetInboundParams"
|
||||
export { UpdatingState } from "./UpdatingState"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Effects } from "../types"
|
||||
import {
|
||||
CheckDependenciesParam,
|
||||
ClearActionRequestsParams,
|
||||
ClearTasksParams,
|
||||
ClearActionsParams,
|
||||
ClearBindingsParams,
|
||||
ClearCallbacksParams,
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
GetActionInputParams,
|
||||
GetContainerIpParams,
|
||||
GetStatusParams,
|
||||
RequestActionParams,
|
||||
CreateTaskParams,
|
||||
RunActionParams,
|
||||
SetDataVersionParams,
|
||||
SetMainStatus,
|
||||
@@ -30,6 +30,7 @@ import { ListServiceInterfacesParams } from ".././osBindings"
|
||||
import { ExportActionParams } from ".././osBindings"
|
||||
import { MountParams } from ".././osBindings"
|
||||
import { StringObject } from "../util"
|
||||
import { ExtendedVersion, VersionRange } from "../exver"
|
||||
function typeEquality<ExpectedType>(_a: ExpectedType) {}
|
||||
|
||||
type WithCallback<T> = Omit<T, "callback"> & { callback: () => void }
|
||||
@@ -54,8 +55,8 @@ describe("startosTypeValidation ", () => {
|
||||
export: {} as ExportActionParams,
|
||||
getInput: {} as GetActionInputParams,
|
||||
run: {} as RunActionParams,
|
||||
request: {} as RequestActionParams,
|
||||
clearRequests: {} as ClearActionRequestsParams,
|
||||
createTask: {} as CreateTaskParams,
|
||||
clearTasks: {} as ClearTasksParams,
|
||||
},
|
||||
subcontainer: {
|
||||
createFs: {} as CreateSubcontainerFsParams,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
import { Affine, StringObject, ToKebab } from "./util"
|
||||
import { Action, Actions } from "./actions/setupActions"
|
||||
import { Effects } from "./Effects"
|
||||
import { ExtendedVersion, VersionRange } from "./exver"
|
||||
export { Effects }
|
||||
export * from "./osBindings"
|
||||
export { SDKManifest } from "./types/ManifestTypes"
|
||||
@@ -38,10 +39,6 @@ export namespace ExpectedExports {
|
||||
|
||||
/** For backing up service data though the startOS UI */
|
||||
export type createBackup = (options: { effects: Effects }) => Promise<unknown>
|
||||
/** For restoring service data that was previously backed up using the startOS UI create backup flow. Backup restores are also triggered via the startOS UI, or doing a system restore flow during setup. */
|
||||
export type restoreBackup = (options: {
|
||||
effects: Effects
|
||||
}) => Promise<unknown>
|
||||
|
||||
/**
|
||||
* This is the entrypoint for the main container. Used to start up something like the service that the
|
||||
@@ -52,33 +49,20 @@ export namespace ExpectedExports {
|
||||
started(onTerm: () => PromiseLike<void>): PromiseLike<null>
|
||||
}) => Promise<DaemonBuildable>
|
||||
|
||||
/**
|
||||
* After a shutdown, if we wanted to do any operations to clean up things, like
|
||||
* set the action as unavailable or something.
|
||||
*/
|
||||
export type afterShutdown = (options: {
|
||||
effects: Effects
|
||||
}) => Promise<unknown>
|
||||
|
||||
/**
|
||||
* Every time a service launches (both on startup, and on install) this function is called before packageInit
|
||||
* Can be used to register callbacks
|
||||
*/
|
||||
export type containerInit = (options: {
|
||||
export type init = (options: {
|
||||
effects: Effects
|
||||
kind: "install" | "update" | "restore" | null
|
||||
}) => Promise<unknown>
|
||||
|
||||
/**
|
||||
* Every time a package completes an install, this function is called before the main.
|
||||
* Can be used to do migration like things.
|
||||
*/
|
||||
export type packageInit = (options: { effects: Effects }) => Promise<unknown>
|
||||
/** This will be ran during any time a package is uninstalled, for example during a update
|
||||
* this will be called.
|
||||
*/
|
||||
export type packageUninit = (options: {
|
||||
export type uninit = (options: {
|
||||
effects: Effects
|
||||
nextVersion: null | string
|
||||
target: ExtendedVersion | VersionRange | null
|
||||
}) => Promise<unknown>
|
||||
|
||||
export type manifest = Manifest
|
||||
@@ -87,12 +71,9 @@ export namespace ExpectedExports {
|
||||
}
|
||||
export type ABI = {
|
||||
createBackup: ExpectedExports.createBackup
|
||||
restoreBackup: ExpectedExports.restoreBackup
|
||||
main: ExpectedExports.main
|
||||
afterShutdown: ExpectedExports.afterShutdown
|
||||
containerInit: ExpectedExports.containerInit
|
||||
packageInit: ExpectedExports.packageInit
|
||||
packageUninit: ExpectedExports.packageUninit
|
||||
init: ExpectedExports.init
|
||||
uninit: ExpectedExports.uninit
|
||||
manifest: ExpectedExports.manifest
|
||||
actions: ExpectedExports.actions
|
||||
}
|
||||
@@ -119,8 +100,14 @@ export type SmtpValue = {
|
||||
}
|
||||
|
||||
export class UseEntrypoint {
|
||||
readonly USE_ENTRYPOINT = "USE_ENTRYPOINT"
|
||||
constructor(readonly overridCmd?: string[]) {}
|
||||
}
|
||||
export function isUseEntrypoint(
|
||||
command: CommandType,
|
||||
): command is UseEntrypoint {
|
||||
return typeof command === "object" && "ENTRYPOINT" in command
|
||||
}
|
||||
|
||||
export type CommandType = string | [string, ...string[]] | UseEntrypoint
|
||||
|
||||
|
||||
Reference in New Issue
Block a user