@vuu-ui/vuu-data-remote 2.1.19-beta.1 → 2.1.19-beta.2

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/package.json CHANGED
@@ -1,27 +1,26 @@
1
1
  {
2
- "version": "2.1.19-beta.1",
2
+ "version": "2.1.19-beta.2",
3
3
  "author": "heswell",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "devDependencies": {
7
- "@vuu-ui/vuu-data-types": "2.1.19-beta.1",
8
- "@vuu-ui/vuu-table-types": "2.1.19-beta.1",
9
- "@vuu-ui/vuu-filter-types": "2.1.19-beta.1",
10
- "@vuu-ui/vuu-protocol-types": "2.1.19-beta.1"
7
+ "@vuu-ui/vuu-data-types": "2.1.19-beta.2",
8
+ "@vuu-ui/vuu-table-types": "2.1.19-beta.2",
9
+ "@vuu-ui/vuu-filter-types": "2.1.19-beta.2",
10
+ "@vuu-ui/vuu-protocol-types": "2.1.19-beta.2"
11
11
  },
12
12
  "dependencies": {
13
- "@vuu-ui/vuu-filter-parser": "2.1.19-beta.1",
14
- "@vuu-ui/vuu-utils": "2.1.19-beta.1"
13
+ "@vuu-ui/vuu-filter-parser": "2.1.19-beta.2",
14
+ "@vuu-ui/vuu-utils": "2.1.19-beta.2"
15
15
  },
16
16
  "files": [
17
17
  "README.md",
18
- "esm",
19
- "cjs",
18
+ "src",
20
19
  "/types"
21
20
  ],
22
21
  "exports": {
23
22
  ".": {
24
- "import": "./index.js",
23
+ "import": "./src/index.js",
25
24
  "types": "./types/index.d.ts"
26
25
  }
27
26
  },
@@ -0,0 +1,134 @@
1
+ import { DeferredPromise, EventEmitter, isConnectionQualityMetrics, isRequestResponse, isTableSchemaMessage, messageHasResult, uuid } from "@vuu-ui/vuu-utils";
2
+ import { isWebSocketConnectionStatus } from "./WebSocketConnection.js";
3
+ import { DedicatedWorker } from "./DedicatedWorker.js";
4
+ import { shouldMessageBeRoutedToDataSource } from "./data-source.js";
5
+ class ConnectionManager extends EventEmitter {
6
+ static #instance;
7
+ #connectionStatus = "closed";
8
+ #deferredServerAPI = new DeferredPromise();
9
+ #pendingRequests = new Map();
10
+ #viewports = new Map();
11
+ #worker;
12
+ constructor(){
13
+ super();
14
+ this.#worker = new DedicatedWorker(this.handleMessageFromWorker);
15
+ }
16
+ static get instance() {
17
+ if (!ConnectionManager.#instance) ConnectionManager.#instance = new ConnectionManager();
18
+ return ConnectionManager.#instance;
19
+ }
20
+ get connectionStatus() {
21
+ return this.#connectionStatus;
22
+ }
23
+ get connected() {
24
+ return "connected" === this.#connectionStatus || "reconnected" === this.#connectionStatus;
25
+ }
26
+ async connect(options, throwOnRejected = false) {
27
+ try {
28
+ const result = await this.#worker.connect(options);
29
+ if ("connected" === result) this.#deferredServerAPI.resolve(this.connectedServerAPI);
30
+ return result;
31
+ } catch (err) {
32
+ if (!throwOnRejected) return "connection-failed";
33
+ throw err;
34
+ }
35
+ }
36
+ disableActiveSubscriptions() {
37
+ console.log("[ConnectionManager] disableActiveSubscriptions");
38
+ this.#worker.send({
39
+ type: "disable-all-active"
40
+ });
41
+ }
42
+ enableActiveSubscriptions() {
43
+ console.log("[ConnectionManager] enableActiveSubscriptions");
44
+ this.#worker.send({
45
+ type: "enable-all-active"
46
+ });
47
+ }
48
+ handleMessageFromWorker = (message)=>{
49
+ if (shouldMessageBeRoutedToDataSource(message)) {
50
+ const viewport = this.#viewports.get(message.clientViewportId);
51
+ if (viewport) viewport.postMessageToClientDataSource(message);
52
+ else console.error(`[ConnectionManager] ${message.type} message received, viewport not found`);
53
+ } else if (isWebSocketConnectionStatus(message)) {
54
+ this.#connectionStatus = message;
55
+ this.emit("connection-status", message);
56
+ } else if (isConnectionQualityMetrics(message)) this.emit("connection-metrics", message);
57
+ else if (isRequestResponse(message)) {
58
+ const { requestId } = message;
59
+ if (this.#pendingRequests.has(requestId)) {
60
+ const { resolve } = this.#pendingRequests.get(requestId);
61
+ this.#pendingRequests.delete(requestId);
62
+ const { requestId: _, ...messageWithoutRequestId } = message;
63
+ resolve(messageHasResult(message) ? message.result : isTableSchemaMessage(message) ? message.tableSchema : messageWithoutRequestId);
64
+ } else console.warn("%cConnectionManager Unexpected message from the worker", "color:red;font-weight:bold;");
65
+ }
66
+ };
67
+ get serverAPI() {
68
+ return this.#deferredServerAPI.promise;
69
+ }
70
+ connectedServerAPI = {
71
+ subscribe: (message, callback)=>{
72
+ if (this.#viewports.get(message.viewport)) throw Error("ConnectionManager attempting to subscribe with an existing viewport id");
73
+ this.#viewports.set(message.viewport, {
74
+ status: "subscribing",
75
+ request: message,
76
+ postMessageToClientDataSource: callback
77
+ });
78
+ this.#worker.send({
79
+ type: "subscribe",
80
+ ...message
81
+ });
82
+ },
83
+ unsubscribe: (viewport)=>{
84
+ this.#worker.send({
85
+ type: "unsubscribe",
86
+ viewport
87
+ });
88
+ },
89
+ send: (message)=>{
90
+ this.#worker.send(message);
91
+ },
92
+ destroy: (viewportId)=>{
93
+ if (viewportId && this.#viewports.has(viewportId)) this.#viewports.delete(viewportId);
94
+ },
95
+ rpcCall: async (message)=>this.asyncRequest(message),
96
+ select: async (selectRequest)=>this.asyncRequest(selectRequest),
97
+ getTableList: async ()=>this.asyncRequest({
98
+ type: "GET_TABLE_LIST"
99
+ }),
100
+ getTableSchema: async (table)=>this.asyncRequest({
101
+ type: "GET_TABLE_META",
102
+ table
103
+ })
104
+ };
105
+ asyncRequest = (msg)=>{
106
+ const requestId = uuid();
107
+ this.#worker.send({
108
+ requestId,
109
+ ...msg
110
+ });
111
+ return new Promise((resolve, reject)=>{
112
+ this.#pendingRequests.set(requestId, {
113
+ resolve,
114
+ reject
115
+ });
116
+ });
117
+ };
118
+ async disconnect() {
119
+ try {
120
+ this.#worker.send({
121
+ type: "disconnect"
122
+ });
123
+ this.#deferredServerAPI = new DeferredPromise();
124
+ return "disconnected";
125
+ } catch (err) {
126
+ return "rejected";
127
+ }
128
+ }
129
+ destroy() {
130
+ this.#worker.terminate();
131
+ }
132
+ }
133
+ var src_ConnectionManager = ConnectionManager.instance;
134
+ export default src_ConnectionManager;
@@ -0,0 +1,44 @@
1
+ import { DeferredPromise, getLoggingConfigForWorker } from "@vuu-ui/vuu-utils";
2
+ import { workerSourceCode } from "./inlined-worker.js";
3
+ const workerBlob = new Blob([
4
+ getLoggingConfigForWorker() + workerSourceCode
5
+ ], {
6
+ type: "text/javascript"
7
+ });
8
+ const workerBlobUrl = URL.createObjectURL(workerBlob);
9
+ class DedicatedWorker {
10
+ #deferredConnection;
11
+ #worker;
12
+ constructor(onMessage){
13
+ const deferredWorker = new DeferredPromise();
14
+ this.#worker = deferredWorker.promise;
15
+ const worker = new Worker(workerBlobUrl);
16
+ const timer = window.setTimeout(()=>{
17
+ console.warn("timed out waiting for worker to load");
18
+ }, 1000);
19
+ worker.onmessage = (msg)=>{
20
+ const { data: message } = msg;
21
+ if ("ready" === message.type) {
22
+ window.clearTimeout(timer);
23
+ deferredWorker.resolve(worker);
24
+ } else if ("connected" === message.type) this.#deferredConnection?.resolve("connected");
25
+ else if ("connection-failed" === message.type) this.#deferredConnection?.reject(message.reason);
26
+ else onMessage(message);
27
+ };
28
+ }
29
+ async connect(options) {
30
+ this.#deferredConnection = new DeferredPromise();
31
+ this.send({
32
+ ...options,
33
+ type: "connect"
34
+ });
35
+ return this.#deferredConnection.promise;
36
+ }
37
+ async send(message) {
38
+ (await this.#worker).postMessage(message);
39
+ }
40
+ async terminate() {
41
+ (await this.#worker).terminate();
42
+ }
43
+ }
44
+ export { DedicatedWorker };
@@ -0,0 +1,89 @@
1
+ function _to_primitive(input, hint) {
2
+ if ("object" !== _type_of(input) || null === input) return input;
3
+ var prim = input[Symbol.toPrimitive];
4
+ if (void 0 !== prim) {
5
+ var res = prim.call(input, hint || "default");
6
+ if ("object" !== _type_of(res)) return res;
7
+ throw new TypeError("@@toPrimitive must return a primitive value.");
8
+ }
9
+ return ("string" === hint ? String : Number)(input);
10
+ }
11
+ function _to_property_key(arg) {
12
+ var key = _to_primitive(arg, "string");
13
+ return "symbol" === _type_of(key) ? key : String(key);
14
+ }
15
+ function _type_of(obj) {
16
+ return obj && "u" > typeof Symbol && obj.constructor === Symbol ? "symbol" : typeof obj;
17
+ }
18
+ let _computedKey;
19
+ class RetryOptionsImpl {
20
+ retryIntervals;
21
+ ind = 0;
22
+ constructor(retryIntervals){
23
+ this.retryIntervals = retryIntervals;
24
+ console.log("[RetryOptionsImpl] constructor");
25
+ }
26
+ next() {
27
+ this.ind = Math.min(this.retryIntervals.length, this.ind + 1);
28
+ }
29
+ get remaining() {
30
+ return this.retryIntervals.length - this.ind;
31
+ }
32
+ get interval() {
33
+ if (this.ind === this.retryIntervals.length) return -1;
34
+ return 1000 * this.retryIntervals[this.ind];
35
+ }
36
+ }
37
+ function RetryOptions(retryIntervals) {
38
+ if (Array.isArray(retryIntervals)) return new RetryOptionsImpl(retryIntervals);
39
+ throw Error("[lostConnectionHandler] RetryOptions, invalid retryIntervals");
40
+ }
41
+ const defaultRetryIntervals = [
42
+ 1,
43
+ 2,
44
+ 3,
45
+ 5,
46
+ 10,
47
+ 30,
48
+ 60,
49
+ 120
50
+ ];
51
+ _computedKey = _to_property_key(Symbol.asyncIterator);
52
+ class RetryGenerator {
53
+ vuuAuth;
54
+ options;
55
+ constructor(vuuAuth, options){
56
+ this.vuuAuth = vuuAuth;
57
+ this.options = options;
58
+ console.log("[RetryGenerator] constructor");
59
+ }
60
+ async *[_computedKey]() {
61
+ let connected = false;
62
+ do {
63
+ await new Promise((resolve)=>setTimeout(resolve, this.options.interval));
64
+ try {
65
+ await this.vuuAuth.login();
66
+ connected = true;
67
+ yield "connected";
68
+ } catch (err) {}
69
+ this.options.next();
70
+ }while (!connected && -1 !== this.options.interval)
71
+ if (!connected) yield "connection-failed";
72
+ }
73
+ }
74
+ class LostConnectionHandler {
75
+ vuuAuth;
76
+ retryIntervals;
77
+ constructor(vuuAuth, retryIntervals = defaultRetryIntervals){
78
+ this.vuuAuth = vuuAuth;
79
+ this.retryIntervals = retryIntervals;
80
+ }
81
+ async reconnect() {
82
+ for await (const result of new RetryGenerator(this.vuuAuth, RetryOptions(this.retryIntervals))){
83
+ console.log(` ... async iterator result = ${result}`);
84
+ if ("connected" === result) return result;
85
+ }
86
+ return "connection-failed";
87
+ }
88
+ }
89
+ export { LostConnectionHandler, RetryGenerator, RetryOptions };
@@ -0,0 +1,78 @@
1
+ import { getCookieValue } from "@vuu-ui/vuu-utils";
2
+ import { parseVuuUserFromToken } from "./authenticate.js";
3
+ class VuuAuthProvider {
4
+ authEndpoint;
5
+ constructor(authEndpoint){
6
+ this.authEndpoint = authEndpoint;
7
+ }
8
+ login = async (username, password)=>{
9
+ const date = new Date();
10
+ const days = 1;
11
+ date.setTime(date.getTime() + 24 * days * 3600000);
12
+ if (username && password) {
13
+ const { token } = await this.getVuuTokenWithUsernameAndPassword(username, password);
14
+ document.cookie = `vuu-auth-user=${username};expires=${date.toUTCString()};path=/`;
15
+ document.cookie = `vuu-auth-password=${password};expires=${date.toUTCString()};path=/`;
16
+ document.cookie = `vuu-auth-token=${token};expires=${date.toUTCString()};path=/`;
17
+ return this.redirectToApplication();
18
+ }
19
+ {
20
+ const userName = getCookieValue("vuu-auth-user");
21
+ const password = getCookieValue("vuu-auth-password");
22
+ if (!userName || !password) return this.redirectToLoginPage();
23
+ {
24
+ const { authorizations, token } = await this.getVuuTokenWithUsernameAndPassword(userName, password);
25
+ document.cookie = `vuu-auth-token=${token};expires=${date.toUTCString()};path=/`;
26
+ return {
27
+ authorizations,
28
+ user: {
29
+ userName
30
+ },
31
+ token
32
+ };
33
+ }
34
+ }
35
+ };
36
+ async getVuuTokenWithUsernameAndPassword(username, password) {
37
+ const response = await fetch(this.authEndpoint, {
38
+ method: "POST",
39
+ credentials: "include",
40
+ headers: {
41
+ "Content-Type": "application/json",
42
+ "access-control-allow-origin": location.host
43
+ },
44
+ body: JSON.stringify({
45
+ username,
46
+ password
47
+ })
48
+ });
49
+ if (response.ok) {
50
+ const vuuAuthToken = response.headers.get("vuu-auth-token");
51
+ if ("string" == typeof vuuAuthToken && vuuAuthToken.length > 0) {
52
+ const { authorizations } = parseVuuUserFromToken(vuuAuthToken);
53
+ return {
54
+ authorizations,
55
+ token: vuuAuthToken
56
+ };
57
+ }
58
+ throw Error("Authentication failed auth token not returned by server");
59
+ }
60
+ throw Error(`Authentication failed, ${response.status}`);
61
+ }
62
+ clear() {
63
+ document.cookie = "vuu-auth-user= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
64
+ document.cookie = "vuu-auth-password= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
65
+ document.cookie = "vuu-auth-token= ; expires = Thu, 01 Jan 1970 00:00:00 GMT";
66
+ }
67
+ redirectToLoginPage() {
68
+ window.location.href = "login.html";
69
+ }
70
+ redirectToApplication() {
71
+ window.location.href = "index.html";
72
+ }
73
+ logout() {
74
+ this.clear();
75
+ this.redirectToLoginPage();
76
+ }
77
+ }
78
+ export { VuuAuthProvider };
@@ -0,0 +1,36 @@
1
+ import ConnectionManager from "./ConnectionManager.js";
2
+ const VuuAuthTokenIssuePolicy = {
3
+ BearerToken: "bearer-token",
4
+ UsernamePassword: "username-password"
5
+ };
6
+ class VuuAuthenticator {
7
+ authProvider;
8
+ authTokenIssuePolicy;
9
+ websocketUrl;
10
+ constructor({ authProvider, authTokenIssuePolicy = VuuAuthTokenIssuePolicy.BearerToken, websocketUrl }){
11
+ this.authProvider = authProvider;
12
+ this.authTokenIssuePolicy = authTokenIssuePolicy;
13
+ this.websocketUrl = websocketUrl;
14
+ }
15
+ openWebsocketConnection = async (vuuToken)=>{
16
+ await ConnectionManager.connect({
17
+ url: this.websocketUrl,
18
+ token: vuuToken
19
+ }, true);
20
+ };
21
+ login = async ()=>{
22
+ const { authorizations, user, token, websocket = true } = await this.authProvider.login();
23
+ if (token && user) {
24
+ if (websocket) await this.openWebsocketConnection(token);
25
+ return [
26
+ user,
27
+ authorizations
28
+ ];
29
+ }
30
+ throw Error("[VuuAuthenticator] login failed");
31
+ };
32
+ logout = ()=>{
33
+ this.authProvider.logout();
34
+ };
35
+ }
36
+ export { VuuAuthTokenIssuePolicy, VuuAuthenticator };