@dsptch-work/api-client 0.36.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,275 @@ All notable changes to `@dsptch-work/api-client` are documented here. The format
5
5
  [Semantic Versioning](https://semver.org) — currently `0.x`, so breaking changes may land in a
6
6
  minor bump until `1.0.0`. See [RELEASING.md](./RELEASING.md) for the release and versioning process.
7
7
 
8
+ ## [0.38.0] - 2026-10-15
9
+
10
+ ### Added
11
+
12
+ - New class `ProjectUserVisibilities`: `listUserVisibilities()`, `getUserVisibility()`,
13
+ `createUserVisibility()`, and `deleteUserVisibility()`, with operation types and Zod schemas.
14
+ Supply `path: { project_id }` for list/create and `path: { project_id, id }` for get/delete;
15
+ `id` is the visibility join ID. `ProjectUserVisibilityParameters` requires `user_id`, and
16
+ `ProjectUserVisibilityResponseObject` returns the join ID, project ID, user ID, and timestamps.
17
+ Grant `projects.user_visibilities:read`, `:create`, or `:delete` as appropriate. Access requires
18
+ the restricting owner's company key or a user key the owner issued to one of its admins;
19
+ the named user must be a manager, safety manager, or field lead of the owner. Other callers
20
+ that can read the project get an empty list, `404` on get/delete, and `403` on create. This
21
+ also applies to the owner's keys when visibility is not restricted. There is no update
22
+ method; deletion returns `204` with no body and preserves descendant projects' visibility rows.
23
+ - `FormSubmissionResponseObject` and `zFormSubmissionResponseObject` add required `id` to the
24
+ detail returned by `Forms.getFormSubmission()`. Add it to typed fixtures and custom validators.
25
+ - `FormDefinitionObject` and `zFormDefinitionObject` add required `submission_shape` to
26
+ `Forms.listFormDefinitions()` / `getFormDefinition()` responses. It describes the answers as an OpenAPI 3.0
27
+ schema, including object properties, array items, and choice descriptions; unanswered fields
28
+ may be absent or null. The generated type is `{ [key: string]: unknown }`, so narrow the
29
+ schema before inspecting it. Add the field to typed fixtures. File, signature, and matrix
30
+ questions are omitted, so the shape does not cover every submission field.
31
+
32
+ ### Changed
33
+
34
+ - **Breaking:** `ProductionJobScopePriceParameters`, `ProductionJobScopePriceUpdateParameters`,
35
+ and `ProductionJobScopePriceResponseObject` replace `unit_price` with `unit_price_cents`,
36
+ including their Zod schemas. Update `ProductionJobScopePrices.createJobScopePrice()` /
37
+ `updateJobScopePrice()` calls and read consumers. Send nonnegative decimal-string cents:
38
+ `'120000'` replaces the former dollar amount `'1200'`; fractional cents such as `'3.5'`
39
+ remain exact. The retired name returns `400 unknown_key`; JSON numbers and negative prices
40
+ return `422`. Price fields remain omitted for users without financial access.
41
+ - **Breaking at runtime:** `TimeEntries.createTimeEntry()` / `updateTimeEntry()` now require
42
+ explicit UTC offsets in `start_time` and `end_time`. Offset-free values, previously interpreted
43
+ in the pay schedule's time zone, now return `422 invalid_date`. Send `Z` or a numeric offset
44
+ such as `-04:00`; use the desired offset to select either occurrence of a repeated daylight
45
+ saving time. `TimeEntryCreateParameters` / `TimeEntryUpdateParameters` still use strings, so
46
+ TypeScript alone cannot catch missing offsets.
47
+ - **Breaking at runtime:** timestamp `filter[...][gte]` / `[lte]` bounds and `as_of[valid]` /
48
+ `as_of[transaction]` coordinates now require an explicit UTC offset. Date-only or offset-free
49
+ values return `422`; send `'2026-10-15T00:00:00Z'` for midnight UTC. Calendar-date filters
50
+ still accept date-only bounds. Generated query fields remain strings.
51
+ - **Breaking:** `TimecodeParameters`, `TimecodeGenesisParameters`, and
52
+ `TimecodeScheduledChangeParameters` now describe `effective_date` as a calendar date.
53
+ Send `'2026-10-15'` through `Timecodes.createTimecode()`, `shiftTimecodeGenesis()`, or
54
+ `scheduleTimecodeChange()`; a value containing a time of day returns `422`. The day starts
55
+ at midnight UTC, except that a scheduled change on the timecode's first day starts at its
56
+ existing beginning. The three corresponding Zod schemas now validate ISO dates.
57
+ `TimecodeCorrectionParameters.effective_from` / `effective_to`, used by
58
+ `Timecodes.updateTimecode()`, instead require date-times with explicit offsets; offset-free
59
+ bounds return `422 invalid_date`.
60
+ - **Breaking validation:** `zTimeEntryCreateParameters`, `zTimeEntryUpdateParameters`, and
61
+ `zTimecodeCorrectionParameters` now validate ISO date-times. These generated validators
62
+ accept UTC `Z` strings and reject numeric offsets, although the API accepts either; normalize
63
+ offset-bearing timestamps to UTC `Z` before validating them with these schemas.
64
+ - **Breaking at runtime:** `Users.updateUser()` returns `422` with field pointers when changing
65
+ an already verified `email`, `personal_email`, or `phone_number`, instead of silently keeping
66
+ the old value. Omit verified contacts or resend their current values; changes require the
67
+ user's confirmation. `UserUpdateParameters` is unchanged.
68
+ - **Breaking:** `AssetsItemParameters.purchase_date`, `AssetsItemUpdateParameters.purchase_date`,
69
+ and `ComplianceCheckParameters.time_due` now accept calendar dates, without a time of day.
70
+ Send `'2026-10-15'` through `AssetsItems.createItem()` / `updateItem()` or
71
+ `ComplianceChecks.updateCheck()`; timestamps now return `422`. Null clears the date and
72
+ omission retains it on update. The corresponding Zod schemas now validate ISO dates, while
73
+ the TypeScript fields remain `string | null`. Asset purchase-date responses remain nullable
74
+ ISO date-time strings; use their calendar date rather than echoing the full timestamp on write.
75
+ - **Breaking at runtime:** date parsing now rejects impossible calendar dates such as
76
+ `'2026-02-30'` with `422`, rather than rolling them into the next month.
77
+ Correct invalid date or timestamp values in bodies, date filters, and `as_of` coordinates;
78
+ method signatures are unchanged.
79
+ - **Breaking error handling:** `AssetsProducts.createProduct()` now returns `400 parameter_missing`
80
+ with pointer `#/type` when `type` is omitted, and `422 validation_failed` with that pointer
81
+ for an unsupported value or wrong JSON type. `AssetsItems.createItem()` / `updateItem()`
82
+ return `404`, rather than `422`, for an unknown or inaccessible newly assigned
83
+ `assets_product_id`. Handle these statuses through the existing generated error unions.
84
+
85
+ ### Fixed
86
+
87
+ - `AssetsFormAssignmentTriggers.createFormAssignmentTrigger()` / `updateFormAssignmentTrigger()`
88
+ now consistently store `assigned_user_ids: []` unless `assign_to` is `'custom'`, including
89
+ updates that omit `assign_to`. Supplied user IDs are checked before clearing them; an unseen
90
+ user returns `404` even for another assignment mode. The generated parameter types are unchanged.
91
+ - `AssetsFormAssignmentTriggers` writes now retain the requested `time_of_day_due` when a time
92
+ in the skipped hour is saved on the time zone's spring daylight saving transition day, rather than
93
+ permanently shifting the recurring due time forward an hour. Existing saved times and method
94
+ signatures are unchanged.
95
+ - `PwaTrades.createMerge()` now points a self-merge or different-owner refusal at
96
+ `#/target_trade_id`, and `People.createEmploymentScheduledChange()` points a refused
97
+ current/past change to an older segment at `#/effective_date`. Both remain
98
+ `422 validation_failed`; use `Problem.errors` to associate the error with the input.
99
+ - Conflicting placement fields in `AssetsItems.createItem()` now return `422 validation_failed`
100
+ with a pointer for every supplied placement field. Unseen placement sites, users, and containers
101
+ return `404`, including a former employee without a current role. Method signatures are unchanged.
102
+
103
+ See the [API changelog](https://dsptch.app/support/docs/developers/api-changelog#2026-10-15) for the
104
+ complete REST contract details and error behavior.
105
+
106
+ ## [0.37.0] - 2026-10-14
107
+
108
+ ### Added
109
+
110
+ - `Jobs` adds `listJobDocuments()`, `createJobDocument()`, `getJobDocument()`,
111
+ `updateJobDocument()`, and `deleteJobDocument()`, with corresponding operation types and Zod
112
+ schemas. Use `path: { job_id }` for list/create and `path: { job_id, id }` for the others.
113
+ `JobDocumentParameters` and `JobDocumentUpdateParameters` support an external `url` or an
114
+ uploaded `file`; supply exactly one source on create and retain exactly one after an update.
115
+ Although create's generated fields are optional, the server requires nonblank `type` and `name`.
116
+ Register files through `DirectUploads.createDirectUpload()` with
117
+ `DirectUploadParameters.resource: 'jobs.documents'`, then send its signed ID as `file`.
118
+ `JobDocumentResponseObject` exposes nullable `url` and `file` download metadata;
119
+ `JobDocumentsResponseObject` wraps the list, and `ListJobDocumentsData.query` accepts
120
+ `'filter[type]'`. PWA documents are always `admin_only`; callers without job financial access
121
+ cannot read them. Grant the appropriate `jobs.documents:read` / `:create` / `:update` / `:delete`
122
+ scope. Deletion resolves `204` with no body.
123
+ - `PositionParameters.pay_rates_rule_package_id` accepts a nullable package ID through
124
+ `Jobs.createPosition()` / `updatePosition()`. Choose a selectable package belonging to the path
125
+ job; an inaccessible, hidden, or other-job package returns `404`. Omit it on create to leave the
126
+ assignment unset, omit it on update to retain it, or send null to clear it. A cash-fringe package
127
+ on a non-PWA position returns `422`.
128
+ - `SiteCheckInResponseObject` and `zSiteCheckInResponseObject` add required nullable
129
+ `duration_minutes`, the elapsed whole minutes between check-in and check-out, rounded to the nearest minute. It is null until the
130
+ visitor checks out. Add the field to typed fixtures for `OversiteSiteCheckIns` reads.
131
+ - `TodoInboxTodoResponseObject` and `zTodoInboxTodoResponseObject` add required `priority`
132
+ (`'critical' | 'high' | 'medium' | 'low' | null`) and `category` (the same ten categories used by
133
+ compliance checks). `Todos.listTodoInbox()` now carries them on `kind: 'todo'` entries;
134
+ add both fields to typed fixtures. These are read fields, without new SDK write methods or
135
+ query filters.
136
+
137
+ ### Changed
138
+
139
+ - **Breaking:** `UserParameters`, `UserCompanyCreateParameters`,
140
+ `UserCompanyScheduledChangesParameters`, `UserCompanyScheduledChange`, and `UserResponseObject`
141
+ replace `hourly_rate`, `training_annual_amount`, `employer_combined_health_amount`, and
142
+ `employer_combined_savings` with the corresponding `_cents` fields. Update calls to
143
+ `Users.createUser()`, `createCompany()`, `createUserCompanyScheduledChange()`, and
144
+ `updateScheduledChange()` and consumers of user and scheduled-change responses. Send decimal
145
+ strings in cents: `hourly_rate_cents: '3250'` replaces `hourly_rate: '32.50'`.
146
+ Response values are decimal-string cents such as `'3250.0'`, without a currency symbol;
147
+ obtain the currency from `People.getEmployment()`. Omitted amounts remain unset on create
148
+ or unchanged on scheduled updates, null clears them, and `'0'` sets zero. Old dollar-field
149
+ names return `400 unknown_key`; corresponding Zod schemas now expose only the cents names.
150
+ - **Breaking:** `ProjectParameters` and `ProjectUpdateParameters` replace `budget` with
151
+ `budget_cents` for `Projects.createProject()` / `updateProject()`, including their Zod schemas.
152
+ Send `'123450'` for a budget of $1,234.50, rather than the former dollar string `'1234.50'`.
153
+ Null clears it and omission retains it on update. `budget` now returns `400 unknown_key`.
154
+ A budget, including null, still returns `422` while federal PWA tracking is off.
155
+ `ProjectResponseObject.budget_cents` and `budget_currency` are now optional nullable fields:
156
+ handle their absence when the caller cannot see project financials instead of assuming null.
157
+ - **Breaking:** `ApprenticeshipWageScheduleParameters` / `ApprenticeshipWageScheduleUpdateParameters`
158
+ make `journeyworker_wage_cents`, `journeyworker_fringe_cents`, and `end_wage_cents` decimal
159
+ strings. `ApprenticeshipWageSchedulePeriodParameters` /
160
+ `ApprenticeshipWageSchedulePeriodUpdateParameters`, including nested `periods_attributes`,
161
+ likewise make `wage_cents`, `fringe_cents`, `wage_percent`, and `fringe_percent` strings.
162
+ Update the `ApprenticeshipWageSchedules` and `ApprenticeshipWageSchedulePeriods` write calls
163
+ to send `'2800.5'` cents or `'62.5'` percent, or echo the string from a read. JSON numbers
164
+ now return `422` at the field pointer; nullable fringe fields still accept null.
165
+ The corresponding Zod schemas enforce nonnegative decimal strings.
166
+ - **Breaking:** `AssetsItemParameters.purchase_price_cents` and
167
+ `AssetsItemUpdateParameters.purchase_price_cents` change from `number | null` to
168
+ `string | null` for `AssetsItems.createItem()` / `updateItem()`. Send `'2800'` or `'2800.5'`,
169
+ or null to clear it. JSON numbers now return `422`; the corresponding Zod schemas enforce
170
+ nonnegative decimal strings. Purchase-price storage rounds beyond two decimal places in cents.
171
+ - **Breaking:** `PositionParameters` now requires decimal strings for `cash_fringe_rate_cents`,
172
+ `hourly_rate_cents`, `pwa_wage_pay_rate_cents`, and `wage_adder_rate_cents` in
173
+ `Jobs.createPosition()` / `updatePosition()`. `start_time` / `end_time` no longer accept null;
174
+ supply real `YYYY-MM-DD` dates or omit the keys to retain dates on update or leave a new
175
+ position unscheduled. A supplied `pwa_details_attributes` object requires
176
+ `skill_level: 'journeyman' | 'foreman' | null`; use `{ skill_level: null }` rather than `{}`.
177
+ Send `pwa` as a boolean and nonblank string IDs, using null to clear nullable references.
178
+ Use `zPositionParameters` to validate these forms locally.
179
+ - **Breaking:** `UserParameters` now types `enrolled_in_t_and_a` and `overtime_eligible` as
180
+ booleans, and `worked_annual_minutes`, `pto_annual_minutes`, `holiday_annual_minutes`, and
181
+ `training_annual_minutes` as nullable numbers instead of strings. Send whole-minute integers
182
+ and real booleans through `Users.createUser()`. `roles` no longer accepts null; omit it or
183
+ send `[]` to grant no roles, and send unique nonblank role strings. `company_user_pwa_info`
184
+ must be an object when supplied, without null. `zUserParameters` also checks nonblank names
185
+ and IDs and a date-only nullable `birth_date`. The old contact union is removed from the
186
+ generated type and schema, but the server still requires an email or phone unless
187
+ `skip_invite: true`; missing names return `400`, and invalid values return `422` with pointers.
188
+ Optional nullable profile fields now match accepted nulls. Omitted or null pay amounts now
189
+ remain unset rather than becoming zero. Send explicit '0' to designate zero: an unset
190
+ `training_annual_amount_cents` can fail the PWA designation check, and an unset
191
+ `hourly_rate_cents` can cause aggregate imports to return `HOURLY_RATE_NOT_FOUND` when no
192
+ position rate exists.
193
+ - **Breaking:** `JobCreateParameters` and `JobUpdateParameters` are standalone objects.
194
+ `created_by_user_id` is optional in the create type so template copies can inherit it; plain
195
+ creates still need a creator and requesting company. Job feature-allocation flags,
196
+ `job_work_types_attributes`, `job_address_attributes`, and address `verified` no longer accept
197
+ null; omit them to retain current values. `region` now accepts null.
198
+ `time_card_start_day` is a number, with `zJobCreateParameters` / `zJobUpdateParameters`
199
+ requiring an integer from 0 through 6. `Jobs.createJob()` / `updateJob()` now refuse wrong
200
+ JSON types and malformed nested fields with `422` pointers. Send lowercase PWA mode keys
201
+ (`'all'`, `'pw_only'`, `'ap_only'`, `'none'`), booleans for flags, nonblank IDs, and declared
202
+ nested keys. Null can still clear nullable schedule dates and references.
203
+ - **Breaking:** monetary write Zod schemas now reject malformed strings before submission,
204
+ matching server-side `422 validation_failed` errors with exact field pointers. Use plain
205
+ decimal strings with digits before the decimal point; blanks, whitespace, currency symbols,
206
+ scientific notation, and values such as `'.5'` are refused. This applies to employment pay,
207
+ time-entry and position rates, wage determinations, per diems, payroll amounts, project
208
+ budgets, asset prices, and production scope prices. Most values must be nonnegative;
209
+ `PaystubLineItemParameters.amount_cents` and `PositionParameters.pwa_wage_pay_rate_cents`
210
+ allow a leading minus. `RateRuleEffect.amount_cents` requires nonnegative whole-cent strings
211
+ such as `'300'`, without a decimal part. Handle these refusals through `Problem.errors`.
212
+ - **Breaking:** `PaystubLineItems.createPaystubLineItem()` / `updatePaystubLineItem()` enforce
213
+ the documented string `amount_cents`, nonblank reference IDs, and lowercase
214
+ `contributor: 'employee' | 'employer'`. JSON-number amounts now return `422`, and omitting any
215
+ of create's four required fields returns `400 parameter_missing`. Send decimal-string cents;
216
+ negative and fractional amounts remain supported. `zPaystubLineItemParameters` /
217
+ `zPaystubLineItemUpdateParameters` now validate the ID and money patterns.
218
+ - **Breaking:** `Users.createUser()`, `createCompany()`, `updateCompany()`,
219
+ `People.createEmployment()`, and `updateEmployment()` return `404` for a newly assigned
220
+ `manager_user_id` outside the key's visible people. Choose a visible manager. Employment
221
+ updates can still omit or resend an already held legacy manager; method signatures are unchanged.
222
+ - **Breaking:** `Users.removeUserFromCompany()` now requires
223
+ `headers: { 'If-Match': etag }` in `RemoveUserFromCompanyData`. Read the employment ID from
224
+ `UserResponseObject.employment_id`, then obtain its validator through
225
+ `People.listEmploymentHistory()` or, while a version covers now, `People.getEmployment()`.
226
+ A key without those read scopes may send `'*'` to delete whatever state exists.
227
+ `RemoveUserFromCompanyErrors` adds `412` and `428`: re-read after a stale validator and add
228
+ the header when it is missing. Success remains `200` with the user body.
229
+ - **Breaking at runtime:** `TimeEntries.createTimeEntry()` / `updateTimeEntry()` now interpret
230
+ `start_time` / `end_time` without an offset in the time card's pay schedule zone. If you mean
231
+ UTC, append `Z`; explicit `Z` or `±HH:MM` values retain their prior meaning. A bare date-time
232
+ now represents local wall time, including DST resolution and pay-period edge validation.
233
+ Request types remain strings, so TypeScript cannot catch a missing offset.
234
+ - **Breaking:** `CompetenciesAssessmentCriteria.listAssessmentCriteria()` /
235
+ `getAssessmentCriterion()` replace the assessment key-activity read methods. The new
236
+ `CompetencyAssessmentCriterionResponseObject` uses `competencies_criterion_id`.
237
+ `CompetenciesEvidenceItems.listEvidenceItems()` / `getEvidenceItem()` keep their method names
238
+ but replace `path.key_activity_id` with `path.criterion_id`; evidence responses replace
239
+ `competencies_assessment_key_activity_id` with `competencies_assessment_criterion_id`.
240
+ Grant `competencies.assessments.criteria:read` and
241
+ `competencies.assessments.criteria.evidence_items:read` in place of the retired key-activity
242
+ scopes. These reads remain available to companies with Competencies enabled.
243
+ `CompetencyCriterionParameters` / `CompetencyCriterionResponseObject` replace nullable
244
+ `assessment_method` with nonnullable `assessment_methods`, an array of the same eight method
245
+ values. Use `[]` for no suggested methods; corresponding Zod schemas follow the new shapes.
246
+
247
+ ### Removed
248
+
249
+ - **Breaking:** `JobParameters` and `zJobParameters` are removed. Import
250
+ `JobCreateParameters` / `zJobCreateParameters` or `JobUpdateParameters` /
251
+ `zJobUpdateParameters` for the owning write.
252
+ - **Breaking:** `PositionParameters.per_diem_rate_cents` is removed, including from
253
+ `zPositionParameters`; sending it now returns `400 unknown_key`. Select `per_diem_id`
254
+ instead, since the rate comes from that per diem.
255
+ - **Breaking:** `CompetenciesAssessmentKeyActivities`,
256
+ `CompetencyAssessmentKeyActivityResponseObject`, `ListAssessmentKeyActivities*`,
257
+ `GetAssessmentKeyActivity*`, and their corresponding Zod exports are removed. Migrate to
258
+ `CompetenciesAssessmentCriteria`, `CompetencyAssessmentCriterionResponseObject`,
259
+ `ListAssessmentCriteria*`, and `GetAssessmentCriterion*`.
260
+ - **Breaking:** `ProblemTypeCatalog` and `zProblemTypeCatalog` remove `non_numeric_cents`.
261
+ Delete that case from exhaustive switches and handle malformed money as `validation_failed`
262
+ with field pointers instead.
263
+
264
+ ### Fixed
265
+
266
+ - **Breaking response correction:** `AssetsItems.deleteDocument()` now resolves `204`
267
+ with no body. `DeleteDocumentResponses` replaces its `200: AssetsDocumentResponseObject`
268
+ arm with `204: void`, and `zDeleteDocumentResponse` validates void. Remove code that reads
269
+ the deleted document from the response; read it before deletion if needed.
270
+ - `DirectUploads.createDirectUpload()` now stores `resource: 'assets.items.documents'` uploads
271
+ on protected storage, matching the asset document attachment. Request and response types
272
+ stay unchanged; continue attaching the returned purpose-bound signed ID to an asset document.
273
+
274
+ See the [API changelog](https://dsptch.app/support/docs/developers/api-changelog#2026-10-14) for the
275
+ complete REST contract details and error behavior.
276
+
8
277
  ## [0.36.0] - 2026-10-13
9
278
 
10
279
  ### Added