@wandelbots/nova-js 3.7.0-pr.267.2d2af4c → 3.7.0-pr.276.de5eb8e
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/README.md +3 -46
- package/dist/AutoReconnectingWebsocket-9Of5_BJe.d.cts +68 -0
- package/dist/AutoReconnectingWebsocket-9Of5_BJe.d.cts.map +1 -0
- package/dist/LoginWithAuth0-oZFpwe7m.cjs +409 -0
- package/dist/LoginWithAuth0-oZFpwe7m.cjs.map +1 -0
- package/dist/NovaClient-4PG1cMau.d.cts +346 -0
- package/dist/NovaClient-4PG1cMau.d.cts.map +1 -0
- package/dist/NovaClient-B-QdK0HR.cjs +2035 -0
- package/dist/NovaClient-B-QdK0HR.cjs.map +1 -0
- package/dist/index.cjs +54 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +104 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/lib/v1/index.cjs +196 -0
- package/dist/lib/v1/index.cjs.map +1 -0
- package/dist/lib/v1/index.d.cts +62 -0
- package/dist/lib/v1/index.d.cts.map +1 -0
- package/dist/lib/v2/index.cjs +825 -0
- package/dist/lib/v2/index.cjs.map +1 -0
- package/dist/lib/v2/index.d.cts +124 -0
- package/dist/lib/v2/index.d.cts.map +1 -0
- package/dist/lib/v2/index.d.mts +6 -1
- package/dist/lib/v2/index.d.mts.map +1 -1
- package/dist/lib/v2/index.mjs +6 -1
- package/dist/lib/v2/index.mjs.map +1 -1
- package/package.json +11 -11
- package/src/lib/v1/index.ts +1 -1
- package/src/lib/v2/NovaCellAPIClient.ts +14 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://github.com/wandelbotsgmbh/nova-js/actions/workflows/release.yml)
|
|
6
6
|
[](https://deepwiki.com/wandelbotsgmbh/nova-js)
|
|
7
7
|
|
|
8
|
-
This library provides an idiomatic TypeScript client for working with the Wandelbots NOVA API.
|
|
8
|
+
This library provides an idiomatic TypeScript client for working with the [Wandelbots NOVA](https://docs.wandelbots.io) robotics software platform API.
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
11
|
npm install @wandelbots/nova-js
|
|
@@ -19,18 +19,12 @@ If you develop a React application we also provide a set of [React components](h
|
|
|
19
19
|
- [API calls](#api-calls)
|
|
20
20
|
- [API version support](#api-version-support)
|
|
21
21
|
- [Opening websockets](#opening-websockets)
|
|
22
|
-
- [Execute Wandelscript (V1)](#execute-wandelscript-v1)
|
|
23
22
|
|
|
24
23
|
## Basic usage
|
|
25
24
|
|
|
26
|
-
The core of this package is the `NovaClient`, which represents a connection to a configured robot cell on a given
|
|
25
|
+
The core of this package is the `NovaClient`, which represents a connection to a configured robot cell on a given NOVA instance:
|
|
27
26
|
|
|
28
27
|
```ts
|
|
29
|
-
// Please make sure you import NovaClient from "@wandelbots/nova-js/v2"
|
|
30
|
-
//
|
|
31
|
-
// The NovaClient from "@wandelbots/nova-js" is still API v1,
|
|
32
|
-
// but it will be removed in the future, use "@wandelbots/nova-js/v1" if
|
|
33
|
-
// you need the API v1 client
|
|
34
28
|
import { NovaClient } from "@wandelbots/nova-js/v2"
|
|
35
29
|
|
|
36
30
|
const nova = new NovaClient({
|
|
@@ -54,31 +48,6 @@ const controllerIds = await nova.api.controller.listRobotControllers()
|
|
|
54
48
|
|
|
55
49
|
Documentation for the various API endpoints is available on your Nova instance at `/api/v2/ui` or on [portal.wandelbots.io](https://portal.wandelbots.io/docs/api/v2/ui/)
|
|
56
50
|
|
|
57
|
-
|
|
58
|
-
## API version support
|
|
59
|
-
|
|
60
|
-
This library supports **Nova API v1** and **v2**. Please note that except for Wandelscript execution, usage of **API v1** is deprecated and not recommended.
|
|
61
|
-
|
|
62
|
-
V1 usage:
|
|
63
|
-
|
|
64
|
-
```ts
|
|
65
|
-
// The NovaClient from "@wandelbots/nova-js" is still API v1,
|
|
66
|
-
// but it will be removed in the future, use "@wandelbots/nova-js/v1" if
|
|
67
|
-
// you need the API v1 client
|
|
68
|
-
import { NovaClient } from "@wandelbots/nova-js/v1"
|
|
69
|
-
|
|
70
|
-
const nova = new NovaClient({
|
|
71
|
-
instanceUrl: "https://example.instance.wandelbots.io",
|
|
72
|
-
cellId: "cell",
|
|
73
|
-
accessToken: "...",
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
// Deprecated API version is still callable
|
|
77
|
-
const { instances } = await nova.api.controller.listControllers()
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
*Please note*: When using the v1 client, please make sure to add `"three"` to your package.json, since it will be moved to peer dependency in *v4.0* of this library.
|
|
81
|
-
|
|
82
51
|
## Opening websockets
|
|
83
52
|
|
|
84
53
|
`NovaClient` has various convenience features for websocket handling in general. Use `openReconnectingWebsocket` to get a persistent socket for a given Nova streaming endpoint that will handle unexpected closes with exponential backoff:
|
|
@@ -91,7 +60,7 @@ this.programStateSocket.addEventListener("message", (ev) => {
|
|
|
91
60
|
})
|
|
92
61
|
```
|
|
93
62
|
|
|
94
|
-
Websockets on a given
|
|
63
|
+
Websockets on a given NOVA client are deduplicated by path, so if you call `openReconnectingWebsocket` twice with the same path you'll get the same object. The exception is if you called `dispose`, which you may do to permanently clean up a reconnecting websocket and free its resources:
|
|
95
64
|
|
|
96
65
|
```ts
|
|
97
66
|
programStateSocket.dispose()
|
|
@@ -99,18 +68,6 @@ programStateSocket.dispose()
|
|
|
99
68
|
|
|
100
69
|
The reconnecting websocket interface is fairly low-level and you won't get type safety on the messages. So when available, you'll likely want to use one of the following endpoint-specific abstractions instead which are built on top!
|
|
101
70
|
|
|
102
|
-
## Execute Wandelscript (V1)
|
|
103
|
-
|
|
104
|
-
The `ProgramStateConnection` provides an object which allows to execute and stop a given Wandelscript.
|
|
105
|
-
|
|
106
|
-
```ts
|
|
107
|
-
import script from "./example.ws"
|
|
108
|
-
...
|
|
109
|
-
programRunner.executeProgram(script)
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
You can `stop` the current execution or listen to state updates of your wandelscript code by observing the `programRunner.executionState`.
|
|
113
|
-
|
|
114
71
|
## Contributing
|
|
115
72
|
|
|
116
73
|
If you would like to contribute a change to this repository, see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import ReconnectingWebSocket from "reconnecting-websocket";
|
|
2
|
+
import { AxiosResponse, InternalAxiosRequestConfig } from "axios";
|
|
3
|
+
|
|
4
|
+
//#region src/lib/v1/mock/MockNovaInstance.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Ultra-simplified mock Nova server for testing stuff
|
|
7
|
+
*/
|
|
8
|
+
declare class MockNovaInstance$1 {
|
|
9
|
+
readonly connections: AutoReconnectingWebsocket[];
|
|
10
|
+
handleAPIRequest(config: InternalAxiosRequestConfig): Promise<AxiosResponse>;
|
|
11
|
+
handleWebsocketConnection(socket: AutoReconnectingWebsocket): void;
|
|
12
|
+
handleWebsocketMessage(socket: AutoReconnectingWebsocket, message: string): void;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/lib/v2/mock/MockNovaInstance.d.ts
|
|
16
|
+
/**
|
|
17
|
+
* Ultra-simplified mock Nova server for testing stuff
|
|
18
|
+
*/
|
|
19
|
+
declare class MockNovaInstance {
|
|
20
|
+
readonly connections: AutoReconnectingWebsocket[];
|
|
21
|
+
handleAPIRequest(config: InternalAxiosRequestConfig): Promise<AxiosResponse>;
|
|
22
|
+
handleWebsocketConnection(socket: AutoReconnectingWebsocket): void;
|
|
23
|
+
handleWebsocketMessage(socket: AutoReconnectingWebsocket, message: string): void;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/lib/AutoReconnectingWebsocket.d.ts
|
|
27
|
+
declare class AutoReconnectingWebsocket extends ReconnectingWebSocket {
|
|
28
|
+
readonly opts: {
|
|
29
|
+
mock?: MockNovaInstance$1 | MockNovaInstance;
|
|
30
|
+
onDispose?: () => void;
|
|
31
|
+
};
|
|
32
|
+
receivedFirstMessage?: MessageEvent;
|
|
33
|
+
targetUrl: string;
|
|
34
|
+
disposed: boolean;
|
|
35
|
+
constructor(targetUrl: string, opts?: {
|
|
36
|
+
mock?: MockNovaInstance$1 | MockNovaInstance;
|
|
37
|
+
onDispose?: () => void;
|
|
38
|
+
});
|
|
39
|
+
changeUrl(targetUrl: string): void;
|
|
40
|
+
sendJson(data: unknown): void;
|
|
41
|
+
/**
|
|
42
|
+
* Permanently close this websocket and indicate that
|
|
43
|
+
* this object should not be used again.
|
|
44
|
+
**/
|
|
45
|
+
dispose(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Returns a promise that resolves once the websocket
|
|
48
|
+
* is in the OPEN state. */
|
|
49
|
+
opened(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Returns a promise that resolves once the websocket
|
|
52
|
+
* is in the CLOSED state. */
|
|
53
|
+
closed(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Returns a promise that resolves when the first message
|
|
56
|
+
* is received from the websocket. Resolves immediately if
|
|
57
|
+
* the first message has already been received.
|
|
58
|
+
*/
|
|
59
|
+
firstMessage(): Promise<MessageEvent<any>>;
|
|
60
|
+
/**
|
|
61
|
+
* Returns a promise that resolves when the next message
|
|
62
|
+
* is received from the websocket.
|
|
63
|
+
*/
|
|
64
|
+
nextMessage(): Promise<MessageEvent<any>>;
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { MockNovaInstance as n, MockNovaInstance$1 as r, AutoReconnectingWebsocket as t };
|
|
68
|
+
//# sourceMappingURL=AutoReconnectingWebsocket-9Of5_BJe.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AutoReconnectingWebsocket-9Of5_BJe.d.cts","names":[],"sources":["../src/lib/v1/mock/MockNovaInstance.ts","../src/lib/v2/mock/MockNovaInstance.ts","../src/lib/AutoReconnectingWebsocket.ts"],"mappings":";;;;;;AAeA;cAAa,kBAAA;EAAA,SACF,WAAA,EAAa,yBAAA;EAEhB,gBAAA,CACJ,MAAA,EAAQ,0BAAA,GACP,OAAA,CAAQ,aAAA;EAg8BX,yBAAA,CAA0B,MAAA,EAAQ,yBAAA;EAkOlC,sBAAA,CAAuB,MAAA,EAAQ,yBAAA,EAA2B,OAAA;AAAA;;;;;AAvqC5D;cCAa,gBAAA;EAAA,SACF,WAAA,EAAa,yBAAA;EAEhB,gBAAA,CACJ,MAAA,EAAQ,0BAAA,GACP,OAAA,CAAQ,aAAA;EAyCX,yBAAA,CAA0B,MAAA,EAAQ,yBAAA;EA+BlC,sBAAA,CAAuB,MAAA,EAAQ,yBAAA,EAA2B,OAAA;AAAA;;;cCxF/C,yBAAA,SAAkC,qBAAA;EAAA,SAOlC,IAAA;IACP,IAAA,GAAO,kBAAA,GAAsB,gBAAA;IAC7B,SAAA;EAAA;EARJ,oBAAA,GAAuB,YAAA;EACvB,SAAA;EACA,QAAA;cAGE,SAAA,UACS,IAAA;IACP,IAAA,GAAO,kBAAA,GAAsB,gBAAA;IAC7B,SAAA;EAAA;EA4CJ,SAAA,CAAU,SAAA;EAMV,QAAA,CAAS,IAAA;EF7CH;;;;EEyDN,OAAA,CAAA;EFy4BA;;;EE93BM,MAAA,CAAA,GAAM,OAAA;EFgmCmB;;;EEllCzB,MAAA,CAAA,GAAM,OAAA;EFklC6D;;;;ACvqC3E;ECqGQ,YAAA,CAAA,GAAY,OAAA,CAAA,YAAA;;;;;EA4BZ,WAAA,CAAA,GAAW,OAAA,CAAA,YAAA;AAAA"}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
//#region \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
//#endregion
|
|
23
|
+
let reconnecting_websocket = require("reconnecting-websocket");
|
|
24
|
+
reconnecting_websocket = __toESM(reconnecting_websocket, 1);
|
|
25
|
+
//#region src/lib/AutoReconnectingWebsocket.ts
|
|
26
|
+
var AutoReconnectingWebsocket = class extends reconnecting_websocket.default {
|
|
27
|
+
constructor(targetUrl, opts = {}) {
|
|
28
|
+
console.log("Opening websocket to", targetUrl);
|
|
29
|
+
super(() => this.targetUrl || targetUrl, void 0, { startClosed: true });
|
|
30
|
+
this.opts = opts;
|
|
31
|
+
this.disposed = false;
|
|
32
|
+
Object.defineProperty(this, "url", { get() {
|
|
33
|
+
return this.targetUrl;
|
|
34
|
+
} });
|
|
35
|
+
this.targetUrl = targetUrl;
|
|
36
|
+
this.addEventListener("open", () => {
|
|
37
|
+
console.log(`Websocket to ${this.url} opened`);
|
|
38
|
+
});
|
|
39
|
+
this.addEventListener("message", (ev) => {
|
|
40
|
+
if (!this.receivedFirstMessage) this.receivedFirstMessage = ev;
|
|
41
|
+
});
|
|
42
|
+
this.addEventListener("close", () => {
|
|
43
|
+
console.log(`Websocket to ${this.url} closed`);
|
|
44
|
+
});
|
|
45
|
+
const origReconnect = this.reconnect;
|
|
46
|
+
this.reconnect = () => {
|
|
47
|
+
if (this.opts.mock) this.opts.mock.handleWebsocketConnection(this);
|
|
48
|
+
else origReconnect.apply(this);
|
|
49
|
+
};
|
|
50
|
+
this.reconnect();
|
|
51
|
+
}
|
|
52
|
+
changeUrl(targetUrl) {
|
|
53
|
+
this.receivedFirstMessage = void 0;
|
|
54
|
+
this.targetUrl = targetUrl;
|
|
55
|
+
this.reconnect();
|
|
56
|
+
}
|
|
57
|
+
sendJson(data) {
|
|
58
|
+
if (this.opts.mock) this.opts.mock.handleWebsocketMessage(this, JSON.stringify(data));
|
|
59
|
+
else this.send(JSON.stringify(data));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Permanently close this websocket and indicate that
|
|
63
|
+
* this object should not be used again.
|
|
64
|
+
**/
|
|
65
|
+
dispose() {
|
|
66
|
+
this.close();
|
|
67
|
+
this.disposed = true;
|
|
68
|
+
if (this.opts.onDispose) this.opts.onDispose();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns a promise that resolves once the websocket
|
|
72
|
+
* is in the OPEN state. */
|
|
73
|
+
async opened() {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
if (this.readyState === WebSocket.OPEN) resolve();
|
|
76
|
+
else {
|
|
77
|
+
this.addEventListener("open", () => resolve());
|
|
78
|
+
this.addEventListener("error", reject);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Returns a promise that resolves once the websocket
|
|
84
|
+
* is in the CLOSED state. */
|
|
85
|
+
async closed() {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
if (this.readyState === WebSocket.CLOSED) resolve();
|
|
88
|
+
else {
|
|
89
|
+
this.addEventListener("close", () => resolve());
|
|
90
|
+
this.addEventListener("error", reject);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Returns a promise that resolves when the first message
|
|
96
|
+
* is received from the websocket. Resolves immediately if
|
|
97
|
+
* the first message has already been received.
|
|
98
|
+
*/
|
|
99
|
+
async firstMessage() {
|
|
100
|
+
if (this.receivedFirstMessage) return this.receivedFirstMessage;
|
|
101
|
+
return new Promise((resolve, reject) => {
|
|
102
|
+
const onMessage = (ev) => {
|
|
103
|
+
this.receivedFirstMessage = ev;
|
|
104
|
+
this.removeEventListener("message", onMessage);
|
|
105
|
+
this.removeEventListener("error", onError);
|
|
106
|
+
resolve(ev);
|
|
107
|
+
};
|
|
108
|
+
const onError = (ev) => {
|
|
109
|
+
this.removeEventListener("message", onMessage);
|
|
110
|
+
this.removeEventListener("error", onError);
|
|
111
|
+
reject(ev);
|
|
112
|
+
};
|
|
113
|
+
this.addEventListener("message", onMessage);
|
|
114
|
+
this.addEventListener("error", onError);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns a promise that resolves when the next message
|
|
119
|
+
* is received from the websocket.
|
|
120
|
+
*/
|
|
121
|
+
async nextMessage() {
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const onMessage = (ev) => {
|
|
124
|
+
this.removeEventListener("message", onMessage);
|
|
125
|
+
this.removeEventListener("error", onError);
|
|
126
|
+
resolve(ev);
|
|
127
|
+
};
|
|
128
|
+
const onError = (ev) => {
|
|
129
|
+
this.removeEventListener("message", onMessage);
|
|
130
|
+
this.removeEventListener("error", onError);
|
|
131
|
+
reject(ev);
|
|
132
|
+
};
|
|
133
|
+
this.addEventListener("message", onMessage);
|
|
134
|
+
this.addEventListener("error", onError);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/lib/availableStorage.ts
|
|
140
|
+
/**
|
|
141
|
+
* Safety wrapper around browser localStorage providing context availability
|
|
142
|
+
* checks and JSON parsing
|
|
143
|
+
*/
|
|
144
|
+
var AvailableStorage = class {
|
|
145
|
+
constructor() {
|
|
146
|
+
this.available = typeof window !== "undefined" && !!window.localStorage;
|
|
147
|
+
}
|
|
148
|
+
getJSON(key) {
|
|
149
|
+
if (!this.available) return null;
|
|
150
|
+
const result = window.localStorage.getItem(key);
|
|
151
|
+
if (result === null) return null;
|
|
152
|
+
try {
|
|
153
|
+
return JSON.parse(result);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
setJSON(key, obj) {
|
|
159
|
+
if (!this.available) return null;
|
|
160
|
+
window.localStorage.setItem(key, JSON.stringify(obj));
|
|
161
|
+
}
|
|
162
|
+
delete(key) {
|
|
163
|
+
if (!this.available) return null;
|
|
164
|
+
window.localStorage.removeItem(key);
|
|
165
|
+
}
|
|
166
|
+
setString(key, value) {
|
|
167
|
+
if (!this.available) return null;
|
|
168
|
+
window.localStorage.setItem(key, value);
|
|
169
|
+
}
|
|
170
|
+
getString(key) {
|
|
171
|
+
if (!this.available) return null;
|
|
172
|
+
return window.localStorage.getItem(key);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const availableStorage = new AvailableStorage();
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/lib/converters.ts
|
|
178
|
+
/**
|
|
179
|
+
* Parse a string as a URL, with options to enforce or default the scheme.
|
|
180
|
+
*/
|
|
181
|
+
function parseUrl(url, options = {}) {
|
|
182
|
+
const { scheme, defaultScheme } = options;
|
|
183
|
+
const schemeRegex = /^[a-zA-Z]+:\/\//;
|
|
184
|
+
if (scheme) {
|
|
185
|
+
url = url.replace(schemeRegex, "");
|
|
186
|
+
url = `${scheme}://${url}`;
|
|
187
|
+
} else if (defaultScheme && !schemeRegex.test(url)) url = `${defaultScheme}://${url}`;
|
|
188
|
+
return new URL(url);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Attempt to parse a string as a URL; return undefined if we can't
|
|
192
|
+
*/
|
|
193
|
+
function tryParseUrl(url, options = {}) {
|
|
194
|
+
try {
|
|
195
|
+
return parseUrl(url, options);
|
|
196
|
+
} catch {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Permissively parse a NOVA instance URL from a config variable.
|
|
202
|
+
* If scheme is not specified, defaults to https for *.wandelbots.io hosts,
|
|
203
|
+
* and http otherwise.
|
|
204
|
+
* Throws an error if a valid URL could not be determined.
|
|
205
|
+
*/
|
|
206
|
+
function parseNovaInstanceUrl(url) {
|
|
207
|
+
if (tryParseUrl(url, { defaultScheme: "http" })?.host.endsWith(".wandelbots.io")) return parseUrl(url, { defaultScheme: "https" });
|
|
208
|
+
else return parseUrl(url, { defaultScheme: "http" });
|
|
209
|
+
}
|
|
210
|
+
/** Try to parse something as JSON; return undefined if we can't */
|
|
211
|
+
function tryParseJson(json) {
|
|
212
|
+
try {
|
|
213
|
+
return JSON.parse(json);
|
|
214
|
+
} catch {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/** Try to turn something into JSON; return undefined if we can't */
|
|
219
|
+
function tryStringifyJson(json) {
|
|
220
|
+
try {
|
|
221
|
+
return JSON.stringify(json);
|
|
222
|
+
} catch {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Converts object parameters to query string.
|
|
228
|
+
* e.g. { a: "1", b: "2" } => "?a=1&b=2"
|
|
229
|
+
* {} => ""
|
|
230
|
+
*/
|
|
231
|
+
function makeUrlQueryString(obj) {
|
|
232
|
+
const str = new URLSearchParams(obj).toString();
|
|
233
|
+
return str ? `?${str}` : "";
|
|
234
|
+
}
|
|
235
|
+
/** Convert radians to degrees */
|
|
236
|
+
function radiansToDegrees(radians) {
|
|
237
|
+
return radians * (180 / Math.PI);
|
|
238
|
+
}
|
|
239
|
+
/** Convert degrees to radians */
|
|
240
|
+
function degreesToRadians(degrees) {
|
|
241
|
+
return degrees * (Math.PI / 180);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check for coordinate system id equivalence, accounting for the "world" default
|
|
245
|
+
* on empty/undefined values.
|
|
246
|
+
*/
|
|
247
|
+
function isSameCoordinateSystem(firstCoordSystem, secondCoordSystem) {
|
|
248
|
+
if (!firstCoordSystem) firstCoordSystem = "world";
|
|
249
|
+
if (!secondCoordSystem) secondCoordSystem = "world";
|
|
250
|
+
return firstCoordSystem === secondCoordSystem;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Helpful const for converting {x, y, z} to [x, y, z] and vice versa
|
|
254
|
+
*/
|
|
255
|
+
const XYZ_TO_VECTOR = {
|
|
256
|
+
x: 0,
|
|
257
|
+
y: 1,
|
|
258
|
+
z: 2
|
|
259
|
+
};
|
|
260
|
+
//#endregion
|
|
261
|
+
//#region src/LoginWithAuth0.ts
|
|
262
|
+
/**
|
|
263
|
+
* Mapping of stages to Auth0 configurations.
|
|
264
|
+
* The client ids are public identifiers for a specific auth0 application
|
|
265
|
+
* and are safe to include in client-side code.
|
|
266
|
+
* https://auth0.com/docs/get-started/applications/application-settings
|
|
267
|
+
*/
|
|
268
|
+
const auth0ConfigMap = {
|
|
269
|
+
dev: {
|
|
270
|
+
domain: `https://auth.portal.dev.wandelbots.io`,
|
|
271
|
+
clientId: "fLbJD0RLp5r2Dpucm5j8BjwMR6Hunfha"
|
|
272
|
+
},
|
|
273
|
+
stg: {
|
|
274
|
+
domain: `https://auth.portal.stg.wandelbots.io`,
|
|
275
|
+
clientId: "joVDeD9e786WzFNSGCqoVq7HNkWt5j6s"
|
|
276
|
+
},
|
|
277
|
+
prod: {
|
|
278
|
+
domain: `https://auth.portal.wandelbots.io`,
|
|
279
|
+
clientId: "J7WJUi38xVQdJAEBNRT9Xw1b0fXDb4J2"
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
/** Determine which Auth0 configuration to use based on instance URL */
|
|
283
|
+
const getAuth0Config = (instanceUrl) => {
|
|
284
|
+
if (instanceUrl.host.endsWith(".dev.wandelbots.io")) return auth0ConfigMap.dev;
|
|
285
|
+
if (instanceUrl.host.endsWith(".stg.wandelbots.io")) return auth0ConfigMap.stg;
|
|
286
|
+
if (instanceUrl.host.endsWith(".wandelbots.io")) return auth0ConfigMap.prod;
|
|
287
|
+
throw new Error(`Unable to authenticate with NOVA instance "${instanceUrl}". Auth0 login is only supported for cloud instances with hosts of the form "**.wandelbots.io".`);
|
|
288
|
+
};
|
|
289
|
+
/**
|
|
290
|
+
* Initializes Auth0 login process using redirect if necessary and retrieves an access token.
|
|
291
|
+
* Returns null when an access token should not be needed to authenticate (i.e. cookie auth
|
|
292
|
+
* when deployed on the instance domain)
|
|
293
|
+
*/
|
|
294
|
+
const loginWithAuth0 = async (instanceUrl) => {
|
|
295
|
+
if (typeof window === "undefined") throw new Error(`Access token must be set to use NovaClient when not in a browser environment.`);
|
|
296
|
+
if (instanceUrl.origin === window.location.origin) {
|
|
297
|
+
window.location.reload();
|
|
298
|
+
throw new Error("Failed to reload page to get auth details, please refresh manually");
|
|
299
|
+
}
|
|
300
|
+
const { Auth0Client } = await import("@auth0/auth0-spa-js");
|
|
301
|
+
const auth0Config = getAuth0Config(instanceUrl);
|
|
302
|
+
const auth0Client = new Auth0Client({
|
|
303
|
+
domain: auth0Config.domain,
|
|
304
|
+
clientId: auth0Config.clientId ?? "",
|
|
305
|
+
useRefreshTokens: false,
|
|
306
|
+
authorizationParams: {
|
|
307
|
+
audience: "nova-api",
|
|
308
|
+
redirect_uri: window.location.origin
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
if (window.location.search.includes("code=") && window.location.search.includes("state=")) {
|
|
312
|
+
const { appState } = await auth0Client.handleRedirectCallback();
|
|
313
|
+
window.history.replaceState({}, document.title, appState?.returnTo || window.location.pathname);
|
|
314
|
+
} else await auth0Client.loginWithRedirect();
|
|
315
|
+
return await auth0Client.getTokenSilently();
|
|
316
|
+
};
|
|
317
|
+
//#endregion
|
|
318
|
+
Object.defineProperty(exports, "AutoReconnectingWebsocket", {
|
|
319
|
+
enumerable: true,
|
|
320
|
+
get: function() {
|
|
321
|
+
return AutoReconnectingWebsocket;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
Object.defineProperty(exports, "XYZ_TO_VECTOR", {
|
|
325
|
+
enumerable: true,
|
|
326
|
+
get: function() {
|
|
327
|
+
return XYZ_TO_VECTOR;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
Object.defineProperty(exports, "__toESM", {
|
|
331
|
+
enumerable: true,
|
|
332
|
+
get: function() {
|
|
333
|
+
return __toESM;
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
Object.defineProperty(exports, "availableStorage", {
|
|
337
|
+
enumerable: true,
|
|
338
|
+
get: function() {
|
|
339
|
+
return availableStorage;
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
Object.defineProperty(exports, "degreesToRadians", {
|
|
343
|
+
enumerable: true,
|
|
344
|
+
get: function() {
|
|
345
|
+
return degreesToRadians;
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
Object.defineProperty(exports, "getAuth0Config", {
|
|
349
|
+
enumerable: true,
|
|
350
|
+
get: function() {
|
|
351
|
+
return getAuth0Config;
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
Object.defineProperty(exports, "isSameCoordinateSystem", {
|
|
355
|
+
enumerable: true,
|
|
356
|
+
get: function() {
|
|
357
|
+
return isSameCoordinateSystem;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
Object.defineProperty(exports, "loginWithAuth0", {
|
|
361
|
+
enumerable: true,
|
|
362
|
+
get: function() {
|
|
363
|
+
return loginWithAuth0;
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
Object.defineProperty(exports, "makeUrlQueryString", {
|
|
367
|
+
enumerable: true,
|
|
368
|
+
get: function() {
|
|
369
|
+
return makeUrlQueryString;
|
|
370
|
+
}
|
|
371
|
+
});
|
|
372
|
+
Object.defineProperty(exports, "parseNovaInstanceUrl", {
|
|
373
|
+
enumerable: true,
|
|
374
|
+
get: function() {
|
|
375
|
+
return parseNovaInstanceUrl;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
Object.defineProperty(exports, "parseUrl", {
|
|
379
|
+
enumerable: true,
|
|
380
|
+
get: function() {
|
|
381
|
+
return parseUrl;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
Object.defineProperty(exports, "radiansToDegrees", {
|
|
385
|
+
enumerable: true,
|
|
386
|
+
get: function() {
|
|
387
|
+
return radiansToDegrees;
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
Object.defineProperty(exports, "tryParseJson", {
|
|
391
|
+
enumerable: true,
|
|
392
|
+
get: function() {
|
|
393
|
+
return tryParseJson;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
Object.defineProperty(exports, "tryParseUrl", {
|
|
397
|
+
enumerable: true,
|
|
398
|
+
get: function() {
|
|
399
|
+
return tryParseUrl;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
Object.defineProperty(exports, "tryStringifyJson", {
|
|
403
|
+
enumerable: true,
|
|
404
|
+
get: function() {
|
|
405
|
+
return tryStringifyJson;
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
//# sourceMappingURL=LoginWithAuth0-oZFpwe7m.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LoginWithAuth0-oZFpwe7m.cjs","names":["ReconnectingWebSocket"],"sources":["../src/lib/AutoReconnectingWebsocket.ts","../src/lib/availableStorage.ts","../src/lib/converters.ts","../src/LoginWithAuth0.ts"],"sourcesContent":["import ReconnectingWebSocket, { type ErrorEvent } from \"reconnecting-websocket\"\nimport type * as v1 from \"./v1/mock/MockNovaInstance\"\nimport type * as v2 from \"./v2/mock/MockNovaInstance\"\n\nexport class AutoReconnectingWebsocket extends ReconnectingWebSocket {\n receivedFirstMessage?: MessageEvent\n targetUrl: string\n disposed = false\n\n constructor(\n targetUrl: string,\n readonly opts: {\n mock?: v1.MockNovaInstance | v2.MockNovaInstance\n onDispose?: () => void\n } = {},\n ) {\n console.log(\"Opening websocket to\", targetUrl)\n\n super(() => this.targetUrl || targetUrl, undefined, {\n startClosed: true,\n })\n\n // Reconnecting websocket doesn't set this properly with startClosed\n Object.defineProperty(this, \"url\", {\n get() {\n return this.targetUrl\n },\n })\n\n this.targetUrl = targetUrl\n\n this.addEventListener(\"open\", () => {\n console.log(`Websocket to ${this.url} opened`)\n })\n\n this.addEventListener(\"message\", (ev) => {\n if (!this.receivedFirstMessage) {\n this.receivedFirstMessage = ev\n }\n })\n\n this.addEventListener(\"close\", () => {\n console.log(`Websocket to ${this.url} closed`)\n })\n\n const origReconnect = this.reconnect\n this.reconnect = () => {\n if (this.opts.mock) {\n this.opts.mock.handleWebsocketConnection(this)\n } else {\n origReconnect.apply(this)\n }\n }\n\n this.reconnect()\n }\n\n changeUrl(targetUrl: string) {\n this.receivedFirstMessage = undefined\n this.targetUrl = targetUrl\n this.reconnect()\n }\n\n sendJson(data: unknown) {\n if (this.opts.mock) {\n this.opts.mock.handleWebsocketMessage(this, JSON.stringify(data))\n } else {\n this.send(JSON.stringify(data))\n }\n }\n\n /**\n * Permanently close this websocket and indicate that\n * this object should not be used again.\n **/\n dispose() {\n this.close()\n this.disposed = true\n if (this.opts.onDispose) {\n this.opts.onDispose()\n }\n }\n\n /**\n * Returns a promise that resolves once the websocket\n * is in the OPEN state. */\n async opened() {\n return new Promise<void>((resolve, reject) => {\n if (this.readyState === WebSocket.OPEN) {\n resolve()\n } else {\n this.addEventListener(\"open\", () => resolve())\n this.addEventListener(\"error\", reject)\n }\n })\n }\n\n /**\n * Returns a promise that resolves once the websocket\n * is in the CLOSED state. */\n async closed() {\n return new Promise<void>((resolve, reject) => {\n if (this.readyState === WebSocket.CLOSED) {\n resolve()\n } else {\n this.addEventListener(\"close\", () => resolve())\n this.addEventListener(\"error\", reject)\n }\n })\n }\n\n /**\n * Returns a promise that resolves when the first message\n * is received from the websocket. Resolves immediately if\n * the first message has already been received.\n */\n async firstMessage() {\n if (this.receivedFirstMessage) {\n return this.receivedFirstMessage\n }\n\n return new Promise<MessageEvent>((resolve, reject) => {\n const onMessage = (ev: MessageEvent) => {\n this.receivedFirstMessage = ev\n this.removeEventListener(\"message\", onMessage)\n this.removeEventListener(\"error\", onError)\n resolve(ev)\n }\n\n const onError = (ev: ErrorEvent) => {\n this.removeEventListener(\"message\", onMessage)\n this.removeEventListener(\"error\", onError)\n reject(ev)\n }\n\n this.addEventListener(\"message\", onMessage)\n this.addEventListener(\"error\", onError)\n })\n }\n\n /**\n * Returns a promise that resolves when the next message\n * is received from the websocket.\n */\n async nextMessage() {\n return new Promise<MessageEvent>((resolve, reject) => {\n const onMessage = (ev: MessageEvent) => {\n this.removeEventListener(\"message\", onMessage)\n this.removeEventListener(\"error\", onError)\n resolve(ev)\n }\n\n const onError = (ev: ErrorEvent) => {\n this.removeEventListener(\"message\", onMessage)\n this.removeEventListener(\"error\", onError)\n reject(ev)\n }\n\n this.addEventListener(\"message\", onMessage)\n this.addEventListener(\"error\", onError)\n })\n }\n}\n","/**\n * Safety wrapper around browser localStorage providing context availability\n * checks and JSON parsing\n */\nclass AvailableStorage {\n available = typeof window !== \"undefined\" && !!window.localStorage\n\n getJSON<T>(key: string): Partial<T> | null {\n if (!this.available) return null\n\n const result = window.localStorage.getItem(key)\n if (result === null) return null\n\n try {\n return JSON.parse(result)\n } catch (err) {\n return null\n }\n }\n\n setJSON(key: string, obj: unknown) {\n if (!this.available) return null\n\n window.localStorage.setItem(key, JSON.stringify(obj))\n }\n\n delete(key: string) {\n if (!this.available) return null\n\n window.localStorage.removeItem(key)\n }\n\n setString(key: string, value: string) {\n if (!this.available) return null\n\n window.localStorage.setItem(key, value)\n }\n\n getString(key: string): string | null {\n if (!this.available) return null\n\n return window.localStorage.getItem(key)\n }\n}\n\nexport const availableStorage = new AvailableStorage()\n","export type URLParseOptions = {\n /**\n * Ignore any scheme in the input string and force this scheme instead.\n */\n scheme?: \"http\" | \"https\"\n /**\n * If the input string does not include a scheme, use this as the default\n * scheme.\n */\n defaultScheme?: \"http\" | \"https\"\n}\n\n/**\n * Parse a string as a URL, with options to enforce or default the scheme.\n */\nexport function parseUrl(url: string, options: URLParseOptions = {}): URL {\n const { scheme, defaultScheme } = options\n\n const schemeRegex = /^[a-zA-Z]+:\\/\\//\n\n if (scheme) {\n // Force the scheme by removing any existing scheme and prepending the desired one\n url = url.replace(schemeRegex, \"\")\n url = `${scheme}://${url}`\n } else if (defaultScheme && !schemeRegex.test(url)) {\n // No scheme is present, add the default one\n url = `${defaultScheme}://${url}`\n }\n\n return new URL(url)\n}\n\n/**\n * Attempt to parse a string as a URL; return undefined if we can't\n */\nexport function tryParseUrl(\n url: string,\n options: URLParseOptions = {},\n): URL | undefined {\n try {\n return parseUrl(url, options)\n } catch {\n return undefined\n }\n}\n\n/**\n * Permissively parse a NOVA instance URL from a config variable.\n * If scheme is not specified, defaults to https for *.wandelbots.io hosts,\n * and http otherwise.\n * Throws an error if a valid URL could not be determined.\n */\nexport function parseNovaInstanceUrl(url: string): URL {\n const testUrl = tryParseUrl(url, { defaultScheme: \"http\" })\n if (testUrl?.host.endsWith(\".wandelbots.io\")) {\n return parseUrl(url, { defaultScheme: \"https\" })\n } else {\n return parseUrl(url, { defaultScheme: \"http\" })\n }\n}\n\n/** Try to parse something as JSON; return undefined if we can't */\n// biome-ignore lint/suspicious/noExplicitAny: it's json\nexport function tryParseJson(json: unknown): any {\n try {\n return JSON.parse(json as string)\n } catch {\n return undefined\n }\n}\n\n/** Try to turn something into JSON; return undefined if we can't */\nexport function tryStringifyJson(json: unknown): string | undefined {\n try {\n return JSON.stringify(json)\n } catch {\n return undefined\n }\n}\n\n/**\n * Converts object parameters to query string.\n * e.g. { a: \"1\", b: \"2\" } => \"?a=1&b=2\"\n * {} => \"\"\n */\nexport function makeUrlQueryString(obj: Record<string, string>): string {\n const str = new URLSearchParams(obj).toString()\n return str ? `?${str}` : \"\"\n}\n\n/** Convert radians to degrees */\nexport function radiansToDegrees(radians: number): number {\n return radians * (180 / Math.PI)\n}\n\n/** Convert degrees to radians */\nexport function degreesToRadians(degrees: number): number {\n return degrees * (Math.PI / 180)\n}\n\n/**\n * Check for coordinate system id equivalence, accounting for the \"world\" default\n * on empty/undefined values.\n */\nexport function isSameCoordinateSystem(\n firstCoordSystem: string | undefined,\n secondCoordSystem: string | undefined,\n) {\n if (!firstCoordSystem) firstCoordSystem = \"world\"\n if (!secondCoordSystem) secondCoordSystem = \"world\"\n\n return firstCoordSystem === secondCoordSystem\n}\n\n/**\n * Helpful const for converting {x, y, z} to [x, y, z] and vice versa\n */\nexport const XYZ_TO_VECTOR = { x: 0, y: 1, z: 2 }\n","/**\n * Mapping of stages to Auth0 configurations.\n * The client ids are public identifiers for a specific auth0 application\n * and are safe to include in client-side code.\n * https://auth0.com/docs/get-started/applications/application-settings\n */\nconst auth0ConfigMap = {\n dev: {\n domain: `https://auth.portal.dev.wandelbots.io`,\n clientId: \"fLbJD0RLp5r2Dpucm5j8BjwMR6Hunfha\",\n },\n stg: {\n domain: `https://auth.portal.stg.wandelbots.io`,\n clientId: \"joVDeD9e786WzFNSGCqoVq7HNkWt5j6s\",\n },\n prod: {\n domain: `https://auth.portal.wandelbots.io`,\n clientId: \"J7WJUi38xVQdJAEBNRT9Xw1b0fXDb4J2\",\n },\n}\n\n/** Determine which Auth0 configuration to use based on instance URL */\nexport const getAuth0Config = (instanceUrl: URL) => {\n if (instanceUrl.host.endsWith(\".dev.wandelbots.io\")) return auth0ConfigMap.dev\n if (instanceUrl.host.endsWith(\".stg.wandelbots.io\")) return auth0ConfigMap.stg\n if (instanceUrl.host.endsWith(\".wandelbots.io\")) return auth0ConfigMap.prod\n throw new Error(\n `Unable to authenticate with NOVA instance \"${instanceUrl}\". Auth0 login is only supported for cloud instances with hosts of the form \"**.wandelbots.io\".`,\n )\n}\n\n/**\n * Initializes Auth0 login process using redirect if necessary and retrieves an access token.\n * Returns null when an access token should not be needed to authenticate (i.e. cookie auth\n * when deployed on the instance domain)\n */\nexport const loginWithAuth0 = async (\n instanceUrl: URL,\n): Promise<string | null> => {\n if (typeof window === \"undefined\") {\n throw new Error(\n `Access token must be set to use NovaClient when not in a browser environment.`,\n )\n }\n\n if (instanceUrl.origin === window.location.origin) {\n // When deployed on the instance itself, our auth is handled by cookies\n // and no access token is needed-- just need to reload the page and it'll\n // login again / set cookie as needed\n window.location.reload()\n throw new Error(\n \"Failed to reload page to get auth details, please refresh manually\",\n )\n }\n\n // If we're on localhost or another domain, we need to do the full oauth flow\n // Note this will ONLY work for origins which are whitelisted as a redirect_uri\n // in the auth0 config, currently\n const { Auth0Client } = await import(\"@auth0/auth0-spa-js\")\n\n const auth0Config = getAuth0Config(instanceUrl)\n\n const auth0Client = new Auth0Client({\n domain: auth0Config.domain,\n clientId: auth0Config.clientId ?? \"\",\n useRefreshTokens: false,\n authorizationParams: {\n audience: \"nova-api\",\n redirect_uri: window.location.origin,\n },\n })\n\n // If the URL includes a redirect result, handle it\n if (\n window.location.search.includes(\"code=\") &&\n window.location.search.includes(\"state=\")\n ) {\n const { appState } = await auth0Client.handleRedirectCallback()\n // Return to the URL the user was originally on before the redirect\n window.history.replaceState(\n {},\n document.title,\n appState?.returnTo || window.location.pathname,\n )\n } else {\n // Initiate login with redirect\n await auth0Client.loginWithRedirect()\n }\n\n // Once logged in, retrieve the access token silently\n const accessToken = await auth0Client.getTokenSilently()\n return accessToken\n}\n"],"mappings":"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"}
|