From b67af47827137fbbf0cf0de3146231bded39a60a Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Wed, 23 Oct 2024 17:34:54 -0300 Subject: [PATCH 01/27] Adding tagoio integration plugin to tagocore --- package-lock.json | 70 +++- package.json | 17 + packages/console/package.json | 12 - packages/sdk/build_npm.ts | 16 +- .../ActionTriggerModule.ts | 11 +- .../Lib/ActionTypeModule/ActionTypeModule.ts | 6 +- packages/sdk/src/Lib/Core/Core.test.ts | 207 ++++++++--- packages/sdk/src/Lib/Core/Core.ts | 92 +++-- .../src/Lib/DatabaseModule/DatabaseModule.ts | 176 ++++++--- .../Lib/FileSystemModule/FileSystemModule.ts | 5 +- packages/sdk/src/Lib/Helpers/Helpers.ts | 18 +- packages/sdk/src/Lib/HookModule/HookModule.ts | 11 +- .../sdk/src/Lib/NavbarModule/NavbarModule.ts | 13 + packages/sdk/src/Lib/PageModule/PageModule.ts | 13 + .../sdk/src/Lib/QueueModule/QueueModule.ts | 12 +- .../SidebarButtonModule.ts | 13 + .../sdk/src/Lib/SystemModule/SystemModule.ts | 64 ++++ .../sdk/src/Lib/TCoreModule/TCoreModule.ts | 16 +- packages/sdk/src/Lib/index.ts | 16 +- packages/sdk/src/Shared/ResourceID.ts | 4 +- .../src/Types/Account/Account.types.test.ts | 17 +- .../sdk/src/Types/Account/Account.types.ts | 17 +- .../sdk/src/Types/Action/Action.types.test.ts | 31 +- packages/sdk/src/Types/Action/Action.types.ts | 46 ++- .../src/Types/Analysis/Analysis.type.test.ts | 54 ++- .../sdk/src/Types/Analysis/Analysis.types.ts | 20 +- .../sdk/src/Types/Common/Common.types.test.ts | 19 +- packages/sdk/src/Types/Common/Common.types.ts | 20 +- .../DatabaseModule/DatabaseModule.types.ts | 36 +- .../sdk/src/Types/Device/Device.types.test.ts | 116 ++++-- packages/sdk/src/Types/Device/Device.types.ts | 69 +++- .../Types/DeviceData/DeviceData.types.test.ts | 64 +++- .../src/Types/DeviceData/DeviceData.types.ts | 61 +++- .../src/Types/Hardware/Hardware.types.test.ts | 8 +- .../src/Types/Helpers/createQueryOrderBy.ts | 2 +- .../Types/Helpers/parseRelativeDate.test.ts | 2 +- .../src/Types/Helpers/parseRelativeDate.ts | 19 +- .../sdk/src/Types/Helpers/parseSafe.test.ts | 2 +- .../Types/Helpers/preprocessBoolean.test.ts | 2 +- .../Types/Helpers/preprocessNumber.test.ts | 2 +- .../Types/Helpers/preprocessObject.test.ts | 2 +- .../sdk/src/Types/Helpers/preprocessObject.ts | 10 +- .../src/Types/Helpers/refineOrderBy.test.ts | 2 +- .../Types/Helpers/removeNullValues.test.ts | 2 +- .../LiveInspector/LiveInspector.types.test.ts | 12 +- .../LiveInspector/LiveInspector.types.ts | 8 +- packages/sdk/src/Types/Log/Log.types.test.ts | 2 +- .../sdk/src/Types/Plugin/Plugin.types.test.ts | 36 +- packages/sdk/src/Types/Plugin/Plugin.types.ts | 177 ++++++--- .../sdk/src/Types/Resource/ResourceID.test.ts | 2 +- packages/sdk/src/Types/Resource/ResourceID.ts | 4 +- .../src/Types/Settings/Settings.types.test.ts | 12 +- .../Types/Statistic/Statistic.types.test.ts | 2 +- .../src/Types/Summary/Summary.types.test.ts | 2 +- packages/sdk/src/Types/Tag/Tag.types.test.ts | 2 +- packages/sdk/src/__mocks__/fs.ts | 2 +- packages/sdk/src/__mocks__/fs/promises.ts | 2 +- packages/server/package.json | 7 +- plugins/tagoio-integration/README.md | 11 + plugins/tagoio-integration/assets/desert.png | Bin 0 -> 1208 bytes plugins/tagoio-integration/assets/icon.png | Bin 0 -> 5554 bytes .../assets/logo-plugin-black.png | Bin 0 -> 11552 bytes .../tagoio-integration/assets/tagoio-logo.svg | 1 + plugins/tagoio-integration/esbuild/build.js | 66 ++++ .../esbuild/dirname-shim.js | 2 + .../tagoio-integration/esbuild/react-shim.js | 5 + plugins/tagoio-integration/esbuild/svgr.js | 16 + plugins/tagoio-integration/package.json | 28 ++ .../tagoio-integration/src/back/Cluster.ts | 229 ++++++++++++ plugins/tagoio-integration/src/back/Global.ts | 54 +++ .../tagoio-integration/src/back/Helpers.ts | 43 +++ plugins/tagoio-integration/src/back/Log.ts | 9 + .../tagoio-integration/src/back/Request.ts | 40 +++ plugins/tagoio-integration/src/back/Server.ts | 120 +++++++ plugins/tagoio-integration/src/back/Socket.ts | 337 ++++++++++++++++++ plugins/tagoio-integration/src/back/index.ts | 251 +++++++++++++ plugins/tagoio-integration/src/front/App.tsx | 76 ++++ .../src/front/Auth/Auth.style.ts | 129 +++++++ .../src/front/Auth/Auth.tsx | 273 ++++++++++++++ .../src/front/Auth/Banner/Banner.style.ts | 47 +++ .../src/front/Auth/Banner/Banner.tsx | 42 +++ .../Auth/Credentials/Credentials.style.ts | 25 ++ .../front/Auth/Credentials/Credentials.tsx | 120 +++++++ .../Auth/InstanceName/InstanceName.style.ts | 25 ++ .../front/Auth/InstanceName/InstanceName.tsx | 69 ++++ .../src/front/Auth/Otp/Otp.style.ts | 30 ++ .../src/front/Auth/Otp/Otp.tsx | 154 ++++++++ .../front/Auth/OtpPicker/OtpPicker.style.ts | 55 +++ .../src/front/Auth/OtpPicker/OtpPicker.tsx | 83 +++++ .../src/front/Auth/Profiles/Profiles.style.ts | 45 +++ .../src/front/Auth/Profiles/Profiles.tsx | 29 ++ .../src/front/Details/Details.style.ts | 151 ++++++++ .../src/front/Details/Details.tsx | 306 ++++++++++++++++ .../tagoio-integration/src/front/index.tsx | 12 + 94 files changed, 4133 insertions(+), 435 deletions(-) create mode 100644 packages/sdk/src/Lib/NavbarModule/NavbarModule.ts create mode 100644 packages/sdk/src/Lib/PageModule/PageModule.ts create mode 100644 packages/sdk/src/Lib/SidebarButtonModule/SidebarButtonModule.ts create mode 100644 packages/sdk/src/Lib/SystemModule/SystemModule.ts create mode 100644 plugins/tagoio-integration/README.md create mode 100644 plugins/tagoio-integration/assets/desert.png create mode 100644 plugins/tagoio-integration/assets/icon.png create mode 100644 plugins/tagoio-integration/assets/logo-plugin-black.png create mode 100644 plugins/tagoio-integration/assets/tagoio-logo.svg create mode 100644 plugins/tagoio-integration/esbuild/build.js create mode 100644 plugins/tagoio-integration/esbuild/dirname-shim.js create mode 100644 plugins/tagoio-integration/esbuild/react-shim.js create mode 100644 plugins/tagoio-integration/esbuild/svgr.js create mode 100644 plugins/tagoio-integration/package.json create mode 100644 plugins/tagoio-integration/src/back/Cluster.ts create mode 100644 plugins/tagoio-integration/src/back/Global.ts create mode 100644 plugins/tagoio-integration/src/back/Helpers.ts create mode 100644 plugins/tagoio-integration/src/back/Log.ts create mode 100644 plugins/tagoio-integration/src/back/Request.ts create mode 100644 plugins/tagoio-integration/src/back/Server.ts create mode 100644 plugins/tagoio-integration/src/back/Socket.ts create mode 100644 plugins/tagoio-integration/src/back/index.ts create mode 100644 plugins/tagoio-integration/src/front/App.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/Auth.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/Auth.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/Banner/Banner.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/Banner/Banner.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/Otp/Otp.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/Otp/Otp.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.tsx create mode 100644 plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.style.ts create mode 100644 plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.tsx create mode 100644 plugins/tagoio-integration/src/front/Details/Details.style.ts create mode 100644 plugins/tagoio-integration/src/front/Details/Details.tsx create mode 100644 plugins/tagoio-integration/src/front/index.tsx diff --git a/package-lock.json b/package-lock.json index 20e3133d..dbb7fcef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,12 +18,20 @@ "axios": "0.26.0", "body-parser": "2.0.1", "chalk": "5.3.0", + "cors": "2.8.5", "express": "4.21.1", "luxon": "3.5.0", + "md5": "2.3.0", "nanoid": "5.0.7", "ora": "8.1.0", + "polished": "4.1.3", "qs": "6.10.1", + "react": "17.0.2", + "react-dom": "17.0.2", "semver": "7.6.3", + "socket.io": "4.4.1", + "socket.io-client": "4.4.1", + "styled-components": "5.3.5", "systeminformation": "5.23.5", "uuid": "10.0.0", "zod": "3.23.8" @@ -35,13 +43,22 @@ "@biomejs/biome": "1.9.3", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "12.0.0", "@types/async": "3.2.24", "@types/axios": "0.14.0", + "@types/cors": "2.8.17", "@types/express": "5.0.0", "@types/luxon": "3.4.2", + "@types/md5": "2.3.5", "@types/ms": "0.7.34", "@types/node": "20.14.8", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.9", + "@types/react-router": "5.1.16", + "@types/react-router-dom": "5.1.8", "@types/semver": "7.5.8", + "@types/styled-components": "5.1.11", "@types/uuid": "10.0.0", "concurrently": "9.0.1", "esbuild": "0.24.0", @@ -3693,6 +3710,10 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@tago-io/tagocore-plugin-tagoio-integration": { + "resolved": "plugins/tagoio-integration", + "link": true + }, "node_modules/@tago-io/tcore-api": { "resolved": "packages/server", "link": true @@ -3983,6 +4004,20 @@ "react-dom": "*" } }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -10019,6 +10054,12 @@ "node": ">= 0.8" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "license": "MIT" + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -13414,30 +13455,18 @@ "mobx": "6.4.2", "mobx-react": "7.3.0", "multer": "1.4.5-lts.1", - "polished": "4.1.3", - "react": "17.0.2", - "react-dom": "17.0.2", "react-helmet": "6.1.0", "react-markdown": "7.0.0", "react-router": "5.2.0", "react-router-dom": "5.2.0", - "socket.io-client": "4.4.1", - "styled-components": "5.3.5", "styled-jsx": "3.4.5", "swr": "0.5.6", "tinycolor2": "1.4.2" }, "devDependencies": { - "@testing-library/jest-dom": "5.14.1", - "@testing-library/react": "12.0.0", "@types/lodash.clonedeep": "4.5.6", "@types/multer": "1.4.7", - "@types/react": "17.0.14", - "@types/react-dom": "17.0.9", "@types/react-helmet": "6.1.4", - "@types/react-router": "5.1.16", - "@types/react-router-dom": "5.1.8", - "@types/styled-components": "5.1.11", "@types/tinycolor2": "1.4.3", "@vitejs/plugin-react-swc": "3.7.1", "jest-transform-stub": "2.0.0", @@ -13461,21 +13490,16 @@ "dependencies": { "boxen": "5.1.2", "compression": "1.7.4", - "cors": "2.8.5", "cron-parser": "4.4.0", "dayjs": "1.11.13", "extract-zip": "2.0.1", "js-yaml": "4.1.0", - "md5": "2.3.0", "method-override": "3.0.0", - "multer": "1.4.5-lts.1", - "socket.io": "4.4.1" + "multer": "1.4.5-lts.1" }, "devDependencies": { "@types/compression": "1.7.5", - "@types/cors": "2.8.17", "@types/js-yaml": "4.0.9", - "@types/md5": "2.3.5", "@types/method-override": "0.0.35" } }, @@ -13715,6 +13739,16 @@ "sqlite3": "5.1.7" }, "devDependencies": {} + }, + "plugins/tagoio-integration": { + "name": "@tago-io/tagocore-plugin-tagoio-integration", + "version": "0.7.0", + "dependencies": { + "path-browserify": "1.0.1" + }, + "devDependencies": { + "@testing-library/user-event": "14.5.2" + } } } } diff --git a/package.json b/package.json index 44b4e9f5..fc8eb145 100644 --- a/package.json +++ b/package.json @@ -33,17 +33,27 @@ "axios": "0.26.0", "body-parser": "2.0.1", "chalk": "5.3.0", + "cors": "2.8.5", "express": "4.21.1", "luxon": "3.5.0", "nanoid": "5.0.7", + "md5": "2.3.0", + "polished": "4.1.3", "ora": "8.1.0", "qs": "6.10.1", + "react": "17.0.2", + "react-dom": "17.0.2", "semver": "7.6.3", + "socket.io": "4.4.1", + "socket.io-client": "4.4.1", + "styled-components": "5.3.5", "systeminformation": "5.23.5", "uuid": "10.0.0", "zod": "3.23.8" }, "devDependencies": { + "@testing-library/jest-dom": "5.14.1", + "@testing-library/react": "12.0.0", "@biomejs/biome": "1.9.3", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", @@ -54,7 +64,14 @@ "@types/ms": "0.7.34", "@types/node": "20.14.8", "@types/semver": "7.5.8", + "@types/cors": "2.8.17", "@types/uuid": "10.0.0", + "@types/md5": "2.3.5", + "@types/react-router": "5.1.16", + "@types/react-router-dom": "5.1.8", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.9", + "@types/styled-components": "5.1.11", "concurrently": "9.0.1", "esbuild": "0.24.0", "ts-node": "10.9.2", diff --git a/packages/console/package.json b/packages/console/package.json index 829c6cd8..59acfac6 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -16,30 +16,18 @@ "mobx": "6.4.2", "mobx-react": "7.3.0", "multer": "1.4.5-lts.1", - "polished": "4.1.3", - "react": "17.0.2", - "react-dom": "17.0.2", "react-helmet": "6.1.0", "react-markdown": "7.0.0", "react-router": "5.2.0", "react-router-dom": "5.2.0", - "socket.io-client": "4.4.1", - "styled-components": "5.3.5", "styled-jsx": "3.4.5", "swr": "0.5.6", "tinycolor2": "1.4.2" }, "devDependencies": { - "@testing-library/jest-dom": "5.14.1", - "@testing-library/react": "12.0.0", "@types/lodash.clonedeep": "4.5.6", "@types/multer": "1.4.7", - "@types/react": "17.0.14", - "@types/react-dom": "17.0.9", "@types/react-helmet": "6.1.4", - "@types/react-router": "5.1.16", - "@types/react-router-dom": "5.1.8", - "@types/styled-components": "5.1.11", "@types/tinycolor2": "1.4.3", "@vitejs/plugin-react-swc": "3.7.1", "jest-transform-stub": "2.0.0", diff --git a/packages/sdk/build_npm.ts b/packages/sdk/build_npm.ts index 16c41727..3fe06d34 100644 --- a/packages/sdk/build_npm.ts +++ b/packages/sdk/build_npm.ts @@ -15,14 +15,14 @@ await build({ deno: false, }, package: { - "name": "@tago-io/tcore-sdk", - "version": "0.7.0", - "description": "TCore SDK for creating plugins", - "author": "Tago LLC", - "homepage": "https://github.com/tago-io/tcore", - "repository": { - "type": "git", - "url": "https://github.com/tago-io/tcore" + name: "@tago-io/tcore-sdk", + version: "0.7.0", + description: "TCore SDK for creating plugins", + author: "Tago LLC", + homepage: "https://github.com/tago-io/tcore", + repository: { + type: "git", + url: "https://github.com/tago-io/tcore", }, }, // postBuild() { diff --git a/packages/sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts b/packages/sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts index 1df2902f..81b19f4f 100644 --- a/packages/sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts +++ b/packages/sdk/src/Lib/ActionTriggerModule/ActionTriggerModule.ts @@ -13,14 +13,21 @@ class ActionTriggerModule extends TCoreModule { * Called when this action type is triggered. * This will decide if the action should be executed or not. */ - public async onCall(actionID: TGenericID, values: any, data: any): Promise { + public async onCall( + actionID: TGenericID, + values: any, + data: any, + ): Promise { return Promise.resolve(); } /** * Called when the triggers of an action change. */ - public async onTriggerChange(actionID: TGenericID, trigger: any): Promise { + public async onTriggerChange( + actionID: TGenericID, + trigger: any, + ): Promise { // } } diff --git a/packages/sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts b/packages/sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts index eee114d2..a5f5a042 100644 --- a/packages/sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts +++ b/packages/sdk/src/Lib/ActionTypeModule/ActionTypeModule.ts @@ -12,7 +12,11 @@ class ActionTypeModule extends TCoreModule { /** * Called when this action type is executed. */ - public async onCall(actionID: TGenericID, values: any, data: any): Promise { + public async onCall( + actionID: TGenericID, + values: any, + data: any, + ): Promise { return Promise.resolve(); } } diff --git a/packages/sdk/src/Lib/Core/Core.test.ts b/packages/sdk/src/Lib/Core/Core.test.ts index b822a3d5..d678a015 100644 --- a/packages/sdk/src/Lib/Core/Core.test.ts +++ b/packages/sdk/src/Lib/Core/Core.test.ts @@ -1,5 +1,5 @@ +import { afterEach, expect, test, vi } from "vitest"; import core from "./Core.ts"; -import { test, expect, vi, afterEach } from "vitest"; afterEach(() => { vi.clearAllMocks(); @@ -21,7 +21,9 @@ test("getDeviceList works with query", async () => { test("getDeviceInfo", async () => { const mockDevice = { name: "Device #1" }; - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockDevice); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue(mockDevice); const response = await core.getDeviceInfo("6126ff702e576dd238e1da3e"); expect(fn).toHaveBeenCalledWith("getDeviceInfo", "6126ff702e576dd238e1da3e"); expect(response).toEqual(mockDevice); @@ -29,16 +31,25 @@ test("getDeviceInfo", async () => { test("getDeviceByToken", async () => { const mockDevice = { name: "Device #2" }; - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockDevice); - const response = await core.getDeviceByToken("b24afe36-33ff-4f48-9bbd-b10d446d779d"); - expect(fn).toHaveBeenCalledWith("getDeviceByToken", "b24afe36-33ff-4f48-9bbd-b10d446d779d"); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue(mockDevice); + const response = await core.getDeviceByToken( + "b24afe36-33ff-4f48-9bbd-b10d446d779d", + ); + expect(fn).toHaveBeenCalledWith( + "getDeviceByToken", + "b24afe36-33ff-4f48-9bbd-b10d446d779d", + ); expect(response).toEqual(mockDevice); }); test("editDevice", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod"); await core.editDevice("6126ff702e576dd238e1da3e", { active: false }); - expect(fn).toHaveBeenCalledWith("editDevice", "6126ff702e576dd238e1da3e", { active: false }); + expect(fn).toHaveBeenCalledWith("editDevice", "6126ff702e576dd238e1da3e", { + active: false, + }); }); test("deleteDevice", async () => { @@ -49,7 +60,9 @@ test("deleteDevice", async () => { }); test("createDevice", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ device_id: 1, token: 3 }); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue({ device_id: 1, token: 3 }); const response = await core.createDevice({ name: "My new device" }); expect(response.device_id).toEqual(1); expect(response.token).toEqual(3); @@ -57,74 +70,121 @@ test("createDevice", async () => { }); test("createDeviceToken", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ token: "123" }); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue({ token: "123" }); const response = await core.createDeviceToken("6126ff702e576dd238e1da3e", { name: "Token #1", permission: "full", expire_time: "1 day", }); expect(response).toEqual({ token: "123" }); - expect(fn).toHaveBeenCalledWith("createDeviceToken", "6126ff702e576dd238e1da3e", { - name: "Token #1", - permission: "full", - expire_time: "1 day", - }); + expect(fn).toHaveBeenCalledWith( + "createDeviceToken", + "6126ff702e576dd238e1da3e", + { + name: "Token #1", + permission: "full", + expire_time: "1 day", + }, + ); }); test("getDeviceTokenList works without query", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2, 3]); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([1, 2, 3]); const response = await core.getDeviceTokenList("6126ff702e576dd238e1da3e"); expect(response).toEqual([1, 2, 3]); - expect(fn).toHaveBeenCalledWith("getDeviceTokenList", "6126ff702e576dd238e1da3e", undefined); + expect(fn).toHaveBeenCalledWith( + "getDeviceTokenList", + "6126ff702e576dd238e1da3e", + undefined, + ); }); test("getDeviceTokenList works with query", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2]); - const response = await core.getDeviceTokenList("6126ff702e576dd238e1da3e", {}); + const response = await core.getDeviceTokenList( + "6126ff702e576dd238e1da3e", + {}, + ); expect(response).toEqual([1, 2]); - expect(fn).toHaveBeenCalledWith("getDeviceTokenList", "6126ff702e576dd238e1da3e", {}); + expect(fn).toHaveBeenCalledWith( + "getDeviceTokenList", + "6126ff702e576dd238e1da3e", + {}, + ); }); test("deleteDeviceToken", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([1, 2]); const response = await core.deleteDeviceToken("6126ff702e576dd238e1da3e"); expect(response).toEqual(undefined); - expect(fn).toHaveBeenCalledWith("deleteDeviceToken", "6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith( + "deleteDeviceToken", + "6126ff702e576dd238e1da3e", + ); }); test("getDeviceParamList works without sentStatus", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ key: "key", value: "value" }]); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([{ key: "key", value: "value" }]); const response = await core.getDeviceParamList("6126ff702e576dd238e1da3e"); expect(response).toEqual([{ key: "key", value: "value" }]); - expect(fn).toHaveBeenCalledWith("getDeviceParamList", "6126ff702e576dd238e1da3e", undefined); + expect(fn).toHaveBeenCalledWith( + "getDeviceParamList", + "6126ff702e576dd238e1da3e", + undefined, + ); }); test("getDeviceParamList works with sentStatus", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ key: "key", value: "value" }]); - const response = await core.getDeviceParamList("6126ff702e576dd238e1da3e", true); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([{ key: "key", value: "value" }]); + const response = await core.getDeviceParamList( + "6126ff702e576dd238e1da3e", + true, + ); expect(response).toEqual([{ key: "key", value: "value" }]); - expect(fn).toHaveBeenCalledWith("getDeviceParamList", "6126ff702e576dd238e1da3e", true); + expect(fn).toHaveBeenCalledWith( + "getDeviceParamList", + "6126ff702e576dd238e1da3e", + true, + ); }); test("deleteDeviceParam", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue("abc"); const response = await core.deleteDeviceParam("6126ff702e576dd238e1da3e"); expect(response).toEqual(undefined); - expect(fn).toHaveBeenCalledWith("deleteDeviceParam", "6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith( + "deleteDeviceParam", + "6126ff702e576dd238e1da3e", + ); }); test("setDeviceParams", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue("abc"); const response = await core.setDeviceParams("6126ff702e576dd238e1da3e", []); expect(response).toEqual(undefined); - expect(fn).toHaveBeenCalledWith("setDeviceParams", "6126ff702e576dd238e1da3e", []); + expect(fn).toHaveBeenCalledWith( + "setDeviceParams", + "6126ff702e576dd238e1da3e", + [], + ); }); test("getDeviceDataAmount", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue(1337); const response = await core.getDeviceDataAmount("61261ef1f87480ff318b7bcb"); expect(response).toEqual(1337); - expect(fn).toHaveBeenCalledWith("getDeviceDataAmount", "61261ef1f87480ff318b7bcb"); + expect(fn).toHaveBeenCalledWith( + "getDeviceDataAmount", + "61261ef1f87480ff318b7bcb", + ); }); test("getActiontypes.ts", async () => { @@ -135,7 +195,9 @@ test("getActiontypes.ts", async () => { }); test("getActionList works without query", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ name: "Action #1" }]); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([{ name: "Action #1" }]); const response = await core.getActionList(); expect(response).toEqual([{ name: "Action #1" }]); expect(fn).toHaveBeenCalledWith("getActionList", undefined); @@ -150,7 +212,9 @@ test("getActionList works with query", async () => { test("getActionInfo", async () => { const mockAction = { name: "Action #1" }; - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockAction); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue(mockAction); const response = await core.getActionInfo("6126ff702e576dd238e1da3e"); expect(fn).toHaveBeenCalledWith("getActionInfo", "6126ff702e576dd238e1da3e"); expect(response).toEqual(mockAction); @@ -159,7 +223,9 @@ test("getActionInfo", async () => { test("editAction", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod"); await core.editAction("6126ff702e576dd238e1da3e", { name: "New name" }); - expect(fn).toHaveBeenCalledWith("editAction", "6126ff702e576dd238e1da3e", { name: "New name" }); + expect(fn).toHaveBeenCalledWith("editAction", "6126ff702e576dd238e1da3e", { + name: "New name", + }); }); test("deleteAction", async () => { @@ -170,28 +236,48 @@ test("deleteAction", async () => { }); test("createAction", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue("61261ef1f87480ff318b7bcb"); - const response = await core.createAction({ name: "My new Action", active: false, type: "" } as any); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue("61261ef1f87480ff318b7bcb"); + const response = await core.createAction({ + name: "My new Action", + active: false, + type: "", + } as any); expect(response).toEqual("61261ef1f87480ff318b7bcb"); - expect(fn).toHaveBeenCalledWith("createAction", { name: "My new Action", active: false, type: "" }); + expect(fn).toHaveBeenCalledWith("createAction", { + name: "My new Action", + active: false, + type: "", + }); }); test("triggerAction works without data", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); const response = await core.triggerAction("6126ff702e576dd238e1da3e"); expect(response).toEqual([]); - expect(fn).toHaveBeenCalledWith("triggerAction", "6126ff702e576dd238e1da3e", undefined); + expect(fn).toHaveBeenCalledWith( + "triggerAction", + "6126ff702e576dd238e1da3e", + undefined, + ); }); test("triggerAction works with data", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); const response = await core.triggerAction("6126ff702e576dd238e1da3e", {}); expect(response).toEqual([]); - expect(fn).toHaveBeenCalledWith("triggerAction", "6126ff702e576dd238e1da3e", {}); + expect(fn).toHaveBeenCalledWith( + "triggerAction", + "6126ff702e576dd238e1da3e", + {}, + ); }); test("getAnalysisList works without query", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ name: "Analysis #1" }]); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([{ name: "Analysis #1" }]); const response = await core.getAnalysisList(); expect(response).toEqual([{ name: "Analysis #1" }]); expect(fn).toHaveBeenCalledWith("getAnalysisList", undefined); @@ -206,16 +292,23 @@ test("getAnalysisList works with query", async () => { test("getAnalysisInfo", async () => { const mockAnalysis = { name: "Analysis #1" }; - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue(mockAnalysis); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue(mockAnalysis); const response = await core.getAnalysisInfo("6126ff702e576dd238e1da3e"); - expect(fn).toHaveBeenCalledWith("getAnalysisInfo", "6126ff702e576dd238e1da3e"); + expect(fn).toHaveBeenCalledWith( + "getAnalysisInfo", + "6126ff702e576dd238e1da3e", + ); expect(response).toEqual(mockAnalysis); }); test("editAnalysis", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod"); await core.editAnalysis("6126ff702e576dd238e1da3e", { name: "New name" }); - expect(fn).toHaveBeenCalledWith("editAnalysis", "6126ff702e576dd238e1da3e", { name: "New name" }); + expect(fn).toHaveBeenCalledWith("editAnalysis", "6126ff702e576dd238e1da3e", { + name: "New name", + }); }); test("deleteAnalysis", async () => { @@ -226,14 +319,26 @@ test("deleteAnalysis", async () => { }); test("createAnalysis", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue("61261ef1f87480ff318b7bcb"); - const response = await core.createAnalysis({ name: "My new Analysis", active: false, tags: [] }); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue("61261ef1f87480ff318b7bcb"); + const response = await core.createAnalysis({ + name: "My new Analysis", + active: false, + tags: [], + }); expect(response).toEqual("61261ef1f87480ff318b7bcb"); - expect(fn).toHaveBeenCalledWith("createAnalysis", { name: "My new Analysis", active: false, tags: [] }); + expect(fn).toHaveBeenCalledWith("createAnalysis", { + name: "My new Analysis", + active: false, + tags: [], + }); }); test("getSummary", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue({ device: 20 }); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue({ device: 20 }); const response = await core.getSummary(); expect(response).toEqual({ device: 20 }); expect(fn).toHaveBeenCalledWith("getSummary"); @@ -253,7 +358,7 @@ test("addDeviceData", async () => { variable: "temperature", value: 10, }, - undefined + undefined, ); }); @@ -261,14 +366,24 @@ test("getDeviceData works without query", async () => { const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([]); const response = await core.getDeviceData("61261ef1f87480ff318b7bcb"); expect(response).toEqual([]); - expect(fn).toHaveBeenCalledWith("getDeviceData", "61261ef1f87480ff318b7bcb", undefined); + expect(fn).toHaveBeenCalledWith( + "getDeviceData", + "61261ef1f87480ff318b7bcb", + undefined, + ); }); test("getDeviceData works with query", async () => { - const fn = vi.spyOn(core as any, "invokeApiMethod").mockResolvedValue([{ variable: "temperature", value: 10 }]); + const fn = vi + .spyOn(core as any, "invokeApiMethod") + .mockResolvedValue([{ variable: "temperature", value: 10 }]); const response = await core.getDeviceData("61261ef1f87480ff318b7bcb", {}); expect(response).toEqual([{ variable: "temperature", value: 10 }]); - expect(fn).toHaveBeenCalledWith("getDeviceData", "61261ef1f87480ff318b7bcb", {}); + expect(fn).toHaveBeenCalledWith( + "getDeviceData", + "61261ef1f87480ff318b7bcb", + {}, + ); }); test("getTagKeys works for all types of resources", async () => { diff --git a/packages/sdk/src/Lib/Core/Core.ts b/packages/sdk/src/Lib/Core/Core.ts index 852c019e..b1de0625 100644 --- a/packages/sdk/src/Lib/Core/Core.ts +++ b/packages/sdk/src/Lib/Core/Core.ts @@ -10,11 +10,11 @@ import type { IAnalysisEdit, IAnalysisList, IAnalysisListQuery, - IDeviceData, - IDeviceDataQuery, ICreateDeviceResponse, IDevice, IDeviceCreate, + IDeviceData, + IDeviceDataQuery, IDeviceEdit, IDeviceList, IDeviceListQuery, @@ -24,10 +24,10 @@ import type { IDeviceTokenCreate, IDeviceTokenCreateResponse, IDeviceTokenListQuery, + ILiveInspectorMessageCreate, ISummary, TGenericID, TGenericToken, - ILiveInspectorMessageCreate, TLiveInspectorConnectionID, } from "../../Types.ts"; import APIBridge from "../APIBridge/APIBridge.ts"; @@ -78,7 +78,9 @@ class Core extends APIBridge { /** * Creates a new device. */ - public async createDevice(params: Omit): Promise { + public async createDevice( + params: Omit, + ): Promise { const response = await this.invokeApiMethod("createDevice", params); return response; } @@ -88,9 +90,13 @@ class Core extends APIBridge { */ public async createDeviceToken( deviceID: TGenericID, - token: Omit + token: Omit, ): Promise { - const response = await this.invokeApiMethod("createDeviceToken", deviceID, token); + const response = await this.invokeApiMethod( + "createDeviceToken", + deviceID, + token, + ); return response; } @@ -98,8 +104,15 @@ class Core extends APIBridge { * Retrieves a list of device tokens. * Additional filters can be passed via the query argument. */ - public async getDeviceTokenList(deviceID: TGenericID, query?: IDeviceTokenListQuery): Promise { - const response = await this.invokeApiMethod("getDeviceTokenList", deviceID, query); + public async getDeviceTokenList( + deviceID: TGenericID, + query?: IDeviceTokenListQuery, + ): Promise { + const response = await this.invokeApiMethod( + "getDeviceTokenList", + deviceID, + query, + ); return response; } @@ -113,8 +126,15 @@ class Core extends APIBridge { /** * Gets all the parameters of a device. */ - public async getDeviceParamList(deviceID: TGenericID, sentStatus?: boolean): Promise { - const response = await this.invokeApiMethod("getDeviceParamList", deviceID, sentStatus); + public async getDeviceParamList( + deviceID: TGenericID, + sentStatus?: boolean, + ): Promise { + const response = await this.invokeApiMethod( + "getDeviceParamList", + deviceID, + sentStatus, + ); return response; } @@ -129,7 +149,10 @@ class Core extends APIBridge { * Overrides or edits device parameters. If you want to edit a device parameter, pass the ID * property inside of an object in the array. */ - public async setDeviceParams(deviceID: TGenericID, parameters: IDeviceParameterCreate[]): Promise { + public async setDeviceParams( + deviceID: TGenericID, + parameters: IDeviceParameterCreate[], + ): Promise { await this.invokeApiMethod("setDeviceParams", deviceID, parameters); } @@ -184,7 +207,9 @@ class Core extends APIBridge { /** * Creates a new action. */ - public async createAction(params: Omit): Promise { + public async createAction( + params: Omit, + ): Promise { const response = await this.invokeApiMethod("createAction", params); return response; } @@ -201,7 +226,9 @@ class Core extends APIBridge { * Retrieves a list of analyses. * Additional filters can be passed via the query argument. */ - public async getAnalysisList(query?: IAnalysisListQuery): Promise { + public async getAnalysisList( + query?: IAnalysisListQuery, + ): Promise { const response = await this.invokeApiMethod("getAnalysisList", query); return response; } @@ -217,7 +244,10 @@ class Core extends APIBridge { /** * Edits the information of a single analysis. */ - public async editAnalysis(id: TGenericID, analysis: IAnalysisEdit): Promise { + public async editAnalysis( + id: TGenericID, + analysis: IAnalysisEdit, + ): Promise { const response = await this.invokeApiMethod("editAnalysis", id, analysis); return response; } @@ -232,7 +262,9 @@ class Core extends APIBridge { /** * Creates a new analysis. */ - public async createAnalysis(params: Omit): Promise { + public async createAnalysis( + params: Omit, + ): Promise { const response = await this.invokeApiMethod("createAnalysis", params); return response; } @@ -248,7 +280,11 @@ class Core extends APIBridge { /** * Adds a data item into a device. */ - public async addDeviceData(deviceID: TGenericID, data: any, options?: { forceDBInsert: boolean }): Promise { + public async addDeviceData( + deviceID: TGenericID, + data: any, + options?: { forceDBInsert: boolean }, + ): Promise { await this.invokeApiMethod("addDeviceData", deviceID, data, options); } @@ -256,15 +292,24 @@ class Core extends APIBridge { * Retrieves data from a device. * Additional filters can be passed via the query argument. */ - public async getDeviceData(deviceID: TGenericID, query?: IDeviceDataQuery): Promise { - const response = await this.invokeApiMethod("getDeviceData", deviceID, query); + public async getDeviceData( + deviceID: TGenericID, + query?: IDeviceDataQuery, + ): Promise { + const response = await this.invokeApiMethod( + "getDeviceData", + deviceID, + query, + ); return response; } /** * Retrieves all the tag keys of a resource type. */ - public async getTagKeys(type: "device" | "analysis" | "action"): Promise { + public async getTagKeys( + type: "device" | "analysis" | "action", + ): Promise { const response = await this.invokeApiMethod("getTagKeys", type); return response; } @@ -275,9 +320,14 @@ class Core extends APIBridge { public async emitToLiveInspector( deviceID: TGenericID, msg: ILiveInspectorMessageCreate | ILiveInspectorMessageCreate[], - liveInspectorID?: TLiveInspectorConnectionID + liveInspectorID?: TLiveInspectorConnectionID, ): Promise { - await this.invokeApiMethod("emitToLiveInspector", deviceID, msg, liveInspectorID); + await this.invokeApiMethod( + "emitToLiveInspector", + deviceID, + msg, + liveInspectorID, + ); } } diff --git a/packages/sdk/src/Lib/DatabaseModule/DatabaseModule.ts b/packages/sdk/src/Lib/DatabaseModule/DatabaseModule.ts index 22f6e60c..f6903c69 100644 --- a/packages/sdk/src/Lib/DatabaseModule/DatabaseModule.ts +++ b/packages/sdk/src/Lib/DatabaseModule/DatabaseModule.ts @@ -1,18 +1,24 @@ import type { + IAccount, + IAccountList, + IAccountToken, IAction, IActionList, IAnalysis, IAnalysisList, - IDeviceData, + IDatabaseAccountCreateTokenData, + IDatabaseAccountListQuery, IDatabaseActionListQuery, IDatabaseAddAnalysisLogData, IDatabaseAddStatisticData, IDatabaseAnalysisListQuery, - IDatabaseDeviceDataCreate, + IDatabaseCreateAccountData, IDatabaseCreateActionData, IDatabaseCreateAnalysisData, IDatabaseCreateDeviceData, IDatabaseCreateDeviceTokenData, + IDatabaseDeviceDataCreate, + IDatabaseDeviceDataEdit, IDatabaseDeviceListQuery, IDatabaseEditActionData, IDatabaseEditAnalysisData, @@ -22,26 +28,20 @@ import type { IDatabaseSetDeviceParamsData, IDatabaseSetPluginStorageData, IDevice, + IDeviceApplyDataRetentionQuery, + IDeviceData, IDeviceList, IDeviceParameter, + IDeviceToken, IDeviceTokenList, ILog, IModuleSetupWithoutType, IStatistic, ISummary, TDatabaseGetTagKeysType, + TDeviceType, TGenericID, TGenericToken, - TDeviceType, - IDatabaseDeviceDataEdit, - IAccountToken, - IAccount, - IAccountList, - IDatabaseCreateAccountData, - IDatabaseAccountListQuery, - IDatabaseAccountCreateTokenData, - IDeviceToken, - IDeviceApplyDataRetentionQuery, } from "../../Types.ts"; import TCoreModule from "../TCoreModule/TCoreModule.ts"; @@ -59,7 +59,7 @@ class DatabaseModule extends TCoreModule { public async addDeviceData( deviceID: TGenericID, type: TDeviceType, - data: IDatabaseDeviceDataCreate[] + data: IDatabaseDeviceDataCreate[], ): Promise { throw new Error("Method not implemented"); } @@ -67,14 +67,22 @@ class DatabaseModule extends TCoreModule { /** * Edits a device data point. */ - public async editDeviceData(deviceID: TGenericID, type: TDeviceType, data: IDatabaseDeviceDataEdit[]): Promise { + public async editDeviceData( + deviceID: TGenericID, + type: TDeviceType, + data: IDatabaseDeviceDataEdit[], + ): Promise { throw new Error("Method not implemented"); } /** * Deletes data from a device. */ - public async deleteDeviceData(deviceID: TGenericID, type: TDeviceType, ids: string[]): Promise { + public async deleteDeviceData( + deviceID: TGenericID, + type: TDeviceType, + ids: string[], + ): Promise { throw new Error("Method not implemented"); } @@ -84,7 +92,7 @@ class DatabaseModule extends TCoreModule { public async applyDeviceDataRetention( deviceID: TGenericID, type: TDeviceType, - query: IDeviceApplyDataRetentionQuery + query: IDeviceApplyDataRetentionQuery, ): Promise { throw new Error("Method not implemented"); } @@ -95,7 +103,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataDefaultQ( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -106,7 +114,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataLastValue( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -117,7 +125,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataLastLocation( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -128,7 +136,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataLastItem( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -139,7 +147,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataLastInsert( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -150,7 +158,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataFirstValue( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -161,7 +169,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataFirstLocation( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -172,7 +180,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataFirstItem( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -183,7 +191,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataFirstInsert( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -194,7 +202,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataCount( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -205,7 +213,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataMax( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -216,7 +224,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataMin( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -227,7 +235,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataAvg( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -238,7 +246,7 @@ class DatabaseModule extends TCoreModule { public async getDeviceDataSum( deviceID: TGenericID, type: TDeviceType, - query: IDatabaseGetDeviceDataQuery + query: IDatabaseGetDeviceDataQuery, ): Promise { throw new Error("Method not implemented"); } @@ -247,7 +255,9 @@ class DatabaseModule extends TCoreModule { * Retrieves a list of devices. * Additional filters can be passed via the query argument. */ - public async getDeviceList(query: IDatabaseDeviceListQuery): Promise { + public async getDeviceList( + query: IDatabaseDeviceListQuery, + ): Promise { throw new Error("Method not implemented"); } @@ -261,7 +271,10 @@ class DatabaseModule extends TCoreModule { /** * Edits the information of a single device. */ - public async editDevice(deviceID: TGenericID, data: IDatabaseEditDeviceData): Promise { + public async editDevice( + deviceID: TGenericID, + data: IDatabaseEditDeviceData, + ): Promise { throw new Error("Method not implemented"); } @@ -289,7 +302,10 @@ class DatabaseModule extends TCoreModule { /** * Generates and retrieves a new device token. */ - public async createDeviceToken(deviceID: TGenericID, data: IDatabaseCreateDeviceTokenData): Promise { + public async createDeviceToken( + deviceID: TGenericID, + data: IDatabaseCreateDeviceTokenData, + ): Promise { throw new Error("Method not implemented"); } @@ -299,7 +315,7 @@ class DatabaseModule extends TCoreModule { */ public async getDeviceTokenList( deviceID: TGenericID, - query: IDatabaseGetDeviceTokenListQuery + query: IDatabaseGetDeviceTokenListQuery, ): Promise { throw new Error("Method not implemented"); } @@ -314,7 +330,10 @@ class DatabaseModule extends TCoreModule { /** * Gets all the parameters of a device. */ - public async getDeviceParamList(deviceID: TGenericID, sentStatus?: boolean): Promise { + public async getDeviceParamList( + deviceID: TGenericID, + sentStatus?: boolean, + ): Promise { throw new Error("Method not implemented"); } @@ -328,35 +347,48 @@ class DatabaseModule extends TCoreModule { /** * Overrides the device parameters. */ - public async setDeviceParams(deviceID: TGenericID, data: IDatabaseSetDeviceParamsData[]): Promise { + public async setDeviceParams( + deviceID: TGenericID, + data: IDatabaseSetDeviceParamsData[], + ): Promise { throw new Error("Method not implemented"); } /** * Retrieves the amount of data in a device. */ - public async getDeviceDataAmount(deviceID: TGenericID, type: TDeviceType): Promise { + public async getDeviceDataAmount( + deviceID: TGenericID, + type: TDeviceType, + ): Promise { throw new Error("Method not implemented"); } /** * Empties a device. */ - public async emptyDevice(deviceID: TGenericID, type: TDeviceType): Promise { + public async emptyDevice( + deviceID: TGenericID, + type: TDeviceType, + ): Promise { throw new Error("Method not implemented"); } /** * Retrieves the token info of a particular uuid. */ - public async getDeviceToken(token: TGenericToken): Promise { + public async getDeviceToken( + token: TGenericToken, + ): Promise { throw new Error("Method not implemented"); } /** * Retrieves a list of actions. */ - public async getActionList(query: IDatabaseActionListQuery): Promise { + public async getActionList( + query: IDatabaseActionListQuery, + ): Promise { throw new Error("Method not implemented"); } @@ -370,7 +402,10 @@ class DatabaseModule extends TCoreModule { /** * Edits the information of a single action. */ - public async editAction(actionID: TGenericID, data: IDatabaseEditActionData): Promise { + public async editAction( + actionID: TGenericID, + data: IDatabaseEditActionData, + ): Promise { throw new Error("Method not implemented"); } @@ -391,21 +426,28 @@ class DatabaseModule extends TCoreModule { /** * Retrieves a list of analyses. */ - public async getAnalysisList(query: IDatabaseAnalysisListQuery): Promise { + public async getAnalysisList( + query: IDatabaseAnalysisListQuery, + ): Promise { throw new Error("Method not implemented"); } /** * Retrieves all the information of an analysis. */ - public async getAnalysisInfo(analysisID: TGenericID): Promise { + public async getAnalysisInfo( + analysisID: TGenericID, + ): Promise { throw new Error("Method not implemented"); } /** * Edits the information of a single analysis. */ - public async editAnalysis(analysisID: TGenericID, data: IDatabaseEditAnalysisData): Promise { + public async editAnalysis( + analysisID: TGenericID, + data: IDatabaseEditAnalysisData, + ): Promise { throw new Error("Method not implemented"); } @@ -426,14 +468,19 @@ class DatabaseModule extends TCoreModule { /** * Creates a new analysis. */ - public async createAnalysis(data: IDatabaseCreateAnalysisData): Promise { + public async createAnalysis( + data: IDatabaseCreateAnalysisData, + ): Promise { throw new Error("Method not implemented"); } /** * Creates/adds a new log for an analysis. */ - public async addAnalysisLog(analysisID: TGenericID, data: IDatabaseAddAnalysisLogData): Promise { + public async addAnalysisLog( + analysisID: TGenericID, + data: IDatabaseAddAnalysisLogData, + ): Promise { throw new Error("Method not implemented"); } @@ -454,7 +501,10 @@ class DatabaseModule extends TCoreModule { /** * Retrieves a storage item of a plugin. */ - public async getPluginStorageItem(pluginID: string, key: string): Promise { + public async getPluginStorageItem( + pluginID: string, + key: string, + ): Promise { throw new Error("Method not implemented"); } @@ -468,14 +518,20 @@ class DatabaseModule extends TCoreModule { /** * Creates/edits a storage item of a plugin. */ - public async setPluginStorageItem(pluginID: string, data: IDatabaseSetPluginStorageData): Promise { + public async setPluginStorageItem( + pluginID: string, + data: IDatabaseSetPluginStorageData, + ): Promise { throw new Error("Method not implemented"); } /** * Deletes a storage item of a plugin. */ - public async deletePluginStorageItem(pluginID: string, key: string): Promise { + public async deletePluginStorageItem( + pluginID: string, + key: string, + ): Promise { throw new Error("Method not implemented"); } @@ -489,7 +545,10 @@ class DatabaseModule extends TCoreModule { /** * Adds a statistic. */ - public async addStatistic(isoTime: string, data: IDatabaseAddStatisticData): Promise { + public async addStatistic( + isoTime: string, + data: IDatabaseAddStatisticData, + ): Promise { throw new Error("Method not implemented"); } @@ -503,7 +562,10 @@ class DatabaseModule extends TCoreModule { /** * Generates and retrieves a new account token. */ - public async createAccountToken(accountID: TGenericID, data: IDatabaseAccountCreateTokenData): Promise { + public async createAccountToken( + accountID: TGenericID, + data: IDatabaseAccountCreateTokenData, + ): Promise { throw new Error("Method not implemented"); } @@ -524,7 +586,9 @@ class DatabaseModule extends TCoreModule { /** * Retrieves all the information of a single account via its username. */ - public async getAccountByUsername(username: string): Promise { + public async getAccountByUsername( + username: string, + ): Promise { throw new Error("Method not implemented"); } @@ -538,14 +602,18 @@ class DatabaseModule extends TCoreModule { /** * Retrieves a list of accounts. */ - public async getAccountList(query: IDatabaseAccountListQuery): Promise { + public async getAccountList( + query: IDatabaseAccountListQuery, + ): Promise { throw new Error("Method not implemented"); } /** * Retrieves the token info of a particular uuid. */ - public async getAccountToken(token: TGenericToken): Promise { + public async getAccountToken( + token: TGenericToken, + ): Promise { throw new Error("Method not implemented"); } diff --git a/packages/sdk/src/Lib/FileSystemModule/FileSystemModule.ts b/packages/sdk/src/Lib/FileSystemModule/FileSystemModule.ts index d4f56c60..763ccb25 100644 --- a/packages/sdk/src/Lib/FileSystemModule/FileSystemModule.ts +++ b/packages/sdk/src/Lib/FileSystemModule/FileSystemModule.ts @@ -1,4 +1,7 @@ -import type { IPluginFilesystemItem, IModuleSetupWithoutType } from "../../Types.ts"; +import type { + IModuleSetupWithoutType, + IPluginFilesystemItem, +} from "../../Types.ts"; import TCoreModule from "../TCoreModule/TCoreModule.ts"; /** diff --git a/packages/sdk/src/Lib/Helpers/Helpers.ts b/packages/sdk/src/Lib/Helpers/Helpers.ts index 55eaad4a..f299db9b 100644 --- a/packages/sdk/src/Lib/Helpers/Helpers.ts +++ b/packages/sdk/src/Lib/Helpers/Helpers.ts @@ -1,7 +1,10 @@ import type { WriteFileOptions } from "node:fs"; import { nanoid } from "nanoid"; +import { + generateResourceID, + validateResourceID, +} from "../../Shared/ResourceID.ts"; import type { IComputerUsage } from "../../Types.ts"; -import { generateResourceID, validateResourceID } from "../../Shared/ResourceID.ts"; import APIBridge from "../APIBridge/APIBridge.ts"; /** @@ -33,7 +36,12 @@ class Helpers extends APIBridge { /** * Retrieves information about the OS. */ - public async getOSInfo(): Promise<{ arch: string; name: string; platform: string; version: string }> { + public async getOSInfo(): Promise<{ + arch: string; + name: string; + platform: string; + version: string; + }> { return await this.invokeApiMethod("getOSInfo"); } @@ -64,7 +72,11 @@ class Helpers extends APIBridge { * Writes data to the file, replacing the file if it already exists. * `data` can be a string or a buffer. */ - public async writeFile(filename: string, data: string, options?: WriteFileOptions): Promise { + public async writeFile( + filename: string, + data: string, + options?: WriteFileOptions, + ): Promise { await this.invokeApiMethod("writeFile", filename, data, options); } diff --git a/packages/sdk/src/Lib/HookModule/HookModule.ts b/packages/sdk/src/Lib/HookModule/HookModule.ts index 318cf5a0..e11ba7a9 100644 --- a/packages/sdk/src/Lib/HookModule/HookModule.ts +++ b/packages/sdk/src/Lib/HookModule/HookModule.ts @@ -1,4 +1,8 @@ -import type { TGenericID, IModuleSetupWithoutType, IDeviceData } from "../../Types.ts"; +import type { + IDeviceData, + IModuleSetupWithoutType, + TGenericID, +} from "../../Types/index.ts"; import TCoreModule from "../TCoreModule/TCoreModule.ts"; /** @@ -13,7 +17,10 @@ class HookModule extends TCoreModule { /** * Called after the data sent by a device is inserted into the bucket. */ - public async onAfterInsertDeviceData(deviceID: TGenericID, data: IDeviceData[]): Promise { + public async onAfterInsertDeviceData( + deviceID: TGenericID, + data: IDeviceData[], + ): Promise { // not implemented } diff --git a/packages/sdk/src/Lib/NavbarModule/NavbarModule.ts b/packages/sdk/src/Lib/NavbarModule/NavbarModule.ts new file mode 100644 index 00000000..7d39425a --- /dev/null +++ b/packages/sdk/src/Lib/NavbarModule/NavbarModule.ts @@ -0,0 +1,13 @@ +import TCoreModule from "../TCoreModule/TCoreModule.ts"; + +/** + * This class allows a plugin to create a navbar button inside of tagocore. + * ! only available internally to certain plugins developed by TagoIO. + */ +class NavbarButtonModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "navbar-button"); + } +} + +export default NavbarButtonModule; diff --git a/packages/sdk/src/Lib/PageModule/PageModule.ts b/packages/sdk/src/Lib/PageModule/PageModule.ts new file mode 100644 index 00000000..b120bf7a --- /dev/null +++ b/packages/sdk/src/Lib/PageModule/PageModule.ts @@ -0,0 +1,13 @@ +import TCoreModule from "../TCoreModule/TCoreModule.ts"; + +/** + * This module allows the creation of a page inside tagocore with HTML and CSS. + * ! only available internally to certain plugins developed by TagoIO. + */ +class PageModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "page"); + } +} + +export default PageModule; diff --git a/packages/sdk/src/Lib/QueueModule/QueueModule.ts b/packages/sdk/src/Lib/QueueModule/QueueModule.ts index 8dad711f..89c8b884 100644 --- a/packages/sdk/src/Lib/QueueModule/QueueModule.ts +++ b/packages/sdk/src/Lib/QueueModule/QueueModule.ts @@ -1,4 +1,9 @@ -import { type IDatabaseDeviceDataCreate, type IModuleSetupWithoutType, type TGenericID, TDeviceType } from "../../Types.ts"; +import { + type IDatabaseDeviceDataCreate, + type IModuleSetupWithoutType, + TDeviceType, + type TGenericID, +} from "../../Types.ts"; import TCoreModule from "../TCoreModule/TCoreModule.ts"; /** @@ -13,7 +18,10 @@ class QueueModule extends TCoreModule { * Trigger this function when data added to device. * The data is already parsed and encoded. */ - public async onAddDeviceData(deviceID: TGenericID, data: IDatabaseDeviceDataCreate[]): Promise { + public async onAddDeviceData( + deviceID: TGenericID, + data: IDatabaseDeviceDataCreate[], + ): Promise { throw new Error("Method not implemented"); } } diff --git a/packages/sdk/src/Lib/SidebarButtonModule/SidebarButtonModule.ts b/packages/sdk/src/Lib/SidebarButtonModule/SidebarButtonModule.ts new file mode 100644 index 00000000..1e505db8 --- /dev/null +++ b/packages/sdk/src/Lib/SidebarButtonModule/SidebarButtonModule.ts @@ -0,0 +1,13 @@ +import TCoreModule from "../TCoreModule/TCoreModule.ts"; + +/** + * This module allows a plugin to create a sidebar button inside of tagocore. + * ! only available internally to certain plugins developed by TagoIO. + */ +class SidebarButtonModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "sidebar-button"); + } +} + +export default SidebarButtonModule; diff --git a/packages/sdk/src/Lib/SystemModule/SystemModule.ts b/packages/sdk/src/Lib/SystemModule/SystemModule.ts new file mode 100644 index 00000000..6e31c2a3 --- /dev/null +++ b/packages/sdk/src/Lib/SystemModule/SystemModule.ts @@ -0,0 +1,64 @@ +import APIBridge from "../APIBridge/APIBridge.ts"; +import TCoreModule from "../TCoreModule/TCoreModule.ts"; + +/** + * This module allows a plugin to override some system functionality. + * ! only available internally to certain plugins developed by TagoIO. + */ +class SystemModule extends TCoreModule { + constructor(protected setup: any) { + super(setup, "system-override"); + } + + async onInstallStorePlugin(id: string, version: string, platform: string) { + // + } + + async onUninstallStorePlugin(id: string) { + // + } + + async onEditModuleSettings(pluginID: string, settings: any) { + // + } + + async onDisablePlugin(id: string) { + // + } + + async onEnablePlugin(id: string) { + // + } + + async onStartPluginModule(pluginID: string, moduleID: string) { + // + } + + async onStopPluginModule(pluginID: string, moduleID: string) { + // + } + + /** + */ + async exit(code: number) { + const bridge: any = new APIBridge(); + try { + await bridge.invokeApiMethod("exitSystem", code); + } finally { + (bridge as any).destroy(); + } + } + + /** + */ + async emitInstallLog(data: any) { + const bridge: any = new APIBridge(); + try { + await bridge.invokeApiMethod("emitInstallLog", data); + } finally { + (bridge as any).destroy(); + } + } +} + +export default SystemModule; diff --git a/packages/sdk/src/Lib/TCoreModule/TCoreModule.ts b/packages/sdk/src/Lib/TCoreModule/TCoreModule.ts index 01017036..5c23973d 100644 --- a/packages/sdk/src/Lib/TCoreModule/TCoreModule.ts +++ b/packages/sdk/src/Lib/TCoreModule/TCoreModule.ts @@ -19,7 +19,10 @@ parentPort?.setMaxListeners(100); abstract class TCoreModule { private started = false; - constructor(protected setup: IModuleSetupWithoutType, protected type: TPluginType) { + constructor( + protected setup: IModuleSetupWithoutType, + protected type: TPluginType, + ) { this.attachEvents(); this.validateSetupID(); @@ -31,7 +34,10 @@ abstract class TCoreModule { /** * Shows a message in the module's configuration page. */ - public async showMessage(type: TModuleMessageType, message: string): Promise { + public async showMessage( + type: TModuleMessageType, + message: string, + ): Promise { if (type === "info") { const color = "hsl(208, 96%, 75%, 0.2)"; const iconColor = "hsl(208, 96%, 35%, 1)"; @@ -146,7 +152,11 @@ abstract class TCoreModule { * Executes a method from this module with the given parameters. * The connectionID must be informed in order to sync the result in the API. */ - private async executeMethod(method: string, params: any[], connectionID: string) { + private async executeMethod( + method: string, + params: any[], + connectionID: string, + ) { const event = "pluginMethodResponse"; const methodExists = !!this[method]; diff --git a/packages/sdk/src/Lib/index.ts b/packages/sdk/src/Lib/index.ts index f3c09e97..e5a5a1c0 100644 --- a/packages/sdk/src/Lib/index.ts +++ b/packages/sdk/src/Lib/index.ts @@ -1,15 +1,19 @@ -import ActionTypeModule from "./ActionTypeModule/ActionTypeModule.ts"; import ActionTriggerModule from "./ActionTriggerModule/ActionTriggerModule.ts"; +import ActionTypeModule from "./ActionTypeModule/ActionTypeModule.ts"; import core from "./Core/Core.ts"; import DatabaseModule from "./DatabaseModule/DatabaseModule.ts"; -import QueueModule from "./QueueModule/QueueModule.ts"; +import FileSystemModule from "./FileSystemModule/FileSystemModule.ts"; import helpers from "./Helpers/Helpers.ts"; +import HookModule from "./HookModule/HookModule.ts"; +import NavbarButtonModule from "./NavbarModule/NavbarModule.ts"; +import PageModule from "./PageModule/PageModule.ts"; import PayloadEncoderModule from "./PayloadEncoderModule/PayloadEncoderModule.ts"; import pluginStorage from "./PluginStorage/PluginStorage.ts"; +import QueueModule from "./QueueModule/QueueModule.ts"; import ServiceModule from "./ServiceModule/ServiceModule.ts"; -import FileSystemModule from "./FileSystemModule/FileSystemModule.ts"; +import SidebarButtonModule from "./SidebarButtonModule/SidebarButtonModule.ts"; +import SystemModule from "./SystemModule/SystemModule.ts"; import TCoreModule from "./TCoreModule/TCoreModule.ts"; -import HookModule from "./HookModule/HookModule.ts"; export { ActionTriggerModule, @@ -24,4 +28,8 @@ export { pluginStorage, ServiceModule, TCoreModule, + PageModule, + NavbarButtonModule, + SidebarButtonModule, + SystemModule, }; diff --git a/packages/sdk/src/Shared/ResourceID.ts b/packages/sdk/src/Shared/ResourceID.ts index 41809a96..a1c5c4cf 100644 --- a/packages/sdk/src/Shared/ResourceID.ts +++ b/packages/sdk/src/Shared/ResourceID.ts @@ -13,7 +13,9 @@ export function generateResourceID(): string { return ""; } const firstCase = String(Date.now()).slice(0, 2).split("").reverse().join(""); - const secondCase = Buffer.from([Number(String(Date.now()).slice(2, 4))]).toString("hex"); + const secondCase = Buffer.from([ + Number(String(Date.now()).slice(2, 4)), + ]).toString("hex"); return `${firstCase}${secondCase}${nanoid()}`; } diff --git a/packages/sdk/src/Types/Account/Account.types.test.ts b/packages/sdk/src/Types/Account/Account.types.test.ts index f7963681..58436fd0 100644 --- a/packages/sdk/src/Types/Account/Account.types.test.ts +++ b/packages/sdk/src/Types/Account/Account.types.test.ts @@ -1,6 +1,11 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; -import { zAccountList, zAccountCreate, zAccountTokenCreate, zAccountListQuery } from "./Account.types.ts"; -import { test, expect, describe } from "vitest"; +import { + zAccountCreate, + zAccountList, + zAccountListQuery, + zAccountTokenCreate, +} from "./Account.types.ts"; describe("zAccountList", () => { test("parses simple object", () => { @@ -59,7 +64,9 @@ describe("zAccountListQuery", () => { zAccountListQuery.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.fields[0].startsWith("Invalid enum value.")).toBeTruthy(); + expect( + e.fieldErrors.fields[0].startsWith("Invalid enum value."), + ).toBeTruthy(); } }); @@ -113,7 +120,9 @@ describe("zAccountTokenCreate", () => { zAccountTokenCreate.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.permission[0].startsWith("Invalid enum value.")).toBeTruthy(); + expect( + e.fieldErrors.permission[0].startsWith("Invalid enum value."), + ).toBeTruthy(); } }); diff --git a/packages/sdk/src/Types/Account/Account.types.ts b/packages/sdk/src/Types/Account/Account.types.ts index a38e9b68..d60e250c 100644 --- a/packages/sdk/src/Types/Account/Account.types.ts +++ b/packages/sdk/src/Types/Account/Account.types.ts @@ -1,7 +1,7 @@ -import { z } from "zod"; import { v4 as uuid } from "uuid"; -import { zObjectID, zToken } from "../index.ts"; +import { z } from "zod"; import { generateResourceID } from "../../Shared/ResourceID.ts"; +import { zObjectID, zToken } from "../index.ts"; /** * Configuration of an account. @@ -18,12 +18,21 @@ export const zAccount = z.object({ /** * Configuration of the account list. */ -export const zAccountList = z.array(zAccount.partial().extend({ password: z.string(), id: zObjectID })); +export const zAccountList = z.array( + zAccount.partial().extend({ password: z.string(), id: zObjectID }), +); /** * Allowed fields in a account list query. */ -const zAccountListQueryField = z.enum(["id", "name", "username", "password", "password_hint", "created_at"]); +const zAccountListQueryField = z.enum([ + "id", + "name", + "username", + "password", + "password_hint", + "created_at", +]); /** * Configuration of the account list. diff --git a/packages/sdk/src/Types/Action/Action.types.test.ts b/packages/sdk/src/Types/Action/Action.types.test.ts index acda42fa..cacd3e7a 100644 --- a/packages/sdk/src/Types/Action/Action.types.test.ts +++ b/packages/sdk/src/Types/Action/Action.types.test.ts @@ -1,3 +1,5 @@ +import { describe, expect, test } from "vitest"; +import { validateResourceID } from "../../Shared/ResourceID.ts"; import { type IActionTypePost, type IActionTypeScript, @@ -6,9 +8,7 @@ import { zActionTypeScript, zActionTypeTagoIO, } from "../index.ts"; -import { validateResourceID } from "../../Shared/ResourceID.ts"; import { zActionCreate } from "./Action.types.ts"; -import { test, expect, describe } from "vitest"; describe("zActionCreate", () => { test("parses simple object", () => { @@ -103,7 +103,10 @@ describe("zActionTypeScript", () => { describe("zActionTypeTagoIO", () => { test("parses simple tagoio object", () => { - const data: IActionTypeTagoIO = { type: "tagoio", token: "1014121a-d123-4a56-789a-c16b4be056fa" }; + const data: IActionTypeTagoIO = { + type: "tagoio", + token: "1014121a-d123-4a56-789a-c16b4be056fa", + }; const parsed = zActionTypeTagoIO.parse(data); expect(parsed).toEqual(data); }); @@ -115,7 +118,10 @@ describe("zActionTypeTagoIO", () => { }); test("throws error if token is not an uuid", () => { - const data: IActionTypeTagoIO = { type: "tagoio", token: "1014121a-c16b4be056" }; + const data: IActionTypeTagoIO = { + type: "tagoio", + token: "1014121a-c16b4be056", + }; const fn = () => zActionTypeTagoIO.parse(data); expect(fn).toThrow(); }); @@ -123,13 +129,20 @@ describe("zActionTypeTagoIO", () => { describe("zActionTypePost", () => { test("parses simple post object", () => { - const data: IActionTypePost = { type: "post", url: "http://localhost:8888" }; + const data: IActionTypePost = { + type: "post", + url: "http://localhost:8888", + }; const parsed = zActionTypePost.parse(data); expect(parsed).toEqual(data); }); test("allows headers", () => { - const data: IActionTypePost = { type: "post", url: "http://localhost:8888", headers: { token: "abc" } }; + const data: IActionTypePost = { + type: "post", + url: "http://localhost:8888", + headers: { token: "abc" }, + }; const parsed = zActionTypePost.parse(data); expect(parsed).toEqual(data); }); @@ -145,7 +158,11 @@ describe("zActionTypePost", () => { }); test("throws error if fallback_token is not an uuid", () => { - const data: IActionTypePost = { type: "post", url: "hello world", fallback_token: 1 as any }; + const data: IActionTypePost = { + type: "post", + url: "hello world", + fallback_token: 1 as any, + }; const fn = () => zActionTypePost.parse(data); expect(fn).toThrow(); }); diff --git a/packages/sdk/src/Types/Action/Action.types.ts b/packages/sdk/src/Types/Action/Action.types.ts index 11585da3..b48d00e9 100644 --- a/packages/sdk/src/Types/Action/Action.types.ts +++ b/packages/sdk/src/Types/Action/Action.types.ts @@ -1,12 +1,21 @@ import { z } from "zod"; import { generateResourceID } from "../../Shared/ResourceID.ts"; -import { type IPluginConfigField, zPluginModuleIDCombo } from "../Plugin/Plugin.types.ts"; -import { zQuery, zName, zObjectID, zActiveAutoGen, zTagsAutoGen } from "../Common/Common.types.ts"; -import { zTags } from "../Tag/Tag.types.ts"; +import { + zActiveAutoGen, + zName, + zObjectID, + zQuery, + zTagsAutoGen, +} from "../Common/Common.types.ts"; +import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; import preprocessBoolean from "../Helpers/preprocessBoolean.ts"; import preprocessObject from "../Helpers/preprocessObject.ts"; import removeNullValues from "../Helpers/removeNullValues.ts"; -import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; +import { + type IPluginConfigField, + zPluginModuleIDCombo, +} from "../Plugin/Plugin.types.ts"; +import { zTags } from "../Tag/Tag.types.ts"; /** * Validation for a "script" action type. @@ -23,7 +32,11 @@ export const zActionTypePost = z.object({ type: z.literal("post"), url: z.string().url(), headers: z.record(z.string()).optional(), - fallback_token: z.string().uuid("Invalid fallback token").nullable().optional(), + fallback_token: z + .string() + .uuid("Invalid fallback token") + .nullable() + .optional(), }); /** @@ -37,7 +50,9 @@ export const zActionTypeTagoIO = z.object({ /** * Validation for an action type that uses a plugin module. */ -export const zActionTypePluginModule = z.object({ type: zPluginModuleIDCombo }).passthrough(); +export const zActionTypePluginModule = z + .object({ type: zPluginModuleIDCombo }) + .passthrough(); /** * Validation for the `action` object of an action. @@ -45,11 +60,14 @@ export const zActionTypePluginModule = z.object({ type: zPluginModuleIDCombo }). const zActionType = z.any().transform((x) => { if (x?.type === "script") { return zActionTypeScript.parse(x); - }if (x?.type === "post") { + } + if (x?.type === "post") { return zActionTypePost.parse(x); - }if (x?.type === "tagoio") { + } + if (x?.type === "tagoio") { return zActionTypeTagoIO.parse(x); - }if (x) { + } + if (x) { return zActionTypePluginModule.parse(x); } }); @@ -86,7 +104,9 @@ export const zActionCreate = zAction updated_at: true, }) .extend({ - type: z.enum(["condition", "interval", "schedule"]).or(zPluginModuleIDCombo), + type: z + .enum(["condition", "interval", "schedule"]) + .or(zPluginModuleIDCombo), action: zActionType, active: zActiveAutoGen, tags: zTagsAutoGen, @@ -96,7 +116,7 @@ export const zActionCreate = zAction ...x, created_at: new Date(), id: generateResourceID(), - }) + }), ); /** @@ -120,7 +140,7 @@ export const zActionList = z.array( zAction.partial().extend({ id: zObjectID, tags: zTags, - }) + }), ); /** @@ -157,7 +177,7 @@ export const zActionListQuery = zQuery.extend({ }) .partial() .nullish() - .transform((x) => x ?? {}) + .transform((x) => x ?? {}), ), fields: z .array(zActionListQueryFields) diff --git a/packages/sdk/src/Types/Analysis/Analysis.type.test.ts b/packages/sdk/src/Types/Analysis/Analysis.type.test.ts index 385b0c00..219fbceb 100644 --- a/packages/sdk/src/Types/Analysis/Analysis.type.test.ts +++ b/packages/sdk/src/Types/Analysis/Analysis.type.test.ts @@ -1,6 +1,12 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; -import { zAnalysisCreate, zAnalysisEdit, zAnalysisList, zAnalysisListQuery, zAnalysisLogList } from "./Analysis.types.ts"; -import { test, expect, describe } from "vitest"; +import { + zAnalysisCreate, + zAnalysisEdit, + zAnalysisList, + zAnalysisListQuery, + zAnalysisLogList, +} from "./Analysis.types.ts"; describe("zAnalysis Create", () => { test("Success", () => { @@ -24,7 +30,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.name[0]).toBe("String must contain at least 3 character(s)"); + expect(e.fieldErrors.name[0]).toBe( + "String must contain at least 3 character(s)", + ); } }); @@ -41,7 +49,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.name[0]).toBe("String must contain at most 100 character(s)"); + expect(errorF.fieldErrors.name[0]).toBe( + "String must contain at most 100 character(s)", + ); } }); @@ -55,7 +65,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.active[0]).toBe("Expected boolean, received string"); + expect(errorF.fieldErrors.active[0]).toBe( + "Expected boolean, received string", + ); } }); @@ -69,7 +81,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.tags[0]).toBe("Expected array, received object"); + expect(errorF.fieldErrors.tags[0]).toBe( + "Expected array, received object", + ); } }); @@ -97,7 +111,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.file_path[0]).toBe("Expected string, received object"); + expect(errorF.fieldErrors.file_path[0]).toBe( + "Expected string, received object", + ); } }); @@ -111,7 +127,9 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.binary_path[0]).toBe("Expected string, received object"); + expect(errorF.fieldErrors.binary_path[0]).toBe( + "Expected string, received object", + ); } }); @@ -126,8 +144,12 @@ describe("zAnalysis Create", () => { zAnalysisCreate.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.created_at[0]).toBe("Expected date, received string"); - expect(errorF.fieldErrors.updated_at[0]).toBe("Expected date, received string"); + expect(errorF.fieldErrors.created_at[0]).toBe( + "Expected date, received string", + ); + expect(errorF.fieldErrors.updated_at[0]).toBe( + "Expected date, received string", + ); } }); }); @@ -163,17 +185,23 @@ describe("Analysis Edit", () => { zAnalysisEdit.parse(analysis_obj); } catch (error) { const errorF = (error as ZodError).flatten(); - expect(errorF.fieldErrors.name[0]).toBe("String must contain at least 3 character(s)"); + expect(errorF.fieldErrors.name[0]).toBe( + "String must contain at least 3 character(s)", + ); } }); }); describe("Analysis List", () => { test("Success", () => { - const result = zAnalysisList.parse([{ id: "testid", tags: [{ key: "analysis_type", value: "math" }] }]); + const result = zAnalysisList.parse([ + { id: "testid", tags: [{ key: "analysis_type", value: "math" }] }, + ]); expect(result[0].id).toBe("testid"); - expect(result[0].tags).toStrictEqual([{ key: "analysis_type", value: "math" }]); + expect(result[0].tags).toStrictEqual([ + { key: "analysis_type", value: "math" }, + ]); }); test("Error - Required tags", () => { diff --git a/packages/sdk/src/Types/Analysis/Analysis.types.ts b/packages/sdk/src/Types/Analysis/Analysis.types.ts index 794a9300..eec4837a 100644 --- a/packages/sdk/src/Types/Analysis/Analysis.types.ts +++ b/packages/sdk/src/Types/Analysis/Analysis.types.ts @@ -1,18 +1,18 @@ import { z } from "zod"; import { - zDateAutoGen, zActiveAutoGen, + zDateAutoGen, zName, zObjectID, - zTagsAutoGen, - zQuery, zObjectIDAutoGen, + zQuery, + zTagsAutoGen, } from "../Common/Common.types.ts"; -import { zTags } from "../Tag/Tag.types.ts"; -import { zLog } from "../Log/Log.types.ts"; +import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; import preprocessBoolean from "../Helpers/preprocessBoolean.ts"; import preprocessObject from "../Helpers/preprocessObject.ts"; -import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; +import { zLog } from "../Log/Log.types.ts"; +import { zTags } from "../Tag/Tag.types.ts"; export interface IAnalysisVariable { key: string; @@ -85,13 +85,15 @@ export const zAnalysisList = z.array( zAnalysis.partial().extend({ id: zObjectID, tags: zTags, - }) + }), ); /** * Configuration of the analysis log list. */ -export const zAnalysisLogList = z.array(zLog.extend({ analysis_id: zObjectID })); +export const zAnalysisLogList = z.array( + zLog.extend({ analysis_id: zObjectID }), +); /** * Allowed fields in an analysis list query. @@ -127,7 +129,7 @@ export const zAnalysisListQuery = zQuery.extend({ }) .partial() .nullish() - .transform((x) => x ?? {}) + .transform((x) => x ?? {}), ), fields: z .array(zAnalysisListQueryFields) diff --git a/packages/sdk/src/Types/Common/Common.types.test.ts b/packages/sdk/src/Types/Common/Common.types.test.ts index 302041f9..8f6874ca 100644 --- a/packages/sdk/src/Types/Common/Common.types.test.ts +++ b/packages/sdk/src/Types/Common/Common.types.test.ts @@ -1,6 +1,13 @@ +import { describe, expect, test } from "vitest"; import { validateResourceID } from "../index.ts"; -import { type IQuery, zActiveAutoGen, zDateAutoGen, zObjectIDAutoGen, zQuery, zTagsAutoGen } from "./Common.types.ts"; -import { test, expect, describe } from "vitest"; +import { + type IQuery, + zActiveAutoGen, + zDateAutoGen, + zObjectIDAutoGen, + zQuery, + zTagsAutoGen, +} from "./Common.types.ts"; describe("zTagsAutoGen", () => { test("parses null", () => { @@ -137,7 +144,13 @@ describe("zQuery", () => { test("parses empty object", () => { const data: IQuery = {}; const parsed = zQuery.parse(data); - expect(parsed).toEqual({ page: 1, amount: 20, fields: [], filter: {}, orderBy: ["name", "asc"] }); + expect(parsed).toEqual({ + page: 1, + amount: 20, + fields: [], + filter: {}, + orderBy: ["name", "asc"], + }); }); test("parses page correctly", () => { diff --git a/packages/sdk/src/Types/Common/Common.types.ts b/packages/sdk/src/Types/Common/Common.types.ts index 61f40a5b..87645ecb 100644 --- a/packages/sdk/src/Types/Common/Common.types.ts +++ b/packages/sdk/src/Types/Common/Common.types.ts @@ -1,12 +1,12 @@ -import { z } from "zod"; -import { DateTime } from "luxon"; import cronParser from "cron-parser"; -import preprocessNumber from "../Helpers/preprocessNumber.ts"; +import { DateTime } from "luxon"; +import { z } from "zod"; import { generateResourceID } from "../../Shared/ResourceID.ts"; -import { zTag } from "../Tag/Tag.types.ts"; -import { parseSafe } from "../Helpers/parseSafe.ts"; import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; import { parseRelativeDate } from "../Helpers/parseRelativeDate.ts"; +import { parseSafe } from "../Helpers/parseSafe.ts"; +import preprocessNumber from "../Helpers/preprocessNumber.ts"; +import { zTag } from "../Tag/Tag.types.ts"; /** * Validation for relative date intervals, such as "1 minute", or "30 hours". @@ -19,7 +19,10 @@ export const zInterval = z.string().refine((value) => { if (!time) { return false; } - const diff = DateTime.now().diff(DateTime.fromJSDate(new Date(time)), "minutes").minutes; + const diff = DateTime.now().diff( + DateTime.fromJSDate(new Date(time)), + "minutes", + ).minutes; if (diff < 1) { return false; } @@ -61,7 +64,10 @@ export const zQuery = z.object({ filter: z .any() .nullish() - .refine((x) => x === null || x === undefined || typeof x === "object", "Filter must be an object") + .refine( + (x) => x === null || x === undefined || typeof x === "object", + "Filter must be an object", + ) .transform((x) => parseSafe(x, {})) .refine((x) => !Array.isArray(x), "Filter must be an object"), orderBy: createQueryOrderBy(z.string()), diff --git a/packages/sdk/src/Types/DatabaseModule/DatabaseModule.types.ts b/packages/sdk/src/Types/DatabaseModule/DatabaseModule.types.ts index a834ea16..f59e427b 100644 --- a/packages/sdk/src/Types/DatabaseModule/DatabaseModule.types.ts +++ b/packages/sdk/src/Types/DatabaseModule/DatabaseModule.types.ts @@ -2,25 +2,25 @@ import type { z } from "zod"; import type { ILog, IStatisticCreate, + zAccountCreate, + zAccountListQuery, + zAccountTokenCreate, zActionCreate, zActionEdit, zActionListQuery, zAnalysisCreate, zAnalysisEdit, zAnalysisListQuery, + zDeviceCreate, zDeviceDataCreate, zDeviceDataQuery, - zDeviceCreate, + zDeviceDataUpdate, zDeviceEdit, zDeviceListQuery, zDeviceParameterCreate, zDeviceTokenCreate, zDeviceTokenListQuery, zPluginStorageItemSet, - zDeviceDataUpdate, - zAccountTokenCreate, - zAccountCreate, - zAccountListQuery, } from "../index.ts"; /** @@ -39,7 +39,10 @@ export type IDatabaseDeviceDataEdit = z.output; /** * Data parameter of the `getDeviceData` functions. */ -export type IDatabaseGetDeviceDataQuery = Omit, "details">; +export type IDatabaseGetDeviceDataQuery = Omit< + z.output, + "details" +>; /** * Data parameter of the `addStatistic` function. @@ -49,7 +52,9 @@ export type IDatabaseAddStatisticData = IStatisticCreate; /** * Data parameter of the `setPluginStorageItem` function. */ -export type IDatabaseSetPluginStorageData = z.output; +export type IDatabaseSetPluginStorageData = z.output< + typeof zPluginStorageItemSet +>; /** * Data parameter of the `addAnalysisLog` function. @@ -104,17 +109,24 @@ export type IDatabaseDeviceListQuery = z.infer; /** * Data parameter of the `setDeviceParams` function. */ -export type IDatabaseSetDeviceParamsData = z.infer; +export type IDatabaseSetDeviceParamsData = z.infer< + typeof zDeviceParameterCreate +>; /** * Query parameter of the `getDeviceTokenList` function. */ -export type IDatabaseGetDeviceTokenListQuery = z.infer; +export type IDatabaseGetDeviceTokenListQuery = z.infer< + typeof zDeviceTokenListQuery +>; /** * Data parameter of the `createDeviceToken` function. */ -export type IDatabaseCreateDeviceTokenData = Omit, "device_id">; +export type IDatabaseCreateDeviceTokenData = Omit< + z.infer, + "device_id" +>; /** * Type parameter of the `getTagKeys` function. @@ -124,7 +136,9 @@ export type TDatabaseGetTagKeysType = "action" | "analysis" | "device"; /** * Data parameter of the `createAccountToken` function. */ -export type IDatabaseAccountCreateTokenData = z.infer; +export type IDatabaseAccountCreateTokenData = z.infer< + typeof zAccountTokenCreate +>; /** * Data parameter of the `createAccount` function. diff --git a/packages/sdk/src/Types/Device/Device.types.test.ts b/packages/sdk/src/Types/Device/Device.types.test.ts index d71adedf..dbbee59e 100644 --- a/packages/sdk/src/Types/Device/Device.types.test.ts +++ b/packages/sdk/src/Types/Device/Device.types.test.ts @@ -1,15 +1,18 @@ -import { generateResourceID, validateResourceID } from "../../Shared/ResourceID.ts"; +import { describe, expect, test } from "vitest"; +import { + generateResourceID, + validateResourceID, +} from "../../Shared/ResourceID.ts"; import { - type IDeviceEdit, type IDeviceCreate, - zDeviceEdit, - zDeviceCreate, + type IDeviceEdit, type IDeviceListQuery, + type IDeviceParameter, + zDeviceCreate, + zDeviceEdit, zDeviceListQuery, zDeviceParameter, - type IDeviceParameter, } from "./Device.types.ts"; -import { test, expect, describe } from "vitest"; describe("zDeviceParameter", () => { test("parses simple object", () => { @@ -57,8 +60,12 @@ describe("zDeviceCreate", () => { }); test("throws error if active is not boolean", () => { - expect(() => zDeviceCreate.parse({ name: "ABC", active: "abc" })).toThrowError(); - expect(() => zDeviceCreate.parse({ name: "ABC", active: 123 })).toThrowError(); + expect(() => + zDeviceCreate.parse({ name: "ABC", active: "abc" }), + ).toThrowError(); + expect(() => + zDeviceCreate.parse({ name: "ABC", active: 123 }), + ).toThrowError(); }); test("ignores created_at", () => { @@ -77,7 +84,10 @@ describe("zDeviceCreate", () => { }); test("parses tags", () => { - const data: IDeviceCreate = { name: "Device #1", tags: [{ key: "hello", value: "world" }] }; + const data: IDeviceCreate = { + name: "Device #1", + tags: [{ key: "hello", value: "world" }], + }; const parsed = zDeviceCreate.parse(data); expect(parsed.tags).toEqual([{ key: "hello", value: "world" }]); }); @@ -95,13 +105,21 @@ describe("zDeviceCreate", () => { }); test("parses payload_parser", () => { - const data: IDeviceCreate = { name: "Device #1", payload_parser: "/parser.js" }; + const data: IDeviceCreate = { + name: "Device #1", + payload_parser: "/parser.js", + }; const parsed = zDeviceCreate.parse(data); expect(parsed.payload_parser).toEqual("/parser.js"); }); test("doesn't parse chunk variables if type is mutable", () => { - const data: IDeviceCreate = { name: "Device #1", type: "mutable", chunk_period: "day", chunk_retention: 1 }; + const data: IDeviceCreate = { + name: "Device #1", + type: "mutable", + chunk_period: "day", + chunk_retention: 1, + }; const parsed = zDeviceCreate.parse(data); expect(parsed.chunk_period).toBeFalsy(); expect(parsed.chunk_retention).toBeFalsy(); @@ -110,7 +128,11 @@ describe("zDeviceCreate", () => { test("parses different types of retentions", () => { const retentions: any = ["0", "12", "36", 0, 12, 36]; for (const chunk_retention of retentions) { - const data: IDeviceCreate = { name: "Device #1", chunk_period: "week", chunk_retention }; + const data: IDeviceCreate = { + name: "Device #1", + chunk_period: "week", + chunk_retention, + }; const parsed = zDeviceCreate.parse(data); expect(parsed.chunk_retention).toEqual(Number(chunk_retention)); } @@ -185,7 +207,10 @@ describe("zDeviceEdit", () => { }); test("parses payload_parser", () => { - const data: IDeviceEdit = { name: "Device #1", payload_parser: "/parser.js" }; + const data: IDeviceEdit = { + name: "Device #1", + payload_parser: "/parser.js", + }; const parsed = zDeviceEdit.parse(data); expect(parsed.payload_parser).toEqual("/parser.js"); }); @@ -304,12 +329,18 @@ describe("zDeviceListQuery", () => { test("throws error if filter fields are invalid", () => { expect(() => zDeviceListQuery.parse({ fields: ["temp"] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ fields: ["abc", "hello"] })).toThrowError(); + expect(() => + zDeviceListQuery.parse({ fields: ["abc", "hello"] }), + ).toThrowError(); expect(() => zDeviceListQuery.parse({ fields: [123] })).toThrowError(); expect(() => zDeviceListQuery.parse({ fields: [null] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ fields: [undefined] })).toThrowError(); + expect(() => + zDeviceListQuery.parse({ fields: [undefined] }), + ).toThrowError(); expect(() => zDeviceListQuery.parse({ fields: [{}] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ fields: [1, "name"] })).toThrowError(); + expect(() => + zDeviceListQuery.parse({ fields: [1, "name"] }), + ).toThrowError(); }); test("parses orderBy", () => { @@ -319,15 +350,34 @@ describe("zDeviceListQuery", () => { }); test("parses all orderBy available", () => { - expect(zDeviceListQuery.parse({ orderBy: ["id", "asc"] }).orderBy).toEqual(["id", "asc"]); - expect(zDeviceListQuery.parse({ orderBy: ["name", "asc"] }).orderBy).toEqual(["name", "asc"]); - expect(zDeviceListQuery.parse({ orderBy: ["active", "asc"] }).orderBy).toEqual(["active", "asc"]); - expect(zDeviceListQuery.parse({ orderBy: ["payload_parser", "desc"] }).orderBy).toEqual(["payload_parser", "desc"]); - expect(zDeviceListQuery.parse({ orderBy: ["last_output", "desc"] }).orderBy).toEqual(["last_output", "desc"]); - expect(zDeviceListQuery.parse({ orderBy: ["last_input", "desc"] }).orderBy).toEqual(["last_input", "desc"]); - expect(zDeviceListQuery.parse({ orderBy: ["created_at", "desc"] }).orderBy).toEqual(["created_at", "desc"]); - expect(zDeviceListQuery.parse({ orderBy: ["updated_at", "desc"] }).orderBy).toEqual(["updated_at", "desc"]); - expect(zDeviceListQuery.parse({ orderBy: ["tags", "desc"] }).orderBy).toEqual(["tags", "desc"]); + expect(zDeviceListQuery.parse({ orderBy: ["id", "asc"] }).orderBy).toEqual([ + "id", + "asc", + ]); + expect( + zDeviceListQuery.parse({ orderBy: ["name", "asc"] }).orderBy, + ).toEqual(["name", "asc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["active", "asc"] }).orderBy, + ).toEqual(["active", "asc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["payload_parser", "desc"] }).orderBy, + ).toEqual(["payload_parser", "desc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["last_output", "desc"] }).orderBy, + ).toEqual(["last_output", "desc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["last_input", "desc"] }).orderBy, + ).toEqual(["last_input", "desc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["created_at", "desc"] }).orderBy, + ).toEqual(["created_at", "desc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["updated_at", "desc"] }).orderBy, + ).toEqual(["updated_at", "desc"]); + expect( + zDeviceListQuery.parse({ orderBy: ["tags", "desc"] }).orderBy, + ).toEqual(["tags", "desc"]); }); test("parses orderBy as null", () => { @@ -352,10 +402,18 @@ describe("zDeviceListQuery", () => { }); test("throws error if orderBy configuration is incorrect", () => { - expect(() => zDeviceListQuery.parse({ orderBy: [123, "asc"] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ orderBy: ["name", "ASC"] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ orderBy: ["name", "DESC"] })).toThrowError(); - expect(() => zDeviceListQuery.parse({ orderBy: [true, "asc"] })).toThrowError(); + expect(() => + zDeviceListQuery.parse({ orderBy: [123, "asc"] }), + ).toThrowError(); + expect(() => + zDeviceListQuery.parse({ orderBy: ["name", "ASC"] }), + ).toThrowError(); + expect(() => + zDeviceListQuery.parse({ orderBy: ["name", "DESC"] }), + ).toThrowError(); + expect(() => + zDeviceListQuery.parse({ orderBy: [true, "asc"] }), + ).toThrowError(); expect(() => zDeviceListQuery.parse({ orderBy: ["name"] })).toThrowError(); }); }); diff --git a/packages/sdk/src/Types/Device/Device.types.ts b/packages/sdk/src/Types/Device/Device.types.ts index 314d1a44..ba56225a 100644 --- a/packages/sdk/src/Types/Device/Device.types.ts +++ b/packages/sdk/src/Types/Device/Device.types.ts @@ -1,13 +1,21 @@ -import { z } from "zod"; import { v4 as uuid } from "uuid"; -import preprocessObject from "../Helpers/preprocessObject.ts"; -import preprocessBoolean from "../Helpers/preprocessBoolean.ts"; -import removeNullValues from "../Helpers/removeNullValues.ts"; +import { z } from "zod"; import { generateResourceID } from "../../Shared/ResourceID.ts"; -import { zTags } from "../Tag/Tag.types.ts"; -import { zToken, type TGenericID, zName, zObjectID, zQuery, zActiveAutoGen, zTagsAutoGen } from "../Common/Common.types.ts"; +import { + type TGenericID, + zActiveAutoGen, + zName, + zObjectID, + zQuery, + zTagsAutoGen, + zToken, +} from "../Common/Common.types.ts"; import createQueryOrderBy from "../Helpers/createQueryOrderBy.ts"; +import preprocessBoolean from "../Helpers/preprocessBoolean.ts"; import preprocessNumber from "../Helpers/preprocessNumber.ts"; +import preprocessObject from "../Helpers/preprocessObject.ts"; +import removeNullValues from "../Helpers/removeNullValues.ts"; +import { zTags } from "../Tag/Tag.types.ts"; /** */ @@ -31,14 +39,19 @@ export const zDeviceParameterList = z.array(zDeviceParameter); /** * Configuration to create a new device param. */ -export const zDeviceParameterCreate = zDeviceParameter.omit({ id: true }).transform((x) => ({ - ...x, - id: generateResourceID(), -})); +export const zDeviceParameterCreate = zDeviceParameter + .omit({ id: true }) + .transform((x) => ({ + ...x, + id: generateResourceID(), + })); export const zDeviceChunkPeriod = z.enum(["day", "week", "month", "quarter"]); -export const zDeviceChunkRetention = z.preprocess(preprocessNumber, z.number().int().min(0).max(36)); +export const zDeviceChunkRetention = z.preprocess( + preprocessNumber, + z.number().int().min(0).max(36), +); /** * Base configuration of a device. @@ -89,7 +102,7 @@ export const zDeviceCreate = zDevice chunk_retention: x.type !== "immutable" ? undefined : x.chunk_retention, created_at: new Date(), id: generateResourceID(), - }) + }), ); /** @@ -115,7 +128,7 @@ export const zDeviceList = z.array( zDevice.partial().extend({ id: zObjectID, tags: zTags, - }) + }), ); /** @@ -212,7 +225,7 @@ export const zDeviceListQuery = zQuery.extend({ }) .partial() .nullish() - .transform((x) => x ?? {}) + .transform((x) => x ?? {}), ), fields: z .array(zDeviceListQueryField) @@ -237,10 +250,26 @@ export const zDeviceApplyDataRetentionQuery = z.object({ */ export const zDeviceTokenListQuery = zQuery.extend({ fields: z - .array(z.enum(["name", "permission", "serie_number", "last_authorization", "created_at", "expire_time"])) + .array( + z.enum([ + "name", + "permission", + "serie_number", + "last_authorization", + "created_at", + "expire_time", + ]), + ) .nullish() .transform((x) => { - const values: string[] = x || ["name", "permission", "token", "serie_number", "last_authorization", "created_at"]; + const values: string[] = x || [ + "name", + "permission", + "token", + "serie_number", + "last_authorization", + "created_at", + ]; if (!values.includes("expire_time")) values.push("expire_time"); return values; }), @@ -256,9 +285,13 @@ export type IDeviceParameterCreate = z.input; export type IDeviceParameterList = z.infer; export type IDeviceToken = z.infer; export type IDeviceTokenCreate = z.input; -export type IDeviceTokenCreateResponse = z.infer; +export type IDeviceTokenCreateResponse = z.infer< + typeof zDeviceTokenCreateResponse +>; export type IDeviceTokenList = z.input; export type IDeviceTokenListQuery = z.input; export type TDeviceType = z.input; -export type IDeviceApplyDataRetentionQuery = z.input; +export type IDeviceApplyDataRetentionQuery = z.input< + typeof zDeviceApplyDataRetentionQuery +>; export type IDeviceChunkPeriod = z.input; diff --git a/packages/sdk/src/Types/DeviceData/DeviceData.types.test.ts b/packages/sdk/src/Types/DeviceData/DeviceData.types.test.ts index 2fb6ba24..e932afb2 100644 --- a/packages/sdk/src/Types/DeviceData/DeviceData.types.test.ts +++ b/packages/sdk/src/Types/DeviceData/DeviceData.types.test.ts @@ -1,3 +1,4 @@ +import { describe, expect, test } from "vitest"; import { type IDeviceDataCreate, type IDeviceDataCreateLocation, @@ -6,8 +7,11 @@ import { validateResourceID, zDeviceDataQuery, } from "../index.ts"; -import { type IDeviceData, zDeviceData, zDeviceDataCreate } from "./DeviceData.types.ts"; -import { test, expect, describe } from "vitest"; +import { + type IDeviceData, + zDeviceData, + zDeviceDataCreate, +} from "./DeviceData.types.ts"; describe("zDeviceData", () => { const data: IDeviceData = { @@ -57,7 +61,10 @@ describe("zDeviceDataCreate", () => { }); test("uses time from object if it was informed", () => { - const data: IDeviceDataCreate = { time: new Date("2020-01-01T15:00:00Z"), variable: "temperature" }; + const data: IDeviceDataCreate = { + time: new Date("2020-01-01T15:00:00Z"), + variable: "temperature", + }; const parsed = zDeviceDataCreate.parse(data); expect(parsed.time).toEqual(new Date("2020-01-01T15:00:00Z")); }); @@ -67,13 +74,19 @@ describe("zDeviceDataCreate", () => { zDeviceDataCreate.parse({ time: "2021", variable: "temperature" }); zDeviceDataCreate.parse({ time: "2021/01", variable: "temperature" }); zDeviceDataCreate.parse({ time: "2021/01/20", variable: "temperature" }); - zDeviceDataCreate.parse({ time: "2021T15:00:00Z", variable: "temperature" }); + zDeviceDataCreate.parse({ + time: "2021T15:00:00Z", + variable: "temperature", + }); }; expect(fn).not.toThrow(); }); test("throws error if time is invalid", () => { - const data: IDeviceDataCreate = { time: new Date("2020-01-01ABC15:00:00Z"), variable: "temperature" }; + const data: IDeviceDataCreate = { + time: new Date("2020-01-01ABC15:00:00Z"), + variable: "temperature", + }; const fn = () => zDeviceDataCreate.parse(data); expect(fn).toThrow(); }); @@ -86,7 +99,10 @@ describe("zDeviceDataCreate", () => { }); test("parses location with coordinates", () => { - const location: IDeviceDataCreateLocation = { type: "Point", coordinates: [20, 10] }; + const location: IDeviceDataCreateLocation = { + type: "Point", + coordinates: [20, 10], + }; const data: IDeviceDataCreate = { variable: "location", location }; const parsed = zDeviceDataCreate.parse(data); expect(parsed.location).toEqual(location); @@ -213,7 +229,9 @@ describe("zDeviceDataQuery", () => { }); test("throws error if start_date has invalid dates", () => { - expect(() => zDeviceDataQuery.parse({ start_date: new Date("abc") })).toThrowError(); + expect(() => + zDeviceDataQuery.parse({ start_date: new Date("abc") }), + ).toThrowError(); expect(() => zDeviceDataQuery.parse({ start_date: true })).toThrowError(); expect(() => zDeviceDataQuery.parse({ start_date: false })).toThrowError(); expect(() => zDeviceDataQuery.parse({ start_date: {} })).toThrowError(); @@ -227,9 +245,14 @@ describe("zDeviceDataQuery", () => { }); test("parses ids as filled array", () => { - const data: IDeviceDataQuery = { ids: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"] }; + const data: IDeviceDataQuery = { + ids: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"], + }; const parsed = zDeviceDataQuery.parse(data); - expect(parsed.ids).toEqual(["61b2517991639c00197811e2", "11b2517991639c00197811e2"]); + expect(parsed.ids).toEqual([ + "61b2517991639c00197811e2", + "11b2517991639c00197811e2", + ]); }); test("parses ids as null", () => { @@ -259,7 +282,10 @@ describe("zDeviceDataQuery", () => { }); test("prefers ids property over id property", () => { - const data = { ids: ["61b251e291639c0019781ec2"], id: "11b2517991639c00197811e2" }; + const data = { + ids: ["61b251e291639c0019781ec2"], + id: "11b2517991639c00197811e2", + }; const parsed = zDeviceDataQuery.parse(data); expect(parsed.ids).toEqual(["61b251e291639c0019781ec2"]); expect(parsed).not.toHaveProperty("id"); @@ -279,9 +305,14 @@ describe("zDeviceDataQuery", () => { }); test("parses values as filled array", () => { - const data: IDeviceDataQuery = { values: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"] }; + const data: IDeviceDataQuery = { + values: ["61b2517991639c00197811e2", "11b2517991639c00197811e2"], + }; const parsed = zDeviceDataQuery.parse(data); - expect(parsed.values).toEqual(["61b2517991639c00197811e2", "11b2517991639c00197811e2"]); + expect(parsed.values).toEqual([ + "61b2517991639c00197811e2", + "11b2517991639c00197811e2", + ]); }); test("parses values as null", () => { @@ -323,7 +354,10 @@ describe("zDeviceDataQuery", () => { }); test("prefers values property over value property", () => { - const data = { values: ["61b251e291639c0019781ec2"], value: "11b2517991639c00197811e2" }; + const data = { + values: ["61b251e291639c0019781ec2"], + value: "11b2517991639c00197811e2", + }; const parsed = zDeviceDataQuery.parse(data); expect(parsed.values).toEqual(["61b251e291639c0019781ec2"]); expect(parsed).not.toHaveProperty("value"); @@ -536,7 +570,9 @@ describe("zDeviceDataQuery", () => { }); test("throws error if ordination is not a valid value", () => { - expect(() => zDeviceDataQuery.parse({ ordination: "hello" })).toThrowError(); + expect(() => + zDeviceDataQuery.parse({ ordination: "hello" }), + ).toThrowError(); expect(() => zDeviceDataQuery.parse({ ordination: true })).toThrowError(); expect(() => zDeviceDataQuery.parse({ ordination: false })).toThrowError(); expect(() => zDeviceDataQuery.parse({ ordination: {} })).toThrowError(); diff --git a/packages/sdk/src/Types/DeviceData/DeviceData.types.ts b/packages/sdk/src/Types/DeviceData/DeviceData.types.ts index 2c8cfa06..02c13f84 100644 --- a/packages/sdk/src/Types/DeviceData/DeviceData.types.ts +++ b/packages/sdk/src/Types/DeviceData/DeviceData.types.ts @@ -1,8 +1,11 @@ -import { z } from "zod"; import { DateTime } from "luxon"; +import { z } from "zod"; import { generateResourceID } from "../../Shared/ResourceID.ts"; import { zObjectID } from "../Common/Common.types.ts"; -import { parseRelativeDate, convertDateToISO } from "../Helpers/parseRelativeDate.ts"; +import { + convertDateToISO, + parseRelativeDate, +} from "../Helpers/parseRelativeDate.ts"; import removeNullValues from "../Helpers/removeNullValues.ts"; /** @@ -16,7 +19,11 @@ function isDate(date: any) { * Handles absolute/relative dates. * @returns {Date} a date object. */ -function handleDates(rawDate: Date | string, timezone: string, type: "start" | "end"): Date { +function handleDates( + rawDate: Date | string, + timezone: string, + type: "start" | "end", +): Date { let date: any = new Date(rawDate); if (!isDate(date)) { @@ -58,7 +65,10 @@ const zDeviceDataLocationCoordinates = z.object({ .string() .nullish() .transform((x) => x || "Point"), - coordinates: z.tuple([z.number().min(-180).max(180), z.number().min(-90).max(90)]), + coordinates: z.tuple([ + z.number().min(-180).max(180), + z.number().min(-90).max(90), + ]), }); /** @@ -95,10 +105,11 @@ const zDeviceDataCreateLocation = zDeviceDataLocationCoordinates .transform((x: any): IDeviceDataLocationCoordinates | undefined => { if (!x) { return undefined; - }if (Array.isArray(x.coordinates)) { + } + if (Array.isArray(x.coordinates)) { return x; } - return { type: "Point", coordinates: [x.lng, x.lat] }; + return { type: "Point", coordinates: [x.lng, x.lat] }; }); /** @@ -108,7 +119,10 @@ export const zDeviceDataCreate = zDeviceData .omit({ created_at: true, id: true, device: true }) .extend({ location: zDeviceDataCreateLocation, - time: z.preprocess((x) => (x ? new Date(x as string) : undefined), z.date().nullish()), + time: z.preprocess( + (x) => (x ? new Date(x as string) : undefined), + z.date().nullish(), + ), }) .transform((data) => { const now = new Date(); @@ -123,10 +137,15 @@ export const zDeviceDataCreate = zDeviceData /** * Configuration to update a device data. */ -export const zDeviceDataUpdate = zDeviceData.omit({ created_at: true, variable: true, device: true }).extend({ - location: zDeviceDataCreateLocation, - time: z.preprocess((x) => (x ? new Date(x as string) : undefined), z.date().nullish()), -}); +export const zDeviceDataUpdate = zDeviceData + .omit({ created_at: true, variable: true, device: true }) + .extend({ + location: zDeviceDataCreateLocation, + time: z.preprocess( + (x) => (x ? new Date(x as string) : undefined), + z.date().nullish(), + ), + }); /** * Configuration to query the device data list. @@ -205,7 +224,11 @@ export const zDeviceDataQuery = z.preprocess( .transform((x) => x || "defaultQ"), groups: z.array(z.string()).nullish(), start_date: z.date().nullish(), - values: z.array(z.string()).or(z.array(z.boolean())).or(z.array(z.number())).nullish(), + values: z + .array(z.string()) + .or(z.array(z.boolean())) + .or(z.array(z.number())) + .nullish(), variables: z.array(z.string()).nullish(), skip: z .number() @@ -222,7 +245,7 @@ export const zDeviceDataQuery = z.preprocess( .enum(["ASC", "DESC", "asc", "desc"]) .nullish() .transform((x) => String(x || "DESC").toLowerCase()), - }) + }), ); const zDeviceAddDataOptions = z.object({ @@ -233,8 +256,14 @@ const zDeviceAddDataOptions = z.object({ export type IDeviceAddDataOptions = z.infer; export type IDeviceData = z.infer; export type IDeviceDataCreate = z.input; -export type IDeviceDataCreateLocation = z.input; -export type IDeviceDataLocationCoordinates = z.input; -export type IDeviceDataLocationLatLng = z.input; +export type IDeviceDataCreateLocation = z.input< + typeof zDeviceDataCreateLocation +>; +export type IDeviceDataLocationCoordinates = z.input< + typeof zDeviceDataLocationCoordinates +>; +export type IDeviceDataLocationLatLng = z.input< + typeof zDeviceDataLocationLatLng +>; export type IDeviceDataQuery = z.input; export type IDeviceDataUpdate = z.input; diff --git a/packages/sdk/src/Types/Hardware/Hardware.types.test.ts b/packages/sdk/src/Types/Hardware/Hardware.types.test.ts index ddf5a5d5..ce5dea11 100644 --- a/packages/sdk/src/Types/Hardware/Hardware.types.test.ts +++ b/packages/sdk/src/Types/Hardware/Hardware.types.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; -import { zOSInfo, zNetworkInfo, zComputerUsage } from "./Hardware.types.ts"; -import { test, expect, describe } from "vitest"; +import { zComputerUsage, zNetworkInfo, zOSInfo } from "./Hardware.types.ts"; describe("zOSInfo", () => { test("parses simple object", () => { @@ -41,7 +41,9 @@ describe("zOSInfo", () => { zOSInfo.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.code[0].startsWith("Invalid enum value.")).toBeTruthy(); + expect( + e.fieldErrors.code[0].startsWith("Invalid enum value."), + ).toBeTruthy(); } }); }); diff --git a/packages/sdk/src/Types/Helpers/createQueryOrderBy.ts b/packages/sdk/src/Types/Helpers/createQueryOrderBy.ts index 927b1156..1c382a52 100644 --- a/packages/sdk/src/Types/Helpers/createQueryOrderBy.ts +++ b/packages/sdk/src/Types/Helpers/createQueryOrderBy.ts @@ -14,7 +14,7 @@ function createQueryOrderBy(value: T) { z .string() .transform((x) => x.split(",")) - .refine((x) => x[0] && (x[1] === "asc" || x[1] === "desc"), errorMsg) + .refine((x) => x[0] && (x[1] === "asc" || x[1] === "desc"), errorMsg), ) .nullish() .transform((x) => x ?? ["name", "asc"]); diff --git a/packages/sdk/src/Types/Helpers/parseRelativeDate.test.ts b/packages/sdk/src/Types/Helpers/parseRelativeDate.test.ts index 1f879177..2241b856 100644 --- a/packages/sdk/src/Types/Helpers/parseRelativeDate.test.ts +++ b/packages/sdk/src/Types/Helpers/parseRelativeDate.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import { convertDateToISO, parseRelativeDate } from "./parseRelativeDate.ts"; -import { test, expect, describe } from "vitest"; describe("convertDateToISO", () => { test("convert simple date", () => { diff --git a/packages/sdk/src/Types/Helpers/parseRelativeDate.ts b/packages/sdk/src/Types/Helpers/parseRelativeDate.ts index 4a0bb6b0..206bc0f7 100644 --- a/packages/sdk/src/Types/Helpers/parseRelativeDate.ts +++ b/packages/sdk/src/Types/Helpers/parseRelativeDate.ts @@ -5,9 +5,16 @@ import { DateTime } from "luxon"; export function convertDateToISO(date: Date | string, timezone?: string) { const rawDate = DateTime.fromJSDate(new Date(date)); if (timezone) { - return rawDate.setZone(timezone, { keepLocalTime: true }).toISO() || rawDate.toISO() || DateTime.utc().toISO(); + return ( + rawDate.setZone(timezone, { keepLocalTime: true }).toISO() || + rawDate.toISO() || + DateTime.utc().toISO() + ); } - return rawDate.setZone("UTC", { keepLocalTime: true }).toISO() || DateTime.utc().toISO(); + return ( + rawDate.setZone("UTC", { keepLocalTime: true }).toISO() || + DateTime.utc().toISO() + ); } /** @@ -59,9 +66,13 @@ export function parseRelativeDate(expire_time, bool_minus, date = new Date()) { let time: DateTime; if (bool_minus) { - time = DateTime.fromJSDate(new Date(date)).minus({ [fixDuration(split[2])]: Number(split[1]) }); + time = DateTime.fromJSDate(new Date(date)).minus({ + [fixDuration(split[2])]: Number(split[1]), + }); } else { - time = DateTime.fromJSDate(new Date(date)).plus({ [fixDuration(split[2])]: Number(split[1]) }); + time = DateTime.fromJSDate(new Date(date)).plus({ + [fixDuration(split[2])]: Number(split[1]), + }); } if (!time.isValid) { diff --git a/packages/sdk/src/Types/Helpers/parseSafe.test.ts b/packages/sdk/src/Types/Helpers/parseSafe.test.ts index 3573e108..c264ef08 100644 --- a/packages/sdk/src/Types/Helpers/parseSafe.test.ts +++ b/packages/sdk/src/Types/Helpers/parseSafe.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import { parseSafe } from "./parseSafe.ts"; -import { test, expect, describe } from "vitest"; describe("parseSafe", () => { test("assure correct parsing", () => { diff --git a/packages/sdk/src/Types/Helpers/preprocessBoolean.test.ts b/packages/sdk/src/Types/Helpers/preprocessBoolean.test.ts index 971076ae..e8852c0f 100644 --- a/packages/sdk/src/Types/Helpers/preprocessBoolean.test.ts +++ b/packages/sdk/src/Types/Helpers/preprocessBoolean.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import preprocessBoolean from "./preprocessBoolean.ts"; -import { test, expect, describe } from "vitest"; describe("preprocessBoolean", () => { test("process standard boolean", () => { diff --git a/packages/sdk/src/Types/Helpers/preprocessNumber.test.ts b/packages/sdk/src/Types/Helpers/preprocessNumber.test.ts index 558009e0..8b5db830 100644 --- a/packages/sdk/src/Types/Helpers/preprocessNumber.test.ts +++ b/packages/sdk/src/Types/Helpers/preprocessNumber.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import preprocessNumber from "./preprocessNumber.ts"; -import { test, expect, describe } from "vitest"; describe("preprocessNumber", () => { test("process string param", () => { diff --git a/packages/sdk/src/Types/Helpers/preprocessObject.test.ts b/packages/sdk/src/Types/Helpers/preprocessObject.test.ts index dcee394b..2fc91090 100644 --- a/packages/sdk/src/Types/Helpers/preprocessObject.test.ts +++ b/packages/sdk/src/Types/Helpers/preprocessObject.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import preprocessObject from "./preprocessObject.ts"; -import { test, expect, describe } from "vitest"; describe("preprocessObject", () => { test("process simple object", () => { diff --git a/packages/sdk/src/Types/Helpers/preprocessObject.ts b/packages/sdk/src/Types/Helpers/preprocessObject.ts index b00f95e9..0a0c4d10 100644 --- a/packages/sdk/src/Types/Helpers/preprocessObject.ts +++ b/packages/sdk/src/Types/Helpers/preprocessObject.ts @@ -7,11 +7,11 @@ function preprocessObject(value: unknown): any { if (typeof value === "object") { return value; } - try { - return JSON.parse(value as string); - } catch (ex) { - return null; - } + try { + return JSON.parse(value as string); + } catch (ex) { + return null; + } } export default preprocessObject; diff --git a/packages/sdk/src/Types/Helpers/refineOrderBy.test.ts b/packages/sdk/src/Types/Helpers/refineOrderBy.test.ts index 03f90959..4f642997 100644 --- a/packages/sdk/src/Types/Helpers/refineOrderBy.test.ts +++ b/packages/sdk/src/Types/Helpers/refineOrderBy.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import { refineOrderBy } from "./refineOrderBy.ts"; -import { test, expect, describe } from "vitest"; describe("refineOrderBy", () => { test("assure correct validation", () => { diff --git a/packages/sdk/src/Types/Helpers/removeNullValues.test.ts b/packages/sdk/src/Types/Helpers/removeNullValues.test.ts index cf1d3f10..fc48cd83 100644 --- a/packages/sdk/src/Types/Helpers/removeNullValues.test.ts +++ b/packages/sdk/src/Types/Helpers/removeNullValues.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import removeNullValues from "./removeNullValues.ts"; -import { test, expect, describe } from "vitest"; describe("removeNullValues", () => { test("process simple object", () => { diff --git a/packages/sdk/src/Types/LiveInspector/LiveInspector.types.test.ts b/packages/sdk/src/Types/LiveInspector/LiveInspector.types.test.ts index 3ac49062..e9dfa2b4 100644 --- a/packages/sdk/src/Types/LiveInspector/LiveInspector.types.test.ts +++ b/packages/sdk/src/Types/LiveInspector/LiveInspector.types.test.ts @@ -1,6 +1,10 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; -import { zLiveInspectorConnectionID, zLiveInspectorMessage, zLiveInspectorMessageCreate } from "./LiveInspector.types.ts"; -import { test, expect, describe } from "vitest"; +import { + zLiveInspectorConnectionID, + zLiveInspectorMessage, + zLiveInspectorMessageCreate, +} from "./LiveInspector.types.ts"; describe("zLiveInspectorConnectionID", () => { test("parses string", () => { @@ -45,7 +49,9 @@ describe("zLiveInspectorMessage", () => { zLiveInspectorMessage.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.device_id[0]).toBe("Expected string, received number"); + expect(e.fieldErrors.device_id[0]).toBe( + "Expected string, received number", + ); } }); diff --git a/packages/sdk/src/Types/LiveInspector/LiveInspector.types.ts b/packages/sdk/src/Types/LiveInspector/LiveInspector.types.ts index 177ba480..43c67c04 100644 --- a/packages/sdk/src/Types/LiveInspector/LiveInspector.types.ts +++ b/packages/sdk/src/Types/LiveInspector/LiveInspector.types.ts @@ -25,6 +25,10 @@ export const zLiveInspectorMessageCreate = z.object({ title: z.string(), }); -export type ILiveInspectorMessageCreate = z.infer; +export type ILiveInspectorMessageCreate = z.infer< + typeof zLiveInspectorMessageCreate +>; export type ILiveInspectorMessage = z.infer; -export type TLiveInspectorConnectionID = z.infer; +export type TLiveInspectorConnectionID = z.infer< + typeof zLiveInspectorConnectionID +>; diff --git a/packages/sdk/src/Types/Log/Log.types.test.ts b/packages/sdk/src/Types/Log/Log.types.test.ts index d301fc52..aff7a806 100644 --- a/packages/sdk/src/Types/Log/Log.types.test.ts +++ b/packages/sdk/src/Types/Log/Log.types.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; import { zLogCreate, zLogList } from "./Log.types.ts"; -import { test, expect, describe } from "vitest"; describe("zLogCreate", () => { test("parses simple object", () => { diff --git a/packages/sdk/src/Types/Plugin/Plugin.types.test.ts b/packages/sdk/src/Types/Plugin/Plugin.types.test.ts index a0d0e555..1f3a4548 100644 --- a/packages/sdk/src/Types/Plugin/Plugin.types.test.ts +++ b/packages/sdk/src/Types/Plugin/Plugin.types.test.ts @@ -1,22 +1,22 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; import { - zPluginModuleIDCombo, - zPluginType, - zPluginPublisher, + zModuleMessageOptions, + zPlugin, + zPluginConfigField, zPluginInstallOptions, - zPluginPermission, - zPluginManifestCliOption, zPluginManifestCliCommand, - zPluginPackageTCore, - zPluginConfigField, - zPluginStorageItemSet, + zPluginManifestCliOption, zPluginModule, - zPlugin, - zModuleMessageOptions, - zPluginModuleListItem, + zPluginModuleIDCombo, zPluginModuleList, + zPluginModuleListItem, + zPluginPackageTCore, + zPluginPermission, + zPluginPublisher, + zPluginStorageItemSet, + zPluginType, } from "./Plugin.types.ts"; -import { test, expect, describe } from "vitest"; describe("zPluginModuleIDCombo", () => { test("valid id", () => { @@ -101,7 +101,9 @@ describe("zPluginManifestCliCommand", () => { zPluginManifestCliCommand.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors).toStrictEqual({ arguments: ["Expected string, received number"] }); + expect(e.fieldErrors).toStrictEqual({ + arguments: ["Expected string, received number"], + }); } }); }); @@ -194,7 +196,9 @@ describe("zPluginModuleListItem", () => { zPluginModuleListItem.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors).toStrictEqual({ setup: ["Required", "Required", "Required"] }); + expect(e.fieldErrors).toStrictEqual({ + setup: ["Required", "Required", "Required"], + }); } }); }); @@ -207,7 +211,9 @@ describe("zPluginModuleList", () => { } catch (error) { const e = (error as ZodError).flatten(); console.log(e); - expect(e.formErrors).toStrictEqual({ setup: ["Required", "Required", "Required"] }); + expect(e.formErrors).toStrictEqual({ + setup: ["Required", "Required", "Required"], + }); } }); }); diff --git a/packages/sdk/src/Types/Plugin/Plugin.types.ts b/packages/sdk/src/Types/Plugin/Plugin.types.ts index b3ab0081..236a3790 100644 --- a/packages/sdk/src/Types/Plugin/Plugin.types.ts +++ b/packages/sdk/src/Types/Plugin/Plugin.types.ts @@ -34,7 +34,8 @@ export const zPluginType = z.enum([ "service", "sidebar-button", "sidebar-footer-button", - "sqlite" + "system-override", + "sqlite", ]); /** @@ -57,7 +58,14 @@ export const zPluginInstallOptions = z.object({ /** * Types of permissions available. */ -export const zPluginPermission = z.enum(["device", "analysis", "action", "device-data", "cli"]); +export const zPluginPermission = z.enum([ + "device", + "analysis", + "action", + "device-data", + "cli", + "plugin", +]); /** */ @@ -190,10 +198,12 @@ const zPluginConfigFieldPassword = zGenericConfigField.extend({ /** * The configuration for a "boolean" field. */ -const zPluginConfigFieldBoolean = zGenericConfigField.omit({ placeholder: true, required: true }).extend({ - type: z.literal("boolean"), - defaultValue: z.boolean().nullish(), -}); +const zPluginConfigFieldBoolean = zGenericConfigField + .omit({ placeholder: true, required: true }) + .extend({ + type: z.literal("boolean"), + defaultValue: z.boolean().nullish(), + }); /** * The configuration for a "divisor" field. @@ -273,14 +283,28 @@ export type IShallowGroupField = { icon?: string | null; name?: string | null; field: string; - configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; - visibility_conditions?: z.infer[] | null; + configs: ( + | INonRecursiveFields + | IShallowGroupField + | IShallowRowField + | IShallowRadioField + )[]; + visibility_conditions?: + | z.infer[] + | null; }; export type IShallowRowField = { type: "row"; - configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; - visibility_conditions?: z.infer[] | null; + configs: ( + | INonRecursiveFields + | IShallowGroupField + | IShallowRowField + | IShallowRadioField + )[]; + visibility_conditions?: + | z.infer[] + | null; }; export type IShallowRadioField = { @@ -293,9 +317,16 @@ export type IShallowRadioField = { color?: string | null; icon?: string | null; description?: string | null; - configs: (INonRecursiveFields | IShallowGroupField | IShallowRowField | IShallowRadioField)[]; + configs: ( + | INonRecursiveFields + | IShallowGroupField + | IShallowRowField + | IShallowRadioField + )[]; }>; - visibility_conditions?: z.infer[] | null; + visibility_conditions?: + | z.infer[] + | null; }; /** @@ -305,9 +336,12 @@ const zPluginConfigFieldRow: z.ZodType = z.lazy(() => zGenericConfigField.extend({ type: z.literal("row"), configs: z.array( - zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + zNonRecursiveFields + .or(zPluginConfigFieldRow) + .or(zPluginConfigFieldGroup) + .or(zPluginConfigFieldRadio), ), - }) + }), ); /** @@ -317,9 +351,12 @@ const zPluginConfigFieldGroup: z.ZodType = z.lazy(() => zGenericConfigField.extend({ type: z.literal("group"), configs: z.array( - zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + zNonRecursiveFields + .or(zPluginConfigFieldRow) + .or(zPluginConfigFieldGroup) + .or(zPluginConfigFieldRadio), ), - }) + }), ); /** @@ -337,11 +374,14 @@ const zPluginConfigFieldRadio: z.ZodType = z.lazy(() => icon: zIcon.nullish(), description: z.string().nullish(), configs: z.array( - zNonRecursiveFields.or(zPluginConfigFieldRow).or(zPluginConfigFieldGroup).or(zPluginConfigFieldRadio) + zNonRecursiveFields + .or(zPluginConfigFieldRow) + .or(zPluginConfigFieldGroup) + .or(zPluginConfigFieldRadio), ), - }) + }), ), - }) + }), ); /** @@ -372,7 +412,9 @@ const zPluginMessage = z.object({ method: z.string(), params: z.any(), setupID: z.string().optional(), - type: z.enum(["pluginRequest", "pluginResponse", "apiRequest", "apiResponse"]).optional(), + type: z + .enum(["pluginRequest", "pluginResponse", "apiRequest", "apiResponse"]) + .optional(), }); /** @@ -421,32 +463,47 @@ const zPluginStorageItem = z.object({ /** * Configuration to set a plugin storage item. */ -export const zPluginStorageItemSet = zPluginStorageItem.omit({ created_at: true, type: true }).transform((x) => { - let type = "string"; - if (x.value === null) { - type = "null"; - } else if (typeof x.value === "boolean") { - type = "boolean"; - } else if (typeof x.value === "string") { - type = "string"; - } else if (typeof x.value === "number") { - type = "number"; - } else if (typeof x.value === "object") { - type = "object"; - } - return { - ...x, - type, - }; -}); - -/** - */ -export const zModuleState = z.enum(["idle", "stopping", "starting", "started", "stopped"]); +export const zPluginStorageItemSet = zPluginStorageItem + .omit({ created_at: true, type: true }) + .transform((x) => { + let type = "string"; + if (x.value === null) { + type = "null"; + } else if (typeof x.value === "boolean") { + type = "boolean"; + } else if (typeof x.value === "string") { + type = "string"; + } else if (typeof x.value === "number") { + type = "number"; + } else if (typeof x.value === "object") { + type = "object"; + } + return { + ...x, + type, + }; + }); + +/** + */ +export const zModuleState = z.enum([ + "idle", + "stopping", + "starting", + "started", + "stopped", +]); /** */ -export const zPluginState = z.enum(["idle", "disabled", "stopping", "starting", "started", "stopped"]); +export const zPluginState = z.enum([ + "idle", + "disabled", + "stopping", + "starting", + "started", + "stopped", +]); /** */ @@ -520,7 +577,9 @@ const zPluginButtonModuleSetupOption = z.object({ const zPluginListItem = z.object({ publisher: zPluginPublisher.nullish(), buttons: z.object({ - sidebar: z.array(zPluginButtonModuleSetupOption.extend({ position: z.number() })), + sidebar: z.array( + zPluginButtonModuleSetupOption.extend({ position: z.number() }), + ), navbar: z.array(zPluginButtonModuleSetupOption), sidebarFooter: z.array(zPluginButtonModuleSetupOption), }), @@ -583,28 +642,42 @@ interface IPluginFilesystemItem { } export type { IPluginFilesystemItem }; -export type IActionTriggerModuleSetup = z.infer; +export type IActionTriggerModuleSetup = z.infer< + typeof zActionTriggerModuleSetup +>; export type IActionTypeModuleSetup = z.infer; export type IModuleMessageOptions = z.infer; export type IModuleSetup = z.infer; export type IModuleSetupWithoutType = Omit; export type IPlugin = z.infer; -export type IPluginButtonModuleSetupAction = z.infer; -export type IPluginButtonModuleSetupOption = z.infer; +export type IPluginButtonModuleSetupAction = z.infer< + typeof zPluginButtonModuleSetupAction +>; +export type IPluginButtonModuleSetupOption = z.infer< + typeof zPluginButtonModuleSetupOption +>; export type IPluginClassListItem = z.infer; export type IPluginConfigField = z.infer; -export type IPluginConfigFieldBoolean = z.infer; -export type IPluginConfigFieldDivisor = z.infer; +export type IPluginConfigFieldBoolean = z.infer< + typeof zPluginConfigFieldBoolean +>; +export type IPluginConfigFieldDivisor = z.infer< + typeof zPluginConfigFieldDivisor +>; export type IPluginConfigFieldFile = z.infer; export type IPluginConfigFieldFolder = z.infer; export type IPluginConfigFieldGroup = z.infer; export type IPluginConfigFieldNumber = z.infer; export type IPluginConfigFieldOption = z.infer; -export type IPluginConfigFieldPassword = z.infer; +export type IPluginConfigFieldPassword = z.infer< + typeof zPluginConfigFieldPassword +>; export type IPluginConfigFieldRadio = z.infer; export type IPluginConfigFieldRow = z.infer; export type IPluginConfigFieldString = z.infer; -export type IPluginConfigFieldStringList = z.infer; +export type IPluginConfigFieldStringList = z.infer< + typeof zPluginConfigFieldStringList +>; export type IPluginInstallOptions = z.infer; export type IPluginList = z.infer; export type IPluginListItem = z.infer; @@ -613,7 +686,7 @@ export type IPluginMessage = z.infer; export type IPluginModule = z.infer; export type IPluginModuleList = z.infer; export type IPluginModuleListItem = z.infer; -export type IPluginPayloadEncoderList = {}; +export type IPluginPayloadEncoderList = any; export type IPluginPublisher = z.infer; export type IPluginSettings = z.infer; export type IPluginSettingsModule = z.infer; diff --git a/packages/sdk/src/Types/Resource/ResourceID.test.ts b/packages/sdk/src/Types/Resource/ResourceID.test.ts index 1aa18413..c525cedd 100644 --- a/packages/sdk/src/Types/Resource/ResourceID.test.ts +++ b/packages/sdk/src/Types/Resource/ResourceID.test.ts @@ -1,5 +1,5 @@ +import { describe, expect, test } from "vitest"; import { generateResourceID, validateResourceID } from "./ResourceID.ts"; -import { test, expect, describe } from "vitest"; describe("Test generateResourceID", () => { test("Generate resource id", () => { diff --git a/packages/sdk/src/Types/Resource/ResourceID.ts b/packages/sdk/src/Types/Resource/ResourceID.ts index a7dcda8e..4cfec35a 100644 --- a/packages/sdk/src/Types/Resource/ResourceID.ts +++ b/packages/sdk/src/Types/Resource/ResourceID.ts @@ -9,7 +9,9 @@ const nanoid = customAlphabet(hexAlphabet, 20); */ export function generateResourceID(): string { const firstCase = String(Date.now()).slice(0, 2).split("").reverse().join(""); - const secondCase = Buffer.from([Number(String(Date.now()).slice(2, 4))]).toString("hex"); + const secondCase = Buffer.from([ + Number(String(Date.now()).slice(2, 4)), + ]).toString("hex"); return `${firstCase}${secondCase}${nanoid()}`; } diff --git a/packages/sdk/src/Types/Settings/Settings.types.test.ts b/packages/sdk/src/Types/Settings/Settings.types.test.ts index ebc65a4a..fdb9af78 100644 --- a/packages/sdk/src/Types/Settings/Settings.types.test.ts +++ b/packages/sdk/src/Types/Settings/Settings.types.test.ts @@ -1,6 +1,10 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; -import { zSettings, zSettingsEdit, zSettingsMetadata } from "./Settings.types.ts"; -import { test, expect, describe } from "vitest"; +import { + zSettings, + zSettingsEdit, + zSettingsMetadata, +} from "./Settings.types.ts"; describe("zSettings", () => { test("parses simple object", () => { @@ -65,7 +69,9 @@ describe("zSettingsMetadata", () => { zSettingsMetadata.parse(data); } catch (error) { const e = (error as ZodError).flatten(); - expect(e.fieldErrors.port_disabled[0]).toBe("Expected boolean, received number"); + expect(e.fieldErrors.port_disabled[0]).toBe( + "Expected boolean, received number", + ); } }); }); diff --git a/packages/sdk/src/Types/Statistic/Statistic.types.test.ts b/packages/sdk/src/Types/Statistic/Statistic.types.test.ts index a561cd7e..acf8854d 100644 --- a/packages/sdk/src/Types/Statistic/Statistic.types.test.ts +++ b/packages/sdk/src/Types/Statistic/Statistic.types.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; import { zStatistic, zStatisticCreate } from "./Statistic.types.ts"; -import { test, expect, describe } from "vitest"; describe("zStatistic", () => { test("parses simple object", () => { diff --git a/packages/sdk/src/Types/Summary/Summary.types.test.ts b/packages/sdk/src/Types/Summary/Summary.types.test.ts index ea0b2c00..a4e68f7c 100644 --- a/packages/sdk/src/Types/Summary/Summary.types.test.ts +++ b/packages/sdk/src/Types/Summary/Summary.types.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; import { zSummary } from "./Summary.types.ts"; -import { describe, test, expect } from "vitest"; describe("zSummary", () => { test("parses simple object", () => { diff --git a/packages/sdk/src/Types/Tag/Tag.types.test.ts b/packages/sdk/src/Types/Tag/Tag.types.test.ts index 55ec58ca..a7331d90 100644 --- a/packages/sdk/src/Types/Tag/Tag.types.test.ts +++ b/packages/sdk/src/Types/Tag/Tag.types.test.ts @@ -1,6 +1,6 @@ +import { describe, expect, test } from "vitest"; import type { ZodError } from "zod"; import { zTag, zTags } from "./Tag.types.ts"; -import { test, expect, describe } from "vitest"; describe("zTag", () => { test("parses simple object", () => { diff --git a/packages/sdk/src/__mocks__/fs.ts b/packages/sdk/src/__mocks__/fs.ts index 965e2a70..3c909d1d 100644 --- a/packages/sdk/src/__mocks__/fs.ts +++ b/packages/sdk/src/__mocks__/fs.ts @@ -1,3 +1,3 @@ import { fs } from "memfs"; -module.exports = fs; +export default fs; diff --git a/packages/sdk/src/__mocks__/fs/promises.ts b/packages/sdk/src/__mocks__/fs/promises.ts index 3f5afefc..407f315d 100644 --- a/packages/sdk/src/__mocks__/fs/promises.ts +++ b/packages/sdk/src/__mocks__/fs/promises.ts @@ -1,3 +1,3 @@ import { fs } from "memfs"; -module.exports = fs.promises; +export default fs.promises; diff --git a/packages/server/package.json b/packages/server/package.json index c80d15b3..f5c5f124 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -5,21 +5,16 @@ "dependencies": { "boxen": "5.1.2", "compression": "1.7.4", - "cors": "2.8.5", "cron-parser": "4.4.0", "dayjs": "1.11.13", "extract-zip": "2.0.1", "js-yaml": "4.1.0", - "md5": "2.3.0", "method-override": "3.0.0", - "multer": "1.4.5-lts.1", - "socket.io": "4.4.1" + "multer": "1.4.5-lts.1" }, "devDependencies": { "@types/compression": "1.7.5", - "@types/cors": "2.8.17", "@types/js-yaml": "4.0.9", - "@types/md5": "2.3.5", "@types/method-override": "0.0.35" } } diff --git a/plugins/tagoio-integration/README.md b/plugins/tagoio-integration/README.md new file mode 100644 index 00000000..2756755f --- /dev/null +++ b/plugins/tagoio-integration/README.md @@ -0,0 +1,11 @@ +![TCore](/assets/logo-plugin-black.png) + +# About + +This is a TagoIO Integration Plugin. It allows the application to connect to the TagoIO servers in order to send or receive data in realtime, as well as manage this application inside of TagoIO servers. + +--- + +# Settings + +*This Plugin has no settings.* diff --git a/plugins/tagoio-integration/assets/desert.png b/plugins/tagoio-integration/assets/desert.png new file mode 100644 index 0000000000000000000000000000000000000000..fa333569aeb35959f5af9352a5f2d0787810790d GIT binary patch literal 1208 zcmV;p1V{UcP)d z)6>(&#>Tq3y1~K0(b3VqzP`4$w!_22x3{+lQ$yDP001C#QchC3&wa@cj zhPKx4|M@m`^NMZAgUMDo`M>KqrSgN27|KGSP$(1%g+ifFC=?2XLZMJ76#D;VRSEDi zWqoW6yBeIc{uRMKM0}dDo>jrV74CGbSMeMUt#Q`_>rp&~KYie?K0SA2g9Z=XvVT!B z0st{)t-RR)(W7o0MM=vhV3#Nu<L#i#NR>vpu#1ealG{% z1`_8sno=xuJf&k_&2h>3Z(LLk(l)h)ZUlrINCqZ{Ly;7>aDp2_M{6|JO=zy|*y$>9 z5&h`N1{*ZhWrF5f*?xkii~MYulDBez%b~juLmf}g4!xUoJ?A1GMY~34IGP9+KJFV0 zE+bv_>Ck7bNlcFOXWKMLY3%P7a8lE;jjwcZkvAJiY_e14qJ7up19Jkh^2>2#Q%sgd zy8O#a^Z4a^23c_%H?e-NtbX8(bPLJxh4eb8af$2uMoYMnjtj}Celq#|w2k9-uV`!s zB{fu??t9nEv#g5a5uwQzK|eA%{W(n@2xrBzX}N64*hnE+R#l6u#@`OiA*ZftAg0^Ek-Fe(5y!7>W#q#D%7~tes}8rky|NOO7(h>!AZ9NtJQ6V+O0v2Q-4vp1V-nTHy+T7TxD51LUoa>s$u7w;j<#E_C(E_@Uzxkd@e(}X8om3k{-Po-!o^?`YPPkR zmIkx#)3aCveBjo0tL1}R+!%b|nyuw#e(C^sbF4P(r&d@iLdk(YZq9olo4C=5Ew87B za4W3?t_fEIwNw{y-==`00`A)sa8$s3o3PKgw?5;RZ`4xVmElebxPZIX0`6MtHSQNq W;kM@nVh^PN0000R zYA7*PYi<=0BnV1Ozxckp*8K;5-&yOdbI$WV@4NTA*1Mm*_xaP@)PRFkm=yp3jytz+ zS^~hi9oikp%t%A%bS|6G9zsZcTO`cS9U0;p=my+);CJ6m;*O82hnuCF>w~a>J~vGO z;Iq1O^M+OE)cWj=K>Kbi(aru_|Gk8=c$(!fq&o=@WLW1*sTc7>Rasps!A zJm=F?#0B%kR6uYwwjWgFLfs#&?Py$i#+Lqjq7V3v!5-O$;T#EEstw*fjflh^KB2kt zzq~eYS%IpyH&;hu%u~GeAyYDM>-+SRbyp%!PkCV)Pn(JZ{p*Rpko+*ww$n!5r|B_B zO*xnvt6M%JIJvf?c2Xsn-1*lf*Soh2 z&3domGhYp~ExOGs1-k4N<&JV}Uj% zLY+seH0!U1n}*V*NqjMIGq!JNVnNQGUoHsJejg3C&AQFC3Q34dl-YN`oRWXeH8<&z zkK=0=giEt}XVcyHqn_|zn@khy^Q|d%tpBIlfe45W-PR$+Vv!6WeEp1 z+_ey_4t_#IR3T_OQede)L>f;v$*@0SoLRlyXlt6!h5!l@p#sZ*?(tl$kB^f;@Y);c zLCoQV;R)|+ z#&L?i74*2g0#b%8rrp6cci8kgde8bs{&2MhZNDF_G;olQdrMp2W|{&G{gsl(7GA`SJUIOws2?c#)V)Q-+Efzp z9;kx)s|~SgIEcpQrnDCntyFx$aDzt3T@9Q=N{xd~*vU6P*#f;h{SaSCQCzF~kQHGx zh_E{_J^sS#bvgaxtB%jwXF^^$S_Al^HGF!8#|nT&f~jByyKh$q&+(6irOmm^;Md}i z0vB+dJX*-MCjES~D|xnWHJEH4D35}12e5~m_2QwT}dLCfVMlwyIfN(P5?42#ltJlaD$VyoWs61XLAZTpW z7JuUnKw191<&-4@20eB=WCTz)VFl}lnt925m?lxp(2s#HA5Jq)!+s%wL2Q#p=#eyN%zve~l zP5=H?8n)%?5_I$)t`fE6lG!MKL4XA@xaFTUFXZ2P`cvGG5k=B_N7f1B>#bOmDa!Q{ ztYDzBhpLEENd55UQSG^?qr&?$ItMlVYsb>gN$?r$OyYAz`}|4O_Nq`JHU##I?$-gw zW{;)#T)&f)9{ss4ZF3HI1GKtAuun`?Oyb=j?ww4k2qkI&r{78?s$OGIz8Vm*N7^o@t0|OLV6u1^A5@Y=$K5fN)CR23pq$;?x z?W|UD+TSkK>8BX($qs7CuS^wa+g&b$snUiXR&fr)OH~Ica>fHqQiIJVC8SI&%~d^E zXM_V%Q)#7PTPcX9Z5;)DB7fx%(WGmfm)P)LsD**bk<#5a=RNn+Sb|#Zq`p+gMZeKdHV_R3n2ioV&<7#aea` zO36AW0o&W+G>;rZNPy6c)kXXVC@U68uTB{H@L383E*62p*ULZ&#L>!70fHgWsNlQH zhq-lUF8eATBf|Omq078lLJMR-H=hl;;Qj;3;hEL98o=Mnf?Qzi=fjx74v~|^P^KzX zr>6z0!C9y#w~Xun9cw3=83L2!g)~?5Vemm=PFGZe zr7&TLb>;vWYQSTA^`pG)*xg=6H4*_Q#6V|1%Gma&g zU0We@rw&Q zc?sX#YdpB*E=|5@&P=ZkDJT}33Q#-tE{~kM=l0Eq=z#$Kf-*HAR#TA0dn#; zt!PAZvns-nKrv)!LJY$>o<;!c+gc@)ZvH{94oKk70T@mI1O~VXz+)&AK*N}k05qTO zAM78(f3bfE|8J9M3;k>9Y;l?^|62doJsS3}d;gtelGbT{p5Ka^GJdwF)Rl*CS=of4 z1J?Bh`CYYPJ3Hw~S^LfXZ}3uAm+yKZkG99=vkyi_v&aVdbYzYpO7I1pNy5RhnRPmP zStRRl^P3-0I!>}7QU?UK)m7~FvCi(VMf~ah#NtKr*}nZ;i4FtrmgBW zvMy4}o6PA*TMhiXUR|D1+Tt5;Vx-vQ4Z=#VsL4sZ;>}?^gZk#&jcY0`YieQ52j0R0 zIhx@0=`4$kl5y1WkF9hXiz`n|Ytw`lE5rtmwpDS(XWvd#f^OB_*j zFew89^XCwZwj2U$Q@vWJ%CyN1GW++UBWx4lhk-erJnY0i3If9!f$z$RF-wygr^v3i zUY9kyz_vHd5Ju{+kT}iLq|_)k=Exu;!hVgt;K6Y)4hT|Q4!rEN$$gYzbj8W1v5(GX zxt07y-IkN9$o`3CF=5JwIIFXu#?B5m4(xwRFB|w7oaV;(r_k(k*>f|0A3h|Wf5)x& zm6o(Q9S&^}uK2fQuSiq81l+Dv%%z0n$=e@22eP0{zIgiXD`O;OQZ1yvN|qV9P<#&_ zBh6v7vyesOniQq9&c^qI(&8kRGJT%lpY4A6>F!=#;jneIyTeOg1sddCIV#cr!;z$w zl!(&L@7id2gAaJg6es?1F_)%(u0-RcNNX31?K*@(+eJK0nUh>2ua$O!-f|;Xn31JE z<_TpU&gztg8q|J5%mZ$Mxkq|#BOBjJWU7nPrIOCoA)2VhStZ#w)F?J$TCA~{oB3UX zXydZ=>~N1S+g2?;Ud+f0w`A?i@D9OJ`ntaw?__z=4q1d{TU`xeGe_4Pm7#NZuqYTK za*JMl@X8o`rXe*!eaS#g{{`Jj{crec>pzj@%;R6neo+h`#OCL2$&lY{&dhwhg0EgW zYgNiX_3q&nqO3v1^)wgt=JX4A&XNY3_vm7lxyO`3(gzgHMSO;Nqd`vgr{O{I4bh`& z1%v$gyR3TpF8l>^h7Vl|L?<~Ycy;kCcUlTVdivJ>idCOvMX)V!6UOG&i(bhpP|WAG zsD_gJEv>^286tHI;XW}wnlSoh1@>LB4YAkPFQr923qyZ1eDRyB?;t-xMFx&+>}|dE zCRq0Bt-H8nGyXv~X|OPyHWb8JBktGNxi~VOhY!kbS8c!vQp_A{elpL%_O=R33oQv8v#cpF6*I@eif+$aO@RA$@ztH-GI7&q0*=+0QE8Vr^R-zQg z_R-0RQfzWB|Fk zE#v1nyU*TBw8}DxtPonbBGSTi8j^04Bi0crnr(mB?=!z7C38v|*@orL7>=wS1_xx!Ud}*bs>60j_BzBedgX`J^d#yZM|mk-kBaTM7fM-psLL7t`H6s;(AWZVSJW7z0(Xw+4*HB>kiBDx?k*_zt6r7==@AX zRa?w8)FAe&Rl(eV2@B=rkW)wKwzKTkABXt)sES2S?)+qd&%Z1g zD)b6ky)oo(#s}~#GnTy75FqS+3VC|KX(0tH&*gHN?d7#vGGj=b=Ux6xmE0(chE_Kk zRg<`bRsk#mgBGZ|GCXk-_jZ(IW! zxpA=hPm8${C2dzl$_!^J{cT_@Gu9sz>1y0YH$E;=)Z`=i8tQx*Mh0MwE5%a`;YzKv zLmw2RpJ)YID7MQT(rvCS;sLcO_GdJRUZ?Z#f||Jwlm}zxE+@lXE7)LCK$V=Y#+-G& zs?xap{HKNz9zgujXQp2HKRRrfF>|)n&YCA**c^Z=V~WLPn--#ZHBFzkJbx{`mG!fi z0#10ABy)-~rW#6D@#(#x_3$MP-27P)`=lA_EE_gaoJt0wWZ@%PwCq%2$h=deWOv{+ zo4^_bMTubxSF&|vKCXv8)n+I%#1AHlo(`C*9Ai}@ITlN zF6jHN6kxCNc!`UG&wC9>4+ar_VeRMDj^0o&QDx6TyfZq`Tl+?|9+4h3fhjUUOpgk8 zrl9nU_sV<6tI(o)6F{0opMjep*tJS;g*7QSsl6Nx(MkofzNI`vi&j4}`vQ{0H&2~q z#ry1ZuuUi;S~I8Hd>!2J^~gzuUS0J)O~4)F?{?C$nNeIX+cY4TKsgVwyCnu(FD~wu z`&ASQ;~Ws0v17H*r{_{G;mhjm=e3TCsbN0ZPnni4ESCukOlUbaLp>O`SrBDGBNb>b z`)F{6#a~?gwOEdoj%mP?0()HFiCub)Rze+ysckSGeq6xqNMf zFm5AIlYQWt@7gB@_0KGORUYfO-D{dT*5?&&FMhr76O{8bOVl`dG|hSoXMZEN^C3Fq zrfBsJB=`aW0-JQ|*&y1Jh*RI&Lw*+ISrSp&SMhdx{=?G4vG1%Sm+Tdv2JvB9#1_(F zM7MZ46wO44$_(X(N+q79Z2hgEIyR(9Nk*I9`f>WA!j6MOKEj!<{r1Lyzu5+{*0X|D zS-Z`^bz8GlFs)29)6gKFLV6jsN9iqyUsLQUPd4-3GWoP((@G?`CW3$cOp-V^vu>Bebbv&x-QZG2d-&=!T>|^-d>GOU3&L8I9>zvnlopWC2wLYVa40JAC;J5$)z$IPCJre*p=MO%2)1C+a zZaQbE0stSNd+&~^f7Zs_hA|d$aInp5Mck>NG$-K%b$~cPnerFy?Kt~sT1f#5MapHA%DdF8%`W&oA5Q;zJn=$((@jTCjxa$oFkmk!Ke*C5N43t1Z z>t=r#FEr4Zi3a#+P;7YGQcFt-AZFGhsbLHT-QCQ9z1r|E0Kp~u-#GxGd0NE)G8coH zZ@eR2tp{fV5~2mwvRcyME46B0LGHzRaxoMDfN-u)8W!H*=%oMlQyc)mKFDr)I5*sj3jl=PP=kcF|;8DxtRU}69l2rM4zjWv-eS^Q%-3<=o;|23QiX3(A$lrmH#WqI3NKzZ*P?nKQ2|TT9npc_%L9pAVLhV|VhB*f$JPT>V|`&>B^?(B?QEI>5fh+Q1W40`4q?UhpM&d?Tp^ zckz5I+XiDtZ_%o0yHXC4AZf8tkgI);f6NKdU?_wf>^uuLMFxpsR6rj<-n@o!$gvA~ zj`!<5DhTQ<-I<`@goDkqO8_5LQ;O)H`%&isO%AakaJi?hXhyCewTDDsN`#~=S(dg- zrfC4pYyS51fY^C5wI1RVGUHosg=Bz_v_han{cC&=$&c(2bdNzHHFP6)@lISg2P{0L z*KHvmJV0o(0{5}qn%vKS+L_F-rYzD2{P}i=Jkv`3Kgs^c-c1kmage9V@$)3pq22tZ z0{#>UfLqc2w*&=>+7T>upGG$3Om5xVVw4 zIKc75DtjH>Vzc1$;JyseW1~#Lw(-FSj%h-1wFhm@x%CZ~79~cwi;}vM$^HEl!=Ty_HqX0#PVh>tNG7%MjvvdG!G;4{ zhUY|E<*L>2q6m-Op+q8m!>$hONFMNq8Iu*1Wg(4-^jBF6+$ zsEq>8r#H^1c(?ZdTlIln;Itj>k-N8c>~B|b;>IRXH5tlPYBdmw-XW1>@E%|Ee_eg9 zQGW1iJOoO)iatM0NSE8V@%{MM%RO~%uJx6zDOLdSC(vtWUZ_4XM}2kyc2ju6Xn!_v z787UPm>`$(F_F}EaT;!5^cdDM(?%~|H6LH5-5FYIyHAWDIC7L%gz5PsKG3%f{;ZY) zKJtZG&>;HFM6ot_P0E>ctKK(WT>SM(p%yf99e&1k&nr}QHIU)7>*?%6tTS;wz}6aS zCsdZjQerjMhiSy$ja&2nzL3qe-N7v8y+33@{&)}NuOgAEF+*rFvrH1}HEzMr=m`#K z?Pr%I>C9>a-;Ov?k8p{d)d0vHUARYnm(R|s#h5dwoI0v+@IJjZ zux7wr)8zlBA)ur);P)z;vuUQjaPjIdoC2I~sItea z;J3k1Xgo3zE7i-XtB2>iP$jyW>cf;YTuxPD{RgML4_Xums2rC5WbbfpzbM(U8^T@f ze^=}(UAB|tC(z%5bi)G+LprICeEVi%*G28{u|ypU6!{7RBm5oF)*)u<3iOPR42I^? zgR2<$m}AB6%l4?^fg9tXmX}d~7x9EYLAKY5tet@JgoXRVp^s@~wJHOXS|sX46=~$) zew=;+ayQQxUK@BWoYca<(dXefQOX7b)e8cexNv_H)Wo*WowyN+pvDo5eb40ejzz@i zV$|#V$_z-VlJ>m!Ol8mhX+3}yvL)ar9-mSkFjmcRc{X-To#&zXFS(m$j@&@2{T1Ka zO)1Y`g@ym)9qj9nO|M%VKQo-)a9kTU^oeK#<8J3rx*ldypFUywIS;g2ysj$GjM$P| zwzEO|b~B8uZUH7MX(cXHXYA&{Q_k0rVCz2NqCmz$SK*L@s;p9znfMiG&`wFT&KcUc zP57M2%!;_Eh)m9jAA{gicwiAe`)m?S^C7t{L!>2Ru88$Z4nghM~dpt=A} z>#YCbma29=cwO-~=uIr>%lJ`V7={0I3kiCIG{pGF_+(aeE6xVD%-vU)>m zOFf*k83?s1x2)Vqei>Wf*u=?>KQtc-9IH3jpSAyy@zL#Fuhz!hfpb&S4_gV>#})t&;A_1^_~3@=Vf{UAwABZGLK%n8jp&cKs8J?}oKp1rZ|x)@~=R?M_Q zd{=ikkM@}O!#|xHPPq3f9j62!{7_%`aL=+?75P1{xKaP{D!)3@zP5O?sId2owuS^gI`W{gL+=RJ2h%geqB+tkELYq@!dre!bzr|7zyus+hEa1!^IcpiwXU}Ia7 zLH63SPT#6tTX_5~WOQ2laoJwE%opUr-iO5sJkwL8?K8QgS*^zV!G*}6p{cN^zlfIU zg(sUh#b;Zxnd84)+&U|YltXcATe{zPVd?{LF$U4 ziH)(>Zhu>$u&5W=3bg!nfMm#(-#9#TVwQZs1v$?1>g_hyZBcx(C`{In)4o?Kc~-1d znUDVy*sV7BR{Xe9aDR`hte;r^ro!*UG=?yw$RKQEMML5LLi$We4ug)TSF?@`OMBtO z^fiLmX6}{6-nBK=`6Ueag^gUI0J>@<4w!=1>+#jt*>cEt&_}jUvYH;2)##PbMN>+j z6)%c*IjB#E3eWZz=gb&~uq{?69aW}c#M*l^i2FB9!sve}{hVrqkYsQ4qTQxR2F0x! zXHBrQNm;ukmJwywW!pr_`>u>K4-<9{*h)IuI@K<&Po7K{VwIVzCR~Uw>FAp%SgJS8 zWm)LvPnNQk(mgUYHF$ZTxlKtw5#oHWQe{Tq}e3v^?~z`^o3YCldNLG zle+UEIeo&0-c=HQ!-t;^^Ih2nlt4d)wk%Q4w;MBPV{SKpb|w+dZd7ceANKY0WxDyL zgoUBO)O9=JZeD8Hw#h3CL3W(P(9-5W+!|!32YPYoM$M|x_I^^PaPl8 zq`r{jtvj3AzAl_#08}(1dZyMF8+ZHi(@`eOcFYLRfK3=YM&va|>(P|4veK_=xA$oa zSQP}b0g{T=J#xZOx_>U!V!J2sJ>|D;*wU$IiZk5r>7#tmzrGcVEg87usa2LW@)u&| zcoN_by4?^vX*%?<3ZmV?+Pd(@OWV(&VnncYWkJ?WmQz&UeON+8PJv^+xdw#;Lk!Q; zf7BH6e^U55??i6R{I}wD#dN3LhTpAiHL?6A8g1P(gh2=iD76xse;r@AO16yldfC=d zUrl({1ul8(X%<;))j&Z4PoHojXu|IQ$&da{W4o`Q#oH7=ADg(O_U=1PLih-Vf||+g z3XHdu7XX4)Qi6gak}ho(=59}O%JJL7AzPgT_T23c&@)T zoV5HUhUsj~-6MhF$Y3T8_8km`#+eI$N6Vz z4DM{2;BoBMUPb8peVEY&})O5|MFDh1-IXGa6?Zq}8JY2qlu89#_Sd_DCKK7vgv?WOV zAXAo(ZvOa%1H4w5e3>3xypXxD(IvSGB!s(pk*I-@56KJq9c@M3I5*qHjqsvuI|Jw4 zrv3`7)%9NZftXBeUt6NpnRk;3x1s)A(bu=j9yfeArR#0_J4%&HR`!3iVS!e&U-NZs zDYNr>-QwwA$|91A$_^P6LhDYK^D$)~BPdZhx#eyK5;kSeXQh8&0;W7OU&o>3m0=S5 zd$*CDo@jOZb(@7LWLU3RVEEqkrfz#woV#Aj`&mG)_dhe3`jKrsXxDtI)D?T{L?#AA z1yXU1rd%$^)eh4KdZe(7FW(HA7jZ@LK5d5Ulf^c=XOLqBxwIDINT`1ewsdxvn6_;= z_g2Sh|JUEC`Se|%o*M+AkhEDp{?_DO$7jJK8@OuI?nwxKYuHc0K$x zvHLO|M{TPP6#O>zywV%%!#BddnOW%l>y*OYD*dLq>fr@Ss~}M&ju)<^rBoDgxm-Kn zAoM<(GOYgxGRG}1BA_TZHbyO><-E&nDOk4I2p3Gqe{hlLas?=G#erfOS;FSi+v|`( zg}{FM&=<6Im0Ei?Rj=N)2f$_()jVgnFY-n(|-i{Za+32!|S~dcA|*cX{Cci=4#| zZ>V8yD*9#Bl;D7rND4*(J~4c_p0&d;HQa{X&$+o67^5w{O1r}QCj0es!|_3N$*a=S zXa%VJQdIQh4KFx34Tflzzp0)Hx7i=d5})t0)ZS9jd3W=Pn}pKnT)LF{UtKz3KVj{y z-_Hz%{PcSIuYqcpL&Tgap-fr#)4Vy8KgJF!`N2F2G;IyKLIjD#nv3y?3q!rx1$LM_ zrWOBNjGJ5&2ZAf)d+TUM>p2eFr2bZ@JTp;c;?S~HPWvh>mKw%$I7;RP;|A(=1f8z} zYQK1C-ulbl6?(#U~`T5}5`eS)u%i0&wx0-nA=IfTTu&6I*I0H}Wo#x{jKFkb@adA(D32S z{q^LVq#;E^o-l>RP1iQ zaEsUo6UH@HzdmKxYYB}?+tnWPJ5pAMdJC-Ln9nw~Jc&c%-hl-X6w!G3%jvU*C)k1d z0(35sM#z8sg_ya!nlL|0lR1Z77Y9h+f4vOUyB`l>MGQ#>f(MWDmHX%PVhuOdeLo!) zszS%ztl@skP-)l?{dJj%2G~+kU59MHWgu%(DEt1ISth+&QLLBMYqLh}N^V?>)*K}9vb3%qxqn~zb~5@i^(#V zq2P1Q&It?Q3SD;%`~)ivApSAE_|{5!vd*}25-QVJpRjA##{k*F;7u8IZ3^$CYE=`Sn`a)UPv0GuM1q!E@<3dkafA{Wt6&jg8D*~zS~XS%;zt1qv4 z@QsU-!rZ^RW$}RDk z%E1bX-*QffZ0(flodfp1B$q{4)D-#viIQE^0qqv)@PkOZa;j3Jo7>)~;!~KK6wMP! zH5q~tWB+_*(!Bm-TDp08NlIyA{us9ud%-582Rh3WgrR7knE2q>yI86Sq`*o8lV0*J zVd{6E$>qr>WO6pSttw?Gc3k=GCK4KVN6g3KI<`$cjg#*5;aIVUIw+8r_+?(CQKVnG z9l_l1Q}!g~#uhs|0AYu+9=i;<%Jrr4y9trpuF;B!`hTEpW@x;iYV;7^YcFcv_GAL3 zKsR4woJNtRf(M>mP`m5VFPN0kKDg3JC;o1`;lU-PAh|Z2$7^-jIoASb7nmYNyGlB| z@)_@deq`u%+YuW0mj2J=)+D0Gmx;*H*08tn=QIo9XgMp_L34pEjp+740;LS^`%kgo zd!w+_7loq}#SH6TJlat4nm?CN9NLLSx585Fft|hk6{cTJe(IU}!Y8Ycinpl+I;<+b z=QFzbU(WdR;P&2yVUN}m+cKLYBl1A1TlqnpQj7A#h;XX*QEP4W3fsgjW zhW6LW>P-9TcDT3()$TnVlL7#vS8h!-YRFDTZIy|)O2?3`nXOh5x3nQC&;QyE zcnv`gH?pa1Pt)56Y3##svpaKr!Y|P8XkG${8%G)cWzd!VeUW!7YQFve3p$&^lgH(E zU#ky;?0SK_ePh>fVfil!C@=@T+wb?+oS92`ah7T^{&Ph(99_-2bc|ILfDgM!=ssz=M#i9$J2t+VyD5R49=5UyHy^VPofrZx>=)acve?00p)Rncc` z((xa?v2Fb^9DGtU_BR@ZQ72Kcv{rowcYGX_9xe259w?Y31LO=U3S*!oX8$9$m+6e( zp2`K759jmiZuaaAsvvaE8$aX*TqnOBy5q&)>KD!Da=V6R9|;9(mTqAir z2Xn_3hn}FjU!7A_cw_7tXA{9nf@a`M+=DkSUQvrz;jsmcQOVP#)8S>7LYUxzYOmF_ zkY9jmPwbNZQ&q{OxNvsHVehR*P^ZX_PTXOSEix2gJ+{V-9J(vj5}I;#)GL-NqERUx zLLJdl;5ps?Be<752Fa8&`MjN;Ux}gkmV)n!Ds>gymFu%HZI>xiSwmUZtPhl&$yF>l ztj8XY>}{~)P7~+UEkq+|X28`Cca=N?_C6$)sF^ei`U@Wb-fO5)I|n1Z*w&N)!49{w zT88#^QF1B^G>E#Jdr|Be5Yi#5U{mh+pL@I+k)(CgdE246NH=+kG-XU4Hn32hW2@f! zL7GpqH$AZEKZfdu>H6Qt@VNGU6)z#mw?p}pPqFiZC{OhKl9){QvY zA0~bp%rG@iQz-XkwNYhM$lt>ULvhb+jCRC=Ef<&C>vf}^HblA^LOL_Kpytith|25Ya245{+S=RRwA>JGMeCdg~PYQPaUDVHrv1Y~D#N8g1$V;a+3?Bth zV`>b5yW)crY>suO?}Hn=niW^f$|F1nKjab=LbWyw1)4IWwLNj6spy~v@nw#%AOI{S zyf2EMGGEKj37UQ&d1ba2LVBH3@~x3yi&y`(I*=l9z_F57n6iYr^7Mky@KUX&{_(Y3 zk4=p;UHs)|I!Wq-B*m^^LFY}#&qq7QEsF7nCwxk>A2X-f7FE+)*iOq=>kE9&rn_H{ zBrYH!F_WwfiDN_IGB|<#`pBtC#o^Q*Je{1R;C|}h!BZpd{t)|jpp87t#kytnCX8j? zqVEnWxd3c^)wxlZ+=BiRG!{5*ZEiC-qGm7A$Y3~$-wZv9jZn9D=1+Ggi7SnCsG_pA z=6;;eu#v_!_&{Ce2X*d(O80;E=*G6?recQDmqPn`+TbSdnCexObV)%s#SE^!%y8S5 zLQ=I$=H8z(Uve~ORLT&yxQ=RWC5K%JRc?jGN&SsrFy)k=m?^(yE$u?o^W5EU_RSAq zls=EV_8ju6(Oo>oLRU>UHQA=nd(3?~iLE{=+sSZ`cvH+ac1qnuL;TpD8+ew#S%#Y6 zi7VO+9}ARCG)ZbCJA5pSF<848@00qH*l3sir5zFcjI}8KG=W-1YptA0?0egKBfb#( zu-MY({-#X55FvX}*w2jz6%8-gQPhvMG}eCh&JOCewq<6y-{_ksxEW=v51Te zY_v_8V#9D1!KUdR;q!~|k*?8c5}e?4GjX2HxOTUcgEuSnPXzl1p08S)2h6AI*O9n9 zwP{;FIRRd>y={HTD+x%-JuE;ng*W2sKlTz zYR+BwSS+c-s_3UV*%{&O8yq-b0!D5C-1hapKtoL znA+gqvNvKhYA+Ec5vpHFr55x2sL1P0t7?-_c>Lqnc4e*1iiA{*lZsAFru}cEF`9K= zEZZ`kW+2Ff-}Ai^u|l3l%)aeT3KMN%gEAm_Vq}TFZ?>`k3b`uq9%l3bHnW@2U<*2V zhRZt_Md5L5~eG{x23o(^A#lb-L+1Gzf#v6WC zEu#q{yKRH?i)-}O=PJz^e4{I)q1)|aGJRegbUM}ztk|*@aU7pF(U_W6c_N>+t?03mbidhvMwZ@*03((`ikcoJsGYV|gP>FF$M=}8;K;hdp9ac-uOmeu9sd6|4RAz51>oOhFx9GSnc~-F_rr;J2LU9_+fdS zb`8(<)4kp7G3W~_V8{0c=+BSvA&dgw1nr3^uvVsbyBfY(E9R`t6a3E!J>*!gpa0!~ z$58y56WY)OCjP_Ix;Ky*<5DVQ3Vnjo5J$_+7p@;njA-^vNIx!GP^;+CmShxXjGIX=ZNcucW<+1?Im z2FK!|$rK;&h4rUmF09rTrPtkNE2K<}vfV=&qz;sS=Wm3SsJE~k*H@*G+NusuE%vin z@T3$i{BO^$zVgP&6kk>+y@{`ZXGpgckG_>au{zB2Ip{54Dd@+-hD&hAkc*QD4~iH+ z(Sv<#1TZ+C9+d1h48w#Xz99Gle+2A!J`MA_44-|w*2p>9_(pr5*k$gfQ&GFTotgnw zwue41_XTDSxrCn$8J`0y+16HXtu~yp`$Jn`<63T)CZ(1)YA%&|R7F;K3NKDwiU(&p zI8@!fd&+_$EV1-@hgPZwy*n5A$s8q0aGbVVcs)~*cf6^+59*1#nM--aZ4HdzBBULyJ|=7b_l8hzK4-RbRb<8cK(8*bkfw0+62 zC@bZ(-2s(I1yGkW`|uY3CuH-OW;;frsd!&GzUu*4i`ggr$KCgU4UQk>=>0i927)o@ ziSSBV^|n8D18ODzAzw8UTE+>CYiOuS)rAXyZTo{=z{Ib#m1mRcY&^QSHhx1qJ25x< z8lL%jk*D?pv;CC$|B8CP2EK`@yjL1O7B(aOXkYRtW;R_L0$CDA*N9)DU zGA`R;E>JApc-5H7$<6v{`H!~rQG=ioT(RMynmfAi&Y5s?qFxHJq3lP=d@nAxL+ot^ zHy%w~$n?17rWQvqlI{nADMs%==LDFt7f+{J)TcTTNvD=kv_dU%3tp>(uKVVsv0Zl| zNT}j!a_{b$X zfUe`E1S8?J-u$y*;c)fOqNq@Iu5q z?PbzMe-PIJXwe0*fRWGp_x98PLS^Db*n?MW>;#A>WzYTBZRZoGx~WersAz?qOk!}- zUH8cNAFxxb?kl#b`8I1Q?A@bm@1k^x?y8iz*Z4jzGC{CQG`rLrm12H{D2^wIU z(WoGye-7Na^O&YOa>|w3$Mqj%X-l3#llDQ?+p#)_DRUT6eFFc1mzZMa&jC*H#a=)#y>g)Wq946)oN&lL{`?=|>xDtI-A6ufm0PjYGEmmz zLojc)ZLQ~89xkf|uJ?i#2)j~O0F#O@K|uytXmvq?WvzCaoF0lT@!dZ?89I;oxMLR2 z0eoR>pH({sL7bi#ElBfl46LI>eW%$7>Z#O_ zx9LHr!apv=ViwLV+`XI^KTaD0IR3*~ffMp=%QLhGMHrdFdt-nWGeQY$-zGi)>gS&BK90`C5BpNVI-#j^y)m)Hx0Iv zTG$egDT-9mcSlud!34OmBe&+O9-&spZ%ieo?AWeI;+Pag>>^3;^Q%O)b-@SVT&u zLYSZTnco8udf>ytYnsDx=<(?{T<&#T@q*c&?@_E)94PJNr5ZIg!dIMb6Ew%7cm^yk z!Wogeo0OW`kR0H&E>OLLIJFja#B`mVkwZ7VCKD2i6J07#+#M$~b$wTVISon$*n{OP zKoOKt4L^9)&xu|5_G4i`SnTn+;A>rdVEI!r0o)7I2x=L7LW}jM#`HR8_TC(8lQo0= z%5>?OflFbq}iDAALVC&A}5m8C@d9 z@eIZdnY&KWH(D*GLcQa(4K4d%WZ3T`#xiR5E#mCtPwbMd0*Z8 zWj=g)ltQM79K9hZj&mxm z-y=bs3Zki^`{)XQIOFf2=R0TpF<(&?F02cRvHv9euY!D!7Z`C~0dHNo+^n4IkN&v= z5G|T+( diff --git a/plugins/tagoio-integration/esbuild/build.js b/plugins/tagoio-integration/esbuild/build.js new file mode 100644 index 00000000..0d1d2a23 --- /dev/null +++ b/plugins/tagoio-integration/esbuild/build.js @@ -0,0 +1,66 @@ +const svgr = require("./svgr.js"); +const esbuild = require("esbuild"); +const fs = require("node:fs"); + +const dev = process.argv.includes("--watch"); + +const TAGOIO_API = "https://api.tago.io"; +const TAGOIO_REALTIME = "https://realtime.tago.io"; + +/** + */ +async function buildFront() { + await esbuild.build({ + entryPoints: ["./src/front/index.tsx"], + bundle: true, + charset: "utf8", + outfile: "./build/front/index.js", + target: ["chrome58", "safari11"], + inject: ["./esbuild/react-shim.js", "./esbuild/dirname-shim.js"], + minify: !dev, + publicPath: "/pages/tagoio-integration", + sourcemap: dev, + watch: dev, + external: ["path"], + plugins: [svgr()], + define: { + "process.env.TAGOIO_API": `"${TAGOIO_API}"`, + "process.env.TAGO_API": `"${TAGOIO_API}"`, + "process.env.TAGOIO_REALTIME": `"${TAGOIO_REALTIME}"`, + "process.env.TAGO_REALTIME": `"${TAGOIO_REALTIME}"`, + }, + loader: { + ".png": "file", + }, + }); +} + +/** + */ +async function generateHTML() { + const template = ` + + + + + + + + +
+ + + + `; + + fs.writeFileSync("./build/front/index.html", template, { encoding: "utf-8" }); +} + +/** + */ +async function build() { + await fs.promises.rm("./build", { recursive: true }).catch(() => null); + await Promise.all([await buildFront(), await generateHTML()]); +} + +build(); diff --git a/plugins/tagoio-integration/esbuild/dirname-shim.js b/plugins/tagoio-integration/esbuild/dirname-shim.js new file mode 100644 index 00000000..3b401f34 --- /dev/null +++ b/plugins/tagoio-integration/esbuild/dirname-shim.js @@ -0,0 +1,2 @@ +const __dirname = ""; +export { __dirname }; diff --git a/plugins/tagoio-integration/esbuild/react-shim.js b/plugins/tagoio-integration/esbuild/react-shim.js new file mode 100644 index 00000000..392f014c --- /dev/null +++ b/plugins/tagoio-integration/esbuild/react-shim.js @@ -0,0 +1,5 @@ +import * as React from "react"; +window.require = () => {}; // for 'path' in tagoio sdk +window.process = window; +window.process.env = {}; +export { React }; diff --git a/plugins/tagoio-integration/esbuild/svgr.js b/plugins/tagoio-integration/esbuild/svgr.js new file mode 100644 index 00000000..6591359d --- /dev/null +++ b/plugins/tagoio-integration/esbuild/svgr.js @@ -0,0 +1,16 @@ +const svgr = require("@svgr/core").default; +const fs = require("node:fs"); + +module.exports = (options = {}) => ({ + name: "svgr", + setup(build) { + build.onLoad({ filter: /\.svg$/ }, async (args) => { + const svg = await fs.promises.readFile(args.path, "utf8"); + const contents = await svgr(svg, { ...options }, { filePath: args.path }); + return { + contents, + loader: "jsx", + }; + }); + }, +}); diff --git a/plugins/tagoio-integration/package.json b/plugins/tagoio-integration/package.json new file mode 100644 index 00000000..d4ffc108 --- /dev/null +++ b/plugins/tagoio-integration/package.json @@ -0,0 +1,28 @@ +{ + "name": "@tago-io/tagocore-plugin-tagoio-integration", + "version": "0.7.0", + "private": true, + "main": "./src/back/index.ts", + "type": "module", + "tcore": { + "name": "TagoIO Integration", + "short_description": "Enables integration between TagoIO Cloud and TagoCore", + "full_description": "./README.md", + "icon": "./assets/icon.png", + "priority": "highest", + "cluster": true, + "hidden": true, + "permissions": ["device", "device-data", "plugin", "action"], + "types": ["navbar-button", "page", "system-override", "hook"], + "publisher": { + "name": "TagoIO", + "domain": "tago.io" + } + }, + "dependencies": { + "path-browserify": "1.0.1" + }, + "devDependencies": { + "@testing-library/user-event": "14.5.2" + } +} diff --git a/plugins/tagoio-integration/src/back/Cluster.ts b/plugins/tagoio-integration/src/back/Cluster.ts new file mode 100644 index 00000000..45f62f71 --- /dev/null +++ b/plugins/tagoio-integration/src/back/Cluster.ts @@ -0,0 +1,229 @@ +import { core } from "@tago-io/tcore-sdk"; +import chalk from "chalk"; +import { cache } from "./Global.ts"; + +const red = chalk.redBright; +const green = chalk.green; +const yellow = chalk.yellow; + +/** + */ +async function downloadPlugin(id: string, version: string, platform: string) { + const source = `https://plugins.tagocore.com/${id}/${version}/download/${platform}`; + const start = id !== "4fb07d6c56d8f67e504dcbcf38ddc15f"; + await core.installPlugin(source, { start }); +} + +/** + */ +async function handlePluginInstall(serverPlugin: any, trimmedID: string) { + const { id, version, platform } = serverPlugin; + + const localPlugins = await core.getPluginList(); + const localPlugin = localPlugins.find((x) => x.id === id); + if (!localPlugin) { + branch("Installing plugin", yellow(trimmedID), yellow(`v${version}`)); + await downloadPlugin(id, version, platform); + return true; + } + if (localPlugin.version !== version) { + branch("Installing plugin", yellow(trimmedID), yellow(`v${version}`)); + await downloadPlugin(id, version, platform); + return true; + } +} + +function JSONstringifyInOrder(obj: any) { + const allKeys = new Set(); + JSON.stringify(obj, (key, value) => (allKeys.add(key), value)); + return JSON.stringify(obj, Array.from(allKeys).sort() as string[]); +} + +/** + */ +async function handlePluginSettings(serverPlugin: any, trimmedID: string) { + const serverModules = serverPlugin.modules || []; + const actions: any = {}; + let logged = false; + + const localPluginSettings = await core.getPluginSettings(serverPlugin.id); + + for (const serverModule of serverModules) { + const moduleID = serverModule.id; + const moduleInfo = await core.getPluginModuleInfo( + serverPlugin.id, + moduleID, + ); + const moduleSettings = localPluginSettings.modules?.find( + (x: any) => x.id === moduleID, + ); + const settingsDiffer = + JSONstringifyInOrder(moduleSettings) !== + JSONstringifyInOrder(serverModule); + if (settingsDiffer) { + if (!logged) { + logged = true; + if (moduleSettings) { + branch("Changed settings for plugin", yellow(trimmedID)); + } else { + branch("Added settings for plugin", yellow(trimmedID)); + } + } + + if (serverModule.disabled) { + if (moduleInfo?.state === "started") { + actions[moduleID] = "stop"; + } + } else { + actions[moduleID] = "restart"; + } + } else { + if ( + !serverPlugin.disabled && + moduleInfo?.error && + !serverModule.disabled + ) { + actions[moduleID] = "start"; + } + } + } + + await core.setPluginSettings(serverPlugin.id, { + disabled: localPluginSettings.disabled, + modules: serverPlugin.modules, + }); + + for (const moduleID in actions) { + if (actions[moduleID] === "start") { + branch( + green("Started"), + "plugin module", + yellow(trimmedID), + "-", + yellow(moduleID), + ); + await core.startPluginModule(serverPlugin.id, moduleID); + } else if (actions[moduleID] === "restart") { + branch( + green("Restarted"), + "plugin module", + yellow(trimmedID), + "-", + yellow(moduleID), + ); + await core.startPluginModule(serverPlugin.id, moduleID); + } else if (actions[moduleID] === "stop") { + branch( + red("Stopped"), + "plugin module", + yellow(trimmedID), + "-", + yellow(moduleID), + ); + await core.stopPluginModule(serverPlugin.id, moduleID).catch(() => null); + } + } +} + +/** + */ +async function handlePluginDisabled(serverPlugin: any, trimmedID: string) { + const settings = await core.getPluginSettings(serverPlugin.id); + + const serverDisabled = !!serverPlugin.disabled; + const localDisabled = !!settings.disabled; + + if (serverDisabled !== localDisabled) { + if (serverPlugin.disabled) { + branch("Disabled plugin", yellow(trimmedID)); + await core.disablePlugin(serverPlugin.id).catch(() => null); + } else { + branch("Enabled plugin", yellow(trimmedID)); + await core.enablePlugin(serverPlugin.id).catch(() => null); + } + } +} + +/** + */ +async function handleClusterState(clusterState: any) { + let reboot = false; + + try { + const statePlugins: any[] = clusterState?.plugins || []; + + if (clusterState === null || clusterState === undefined) { + await core.doFactoryReset(); + } + + if (clusterState?.masterPassword) { + await core.setMasterPassword(clusterState.masterPassword); + } + + if (clusterState?.databasePlugin) { + const settings = await core.getMainSettings(); + await core.setMainSettings({ + ...settings, + database_plugin: clusterState.databasePlugin, + }); + } + + for (const serverPlugin of statePlugins) { + const trimmedID = serverPlugin.id.substring(serverPlugin.id.length - 5); + await handlePluginSettings(serverPlugin, trimmedID); + const installed = await handlePluginInstall(serverPlugin, trimmedID); + await handlePluginDisabled(serverPlugin, trimmedID); + + if (installed && serverPlugin.id === "4fb07d6c56d8f67e504dcbcf38ddc15f") { + // this plugin id + reboot = true; + } + } + + const localPlugins = await core.getPluginList(); + for (const localPlugin of localPlugins) { + // SQLITE, TAGOIO INTEGRATION, PLUGIN STORE are built-ins + if ( + [ + "0810916b6ca256fb25afbe19b4f83b23", + "2e8e52b993bcfbb495f0e4b51f687d89", + "4fb07d6c56d8f67e504dcbcf38ddc15f", + "c311dfe85cf1a29fb1d86a1a2c5afc1c", + ].includes(localPlugin.id) + ) { + continue; + } + + const trimmedID = localPlugin.id.substring(localPlugin.id.length - 5); + const existsInState = statePlugins.some((x) => x.id === localPlugin.id); + if (!existsInState) { + await core.uninstallPlugin(localPlugin.id); + branch("Removed plugin", yellow(trimmedID)); + } + } + + cache.commandsQueue.forEach((x) => x.promise.resolve()); + } catch (ex: any) { + const err = ex?.message || ex?.toString?.() || ex; + cache.commandsQueue.forEach((x) => x.promise.reject(err)); + throw ex; + } finally { + cache.commandsQueue = []; + if (reboot) { + setTimeout(() => { + console.log( + "New TagoIO Integration version detected. Shutting Down cluster instance.", + ); + cache.systemModule?.exit?.(0); + }, 1000); + } + } +} + +/** + */ +function branch(...args: any[]) { + console.log("├─", ...args); +} + +export { handleClusterState }; diff --git a/plugins/tagoio-integration/src/back/Global.ts b/plugins/tagoio-integration/src/back/Global.ts new file mode 100644 index 00000000..b207a8ed --- /dev/null +++ b/plugins/tagoio-integration/src/back/Global.ts @@ -0,0 +1,54 @@ + +import type { SystemModule } from "@tago-io/tcore-sdk"; +import type { Server } from "socket.io"; +import type { Socket } from "socket.io-client"; + +interface ICommandQueueItem { + type: + | "install" + | "settings" + | "uninstall" + | "disable" + | "enable" + | "startModule" + | "stopModule" + | "setMasterPassword" + | "factoryReset" + | "setDatabasePlugin"; + promise: { + resolve: Function; + reject: Function; + }; +} + +interface IStateQueueItem { + connID: string; + state: string; + options?: { + rollback?: boolean; + firstSync?: boolean; + error?: string; + }; +} + +interface IObjects { + tcore: any; + socket: Socket | null; + serverIO: Server | null; + commandsQueue: ICommandQueueItem[]; + stateQueue: IStateQueueItem[]; + systemModule: SystemModule | null; + attachedDevices: Array; +} + +const cache: IObjects = { + tcore: null, + socket: null, + serverIO: null, + commandsQueue: [], + stateQueue: [], + systemModule: null, + attachedDevices: [], +}; + +export { cache }; diff --git a/plugins/tagoio-integration/src/back/Helpers.ts b/plugins/tagoio-integration/src/back/Helpers.ts new file mode 100644 index 00000000..9d22a3a2 --- /dev/null +++ b/plugins/tagoio-integration/src/back/Helpers.ts @@ -0,0 +1,43 @@ +import os from "node:os"; +import md5 from "md5"; + +/** + */ +function getMachineID() { + const interfaces = os.networkInterfaces(); + const hostname = os.hostname(); + + for (const name of Object.keys(interfaces)) { + for (const tmp of interfaces[name] || []) { + const { mac, family, internal } = tmp; + if (family === "IPv4" && !internal) { + const extra = process.env.TCORE_CLUSTER_TOKEN + ? "cluster" + : "standalone"; + return `${md5(mac)}:${hostname}:${extra}`; + } + } + } + + throw new Error("Could not generate a unique ID for this machine"); +} + +/** + */ +function getLocalIPs() { + const interfaces = os.networkInterfaces(); + const addresses: string[] = []; + + for (const name of Object.keys(interfaces)) { + for (const tmp of interfaces[name] || []) { + const { address, family, internal } = tmp; + if (family === "IPv4" && !internal) { + addresses.push(address); + } + } + } + + return addresses; +} + +export { getMachineID, getLocalIPs }; diff --git a/plugins/tagoio-integration/src/back/Log.ts b/plugins/tagoio-integration/src/back/Log.ts new file mode 100644 index 00000000..3b41b357 --- /dev/null +++ b/plugins/tagoio-integration/src/back/Log.ts @@ -0,0 +1,9 @@ +import chalk from "chalk"; + +const red = chalk.redBright; + +function logError(message: string) { + console.log(red("[ERROR]"), message); +} + +export { logError }; diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts new file mode 100644 index 00000000..9aa808f0 --- /dev/null +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -0,0 +1,40 @@ +import { Account } from "@tago-io/sdk"; +import axios from "axios"; +import { getMachineID } from "./Helpers.ts"; + +/** + * Lists all instances that have the current machine id. + */ +async function listTCoresByMachineID(token: string) { + const machine_id = getMachineID(); + const account = new Account({ token, region: "env" }); + const response = await account.tagocores.list({ + fields: ["id", "token"], + filter: { machine_id } as any, + }); + return response; +} + +/** + * Creates a new instance with the given data. + */ +async function updateTCore(token: string, tcoreID: string, data: any) { + const account = new Account({ token, region: "env" }); + const response = await account.tagocores.edit(tcoreID, data); + return response; +} + +/** + * Creates a new instance with the given data. + */ +async function createTCore(token: string, data: any) { + const response = await axios({ + url: `${process.env.TAGOIO_API}/tcore/instance`, + method: "POST", + headers: { token }, + data, + }); + return response.data.result; +} + +export { updateTCore, createTCore, listTCoresByMachineID }; diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts new file mode 100644 index 00000000..2c477b7b --- /dev/null +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -0,0 +1,120 @@ +import http from "node:http"; +import os from "node:os"; +import { helpers, pluginStorage } from "@tago-io/tcore-sdk"; +import bodyParser from "body-parser"; +import cors from "cors"; +import express, { type Request, type Response } from "express"; +import { Server } from "socket.io"; +// @ts-ignore +import pkg from "../../package.json" with { type: "json" }; +import { cache } from "./Global.ts"; +import { getMachineID } from "./Helpers.ts"; +import { createTCore, listTCoresByMachineID, updateTCore } from "./Request.ts"; +import { closeSocket, initSocket } from "./Socket.ts"; + +let server: http.Server | null = null; + +/** + */ +function initServer() { + if (server) { + return; + } + + const app = express(); + app.use(cors()); + app.use(bodyParser.urlencoded({ extended: false })); + app.use(bodyParser.json()); + + app.get("/tcore", routeGetTCore); + app.put("/tcore", (req, res) => { + if (req.body.active) { + cache.socket?.connect(); + } else { + cache.socket?.disconnect(); + } + if (cache.tcore) { + cache.tcore.active = !!req.body.active; + } + }); + app.post("/start", routeStartTCore); + app.post("/sign-out", routeSignOut); + + server = http.createServer(app); + server.listen("8999"); + + cache.serverIO = new Server(server); + cache.serverIO.on("connection", () => { + if (cache.socket) { + cache.serverIO?.emit("status", cache.socket.connected); + } + }); +} + +/** + */ +function closeServer() { + server?.close(); + server = null; +} + +/** + */ +function routeGetTCore(req: Request, res: Response) { + if (cache.tcore) { + res.status(200); + res.send({ status: true, result: cache.tcore }); + } else { + res.status(404); + res.send({ status: false }); + } +} + +/** + */ +async function routeSignOut(req: Request, res: Response) { + await pluginStorage.delete("token"); + closeSocket(); + cache.tcore = null; + res.sendStatus(200); +} + +/** + */ +async function routeStartTCore(req: Request, res: Response) { + const systemStartTime = new Date(Date.now() - os.uptime() * 1000); + const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); + const osInfo = await helpers.getOSInfo(); + const profileToken = req.headers.token as string; + + const list = await listTCoresByMachineID(profileToken).catch(() => null); + const item = list?.[0] as any; + + if (item?.token) { + await updateTCore(profileToken, item.id, { name: req.body.name }); + await pluginStorage.set("token", item?.token); + await initSocket(item?.token); + res.sendStatus(200); + return; + } + + const data = await createTCore(profileToken, { + machine_id: getMachineID(), + name: req.body.name, + system_start_time: systemStartTime.toISOString(), + tcore_start_time: tcoreStartTime.toISOString(), + tcore_version: pkg.version, + os: osInfo, + }).catch((err) => { + console.log(err); + return null; + }); + + if (data) { + await pluginStorage.set("token", data?.token); + await initSocket(data?.token); + res.sendStatus(200); + } +} + +export { closeServer, initServer }; diff --git a/plugins/tagoio-integration/src/back/Socket.ts b/plugins/tagoio-integration/src/back/Socket.ts new file mode 100644 index 00000000..8e7a7be4 --- /dev/null +++ b/plugins/tagoio-integration/src/back/Socket.ts @@ -0,0 +1,337 @@ +import os from "node:os"; +import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; +import type { + IDeviceDataQuery, + IDeviceListQuery, + TGenericID, +} from "@tago-io/tcore-sdk/types"; +import chalk from "chalk"; +import { type Socket, io } from "socket.io-client"; +import { handleClusterState } from "./Cluster.ts"; +import { cache } from "./Global.ts"; +import { getMachineID } from "./Helpers.ts"; + +/** + * Socket used to communicate with the API. + */ +let socket: Socket | null; + +if (!process.env.TCORE_CLUSTER_TOKEN) { + setInterval( + async () => { + const token = await pluginStorage.get("token").catch(() => null); + if (token && socket && socket?.disconnected) { + const tokenEnd = token.substring(token.length - 5); + console.log( + "Trying to reconnect using token ending in", + chalk.yellow(tokenEnd), + ); + socket?.connect(); + } + }, + 1000 * 60 * 5, + ); +} + +/** + */ +function initSocket(token: string) { + if (!token || socket) { + return; + } + + return new Promise((resolve, reject) => { + console.log("Connecting..."); + + const query = { token }; + let connectErrors = 0; + + socket = io(process.env.TAGOIO_REALTIME || "", { + transports: ["websocket"], + query, + }); + socket.connect(); + + cache.socket = socket; + + /** + */ + socket.on("ready", () => { + connectErrors = 0; + console.log("Connected to TagoIO"); + emitStartData(); + cache.serverIO?.emit("status", cache.socket?.connected); + }); + + /** + */ + socket.on("disconnect", () => { + console.log(chalk.redBright("[ERROR]"), "Unexpected disconnection"); + cache.serverIO?.emit("status", cache.socket?.connected); + cache.attachedDevices = []; + + if (process.env.TCORE_CLUSTER_TOKEN) { + // if the promise is still active the reject will make sure that + // the other side receives an error and cancels the execution flow + reject(); + } else { + // if the tcore was deleted without this instance logging out we need + // to resolve the connection normally for the user to try again + resolve(); + } + }); + + /** + */ + socket.on("connect_error", () => { + connectErrors += 1; + console.log( + chalk.redBright("[ERROR]"), + `Connect error (${connectErrors}/3).`, + ); + + cache.serverIO?.emit("status", cache.socket?.connected); + cache.attachedDevices = []; + + if (connectErrors >= 3 || !process.env.TCORE_CLUSTER_TOKEN) { + connectErrors = 0; + socket?.disconnect(); + reject(); + } + }); + + /** + */ + socket.on("tcore::instance", (tcore) => { + cache.tcore = tcore; + if (!process.env.TCORE_CLUSTER_TOKEN) { + resolve(); + } + }); + + /** + */ + socket.on("tcore::action::schedule", (connID: string) => { + call("tcore::action::schedule", connID, async () => { + await core.triggerActionScheduleCheck(); + await core.triggerDeviceDataRetentionCheck(); + }); + }); + + /** + */ + socket.on("tcore::cluster::busy", (connID: string) => { + call("tcore::cluster::busy", connID, async () => { + const message = + "Cluster is busy executing another action. Try again later."; + cache.commandsQueue.forEach((x) => x.promise.reject(message)); + cache.commandsQueue = []; + }); + }); + + /** + */ + socket.on("tcore::cluster::state", async (connID, state, options) => { + if (cache.stateQueue.length > 0) { + // already has a state in the queue, add to the queue and wait + cache.stateQueue.push({ connID, state, options }); + } else { + // no state in queue, run it right now + cache.stateQueue.push({ connID, state, options }); + await checkStateQueue(); + resolve(); + } + }); + + /** + */ + socket.on( + "tcore::device::data::added", + async (connID, deviceToken, data) => { + call("tcore::device::data::added", connID, async () => { + const device = await core.getDeviceByToken(deviceToken); + if (device) { + await core.addDeviceData(device.id, data).catch(() => null); + } + }); + }, + ); + + /** + * Called when the realtime server requests a device list on this instance. + */ + socket.on( + "tcore::device::list", + async (connID, query: IDeviceListQuery) => { + call("tcore::device::list", connID, async () => { + query.fields = (query.fields || []).filter( + (x: string) => x !== "bucket", + ); + const list = await core.getDeviceList(query); + return list; + }); + }, + ); + + /** + * Called when the realtime server requests a device info on this instance. + */ + socket.on("tcore::device::info", async (connID, deviceID: TGenericID) => { + call("tcore::device::info", connID, async () => { + const info = await core.getDeviceInfo(deviceID); + return info; + }); + }); + + /** + * Called when the realtime server requests data from this instance. + */ + socket.on( + "tcore::device::data", + async (connID, deviceID: TGenericID, query: IDeviceDataQuery) => { + call("tcore::device::data", connID, async () => { + const data = await core.getDeviceData(deviceID, query); + return data; + }); + }, + ); + + /** + */ + socket.on("tcore::summary", async (connID) => { + call("tcore::summary", connID, () => core.getSummary()); + }); + + /** + * Called when someone enters a dashboard with this device in a widget. + */ + socket.on("tcore::data::attach", async (deviceID) => { + cache.attachedDevices.push(deviceID); + }); + + /** + * Called when someone leaves a dashboard with this device in a widget. + */ + socket.on("tcore::data::unattach", async (deviceID) => { + const i = cache.attachedDevices.indexOf(deviceID); + if (i >= 0) { + cache.attachedDevices.splice(i, 1); + } + }); + + /** + */ + socket.on("tcore::summary-and-computer-usage", async (connID) => { + call("tcore::summary-and-computer-usage", connID, async () => { + const data = await Promise.all([ + core.getSummary(), + helpers.getComputerUsage(), + ]); + return { summary: data[0], computer_usage: data[1] }; + }); + }); + }); +} + +/** + */ +function closeSocket() { + socket?.off(); + socket?.disconnect?.(); + socket = null; +} + +/** + * Calls a procedure. + */ +async function call(event: string, connID: string, fn: Function) { + try { + console.log(`• Received ${chalk.cyanBright(event)} event`); + const promise = fn(); + const result = await promise; + cache.serverIO?.emit("event", "receive", event, Date.now(), result); + socket?.emit("tcore::response::success", connID, result); + console.log("└─", chalk.green("[DONE]"), "Handled event"); + } catch (ex: any) { + const err = ex?.message || ex; + console.log("└─", chalk.redBright("[ERROR]"), err); + socket?.emit("tcore::response::error", connID, err); + } +} + +/** + * Emits a ping event to the API. + */ +async function emitStartData() { + const systemStartTime = new Date(Date.now() - os.uptime() * 1000); + const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); + const osInfo = await helpers.getOSInfo(); + + socket?.emit("tcore::start", { + machine_id: getMachineID(), + local_ips: getLocalIPs().join(", "), + name: os.hostname(), + os: osInfo, + system_start_time: systemStartTime, + tcore_start_time: tcoreStartTime, + tcore_version: "0.7.0", + }); +} + +/** + * TODO + */ +async function checkStateQueue() { + for (const item of cache.stateQueue) { + const isRollback = item.options?.rollback; + const error = item.options?.error; + const event = `tcore::cluster::state${isRollback ? "::rollback" : ""}`; + + if (isRollback) { + const message = `Rolling back due to error in one of the Cluster instances: ${error}`; + cache.systemModule?.emitInstallLog({ error: true, message }); + } + + await call(event, item.connID, async () => { + if (isRollback) { + console.log( + "├─", + chalk.cyanBright("[ROLLBACK]"), + "due to error", + chalk.redBright(error), + ); + } + await handleClusterState(item.state); + }); + } + + cache.stateQueue = []; +} + +/** + * TODO + */ +function getLocalIPs() { + const interfaces = os.networkInterfaces(); + const addresses: string[] = []; + + for (const name of Object.keys(interfaces)) { + for (const tmp of interfaces[name] || []) { + const { address, family, internal } = tmp; + if (family === "IPv4" && !internal) { + addresses.push(address); + } + } + } + + return addresses; +} + +/** + * TODO + */ +function isConnectedToAPI() { + return true; +} + +export { closeSocket, initSocket, isConnectedToAPI }; diff --git a/plugins/tagoio-integration/src/back/index.ts b/plugins/tagoio-integration/src/back/index.ts new file mode 100644 index 00000000..25d5afda --- /dev/null +++ b/plugins/tagoio-integration/src/back/index.ts @@ -0,0 +1,251 @@ + +import { HookModule, NavbarButtonModule, PageModule, pluginStorage, SystemModule } from "@tago-io/tcore-sdk"; +import { cache } from "./Global.ts"; +import { logError } from "./Log.ts"; +import { closeServer, initServer } from "./Server.ts"; +import { initSocket } from "./Socket.ts"; + +let started = false; + +/** + */ +async function cleanUpOldStructure() { + await pluginStorage.delete("tcore-token"); + await pluginStorage.delete("tcore-profile-token"); + await pluginStorage.delete("tcore-id"); +} + +/** + */ +async function init() { + if (started) { + return; + } + initServer(); + + if (process.env.TCORE_CLUSTER_TOKEN) { + // cluster start + try { + started = true; + await initSocket(process.env.TCORE_CLUSTER_TOKEN); + } catch (ex) { + logError("These are the possible causes for the disconnect:"); + logError(" • Invalid TagoCore Cluster token"); + logError(" • No connection to TagoIO servers"); + logError( + " • You exceeded the maximum amount of TagoCore instances in your TagoIO Profile", + ); + logError("Verify all these possible issues and try again."); + await new Promise((resolve) => setTimeout(resolve, 200)); + await cache.systemModule?.exit?.(0); + } + } else { + // non-cluster start + await cleanUpOldStructure().catch(() => null); + + const normalToken = await pluginStorage.get("token").catch(() => null); + if (normalToken) { + await initSocket(normalToken); + } + } +} + +/** + */ +async function onPluginDestroy() { + closeServer(); + started = false; +} + +/** + */ +function onInstallStorePlugin(id: string, version: string, platform: any) { + const promise = new Promise((resolve, reject) => { + const type = "install"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { + type, + data: { platform, id, version }, + }); + }); + return promise; +} + +/** + */ +function onUninstallStorePlugin(id: string) { + const promise = new Promise((resolve, reject) => { + const type = "uninstall"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { id } }); + }); + return promise; +} + +/** + */ +function onEditModuleSettings(id: string, settings: any) { + const promise = new Promise((resolve, reject) => { + const type = "settings"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { id, settings } }); + }); + return promise; +} + +/** + */ +function onDisablePlugin(id: string) { + const promise = new Promise((resolve, reject) => { + const type = "disable"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { id } }); + }); + return promise; +} + +/** + */ +function onEnablePlugin(id: string) { + const promise = new Promise((resolve, reject) => { + const type = "enable"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { id } }); + }); + return promise; +} + +/** + */ +function onStartPluginModule(pluginID: string, moduleID: string) { + const promise = new Promise((resolve, reject) => { + const type = "startModule"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { + type, + data: { pluginID, moduleID }, + }); + }); + return promise; +} + +/** + */ +function onStopPluginModule(pluginID: string, moduleID: string) { + const promise = new Promise((resolve, reject) => { + const type = "stopModule"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { + type, + data: { pluginID, moduleID }, + }); + }); + return promise; +} + +/** + */ +function onSetMasterPassword(password: string) { + const promise = new Promise((resolve, reject) => { + const type = "setMasterPassword"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { password } }); + }); + return promise; +} + +/** + */ +function onSetDatabasePlugin(databasePlugin: string) { + const promise = new Promise((resolve, reject) => { + const type = "setDatabasePlugin"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { + type, + data: { databasePlugin }, + }); + }); + return promise; +} + +/** + */ +function onFactoryReset(password: string) { + const promise = new Promise((resolve, reject) => { + const type = "factoryReset"; + cache.commandsQueue.push({ type, promise: { resolve, reject } }); + cache.socket?.emit("tcore::message:add", { type, data: { password } }); + }); + return promise; +} + +/* + * Hook module to listen to data events and then send + * the data to the server's realtime. + */ +const hookModule = new HookModule({ + id: "hook", + name: "Events listener", +}); + +hookModule.onMainDatabaseModuleLoaded = init; + +hookModule.onAfterInsertDeviceData = async (deviceID, data) => { + if (cache.attachedDevices.includes(deviceID)) { + const event = "tcore::device::data::add"; + cache.serverIO?.emit("event", "send", event, Date.now(), data); + cache.socket?.emit(event, deviceID, data); + } +}; + +/** + * Main .html page + */ +new PageModule({ + id: "main-page", + route: "/tagoio-integration", + assets: "./build/front", + name: "Main page", +}); + +/** + * Assets (.js, .css) and other routes + */ +const assetsPage = new PageModule({ + id: "other", + route: "/tagoio-integration/*", + assets: "./build/front", + name: "Details page", +}); + +if (process.env.TCORE_CLUSTER_TOKEN) { + const systemModule: any = new SystemModule({ id: "system" }); + systemModule.onLoad = init; + systemModule.onDestroy = onPluginDestroy; + systemModule.onInstallStorePlugin = onInstallStorePlugin; + systemModule.onUninstallStorePlugin = onUninstallStorePlugin; + systemModule.onEditModuleSettings = onEditModuleSettings; + systemModule.onDisablePlugin = onDisablePlugin; + systemModule.onEnablePlugin = onEnablePlugin; + systemModule.onStartPluginModule = onStartPluginModule; + systemModule.onStopPluginModule = onStopPluginModule; + systemModule.onSetMasterPassword = onSetMasterPassword; + systemModule.onSetDatabasePlugin = onSetDatabasePlugin; + systemModule.onFactoryReset = onFactoryReset; + cache.systemModule = systemModule; +} else { + assetsPage.onLoad = init; + assetsPage.onDestroy = onPluginDestroy; +} + +new NavbarButtonModule({ + id: "navbar-button", + name: "Integration button", + option: { + icon: "io", + action: { + type: "open-url", + url: "/tagoio-integration", + }, + }, +}); diff --git a/plugins/tagoio-integration/src/front/App.tsx b/plugins/tagoio-integration/src/front/App.tsx new file mode 100644 index 00000000..0f3a64d0 --- /dev/null +++ b/plugins/tagoio-integration/src/front/App.tsx @@ -0,0 +1,76 @@ +import { Loading } from "@tago-io/tcore-console"; +import axios from "axios"; +import { useCallback, useEffect, useState } from "react"; +import Auth from "./Auth/Auth.tsx"; +import Details from "./Details/Details.tsx"; + +/** + * Main app of the front-end system. This component will figure out what + * screen to show based on the authentication status of the user, and will also + * identify which port to use from the configs. + */ +function App() { + const [tcore, setTCore] = useState(null); + const [loading, setLoading] = useState(true); + const [port, setPort] = useState(8999); + + /** + * Fetches the tcore instance and sets it locally. + */ + const fetchTCore = async () => { + const location = window.location; + axios + .get(`${location.protocol}//${location.hostname}:${port}/tcore`) + .then((r) => { + setTCore(r.data.result); + setLoading(false); + }) + .catch(() => { + setLoading(false); + }); + }; + + /** + * Signs out. + */ + const signOut = useCallback(async () => { + const location = window.location; + await axios.post( + `${location.protocol}//${location.hostname}:${port}/sign-out`, + ); + setTCore(null); + setLoading(false); + }, []); + + /** + * Tries to fetch tcore once we load the app. + */ + useEffect(() => { + if (port) { + fetchTCore(); + } + }, [port]); + + /** + * TODO: + * Tries to fetch tcore once we load the app. + */ + // useEffect(() => { + // const portConfig = data?.modules?.find((x) => x.id === "navbar-button")?.configs?.[0]; + // if (portConfig?.type == "number") { + // setPort(Number(portConfig.defaultValue)); + // } + // }, [data]); + + if (loading || !port) { + return ; + } + + if (tcore) { + return
; + } + + return ; +} + +export default App; diff --git a/plugins/tagoio-integration/src/front/Auth/Auth.style.ts b/plugins/tagoio-integration/src/front/Auth/Auth.style.ts new file mode 100644 index 00000000..a3764db6 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Auth.style.ts @@ -0,0 +1,129 @@ +import { darken } from "polished"; +import styled from "styled-components"; + +export const Container = styled.div` + height: 100%; + width: 100%; + border: 0; + display: flex; + align-items: center; + justify-content: center; + flex: 1; + background: rgba(0, 0, 0, 0.02); + + .fake-link, + a { + cursor: pointer; + color: ${(props) => props.theme.link}; + + &:hover { + color: ${(props) => darken(0.04, props.theme.link)}; + } + &:active { + color: ${(props) => darken(0.08, props.theme.link)}; + } + } +`; + +export const Inner = styled.div` + background: white; + border-radius: 7px; + height: 80%; + display: flex; + flex-direction: row; + align-items: center; + position: relative; + background: white; + overflow: hidden; + width: 1440px; + max-width: calc(100% - 120px); + box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.1); + + button { + width: 100%; + } + + .left { + padding: 60px; + position: relative; + display: flex; + align-items: center; + height: 100%; + flex: 1; + overflow: auto; + } + + .right { + background: black; + height: 100%; + width: 40%; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + position: relative; + + h2 { + color: white; + font-size: 29px; + margin: 60px 0px; + text-align: center; + justify-content: center; + display: flex; + flex-direction: column; + align-items: center; + + span { + font-size: 1.1rem; + color: white; + font-weight: normal; + opacity: 0.8; + margin-top: 2px; + display: flex; + } + } + + .block { + height: 100px; + display: flex; + align-items: center; + } + + .connection { + display: flex; + padding: 0px 0px; + margin-bottom: 20px; + align-items: center; + justify-content: center; + } + } + + @media screen and (max-width: 992px) { + .banner { + display: none; + } + } +`; + +export const Steps = styled.div` + display: flex; + margin: 0 auto; + justify-content: center; + position: absolute; + top: 20px; + left: 50%; + transform: translate(-50%, 0%); + + > div { + border-radius: 50%; + background: rgba(0, 0, 0, 0.2); + width: 10px; + height: 10px; + margin: 0px 3px; + transition: background-color 0.3s; + + &.selected { + background: black; + } + } +`; diff --git a/plugins/tagoio-integration/src/front/Auth/Auth.tsx b/plugins/tagoio-integration/src/front/Auth/Auth.tsx new file mode 100644 index 00000000..d0cad995 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Auth.tsx @@ -0,0 +1,273 @@ +import { useApiRequest } from "@tago-io/tcore-console"; +import type { IOSInfo } from "@tago-io/tcore-sdk/types"; +import axios from "axios"; +import { useCallback, useState } from "react"; +import { useEffect } from "react"; +import * as Style from "./Auth.style"; +import Banner from "./Banner/Banner.tsx"; +import Credentials from "./Credentials/Credentials.tsx"; +import InstanceName from "./InstanceName/InstanceName.tsx"; +import Otp from "./Otp/Otp.tsx"; +import OtpPicker from "./OtpPicker/OtpPicker.tsx"; +import Profiles from "./Profiles/Profiles.tsx"; + +const API_URL = process.env.TAGOIO_API; + +/** + * Props. + */ +interface IAuthProps { + /** + * Port of the integration server. + */ + port: number; + /** + * Called when the user successfully signed in. + */ + onSignIn: (tagocoreID: string) => void; +} + +/** + */ +function Auth(props: IAuthProps) { + const [loading, setLoading] = useState(false); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [content, setContent] = useState("credentials"); + const [otpType, setOtpType] = useState("authenticator"); + const [invalidCredentials, setInvalidCredentials] = useState(false); + const [lastPinCode, setLastPinCode] = useState(""); + const { data: osInfo } = useApiRequest("/hardware/os"); + const [otpTypesEnabled, setOtpTypesEnabled] = useState([ + "authenticator", + "email", + "sms", + ]); + + const [name, setName] = useState(""); + const [token, setToken] = useState(""); + const [profiles, setProfiles] = useState([]); + + const { onSignIn, port } = props; + + /** + * Logs in. + */ + const login = useCallback( + async (pinCode?: string) => { + try { + if (loading) { + // prevent user clicking enter multiple times while focusing an input + return; + } + + setLoading(true); + setInvalidCredentials(false); + setLastPinCode(pinCode || ""); + + // logs in and gets the account + const result = await axios.post( + `${API_URL}/account/login`, + { + email, + password, + otp_type: pinCode ? otpType : undefined, + pin_code: pinCode ? pinCode : undefined, + }, + { validateStatus: () => true }, + ); + + if (!result.data.status) { + throw result.data; + } + + setProfiles(result.data.result.profiles); + setContent("profiles"); + } catch (ex: any) { + const error = String(ex.message).includes("otp_enabled") + ? JSON.parse(ex.message) + : {}; + + if (error.otp_enabled && error.otp_autosend) { + setOtpType(error.otp_autosend); + setOtpTypesEnabled(error.otp_enabled); + setContent("otp"); + } else { + setInvalidCredentials(true); + } + } finally { + setLoading(false); + } + }, + [email, password, loading, otpType], + ); + + /** + * Called when the user finishes the integration in the last step. + */ + const startIntegration = async () => { + try { + setLoading(true); + + const location = window.location; + const response = await axios({ + url: `${location.protocol}//${location.hostname}:${port}/start`, + method: "POST", + headers: { token }, + data: { name }, + }); + + onSignIn(response.data.id); + } catch (ex) { + setLoading(false); + throw ex; + } + }; + + /** + */ + const chooseProfile = useCallback( + async (id: string) => { + try { + setLoading(true); + + // uses the account to get a profile token + // logs in and gets the account + const tokenData = await axios.post(`${API_URL}/account/profile/token`, { + email, + password, + otp_type: lastPinCode ? otpType : undefined, + pin_code: lastPinCode ? lastPinCode : undefined, + expire_time: "3 months", + name: "Generated automatically by TagoCore", + profile_id: id, + }); + + setToken(tokenData.data.result.token); + setContent("instance-name"); + } catch (ex) { + console.error(ex); + setContent("credentials"); + } finally { + setLoading(false); + } + }, + [email, otpType, lastPinCode, password], + ); + + /** + * Switches to the OTP picker content. + */ + const activateOtpPickerContent = useCallback(() => { + setContent("otp-picker"); + }, []); + + /** + * Switches to the OTP content. + */ + const activateOtpContent = useCallback(() => { + setContent("otp"); + }, []); + + /** + * Switches to the credentials content. + */ + const activateCredentialsContent = useCallback(() => { + setLoading(false); + setContent("credentials"); + setInvalidCredentials(false); + }, []); + + /** + * Switches the OTP type to another type. + */ + const switchOtpType = useCallback( + async (newType: string) => { + setOtpType(newType); + setContent("otp"); + + if (newType !== "authenticator") { + await axios.post(`${API_URL}/account/login/otp`, { + email, + password, + otp_type: newType, + }); + } + }, + [email, password], + ); + + /** + * Sets the hostname. + */ + useEffect(() => { + if (osInfo?.hostname) { + setName(osInfo.hostname); + } + }, [osInfo]); + + return ( + + +
+ +
+
+
+ + + {content === "credentials" ? ( + // email and password + + ) : content === "profiles" ? ( + // profile selection + + ) : content === "otp-picker" ? ( + + ) : content === "otp" ? ( + // currently selected otp + + ) : ( + // instance name selection + + )} +
+ + + + + ); +} + +export default Auth; diff --git a/plugins/tagoio-integration/src/front/Auth/Banner/Banner.style.ts b/plugins/tagoio-integration/src/front/Auth/Banner/Banner.style.ts new file mode 100644 index 00000000..d592ac39 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Banner/Banner.style.ts @@ -0,0 +1,47 @@ +import styled from "styled-components"; + +export const Container = styled.div` + background: black; + height: 100%; + width: 40%; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + position: relative; + padding: 20px; + + h2 { + color: white; + font-size: 29px; + margin: 60px 0px; + text-align: center; + justify-content: center; + display: flex; + flex-direction: column; + align-items: center; + + span { + font-size: 1.1rem; + color: white; + font-weight: normal; + opacity: 0.8; + margin-top: 2px; + display: flex; + } + } + + .block { + height: 100px; + display: flex; + align-items: center; + } + + .connection { + display: flex; + padding: 0px 0px; + margin-bottom: 20px; + align-items: center; + justify-content: center; + } +`; diff --git a/plugins/tagoio-integration/src/front/Auth/Banner/Banner.tsx b/plugins/tagoio-integration/src/front/Auth/Banner/Banner.tsx new file mode 100644 index 00000000..6eced529 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Banner/Banner.tsx @@ -0,0 +1,42 @@ +import { EIcon, Icon } from "@tago-io/tcore-console"; +import * as Style from "./Banner.style"; + +/** + */ +function Banner() { + return ( + +

+ Get the best of both worlds +
+ Link your TagoIO Cloud account with your TagoCore. +

+ +
+ +
+ +
+ +
+
+ + +
+
+ +
+

+ + ); +} + +export default Banner; diff --git a/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.style.ts b/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.style.ts new file mode 100644 index 00000000..6d266aab --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.style.ts @@ -0,0 +1,25 @@ +import styled, { css } from "styled-components"; + +export const Container = styled.div<{ $loading: boolean }>` + transition: opacity 0.15s; + width: 400px; + margin: 0 auto; + + h3 { + font-size: 1.6rem; + margin-bottom: 5px; + } + + .tagoio-logo { + display: inline-flex; + vertical-align: bottom; + margin: 0px 5px; + } + + ${(props) => + props.$loading && + css` + opacity: 0.5; + pointer-events: none; + `} +`; diff --git a/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.tsx b/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.tsx new file mode 100644 index 00000000..74754e31 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Credentials/Credentials.tsx @@ -0,0 +1,120 @@ +import { Button, EButton, FormGroup, Input } from "@tago-io/tcore-console"; +import { type KeyboardEvent, useCallback, useRef, useState } from "react"; +// @ts-ignore +import SVGTagoIO from "../../../../assets/tagoio-logo.svg"; +import * as Style from "./Credentials.style"; + +/** + */ +function Credentials(props: any) { + const { + loading, + email, + invalidCredentials, + password, + onChangeEmail, + onChangePassword, + onLogin, + } = props; + const [emailError, setEmailError] = useState(false); + const [passwordError, setPasswordError] = useState(false); + const passwordRef = useRef(null); + const emailRef = useRef(null); + + /** + * Tries to log in. + */ + const login = useCallback(() => { + if (String(emailError).length <= 3) { + setEmailError(true); + return; + } + if (String(passwordError).length <= 3) { + setPasswordError(true); + return; + } + + onLogin(); + emailRef?.current?.blur(); + passwordRef?.current?.blur(); + }, [emailError, passwordError, onLogin]); + + /** + * Called when the email input receives a keydown event. + */ + const onEmailKeyDown = useCallback((e: KeyboardEvent) => { + if (e.key === "Enter") { + passwordRef?.current?.focus(); + } + }, []); + + /** + * Called when the password input receives a keydown event. + */ + const onPasswordKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "Enter") { + login(); + } + }, + [login], + ); + + return ( + + +

Sign in

+
+ Enter your + + + + credentials. +
+
+ + + onChangeEmail(e.target.value)} + onKeyDown={onEmailKeyDown} + error={invalidCredentials} + ref={emailRef} + value={email} + /> + + + + onChangePassword(e.target.value)} + onKeyDown={onPasswordKeyDown} + error={invalidCredentials} + ref={passwordRef} + type="password" + value={password} + /> + + + + + + +
+ Don't have a TagoIO account? + + Sign up + + . +
+
+ ); +} + +export default Credentials; diff --git a/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.style.ts b/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.style.ts new file mode 100644 index 00000000..1dbc1afd --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.style.ts @@ -0,0 +1,25 @@ +import styled, { css } from "styled-components"; + +export const Container = styled.div<{ loading: boolean }>` + transition: opacity 0.15s; + width: 400px; + margin: auto; + + .title-container { + display: flex; + align-items: center; + + h3 { + font-size: 1.6rem; + margin-bottom: 5px; + flex: 1; + } + } + + ${(props) => + props.loading && + css` + opacity: 0.5; + pointer-events: none; + `} +`; diff --git a/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.tsx b/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.tsx new file mode 100644 index 00000000..5d543fa3 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/InstanceName/InstanceName.tsx @@ -0,0 +1,69 @@ +import { Button, EButton, FormGroup, Input } from "@tago-io/tcore-console"; +import { type KeyboardEvent, useCallback, useRef, useState } from "react"; +import * as Style from "./InstanceName.style"; + +/** + */ +function InstanceName(props: any) { + const [error, setError] = useState(false); + const { name, onChangeName, onStart, onSignOut, loading } = props; + const ref = useRef(); + + /** + * Called to start the integration. + */ + const start = useCallback(() => { + if (loading) { + return; + } + if (String(name).length < 3) { + setError(true); + return; + } + + ref?.current?.blur(); + setError(false); + onStart().catch(() => setError(true)); + }, [name, loading, onStart]); + + /** + * Called when the input receives a keydown event. + */ + const onKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "Enter") { + start(); + } + }, + [start], + ); + + return ( + +
+

Instance name

+ + Sign out + +
+ + + onChangeName(e.target.value)} + onKeyDown={onKeyDown} + placeholder="e.g. tcore-gateway-1" + ref={ref} + value={name} + /> + + + +
+ ); +} + +export default InstanceName; diff --git a/plugins/tagoio-integration/src/front/Auth/Otp/Otp.style.ts b/plugins/tagoio-integration/src/front/Auth/Otp/Otp.style.ts new file mode 100644 index 00000000..49ac3a6f --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Otp/Otp.style.ts @@ -0,0 +1,30 @@ +import styled, { css } from "styled-components"; + +export const Container = styled.div<{ loading: boolean }>` + transition: opacity 0.15s; + width: 400px; + margin: auto; + + .title-container { + display: flex; + align-items: center; + margin-bottom: 1rem; + + > div { + flex: 1; + } + + h3 { + font-size: 1.6rem; + margin-bottom: 5px; + flex: 1; + } + } + + ${(props) => + props.loading && + css` + opacity: 0.5; + pointer-events: none; + `} +`; diff --git a/plugins/tagoio-integration/src/front/Auth/Otp/Otp.tsx b/plugins/tagoio-integration/src/front/Auth/Otp/Otp.tsx new file mode 100644 index 00000000..f62cb935 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Otp/Otp.tsx @@ -0,0 +1,154 @@ +import { Button, EButton, FormGroup, Input } from "@tago-io/tcore-console"; +import { + type KeyboardEvent, + type MouseEvent, + useCallback, + useState, +} from "react"; +import * as Style from "./Otp.style"; + +/** + * Props. + */ +interface IOtpProps { + type: any; + typesEnabled: any[]; + phone?: string; + loading: boolean; + invalidCredentials?: boolean; + onGoToOtpTypes: () => void; + onGoToCredentials: () => void; + onLogin: (pinCode?: string) => void; +} + +/** + */ +function Otp(props: IOtpProps) { + const [pinCode, setPinCode] = useState(""); + const { + type, + invalidCredentials, + loading, + typesEnabled, + onGoToCredentials, + onLogin, + onGoToOtpTypes, + phone, + } = props; + + /** + * Renders the description of the selected type. + */ + const renderDescription = useCallback(() => { + if (type === "authenticator") { + return ( + + Your app will display an authentication code. + + ); + } + if (type === "sms") { + return ( + + We sent you a SMS with the authentication code to your phone + {phone}. It can take up to 1 minute to arrive. + + ); + } + return ( + + We sent you an authentication code to your email, it may take a + minute to arrive. + + ); + }, [phone, type]); + + /** + * Goes to the otp type selector. + */ + const pickAnotherType = useCallback( + (e: MouseEvent) => { + e.preventDefault(); + onGoToOtpTypes(); + }, + [onGoToOtpTypes], + ); + + /** + * Signs out. + */ + const signOut = useCallback( + (e: MouseEvent) => { + e.preventDefault(); + onGoToCredentials(); + }, + [onGoToCredentials], + ); + + /** + * Tries to log in. + */ + const login = useCallback(() => { + onLogin(pinCode); + }, [pinCode, onLogin]); + + /** + * Called when the input receives a keydown event. + */ + const onKeyDown = useCallback( + (e: KeyboardEvent) => { + if (e.key === "Enter") { + login(); + } + }, + [login], + ); + + return ( + +
+
+

Two-factor Authentication

+
{renderDescription()}
+
+ + + Sign out + +
+ + + setPinCode(e.target.value)} + onKeyDown={onKeyDown} + placeholder="6-digit code" + value={pinCode} + /> + + + + + + + {(typesEnabled.length > 1 || type !== "authenticator") && ( +
+ Haven't received a code? + + Send one again + + . +
+ )} +
+ ); +} + +export default Otp; diff --git a/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.style.ts b/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.style.ts new file mode 100644 index 00000000..256baf3e --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.style.ts @@ -0,0 +1,55 @@ +import styled from "styled-components"; + +export const Container = styled.div` + transition: opacity 0.15s; + width: 400px; + margin: auto; + + .title-container { + display: flex; + align-items: center; + margin-bottom: 1rem; + + h3 { + font-size: 1.6rem; + margin-bottom: 5px; + flex: 1; + } + } +`; + +export const Item = styled.div` + padding: 10px 20px; + display: flex; + align-items: center; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 5px; + margin-bottom: 5px; + cursor: pointer; + background: white; + + &:last-child { + margin-bottom: 0px; + } + + > .data { + flex: 1; + display: flex; + align-items: center; + + .icon-container { + width: 20px; + margin-right: 20px; + display: flex; + align-items: center; + justify-content: center; + } + } + + &:hover { + background: rgba(0, 0, 0, 0.05); + } + &:active { + background: rgba(0, 0, 0, 0.1); + } +`; diff --git a/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.tsx b/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.tsx new file mode 100644 index 00000000..83096701 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/OtpPicker/OtpPicker.tsx @@ -0,0 +1,83 @@ +import { EIcon, FormGroup, Icon } from "@tago-io/tcore-console"; +import { type MouseEvent, useCallback } from "react"; +import * as Style from "./OtpPicker.style"; + +/** + * Props. + */ +interface IOtpPickerProps { + types: any[]; + onPick: (value: any) => void; + onGoBack: () => void; +} + +/** + */ +function OtpPicker(props: IOtpPickerProps) { + const { types, onPick, onGoBack } = props; + + /** + */ + const renderType = useCallback( + (type: any) => { + let icon = EIcon.lock; + let text = ""; + + if (type === "authenticator") { + icon = EIcon.key; + text = "Authenticator"; + } else if (type === "sms") { + icon = EIcon.key; + text = "SMS"; + } else if (type === "email") { + icon = EIcon.envelope; + text = "Email"; + } + + return ( + onPick(type)}> +
+
+ +
+ {text} +
+ + +
+ ); + }, + [onPick], + ); + + /** + * Goes back to the OTP page. + */ + const goBack = useCallback( + (e: MouseEvent) => { + e.preventDefault(); + onGoBack(); + }, + [onGoBack], + ); + + return ( + +
+

Request a new code

+
+ + {types.map(renderType)} + +
+ Or + + type the code again + + . +
+
+ ); +} + +export default OtpPicker; diff --git a/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.style.ts b/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.style.ts new file mode 100644 index 00000000..7fa7712a --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.style.ts @@ -0,0 +1,45 @@ +import styled, { css } from "styled-components"; + +export const Container = styled.div<{ loading: boolean }>` + transition: opacity 0.15s; + width: 400px; + margin: auto; + + .title-container { + display: flex; + align-items: center; + + h3 { + font-size: 1.6rem; + margin-bottom: 5px; + flex: 1; + } + } + + .item { + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.05); + border-radius: 5px; + padding: 10px; + cursor: pointer; + + &:not(:last-child) { + margin-bottom: 5px; + } + + &:hover { + background: rgba(0, 0, 0, 0.05); + } + + &:active { + background: rgba(0, 0, 0, 0.1); + } + } + + ${(props) => + props.loading && + css` + opacity: 0.5; + pointer-events: none; + `} +`; diff --git a/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.tsx b/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.tsx new file mode 100644 index 00000000..14815876 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Auth/Profiles/Profiles.tsx @@ -0,0 +1,29 @@ +import { FormGroup } from "@tago-io/tcore-console"; +import * as Style from "./Profiles.style"; + +/** + */ +function Profiles(props: any) { + const { profiles, onChooseProfile, onSignOut, loading } = props; + + return ( + + +
+

Select a Profile

+ + Sign out + +
+
+ + {profiles.map((x: any) => ( +
onChooseProfile(x.id)}> + {x.name} +
+ ))} +
+ ); +} + +export default Profiles; diff --git a/plugins/tagoio-integration/src/front/Details/Details.style.ts b/plugins/tagoio-integration/src/front/Details/Details.style.ts new file mode 100644 index 00000000..05e26d86 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Details/Details.style.ts @@ -0,0 +1,151 @@ +import { theme } from "@tago-io/tcore-console"; +import styled, { css, keyframes } from "styled-components"; + +const opacity = keyframes` + from { opacity: 0 }; + to { opacity: 1 }; +`; + +export const Container = styled.div` + height: 100%; + width: 100%; + border: 0; + display: flex; + flex-direction: column; + flex: 1; + background: white; + animation: ${opacity} 0.2s forwards; + + .eye { + position: absolute; + right: 20px; + top: calc(40% - 0px); + translate(0%, -50%); + padding: 3px 5px; + display: flex; + border-radius: 5px; + cursor: pointer; + z-index: 111; + + &:hover { + background: rgba(0, 0, 0, 0.1); + } + &:active { + background: rgba(0, 0, 0, 0.15); + } + } + + .inner-profile { + display: flex; + + input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + button { + white-space: nowrap; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + .connected-container { + display: flex; + align-items: center; + + .ball { + width: 12px; + height: 12px; + background: ${(props) => + props.connected + ? theme.lightTheme.buttonSuccess + : theme.lightTheme.buttonDanger}; + margin-right: 5px; + border-radius: 50%; + } + } + + .active-container { + display: flex; + margin-left: 15px; + padding-left: 15px; + border-left: 1px solid rgba(0, 0, 0, 0.1); + align-items: center; + } + + > .content { + flex: 1; + display: flex; + flex-direction: column; + padding: 15px; + overflow: hidden; + + .table-container { + flex: 1; + overflow: hidden; + + .table { + overflow: auto; + + .data b { + background: rgba(0, 0, 0, 0.1); + border-radius: 3px; + padding: 1px 5px; + margin: 0px 2px; + } + + .data:nth-child(odd) { + background: rgba(0, 0, 0, 0.05); + } + } + + > div { + flex: 1; + height: 100%; + display: flex; + flex-direction: column; + } + } + + .table { + width: 100%; + border-radius: 5px; + border: 1px solid rgba(0, 0, 0, 0.1); + overflow: auto; + flex: 1; + transition: opacity 0.2s; + position: relative; + + > .header { + font-weight: bold; + display: flex; + + > span { + padding: 10px; + flex: 1; + background: rgba(0, 0, 0, 0.05); + } + } + + > .data { + display: flex; + + > span { + padding: 10px; + flex: 1; + margin-top: -1px; + } + } + } + } + + ${(props) => + !props.enabled && + css` + .table { + background: rgba(0, 0, 0, 0.07); + opacity: 0.7; + } + `} +`; diff --git a/plugins/tagoio-integration/src/front/Details/Details.tsx b/plugins/tagoio-integration/src/front/Details/Details.tsx new file mode 100644 index 00000000..29fb9405 --- /dev/null +++ b/plugins/tagoio-integration/src/front/Details/Details.tsx @@ -0,0 +1,306 @@ +import { + Button, + Col, + EButton, + EIcon, + EmptyMessage, + Footer, + FormGroup, + Icon, + InnerNav, + Input, + Row, + Switch, + Tooltip, +} from "@tago-io/tcore-console"; +import axios from "axios"; +import { useCallback, useEffect, useRef, useState } from "react"; +import { io } from "socket.io-client"; +import { useTheme } from "styled-components"; +import * as Style from "./Details.style"; + +const imgDesert = require("../../../assets/desert.png"); + +/** + * Props. + */ +interface IDetailsProps { + tcore: any; + port: number; + onSignOut: () => Promise; +} + +/** + */ +function Details(props: IDetailsProps) { + const [active, setActive] = useState(props.tcore.active); + const [signingOut, setSigningOut] = useState(false); + const [connected, setConnected] = useState(active && window.navigator.onLine); + const [effective, setEffective] = useState(active); + const [events, setEvents] = useState([]); + const [ipVisible, setIPVisible] = useState(false); + const socket = useRef(null); + + const theme = useTheme() as any; + + const { onSignOut, port } = props; + + /** + * Updates tcore in the API. + */ + const updateTCoreInstance = useCallback(async () => { + const { location } = window; + await axios.put( + `${location.protocol}//${location.hostname}:${port}/tcore`, + { active }, + ); + }, [active]); + + /** + * Called when the active changes. + */ + const onChangeActive = useCallback((e: boolean) => { + setActive(e); + }, []); + + /** + * Signs out. + */ + const signOut = useCallback(async () => { + try { + setSigningOut(true); + await onSignOut(); + } finally { + setSigningOut(false); + } + }, [onSignOut]); + + /** + */ + const onEvent = useCallback( + ( + type: "send" | "receive", + ev: string, + timestamp: number, + response: any, + ) => { + let extra = ""; + if (type === "receive") { + extra = " (sent back 1 item)"; + if (Array.isArray(response)) { + extra = ` (sent back ${response.length} items)`; + } + } else { + extra = " (sent 1 item)"; + if (Array.isArray(response)) { + extra = ` (sent ${response.length} items)`; + } + } + + const event: any = { + event: ev, + response: extra, + type, + timestamp: new Date(timestamp).toISOString(), + }; + setEvents([event, ...events]); + }, + [events], + ); + + /** + */ + const onStatus = useCallback((ev: boolean) => { + setConnected(ev); + }, []); + + /** + * Saves the record. + */ + const save = useCallback(() => { + setEffective(active); + updateTCoreInstance(); + }, [active, updateTCoreInstance]); + + /** + */ + useEffect(() => { + if (effective) { + if (!socket.current) { + socket.current = io( + `${location.protocol}//${location.hostname}:${port}`, + { transports: ["websocket"] }, + ); + socket.current.connect(); + } + + socket.current.on("event", onEvent); + socket.current.on("status", onStatus); + socket.current.on("disconnect", () => onStatus(false)); + + return () => { + socket.current.off(); + }; + } + }, [port, onEvent, onStatus, effective]); + + return ( + + +
+
+ {connected && effective ? "Connected" : "Disconnected"} +
+ + {!props.tcore.cluster && ( +
+ + Active + +
+ )} + + +
+ + + + + + + + + + (x === "." ? "." : "x")) + .join("") + } + readOnly + /> + +
setIPVisible(!ipVisible)}> + +
+
+
+ + + + + + + + + + +
+ + {!props.tcore.cluster && ( + + )} +
+
+ +
+ +
+ +
+
+ Type + Timestamp +
+ + {events?.map((x: any, i: any) => ( +
+ + + {x.type === "send" ? "Sent event" : "Received event"}{" "} + + {x.event} + {x.response} + + {x.timestamp} +
+ ))} + + {events.length === 0 && + (effective ? ( + + + No activity yet. +
+ } + /> + ) : ( + + ))} +
+ +
+
+ +
+
+
+ +
+
+
+ ); +} + +export default Details; diff --git a/plugins/tagoio-integration/src/front/index.tsx b/plugins/tagoio-integration/src/front/index.tsx new file mode 100644 index 00000000..1bb21aea --- /dev/null +++ b/plugins/tagoio-integration/src/front/index.tsx @@ -0,0 +1,12 @@ +import { GlobalStyles, theme } from "@tago-io/tcore-console"; +import ReactDOM from "react-dom"; +import { ThemeProvider } from "styled-components"; +import App from "./App.tsx"; + +ReactDOM.render( + + + + , + document.getElementById("root"), +); From 7dc595ee494d7d8f662d36ff94c462efb2b39d34 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Thu, 24 Oct 2024 17:59:59 -0300 Subject: [PATCH 02/27] Changing the integration to SSE --- package-lock.json | 20 +- packages/sdk/src/Lib/Core/Core.ts | 2 +- packages/sdk/src/Types/Plugin/Plugin.types.ts | 2 +- plugins/README.md | 1 - plugins/tagoio-integration/package.json | 6 +- .../tagoio-integration/src/back/Cluster.ts | 229 ------------ plugins/tagoio-integration/src/back/Global.ts | 11 +- .../src/back/RealtimeConnection.ts | 349 ++++++++++++++++++ .../tagoio-integration/src/back/Request.ts | 2 +- plugins/tagoio-integration/src/back/Server.ts | 25 +- plugins/tagoio-integration/src/back/Socket.ts | 337 ----------------- plugins/tagoio-integration/src/back/index.ts | 178 +-------- 12 files changed, 399 insertions(+), 763 deletions(-) delete mode 100644 plugins/README.md delete mode 100644 plugins/tagoio-integration/src/back/Cluster.ts create mode 100644 plugins/tagoio-integration/src/back/RealtimeConnection.ts delete mode 100644 plugins/tagoio-integration/src/back/Socket.ts diff --git a/package-lock.json b/package-lock.json index dbb7fcef..68a370bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4165,6 +4165,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/eventsource": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", + "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/express": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", @@ -6662,6 +6669,15 @@ "node": ">=0.4.x" } }, + "node_modules/eventsource": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-2.0.2.tgz", + "integrity": "sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/expand-template": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", @@ -13744,10 +13760,12 @@ "name": "@tago-io/tagocore-plugin-tagoio-integration", "version": "0.7.0", "dependencies": { + "eventsource": "^2.0.2", "path-browserify": "1.0.1" }, "devDependencies": { - "@testing-library/user-event": "14.5.2" + "@testing-library/user-event": "14.5.2", + "@types/eventsource": "^1.1.15" } } } diff --git a/packages/sdk/src/Lib/Core/Core.ts b/packages/sdk/src/Lib/Core/Core.ts index b1de0625..15dfbb0d 100644 --- a/packages/sdk/src/Lib/Core/Core.ts +++ b/packages/sdk/src/Lib/Core/Core.ts @@ -29,7 +29,7 @@ import type { TGenericID, TGenericToken, TLiveInspectorConnectionID, -} from "../../Types.ts"; +} from "../../Types/index.ts"; import APIBridge from "../APIBridge/APIBridge.ts"; /** diff --git a/packages/sdk/src/Types/Plugin/Plugin.types.ts b/packages/sdk/src/Types/Plugin/Plugin.types.ts index 236a3790..f2b6b373 100644 --- a/packages/sdk/src/Types/Plugin/Plugin.types.ts +++ b/packages/sdk/src/Types/Plugin/Plugin.types.ts @@ -34,8 +34,8 @@ export const zPluginType = z.enum([ "service", "sidebar-button", "sidebar-footer-button", - "system-override", "sqlite", + "system-override", ]); /** diff --git a/plugins/README.md b/plugins/README.md deleted file mode 100644 index 7f7a9e1a..00000000 --- a/plugins/README.md +++ /dev/null @@ -1 +0,0 @@ -This folder contains .tcore files that will be extracted to the plugins folder during a version migration. diff --git a/plugins/tagoio-integration/package.json b/plugins/tagoio-integration/package.json index d4ffc108..dc503658 100644 --- a/plugins/tagoio-integration/package.json +++ b/plugins/tagoio-integration/package.json @@ -20,9 +20,11 @@ } }, "dependencies": { - "path-browserify": "1.0.1" + "path-browserify": "1.0.1", + "eventsource": "^2.0.2" }, "devDependencies": { - "@testing-library/user-event": "14.5.2" + "@testing-library/user-event": "14.5.2", + "@types/eventsource": "^1.1.15" } } diff --git a/plugins/tagoio-integration/src/back/Cluster.ts b/plugins/tagoio-integration/src/back/Cluster.ts deleted file mode 100644 index 45f62f71..00000000 --- a/plugins/tagoio-integration/src/back/Cluster.ts +++ /dev/null @@ -1,229 +0,0 @@ -import { core } from "@tago-io/tcore-sdk"; -import chalk from "chalk"; -import { cache } from "./Global.ts"; - -const red = chalk.redBright; -const green = chalk.green; -const yellow = chalk.yellow; - -/** - */ -async function downloadPlugin(id: string, version: string, platform: string) { - const source = `https://plugins.tagocore.com/${id}/${version}/download/${platform}`; - const start = id !== "4fb07d6c56d8f67e504dcbcf38ddc15f"; - await core.installPlugin(source, { start }); -} - -/** - */ -async function handlePluginInstall(serverPlugin: any, trimmedID: string) { - const { id, version, platform } = serverPlugin; - - const localPlugins = await core.getPluginList(); - const localPlugin = localPlugins.find((x) => x.id === id); - if (!localPlugin) { - branch("Installing plugin", yellow(trimmedID), yellow(`v${version}`)); - await downloadPlugin(id, version, platform); - return true; - } - if (localPlugin.version !== version) { - branch("Installing plugin", yellow(trimmedID), yellow(`v${version}`)); - await downloadPlugin(id, version, platform); - return true; - } -} - -function JSONstringifyInOrder(obj: any) { - const allKeys = new Set(); - JSON.stringify(obj, (key, value) => (allKeys.add(key), value)); - return JSON.stringify(obj, Array.from(allKeys).sort() as string[]); -} - -/** - */ -async function handlePluginSettings(serverPlugin: any, trimmedID: string) { - const serverModules = serverPlugin.modules || []; - const actions: any = {}; - let logged = false; - - const localPluginSettings = await core.getPluginSettings(serverPlugin.id); - - for (const serverModule of serverModules) { - const moduleID = serverModule.id; - const moduleInfo = await core.getPluginModuleInfo( - serverPlugin.id, - moduleID, - ); - const moduleSettings = localPluginSettings.modules?.find( - (x: any) => x.id === moduleID, - ); - const settingsDiffer = - JSONstringifyInOrder(moduleSettings) !== - JSONstringifyInOrder(serverModule); - if (settingsDiffer) { - if (!logged) { - logged = true; - if (moduleSettings) { - branch("Changed settings for plugin", yellow(trimmedID)); - } else { - branch("Added settings for plugin", yellow(trimmedID)); - } - } - - if (serverModule.disabled) { - if (moduleInfo?.state === "started") { - actions[moduleID] = "stop"; - } - } else { - actions[moduleID] = "restart"; - } - } else { - if ( - !serverPlugin.disabled && - moduleInfo?.error && - !serverModule.disabled - ) { - actions[moduleID] = "start"; - } - } - } - - await core.setPluginSettings(serverPlugin.id, { - disabled: localPluginSettings.disabled, - modules: serverPlugin.modules, - }); - - for (const moduleID in actions) { - if (actions[moduleID] === "start") { - branch( - green("Started"), - "plugin module", - yellow(trimmedID), - "-", - yellow(moduleID), - ); - await core.startPluginModule(serverPlugin.id, moduleID); - } else if (actions[moduleID] === "restart") { - branch( - green("Restarted"), - "plugin module", - yellow(trimmedID), - "-", - yellow(moduleID), - ); - await core.startPluginModule(serverPlugin.id, moduleID); - } else if (actions[moduleID] === "stop") { - branch( - red("Stopped"), - "plugin module", - yellow(trimmedID), - "-", - yellow(moduleID), - ); - await core.stopPluginModule(serverPlugin.id, moduleID).catch(() => null); - } - } -} - -/** - */ -async function handlePluginDisabled(serverPlugin: any, trimmedID: string) { - const settings = await core.getPluginSettings(serverPlugin.id); - - const serverDisabled = !!serverPlugin.disabled; - const localDisabled = !!settings.disabled; - - if (serverDisabled !== localDisabled) { - if (serverPlugin.disabled) { - branch("Disabled plugin", yellow(trimmedID)); - await core.disablePlugin(serverPlugin.id).catch(() => null); - } else { - branch("Enabled plugin", yellow(trimmedID)); - await core.enablePlugin(serverPlugin.id).catch(() => null); - } - } -} - -/** - */ -async function handleClusterState(clusterState: any) { - let reboot = false; - - try { - const statePlugins: any[] = clusterState?.plugins || []; - - if (clusterState === null || clusterState === undefined) { - await core.doFactoryReset(); - } - - if (clusterState?.masterPassword) { - await core.setMasterPassword(clusterState.masterPassword); - } - - if (clusterState?.databasePlugin) { - const settings = await core.getMainSettings(); - await core.setMainSettings({ - ...settings, - database_plugin: clusterState.databasePlugin, - }); - } - - for (const serverPlugin of statePlugins) { - const trimmedID = serverPlugin.id.substring(serverPlugin.id.length - 5); - await handlePluginSettings(serverPlugin, trimmedID); - const installed = await handlePluginInstall(serverPlugin, trimmedID); - await handlePluginDisabled(serverPlugin, trimmedID); - - if (installed && serverPlugin.id === "4fb07d6c56d8f67e504dcbcf38ddc15f") { - // this plugin id - reboot = true; - } - } - - const localPlugins = await core.getPluginList(); - for (const localPlugin of localPlugins) { - // SQLITE, TAGOIO INTEGRATION, PLUGIN STORE are built-ins - if ( - [ - "0810916b6ca256fb25afbe19b4f83b23", - "2e8e52b993bcfbb495f0e4b51f687d89", - "4fb07d6c56d8f67e504dcbcf38ddc15f", - "c311dfe85cf1a29fb1d86a1a2c5afc1c", - ].includes(localPlugin.id) - ) { - continue; - } - - const trimmedID = localPlugin.id.substring(localPlugin.id.length - 5); - const existsInState = statePlugins.some((x) => x.id === localPlugin.id); - if (!existsInState) { - await core.uninstallPlugin(localPlugin.id); - branch("Removed plugin", yellow(trimmedID)); - } - } - - cache.commandsQueue.forEach((x) => x.promise.resolve()); - } catch (ex: any) { - const err = ex?.message || ex?.toString?.() || ex; - cache.commandsQueue.forEach((x) => x.promise.reject(err)); - throw ex; - } finally { - cache.commandsQueue = []; - if (reboot) { - setTimeout(() => { - console.log( - "New TagoIO Integration version detected. Shutting Down cluster instance.", - ); - cache.systemModule?.exit?.(0); - }, 1000); - } - } -} - -/** - */ -function branch(...args: any[]) { - console.log("├─", ...args); -} - -export { handleClusterState }; diff --git a/plugins/tagoio-integration/src/back/Global.ts b/plugins/tagoio-integration/src/back/Global.ts index b207a8ed..d72f02c8 100644 --- a/plugins/tagoio-integration/src/back/Global.ts +++ b/plugins/tagoio-integration/src/back/Global.ts @@ -1,7 +1,6 @@ - import type { SystemModule } from "@tago-io/tcore-sdk"; -import type { Server } from "socket.io"; -import type { Socket } from "socket.io-client"; +import type EventSource from "eventsource"; + interface ICommandQueueItem { type: @@ -33,8 +32,7 @@ interface IStateQueueItem { interface IObjects { tcore: any; - socket: Socket | null; - serverIO: Server | null; + realtimeConnection: EventSource | null; commandsQueue: ICommandQueueItem[]; stateQueue: IStateQueueItem[]; systemModule: SystemModule | null; @@ -43,8 +41,7 @@ interface IObjects { const cache: IObjects = { tcore: null, - socket: null, - serverIO: null, + realtimeConnection: null, commandsQueue: [], stateQueue: [], systemModule: null, diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts new file mode 100644 index 00000000..de7b31fa --- /dev/null +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -0,0 +1,349 @@ +import os from "node:os"; +import { URLSearchParams } from "node:url"; +import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; +import type { + IDeviceDataQuery, + IDeviceListQuery, + TGenericID, +} from "@tago-io/tcore-sdk/types"; +import chalk from "chalk"; +import { type Socket, io } from "socket.io-client"; +import { cache } from "./Global.ts"; +import { getMachineID } from "./Helpers.ts"; +import EventSource from "eventsource"; + +/** + * Eventsource used to communicate with the API. + */ +let events: EventSource | null = null; + +/** + */ +function startRealtimeCommunication(token: string) { + if (!token || events) { + return; + } + + const channel = "commands"; + const params = new URLSearchParams({ token, channel }); + const url = `https://sse.tago.io/events?${params.toString()}`; + + const connect = () => { + events = new EventSource(url); + + events.onmessage = (event) => { + console.log("Received event", event); + switch (event.type) { + case "sse::commands": + console.log("Connected to TagoIO"); + break; + default: + console.error("Unknown event type", event.type); + } + + }; + + events.onerror = (error: any) => { + console.error("EventSource encountered an error:", error); + if (events) { + events.close(); + } + setTimeout(connect, 5000); + }; + }; + + connect(); + + // return new Promise((resolve, reject) => { + // console.log("Connecting..."); + + // const query = { token }; + // let connectErrors = 0; + + // socket = io(process.env.TAGOIO_REALTIME || "", { + // transports: ["websocket"], + // query, + // }); + // socket.connect(); + + // cache.socket = socket; + + // /** + // */ + // socket.on("ready", () => { + // connectErrors = 0; + // console.log("Connected to TagoIO"); + // emitStartData(); + // cache.serverIO?.emit("status", cache.socket?.connected); + // }); + + // /** + // */ + // socket.on("disconnect", () => { + // console.log(chalk.redBright("[ERROR]"), "Unexpected disconnection"); + // cache.serverIO?.emit("status", cache.socket?.connected); + // cache.attachedDevices = []; + + // if (process.env.TCORE_CLUSTER_TOKEN) { + // // if the promise is still active the reject will make sure that + // // the other side receives an error and cancels the execution flow + // reject(); + // } else { + // // if the tcore was deleted without this instance logging out we need + // // to resolve the connection normally for the user to try again + // resolve(); + // } + // }); + + // /** + // */ + // socket.on("connect_error", () => { + // connectErrors += 1; + // console.log( + // chalk.redBright("[ERROR]"), + // `Connect error (${connectErrors}/3).`, + // ); + + // cache.serverIO?.emit("status", cache.socket?.connected); + // cache.attachedDevices = []; + + // if (connectErrors >= 3 || !process.env.TCORE_CLUSTER_TOKEN) { + // connectErrors = 0; + // socket?.disconnect(); + // reject(); + // } + // }); + + // /** + // */ + // socket.on("tcore::instance", (tcore) => { + // cache.tcore = tcore; + // if (!process.env.TCORE_CLUSTER_TOKEN) { + // resolve(); + // } + // }); + + // /** + // */ + // socket.on("tcore::action::schedule", (connID: string) => { + // call("tcore::action::schedule", connID, async () => { + // await core.triggerActionScheduleCheck(); + // await core.triggerDeviceDataRetentionCheck(); + // }); + // }); + + // /** + // */ + // socket.on("tcore::cluster::busy", (connID: string) => { + // call("tcore::cluster::busy", connID, async () => { + // const message = + // "Cluster is busy executing another action. Try again later."; + // cache.commandsQueue.forEach((x) => x.promise.reject(message)); + // cache.commandsQueue = []; + // }); + // }); + + // /** + // */ + // socket.on("tcore::cluster::state", async (connID, state, options) => { + // if (cache.stateQueue.length > 0) { + // // already has a state in the queue, add to the queue and wait + // cache.stateQueue.push({ connID, state, options }); + // } else { + // // no state in queue, run it right now + // cache.stateQueue.push({ connID, state, options }); + // await checkStateQueue(); + // resolve(); + // } + // }); + + // /** + // */ + // socket.on( + // "tcore::device::data::added", + // async (connID, deviceToken, data) => { + // call("tcore::device::data::added", connID, async () => { + // const device = await core.getDeviceByToken(deviceToken); + // if (device) { + // await core.addDeviceData(device.id, data).catch(() => null); + // } + // }); + // }, + // ); + + // /** + // * Called when the realtime server requests a device list on this instance. + // */ + // socket.on( + // "tcore::device::list", + // async (connID, query: IDeviceListQuery) => { + // call("tcore::device::list", connID, async () => { + // query.fields = (query.fields || []).filter( + // (x: string) => x !== "bucket", + // ); + // const list = await core.getDeviceList(query); + // return list; + // }); + // }, + // ); + + // /** + // * Called when the realtime server requests a device info on this instance. + // */ + // socket.on("tcore::device::info", async (connID, deviceID: TGenericID) => { + // call("tcore::device::info", connID, async () => { + // const info = await core.getDeviceInfo(deviceID); + // return info; + // }); + // }); + + // /** + // * Called when the realtime server requests data from this instance. + // */ + // socket.on( + // "tcore::device::data", + // async (connID, deviceID: TGenericID, query: IDeviceDataQuery) => { + // call("tcore::device::data", connID, async () => { + // const data = await core.getDeviceData(deviceID, query); + // return data; + // }); + // }, + // ); + + // /** + // */ + // socket.on("tcore::summary", async (connID) => { + // call("tcore::summary", connID, () => core.getSummary()); + // }); + + // /** + // * Called when someone enters a dashboard with this device in a widget. + // */ + // socket.on("tcore::data::attach", async (deviceID) => { + // cache.attachedDevices.push(deviceID); + // }); + + // /** + // * Called when someone leaves a dashboard with this device in a widget. + // */ + // socket.on("tcore::data::unattach", async (deviceID) => { + // const i = cache.attachedDevices.indexOf(deviceID); + // if (i >= 0) { + // cache.attachedDevices.splice(i, 1); + // } + // }); + + // /** + // */ + // socket.on("tcore::summary-and-computer-usage", async (connID) => { + // call("tcore::summary-and-computer-usage", connID, async () => { + // const data = await Promise.all([ + // core.getSummary(), + // helpers.getComputerUsage(), + // ]); + // return { summary: data[0], computer_usage: data[1] }; + // }); + // }); + // }); +} + +/** + */ +function closeRealtimeConnection() { + events?.close(); + events = null; +} + +/** + * Calls a procedure. + */ +async function call(event: string, connID: string, fn: Function) { + try { + console.log(`• Received ${chalk.cyanBright(event)} event`); + const promise = fn(); + const result = await promise; + cache.serverIO?.emit("event", "receive", event, Date.now(), result); + socket?.emit("tcore::response::success", connID, result); + console.log("└─", chalk.green("[DONE]"), "Handled event"); + } catch (ex: any) { + const err = ex?.message || ex; + console.log("└─", chalk.redBright("[ERROR]"), err); + socket?.emit("tcore::response::error", connID, err); + } +} + +/** + * Emits a ping event to the API. + */ +// async function emitStartData() { +// const systemStartTime = new Date(Date.now() - os.uptime() * 1000); +// const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); +// const osInfo = await helpers.getOSInfo(); + +// socket?.emit("tcore::start", { +// machine_id: getMachineID(), +// local_ips: getLocalIPs().join(", "), +// name: os.hostname(), +// os: osInfo, +// system_start_time: systemStartTime, +// tcore_start_time: tcoreStartTime, +// tcore_version: "0.7.0", +// }); +// } + +/** + * TODO + */ +async function checkStateQueue() { + for (const item of cache.stateQueue) { + const isRollback = item.options?.rollback; + const error = item.options?.error; + const event = `tcore::cluster::state${isRollback ? "::rollback" : ""}`; + + if (isRollback) { + const message = `Rolling back due to error in one of the Cluster instances: ${error}`; + cache.systemModule?.emitInstallLog({ error: true, message }); + } + + await call(event, item.connID, async () => { + if (isRollback) { + console.log( + "├─", + chalk.cyanBright("[ROLLBACK]"), + "due to error", + chalk.redBright(error), + ); + } + }); + } + + cache.stateQueue = []; +} + +/** + * TODO + */ +function getLocalIPs() { + const interfaces = os.networkInterfaces(); + const addresses: string[] = []; + + for (const name of Object.keys(interfaces)) { + for (const tmp of interfaces[name] || []) { + const { address, family, internal } = tmp; + if (family === "IPv4" && !internal) { + addresses.push(address); + } + } + } + + return addresses; +} + +/** + * TODO + */ +function isConnectedToAPI() { + return true; +} + +export { closeRealtimeConnection, startRealtimeCommunication, isConnectedToAPI }; diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index 9aa808f0..7ded3d74 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -20,7 +20,7 @@ async function listTCoresByMachineID(token: string) { */ async function updateTCore(token: string, tcoreID: string, data: any) { const account = new Account({ token, region: "env" }); - const response = await account.tagocores.edit(tcoreID, data); + const response = await account.tagocore.edit(tcoreID, data); return response; } diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts index 2c477b7b..0a5fbbcc 100644 --- a/plugins/tagoio-integration/src/back/Server.ts +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -10,7 +10,7 @@ import pkg from "../../package.json" with { type: "json" }; import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; import { createTCore, listTCoresByMachineID, updateTCore } from "./Request.ts"; -import { closeSocket, initSocket } from "./Socket.ts"; +import { closeRealtimeConnection, startRealtimeCommunication } from "./RealtimeConnection.ts"; let server: http.Server | null = null; @@ -28,11 +28,6 @@ function initServer() { app.get("/tcore", routeGetTCore); app.put("/tcore", (req, res) => { - if (req.body.active) { - cache.socket?.connect(); - } else { - cache.socket?.disconnect(); - } if (cache.tcore) { cache.tcore.active = !!req.body.active; } @@ -43,12 +38,12 @@ function initServer() { server = http.createServer(app); server.listen("8999"); - cache.serverIO = new Server(server); - cache.serverIO.on("connection", () => { - if (cache.socket) { - cache.serverIO?.emit("status", cache.socket.connected); - } - }); + // cache.serverIO = new Server(server); + // cache.serverIO.on("connection", () => { + // if (cache.socket) { + // cache.serverIO?.emit("status", cache.socket.connected); + // } + // }); } /** @@ -74,7 +69,7 @@ function routeGetTCore(req: Request, res: Response) { */ async function routeSignOut(req: Request, res: Response) { await pluginStorage.delete("token"); - closeSocket(); + closeRealtimeConnection(); cache.tcore = null; res.sendStatus(200); } @@ -93,7 +88,7 @@ async function routeStartTCore(req: Request, res: Response) { if (item?.token) { await updateTCore(profileToken, item.id, { name: req.body.name }); await pluginStorage.set("token", item?.token); - await initSocket(item?.token); + await startRealtimeCommunication(item?.token); res.sendStatus(200); return; } @@ -112,7 +107,7 @@ async function routeStartTCore(req: Request, res: Response) { if (data) { await pluginStorage.set("token", data?.token); - await initSocket(data?.token); + await startRealtimeCommunication(data?.token); res.sendStatus(200); } } diff --git a/plugins/tagoio-integration/src/back/Socket.ts b/plugins/tagoio-integration/src/back/Socket.ts deleted file mode 100644 index 8e7a7be4..00000000 --- a/plugins/tagoio-integration/src/back/Socket.ts +++ /dev/null @@ -1,337 +0,0 @@ -import os from "node:os"; -import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; -import type { - IDeviceDataQuery, - IDeviceListQuery, - TGenericID, -} from "@tago-io/tcore-sdk/types"; -import chalk from "chalk"; -import { type Socket, io } from "socket.io-client"; -import { handleClusterState } from "./Cluster.ts"; -import { cache } from "./Global.ts"; -import { getMachineID } from "./Helpers.ts"; - -/** - * Socket used to communicate with the API. - */ -let socket: Socket | null; - -if (!process.env.TCORE_CLUSTER_TOKEN) { - setInterval( - async () => { - const token = await pluginStorage.get("token").catch(() => null); - if (token && socket && socket?.disconnected) { - const tokenEnd = token.substring(token.length - 5); - console.log( - "Trying to reconnect using token ending in", - chalk.yellow(tokenEnd), - ); - socket?.connect(); - } - }, - 1000 * 60 * 5, - ); -} - -/** - */ -function initSocket(token: string) { - if (!token || socket) { - return; - } - - return new Promise((resolve, reject) => { - console.log("Connecting..."); - - const query = { token }; - let connectErrors = 0; - - socket = io(process.env.TAGOIO_REALTIME || "", { - transports: ["websocket"], - query, - }); - socket.connect(); - - cache.socket = socket; - - /** - */ - socket.on("ready", () => { - connectErrors = 0; - console.log("Connected to TagoIO"); - emitStartData(); - cache.serverIO?.emit("status", cache.socket?.connected); - }); - - /** - */ - socket.on("disconnect", () => { - console.log(chalk.redBright("[ERROR]"), "Unexpected disconnection"); - cache.serverIO?.emit("status", cache.socket?.connected); - cache.attachedDevices = []; - - if (process.env.TCORE_CLUSTER_TOKEN) { - // if the promise is still active the reject will make sure that - // the other side receives an error and cancels the execution flow - reject(); - } else { - // if the tcore was deleted without this instance logging out we need - // to resolve the connection normally for the user to try again - resolve(); - } - }); - - /** - */ - socket.on("connect_error", () => { - connectErrors += 1; - console.log( - chalk.redBright("[ERROR]"), - `Connect error (${connectErrors}/3).`, - ); - - cache.serverIO?.emit("status", cache.socket?.connected); - cache.attachedDevices = []; - - if (connectErrors >= 3 || !process.env.TCORE_CLUSTER_TOKEN) { - connectErrors = 0; - socket?.disconnect(); - reject(); - } - }); - - /** - */ - socket.on("tcore::instance", (tcore) => { - cache.tcore = tcore; - if (!process.env.TCORE_CLUSTER_TOKEN) { - resolve(); - } - }); - - /** - */ - socket.on("tcore::action::schedule", (connID: string) => { - call("tcore::action::schedule", connID, async () => { - await core.triggerActionScheduleCheck(); - await core.triggerDeviceDataRetentionCheck(); - }); - }); - - /** - */ - socket.on("tcore::cluster::busy", (connID: string) => { - call("tcore::cluster::busy", connID, async () => { - const message = - "Cluster is busy executing another action. Try again later."; - cache.commandsQueue.forEach((x) => x.promise.reject(message)); - cache.commandsQueue = []; - }); - }); - - /** - */ - socket.on("tcore::cluster::state", async (connID, state, options) => { - if (cache.stateQueue.length > 0) { - // already has a state in the queue, add to the queue and wait - cache.stateQueue.push({ connID, state, options }); - } else { - // no state in queue, run it right now - cache.stateQueue.push({ connID, state, options }); - await checkStateQueue(); - resolve(); - } - }); - - /** - */ - socket.on( - "tcore::device::data::added", - async (connID, deviceToken, data) => { - call("tcore::device::data::added", connID, async () => { - const device = await core.getDeviceByToken(deviceToken); - if (device) { - await core.addDeviceData(device.id, data).catch(() => null); - } - }); - }, - ); - - /** - * Called when the realtime server requests a device list on this instance. - */ - socket.on( - "tcore::device::list", - async (connID, query: IDeviceListQuery) => { - call("tcore::device::list", connID, async () => { - query.fields = (query.fields || []).filter( - (x: string) => x !== "bucket", - ); - const list = await core.getDeviceList(query); - return list; - }); - }, - ); - - /** - * Called when the realtime server requests a device info on this instance. - */ - socket.on("tcore::device::info", async (connID, deviceID: TGenericID) => { - call("tcore::device::info", connID, async () => { - const info = await core.getDeviceInfo(deviceID); - return info; - }); - }); - - /** - * Called when the realtime server requests data from this instance. - */ - socket.on( - "tcore::device::data", - async (connID, deviceID: TGenericID, query: IDeviceDataQuery) => { - call("tcore::device::data", connID, async () => { - const data = await core.getDeviceData(deviceID, query); - return data; - }); - }, - ); - - /** - */ - socket.on("tcore::summary", async (connID) => { - call("tcore::summary", connID, () => core.getSummary()); - }); - - /** - * Called when someone enters a dashboard with this device in a widget. - */ - socket.on("tcore::data::attach", async (deviceID) => { - cache.attachedDevices.push(deviceID); - }); - - /** - * Called when someone leaves a dashboard with this device in a widget. - */ - socket.on("tcore::data::unattach", async (deviceID) => { - const i = cache.attachedDevices.indexOf(deviceID); - if (i >= 0) { - cache.attachedDevices.splice(i, 1); - } - }); - - /** - */ - socket.on("tcore::summary-and-computer-usage", async (connID) => { - call("tcore::summary-and-computer-usage", connID, async () => { - const data = await Promise.all([ - core.getSummary(), - helpers.getComputerUsage(), - ]); - return { summary: data[0], computer_usage: data[1] }; - }); - }); - }); -} - -/** - */ -function closeSocket() { - socket?.off(); - socket?.disconnect?.(); - socket = null; -} - -/** - * Calls a procedure. - */ -async function call(event: string, connID: string, fn: Function) { - try { - console.log(`• Received ${chalk.cyanBright(event)} event`); - const promise = fn(); - const result = await promise; - cache.serverIO?.emit("event", "receive", event, Date.now(), result); - socket?.emit("tcore::response::success", connID, result); - console.log("└─", chalk.green("[DONE]"), "Handled event"); - } catch (ex: any) { - const err = ex?.message || ex; - console.log("└─", chalk.redBright("[ERROR]"), err); - socket?.emit("tcore::response::error", connID, err); - } -} - -/** - * Emits a ping event to the API. - */ -async function emitStartData() { - const systemStartTime = new Date(Date.now() - os.uptime() * 1000); - const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); - const osInfo = await helpers.getOSInfo(); - - socket?.emit("tcore::start", { - machine_id: getMachineID(), - local_ips: getLocalIPs().join(", "), - name: os.hostname(), - os: osInfo, - system_start_time: systemStartTime, - tcore_start_time: tcoreStartTime, - tcore_version: "0.7.0", - }); -} - -/** - * TODO - */ -async function checkStateQueue() { - for (const item of cache.stateQueue) { - const isRollback = item.options?.rollback; - const error = item.options?.error; - const event = `tcore::cluster::state${isRollback ? "::rollback" : ""}`; - - if (isRollback) { - const message = `Rolling back due to error in one of the Cluster instances: ${error}`; - cache.systemModule?.emitInstallLog({ error: true, message }); - } - - await call(event, item.connID, async () => { - if (isRollback) { - console.log( - "├─", - chalk.cyanBright("[ROLLBACK]"), - "due to error", - chalk.redBright(error), - ); - } - await handleClusterState(item.state); - }); - } - - cache.stateQueue = []; -} - -/** - * TODO - */ -function getLocalIPs() { - const interfaces = os.networkInterfaces(); - const addresses: string[] = []; - - for (const name of Object.keys(interfaces)) { - for (const tmp of interfaces[name] || []) { - const { address, family, internal } = tmp; - if (family === "IPv4" && !internal) { - addresses.push(address); - } - } - } - - return addresses; -} - -/** - * TODO - */ -function isConnectedToAPI() { - return true; -} - -export { closeSocket, initSocket, isConnectedToAPI }; diff --git a/plugins/tagoio-integration/src/back/index.ts b/plugins/tagoio-integration/src/back/index.ts index 25d5afda..59f288bd 100644 --- a/plugins/tagoio-integration/src/back/index.ts +++ b/plugins/tagoio-integration/src/back/index.ts @@ -3,7 +3,7 @@ import { HookModule, NavbarButtonModule, PageModule, pluginStorage, SystemModule import { cache } from "./Global.ts"; import { logError } from "./Log.ts"; import { closeServer, initServer } from "./Server.ts"; -import { initSocket } from "./Socket.ts"; +import { startRealtimeCommunication } from "./RealtimeConnection.ts"; let started = false; @@ -23,30 +23,11 @@ async function init() { } initServer(); - if (process.env.TCORE_CLUSTER_TOKEN) { - // cluster start - try { - started = true; - await initSocket(process.env.TCORE_CLUSTER_TOKEN); - } catch (ex) { - logError("These are the possible causes for the disconnect:"); - logError(" • Invalid TagoCore Cluster token"); - logError(" • No connection to TagoIO servers"); - logError( - " • You exceeded the maximum amount of TagoCore instances in your TagoIO Profile", - ); - logError("Verify all these possible issues and try again."); - await new Promise((resolve) => setTimeout(resolve, 200)); - await cache.systemModule?.exit?.(0); - } - } else { - // non-cluster start - await cleanUpOldStructure().catch(() => null); + await cleanUpOldStructure().catch(() => null); - const normalToken = await pluginStorage.get("token").catch(() => null); - if (normalToken) { - await initSocket(normalToken); - } + const normalToken = await pluginStorage.get("token").catch(() => null); + if (normalToken) { + await startRealtimeCommunication(normalToken); } } @@ -57,128 +38,6 @@ async function onPluginDestroy() { started = false; } -/** - */ -function onInstallStorePlugin(id: string, version: string, platform: any) { - const promise = new Promise((resolve, reject) => { - const type = "install"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { - type, - data: { platform, id, version }, - }); - }); - return promise; -} - -/** - */ -function onUninstallStorePlugin(id: string) { - const promise = new Promise((resolve, reject) => { - const type = "uninstall"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { id } }); - }); - return promise; -} - -/** - */ -function onEditModuleSettings(id: string, settings: any) { - const promise = new Promise((resolve, reject) => { - const type = "settings"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { id, settings } }); - }); - return promise; -} - -/** - */ -function onDisablePlugin(id: string) { - const promise = new Promise((resolve, reject) => { - const type = "disable"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { id } }); - }); - return promise; -} - -/** - */ -function onEnablePlugin(id: string) { - const promise = new Promise((resolve, reject) => { - const type = "enable"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { id } }); - }); - return promise; -} - -/** - */ -function onStartPluginModule(pluginID: string, moduleID: string) { - const promise = new Promise((resolve, reject) => { - const type = "startModule"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { - type, - data: { pluginID, moduleID }, - }); - }); - return promise; -} - -/** - */ -function onStopPluginModule(pluginID: string, moduleID: string) { - const promise = new Promise((resolve, reject) => { - const type = "stopModule"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { - type, - data: { pluginID, moduleID }, - }); - }); - return promise; -} - -/** - */ -function onSetMasterPassword(password: string) { - const promise = new Promise((resolve, reject) => { - const type = "setMasterPassword"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { password } }); - }); - return promise; -} - -/** - */ -function onSetDatabasePlugin(databasePlugin: string) { - const promise = new Promise((resolve, reject) => { - const type = "setDatabasePlugin"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { - type, - data: { databasePlugin }, - }); - }); - return promise; -} - -/** - */ -function onFactoryReset(password: string) { - const promise = new Promise((resolve, reject) => { - const type = "factoryReset"; - cache.commandsQueue.push({ type, promise: { resolve, reject } }); - cache.socket?.emit("tcore::message:add", { type, data: { password } }); - }); - return promise; -} - /* * Hook module to listen to data events and then send * the data to the server's realtime. @@ -192,9 +51,9 @@ hookModule.onMainDatabaseModuleLoaded = init; hookModule.onAfterInsertDeviceData = async (deviceID, data) => { if (cache.attachedDevices.includes(deviceID)) { - const event = "tcore::device::data::add"; - cache.serverIO?.emit("event", "send", event, Date.now(), data); - cache.socket?.emit(event, deviceID, data); + // const event = "tcore::device::data::add"; + // cache.serverIO?.emit("event", "send", event, Date.now(), data); + // cache.socket?.emit(event, deviceID, data); } }; @@ -218,25 +77,8 @@ const assetsPage = new PageModule({ name: "Details page", }); -if (process.env.TCORE_CLUSTER_TOKEN) { - const systemModule: any = new SystemModule({ id: "system" }); - systemModule.onLoad = init; - systemModule.onDestroy = onPluginDestroy; - systemModule.onInstallStorePlugin = onInstallStorePlugin; - systemModule.onUninstallStorePlugin = onUninstallStorePlugin; - systemModule.onEditModuleSettings = onEditModuleSettings; - systemModule.onDisablePlugin = onDisablePlugin; - systemModule.onEnablePlugin = onEnablePlugin; - systemModule.onStartPluginModule = onStartPluginModule; - systemModule.onStopPluginModule = onStopPluginModule; - systemModule.onSetMasterPassword = onSetMasterPassword; - systemModule.onSetDatabasePlugin = onSetDatabasePlugin; - systemModule.onFactoryReset = onFactoryReset; - cache.systemModule = systemModule; -} else { - assetsPage.onLoad = init; - assetsPage.onDestroy = onPluginDestroy; -} +assetsPage.onLoad = init; +assetsPage.onDestroy = onPluginDestroy; new NavbarButtonModule({ id: "navbar-button", From f83638f0ef27748004c96a3b3081cfebf973a739 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Fri, 25 Oct 2024 17:54:23 -0300 Subject: [PATCH 03/27] Changing the integration to SSE --- .../src/back/RealtimeConnection.ts | 363 +++++------------- .../tagoio-integration/src/back/Request.ts | 18 +- plugins/tagoio-integration/src/back/Server.ts | 7 - plugins/tagoio-integration/src/back/index.ts | 2 + 4 files changed, 110 insertions(+), 280 deletions(-) diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts index de7b31fa..a4b61aba 100644 --- a/plugins/tagoio-integration/src/back/RealtimeConnection.ts +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -1,16 +1,10 @@ import os from "node:os"; import { URLSearchParams } from "node:url"; -import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; -import type { - IDeviceDataQuery, - IDeviceListQuery, - TGenericID, -} from "@tago-io/tcore-sdk/types"; -import chalk from "chalk"; -import { type Socket, io } from "socket.io-client"; +import { core, helpers } from "@tago-io/tcore-sdk"; import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; import EventSource from "eventsource"; +import { sendDataToTagoio } from "./Request.ts"; /** * Eventsource used to communicate with the API. @@ -31,14 +25,82 @@ function startRealtimeCommunication(token: string) { const connect = () => { events = new EventSource(url); - events.onmessage = (event) => { + events.onmessage = async (event) => { console.log("Received event", event); - switch (event.type) { + switch (event.data.channel) { case "sse::commands": - console.log("Connected to TagoIO"); + console.info("Connected to TagoIO"); + emitStartData(token, event.data.connID); break; + case "sse::instance": + cache.tcore = event.data.tcore; + break; + case "sse::action::schedule": { + const schedule = await core.triggerActionScheduleCheck(); + const dataRetentions = await core.triggerDeviceDataRetentionCheck(); + const response = await sendDataToTagoio(token, { schedule, dataRetentions }, event.data.connID, ""); + console.info("Schedule sent", response); + break; + } + case "sse::device::data::added": { + const device = await core.getDeviceByToken(event.data.deviceToken); + let result: any = null; + if (device) { + result = await core.addDeviceData(device.id, event.data.deviceData).catch(() => null); + } + const response = await sendDataToTagoio(token, result, event.data.connID, ""); + console.info("Data added", response); + break; + } + case "sse::device::list": { + event.data.query.fields = (event.data.query.fields || []).filter( + (x: string) => x !== "bucket", + ); + const list = await core.getDeviceList(event.data.query); + const response = await sendDataToTagoio(token, list, event.data.connID, ""); + console.info("Device list sent", response); + break; + } + case "sse::device::info": { + const info = await core.getDeviceInfo(event.data.deviceID); + const response = await sendDataToTagoio(token, info, event.data.connID, ""); + console.info("Device info sent", response); + break; + } + case "sse::device::data": { + const data = await core.getDeviceData(event.data.deviceID, event.data.query); + const response = await sendDataToTagoio(token, data, event.data.connID, ""); + console.info("Device data sent", response); + break; + } + case "sse::summary": { + const summary = await core.getSummary(); + const response = await sendDataToTagoio(token, summary, event.data.connID, ""); + console.info("Summary sent", response); + break; + } + case "sse::data::attach": { + cache.attachedDevices.push(event.data.deviceID); + break; + } + case "sse::data::unattach": { + const i = cache.attachedDevices.indexOf(event.data.deviceID); + if (i >= 0) { + cache.attachedDevices.splice(i, 1); + } + break; + } + case "sse::summary-and-computer-usage": { + const data = await Promise.all([ + core.getSummary(), + helpers.getComputerUsage(), + ]); + const response = await sendDataToTagoio(token, { summary: data[0], computer_usage: data[1] }, event.data.connID, ""); + console.info("Summary and Computer Usage sent", response); + break; + } default: - console.error("Unknown event type", event.type); + console.error("Unknown event channel", event.data.channel); } }; @@ -53,198 +115,6 @@ function startRealtimeCommunication(token: string) { }; connect(); - - // return new Promise((resolve, reject) => { - // console.log("Connecting..."); - - // const query = { token }; - // let connectErrors = 0; - - // socket = io(process.env.TAGOIO_REALTIME || "", { - // transports: ["websocket"], - // query, - // }); - // socket.connect(); - - // cache.socket = socket; - - // /** - // */ - // socket.on("ready", () => { - // connectErrors = 0; - // console.log("Connected to TagoIO"); - // emitStartData(); - // cache.serverIO?.emit("status", cache.socket?.connected); - // }); - - // /** - // */ - // socket.on("disconnect", () => { - // console.log(chalk.redBright("[ERROR]"), "Unexpected disconnection"); - // cache.serverIO?.emit("status", cache.socket?.connected); - // cache.attachedDevices = []; - - // if (process.env.TCORE_CLUSTER_TOKEN) { - // // if the promise is still active the reject will make sure that - // // the other side receives an error and cancels the execution flow - // reject(); - // } else { - // // if the tcore was deleted without this instance logging out we need - // // to resolve the connection normally for the user to try again - // resolve(); - // } - // }); - - // /** - // */ - // socket.on("connect_error", () => { - // connectErrors += 1; - // console.log( - // chalk.redBright("[ERROR]"), - // `Connect error (${connectErrors}/3).`, - // ); - - // cache.serverIO?.emit("status", cache.socket?.connected); - // cache.attachedDevices = []; - - // if (connectErrors >= 3 || !process.env.TCORE_CLUSTER_TOKEN) { - // connectErrors = 0; - // socket?.disconnect(); - // reject(); - // } - // }); - - // /** - // */ - // socket.on("tcore::instance", (tcore) => { - // cache.tcore = tcore; - // if (!process.env.TCORE_CLUSTER_TOKEN) { - // resolve(); - // } - // }); - - // /** - // */ - // socket.on("tcore::action::schedule", (connID: string) => { - // call("tcore::action::schedule", connID, async () => { - // await core.triggerActionScheduleCheck(); - // await core.triggerDeviceDataRetentionCheck(); - // }); - // }); - - // /** - // */ - // socket.on("tcore::cluster::busy", (connID: string) => { - // call("tcore::cluster::busy", connID, async () => { - // const message = - // "Cluster is busy executing another action. Try again later."; - // cache.commandsQueue.forEach((x) => x.promise.reject(message)); - // cache.commandsQueue = []; - // }); - // }); - - // /** - // */ - // socket.on("tcore::cluster::state", async (connID, state, options) => { - // if (cache.stateQueue.length > 0) { - // // already has a state in the queue, add to the queue and wait - // cache.stateQueue.push({ connID, state, options }); - // } else { - // // no state in queue, run it right now - // cache.stateQueue.push({ connID, state, options }); - // await checkStateQueue(); - // resolve(); - // } - // }); - - // /** - // */ - // socket.on( - // "tcore::device::data::added", - // async (connID, deviceToken, data) => { - // call("tcore::device::data::added", connID, async () => { - // const device = await core.getDeviceByToken(deviceToken); - // if (device) { - // await core.addDeviceData(device.id, data).catch(() => null); - // } - // }); - // }, - // ); - - // /** - // * Called when the realtime server requests a device list on this instance. - // */ - // socket.on( - // "tcore::device::list", - // async (connID, query: IDeviceListQuery) => { - // call("tcore::device::list", connID, async () => { - // query.fields = (query.fields || []).filter( - // (x: string) => x !== "bucket", - // ); - // const list = await core.getDeviceList(query); - // return list; - // }); - // }, - // ); - - // /** - // * Called when the realtime server requests a device info on this instance. - // */ - // socket.on("tcore::device::info", async (connID, deviceID: TGenericID) => { - // call("tcore::device::info", connID, async () => { - // const info = await core.getDeviceInfo(deviceID); - // return info; - // }); - // }); - - // /** - // * Called when the realtime server requests data from this instance. - // */ - // socket.on( - // "tcore::device::data", - // async (connID, deviceID: TGenericID, query: IDeviceDataQuery) => { - // call("tcore::device::data", connID, async () => { - // const data = await core.getDeviceData(deviceID, query); - // return data; - // }); - // }, - // ); - - // /** - // */ - // socket.on("tcore::summary", async (connID) => { - // call("tcore::summary", connID, () => core.getSummary()); - // }); - - // /** - // * Called when someone enters a dashboard with this device in a widget. - // */ - // socket.on("tcore::data::attach", async (deviceID) => { - // cache.attachedDevices.push(deviceID); - // }); - - // /** - // * Called when someone leaves a dashboard with this device in a widget. - // */ - // socket.on("tcore::data::unattach", async (deviceID) => { - // const i = cache.attachedDevices.indexOf(deviceID); - // if (i >= 0) { - // cache.attachedDevices.splice(i, 1); - // } - // }); - - // /** - // */ - // socket.on("tcore::summary-and-computer-usage", async (connID) => { - // call("tcore::summary-and-computer-usage", connID, async () => { - // const data = await Promise.all([ - // core.getSummary(), - // helpers.getComputerUsage(), - // ]); - // return { summary: data[0], computer_usage: data[1] }; - // }); - // }); - // }); } /** @@ -254,74 +124,29 @@ function closeRealtimeConnection() { events = null; } -/** - * Calls a procedure. - */ -async function call(event: string, connID: string, fn: Function) { - try { - console.log(`• Received ${chalk.cyanBright(event)} event`); - const promise = fn(); - const result = await promise; - cache.serverIO?.emit("event", "receive", event, Date.now(), result); - socket?.emit("tcore::response::success", connID, result); - console.log("└─", chalk.green("[DONE]"), "Handled event"); - } catch (ex: any) { - const err = ex?.message || ex; - console.log("└─", chalk.redBright("[ERROR]"), err); - socket?.emit("tcore::response::error", connID, err); - } -} - /** * Emits a ping event to the API. */ -// async function emitStartData() { -// const systemStartTime = new Date(Date.now() - os.uptime() * 1000); -// const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); -// const osInfo = await helpers.getOSInfo(); - -// socket?.emit("tcore::start", { -// machine_id: getMachineID(), -// local_ips: getLocalIPs().join(", "), -// name: os.hostname(), -// os: osInfo, -// system_start_time: systemStartTime, -// tcore_start_time: tcoreStartTime, -// tcore_version: "0.7.0", -// }); -// } - -/** - * TODO - */ -async function checkStateQueue() { - for (const item of cache.stateQueue) { - const isRollback = item.options?.rollback; - const error = item.options?.error; - const event = `tcore::cluster::state${isRollback ? "::rollback" : ""}`; - - if (isRollback) { - const message = `Rolling back due to error in one of the Cluster instances: ${error}`; - cache.systemModule?.emitInstallLog({ error: true, message }); - } - - await call(event, item.connID, async () => { - if (isRollback) { - console.log( - "├─", - chalk.cyanBright("[ROLLBACK]"), - "due to error", - chalk.redBright(error), - ); - } - }); - } +async function emitStartData(token: string, connID: string) { + const systemStartTime = new Date(Date.now() - os.uptime() * 1000); + const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); + const osInfo = await helpers.getOSInfo(); + const startData = { + machine_id: getMachineID(), + local_ips: getLocalIPs().join(", "), + name: os.hostname(), + os: osInfo, + system_start_time: systemStartTime, + tcore_start_time: tcoreStartTime, + tcore_version: "0.7.0", + }; - cache.stateQueue = []; + const response = await sendDataToTagoio(token, startData, connID, "update-tcore"); + console.info("Start data sent", response); } /** - * TODO + * Get local IP addresses. */ function getLocalIPs() { const interfaces = os.networkInterfaces(); @@ -339,11 +164,5 @@ function getLocalIPs() { return addresses; } -/** - * TODO - */ -function isConnectedToAPI() { - return true; -} -export { closeRealtimeConnection, startRealtimeCommunication, isConnectedToAPI }; +export { closeRealtimeConnection, startRealtimeCommunication }; diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index 7ded3d74..b6d8f1df 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -37,4 +37,20 @@ async function createTCore(token: string, data: any) { return response.data.result; } -export { updateTCore, createTCore, listTCoresByMachineID }; +/** + * Send data to Tagoio. + */ +async function sendDataToTagoio(token: string, data: any, connId: string, operation: string) { + const response = await axios({ + url: `${process.env.TAGOIO_API}/tcore/${connId}`, + method: "POST", + headers: { token }, + data: { + operation, + data, + }, + }); + return response.data.result; +} + +export { updateTCore, createTCore, listTCoresByMachineID, sendDataToTagoio }; diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts index 0a5fbbcc..6d52a4a7 100644 --- a/plugins/tagoio-integration/src/back/Server.ts +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -37,13 +37,6 @@ function initServer() { server = http.createServer(app); server.listen("8999"); - - // cache.serverIO = new Server(server); - // cache.serverIO.on("connection", () => { - // if (cache.socket) { - // cache.serverIO?.emit("status", cache.socket.connected); - // } - // }); } /** diff --git a/plugins/tagoio-integration/src/back/index.ts b/plugins/tagoio-integration/src/back/index.ts index 59f288bd..b4825138 100644 --- a/plugins/tagoio-integration/src/back/index.ts +++ b/plugins/tagoio-integration/src/back/index.ts @@ -4,6 +4,7 @@ import { cache } from "./Global.ts"; import { logError } from "./Log.ts"; import { closeServer, initServer } from "./Server.ts"; import { startRealtimeCommunication } from "./RealtimeConnection.ts"; +import { sendDataToTagoio } from "./Request.ts"; let started = false; @@ -54,6 +55,7 @@ hookModule.onAfterInsertDeviceData = async (deviceID, data) => { // const event = "tcore::device::data::add"; // cache.serverIO?.emit("event", "send", event, Date.now(), data); // cache.socket?.emit(event, deviceID, data); + sendDataToTagoio(await pluginStorage.get("token"), data, deviceID, "device-data").catch(logError); } }; From fb5d6b4fe91dfcefcde1611a0566ddb8f4145ca9 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Mon, 28 Oct 2024 17:43:42 -0300 Subject: [PATCH 04/27] Changing the integration with tagoio to SSE --- plugins/tagoio-integration/src/back/Global.ts | 2 - .../src/back/RealtimeConnection.ts | 56 ++----------------- plugins/tagoio-integration/src/back/Server.ts | 2 - plugins/tagoio-integration/src/back/index.ts | 12 ---- 4 files changed, 5 insertions(+), 67 deletions(-) diff --git a/plugins/tagoio-integration/src/back/Global.ts b/plugins/tagoio-integration/src/back/Global.ts index d72f02c8..09f93941 100644 --- a/plugins/tagoio-integration/src/back/Global.ts +++ b/plugins/tagoio-integration/src/back/Global.ts @@ -36,7 +36,6 @@ interface IObjects { commandsQueue: ICommandQueueItem[]; stateQueue: IStateQueueItem[]; systemModule: SystemModule | null; - attachedDevices: Array; } const cache: IObjects = { @@ -45,7 +44,6 @@ const cache: IObjects = { commandsQueue: [], stateQueue: [], systemModule: null, - attachedDevices: [], }; export { cache }; diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts index a4b61aba..a99f3d7a 100644 --- a/plugins/tagoio-integration/src/back/RealtimeConnection.ts +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -35,70 +35,24 @@ function startRealtimeCommunication(token: string) { case "sse::instance": cache.tcore = event.data.tcore; break; - case "sse::action::schedule": { - const schedule = await core.triggerActionScheduleCheck(); - const dataRetentions = await core.triggerDeviceDataRetentionCheck(); - const response = await sendDataToTagoio(token, { schedule, dataRetentions }, event.data.connID, ""); - console.info("Schedule sent", response); - break; - } - case "sse::device::data::added": { - const device = await core.getDeviceByToken(event.data.deviceToken); - let result: any = null; - if (device) { - result = await core.addDeviceData(device.id, event.data.deviceData).catch(() => null); - } - const response = await sendDataToTagoio(token, result, event.data.connID, ""); - console.info("Data added", response); - break; - } - case "sse::device::list": { - event.data.query.fields = (event.data.query.fields || []).filter( - (x: string) => x !== "bucket", - ); - const list = await core.getDeviceList(event.data.query); - const response = await sendDataToTagoio(token, list, event.data.connID, ""); - console.info("Device list sent", response); - break; - } - case "sse::device::info": { - const info = await core.getDeviceInfo(event.data.deviceID); - const response = await sendDataToTagoio(token, info, event.data.connID, ""); - console.info("Device info sent", response); - break; - } - case "sse::device::data": { - const data = await core.getDeviceData(event.data.deviceID, event.data.query); - const response = await sendDataToTagoio(token, data, event.data.connID, ""); - console.info("Device data sent", response); - break; - } case "sse::summary": { const summary = await core.getSummary(); - const response = await sendDataToTagoio(token, summary, event.data.connID, ""); + const response = await sendDataToTagoio(token, summary, event.data.connID, "update-summary-tcore"); console.info("Summary sent", response); break; } - case "sse::data::attach": { - cache.attachedDevices.push(event.data.deviceID); - break; - } - case "sse::data::unattach": { - const i = cache.attachedDevices.indexOf(event.data.deviceID); - if (i >= 0) { - cache.attachedDevices.splice(i, 1); - } - break; - } case "sse::summary-and-computer-usage": { const data = await Promise.all([ core.getSummary(), helpers.getComputerUsage(), ]); - const response = await sendDataToTagoio(token, { summary: data[0], computer_usage: data[1] }, event.data.connID, ""); + const response = await sendDataToTagoio(token, { summary: data[0], computer_usage: data[1] }, event.data.connID, "summary-computer-usage-tcore"); console.info("Summary and Computer Usage sent", response); break; } + case "sse::disconnect": + events?.close(); + break; default: console.error("Unknown event channel", event.data.channel); } diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts index 6d52a4a7..97fd1558 100644 --- a/plugins/tagoio-integration/src/back/Server.ts +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -4,8 +4,6 @@ import { helpers, pluginStorage } from "@tago-io/tcore-sdk"; import bodyParser from "body-parser"; import cors from "cors"; import express, { type Request, type Response } from "express"; -import { Server } from "socket.io"; -// @ts-ignore import pkg from "../../package.json" with { type: "json" }; import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; diff --git a/plugins/tagoio-integration/src/back/index.ts b/plugins/tagoio-integration/src/back/index.ts index b4825138..99ec7ec2 100644 --- a/plugins/tagoio-integration/src/back/index.ts +++ b/plugins/tagoio-integration/src/back/index.ts @@ -1,10 +1,7 @@ import { HookModule, NavbarButtonModule, PageModule, pluginStorage, SystemModule } from "@tago-io/tcore-sdk"; -import { cache } from "./Global.ts"; -import { logError } from "./Log.ts"; import { closeServer, initServer } from "./Server.ts"; import { startRealtimeCommunication } from "./RealtimeConnection.ts"; -import { sendDataToTagoio } from "./Request.ts"; let started = false; @@ -50,15 +47,6 @@ const hookModule = new HookModule({ hookModule.onMainDatabaseModuleLoaded = init; -hookModule.onAfterInsertDeviceData = async (deviceID, data) => { - if (cache.attachedDevices.includes(deviceID)) { - // const event = "tcore::device::data::add"; - // cache.serverIO?.emit("event", "send", event, Date.now(), data); - // cache.socket?.emit(event, deviceID, data); - sendDataToTagoio(await pluginStorage.get("token"), data, deviceID, "device-data").catch(logError); - } -}; - /** * Main .html page */ From a6c747afe4da84354b634639ce7d8809eddc1ac4 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 08:48:26 -0300 Subject: [PATCH 05/27] Changing the integration with tagoio to SSE --- package-lock.json | 152 ++++++++++++++---- package.json | 2 +- .../tagoio-integration/src/back/Request.ts | 3 +- 3 files changed, 125 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68a370bf..74928bd5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "plugins/*" ], "dependencies": { - "@tago-io/sdk": "10.4.4", + "@tago-io/sdk": "11.3.2", "async": "3.2.6", "axios": "0.26.0", "body-parser": "2.0.1", @@ -3659,35 +3659,76 @@ } }, "node_modules/@tago-io/sdk": { - "version": "10.4.4", - "resolved": "https://registry.npmjs.org/@tago-io/sdk/-/sdk-10.4.4.tgz", - "integrity": "sha512-5rZxeJCRCCf0wfEVsFjS4OJL31YvRDDJSAA0OgEh1vkGtowO0JuYbASyZV6ZYxU4kczHCC4FfjkeIw5uu8G/hg==", + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/@tago-io/sdk/-/sdk-11.3.2.tgz", + "integrity": "sha512-fya4bDvxLfBxPAkSOrGFi08N8TvcP2LhhloLTb+85Yd5nE1MnOk+rCwSEW+M2phFIjqzbELDoEXrBtHzpsqO7A==", + "license": "Apache-2.0", "dependencies": { - "axios": "0.25.0", + "axios": "1.6.8", "form-data": "4.0.0", - "lodash.chunk": "4.2.0", - "nanoid": "3.2.0", - "papaparse": "5.3.1", - "qs": "6.10.3", - "socket.io-client": "4.4.1" + "nanoid": "3.3.7", + "papaparse": "5.4.1", + "qs": "6.12.0", + "socket.io-client": "4.7.5" }, "engines": { - "node": ">=14.0.0", + "node": ">=16.0.0", "npm": ">=6.0.0" + }, + "optionalDependencies": { + "eventsource": "2.0.2" } }, + "node_modules/@tago-io/sdk/node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, "node_modules/@tago-io/sdk/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/@tago-io/sdk/node_modules/engine.io-client": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.14.7" + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/@tago-io/sdk/node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" } }, "node_modules/@tago-io/sdk/node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -3696,12 +3737,12 @@ } }, "node_modules/@tago-io/sdk/node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", + "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3710,6 +3751,55 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/@tago-io/sdk/node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@tago-io/sdk/node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@tago-io/sdk/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@tago-io/tagocore-plugin-tagoio-integration": { "resolved": "plugins/tagoio-integration", "link": true @@ -8398,11 +8488,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, - "node_modules/lodash.chunk": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.chunk/-/lodash.chunk-4.2.0.tgz", - "integrity": "sha512-ZzydJKfUHJwHa+hF5X66zLFCBrWn5GeF28OHEr4WVWtNDXlQ/IjWKPBiikqKo2ne0+v6JgCgJ0GzJp8k8bHC7w==" - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -10018,9 +10103,10 @@ } }, "node_modules/papaparse": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.1.tgz", - "integrity": "sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA==" + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==", + "license": "MIT" }, "node_modules/parent-module": { "version": "1.0.1", @@ -10607,6 +10693,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", diff --git a/package.json b/package.json index fc8eb145..4011c224 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "url": "git+https://github.com/tago-io/tcore.git" }, "dependencies": { - "@tago-io/sdk": "10.4.4", + "@tago-io/sdk": "11.3.2", "async": "3.2.6", "axios": "0.26.0", "body-parser": "2.0.1", diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index b6d8f1df..e755076c 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -1,6 +1,7 @@ -import { Account } from "@tago-io/sdk"; import axios from "axios"; import { getMachineID } from "./Helpers.ts"; +import Account from "@tago-io/sdk/lib/modules/Resources/Account.js"; + /** * Lists all instances that have the current machine id. From fdc46acf9380a90db727c9bfab878385b47c7d02 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 08:49:18 -0300 Subject: [PATCH 06/27] Changing the integration with tagoio to SSE --- plugins/tagoio-integration/src/back/Request.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index e755076c..b3066ba5 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -21,7 +21,7 @@ async function listTCoresByMachineID(token: string) { */ async function updateTCore(token: string, tcoreID: string, data: any) { const account = new Account({ token, region: "env" }); - const response = await account.tagocore.edit(tcoreID, data); + const response = await account.tagocores.edit(tcoreID, data); return response; } From f4e73619300f9beac04317778029bf3ef022acb8 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 08:53:23 -0300 Subject: [PATCH 07/27] Changing the integration with tagoio to SSE --- plugins/tagoio-integration/src/back/Request.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index b3066ba5..acf8d552 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -1,6 +1,6 @@ import axios from "axios"; import { getMachineID } from "./Helpers.ts"; -import Account from "@tago-io/sdk/lib/modules/Resources/Account.js"; +import TagoCores from "@tago-io/sdk/lib/modules/Resources/TagoCores"; /** @@ -8,8 +8,8 @@ import Account from "@tago-io/sdk/lib/modules/Resources/Account.js"; */ async function listTCoresByMachineID(token: string) { const machine_id = getMachineID(); - const account = new Account({ token, region: "env" }); - const response = await account.tagocores.list({ + const tcore = new TagoCores({ token, region: "env" }); + const response = await tcore.list({ fields: ["id", "token"], filter: { machine_id } as any, }); @@ -20,8 +20,8 @@ async function listTCoresByMachineID(token: string) { * Creates a new instance with the given data. */ async function updateTCore(token: string, tcoreID: string, data: any) { - const account = new Account({ token, region: "env" }); - const response = await account.tagocores.edit(tcoreID, data); + const tcore = new TagoCores({ token, region: "env" }); + const response = await tcore.edit(tcoreID, data); return response; } From 223a65311dc963c84351325e2424a070349dbdb1 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 08:54:01 -0300 Subject: [PATCH 08/27] Changing the integration with tagoio to SSE --- plugins/tagoio-integration/src/back/Request.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index acf8d552..a7f38125 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -1,6 +1,6 @@ import axios from "axios"; import { getMachineID } from "./Helpers.ts"; -import TagoCores from "@tago-io/sdk/lib/modules/Resources/TagoCores"; +import TagoCores from "@tago-io/sdk/lib/modules/Resources/TagoCores.js"; /** From 9db8f84fa6e57567556821aae80d148a5bc1f898 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 10:10:19 -0300 Subject: [PATCH 09/27] Merge main --- package-lock.json | 1370 +++++++++++++---- package.json | 6 +- packages/console/package.json | 2 - .../tagoio-integration/src/back/Request.ts | 11 +- 4 files changed, 1099 insertions(+), 290 deletions(-) diff --git a/package-lock.json b/package-lock.json index b2dfdbaf..eeebee4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "plugins/*" ], "dependencies": { - "@tago-io/sdk": "11.3.2", + "@tago-io/sdk": "10.4.4", "async": "3.2.6", "axios": "0.26.0", "body-parser": "2.0.1", @@ -26,8 +26,8 @@ "ora": "8.1.0", "polished": "4.1.3", "qs": "6.10.1", - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "18.3.1", + "react-dom": "18.3.1", "semver": "7.6.3", "socket.io": "4.4.1", "socket.io-client": "4.4.1", @@ -101,7 +101,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -115,7 +114,6 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1027,7 +1025,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -1042,7 +1039,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1052,7 +1048,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -1083,7 +1078,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1093,7 +1087,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.26.0", @@ -1110,18 +1103,28 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-compilation-targets": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.9", @@ -1138,7 +1141,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -1148,7 +1150,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1158,14 +1159,12 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -1179,7 +1178,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -1193,11 +1191,19 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1207,7 +1213,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1217,7 +1222,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1227,7 +1231,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -1241,7 +1244,6 @@ "version": "7.26.1", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.26.0" @@ -1253,6 +1255,21 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", @@ -1265,11 +1282,24 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", + "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js-pure": "^3.30.2", + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.9", @@ -1284,7 +1314,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.9", @@ -1303,7 +1332,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -1539,10 +1567,16 @@ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", "license": "MIT" }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", + "license": "MIT" + }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { @@ -1964,7 +1998,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -1979,7 +2012,6 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1990,7 +2022,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2000,7 +2031,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2010,7 +2040,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -3652,58 +3681,26 @@ "integrity": "sha512-5rZxeJCRCCf0wfEVsFjS4OJL31YvRDDJSAA0OgEh1vkGtowO0JuYbASyZV6ZYxU4kczHCC4FfjkeIw5uu8G/hg==", "license": "Apache-2.0", "dependencies": { - "axios": "1.6.8", + "axios": "0.25.0", "form-data": "4.0.0", - "nanoid": "3.3.7", - "papaparse": "5.4.1", - "qs": "6.12.0", - "socket.io-client": "4.7.5" + "lodash.chunk": "4.2.0", + "nanoid": "3.2.0", + "papaparse": "5.3.1", + "qs": "6.10.3", + "socket.io-client": "4.4.1" }, "engines": { - "node": ">=16.0.0", + "node": ">=14.0.0", "npm": ">=6.0.0" - }, - "optionalDependencies": { - "eventsource": "2.0.2" } }, - "node_modules/@tago-io/sdk/node_modules/@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "license": "MIT" - }, "node_modules/@tago-io/sdk/node_modules/axios": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/@tago-io/sdk/node_modules/engine.io-client": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", - "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1", - "xmlhttprequest-ssl": "~2.0.0" - } - }, - "node_modules/@tago-io/sdk/node_modules/engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" + "follow-redirects": "^1.14.7" } }, "node_modules/@tago-io/sdk/node_modules/nanoid": { @@ -3719,12 +3716,12 @@ } }, "node_modules/@tago-io/sdk/node_modules/qs": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.0.tgz", - "integrity": "sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.0.4" }, "engines": { "node": ">=0.6" @@ -3733,55 +3730,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@tago-io/sdk/node_modules/socket.io-client": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", - "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@tago-io/sdk/node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "license": "MIT", - "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@tago-io/sdk/node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@tago-io/tagocore-plugin-tagoio-integration": { "resolved": "plugins/tagoio-integration", "link": true @@ -3921,26 +3869,42 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", - "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", "dev": true, "license": "MIT", "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", + "@babel/runtime": "^7.9.2", + "@types/testing-library__jest-dom": "^5.9.1", + "aria-query": "^4.2.2", "chalk": "^3.0.0", + "css": "^3.0.0", "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", "redent": "^3.0.0" }, "engines": { - "node": ">=14", + "node": ">=8", "npm": ">=6", "yarn": ">=1" } }, + "node_modules/@testing-library/jest-dom/node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, "node_modules/@testing-library/jest-dom/node_modules/chalk": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", @@ -3955,13 +3919,6 @@ "node": ">=8" } }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, "node_modules/@testing-library/jest-dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3976,31 +3933,81 @@ } }, "node_modules/@testing-library/react": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", + "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5" + "@babel/runtime": "^7.12.5", + "@testing-library/dom": "^8.0.0" }, "engines": { - "node": ">=18" + "node": ">=12" }, "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "*", + "react-dom": "*" + } + }, + "node_modules/@testing-library/react/node_modules/@testing-library/dom": { + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", + "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.1.3", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "engines": { + "node": ">=12" + } + }, + "node_modules/@testing-library/react/node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "deep-equal": "^2.0.5" + } + }, + "node_modules/@testing-library/react/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/react/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/@testing-library/user-event": { @@ -4183,6 +4190,13 @@ "@types/estree": "*" } }, + "node_modules/@types/eventsource": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", + "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/express": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.0.tgz", @@ -4218,6 +4232,24 @@ "@types/unist": "*" } }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", + "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -4357,25 +4389,55 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz", + "integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==", "license": "MIT", "dependencies": { "@types/prop-types": "*", + "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", + "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", "dev": true, "license": "MIT", "dependencies": { + "@types/history": "*", "@types/react": "*" } }, + "node_modules/@types/react-router-dom": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz", + "integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -4406,12 +4468,34 @@ "@types/send": "*" } }, + "node_modules/@types/styled-components": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", + "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/stylis": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", "license": "MIT" }, + "node_modules/@types/testing-library__jest-dom": { + "version": "5.14.9", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", + "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/jest": "*" + } + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -4828,9 +4912,26 @@ "dequal": "^2.0.3" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "license": "MIT" }, @@ -4856,6 +4957,19 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "license": "(MIT OR Apache-2.0)", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -4920,6 +5034,34 @@ "follow-redirects": "^1.14.8" } }, + "node_modules/babel-plugin-styled-components": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", + "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/plugin-syntax-jsx": "^7.22.5", + "lodash": "^4.17.21", + "picomatch": "^2.3.1" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, + "node_modules/babel-plugin-styled-components/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -5203,7 +5345,6 @@ "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -5404,7 +5545,6 @@ "version": "1.0.30001673", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001673.tgz", "integrity": "sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==", - "dev": true, "funding": [ { "type": "opencollective", @@ -5918,7 +6058,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -5936,6 +6075,18 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, + "node_modules/core-js-pure": { + "version": "3.38.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", + "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -6031,6 +6182,18 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, + "node_modules/css": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", + "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "source-map": "^0.6.1", + "source-map-resolve": "^0.6.0" + } + }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -6182,6 +6345,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -6207,6 +6380,46 @@ "node": ">=6" } }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -6233,6 +6446,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6403,7 +6634,6 @@ "version": "1.5.47", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz", "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==", - "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -6570,6 +6800,34 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", @@ -7032,6 +7290,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -7118,7 +7386,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7233,7 +7500,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -7258,6 +7524,16 @@ "license": "ISC", "optional": true }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -7383,6 +7659,21 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -7569,6 +7860,21 @@ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -7650,6 +7956,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -7657,6 +7980,36 @@ "dev": true, "license": "MIT" }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -7690,6 +8043,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -7753,6 +8122,35 @@ "license": "MIT", "optional": true }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -7778,13 +8176,15 @@ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", "license": "MIT" }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -7793,48 +8193,154 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC", - "optional": true - }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "call-bind": "^1.0.7" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jest-diff/node_modules/chalk": { - "version": "4.1.2", + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC", + "optional": true + }, + "node_modules/jest-diff": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", + "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^27.5.1", + "jest-get-type": "^27.5.1", + "pretty-format": "^27.5.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", @@ -8014,7 +8520,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -8034,7 +8539,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -9508,7 +10012,6 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -9572,6 +10075,52 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -10038,12 +10587,12 @@ } }, "node_modules/polished": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", - "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz", + "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.17.8" + "@babel/runtime": "^7.14.0" }, "engines": { "node": ">=10" @@ -10273,12 +10822,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", @@ -10535,6 +11078,25 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "license": "MIT" }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", + "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -10881,6 +11443,22 @@ "node": ">= 0.4" } }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -11136,6 +11714,18 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-resolve": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", + "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", + "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", + "dev": true, + "license": "MIT", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0" + } + }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -11254,6 +11844,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", @@ -11358,23 +11961,25 @@ } }, "node_modules/styled-components": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", - "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", + "version": "5.3.5", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", + "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", + "hasInstallScript": true, "license": "MIT", "dependencies": { - "@emotion/is-prop-valid": "1.2.2", - "@emotion/unitless": "0.8.1", - "@types/stylis": "4.2.5", - "css-to-react-native": "3.2.0", - "csstype": "3.1.3", - "postcss": "8.4.38", - "shallowequal": "1.1.0", - "stylis": "4.3.2", - "tslib": "2.6.2" + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^1.1.0", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" }, "engines": { - "node": ">= 16" + "node": ">=10" }, "funding": { "type": "opencollective", @@ -11382,61 +11987,31 @@ }, "peerDependencies": { "react": ">= 16.8.0", - "react-dom": ">= 16.8.0" + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" } }, - "node_modules/styled-components/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/styled-components/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=4" } }, - "node_modules/styled-components/node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/styled-components/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" + "has-flag": "^3.0.0" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=4" } }, - "node_modules/styled-components/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "license": "0BSD" - }, "node_modules/stylis": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", @@ -12049,7 +12624,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -12871,6 +13445,42 @@ "node": ">= 8" } }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", @@ -13301,8 +13911,6 @@ "mobx": "6.13.5", "mobx-react": "9.1.1", "polished": "4.3.1", - "react": "18.3.1", - "react-dom": "18.3.1", "react-helmet-async": "2.0.5", "react-markdown": "9.0.1", "react-router": "6.27.0", @@ -13325,6 +13933,208 @@ "vite-plugin-svgr": "4.2.0" } }, + "packages/console/node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, + "packages/console/node_modules/@testing-library/jest-dom": { + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", + "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "packages/console/node_modules/@testing-library/react": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "packages/console/node_modules/@types/react": { + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "packages/console/node_modules/@types/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "packages/console/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/console/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "packages/console/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "packages/console/node_modules/polished": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.8" + }, + "engines": { + "node": ">=10" + } + }, + "packages/console/node_modules/postcss": { + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "packages/console/node_modules/styled-components": { + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "packages/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/console/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "packages/sdk": { "name": "@tago-io/tcore-sdk", "version": "0.7.0", diff --git a/package.json b/package.json index 4011c224..3f3610ac 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "url": "git+https://github.com/tago-io/tcore.git" }, "dependencies": { - "@tago-io/sdk": "11.3.2", + "@tago-io/sdk": "10.4.4", "async": "3.2.6", "axios": "0.26.0", "body-parser": "2.0.1", @@ -41,8 +41,8 @@ "polished": "4.1.3", "ora": "8.1.0", "qs": "6.10.1", - "react": "17.0.2", - "react-dom": "17.0.2", + "react": "18.3.1", + "react-dom": "18.3.1", "semver": "7.6.3", "socket.io": "4.4.1", "socket.io-client": "4.4.1", diff --git a/packages/console/package.json b/packages/console/package.json index 5ddd2f92..97736611 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -18,8 +18,6 @@ "mobx": "6.13.5", "mobx-react": "9.1.1", "polished": "4.3.1", - "react": "18.3.1", - "react-dom": "18.3.1", "react-helmet-async": "2.0.5", "react-markdown": "9.0.1", "react-router": "6.27.0", diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index a7f38125..a7acc003 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -1,6 +1,7 @@ import axios from "axios"; import { getMachineID } from "./Helpers.ts"; -import TagoCores from "@tago-io/sdk/lib/modules/Resources/TagoCores.js"; +import Account from "@tago-io/sdk/out/modules/Account/Account.js"; + /** @@ -8,8 +9,8 @@ import TagoCores from "@tago-io/sdk/lib/modules/Resources/TagoCores.js"; */ async function listTCoresByMachineID(token: string) { const machine_id = getMachineID(); - const tcore = new TagoCores({ token, region: "env" }); - const response = await tcore.list({ + const account = new Account({ token, region: "env" }); + const response = await account.tagocores.list({ fields: ["id", "token"], filter: { machine_id } as any, }); @@ -20,8 +21,8 @@ async function listTCoresByMachineID(token: string) { * Creates a new instance with the given data. */ async function updateTCore(token: string, tcoreID: string, data: any) { - const tcore = new TagoCores({ token, region: "env" }); - const response = await tcore.edit(tcoreID, data); + const account = new Account({ token, region: "env" }); + const response = await account.tagocores.edit(tcoreID, data); return response; } From 16e1d7dd5871d274748b759cab5ab1772ebc5b1e Mon Sep 17 00:00:00 2001 From: Klaus Borges Date: Tue, 29 Oct 2024 10:36:41 -0300 Subject: [PATCH 10/27] fix: integration build Vite --- plugins/tagoio-integration/esbuild/build.js | 66 ------------------- .../esbuild/dirname-shim.js | 2 - plugins/tagoio-integration/esbuild/svgr.js | 16 ----- plugins/tagoio-integration/index.html | 20 ++++++ plugins/tagoio-integration/package.json | 26 +++++++- plugins/tagoio-integration/vite.config.ts | 50 ++++++++++++++ 6 files changed, 93 insertions(+), 87 deletions(-) delete mode 100644 plugins/tagoio-integration/esbuild/build.js delete mode 100644 plugins/tagoio-integration/esbuild/dirname-shim.js delete mode 100644 plugins/tagoio-integration/esbuild/svgr.js create mode 100644 plugins/tagoio-integration/index.html create mode 100644 plugins/tagoio-integration/vite.config.ts diff --git a/plugins/tagoio-integration/esbuild/build.js b/plugins/tagoio-integration/esbuild/build.js deleted file mode 100644 index 0d1d2a23..00000000 --- a/plugins/tagoio-integration/esbuild/build.js +++ /dev/null @@ -1,66 +0,0 @@ -const svgr = require("./svgr.js"); -const esbuild = require("esbuild"); -const fs = require("node:fs"); - -const dev = process.argv.includes("--watch"); - -const TAGOIO_API = "https://api.tago.io"; -const TAGOIO_REALTIME = "https://realtime.tago.io"; - -/** - */ -async function buildFront() { - await esbuild.build({ - entryPoints: ["./src/front/index.tsx"], - bundle: true, - charset: "utf8", - outfile: "./build/front/index.js", - target: ["chrome58", "safari11"], - inject: ["./esbuild/react-shim.js", "./esbuild/dirname-shim.js"], - minify: !dev, - publicPath: "/pages/tagoio-integration", - sourcemap: dev, - watch: dev, - external: ["path"], - plugins: [svgr()], - define: { - "process.env.TAGOIO_API": `"${TAGOIO_API}"`, - "process.env.TAGO_API": `"${TAGOIO_API}"`, - "process.env.TAGOIO_REALTIME": `"${TAGOIO_REALTIME}"`, - "process.env.TAGO_REALTIME": `"${TAGOIO_REALTIME}"`, - }, - loader: { - ".png": "file", - }, - }); -} - -/** - */ -async function generateHTML() { - const template = ` - - - - - - - - -
- - - - `; - - fs.writeFileSync("./build/front/index.html", template, { encoding: "utf-8" }); -} - -/** - */ -async function build() { - await fs.promises.rm("./build", { recursive: true }).catch(() => null); - await Promise.all([await buildFront(), await generateHTML()]); -} - -build(); diff --git a/plugins/tagoio-integration/esbuild/dirname-shim.js b/plugins/tagoio-integration/esbuild/dirname-shim.js deleted file mode 100644 index 3b401f34..00000000 --- a/plugins/tagoio-integration/esbuild/dirname-shim.js +++ /dev/null @@ -1,2 +0,0 @@ -const __dirname = ""; -export { __dirname }; diff --git a/plugins/tagoio-integration/esbuild/svgr.js b/plugins/tagoio-integration/esbuild/svgr.js deleted file mode 100644 index 6591359d..00000000 --- a/plugins/tagoio-integration/esbuild/svgr.js +++ /dev/null @@ -1,16 +0,0 @@ -const svgr = require("@svgr/core").default; -const fs = require("node:fs"); - -module.exports = (options = {}) => ({ - name: "svgr", - setup(build) { - build.onLoad({ filter: /\.svg$/ }, async (args) => { - const svg = await fs.promises.readFile(args.path, "utf8"); - const contents = await svgr(svg, { ...options }, { filePath: args.path }); - return { - contents, - loader: "jsx", - }; - }); - }, -}); diff --git a/plugins/tagoio-integration/index.html b/plugins/tagoio-integration/index.html new file mode 100644 index 00000000..6fcad7cf --- /dev/null +++ b/plugins/tagoio-integration/index.html @@ -0,0 +1,20 @@ + + + + + + + TCore + + + +
+ + + + diff --git a/plugins/tagoio-integration/package.json b/plugins/tagoio-integration/package.json index dc503658..be11fdd1 100644 --- a/plugins/tagoio-integration/package.json +++ b/plugins/tagoio-integration/package.json @@ -12,19 +12,39 @@ "priority": "highest", "cluster": true, "hidden": true, - "permissions": ["device", "device-data", "plugin", "action"], - "types": ["navbar-button", "page", "system-override", "hook"], + "permissions": [ + "device", + "device-data", + "plugin", + "action" + ], + "types": [ + "navbar-button", + "page", + "system-override", + "hook" + ], "publisher": { "name": "TagoIO", "domain": "tago.io" } }, + "scripts": { + "dev": "vite", + "watch": "vite", + "build": "vite build", + "build-watch": "vite build --watch", + "test": "vitest" + }, "dependencies": { "path-browserify": "1.0.1", "eventsource": "^2.0.2" }, "devDependencies": { "@testing-library/user-event": "14.5.2", - "@types/eventsource": "^1.1.15" + "@types/eventsource": "^1.1.15", + "@vitejs/plugin-react-swc": "3.7.1", + "vite": "5.4.10", + "vite-plugin-svgr": "4.2.0" } } diff --git a/plugins/tagoio-integration/vite.config.ts b/plugins/tagoio-integration/vite.config.ts new file mode 100644 index 00000000..255238db --- /dev/null +++ b/plugins/tagoio-integration/vite.config.ts @@ -0,0 +1,50 @@ +/// + +import react from "@vitejs/plugin-react-swc"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vite"; +import svgr from "vite-plugin-svgr"; + +const configFilePath = fileURLToPath(import.meta.url); +const buildPath = join(dirname(configFilePath), "./build/front"); + +const TAGOIO_API = "https://api.tago.io"; +const TAGOIO_REALTIME = "https://realtime.tago.io"; + +// FIXME:(klaus) external dep 'path'? 'eventsource'? +// https://vite.dev/config/ +export default defineConfig({ + plugins: [ + svgr({ + svgrOptions: { icon: true }, + include: ["**/*.svg", "**/*.svg?react"], + exclude: [], + }), + react(), + ], + // FIXME::(klaus) test it + base: "/pages/tagoio-integration", + esbuild: { + target: ["chrome58", "safari11"], + }, + build: { + minify: true, + sourcemap: false, + // FIXME:(klaus) ./build/front/index.js ? + // FIXME:(klaus) ./build/front/index.html ? + outDir: buildPath, + }, + // FIXME:(klaus) see what tests this has, fix config if needed + test: { + environment: "jsdom", + globals: true, + // setupFiles: ["./utils/setup-tests.ts"], + }, + define: { + "process.env.TAGOIO_API": `"${TAGOIO_API}"`, + "process.env.TAGO_API": `"${TAGOIO_API}"`, + "process.env.TAGOIO_REALTIME": `"${TAGOIO_REALTIME}"`, + "process.env.TAGO_REALTIME": `"${TAGOIO_REALTIME}"`, + }, +}); From 1ec0886a5f08160edd9c35f575cfe9054f946fa7 Mon Sep 17 00:00:00 2001 From: Klaus Borges Date: Tue, 29 Oct 2024 11:03:07 -0300 Subject: [PATCH 11/27] fix: import png on Vite, organize shared front end dependencies on main package --- package-lock.json | 1777 +++++------------ package.json | 23 +- packages/console/package.json | 15 +- plugins/tagoio-integration/package.json | 6 +- .../src/front/Details/Details.tsx | 2 +- 5 files changed, 493 insertions(+), 1330 deletions(-) diff --git a/package-lock.json b/package-lock.json index eeebee4e..a747dbfe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,14 +24,14 @@ "md5": "2.3.0", "nanoid": "5.0.7", "ora": "8.1.0", - "polished": "4.1.3", + "polished": "4.3.1", "qs": "6.10.1", "react": "18.3.1", "react-dom": "18.3.1", "semver": "7.6.3", "socket.io": "4.4.1", "socket.io-client": "4.4.1", - "styled-components": "5.3.5", + "styled-components": "6.1.13", "systeminformation": "5.23.5", "uuid": "10.0.0", "zod": "3.23.8" @@ -43,8 +43,10 @@ "@biomejs/biome": "1.9.3", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", - "@testing-library/jest-dom": "5.14.1", - "@testing-library/react": "12.0.0", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.6.2", + "@testing-library/react": "16.0.1", + "@testing-library/user-event": "14.5.2", "@types/async": "3.2.24", "@types/axios": "0.14.0", "@types/cors": "2.8.17", @@ -53,17 +55,18 @@ "@types/md5": "2.3.5", "@types/ms": "0.7.34", "@types/node": "20.14.8", - "@types/react": "17.0.14", - "@types/react-dom": "17.0.9", - "@types/react-router": "5.1.16", - "@types/react-router-dom": "5.1.8", + "@types/react": "18.3.12", + "@types/react-dom": "18.3.1", "@types/semver": "7.5.8", - "@types/styled-components": "5.1.11", "@types/uuid": "10.0.0", + "@vitejs/plugin-react-swc": "3.7.1", "concurrently": "9.0.1", "esbuild": "0.24.0", + "jsdom": "25.0.1", "ts-node": "10.9.2", "typescript": "5.6.3", + "vite": "5.4.10", + "vite-plugin-svgr": "4.2.0", "vitest": "2.1.3" }, "engines": { @@ -101,6 +104,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -114,6 +118,7 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -1025,6 +1030,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.0.tgz", "integrity": "sha512-INCKxTtbXtcNbUZ3YXutwMpEleqttcswhAdee7dhuoVrD2cnuc3PqtERBtxkX5nziX9vnBL8WXmSGwv8CuPV6g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -1039,6 +1045,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.0.tgz", "integrity": "sha512-qETICbZSLe7uXv9VE8T/RWOdIE5qqyTucOt4zLYMafj2MRO271VGgLd4RACJMeBO37UPWhXiKMBk7YlJ0fOzQA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1048,6 +1055,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", + "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -1078,6 +1086,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -1087,6 +1096,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.0.tgz", "integrity": "sha512-/AIkAmInnWwgEAJGQr9vY0c66Mj6kjkE2ZPB1PurTRaRAh3U+J45sAQMjQDJdh4WbR3l0x5xkimXBKyBXXAu2w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.26.0", @@ -1103,28 +1113,18 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-compilation-targets": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.25.9", @@ -1137,34 +1137,21 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC" - }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -1178,6 +1165,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.25.9", @@ -1191,19 +1179,11 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", - "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1213,6 +1193,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1222,6 +1203,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -1231,6 +1213,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -1244,6 +1227,7 @@ "version": "7.26.1", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.1.tgz", "integrity": "sha512-reoQYNiAJreZNsJzyrDNzFQ+IQ5JFiIzAHJg9bn94S3l+4++J7RsIhNMoB+lgP/9tpmiAQqspv+xfdxTSzREOw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.26.0" @@ -1255,21 +1239,6 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, "node_modules/@babel/runtime": { "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", @@ -1282,24 +1251,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.0.tgz", - "integrity": "sha512-YXHu5lN8kJCb1LOb9PgV6pvak43X2h4HvRApcN5SdWeaItQOzfn1hgP6jasD6KWQyJDBxrVmA9o9OivlnNJK/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.9", @@ -1314,6 +1270,7 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.25.9", @@ -1332,6 +1289,7 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -1567,16 +1525,10 @@ "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", "license": "MIT" }, - "node_modules/@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", - "license": "MIT" - }, "node_modules/@emotion/unitless": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", - "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { @@ -1998,6 +1950,7 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -2012,6 +1965,7 @@ "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2022,6 +1976,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2031,6 +1986,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2040,6 +1996,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -2294,13 +2251,6 @@ } } }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.24.2", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.2.tgz", @@ -3491,7 +3441,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=10" } @@ -3509,7 +3458,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=10" } @@ -3527,7 +3475,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } @@ -3545,7 +3492,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } @@ -3563,7 +3509,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } @@ -3581,7 +3526,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } @@ -3599,7 +3543,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=10" } @@ -3617,7 +3560,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=10" } @@ -3635,7 +3577,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=10" } @@ -3653,7 +3594,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=10" } @@ -3838,6 +3778,22 @@ "node": ">=18" } }, + "node_modules/@testing-library/dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@testing-library/dom/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3869,40 +3825,40 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "5.14.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", - "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", + "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.9.2", - "@types/testing-library__jest-dom": "^5.9.1", - "aria-query": "^4.2.2", + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", "chalk": "^3.0.0", - "css": "^3.0.0", "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", "redent": "^3.0.0" }, "engines": { - "node": ">=8", + "node": ">=14", "npm": ">=6", "yarn": ">=1" } }, - "node_modules/@testing-library/jest-dom/node_modules/aria-query": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", - "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.10.2", - "@babel/runtime-corejs3": "^7.10.2" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=6.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/@testing-library/jest-dom/node_modules/chalk": { @@ -3919,6 +3875,13 @@ "node": ">=8" } }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, "node_modules/@testing-library/jest-dom/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3933,81 +3896,31 @@ } }, "node_modules/@testing-library/react": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.0.0.tgz", - "integrity": "sha512-sh3jhFgEshFyJ/0IxGltRhwZv2kFKfJ3fN1vTZ6hhMXzz9ZbbcTgmDYM4e+zJv+oiVKKEWZPyqPAh4MQBI65gA==", + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", + "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^8.0.0" + "@babel/runtime": "^7.12.5" }, "engines": { - "node": ">=12" + "node": ">=18" }, "peerDependencies": { - "react": "*", - "react-dom": "*" - } - }, - "node_modules/@testing-library/react/node_modules/@testing-library/dom": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.1.tgz", - "integrity": "sha512-/DiOQ5xBxgdYRC8LNk7U+RWat0S3qRLeIw3ZIkMQ9kkVlRmwD/Eg8k8CqIpD6GW7u20JIUOfMKbxtiLutpjQ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@testing-library/react/node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/@testing-library/react/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@testing-library/react/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" }, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, "node_modules/@testing-library/user-event": { @@ -4232,24 +4145,6 @@ "@types/unist": "*" } }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, "node_modules/@types/http-errors": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", @@ -4389,55 +4284,25 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "17.0.14", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz", - "integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==", + "version": "18.3.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", + "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", "license": "MIT", "dependencies": { "@types/prop-types": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", - "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-router": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.16.tgz", - "integrity": "sha512-8d7nR/fNSqlTFGHti0R3F9WwIertOaaA1UEB8/jr5l5mDMOs4CidEgvvYMw4ivqrBK+vtVLxyTj2P+Pr/dtgzg==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/history": "*", "@types/react": "*" } }, - "node_modules/@types/react-router-dom": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.8.tgz", - "integrity": "sha512-03xHyncBzG0PmDmf8pf3rehtjY0NpUj7TIN46FrT5n1ZWHPZvXz32gUyNboJ+xsL8cpg8bQVLcllptcQHvocrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/history": "*", - "@types/react": "*", - "@types/react-router": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==", - "license": "MIT" - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -4468,34 +4333,12 @@ "@types/send": "*" } }, - "node_modules/@types/styled-components": { - "version": "5.1.11", - "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.11.tgz", - "integrity": "sha512-u8g3bSw9KUiZY+S++gh+LlURGraqBe3MC5I5dygrNjGDHWWQfsmZZRTJ9K9oHU2CqWtxChWmJkDI/gp+TZPQMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/hoist-non-react-statics": "*", - "@types/react": "*", - "csstype": "^3.0.2" - } - }, "node_modules/@types/stylis": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", "license": "MIT" }, - "node_modules/@types/testing-library__jest-dom": { - "version": "5.14.9", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.9.tgz", - "integrity": "sha512-FSYhIjFlfOpGSRyVoMBMuS3ws5ehFQODymf3vlI7U1K8c7PHwWwFY7VREfmsuzHSOnoKs/9/Y983ayOs7eRzqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/jest": "*" - } - }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -4582,10 +4425,20 @@ } } }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/@vitest/pretty-format": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz", - "integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.4.tgz", + "integrity": "sha512-L95zIAkEuTDbUX1IsjRl+vyBSLh3PwLLgKpghl37aCK9Jvw0iP+wKwIFhfjdUtA2myLgjrG6VU6JCFLv8q/3Ww==", "dev": true, "license": "MIT", "dependencies": { @@ -4624,9 +4477,22 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/spy": { + "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz", + "integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz", "integrity": "sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==", "dev": true, "license": "MIT", @@ -4652,6 +4518,19 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz", + "integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^1.2.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -4768,15 +4647,6 @@ "string-width": "^4.1.0" } }, - "node_modules/ansi-align/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/ansi-align/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -4810,27 +4680,21 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -4912,23 +4776,6 @@ "dequal": "^2.0.3" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", @@ -4957,19 +4804,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5034,34 +4868,6 @@ "follow-redirects": "^1.14.8" } }, - "node_modules/babel-plugin-styled-components": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz", - "integrity": "sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==", - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "lodash": "^4.17.21", - "picomatch": "^2.3.1" - }, - "peerDependencies": { - "styled-components": ">= 2" - } - }, - "node_modules/babel-plugin-styled-components/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -5261,13 +5067,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boxen/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/boxen/node_modules/chalk": { @@ -5345,6 +5157,7 @@ "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, "funding": [ { "type": "opencollective", @@ -5491,6 +5304,13 @@ "node": ">=10" } }, + "node_modules/cacache/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true + }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -5542,9 +5362,10 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001673", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001673.tgz", - "integrity": "sha512-WTrjUCSMp3LYX0nE12ECkV0a+e6LC85E0Auz75555/qr78Oc8YWhEPNfDd6SHdtlCMSzqtuXY0uyEMNRcsKpKw==", + "version": "1.0.30001674", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001674.tgz", + "integrity": "sha512-jOsKlZVRnzfhLojb+Ykb+gyUSp9Xb57So+fAiFlLzzTKpqg8xxSav0e40c8/4F/v9N8QSvrRRaLeVzQbLqomYw==", + "dev": true, "funding": [ { "type": "opencollective", @@ -5738,16 +5559,6 @@ "node": ">=12" } }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/cliui/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5996,6 +5807,22 @@ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" } }, + "node_modules/concurrently/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/concurrently/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -6058,6 +5885,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -6075,18 +5903,6 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "license": "MIT" }, - "node_modules/core-js-pure": { - "version": "3.38.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.38.1.tgz", - "integrity": "sha512-BY8Etc1FZqdw1glX0XNOq2FDwfrg/VGqoZOZCdaL+UmdaqDwQwYXkMJT4t6In+zfEfOJDcM9T0KdbBeJg8KKCQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -6182,18 +5998,6 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, - "node_modules/css": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz", - "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "source-map": "^0.6.1", - "source-map-resolve": "^0.6.0" - } - }, "node_modules/css-color-keywords": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", @@ -6345,16 +6149,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decode-uri-component": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", - "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -6380,46 +6174,6 @@ "node": ">=6" } }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, "node_modules/deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", @@ -6446,24 +6200,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -6631,9 +6367,10 @@ "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.47", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.47.tgz", - "integrity": "sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==", + "version": "1.5.49", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.49.tgz", + "integrity": "sha512-ZXfs1Of8fDb6z7WEYZjXpgIRF6MEu8JdeGA0A40aZq6OQbS+eJpnnV49epZRna2DU/YsEjSQuGtQPPtvt6J65A==", + "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { @@ -6721,6 +6458,27 @@ "yeast": "0.1.2" } }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/engine.io-parser": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", @@ -6739,6 +6497,27 @@ "node": ">= 0.6" } }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -6800,34 +6579,6 @@ "node": ">= 0.4" } }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, "node_modules/esbuild": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", @@ -6903,14 +6654,11 @@ } }, "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } + "license": "MIT" }, "node_modules/etag": { "version": "1.8.1", @@ -7290,16 +7038,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gauge": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", @@ -7321,16 +7059,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/gauge/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -7386,6 +7114,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7500,6 +7229,7 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -7524,16 +7254,6 @@ "license": "ISC", "optional": true }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -7659,21 +7379,6 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "license": "BSD-3-Clause", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" - }, "node_modules/html-encoding-sniffer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", @@ -7793,16 +7498,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -7860,21 +7555,6 @@ "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -7956,23 +7636,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -7980,36 +7643,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -8043,22 +7676,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-decimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", @@ -8122,35 +7739,6 @@ "license": "MIT", "optional": true }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -8176,84 +7764,6 @@ "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", "license": "MIT" }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-typed-array": { "version": "1.1.13", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", @@ -8281,36 +7791,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", - "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -8339,6 +7819,21 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -8391,6 +7886,21 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/jest-matcher-utils/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -8494,32 +8004,11 @@ } } }, - "node_modules/jsdom/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -8539,6 +8028,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -8627,11 +8117,20 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "license": "MIT" }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/lodash": { @@ -8743,12 +8242,13 @@ } }, "node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", - "engines": { - "node": ">=12" + "dependencies": { + "yallist": "^3.0.2" } }, "node_modules/lru.min": { @@ -8885,6 +8385,13 @@ "node": ">=10" } }, + "node_modules/make-fetch-happen/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -9731,6 +9238,12 @@ "node": ">=8" } }, + "node_modules/minipass/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -9744,6 +9257,12 @@ "node": ">= 8" } }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", @@ -9914,6 +9433,15 @@ "node": ">=12.0.0" } }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/nan": { "version": "2.22.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.0.tgz", @@ -10012,6 +9540,7 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, "license": "MIT" }, "node_modules/nopt": { @@ -10075,52 +9604,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -10587,12 +10070,12 @@ } }, "node_modules/polished": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz", - "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", + "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.14.0" + "@babel/runtime": "^7.17.8" }, "engines": { "node": ">=10" @@ -10608,10 +10091,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "funding": [ { "type": "opencollective", @@ -10629,8 +10111,8 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.1.0", - "source-map-js": "^1.2.1" + "picocolors": "^1.0.0", + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -10646,7 +10128,6 @@ "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -10751,27 +10232,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -10833,10 +10293,14 @@ } }, "node_modules/punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", - "license": "MIT" + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, "node_modules/qs": { "version": "6.10.1", @@ -11078,25 +10542,6 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "license": "MIT" }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/remark-parse": { "version": "11.0.0", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", @@ -11164,12 +10609,13 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/restore-cursor": { @@ -11443,22 +10889,6 @@ "node": ">= 0.4" } }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -11625,7 +11055,7 @@ "node": ">=10.0.0" } }, - "node_modules/socket.io-parser": { + "node_modules/socket.io-client/node_modules/socket.io-parser": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", @@ -11638,7 +11068,7 @@ "node": ">=10.0.0" } }, - "node_modules/socket.io/node_modules/socket.io-parser": { + "node_modules/socket.io-parser": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.0.5.tgz", "integrity": "sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig==", @@ -11714,18 +11144,6 @@ "node": ">=0.10.0" } }, - "node_modules/source-map-resolve": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz", - "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "license": "MIT", - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0" - } - }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", @@ -11844,19 +11262,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/stream-shift": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", @@ -11923,6 +11328,18 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -11961,25 +11378,23 @@ } }, "node_modules/styled-components": { - "version": "5.3.5", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.5.tgz", - "integrity": "sha512-ndETJ9RKaaL6q41B69WudeqLzOpY1A/ET/glXkNZ2T7dPjPqpPCXXQjDFYZWwNnE5co0wX+gTCqx9mfxTmSIPg==", - "hasInstallScript": true, + "version": "6.1.13", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", + "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.0.0", - "@babel/traverse": "^7.4.5", - "@emotion/is-prop-valid": "^1.1.0", - "@emotion/stylis": "^0.8.4", - "@emotion/unitless": "^0.7.4", - "babel-plugin-styled-components": ">= 1.12.0", - "css-to-react-native": "^3.0.0", - "hoist-non-react-statics": "^3.0.0", - "shallowequal": "^1.1.0", - "supports-color": "^5.5.0" + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.38", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" }, "engines": { - "node": ">=10" + "node": ">= 16" }, "funding": { "type": "opencollective", @@ -11987,30 +11402,14 @@ }, "peerDependencies": { "react": ">= 16.8.0", - "react-dom": ">= 16.8.0", - "react-is": ">= 16.8.0" - } - }, - "node_modules/styled-components/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" + "react-dom": ">= 16.8.0" } }, - "node_modules/styled-components/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "node_modules/styled-components/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" }, "node_modules/stylis": { "version": "4.3.2", @@ -12194,6 +11593,12 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, "node_modules/tarn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", @@ -12297,22 +11702,22 @@ } }, "node_modules/tldts": { - "version": "6.1.56", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.56.tgz", - "integrity": "sha512-2PT1oRZCxtsbLi5R2SQjE/v4vvgRggAtVcYj+3Rrcnu2nPZvu7m64+gDa/EsVSWd3QzEc0U0xN+rbEKsJC47kA==", + "version": "6.1.57", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.57.tgz", + "integrity": "sha512-Oy7yDXK8meJl8vPMOldzA+MtueAJ5BrH4l4HXwZuj2AtfoQbLjmTJmjNWPUcAo+E/ibHn7QlqMS0BOcXJFJyHQ==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.56" + "tldts-core": "^6.1.57" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.56", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.56.tgz", - "integrity": "sha512-Ihxv/Bwiyj73icTYVgBUkQ3wstlCglLoegSgl64oSrGUBX1hc7Qmf/CnrnJLaQdZrCnTaLqMYOwKMKlkfkFrxQ==", + "version": "6.1.57", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.57.tgz", + "integrity": "sha512-lXnRhuQpx3zU9EONF9F7HfcRLvN1uRYUBIiKL+C/gehC/77XTU+Jye6ui86GA3rU6FjlJ0triD1Tkjt2F/2lEg==", "dev": true, "license": "MIT" }, @@ -12351,16 +11756,6 @@ "node": ">=18" } }, - "node_modules/tr46/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -12624,6 +12019,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -12670,6 +12066,12 @@ "requires-port": "^1.0.0" } }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==", + "license": "MIT" + }, "node_modules/use-sync-external-store": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", @@ -13291,16 +12693,64 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/vitest": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz", - "integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==", + "node_modules/vite/node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "2.1.3", - "@vitest/mocker": "2.1.3", - "@vitest/pretty-format": "^2.1.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/vite/node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/vitest": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz", + "integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "2.1.3", + "@vitest/mocker": "2.1.3", + "@vitest/pretty-format": "^2.1.3", "@vitest/runner": "2.1.3", "@vitest/snapshot": "2.1.3", "@vitest/spy": "2.1.3", @@ -13445,42 +12895,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/which-typed-array": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", @@ -13527,16 +12941,6 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/wide-align/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/wide-align/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13584,15 +12988,6 @@ "node": ">=8" } }, - "node_modules/widest-line/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/widest-line/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13642,13 +13037,19 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/emoji-regex": { @@ -13690,16 +13091,17 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -13777,9 +13179,10 @@ } }, "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yargs": { @@ -13811,16 +13214,6 @@ "node": ">=12" } }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/yargs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -13910,231 +13303,16 @@ "lodash.clonedeep": "4.5.0", "mobx": "6.13.5", "mobx-react": "9.1.1", - "polished": "4.3.1", "react-helmet-async": "2.0.5", "react-markdown": "9.0.1", "react-router": "6.27.0", "react-router-dom": "6.27.0", - "socket.io-client": "4.4.1", - "styled-components": "6.1.13", "swr": "2.2.5" }, "devDependencies": { - "@testing-library/dom": "10.4.0", - "@testing-library/jest-dom": "6.6.2", - "@testing-library/react": "16.0.1", - "@testing-library/user-event": "14.5.2", - "@types/lodash.clonedeep": "4.5.9", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react-swc": "3.7.1", - "jsdom": "25.0.1", - "vite": "5.4.10", - "vite-plugin-svgr": "4.2.0" + "@types/lodash.clonedeep": "4.5.9" } }, - "packages/console/node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", - "license": "MIT" - }, - "packages/console/node_modules/@testing-library/jest-dom": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.2.tgz", - "integrity": "sha512-P6GJD4yqc9jZLbe98j/EkyQDTPgqftohZF5FBkHY5BUERZmcf4HeO2k0XaefEg329ux2p21i1A1DmyQ1kKw2Jw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "lodash": "^4.17.21", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "packages/console/node_modules/@testing-library/react": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.0.1.tgz", - "integrity": "sha512-dSmwJVtJXmku+iocRhWOUFbrERC76TX2Mnf0ATODz8brzAZrMBbzLwQixlBSanZxR6LddK3eiwpSFZgDET1URg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0", - "@types/react-dom": "^18.0.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "packages/console/node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.0.2" - } - }, - "packages/console/node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, - "packages/console/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/console/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, - "packages/console/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "packages/console/node_modules/polished": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz", - "integrity": "sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.8" - }, - "engines": { - "node": ">=10" - } - }, - "packages/console/node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.2.0" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "packages/console/node_modules/styled-components": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.13.tgz", - "integrity": "sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==", - "license": "MIT", - "dependencies": { - "@emotion/is-prop-valid": "1.2.2", - "@emotion/unitless": "0.8.1", - "@types/stylis": "4.2.5", - "css-to-react-native": "3.2.0", - "csstype": "3.1.3", - "postcss": "8.4.38", - "shallowequal": "1.1.0", - "stylis": "4.3.2", - "tslib": "2.6.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/styled-components" - }, - "peerDependencies": { - "react": ">= 16.8.0", - "react-dom": ">= 16.8.0" - } - }, - "packages/console/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/console/node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "license": "0BSD" - }, "packages/sdk": { "name": "@tago-io/tcore-sdk", "version": "0.7.0", @@ -14301,7 +13479,6 @@ "path-browserify": "1.0.1" }, "devDependencies": { - "@testing-library/user-event": "14.5.2", "@types/eventsource": "^1.1.15" } } diff --git a/package.json b/package.json index 3f3610ac..32f861d1 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "luxon": "3.5.0", "nanoid": "5.0.7", "md5": "2.3.0", - "polished": "4.1.3", + "polished": "4.3.1", "ora": "8.1.0", "qs": "6.10.1", "react": "18.3.1", @@ -46,17 +46,19 @@ "semver": "7.6.3", "socket.io": "4.4.1", "socket.io-client": "4.4.1", - "styled-components": "5.3.5", + "styled-components": "6.1.13", "systeminformation": "5.23.5", "uuid": "10.0.0", "zod": "3.23.8" }, "devDependencies": { - "@testing-library/jest-dom": "5.14.1", - "@testing-library/react": "12.0.0", "@biomejs/biome": "1.9.3", "@swc-node/register": "1.10.9", "@tago-io/tcore-sdk": "0.7.2", + "@testing-library/dom": "10.4.0", + "@testing-library/jest-dom": "6.6.2", + "@testing-library/react": "16.0.1", + "@testing-library/user-event": "14.5.2", "@types/async": "3.2.24", "@types/axios": "0.14.0", "@types/express": "5.0.0", @@ -67,15 +69,16 @@ "@types/cors": "2.8.17", "@types/uuid": "10.0.0", "@types/md5": "2.3.5", - "@types/react-router": "5.1.16", - "@types/react-router-dom": "5.1.8", - "@types/react": "17.0.14", - "@types/react-dom": "17.0.9", - "@types/styled-components": "5.1.11", + "@types/react": "18.3.12", + "@types/react-dom": "18.3.1", + "@vitejs/plugin-react-swc": "3.7.1", "concurrently": "9.0.1", "esbuild": "0.24.0", + "jsdom": "25.0.1", "ts-node": "10.9.2", "typescript": "5.6.3", - "vitest": "2.1.3" + "vitest": "2.1.3", + "vite": "5.4.10", + "vite-plugin-svgr": "4.2.0" } } diff --git a/packages/console/package.json b/packages/console/package.json index 97736611..0840f885 100644 --- a/packages/console/package.json +++ b/packages/console/package.json @@ -17,26 +17,13 @@ "lodash.clonedeep": "4.5.0", "mobx": "6.13.5", "mobx-react": "9.1.1", - "polished": "4.3.1", "react-helmet-async": "2.0.5", "react-markdown": "9.0.1", "react-router": "6.27.0", "react-router-dom": "6.27.0", - "socket.io-client": "4.4.1", - "styled-components": "6.1.13", "swr": "2.2.5" }, "devDependencies": { - "@testing-library/dom": "10.4.0", - "@testing-library/jest-dom": "6.6.2", - "@testing-library/react": "16.0.1", - "@testing-library/user-event": "14.5.2", - "@types/lodash.clonedeep": "4.5.9", - "@types/react": "18.3.12", - "@types/react-dom": "18.3.1", - "@vitejs/plugin-react-swc": "3.7.1", - "jsdom": "25.0.1", - "vite": "5.4.10", - "vite-plugin-svgr": "4.2.0" + "@types/lodash.clonedeep": "4.5.9" } } diff --git a/plugins/tagoio-integration/package.json b/plugins/tagoio-integration/package.json index be11fdd1..65b84e21 100644 --- a/plugins/tagoio-integration/package.json +++ b/plugins/tagoio-integration/package.json @@ -41,10 +41,6 @@ "eventsource": "^2.0.2" }, "devDependencies": { - "@testing-library/user-event": "14.5.2", - "@types/eventsource": "^1.1.15", - "@vitejs/plugin-react-swc": "3.7.1", - "vite": "5.4.10", - "vite-plugin-svgr": "4.2.0" + "@types/eventsource": "^1.1.15" } } diff --git a/plugins/tagoio-integration/src/front/Details/Details.tsx b/plugins/tagoio-integration/src/front/Details/Details.tsx index 29fb9405..561db2ed 100644 --- a/plugins/tagoio-integration/src/front/Details/Details.tsx +++ b/plugins/tagoio-integration/src/front/Details/Details.tsx @@ -19,7 +19,7 @@ import { io } from "socket.io-client"; import { useTheme } from "styled-components"; import * as Style from "./Details.style"; -const imgDesert = require("../../../assets/desert.png"); +import imgDesert from "../../../assets/desert.png"; /** * Props. From 13a2beb5963cfea8557cb764e0b038f6d3370b74 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 18:15:59 -0300 Subject: [PATCH 12/27] Changing the way of the connection with tagoio to SSE --- Justfile | 4 +++ .../src/back/RealtimeConnection.ts | 11 +++++-- .../tagoio-integration/src/back/Request.ts | 33 ++++--------------- plugins/tagoio-integration/src/back/Server.ts | 30 +++++++++-------- .../src/front/Auth/Auth.tsx | 3 +- .../src/front/Details/Details.tsx | 1 - 6 files changed, 37 insertions(+), 45 deletions(-) diff --git a/Justfile b/Justfile index a5bf16b3..85d5eef1 100644 --- a/Justfile +++ b/Justfile @@ -19,6 +19,10 @@ build-console: @rm -rf build/console @cd packages/console && npm run build +build-integration: + @rm -rf plugins/tagoio-integration/build + @cd plugins/tagoio-integration && npm run build + ########################### INFRA diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts index a99f3d7a..06c72929 100644 --- a/plugins/tagoio-integration/src/back/RealtimeConnection.ts +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -1,6 +1,6 @@ import os from "node:os"; import { URLSearchParams } from "node:url"; -import { core, helpers } from "@tago-io/tcore-sdk"; +import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; import EventSource from "eventsource"; @@ -20,11 +20,16 @@ function startRealtimeCommunication(token: string) { const channel = "commands"; const params = new URLSearchParams({ token, channel }); - const url = `https://sse.tago.io/events?${params.toString()}`; + const url = `${process.env.TAGOIO_SSE}/events?${params.toString()}`; const connect = () => { events = new EventSource(url); + events.onopen = async () => { + const tcore = await pluginStorage.get("tcore").catch(() => null); + await emitStartData(token, tcore.id); + }; + events.onmessage = async (event) => { console.log("Received event", event); switch (event.data.channel) { @@ -94,7 +99,7 @@ async function emitStartData(token: string, connID: string) { tcore_start_time: tcoreStartTime, tcore_version: "0.7.0", }; - + console.log("Start data", connID); const response = await sendDataToTagoio(token, startData, connID, "update-tcore"); console.info("Start data sent", response); } diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index a7acc003..330637b8 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -1,30 +1,4 @@ import axios from "axios"; -import { getMachineID } from "./Helpers.ts"; -import Account from "@tago-io/sdk/out/modules/Account/Account.js"; - - - -/** - * Lists all instances that have the current machine id. - */ -async function listTCoresByMachineID(token: string) { - const machine_id = getMachineID(); - const account = new Account({ token, region: "env" }); - const response = await account.tagocores.list({ - fields: ["id", "token"], - filter: { machine_id } as any, - }); - return response; -} - -/** - * Creates a new instance with the given data. - */ -async function updateTCore(token: string, tcoreID: string, data: any) { - const account = new Account({ token, region: "env" }); - const response = await account.tagocores.edit(tcoreID, data); - return response; -} /** * Creates a new instance with the given data. @@ -43,6 +17,11 @@ async function createTCore(token: string, data: any) { * Send data to Tagoio. */ async function sendDataToTagoio(token: string, data: any, connId: string, operation: string) { + const teste = { + operation, + data, + }; + console.log(teste); const response = await axios({ url: `${process.env.TAGOIO_API}/tcore/${connId}`, method: "POST", @@ -55,4 +34,4 @@ async function sendDataToTagoio(token: string, data: any, connId: string, operat return response.data.result; } -export { updateTCore, createTCore, listTCoresByMachineID, sendDataToTagoio }; +export { createTCore, sendDataToTagoio }; diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts index 97fd1558..417a4836 100644 --- a/plugins/tagoio-integration/src/back/Server.ts +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -1,14 +1,15 @@ import http from "node:http"; import os from "node:os"; -import { helpers, pluginStorage } from "@tago-io/tcore-sdk"; +import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; import bodyParser from "body-parser"; import cors from "cors"; import express, { type Request, type Response } from "express"; import pkg from "../../package.json" with { type: "json" }; import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; -import { createTCore, listTCoresByMachineID, updateTCore } from "./Request.ts"; +import { createTCore, sendDataToTagoio } from "./Request.ts"; import { closeRealtimeConnection, startRealtimeCommunication } from "./RealtimeConnection.ts"; +import Tags from "@tago-io/sdk/out/modules/Account/Tags"; let server: http.Server | null = null; @@ -46,10 +47,11 @@ function closeServer() { /** */ -function routeGetTCore(req: Request, res: Response) { - if (cache.tcore) { +async function routeGetTCore(req: Request, res: Response) { + const tcore = await pluginStorage.get("tcore").catch(() => null); + if (tcore) { res.status(200); - res.send({ status: true, result: cache.tcore }); + res.send({ status: true, result: tcore }); } else { res.status(404); res.send({ status: false }); @@ -61,7 +63,7 @@ function routeGetTCore(req: Request, res: Response) { async function routeSignOut(req: Request, res: Response) { await pluginStorage.delete("token"); closeRealtimeConnection(); - cache.tcore = null; + pluginStorage.delete("tcore"); res.sendStatus(200); } @@ -72,12 +74,10 @@ async function routeStartTCore(req: Request, res: Response) { const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); const osInfo = await helpers.getOSInfo(); const profileToken = req.headers.token as string; - - const list = await listTCoresByMachineID(profileToken).catch(() => null); - const item = list?.[0] as any; + const item = await pluginStorage.get("tcore").catch(() => null); if (item?.token) { - await updateTCore(profileToken, item.id, { name: req.body.name }); + await sendDataToTagoio(profileToken, { name: req.body.name }, item.id, "update-tcore-connect"); await pluginStorage.set("token", item?.token); await startRealtimeCommunication(item?.token); res.sendStatus(200); @@ -97,9 +97,13 @@ async function routeStartTCore(req: Request, res: Response) { }); if (data) { - await pluginStorage.set("token", data?.token); - await startRealtimeCommunication(data?.token); - res.sendStatus(200); + const tcore = await sendDataToTagoio(profileToken, { summary: true }, data.id, "get-tcore"); + if (tcore) { + await pluginStorage.set("token", data?.token); + await pluginStorage.set("tcore", tcore); + await startRealtimeCommunication(data?.token); + res.sendStatus(200); + } } } diff --git a/plugins/tagoio-integration/src/front/Auth/Auth.tsx b/plugins/tagoio-integration/src/front/Auth/Auth.tsx index d0cad995..6af2e91e 100644 --- a/plugins/tagoio-integration/src/front/Auth/Auth.tsx +++ b/plugins/tagoio-integration/src/front/Auth/Auth.tsx @@ -11,7 +11,8 @@ import Otp from "./Otp/Otp.tsx"; import OtpPicker from "./OtpPicker/OtpPicker.tsx"; import Profiles from "./Profiles/Profiles.tsx"; -const API_URL = process.env.TAGOIO_API; +// const API_URL = process.env.TAGOIO_API; +const API_URL = "http://localhost:3000"; /** * Props. diff --git a/plugins/tagoio-integration/src/front/Details/Details.tsx b/plugins/tagoio-integration/src/front/Details/Details.tsx index 561db2ed..2c2c8ea3 100644 --- a/plugins/tagoio-integration/src/front/Details/Details.tsx +++ b/plugins/tagoio-integration/src/front/Details/Details.tsx @@ -18,7 +18,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { io } from "socket.io-client"; import { useTheme } from "styled-components"; import * as Style from "./Details.style"; - import imgDesert from "../../../assets/desert.png"; /** From ed0b304ca5d96ea135cd4e88a38bd32110f5ff4b Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Tue, 29 Oct 2024 18:40:02 -0300 Subject: [PATCH 13/27] Changing the way of the connection with tagoio to SSE --- plugins/tagoio-integration/src/back/Request.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index 330637b8..83fcc55c 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -17,13 +17,8 @@ async function createTCore(token: string, data: any) { * Send data to Tagoio. */ async function sendDataToTagoio(token: string, data: any, connId: string, operation: string) { - const teste = { - operation, - data, - }; - console.log(teste); const response = await axios({ - url: `${process.env.TAGOIO_API}/tcore/${connId}`, + url: `${process.env.TAGOIO_API}/tcore/sse/${connId}`, method: "POST", headers: { token }, data: { From 2523fb1219fac39b4d96c143ef44ce459ee35441 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Wed, 30 Oct 2024 17:29:11 -0300 Subject: [PATCH 14/27] Changing the way of the connection with tagoio to SSE --- plugins/tagoio-integration/src/back/Global.ts | 24 +++---- .../src/back/RealtimeConnection.ts | 64 +++++++++++-------- .../tagoio-integration/src/back/Request.ts | 42 +++++++----- plugins/tagoio-integration/src/back/Server.ts | 14 ++-- .../src/front/Auth/Auth.tsx | 3 +- 5 files changed, 83 insertions(+), 64 deletions(-) diff --git a/plugins/tagoio-integration/src/back/Global.ts b/plugins/tagoio-integration/src/back/Global.ts index 09f93941..204f44fd 100644 --- a/plugins/tagoio-integration/src/back/Global.ts +++ b/plugins/tagoio-integration/src/back/Global.ts @@ -1,19 +1,9 @@ -import type { SystemModule } from "@tago-io/tcore-sdk"; -import type EventSource from "eventsource"; +import type { SystemModule } from "@tago-io/tcore-sdk"; +import type { Server } from "socket.io"; interface ICommandQueueItem { - type: - | "install" - | "settings" - | "uninstall" - | "disable" - | "enable" - | "startModule" - | "stopModule" - | "setMasterPassword" - | "factoryReset" - | "setDatabasePlugin"; + type: "install" | "settings" | "uninstall" | "disable" | "enable" | "startModule" | "stopModule" | "setMasterPassword" | "factoryReset" | "setDatabasePlugin"; promise: { resolve: Function; reject: Function; @@ -32,18 +22,22 @@ interface IStateQueueItem { interface IObjects { tcore: any; - realtimeConnection: EventSource | null; + serverIO: Server | null; commandsQueue: ICommandQueueItem[]; stateQueue: IStateQueueItem[]; systemModule: SystemModule | null; + attachedDevices: Array; + events: any; } const cache: IObjects = { tcore: null, - realtimeConnection: null, + serverIO: null, commandsQueue: [], stateQueue: [], systemModule: null, + attachedDevices: [], + events: null, }; export { cache }; diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts index 06c72929..7c769164 100644 --- a/plugins/tagoio-integration/src/back/RealtimeConnection.ts +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -1,15 +1,17 @@ import os from "node:os"; import { URLSearchParams } from "node:url"; import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; -import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; import EventSource from "eventsource"; import { sendDataToTagoio } from "./Request.ts"; +import { cache } from "./Global.ts"; + +let events: EventSource | null = null; +const pingInterval = 240000; /** * Eventsource used to communicate with the API. */ -let events: EventSource | null = null; /** */ @@ -24,42 +26,38 @@ function startRealtimeCommunication(token: string) { const connect = () => { events = new EventSource(url); + let pingFunction: NodeJS.Timeout | undefined = undefined; events.onopen = async () => { const tcore = await pluginStorage.get("tcore").catch(() => null); + cache.events = events; await emitStartData(token, tcore.id); + pingFunction = setInterval(async () => { + await emitStartData(token, tcore.id); + console.log("enviou"); + }, pingInterval); }; events.onmessage = async (event) => { - console.log("Received event", event); - switch (event.data.channel) { - case "sse::commands": - console.info("Connected to TagoIO"); - emitStartData(token, event.data.connID); - break; - case "sse::instance": - cache.tcore = event.data.tcore; - break; - case "sse::summary": { - const summary = await core.getSummary(); - const response = await sendDataToTagoio(token, summary, event.data.connID, "update-summary-tcore"); - console.info("Summary sent", response); - break; - } - case "sse::summary-and-computer-usage": { + const messageData = JSON.parse(event.data); + const connID = messageData.channel.slice(9); + switch (messageData.payload) { + case "summary-computer-usage": { const data = await Promise.all([ core.getSummary(), helpers.getComputerUsage(), ]); - const response = await sendDataToTagoio(token, { summary: data[0], computer_usage: data[1] }, event.data.connID, "summary-computer-usage-tcore"); - console.info("Summary and Computer Usage sent", response); + const response = await sendDataToTagoio(token, { summary: data[0], computer_usage: data[1] }, connID, "summary-computer-usage-tcore"); + if (response) { + cache.serverIO?.emit("event", "summary-computer-usage", "sse::summary-computer-usage", Date.now(), response); + } break; } - case "sse::disconnect": - events?.close(); + case "disconnect": + closeRealtimeConnection(); break; default: - console.error("Unknown event channel", event.data.channel); + console.error("Unknown event payload", messageData.payload); } }; @@ -67,7 +65,8 @@ function startRealtimeCommunication(token: string) { events.onerror = (error: any) => { console.error("EventSource encountered an error:", error); if (events) { - events.close(); + closeRealtimeConnection(); + clearInterval(pingFunction); } setTimeout(connect, 5000); }; @@ -81,6 +80,7 @@ function startRealtimeCommunication(token: string) { function closeRealtimeConnection() { events?.close(); events = null; + cache.events = null; } /** @@ -90,6 +90,10 @@ async function emitStartData(token: string, connID: string) { const systemStartTime = new Date(Date.now() - os.uptime() * 1000); const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); const osInfo = await helpers.getOSInfo(); + const data = await Promise.all([ + core.getSummary(), + helpers.getComputerUsage(), + ]); const startData = { machine_id: getMachineID(), local_ips: getLocalIPs().join(", "), @@ -98,10 +102,18 @@ async function emitStartData(token: string, connID: string) { system_start_time: systemStartTime, tcore_start_time: tcoreStartTime, tcore_version: "0.7.0", + summary: data[0], + computer_usage: data[1], + last_ping: Date.now(), }; - console.log("Start data", connID); const response = await sendDataToTagoio(token, startData, connID, "update-tcore"); - console.info("Start data sent", response); + if (response) { + const tcore = await sendDataToTagoio(token, { summary: true }, connID, "get-tcore"); + if (tcore) { + await pluginStorage.set("tcore", tcore); + cache.serverIO?.emit("event", "connected", "sse::commands", Date.now(), tcore); + } + } } /** diff --git a/plugins/tagoio-integration/src/back/Request.ts b/plugins/tagoio-integration/src/back/Request.ts index 83fcc55c..325ca17b 100644 --- a/plugins/tagoio-integration/src/back/Request.ts +++ b/plugins/tagoio-integration/src/back/Request.ts @@ -4,29 +4,37 @@ import axios from "axios"; * Creates a new instance with the given data. */ async function createTCore(token: string, data: any) { - const response = await axios({ - url: `${process.env.TAGOIO_API}/tcore/instance`, - method: "POST", - headers: { token }, - data, - }); - return response.data.result; + try { + const response = await axios({ + url: `${process.env.TAGOIO_API}/tcore/instance`, + method: "POST", + headers: { token }, + data, + }); + return response.data.result; + } catch (error) { + console.error("Error on creating TCore", error); + } } /** * Send data to Tagoio. */ async function sendDataToTagoio(token: string, data: any, connId: string, operation: string) { - const response = await axios({ - url: `${process.env.TAGOIO_API}/tcore/sse/${connId}`, - method: "POST", - headers: { token }, - data: { - operation, - data, - }, - }); - return response.data.result; + try { + const response = await axios({ + url: `${process.env.TAGOIO_API}/tcore/sse/${connId}`, + method: "POST", + headers: { token }, + data: { + operation, + data, + }, + }); + return response.data.result; + } catch (error) { + console.error(`Error on sending operation ${operation}`, error); + } } export { createTCore, sendDataToTagoio }; diff --git a/plugins/tagoio-integration/src/back/Server.ts b/plugins/tagoio-integration/src/back/Server.ts index 417a4836..a0211686 100644 --- a/plugins/tagoio-integration/src/back/Server.ts +++ b/plugins/tagoio-integration/src/back/Server.ts @@ -1,6 +1,6 @@ import http from "node:http"; import os from "node:os"; -import { core, helpers, pluginStorage } from "@tago-io/tcore-sdk"; +import { helpers, pluginStorage } from "@tago-io/tcore-sdk"; import bodyParser from "body-parser"; import cors from "cors"; import express, { type Request, type Response } from "express"; @@ -9,7 +9,7 @@ import { cache } from "./Global.ts"; import { getMachineID } from "./Helpers.ts"; import { createTCore, sendDataToTagoio } from "./Request.ts"; import { closeRealtimeConnection, startRealtimeCommunication } from "./RealtimeConnection.ts"; -import Tags from "@tago-io/sdk/out/modules/Account/Tags"; +import { Server } from "socket.io"; let server: http.Server | null = null; @@ -36,6 +36,13 @@ function initServer() { server = http.createServer(app); server.listen("8999"); + + cache.serverIO = new Server(server); + cache.serverIO.on("connection", () => { + if (cache.events) { + cache.serverIO?.emit("status", { status: true }); + } + }); } /** @@ -63,7 +70,6 @@ async function routeGetTCore(req: Request, res: Response) { async function routeSignOut(req: Request, res: Response) { await pluginStorage.delete("token"); closeRealtimeConnection(); - pluginStorage.delete("tcore"); res.sendStatus(200); } @@ -73,7 +79,7 @@ async function routeStartTCore(req: Request, res: Response) { const systemStartTime = new Date(Date.now() - os.uptime() * 1000); const tcoreStartTime = new Date(Date.now() - process.uptime() * 1000); const osInfo = await helpers.getOSInfo(); - const profileToken = req.headers.token as string; + const profileToken = "p-".concat(req.headers.token as string); const item = await pluginStorage.get("tcore").catch(() => null); if (item?.token) { diff --git a/plugins/tagoio-integration/src/front/Auth/Auth.tsx b/plugins/tagoio-integration/src/front/Auth/Auth.tsx index 6af2e91e..d0cad995 100644 --- a/plugins/tagoio-integration/src/front/Auth/Auth.tsx +++ b/plugins/tagoio-integration/src/front/Auth/Auth.tsx @@ -11,8 +11,7 @@ import Otp from "./Otp/Otp.tsx"; import OtpPicker from "./OtpPicker/OtpPicker.tsx"; import Profiles from "./Profiles/Profiles.tsx"; -// const API_URL = process.env.TAGOIO_API; -const API_URL = "http://localhost:3000"; +const API_URL = process.env.TAGOIO_API; /** * Props. From 4193a23df5cbbbfc70ba5f34c5adf085dea9ed7e Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Thu, 31 Oct 2024 09:10:54 -0300 Subject: [PATCH 15/27] Changing the way of the connection with tagoio to SSE --- plugins/tagoio-integration/src/back/RealtimeConnection.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/tagoio-integration/src/back/RealtimeConnection.ts b/plugins/tagoio-integration/src/back/RealtimeConnection.ts index 7c769164..d6f992eb 100644 --- a/plugins/tagoio-integration/src/back/RealtimeConnection.ts +++ b/plugins/tagoio-integration/src/back/RealtimeConnection.ts @@ -34,7 +34,6 @@ function startRealtimeCommunication(token: string) { await emitStartData(token, tcore.id); pingFunction = setInterval(async () => { await emitStartData(token, tcore.id); - console.log("enviou"); }, pingInterval); }; From ccf29f383d38cab946b075e4a15e7ed2dee50c69 Mon Sep 17 00:00:00 2001 From: Bruno Gelatti Date: Thu, 31 Oct 2024 09:13:48 -0300 Subject: [PATCH 16/27] Changing the way of the connection with tagoio to SSE --- plugins/tagoio-integration/src/front/Details/Details.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/tagoio-integration/src/front/Details/Details.tsx b/plugins/tagoio-integration/src/front/Details/Details.tsx index 2c2c8ea3..b1a46063 100644 --- a/plugins/tagoio-integration/src/front/Details/Details.tsx +++ b/plugins/tagoio-integration/src/front/Details/Details.tsx @@ -219,7 +219,7 @@ function Details(props: IDetailsProps) { tooltip="Which TagoIO Cloud Profile is associated to this TagoCore instance." >
- + {!props.tcore.cluster && (