From 7a96e944919ca3687e626c439a881f77e11b003a Mon Sep 17 00:00:00 2001 From: Matt Hill Date: Mon, 2 Dec 2024 13:58:28 -0700 Subject: [PATCH] More SDK comments (#2796) * sdk tweaks * switch back to deeppartial * WIP, update comments * reinstall chesterton's fence * more comments * delete extra package.lock * handle TODOs --------- Co-authored-by: Aiden McClelland --- core/startos/src/action.rs | 10 +++++++ core/startos/src/db/model/package.rs | 12 ++++++++ sdk/base/lib/osBindings/ActionMetadata.ts | 24 +++++++++++++++ sdk/base/lib/osBindings/ActionResultMember.ts | 26 ++++++++++++++++- sdk/base/lib/osBindings/ActionResultV1.ts | 9 ++++++ sdk/base/lib/osBindings/ActionResultValue.ts | 20 ++++++++++++- sdk/package-lock.json | 6 ---- sdk/package/lib/mainFn/Daemons.ts | 29 ++++++++++++++++++- sdk/package/lib/mainFn/Mounts.ts | 12 ++++++++ sdk/package/lib/test/inputSpecBuilder.test.ts | 2 -- 10 files changed, 139 insertions(+), 11 deletions(-) delete mode 100644 sdk/package-lock.json diff --git a/core/startos/src/action.rs b/core/startos/src/action.rs index d0748265b..801360a44 100644 --- a/core/startos/src/action.rs +++ b/core/startos/src/action.rs @@ -124,15 +124,20 @@ impl fmt::Display for ActionResultV0 { #[derive(Debug, Serialize, Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct ActionResultV1 { + /// Primary text to display as the header of the response modal. e.g. "Success!", "Name Updated", or "Service Information", whatever makes sense pub title: String, + /// (optional) A general message for the user, just under the title pub message: Option, + /// (optional) Structured data to present inside the modal pub result: Option, } #[derive(Debug, Serialize, Deserialize, TS)] #[serde(rename_all = "camelCase")] pub struct ActionResultMember { + /// A human-readable name or title of the value, such as "Last Active" or "Login Password" pub name: String, + /// (optional) A description of the value, such as an explaining why it exists or how to use it pub description: Option, #[serde(flatten)] #[ts(flatten)] @@ -145,12 +150,17 @@ pub struct ActionResultMember { #[serde(tag = "type")] pub enum ActionResultValue { Single { + /// The actual string value to display value: String, + /// Whether or not to include a copy to clipboard icon to copy the value copyable: bool, + /// Whether or not to also display the value as a QR code qr: bool, + /// Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information masked: bool, }, Group { + /// An new group of nested values, experienced by the user as an accordion dropdown value: Vec, }, } diff --git a/core/startos/src/db/model/package.rs b/core/startos/src/db/model/package.rs index df5773cc3..6f1155311 100644 --- a/core/startos/src/db/model/package.rs +++ b/core/startos/src/db/model/package.rs @@ -322,13 +322,25 @@ pub enum AllowedStatuses { #[serde(rename_all = "camelCase")] #[model = "Model"] pub struct ActionMetadata { + /// A human-readable name pub name: String, + /// A detailed description of what the action will do pub description: String, + /// Presents as an alert prior to executing the action. Should be used sparingly but important if the action could have harmful, unintended consequences pub warning: Option, #[serde(default)] + /// One of: "enabled", "hidden", or { disabled: "" } + /// - "enabled" - the action is available be run + /// - "hidden" - the action cannot be seen or run + /// - { disabled: "example explanation" } means the action is visible but cannot be run. Replace "example explanation" with a reason why the action is disable to prevent user confusion. pub visibility: ActionVisibility, + /// One of: "only-stopped", "only-running", "all" + /// - "only-stopped" - the action can only be run when the service is stopped + /// - "only-running" - the action can only be run when the service is running + /// - "any" - the action can only be run regardless of the service's status pub allowed_statuses: AllowedStatuses, pub has_input: bool, + /// If provided, this action will be nested under a header of this value, along with other actions of the same group pub group: Option, } diff --git a/sdk/base/lib/osBindings/ActionMetadata.ts b/sdk/base/lib/osBindings/ActionMetadata.ts index ade129fd4..01809ab57 100644 --- a/sdk/base/lib/osBindings/ActionMetadata.ts +++ b/sdk/base/lib/osBindings/ActionMetadata.ts @@ -3,11 +3,35 @@ import type { ActionVisibility } from "./ActionVisibility" import type { AllowedStatuses } from "./AllowedStatuses" export type ActionMetadata = { + /** + * A human-readable name + */ name: string + /** + * A detailed description of what the action will do + */ description: string + /** + * Presents as an alert prior to executing the action. Should be used sparingly but important if the action could have harmful, unintended consequences + */ warning: string | null + /** + * One of: "enabled", "hidden", or { disabled: "" } + * - "enabled" - the action is available be run + * - "hidden" - the action cannot be seen or run + * - { disabled: "example explanation" } means the action is visible but cannot be run. Replace "example explanation" with a reason why the action is disable to prevent user confusion. + */ visibility: ActionVisibility + /** + * One of: "only-stopped", "only-running", "all" + * - "only-stopped" - the action can only be run when the service is stopped + * - "only-running" - the action can only be run when the service is running + * - "any" - the action can only be run regardless of the service's status + */ allowedStatuses: AllowedStatuses hasInput: boolean + /** + * If provided, this action will be nested under a header of this value, along with other actions of the same group + */ group: string | null } diff --git a/sdk/base/lib/osBindings/ActionResultMember.ts b/sdk/base/lib/osBindings/ActionResultMember.ts index cdc23ecaa..c27a6a3a9 100644 --- a/sdk/base/lib/osBindings/ActionResultMember.ts +++ b/sdk/base/lib/osBindings/ActionResultMember.ts @@ -1,15 +1,39 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. export type ActionResultMember = { + /** + * A human-readable name or title of the value, such as "Last Active" or "Login Password" + */ name: string + /** + * (optional) A description of the value, such as an explaining why it exists or how to use it + */ description: string | null } & ( | { type: "single" + /** + * The actual string value to display + */ value: string + /** + * Whether or not to include a copy to clipboard icon to copy the value + */ copyable: boolean + /** + * Whether or not to also display the value as a QR code + */ qr: boolean + /** + * Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information + */ masked: boolean } - | { type: "group"; value: Array } + | { + type: "group" + /** + * An new group of nested values, experienced by the user as an accordion dropdown + */ + value: Array + } ) diff --git a/sdk/base/lib/osBindings/ActionResultV1.ts b/sdk/base/lib/osBindings/ActionResultV1.ts index eece18477..ee06ebab9 100644 --- a/sdk/base/lib/osBindings/ActionResultV1.ts +++ b/sdk/base/lib/osBindings/ActionResultV1.ts @@ -2,7 +2,16 @@ import type { ActionResultValue } from "./ActionResultValue" export type ActionResultV1 = { + /** + * Primary text to display as the header of the response modal. e.g. "Success!", "Name Updated", or "Service Information", whatever makes sense + */ title: string + /** + * (optional) A general message for the user, just under the title + */ message: string | null + /** + * (optional) Structured data to present inside the modal + */ result: ActionResultValue | null } diff --git a/sdk/base/lib/osBindings/ActionResultValue.ts b/sdk/base/lib/osBindings/ActionResultValue.ts index d1cb6c8c3..3ffabef8b 100644 --- a/sdk/base/lib/osBindings/ActionResultValue.ts +++ b/sdk/base/lib/osBindings/ActionResultValue.ts @@ -4,9 +4,27 @@ import type { ActionResultMember } from "./ActionResultMember" export type ActionResultValue = | { type: "single" + /** + * The actual string value to display + */ value: string + /** + * Whether or not to include a copy to clipboard icon to copy the value + */ copyable: boolean + /** + * Whether or not to also display the value as a QR code + */ qr: boolean + /** + * Whether or not to mask the value using ●●●●●●●, which is useful for password or other sensitive information + */ masked: boolean } - | { type: "group"; value: Array } + | { + type: "group" + /** + * An new group of nested values, experienced by the user as an accordion dropdown + */ + value: Array + } diff --git a/sdk/package-lock.json b/sdk/package-lock.json deleted file mode 100644 index 9699e0851..000000000 --- a/sdk/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "sdk", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/sdk/package/lib/mainFn/Daemons.ts b/sdk/package/lib/mainFn/Daemons.ts index cefa06698..495e6c527 100644 --- a/sdk/package/lib/mainFn/Daemons.ts +++ b/sdk/package/lib/mainFn/Daemons.ts @@ -19,7 +19,22 @@ import { CommandController } from "./CommandController" export const cpExec = promisify(CP.exec) export const cpExecFile = promisify(CP.execFile) export type Ready = { + /** A human-readable display name for the health check. If null, the health check itself will be from the UI */ display: string | null + /** + * @description The function to determine the health status of the daemon + * + * The SDK provides some built-in health checks. To see them, type sdk.healthCheck. + * + * @example + * ``` + fn: () => + sdk.healthCheck.checkPortListening(effects, 80, { + successMessage: 'service listening on port 80', + errorMessage: 'service is unreachable', + }) + * ``` + */ fn: ( spawnable: ExecSpawnable, ) => Promise | HealthCheckResult @@ -32,11 +47,23 @@ type DaemonsParams< Command extends string, Id extends string, > = { + /** The command line command to start the daemon */ command: T.CommandType - image: { id: keyof Manifest["images"] & T.ImageId; sharedRun?: boolean } + /** Information about the image in which the daemon runs */ + image: { + /** The ID of the image. Must be one of the image IDs declared in the manifest */ + id: keyof Manifest["images"] & T.ImageId + /** + * Whether or not to share the `/run` directory with the parent container. + * This is useful if you are trying to connect to a service that exposes a unix domain socket or auth cookie via the `/run` directory + */ + sharedRun?: boolean + } + /** For mounting the necessary volumes. Syntax: sdk.Mounts.of().addVolume() */ mounts: Mounts env?: Record ready: Ready + /** An array of IDs of prior daemons whose successful initializations are required before this daemon will initialize */ requires: Exclude[] sigtermTimeout?: number onStdout?: (chunk: Buffer | string | any) => void diff --git a/sdk/package/lib/mainFn/Mounts.ts b/sdk/package/lib/mainFn/Mounts.ts index 38b3ce2a7..799140871 100644 --- a/sdk/package/lib/mainFn/Mounts.ts +++ b/sdk/package/lib/mainFn/Mounts.ts @@ -30,9 +30,13 @@ export class Mounts { } addVolume( + /** The ID of the volume to mount. Must be one of the volume IDs defined in the manifest */ id: Manifest["volumes"][number], + /** The path within the volume to mount. Use `null` to mount the entire volume */ subpath: string | null, + /** Where to mount the volume. e.g. /data */ mountpoint: string, + /** Whether or not the volume should be readonly for this daemon */ readonly: boolean, ) { this.volumes.push({ @@ -45,8 +49,11 @@ export class Mounts { } addAssets( + /** The ID of the asset directory to mount. This is typically the same as the folder name in your assets directory */ id: Manifest["assets"][number], + /** The path within the asset directory to mount. Use `null` to mount the entire volume */ subpath: string | null, + /** Where to mount the asset. e.g. /asset */ mountpoint: string, ) { this.assets.push({ @@ -58,10 +65,15 @@ export class Mounts { } addDependency( + /** The ID of the dependency service */ dependencyId: keyof Manifest["dependencies"] & string, + /** The ID of the volume belonging to the dependency service to mount */ volumeId: DependencyManifest["volumes"][number], + /** The path within the dependency's volume to mount. Use `null` to mount the entire volume */ subpath: string | null, + /** Where to mount the dependency's volume. e.g. /service-id */ mountpoint: string, + /** Whether or not the volume should be readonly for this daemon */ readonly: boolean, ) { this.dependencies.push({ diff --git a/sdk/package/lib/test/inputSpecBuilder.test.ts b/sdk/package/lib/test/inputSpecBuilder.test.ts index 27869067d..4179a9f04 100644 --- a/sdk/package/lib/test/inputSpecBuilder.test.ts +++ b/sdk/package/lib/test/inputSpecBuilder.test.ts @@ -6,8 +6,6 @@ import { Variants } from "../../../base/lib/actions/input/builder/variants" import { ValueSpec } from "../../../base/lib/actions/input/inputSpecTypes" import { setupManifest } from "../manifest/setupManifest" import { StartSdk } from "../StartSdk" -import { VersionGraph } from "../version/VersionGraph" -import { VersionInfo } from "../version/VersionInfo" describe("builder tests", () => { test("text", async () => {