@wandelbots/nova-js 2.1.4 → 3.0.0-pr.bugfix-compatible-with-non-dom-envs.115.33da73d

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.
Files changed (57) hide show
  1. package/README.md +29 -1
  2. package/dist/LoginWithAuth0.d.ts.map +1 -1
  3. package/dist/{chunk-6WCKJOFL.js → chunk-4FP7NTKS.js} +51 -1
  4. package/dist/chunk-4FP7NTKS.js.map +1 -0
  5. package/dist/{chunk-V3NJLR6P.js → chunk-GVLDRXDW.js} +2 -52
  6. package/dist/chunk-GVLDRXDW.js.map +1 -0
  7. package/dist/index.cjs +1 -1
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.js +8 -8
  10. package/dist/lib/AutoReconnectingWebsocket.d.ts +2 -2
  11. package/dist/lib/AutoReconnectingWebsocket.d.ts.map +1 -1
  12. package/dist/lib/availableStorage.d.ts +1 -1
  13. package/dist/lib/availableStorage.d.ts.map +1 -1
  14. package/dist/lib/v1/NovaClient.d.ts +1 -1
  15. package/dist/lib/v1/NovaClient.d.ts.map +1 -1
  16. package/dist/lib/v1/index.cjs +1 -1
  17. package/dist/lib/v1/index.cjs.map +1 -1
  18. package/dist/lib/v1/index.js +6 -6
  19. package/dist/lib/v1/index.js.map +1 -1
  20. package/dist/lib/v2/NovaCellAPIClient.d.ts +9 -11
  21. package/dist/lib/v2/NovaCellAPIClient.d.ts.map +1 -1
  22. package/dist/lib/v2/NovaClient.d.ts +0 -8
  23. package/dist/lib/v2/NovaClient.d.ts.map +1 -1
  24. package/dist/lib/v2/index.cjs +29 -772
  25. package/dist/lib/v2/index.cjs.map +1 -1
  26. package/dist/lib/v2/index.d.ts +0 -4
  27. package/dist/lib/v2/index.d.ts.map +1 -1
  28. package/dist/lib/v2/index.js +32 -764
  29. package/dist/lib/v2/index.js.map +1 -1
  30. package/dist/lib/v2/mock/MockNovaInstance.d.ts.map +1 -1
  31. package/package.json +2 -2
  32. package/src/LoginWithAuth0.ts +5 -0
  33. package/src/lib/AutoReconnectingWebsocket.ts +6 -2
  34. package/src/lib/availableStorage.ts +5 -2
  35. package/src/lib/v1/NovaClient.ts +7 -1
  36. package/src/lib/v2/NovaCellAPIClient.ts +22 -22
  37. package/src/lib/v2/NovaClient.ts +7 -28
  38. package/src/lib/v2/index.ts +0 -4
  39. package/src/lib/v2/mock/MockNovaInstance.ts +9 -32
  40. package/src/types/non-dom.d.ts +118 -0
  41. package/dist/chunk-6WCKJOFL.js.map +0 -1
  42. package/dist/chunk-V3NJLR6P.js.map +0 -1
  43. package/dist/lib/v2/ConnectedMotionGroup.d.ts +0 -41
  44. package/dist/lib/v2/ConnectedMotionGroup.d.ts.map +0 -1
  45. package/dist/lib/v2/JoggerConnection.d.ts +0 -53
  46. package/dist/lib/v2/JoggerConnection.d.ts.map +0 -1
  47. package/dist/lib/v2/MotionStreamConnection.d.ts +0 -25
  48. package/dist/lib/v2/MotionStreamConnection.d.ts.map +0 -1
  49. package/dist/lib/v2/ProgramStateConnection.d.ts +0 -53
  50. package/dist/lib/v2/ProgramStateConnection.d.ts.map +0 -1
  51. package/dist/lib/v2/motionStateUpdate.d.ts +0 -4
  52. package/dist/lib/v2/motionStateUpdate.d.ts.map +0 -1
  53. package/src/lib/v2/ConnectedMotionGroup.ts +0 -216
  54. package/src/lib/v2/JoggerConnection.ts +0 -207
  55. package/src/lib/v2/MotionStreamConnection.ts +0 -201
  56. package/src/lib/v2/ProgramStateConnection.ts +0 -249
  57. package/src/lib/v2/motionStateUpdate.ts +0 -55
@@ -1,201 +0,0 @@
1
- import type {
2
- Controller,
3
- MotionGroupPhysical,
4
- MotionGroupState,
5
- } from "@wandelbots/nova-api/v2"
6
- import { makeAutoObservable, runInAction } from "mobx"
7
- import * as THREE from "three"
8
- import type { AutoReconnectingWebsocket } from "../AutoReconnectingWebsocket"
9
- import { tryParseJson } from "../converters"
10
- import { jointValuesEqual, tcpPoseEqual } from "./motionStateUpdate"
11
- import type { NovaClient } from "./NovaClient"
12
- import { Vector3d, vector3ToArray } from "./vectorUtils"
13
-
14
- const MOTION_DELTA_THRESHOLD = 0.0001
15
-
16
- function unwrapRotationVector(
17
- newRotationVectorApi: Vector3d,
18
- currentRotationVectorApi: Vector3d,
19
- ): Vector3d {
20
- const currentRotationVector = new THREE.Vector3(
21
- currentRotationVectorApi[0],
22
- currentRotationVectorApi[1],
23
- currentRotationVectorApi[2],
24
- )
25
-
26
- const newRotationVector = new THREE.Vector3(
27
- newRotationVectorApi[0],
28
- newRotationVectorApi[1],
29
- newRotationVectorApi[2],
30
- )
31
-
32
- const currentAngle = currentRotationVector.length()
33
- const currentAxis = currentRotationVector.normalize()
34
-
35
- let newAngle = newRotationVector.length()
36
- let newAxis = newRotationVector.normalize()
37
-
38
- // Align rotation axes
39
- if (newAxis.dot(currentAxis) < 0) {
40
- newAngle = -newAngle
41
- newAxis = newAxis.multiplyScalar(-1.0)
42
- }
43
-
44
- // Shift rotation angle close to previous one to extend domain of rotation angles beyond [0, pi]
45
- // - this simplifies interpolation and prevents abruptly changing signs of the rotation angles
46
- let angleDifference = newAngle - currentAngle
47
- angleDifference -=
48
- 2.0 * Math.PI * Math.floor((angleDifference + Math.PI) / (2.0 * Math.PI))
49
-
50
- newAngle = currentAngle + angleDifference
51
-
52
- return vector3ToArray(newAxis.multiplyScalar(newAngle))
53
- }
54
-
55
- /**
56
- * Store representing the current state of a connected motion group.
57
- */
58
- export class MotionStreamConnection {
59
- static async open(nova: NovaClient, motionGroupId: string) {
60
- const { controllers: controllers } =
61
- await nova.api.controller.listControllers()
62
-
63
- const [_motionGroupIndex, controllerId] = motionGroupId.split("@") as [
64
- string,
65
- string,
66
- ]
67
- const controller = controllers.find((c) => c.controller === controllerId)
68
- const motionGroup = controller?.motion_groups.find(
69
- (mg) => mg.motion_group === motionGroupId,
70
- )
71
- if (!controller || !motionGroup) {
72
- throw new Error(
73
- `Controller ${controllerId} or motion group ${motionGroupId} not found`,
74
- )
75
- }
76
-
77
- const motionStateSocket = nova.openReconnectingWebsocket(
78
- `/motion-groups/${motionGroupId}/state-stream`,
79
- )
80
-
81
- // Wait for the first message to get the initial state
82
- const firstMessage = await motionStateSocket.firstMessage()
83
- console.log("got first message", firstMessage)
84
- const initialMotionState = tryParseJson(firstMessage.data)
85
- ?.result as MotionGroupState
86
-
87
- if (!initialMotionState) {
88
- throw new Error(
89
- `Unable to parse initial motion state message ${firstMessage.data}`,
90
- )
91
- }
92
-
93
- console.log(
94
- `Connected motion state websocket to motion group ${motionGroup.motion_group}. Initial state:\n `,
95
- initialMotionState,
96
- )
97
-
98
- return new MotionStreamConnection(
99
- nova,
100
- controller,
101
- motionGroup,
102
- initialMotionState,
103
- motionStateSocket,
104
- )
105
- }
106
-
107
- // Not mobx-observable as this changes very fast; should be observed
108
- // using animation frames
109
- rapidlyChangingMotionState: MotionGroupState
110
-
111
- constructor(
112
- readonly nova: NovaClient,
113
- readonly controller: Controller,
114
- readonly motionGroup: MotionGroupPhysical,
115
- readonly initialMotionState: MotionGroupState,
116
- readonly motionStateSocket: AutoReconnectingWebsocket,
117
- ) {
118
- this.rapidlyChangingMotionState = initialMotionState
119
-
120
- motionStateSocket.addEventListener("message", (event) => {
121
- const motionState = tryParseJson(event.data)?.result as
122
- | MotionGroupState
123
- | undefined
124
-
125
- if (!motionState) {
126
- throw new Error(
127
- `Failed to get motion state for ${this.motionGroupId}: ${event.data}`,
128
- )
129
- }
130
-
131
- // handle motionState message
132
- if (
133
- !jointValuesEqual(
134
- this.rapidlyChangingMotionState.joint_position.joints,
135
- motionState.joint_position.joints,
136
- MOTION_DELTA_THRESHOLD,
137
- )
138
- ) {
139
- runInAction(() => {
140
- this.rapidlyChangingMotionState = motionState
141
- })
142
- }
143
-
144
- // handle tcpPose message
145
- if (
146
- !tcpPoseEqual(
147
- this.rapidlyChangingMotionState.tcp_pose,
148
- motionState.tcp_pose,
149
- MOTION_DELTA_THRESHOLD,
150
- )
151
- ) {
152
- runInAction(() => {
153
- if (this.rapidlyChangingMotionState.tcp_pose == undefined) {
154
- this.rapidlyChangingMotionState.tcp_pose = motionState.tcp_pose
155
- } else {
156
- this.rapidlyChangingMotionState.tcp_pose = {
157
- position: motionState.tcp_pose!.position,
158
- orientation: unwrapRotationVector(
159
- motionState.tcp_pose!.orientation as Vector3d,
160
- this.rapidlyChangingMotionState.tcp_pose!
161
- .orientation as Vector3d,
162
- ),
163
- tcp: motionState.tcp_pose!.tcp,
164
- coordinate_system: motionState.tcp_pose!.coordinate_system,
165
- }
166
- }
167
- })
168
- }
169
- })
170
- makeAutoObservable(this)
171
- }
172
-
173
- get motionGroupId() {
174
- return this.motionGroup.motion_group
175
- }
176
-
177
- get controllerId() {
178
- return this.controller.controller
179
- }
180
-
181
- get modelFromController() {
182
- return this.motionGroup.model_from_controller
183
- }
184
-
185
- get wandelscriptIdentifier() {
186
- const num = this.motionGroupId.split("@")[0]
187
- return `${this.controllerId.replaceAll("-", "_")}_${num}`
188
- }
189
-
190
- get joints() {
191
- return this.initialMotionState.joint_position.joints.map((_, i) => {
192
- return {
193
- index: i,
194
- }
195
- })
196
- }
197
-
198
- dispose() {
199
- this.motionStateSocket.close()
200
- }
201
- }
@@ -1,249 +0,0 @@
1
- import { AxiosError } from "axios"
2
- import { makeAutoObservable, runInAction } from "mobx"
3
- import { AutoReconnectingWebsocket } from "../AutoReconnectingWebsocket"
4
- import { tryParseJson } from "../converters"
5
- import type { MotionStreamConnection } from "./MotionStreamConnection"
6
- import type { NovaClient } from "./NovaClient"
7
-
8
- export type ProgramRunnerLogEntry = {
9
- timestamp: number
10
- message: string
11
- level?: "warn" | "error"
12
- }
13
-
14
- export enum ProgramState {
15
- NotStarted = "not started",
16
- Running = "running",
17
- Stopped = "stopped",
18
- Failed = "failed",
19
- Completed = "completed",
20
- }
21
-
22
- export type CurrentProgram = {
23
- id?: string
24
- wandelscript?: string
25
- state?: ProgramState
26
- }
27
-
28
- type ProgramStateMessage = {
29
- type: string
30
- runner: {
31
- id: string
32
- state: ProgramState
33
- start_time?: number | null
34
- execution_time?: number | null
35
- }
36
- }
37
-
38
- /**
39
- * Interface for running Wandelscript programs on the Nova instance and
40
- * tracking their progress and output
41
- */
42
- export class ProgramStateConnection {
43
- currentProgram: CurrentProgram = {}
44
- logs: ProgramRunnerLogEntry[] = []
45
-
46
- executionState = "idle" as "idle" | "starting" | "executing" | "stopping"
47
- currentlyExecutingProgramRunnerId = null as string | null
48
-
49
- programStateSocket: AutoReconnectingWebsocket
50
-
51
- constructor(readonly nova: NovaClient) {
52
- makeAutoObservable(this, {}, { autoBind: true })
53
-
54
- this.programStateSocket = nova.openReconnectingWebsocket(`/programs/state`)
55
-
56
- this.programStateSocket.addEventListener("message", (ev) => {
57
- const msg = tryParseJson(ev.data)
58
-
59
- if (!msg) {
60
- console.error("Failed to parse program state message", ev.data)
61
- return
62
- }
63
- if (msg.type === "update") {
64
- this.handleProgramStateMessage(msg)
65
- }
66
- })
67
- }
68
-
69
- /** Handle a program state update from the backend */
70
- async handleProgramStateMessage(msg: ProgramStateMessage) {
71
- const { runner } = msg
72
-
73
- // Ignoring other programs for now
74
- // TODO - show if execution state is busy from another source
75
- if (runner.id !== this.currentlyExecutingProgramRunnerId) return
76
-
77
- if (runner.state === ProgramState.Failed) {
78
- try {
79
- const runnerState = await this.nova.api.program.getProgramRun(runner.id)
80
-
81
- // TODO - wandelengine should send print statements in real time over
82
- // websocket as well, rather than at the end
83
- const stdout = (runnerState as any).stdout
84
- if (stdout) {
85
- this.log(stdout)
86
- }
87
- this.logError(
88
- `Program runner ${runner.id} failed with error: ${runnerState.error}\n${runnerState.traceback}`,
89
- )
90
- } catch (err) {
91
- this.logError(
92
- `Failed to retrieve results for program ${runner.id}: ${err}`,
93
- )
94
- }
95
-
96
- this.currentProgram.state = ProgramState.Failed
97
-
98
- this.gotoIdleState()
99
- } else if (runner.state === ProgramState.Stopped) {
100
- try {
101
- const runnerState = await this.nova.api.program.getProgramRun(runner.id)
102
-
103
- const stdout = (runnerState as any).stdout
104
- if (stdout) {
105
- this.log(stdout)
106
- }
107
-
108
- this.currentProgram.state = ProgramState.Stopped
109
- this.log(`Program runner ${runner.id} stopped`)
110
- } catch (err) {
111
- this.logError(
112
- `Failed to retrieve results for program ${runner.id}: ${err}`,
113
- )
114
- }
115
-
116
- this.gotoIdleState()
117
- } else if (runner.state === ProgramState.Completed) {
118
- try {
119
- const runnerState = await this.nova.api.program.getProgramRun(runner.id)
120
-
121
- const stdout = (runnerState as any).stdout
122
- if (stdout) {
123
- this.log(stdout)
124
- }
125
- this.log(
126
- `Program runner ${runner.id} finished successfully in ${runner.execution_time?.toFixed(2)} seconds`,
127
- )
128
-
129
- this.currentProgram.state = ProgramState.Completed
130
- } catch (err) {
131
- this.logError(
132
- `Failed to retrieve results for program ${runner.id}: ${err}`,
133
- )
134
- }
135
-
136
- this.gotoIdleState()
137
- } else if (runner.state === ProgramState.Running) {
138
- this.currentProgram.state = ProgramState.Running
139
- this.log(`Program runner ${runner.id} now running`)
140
- } else if (runner.state !== ProgramState.NotStarted) {
141
- console.error(runner)
142
- this.logError(
143
- `Program runner ${runner.id} entered unexpected state: ${runner.state}`,
144
- )
145
- this.currentProgram.state = ProgramState.NotStarted
146
- this.gotoIdleState()
147
- }
148
- }
149
-
150
- /** Call when a program is no longer executing */
151
- gotoIdleState() {
152
- runInAction(() => {
153
- this.executionState = "idle"
154
- })
155
- this.currentlyExecutingProgramRunnerId = null
156
- }
157
-
158
- async executeProgram(
159
- wandelscript: string,
160
- initial_state?: Object,
161
- activeRobot?: MotionStreamConnection,
162
- ) {
163
- this.currentProgram = {
164
- wandelscript: wandelscript,
165
- state: ProgramState.NotStarted,
166
- }
167
-
168
- const { currentProgram: openProgram } = this
169
- if (!openProgram) return
170
- runInAction(() => {
171
- this.executionState = "starting"
172
- })
173
-
174
- // WOS-1539: Wandelengine parser currently breaks if there are empty lines with indentation
175
- const trimmedCode = openProgram.wandelscript!.replaceAll(/^\s*$/gm, "")
176
-
177
- try {
178
- const programRunnerRef = await this.nova.api.program.createProgramRun(
179
- {
180
- code: trimmedCode,
181
- initial_state: initial_state,
182
- default_robot: activeRobot?.wandelscriptIdentifier,
183
- } as any,
184
- {
185
- headers: {
186
- "Content-Type": "application/json",
187
- },
188
- },
189
- )
190
-
191
- this.log(`Created program runner ${programRunnerRef.id}"`)
192
- runInAction(() => {
193
- this.executionState = "executing"
194
- })
195
- this.currentlyExecutingProgramRunnerId = programRunnerRef.id
196
- } catch (error) {
197
- if (error instanceof AxiosError && error.response && error.request) {
198
- this.logError(
199
- `${error.response.status} ${error.response.statusText} from ${error.response.config.url} ${JSON.stringify(error.response.data)}`,
200
- )
201
- } else {
202
- this.logError(JSON.stringify(error))
203
- }
204
- runInAction(() => {
205
- this.executionState = "idle"
206
- })
207
- }
208
- }
209
-
210
- async stopProgram() {
211
- if (!this.currentlyExecutingProgramRunnerId) return
212
- runInAction(() => {
213
- this.executionState = "stopping"
214
- })
215
-
216
- try {
217
- await this.nova.api.program.stopProgramRun(
218
- this.currentlyExecutingProgramRunnerId,
219
- )
220
- } catch (err) {
221
- // Reactivate the stop button so user can try again
222
- runInAction(() => {
223
- this.executionState = "executing"
224
- })
225
- throw err
226
- }
227
- }
228
-
229
- reset() {
230
- this.currentProgram = {}
231
- }
232
-
233
- log(message: string) {
234
- console.log(message)
235
- this.logs.push({
236
- timestamp: Date.now(),
237
- message,
238
- })
239
- }
240
-
241
- logError(message: string) {
242
- console.log(message)
243
- this.logs.push({
244
- timestamp: Date.now(),
245
- message,
246
- level: "error",
247
- })
248
- }
249
- }
@@ -1,55 +0,0 @@
1
- import type { TcpPose } from "@wandelbots/nova-api/v2"
2
-
3
- export function jointValuesEqual(
4
- oldJointValues: number[],
5
- newJointValues: number[],
6
- changeDeltaThreshold: number,
7
- ): boolean {
8
- if (newJointValues.length !== oldJointValues.length) {
9
- return true
10
- }
11
-
12
- for (let jointIndex = 0; jointIndex < newJointValues.length; jointIndex++) {
13
- if (
14
- Math.abs(newJointValues[jointIndex]! - oldJointValues[jointIndex]!) >
15
- changeDeltaThreshold
16
- ) {
17
- return false
18
- }
19
- }
20
-
21
- return true
22
- }
23
-
24
- export function tcpPoseEqual(
25
- oldTcp: TcpPose | undefined,
26
- newTcp: TcpPose | undefined,
27
- changeDeltaThreshold: number,
28
- ): boolean {
29
- // undefined -> defined (+reverse) transition
30
- if ((oldTcp === undefined && newTcp) || (oldTcp && newTcp === undefined)) {
31
- return false
32
- }
33
-
34
- // the typechecker cannot resolve states to "!= undefined" if "&&" is used
35
- if (oldTcp === undefined || newTcp === undefined) {
36
- return true
37
- }
38
-
39
- let changedDelta = 0
40
- changedDelta += Math.abs(oldTcp.orientation[0] - newTcp.orientation[0])
41
- changedDelta += Math.abs(oldTcp.orientation[1] - newTcp.orientation[1])
42
- changedDelta += Math.abs(oldTcp.orientation[2] - newTcp.orientation[2])
43
- changedDelta += Math.abs(oldTcp.position[0] - newTcp.position[0])
44
- changedDelta += Math.abs(oldTcp.position[1] - newTcp.position[1])
45
- changedDelta += Math.abs(oldTcp.position[2] - newTcp.position[2])
46
-
47
- if (changedDelta > changeDeltaThreshold) {
48
- return false
49
- }
50
-
51
- return (
52
- oldTcp.coordinate_system === newTcp.coordinate_system &&
53
- oldTcp.tcp === newTcp.tcp
54
- )
55
- }