mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
Merge branch 'integration/new-container-runtime' of github.com:Start9Labs/start-os into integration/new-container-runtime
This commit is contained in:
@@ -147,11 +147,6 @@ export class HostSystemStartOs implements Effects {
|
||||
T.Effects["exposeForDependents"]
|
||||
>
|
||||
}
|
||||
exposeUi(...[options]: Parameters<T.Effects["exposeUi"]>) {
|
||||
return this.rpcRound("exposeUi", options) as ReturnType<
|
||||
T.Effects["exposeUi"]
|
||||
>
|
||||
}
|
||||
getConfigured(...[]: Parameters<T.Effects["getConfigured"]>) {
|
||||
return this.rpcRound("getConfigured", null) as ReturnType<
|
||||
T.Effects["getConfigured"]
|
||||
|
||||
@@ -25,15 +25,12 @@ export class MainLoop {
|
||||
wait: Promise<unknown>
|
||||
}>
|
||||
| undefined
|
||||
private propertiesEvent: NodeJS.Timeout | undefined
|
||||
constructor(
|
||||
readonly system: SystemForEmbassy,
|
||||
readonly effects: HostSystemStartOs,
|
||||
readonly runProperties: () => Promise<void>,
|
||||
) {
|
||||
this.healthLoops = this.constructHealthLoops()
|
||||
this.mainEvent = this.constructMainEvent()
|
||||
this.propertiesEvent = this.constructPropertiesEvent()
|
||||
}
|
||||
|
||||
private async constructMainEvent() {
|
||||
@@ -85,23 +82,14 @@ export class MainLoop {
|
||||
}
|
||||
|
||||
public async clean(options?: { timeout?: number }) {
|
||||
const { mainEvent, healthLoops, propertiesEvent } = this
|
||||
const { mainEvent, healthLoops } = this
|
||||
const main = await mainEvent
|
||||
delete this.mainEvent
|
||||
delete this.healthLoops
|
||||
delete this.propertiesEvent
|
||||
if (mainEvent) await main?.daemon.term()
|
||||
clearInterval(propertiesEvent)
|
||||
if (healthLoops) healthLoops.forEach((x) => clearInterval(x.interval))
|
||||
}
|
||||
|
||||
private constructPropertiesEvent() {
|
||||
const { runProperties } = this
|
||||
return setInterval(() => {
|
||||
runProperties()
|
||||
}, EMBASSY_PROPERTIES_LOOP)
|
||||
}
|
||||
|
||||
private constructHealthLoops() {
|
||||
const { manifest } = this.system
|
||||
const effects = this.effects
|
||||
|
||||
@@ -59,6 +59,33 @@ export type PackagePropertyObject = {
|
||||
type: "object"
|
||||
description: string
|
||||
}
|
||||
|
||||
const asProperty_ = (
|
||||
x: PackagePropertyString | PackagePropertyObject,
|
||||
): T.PropertiesValue => {
|
||||
if (x.type === "object") {
|
||||
return {
|
||||
...x,
|
||||
value: Object.fromEntries(
|
||||
Object.entries(x.value).map(([key, value]) => [
|
||||
key,
|
||||
asProperty_(value),
|
||||
]),
|
||||
),
|
||||
}
|
||||
}
|
||||
return {
|
||||
masked: false,
|
||||
description: null,
|
||||
qr: null,
|
||||
copyable: null,
|
||||
...x,
|
||||
}
|
||||
}
|
||||
const asProperty = (x: PackagePropertiesV2): T.PropertiesReturn =>
|
||||
Object.fromEntries(
|
||||
Object.entries(x).map(([key, value]) => [key, asProperty_(value)]),
|
||||
)
|
||||
const [matchPackageProperties, setMatchPackageProperties] =
|
||||
deferred<PackagePropertiesV2>()
|
||||
const matchPackagePropertyObject: Parser<unknown, PackagePropertyObject> =
|
||||
@@ -92,44 +119,6 @@ const matchProperties = object({
|
||||
data: matchPackageProperties,
|
||||
})
|
||||
|
||||
type ExportUi = {
|
||||
values: { [key: string]: any }
|
||||
expose: { [key: string]: T.ExposeUiPathsAll }
|
||||
}
|
||||
|
||||
function propertiesToExportUi(
|
||||
properties: PackagePropertiesV2,
|
||||
previousPath = "",
|
||||
): ExportUi {
|
||||
const exportUi: ExportUi = {
|
||||
values: {},
|
||||
expose: {},
|
||||
}
|
||||
for (const [key, value] of Object.entries(properties)) {
|
||||
const path = `${previousPath}/${key}`
|
||||
if (value.type === "object") {
|
||||
const { values, expose } = propertiesToExportUi(value.value, path)
|
||||
exportUi.values[key] = values
|
||||
exportUi.expose[key] = {
|
||||
type: "object",
|
||||
value: expose,
|
||||
description: value.description,
|
||||
}
|
||||
continue
|
||||
}
|
||||
exportUi.values[key] = value.value
|
||||
exportUi.expose[key] = {
|
||||
type: "string",
|
||||
path,
|
||||
description: value.description ?? null,
|
||||
masked: value.masked ?? false,
|
||||
copyable: value.copyable ?? null,
|
||||
qr: value.qr ?? null,
|
||||
}
|
||||
}
|
||||
return exportUi
|
||||
}
|
||||
|
||||
export class SystemForEmbassy implements System {
|
||||
currentRunning: MainLoop | undefined
|
||||
static async of(manifestLocation: string = MANIFEST_LOCATION) {
|
||||
@@ -236,6 +225,8 @@ export class SystemForEmbassy implements System {
|
||||
return this.getConfig(effects)
|
||||
case "/config/set":
|
||||
return this.setConfig(effects, input)
|
||||
case "/properties":
|
||||
return this.properties(effects)
|
||||
case "/actions/metadata":
|
||||
return todo()
|
||||
case "/init":
|
||||
@@ -279,9 +270,7 @@ export class SystemForEmbassy implements System {
|
||||
private async mainStart(effects: HostSystemStartOs): Promise<void> {
|
||||
if (!!this.currentRunning) return
|
||||
|
||||
this.currentRunning = new MainLoop(this, effects, () =>
|
||||
this.properties(effects),
|
||||
)
|
||||
this.currentRunning = new MainLoop(this, effects)
|
||||
}
|
||||
private async mainStop(
|
||||
effects: HostSystemStartOs,
|
||||
@@ -472,51 +461,44 @@ export class SystemForEmbassy implements System {
|
||||
}
|
||||
return { configured: true }
|
||||
}
|
||||
private async properties(effects: HostSystemStartOs): Promise<undefined> {
|
||||
private async properties(
|
||||
effects: HostSystemStartOs,
|
||||
): Promise<ReturnType<T.ExpectedExports.Properties>> {
|
||||
// TODO BLU-J set the properties ever so often
|
||||
const setConfigValue = this.manifest.properties
|
||||
if (!setConfigValue) return
|
||||
if (!setConfigValue) throw new Error("There is no properties")
|
||||
if (setConfigValue.type === "docker") {
|
||||
const container = await DockerProcedureContainer.of(
|
||||
effects,
|
||||
setConfigValue,
|
||||
this.manifest.volumes,
|
||||
)
|
||||
const properties = JSON.parse(
|
||||
(
|
||||
await container.exec([
|
||||
setConfigValue.entrypoint,
|
||||
...setConfigValue.args,
|
||||
])
|
||||
).stdout.toString(),
|
||||
const properties = matchProperties.unsafeCast(
|
||||
JSON.parse(
|
||||
(
|
||||
await container.exec([
|
||||
setConfigValue.entrypoint,
|
||||
...setConfigValue.args,
|
||||
])
|
||||
).stdout.toString(),
|
||||
),
|
||||
)
|
||||
if (!matchProperties.test(properties)) return
|
||||
const exposeUis = propertiesToExportUi(properties.data)
|
||||
await effects.store.set<any, any>({
|
||||
path: "/properties",
|
||||
value: exposeUis.values,
|
||||
})
|
||||
await effects.exposeUi(exposeUis.expose)
|
||||
return asProperty(properties.data)
|
||||
} else if (setConfigValue.type === "script") {
|
||||
const moduleCode = this.moduleCode
|
||||
const method = moduleCode.properties
|
||||
if (!method)
|
||||
throw new Error("Expecting that the method properties exists")
|
||||
const properties = await method(
|
||||
new PolyfillEffects(effects, this.manifest),
|
||||
).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
throw new Error("Error getting config: " + x["error-code"][1])
|
||||
})
|
||||
if (!matchProperties.test(properties)) return
|
||||
const exposeUis = propertiesToExportUi(properties.data)
|
||||
await effects.store.set<any, any>({
|
||||
path: "/properties",
|
||||
value: exposeUis.values,
|
||||
})
|
||||
await effects.exposeUi(exposeUis.expose)
|
||||
const properties = matchProperties.unsafeCast(
|
||||
await method(new PolyfillEffects(effects, this.manifest)).then((x) => {
|
||||
if ("result" in x) return x.result
|
||||
if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
throw new Error("Error getting config: " + x["error-code"][1])
|
||||
}),
|
||||
)
|
||||
return asProperty(properties.data)
|
||||
}
|
||||
throw new Error(`Unknown type in the fetch properties: ${setConfigValue}`)
|
||||
}
|
||||
private async health(
|
||||
effects: HostSystemStartOs,
|
||||
@@ -651,279 +633,6 @@ export class SystemForEmbassy implements System {
|
||||
throw new Error("Error getting config: " + x["error-code"][1])
|
||||
})) as any
|
||||
}
|
||||
// private async sandbox(
|
||||
// effects: HostSystemStartOs,
|
||||
// options: {
|
||||
// procedure:
|
||||
// | "/createBackup"
|
||||
// | "/restoreBackup"
|
||||
// | "/getConfig"
|
||||
// | "/setConfig"
|
||||
// | "migration"
|
||||
// | "/properties"
|
||||
// | `/action/${string}`
|
||||
// | `/dependencies/${string}/check`
|
||||
// | `/dependencies/${string}/autoConfigure`
|
||||
// input: unknown
|
||||
// timeout?: number | undefined
|
||||
// },
|
||||
// ): Promise<unknown> {
|
||||
// const input = options.input
|
||||
// switch (options.procedure) {
|
||||
// case "/createBackup":
|
||||
// return this.roCreateBackup(effects)
|
||||
// case "/restoreBackup":
|
||||
// return this.roRestoreBackup(effects)
|
||||
// case "/getConfig":
|
||||
// return this.roGetConfig(effects)
|
||||
// case "/setConfig":
|
||||
// return this.roSetConfig(effects, input)
|
||||
// case "migration":
|
||||
// return this.roMigration(effects, input)
|
||||
// case "/properties":
|
||||
// return this.roProperties(effects)
|
||||
// default:
|
||||
// const procedure = options.procedure.split("/")
|
||||
// switch (true) {
|
||||
// case options.procedure.startsWith("/action/"):
|
||||
// return this.roAction(effects, procedure[2], input)
|
||||
// case options.procedure.startsWith("/dependencies/") &&
|
||||
// procedure[3] === "check":
|
||||
// return this.roDependenciesCheck(effects, procedure[2], input)
|
||||
|
||||
// case options.procedure.startsWith("/dependencies/") &&
|
||||
// procedure[3] === "autoConfigure":
|
||||
// return this.roDependenciesAutoconfig(effects, procedure[2], input)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// private async roCreateBackup(effects: HostSystemStartOs): Promise<void> {
|
||||
// const backup = this.manifest.backup.create
|
||||
// if (backup.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(backup)
|
||||
// await container.exec([backup.entrypoint, ...backup.args])
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// await moduleCode.createBackup?.(new PolyfillEffects(effects))
|
||||
// }
|
||||
// }
|
||||
// private async roRestoreBackup(effects: HostSystemStartOs): Promise<void> {
|
||||
// const restoreBackup = this.manifest.backup.restore
|
||||
// if (restoreBackup.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(restoreBackup)
|
||||
// await container.exec([restoreBackup.entrypoint, ...restoreBackup.args])
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// await moduleCode.restoreBackup?.(new PolyfillEffects(effects))
|
||||
// }
|
||||
// }
|
||||
// private async roGetConfig(effects: HostSystemStartOs): Promise<T.ConfigRes> {
|
||||
// const config = this.manifest.config?.get
|
||||
// if (!config) return { spec: {} }
|
||||
// if (config.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(config)
|
||||
// return JSON.parse(
|
||||
// (await container.exec([config.entrypoint, ...config.args])).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.getConfig
|
||||
// if (!method) throw new Error("Expecting that the method getConfig exists")
|
||||
// return (await method(new PolyfillEffects(effects)).then((x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// })) as any
|
||||
// }
|
||||
// }
|
||||
// private async roSetConfig(
|
||||
// effects: HostSystemStartOs,
|
||||
// newConfig: unknown,
|
||||
// ): Promise<T.SetResult> {
|
||||
// const setConfigValue = this.manifest.config?.set
|
||||
// if (!setConfigValue) return { signal: "SIGTERM", "depends-on": {} }
|
||||
// if (setConfigValue.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(
|
||||
// setConfigValue,
|
||||
// )
|
||||
// return JSON.parse(
|
||||
// (
|
||||
// await container.exec([
|
||||
// setConfigValue.entrypoint,
|
||||
// ...setConfigValue.args,
|
||||
// JSON.stringify(newConfig),
|
||||
// ])
|
||||
// ).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.setConfig
|
||||
// if (!method) throw new Error("Expecting that the method setConfig exists")
|
||||
// return await method(
|
||||
// new PolyfillEffects(effects),
|
||||
// newConfig as U.Config,
|
||||
// ).then((x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// private async roMigration(
|
||||
// effects: HostSystemStartOs,
|
||||
// fromVersion: unknown,
|
||||
// ): Promise<T.MigrationRes> {
|
||||
// throw new Error("Migrations should never be ran in the sandbox mode")
|
||||
// }
|
||||
// private async roProperties(effects: HostSystemStartOs): Promise<unknown> {
|
||||
// const setConfigValue = this.manifest.properties
|
||||
// if (!setConfigValue) return {}
|
||||
// if (setConfigValue.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(
|
||||
// setConfigValue,
|
||||
// )
|
||||
// return JSON.parse(
|
||||
// (
|
||||
// await container.exec([
|
||||
// setConfigValue.entrypoint,
|
||||
// ...setConfigValue.args,
|
||||
// ])
|
||||
// ).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.properties
|
||||
// if (!method)
|
||||
// throw new Error("Expecting that the method properties exists")
|
||||
// return await method(new PolyfillEffects(effects)).then((x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// private async roHealth(
|
||||
// effects: HostSystemStartOs,
|
||||
// healthId: string,
|
||||
// timeSinceStarted: unknown,
|
||||
// ): Promise<void> {
|
||||
// const healthProcedure = this.manifest["health-checks"][healthId]
|
||||
// if (!healthProcedure) return
|
||||
// if (healthProcedure.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(
|
||||
// healthProcedure,
|
||||
// )
|
||||
// return JSON.parse(
|
||||
// (
|
||||
// await container.exec([
|
||||
// healthProcedure.entrypoint,
|
||||
// ...healthProcedure.args,
|
||||
// JSON.stringify(timeSinceStarted),
|
||||
// ])
|
||||
// ).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.health?.[healthId]
|
||||
// if (!method) throw new Error("Expecting that the method health exists")
|
||||
// await method(new PolyfillEffects(effects), Number(timeSinceStarted)).then(
|
||||
// (x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// },
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// private async roAction(
|
||||
// effects: HostSystemStartOs,
|
||||
// actionId: string,
|
||||
// formData: unknown,
|
||||
// ): Promise<T.ActionResult> {
|
||||
// const actionProcedure = this.manifest.actions?.[actionId]?.implementation
|
||||
// if (!actionProcedure) return { message: "Action not found", value: null }
|
||||
// if (actionProcedure.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(
|
||||
// actionProcedure,
|
||||
// )
|
||||
// return JSON.parse(
|
||||
// (
|
||||
// await container.exec([
|
||||
// actionProcedure.entrypoint,
|
||||
// ...actionProcedure.args,
|
||||
// JSON.stringify(formData),
|
||||
// ])
|
||||
// ).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.action?.[actionId]
|
||||
// if (!method) throw new Error("Expecting that the method action exists")
|
||||
// return (await method(new PolyfillEffects(effects), formData as any).then(
|
||||
// (x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// },
|
||||
// )) as any
|
||||
// }
|
||||
// }
|
||||
// private async roDependenciesCheck(
|
||||
// effects: HostSystemStartOs,
|
||||
// id: string,
|
||||
// oldConfig: unknown,
|
||||
// ): Promise<object> {
|
||||
// const actionProcedure = this.manifest.dependencies?.[id]?.config?.check
|
||||
// if (!actionProcedure) return { message: "Action not found", value: null }
|
||||
// if (actionProcedure.type === "docker") {
|
||||
// const container = await DockerProcedureContainer.readonlyOf(
|
||||
// actionProcedure,
|
||||
// )
|
||||
// return JSON.parse(
|
||||
// (
|
||||
// await container.exec([
|
||||
// actionProcedure.entrypoint,
|
||||
// ...actionProcedure.args,
|
||||
// JSON.stringify(oldConfig),
|
||||
// ])
|
||||
// ).stdout,
|
||||
// )
|
||||
// } else {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.dependencies?.[id]?.check
|
||||
// if (!method)
|
||||
// throw new Error(
|
||||
// `Expecting that the method dependency check ${id} exists`,
|
||||
// )
|
||||
// return (await method(new PolyfillEffects(effects), oldConfig as any).then(
|
||||
// (x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// },
|
||||
// )) as any
|
||||
// }
|
||||
// }
|
||||
// private async roDependenciesAutoconfig(
|
||||
// effects: HostSystemStartOs,
|
||||
// id: string,
|
||||
// oldConfig: unknown,
|
||||
// ): Promise<void> {
|
||||
// const moduleCode = await this.moduleCode
|
||||
// const method = moduleCode.dependencies?.[id]?.autoConfigure
|
||||
// if (!method)
|
||||
// throw new Error(
|
||||
// `Expecting that the method dependency autoConfigure ${id} exists`,
|
||||
// )
|
||||
// return (await method(new PolyfillEffects(effects), oldConfig as any).then(
|
||||
// (x) => {
|
||||
// if ("result" in x) return x.result
|
||||
// if ("error" in x) throw new Error("Error getting config: " + x.error)
|
||||
// throw new Error("Error getting config: " + x["error-code"][1])
|
||||
// },
|
||||
// )) as any
|
||||
// }
|
||||
}
|
||||
async function removePointers(value: T.ConfigRes): Promise<T.ConfigRes> {
|
||||
const startingSpec = structuredClone(value.spec)
|
||||
|
||||
@@ -35,6 +35,7 @@ export const jsonPath = some(
|
||||
"/backup/create",
|
||||
"/backup/restore",
|
||||
"/actions/metadata",
|
||||
"/properties",
|
||||
),
|
||||
string.refine(isNestedPath, "isNestedPath"),
|
||||
)
|
||||
|
||||
@@ -9,6 +9,7 @@ pub enum ProcedureName {
|
||||
GetConfig,
|
||||
SetConfig,
|
||||
CreateBackup,
|
||||
Properties,
|
||||
RestoreBackup,
|
||||
ActionMetadata,
|
||||
RunAction(ActionId),
|
||||
@@ -29,6 +30,7 @@ impl ProcedureName {
|
||||
ProcedureName::SetConfig => "/config/set".to_string(),
|
||||
ProcedureName::GetConfig => "/config/get".to_string(),
|
||||
ProcedureName::CreateBackup => "/backup/create".to_string(),
|
||||
ProcedureName::Properties => "/properties".to_string(),
|
||||
ProcedureName::RestoreBackup => "/backup/restore".to_string(),
|
||||
ProcedureName::ActionMetadata => "/actions/metadata".to_string(),
|
||||
ProcedureName::RunAction(id) => format!("/actions/{}/run", id),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::{borrow::Borrow, collections::BTreeMap};
|
||||
|
||||
use clap::Parser;
|
||||
use imbl_value::{json, InOMap, InternedString, Value};
|
||||
@@ -15,48 +15,6 @@ pub fn display_properties(response: Value) {
|
||||
println!("{}", response);
|
||||
}
|
||||
|
||||
trait IntoProperties {
|
||||
fn into_properties(self, store: &Value) -> Value;
|
||||
}
|
||||
impl IntoProperties for ExposedUI {
|
||||
fn into_properties(self, store: &Value) -> Value {
|
||||
match self {
|
||||
ExposedUI::Object { value, description } => {
|
||||
json!({
|
||||
"type": "object",
|
||||
"description": description,
|
||||
"value": value.into_iter().map(|(k, v)| (k, v.into_properties(store))).collect::<BTreeMap<String,_>>()
|
||||
})
|
||||
}
|
||||
ExposedUI::String {
|
||||
path,
|
||||
description,
|
||||
masked,
|
||||
copyable,
|
||||
qr,
|
||||
} => json!({
|
||||
"type": "string",
|
||||
"description": description,
|
||||
"value": path.get(store).cloned().unwrap_or_default(),
|
||||
"copyable": copyable,
|
||||
"qr": qr,
|
||||
"masked": masked
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoProperties for StoreExposedUI {
|
||||
fn into_properties(self, store: &Value) -> Value {
|
||||
Value::Object(
|
||||
self.0
|
||||
.into_iter()
|
||||
.map(|(k, v)| (k, v.into_properties(store)))
|
||||
.collect::<InOMap<InternedString, Value>>(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Parser)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[command(rename_all = "kebab-case")]
|
||||
@@ -68,19 +26,11 @@ pub async fn properties(
|
||||
ctx: RpcContext,
|
||||
PropertiesParam { id }: PropertiesParam,
|
||||
) -> Result<Value, Error> {
|
||||
let peeked = ctx.db.peek().await;
|
||||
let data = peeked
|
||||
.as_private()
|
||||
.as_package_stores()
|
||||
.as_idx(&id)
|
||||
.map(|x| x.de())
|
||||
.unwrap_or_else(|| Ok(json!({})))?;
|
||||
Ok(peeked
|
||||
.as_public()
|
||||
.as_package_data()
|
||||
.as_idx(&id)
|
||||
.or_not_found(&id)?
|
||||
.as_store_exposed_ui()
|
||||
.de()?
|
||||
.into_properties(&data))
|
||||
match &*ctx.services.get(&id).await {
|
||||
Some(service) => service.properties().await,
|
||||
None => Err(Error::new(
|
||||
eyre!("Could not find a service with id {id}"),
|
||||
ErrorKind::NotFound,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,6 +325,17 @@ impl Service {
|
||||
.await
|
||||
.with_kind(ErrorKind::Action)
|
||||
}
|
||||
pub async fn properties(&self) -> Result<Value, Error> {
|
||||
let container = &self.seed.persistent_container;
|
||||
container
|
||||
.execute::<Value>(
|
||||
ProcedureName::Properties,
|
||||
Value::Null,
|
||||
Some(Duration::from_secs(30)),
|
||||
)
|
||||
.await
|
||||
.with_kind(ErrorKind::Unknown)
|
||||
}
|
||||
|
||||
pub async fn shutdown(self) -> Result<(), Error> {
|
||||
self.actor
|
||||
|
||||
14
sdk/lib/index.browser.ts
Normal file
14
sdk/lib/index.browser.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
export { EmVer } from "./emverLite/mod"
|
||||
export { setupManifest } from "./manifest/setupManifest"
|
||||
export { setupExposeStore } from "./store/setupExposeStore"
|
||||
export * as config from "./config"
|
||||
export * as CB from "./config/builder"
|
||||
export * as CT from "./config/configTypes"
|
||||
export * as dependencyConfig from "./dependencyConfig"
|
||||
export * as manifest from "./manifest"
|
||||
export * as types from "./types"
|
||||
export * as T from "./types"
|
||||
export * as yaml from "yaml"
|
||||
export * as matches from "ts-matches"
|
||||
|
||||
export * as util from "./util/index.browser"
|
||||
@@ -5,6 +5,7 @@ export { StartSdk } from "./StartSdk"
|
||||
export { setupManifest } from "./manifest/setupManifest"
|
||||
export { FileHelper } from "./util/fileHelper"
|
||||
export { setupExposeStore } from "./store/setupExposeStore"
|
||||
export { pathBuilder } from "./store/PathBuilder"
|
||||
export * as actions from "./actions"
|
||||
export * as backup from "./backup"
|
||||
export * as config from "./config"
|
||||
|
||||
25
sdk/lib/util/index.browser.ts
Normal file
25
sdk/lib/util/index.browser.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import * as T from "../types"
|
||||
|
||||
export { GetServiceInterface, getServiceInterface } from "./getServiceInterface"
|
||||
export { getServiceInterfaces } from "./getServiceInterfaces"
|
||||
// prettier-ignore
|
||||
export type FlattenIntersection<T> =
|
||||
T extends ArrayLike<any> ? T :
|
||||
T extends object ? {} & {[P in keyof T]: T[P]} :
|
||||
T;
|
||||
|
||||
export type _<T> = FlattenIntersection<T>
|
||||
|
||||
export const isKnownError = (e: unknown): e is T.KnownError =>
|
||||
e instanceof Object && ("error" in e || "error-code" in e)
|
||||
|
||||
declare const affine: unique symbol
|
||||
|
||||
export type Affine<A> = { [affine]: A }
|
||||
|
||||
type NeverPossible = { [affine]: string }
|
||||
export type NoAny<A> = NeverPossible extends A
|
||||
? keyof NeverPossible extends keyof A
|
||||
? never
|
||||
: A
|
||||
: A
|
||||
12
sdk/package-lock.json
generated
12
sdk/package-lock.json
generated
@@ -9,19 +9,19 @@
|
||||
"version": "0.4.0-rev0.lib0.rc8.beta10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"ts-matches": "^5.4.1",
|
||||
"yaml": "^2.2.2"
|
||||
"ts-matches": "^5.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@types/jest": "^29.4.0",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.0.4",
|
||||
"yaml": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
@@ -651,7 +651,8 @@
|
||||
"node_modules/@iarna/toml": {
|
||||
"version": "2.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
|
||||
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg=="
|
||||
"integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@istanbuljs/load-nyc-config": {
|
||||
"version": "1.1.0",
|
||||
@@ -4235,6 +4236,7 @@
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
|
||||
@@ -5,14 +5,8 @@
|
||||
"main": "./cjs/sdk/lib/index.js",
|
||||
"types": "./cjs/sdk/lib/index.d.ts",
|
||||
"module": "./mjs/sdk/lib/index.js",
|
||||
"browser": "./mjs/sdk/lib/index.browser.js",
|
||||
"sideEffects": true,
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./mjs/sdk/lib/index.js",
|
||||
"require": "./cjs/sdk/lib/index.js",
|
||||
"types": "./cjs/sdk/lib/index.d.ts"
|
||||
}
|
||||
},
|
||||
"typesVersion": {
|
||||
">=3.1": {
|
||||
"*": [
|
||||
@@ -36,10 +30,8 @@
|
||||
},
|
||||
"homepage": "https://github.com/Start9Labs/start-sdk#readme",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"ts-matches": "^5.4.1",
|
||||
"yaml": "^2.2.2"
|
||||
"ts-matches": "^5.4.1"
|
||||
},
|
||||
"prettier": {
|
||||
"trailingComma": "all",
|
||||
@@ -48,6 +40,8 @@
|
||||
"singleQuote": false
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"yaml": "^2.2.2",
|
||||
"@types/jest": "^29.4.0",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^3.2.5",
|
||||
|
||||
8
web/package-lock.json
generated
8
web/package-lock.json
generated
@@ -1976,19 +1976,19 @@
|
||||
"version": "0.4.0-rev0.lib0.rc8.beta10",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"ts-matches": "^5.4.1",
|
||||
"yaml": "^2.2.2"
|
||||
"ts-matches": "^5.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@types/jest": "^29.4.0",
|
||||
"jest": "^29.4.3",
|
||||
"prettier": "^3.2.5",
|
||||
"ts-jest": "^29.0.5",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsx": "^4.7.1",
|
||||
"typescript": "^5.0.4"
|
||||
"typescript": "^5.0.4",
|
||||
"yaml": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@adobe/css-tools": {
|
||||
|
||||
Reference in New Issue
Block a user