TypeScript client API ​

Generated from packages/sketchforge-client/dist/index.d.ts by node scripts/docs/generate-package-references.mjs. Do not edit this file directly.

This reference lists the package's exported declaration surface. For usage and behavior, see the package README.

Align ​

class

ts
export declare class Align {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Puts one edge or one centre of every shape on the same coordinate.
     *
     * `moved` is the answer to "did anything happen": a selection that was
     * already flush reports zero and the project is not written, so the revision
     * comes back where it was.
     */
    apply(projectId: string, request: AlignRequest): Promise<AlignResult>;
    /** Flush tops, which is the alignment a row of parts on a plate usually wants. */
    tops(projectId: string, ids: readonly string[], anchorId?: string): Promise<AlignResult>;
    /** Seated on one plane: every underside at the same elevation. */
    bottoms(projectId: string, ids: readonly string[], anchorId?: string): Promise<AlignResult>;
    /** Centred on one another along an axis. */
    centers(projectId: string, ids: readonly string[], axis: AlignRequest["axis"], anchorId?: string): Promise<AlignResult>;
}

ALIGN_AXES ​

value

ts
ALIGN_AXES: readonly ["x", "y", "z"]

ALIGN_TARGETS ​

value

ts
ALIGN_TARGETS: readonly ["min", "center", "max"]

AlignAxis ​

type

ts
export type AlignAxis = (typeof ALIGN_AXES)[number];

x is left/right, z front/back, y bottom/top.

AlignRequest ​

type

ts
export type AlignRequest = {
    ids: readonly string[];
    axis: AlignAxis;
    target: AlignTarget;
    /**
     * The shape to keep fixed.
     *
     * Omit and the reference is the box around the whole selection. A locked
     * shape in the selection becomes the anchor whatever this says, since it
     * cannot move, and the result reports which shape was used.
     */
    anchorId?: string;
};

AlignResult ​

type

ts
export type AlignResult = {
    /** How many shapes actually moved. Zero means the selection was already flush. */
    moved: number;
    axis: AlignAxis;
    target: AlignTarget;
    anchorId: string | null;
    shapes: ShapeSummary[];
    revision: number;
};

AlignTarget ​

type

ts
export type AlignTarget = (typeof ALIGN_TARGETS)[number];

Which edge or centre of each shape to line up.

AnyKindFields ​

type

ts
export type AnyKindFields = {
    [Kind in ParametricShapeKind]: KindFields[Kind] extends object ? KindFields[Kind] : Record<never, never>;
}[ParametricShapeKind] extends infer Union ? Partial<UnionToIntersection<Union>> : never;

Every per-kind parameter, for a context that does not know the kind yet.

API_ERROR_CODES ​

value

ts
API_ERROR_CODES: readonly ["api_disabled", "unauthorized", "storage_unconfigured", "invalid_project_id", "invalid_shape_id", "invalid_body", "invalid_request", "project_not_found", "project_exists", "project_busy", "revision_mismatch", "shape_not_found", "shape_locked", "unsupported_kind", "unsupported_format", "unapplicable_fields", "too_many_shapes", "limit_exceeded", "geometry_failed", "cad_failed"]

ApiErrorCode ​

type

ts
export type ApiErrorCode = (typeof API_ERROR_CODES)[number];

ApiErrorContext ​

type

ts
export type ApiErrorContext = {
    method: string;
    url: string;
    status: number;
    /** The server's `error` string, when it sent one. */
    detail?: string;
    /** The server's `code`, absent against a server older than codes. */
    code?: string;
    body?: unknown;
};

BakedMirrorResult ​

type

ts
export type BakedMirrorResult = {
    moved: number;
    axis: MirrorAxis;
    shapes: ShapeSummary[];
    revision: number;
};

Result of reflecting exact parameter-built solids across their selection bounds plane.

BASE_URL_ENV ​

value

ts
BASE_URL_ENV = "SKETCHFORGE_URL"

BooleanCutRequest ​

type

ts
export type BooleanCutRequest = {
    solidIds: readonly string[];
    holeIds: readonly string[];
};

Shapes to cut from, and shapes to cut away. No shape may be both.

BooleanCutResult ​

type

ts
export type BooleanCutResult = TreatmentResult;

The one shape a cut leaves, replacing every operand.

triangles counts the result's mesh. A cut that removed nothing is refused rather than answered with an unchanged shape.

Booleans ​

class

ts
export declare class Booleans {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Subtract the `holeIds` shapes from the `solidIds` shapes, as exact geometry.
     *
     * The operands are named rather than marked, so a cutter need not be patched
     * to `hole: true` first. Every operand is replaced by the one result.
     */
    cut(projectId: string, request: BooleanCutRequest): Promise<BooleanCutResult>;
}

buildUrl ​

function

ts
export declare function buildUrl(root: string, path: string, query?: Record<string, string | undefined>): string;

centeredOffsets ​

function

ts
export declare function centeredOffsets(count: number, spacing: number): number[];

chunk ​

function

ts
export declare function chunk<Item>(items: readonly Item[], size: number): Item[][];

clientFromEnvironment ​

function

ts
export declare function clientFromEnvironment(environment?: Environment, overrides?: Partial<SketchForgeClientOptions>): SketchForgeClient;

DEFAULT_BASE_URL ​

value

ts
DEFAULT_BASE_URL = "http://127.0.0.1:3000"

defineMacro ​

function

ts
export declare function defineMacro<Params extends Record<string, MacroParameterValue>>(definition: MacroDefinition<Params>): MacroDefinition<Params>;

DeleteResult ​

type

ts
export type DeleteResult = {
    deleted: true;
    id: string;
    revision?: number;
};

Distribute ​

class

ts
export declare class Distribute {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Spreads three or more shapes evenly along an axis.
     *
     * The outermost two never move -- they define the span -- so a selection of
     * three has exactly one shape to place. Leave `axis` out and it is whichever
     * axis the shapes are already most spread along.
     */
    apply(projectId: string, request: DistributeRequest): Promise<DistributeResult>;
    /** Equal clear space between neighbours: the one for parts of different sizes. */
    gaps(projectId: string, ids: readonly string[], axis?: DistributeRequest["axis"]): Promise<DistributeResult>;
    /** Equal centre-to-centre pitch: the one a row of holes wants. */
    pitch(projectId: string, ids: readonly string[], axis?: DistributeRequest["axis"]): Promise<DistributeResult>;
}

DISTRIBUTE_SPACINGS ​

value

ts
DISTRIBUTE_SPACINGS: readonly ["gaps", "centers"]

DistributeRequest ​

type

ts
export type DistributeRequest = {
    ids: readonly string[];
    /** Omit to spread along whichever axis the shapes are already most spread along. */
    axis?: "x" | "z";
    spacing?: DistributeSpacing;
};

DistributeResult ​

type

ts
export type DistributeResult = {
    moved: number;
    axis: "x" | "z";
    spacing: DistributeSpacing;
    shapes: ShapeSummary[];
    revision: number;
};

DistributeSpacing ​

type

ts
export type DistributeSpacing = (typeof DISTRIBUTE_SPACINGS)[number];

gaps leaves equal clear space; centers puts the centres at an equal pitch.

Drawings ​

class

ts
export declare class Drawings {
    private readonly transport;
    constructor(transport: Transport);
    /** Return exact CAD section contours from one named axis plane as SVG. */
    section(projectId: string, request: SectionDrawingRequest): Promise<SectionDrawingArtifact>;
    dxf(projectId: string, request: SectionDrawingRequest): Promise<SectionDxfArtifact>;
}

Edges ​

class

ts
export declare class Edges {
    private readonly transport;
    constructor(transport: Transport);
    /** Every edge, numbered as a treatment request refers to them. */
    list(projectId: string, shapeId: string): Promise<EdgeSummary[]>;
    /** The indexes a fillet or chamfer can act on, which is what most callers want. */
    filletableIndexes(projectId: string, shapeId: string): Promise<number[]>;
}

EdgeSummary ​

type

ts
export type EdgeSummary = {
    index: number;
    length: number;
    /** As OCCT names it: `line`, `circle`, `bspline`, or `unknown`. */
    curveType: string;
    midpoint: {
        x: number;
        y: number;
        z: number;
    };
    /**
     * Whether a fillet or chamfer can act on this edge. A seam -- where one
     * curved surface meets itself -- has no two faces to blend, and naming one
     * explicitly is an error rather than a silent skip.
     */
    filletable: boolean;
};

EdgeTreatment ​

type

ts
export type EdgeTreatment = {
    kind: "fillet" | "chamfer";
    /** Fillet radius or chamfer distance, in mm. */
    amount: number;
    /** Chamfers only; 45 is symmetric. */
    angle?: number;
    /** Edge indexes from the edge listing, or omitted for every edge that can be treated. */
    edges?: readonly number[];
};

Environment ​

type

ts
export type Environment = Record<string, string | undefined>;

Explosions ​

class

ts
export declare class Explosions {
    private readonly transport;
    constructor(transport: Transport);
    explode(projectId: string, shapeId: string): Promise<ShapeWriteResult>;
}

EXPORT_VIEWS ​

value

ts
EXPORT_VIEWS: readonly ["multiview", "front", "back", "top", "bottom", "left", "right", "iso"]

What an SVG export shows: the four-view grid, or one named view.

Exports ​

class

ts
export declare class Exports {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Export the project, or the named shapes, as one file.
     *
     * The artifact comes back whole as `data`; writing it to disk is the
     * caller's choice. `view` projects an SVG; `section` cuts SVG or DXF
     * contours with one axis plane.
     */
    export(projectId: string, request: ProjectExportRequest): Promise<ProjectExportArtifact>;
}

ExportSection ​

type

ts
export type ExportSection = {
    plane: SectionPlane;
    offset: number;
};

Section contours cut by one axis plane, at offset millimetres along its omitted axis.

ExportSkippedShape ​

type

ts
export type ExportSkippedShape = {
    name: string;
    kind: string;
    reason: string;
};

A shape a STEP export left out, and why.

ExportView ​

type

ts
export type ExportView = (typeof EXPORT_VIEWS)[number];

FACE_DIRECTIONS ​

value

ts
FACE_DIRECTIONS: readonly ["top", "bottom", "left", "right", "front", "back"]

The directions a shell request can name a face by, in the shape's own frame: centred in X and Z with its base at the bottom, front towards the viewer.

FaceDirection ​

type

ts
export type FaceDirection = (typeof FACE_DIRECTIONS)[number];

Faces ​

class

ts
export declare class Faces {
    private readonly transport;
    constructor(transport: Transport);
    /** Every face, numbered as a shell request refers to them. */
    list(projectId: string, shapeId: string, options?: {
        topology?: "mesh" | "exact";
    }): Promise<FaceSummary[]>;
    /**
     * The indexes of the faces pointing a given way, which is usually one.
     *
     * A shell request can name the direction itself, so this is for a caller that
     * wants to know what it would get first -- or to find out that this shape has
     * no flat face pointing that way before asking for a tray with no lid off.
     */
    facing(projectId: string, shapeId: string, direction: FaceDirection): Promise<number[]>;
}

FaceSummary ​

type

ts
export type FaceSummary = {
    /** Stable, project-persisted identity for this face. */
    id: string;
    index: number;
    /** As OCCT names the surface: `plane`, `cylinder`, `bspline`, or `unknown`. */
    surfaceType: string;
    area: number;
    /** Area-weighted centre, which is a real point on the face even when curved. */
    centroid: {
        x: number;
        y: number;
        z: number;
    };
    /** The outward normal, or null for a surface that cannot report one. */
    normal: {
        x: number;
        y: number;
        z: number;
    } | null;
    /**
     * The direction name this face answers to in a shell request.
     *
     * Only the outermost flat face pointing a given way takes the name: the floor
     * of a hollow part's cavity points up as surely as its lid does, and opening
     * the wrong one of those looks like nothing happened.
     */
    facing: FaceDirection | null;
};

FetchLike ​

type

ts
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;

GearKindType ​

type

ts
export type GearKindType = "spur" | "helical" | "bevel";

grid ​

function

ts
export declare function grid(columns: number, rows: number, spacing: {
    x: number;
    z: number;
}, center?: Point2): Point2[];

GroupResult ​

type

ts
export type GroupResult = {
    shape: ShapeSummary;
    revision: number;
};

The new group, which replaces its members; members marked hole are subtracted.

Groups ​

class

ts
export declare class Groups {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Group two or more shapes into one.
     *
     * Grouping is also how the editor subtracts: members marked `hole: true` are
     * cut from the rest, exactly as the editor's Group button does.
     */
    group(projectId: string, ids: readonly string[]): Promise<GroupResult>;
    /** Take a group apart; its members come back carrying the group's move, turn and resize. */
    ungroup(projectId: string, shapeId: string): Promise<ShapeWriteResult>;
}

IMPORTABLE_MESH_FORMATS ​

value

ts
IMPORTABLE_MESH_FORMATS: readonly ["stl", "obj", "svg"]

Imports ​

class

ts
export declare class Imports {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Adds the model a file describes, and keeps the file with the project.
     *
     * The source file is stored as a project asset and the shape points at it,
     * both in one write -- a shape stored without its asset loses its geometry
     * the next time the project is saved.
     *
     * `stl`, `obj` and `svg`. A STEP file is refused with `unsupported_format`:
     * reading one needs the CAD kernel the editor loads in a browser.
     */
    apply(projectId: string, request: MeshImportRequest): Promise<MeshImportResult>;
    /** Whether this file's name is one the server will try to read at all. */
    readable(fileName: string): boolean;
}

Interference ​

class

ts
export declare class Interference {
    private readonly transport;
    constructor(transport: Transport);
    /** Exact gaps and overlap volumes; the server refuses requests above its work caps. */
    check(projectId: string, request?: InterferenceRequest): Promise<InterferenceReport>;
}

InterferenceReport ​

type

ts
export type InterferenceReport = {
    shapesChecked: number;
    candidatePairsChecked: number;
    clearance: number;
    method: "OCCT exact distance and common volume; AABB candidate prefilter";
    pairs: Array<{
        a: {
            id: string;
            name: string;
        };
        b: {
            id: string;
            name: string;
        };
        gap: number;
        overlapVolume: number;
        precision: "exact" | "tessellated";
    }>;
};

Exact surface-gap and penetration report for selected visible solids.

InterferenceRequest ​

type

ts
export type InterferenceRequest = {
    ids?: readonly string[];
    clearance?: number;
};

ListPage ​

type

ts
export type ListPage<Item> = {
    items: Item[];
    nextCursor: string | null;
};

ListPageOptions ​

type

ts
export type ListPageOptions = {
    limit?: number;
    cursor?: string;
};

LoftProfileShape ​

type

ts
export type LoftProfileShape = "Oval" | "Rectangle" | "Triangle" | "Pentagon" | "Hexagon";

MacroContext ​

type

ts
export type MacroContext<Params extends Record<string, MacroParameterValue>> = {
    client: SketchForgeClient;
    /** The project the mode resolved to, already created or emptied as declared. */
    project: ProjectHandle;
    params: Params;
    layout: MacroLayout;
    /** Progress, on stderr, so a macro's own result can be piped. */
    log: (message: string) => void;
};

MacroDefinition ​

type

ts
export type MacroDefinition<Params extends Record<string, MacroParameterValue>> = {
    name: string;
    description?: string;
    project: MacroProjectSpec;
    /**
     * Defaults for every parameter the macro takes.
     *
     * They double as the schema: a CLI argument is coerced to the type of the
     * default, and a name with no default is refused rather than passed through
     * as a string the macro will silently misread.
     */
    params?: Params;
    run: (context: MacroContext<Params>) => Promise<unknown> | unknown;
};

macroFromModule ​

function

ts
export declare function macroFromModule(module: unknown, fallbackName: string): MacroDefinition<Record<string, MacroParameterValue>>;

macroLayout ​

value

ts
macroLayout: {
    readonly centeredOffsets: typeof centeredOffsets;
    readonly grid: typeof grid;
    readonly mm: typeof mm;
    readonly ring: typeof ring;
    readonly row: typeof row;
}

MacroLayout ​

type

ts
export type MacroLayout = typeof macroLayout;

MacroParameterValue ​

type

ts
export type MacroParameterValue = number | string | boolean;

MacroProjectMode ​

type

ts
export type MacroProjectMode = "fresh" | "replace" | "reuse" | "target";

MacroProjectSpec ​

type

ts
export type MacroProjectSpec = MacroProjectMode | {
    mode: MacroProjectMode;
    /** The project's name. `fresh` appends a stamp to it. */
    name?: string;
};

MacroRunReport ​

type

ts
export type MacroRunReport = {
    macro: string;
    projectId: string;
    projectCreated: boolean;
    shapesCleared: number;
    shapeCount: number;
    durationMs: number;
    result: unknown;
};

MAX_DIMENSION ​

value

ts
MAX_DIMENSION = 10000

MAX_PATTERN_COUNT ​

value

ts
MAX_PATTERN_COUNT = 200

MAX_SHAPES_PER_REQUEST ​

value

ts
MAX_SHAPES_PER_REQUEST = 200

One POST may carry at most this many shapes.

MEASUREMENT_ANGLE_UNAVAILABLE_CODES ​

value

ts
MEASUREMENT_ANGLE_UNAVAILABLE_CODES: readonly ["notPlanar", "degenerateNormal"]

Why there is no angle. An angle is only defined between two flat faces.

MEASUREMENT_END_ENTITIES ​

value

ts
MEASUREMENT_END_ENTITIES: readonly ["edge", "face", "shape"]

What one end of a between-entities measurement names.

shape is the whole solid, which is what "how far apart are these two parts" means; edge and face narrow it to one entity of that solid.

MEASUREMENT_ENTITIES ​

value

ts
MEASUREMENT_ENTITIES: readonly ["edge", "face"]

The entities a measurement listing reports, one entry each.

MEASUREMENT_RADIUS_UNAVAILABLE_CODES ​

value

ts
MEASUREMENT_RADIUS_UNAVAILABLE_CODES: readonly ["notCircular", "ellipseHasNoSingleRadius", "degenerateCurve", "notCurved", "radiusVariesOverSurface", "radiusNotReportedByKernel", "degenerateSurface"]

Why there is no radius, instead of a guessed number.

The first three answer for an edge and the last four for a face, which is why they are one set: a caller reads them off radiusUnavailable without having to know which entity it was looking at.

MeasurementAngleUnavailableCode ​

type

ts
export type MeasurementAngleUnavailableCode = (typeof MEASUREMENT_ANGLE_UNAVAILABLE_CODES)[number];

MeasurementEnd ​

type

ts
export type MeasurementEnd = {
    shapeId: string;
    entity?: MeasurementEndEntity;
    /** Which edge or face, from the measurement listing. Required for those two. */
    index?: number;
};

One end of a between-entities measurement.

The shapeId is required on each end rather than shared, because the two ends may be different shapes -- which is the measurement the route exists for. An entity left out means the whole shape, and takes no index.

MeasurementEndEntity ​

type

ts
export type MeasurementEndEntity = (typeof MEASUREMENT_END_ENTITIES)[number];

MeasurementEntity ​

type

ts
export type MeasurementEntity = (typeof MEASUREMENT_ENTITIES)[number];

MeasurementPair ​

type

ts
export type MeasurementPair = {
    /** Exact minimum distance between the two entities, in mm. Zero when they touch. */
    distance: number;
    /** Angle between two planar faces' outward normals, 0 to 180. Null otherwise. */
    angleDegrees: number | null;
    /** Why there is no angle. Null when one is reported. */
    angleUnavailable: MeasurementAngleUnavailableCode | null;
};

MeasurementRadiusUnavailableCode ​

type

ts
export type MeasurementRadiusUnavailableCode = (typeof MEASUREMENT_RADIUS_UNAVAILABLE_CODES)[number];

Measurements ​

class

ts
export declare class Measurements {
    private readonly transport;
    constructor(transport: Transport);
    /** Every edge and face, measured, numbered as the edge and face listings number them. */
    list(projectId: string, shapeId: string): Promise<MeasurementSummary[]>;
    /**
     * The distance between two entities, and the angle if both are flat faces.
     *
     * The ends may be on different shapes, and either may be a whole shape, so
     * this answers both "how deep is that pocket" and "how far apart are those
     * two parts". The distance is measured between the real surfaces, so two
     * cylinders 5mm apart at their nearest walls read 5.
     */
    between(projectId: string, from: MeasurementEnd, to: MeasurementEnd): Promise<MeasurementPair>;
    /**
     * The entries that carry a radius, which is how a caller finds the bores.
     *
     * Most entities of a shape have none -- a flat face and a straight edge both
     * answer with a reason instead -- so filtering on the reported radius is what
     * a caller wanting the round features has to do anyway.
     */
    withRadius(projectId: string, shapeId: string): Promise<MeasurementSummary[]>;
}

MeasurementSummary ​

type

ts
export type MeasurementSummary = {
    entity: MeasurementEntity;
    index: number;
    /** As OCCT names it: `line`, `circle`, `ellipse`, `bspline` for an edge; `plane`, `cylinder`, `sphere`, `cone`, `torus` for a face. */
    geometryType: string;
    /** Edge length in mm, arcs measured along the curve. Null for a face. */
    length: number | null;
    /** Face area in mm^2. Null for an edge. */
    area: number | null;
    radius: number | null;
    diameter: number | null;
    /** Degrees a circular edge runs through; a full circle is 360. Null otherwise. */
    sweepDegrees: number | null;
    /** Why there is no radius. Null when one is reported. */
    radiusUnavailable: MeasurementRadiusUnavailableCode | null;
};

One edge or face, measured from the exact B-rep rather than the mesh.

index is the same index the edge and face listings give the entity, so a measurement and the fillet that follows it name the same thing. The fields that do not apply are null rather than zero: a face has no length, an edge has no area, and a straight line has no radius -- and a radius of 0 would read as a measurement rather than as the absence of one.

MeasurementUnavailableCode ​

type

ts
export type MeasurementUnavailableCode = MeasurementRadiusUnavailableCode | MeasurementAngleUnavailableCode;

Either reason, for a caller that only logs it.

The server derives both from one union of its own, but the two fields draw on disjoint halves of it -- a radius is never missing because a face was not planar -- so each field is typed to its own half and this is the sum.

MeshImportRequest ​

type

ts
export type MeshImportRequest = {
    fileName: string;
    bytes: Uint8Array;
    /** Recorded on the stored asset; the format's own default otherwise. */
    mediaType?: string;
};

A model file to import.

fileName chooses the importer, names the stored asset, and for an STL decides which way is up -- a slicer writes Z-up and SketchForge's own older exports are Y-up, recognised by the word in the file header.

MeshImportResult ​

type

ts
export type MeshImportResult = TreatmentResult;

The same three fields a treatment answers with; an import is one more of them.

MIN_DIMENSION ​

value

ts
MIN_DIMENSION = 0.01

Dimensions outside this range are clamped by the server rather than refused.

MIN_PATTERN_COUNT ​

value

ts
MIN_PATTERN_COUNT = 2

MirrorAxis ​

type

ts
export type MirrorAxis = "x" | "y" | "z";

Mirrors ​

class

ts
export declare class Mirrors {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Reflects each named solid across the selected bounds midpoint plane and
     * stores the exact reflected BREP. Imported meshes, groups, and previously
     * treated shapes are refused instead of being silently tessellated.
     */
    bake(projectId: string, ids: readonly string[], axis: MirrorAxis): Promise<BakedMirrorResult>;
}

MissingConfigurationError ​

class

ts
export declare class MissingConfigurationError extends Error {
    constructor(message: string);
}

mm ​

function

ts
export declare function mm(value: number): number;

normalizeBaseUrl ​

function

ts
export declare function normalizeBaseUrl(baseUrl: string): string;

PARAMETRIC_SHAPE_KINDS ​

value

ts
PARAMETRIC_SHAPE_KINDS: readonly ["box", "cube", "cylinder", "cone", "sphere", "halfSphere", "torus", "tube", "ring", "polygon", "pyramid", "roof", "roundRoof", "wedge", "icosahedron", "text", "loft", "gear"]

Kinds the server can build from parameters alone, with no OCCT and no browser.

ParametricShapeKind ​

type

ts
export type ParametricShapeKind = (typeof PARAMETRIC_SHAPE_KINDS)[number];

ParametricShapeRequest ​

type

ts
export type ParametricShapeRequest = {
    [Kind in ParametricShapeKind]: {
        kind: Kind;
    } & ShapePlacement & ShapeDimensions & (KindFields[Kind] extends object ? KindFields[Kind] : Record<never, never>) & (Kind extends "gear" ? Record<never, never> : TaperFields);
}[ParametricShapeKind];

Parts ​

class

ts
export declare class Parts {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Split a shape into the separate bodies it is made of.
     *
     * A cut often leaves several pieces -- a bar cut through the middle is two
     * bars -- and until they are separate shapes none can be moved or exported
     * alone. A plain group is restored to its members.
     */
    separate(projectId: string, shapeId: string): Promise<ShapeWriteResult>;
}

PATTERN_KINDS ​

value

ts
PATTERN_KINDS: readonly ["linear", "circular"]

PatternKind ​

type

ts
export type PatternKind = (typeof PATTERN_KINDS)[number];

PatternRequest ​

type

ts
export type PatternRequest = {
    ids: readonly string[];
    kind?: PatternKind;
    /** Total copies including the original, so 4 adds 3. From 2 to 200; default 4. */
    count?: number;
    /** `linear`: centre-to-centre step along each axis, in mm. A pitch, not a gap. */
    stepX?: number;
    stepZ?: number;
    /** `circular`: the point to turn about. Default the origin. */
    centerX?: number;
    centerZ?: number;
    /** `circular`: how far round to spread the copies, in degrees. Default 360. */
    sweepAngle?: number;
    /** `circular`: whether each copy turns to follow the ring. On by default. */
    rotateCopies?: boolean;
};

PatternResult ​

type

ts
export type PatternResult = {
    /** How many copies were added, which is `count` minus the original. */
    created: number;
    kind: PatternKind;
    shapes: ShapeSummary[];
    revision: number;
};

Patterns ​

class

ts
export declare class Patterns {
    private readonly transport;
    constructor(transport: Transport);
    /** Repeats shapes in a row or around a ring, adding the copies to the project. */
    apply(projectId: string, request: PatternRequest): Promise<PatternResult>;
    /**
     * A row at a centre-to-centre pitch.
     *
     * `count` includes the original, so `row(p, [id], 4, 25)` adds three copies
     * at 25, 50 and 75mm along X. The step is a pitch rather than a gap, because
     * "four at 25mm" is unambiguous and "four with 25mm between them" is not.
     */
    row(projectId: string, ids: readonly string[], count: number, stepX: number, stepZ?: number): Promise<PatternResult>;
    /**
     * A ring about a point, which is how a bolt circle is made.
     *
     * A full turn divides by the count, so six land every 60 degrees and the
     * last does not sit on the first.
     */
    ring(projectId: string, ids: readonly string[], count: number, center: {
        x: number;
        z: number;
    }, options?: {
        sweepAngle?: number;
        rotateCopies?: boolean;
    }): Promise<PatternResult>;
}

Point2 ​

type

ts
export type Point2 = {
    x: number;
    z: number;
};

ProfilePoint ​

type

ts
export type ProfilePoint = readonly [number, number];

A point of a revolve outline: [distance from the axis, position along it].

PROJECT_ENV ​

value

ts
PROJECT_ENV = "SKETCHFORGE_PROJECT_ID"

PROJECT_EXPORT_FORMATS ​

value

ts
PROJECT_EXPORT_FORMATS: readonly ["stl", "obj", "3mf", "step", "skf", "zip", "svg", "dxf"]

Every format POST /exports produces, in the server's order.

ProjectDetail ​

type

ts
export type ProjectDetail = {
    id: string;
    name: string;
    createdAt: number;
    snapGrid: ProjectSnapGrid;
    workspace: Record<string, unknown>;
    shapes: ShapeSummary[];
};

ProjectExportArtifact ​

type

ts
export type ProjectExportArtifact = {
    format: ProjectExportFormat;
    filename: string;
    mimeType: string;
    /** The artifact's length in bytes, as the server counted it. */
    bytes: number;
    /** How many shapes the export covered. */
    shapeCount: number;
    /** STEP only: how many of those shapes became exact solids. */
    exportedCount?: number;
    /** STEP only: the shapes left out, which a mesh-only shape always is. */
    skipped?: ExportSkippedShape[];
    /** The file itself, byte for byte. */
    data: Uint8Array;
};

ProjectExportFormat ​

type

ts
export type ProjectExportFormat = (typeof PROJECT_EXPORT_FORMATS)[number];

ProjectExportRequest ​

type

ts
export type ProjectExportRequest = {
    format: ProjectExportFormat;
    /** Omit to export every shape in the project. */
    shapeIds?: readonly string[];
    /** Output basename; the project name when omitted. At most 120 characters. */
    name?: string;
    /** SVG only. Cannot be combined with `section`. */
    view?: ExportView;
    /** SVG projection only: crease angle in degrees for mesh feature edges. */
    featureAngle?: number;
    /** SVG or DXF only. Cannot be combined with `view`. */
    section?: ExportSection;
};

ProjectHandle ​

class

ts
export declare class ProjectHandle {
    private readonly client;
    readonly id: string;
    constructor(client: SketchForgeClient, id: string);
    get(): Promise<ProjectDetail>;
    delete(): Promise<import("./types.js").DeleteResult>;
    listShapes(): Promise<ShapeSummary[]>;
    add(shape: ShapeRequest): Promise<ShapeSummary>;
    addMany(shapes: readonly ShapeRequest[]): Promise<ShapeWriteResult>;
    update(shapeId: string, changes: ShapePatch): Promise<import("./types.js").ShapePatchResult>;
    remove(shapeId: string): Promise<import("./types.js").DeleteResult>;
    clear(): Promise<number>;
    edges(shapeId: string): Promise<EdgeSummary[]>;
    filletableEdges(shapeId: string): Promise<number[]>;
    treat(shapeId: string, treatment: EdgeTreatment): Promise<TreatmentResult>;
    fillet(shapeId: string, radius: number, edges?: readonly number[]): Promise<TreatmentResult>;
    chamfer(shapeId: string, distance: number, options?: {
        angle?: number;
        edges?: readonly number[];
    }): Promise<TreatmentResult>;
    faces(shapeId: string, options?: {
        topology?: "mesh" | "exact";
    }): Promise<FaceSummary[]>;
    facesFacing(shapeId: string, direction: FaceDirection): Promise<number[]>;
    measurements(shapeId: string): Promise<MeasurementSummary[]>;
    propertiesOf(shapeId: string): Promise<ShapeProperties>;
    explodeStepAssembly(shapeId: string): Promise<ShapeWriteResult>;
    sectionDrawing(request: SectionDrawingRequest): Promise<SectionDrawingArtifact>;
    sectionDxf(request: SectionDrawingRequest): Promise<SectionDxfArtifact>;
    /** Exports the project, or the named shapes, as one file in any of `PROJECT_EXPORT_FORMATS`. */
    export(request: ProjectExportRequest): Promise<ProjectExportArtifact>;
    /** Subtracts the named holes from the named solids, leaving one exact shape. */
    cut(request: BooleanCutRequest): Promise<BooleanCutResult>;
    /** Groups shapes; members marked `hole: true` are subtracted. */
    group(ids: readonly string[]): Promise<GroupResult>;
    /** Restores a group's members as separate project shapes. */
    ungroup(shapeId: string): Promise<ShapeWriteResult>;
    /** Splits a shape into its disconnected bodies. */
    separate(shapeId: string): Promise<ShapeWriteResult>;
    /** A sampled estimate of the shape's thinnest wall; not a certified minimum. */
    estimateWallThickness(shapeId: string): Promise<WallThicknessEstimate>;
    measurementsWithRadius(shapeId: string): Promise<MeasurementSummary[]>;
    /** The distance between two entities, which may be on two different shapes. */
    measureBetween(from: MeasurementEnd, to: MeasurementEnd): Promise<MeasurementPair>;
    /** Exact gaps and penetration volumes between selected project solids. */
    interferenceReport(request?: import("./types.js").InterferenceRequest): Promise<import("./types.js").InterferenceReport>;
    /** Reflects exact parameter-built solids across the selected bounds plane. */
    mirrorBaked(ids: readonly string[], axis: MirrorAxis): Promise<BakedMirrorResult>;
    /** Hollows the shape out, sealed unless `openFaces` names faces to leave off. */
    shell(shapeId: string, request: ShellRequest): Promise<ShellResult>;
    /** Draft a retained straight polygon sketch extrusion and store the exact result. */
    draftPrism(shapeId: string, angle: number): Promise<TreatmentResult>;
    hollow(shapeId: string, thickness: number): Promise<TreatmentResult>;
    tray(shapeId: string, thickness: number, openFaces?: ShellRequest["openFaces"]): Promise<TreatmentResult>;
    /** Puts one edge or one centre of every named shape on the same coordinate. */
    align(request: AlignRequest): Promise<AlignResult>;
    /** Flush tops, which is the alignment a row of parts on a plate usually wants. */
    alignTops(ids: readonly string[], anchorId?: string): Promise<AlignResult>;
    /** Spreads three or more shapes evenly; the outermost two define the span. */
    distribute(request: DistributeRequest): Promise<DistributeResult>;
    /** Repeats shapes in a row or around a ring, adding the copies. */
    pattern(request: PatternRequest): Promise<PatternResult>;
    /** A row at a centre-to-centre pitch; `count` includes the original. */
    row(ids: readonly string[], count: number, stepX: number, stepZ?: number): Promise<PatternResult>;
    /** A ring about a point, which is how a bolt circle is made. */
    ring(ids: readonly string[], count: number, center: {
        x: number;
        z: number;
    }, options?: {
        sweepAngle?: number;
        rotateCopies?: boolean;
    }): Promise<PatternResult>;
    /** Adds the model a file describes, keeping the file with the project. */
    importMesh(request: MeshImportRequest): Promise<MeshImportResult>;
}

Projects ​

class

ts
export declare class Projects {
    private readonly transport;
    constructor(transport: Transport);
    list(): Promise<ProjectSummary[]>;
    listPage(options?: ListPageOptions): Promise<ListPage<ProjectSummary>>;
    get(projectId: string): Promise<ProjectDetail>;
    /** The server truncates a name to 80 characters and refuses an empty one. */
    create(name: string): Promise<ProjectSummary>;
    delete(projectId: string): Promise<DeleteResult>;
    /** The first project with this name, or null. Names are not unique server-side. */
    findByName(name: string): Promise<ProjectSummary | null>;
}

ProjectSnapGrid ​

type

ts
export type ProjectSnapGrid = {
    enabled?: boolean;
    size?: number;
} & Record<string, unknown>;

ProjectSummary ​

type

ts
export type ProjectSummary = {
    id: string;
    name: string;
    /** How many shapes the project holds. */
    shapes: number;
    revision: number;
    updatedAt: number;
    packageBytes: number;
};

Properties ​

class

ts
export declare class Properties {
    private readonly transport;
    constructor(transport: Transport);
    /** Exact mass properties and geometry provenance for one shape. */
    get(projectId: string, shapeId: string): Promise<ShapeProperties>;
}

RequestSpec ​

type

ts
export type RequestSpec = {
    method: "GET" | "POST" | "PATCH" | "DELETE";
    path: string;
    query?: Record<string, string | undefined>;
    body?: unknown;
    /** Writes are retried when the project lock is busy; reads need no retry. */
    retryable?: boolean;
};

ResolvedMacroProject ​

type

ts
export type ResolvedMacroProject = {
    project: ProjectHandle;
    summary: ProjectSummary | null;
    created: boolean;
    cleared: number;
};

resolveMacroParams ​

function

ts
export declare function resolveMacroParams<Params extends Record<string, MacroParameterValue>>(defaults: Params | undefined, overrides: Record<string, string>): Params;

resolveMacroProject ​

function

ts
export declare function resolveMacroProject(client: SketchForgeClient, spec: MacroProjectSpec, options: {
    fallbackName: string;
    targetProjectId?: string | undefined;
    now?: Date;
}): Promise<ResolvedMacroProject>;

RevolveSettings ​

type

ts
export type RevolveSettings = {
    /** Axial rise per full turn, in mm. `0` is a plain revolve; negative is left-hand. */
    pitch?: number;
    /** Full turns to sweep, 0.1 to 20. */
    turns?: number;
    startAngle?: number;
    /** How far round to revolve when there is no pitch, +/-360. */
    sweepAngle?: number;
    /** Facets per full turn of the sweep, 3 to 512 (default 64). Not a prism's side count. */
    sides?: number;
    /** How finely curved profile segments are sampled, 1 to 10 (default 6). A point outline has none. */
    quality?: number;
    /** The solid the sweep is fused into. `0` leaves the bare ribbon. */
    coreRadius?: number;
};

RevolveShapeRequest ​

type

ts
export type RevolveShapeRequest = {
    kind: "revolve";
    profile: readonly ProfilePoint[];
} & RevolveSettings & ShapePlacement;

RevolveSummary ​

type

ts
export type RevolveSummary = {
    startAngle: number;
    sweepAngle: number;
    /** Facets per full turn of the sweep, not a prism's side count. */
    sides: number;
    /** How finely a curved profile is sampled, 1 to 10. */
    quality: number;
    pitch: number;
    turns: number;
    coreRadius: number;
    /**
     * Where the axis of revolution is on the workplane. A shape's `x`/`z` is the
     * centre of its box, which for a partial sweep is off to one side of the
     * axis. Absent for a revolve saved before the axis was recorded, until it is
     * next rebuilt, and while the shape is tilted by `rotationX` or `rotationZ`,
     * since a tilted axis crosses the workplane at no single point. Read-only:
     * a change sent back with it ignores it.
     */
    axis?: {
        x: number;
        z: number;
    };
};

How far round a sweep goes, and how fast it rises, as the server reports it.

ring ​

function

ts
export declare function ring(count: number, radius: number, options?: {
    center?: Point2;
    startAngle?: number;
}): Point2[];

row ​

function

ts
export declare function row(count: number, spacing: number, center?: Point2): Point2[];

runMacro ​

function

ts
export declare function runMacro<Params extends Record<string, MacroParameterValue>>(client: SketchForgeClient, definition: MacroDefinition<Params>, options?: {
    params?: Record<string, string>;
    targetProjectId?: string | undefined;
    log?: (message: string) => void;
    now?: Date;
}): Promise<MacroRunReport>;

runStamp ​

function

ts
export declare function runStamp(now?: Date): string;

SECTION_PLANES ​

value

ts
SECTION_PLANES: readonly ["xy", "xz", "yz"]

Axis-aligned section planes in the CAD drawing's Z-up coordinates.

SectionDrawingArtifact ​

type

ts
export type SectionDrawingArtifact = {
    filename: string;
    mimeType: "image/svg+xml";
    bytes: number;
    shapeCount: number;
    svg: string;
};

SectionDrawingRequest ​

type

ts
export type SectionDrawingRequest = {
    plane: SectionPlane;
    /** Coordinate of the plane's omitted axis, in millimetres. */
    offset: number;
    shapeIds?: readonly string[];
    name?: string;
};

SectionDxfArtifact ​

type

ts
export type SectionDxfArtifact = {
    filename: string;
    mimeType: "application/dxf";
    bytes: number;
    shapeCount: number;
    dxf: string;
};

SectionPlane ​

type

ts
export type SectionPlane = (typeof SECTION_PLANES)[number];

ShapeDimensions ​

type

ts
export type ShapeDimensions = {
    width?: number;
    depth?: number;
    height?: number;
    /** Stands in for all three, which is what `cube` is for. */
    size?: number;
};

ShapeGeometryProvenance ​

type

ts
export type ShapeGeometryProvenance = {
    source: "parametric" | "brep" | "mesh";
    precision: "exact" | "tessellated";
};

Which stored representation supplied the solid to the CAD kernel.

ShapeKind ​

type

ts
export type ShapeKind = ParametricShapeKind | "revolve" | "thread" | "sketchSweep";

Every kind a shape request may name, including the two swept ones.

ShapePatch ​

type

ts
export type ShapePatch = ShapePlacement & ShapeDimensions & AnyKindFields & TaperFields & RevolveSettings & {
    /** Colors keyed by stable face ID; numeric keys remain accepted for older projects. */
    faceColors?: Record<string, string>;
    locked?: boolean;
    hidden?: boolean;
    /** Replaces a revolve's outline; the sweep is rebuilt on the server. */
    profile?: readonly ProfilePoint[];
    /** Replaces a sketch sweep's editable source profile and rebuilds its mesh. */
    sketchProfile?: SketchSweepProfile;
    /** Creates, updates, or clears one persisted face draft on a sketch extrusion. */
    faceDraft?: SketchFaceDraft | null;
    /** The sweep's settings as one object, for a caller that keeps them together. */
    revolve?: RevolveSettings;
};

The fields a PATCH may change.

Everything a summary reports is here, which is the point: a shape can be read, one number changed, and the whole thing sent back. The kind is not in the type -- a summary reports it as a plain string, so there is nothing to narrow on -- which means this is wider than any one shape accepts. The server refuses what the shape's kind has no use for, naming the fields in fields on a 422 unapplicable_fields, rather than ignoring them as it used to.

shapePatchFromSummary ​

function

ts
export declare function shapePatchFromSummary(summary: ShapeSummary, changes?: ShapePatch): ShapePatch;

ShapePatchResult ​

type

ts
export type ShapePatchResult = {
    shape: ShapeSummary;
    revision: number;
};

ShapePlacement ​

type

ts
export type ShapePlacement = {
    name?: string;
    /** A CSS hex colour, as the editor stores it. */
    color?: string;
    x?: number;
    z?: number;
    elevation?: number;
    rotation?: number;
    rotationX?: number;
    rotationZ?: number;
    /** Marked as a hole, so grouping it with a solid subtracts it. */
    hole?: boolean;
};

ShapeProperties ​

type

ts
export type ShapeProperties = {
    volume: number;
    area: number;
    centerOfMass: {
        x: number;
        y: number;
        z: number;
    };
    bbox: {
        xmin: number;
        ymin: number;
        zmin: number;
        xmax: number;
        ymax: number;
        zmax: number;
    };
    isValid: boolean;
    provenance: ShapeGeometryProvenance;
};

Exact mass properties for one shape in project coordinates.

ShapeRequest ​

type

ts
export type ShapeRequest = ParametricShapeRequest | RevolveShapeRequest | ThreadShapeRequest | SketchSweepShapeRequest;

Shapes ​

class

ts
export declare class Shapes {
    private readonly transport;
    constructor(transport: Transport);
    list(projectId: string): Promise<ShapeSummary[]>;
    listPage(projectId: string, options?: ListPageOptions): Promise<ListPage<ShapeSummary>>;
    /** One shape. The created shape comes back with the id later calls need. */
    create(projectId: string, shape: ShapeRequest): Promise<ShapeSummary>;
    /**
     * A batch, in request order.
     *
     * One request is one write of the project package, so a row of forty holes
     * should be one call rather than forty. Lists longer than the server's limit
     * are split, which means a long list is no longer atomic -- a later chunk can
     * fail with earlier ones already written.
     */
    createMany(projectId: string, shapes: readonly ShapeRequest[]): Promise<ShapeWriteResult>;
    /** Changes the fields given and leaves the rest. A locked shape needs `locked: false`. */
    update(projectId: string, shapeId: string, changes: ShapePatch): Promise<ShapePatchResult>;
    delete(projectId: string, shapeId: string): Promise<DeleteResult>;
    /**
     * Empties the project, one delete at a time.
     *
     * There is no bulk delete, and each call rewrites the package, so this is
     * slow by nature -- which is exactly why a macro that wants a clean slate
     * should usually make a fresh project instead.
     */
    deleteAll(projectId: string): Promise<number>;
}

ShapeSummary ​

type

ts
export type ShapeSummary = {
    id: string;
    name: string;
    kind: string;
    requestKind?: ShapeKind;
    sketchOperation?: SketchOperation;
    /** Stable source sketch identity for editable sketch-derived geometry. */
    sketchSourceId?: string;
    faceDraft?: SketchFaceDraft;
    /** Editable profile retained for a sketch sweep created through REST. */
    sketchProfile?: SketchSweepProfile;
    color: string;
    faceIds?: string[];
    faceColors?: Record<string, string>;
    /** Product hierarchy from an imported STEP assembly, when available. */
    stepAssembly?: StepAssemblyNode[];
    /** Source occurrence identity and ancestry for a STEP solid made selectable by explosion. */
    stepComponent?: StepComponent;
    hole: boolean;
    locked: boolean;
    hidden: boolean;
    x: number;
    z: number;
    elevation: number;
    width: number;
    depth: number;
    height: number;
    rotation: number;
    rotationX: number;
    rotationZ: number;
    steps?: number;
    sides?: number;
    bevel?: number;
    segments?: number;
    topRadius?: number;
    baseRadius?: number;
    teeth?: number;
    toothSize?: number;
    toothWidth?: number;
    centerHoleSize?: number;
    gearType?: GearKindType;
    helixAngle?: number;
    loftBottomShape?: LoftProfileShape;
    loftTopShape?: LoftProfileShape;
    loftTopWidth?: number;
    loftTopDepth?: number;
    loftBottomRotation?: number;
    loftTopRotation?: number;
    loftSegments?: number;
    loftLayers?: number;
    text?: string;
    font?: string;
    /** Present on a revolve or a thread: the sweep that built it. */
    revolve?: RevolveSummary;
    /**
     * The outline the sweep ran round, when it was described rather than drawn.
     *
     * A profile drawn in the editor can be several paths with curve handles, which
     * no list of `[x, z]` pairs describes, so it is omitted rather than flattened.
     */
    profile?: ProfilePoint[];
    groupedCount?: number;
} & TaperFields;

A shape as the server reports it.

kind is the stored kind rather than the requested one: a cube comes back as a box, and a revolve or thread as a mesh, because that is what the project holds. requestKind is the other half of that -- the kind a POST would need to build the shape again, which is what tells a thread apart from an imported STL when both store as mesh. It is absent for a shape no request can reproduce, such as a boolean cut.

Every per-kind parameter the server accepts also comes back, so a read, change and write loses nothing; which ones are present depends on the kind.

ShapeWriteResult ​

type

ts
export type ShapeWriteResult = {
    shapes: ShapeSummary[];
    revision: number;
};

Shell ​

class

ts
export declare class Shell {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Hollows a solid out on the server, with OCCT.
     *
     * The result is exact, so it still exports to STEP and can still be filleted.
     * Not every shape can be hollowed: a sphere, a torus, a cone and a tube's
     * round wall are each one continuous curved surface, and OCCT refuses to
     * offset them inwards at any thickness.
     */
    apply(projectId: string, shapeId: string, request: ShellRequest): Promise<ShellResult>;
    /** A sealed hollow: a wall all the way round, with the void closed in. */
    hollow(projectId: string, shapeId: string, thickness: number): Promise<import("../types.js").TreatmentResult>;
    /** The usual print: a box with its lid off, which is a tray. */
    tray(projectId: string, shapeId: string, thickness: number, openFaces?: ShellRequest["openFaces"]): Promise<import("../types.js").TreatmentResult>;
}

ShellRequest ​

type

ts
export type ShellRequest = {
    /** Wall thickness in mm, measured inwards from the surface. */
    thickness: number;
    /**
     * Faces to leave open, as direction names or as indexes from the face
     * listing. Omitted or empty seals the hollow in.
     */
    openFaces?: readonly (FaceDirection | number)[];
};

ShellResult ​

type

ts
export type ShellResult = TreatmentResult;

The same three fields a treatment answers with; hollowing is one more of them.

SketchFaceDraft ​

type

ts
export type SketchFaceDraft = {
    sourceFaceId: string;
    angle: number;
    pullDirection: "x" | "y" | "z" | "-x" | "-y" | "-z";
    /** Included in responses as matching evidence; patches may omit it. */
    sourceFaceNormal?: {
        x: number;
        y: number;
        z: number;
    };
};

SketchForgeApiError ​

class

ts
export declare class SketchForgeApiError extends Error {
    readonly method: string;
    readonly url: string;
    readonly status: number;
    readonly detail: string | undefined;
    readonly code: string | undefined;
    readonly body: unknown;
    constructor(context: ApiErrorContext);
    /**
     * Whether the server gave this reason.
     *
     * The prose match is the fallback for a server from before codes existed, and
     * is deliberately kept: a client that only read `code` would treat every error
     * from such a server as unrecognised.
     */
    private is;
    /**
     * The API answers 404 for every route when `SKETCHFORGE_API_TOKEN` is unset,
     * which is indistinguishable from a missing project by status alone.
     */
    get looksDisabled(): boolean;
    /** The server has a token but no project directory, so it can store nothing. */
    get needsStorage(): boolean;
    /** A size or count cap was reached; `too_many_shapes` is accepted during the compatibility window. */
    get isLimitExceeded(): boolean;
    /** Another write holds the project's lock. Retrying is the right response. */
    get isProjectBusy(): boolean;
    /** The project changed since the supplied If-Match revision. */
    get isRevisionMismatch(): boolean;
    get currentRevision(): number | undefined;
    /** That shape is locked. Retrying will not help; unlock it first. */
    get isShapeLocked(): boolean;
    /** No such project on the server. */
    get isProjectMissing(): boolean;
    /** No such shape in the project. */
    get isShapeMissing(): boolean;
    /**
     * The change named fields the shape's kind has no use for.
     *
     * `unapplicableFields` lists them, which is the whole reason this is an error
     * rather than a silent no-op.
     */
    get hasUnapplicableFields(): boolean;
    get unapplicableFields(): string[];
}

SketchForgeClient ​

class

ts
export declare class SketchForgeClient {
    readonly projects: Projects;
    readonly shapes: Shapes;
    readonly edges: Edges;
    readonly explosions: Explosions;
    readonly faces: Faces;
    readonly measurements: Measurements;
    readonly mirrors: Mirrors;
    readonly properties: Properties;
    readonly treatments: Treatments;
    readonly drawings: Drawings;
    readonly draftPrism: DraftPrism;
    readonly shell: Shell;
    readonly align: Align;
    readonly distribute: Distribute;
    readonly patterns: Patterns;
    readonly imports: Imports;
    readonly interference: Interference;
    readonly thickness: Thickness;
    readonly exports: Exports;
    readonly booleans: Booleans;
    readonly groups: Groups;
    readonly parts: Parts;
    private readonly transport;
    constructor(options: SketchForgeClientOptions);
    get apiRoot(): string;
    /** A view of one project, so a macro does not thread its id through every call. */
    project(projectId: string): ProjectHandle;
    /**
     * Whether the API is reachable, enabled, and has storage.
     *
     * Worth calling first in anything interactive: the three ways this fails --
     * no token on the server, no project directory, wrong port -- are answered by
     * a 404, a 503 and a connection error, none of which reads as a
     * configuration mistake on its own.
     */
    check(): Promise<{
        ok: true;
        projects: number;
    } | {
        ok: false;
        reason: string;
    }>;
}

SketchForgeClientOptions ​

type

ts
export type SketchForgeClientOptions = TransportOptions;

SketchForgeTransportError ​

class

ts
export declare class SketchForgeTransportError extends Error {
    readonly method: string;
    readonly url: string;
    constructor(method: string, url: string, cause: unknown);
}

SketchOperation ​

type

ts
export type SketchOperation = "extrude" | "revolve" | "loft" | "sweep";

The operation a shape's geometry came out of, for the ones that have one.

SketchSweepPoint ​

type

ts
export type SketchSweepPoint = {
    id: string;
    x: number;
    z: number;
    sweepDepth?: number;
    sweepRole?: "section" | "spine";
    handleIn?: {
        x: number;
        z: number;
        sweepDepth?: number;
    };
    handleOut?: {
        x: number;
        z: number;
        sweepDepth?: number;
    };
    mode?: "corner" | "smooth" | "split";
};

SketchSweepProfile ​

type

ts
export type SketchSweepProfile = {
    points: readonly SketchSweepPoint[];
    segments: readonly {
        id: string;
        startId: string;
        endId: string;
        kind?: "line" | "bezier" | "smooth";
    }[];
    constraints?: readonly ({
        id: string;
        kind: "coincident";
        pointIds: readonly [string, string];
    } | {
        id: string;
        kind: "horizontal" | "vertical";
        segmentId: string;
    } | {
        id: string;
        kind: "parallel";
        segmentIds: readonly [string, string];
    } | {
        id: string;
        kind: "perpendicular";
        segmentIds: readonly [string, string];
    } | {
        id: string;
        kind: "tangent";
        segmentIds: readonly [string, string];
    } | {
        id: string;
        kind: "equalLength";
        segmentIds: readonly [string, string];
    } | {
        id: string;
        kind: "angle";
        segmentIds: readonly [string, string];
        valueDeg: number;
    } | {
        id: string;
        kind: "symmetry";
        pointIds: readonly [string, string];
        segmentId: string;
    } | {
        id: string;
        kind: "distance";
        pointIds: readonly [string, string];
        valueMm: number;
    } | {
        id: string;
        kind: "radius" | "diameter";
        pointIds: readonly [string, string];
        valueMm: number;
    })[];
    sweepFrames?: {
        section: {
            origin: {
                x: number;
                y: number;
                z: number;
            };
            normal: {
                x: number;
                y: number;
                z: number;
            };
            xAxis: {
                x: number;
                y: number;
                z: number;
            };
            zAxis: {
                x: number;
                y: number;
                z: number;
            };
        };
        spine: {
            origin: {
                x: number;
                y: number;
                z: number;
            };
            normal: {
                x: number;
                y: number;
                z: number;
            };
            xAxis: {
                x: number;
                y: number;
                z: number;
            };
            zAxis: {
                x: number;
                y: number;
                z: number;
            };
        };
    };
};

SketchSweepShapeRequest ​

type

ts
export type SketchSweepShapeRequest = {
    kind: "sketchSweep";
    profile: SketchSweepProfile;
} & ShapePlacement;

A retained OCCT sweep made from closed section loops and one open spine.

StepAssemblyNode ​

type

ts
export type StepAssemblyNode = {
    id?: string;
    name: string;
    children: StepAssemblyNode[];
};

A named STEP product and its nested component occurrences.

StepAssemblyPathNode ​

type

ts
export type StepAssemblyPathNode = {
    id?: string;
    name: string;
};

StepComponent ​

type

ts
export type StepComponent = {
    id: string;
    occurrenceId: string;
    path: StepAssemblyPathNode[];
};

TaperFields ​

type

ts
export type TaperFields = {
    taperTopWidth?: number;
    taperTopDepth?: number;
    taperBottomWidth?: number;
    taperBottomDepth?: number;
};

The taper every kind but gear carries: the footprint at each end of the extrusion, which need not match the shape's own width and depth.

targetProjectFromEnvironment ​

function

ts
export declare function targetProjectFromEnvironment(environment?: Environment): string | undefined;

Thickness ​

class

ts
export declare class Thickness {
    private readonly transport;
    constructor(transport: Transport);
    estimate(projectId: string, shapeId: string): Promise<WallThicknessEstimate>;
}

THREAD_DESIGNATIONS ​

value

ts
THREAD_DESIGNATIONS: readonly ["M2", "M2.5", "M3", "M4", "M5", "M6", "M8", "M10", "M12", "M16", "M20", "#4-40", "#6-32", "#8-32", "#10-24", "1/4-20", "5/16-18", "3/8-16", "1/2-13"]

Thread designations the server's catalog carries a pitch for.

ThreadDesignation ​

type

ts
export type ThreadDesignation = (typeof THREAD_DESIGNATIONS)[number];

ThreadShapeRequest ​

type

ts
export type ThreadShapeRequest = {
    kind: "thread";
    /** A catalog designation, which carries its own pitch. Defaults to `M8`. */
    size?: ThreadDesignation | string;
    /** Outside diameter, for a size the catalog does not list. */
    diameter?: number;
    pitch?: number;
    turns?: number;
    /** How long the thread should be, instead of counting turns. */
    length?: number;
    /** Cut wider by a clearance and marked as a hole, so a bolt of that size fits. */
    hole?: boolean;
    clearance?: number;
    /** `false` leaves the bare helix, with no shank and no drilled hole. */
    core?: boolean;
    /** Facets per full turn, as for a revolve (default 64). */
    sides?: number;
    /** How finely curved profile segments are sampled, 1 to 10 (default 6), as for a revolve. */
    quality?: number;
    /** Overrides the catalog's 60-degree V. */
    profile?: readonly ProfilePoint[];
} & ShapePlacement;

TOKEN_ENV ​

value

ts
TOKEN_ENV = "SKETCHFORGE_API_TOKEN"

Transport ​

class

ts
export declare class Transport {
    private readonly root;
    private readonly token;
    private readonly fetchImpl;
    private readonly timeoutMs;
    private readonly retryOnBusy;
    private readonly extraHeaders;
    private readonly expectedRevision;
    constructor(options: TransportOptions);
    get apiRoot(): string;
    send<Result>(spec: RequestSpec): Promise<Result>;
    private sendOnce;
}

TransportOptions ​

type

ts
export type TransportOptions = {
    /** Where the app is served, with or without the `/api/v1` suffix. */
    baseUrl: string;
    /** `SKETCHFORGE_API_TOKEN`. Without it every route answers 404. */
    token: string;
    /** Defaults to the global `fetch`. */
    fetch?: FetchLike;
    /** Per-request timeout. Defaults to 60s, because a fillet runs OCCT. */
    timeoutMs?: number;
    /**
     * How many times to retry a write that lost the project lock.
     *
     * A project write is serialised and answers 409 when another write holds it,
     * which a macro that batches shapes will meet routinely. Only that one 409 is
     * retried -- a locked *shape* also answers 409 and must not be.
     */
    retryOnBusy?: number;
    /** Extra headers, for a reverse proxy that wants its own. */
    headers?: Record<string, string>;
    /** Send this project revision as If-Match on every write request. */
    expectedRevision?: number | string;
};

TreatmentResult ​

type

ts
export type TreatmentResult = {
    shape: ShapeSummary;
    triangles: number;
    revision: number;
};

Treatments ​

class

ts
export declare class Treatments {
    private readonly transport;
    constructor(transport: Transport);
    /**
     * Rounds or cuts edges on the server, with OCCT.
     *
     * Treat every edge you want in one request where you can: OCCT refuses a
     * second treatment on edges adjacent to the first, because the surfaces there
     * are already tangent.
     */
    apply(projectId: string, shapeId: string, treatment: EdgeTreatment): Promise<TreatmentResult>;
    fillet(projectId: string, shapeId: string, radius: number, edges?: readonly number[]): Promise<TreatmentResult>;
    chamfer(projectId: string, shapeId: string, distance: number, options?: {
        angle?: number;
        edges?: readonly number[];
    }): Promise<TreatmentResult>;
}

WallThicknessEstimate ​

type

ts
export type WallThicknessEstimate = {
    minimum: number | null;
    unit: "mm";
    method: "sampled-opposing-surface-distance";
    samplesPerFace: number;
    facesChecked: number;
};

Sampled wall-thickness estimate; not a certified minimum-thickness result.


Documentation version: 1.30.0 · Repository revision: 1cb9fee8dff4d394684c229dd67a21da539d167f · View source