Common types#

Scalar types, string unions and small object shapes that several calls and records share. Every one of them is exported as a type from plen-js.

Id#

The id of a task, link, calendar, resource, assignment, slot or candidate.

type Id = string | number;

Ids compare the way JavaScript object keys do, so 7 and "7" name the same object. Numeric ids are plain numbers: an integer above Number.MAX_SAFE_INTEGER loses precision, so pass 64-bit ids as strings. Results return each id in the type it was passed in.

const ids = [1, "1", "task-7", 2.5]; // the first two name the same object

Used wherever a record or option refers to an object: id, parent, source, target, task, resource, calendar_id, and the id lists in results. See Numbers and ids.

DateValue#

A date and time of day, as a string or a Date.

type DateValue = string | Date;
Direction Form
Input string YYYY-MM-DD, with an optional HH:MM or HH:MM:SS after a space or a T. A bare date means 00:00. Seconds are dropped.
Input Date Read from its local components (year, month, day, hour, minute). Seconds and milliseconds are dropped.
Output A "YYYY-MM-DD HH:MM" string. A local Date when the project was created with dates: "date".

Dates have no timezone: every value is local wall-clock time at minute precision.

const starts = ["2026-03-02", "2026-03-02 08:00", "2026-03-02T08:00:30", new Date(2026, 2, 2, 8, 0)];
// read as 2026-03-02 00:00, then 2026-03-02 08:00 three times

An unparseable string throws InputError with kind: "validation" and message "invalid date". An invalid Date throws InputError with message "Invalid Date".

Used by task and constraint dates, config.project_start / project_end, profile and leveling ranges, and every date in a result. See Plain objects and dates.

TimeUnit#

The unit of a duration, a lag, a leveling delay or a pause.

type TimeUnit = "minute" | "hour" | "day";

"week", "month" and "year" are reserved and throw InputError with kind: "validation". In the elapsed fields leveling_delay and pauses, an hour is 60 minutes and a day is 24 hours.

Used by SchedulingConfig.duration_unit (default "day"), TaskData.duration_unit and LinkData.lag_unit.

ConstraintType#

A task's scheduling constraint. Values match in any case, so "SNET" is accepted.

type ConstraintType = "asap" | "alap" | "snet" | "snlt" | "fnet" | "fnlt" | "mso" | "mfo";
Value Constraint Needs constraint_date
"asap" As soon as possible no
"alap" As late as possible no
"snet" Start no earlier than yes
"snlt" Start no later than yes
"fnet" Finish no earlier than yes
"fnlt" Finish no later than yes
"mso" Must start on yes
"mfo" Must finish on yes

Any other string throws InputError with kind: "validation". Used by TaskData.constraint_type, TaskUpdate.constraint_type and the constraint-violation conflict. How constraints act is in Links, constraints and summaries.

ResourceData#

A resource that assignments book.

interface ResourceData { id: Id; capacity?: number | null; calendar_id?: Id | null }
Field Type Default Description
id Id required Resource id.
capacity number | null config.default_resource_capacity (1) Units the resource carries per bucket, in assignment value units (1 = 100 %). Finite and >= 0.
calendar_id Id | null none The resource's calendar. With calendar_mode: "resource" it must name a calendar in ProjectData.calendars.

Unknown fields are ignored. An invalid capacity throws InputError with kind: "validation" at resources[i].capacity; an unknown calendar_id at resources[i].calendar_id.

Used by ProjectData.resources and resources.add in SchedulingChanges. An edit to an existing resource is a ResourceUpdate. How resource calendars work is in Working time and calendars.

LinkAdd#

A new link in links.add of a change set: a LinkData whose id is optional.

type LinkAdd = Omit<LinkData, "id"> & { id?: Id | null };

A link without an id (or with id: null) gets a generated one. Used by SchedulingChanges.links.add.

LinkUpdate, ResourceUpdate, AssignmentUpdate#

Partial records in the update arrays of a change set: id is required, every other field of the base record is optional.

type LinkUpdate = Partial<LinkData> & { id: Id };
type ResourceUpdate = Partial<ResourceData> & { id: Id };
type AssignmentUpdate = Partial<AssignmentData> & { id: Id };
Type Base record Used by
LinkUpdate LinkData links.update
ResourceUpdate ResourceData resources.update
AssignmentUpdate AssignmentData assignments.update

All three go in SchedulingChanges. A task edit is a TaskUpdate.

Pause#

One leveling split in a task's work.

interface Pause { at: number; length: number; by?: "leveling" }
Field Type Default Description
at number required Start of the pause after the task start. Elapsed time in the task's duration_unit, finite and >= 0.
length number required Length of the pause. Elapsed time in the task's duration_unit, finite and > 0.
by "leveling" absent Who wrote the pause. "leveling" is the only value; the leveler sets it on every pause it writes.

A pause occupies the whole minutes from round(at) to round(at + length). A pause that rounds to zero length is ignored. Unknown fields are ignored.

Used by TaskData.pauses, TaskUpdate.pauses and Mutation.pauses. How pauses affect dates and load is in Leveling resources.

Subtree#

Limits a run to one task's subtree and the tasks that depend on it.

interface Subtree { task: Id; inclusive?: boolean }
Field Type Default Description
task Id required Root task of the branch. Must be a known, scheduled task.
inclusive boolean true Whether the root task itself is scheduled. null reads as true.

Unknown fields throw InputError with kind: "parse". An unknown or unscheduled task throws InputError with kind: "validation" at subtree.task.

Used by SolveOptions.subtree and PreviewOptions.subtree. See Reschedule a branch.

AnalyticsOptions#

Requests analytics in a result.

interface AnalyticsOptions { slack?: boolean; criticalPath?: boolean }
Field Type Default Description
slack boolean false true fills analytics.slack: total and free slack per task, in config.duration_unit.
criticalPath boolean false true fills analytics.criticalPath: critical task and link ids.

null reads as false. Unknown fields throw InputError with kind: "parse". The filled shape is Analytics.

Used by SolveOptions.analytics, PreviewOptions.analytics and AnalyzeOptions.analytics. See Critical path and slack.

ProfileQuery#

The range, resources and detail a load profile covers.

interface ProfileQuery {
  from: DateValue;
  to: DateValue;
  resources?: Id[];
  basis?: "hour" | "day";
  tasks?: "none" | "overallocated" | "all";
}
Field Type Default Description
from DateValue required Range start. Buckets whose start lies in [from, to) are reported.
to DateValue required Range end, after from.
resources Id[] every resource Resources to report.
basis "hour" | "day" derived from config.duration_unit Bucket size: "day" for a "day" unit, "hour" for "hour" and "minute".
tasks "none" | "overallocated" | "all" "none" Task ids per bucket: none (the field is absent), only in buckets where load exceeds capacity, or every booked task. null reads as "none".

Unknown fields throw InputError with kind: "parse". These throw InputError with kind: "validation":

  • to not after from, or more than 100 000 buckets per resource, at to
  • an unknown resource id, at resources
  • any other tasks value

Used by PreviewOptions.profile. LoadProfileOptions takes the same fields flat, next to baselineId. The result is a LoadProfile. See Resource load.

RejectedOperation#

An operation of a change set that was refused.

interface RejectedOperation { path: string; message: string }
Field Type Description
path string The refused operation, e.g. "tasks.update[0]".
message string Why the operation was refused.

Used by ApplyReport.rejected and CandidateResult.error. See Recover from rejected changes.