@lifi/compose-spec
Version:
Public wire-format types and schemas for Compose flows
135 lines (121 loc) • 3.99 kB
text/typescript
import type { HandleInput, Ref, ResourceInput, SolType } from "./flowSchema.js";
import type {
Port,
ResourcePort,
HandlePort,
ResourceOutputPort,
} from "./flow.js";
import type { Availability } from "./resource.js";
import { erc20Resource, nativeResource } from "./resource.js";
import type { HandleUnits } from "./zodSchemas.js";
export interface OpHandleOptions {
readonly expose?: boolean;
readonly units?: HandleUnits;
}
export const inputRef = (port: string): Ref => ({ $ref: `input.${port}` });
export const outputRef = (node: string, port: string): Ref => ({
$ref: `${node}.${port}`,
});
/** Returns `{ [key]: value }` when `value` is not nullish, else `{}`. */
const optionalProp = <K extends string, V>(
key: K,
value: V | undefined | null
): Partial<Record<K, V>> =>
value != null ? ({ [key]: value } as Partial<Record<K, V>>) : {};
export const linear = <N extends string, T extends SolType>(
name: N,
type: T
): Port & { readonly name: N; readonly type: T; readonly mode: "linear" } =>
({ name, type, mode: "linear", availability: "now" } as Port & {
readonly name: N;
readonly type: T;
readonly mode: "linear";
});
export const copy = <N extends string, T extends SolType>(
name: N,
type: T
): Port & { readonly name: N; readonly type: T; readonly mode: "copy" } =>
({ name, type, mode: "copy", availability: "now" } as Port & {
readonly name: N;
readonly type: T;
readonly mode: "copy";
});
export const handle = <N extends string, T extends SolType>(
name: N,
type: T
): HandleInput & { readonly name: N; readonly type: T } =>
({ name, type } as HandleInput & { readonly name: N; readonly type: T });
export const native = <N extends string>(
name: N,
chainId: number
): ResourceInput & { readonly name: N } =>
({ name, resource: nativeResource(chainId) } as ResourceInput & {
readonly name: N;
});
export const erc20 = <N extends string>(
name: N,
token: string,
chainId: number
): ResourceInput & { readonly name: N } =>
({ name, resource: erc20Resource(token, chainId) } as ResourceInput & {
readonly name: N;
});
export const resource = <N extends string, Opt extends boolean = false>(
name: N,
accepts: "erc20" | "native" | "any",
options?: { optional?: Opt }
): ResourcePort & { readonly name: N; readonly optional: Opt } =>
({
kind: "resource",
name,
accepts,
mode: "linear",
...optionalProp("optional", options?.optional),
} as ResourcePort & { readonly name: N; readonly optional: Opt });
export const readResource = <N extends string>(
name: N,
accepts: "erc20" | "native" | "any"
): ResourcePort & { readonly name: N; readonly mode: "copy" } =>
({ kind: "resource", name, accepts, mode: "copy" } as ResourcePort & {
readonly name: N;
readonly mode: "copy";
});
export const opHandle = <N extends string, T extends SolType>(
name: N,
type: T,
options?: OpHandleOptions
): HandlePort & { readonly name: N; readonly type: T } =>
({
kind: "handle",
name,
type,
mode: "copy",
...optionalProp("expose", options?.expose),
...optionalProp("units", options?.units),
} as HandlePort & {
readonly name: N;
readonly type: T;
});
export const resourceOutput = <N extends string>(
name: N,
options?:
| Availability
| {
availability?: Availability;
providesMinimum?: boolean;
omitIfZero?: boolean;
deliveryAddressInput?: string;
}
): ResourceOutputPort & { readonly name: N } => {
const opts =
typeof options === "string" ? { availability: options } : options;
return {
kind: "resource_output",
name,
mode: "linear",
...optionalProp("availability", opts?.availability),
...optionalProp("providesMinimum", opts?.providesMinimum),
...optionalProp("omitIfZero", opts?.omitIfZero),
...optionalProp("deliveryAddressInput", opts?.deliveryAddressInput),
} as ResourceOutputPort & { readonly name: N };
};