mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
wip: Adding in properties and nested path
This commit is contained in:
@@ -257,7 +257,7 @@ struct RemoveAddressParams {
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
enum AllowedStatuses {
|
||||
OnlyRunning,
|
||||
OnlyRunning, // onlyRunning
|
||||
OnlyStopped,
|
||||
Any,
|
||||
Disabled,
|
||||
@@ -1073,20 +1073,19 @@ enum DependencyKind {
|
||||
#[serde(rename_all = "camelCase", tag = "kind")]
|
||||
#[ts(export)]
|
||||
enum DependencyRequirement {
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Running {
|
||||
#[ts(type = "string")]
|
||||
id: PackageId,
|
||||
#[ts(type = "string[]")]
|
||||
#[serde(rename = "healthChecks")]
|
||||
health_checks: BTreeSet<HealthCheckId>,
|
||||
#[serde(rename = "versionSpec")]
|
||||
version_spec: String,
|
||||
url: String,
|
||||
},
|
||||
#[serde(rename_all = "camelCase")]
|
||||
Exists {
|
||||
#[ts(type = "string")]
|
||||
id: PackageId,
|
||||
#[serde(rename = "versionSpec")]
|
||||
version_spec: String,
|
||||
url: String,
|
||||
},
|
||||
|
||||
@@ -21,9 +21,6 @@ import {
|
||||
MaybePromise,
|
||||
ServiceInterfaceId,
|
||||
PackageId,
|
||||
EnsureStorePath,
|
||||
ExtractStore,
|
||||
DaemonReturned,
|
||||
ValidIfNoStupidEscape,
|
||||
} from "./types"
|
||||
import * as patterns from "./util/patterns"
|
||||
@@ -61,7 +58,6 @@ import {
|
||||
setupInterfaces,
|
||||
} from "./interfaces/setupInterfaces"
|
||||
import { successFailure } from "./trigger/successFailure"
|
||||
import { SetupExports } from "./inits/setupExports"
|
||||
import { HealthReceipt } from "./health/HealthReceipt"
|
||||
import { MultiHost, Scheme, SingleHost, StaticHost } from "./interfaces/Host"
|
||||
import { ServiceInterfaceBuilder } from "./interfaces/ServiceInterfaceBuilder"
|
||||
@@ -79,6 +75,8 @@ import { Mounts } from "./mainFn/Mounts"
|
||||
import { Dependency } from "./Dependency"
|
||||
import * as T from "./types"
|
||||
import { Checker, EmVer } from "./emverLite/mod"
|
||||
import { ExposedStorePaths } from "./store/setupExposeStore"
|
||||
import { PathBuilder, extractJsonPath, pathBuilder } from "./store/PathBuilder"
|
||||
|
||||
// prettier-ignore
|
||||
type AnyNeverCond<T extends any[], Then, Else> =
|
||||
@@ -151,25 +149,29 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
},
|
||||
|
||||
store: {
|
||||
get: <E extends Effects, Path extends string = never>(
|
||||
get: <E extends Effects, StoreValue = unknown>(
|
||||
effects: E,
|
||||
packageId: string,
|
||||
path: EnsureStorePath<Store, Path>,
|
||||
path: PathBuilder<Store, StoreValue>,
|
||||
) =>
|
||||
removeConstType<E>()(
|
||||
getStore<Store, Path>(effects, path as any, {
|
||||
getStore<Store, StoreValue>(effects, path, {
|
||||
packageId,
|
||||
}),
|
||||
),
|
||||
getOwn: <E extends Effects, Path extends string>(
|
||||
getOwn: <E extends Effects, StoreValue = unknown>(
|
||||
effects: E,
|
||||
path: EnsureStorePath<Store, Path>,
|
||||
) => removeConstType<E>()(getStore<Store, Path>(effects, path as any)),
|
||||
setOwn: <E extends Effects, Path extends string | never>(
|
||||
path: PathBuilder<Store, StoreValue>,
|
||||
) => removeConstType<E>()(getStore<Store, StoreValue>(effects, path)),
|
||||
setOwn: <E extends Effects, Path extends PathBuilder<Store, unknown>>(
|
||||
effects: E,
|
||||
path: EnsureStorePath<Store, Path>,
|
||||
value: ExtractStore<Store, Path>,
|
||||
) => effects.store.set<Store, Path>({ value, path: path as any }),
|
||||
path: Path,
|
||||
value: Path extends PathBuilder<Store, infer Value> ? Value : never,
|
||||
) =>
|
||||
effects.store.set<Store>({
|
||||
value,
|
||||
path: extractJsonPath(path),
|
||||
}),
|
||||
},
|
||||
|
||||
host: {
|
||||
@@ -180,24 +182,17 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
multi: (effects: Effects, id: string) => new MultiHost({ id, effects }),
|
||||
},
|
||||
nullIfEmpty,
|
||||
|
||||
configConstants: { smtpConfig },
|
||||
createInterface: (
|
||||
runCommand: async <A extends string>(
|
||||
effects: Effects,
|
||||
options: {
|
||||
name: string
|
||||
id: string
|
||||
description: string
|
||||
hasPrimary: boolean
|
||||
disabled: boolean
|
||||
type: ServiceInterfaceType
|
||||
username: null | string
|
||||
path: string
|
||||
search: Record<string, string>
|
||||
schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
|
||||
masked: boolean
|
||||
imageId: Manifest["images"][number],
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
options: CommandOptions & {
|
||||
mounts?: { path: string; options: MountOptions }[]
|
||||
},
|
||||
) => new ServiceInterfaceBuilder({ ...options, effects }),
|
||||
): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => {
|
||||
return runCommand<Manifest>(effects, imageId, command, options)
|
||||
},
|
||||
|
||||
createAction: <
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
@@ -216,18 +211,25 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
const { input, ...rest } = metaData
|
||||
return createAction<Manifest, Store, ConfigType, Type>(rest, fn, input)
|
||||
},
|
||||
configConstants: { smtpConfig },
|
||||
createInterface: (
|
||||
effects: Effects,
|
||||
options: {
|
||||
name: string
|
||||
id: string
|
||||
description: string
|
||||
hasPrimary: boolean
|
||||
disabled: boolean
|
||||
type: ServiceInterfaceType
|
||||
username: null | string
|
||||
path: string
|
||||
search: Record<string, string>
|
||||
schemeOverride: { ssl: Scheme; noSsl: Scheme } | null
|
||||
masked: boolean
|
||||
},
|
||||
) => new ServiceInterfaceBuilder({ ...options, effects }),
|
||||
getSystemSmtp: <E extends Effects>(effects: E) =>
|
||||
removeConstType<E>()(new GetSystemSmtp(effects)),
|
||||
runCommand: async <A extends string>(
|
||||
effects: Effects,
|
||||
imageId: Manifest["images"][number],
|
||||
command: ValidIfNoStupidEscape<A> | [string, ...string[]],
|
||||
options: CommandOptions & {
|
||||
mounts?: { path: string; options: MountOptions }[]
|
||||
},
|
||||
): Promise<{ stdout: string | Buffer; stderr: string | Buffer }> => {
|
||||
return runCommand<Manifest>(effects, imageId, command, options)
|
||||
},
|
||||
|
||||
createDynamicAction: <
|
||||
ConfigType extends
|
||||
@@ -336,7 +338,6 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
})
|
||||
}
|
||||
},
|
||||
setupExports: (fn: SetupExports<Store>) => fn,
|
||||
setupInit: (
|
||||
migrations: Migrations<Manifest, Store>,
|
||||
install: Install<Manifest, Store>,
|
||||
@@ -346,15 +347,15 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
effects: Effects
|
||||
input: any
|
||||
}) => Promise<DependenciesReceipt>,
|
||||
setupExports: SetupExports<Store>,
|
||||
exposedStore: ExposedStorePaths,
|
||||
) =>
|
||||
setupInit<Manifest, Store>(
|
||||
migrations,
|
||||
install,
|
||||
uninstall,
|
||||
setInterfaces,
|
||||
setupExports,
|
||||
setDependencies,
|
||||
exposedStore,
|
||||
),
|
||||
setupInstall: (fn: InstallFn<Manifest, Store>) => Install.of(fn),
|
||||
setupInterfaces: <
|
||||
@@ -379,6 +380,12 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
this.manifest,
|
||||
...migrations,
|
||||
),
|
||||
setupProperties:
|
||||
(
|
||||
fn: (options: { effects: Effects }) => Promise<T.SdkPropertiesReturn>,
|
||||
): T.ExpectedExports.Properties =>
|
||||
(options) =>
|
||||
fn(options).then(nullifyProperties),
|
||||
setupUninstall: (fn: UninstallFn<Manifest, Store>) =>
|
||||
setupUninstall<Manifest, Store>(fn),
|
||||
trigger: {
|
||||
@@ -531,6 +538,7 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
down: (opts: { effects: Effects }) => Promise<void>
|
||||
}) => Migration.of<Manifest, Store, Version>(options),
|
||||
},
|
||||
StorePath: pathBuilder<Store>(),
|
||||
Value: {
|
||||
toggle: Value.toggle,
|
||||
text: Value.text,
|
||||
@@ -739,3 +747,20 @@ export async function runCommand<Manifest extends SDKManifest>(
|
||||
await overlay.destroy()
|
||||
}
|
||||
}
|
||||
function nullifyProperties(value: T.SdkPropertiesReturn): T.PropertiesReturn {
|
||||
return Object.fromEntries(
|
||||
Object.entries(value).map(([k, v]) => [k, nullifyProperties_(v)]),
|
||||
)
|
||||
}
|
||||
function nullifyProperties_(value: T.SdkPropertiesValue): T.PropertiesValue {
|
||||
if (value.type === "string") {
|
||||
return { description: null, copyable: null, qr: null, ...value }
|
||||
}
|
||||
return {
|
||||
description: null,
|
||||
...value,
|
||||
value: Object.fromEntries(
|
||||
Object.entries(value.value).map(([k, v]) => [k, nullifyProperties_(v)]),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import matches from "ts-matches"
|
||||
|
||||
export { Daemons } from "./mainFn/Daemons"
|
||||
export { EmVer } from "./emverLite/mod"
|
||||
export { Overlay } from "./util/Overlay"
|
||||
export { StartSdk } from "./StartSdk"
|
||||
export { setupManifest } from "./manifest/setupManifest"
|
||||
export { FileHelper } from "./util/fileHelper"
|
||||
export { setupExposeStore } from "./store/setupExposeStore"
|
||||
export * as actions from "./actions"
|
||||
export * as backup from "./backup"
|
||||
export * as config from "./config"
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Effects, ExposeServicePaths, ExposeUiPaths } from "../types"
|
||||
|
||||
export type SetupExports<Store> = (opts: { effects: Effects }) =>
|
||||
| {
|
||||
ui: { [k: string]: ExposeUiPaths<Store> }
|
||||
services: ExposeServicePaths<Store>["paths"]
|
||||
}
|
||||
| Promise<{
|
||||
ui: { [k: string]: ExposeUiPaths<Store> }
|
||||
services: ExposeServicePaths<Store>["paths"]
|
||||
}>
|
||||
|
||||
export const setupExports = <Store>(fn: (opts: SetupExports<Store>) => void) =>
|
||||
fn
|
||||
@@ -1,14 +1,9 @@
|
||||
import { DependenciesReceipt } from "../config/setupConfig"
|
||||
import { SetInterfaces } from "../interfaces/setupInterfaces"
|
||||
import { SDKManifest } from "../manifest/ManifestTypes"
|
||||
import {
|
||||
Effects,
|
||||
ExpectedExports,
|
||||
ExposeUiPaths,
|
||||
ExposeUiPathsAll,
|
||||
} from "../types"
|
||||
import { ExposedStorePaths } from "../store/setupExposeStore"
|
||||
import { Effects, ExpectedExports } from "../types"
|
||||
import { Migrations } from "./migrations/setupMigrations"
|
||||
import { SetupExports } from "./setupExports"
|
||||
import { Install } from "./setupInstall"
|
||||
import { Uninstall } from "./setupUninstall"
|
||||
|
||||
@@ -17,11 +12,11 @@ export function setupInit<Manifest extends SDKManifest, Store>(
|
||||
install: Install<Manifest, Store>,
|
||||
uninstall: Uninstall<Manifest, Store>,
|
||||
setInterfaces: SetInterfaces<Manifest, Store, any, any>,
|
||||
setupExports: SetupExports<Store>,
|
||||
setDependencies: (options: {
|
||||
effects: Effects
|
||||
input: any
|
||||
}) => Promise<DependenciesReceipt>,
|
||||
exposedStore: ExposedStorePaths,
|
||||
): {
|
||||
init: ExpectedExports.init
|
||||
uninit: ExpectedExports.uninit
|
||||
@@ -34,9 +29,7 @@ export function setupInit<Manifest extends SDKManifest, Store>(
|
||||
...opts,
|
||||
input: null,
|
||||
})
|
||||
const { services, ui } = await setupExports(opts)
|
||||
await opts.effects.exposeForDependents({ paths: services })
|
||||
await opts.effects.exposeUi(forExpose(ui))
|
||||
await opts.effects.exposeForDependents({ paths: exposedStore })
|
||||
await setDependencies({ effects: opts.effects, input: null })
|
||||
},
|
||||
uninit: async (opts) => {
|
||||
@@ -45,30 +38,3 @@ export function setupInit<Manifest extends SDKManifest, Store>(
|
||||
},
|
||||
}
|
||||
}
|
||||
function forExpose<Store>(ui: { [key: string]: ExposeUiPaths<Store> }) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(ui).map(([key, value]) => [key, forExpose_(value)]),
|
||||
)
|
||||
}
|
||||
|
||||
function forExpose_<Store>(ui: ExposeUiPaths<Store>): ExposeUiPathsAll {
|
||||
if (ui.type === ("object" as const)) {
|
||||
return {
|
||||
type: "object" as const,
|
||||
value: Object.fromEntries(
|
||||
Object.entries(ui.value).map(([key, value]) => [
|
||||
key,
|
||||
forExpose_(value),
|
||||
]),
|
||||
),
|
||||
description: ui.description ?? null,
|
||||
}
|
||||
}
|
||||
return {
|
||||
description: null,
|
||||
|
||||
copyable: null,
|
||||
qr: null,
|
||||
...ui,
|
||||
}
|
||||
}
|
||||
|
||||
38
sdk/lib/store/PathBuilder.ts
Normal file
38
sdk/lib/store/PathBuilder.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { Affine } from "../util"
|
||||
|
||||
const pathValue = Symbol("pathValue")
|
||||
export type PathValue = typeof pathValue
|
||||
|
||||
export type PathBuilderStored<AllStore, Store> = {
|
||||
[K in PathValue]: [AllStore, Store]
|
||||
}
|
||||
|
||||
export type PathBuilder<AllStore, Store = AllStore> = (Store extends Record<
|
||||
string,
|
||||
unknown
|
||||
>
|
||||
? {
|
||||
[K in keyof Store]: PathBuilder<AllStore, Store[K]>
|
||||
}
|
||||
: {}) &
|
||||
PathBuilderStored<AllStore, Store>
|
||||
|
||||
export type StorePath = string & Affine<"StorePath">
|
||||
const privateSymbol = Symbol("jsonPath")
|
||||
export const extractJsonPath = (builder: PathBuilder<unknown>) => {
|
||||
return (builder as any)[privateSymbol] as StorePath
|
||||
}
|
||||
|
||||
export const pathBuilder = <Store, StorePath = Store>(
|
||||
paths: string[] = [],
|
||||
): PathBuilder<Store, StorePath> => {
|
||||
return new Proxy({} as PathBuilder<Store, StorePath>, {
|
||||
get(target, prop) {
|
||||
if (prop === privateSymbol) {
|
||||
if (paths.length === 0) return ""
|
||||
return `/${paths.join("/")}`
|
||||
}
|
||||
return pathBuilder<any>([...paths, prop as string])
|
||||
},
|
||||
}) as PathBuilder<Store, StorePath>
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Effects, EnsureStorePath } from "../types"
|
||||
import { Effects } from "../types"
|
||||
import { PathBuilder, extractJsonPath } from "./PathBuilder"
|
||||
|
||||
export class GetStore<Store, Path extends string> {
|
||||
export class GetStore<Store, StoreValue> {
|
||||
constructor(
|
||||
readonly effects: Effects,
|
||||
readonly path: Path & EnsureStorePath<Store, Path>,
|
||||
readonly path: PathBuilder<Store, StoreValue>,
|
||||
readonly options: {
|
||||
/** Defaults to what ever the package currently in */
|
||||
packageId?: string | undefined
|
||||
@@ -14,9 +15,9 @@ export class GetStore<Store, Path extends string> {
|
||||
* Returns the value of Store at the provided path. Restart the service if the value changes
|
||||
*/
|
||||
const() {
|
||||
return this.effects.store.get<Store, Path>({
|
||||
return this.effects.store.get<Store, StoreValue>({
|
||||
...this.options,
|
||||
path: this.path as any,
|
||||
path: extractJsonPath(this.path),
|
||||
callback: this.effects.restart,
|
||||
})
|
||||
}
|
||||
@@ -24,9 +25,9 @@ export class GetStore<Store, Path extends string> {
|
||||
* Returns the value of Store at the provided path. Does nothing if the value changes
|
||||
*/
|
||||
once() {
|
||||
return this.effects.store.get<Store, Path>({
|
||||
return this.effects.store.get<Store, StoreValue>({
|
||||
...this.options,
|
||||
path: this.path as any,
|
||||
path: extractJsonPath(this.path),
|
||||
callback: () => {},
|
||||
})
|
||||
}
|
||||
@@ -40,22 +41,22 @@ export class GetStore<Store, Path extends string> {
|
||||
const waitForNext = new Promise<void>((resolve) => {
|
||||
callback = resolve
|
||||
})
|
||||
yield await this.effects.store.get<Store, Path>({
|
||||
yield await this.effects.store.get<Store, StoreValue>({
|
||||
...this.options,
|
||||
path: this.path as any,
|
||||
path: extractJsonPath(this.path),
|
||||
callback: () => callback(),
|
||||
})
|
||||
await waitForNext
|
||||
}
|
||||
}
|
||||
}
|
||||
export function getStore<Store, Path extends string>(
|
||||
export function getStore<Store, StoreValue>(
|
||||
effects: Effects,
|
||||
path: Path & EnsureStorePath<Store, Path>,
|
||||
path: PathBuilder<Store, StoreValue>,
|
||||
options: {
|
||||
/** Defaults to what ever the package currently in */
|
||||
packageId?: string | undefined
|
||||
} = {},
|
||||
) {
|
||||
return new GetStore<Store, Path>(effects, path as any, options)
|
||||
return new GetStore<Store, StoreValue>(effects, path, options)
|
||||
}
|
||||
|
||||
12
sdk/lib/store/setupExposeStore.ts
Normal file
12
sdk/lib/store/setupExposeStore.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Affine, _ } from "../util"
|
||||
import { PathBuilder, extractJsonPath, pathBuilder } from "./PathBuilder"
|
||||
|
||||
export type ExposedStorePaths = string[] & Affine<"ExposedStorePaths">
|
||||
|
||||
export const setupExposeStore = <Store extends Record<string, any>>(
|
||||
fn: (pathBuilder: PathBuilder<Store>) => PathBuilder<Store, any>[],
|
||||
) => {
|
||||
return fn(pathBuilder<Store>()).map(
|
||||
(x) => extractJsonPath(x) as string,
|
||||
) as ExposedStorePaths
|
||||
}
|
||||
@@ -425,7 +425,9 @@ describe("values", () => {
|
||||
const value = Value.dynamicDatetime<{ test: "a" }>(
|
||||
async ({ effects }) => {
|
||||
;async () => {
|
||||
;(await sdk.store.getOwn(effects, "/test").once()) satisfies "a"
|
||||
;(await sdk.store
|
||||
.getOwn(effects, sdk.StorePath.test)
|
||||
.once()) satisfies "a"
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -49,7 +49,6 @@ describe("startosTypeValidation ", () => {
|
||||
setConfigured: {} as SetConfigured,
|
||||
setHealth: {} as SetHealth,
|
||||
exposeForDependents: {} as ExposeForDependentsParams,
|
||||
exposeUi: {} as { [key: string]: ExposedUI },
|
||||
getSslCertificate: {} as GetSslCertificateParams,
|
||||
getSslKey: {} as GetSslKeyParams,
|
||||
getServiceInterface: {} as GetServiceInterfaceParams,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { MainEffects, StartSdk } from "../StartSdk"
|
||||
import { extractJsonPath } from "../store/PathBuilder"
|
||||
import { Effects } from "../types"
|
||||
|
||||
type Store = {
|
||||
@@ -17,19 +18,21 @@ const sdk = StartSdk.of()
|
||||
.withStore<Store>()
|
||||
.build(true)
|
||||
|
||||
const storePath = sdk.StorePath
|
||||
|
||||
describe("Store", () => {
|
||||
test("types", async () => {
|
||||
;async () => {
|
||||
sdk.store.setOwn(todo<Effects>(), "/config", {
|
||||
sdk.store.setOwn(todo<Effects>(), storePath.config, {
|
||||
someValue: "a",
|
||||
})
|
||||
sdk.store.setOwn(todo<Effects>(), "/config/someValue", "b")
|
||||
sdk.store.setOwn(todo<Effects>(), "", {
|
||||
sdk.store.setOwn(todo<Effects>(), storePath.config.someValue, "b")
|
||||
sdk.store.setOwn(todo<Effects>(), storePath, {
|
||||
config: { someValue: "b" },
|
||||
})
|
||||
sdk.store.setOwn(
|
||||
todo<Effects>(),
|
||||
"/config/someValue",
|
||||
storePath.config.someValue,
|
||||
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
5,
|
||||
@@ -41,48 +44,42 @@ describe("Store", () => {
|
||||
"someValue",
|
||||
)
|
||||
|
||||
todo<Effects>().store.set<Store, "/config/someValue">({
|
||||
path: "/config/someValue",
|
||||
todo<Effects>().store.set<Store>({
|
||||
path: extractJsonPath(storePath.config.someValue),
|
||||
value: "b",
|
||||
})
|
||||
todo<Effects>().store.set<Store, "/config/some2Value">({
|
||||
//@ts-expect-error Path is wrong
|
||||
path: "/config/someValue",
|
||||
path: extractJsonPath(storePath.config.someValue),
|
||||
//@ts-expect-error Path is wrong
|
||||
value: "someValueIn",
|
||||
})
|
||||
todo<Effects>().store.set<Store, "/config/someValue">({
|
||||
//@ts-expect-error Path is wrong
|
||||
path: "/config/some2Value",
|
||||
value: "a",
|
||||
})
|
||||
;(await sdk.store
|
||||
.getOwn(todo<MainEffects>(), "/config/someValue")
|
||||
.getOwn(todo<MainEffects>(), storePath.config.someValue)
|
||||
.const()) satisfies string
|
||||
;(await sdk.store
|
||||
.getOwn(todo<MainEffects>(), "/config")
|
||||
.getOwn(todo<MainEffects>(), storePath.config)
|
||||
.const()) satisfies Store["config"]
|
||||
await sdk.store // @ts-expect-error Path is wrong
|
||||
.getOwn(todo<MainEffects>(), "/config/somdsfeValue")
|
||||
.const()
|
||||
/// ----------------- ERRORS -----------------
|
||||
|
||||
sdk.store.setOwn(todo<MainEffects>(), "", {
|
||||
sdk.store.setOwn(todo<MainEffects>(), storePath, {
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
config: { someValue: "notInAOrB" },
|
||||
})
|
||||
sdk.store.setOwn(
|
||||
todo<MainEffects>(),
|
||||
"/config/someValue",
|
||||
sdk.StorePath.config.someValue,
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
"notInAOrB",
|
||||
)
|
||||
;(await sdk.store
|
||||
.getOwn(todo<Effects>(), "/config/someValue")
|
||||
.getOwn(todo<Effects>(), storePath.config.someValue)
|
||||
// @ts-expect-error Const should normally not be callable
|
||||
.const()) satisfies string
|
||||
;(await sdk.store
|
||||
.getOwn(todo<Effects>(), "/config")
|
||||
.getOwn(todo<Effects>(), storePath.config)
|
||||
// @ts-expect-error Const should normally not be callable
|
||||
.const()) satisfies Store["config"]
|
||||
await sdk.store // @ts-expect-error Path is wrong
|
||||
@@ -92,14 +89,14 @@ describe("Store", () => {
|
||||
|
||||
///
|
||||
;(await sdk.store
|
||||
.getOwn(todo<MainEffects>(), "/config/someValue")
|
||||
.getOwn(todo<MainEffects>(), storePath.config.someValue)
|
||||
// @ts-expect-error satisfies type is wrong
|
||||
.const()) satisfies number
|
||||
;(await sdk.store // @ts-expect-error Path is wrong
|
||||
.getOwn(todo<MainEffects>(), "/config/")
|
||||
.const()) satisfies Store["config"]
|
||||
;(await todo<Effects>().store.get<Store, "/config/someValue">({
|
||||
path: "/config/someValue",
|
||||
await sdk.store // @ts-expect-error Path is wrong
|
||||
.getOwn(todo<MainEffects>(), extractJsonPath(storePath.config))
|
||||
.const()
|
||||
;(await todo<Effects>().store.get({
|
||||
path: extractJsonPath(storePath.config.someValue),
|
||||
callback: noop,
|
||||
})) satisfies string
|
||||
await todo<Effects>().store.get<Store, "/config/someValue">({
|
||||
|
||||
@@ -5,6 +5,8 @@ import { InputSpec } from "./config/configTypes"
|
||||
import { DependenciesReceipt } from "./config/setupConfig"
|
||||
import { BindOptions, Scheme } from "./interfaces/Host"
|
||||
import { Daemons } from "./mainFn/Daemons"
|
||||
import { PathBuilder, StorePath } from "./store/PathBuilder"
|
||||
import { ExposedStorePaths } from "./store/setupExposeStore"
|
||||
import { UrlString } from "./util/getServiceInterface"
|
||||
|
||||
export { SDKManifest } from "./manifest/ManifestTypes"
|
||||
@@ -93,6 +95,10 @@ export namespace ExpectedExports {
|
||||
* that this service could use.
|
||||
*/
|
||||
export type dependencyConfig = Record<PackageId, DependencyConfig | null>
|
||||
|
||||
export type Properties = (options: {
|
||||
effects: Effects
|
||||
}) => Promise<PropertiesReturn>
|
||||
}
|
||||
export type TimeMs = number
|
||||
export type VersionString = string
|
||||
@@ -248,31 +254,21 @@ export type ServiceInterfaceWithHostInfo = ServiceInterface & {
|
||||
hostInfo: HostInfo
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export type ExposeAllServicePaths<Store, PreviousPath extends string = ""> =
|
||||
Store extends never ? string :
|
||||
Store extends Record<string, unknown> ? {[K in keyof Store & string]: ExposeAllServicePaths<Store[K], `${PreviousPath}/${K & string}`>}[keyof Store & string] :
|
||||
PreviousPath
|
||||
// prettier-ignore
|
||||
export type ExposeAllUiPaths<Store, PreviousPath extends string = ""> =
|
||||
Store extends Record<string, unknown> ? {[K in keyof Store & string]: ExposeAllUiPaths<Store[K], `${PreviousPath}/${K & string}`>}[keyof Store & string] :
|
||||
Store extends string ? PreviousPath :
|
||||
never
|
||||
export type ExposeServicePaths<Store = never> = {
|
||||
/** The path to the value in the Store. [JsonPath](https://jsonpath.com/) */
|
||||
paths: Store extends never ? string[] : ExposeAllServicePaths<Store>[]
|
||||
paths: ExposedStorePaths
|
||||
}
|
||||
|
||||
export type ExposeUiPaths<Store> =
|
||||
export type SdkPropertiesValue =
|
||||
| {
|
||||
type: "object"
|
||||
value: { [k: string]: ExposeUiPaths<Store> }
|
||||
value: { [k: string]: SdkPropertiesValue }
|
||||
description?: string
|
||||
}
|
||||
| {
|
||||
type: "string"
|
||||
/** The path to the value in the Store. [JsonPath](https://jsonpath.com/) */
|
||||
path: ExposeAllUiPaths<Store>
|
||||
/** Value */
|
||||
value: string
|
||||
/** A human readable description or explanation of the value */
|
||||
description?: string
|
||||
/** (string/number only) Whether or not to mask the value, for example, when displaying a password */
|
||||
@@ -282,16 +278,21 @@ export type ExposeUiPaths<Store> =
|
||||
/** (string/number only) Whether or not to include a button for displaying the value as a QR code */
|
||||
qr?: boolean
|
||||
}
|
||||
export type ExposeUiPathsAll =
|
||||
|
||||
export type SdkPropertiesReturn = {
|
||||
[key: string]: SdkPropertiesValue
|
||||
}
|
||||
|
||||
export type PropertiesValue =
|
||||
| {
|
||||
type: "object"
|
||||
value: { [k: string]: ExposeUiPathsAll }
|
||||
value: { [k: string]: PropertiesValue }
|
||||
description: string | null
|
||||
}
|
||||
| {
|
||||
type: "string"
|
||||
/** The path to the value in the Store. [JsonPath](https://jsonpath.com/) */
|
||||
path: string
|
||||
/** Value */
|
||||
value: string
|
||||
/** A human readable description or explanation of the value */
|
||||
description: string | null
|
||||
/** (string/number only) Whether or not to mask the value, for example, when displaying a password */
|
||||
@@ -302,6 +303,10 @@ export type ExposeUiPathsAll =
|
||||
qr: boolean | null
|
||||
}
|
||||
|
||||
export type PropertiesReturn = {
|
||||
[key: string]: PropertiesValue
|
||||
}
|
||||
|
||||
/** Used to reach out from the pure js runtime */
|
||||
export type Effects = {
|
||||
executeAction<Input>(opts: {
|
||||
@@ -361,18 +366,18 @@ export type Effects = {
|
||||
|
||||
store: {
|
||||
/** Get a value in a json like data, can be observed and subscribed */
|
||||
get<Store = never, Path extends string = never>(options: {
|
||||
get<Store = never, ExtractStore = unknown>(options: {
|
||||
/** If there is no packageId it is assumed the current package */
|
||||
packageId?: string
|
||||
/** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */
|
||||
path: Path & EnsureStorePath<Store, Path>
|
||||
path: StorePath
|
||||
callback: (config: unknown, previousConfig: unknown) => void
|
||||
}): Promise<ExtractStore<Store, Path>>
|
||||
}): Promise<ExtractStore>
|
||||
/** Used to store values that can be accessed and subscribed to */
|
||||
set<Store = never, Path extends string = never>(options: {
|
||||
set<Store = never, ExtractStore = unknown>(options: {
|
||||
/** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */
|
||||
path: Path & EnsureStorePath<Store, Path>
|
||||
value: ExtractStore<Store, Path>
|
||||
path: StorePath
|
||||
value: ExtractStore
|
||||
}): Promise<void>
|
||||
}
|
||||
|
||||
@@ -399,7 +404,6 @@ export type Effects = {
|
||||
|
||||
exposeForDependents(options: { paths: string[] }): Promise<void>
|
||||
|
||||
exposeUi(options: { [key: string]: ExposeUiPathsAll }): Promise<void>
|
||||
/**
|
||||
* There are times that we want to see the addresses that where exported
|
||||
* @param options.addressId If we want to filter the address id
|
||||
@@ -524,22 +528,6 @@ export type Effects = {
|
||||
stopped(options: { packageId: string | null }): Promise<boolean>
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export type ExtractStore<Store, Path extends string> =
|
||||
Path extends `/${infer A }/${infer Rest }` ? (A extends keyof Store ? ExtractStore<Store[A], `/${Rest}`> : never) :
|
||||
Path extends `/${infer A }` ? (A extends keyof Store ? Store[A] : never) :
|
||||
Path extends '' ? Store :
|
||||
never
|
||||
|
||||
// prettier-ignore
|
||||
type _EnsureStorePath<Store, Path extends string, Origin extends string> =
|
||||
Path extends`/${infer A }/${infer Rest}` ? (Store extends {[K in A & string]: infer NextStore} ? _EnsureStorePath<NextStore, `/${Rest}`, Origin> : never) :
|
||||
Path extends `/${infer A }` ? (Store extends {[K in A]: infer B} ? Origin : never) :
|
||||
Path extends '' ? Origin :
|
||||
never
|
||||
// prettier-ignore
|
||||
export type EnsureStorePath<Store, Path extends string> = _EnsureStorePath<Store, Path, Path>
|
||||
|
||||
/** rsync options: https://linux.die.net/man/1/rsync
|
||||
*/
|
||||
export type BackupOptions = {
|
||||
|
||||
@@ -23,6 +23,8 @@ export const isKnownError = (e: unknown): e is T.KnownError =>
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user