platform-types 1.10.708 → 1.10.709

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.
@@ -180,6 +180,9 @@ exports.MAX_SERVICE_PICTURES = 20;
180
180
  * someone else wrote the ticket between your read and your write, and nothing
181
181
  * of yours was written. Refetch and let the operator retry against the new
182
182
  * state — the body that lost was built on the old one.
183
+ * `_EDIT_CHANGED` also answers a stale `expectedUpdatedAt`
184
+ * ({@link ServiceOrderRevisionFence}) and carries the current row as
185
+ * {@link ServiceOrderEditChangedRefusal}.
183
186
  * - `SERVICE_ORDER_ILLEGAL_TRANSITION` · 409 — the body is
184
187
  * {@link ServiceOrderIllegalTransitionRefusal}; its `allowed[]` is the menu to
185
188
  * offer instead.
@@ -1170,6 +1170,109 @@ declare global {
1170
1170
  message: string;
1171
1171
  allowed: readonly ServiceCustody[];
1172
1172
  }
1173
+ /**
1174
+ * Optional revision fence on `POST /services` `mode: 'edit'` and
1175
+ * `mode: 'diagnosis'` — request-only, never persisted or returned.
1176
+ *
1177
+ * Send the `updatedAt` of the {@link ServiceOrder} the operator REVIEWED
1178
+ * (from `GET /services/{id}`, a strong read; for a row carrying no
1179
+ * `updatedAt`, its `createdAt`). The write is refused `409
1180
+ * SERVICE_ORDER_EDIT_CHANGED` — body {@link ServiceOrderEditChangedRefusal},
1181
+ * nothing written — when `updatedAt` has moved since, both at the handler's
1182
+ * read and again at the commit. A refusal at the read uploads and deletes no
1183
+ * photo; one at the commit deletes none, but bytes already uploaded for new
1184
+ * photos stay in storage unreferenced.
1185
+ *
1186
+ * **What the fence sees.** `updatedAt` moves on every write of an
1187
+ * operator-entered field, and only those: every `POST /services` mode that
1188
+ * writes the row — `create`, `edit`, `diagnosis`, `hold`, `quote`, `parts`,
1189
+ * `worklog`, `timer` (the stop that books the hours), `deposit`, `status`
1190
+ * (including the delivery mint) and `disable`. It does NOT see system
1191
+ * bookkeeping that leaves `updatedAt` alone, deliberately so a phone is not
1192
+ * sent back to re-review for it: the appointment link
1193
+ * (`appointmentId`/`appointmentDate`/`appointmentTime`, written by
1194
+ * `/appointments`), the invoice stamp (`invoiceId`, written when a factura
1195
+ * settles or is rejected), and notification bookkeeping (`notifiedAt`,
1196
+ * appended by `status` and `renotify`). Those fields can differ from what the
1197
+ * client reviewed while its fenced write still succeeds.
1198
+ *
1199
+ * **Chained writes.** A follow-up write in the same submission — a diagnosis
1200
+ * then a photo edit — fences on the PREVIOUS write's success response,
1201
+ * `data.updatedAt`, never on the revision first reviewed: the first write
1202
+ * moved it, so echoing the original value refuses the second. Both success
1203
+ * bodies carry it — `diagnosis` returns the committed row, `edit` the row
1204
+ * with the `updatedAt` it committed.
1205
+ *
1206
+ * On `diagnosis` a TERMINAL ticket still answers its own codes first
1207
+ * (`SERVICE_ORDER_TERMINAL` at the read, `SERVICE_ORDER_STATUS_CHANGED` when
1208
+ * it closed mid-request), and the stored `diagnosedBy`/`diagnosedAt` stay
1209
+ * server-stamped.
1210
+ *
1211
+ * Absent means today's behaviour: the handler's own read is the lock (`edit`)
1212
+ * or no revision is asserted at all (`diagnosis`).
1213
+ */
1214
+ interface ServiceOrderRevisionFence {
1215
+ expectedUpdatedAt?: number;
1216
+ }
1217
+ /**
1218
+ * The `409 SERVICE_ORDER_EDIT_CHANGED` body of `POST /services`
1219
+ * `mode: 'edit'` and `mode: 'diagnosis'`. `data.current` is the stored row as
1220
+ * a strong read returns it now — without the read-time derivations
1221
+ * (`customer`, `depositBalance`, `slaStatus`); refetch the point read for
1222
+ * those.
1223
+ *
1224
+ * `data` is absent when the row could not be re-read (both modes), and on
1225
+ * `edit` also when the row no longer exists — refetch the point read. A
1226
+ * fenced `diagnosis` whose row is gone answers `SERVICE_ORDER_STATUS_CHANGED`
1227
+ * instead, as it does unfenced.
1228
+ */
1229
+ interface ServiceOrderEditChangedRefusal {
1230
+ error: 'SERVICE_ORDER_EDIT_CHANGED';
1231
+ message: string;
1232
+ data?: {
1233
+ current: ServiceOrder;
1234
+ };
1235
+ }
1236
+ /**
1237
+ * The body of `POST /services` `mode: 'diagnosis'`: it REPLACES the stored
1238
+ * `diagnosis` whole. `diagnosedBy`/`diagnosedAt` are not accepted — the api
1239
+ * stamps the authorizer user and the server time. Success answers the
1240
+ * committed {@link ServiceOrder} as `data`.
1241
+ *
1242
+ * Tied to the handler's schema by `AssertServiceOrderDiagnosisRequestMatchesSchema`
1243
+ * (`stacks/lambdas/services/_diagnosis.ts`).
1244
+ */
1245
+ interface ServiceOrderDiagnosisRequest extends ServiceOrderRevisionFence {
1246
+ mode: 'diagnosis';
1247
+ serviceOrderId: string;
1248
+ /** Internal technician notes, 1–4000 characters. Operator-only. */
1249
+ notes: string;
1250
+ /** What was actually wrong, as told to the customer — at most 4000 characters. */
1251
+ faultFound?: string;
1252
+ }
1253
+ /**
1254
+ * The photo-only body of `POST /services` `mode: 'edit'` — the edit a
1255
+ * technician's phone sends. The mode accepts more fields; this names only the
1256
+ * photo half, so a client typed on it cannot send anything else by accident.
1257
+ *
1258
+ * `pictures` ABSENT means "don't touch", `[]` means "clear"; it is the WHOLE
1259
+ * array, at most {@link MAX_SERVICE_PICTURES} entries. An entry with `base64`
1260
+ * is a new upload (its `url` is a placeholder the api replaces); one without
1261
+ * is a pointer to a photo already on THIS ticket, and may not change its
1262
+ * `stage`. `removePictures` names stored photos to delete after the commit.
1263
+ * Success answers the updated {@link ServiceOrder} as `data`.
1264
+ *
1265
+ * Tied to the handler's schema by `AssertServiceOrderEditPicturesRequestMatchesSchema`
1266
+ * (`stacks/lambdas/services/_edit.ts`).
1267
+ */
1268
+ interface ServiceOrderEditPicturesRequest extends ServiceOrderRevisionFence {
1269
+ mode: 'edit';
1270
+ serviceOrderId: string;
1271
+ pictures?: ServiceOrderPicture[];
1272
+ removePictures?: {
1273
+ url: string;
1274
+ }[];
1275
+ }
1173
1276
  }
1174
1277
  /**
1175
1278
  * The legal moves on a service order. Exhaustive over `ServiceStatus` by
@@ -1294,6 +1397,9 @@ export declare const MAX_SERVICE_PICTURES = 20;
1294
1397
  * someone else wrote the ticket between your read and your write, and nothing
1295
1398
  * of yours was written. Refetch and let the operator retry against the new
1296
1399
  * state — the body that lost was built on the old one.
1400
+ * `_EDIT_CHANGED` also answers a stale `expectedUpdatedAt`
1401
+ * ({@link ServiceOrderRevisionFence}) and carries the current row as
1402
+ * {@link ServiceOrderEditChangedRefusal}.
1297
1403
  * - `SERVICE_ORDER_ILLEGAL_TRANSITION` · 409 — the body is
1298
1404
  * {@link ServiceOrderIllegalTransitionRefusal}; its `allowed[]` is the menu to
1299
1405
  * offer instead.
@@ -177,6 +177,9 @@ export const MAX_SERVICE_PICTURES = 20;
177
177
  * someone else wrote the ticket between your read and your write, and nothing
178
178
  * of yours was written. Refetch and let the operator retry against the new
179
179
  * state — the body that lost was built on the old one.
180
+ * `_EDIT_CHANGED` also answers a stale `expectedUpdatedAt`
181
+ * ({@link ServiceOrderRevisionFence}) and carries the current row as
182
+ * {@link ServiceOrderEditChangedRefusal}.
180
183
  * - `SERVICE_ORDER_ILLEGAL_TRANSITION` · 409 — the body is
181
184
  * {@link ServiceOrderIllegalTransitionRefusal}; its `allowed[]` is the menu to
182
185
  * offer instead.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platform-types",
3
- "version": "1.10.708",
3
+ "version": "1.10.709",
4
4
  "description": "Shared wire and entity contracts for the platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",