diff --git a/src/sdl/SDL/SDL.ts b/src/sdl/SDL/SDL.ts index 955148f..636da4e 100644 --- a/src/sdl/SDL/SDL.ts +++ b/src/sdl/SDL/SDL.ts @@ -57,16 +57,54 @@ function isString(str: any): str is string { type NetworkVersion = "beta2" | "beta3"; +/** + * SDL (Stack Definition Language) parser and validator + * Handles parsing and validation of Akash deployment manifests + * + * @example + * ```ts + * import { SDL } from './SDL'; + * + * const yaml = ` + * version: "2.0" + * services: + * web: + * image: nginx + * expose: + * - port: 80 + * as: 80 + * to: + * - global: true + * `; + * + * // Parse SDL from YAML string + * const sdl = SDL.fromString(yaml); + * + * // Get deployment manifest + * const manifest = sdl.manifest(); + * + * // Get deployment groups + * const groups = sdl.groups(); + * ``` + */ export class SDL { + /** + * Creates an SDL instance from a YAML string + * @param yaml - The YAML string containing the SDL definition + * @param version - The SDL version (beta2 or beta3) + * @param networkId - The network ID to validate against + */ static fromString(yaml: string, version: NetworkVersion = "beta2", networkId: NetworkId = MAINNET_ID) { const data = YAML.load(yaml) as v3Sdl; return new SDL(data, version, networkId); } + /** + * Validates SDL YAML string (deprecated) + * @deprecated Use SDL.constructor directly + */ static validate(yaml: string) { console.warn("SDL.validate is deprecated. Use SDL.constructor directly."); - // TODO: this should really be cast to unknown, then assigned - // to v2 or v3 SDL only after being validated const data = YAML.load(yaml) as v3Sdl; for (const [name, profile] of Object.entries(data.profiles.compute || {})) { @@ -77,6 +115,23 @@ export class SDL { return data; } + /** + * Validates the GPU configuration for a given service profile. + * + * @param name - The name of the service profile. + * @param gpu - The GPU resource configuration. + * @throws Will throw an error if the GPU configuration is invalid. + * + * @example + * ```ts + * SDL.validateGPU("web", { + * units: "1", + * attributes: { + * vendor: { nvidia: [{ model: "RTX 3080", ram: "10GB", interface: "pcie" }] } + * } + * }); + * ``` + */ static validateGPU(name: string, gpu: v3ResourceGPU | undefined) { if (gpu) { if (typeof gpu.units === "undefined") { @@ -118,6 +173,21 @@ export class SDL { } } + /** + * Validates the storage configuration for a given service. + * + * @param name - The name of the service. + * @param storage - The storage resource configuration. + * @throws Will throw an error if the storage configuration is invalid. + * + * @example + * ```ts + * SDL.validateStorage("web", { + * size: "10Gi", + * attributes: { class: "ssd" } + * }); + * ``` + */ static validateStorage(name: string, storage?: v2ResourceStorage | v2ResourceStorageArray) { if (!storage) { throw new Error("Storage is required for service " + name); @@ -579,6 +649,19 @@ export class SDL { }; } + /** + * Parses the service protocol. + * + * @param proto - The protocol string (e.g., "TCP", "UDP"). + * @returns The parsed protocol. + * @throws Will throw an error if the protocol is unsupported. + * + * @example + * ```ts + * const protocol = SDL.parseServiceProto("TCP"); + * // protocol is "TCP" + * ``` + */ parseServiceProto(proto?: string) { const raw = proto?.toUpperCase(); let result = "TCP"; @@ -814,6 +897,18 @@ export class SDL { return this.version === "beta2" ? this.v2Manifest(asString) : this.v3Manifest(asString); } + /** + * Computes the endpoint sequence numbers for the given SDL. + * + * @param sdl - The SDL data. + * @returns An object mapping IPs to their sequence numbers. + * + * @example + * ```ts + * const sequenceNumbers = sdl.computeEndpointSequenceNumbers(sdlData); + * // sequenceNumbers might be { "192.168.1.1": 1, "192.168.1.2": 2 } + * ``` + */ computeEndpointSequenceNumbers(sdl: v2Sdl) { return Object.fromEntries( Object.values(sdl.services).flatMap(service => @@ -1131,6 +1226,18 @@ export class SDL { .map(name => groups[name]); } + /** + * Escapes HTML characters in a string. + * + * @param raw - The raw string to escape. + * @returns The escaped string. + * + * @example + * ```ts + * const escaped = sdl.escapeHtml("
Hello
"); + * // escaped is "\\u003cdiv\\u003eHello\\u003c/div\\u003e" + * ``` + */ escapeHtml(raw: string) { return raw.replace(//g, "\\u003e").replace(/&/g, "\\u0026"); } diff --git a/src/sdl/index.ts b/src/sdl/index.ts index fe6a0c7..66684ca 100644 --- a/src/sdl/index.ts +++ b/src/sdl/index.ts @@ -1 +1,25 @@ +/** + * SDL (Stack Definition Language) module exports + * Provides functionality for parsing and validating Akash deployment manifests + * + * @example + * ```ts + * import { SDL } from './sdl'; + * + * const yaml = ` + * version: "2.0" + * services: + * web: + * image: nginx + * expose: + * - port: 80 + * as: 80 + * to: + * - global: true + * `; + * + * const sdl = SDL.fromString(yaml); + * const manifest = sdl.manifest(); + * ``` + */ export * from "./SDL/SDL"; diff --git a/src/sdl/sizes.ts b/src/sdl/sizes.ts index 10c315b..972ef2b 100644 --- a/src/sdl/sizes.ts +++ b/src/sdl/sizes.ts @@ -1,5 +1,44 @@ const prefixes = "kmgtpe".split(""); +/** + * Converts resource strings like "1k", "5gi", "10m" to their numeric values + * @example + * ```ts + * convertResourceString("1k") // Returns 1000 + * convertResourceString("5gi") // Returns 5368709120 + * convertResourceString("10m") // Returns 10000000 + * ``` + */ +export function convertResourceString(resourceStr: string): number { + const [value, prefix, unit] = parseSizeString(resourceStr.toLowerCase()); + const power = prefixes.indexOf(prefix); + const base = unit === "i" ? 1024 : 1000; + + return power !== -1 ? value * Math.pow(base, power + 1) : value; +} + +/** + * Converts CPU resource strings to their millicpu values + * @example + * ```ts + * convertCpuResourceString("1") // Returns 1000 + * convertCpuResourceString("500m") // Returns 500 + * ``` + */ +export function convertCpuResourceString(resourceStr: string): number { + const [value, unit] = parseCpuResourceString(resourceStr.toLowerCase()); + + if (unit === "m") { + return value; + } + + return value * 1000; +} + +/** + * Parses a size string into value and unit components + * @internal + */ function parseSizeString(size: string): [number, string, string] { const regex = /^([\d.]+)([a-zA-Z])([a-zA-Z]*)$/; const match = size.match(regex); @@ -12,17 +51,10 @@ function parseSizeString(size: string): [number, string, string] { throw new Error(`Invalid size string: ${size}`); } -export function convertResourceString(resourceStr: string): number { - const [value, prefix, unit] = parseSizeString(resourceStr.toLowerCase()); - const power = prefixes.indexOf(prefix); - const base = unit === "i" ? 1024 : 1000; - - return power !== -1 ? value * Math.pow(base, power + 1) : value; -} - -// checks to see if the resource string has an suffix, and extracts the -// value and suffix if it does, otherwise return the numerical value and -// an empty string +/** + * Parses a CPU resource string into value and unit components + * @internal + */ function parseCpuResourceString(size: string): [number, string] { const regex = /^([\d.]+)([a-zA-Z]*)$/; const match = size.match(regex); @@ -34,13 +66,3 @@ function parseCpuResourceString(size: string): [number, string] { throw new Error(`Invalid size string: ${size}`); } - -export function convertCpuResourceString(resourceStr: string): number { - const [value, unit] = parseCpuResourceString(resourceStr.toLowerCase()); - - if (unit === "m") { - return value; - } - - return value * 1000; -} diff --git a/src/stargate/index.ts b/src/stargate/index.ts index a8213f8..fda45d1 100644 --- a/src/stargate/index.ts +++ b/src/stargate/index.ts @@ -1,20 +1,42 @@ import { MessageType, messageTypeRegistry, UnknownMessage } from "@akashnetwork/akash-api/typeRegistry"; +/** + * Retrieves the Akash type registry. + * @returns An array of tuples containing the type URL and the corresponding message type. + */ export const getAkashTypeRegistry: () => [string, MessageType][] = () => Array.from(messageTypeRegistry).map(([path, type]) => [`/${path}`, type]); +/** + * Gets the type URL for a given message type. + * @param type - The message type for which to get the URL. + * @returns The URL string for the specified message type. + */ export const getTypeUrl: (type: MessageType) => string = type => `/${type.$type}`; -/* TODO: this should be generated from the proto files */ +/** + * Enum for Akash message types. + * @enum {string} + */ export enum Message { + /** Message type for creating a certificate. */ MsgCreateCertificate = "/akash.cert.v1beta3.MsgCreateCertificate", + /** Message type for revoking a certificate. */ MsgRevokeCertificate = "/akash.cert.v1beta3.MsgRevokeCertificate", + /** Message type for creating a deployment. */ MsgCreateDeployment = "/akash.deployment.v1beta3.MsgCreateDeployment", + /** Message type for closing a deployment. */ MsgCloseDeployment = "/akash.deployment.v1beta3.MsgCloseDeployment", + /** Message type for depositing into a deployment. */ MsgDepositDeployment = "/akash.deployment.v1beta3.MsgDepositDeployment", + /** Message type for updating a deployment. */ MsgUpdateDeployment = "/akash.deployment.v1beta3.MsgUpdateDeployment", + /** Message type for closing a group. */ MsgCloseGroup = "/akash.deployment.v1beta3.MsgCloseGroup", + /** Message type for pausing a group. */ MsgPauseGroup = "/akash.deployment.v1beta3.MsgPauseGroup", + /** Message type for starting a group. */ MsgStartGroup = "/akash.deployment.v1beta3.MsgStartGroup", + /** Message type for creating a lease. */ MsgCreateLease = "/akash.market.v1beta4.MsgCreateLease" } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index f1e56a7..177b0da 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -3,7 +3,22 @@ import { OfflineDirectSigner, OfflineSigner } from "@cosmjs/proto-signing"; export {}; declare global { + /** + * Extends the Window interface to include Keplr wallet integration methods. + * @interface Window + */ interface Window { + /** + * Gets an offline signer for automatic signing of transactions. + * This method is injected by the Keplr wallet extension. + * + * @param {string} chainId - The chain ID of the network to connect to + * @returns {Promise} A promise that resolves to either an OfflineSigner or OfflineDirectSigner + * @throws {Error} If Keplr wallet is not installed or user rejects the connection + * + * @example + * const signer = await window.getOfflineSignerAuto("cosmoshub-4"); + */ getOfflineSignerAuto: (chainId: string) => Promise; } } diff --git a/src/types/network.ts b/src/types/network.ts index 107482d..20ba94b 100644 --- a/src/types/network.ts +++ b/src/types/network.ts @@ -1,4 +1,24 @@ +/** + * Type representing the mainnet network identifier. + * Used for production environment connections. + */ export type MainnetNetworkId = "mainnet"; + +/** + * Type representing the testnet network identifier. + * Used for testing and development purposes. + */ export type TestnetNetworkId = "testnet"; + +/** + * Type representing the sandbox network identifier. + * Used for local development and testing. + */ export type SandboxNetworkId = "sandbox"; + +/** + * Union type combining all possible network identifiers. + * Can be either "mainnet", "testnet", or "sandbox". + * @typedef {MainnetNetworkId | TestnetNetworkId | SandboxNetworkId} NetworkId + */ export type NetworkId = MainnetNetworkId | TestnetNetworkId | SandboxNetworkId;