@synapticon/motion-master-client 6.0.0-alpha.69 → 6.0.0-alpha.71

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.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The one place that knows how a failed request from the generated client is shaped.
3
+ *
4
+ * `swagger-typescript-api`'s client does not throw an `Error`. On a non-2xx it throws its own
5
+ * `HttpResponse` object, having parsed the response body into that object's `error` property — and
6
+ * Motion Master's own error body is `{ "error": "<message>" }`. So the message a user should see
7
+ * sits at `err.error.error`, two levels down, and reading one level yields the string
8
+ * `"[object Object]"`.
9
+ *
10
+ * That is not a shape any caller should have to know, which is the whole reason this lives here: the
11
+ * wrapping belongs to the generated client, the generated client belongs to this package, so the
12
+ * unwrapping belongs here too rather than being rediscovered in every page that catches a request.
13
+ */
14
+ /**
15
+ * The human-readable reason a request failed.
16
+ *
17
+ * Tries, in order: the server's own message (`{ error }`, at either nesting level), the HTTP status,
18
+ * a thrown `Error`'s message, and finally `fallback`. The server message comes first because it is
19
+ * the only one that says anything specific — Motion Master's node layer writes these, and they name
20
+ * the object, the state, or the grammar that was wrong.
21
+ *
22
+ * @param err Whatever was caught.
23
+ * @param fallback Returned when nothing usable can be found.
24
+ */
25
+ export declare function apiErrorMessage(err: unknown, fallback?: string): string;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The one place that knows how a failed request from the generated client is shaped.
3
+ *
4
+ * `swagger-typescript-api`'s client does not throw an `Error`. On a non-2xx it throws its own
5
+ * `HttpResponse` object, having parsed the response body into that object's `error` property — and
6
+ * Motion Master's own error body is `{ "error": "<message>" }`. So the message a user should see
7
+ * sits at `err.error.error`, two levels down, and reading one level yields the string
8
+ * `"[object Object]"`.
9
+ *
10
+ * That is not a shape any caller should have to know, which is the whole reason this lives here: the
11
+ * wrapping belongs to the generated client, the generated client belongs to this package, so the
12
+ * unwrapping belongs here too rather than being rediscovered in every page that catches a request.
13
+ */
14
+ /**
15
+ * The human-readable reason a request failed.
16
+ *
17
+ * Tries, in order: the server's own message (`{ error }`, at either nesting level), the HTTP status,
18
+ * a thrown `Error`'s message, and finally `fallback`. The server message comes first because it is
19
+ * the only one that says anything specific — Motion Master's node layer writes these, and they name
20
+ * the object, the state, or the grammar that was wrong.
21
+ *
22
+ * @param err Whatever was caught.
23
+ * @param fallback Returned when nothing usable can be found.
24
+ */
25
+ export function apiErrorMessage(err, fallback = 'Unknown error') {
26
+ if (typeof err === 'object' && err !== null) {
27
+ const candidate = err;
28
+ // The generated client's HttpResponse: the parsed body sits in `error`.
29
+ if (typeof candidate.error === 'object' && candidate.error !== null) {
30
+ const body = candidate.error;
31
+ if (typeof body.error === 'string' && body.error !== '') {
32
+ return body.error;
33
+ }
34
+ }
35
+ // A body handed over directly, or an already-unwrapped one.
36
+ if (typeof candidate.error === 'string' && candidate.error !== '') {
37
+ return candidate.error;
38
+ }
39
+ // No body to read — a network failure, or a response with no JSON. The status is what is left,
40
+ // and it is still more use than a generic sentence.
41
+ if (typeof candidate.status === 'number') {
42
+ const statusText = typeof candidate.statusText === 'string' && candidate.statusText !== ''
43
+ ? ` ${candidate.statusText}`
44
+ : '';
45
+ return `HTTP ${candidate.status}${statusText}`;
46
+ }
47
+ }
48
+ if (err instanceof Error && err.message !== '') {
49
+ return err.message;
50
+ }
51
+ return fallback;
52
+ }
@@ -1,4 +1,4 @@
1
- import { AlStatusCode, BrakeState, Cia402Status, DcSyncStatus, DeviceDiagnostics, DeviceFile, DeviceParameter, EscRegister, EsiParseResult, FirmwarePackageName, FoeErrorCode, GameLoopHealth, HrdRecording, MailboxErrorCode, Monitoring, ObjectDataTypeInfo, OutputStageResult, ParameterCacheEntry, PdoMapping, PdoMappingRequest, ProcedureListing, ProcedureRequest, ProcedureSnapshot, ProcessDataWatchdog, ProcessImageObject, SdoAbortCode, SlaveConfig, SlaveInformationInterface, UserCacheListing } from "./data-contracts.js";
1
+ import { AlStatusCode, BrakeState, Cia402Status, DcSyncStatus, DeviceDiagnostics, DeviceFile, DeviceParameter, EscRegister, EsiParseResult, FirmwareCompatibility, FirmwarePackageName, FoeErrorCode, GameLoopHealth, HardwareDescription, HrdRecording, IntegroVariant, IntegroVariantOption, MailboxErrorCode, Monitoring, ObjectDataTypeInfo, OperationModes, OutputStageResult, ParameterCacheEntry, PdoMapping, PdoMappingRequest, ProcedureListing, ProcedureRequest, ProcedureSnapshot, ProcessDataWatchdog, ProcessImageObject, SdoAbortCode, SlaveConfig, SlaveInformationInterface, UserCacheListing } from "./data-contracts.js";
2
2
  import { HttpClient, RequestParams } from "./http-client.js";
3
3
  export declare class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
4
4
  /**
@@ -396,6 +396,52 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
396
396
  * @request GET:/api/meta/sdo-abort-codes
397
397
  */
398
398
  getSdoAbortCodes: (params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<SdoAbortCode[], any>>;
399
+ /**
400
+ * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table. Each entry carries the width, the access type, whether the encoder actually implements it — seven are documented but not implemented — and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` is false for the one 64-bit register, since the command's length byte caps at 4 bytes.
401
+ *
402
+ * @name GetKueblerRegisters
403
+ * @summary The Integro internal encoder's register map
404
+ * @request GET:/api/meta/kuebler-registers
405
+ */
406
+ getKueblerRegisters: (params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<{
407
+ /**
408
+ * Register address, as OS command 19 carries it.
409
+ * @example 48
410
+ */
411
+ address: number;
412
+ /**
413
+ * Width in bits — 8, 16, 32, or 64.
414
+ * @example 32
415
+ */
416
+ bits: number;
417
+ /**
418
+ * The vendor's own name for the register.
419
+ * @example "Absolute position ST"
420
+ */
421
+ name: string;
422
+ /** @example "ro" */
423
+ access: "ro" | "wo" | "rw";
424
+ /**
425
+ * Whether the encoder implements it, per the vendor's draft.
426
+ * @example true
427
+ */
428
+ implemented: boolean;
429
+ /**
430
+ * How to read the assembled value.
431
+ * @example "unsigned"
432
+ */
433
+ format: "unsigned" | "signed" | "bitField" | "signedHalves";
434
+ /**
435
+ * The vendor's bit definitions, clauses joined with "; ".
436
+ * @example "Left aligned 32 bit singleturn position"
437
+ */
438
+ definition: string;
439
+ /**
440
+ * False only for the 64-bit register, which exceeds the command's 4-byte length field.
441
+ * @example true
442
+ */
443
+ readableInOneCommand: boolean;
444
+ }[], any>>;
399
445
  /**
400
446
  * @description Returns the static catalogue of CoE mailbox error codes defined in ETG.1000.4, Table 30 ("Error Reply Service Data"). A slave returns one of these when the mailbox layer (below a specific protocol such as CoE/FoE) rejects a transfer; the code is embedded in the error text the mailbox endpoints return.
401
447
  *
@@ -616,7 +662,15 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
616
662
  */
617
663
  getCia402Status: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<Cia402Status, void>>;
618
664
  /**
619
- * @description Writes the requested operation mode to 0x6060 and returns the resulting control snapshot. The drive reflects the accepted mode in 0x6061 (the modeOfOperation of the response) once it takes effect.
665
+ * @description Every operation mode the device has, standard and manufacturer-specific, with what the drive says about each. The standard modes are CiA402's (ETG.6010 §6.8.1) and carry the bit of "Supported drive modes" (0x6502) that advertises them, decoded into `supported`. The manufacturer modes are the vendor's own — the negative half of 0x6060 — and are listed only for a device whose vendor this server knows; their `supported` is null, because 0x6502 reserves bits 16-31 for the vendor without defining them, so a drive has no way to advertise one that a master could read. That null means "the drive does not say", not "no". Read this once per device and cache it: it is a static property of the firmware, and the one thing that makes a negative value of 0x6061 nameable rather than "Unknown".
666
+ *
667
+ * @name GetOperationModes
668
+ * @summary List a device's operation modes
669
+ * @request GET:/api/devices/{slavePosition}/operation-modes
670
+ */
671
+ getOperationModes: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<OperationModes, void>>;
672
+ /**
673
+ * @description Writes the requested operation mode to 0x6060 and returns the resulting control snapshot. The drive reflects the accepted mode in 0x6061 (the modeOfOperation of the response) once it takes effect. Any value object 0x6060 can hold is accepted, standard or manufacturer-specific — the negative half of that range belongs to the vendor, so a SOMANET's diagnostics (-2) or system identification (-4) go through here like any other. Whether a given drive has the mode is the drive's answer, seen in the modeOfOperation of the response; GET /api/devices/{slavePosition}/operation-modes is what lists them beforehand.
620
674
  *
621
675
  * @name SetCia402OperationMode
622
676
  * @summary Set a device's CiA402 operation mode
@@ -624,13 +678,29 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
624
678
  */
625
679
  setCia402OperationMode: (slavePosition: number, data: {
626
680
  /**
627
- * CiA402 operation mode (0x6060 value): 0 NoMode, 1 Profile Position, 3 Profile Velocity, 4 Profile Torque, 6 Homing, 8 Cyclic Sync Position, 9 Cyclic Sync Velocity, 10 Cyclic Sync Torque.
681
+ * Operation mode to request (the 0x6060 value). Standard modes are 0 NoMode, 1 Profile Position, 2 Velocity, 3 Profile Velocity, 4 Profile Torque, 6 Homing, 7 Interpolated Position, 8 Cyclic Sync Position, 9 Cyclic Sync Velocity, 10 Cyclic Sync Torque, 11 Cyclic Sync Torque with Commutation Angle; negative values are the vendor's.
682
+ * @min -128
683
+ * @max 127
628
684
  * @example 9
629
685
  */
630
686
  mode: number;
631
687
  }, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<Cia402Status, void>>;
632
688
  /**
633
- * @description Drives the CiA402 device-control state machine. "enable" walks every intermediate transition to Operation Enabled (clearing a fault first if needed); "disable" goes to Switch On Disabled; "quickStop" triggers a quick stop; "faultReset" clears a latched fault. The device must be exchanging process data for "enable" to make progress. Returns the resulting control snapshot.
689
+ * @description Walks the CiA402 device-control state machine to the state you name, issuing whatever transitions that takes and re-reading the drive between each — so multi-hop paths are ordinary: Switch On Disabled up to Operation Enabled, Quick Stop Active back down to Ready To Switch On. Starting from Fault begins with a fault reset, and a fault whose cause is still present is reported as such (with the drive's 0x603F error code) rather than as a timeout. Only the five states a master can command are accepted. Not Ready To Switch On, Fault Reaction Active and Fault are entered by the drive itself and are rejected as a bad request. **Asking for Operation Enabled while the drive is in Quick Stop Active leaves that quick stop** (CiA402 transition 16), because naming the destination is an explicit instruction to go there. The "enable" command on the sibling endpoint deliberately does not, so a procedure preparing a drive cannot undo somebody's stop by accident. The device must be exchanging process data for any of this to progress — the statusword has to update between polls, and the firmware refuses Operation Enabled unless master communication is live. Returns the resulting control snapshot.
690
+ *
691
+ * @name TransitionToCia402State
692
+ * @summary Bring a drive to a CiA402 state
693
+ * @request POST:/api/devices/{slavePosition}/cia402/state
694
+ */
695
+ transitionToCia402State: (slavePosition: number, data: {
696
+ /**
697
+ * The state to bring the drive to.
698
+ * @example "OperationEnabled"
699
+ */
700
+ state: "SwitchOnDisabled" | "ReadyToSwitchOn" | "SwitchedOn" | "OperationEnabled" | "QuickStopActive";
701
+ }, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<Cia402Status, void>>;
702
+ /**
703
+ * @description Drives the CiA402 device-control state machine. "enable" walks every intermediate transition to Operation Enabled (clearing a fault first if needed); "disable" goes to Switch On Disabled; "quickStop" triggers a quick stop; "faultReset" clears a latched fault. The device must be exchanging process data for "enable" to make progress. Returns the resulting control snapshot. Use POST /api/devices/{slavePosition}/cia402/state to name a destination instead of an action — it reaches states these four cannot, and it is the one that will leave a quick stop. "enable" here deliberately will not.
634
704
  *
635
705
  * @name RunCia402Command
636
706
  * @summary Run a CiA402 state-machine command
@@ -798,9 +868,37 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
798
868
  * @summary List the files stored on a device
799
869
  * @request GET:/api/devices/{slavePosition}/files
800
870
  */
801
- listDeviceFiles: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<{
802
- files: DeviceFile[];
803
- }, void>>;
871
+ listDeviceFiles: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<DeviceFile[], void>>;
872
+ /**
873
+ * @description Reads and decodes the device's `.hardware_description` file over FoE — its product id and revision, serial number, the components it is built from, and the assembly it was packaged into. It is also the only source of the descriptor that decides which firmware belongs on the device, which is what most callers want it for (see `/api/devices/{slavePosition}/firmware-compatibility`). **Readable in BOOT as well as PRE-OP and above.** The bootloader deliberately allows this one file, which is what lets a compatibility check work on a drive a failed install left stranded there — precisely when knowing whether the package was the right one matters most.
874
+ *
875
+ * @name GetDeviceHardwareDescription
876
+ * @summary Read what a device says it is
877
+ * @request GET:/api/devices/{slavePosition}/hardware-description
878
+ */
879
+ getDeviceHardwareDescription: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<HardwareDescription, void>>;
880
+ /**
881
+ * @description Reads and decodes the device's `.variant` file over FoE — which features the Integro was licensed with. **A 404 is the ordinary answer for most devices.** Only Integro drives carry this file, so the resource being absent is normal rather than a problem. Its one property that matters beyond inspection is `fieldbusProtocol`, which the hardware description deliberately does not carry and a full firmware descriptor ends with.
882
+ *
883
+ * @name GetDeviceIntegroVariant
884
+ * @summary Read a device's Integro variant file
885
+ * @request GET:/api/devices/{slavePosition}/variant
886
+ */
887
+ getDeviceIntegroVariant: (slavePosition: number, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<IntegroVariant, void>>;
888
+ /**
889
+ * @description Reads the device's `.hardware_description` and `.variant`, assembles the full firmware descriptors it accepts, and compares them against the descriptor in `filename`. **A mismatch is a `200` carrying `compatible: false`**, not an error status: the client asked a question and got an answer, and the body names both descriptors so it can say which hardware the package was for. A `4xx` means the question could not be asked — the filename is not a package name, or the hardware description could not be read. **Nothing acts on the answer.** The firmware installation procedure writes whatever it is given, on purpose, so this exists to tell a user before they start.
890
+ *
891
+ * @name CheckDeviceFirmwareCompatibility
892
+ * @summary Check whether a firmware package belongs on a device
893
+ * @request GET:/api/devices/{slavePosition}/firmware-compatibility
894
+ */
895
+ checkDeviceFirmwareCompatibility: (slavePosition: number, query: {
896
+ /**
897
+ * The package filename, with no directory part.
898
+ * @example "package_SOMANET-Circulo-7_8500-04-2332_motion-drive_v5.6.10.zip"
899
+ */
900
+ filename: string;
901
+ }, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<FirmwareCompatibility, void>>;
804
902
  /**
805
903
  * @description Sends an FoE read request for `filename` to the device at `slavePosition` and returns the raw file bytes. FoE is available in Boot, Pre-Op, Safe-Op, and Op states (device-dependent); the caller is responsible for ensuring the device is in a suitable state before calling. The call blocks until the full file has been received or a per-packet timeout of 700 ms is exceeded.
806
904
  *
@@ -885,6 +983,30 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
885
983
  */
886
984
  filename: string;
887
985
  }, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<FirmwarePackageName, void>>;
986
+ /**
987
+ * @description Decodes a `.hardware_description` supplied in the request body. No device is involved — the same parse a device read uses, so a file saved from one device can be inspected with no hardware present. Three things fail a parse: content that is not JSON, content with no `device` object, and a device carrying no `id` or no `version`. Everything else is accepted as written. Those three required fields are exactly what a descriptor is built from, which is also what makes this a usable type check — arbitrary JSON is rejected rather than yielding an empty descriptor. The `fileVersion` major is reported but not enforced: a bump means "a new parser is needed", but refusing an unknown one would make a drive flashed with a future file unreadable today.
988
+ *
989
+ * @name ParseHardwareDescription
990
+ * @summary Parse a .hardware_description file
991
+ * @request POST:/api/hardware-description/parse
992
+ */
993
+ parseHardwareDescription: (data: string, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<HardwareDescription, void>>;
994
+ /**
995
+ * @description Decodes a `.variant` file supplied in the request body. Binary rather than text, hence a `POST` with bytes like `/api/sii/parse` rather than a query like `/api/firmware-package-name`. Trailing bytes past the last option are accepted: the firmware reads only as many options as the count claims and ignores the rest, so refusing padding would reject a file the drive is happy with.
996
+ *
997
+ * @name ParseIntegroVariant
998
+ * @summary Parse a .variant file
999
+ * @request POST:/api/integro-variant/parse
1000
+ */
1001
+ parseIntegroVariant: (data: File, params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<IntegroVariant, void>>;
1002
+ /**
1003
+ * @description Every option an Integro can be licensed with, in code order. Static data: no device, no bus, no request body. Served so a client can explain a decoded file — or simply show what is available — without carrying a second copy of a table that belongs to the firmware. The codes ascend with real gaps, and the catalogue keeps codes current firmware no longer implements, because files written years ago still carry them.
1004
+ *
1005
+ * @name ListIntegroVariantOptions
1006
+ * @summary The whole Integro variant option catalogue
1007
+ * @request GET:/api/integro-variant/options
1008
+ */
1009
+ listIntegroVariantOptions: (params?: RequestParams) => Promise<import("./http-client.js").HttpResponse<IntegroVariantOption[], any>>;
888
1010
  /**
889
1011
  * @description Decodes a vendor's ESI XML supplied in the request body. No device is involved — the Tools page uses this to inspect an ESI with no hardware present, which is the only way to see object descriptions, enum option labels, engineering units and min/max bounds: the CoE SDO-Information service reports none of them. The response carries the vendor, every module, and **every device with its own assembled `entries` table** — one row per addressable `(index, subindex)`, merged from the device's own dictionary plus the dictionaries of the modules its slots reference, with each row recording in `source` where it came from. Object-level annotation (an object's description and raw properties) is attached to **subindex 0 only** — that row *is* the object — rather than repeated onto every subindex. A RECORD member still carries its own description on its own row; an ARRAY element carries none, because the ESI describes an array once rather than per element. To read an object's text for any subindex, look at subindex 0 of the same index. Where a slot offers mutually exclusive module variants the merge necessarily collides; it is resolved last-wins and reported in that device's `warnings`. Pass `modules` to model one concrete configuration instead.
890
1012
  *
@@ -219,6 +219,19 @@ export class Api extends HttpClient {
219
219
  format: "json",
220
220
  ...params,
221
221
  });
222
+ /**
223
+ * @description The register map of the Integro's internal (Kübler) encoder — the reference table for POST /api/devices/{slavePosition}/procedures/kuebler-register-communication, and documentation in its own right. Static: it describes the encoder type, not any connected device, so it needs no bus and no scan. Transcribed from the vendor's own draft table. Each entry carries the width, the access type, whether the encoder actually implements it — seven are documented but not implemented — and the vendor's bit definitions verbatim, which for a bit-field register is the only place its meaning is recorded. `format` says how to read the assembled value, because signedness is not uniform and one register is not a single number at all: `unsigned`, `signed`, `bitField` (the number means nothing on its own), or `signedHalves` — two signed 16-bit values packed into 32 bits, which register 0x3C is the only case of. `readableInOneCommand` is false for the one 64-bit register, since the command's length byte caps at 4 bytes.
224
+ *
225
+ * @name GetKueblerRegisters
226
+ * @summary The Integro internal encoder's register map
227
+ * @request GET:/api/meta/kuebler-registers
228
+ */
229
+ getKueblerRegisters = (params = {}) => this.request({
230
+ path: `/api/meta/kuebler-registers`,
231
+ method: "GET",
232
+ format: "json",
233
+ ...params,
234
+ });
222
235
  /**
223
236
  * @description Returns the static catalogue of CoE mailbox error codes defined in ETG.1000.4, Table 30 ("Error Reply Service Data"). A slave returns one of these when the mailbox layer (below a specific protocol such as CoE/FoE) rejects a transfer; the code is embedded in the error text the mailbox endpoints return.
224
237
  *
@@ -413,7 +426,20 @@ export class Api extends HttpClient {
413
426
  ...params,
414
427
  });
415
428
  /**
416
- * @description Writes the requested operation mode to 0x6060 and returns the resulting control snapshot. The drive reflects the accepted mode in 0x6061 (the modeOfOperation of the response) once it takes effect.
429
+ * @description Every operation mode the device has, standard and manufacturer-specific, with what the drive says about each. The standard modes are CiA402's (ETG.6010 §6.8.1) and carry the bit of "Supported drive modes" (0x6502) that advertises them, decoded into `supported`. The manufacturer modes are the vendor's own — the negative half of 0x6060 — and are listed only for a device whose vendor this server knows; their `supported` is null, because 0x6502 reserves bits 16-31 for the vendor without defining them, so a drive has no way to advertise one that a master could read. That null means "the drive does not say", not "no". Read this once per device and cache it: it is a static property of the firmware, and the one thing that makes a negative value of 0x6061 nameable rather than "Unknown".
430
+ *
431
+ * @name GetOperationModes
432
+ * @summary List a device's operation modes
433
+ * @request GET:/api/devices/{slavePosition}/operation-modes
434
+ */
435
+ getOperationModes = (slavePosition, params = {}) => this.request({
436
+ path: `/api/devices/${slavePosition}/operation-modes`,
437
+ method: "GET",
438
+ format: "json",
439
+ ...params,
440
+ });
441
+ /**
442
+ * @description Writes the requested operation mode to 0x6060 and returns the resulting control snapshot. The drive reflects the accepted mode in 0x6061 (the modeOfOperation of the response) once it takes effect. Any value object 0x6060 can hold is accepted, standard or manufacturer-specific — the negative half of that range belongs to the vendor, so a SOMANET's diagnostics (-2) or system identification (-4) go through here like any other. Whether a given drive has the mode is the drive's answer, seen in the modeOfOperation of the response; GET /api/devices/{slavePosition}/operation-modes is what lists them beforehand.
417
443
  *
418
444
  * @name SetCia402OperationMode
419
445
  * @summary Set a device's CiA402 operation mode
@@ -428,7 +454,22 @@ export class Api extends HttpClient {
428
454
  ...params,
429
455
  });
430
456
  /**
431
- * @description Drives the CiA402 device-control state machine. "enable" walks every intermediate transition to Operation Enabled (clearing a fault first if needed); "disable" goes to Switch On Disabled; "quickStop" triggers a quick stop; "faultReset" clears a latched fault. The device must be exchanging process data for "enable" to make progress. Returns the resulting control snapshot.
457
+ * @description Walks the CiA402 device-control state machine to the state you name, issuing whatever transitions that takes and re-reading the drive between each — so multi-hop paths are ordinary: Switch On Disabled up to Operation Enabled, Quick Stop Active back down to Ready To Switch On. Starting from Fault begins with a fault reset, and a fault whose cause is still present is reported as such (with the drive's 0x603F error code) rather than as a timeout. Only the five states a master can command are accepted. Not Ready To Switch On, Fault Reaction Active and Fault are entered by the drive itself and are rejected as a bad request. **Asking for Operation Enabled while the drive is in Quick Stop Active leaves that quick stop** (CiA402 transition 16), because naming the destination is an explicit instruction to go there. The "enable" command on the sibling endpoint deliberately does not, so a procedure preparing a drive cannot undo somebody's stop by accident. The device must be exchanging process data for any of this to progress — the statusword has to update between polls, and the firmware refuses Operation Enabled unless master communication is live. Returns the resulting control snapshot.
458
+ *
459
+ * @name TransitionToCia402State
460
+ * @summary Bring a drive to a CiA402 state
461
+ * @request POST:/api/devices/{slavePosition}/cia402/state
462
+ */
463
+ transitionToCia402State = (slavePosition, data, params = {}) => this.request({
464
+ path: `/api/devices/${slavePosition}/cia402/state`,
465
+ method: "POST",
466
+ body: data,
467
+ type: ContentType.Json,
468
+ format: "json",
469
+ ...params,
470
+ });
471
+ /**
472
+ * @description Drives the CiA402 device-control state machine. "enable" walks every intermediate transition to Operation Enabled (clearing a fault first if needed); "disable" goes to Switch On Disabled; "quickStop" triggers a quick stop; "faultReset" clears a latched fault. The device must be exchanging process data for "enable" to make progress. Returns the resulting control snapshot. Use POST /api/devices/{slavePosition}/cia402/state to name a destination instead of an action — it reaches states these four cannot, and it is the one that will leave a quick stop. "enable" here deliberately will not.
432
473
  *
433
474
  * @name RunCia402Command
434
475
  * @summary Run a CiA402 state-machine command
@@ -605,6 +646,46 @@ export class Api extends HttpClient {
605
646
  format: "json",
606
647
  ...params,
607
648
  });
649
+ /**
650
+ * @description Reads and decodes the device's `.hardware_description` file over FoE — its product id and revision, serial number, the components it is built from, and the assembly it was packaged into. It is also the only source of the descriptor that decides which firmware belongs on the device, which is what most callers want it for (see `/api/devices/{slavePosition}/firmware-compatibility`). **Readable in BOOT as well as PRE-OP and above.** The bootloader deliberately allows this one file, which is what lets a compatibility check work on a drive a failed install left stranded there — precisely when knowing whether the package was the right one matters most.
651
+ *
652
+ * @name GetDeviceHardwareDescription
653
+ * @summary Read what a device says it is
654
+ * @request GET:/api/devices/{slavePosition}/hardware-description
655
+ */
656
+ getDeviceHardwareDescription = (slavePosition, params = {}) => this.request({
657
+ path: `/api/devices/${slavePosition}/hardware-description`,
658
+ method: "GET",
659
+ format: "json",
660
+ ...params,
661
+ });
662
+ /**
663
+ * @description Reads and decodes the device's `.variant` file over FoE — which features the Integro was licensed with. **A 404 is the ordinary answer for most devices.** Only Integro drives carry this file, so the resource being absent is normal rather than a problem. Its one property that matters beyond inspection is `fieldbusProtocol`, which the hardware description deliberately does not carry and a full firmware descriptor ends with.
664
+ *
665
+ * @name GetDeviceIntegroVariant
666
+ * @summary Read a device's Integro variant file
667
+ * @request GET:/api/devices/{slavePosition}/variant
668
+ */
669
+ getDeviceIntegroVariant = (slavePosition, params = {}) => this.request({
670
+ path: `/api/devices/${slavePosition}/variant`,
671
+ method: "GET",
672
+ format: "json",
673
+ ...params,
674
+ });
675
+ /**
676
+ * @description Reads the device's `.hardware_description` and `.variant`, assembles the full firmware descriptors it accepts, and compares them against the descriptor in `filename`. **A mismatch is a `200` carrying `compatible: false`**, not an error status: the client asked a question and got an answer, and the body names both descriptors so it can say which hardware the package was for. A `4xx` means the question could not be asked — the filename is not a package name, or the hardware description could not be read. **Nothing acts on the answer.** The firmware installation procedure writes whatever it is given, on purpose, so this exists to tell a user before they start.
677
+ *
678
+ * @name CheckDeviceFirmwareCompatibility
679
+ * @summary Check whether a firmware package belongs on a device
680
+ * @request GET:/api/devices/{slavePosition}/firmware-compatibility
681
+ */
682
+ checkDeviceFirmwareCompatibility = (slavePosition, query, params = {}) => this.request({
683
+ path: `/api/devices/${slavePosition}/firmware-compatibility`,
684
+ method: "GET",
685
+ query: query,
686
+ format: "json",
687
+ ...params,
688
+ });
608
689
  /**
609
690
  * @description Sends an FoE read request for `filename` to the device at `slavePosition` and returns the raw file bytes. FoE is available in Boot, Pre-Op, Safe-Op, and Op states (device-dependent); the caller is responsible for ensuring the device is in a suitable state before calling. The call blocks until the full file has been received or a per-packet timeout of 700 ms is exceeded.
610
691
  *
@@ -686,6 +767,48 @@ export class Api extends HttpClient {
686
767
  format: "json",
687
768
  ...params,
688
769
  });
770
+ /**
771
+ * @description Decodes a `.hardware_description` supplied in the request body. No device is involved — the same parse a device read uses, so a file saved from one device can be inspected with no hardware present. Three things fail a parse: content that is not JSON, content with no `device` object, and a device carrying no `id` or no `version`. Everything else is accepted as written. Those three required fields are exactly what a descriptor is built from, which is also what makes this a usable type check — arbitrary JSON is rejected rather than yielding an empty descriptor. The `fileVersion` major is reported but not enforced: a bump means "a new parser is needed", but refusing an unknown one would make a drive flashed with a future file unreadable today.
772
+ *
773
+ * @name ParseHardwareDescription
774
+ * @summary Parse a .hardware_description file
775
+ * @request POST:/api/hardware-description/parse
776
+ */
777
+ parseHardwareDescription = (data, params = {}) => this.request({
778
+ path: `/api/hardware-description/parse`,
779
+ method: "POST",
780
+ body: data,
781
+ type: ContentType.Text,
782
+ format: "json",
783
+ ...params,
784
+ });
785
+ /**
786
+ * @description Decodes a `.variant` file supplied in the request body. Binary rather than text, hence a `POST` with bytes like `/api/sii/parse` rather than a query like `/api/firmware-package-name`. Trailing bytes past the last option are accepted: the firmware reads only as many options as the count claims and ignores the rest, so refusing padding would reject a file the drive is happy with.
787
+ *
788
+ * @name ParseIntegroVariant
789
+ * @summary Parse a .variant file
790
+ * @request POST:/api/integro-variant/parse
791
+ */
792
+ parseIntegroVariant = (data, params = {}) => this.request({
793
+ path: `/api/integro-variant/parse`,
794
+ method: "POST",
795
+ body: data,
796
+ format: "json",
797
+ ...params,
798
+ });
799
+ /**
800
+ * @description Every option an Integro can be licensed with, in code order. Static data: no device, no bus, no request body. Served so a client can explain a decoded file — or simply show what is available — without carrying a second copy of a table that belongs to the firmware. The codes ascend with real gaps, and the catalogue keeps codes current firmware no longer implements, because files written years ago still carry them.
801
+ *
802
+ * @name ListIntegroVariantOptions
803
+ * @summary The whole Integro variant option catalogue
804
+ * @request GET:/api/integro-variant/options
805
+ */
806
+ listIntegroVariantOptions = (params = {}) => this.request({
807
+ path: `/api/integro-variant/options`,
808
+ method: "GET",
809
+ format: "json",
810
+ ...params,
811
+ });
689
812
  /**
690
813
  * @description Decodes a vendor's ESI XML supplied in the request body. No device is involved — the Tools page uses this to inspect an ESI with no hardware present, which is the only way to see object descriptions, enum option labels, engineering units and min/max bounds: the CoE SDO-Information service reports none of them. The response carries the vendor, every module, and **every device with its own assembled `entries` table** — one row per addressable `(index, subindex)`, merged from the device's own dictionary plus the dictionaries of the modules its slots reference, with each row recording in `source` where it came from. Object-level annotation (an object's description and raw properties) is attached to **subindex 0 only** — that row *is* the object — rather than repeated onto every subindex. A RECORD member still carries its own description on its own row; an ARRAY element carries none, because the ESI describes an array once rather than per element. To read an object's text for any subindex, look at subindex 0 of the same index. Where a slot offers mutually exclusive module variants the merge necessarily collides; it is resolved last-wins and reported in that device's `warnings`. Pass `modules` to model one concrete configuration instead.
691
814
  *
@@ -1,3 +1,4 @@
1
+ type UtilRequiredKeys<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
1
2
  /** A CiA402 drive's control snapshot — its state machine, control words, and mode. */
2
3
  export interface Cia402Status {
3
4
  /**
@@ -26,11 +27,69 @@ export interface Cia402Status {
26
27
  */
27
28
  modeName: string;
28
29
  /**
29
- * The setpoint currently commanded for the active mode — target position 0x607A (PP/CSP), velocity 0x60FF (PV/CSV), or torque 0x6071 (PT/CST), widened to INTEGER32. 0 only when the active mode has no linear setpoint (NoMode / Homing).
30
+ * The setpoint currently commanded for the active mode — target position 0x607A (PP/CSP), velocity 0x60FF (PV/CSV), or torque 0x6071 (PT/CST), widened to INTEGER32. 0 only when the active mode has no linear setpoint (NoMode / Homing / vl / ip).
30
31
  * @example 100000
31
32
  */
32
33
  target: number;
33
34
  }
35
+ /** Every operation mode a device has, with what its "Supported drive modes" field (0x6502) says about each. */
36
+ export interface OperationModes {
37
+ /**
38
+ * Object 0x6502 verbatim, as an UNSIGNED32.
39
+ * @example 197549
40
+ */
41
+ supportedDriveModes: number;
42
+ /**
43
+ * The set bits of 0x6502 from bit 16 upwards, reported as bit numbers and nothing more. The profile leaves their meaning entirely to the vendor, so nothing here can decode them — a SOMANET drive sets bits 16 and 17 and publishes no definition for either.
44
+ * @example [16,17]
45
+ */
46
+ manufacturerBits: number[];
47
+ /** Every mode, ascending by value — manufacturer modes first, then standard. */
48
+ modes: OperationMode[];
49
+ }
50
+ /** One operation mode of one device. */
51
+ export interface OperationMode {
52
+ /**
53
+ * The value written to 0x6060 / read from 0x6061. Negative for a vendor mode.
54
+ * @example -2
55
+ */
56
+ value: number;
57
+ /**
58
+ * PascalCase identifier, matching the modeName of GET /api/devices/{n}/cia402.
59
+ * @example "Diagnostics"
60
+ */
61
+ name: string;
62
+ /**
63
+ * The profile's or the vendor's own wording, for a user-facing list.
64
+ * @example "Diagnostics mode"
65
+ */
66
+ label: string;
67
+ /**
68
+ * Whether CiA402 or the vendor defines this mode.
69
+ * @example "manufacturer"
70
+ */
71
+ kind: "standard" | "manufacturer";
72
+ /**
73
+ * The bit of 0x6502 that advertises this mode. Null for every manufacturer mode, and for NoMode, which is always legal and so has no bit.
74
+ * @example 7
75
+ */
76
+ bit: number | null;
77
+ /**
78
+ * The profile's short form (pp, vl, pv, tq, hm, ip, csp, csv, cst, cstca).
79
+ * @example "csp"
80
+ */
81
+ abbreviation: string | null;
82
+ /**
83
+ * Whether the drive advertises this mode. Null for every manufacturer mode — 0x6502 has no bit a master could read for one — which means "the drive does not say", not "no".
84
+ * @example true
85
+ */
86
+ supported: boolean | null;
87
+ /**
88
+ * Present and true only for a mode the vendor's firmware marks deprecated.
89
+ * @example true
90
+ */
91
+ deprecated?: boolean;
92
+ }
34
93
  /** Point-in-time health of the real-time game loop. Times are nanoseconds; rates are hertz. All fields are diagnostic (relaxed reads), not synchronised. */
35
94
  export interface GameLoopHealth {
36
95
  /**
@@ -583,40 +642,224 @@ export interface FirmwarePackageName {
583
642
  */
584
643
  hardwareName: string;
585
644
  /**
586
- * The full firmware descriptor, verbatim.
645
+ * The hardware this package is built for, verbatim — the string a compatibility check compares.
587
646
  * @example "8500-04-2332"
588
647
  */
589
- firmwareId: string;
648
+ fullFirmwareDescriptor: string;
590
649
  /**
591
- * Software name.
650
+ * Firmware or software name.
592
651
  * @example "motion-drive"
593
652
  */
594
- firmwareName: string;
653
+ softwareName: string;
595
654
  /**
596
- * Software version, including the leading `v`.
655
+ * The firmware or software version, including the leading `v`. Not to be confused with `firmwareVersion`, which is the *hardware* revision inside the descriptor.
597
656
  * @example "v5.6.10"
598
657
  */
599
- firmwareVersion: string;
658
+ softwareVersion: string;
600
659
  /**
601
- * Product id from the descriptor.
602
- * @example 8500
660
+ * Firmware id from the descriptor — the hardware product.
661
+ * @example "8500"
603
662
  */
604
- productId?: number;
663
+ firmwareId?: string;
605
664
  /**
606
- * Product version from the descriptor.
607
- * @example 4
665
+ * Hardware revision from the descriptor. A string, so a leading zero survives: `04` read as a number and printed back would be `4`, and `8500-4` matches no package.
666
+ * @example "04"
667
+ */
668
+ firmwareVersion?: string;
669
+ /**
670
+ * Firmware encryption key id from the descriptor. A string because real packages carry non-numeric ones, e.g. `A`.
671
+ * @example "2332"
672
+ */
673
+ keyId?: string;
674
+ /**
675
+ * Fieldbus protocol character from the descriptor, hexadecimal. `1` is EtherCAT.
676
+ * @example "1"
608
677
  */
609
- productVersion?: number;
678
+ fieldbusProtocol?: string;
610
679
  /**
611
- * Firmware encryption key id from the descriptor.
612
- * @example 2332
680
+ * `firmwareId` and `firmwareVersion` joined — the descriptor without the key or fieldbus. Useful for saying *how* a package missed: a matching build descriptor with a different key means right hardware, wrong encryption key.
681
+ * @example "8500-04"
613
682
  */
614
- keyId?: number;
683
+ buildDescriptor?: string;
684
+ }
685
+ /** One item making up a device or assembly. Carries no function beyond recording what has a serial number, so every property can legitimately be empty. */
686
+ export interface HardwareComponent {
687
+ /** @example "Com EtherCAT" */
688
+ name: string;
689
+ /** @example "A.2" */
690
+ version: string;
691
+ /** @example "1000-02-0005739-1815" */
692
+ serialNumber: string;
693
+ }
694
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
695
+ export interface HardwareProduct {
696
+ /**
697
+ * Human-readable description of the hardware.
698
+ * @example "SOMANET Servo Node 400 EtherCAT"
699
+ */
700
+ name: string;
701
+ /**
702
+ * Names the product's picture. Empty when the file carries none.
703
+ * @example "9501-xx"
704
+ */
705
+ imageId: string;
615
706
  /**
616
- * Fieldbus protocol from the descriptor, decoded as hexadecimal. 1 is EtherCAT.
707
+ * The `firmwareId` — identifies the hardware product.
708
+ * @example "9501"
709
+ */
710
+ id: string;
711
+ /**
712
+ * The `firmwareVersion` — revision of that product.
713
+ * @example "01"
714
+ */
715
+ version: string;
716
+ /**
717
+ * Firmware encryption key burned to OTP memory. Device only, and empty on hardware whose firmware predates encryption.
718
+ * @example "4622"
719
+ */
720
+ keyId: string;
721
+ /** @example "9501-01-040595-4023" */
722
+ serialNumber: string;
723
+ /**
724
+ * MAC address of the Ethernet port. Device only.
725
+ * @example "01-23-45-67-89-AB"
726
+ */
727
+ macAddress: string;
728
+ components: HardwareComponent[];
729
+ /**
730
+ * `id` and `version` joined by a dash.
731
+ * @example "9501-01"
732
+ */
733
+ buildDescriptor: string;
734
+ }
735
+ /**
736
+ * A device's `.hardware_description` file — what the hardware says it is, and the source of the descriptor that decides which firmware belongs on it.
737
+ *
738
+ * `device` is never absent, and that is structural rather than a simplification: the file lives *on* the device, so a file without one cannot exist. `assembly` is present only when the device was packaged into a product — an ACTILINK is an assembly with a SOMANET Node device inside it — and when it is, it is what firmware is matched against first.
739
+ */
740
+ export interface HardwareDescription {
741
+ /**
742
+ * Format version of the file itself, semver.
743
+ * @example "1.2.0"
744
+ */
745
+ fileVersion: string;
746
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
747
+ device: HardwareProduct;
748
+ /** A device or an assembly. The two are one shape — the specification lists their fields in a single table and they differ only in that `keyId` and `macAddress` are device-only. */
749
+ assembly?: HardwareProduct;
750
+ }
751
+ /** One entry of the Integro runtime-variant option catalogue. Nothing on the server acts on `socVariables` or `incompatibleOptionIds` — the drive enforces them — but they are what make a decoded file legible. */
752
+ export interface IntegroVariantOption {
753
+ /**
754
+ * The option code as it appears in the file.
755
+ * @example 1
756
+ */
757
+ id: number;
758
+ /**
759
+ * What the option selects.
760
+ * @example "Fieldbus Protocol"
761
+ */
762
+ category: string;
763
+ /**
764
+ * Which choice within that category.
765
+ * @example "EtherCAT"
766
+ */
767
+ meaning: string;
768
+ /**
769
+ * The drive's own configuration values this option sets. Empty for an option the fieldbus firmware acts on rather than the SoC.
770
+ * @example ["adc_phase_current_sensor_gain"]
771
+ */
772
+ socVariables: string[];
773
+ /**
774
+ * Options that cannot be selected alongside this one — the other members of a category that selects exactly one choice. Empty for an independent flag such as "disable DI1".
775
+ * @example [0,2,3,39]
776
+ */
777
+ incompatibleOptionIds: number[];
778
+ /**
779
+ * Segments of the part number this option corresponds to. Empty for an option not distinguished in the part number.
780
+ * @example ["EC"]
781
+ */
782
+ mpnSegmentCodes: string[];
783
+ }
784
+ /** One option code from a decoded file, expanded into its catalogue entry. Everything but `id` is absent for a code the catalogue does not name, so "we do not know what this is" is missing properties rather than the string `unknown`. */
785
+ export type IntegroVariantFileOption = UtilRequiredKeys<IntegroVariantOption, "id">;
786
+ /**
787
+ * A decoded `.variant` file: which features a SOMANET Integro was licensed with.
788
+ *
789
+ * Only Integro drives carry one. Its layout comes from the firmware that reads it rather than from a specification — there is none — and the one thing on it that matters beyond inspection is `fieldbusProtocol`, which the hardware description deliberately does not carry and a full firmware descriptor ends with.
790
+ */
791
+ export interface IntegroVariant {
792
+ /**
793
+ * Format version; 1 in every file seen so far.
794
+ * @example 1
795
+ */
796
+ fileVersion: number;
797
+ /** Lowercase hex. Opaque — verification needs the private key and happens on the drive — and reported only so a caller can see whether one is present. */
798
+ signature: string;
799
+ /**
800
+ * Lowercase hex netX chip id this file was issued for.
801
+ * @example "4e64646c70b286a000000000"
802
+ */
803
+ chipId: string;
804
+ /** @example "9004-02-0000424-2445" */
805
+ serialNumber: string;
806
+ /** @example "40:49:8A:01:21:D6" */
807
+ macAddress: string;
808
+ /**
809
+ * Who the device was licensed to.
810
+ * @example 1
811
+ */
812
+ customerId: number;
813
+ /**
814
+ * Raw mode value. `passive` (0x51) is the failure state as much as a mode: firmware falls back to it when the file is missing, its signature does not verify, or its chip id belongs to another device.
815
+ * @example 87
816
+ */
817
+ operationMode: number;
818
+ /** @example "live" */
819
+ operationModeName: "passive" | "trial" | "production" | "live" | "unknown";
820
+ /**
821
+ * The fieldbus the device is licensed for, for the tail of a full firmware descriptor. **EtherCAT wins when several are selected** — real files do carry more than one. Absent when the file selects no fieldbus at all.
617
822
  * @example 1
618
823
  */
619
824
  fieldbusProtocol?: number;
825
+ /** The option codes, in the order the file lists them — which is not sorted, and is the only record of how the file was written. */
826
+ options: IntegroVariantFileOption[];
827
+ }
828
+ /** The full firmware descriptors one device accepts firmware under. Two rather than one because the specification says both are compatible and lists both for the user to choose from: the assembly's firmware "should have been customized for the assembly", so it is the one to prefer, while the device package is the generic build for the hardware inside it. */
829
+ export interface FullFirmwareDescriptors {
830
+ /**
831
+ * The device's own descriptor. Always present.
832
+ * @example "9010-02-2423-1"
833
+ */
834
+ device: string;
835
+ /**
836
+ * The assembly's build descriptor with the **device's** key id — assemblies have no key of their own. Absent when the hardware description carries no assembly.
837
+ * @example "6000-01-2423-1"
838
+ */
839
+ assembly?: string;
840
+ }
841
+ /**
842
+ * Whether one firmware package belongs on one device.
843
+ *
844
+ * **The whole descriptor string is compared, never its decoded parts.** That is what makes the check correct for descriptors outside the numeric convention, and it is how the specification frames the operation — find compatible firmware by searching for the `fullFirmwareDescriptor` string.
845
+ */
846
+ export interface FirmwareCompatibility {
847
+ /** @example true */
848
+ compatible: boolean;
849
+ /**
850
+ * Which of the device's descriptors matched. `device` is a match that still has something to say: it is the generic build rather than the one customised for the assembly.
851
+ * @example "assembly"
852
+ */
853
+ match: "none" | "assembly" | "device";
854
+ /** A SOMANET firmware package filename broken into its fields. The four decoded-descriptor properties are absent — not null — when the full firmware descriptor is not the numeric kind, which the naming specification explicitly allows. */
855
+ packageName: FirmwarePackageName;
856
+ /** The full firmware descriptors one device accepts firmware under. Two rather than one because the specification says both are compatible and lists both for the user to choose from: the assembly's firmware "should have been customized for the assembly", so it is the one to prefer, while the device package is the generic build for the hardware inside it. */
857
+ deviceDescriptors: FullFirmwareDescriptors;
858
+ /**
859
+ * One sentence naming the descriptors involved, ready to show a user. Populated for a match as well as a mismatch.
860
+ * @example "This package is built for 6000-01-2423-1, which is this device's assembly."
861
+ */
862
+ explanation: string;
620
863
  }
621
864
  /** One procedure paired with how its last run on this device went — an entry of `GET /api/devices/{slavePosition}/procedures`. The pairing is what lets a page render in a single request instead of one per procedure. */
622
865
  export interface ProcedureListing {
@@ -1476,3 +1719,4 @@ export interface EsiParseResult {
1476
1719
  /** Recoverable problems in the document itself — a skipped malformed object, an unparsable value. A file with warnings still parses. Per-device assembly problems are reported on the device instead. */
1477
1720
  warnings?: string[];
1478
1721
  }
1722
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './generated/http-client.js';
2
2
  export * from './generated/data-contracts.js';
3
3
  export * from './generated/Api.js';
4
+ export * from './api-error.js';
4
5
  export * from './constants.js';
5
6
  export * from './web-socket-connection.js';
6
7
  export * from './client.js';
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  export * from './generated/http-client.js';
6
6
  export * from './generated/data-contracts.js';
7
7
  export * from './generated/Api.js';
8
+ export * from './api-error.js';
8
9
  export * from './constants.js';
9
10
  export * from './web-socket-connection.js';
10
11
  export * from './client.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapticon/motion-master-client",
3
- "version": "6.0.0-alpha.69",
3
+ "version": "6.0.0-alpha.71",
4
4
  "description": "Isomorphic TypeScript client for Motion Master: the generated HTTP API client, the WebSocket connection, and helpers.",
5
5
  "license": "MIT",
6
6
  "repository": {