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
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
ALIGN_AXES: readonly ["x", "y", "z"]ALIGN_TARGETS
value
ALIGN_TARGETS: readonly ["min", "center", "max"]AlignAxis
type
export type AlignAxis = (typeof ALIGN_AXES)[number];x is left/right, z front/back, y bottom/top.
AlignRequest
type
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
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
export type AlignTarget = (typeof ALIGN_TARGETS)[number];Which edge or centre of each shape to line up.
AnyKindFields
type
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
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
export type ApiErrorCode = (typeof API_ERROR_CODES)[number];ApiErrorContext
type
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
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
BASE_URL_ENV = "SKETCHFORGE_URL"BooleanCutRequest
type
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
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
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
export declare function buildUrl(root: string, path: string, query?: Record<string, string | undefined>): string;centeredOffsets
function
export declare function centeredOffsets(count: number, spacing: number): number[];chunk
function
export declare function chunk<Item>(items: readonly Item[], size: number): Item[][];clientFromEnvironment
function
export declare function clientFromEnvironment(environment?: Environment, overrides?: Partial<SketchForgeClientOptions>): SketchForgeClient;DEFAULT_BASE_URL
value
DEFAULT_BASE_URL = "http://127.0.0.1:3000"defineMacro
function
export declare function defineMacro<Params extends Record<string, MacroParameterValue>>(definition: MacroDefinition<Params>): MacroDefinition<Params>;DeleteResult
type
export type DeleteResult = {
deleted: true;
id: string;
revision?: number;
};Distribute
class
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
DISTRIBUTE_SPACINGS: readonly ["gaps", "centers"]DistributeRequest
type
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
export type DistributeResult = {
moved: number;
axis: "x" | "z";
spacing: DistributeSpacing;
shapes: ShapeSummary[];
revision: number;
};DistributeSpacing
type
export type DistributeSpacing = (typeof DISTRIBUTE_SPACINGS)[number];gaps leaves equal clear space; centers puts the centres at an equal pitch.
Drawings
class
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
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
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
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
export type Environment = Record<string, string | undefined>;Explosions
class
export declare class Explosions {
private readonly transport;
constructor(transport: Transport);
explode(projectId: string, shapeId: string): Promise<ShapeWriteResult>;
}EXPORT_VIEWS
value
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
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
export type ExportSection = {
plane: SectionPlane;
offset: number;
};Section contours cut by one axis plane, at offset millimetres along its omitted axis.
ExportSkippedShape
type
export type ExportSkippedShape = {
name: string;
kind: string;
reason: string;
};A shape a STEP export left out, and why.
ExportView
type
export type ExportView = (typeof EXPORT_VIEWS)[number];FACE_DIRECTIONS
value
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
export type FaceDirection = (typeof FACE_DIRECTIONS)[number];Faces
class
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
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
export type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;GearKindType
type
export type GearKindType = "spur" | "helical" | "bevel";grid
function
export declare function grid(columns: number, rows: number, spacing: {
x: number;
z: number;
}, center?: Point2): Point2[];GroupResult
type
export type GroupResult = {
shape: ShapeSummary;
revision: number;
};The new group, which replaces its members; members marked hole are subtracted.
Groups
class
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
IMPORTABLE_MESH_FORMATS: readonly ["stl", "obj", "svg"]Imports
class
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
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
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
export type InterferenceRequest = {
ids?: readonly string[];
clearance?: number;
};ListPage
type
export type ListPage<Item> = {
items: Item[];
nextCursor: string | null;
};ListPageOptions
type
export type ListPageOptions = {
limit?: number;
cursor?: string;
};LoftProfileShape
type
export type LoftProfileShape = "Oval" | "Rectangle" | "Triangle" | "Pentagon" | "Hexagon";MacroContext
type
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
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
export declare function macroFromModule(module: unknown, fallbackName: string): MacroDefinition<Record<string, MacroParameterValue>>;macroLayout
value
macroLayout: {
readonly centeredOffsets: typeof centeredOffsets;
readonly grid: typeof grid;
readonly mm: typeof mm;
readonly ring: typeof ring;
readonly row: typeof row;
}MacroLayout
type
export type MacroLayout = typeof macroLayout;MacroParameterValue
type
export type MacroParameterValue = number | string | boolean;MacroProjectMode
type
export type MacroProjectMode = "fresh" | "replace" | "reuse" | "target";MacroProjectSpec
type
export type MacroProjectSpec = MacroProjectMode | {
mode: MacroProjectMode;
/** The project's name. `fresh` appends a stamp to it. */
name?: string;
};MacroRunReport
type
export type MacroRunReport = {
macro: string;
projectId: string;
projectCreated: boolean;
shapesCleared: number;
shapeCount: number;
durationMs: number;
result: unknown;
};MAX_DIMENSION
value
MAX_DIMENSION = 10000MAX_PATTERN_COUNT
value
MAX_PATTERN_COUNT = 200MAX_SHAPES_PER_REQUEST
value
MAX_SHAPES_PER_REQUEST = 200One POST may carry at most this many shapes.
MEASUREMENT_ANGLE_UNAVAILABLE_CODES
value
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
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
MEASUREMENT_ENTITIES: readonly ["edge", "face"]The entities a measurement listing reports, one entry each.
MEASUREMENT_RADIUS_UNAVAILABLE_CODES
value
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
export type MeasurementAngleUnavailableCode = (typeof MEASUREMENT_ANGLE_UNAVAILABLE_CODES)[number];MeasurementEnd
type
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
export type MeasurementEndEntity = (typeof MEASUREMENT_END_ENTITIES)[number];MeasurementEntity
type
export type MeasurementEntity = (typeof MEASUREMENT_ENTITIES)[number];MeasurementPair
type
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
export type MeasurementRadiusUnavailableCode = (typeof MEASUREMENT_RADIUS_UNAVAILABLE_CODES)[number];Measurements
class
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
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
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
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
export type MeshImportResult = TreatmentResult;The same three fields a treatment answers with; an import is one more of them.
MIN_DIMENSION
value
MIN_DIMENSION = 0.01Dimensions outside this range are clamped by the server rather than refused.
MIN_PATTERN_COUNT
value
MIN_PATTERN_COUNT = 2MirrorAxis
type
export type MirrorAxis = "x" | "y" | "z";Mirrors
class
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
export declare class MissingConfigurationError extends Error {
constructor(message: string);
}mm
function
export declare function mm(value: number): number;normalizeBaseUrl
function
export declare function normalizeBaseUrl(baseUrl: string): string;PARAMETRIC_SHAPE_KINDS
value
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
export type ParametricShapeKind = (typeof PARAMETRIC_SHAPE_KINDS)[number];ParametricShapeRequest
type
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
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
PATTERN_KINDS: readonly ["linear", "circular"]PatternKind
type
export type PatternKind = (typeof PATTERN_KINDS)[number];PatternRequest
type
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
export type PatternResult = {
/** How many copies were added, which is `count` minus the original. */
created: number;
kind: PatternKind;
shapes: ShapeSummary[];
revision: number;
};Patterns
class
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
export type Point2 = {
x: number;
z: number;
};ProfilePoint
type
export type ProfilePoint = readonly [number, number];A point of a revolve outline: [distance from the axis, position along it].
PROJECT_ENV
value
PROJECT_ENV = "SKETCHFORGE_PROJECT_ID"PROJECT_EXPORT_FORMATS
value
PROJECT_EXPORT_FORMATS: readonly ["stl", "obj", "3mf", "step", "skf", "zip", "svg", "dxf"]Every format POST /exports produces, in the server's order.
ProjectDetail
type
export type ProjectDetail = {
id: string;
name: string;
createdAt: number;
snapGrid: ProjectSnapGrid;
workspace: Record<string, unknown>;
shapes: ShapeSummary[];
};ProjectExportArtifact
type
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
export type ProjectExportFormat = (typeof PROJECT_EXPORT_FORMATS)[number];ProjectExportRequest
type
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
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
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
export type ProjectSnapGrid = {
enabled?: boolean;
size?: number;
} & Record<string, unknown>;ProjectSummary
type
export type ProjectSummary = {
id: string;
name: string;
/** How many shapes the project holds. */
shapes: number;
revision: number;
updatedAt: number;
packageBytes: number;
};Properties
class
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
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
export type ResolvedMacroProject = {
project: ProjectHandle;
summary: ProjectSummary | null;
created: boolean;
cleared: number;
};resolveMacroParams
function
export declare function resolveMacroParams<Params extends Record<string, MacroParameterValue>>(defaults: Params | undefined, overrides: Record<string, string>): Params;resolveMacroProject
function
export declare function resolveMacroProject(client: SketchForgeClient, spec: MacroProjectSpec, options: {
fallbackName: string;
targetProjectId?: string | undefined;
now?: Date;
}): Promise<ResolvedMacroProject>;RevolveSettings
type
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
export type RevolveShapeRequest = {
kind: "revolve";
profile: readonly ProfilePoint[];
} & RevolveSettings & ShapePlacement;RevolveSummary
type
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
export declare function ring(count: number, radius: number, options?: {
center?: Point2;
startAngle?: number;
}): Point2[];row
function
export declare function row(count: number, spacing: number, center?: Point2): Point2[];runMacro
function
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
export declare function runStamp(now?: Date): string;SECTION_PLANES
value
SECTION_PLANES: readonly ["xy", "xz", "yz"]Axis-aligned section planes in the CAD drawing's Z-up coordinates.
SectionDrawingArtifact
type
export type SectionDrawingArtifact = {
filename: string;
mimeType: "image/svg+xml";
bytes: number;
shapeCount: number;
svg: string;
};SectionDrawingRequest
type
export type SectionDrawingRequest = {
plane: SectionPlane;
/** Coordinate of the plane's omitted axis, in millimetres. */
offset: number;
shapeIds?: readonly string[];
name?: string;
};SectionDxfArtifact
type
export type SectionDxfArtifact = {
filename: string;
mimeType: "application/dxf";
bytes: number;
shapeCount: number;
dxf: string;
};SectionPlane
type
export type SectionPlane = (typeof SECTION_PLANES)[number];ShapeDimensions
type
export type ShapeDimensions = {
width?: number;
depth?: number;
height?: number;
/** Stands in for all three, which is what `cube` is for. */
size?: number;
};ShapeGeometryProvenance
type
export type ShapeGeometryProvenance = {
source: "parametric" | "brep" | "mesh";
precision: "exact" | "tessellated";
};Which stored representation supplied the solid to the CAD kernel.
ShapeKind
type
export type ShapeKind = ParametricShapeKind | "revolve" | "thread" | "sketchSweep";Every kind a shape request may name, including the two swept ones.
ShapePatch
type
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
export declare function shapePatchFromSummary(summary: ShapeSummary, changes?: ShapePatch): ShapePatch;ShapePatchResult
type
export type ShapePatchResult = {
shape: ShapeSummary;
revision: number;
};ShapePlacement
type
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
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
export type ShapeRequest = ParametricShapeRequest | RevolveShapeRequest | ThreadShapeRequest | SketchSweepShapeRequest;Shapes
class
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
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
export type ShapeWriteResult = {
shapes: ShapeSummary[];
revision: number;
};Shell
class
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
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
export type ShellResult = TreatmentResult;The same three fields a treatment answers with; hollowing is one more of them.
SketchFaceDraft
type
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
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
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
export type SketchForgeClientOptions = TransportOptions;SketchForgeTransportError
class
export declare class SketchForgeTransportError extends Error {
readonly method: string;
readonly url: string;
constructor(method: string, url: string, cause: unknown);
}SketchOperation
type
export type SketchOperation = "extrude" | "revolve" | "loft" | "sweep";The operation a shape's geometry came out of, for the ones that have one.
SketchSweepPoint
type
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
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
export type SketchSweepShapeRequest = {
kind: "sketchSweep";
profile: SketchSweepProfile;
} & ShapePlacement;A retained OCCT sweep made from closed section loops and one open spine.
StepAssemblyNode
type
export type StepAssemblyNode = {
id?: string;
name: string;
children: StepAssemblyNode[];
};A named STEP product and its nested component occurrences.
StepAssemblyPathNode
type
export type StepAssemblyPathNode = {
id?: string;
name: string;
};StepComponent
type
export type StepComponent = {
id: string;
occurrenceId: string;
path: StepAssemblyPathNode[];
};TaperFields
type
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
export declare function targetProjectFromEnvironment(environment?: Environment): string | undefined;Thickness
class
export declare class Thickness {
private readonly transport;
constructor(transport: Transport);
estimate(projectId: string, shapeId: string): Promise<WallThicknessEstimate>;
}THREAD_DESIGNATIONS
value
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
export type ThreadDesignation = (typeof THREAD_DESIGNATIONS)[number];ThreadShapeRequest
type
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
TOKEN_ENV = "SKETCHFORGE_API_TOKEN"Transport
class
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
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
export type TreatmentResult = {
shape: ShapeSummary;
triangles: number;
revision: number;
};Treatments
class
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
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