diff --git a/.github/workflows/build-and-release-desktop.yml b/.github/workflows/build-and-release-desktop.yml index cc0d4d48..99d4e4d8 100644 --- a/.github/workflows/build-and-release-desktop.yml +++ b/.github/workflows/build-and-release-desktop.yml @@ -60,6 +60,10 @@ jobs: run: yarn build working-directory: "desktop/local-app" + - name: "Set desktop app version" + run: node helpers/set-version.js + working-directory: "desktop/electron" + - name: "Install dependencies" run: yarn install --froze-lockfile working-directory: "desktop/electron" @@ -68,15 +72,19 @@ jobs: run: yarn build working-directory: "desktop/electron" - - name: "Build app" - run: yarn bundle --publish never + - name: "Install electron tools" + run: yarn electron-builder install-app-deps + working-directory: "desktop/electron" + + - name: "Build app for testing" + run: yarn electron-builder --publish never env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} working-directory: "desktop/electron" if: ${{ github.event_name != 'release' }} - - name: "Build & publish App" - run: yarn release + - name: "Build & release app" + run: yarn electron-builder --publish always env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} working-directory: "desktop/electron" diff --git a/back/.eslintrc.json b/back/.eslintrc.json index ce78dd63..82ee1e79 100644 --- a/back/.eslintrc.json +++ b/back/.eslintrc.json @@ -26,6 +26,9 @@ "rules": { "no-unused-vars": "off", "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": [ + "error", { "args": "none", "caughtErrors": "all", "varsIgnorePattern": "_exhaustiveCheck" } + ], "no-throw-literal": "error" } } diff --git a/back/package.json b/back/package.json index 4e4c9fc1..1216efcf 100644 --- a/back/package.json +++ b/back/package.json @@ -45,7 +45,6 @@ "busboy": "^0.3.1", "circular-json": "^0.5.9", "debug": "^4.3.1", - "generic-type-guard": "^3.2.0", "google-protobuf": "^3.13.0", "grpc": "^1.24.4", "ipaddr.js": "^2.0.1", @@ -56,7 +55,7 @@ "redis": "^3.1.2", "uWebSockets.js": "uNetworking/uWebSockets.js#v18.5.0", "uuidv4": "^6.0.7", - "zod": "^3.12.0" + "zod": "^3.14.3" }, "devDependencies": { "@types/busboy": "^0.2.3", diff --git a/back/src/Controller/DebugController.ts b/back/src/Controller/DebugController.ts index f571d6b2..9a1b4e01 100644 --- a/back/src/Controller/DebugController.ts +++ b/back/src/Controller/DebugController.ts @@ -48,7 +48,7 @@ export class DebugController { return obj; } else if (value instanceof Set) { const obj: Array = []; - for (const [setKey, setValue] of value.entries()) { + for (const setValue of value.values()) { obj.push(setValue); } return obj; diff --git a/back/src/Controller/PrometheusController.ts b/back/src/Controller/PrometheusController.ts index 7fff3981..3779f7b4 100644 --- a/back/src/Controller/PrometheusController.ts +++ b/back/src/Controller/PrometheusController.ts @@ -1,5 +1,5 @@ import { App } from "../Server/sifrr.server"; -import { HttpRequest, HttpResponse } from "uWebSockets.js"; +import { HttpResponse } from "uWebSockets.js"; import { register, collectDefaultMetrics } from "prom-client"; export class PrometheusController { @@ -11,7 +11,7 @@ export class PrometheusController { this.App.get("/metrics", this.metrics.bind(this)); } - private metrics(res: HttpResponse, req: HttpRequest): void { + private metrics(res: HttpResponse): void { res.writeHeader("Content-Type", register.contentType); res.end(register.metrics()); } diff --git a/back/src/Model/GameRoom.ts b/back/src/Model/GameRoom.ts index 157faa4e..efe7f86a 100644 --- a/back/src/Model/GameRoom.ts +++ b/back/src/Model/GameRoom.ts @@ -1,7 +1,7 @@ import { PointInterface } from "./Websocket/PointInterface"; import { Group } from "./Group"; import { User, UserSocket } from "./User"; -import { PositionInterface } from "_Model/PositionInterface"; +import { PositionInterface } from "../Model/PositionInterface"; import { EmoteCallback, EntersCallback, @@ -9,23 +9,20 @@ import { LockGroupCallback, MovesCallback, PlayerDetailsUpdatedCallback, -} from "_Model/Zone"; +} from "../Model/Zone"; import { PositionNotifier } from "./PositionNotifier"; -import { Movable } from "_Model/Movable"; +import { Movable } from "../Model/Movable"; import { - BatchToPusherMessage, BatchToPusherRoomMessage, EmoteEventMessage, - ErrorMessage, JoinRoomMessage, SetPlayerDetailsMessage, SubToPusherRoomMessage, - VariableMessage, VariableWithTagMessage, ServerToClientMessage, } from "../Messages/generated/messages_pb"; import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils"; -import { RoomSocket, ZoneSocket } from "src/RoomManager"; +import { RoomSocket, ZoneSocket } from "../RoomManager"; import { Admin } from "../Model/Admin"; import { adminApi } from "../Services/AdminApi"; import { isMapDetailsData, MapDetailsData } from "../Messages/JsonMessages/MapDetailsData"; @@ -36,7 +33,6 @@ import { ADMIN_API_URL } from "../Enum/EnvironmentVariable"; import { LocalUrlError } from "../Services/LocalUrlError"; import { emitErrorOnRoomSocket } from "../Services/MessageHelpers"; import { VariableError } from "../Services/VariableError"; -import { isRoomRedirect } from "../Messages/JsonMessages/RoomRedirect"; export type ConnectCallback = (user: User, group: Group) => void; export type DisconnectCallback = (user: User, group: Group) => void; @@ -148,8 +144,8 @@ export class GameRoom { joinRoomMessage.getUseruuid(), joinRoomMessage.getIpaddress(), position, - false, this.positionNotifier, + joinRoomMessage.getStatus(), socket, joinRoomMessage.getTagList(), joinRoomMessage.getVisitcardurl(), @@ -210,10 +206,9 @@ export class GameRoom { } updatePlayerDetails(user: User, playerDetailsMessage: SetPlayerDetailsMessage) { - if (playerDetailsMessage.getRemoveoutlinecolor()) { - user.outlineColor = undefined; - } else { - user.outlineColor = playerDetailsMessage.getOutlinecolor(); + user.updateDetails(playerDetailsMessage); + if (user.group !== undefined && user.silent) { + this.leaveGroup(user); } } @@ -352,21 +347,6 @@ export class GameRoom { }); } - setSilent(user: User, silent: boolean) { - if (user.silent === silent) { - return; - } - - user.silent = silent; - if (silent && user.group !== undefined) { - this.leaveGroup(user); - } - if (!silent) { - // If we are back to life, let's trigger a position update to see if we can join some group. - this.updatePosition(user, user.getPosition()); - } - } - /** * Makes a user leave a group and closes and destroy the group if the group contains only one remaining person. * @@ -402,7 +382,7 @@ export class GameRoom { private searchClosestAvailableUserOrGroup(user: User): User | Group | null { let minimumDistanceFound: number = Math.max(this.minDistance, this.groupRadius); let matchingItem: User | Group | null = null; - this.users.forEach((currentUser, userId) => { + this.users.forEach((currentUser) => { // Let's only check users that are not part of a group if (typeof currentUser.group !== "undefined") { return; @@ -579,21 +559,20 @@ export class GameRoom { return { mapUrl, - policy_type: 1, - tags: [], authenticationMandatory: null, - roomSlug: null, - contactPage: null, group: null, }; } - const result = await adminApi.fetchMapDetails(roomUrl); - if (isRoomRedirect(result)) { - console.error("Unexpected room redirect received while querying map details", result); - throw new Error("Unexpected room redirect received while querying map details"); + const result = isMapDetailsData.safeParse(await adminApi.fetchMapDetails(roomUrl)); + + if (result.success) { + return result.data; } - return result; + + console.error(result.error.issues); + console.error("Unexpected room redirect received while querying map details", result); + throw new Error("Unexpected room redirect received while querying map details"); } private mapPromise: Promise | undefined; diff --git a/back/src/Model/Group.ts b/back/src/Model/Group.ts index a960e7b3..2ed6c695 100644 --- a/back/src/Model/Group.ts +++ b/back/src/Model/Group.ts @@ -1,8 +1,8 @@ import { ConnectCallback, DisconnectCallback, GameRoom } from "./GameRoom"; import { User } from "./User"; -import { PositionInterface } from "_Model/PositionInterface"; -import { Movable } from "_Model/Movable"; -import { PositionNotifier } from "_Model/PositionNotifier"; +import { PositionInterface } from "../Model/PositionInterface"; +import { Movable } from "../Model/Movable"; +import { PositionNotifier } from "../Model/PositionNotifier"; import { MAX_PER_GROUP } from "../Enum/EnvironmentVariable"; import type { Zone } from "../Model/Zone"; diff --git a/back/src/Model/Movable.ts b/back/src/Model/Movable.ts index ca586b7c..19bc8f92 100644 --- a/back/src/Model/Movable.ts +++ b/back/src/Model/Movable.ts @@ -1,4 +1,4 @@ -import { PositionInterface } from "_Model/PositionInterface"; +import { PositionInterface } from "../Model/PositionInterface"; /** * A physical object that can be placed into a Zone diff --git a/back/src/Model/PositionNotifier.ts b/back/src/Model/PositionNotifier.ts index 38d538ec..9dd1c544 100644 --- a/back/src/Model/PositionNotifier.ts +++ b/back/src/Model/PositionNotifier.ts @@ -17,8 +17,8 @@ import { PlayerDetailsUpdatedCallback, Zone, } from "./Zone"; -import { Movable } from "_Model/Movable"; -import { PositionInterface } from "_Model/PositionInterface"; +import { Movable } from "../Model/Movable"; +import { PositionInterface } from "../Model/PositionInterface"; import { ZoneSocket } from "../RoomManager"; import { User } from "../Model/User"; import { EmoteEventMessage, SetPlayerDetailsMessage } from "../Messages/generated/messages_pb"; @@ -45,8 +45,8 @@ export class PositionNotifier { private zones: Zone[][] = []; constructor( - private zoneWidth: number, - private zoneHeight: number, + private readonly zoneWidth: number, + private readonly zoneHeight: number, private onUserEnters: EntersCallback, private onUserMoves: MovesCallback, private onUserLeaves: LeavesCallback, diff --git a/back/src/Model/User.ts b/back/src/Model/User.ts index c6abf52a..b103f240 100644 --- a/back/src/Model/User.ts +++ b/back/src/Model/User.ts @@ -1,10 +1,11 @@ import { Group } from "./Group"; import { PointInterface } from "./Websocket/PointInterface"; -import { Zone } from "_Model/Zone"; -import { Movable } from "_Model/Movable"; -import { PositionNotifier } from "_Model/PositionNotifier"; +import { Zone } from "../Model/Zone"; +import { Movable } from "../Model/Movable"; +import { PositionNotifier } from "../Model/PositionNotifier"; import { ServerDuplexStream } from "grpc"; import { + AvailabilityStatus, BatchMessage, CompanionMessage, FollowAbortMessage, @@ -14,7 +15,8 @@ import { SetPlayerDetailsMessage, SubMessage, } from "../Messages/generated/messages_pb"; -import { CharacterLayer } from "_Model/Websocket/CharacterLayer"; +import { CharacterLayer } from "../Model/Websocket/CharacterLayer"; +import { BoolValue, UInt32Value } from "google-protobuf/google/protobuf/wrappers_pb"; export type UserSocket = ServerDuplexStream; @@ -29,15 +31,16 @@ export class User implements Movable { public readonly uuid: string, public readonly IPAddress: string, private position: PointInterface, - public silent: boolean, private positionNotifier: PositionNotifier, + private status: AvailabilityStatus, public readonly socket: UserSocket, public readonly tags: string[], public readonly visitCardUrl: string | null, public readonly name: string, public readonly characterLayers: CharacterLayer[], public readonly companion?: CompanionMessage, - private _outlineColor?: number | undefined + private outlineColor?: number, + private voiceIndicatorShown?: boolean ) { this.listenedZones = new Set(); @@ -83,6 +86,18 @@ export class User implements Movable { return this.followedBy.size !== 0; } + public getOutlineColor(): number | undefined { + return this.outlineColor; + } + + public getStatus(): AvailabilityStatus { + return this.status; + } + + public get silent(): boolean { + return this.status === AvailabilityStatus.SILENT || this.status === AvailabilityStatus.JITSI; + } + get following(): User | undefined { return this._following; } @@ -115,14 +130,31 @@ export class User implements Movable { } } - public set outlineColor(value: number | undefined) { - this._outlineColor = value; + public updateDetails(details: SetPlayerDetailsMessage) { + if (details.getRemoveoutlinecolor()) { + this.outlineColor = undefined; + } else if (details.getOutlinecolor()?.getValue() !== undefined) { + this.outlineColor = details.getOutlinecolor()?.getValue(); + } + this.voiceIndicatorShown = details.getShowvoiceindicator()?.getValue(); + + const status = details.getStatus(); + let sendStatusUpdate = false; + if (status && status !== this.status) { + this.status = status; + sendStatusUpdate = true; + } const playerDetails = new SetPlayerDetailsMessage(); - if (value === undefined) { - playerDetails.setRemoveoutlinecolor(true); - } else { - playerDetails.setOutlinecolor(value); + + if (this.outlineColor !== undefined) { + playerDetails.setOutlinecolor(new UInt32Value().setValue(this.outlineColor)); + } + if (this.voiceIndicatorShown !== undefined) { + playerDetails.setShowvoiceindicator(new BoolValue().setValue(this.voiceIndicatorShown)); + } + if (sendStatusUpdate) { + playerDetails.setStatus(details.getStatus()); } this.positionNotifier.updatePlayerDetails(this, playerDetails); diff --git a/back/src/Model/Websocket/ItemEventMessage.ts b/back/src/Model/Websocket/ItemEventMessage.ts index 1bb7f615..fd28293e 100644 --- a/back/src/Model/Websocket/ItemEventMessage.ts +++ b/back/src/Model/Websocket/ItemEventMessage.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isItemEventMessageInterface = new tg.IsInterface() - .withProperties({ - itemId: tg.isNumber, - event: tg.isString, - state: tg.isUnknown, - parameters: tg.isUnknown, - }) - .get(); -export type ItemEventMessageInterface = tg.GuardedType; +export const isItemEventMessageInterface = z.object({ + itemId: z.number(), + event: z.string(), + state: z.unknown(), + parameters: z.unknown(), +}); + +export type ItemEventMessageInterface = z.infer; diff --git a/back/src/Model/Websocket/PointInterface.ts b/back/src/Model/Websocket/PointInterface.ts index d7c7826e..2275e5f8 100644 --- a/back/src/Model/Websocket/PointInterface.ts +++ b/back/src/Model/Websocket/PointInterface.ts @@ -1,18 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -/*export interface PointInterface { - readonly x: number; - readonly y: number; - readonly direction: string; - readonly moving: boolean; -}*/ +export const isPointInterface = z.object({ + x: z.number(), + y: z.number(), + direction: z.string(), + moving: z.boolean(), +}); -export const isPointInterface = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - direction: tg.isString, - moving: tg.isBoolean, - }) - .get(); -export type PointInterface = tg.GuardedType; +export type PointInterface = z.infer; diff --git a/back/src/Model/Websocket/ProtobufUtils.ts b/back/src/Model/Websocket/ProtobufUtils.ts index 68817a4f..1b4945c0 100644 --- a/back/src/Model/Websocket/ProtobufUtils.ts +++ b/back/src/Model/Websocket/ProtobufUtils.ts @@ -5,10 +5,10 @@ import { PointMessage, PositionMessage, } from "../../Messages/generated/messages_pb"; -import { CharacterLayer } from "_Model/Websocket/CharacterLayer"; +import { CharacterLayer } from "../../Model/Websocket/CharacterLayer"; import Direction = PositionMessage.Direction; -import { ItemEventMessageInterface } from "_Model/Websocket/ItemEventMessage"; -import { PositionInterface } from "_Model/PositionInterface"; +import { ItemEventMessageInterface } from "../../Model/Websocket/ItemEventMessage"; +import { PositionInterface } from "../../Model/PositionInterface"; export class ProtobufUtils { public static toPositionMessage(point: PointInterface): PositionMessage { diff --git a/back/src/Model/Zone.ts b/back/src/Model/Zone.ts index 2d0cefd5..c595447e 100644 --- a/back/src/Model/Zone.ts +++ b/back/src/Model/Zone.ts @@ -1,5 +1,5 @@ import { User } from "./User"; -import { PositionInterface } from "_Model/PositionInterface"; +import { PositionInterface } from "../Model/PositionInterface"; import { Movable } from "./Movable"; import { Group } from "./Group"; import { ZoneSocket } from "../RoomManager"; diff --git a/back/src/RoomManager.ts b/back/src/RoomManager.ts index ab886f50..7211facb 100644 --- a/back/src/RoomManager.ts +++ b/back/src/RoomManager.ts @@ -15,7 +15,6 @@ import { EmptyMessage, ItemEventMessage, JoinRoomMessage, - PlayGlobalMessage, PusherToBackMessage, QueryJitsiJwtMessage, RefreshRoomPromptMessage, @@ -23,7 +22,6 @@ import { SendUserMessage, ServerToAdminClientMessage, SetPlayerDetailsMessage, - SilentMessage, UserMovesMessage, VariableMessage, WebRtcSignalToServerMessage, @@ -81,8 +79,6 @@ const roomManager: IRoomManagerServer = { user, message.getUsermovesmessage() as UserMovesMessage ); - } else if (message.hasSilentmessage()) { - socketManager.handleSilentMessage(room, user, message.getSilentmessage() as SilentMessage); } else if (message.hasItemeventmessage()) { socketManager.handleItemEvent( room, diff --git a/back/src/Services/AdminApi.ts b/back/src/Services/AdminApi.ts index 148877af..cfbab6c3 100644 --- a/back/src/Services/AdminApi.ts +++ b/back/src/Services/AdminApi.ts @@ -18,12 +18,21 @@ class AdminApi { params, }); - if (!isMapDetailsData(res.data) && !isRoomRedirect(res.data)) { - console.error("Unexpected answer from the /api/map admin endpoint.", res.data); - throw new Error("Unexpected answer from the /api/map admin endpoint."); + const mapDetailData = isMapDetailsData.safeParse(res.data); + const roomRedirect = isRoomRedirect.safeParse(res.data); + + if (mapDetailData.success) { + return mapDetailData.data; } - return res.data; + if (roomRedirect.success) { + return roomRedirect.data; + } + + console.error(mapDetailData.error.issues); + console.error(roomRedirect.error.issues); + console.error("Unexpected answer from the /api/map admin endpoint.", res.data); + throw new Error("Unexpected answer from the /api/map admin endpoint."); } } diff --git a/back/src/Services/MessageHelpers.ts b/back/src/Services/MessageHelpers.ts index 34edc473..10e4d514 100644 --- a/back/src/Services/MessageHelpers.ts +++ b/back/src/Services/MessageHelpers.ts @@ -1,5 +1,4 @@ import { - BatchMessage, BatchToPusherMessage, BatchToPusherRoomMessage, ErrorMessage, @@ -7,7 +6,7 @@ import { SubToPusherMessage, SubToPusherRoomMessage, } from "../Messages/generated/messages_pb"; -import { UserSocket } from "_Model/User"; +import { UserSocket } from "../Model/User"; import { RoomSocket, ZoneSocket } from "../RoomManager"; function getMessageFromError(error: unknown): string { diff --git a/back/src/Services/SocketManager.ts b/back/src/Services/SocketManager.ts index 8aa7f6a4..8d71f4d8 100644 --- a/back/src/Services/SocketManager.ts +++ b/back/src/Services/SocketManager.ts @@ -2,11 +2,9 @@ import { GameRoom } from "../Model/GameRoom"; import { ItemEventMessage, ItemStateMessage, - PlayGlobalMessage, PointMessage, RoomJoinedMessage, ServerToClientMessage, - SilentMessage, SubMessage, UserMovedMessage, UserMovesMessage, @@ -35,12 +33,10 @@ import { FollowAbortMessage, VariableMessage, BatchToPusherRoomMessage, - SubToPusherRoomMessage, SetPlayerDetailsMessage, PlayerDetailsUpdatedMessage, GroupUsersUpdateMessage, LockGroupPromptMessage, - RoomMessage, } from "../Messages/generated/messages_pb"; import { User, UserSocket } from "../Model/User"; import { ProtobufUtils } from "../Model/Websocket/ProtobufUtils"; @@ -60,9 +56,9 @@ import { JITSI_URL } from "../Enum/EnvironmentVariable"; import { clientEventsEmitter } from "./ClientEventsEmitter"; import { gaugeManager } from "./GaugeManager"; import { RoomSocket, ZoneSocket } from "../RoomManager"; -import { Zone } from "_Model/Zone"; +import { Zone } from "../Model/Zone"; import Debug from "debug"; -import { Admin } from "_Model/Admin"; +import { Admin } from "../Model/Admin"; import crypto from "crypto"; const debug = Debug("sockermanager"); @@ -163,10 +159,6 @@ export class SocketManager { room.updatePlayerDetails(user, playerDetailsMessage); } - handleSilentMessage(room: GameRoom, user: User, silentMessage: SilentMessage) { - room.setSilent(user, silentMessage.getSilent()); - } - handleItemEvent(room: GameRoom, user: User, itemEventMessage: ItemEventMessage) { const itemEvent = ProtobufUtils.toItemEvent(itemEventMessage); @@ -331,6 +323,7 @@ export class SocketManager { userJoinedZoneMessage.setUserid(thing.id); userJoinedZoneMessage.setUseruuid(thing.uuid); userJoinedZoneMessage.setName(thing.name); + userJoinedZoneMessage.setStatus(thing.getStatus()); userJoinedZoneMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedZoneMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); userJoinedZoneMessage.setFromzone(this.toProtoZone(fromZone)); @@ -338,11 +331,12 @@ export class SocketManager { userJoinedZoneMessage.setVisitcardurl(thing.visitCardUrl); } userJoinedZoneMessage.setCompanion(thing.companion); - if (thing.outlineColor === undefined) { + const outlineColor = thing.getOutlineColor(); + if (outlineColor === undefined) { userJoinedZoneMessage.setHasoutline(false); } else { userJoinedZoneMessage.setHasoutline(true); - userJoinedZoneMessage.setOutlinecolor(thing.outlineColor); + userJoinedZoneMessage.setOutlinecolor(outlineColor); } const subMessage = new SubToPusherMessage(); @@ -657,6 +651,7 @@ export class SocketManager { userJoinedMessage.setUserid(thing.id); userJoinedMessage.setUseruuid(thing.uuid); userJoinedMessage.setName(thing.name); + userJoinedMessage.setStatus(thing.getStatus()); userJoinedMessage.setCharacterlayersList(ProtobufUtils.toCharacterLayerMessages(thing.characterLayers)); userJoinedMessage.setPosition(ProtobufUtils.toPositionMessage(thing.getPosition())); if (thing.visitCardUrl) { diff --git a/back/src/Services/VariablesManager.ts b/back/src/Services/VariablesManager.ts index f7e65a66..32ae0493 100644 --- a/back/src/Services/VariablesManager.ts +++ b/back/src/Services/VariablesManager.ts @@ -2,7 +2,7 @@ * Handles variables shared between the scripting API and the server. */ import { ITiledMap, ITiledMapLayer, ITiledMapObject } from "@workadventure/tiled-map-type-guard/dist"; -import { User } from "_Model/User"; +import { User } from "../Model/User"; import { variablesRepository } from "./Repository/VariablesRepository"; import { redisClient } from "./RedisClient"; import { VariableError } from "./VariableError"; diff --git a/back/tests/GameRoomTest.ts b/back/tests/GameRoomTest.ts index fb9f09fb..03238a3d 100644 --- a/back/tests/GameRoomTest.ts +++ b/back/tests/GameRoomTest.ts @@ -1,11 +1,12 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import "jasmine"; import { ConnectCallback, DisconnectCallback, GameRoom } from "../src/Model/GameRoom"; import { Point } from "../src/Model/Websocket/MessageUserPosition"; import { Group } from "../src/Model/Group"; -import { User, UserSocket } from "_Model/User"; +import { User, UserSocket } from "../src/Model/User"; import { JoinRoomMessage, PositionMessage } from "../src/Messages/generated/messages_pb"; import Direction = PositionMessage.Direction; -import { EmoteCallback } from "_Model/Zone"; +import { EmoteCallback } from "../src/Model/Zone"; function createMockUser(userId: number): User { return { diff --git a/back/tests/MapFetcherTest.ts b/back/tests/MapFetcherTest.ts index 1e7ca447..41298d61 100644 --- a/back/tests/MapFetcherTest.ts +++ b/back/tests/MapFetcherTest.ts @@ -1,4 +1,3 @@ -import { arrayIntersect } from "../src/Services/ArrayHelper"; import { mapFetcher } from "../src/Services/MapFetcher"; describe("MapFetcher", () => { diff --git a/back/tests/PositionNotifierTest.ts b/back/tests/PositionNotifierTest.ts index f21bb4b2..70e4c0a0 100644 --- a/back/tests/PositionNotifierTest.ts +++ b/back/tests/PositionNotifierTest.ts @@ -1,10 +1,12 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import "jasmine"; import { PositionNotifier } from "../src/Model/PositionNotifier"; import { User, UserSocket } from "../src/Model/User"; -import { Zone } from "_Model/Zone"; -import { Movable } from "_Model/Movable"; -import { PositionInterface } from "_Model/PositionInterface"; +import { Zone } from "../src/Model/Zone"; +import { Movable } from "../src/Model/Movable"; +import { PositionInterface } from "../src/Model/PositionInterface"; import { ZoneSocket } from "../src/RoomManager"; +import { AvailabilityStatus } from "../src/Messages/generated/messages_pb"; describe("PositionNotifier", () => { it("should receive notifications when player moves", () => { @@ -39,8 +41,8 @@ describe("PositionNotifier", () => { moving: false, direction: "down", }, - false, positionNotifier, + AvailabilityStatus.ONLINE, {} as UserSocket, [], null, @@ -58,8 +60,8 @@ describe("PositionNotifier", () => { moving: false, direction: "down", }, - false, positionNotifier, + AvailabilityStatus.ONLINE, {} as UserSocket, [], null, @@ -147,8 +149,8 @@ describe("PositionNotifier", () => { moving: false, direction: "down", }, - false, positionNotifier, + AvailabilityStatus.ONLINE, {} as UserSocket, [], null, @@ -166,8 +168,8 @@ describe("PositionNotifier", () => { moving: false, direction: "down", }, - false, positionNotifier, + AvailabilityStatus.ONLINE, {} as UserSocket, [], null, diff --git a/back/tsconfig.json b/back/tsconfig.json index e149d304..906ef01c 100644 --- a/back/tsconfig.json +++ b/back/tsconfig.json @@ -3,18 +3,18 @@ "experimentalDecorators": true, /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ "downlevelIteration": true, - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ - "allowJs": true, /* Allow javascript files to be compiled. */ + "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ // "declaration": true, /* Generates corresponding '.d.ts' file. */ // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ - "sourceMap": true, /* Generates corresponding '.map' file. */ + "sourceMap": true, /* Generates corresponding '.map' file. */ // "outFile": "./", /* Concatenate and emit output to single file. */ - "outDir": "./dist", /* Redirect output structure to the directory. */ + "outDir": "./dist", /* Redirect output structure to the directory. */ // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ // "composite": true, /* Enable project compilation */ // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ @@ -23,50 +23,50 @@ // "importHelpers": true, /* Import emit helpers from 'tslib'. */ // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ - /* Strict Type-Checking Options */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* Enable strict null checks. */ // "strictFunctionTypes": true, /* Enable strict checking of function types. */ // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ - "noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ // Disabled because of sifrr server that is monkey patching HttpResponse + "noImplicitThis": false, /* Raise error on 'this' expressions with an implied 'any' type. */ // Disabled because of sifrr server that is monkey patching HttpResponse // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ - /* Additional Checks */ // "noUnusedLocals": true, /* Report errors on unused locals. */ // "noUnusedParameters": true, /* Report errors on unused parameters. */ - "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ /* Module Resolution Options */ - "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ - "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ - "paths": { - "_Controller/*": ["src/Controller/*"], - "_Model/*": ["src/Model/*"], - "_Enum/*": ["src/Enum/*"] - }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + // "baseUrl": ".", /* Base directory to resolve non-absolute module names. */ + // "paths": { + // "_Controller/*": [ + // "src/Controller/*" + // ], + // "_Model/*": [ + // "src/Model/*" + // ], + // "_Enum/*": [ + // "src/Enum/*" + // ] + // }, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ // "typeRoots": [], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ - "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ - /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ - /* Advanced Options */ - "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ + "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ } -} +} \ No newline at end of file diff --git a/back/yarn.lock b/back/yarn.lock index 0c2a3869..d23fc29b 100644 --- a/back/yarn.lock +++ b/back/yarn.lock @@ -981,7 +981,7 @@ gauge@^3.0.0: strip-ansi "^6.0.1" wide-align "^1.1.2" -generic-type-guard@^3.2.0, generic-type-guard@^3.4.1: +generic-type-guard@^3.4.1: version "3.5.0" resolved "https://registry.yarnpkg.com/generic-type-guard/-/generic-type-guard-3.5.0.tgz#39de9f8fceee65d79e7540959f0e7b23210c07b6" integrity sha512-OpgXv/sbRobhFboaSyN/Tsh97Sxt5pcfLLxCiYZgYIIWFFp+kn2EzAXiaQZKEVRlq1rOE/zh8cYhJXEwplbJiQ== @@ -1459,9 +1459,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass@^3.0.0: version "3.1.6" @@ -2259,7 +2259,7 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -zod@^3.12.0: - version "3.14.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.2.tgz#0b4ed79085c471adce0e7f2c0a4fbb5ddc516ba2" - integrity sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw== +zod@^3.14.3: + version "3.14.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.3.tgz#60e86341c05883c281fe96a0e79acea48a09f123" + integrity sha512-OzwRCSXB1+/8F6w6HkYHdbuWysYWnAF4fkRgKDcSFc54CE+Sv0rHXKfeNUReGCrHukm1LNpi6AYeXotznhYJbQ== diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 5d9ef0c6..3a8d2792 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -369,9 +369,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "mkdirp": { "version": "1.0.4", diff --git a/benchmark/yarn.lock b/benchmark/yarn.lock index 92541451..3aff17f6 100644 --- a/benchmark/yarn.lock +++ b/benchmark/yarn.lock @@ -268,8 +268,8 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" mkdirp@^1.0.4: version "1.0.4" diff --git a/contrib/docker/.env.prod.template b/contrib/docker/.env.prod.template index a6317078..ed40f6e3 100644 --- a/contrib/docker/.env.prod.template +++ b/contrib/docker/.env.prod.template @@ -30,7 +30,7 @@ ADMIN_API_URL= DATA_DIR=./wa # The URL used by default, in the form: "/_/global/map/url.json" -START_ROOM_URL=/_/global/maps.workadventu.re/Floor0/floor0.json +START_ROOM_URL=/_/global/thecodingmachine.github.io/workadventure-map-starter-kit/map.json # If you want to have a contact page in your menu, # you MUST set CONTACT_URL to the URL of the page that you want diff --git a/contrib/docker/README.md b/contrib/docker/README.md new file mode 100644 index 00000000..2de72b41 --- /dev/null +++ b/contrib/docker/README.md @@ -0,0 +1,34 @@ +# Deploying WorkAdventure in production + +This directory contains a sample production deployment of WorkAdventure using docker-compose. + +Every production environment is different and this docker-compose file will not +fit all use cases. But it is intended to be a good starting point for you +to build your own deployment. + +In this docker-compose file, you will find: + +- A reverse-proxy (Traefik) that dispatches requests to the WorkAdventure containers and handles HTTPS certificates using LetsEncrypt +- A front container (nginx) that servers static files (HTML/JS/CSS) +- A pusher container (NodeJS) that is the point of entry for users (you can start many if you want to increase performance) +- A back container (NodeJS) that shares your rooms information +- An icon container to fetch the favicon of sites imported in iframes +- A Redis server to store values from variables originating from the Scripting API + +```mermaid +graph LR + A[Browser] --> B(Traefik) + subgraph docker-compose + B --> C(Front) + B --> D(Pusher) + B --> E(Icon) + D --> F(Back) + F --> G(Redis) + end + A .-> H(Map) + F .-> H +``` + +**Important**: the default docker-compose file does **not** contain a container dedicated to hosting maps. The documentation and +tutorials are relying on GitHub Pages to host the maps. If you want to self-host your maps, you will need to add a simple +HTTP server (nginx / Apache, ...) and properly configure the [CORS settings as explained in the documentation](../../docs/maps/hosting.md). diff --git a/contrib/docker/docker-compose.prod.yaml b/contrib/docker/docker-compose.prod.yaml index eb21ab3d..2346a640 100644 --- a/contrib/docker/docker-compose.prod.yaml +++ b/contrib/docker/docker-compose.prod.yaml @@ -12,7 +12,7 @@ services: - --entryPoints.websecure.address=:${HTTPS_PORT} # HTTP challenge - --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL} - - --certificatesresolvers.myresolver.acme.storage=/acme.json + - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json - --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web # Let's Encrypt's staging server # uncomment during testing to avoid rate limiting @@ -22,7 +22,7 @@ services: - "${HTTPS_PORT}:443" volumes: - /var/run/docker.sock:/var/run/docker.sock - - ${DATA_DIR}/letsencrypt/acme.json:/acme.json + - ${DATA_DIR}/letsencrypt/:/letsencrypt/ restart: ${RESTART_POLICY} @@ -95,6 +95,7 @@ services: - JITSI_ISS - MAX_PER_GROUP - STORE_VARIABLES_FOR_LOCAL_MAPS + - REDIS_HOST=redis labels: - "traefik.http.routers.back.rule=Host(`${BACK_HOST}`)" - "traefik.http.routers.back.entryPoints=web" @@ -117,3 +118,11 @@ services: - "traefik.http.routers.icon-ssl.service=icon" - "traefik.http.routers.icon-ssl.tls=true" - "traefik.http.routers.icon-ssl.tls.certresolver=myresolver" + + redis: + image: redis:6 + volumes: + - redisdata:/data + +volumes: + redisdata: diff --git a/deeployer.libsonnet b/deeployer.libsonnet index 72e6dd43..7305df50 100644 --- a/deeployer.libsonnet +++ b/deeployer.libsonnet @@ -64,6 +64,11 @@ "ADMIN_API_URL": adminUrl, "ADMIN_API_TOKEN": env.ADMIN_API_TOKEN, "ADMIN_SOCKETS_TOKEN": env.ADMIN_SOCKETS_TOKEN, + "OPID_CLIENT_ID": "auth-code-client", + "OPID_CLIENT_SECRET": "mySecretHydraWA2022", + "OPID_CLIENT_ISSUER": "https://publichydra-"+url, + "OPID_CLIENT_REDIRECT_URL": "https://"+url+"/oauth/hydra", + "OPID_LOGIN_SCREEN_PROVIDER": "https://pusher-"+url+"/login-screen", } else {}) }, "front": { diff --git a/desktop/electron/electron-builder.yml b/desktop/electron/electron-builder.yml index faca3d73..d9fd4eb1 100644 --- a/desktop/electron/electron-builder.yml +++ b/desktop/electron/electron-builder.yml @@ -28,5 +28,4 @@ publish: provider: github owner: thecodingmachine repo: workadventure - vPrefixedTagName: false - releaseType: draft + releaseType: release diff --git a/desktop/electron/helpers/set-version.js b/desktop/electron/helpers/set-version.js new file mode 100644 index 00000000..52c5e8c8 --- /dev/null +++ b/desktop/electron/helpers/set-version.js @@ -0,0 +1,18 @@ +const path = require('path'); +const fs = require('fs'); + +let version = '0.0.0'; + +if (process.env.GITHUB_REF.startsWith('refs/tags/v')) { + version = process.env.GITHUB_REF.replace('refs/tags/v', ''); +} + +console.log('Version:', version); + +const packageJsonPath = path.resolve(__dirname, '..', 'package.json'); + +let data = fs.readFileSync(packageJsonPath, 'utf8'); + +data = data.replace('managedbyci', version); + +fs.writeFileSync(packageJsonPath, data); diff --git a/desktop/electron/package.json b/desktop/electron/package.json index 26a3929c..2998919f 100644 --- a/desktop/electron/package.json +++ b/desktop/electron/package.json @@ -1,6 +1,6 @@ { "name": "workadventure-desktop", - "version": "1.0.0", + "version": "managedbyci", "description": "Desktop application for WorkAdventure", "author": "thecodingmachine", "main": "dist/main.js", @@ -11,7 +11,6 @@ "dev": "yarn build --watch --onSuccess 'yarn electron dist/main.js'", "dev:local-app": "cd ../local-app && yarn && yarn dev", "bundle": "yarn build:local-app && yarn build && electron-builder install-app-deps && electron-builder", - "release": "yarn bundle", "typecheck": "tsc --noEmit", "test": "exit 0", "lint": "yarn eslint src/ . --ext .ts", @@ -32,13 +31,13 @@ }, "devDependencies": { "@types/auto-launch": "^5.0.2", - "@typescript-eslint/eslint-plugin": "^2.26.0", - "@typescript-eslint/parser": "^2.26.0", - "electron": "^17.0.1", + "@typescript-eslint/eslint-plugin": "^5.18.0", + "@typescript-eslint/parser": "^5.18.0", + "electron": "^18.0.3", "electron-builder": "^22.14.13", - "eslint": "^6.8.0", - "prettier": "^2.5.1", - "tsup": "^5.11.13", - "typescript": "^3.8.3" + "eslint": "^8.12.0", + "prettier": "^2.6.2", + "tsup": "^5.12.4", + "typescript": "^4.6.3" } } diff --git a/desktop/electron/src/app.ts b/desktop/electron/src/app.ts index b37f13b5..8ef135c5 100644 --- a/desktop/electron/src/app.ts +++ b/desktop/electron/src/app.ts @@ -10,7 +10,7 @@ import { setLogLevel } from "./log"; import "./serve"; // prepare custom url scheme import { loadShortcuts } from "./shortcuts"; -function init() { +async function init() { const appLock = app.requestSingleInstanceLock(); if (!appLock) { @@ -21,7 +21,7 @@ function init() { app.on("second-instance", () => { // re-create window if closed - createWindow(); + void createWindow(); const mainWindow = getWindow(); @@ -36,15 +36,15 @@ function init() { }); // This method will be called when Electron has finished loading - app.whenReady().then(async () => { + await app.whenReady().then(async () => { await settings.init(); setLogLevel(settings.get("log_level") || "info"); - autoUpdater.init(); + await autoUpdater.init(); // enable auto launch - updateAutoLaunch(); + await updateAutoLaunch(); // load ipc handler ipc(); @@ -72,7 +72,7 @@ function init() { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); + void createWindow(); } }); diff --git a/desktop/electron/src/auto-updater.ts b/desktop/electron/src/auto-updater.ts index 5c4af88e..69bc1050 100644 --- a/desktop/electron/src/auto-updater.ts +++ b/desktop/electron/src/auto-updater.ts @@ -38,32 +38,35 @@ export async function manualRequestUpdateCheck() { isManualRequestedUpdate = false; } -function init() { +async function init() { autoUpdater.logger = log; - autoUpdater.on("update-downloaded", ({ releaseNotes, releaseName }) => { - (async () => { - const dialogOpts = { - type: "question", - buttons: ["Install and Restart", "Install Later"], - defaultId: 0, - title: "WorkAdventure - Update", - message: process.platform === "win32" ? releaseNotes : releaseName, - detail: "A new version has been downloaded. Restart the application to apply the updates.", - }; + autoUpdater.on( + "update-downloaded", + ({ releaseNotes, releaseName }: { releaseNotes: string; releaseName: string }) => { + void (async () => { + const dialogOpts = { + type: "question", + buttons: ["Install and Restart", "Install Later"], + defaultId: 0, + title: "WorkAdventure - Update", + message: process.platform === "win32" ? releaseNotes : releaseName, + detail: "A new version has been downloaded. Restart the application to apply the updates.", + }; - const { response } = await dialog.showMessageBox(dialogOpts); - if (response === 0) { - await sleep(1000); + const { response } = await dialog.showMessageBox(dialogOpts); + if (response === 0) { + await sleep(1000); - autoUpdater.quitAndInstall(); + autoUpdater.quitAndInstall(); - // Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app. - // app.confirmedExitPrompt = true; - app.quit(); - } - })(); - }); + // Force app to quit. This is just a workaround, ideally autoUpdater.quitAndInstall() should relaunch the app. + // app.confirmedExitPrompt = true; + app.quit(); + } + })(); + } + ); if (process.platform === "linux" && !process.env.APPIMAGE) { autoUpdater.autoDownload = false; @@ -85,7 +88,7 @@ function init() { } }); - checkForUpdates(); + await checkForUpdates(); // run update check every hour again setInterval(() => checkForUpdates, 1000 * 60 * 1); diff --git a/desktop/electron/src/ipc.ts b/desktop/electron/src/ipc.ts index f8083c3f..7a36d4ed 100644 --- a/desktop/electron/src/ipc.ts +++ b/desktop/electron/src/ipc.ts @@ -1,4 +1,4 @@ -import { ipcMain, app } from "electron"; +import { ipcMain, app, desktopCapturer } from "electron"; import electronIsDev from "electron-is-dev"; import { createAndShowNotification } from "./notification"; import { Server } from "./preload-local-app/types"; @@ -30,10 +30,18 @@ export default () => { ipcMain.handle("get-version", () => (electronIsDev ? "dev" : app.getVersion())); // app ipc - ipcMain.on("app:notify", (event, txt) => { + ipcMain.on("app:notify", (event, txt: string) => { createAndShowNotification({ body: txt }); }); + ipcMain.handle("app:getDesktopCapturerSources", async (event, options: Electron.SourcesOptions) => { + return (await desktopCapturer.getSources(options)).map((source) => ({ + id: source.id, + name: source.name, + thumbnailURL: source.thumbnail.toDataURL(), + })); + }); + // local-app ipc ipcMain.handle("local-app:showLocalApp", () => { hideAppView(); @@ -43,7 +51,7 @@ export default () => { return settings.get("servers"); }); - ipcMain.handle("local-app:selectServer", (event, serverId: string) => { + ipcMain.handle("local-app:selectServer", async (event, serverId: string) => { const servers = settings.get("servers") || []; const selectedServer = servers.find((s) => s._id === serverId); @@ -51,7 +59,7 @@ export default () => { return new Error("Server not found"); } - showAppView(selectedServer.url); + await showAppView(selectedServer.url); return true; }); diff --git a/desktop/electron/src/log.ts b/desktop/electron/src/log.ts index 2c9d6e6c..8aadbbd6 100644 --- a/desktop/electron/src/log.ts +++ b/desktop/electron/src/log.ts @@ -15,6 +15,7 @@ function onError(e: Error) { function onRejection(reason: Error) { if (reason instanceof Error) { let _reason = reason; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const errPrototype = Object.getPrototypeOf(reason); const nameProperty = Object.getOwnPropertyDescriptor(errPrototype, "name"); diff --git a/desktop/electron/src/main.ts b/desktop/electron/src/main.ts index 6d4bcb6a..1089a76c 100644 --- a/desktop/electron/src/main.ts +++ b/desktop/electron/src/main.ts @@ -2,4 +2,4 @@ import app from "./app"; import log from "./log"; log.init(); -app.init(); +void app.init(); diff --git a/desktop/electron/src/preload-app/preload.ts b/desktop/electron/src/preload-app/preload.ts index 702cbef5..91f3b115 100644 --- a/desktop/electron/src/preload-app/preload.ts +++ b/desktop/electron/src/preload-app/preload.ts @@ -8,6 +8,7 @@ const api: WorkAdventureDesktopApi = { notify: (txt) => ipcRenderer.send("app:notify", txt), onMuteToggle: (callback) => ipcRenderer.on("app:on-mute-toggle", callback), onCameraToggle: (callback) => ipcRenderer.on("app:on-camera-toggle", callback), + getDesktopCapturerSources: (options) => ipcRenderer.invoke("app:getDesktopCapturerSources", options), }; contextBridge.exposeInMainWorld("WAD", api); diff --git a/desktop/electron/src/preload-app/types.ts b/desktop/electron/src/preload-app/types.ts index 164153a5..4069f7de 100644 --- a/desktop/electron/src/preload-app/types.ts +++ b/desktop/electron/src/preload-app/types.ts @@ -1,3 +1,15 @@ +// copy of Electron.SourcesOptions to avoid Electron dependency in front +export interface SourcesOptions { + types: string[]; + thumbnailSize?: { height: number; width: number }; +} + +export interface DesktopCapturerSource { + id: string; + name: string; + thumbnailURL: string; +} + export type WorkAdventureDesktopApi = { desktop: boolean; isDevelopment: () => Promise; @@ -5,4 +17,5 @@ export type WorkAdventureDesktopApi = { notify: (txt: string) => void; onMuteToggle: (callback: () => void) => void; onCameraToggle: (callback: () => void) => void; + getDesktopCapturerSources: (options: SourcesOptions) => Promise; }; diff --git a/desktop/electron/src/tray.ts b/desktop/electron/src/tray.ts index cc72b1aa..c611c5ae 100644 --- a/desktop/electron/src/tray.ts +++ b/desktop/electron/src/tray.ts @@ -36,14 +36,14 @@ export function createTray() { }, { label: "Check for updates", - async click() { - await autoUpdater.manualRequestUpdateCheck(); + click() { + void autoUpdater.manualRequestUpdateCheck(); }, }, { label: "Open Logs", click() { - log.openLog(); + void log.openLog(); }, }, { diff --git a/desktop/electron/src/window.ts b/desktop/electron/src/window.ts index 02c2c240..916fcdb6 100644 --- a/desktop/electron/src/window.ts +++ b/desktop/electron/src/window.ts @@ -115,7 +115,7 @@ export async function createWindow() { } } -export function showAppView(url?: string) { +export async function showAppView(url?: string) { if (!appView) { throw new Error("App view not found"); } @@ -130,7 +130,7 @@ export function showAppView(url?: string) { mainWindow.addBrowserView(appView); if (url && url !== appViewUrl) { - appView.webContents.loadURL(url); + await appView.webContents.loadURL(url); appViewUrl = url; } diff --git a/desktop/electron/tsconfig.json b/desktop/electron/tsconfig.json index d356ed64..49c7d058 100644 --- a/desktop/electron/tsconfig.json +++ b/desktop/electron/tsconfig.json @@ -12,10 +12,10 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "moduleResolution": "node", - "baseUrl": ".", - "paths": {}, + //"baseUrl": ".", + //"paths": {}, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true } -} +} \ No newline at end of file diff --git a/desktop/electron/yarn.lock b/desktop/electron/yarn.lock index 32dd7fe9..1914c218 100644 --- a/desktop/electron/yarn.lock +++ b/desktop/electron/yarn.lock @@ -7,27 +7,6 @@ resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.1.1.tgz#9274ec7460652f9c632c59addf24efb1684ef876" integrity sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ== -"@babel/code-frame@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - -"@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - -"@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@develar/schema-utils@~2.6.5": version "2.6.5" resolved "https://registry.yarnpkg.com/@develar/schema-utils/-/schema-utils-2.6.5.tgz#3ece22c5838402419a6e0425f85742b961d9b6c6" @@ -63,6 +42,35 @@ dir-compare "^2.4.0" fs-extra "^9.0.1" +"@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -130,11 +138,6 @@ dependencies: "@types/ms" "*" -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/fs-extra@^9.0.11": version "9.0.13" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" @@ -150,10 +153,10 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/json-schema@^7.0.3": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" - integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/json-schema@^7.0.9": + version "7.0.11" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/minimatch@*": version "3.0.5" @@ -170,10 +173,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.18.tgz#3b4fed5cfb58010e3a2be4b6e74615e4847f1074" integrity sha512-eKj4f/BsN/qcculZiRSujogjvp5O/k4lOW5m35NopjZM/QwLOR075a8pJW5hD+Rtdm2DaCVPENS6KtSQnUD6BA== -"@types/node@^14.6.2": - version "14.18.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.12.tgz#0d4557fd3b94497d793efd4e7d92df2f83b4ef24" - integrity sha512-q4jlIR71hUpWTnGhXWcakgkZeHa3CCjcQcnuzU8M891BAWA2jHiziiWEPEkdS5pFsz7H9HJiy8BrK7tBRNrY7A== +"@types/node@^16.11.26": + version "16.11.26" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.26.tgz#63d204d136c9916fb4dcd1b50f9740fe86884e47" + integrity sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ== "@types/plist@^3.0.1": version "3.0.2" @@ -205,58 +208,95 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^2.26.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" - integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ== +"@typescript-eslint/eslint-plugin@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.18.0.tgz#950df411cec65f90d75d6320a03b2c98f6c3af7d" + integrity sha512-tzrmdGMJI/uii9/V6lurMo4/o+dMTKDH82LkNjhJ3adCW22YQydoRs5MwTiqxGF9CSYxPxQ7EYb4jLNlIs+E+A== dependencies: - "@typescript-eslint/experimental-utils" "2.34.0" + "@typescript-eslint/scope-manager" "5.18.0" + "@typescript-eslint/type-utils" "5.18.0" + "@typescript-eslint/utils" "5.18.0" + debug "^4.3.2" functional-red-black-tree "^1.0.1" - regexpp "^3.0.0" - tsutils "^3.17.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" -"@typescript-eslint/experimental-utils@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== +"@typescript-eslint/parser@^5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.18.0.tgz#2bcd4ff21df33621df33e942ccb21cb897f004c6" + integrity sha512-+08nYfurBzSSPndngnHvFw/fniWYJ5ymOrn/63oMIbgomVQOvIDhBoJmYZ9lwQOCnQV9xHGvf88ze3jFGUYooQ== dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" + "@typescript-eslint/scope-manager" "5.18.0" + "@typescript-eslint/types" "5.18.0" + "@typescript-eslint/typescript-estree" "5.18.0" + debug "^4.3.2" -"@typescript-eslint/parser@^2.26.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8" - integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA== +"@typescript-eslint/scope-manager@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.18.0.tgz#a7d7b49b973ba8cebf2a3710eefd457ef2fb5505" + integrity sha512-C0CZML6NyRDj+ZbMqh9FnPscg2PrzSaVQg3IpTmpe0NURMVBXlghGZgMYqBw07YW73i0MCqSDqv2SbywnCS8jQ== dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "2.34.0" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-visitor-keys "^1.1.0" + "@typescript-eslint/types" "5.18.0" + "@typescript-eslint/visitor-keys" "5.18.0" -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== +"@typescript-eslint/type-utils@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.18.0.tgz#62dbfc8478abf36ba94a90ddf10be3cc8e471c74" + integrity sha512-vcn9/6J5D6jtHxpEJrgK8FhaM8r6J1/ZiNu70ZUJN554Y3D9t3iovi6u7JF8l/e7FcBIxeuTEidZDR70UuCIfA== dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + "@typescript-eslint/utils" "5.18.0" + debug "^4.3.2" + tsutils "^3.21.0" -acorn-jsx@^5.2.0: +"@typescript-eslint/types@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.18.0.tgz#4f0425d85fdb863071680983853c59a62ce9566e" + integrity sha512-bhV1+XjM+9bHMTmXi46p1Led5NP6iqQcsOxgx7fvk6gGiV48c6IynY0apQb7693twJDsXiVzNXTflhplmaiJaw== + +"@typescript-eslint/typescript-estree@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.18.0.tgz#6498e5ee69a32e82b6e18689e2f72e4060986474" + integrity sha512-wa+2VAhOPpZs1bVij9e5gyVu60ReMi/KuOx4LKjGx2Y3XTNUDJgQ+5f77D49pHtqef/klglf+mibuHs9TrPxdQ== + dependencies: + "@typescript-eslint/types" "5.18.0" + "@typescript-eslint/visitor-keys" "5.18.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.18.0.tgz#27fc84cf95c1a96def0aae31684cb43a37e76855" + integrity sha512-+hFGWUMMri7OFY26TsOlGa+zgjEy1ssEipxpLjtl4wSll8zy85x0GrUSju/FHdKfVorZPYJLkF3I4XPtnCTewA== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.18.0" + "@typescript-eslint/types" "5.18.0" + "@typescript-eslint/typescript-estree" "5.18.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + +"@typescript-eslint/visitor-keys@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.18.0.tgz#c7c07709823804171d569017f3b031ced7253e60" + integrity sha512-Hf+t+dJsjAKpKSkg3EHvbtEpFFb/1CiOHnvI8bjHgOD4/wAw3gKrA0i94LrbekypiZVanJu3McWJg7rWDMzRTg== + dependencies: + "@typescript-eslint/types" "5.18.0" + eslint-visitor-keys "^3.0.0" + +acorn-jsx@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== agent-base@6: version "6.0.2" @@ -270,7 +310,7 @@ ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0: +ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -287,24 +327,12 @@ ansi-align@^3.0.0: dependencies: string-width "^4.1.0" -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -372,13 +400,6 @@ applescript@^1.0.0: resolved "https://registry.yarnpkg.com/applescript/-/applescript-1.0.0.tgz#bb87af568cad034a4e48c4bdaf6067a3a2701317" integrity sha1-u4evVoytA0pOSMS9r2Bno6JwExc= -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -406,11 +427,6 @@ assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -615,7 +631,7 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -624,7 +640,7 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.1.0, chalk@^4.1.1: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -632,11 +648,6 @@ chalk@^4.1.0, chalk@^4.1.1: ansi-styles "^4.1.0" supports-color "^7.1.0" -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - chokidar@^3.5.1: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -672,13 +683,6 @@ cli-boxes@^2.2.1: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - cli-truncate@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" @@ -687,11 +691,6 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -818,18 +817,7 @@ crc@^3.8.0: dependencies: buffer "^5.1.0" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - -cross-spawn@^7.0.1, cross-spawn@^7.0.3: +cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -848,7 +836,7 @@ data-uri-to-buffer@^4.0.0: resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b" integrity sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA== -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== @@ -874,7 +862,7 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== @@ -1087,20 +1075,15 @@ electron-window-state@^5.0.3: jsonfile "^4.0.0" mkdirp "^0.5.1" -electron@^17.0.1: - version "17.0.1" - resolved "https://registry.yarnpkg.com/electron/-/electron-17.0.1.tgz#e6c7ad2be26e7be8a5a9bac16b21920ad2671224" - integrity sha512-CBReR/QEOpgwMdt59lWCtj9wC8oHB6aAjMF1lhXcGew132xtp+C5N6EaXb/fmDceVYLouziYjbNcpeXsWrqdpA== +electron@^18.0.3: + version "18.0.3" + resolved "https://registry.yarnpkg.com/electron/-/electron-18.0.3.tgz#58713c92b44e439881540d18910d193defb0c2b4" + integrity sha512-QRUZkGL8O/8CyDmTLSjBeRsZmGTPlPVeWnnpkdNqgHYYaOc/A881FKMiNzvQ9Cj0a+rUavDdwBUfUL82U3Ay7w== dependencies: "@electron/get" "^1.13.0" - "@types/node" "^14.6.2" + "@types/node" "^16.11.26" extract-zip "^1.0.3" -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -1128,125 +1111,131 @@ es6-error@^4.1.1: resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== -esbuild-android-arm64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz#fb051169a63307d958aec85ad596cfc7d7770303" - integrity sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ== +esbuild-android-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.34.tgz#46bc4327dd0809937912346244eaffdb9bfc980d" + integrity sha512-XfxcfJqmMYsT/LXqrptzFxmaR3GWzXHDLdFNIhm6S00zPaQF1TBBWm+9t0RZ6LRR7iwH57DPjaOeW20vMqI4Yw== -esbuild-darwin-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz#615ea0a9de67b57a293a7128d7ac83ee307a856d" - integrity sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw== +esbuild-android-arm64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.34.tgz#a3f7e1ad84b8a7dcb39b5e132768b56ee7133656" + integrity sha512-T02+NXTmSRL1Mc6puz+R9CB54rSPICkXKq6+tw8B6vxZFnCPzbJxgwIX4kcluz9p8nYBjF3+lSilTGWb7+Xgew== -esbuild-darwin-arm64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz#82054dcfcecb15ccfd237093b8008e7745a99ad9" - integrity sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw== +esbuild-darwin-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.34.tgz#a0e4ab7a0cddf76761f1fb5d6bf552a376beb16e" + integrity sha512-pLRip2Bh4Ng7Bf6AMgCrSp3pPe/qZyf11h5Qo2mOfJqLWzSVjxrXW+CFRJfrOVP7TCnh/gmZSM2AFdCPB72vtw== -esbuild-freebsd-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz#778a818c5b078d5cdd6bb6c0e0797217d196999b" - integrity sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A== +esbuild-darwin-arm64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.34.tgz#54c35461f82f83a7f5169d9a6a54201798977b07" + integrity sha512-vpidSJEBxx6lf1NWgXC+DCmGqesJuZ5Y8aQVVsaoO4i8tRXbXb0whChRvop/zd3nfNM4dIl5EXAky0knRX5I6w== -esbuild-freebsd-arm64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz#18da93b9f3db2e036f72383bfe73b28b73bb332c" - integrity sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ== +esbuild-freebsd-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.34.tgz#aebb50248f5874d04ffeab2db8ee1ed6037e2654" + integrity sha512-m0HBjePhe0hAQJgtMRMNV9kMgIyV4/qSnzPx42kRMQBcPhgjAq1JRu4Il26czC+9FgpMbFkUktb07f/Lwnc6CA== -esbuild-linux-32@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz#d0d5d9f5bb3536e17ac097e9512019c65b7c0234" - integrity sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg== +esbuild-freebsd-arm64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.34.tgz#09bef288e29f18b38b0c70a9827b6ee718e36c7f" + integrity sha512-cpRc2B94L1KvMPPYB4D6G39jLqpKlD3noAMY4/e86iXXXkhUYJJEtTuyNFTa9JRpWM0xCAp4mxjHjoIiLuoCLA== -esbuild-linux-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz#2773d540971999ea7f38107ef92fca753f6a8c30" - integrity sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg== +esbuild-linux-32@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.34.tgz#67790061758e008e919e65bbc34549f55dadaca7" + integrity sha512-8nQaEaoW7MH/K/RlozJa+lE1ejHIr8fuPIHhc513UebRav7HtXgQvxHQ6VZRUkWtep23M6dd7UqhwO1tMOfzQQ== -esbuild-linux-arm64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz#5d4480ce6d6bffab1dd76a23158f5a5ab33e7ba4" - integrity sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A== +esbuild-linux-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.34.tgz#b9b19d4ac07e37495dd2508ec843418aa71c98d6" + integrity sha512-Y3of4qQoLLlAgf042MlrY1P+7PnN9zWj8nVtw9XQG5hcLOZLz7IKpU35oeu7n4wvyaZHwvQqDJ93gRLqdJekcQ== -esbuild-linux-arm@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz#c6391b3f7c8fa6d3b99a7e893ce0f45f3a921eef" - integrity sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g== +esbuild-linux-arm64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.34.tgz#fd84b11a6ccfe9e83e00d0c45890e9fb3a7248c1" + integrity sha512-IlWaGtj9ir7+Nrume1DGcyzBDlK8GcnJq0ANKwcI9pVw8tqr+6GD0eqyF9SF1mR8UmAp+odrx1H5NdR2cHdFHA== -esbuild-linux-mips64le@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz#2c8dabac355c502e86c38f9f292b3517d8e181f3" - integrity sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ== +esbuild-linux-arm@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.34.tgz#c89d4714b05265a315a97c8933508cc73950e683" + integrity sha512-9lpq1NcJqssAF7alCO6zL3gvBVVt/lKw4oetUM7OgNnRX0OWpB+ZIO9FwCrSj/dMdmgDhPLf+119zB8QxSMmAg== -esbuild-linux-ppc64le@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz#69d71b2820d5c94306072dac6094bae38e77d1c0" - integrity sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng== +esbuild-linux-mips64le@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.34.tgz#d60752c3fb1260dd0737532af2de2a9521656456" + integrity sha512-k3or+01Rska1AjUyNjA4buEwB51eyN/xPQAoOx1CjzAQC3l8rpjUDw55kXyL63O/1MUi4ISvtNtl8gLwdyEcxw== -esbuild-linux-riscv64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz#c0ec0fc3a23624deebf657781550d2329cec4213" - integrity sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ== +esbuild-linux-ppc64le@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.34.tgz#f4c6229269956564f0c6f9825f5e717c2cfc22b3" + integrity sha512-+qxb8M9FfM2CJaVU7GgYpJOHM1ngQOx+/VrtBjb4C8oVqaPcESCeg2anjl+HRZy8VpYc71q/iBYausPPbJ+Keg== -esbuild-linux-s390x@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz#ec2af4572d63336cfb27f5a5c851fb1b6617dd91" - integrity sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw== +esbuild-linux-riscv64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.34.tgz#549bd18a9eba3135b67f7b742730b5343a1be35d" + integrity sha512-Y717ltBdQ5j5sZIHdy1DV9kieo0wMip0dCmVSTceowCPYSn1Cg33Kd6981+F/3b9FDMzNWldZFOBRILViENZSA== -esbuild-netbsd-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz#0e283278e9fdbaa7f0930f93ee113d7759cd865e" - integrity sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA== +esbuild-linux-s390x@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.34.tgz#2a6b577c437f94c2b37623c755ff5215a05c12bc" + integrity sha512-bDDgYO4LhL4+zPs+WcBkXph+AQoPcQRTv18FzZS0WhjfH8TZx2QqlVPGhmhZ6WidrY+jKthUqO6UhGyIb4MpmA== -esbuild-openbsd-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz#2a73bba04e16d8ef278fbe2be85248e12a2f2cc2" - integrity sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA== +esbuild-netbsd-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.34.tgz#7f0b73229157975eb35597207723df52ba21722a" + integrity sha512-cfaFGXdRt0+vHsjNPyF0POM4BVSHPSbhLPe8mppDc7GDDxjIl08mV1Zou14oDWMp/XZMjYN1kWYRSfftiD0vvQ== -esbuild-sunos-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz#8fe03513b8b2e682a6d79d5e3ca5849651a3c1d8" - integrity sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g== +esbuild-openbsd-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.34.tgz#b9bc44b4f70031fb01b173b279daeffc4d4f54b7" + integrity sha512-vmy9DxXVnRiI14s8GKuYBtess+EVcDALkbpTqd5jw4XITutIzyB7n4x0Tj5utAkKsgZJB22lLWGekr0ABnSLow== -esbuild-windows-32@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz#a75df61e3e49df292a1842be8e877a3153ee644f" - integrity sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg== +esbuild-sunos-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.34.tgz#512dd6085ac1a0dccc20c5f932f16a618bea409c" + integrity sha512-eNPVatNET1F7tRMhii7goL/eptfxc0ALRjrj9SPFNqp0zmxrehBFD6BaP3R4LjMn6DbMO0jOAnTLFKr8NqcJAA== -esbuild-windows-64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz#d06cf8bbe4945b8bf95a730d871e54a22f635941" - integrity sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw== +esbuild-windows-32@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.34.tgz#3ff1afd5cac08050c7c7140a59e343b06f6b037c" + integrity sha512-EFhpXyHEcnqWYe2rAHFd8dRw8wkrd9U+9oqcyoEL84GbanAYjiiIjBZsnR8kl0sCQ5w6bLpk7vCEIA2VS32Vcg== -esbuild-windows-arm64@0.14.22: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz#f8b1b05c548073be8413a5ecb12d7c2f6e717227" - integrity sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg== +esbuild-windows-64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.34.tgz#66f7b43d2a0b132f6748dfa3edac4fc939a99be0" + integrity sha512-a8fbl8Ky7PxNEjf1aJmtxdDZj32/hC7S1OcA2ckEpCJRTjiKslI9vAdPpSjrKIWhws4Galpaawy0nB7fjHYf5Q== -esbuild@^0.14.2: - version "0.14.22" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.22.tgz#2b55fde89d7aa5aaaad791816d58ff9dfc5ed085" - integrity sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA== +esbuild-windows-arm64@0.14.34: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.34.tgz#b74a6395b7b7e53dba70b71b39542afd83352473" + integrity sha512-EYvmKbSa2B3sPnpC28UEu9jBK5atGV4BaVRE7CYGUci2Hlz4AvtV/LML+TcDMT6gBgibnN2gcltWclab3UutMg== + +esbuild@^0.14.25: + version "0.14.34" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.34.tgz#3610056f0a57bcfd0b63ddaafdb2e3bef1cf96e4" + integrity sha512-QIWdPT/gFF6hCaf4m7kP0cJ+JIuFkdHibI7vVFvu3eJS1HpVmYHWDulyN5WXwbRA0SX/7ZDaJ/1DH8SdY9xOJg== optionalDependencies: - esbuild-android-arm64 "0.14.22" - esbuild-darwin-64 "0.14.22" - esbuild-darwin-arm64 "0.14.22" - esbuild-freebsd-64 "0.14.22" - esbuild-freebsd-arm64 "0.14.22" - esbuild-linux-32 "0.14.22" - esbuild-linux-64 "0.14.22" - esbuild-linux-arm "0.14.22" - esbuild-linux-arm64 "0.14.22" - esbuild-linux-mips64le "0.14.22" - esbuild-linux-ppc64le "0.14.22" - esbuild-linux-riscv64 "0.14.22" - esbuild-linux-s390x "0.14.22" - esbuild-netbsd-64 "0.14.22" - esbuild-openbsd-64 "0.14.22" - esbuild-sunos-64 "0.14.22" - esbuild-windows-32 "0.14.22" - esbuild-windows-64 "0.14.22" - esbuild-windows-arm64 "0.14.22" + esbuild-android-64 "0.14.34" + esbuild-android-arm64 "0.14.34" + esbuild-darwin-64 "0.14.34" + esbuild-darwin-arm64 "0.14.34" + esbuild-freebsd-64 "0.14.34" + esbuild-freebsd-arm64 "0.14.34" + esbuild-linux-32 "0.14.34" + esbuild-linux-64 "0.14.34" + esbuild-linux-arm "0.14.34" + esbuild-linux-arm64 "0.14.34" + esbuild-linux-mips64le "0.14.34" + esbuild-linux-ppc64le "0.14.34" + esbuild-linux-riscv64 "0.14.34" + esbuild-linux-s390x "0.14.34" + esbuild-netbsd-64 "0.14.34" + esbuild-openbsd-64 "0.14.34" + esbuild-sunos-64 "0.14.34" + esbuild-windows-32 "0.14.34" + esbuild-windows-64 "0.14.34" + esbuild-windows-arm64 "0.14.34" escalade@^3.1.1: version "3.1.1" @@ -1268,7 +1257,7 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-scope@^5.0.0: +eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -1276,83 +1265,82 @@ eslint-scope@^5.0.0: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== dependencies: - eslint-visitor-keys "^1.1.0" + esrecurse "^4.3.0" + estraverse "^5.2.0" -eslint-utils@^2.0.0: +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== -eslint@^6.8.0: - version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== +eslint@^8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.12.0.tgz#c7a5bd1cfa09079aae64c9076c07eada66a46e8e" + integrity sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q== dependencies: - "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^1.2.1" + "@humanwhocodes/config-array" "^0.9.2" ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" + glob-parent "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^7.0.0" is-glob "^4.0.0" - js-yaml "^3.13.1" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" + levn "^0.4.1" + lodash.merge "^4.6.2" minimatch "^3.0.4" - mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== +espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esquery@^1.0.1: +esquery@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== @@ -1396,15 +1384,6 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extract-zip@^1.0.3: version "1.7.0" resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" @@ -1420,7 +1399,7 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -1441,7 +1420,7 @@ fast-json-stable-stringify@^2.0.0: resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== -fast-levenshtein@~2.0.6: +fast-levenshtein@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= @@ -1468,19 +1447,12 @@ fetch-blob@^3.1.2, fetch-blob@^3.1.4: node-domexception "^1.0.0" web-streams-polyfill "^3.0.3" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" filelist@^1.0.1: version "1.0.2" @@ -1496,19 +1468,18 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== form-data@^4.0.0: version "4.0.0" @@ -1593,13 +1564,20 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -1653,12 +1631,12 @@ global-tunnel-ng@^2.7.1: npm-conf "^1.1.3" tunnel "^0.0.6" -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== +globals@^13.6.0, globals@^13.9.0: + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== dependencies: - type-fest "^0.8.1" + type-fest "^0.20.2" globalthis@^1.0.1: version "1.0.2" @@ -1667,7 +1645,7 @@ globalthis@^1.0.1: dependencies: define-properties "^1.1.3" -globby@^11.0.3: +globby@^11.0.3, globby@^11.0.4: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -1763,13 +1741,6 @@ iconv-corefoundation@^1.1.7: cli-truncate "^2.1.0" node-addon-api "^1.6.3" -iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -1782,17 +1753,12 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.2.0: +ignore@^5.1.8, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -import-fresh@^3.0.0: +import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -1833,25 +1799,6 @@ ini@^1.3.4, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -1878,17 +1825,12 @@ is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -1975,19 +1917,6 @@ joycon@^3.0.1: resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -2057,13 +1986,13 @@ lazy-val@^1.0.4, lazy-val@^1.0.5: resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d" integrity sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q== -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" + prelude-ls "^1.2.1" + type-check "~0.4.0" lilconfig@^2.0.4: version "2.0.4" @@ -2100,6 +2029,11 @@ lodash.isequal@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -2110,7 +2044,7 @@ lodash.unset@^4.5.2: resolved "https://registry.yarnpkg.com/lodash.unset/-/lodash.unset-4.5.2.tgz#370d1d3e85b72a7e1b0cdf2d272121306f23e4ed" integrity sha1-Nw0dPoW3Kn4bDN8tJyEhMG8j5O0= -lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19: +lodash@^4.17.10, lodash@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -2206,9 +2140,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mkdirp@^0.5.1, mkdirp@^0.5.4: version "0.5.5" @@ -2232,11 +2166,6 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - mz@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -2256,11 +2185,6 @@ new-github-issue-url@^0.2.1: resolved "https://registry.yarnpkg.com/new-github-issue-url/-/new-github-issue-url-0.2.1.tgz#e17be1f665a92de465926603e44b9f8685630c1d" integrity sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - node-addon-api@^1.6.3: version "1.7.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" @@ -2322,29 +2246,24 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0, onetime@^5.1.2: +onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" -optionator@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" p-cancelable@^1.0.0: version "1.1.0" @@ -2373,11 +2292,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -2424,27 +2338,27 @@ postcss-load-config@^3.0.1: lilconfig "^2.0.4" yaml "^1.10.2" -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prepend-http@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= -prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== +prettier@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" + integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0, progress@^2.0.3: +progress@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== @@ -2520,12 +2434,7 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - -regexpp@^3.0.0: +regexpp@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== @@ -2566,27 +2475,12 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2612,11 +2506,6 @@ rollup@^2.60.0: optionalDependencies: fsevents "~2.3.2" -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -2624,19 +2513,12 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -2665,12 +2547,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -semver@^5.5.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -2689,13 +2566,6 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -2703,11 +2573,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -2723,15 +2588,6 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - slice-ansi@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" @@ -2769,25 +2625,11 @@ sprintf-js@^1.1.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - stat-mode@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stat-mode/-/stat-mode-1.0.0.tgz#68b55cb61ea639ff57136f36b216a291800d1465" integrity sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg== -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -2804,13 +2646,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -2823,7 +2658,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.0.1: +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -2866,16 +2701,6 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -table@^5.2.3: - version "5.4.6" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - temp-file@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/temp-file/-/temp-file-3.4.0.tgz#766ea28911c683996c248ef1a20eea04d51652c7" @@ -2903,11 +2728,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through@^2.3.6: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - tmp-promise@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/tmp-promise/-/tmp-promise-3.0.3.tgz#60a1a1cc98c988674fcbfd23b6e3367bdeac4ce7" @@ -2915,13 +2735,6 @@ tmp-promise@^3.0.2: dependencies: tmp "^0.2.0" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmp@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" @@ -2958,21 +2771,21 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tsup@^5.11.13: - version "5.11.13" - resolved "https://registry.yarnpkg.com/tsup/-/tsup-5.11.13.tgz#dd9b375513a07c1c84620b22d4164e4293d6a2bb" - integrity sha512-NVMK01gVmojZn7+iZwxRK1CzW2BIabaVMyEjs7Nm9lm4DrSf7IAqs2F3fg0vT7rH72x1cIBsW9U/TlWrCvHVQQ== +tsup@^5.12.4: + version "5.12.4" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-5.12.4.tgz#5139e6d7735727cb8d0c4cdad721aaef7888f77f" + integrity sha512-uUraITfIj2h6rXAdeaVUYrZ2Is9joLFyEGZN5mGAke874JojCizb2MCUcE0wGdcERtyob5mbbFUKkMgal8SlFw== dependencies: bundle-require "^3.0.2" cac "^6.7.12" chokidar "^3.5.1" debug "^4.3.1" - esbuild "^0.14.2" + esbuild "^0.14.25" execa "^5.0.0" globby "^11.0.3" joycon "^3.0.1" @@ -2983,7 +2796,7 @@ tsup@^5.11.13: sucrase "^3.20.3" tree-kill "^1.2.2" -tsutils@^3.17.1: +tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== @@ -2995,12 +2808,12 @@ tunnel@^0.0.6: resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: - prelude-ls "~1.1.2" + prelude-ls "^1.2.1" type-fest@^0.13.1: version "0.13.1" @@ -3012,16 +2825,6 @@ type-fest@^0.20.2: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -3034,10 +2837,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.8.3: - version "3.9.10" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" - integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== +typescript@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== unique-string@^2.0.0: version "2.0.0" @@ -3124,13 +2927,6 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA== -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -3150,7 +2946,7 @@ winreg@1.2.4: resolved "https://registry.yarnpkg.com/winreg/-/winreg-1.2.4.tgz#ba065629b7a925130e15779108cf540990e98d1b" integrity sha1-ugZWKbepJRMOFXeRCM9UCZDpjRs= -word-wrap@~1.2.3: +word-wrap@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== @@ -3179,13 +2975,6 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - xdg-basedir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" diff --git a/desktop/local-app/tsconfig.json b/desktop/local-app/tsconfig.json index 29d24a5f..ca38c31a 100644 --- a/desktop/local-app/tsconfig.json +++ b/desktop/local-app/tsconfig.json @@ -5,7 +5,7 @@ "useDefineForClassFields": true, "module": "esnext", "resolveJsonModule": true, - "baseUrl": ".", + //"baseUrl": ".", /** * Typecheck JS in `.svelte` and `.js` files by default. * Disable checkJs if you'd like to use dynamic types in JS. @@ -15,10 +15,23 @@ "allowJs": true, "checkJs": true, "paths": { - "~/*": ["./src/*"], - "@wa-preload-local-app": ["../electron/src/preload-local-app/types.ts"], + "~/*": [ + "./src/*" + ], + "@wa-preload-local-app": [ + "../electron/src/preload-local-app/types.ts" + ], } }, - "include": ["src/**/*.d.ts", "src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], - "references": [{ "path": "./tsconfig.node.json" }] -} + "include": [ + "src/**/*.d.ts", + "src/**/*.ts", + "src/**/*.js", + "src/**/*.svelte" + ], + "references": [ + { + "path": "./tsconfig.node.json" + } + ] +} \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index 99885ca2..230cf632 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -114,7 +114,6 @@ services: #APACHE_EXTENSION_HEADERS: 1 STARTUP_COMMAND_0: sudo a2enmod headers STARTUP_COMMAND_1: yarn install - STARTUP_COMMAND_2: yarn run dev & volumes: - ./maps:/var/www/html labels: diff --git a/docs/dev/contributing-to-scripting-api.md b/docs/dev/contributing-to-scripting-api.md index 8d716010..e440e837 100644 --- a/docs/dev/contributing-to-scripting-api.md +++ b/docs/dev/contributing-to-scripting-api.md @@ -9,7 +9,7 @@ The [scripting API](https://workadventu.re/map-building/scripting.md) allows map The philosophy behind WorkAdventure is to build a platform that is as open as possible. Part of this strategy is to offer map developers the ability to turn a WorkAdventures map into something unexpected, using the API. For instance, -you could use it to develop games (we have seen a PacMan and a mine-sweeper on WorkAdventure!) +you could use it to develop games (we have seen a PacMan and a mine-sweeper on WorkAdventure!) We started working on the WorkAdventure scripting API with this in mind, but at some point, maybe you will find that a feature is missing in the API. This article is here to explain to you how to add this feature. @@ -35,7 +35,7 @@ directly access Phaser objects (Phaser is the game engine used in WorkAdventure) can contribute a map, we cannot allow anyone to run any code in the scope of the WorkAdventure server (that would be a huge XSS security flaw). -Instead, the only way the script can interact with WorkAdventure is by sending messages using the +Instead, the only way the script can interact with WorkAdventure is by sending messages using the [postMessage API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage). ![](images/scripting_2.svg) @@ -103,14 +103,14 @@ All the other files dedicated to the iframe API are located in the `src/Api/ifra ## Utility functions to exchange messages -In the example above, we already saw you can easily send a message from the iframe to WorkAdventure using the +In the example above, we already saw you can easily send a message from the iframe to WorkAdventure using the [`sendToWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L11-L13) utility function. Of course, messaging can go the other way around and WorkAdventure can also send messages to the iframes. We use the [`IFrameListener.postMessage`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/IframeListener.ts#L455-L459) function for this. Finally, there is a last type of utility function (a quite powerful one). It is quite common to need to call a function -from the iframe in WorkAdventure, and to expect a response. For those use cases, the iframe API comes with a +from the iframe in WorkAdventure, and to expect a response. For those use cases, the iframe API comes with a [`queryWorkadventure`](http://github.com/thecodingmachine/workadventure/blob/ab075ef6f4974766a3e2de12a230ac4df0954b58/front/src/Api/iframe/IframeApiContribution.ts#L30-L49) utility function. ## Types @@ -122,7 +122,7 @@ Indeed, Typescript interfaces only exist at compilation time but cannot be enfor is an entry point to WorkAdventure, and as with any entry point, data must be checked (otherwise, a hacker could send specially crafted JSON packages to try to hack WA). -In WorkAdventure, we use the [generic-type-guard](https://github.com/mscharley/generic-type-guard) package. This package +In WorkAdventure, we use the [zod](https://github.com/colinhacks/zod) package. This package allows us to create interfaces AND custom type guards in one go. Let's go back at our example. Let's have a look at the JSON message sent when we want to send a chat message from the API: @@ -140,21 +140,20 @@ sendToWorkadventure({ The "data" part of the message is defined in `front/src/Api/Events/ChatEvent.ts`: ```typescript -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isChatEvent = z.object({ + message: z.string(), + author: z.string(), +}); -export const isChatEvent = new tg.IsInterface() - .withProperties({ - message: tg.isString, - author: tg.isString, - }) - .get(); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type ChatEvent = tg.GuardedType; +export type ChatEvent = z.infer; ``` -Using the generic-type-guard library, we start by writing a type guard function (`isChatEvent`). +Using the zod library, we start by writing a type guard function (`isChatEvent`). From this type guard, the library can automatically generate the `ChatEvent` type that we can refer in our code. The advantage of this technique is that, **at runtime**, WorkAdventure can verify that the JSON message received @@ -212,7 +211,7 @@ export interface IframeResponseEvent { If you want to add a new "query" (if you are using the `queryWorkadventure` utility function), you will need to define the type of the query and the type of the response. -The signature of `queryWorkadventure` is: +The signature of `queryWorkadventure` is: ```typescript function queryWorkadventure( @@ -250,12 +249,12 @@ Here is a sample: ```typescript iframeListener.registerAnswerer("openCoWebsite", (openCoWebsiteEvent, source) => { // ... - + return /*...*/; }); ``` -The `registerAnswerer` callback is passed the event, and should return a response (or a promise to the response) in the expected format +The `registerAnswerer` callback is passed the event, and should return a response (or a promise to the response) in the expected format (the one you defined in the `answer` key of `iframeQueryMapTypeGuards`). Important: diff --git a/docs/maps/camera.md b/docs/maps/camera.md index 9e58fcad..59a212f8 100644 --- a/docs/maps/camera.md +++ b/docs/maps/camera.md @@ -1,15 +1,15 @@ {.section-title.accent.text-primary} # Working with camera -## Focusable Zones +## Focusable Area -It is possible to define special regions on the map that can make the camera zoom and center on themselves. We call them "Focusable Zones". When player gets inside, his camera view will be altered - focused, zoomed and locked on defined zone, like this: +It is possible to define special regions on the map that can make the camera zoom and center on themselves. We call them "Focusable Area". When player gets inside, his camera view will be altered - focused, zoomed and locked on defined area, like this:
-### Adding new **Focusable Zone**: +### Adding new **Focusable Area**: 1. Make sure you are editing an **Object Layer** @@ -29,7 +29,7 @@ It is possible to define special regions on the map that can make the camera zoo -4. Make sure your object is of type "zone"! +4. Make sure your object is of type "area"!
@@ -53,11 +53,11 @@ It is possible to define special regions on the map that can make the camera zoo
-All should be set up now and your new **Focusable Zone** should be working fine! +All should be set up now and your new **Focusable Area** should be working fine! ### Defining custom zoom margin: -If you want, you can add an additional property to control how much should the camera zoom onto focusable zone. +If you want, you can add an additional property to control how much should the camera zoom onto focusable area. 1. Like before, click on **Add Property** @@ -77,7 +77,7 @@ If you want, you can add an additional property to control how much should the c - For example, if you define your zone as a 300x200 rectangle, setting this property to 0.5 *(50%)* means the camera will try to fit within the viewport the entire zone + margin of 50% of its dimensions, so 450x300. + For example, if you define your area as a 300x200 rectangle, setting this property to 0.5 *(50%)* means the camera will try to fit within the viewport the entire area + margin of 50% of its dimensions, so 450x300. - No margin defined diff --git a/docs/maps/images/camera/4_add_zone_type.png b/docs/maps/images/camera/4_add_zone_type.png index 0416d1e4..18224ea5 100644 Binary files a/docs/maps/images/camera/4_add_zone_type.png and b/docs/maps/images/camera/4_add_zone_type.png differ diff --git a/docs/maps/images/camera/5_click_add_property.png b/docs/maps/images/camera/5_click_add_property.png index 9aa96a2f..329ac437 100644 Binary files a/docs/maps/images/camera/5_click_add_property.png and b/docs/maps/images/camera/5_click_add_property.png differ diff --git a/docs/maps/images/camera/7_make_sure_checked.png b/docs/maps/images/camera/7_make_sure_checked.png index 7fbcdb89..6a2d5e34 100644 Binary files a/docs/maps/images/camera/7_make_sure_checked.png and b/docs/maps/images/camera/7_make_sure_checked.png differ diff --git a/docs/maps/index.md b/docs/maps/index.md index d018dd3c..7257522d 100644 --- a/docs/maps/index.md +++ b/docs/maps/index.md @@ -9,7 +9,7 @@ In order to build your own map for WorkAdventure, you need: * "tiles" (i.e. images) to create your map * a web-server to serve your map -WorkAdventure comes with a "map starter kit" that we recommend using to start designing your map quickly. It contains **a good default tileset** for building an office and it proposes to **use Github static pages as a web-server** which is both free and performant. It also comes with a local webserver for testing purpose and with Typescript support (if you are looking to use the [map scripting API]({{url('/map-building/scripting')}}). +WorkAdventure comes with a "map starter kit" that we recommend using to start designing your map quickly. It contains **a good default tileset** for building an office and it proposes to **use Github static pages as a web-server** which is both free and performant. It also comes with a local webserver for testing purpose and with Typescript support (if you are looking to use the [map scripting API](scripting.md). {.alert.alert-info} If you are looking to host your maps on your own webserver, be sure to read the [Self-hosting your map](hosting.md) guide. diff --git a/docs/maps/meeting-rooms.md b/docs/maps/meeting-rooms.md index 9c3963ed..7753c943 100644 --- a/docs/maps/meeting-rooms.md +++ b/docs/maps/meeting-rooms.md @@ -9,19 +9,24 @@ On your map, you can define special zones (meeting rooms) that will trigger the In order to create Jitsi meet zones: -* You must create a specific layer. -* In layer properties, you MUST add a "`jitsiRoom`" property (of type "`string`"). The value of the property is the name of the room in Jitsi. Note: the name of the room will be "slugified" and prepended with the name of the instance of the map (so that different instances of the map have different rooms) +* You must create a specific object. +* Object must be of type "`area`" +* In object properties, you MUST add a "`jitsiRoom`" property (of type "`string`"). The value of the property is the name of the room in Jitsi. Note: the name of the room will be "slugified" and prepended with a hash of the room URL * You may also use "jitsiWidth" property (of type "number" between 0 and 100) to control the width of the iframe containing the meeting room. -You can have this layer (i.e. your meeting area) to be selectable as the precise location for your meeting using the [Google Calendar integration for Work Adventure](/integrations/google-calendar). To do so, you must set the `meetingRoomLabel` property. You can provide any name that you would like your meeting room to have (as a string). +You can have this object (i.e. your meeting area) to be selectable as the precise location for your meeting using the [Google Calendar integration for Work Adventure](/integrations/google-calendar). To do so, you must set the `meetingRoomLabel` property. You can provide any name that you would like your meeting room to have (as a string). + +{.alert.alert-info} +As an alternative, you may also put the `jitsiRoom` properties on a layer (rather than putting them on an "area" object) +but we advise to stick with "area" objects for better performance! ## Triggering of the "Jitsi meet" action -By default, Jitsi meet will open when a user enters the zone defined on the map. +By default, Jitsi meet will open when a user enters the area defined on the map. It is however possible to trigger Jitsi only on user action. You can do this with the `jitsiTrigger` property. -If you set `jitsiTrigger: onaction`, when the user walks on the layer, an alert message will be displayed at the bottom of the screen: +If you set `jitsiTrigger: onaction`, when the user walks on the area, an alert message will be displayed at the bottom of the screen:
@@ -32,7 +37,7 @@ If you set `jitsiTriggerMessage: your message action` you can edit alert message ## Customizing your "Jitsi meet" -Your Jitsi meet experience can be customized using Jitsi specific config options. The `jitsiConfig` and `jitsiInterfaceConfig` properties can be used on the Jitsi layer to change the way Jitsi looks and behaves. Those 2 properties are accepting a JSON string. +Your Jitsi meet experience can be customized using Jitsi specific config options. The `jitsiConfig` and `jitsiInterfaceConfig` properties can be used on the Jitsi object to change the way Jitsi looks and behaves. Those 2 properties are accepting a JSON string. For instance, use `jitsiConfig: { "startWithAudioMuted": true }` to automatically mute the microphone when someone enters a room. Or use `jitsiInterfaceConfig: { "DEFAULT_BACKGROUND": "#77ee77" }` to change the background color of Jitsi. @@ -60,7 +65,7 @@ You can grant moderator rights to some of your members. Jitsi moderators can: * Mute everybody expect one speaker * Kick users out of the meeting -In order to grant moderator rights to a given user, you can add a `jitsiRoomAdminTag` property to your Jitsi layer. For instance, if you write a property: +In order to grant moderator rights to a given user, you can add a `jitsiRoomAdminTag` property to your Jitsi object. For instance, if you write a property: jitsiRoomAdminTag: speaker @@ -74,7 +79,7 @@ WorkAdventure usually comes with a default Jitsi meet installation. If you are u You have the possibility, in your map, to override the Jitsi meet instance that will be used by default. This can be useful for regulatory reasons. Maybe your company wants to keep control on the video streams and therefore, wants to self-host a Jitsi instance? Or maybe you want to use a very special configuration or very special version of Jitsi? -Use the `jitsiUrl` property to in the Jitsi layer to specify the Jitsi instance that should be used. Beware, `jitsiUrl` takes in parameter a **domain name**, without the protocol. So you should use: +Use the `jitsiUrl` property to in the Jitsi object to specify the Jitsi instance that should be used. Beware, `jitsiUrl` takes in parameter a **domain name**, without the protocol. So you should use: `jitsiUrl: meet.jit.si` and not `jitsiUrl: https://meet.jit.si` @@ -82,3 +87,15 @@ and not {.alert.alert-info} When you use `jitsiUrl`, the targeted Jitsi instance must be public. You cannot use moderation features or the JWT tokens authentication with maps configured using the `jitsiUrl` property. + +## Full control over the Jitsi room name + +By default, the name of the room will be "slugified" and prepended with a hash of the room URL. +This is what you want most of the time. Indeed, different maps with the same Jitsi room name (the same `jitsiRoom` property) will not share the same Jitsi room instance. + +However, sometimes, you may actually want to have different WorkAdventure meeting rooms that are actually sharing +the same Jitsi meet meeting room. Or if you are pointing to a custom Jitsi server (using the `jitsiUrl` property), +you may want to point to a specific existing room. + +For all those use cases, you can use `jitsiNoPrefix: true`. This will remove the automatic prefixing +of the hash and will give you full control on the Jitsi room name. diff --git a/docs/maps/menu.php b/docs/maps/menu.php index c8afc2c0..af8acb9f 100644 --- a/docs/maps/menu.php +++ b/docs/maps/menu.php @@ -166,7 +166,8 @@ return [ ], [ 'title' => 'Troubleshooting', - 'url' => '/map-building/troubleshooting', - 'view' => 'content.map.troubleshooting' + 'url' => '/map-building/troubleshooting.md', + 'markdown' => 'maps.troubleshooting', + 'editUrl' => 'https://github.com/thecodingmachine/workadventure/edit/develop/docs/maps/troubleshooting.md', ], ]; diff --git a/docs/maps/opening-a-website.md b/docs/maps/opening-a-website.md index a84bde30..47ed1a86 100644 --- a/docs/maps/opening-a-website.md +++ b/docs/maps/opening-a-website.md @@ -10,14 +10,26 @@ on the right side of the screen) In order to create a zone that opens websites: -* You must create a specific layer. -* In layer properties, you MUST add a "`openWebsite`" property (of type "`string`"). The value of the property is the URL of the website to open (the URL must start with "https://") +* You must create a specific object. +* Object must be of type "`area`" +* In object properties, you MUST add a "`openWebsite`" property (of type "`string`"). The value of the property is the URL of the website to open (the URL must start with "https://") * You may also use "`openWebsiteWidth`" property (of type "`int`" or "`float`" between 0 and 100) to control the width of the iframe. * You may also use "`openTab`" property (of type "`string`") to open in a new tab instead. {.alert.alert-warning} A website can explicitly forbid another website from loading it in an iFrame using -the [X-Frame-Options HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options). +the [X-Frame-Options HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options). You can +read more about this common issue and possible workaround the [troubleshooting guide](troubleshooting.md#embedding-an-iframe-is-forbidden). + +{.alert.alert-info} +As an alternative, you may also put the `openWebsite` properties on a layer (rather than putting them on an "area" object) +but we advise sticking with "area" objects for better performance! + +{.alert.alert-warning} +If the website you are embedding is using cookies, those cookies must be configured with the `SameSite=none` attribute. Otherwise, +they will be ignored by the browser. If you manage to see the website you embed but cannot log into it, the `SameSite` attribute is most +likely the culprit. You can read more about this common issue and possible workaround the [troubleshooting guide](troubleshooting.md#i-cannot-log-into-my-embedded-website). + ## Integrating a Youtube video @@ -43,7 +55,7 @@ By default, the iFrame will open when a user enters the zone defined on the map. It is however possible to trigger the iFrame only on user action. You can do this with the `openWebsiteTrigger` property. -If you set `openWebsiteTrigger: onaction`, when the user walks on the layer, an alert message will be displayed at the bottom of the screen: +If you set `openWebsiteTrigger: onaction`, when the user walks on the area, an alert message will be displayed at the bottom of the screen:
@@ -52,7 +64,7 @@ If you set `openWebsiteTrigger: onaction`, when the user walks on the layer, an If you set `openWebsiteTriggerMessage: your message action` you can edit alert message displayed. If is not defined, the default message displayed is 'Press on SPACE to open the web site'. -If you set `openWebsiteTrigger: onicon`, when the user walks on the layer, an icon will be displayed at the bottom of the screen: +If you set `openWebsiteTrigger: onicon`, when the user walks on the area, an icon will be displayed at the bottom of the screen:
@@ -78,6 +90,6 @@ Cowebsites allow you to have several sites open at the same time. If you want to open a Jitsi and another page it's easy! -You have just to [add a Jitsi to the map](meeting-rooms.md) and [add a co-website](opening-a-website.md#the-openwebsite-property) on the same layer. +You have just to [add a Jitsi to the map](meeting-rooms.md) and [add a co-website](opening-a-website.md#the-openwebsite-property) on the same object. It's done! diff --git a/docs/maps/special-zones.md b/docs/maps/special-zones.md index 30ebebab..1d22a3fc 100644 --- a/docs/maps/special-zones.md +++ b/docs/maps/special-zones.md @@ -9,8 +9,13 @@ On your map, you can define special silent zones where nobody is allowed to talk In order to create a silent zone: -* You must create a specific layer. -* In layer properties, you MUST add a boolean "`silent`" property. If the silent property is checked, the users are entering the silent zone when they walk on any tile of the layer. +* You must create a specific object. +* Object must be of type "`area`" +* In object properties, you MUST add a boolean "`silent`" property. If the silent property is checked, the users are entering the silent zone when they walk on the area. + +{.alert.alert-info} +As an alternative, you may also put the `silent` property on a layer (rather than putting them on an "area" object) +but we advise to stick with "area" objects for better performance! ## Playing sounds or background music @@ -18,10 +23,15 @@ Your map can define special zones where a sound or background music will automat In order to create a zone that triggers sounds/music: -* You must create a specific layer. -* In layer properties, you MUST add a "`playAudio`" property. The value of the property is a URL to an MP3 file that will be played. The URL can be relative to the URL of the map. +* You must create a specific object. +* Object must be of type "`area`" +* In object properties, you MUST add a "`playAudio`" property. The value of the property is a URL to an MP3 file that will be played. The URL can be relative to the URL of the map. * You may use the boolean property "`audioLoop`" to make the sound loop (thanks captain obvious). * If the "`audioVolume`" property is set, the audio player uses either the value of the property or the last volume set by the user - whichever is smaller. This property is a float from 0 to 1.0 {.alert.alert-info} "`playAudioLoop`" is deprecated and should not be used anymore. + +{.alert.alert-info} +As an alternative, you may also put the `playAudio` properties on a layer (rather than putting them on an "area" object) +but we advise to stick with "area" objects for better performance! diff --git a/docs/maps/troubleshooting.md b/docs/maps/troubleshooting.md new file mode 100644 index 00000000..784d1f66 --- /dev/null +++ b/docs/maps/troubleshooting.md @@ -0,0 +1,94 @@ +{.section-title.accent.text-primary} +# Troubleshooting + +## Look at the browser console + +If your map is not displayed correctly (most notably if you are getting a black screen), open your browser console. +This is usually done by pressing the F12 key and selecting the "console" tab. + +Scan the output. Towards the end, you might see a message explaining why your map cannot be loaded. + +## Check webserver CORS settings + +If you are hosting the map you built on your own webserver and if the map does not load, please check that +[your webserver CORS settings are correctly configured](hosting.md). + +## Issues embedding a website + +When you are embedding a website in WorkAdventure (whether it is using the [`openWebsite` property](opening-a-website.md) or +the [integrated website in a map](website-in-map.md) feature or the [Scripting API](scripting.md)), WorkAdventure +will open your website using an iFrame. + +Browsers have various security measures in place, and website owners can use those measures to prevent websites from +being used inside iFrames (either partially or completely). + +In the chapters below, we will list what can possibly prevent you from embedding a website, and see what are your options. + +### Embedding an iFrame is forbidden + +The worst that can happen is that the website you are trying to embed completely denies you the authorisation. +A website owner can do that using the [`X-Frame-Options` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options), +or the newer [`Content-Security-Policy` HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy). + +Take a look at the headers of the page you are trying to load. + +{.alert.alert-info} +You can view the headers of the web page you try to load in the developer tools of your browser (usually accessible using the F12 key +of your keyboard), in the network tab. Click on the top-most request and check the "Response Headers". + +Below is what you can see when opening a Youtube video page: + +![](images/x-frame-options.png) + +`X-Frame-Options: DENY` or `X-Frame-Options: SAMEORIGIN` will prevent WorkAdventure from loading the page. +`Content-Security-Policy` header have also the potential to prevent WorkAdventure from loading the page. + +If the website you are trying to embed has one of these headers set, here are your options: + +- if you have control over the website or know the owner, you can contact the owner/administrator of the website and ask for an exception +- otherwise, you can look for an "embed" option. Some websites have special pages that can be embedded. For instance, + YouTube has special "embed" links that can be used to embed a video in your website. A lot of websites have the same feature (you + can usually find those links in the "share" section) + +If none of these options are available to you, as a last resort, you can use the [`openTab` property](opening-a-website.md) instead of the `openWebsite` property. +It will open your webpage in another tab instead of opening it in an iFrame. + +### I cannot log into my embedded website + +When you log into a website, the website is issuing a "cookie". The cookie is a unique identifier that allows the website +to recognize you and to identify you. To improve the privacy of their users, browsers can sometimes treat cookies +inside iFrames as "third-party cookies" and discard them. + +Cookies can come with a `SameSite` attribute. + +The `SameSite` attribute can take these values: "Lax", "Strict" or "None". The only value that allows using the +cookie inside an iFrame is "None". + +{.alert.alert-info} +The `SameSite` attribute of your cookie MUST be set to "None" if you want to be able to use this cookie from an iFrame inside WorkAdventure. + +**Default values**: + +If the "SameSite" attribute is not explicitly set, [the behaviour depends on the browser](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#browser_compatibility). +Chrome, Edge and Opera will default to "Lax". +Firefox and Safari will default to "None" (as of 2022/04/25). + +As a result, a website that does not set the `SameSite` attribute on cookies will work correctly in Firefox and Safari but +login will fail on Chrome, Edge and Opera. + +If the website you are trying to embed has the `SameSite` attribute set to a value other than "None", here are your options: + +- if you have control over the website or know the owner, you can contact the owner/administrator of the website and ask + the owner/administrator to change the `SameSite` settings. +- otherwise, you will have to use the [`openTab` property](opening-a-website.md) instead of the `openWebsite` property. + It will open your webpage in another tab instead of in an iFrame. + +## Need some help? + +
+

WorkAdventure is a constantly evolving project and there is plenty of room for improvement regarding map editing.

+

If you are facing any troubles, do not hesitate to seek help in + our Discord server or open an "issue" in the + GitHub WorkAdventure account. +

+
diff --git a/docs/maps/wa-maps.md b/docs/maps/wa-maps.md index 6e84a251..8bec629b 100644 --- a/docs/maps/wa-maps.md +++ b/docs/maps/wa-maps.md @@ -87,11 +87,11 @@ Repeat for every tile that should be "collidable". In the next sections, you will see how you can add behaviour on your map by adding "properties". You can add properties for a variety of features: putting exits, opening websites, meeting rooms, silent zones, etc... -You can add properties either on individual tiles of a tileset OR on a complete layer. +You can add properties either on individual tiles of a tileset, on Tiled object OR on a complete layer. -If you put a property on a layer, it will be triggered if your Woka walks on any tile of the layer. +If you put a property on a object or layer, it will be triggered if your Woka walks on object area / any tile of the layer. -The exception is the "collides" property that can only be set on tiles, but not on a complete layer. +The exception is the "collides" property that can only be set on tiles, but not on an object or on complete layer. ## Insert helpful information in your map diff --git a/front/.eslintrc.js b/front/.eslintrc.js index fa57ebf4..e3f44ef1 100644 --- a/front/.eslintrc.js +++ b/front/.eslintrc.js @@ -27,8 +27,8 @@ module.exports = { ], "overrides": [ { - "files": ["*.svelte"], - "processor": "svelte3/svelte3" + "files": ["*.svelte"], + "processor": "svelte3/svelte3" } ], "rules": { @@ -36,6 +36,7 @@ module.exports = { "eol-last": ["error", "always"], "@typescript-eslint/no-explicit-any": "error", "no-throw-literal": "error", + "@typescript-eslint/no-unused-vars": ["error", { "args": "none", "caughtErrors": "all", "varsIgnorePattern": "_exhaustiveCheck" }], // TODO: remove those ignored rules and write a stronger code! "@typescript-eslint/no-unsafe-call": "off", "@typescript-eslint/restrict-plus-operands": "off", diff --git a/front/.prettierignore b/front/.prettierignore index 8d8c68de..bef7f3b6 100644 --- a/front/.prettierignore +++ b/front/.prettierignore @@ -1,5 +1,3 @@ src/Messages/generated src/Messages/JsonMessages -src/i18n/i18n-svelte.ts -src/i18n/i18n-types.ts -src/i18n/i18n-util.ts +src/i18n/i18n-*.ts diff --git a/front/.typesafe-i18n.json b/front/.typesafe-i18n.json index 0cecbe32..9e01cf76 100644 --- a/front/.typesafe-i18n.json +++ b/front/.typesafe-i18n.json @@ -1,5 +1,5 @@ { - "$schema": "https://unpkg.com/typesafe-i18n@2.59.0/schema/typesafe-i18n.json", + "$schema": "https://unpkg.com/typesafe-i18n@5.4.0/schema/typesafe-i18n.json", "baseLocale": "en-US", "adapter": "svelte" } \ No newline at end of file diff --git a/front/package.json b/front/package.json index 278a5768..e5ccede2 100644 --- a/front/package.json +++ b/front/package.json @@ -4,7 +4,8 @@ "main": "index.js", "license": "SEE LICENSE IN LICENSE.txt", "devDependencies": { - "@geprog/vite-plugin-env-config": "^4.0.0", + "@geprog/vite-plugin-env-config": "^4.0.3", + "@home-based-studio/phaser3-utils": "^0.4.7", "@sveltejs/vite-plugin-svelte": "^1.0.0-next.36", "@tsconfig/svelte": "^1.0.10", "@types/google-protobuf": "^3.7.3", @@ -41,12 +42,11 @@ "buffer": "^6.0.3", "cancelable-promise": "^4.2.1", "cross-env": "^7.0.3", - "deep-copy-ts": "^0.5.0", + "deep-copy-ts": "^0.5.4", "easystarjs": "^0.4.4", "fast-deep-equal": "^3.1.3", - "generic-type-guard": "^3.4.2", "google-protobuf": "^3.13.0", - "phaser": "^3.54.0", + "phaser": "3.55.1", "phaser-animated-tiles": "workadventure/phaser-animated-tiles#da68bbededd605925621dd4f03bd27e69284b254", "phaser3-rex-plugins": "^1.1.42", "posthog-js": "^1.14.1", @@ -60,9 +60,9 @@ "standardized-audio-context": "^25.2.4", "ts-deferred": "^1.0.4", "ts-proto": "^1.96.0", - "typesafe-i18n": "^2.59.0", + "typesafe-i18n": "^5.4.0", "uuidv4": "^6.2.10", - "zod": "^3.11.6" + "zod": "^3.14.3" }, "scripts": { "start": "run-p templater serve watch-iframe-api svelte-check-watch typesafe-i18n-watch", diff --git a/front/public/resources/icons/icon_accessory.png b/front/public/resources/icons/icon_accessory.png new file mode 100644 index 00000000..9ca5f341 Binary files /dev/null and b/front/public/resources/icons/icon_accessory.png differ diff --git a/front/public/resources/icons/icon_body.png b/front/public/resources/icons/icon_body.png new file mode 100644 index 00000000..c2d4983b Binary files /dev/null and b/front/public/resources/icons/icon_body.png differ diff --git a/front/public/resources/icons/icon_clothes.png b/front/public/resources/icons/icon_clothes.png new file mode 100644 index 00000000..0e9c39a0 Binary files /dev/null and b/front/public/resources/icons/icon_clothes.png differ diff --git a/front/public/resources/icons/icon_eyes.png b/front/public/resources/icons/icon_eyes.png new file mode 100644 index 00000000..8d37005e Binary files /dev/null and b/front/public/resources/icons/icon_eyes.png differ diff --git a/front/public/resources/icons/icon_hair.png b/front/public/resources/icons/icon_hair.png new file mode 100644 index 00000000..eee503d3 Binary files /dev/null and b/front/public/resources/icons/icon_hair.png differ diff --git a/front/public/resources/icons/icon_hat.png b/front/public/resources/icons/icon_hat.png new file mode 100644 index 00000000..36ed26ae Binary files /dev/null and b/front/public/resources/icons/icon_hat.png differ diff --git a/front/public/resources/icons/icon_status_indicator_inside.png b/front/public/resources/icons/icon_status_indicator_inside.png new file mode 100644 index 00000000..29a2daad Binary files /dev/null and b/front/public/resources/icons/icon_status_indicator_inside.png differ diff --git a/front/public/resources/icons/icon_status_indicator_outline.png b/front/public/resources/icons/icon_status_indicator_outline.png new file mode 100644 index 00000000..67f86ec5 Binary files /dev/null and b/front/public/resources/icons/icon_status_indicator_outline.png differ diff --git a/front/public/resources/icons/icon_turn.png b/front/public/resources/icons/icon_turn.png new file mode 100644 index 00000000..8e1b367e Binary files /dev/null and b/front/public/resources/icons/icon_turn.png differ diff --git a/front/public/resources/logos/report.svg b/front/public/resources/logos/report.svg new file mode 100644 index 00000000..7c7d12ad --- /dev/null +++ b/front/public/resources/logos/report.svg @@ -0,0 +1 @@ + diff --git a/front/public/resources/tilesets/floor_tiles.png b/front/public/resources/tilesets/floor_tiles.png new file mode 100644 index 00000000..0cdc7fde Binary files /dev/null and b/front/public/resources/tilesets/floor_tiles.png differ diff --git a/front/src/Administration/AnalyticsClient.ts b/front/src/Administration/AnalyticsClient.ts index 4c1ca93a..8c14eaed 100644 --- a/front/src/Administration/AnalyticsClient.ts +++ b/front/src/Administration/AnalyticsClient.ts @@ -9,7 +9,7 @@ class AnalyticsClient { constructor() { if (POSTHOG_API_KEY && POSTHOG_URL) { this.posthogPromise = import("posthog-js").then(({ default: posthog }) => { - posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL, disable_cookie: true }); + posthog.init(POSTHOG_API_KEY, { api_host: POSTHOG_URL }); //the posthog toolbar need a reference in window to be able to work window.posthog = posthog; return posthog; diff --git a/front/src/Api/Events/ActionsMenuActionClickedEvent.ts b/front/src/Api/Events/ActionsMenuActionClickedEvent.ts index 4ff5485a..3f24484b 100644 --- a/front/src/Api/Events/ActionsMenuActionClickedEvent.ts +++ b/front/src/Api/Events/ActionsMenuActionClickedEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isActionsMenuActionClickedEvent = new tg.IsInterface() - .withProperties({ - id: tg.isNumber, - actionName: tg.isString, - }) - .get(); +export const isActionsMenuActionClickedEvent = z.object({ + id: z.number(), + actionName: z.string(), +}); -export type ActionsMenuActionClickedEvent = tg.GuardedType; +export type ActionsMenuActionClickedEvent = z.infer; export type ActionsMenuActionClickedEventCallback = (event: ActionsMenuActionClickedEvent) => void; diff --git a/front/src/Api/Events/AddActionsMenuKeyToRemotePlayerEvent.ts b/front/src/Api/Events/AddActionsMenuKeyToRemotePlayerEvent.ts index 6741d730..6f54d324 100644 --- a/front/src/Api/Events/AddActionsMenuKeyToRemotePlayerEvent.ts +++ b/front/src/Api/Events/AddActionsMenuKeyToRemotePlayerEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isAddActionsMenuKeyToRemotePlayerEvent = new tg.IsInterface() - .withProperties({ - id: tg.isNumber, - actionKey: tg.isString, - }) - .get(); +export const isAddActionsMenuKeyToRemotePlayerEvent = z.object({ + id: z.number(), + actionKey: z.string(), +}); -export type AddActionsMenuKeyToRemotePlayerEvent = tg.GuardedType; +export type AddActionsMenuKeyToRemotePlayerEvent = z.infer; export type AddActionsMenuKeyToRemotePlayerEventCallback = (event: AddActionsMenuKeyToRemotePlayerEvent) => void; diff --git a/front/src/Api/Events/ButtonClickedEvent.ts b/front/src/Api/Events/ButtonClickedEvent.ts index 26a8aceb..be1f9028 100644 --- a/front/src/Api/Events/ButtonClickedEvent.ts +++ b/front/src/Api/Events/ButtonClickedEvent.ts @@ -1,12 +1,11 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isButtonClickedEvent = z.object({ + popupId: z.number(), + buttonId: z.number(), +}); -export const isButtonClickedEvent = new tg.IsInterface() - .withProperties({ - popupId: tg.isNumber, - buttonId: tg.isNumber, - }) - .get(); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ -export type ButtonClickedEvent = tg.GuardedType; +export type ButtonClickedEvent = z.infer; diff --git a/front/src/Api/Events/CameraFollowPlayerEvent.ts b/front/src/Api/Events/CameraFollowPlayerEvent.ts index cf34e7fc..a218ba79 100644 --- a/front/src/Api/Events/CameraFollowPlayerEvent.ts +++ b/front/src/Api/Events/CameraFollowPlayerEvent.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isCameraFollowPlayerEvent = z.object({ + smooth: z.boolean(), +}); -export const isCameraFollowPlayerEvent = new tg.IsInterface() - .withProperties({ - smooth: tg.isBoolean, - }) - .get(); /** * A message sent from the iFrame to the game to make the camera follow player. */ -export type CameraFollowPlayerEvent = tg.GuardedType; +export type CameraFollowPlayerEvent = z.infer; diff --git a/front/src/Api/Events/CameraSetEvent.ts b/front/src/Api/Events/CameraSetEvent.ts index a3da7c62..aa6dab0b 100644 --- a/front/src/Api/Events/CameraSetEvent.ts +++ b/front/src/Api/Events/CameraSetEvent.ts @@ -1,16 +1,15 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isCameraSetEvent = z.object({ + x: z.number(), + y: z.number(), + width: z.optional(z.number()), + height: z.optional(z.number()), + lock: z.boolean(), + smooth: z.boolean(), +}); -export const isCameraSetEvent = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - width: tg.isOptional(tg.isNumber), - height: tg.isOptional(tg.isNumber), - lock: tg.isBoolean, - smooth: tg.isBoolean, - }) - .get(); /** * A message sent from the iFrame to the game to change the camera position. */ -export type CameraSetEvent = tg.GuardedType; +export type CameraSetEvent = z.infer; diff --git a/front/src/Api/Events/ChangeAreaEvent.ts b/front/src/Api/Events/ChangeAreaEvent.ts new file mode 100644 index 00000000..38764ad3 --- /dev/null +++ b/front/src/Api/Events/ChangeAreaEvent.ts @@ -0,0 +1,10 @@ +import { z } from "zod"; + +export const isChangeZoneEvent = z.object({ + name: z.string(), +}); + +/** + * A message sent from the game to the iFrame when a user enters or leaves a zone. + */ +export type ChangeAreaEvent = z.infer; diff --git a/front/src/Api/Events/ChangeLayerEvent.ts b/front/src/Api/Events/ChangeLayerEvent.ts index 77ff8ede..952b0ec4 100644 --- a/front/src/Api/Events/ChangeLayerEvent.ts +++ b/front/src/Api/Events/ChangeLayerEvent.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isChangeLayerEvent = z.object({ + name: z.string(), +}); -export const isChangeLayerEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - }) - .get(); /** * A message sent from the game to the iFrame when a user enters or leaves a layer. */ -export type ChangeLayerEvent = tg.GuardedType; +export type ChangeLayerEvent = z.infer; diff --git a/front/src/Api/Events/ChangeZoneEvent.ts b/front/src/Api/Events/ChangeZoneEvent.ts deleted file mode 100644 index e7ca3668..00000000 --- a/front/src/Api/Events/ChangeZoneEvent.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as tg from "generic-type-guard"; - -export const isChangeZoneEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - }) - .get(); -/** - * A message sent from the game to the iFrame when a user enters or leaves a zone. - */ -export type ChangeZoneEvent = tg.GuardedType; diff --git a/front/src/Api/Events/ChatEvent.ts b/front/src/Api/Events/ChatEvent.ts index 984859e8..0fadb950 100644 --- a/front/src/Api/Events/ChatEvent.ts +++ b/front/src/Api/Events/ChatEvent.ts @@ -1,12 +1,11 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isChatEvent = z.object({ + message: z.string(), + author: z.string(), +}); -export const isChatEvent = new tg.IsInterface() - .withProperties({ - message: tg.isString, - author: tg.isString, - }) - .get(); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type ChatEvent = tg.GuardedType; +export type ChatEvent = z.infer; diff --git a/front/src/Api/Events/CloseCoWebsiteEvent.ts b/front/src/Api/Events/CloseCoWebsiteEvent.ts index 4dc1e51d..0a0123e6 100644 --- a/front/src/Api/Events/CloseCoWebsiteEvent.ts +++ b/front/src/Api/Events/CloseCoWebsiteEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isCloseCoWebsite = new tg.IsInterface() - .withProperties({ - id: tg.isOptional(tg.isString), - }) - .get(); +export const isCloseCoWebsite = z.object({ + id: z.optional(z.string()), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type CloseCoWebsiteEvent = tg.GuardedType; +export type CloseCoWebsiteEvent = z.infer; diff --git a/front/src/Api/Events/ClosePopupEvent.ts b/front/src/Api/Events/ClosePopupEvent.ts index f604a404..d9916560 100644 --- a/front/src/Api/Events/ClosePopupEvent.ts +++ b/front/src/Api/Events/ClosePopupEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isClosePopupEvent = new tg.IsInterface() - .withProperties({ - popupId: tg.isNumber, - }) - .get(); +export const isClosePopupEvent = z.object({ + popupId: z.number(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type ClosePopupEvent = tg.GuardedType; +export type ClosePopupEvent = z.infer; diff --git a/front/src/Api/Events/ColorEvent.ts b/front/src/Api/Events/ColorEvent.ts index c8e6d349..ae0a4f46 100644 --- a/front/src/Api/Events/ColorEvent.ts +++ b/front/src/Api/Events/ColorEvent.ts @@ -1,13 +1,12 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isColorEvent = z.object({ + red: z.number(), + green: z.number(), + blue: z.number(), +}); -export const isColorEvent = new tg.IsInterface() - .withProperties({ - red: tg.isNumber, - green: tg.isNumber, - blue: tg.isNumber, - }) - .get(); /** * A message sent from the iFrame to the game to dynamically set the outline of the player. */ -export type ColorEvent = tg.GuardedType; +export type ColorEvent = z.infer; diff --git a/front/src/Api/Events/EmbeddedWebsiteEvent.ts b/front/src/Api/Events/EmbeddedWebsiteEvent.ts index 57c24853..81c35568 100644 --- a/front/src/Api/Events/EmbeddedWebsiteEvent.ts +++ b/front/src/Api/Events/EmbeddedWebsiteEvent.ts @@ -1,52 +1,43 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isRectangle = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - width: tg.isNumber, - height: tg.isNumber, - }) - .get(); +export const isRectangle = z.object({ + x: z.number(), + y: z.number(), + width: z.number(), + height: z.number(), +}); -export const isEmbeddedWebsiteEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - }) - .withOptionalProperties({ - url: tg.isString, - visible: tg.isBoolean, - allowApi: tg.isBoolean, - allow: tg.isString, - x: tg.isNumber, - y: tg.isNumber, - width: tg.isNumber, - height: tg.isNumber, - origin: tg.isSingletonStringUnion("player", "map"), - scale: tg.isNumber, - }) - .get(); +// TODO: make a variation that is all optional (except for the name) +export type Rectangle = z.infer; -export const isCreateEmbeddedWebsiteEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - url: tg.isString, - position: isRectangle, - }) - .withOptionalProperties({ - visible: tg.isBoolean, - allowApi: tg.isBoolean, - allow: tg.isString, - origin: tg.isSingletonStringUnion("player", "map"), - scale: tg.isNumber, - }) - .get(); +export const isEmbeddedWebsiteEvent = z.object({ + name: z.string(), + url: z.optional(z.string()), + visible: z.optional(z.boolean()), + allowApi: z.optional(z.boolean()), + allow: z.optional(z.string()), + x: z.optional(z.number()), + y: z.optional(z.number()), + width: z.optional(z.number()), + height: z.optional(z.number()), + origin: z.optional(z.enum(["player", "map"])), + scale: z.optional(z.number()), +}); /** * A message sent from the iFrame to the game to modify an embedded website */ -export type ModifyEmbeddedWebsiteEvent = tg.GuardedType; +export type ModifyEmbeddedWebsiteEvent = z.infer; -export type CreateEmbeddedWebsiteEvent = tg.GuardedType; -// TODO: make a variation that is all optional (except for the name) -export type Rectangle = tg.GuardedType; +export const isCreateEmbeddedWebsiteEvent = z.object({ + name: z.string(), + url: z.string(), + position: isRectangle, + visible: z.optional(z.boolean()), + allowApi: z.optional(z.boolean()), + allow: z.optional(z.string()), + origin: z.optional(z.enum(["player", "map"])), + scale: z.optional(z.number()), +}); + +export type CreateEmbeddedWebsiteEvent = z.infer; diff --git a/front/src/Api/Events/EnterLeaveEvent.ts b/front/src/Api/Events/EnterLeaveEvent.ts index ca68136e..13733a1f 100644 --- a/front/src/Api/Events/EnterLeaveEvent.ts +++ b/front/src/Api/Events/EnterLeaveEvent.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isEnterLeaveEvent = z.object({ + name: z.string(), +}); -export const isEnterLeaveEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - }) - .get(); /** * A message sent from the game to the iFrame when a user enters or leaves a zone marked with the "zone" property. */ -export type EnterLeaveEvent = tg.GuardedType; +export type EnterLeaveEvent = z.infer; diff --git a/front/src/Api/Events/GameStateEvent.ts b/front/src/Api/Events/GameStateEvent.ts index 80c07e5a..e576c192 100644 --- a/front/src/Api/Events/GameStateEvent.ts +++ b/front/src/Api/Events/GameStateEvent.ts @@ -1,20 +1,19 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isGameStateEvent = z.object({ + roomId: z.string(), + mapUrl: z.string(), + nickname: z.string(), + language: z.optional(z.string()), + uuid: z.optional(z.string()), + startLayerName: z.optional(z.string()), + tags: z.array(z.string()), + variables: z.unknown(), // Todo : Typing + playerVariables: z.unknown(), // Todo : Typing + userRoomToken: z.optional(z.string()), +}); -export const isGameStateEvent = new tg.IsInterface() - .withProperties({ - roomId: tg.isString, - mapUrl: tg.isString, - nickname: tg.isString, - language: tg.isUnion(tg.isString, tg.isUndefined), - uuid: tg.isUnion(tg.isString, tg.isUndefined), - startLayerName: tg.isUnion(tg.isString, tg.isNull), - tags: tg.isArray(tg.isString), - variables: tg.isObject, - playerVariables: tg.isObject, - userRoomToken: tg.isUnion(tg.isString, tg.isUndefined), - }) - .get(); /** * A message sent from the game to the iFrame when the gameState is received by the script */ -export type GameStateEvent = tg.GuardedType; +export type GameStateEvent = z.infer; diff --git a/front/src/Api/Events/GoToPageEvent.ts b/front/src/Api/Events/GoToPageEvent.ts index d8d6467d..87ff2f7c 100644 --- a/front/src/Api/Events/GoToPageEvent.ts +++ b/front/src/Api/Events/GoToPageEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isGoToPageEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isGoToPageEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type GoToPageEvent = tg.GuardedType; +export type GoToPageEvent = z.infer; diff --git a/front/src/Api/Events/HasPlayerMovedEvent.ts b/front/src/Api/Events/HasPlayerMovedEvent.ts index a3f1aa21..aee1d671 100644 --- a/front/src/Api/Events/HasPlayerMovedEvent.ts +++ b/front/src/Api/Events/HasPlayerMovedEvent.ts @@ -1,19 +1,17 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isHasPlayerMovedEvent = new tg.IsInterface() - .withProperties({ - direction: tg.isElementOf("right", "left", "up", "down"), - moving: tg.isBoolean, - x: tg.isNumber, - y: tg.isNumber, - oldX: tg.isOptional(tg.isNumber), - oldY: tg.isOptional(tg.isNumber), - }) - .get(); +export const isHasPlayerMovedEvent = z.object({ + direction: z.enum(["right", "left", "up", "down"]), + moving: z.boolean(), + x: z.number(), + y: z.number(), + oldX: z.optional(z.number()), + oldY: z.optional(z.number()), +}); /** * A message sent from the game to the iFrame to notify a movement from the current player. */ -export type HasPlayerMovedEvent = tg.GuardedType; +export type HasPlayerMovedEvent = z.infer; export type HasPlayerMovedEventCallback = (event: HasPlayerMovedEvent) => void; diff --git a/front/src/Api/Events/IframeEvent.ts b/front/src/Api/Events/IframeEvent.ts index fc48b040..f584f6d9 100644 --- a/front/src/Api/Events/IframeEvent.ts +++ b/front/src/Api/Events/IframeEvent.ts @@ -1,45 +1,44 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; import type { ButtonClickedEvent } from "./ButtonClickedEvent"; -import type { ChatEvent } from "./ChatEvent"; -import type { ClosePopupEvent } from "./ClosePopupEvent"; +import { isChatEvent } from "./ChatEvent"; +import { isClosePopupEvent } from "./ClosePopupEvent"; import type { EnterLeaveEvent } from "./EnterLeaveEvent"; -import type { GoToPageEvent } from "./GoToPageEvent"; -import type { LoadPageEvent } from "./LoadPageEvent"; +import { isGoToPageEvent } from "./GoToPageEvent"; +import { isLoadPageEvent } from "./LoadPageEvent"; import { isCoWebsite, isOpenCoWebsiteEvent } from "./OpenCoWebsiteEvent"; -import type { OpenPopupEvent } from "./OpenPopupEvent"; -import type { OpenTabEvent } from "./OpenTabEvent"; +import { isOpenPopupEvent } from "./OpenPopupEvent"; +import { isOpenTabEvent } from "./OpenTabEvent"; import type { UserInputChatEvent } from "./UserInputChatEvent"; -import type { LayerEvent } from "./LayerEvent"; -import type { SetPropertyEvent } from "./setPropertyEvent"; -import type { LoadSoundEvent } from "./LoadSoundEvent"; -import type { PlaySoundEvent } from "./PlaySoundEvent"; +import { isLayerEvent } from "./LayerEvent"; +import { isSetPropertyEvent } from "./setPropertyEvent"; +import { isLoadSoundEvent } from "./LoadSoundEvent"; +import { isPlaySoundEvent } from "./PlaySoundEvent"; +import { isStopSoundEvent } from "./StopSoundEvent"; import type { MenuItemClickedEvent } from "./ui/MenuItemClickedEvent"; import type { HasPlayerMovedEvent } from "./HasPlayerMovedEvent"; -import type { SetTilesEvent } from "./SetTilesEvent"; +import { isSetTilesEvent } from "./SetTilesEvent"; import type { SetVariableEvent } from "./SetVariableEvent"; import { isGameStateEvent } from "./GameStateEvent"; import { isMapDataEvent } from "./MapDataEvent"; import { isSetVariableEvent } from "./SetVariableEvent"; -import type { EmbeddedWebsite } from "../iframe/Room/EmbeddedWebsite"; -import { isCreateEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent"; -import type { LoadTilesetEvent } from "./LoadTilesetEvent"; +import { isCreateEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./EmbeddedWebsiteEvent"; import { isLoadTilesetEvent } from "./LoadTilesetEvent"; import type { MessageReferenceEvent } from "./ui/TriggerActionMessageEvent"; import { isMessageReferenceEvent, isTriggerActionMessageEvent } from "./ui/TriggerActionMessageEvent"; -import type { MenuRegisterEvent, UnregisterMenuEvent } from "./ui/MenuRegisterEvent"; +import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./ui/MenuRegisterEvent"; import type { ChangeLayerEvent } from "./ChangeLayerEvent"; import { isPlayerPosition } from "./PlayerPosition"; import type { WasCameraUpdatedEvent } from "./WasCameraUpdatedEvent"; -import type { ChangeZoneEvent } from "./ChangeZoneEvent"; -import type { CameraSetEvent } from "./CameraSetEvent"; -import type { CameraFollowPlayerEvent } from "./CameraFollowPlayerEvent"; +import type { ChangeAreaEvent } from "./ChangeAreaEvent"; +import { isCameraSetEvent } from "./CameraSetEvent"; +import { isCameraFollowPlayerEvent } from "./CameraFollowPlayerEvent"; import { isColorEvent } from "./ColorEvent"; import { isMovePlayerToEventConfig } from "./MovePlayerToEvent"; import { isMovePlayerToEventAnswer } from "./MovePlayerToEventAnswer"; import type { RemotePlayerClickedEvent } from "./RemotePlayerClickedEvent"; -import type { AddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent"; +import { isAddActionsMenuKeyToRemotePlayerEvent } from "./AddActionsMenuKeyToRemotePlayerEvent"; import type { ActionsMenuActionClickedEvent } from "./ActionsMenuActionClickedEvent"; -import type { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent"; +import { isRemoveActionsMenuKeyFromRemotePlayerEvent } from "./RemoveActionsMenuKeyFromRemotePlayerEvent"; export interface TypedMessageEvent extends MessageEvent { data: T; @@ -48,45 +47,114 @@ export interface TypedMessageEvent extends MessageEvent { /** * List event types sent from an iFrame to WorkAdventure */ -export type IframeEventMap = { - addActionsMenuKeyToRemotePlayer: AddActionsMenuKeyToRemotePlayerEvent; - removeActionsMenuKeyFromRemotePlayer: RemoveActionsMenuKeyFromRemotePlayerEvent; - loadPage: LoadPageEvent; - chat: ChatEvent; - cameraFollowPlayer: CameraFollowPlayerEvent; - cameraSet: CameraSetEvent; - openPopup: OpenPopupEvent; - closePopup: ClosePopupEvent; - openTab: OpenTabEvent; - goToPage: GoToPageEvent; - disablePlayerControls: null; - restorePlayerControls: null; - displayBubble: null; - removeBubble: null; - onPlayerMove: undefined; - onOpenActionMenu: undefined; - onCameraUpdate: undefined; - showLayer: LayerEvent; - hideLayer: LayerEvent; - setProperty: SetPropertyEvent; - loadSound: LoadSoundEvent; - playSound: PlaySoundEvent; - stopSound: null; - getState: undefined; - loadTileset: LoadTilesetEvent; - registerMenu: MenuRegisterEvent; - unregisterMenu: UnregisterMenuEvent; - setTiles: SetTilesEvent; - modifyEmbeddedWebsite: Partial; // Note: name should be compulsory in fact -}; -export interface IframeEvent { - type: T; - data: IframeEventMap[T]; -} +export const isIframeEventWrapper = z.union([ + z.object({ + type: z.literal("addActionsMenuKeyToRemotePlayer"), + data: isAddActionsMenuKeyToRemotePlayerEvent, + }), + z.object({ + type: z.literal("removeActionsMenuKeyFromRemotePlayer"), + data: isRemoveActionsMenuKeyFromRemotePlayerEvent, + }), + z.object({ + type: z.literal("loadPage"), + data: isLoadPageEvent, + }), + z.object({ + type: z.literal("chat"), + data: isChatEvent, + }), + z.object({ + type: z.literal("cameraFollowPlayer"), + data: isCameraFollowPlayerEvent, + }), + z.object({ + type: z.literal("cameraSet"), + data: isCameraSetEvent, + }), + z.object({ + type: z.literal("openPopup"), + data: isOpenPopupEvent, + }), + z.object({ + type: z.literal("closePopup"), + data: isClosePopupEvent, + }), + z.object({ + type: z.literal("openTab"), + data: isOpenTabEvent, + }), + z.object({ + type: z.literal("goToPage"), + data: isGoToPageEvent, + }), + z.object({ + type: z.literal("disablePlayerControls"), + data: z.undefined(), + }), + z.object({ + type: z.literal("restorePlayerControls"), + data: z.undefined(), + }), + z.object({ + type: z.literal("displayBubble"), + data: z.undefined(), + }), + z.object({ + type: z.literal("removeBubble"), + data: z.undefined(), + }), + z.object({ + type: z.literal("onPlayerMove"), + data: z.undefined(), + }), + z.object({ + type: z.literal("onCameraUpdate"), + data: z.undefined(), + }), + z.object({ + type: z.literal("showLayer"), + data: isLayerEvent, + }), + z.object({ + type: z.literal("hideLayer"), + data: isLayerEvent, + }), + z.object({ + type: z.literal("setProperty"), + data: isSetPropertyEvent, + }), + z.object({ + type: z.literal("loadSound"), + data: isLoadSoundEvent, + }), + z.object({ + type: z.literal("playSound"), + data: isPlaySoundEvent, + }), + z.object({ + type: z.literal("stopSound"), + data: isStopSoundEvent, + }), + z.object({ + type: z.literal("registerMenu"), + data: isMenuRegisterEvent, + }), + z.object({ + type: z.literal("unregisterMenu"), + data: isUnregisterMenuEvent, + }), + z.object({ + type: z.literal("setTiles"), + data: isSetTilesEvent, + }), + z.object({ + type: z.literal("modifyEmbeddedWebsite"), + data: isEmbeddedWebsiteEvent, + }), +]); -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export const isIframeEventWrapper = (event: any): event is IframeEvent => - typeof event.type === "string"; +export type IframeEvent = z.infer; export interface IframeResponseEventMap { userInputChat: UserInputChatEvent; @@ -94,8 +162,8 @@ export interface IframeResponseEventMap { leaveEvent: EnterLeaveEvent; enterLayerEvent: ChangeLayerEvent; leaveLayerEvent: ChangeLayerEvent; - enterZoneEvent: ChangeZoneEvent; - leaveZoneEvent: ChangeZoneEvent; + enterAreaEvent: ChangeAreaEvent; + leaveAreaEvent: ChangeAreaEvent; buttonClickedEvent: ButtonClickedEvent; remotePlayerClickedEvent: RemotePlayerClickedEvent; actionsMenuActionClickedEvent: ActionsMenuActionClickedEvent; @@ -115,73 +183,78 @@ export const isIframeResponseEventWrapper = (event: { type?: string; }): event is IframeResponseEvent => typeof event.type === "string"; +export const isLookingLikeIframeEventWrapper = z.object({ + type: z.string(), + data: z.unknown().optional(), +}); + /** * List event types sent from an iFrame to WorkAdventure that expect a unique answer from WorkAdventure along the type for the answer from WorkAdventure to the iFrame. * Types are defined using Type guards that will actually bused to enforce and check types. */ export const iframeQueryMapTypeGuards = { getState: { - query: tg.isUndefined, + query: z.undefined(), answer: isGameStateEvent, }, getMapData: { - query: tg.isUndefined, + query: z.undefined(), answer: isMapDataEvent, }, setVariable: { query: isSetVariableEvent, - answer: tg.isUndefined, + answer: z.undefined(), }, loadTileset: { query: isLoadTilesetEvent, - answer: tg.isNumber, + answer: z.number(), }, openCoWebsite: { query: isOpenCoWebsiteEvent, answer: isCoWebsite, }, getCoWebsites: { - query: tg.isUndefined, - answer: tg.isArray(isCoWebsite), + query: z.undefined(), + answer: z.array(isCoWebsite), }, closeCoWebsite: { - query: tg.isString, - answer: tg.isUndefined, + query: z.string(), + answer: z.undefined(), }, closeCoWebsites: { - query: tg.isUndefined, - answer: tg.isUndefined, + query: z.undefined(), + answer: z.undefined(), }, triggerActionMessage: { query: isTriggerActionMessageEvent, - answer: tg.isUndefined, + answer: z.undefined(), }, removeActionMessage: { query: isMessageReferenceEvent, - answer: tg.isUndefined, + answer: z.undefined(), }, getEmbeddedWebsite: { - query: tg.isString, + query: z.string(), answer: isCreateEmbeddedWebsiteEvent, }, deleteEmbeddedWebsite: { - query: tg.isString, - answer: tg.isUndefined, + query: z.string(), + answer: z.undefined(), }, createEmbeddedWebsite: { query: isCreateEmbeddedWebsiteEvent, - answer: tg.isUndefined, + answer: z.undefined(), }, setPlayerOutline: { query: isColorEvent, - answer: tg.isUndefined, + answer: z.undefined(), }, removePlayerOutline: { - query: tg.isUndefined, - answer: tg.isUndefined, + query: z.undefined(), + answer: z.undefined(), }, getPlayerPosition: { - query: tg.isUndefined, + query: z.undefined(), answer: isPlayerPosition, }, movePlayerTo: { @@ -190,14 +263,13 @@ export const iframeQueryMapTypeGuards = { }, }; -type GuardedType = T extends (x: unknown) => x is infer T ? T : never; type IframeQueryMapTypeGuardsType = typeof iframeQueryMapTypeGuards; type UnknownToVoid = undefined extends T ? void : T; export type IframeQueryMap = { [key in keyof IframeQueryMapTypeGuardsType]: { - query: GuardedType; - answer: UnknownToVoid>; + query: z.infer; + answer: UnknownToVoid>; }; }; @@ -225,11 +297,18 @@ export const isIframeQuery = (event: any): event is IframeQuery; +export type LayerEvent = z.infer; diff --git a/front/src/Api/Events/LoadPageEvent.ts b/front/src/Api/Events/LoadPageEvent.ts index 63600a28..c5fe11b3 100644 --- a/front/src/Api/Events/LoadPageEvent.ts +++ b/front/src/Api/Events/LoadPageEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isLoadPageEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isLoadPageEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type LoadPageEvent = tg.GuardedType; +export type LoadPageEvent = z.infer; diff --git a/front/src/Api/Events/LoadSoundEvent.ts b/front/src/Api/Events/LoadSoundEvent.ts index f48f202f..fa338fac 100644 --- a/front/src/Api/Events/LoadSoundEvent.ts +++ b/front/src/Api/Events/LoadSoundEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isLoadSoundEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isLoadSoundEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type LoadSoundEvent = tg.GuardedType; +export type LoadSoundEvent = z.infer; diff --git a/front/src/Api/Events/LoadTilesetEvent.ts b/front/src/Api/Events/LoadTilesetEvent.ts index ecaf93be..239ffcc2 100644 --- a/front/src/Api/Events/LoadTilesetEvent.ts +++ b/front/src/Api/Events/LoadTilesetEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isLoadTilesetEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isLoadTilesetEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type LoadTilesetEvent = tg.GuardedType; +export type LoadTilesetEvent = z.infer; diff --git a/front/src/Api/Events/MapDataEvent.ts b/front/src/Api/Events/MapDataEvent.ts index f63164ed..d5fb62d4 100644 --- a/front/src/Api/Events/MapDataEvent.ts +++ b/front/src/Api/Events/MapDataEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isMapDataEvent = new tg.IsInterface() - .withProperties({ - data: tg.isObject, - }) - .get(); +export const isMapDataEvent = z.object({ + data: z.unknown(), // Todo : Typing +}); /** * A message sent from the game to the iFrame when the data of the layers change after the iFrame send a message to the game that it want to listen to the data of the layers */ -export type MapDataEvent = tg.GuardedType; +export type MapDataEvent = z.infer; diff --git a/front/src/Api/Events/MovePlayerToEvent.ts b/front/src/Api/Events/MovePlayerToEvent.ts index 462e2f43..543270a8 100644 --- a/front/src/Api/Events/MovePlayerToEvent.ts +++ b/front/src/Api/Events/MovePlayerToEvent.ts @@ -1,11 +1,9 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isMovePlayerToEventConfig = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - speed: tg.isOptional(tg.isNumber), - }) - .get(); +export const isMovePlayerToEventConfig = z.object({ + x: z.number(), + y: z.number(), + speed: z.optional(z.number()), +}); -export type MovePlayerToEvent = tg.GuardedType; +export type MovePlayerToEvent = z.infer; diff --git a/front/src/Api/Events/MovePlayerToEventAnswer.ts b/front/src/Api/Events/MovePlayerToEventAnswer.ts index 67d2f9ae..c6cdc0de 100644 --- a/front/src/Api/Events/MovePlayerToEventAnswer.ts +++ b/front/src/Api/Events/MovePlayerToEventAnswer.ts @@ -1,11 +1,9 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isMovePlayerToEventAnswer = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - cancelled: tg.isBoolean, - }) - .get(); +export const isMovePlayerToEventAnswer = z.object({ + x: z.number(), + y: z.number(), + cancelled: z.boolean(), +}); -export type MovePlayerToEventAnswer = tg.GuardedType; +export type ActionsMenuActionClickedEvent = z.infer; diff --git a/front/src/Api/Events/OpenCoWebsiteEvent.ts b/front/src/Api/Events/OpenCoWebsiteEvent.ts index b991d3f7..91a87e41 100644 --- a/front/src/Api/Events/OpenCoWebsiteEvent.ts +++ b/front/src/Api/Events/OpenCoWebsiteEvent.ts @@ -1,24 +1,20 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isOpenCoWebsiteEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - allowApi: tg.isOptional(tg.isBoolean), - allowPolicy: tg.isOptional(tg.isString), - widthPercent: tg.isOptional(tg.isNumber), - position: tg.isOptional(tg.isNumber), - closable: tg.isOptional(tg.isBoolean), - lazy: tg.isOptional(tg.isBoolean), - }) - .get(); +export const isOpenCoWebsiteEvent = z.object({ + url: z.string(), + allowApi: z.optional(z.boolean()), + allowPolicy: z.optional(z.string()), + widthPercent: z.optional(z.number()), + position: z.optional(z.number()), + closable: z.optional(z.boolean()), + lazy: z.optional(z.boolean()), +}); -export const isCoWebsite = new tg.IsInterface() - .withProperties({ - id: tg.isString, - }) - .get(); +export const isCoWebsite = z.object({ + id: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type OpenCoWebsiteEvent = tg.GuardedType; +export type OpenCoWebsiteEvent = z.infer; diff --git a/front/src/Api/Events/OpenPopupEvent.ts b/front/src/Api/Events/OpenPopupEvent.ts index c1070bbe..3e157780 100644 --- a/front/src/Api/Events/OpenPopupEvent.ts +++ b/front/src/Api/Events/OpenPopupEvent.ts @@ -1,22 +1,18 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -const isButtonDescriptor = new tg.IsInterface() - .withProperties({ - label: tg.isString, - className: tg.isOptional(tg.isString), - }) - .get(); +export const isButtonDescriptor = z.object({ + label: z.string(), + className: z.optional(z.string()), +}); -export const isOpenPopupEvent = new tg.IsInterface() - .withProperties({ - popupId: tg.isNumber, - targetObject: tg.isString, - message: tg.isString, - buttons: tg.isArray(isButtonDescriptor), - }) - .get(); +export const isOpenPopupEvent = z.object({ + popupId: z.number(), + targetObject: z.string(), + message: z.string(), + buttons: z.array(isButtonDescriptor), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type OpenPopupEvent = tg.GuardedType; +export type OpenPopupEvent = z.infer; diff --git a/front/src/Api/Events/OpenTabEvent.ts b/front/src/Api/Events/OpenTabEvent.ts index 6fe6ec21..d72d8f23 100644 --- a/front/src/Api/Events/OpenTabEvent.ts +++ b/front/src/Api/Events/OpenTabEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isOpenTabEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isOpenTabEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type OpenTabEvent = tg.GuardedType; +export type OpenTabEvent = z.infer; diff --git a/front/src/Api/Events/PlaySoundEvent.ts b/front/src/Api/Events/PlaySoundEvent.ts index 6fe56746..34cf0ad6 100644 --- a/front/src/Api/Events/PlaySoundEvent.ts +++ b/front/src/Api/Events/PlaySoundEvent.ts @@ -1,25 +1,21 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -const isSoundConfig = new tg.IsInterface() - .withProperties({ - volume: tg.isOptional(tg.isNumber), - loop: tg.isOptional(tg.isBoolean), - mute: tg.isOptional(tg.isBoolean), - rate: tg.isOptional(tg.isNumber), - detune: tg.isOptional(tg.isNumber), - seek: tg.isOptional(tg.isNumber), - delay: tg.isOptional(tg.isNumber), - }) - .get(); +export const isSoundConfig = z.object({ + volume: z.optional(z.number()), + loop: z.optional(z.boolean()), + mute: z.optional(z.boolean()), + rate: z.optional(z.number()), + detune: z.optional(z.number()), + seek: z.optional(z.number()), + delay: z.optional(z.number()), +}); -export const isPlaySoundEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - config: tg.isOptional(isSoundConfig), - }) - .get(); +export const isPlaySoundEvent = z.object({ + url: z.string(), + config: z.optional(isSoundConfig), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type PlaySoundEvent = tg.GuardedType; +export type PlaySoundEvent = z.infer; diff --git a/front/src/Api/Events/PlayerPosition.ts b/front/src/Api/Events/PlayerPosition.ts index 54fac6fe..b5a0c9dd 100644 --- a/front/src/Api/Events/PlayerPosition.ts +++ b/front/src/Api/Events/PlayerPosition.ts @@ -1,10 +1,8 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isPlayerPosition = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - }) - .get(); +export const isPlayerPosition = z.object({ + x: z.number(), + y: z.number(), +}); -export type PlayerPosition = tg.GuardedType; +export type PlayerPosition = z.infer; diff --git a/front/src/Api/Events/RemotePlayerClickedEvent.ts b/front/src/Api/Events/RemotePlayerClickedEvent.ts index bf217adc..a50acf87 100644 --- a/front/src/Api/Events/RemotePlayerClickedEvent.ts +++ b/front/src/Api/Events/RemotePlayerClickedEvent.ts @@ -1,15 +1,13 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; // TODO: Change for player Clicked, add all neccessary data -export const isRemotePlayerClickedEvent = new tg.IsInterface() - .withProperties({ - id: tg.isNumber, - }) - .get(); +export const isRemotePlayerClickedEvent = z.object({ + id: z.number(), +}); /** * A message sent from the game to the iFrame when RemotePlayer is clicked. */ -export type RemotePlayerClickedEvent = tg.GuardedType; +export type RemotePlayerClickedEvent = z.infer; export type RemotePlayerClickedEventCallback = (event: RemotePlayerClickedEvent) => void; diff --git a/front/src/Api/Events/RemoveActionsMenuKeyFromRemotePlayerEvent.ts b/front/src/Api/Events/RemoveActionsMenuKeyFromRemotePlayerEvent.ts index 745a07df..c8857b5d 100644 --- a/front/src/Api/Events/RemoveActionsMenuKeyFromRemotePlayerEvent.ts +++ b/front/src/Api/Events/RemoveActionsMenuKeyFromRemotePlayerEvent.ts @@ -1,15 +1,11 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isRemoveActionsMenuKeyFromRemotePlayerEvent = new tg.IsInterface() - .withProperties({ - id: tg.isNumber, - actionKey: tg.isString, - }) - .get(); +export const isRemoveActionsMenuKeyFromRemotePlayerEvent = z.object({ + id: z.number(), + actionKey: z.string(), +}); -export type RemoveActionsMenuKeyFromRemotePlayerEvent = tg.GuardedType< - typeof isRemoveActionsMenuKeyFromRemotePlayerEvent ->; +export type RemoveActionsMenuKeyFromRemotePlayerEvent = z.infer; export type RemoveActionsMenuKeyFromRemotePlayerEventCallback = ( event: RemoveActionsMenuKeyFromRemotePlayerEvent diff --git a/front/src/Api/Events/SetTilesEvent.ts b/front/src/Api/Events/SetTilesEvent.ts index 371f0884..847eef4c 100644 --- a/front/src/Api/Events/SetTilesEvent.ts +++ b/front/src/Api/Events/SetTilesEvent.ts @@ -1,16 +1,15 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isSetTilesEvent = tg.isArray( - new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - tile: tg.isUnion(tg.isUnion(tg.isNumber, tg.isString), tg.isNull), - layer: tg.isString, - }) - .get() +export const isSetTilesEvent = z.array( + z.object({ + x: z.number(), + y: z.number(), + tile: z.union([z.number(), z.string(), z.null()]), + layer: z.string(), + }) ); + /** * A message sent from the iFrame to the game to set one or many tiles. */ -export type SetTilesEvent = tg.GuardedType; +export type SetTilesEvent = z.infer; diff --git a/front/src/Api/Events/SetVariableEvent.ts b/front/src/Api/Events/SetVariableEvent.ts index 80ac6f6e..3b869afb 100644 --- a/front/src/Api/Events/SetVariableEvent.ts +++ b/front/src/Api/Events/SetVariableEvent.ts @@ -1,20 +1,17 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isSetVariableEvent = z.object({ + key: z.string(), + value: z.unknown(), + target: z.enum(["global", "player"]), +}); + +export const isSetVariableIframeEvent = z.object({ + type: z.enum(["setVariable"]), + data: isSetVariableEvent, +}); -export const isSetVariableEvent = new tg.IsInterface() - .withProperties({ - key: tg.isString, - value: tg.isUnknown, - target: tg.isSingletonStringUnion("global", "player"), - }) - .get(); /** * A message sent from the iFrame to the game to change the value of the property of the layer */ -export type SetVariableEvent = tg.GuardedType; - -export const isSetVariableIframeEvent = new tg.IsInterface() - .withProperties({ - type: tg.isSingletonString("setVariable"), - data: isSetVariableEvent, - }) - .get(); +export type SetVariableEvent = z.infer; diff --git a/front/src/Api/Events/StopSoundEvent.ts b/front/src/Api/Events/StopSoundEvent.ts index cdfe43ca..44d1cd0d 100644 --- a/front/src/Api/Events/StopSoundEvent.ts +++ b/front/src/Api/Events/StopSoundEvent.ts @@ -1,12 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isStopSoundEvent = new tg.IsInterface() - .withProperties({ - url: tg.isString, - }) - .get(); +export const isStopSoundEvent = z.object({ + url: z.string(), +}); /** * A message sent from the iFrame to the game to add a message in the chat. */ -export type StopSoundEvent = tg.GuardedType; +export type StopSoundEvent = z.infer; diff --git a/front/src/Api/Events/UserInputChatEvent.ts b/front/src/Api/Events/UserInputChatEvent.ts index 9de41327..940063ad 100644 --- a/front/src/Api/Events/UserInputChatEvent.ts +++ b/front/src/Api/Events/UserInputChatEvent.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isUserInputChatEvent = z.object({ + message: z.string(), +}); -export const isUserInputChatEvent = new tg.IsInterface() - .withProperties({ - message: tg.isString, - }) - .get(); /** * A message sent from the game to the iFrame when a user types a message in the chat. */ -export type UserInputChatEvent = tg.GuardedType; +export type UserInputChatEvent = z.infer; diff --git a/front/src/Api/Events/WasCameraUpdatedEvent.ts b/front/src/Api/Events/WasCameraUpdatedEvent.ts index 34e39a84..8a686695 100644 --- a/front/src/Api/Events/WasCameraUpdatedEvent.ts +++ b/front/src/Api/Events/WasCameraUpdatedEvent.ts @@ -1,19 +1,16 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; -export const isWasCameraUpdatedEvent = new tg.IsInterface() - .withProperties({ - x: tg.isNumber, - y: tg.isNumber, - width: tg.isNumber, - height: tg.isNumber, - zoom: tg.isNumber, - }) - .get(); +export const isWasCameraUpdatedEvent = z.object({ + x: z.number(), + y: z.number(), + width: z.number(), + height: z.number(), + zoom: z.number(), +}); /** * A message sent from the game to the iFrame to notify a movement from the camera. */ - -export type WasCameraUpdatedEvent = tg.GuardedType; +export type WasCameraUpdatedEvent = z.infer; export type WasCameraUpdatedEventCallback = (event: WasCameraUpdatedEvent) => void; diff --git a/front/src/Api/Events/setPropertyEvent.ts b/front/src/Api/Events/setPropertyEvent.ts index 7335f781..1a1f7e38 100644 --- a/front/src/Api/Events/setPropertyEvent.ts +++ b/front/src/Api/Events/setPropertyEvent.ts @@ -1,13 +1,12 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isSetPropertyEvent = z.object({ + layerName: z.string(), + propertyName: z.string(), + propertyValue: z.optional(z.union([z.string(), z.number(), z.boolean()])), +}); -export const isSetPropertyEvent = new tg.IsInterface() - .withProperties({ - layerName: tg.isString, - propertyName: tg.isString, - propertyValue: tg.isUnion(tg.isString, tg.isUnion(tg.isNumber, tg.isUnion(tg.isBoolean, tg.isUndefined))), - }) - .get(); /** * A message sent from the iFrame to the game to change the value of the property of the layer */ -export type SetPropertyEvent = tg.GuardedType; +export type SetPropertyEvent = z.infer; diff --git a/front/src/Api/Events/ui/MenuItemClickedEvent.ts b/front/src/Api/Events/ui/MenuItemClickedEvent.ts index a8c8d0ed..eb2e21f3 100644 --- a/front/src/Api/Events/ui/MenuItemClickedEvent.ts +++ b/front/src/Api/Events/ui/MenuItemClickedEvent.ts @@ -1,11 +1,10 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; + +export const isMenuItemClickedEvent = z.object({ + menuItem: z.string(), +}); -export const isMenuItemClickedEvent = new tg.IsInterface() - .withProperties({ - menuItem: tg.isString, - }) - .get(); /** * A message sent from the game to the iFrame when a menu item is clicked. */ -export type MenuItemClickedEvent = tg.GuardedType; +export type MenuItemClickedEvent = z.infer; diff --git a/front/src/Api/Events/ui/MenuRegisterEvent.ts b/front/src/Api/Events/ui/MenuRegisterEvent.ts index f620745f..201a52d4 100644 --- a/front/src/Api/Events/ui/MenuRegisterEvent.ts +++ b/front/src/Api/Events/ui/MenuRegisterEvent.ts @@ -1,31 +1,25 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; /** * A message sent from a script to the game to remove a custom menu from the menu */ -export const isUnregisterMenuEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - }) - .get(); +export const isUnregisterMenuEvent = z.object({ + name: z.string(), +}); -export type UnregisterMenuEvent = tg.GuardedType; +export type UnregisterMenuEvent = z.infer; -export const isMenuRegisterOptions = new tg.IsInterface() - .withProperties({ - allowApi: tg.isBoolean, - }) - .get(); +export const isMenuRegisterOptions = z.object({ + allowApi: z.boolean(), +}); /** * A message sent from a script to the game to add a custom menu from the menu */ -export const isMenuRegisterEvent = new tg.IsInterface() - .withProperties({ - name: tg.isString, - iframe: tg.isUnion(tg.isString, tg.isUndefined), - options: isMenuRegisterOptions, - }) - .get(); +export const isMenuRegisterEvent = z.object({ + name: z.string(), + iframe: z.optional(z.string()), + options: isMenuRegisterOptions, +}); -export type MenuRegisterEvent = tg.GuardedType; +export type MenuRegisterEvent = z.infer; diff --git a/front/src/Api/Events/ui/TriggerActionMessageEvent.ts b/front/src/Api/Events/ui/TriggerActionMessageEvent.ts index 48f1cae6..e34d72e8 100644 --- a/front/src/Api/Events/ui/TriggerActionMessageEvent.ts +++ b/front/src/Api/Events/ui/TriggerActionMessageEvent.ts @@ -1,26 +1,22 @@ -import * as tg from "generic-type-guard"; +import { z } from "zod"; export const triggerActionMessage = "triggerActionMessage"; export const removeActionMessage = "removeActionMessage"; -export const isActionMessageType = tg.isSingletonStringUnion("message", "warning"); +export const isActionMessageType = z.enum(["message", "warning"]); -export type ActionMessageType = tg.GuardedType; +export type ActionMessageType = z.infer; -export const isTriggerActionMessageEvent = new tg.IsInterface() - .withProperties({ - message: tg.isString, - uuid: tg.isString, - type: isActionMessageType, - }) - .get(); +export const isTriggerActionMessageEvent = z.object({ + message: z.string(), + uuid: z.string(), + type: isActionMessageType, +}); -export type TriggerActionMessageEvent = tg.GuardedType; +export type TriggerActionMessageEvent = z.infer; -export const isMessageReferenceEvent = new tg.IsInterface() - .withProperties({ - uuid: tg.isString, - }) - .get(); +export const isMessageReferenceEvent = z.object({ + uuid: z.string(), +}); -export type MessageReferenceEvent = tg.GuardedType; +export type MessageReferenceEvent = z.infer; diff --git a/front/src/Api/Events/ui/TriggerMessageEventHandler.ts b/front/src/Api/Events/ui/TriggerMessageEventHandler.ts index f7da0ad2..bd517031 100644 --- a/front/src/Api/Events/ui/TriggerMessageEventHandler.ts +++ b/front/src/Api/Events/ui/TriggerMessageEventHandler.ts @@ -5,20 +5,16 @@ import { triggerActionMessage, } from "./TriggerActionMessageEvent"; -import * as tg from "generic-type-guard"; +import { z } from "zod"; -const isTriggerMessageEventObject = new tg.IsInterface() - .withProperties({ - type: tg.isSingletonString(triggerActionMessage), - data: isTriggerActionMessageEvent, - }) - .get(); +const isTriggerMessageEventObject = z.object({ + type: z.enum([triggerActionMessage]), + data: isTriggerActionMessageEvent, +}); -const isTriggerMessageRemoveEventObject = new tg.IsInterface() - .withProperties({ - type: tg.isSingletonString(removeActionMessage), - data: isMessageReferenceEvent, - }) - .get(); +const isTriggerMessageRemoveEventObject = z.object({ + type: z.enum([removeActionMessage]), + data: isMessageReferenceEvent, +}); -export const isTriggerMessageHandlerEvent = tg.isUnion(isTriggerMessageEventObject, isTriggerMessageRemoveEventObject); +export const isTriggerMessageHandlerEvent = z.union([isTriggerMessageEventObject, isTriggerMessageRemoveEventObject]); diff --git a/front/src/Api/IframeListener.ts b/front/src/Api/IframeListener.ts index e3609b9f..31a89035 100644 --- a/front/src/Api/IframeListener.ts +++ b/front/src/Api/IframeListener.ts @@ -1,13 +1,11 @@ import { Subject } from "rxjs"; -import { isChatEvent } from "./Events/ChatEvent"; import { HtmlUtils } from "../WebRtc/HtmlUtils"; import type { EnterLeaveEvent } from "./Events/EnterLeaveEvent"; -import { isOpenPopupEvent, OpenPopupEvent } from "./Events/OpenPopupEvent"; -import { isOpenTabEvent, OpenTabEvent } from "./Events/OpenTabEvent"; +import { OpenPopupEvent } from "./Events/OpenPopupEvent"; +import { OpenTabEvent } from "./Events/OpenTabEvent"; import type { ButtonClickedEvent } from "./Events/ButtonClickedEvent"; -import { ClosePopupEvent, isClosePopupEvent } from "./Events/ClosePopupEvent"; +import { ClosePopupEvent } from "./Events/ClosePopupEvent"; import { scriptUtils } from "./ScriptUtils"; -import { isGoToPageEvent } from "./Events/GoToPageEvent"; import { IframeErrorAnswerEvent, IframeQueryMap, @@ -15,35 +13,28 @@ import { IframeResponseEventMap, isIframeEventWrapper, isIframeQueryWrapper, + isLookingLikeIframeEventWrapper, } from "./Events/IframeEvent"; import type { UserInputChatEvent } from "./Events/UserInputChatEvent"; -import { isPlaySoundEvent, PlaySoundEvent } from "./Events/PlaySoundEvent"; -import { isStopSoundEvent, StopSoundEvent } from "./Events/StopSoundEvent"; -import { isLoadSoundEvent, LoadSoundEvent } from "./Events/LoadSoundEvent"; -import { isSetPropertyEvent, SetPropertyEvent } from "./Events/setPropertyEvent"; -import { isLayerEvent, LayerEvent } from "./Events/LayerEvent"; +import { PlaySoundEvent } from "./Events/PlaySoundEvent"; +import { StopSoundEvent } from "./Events/StopSoundEvent"; +import { LoadSoundEvent } from "./Events/LoadSoundEvent"; +import { SetPropertyEvent } from "./Events/setPropertyEvent"; +import { LayerEvent } from "./Events/LayerEvent"; import type { HasPlayerMovedEvent } from "./Events/HasPlayerMovedEvent"; -import { isLoadPageEvent } from "./Events/LoadPageEvent"; -import { isMenuRegisterEvent, isUnregisterMenuEvent } from "./Events/ui/MenuRegisterEvent"; -import { SetTilesEvent, isSetTilesEvent } from "./Events/SetTilesEvent"; +import { SetTilesEvent } from "./Events/SetTilesEvent"; import type { SetVariableEvent } from "./Events/SetVariableEvent"; -import { ModifyEmbeddedWebsiteEvent, isEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent"; +import { ModifyEmbeddedWebsiteEvent } from "./Events/EmbeddedWebsiteEvent"; import { handleMenuRegistrationEvent, handleMenuUnregisterEvent } from "../Stores/MenuStore"; import type { ChangeLayerEvent } from "./Events/ChangeLayerEvent"; import type { WasCameraUpdatedEvent } from "./Events/WasCameraUpdatedEvent"; -import type { ChangeZoneEvent } from "./Events/ChangeZoneEvent"; -import { CameraSetEvent, isCameraSetEvent } from "./Events/CameraSetEvent"; -import { CameraFollowPlayerEvent, isCameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent"; +import type { ChangeAreaEvent } from "./Events/ChangeAreaEvent"; +import { CameraSetEvent } from "./Events/CameraSetEvent"; +import { CameraFollowPlayerEvent } from "./Events/CameraFollowPlayerEvent"; import type { RemotePlayerClickedEvent } from "./Events/RemotePlayerClickedEvent"; -import { - AddActionsMenuKeyToRemotePlayerEvent, - isAddActionsMenuKeyToRemotePlayerEvent, -} from "./Events/AddActionsMenuKeyToRemotePlayerEvent"; +import { AddActionsMenuKeyToRemotePlayerEvent } from "./Events/AddActionsMenuKeyToRemotePlayerEvent"; import type { ActionsMenuActionClickedEvent } from "./Events/ActionsMenuActionClickedEvent"; -import { - isRemoveActionsMenuKeyFromRemotePlayerEvent, - RemoveActionsMenuKeyFromRemotePlayerEvent, -} from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent"; +import { RemoveActionsMenuKeyFromRemotePlayerEvent } from "./Events/RemoveActionsMenuKeyFromRemotePlayerEvent"; type AnswererCallback = ( query: IframeQueryMap[T]["query"], @@ -150,8 +141,10 @@ class IframeListener { const payload = message.data; + const lookingLikeEvent = isLookingLikeIframeEventWrapper.safeParse(payload); + if (foundSrc === undefined || iframe === undefined) { - if (isIframeEventWrapper(payload)) { + if (lookingLikeEvent.success) { console.warn( "It seems an iFrame is trying to communicate with WorkAdventure but was not explicitly granted the permission to do so. " + "If you are looking to use the WorkAdventure Scripting API inside an iFrame, you should allow the " + @@ -221,63 +214,70 @@ class IframeListener { } catch (reason) { errorHandler(reason); } - } else if (isIframeEventWrapper(payload)) { - if (payload.type === "showLayer" && isLayerEvent(payload.data)) { - this._showLayerStream.next(payload.data); - } else if (payload.type === "hideLayer" && isLayerEvent(payload.data)) { - this._hideLayerStream.next(payload.data); - } else if (payload.type === "setProperty" && isSetPropertyEvent(payload.data)) { - this._setPropertyStream.next(payload.data); - } else if (payload.type === "cameraSet" && isCameraSetEvent(payload.data)) { - this._cameraSetStream.next(payload.data); - } else if (payload.type === "cameraFollowPlayer" && isCameraFollowPlayerEvent(payload.data)) { - this._cameraFollowPlayerStream.next(payload.data); - } else if (payload.type === "chat" && isChatEvent(payload.data)) { - scriptUtils.sendAnonymousChat(payload.data); - } else if (payload.type === "openPopup" && isOpenPopupEvent(payload.data)) { - this._openPopupStream.next(payload.data); - } else if (payload.type === "closePopup" && isClosePopupEvent(payload.data)) { - this._closePopupStream.next(payload.data); - } else if (payload.type === "openTab" && isOpenTabEvent(payload.data)) { - scriptUtils.openTab(payload.data.url); - } else if (payload.type === "goToPage" && isGoToPageEvent(payload.data)) { - scriptUtils.goToPage(payload.data.url); - } else if (payload.type === "loadPage" && isLoadPageEvent(payload.data)) { - this._loadPageStream.next(payload.data.url); - } else if (payload.type === "playSound" && isPlaySoundEvent(payload.data)) { - this._playSoundStream.next(payload.data); - } else if (payload.type === "stopSound" && isStopSoundEvent(payload.data)) { - this._stopSoundStream.next(payload.data); - } else if (payload.type === "loadSound" && isLoadSoundEvent(payload.data)) { - this._loadSoundStream.next(payload.data); - } else if (payload.type === "disablePlayerControls") { + } else if (lookingLikeEvent.success) { + const iframeEventGuarded = isIframeEventWrapper.safeParse(lookingLikeEvent.data); + + if (!iframeEventGuarded.success) { + console.error( + `Invalid event "${lookingLikeEvent.data.type}" received from Iframe: `, + lookingLikeEvent.data, + iframeEventGuarded.error.issues + ); + return; + } + + const iframeEvent = iframeEventGuarded.data; + + if (iframeEvent.type === "showLayer") { + this._showLayerStream.next(iframeEvent.data); + } else if (iframeEvent.type === "hideLayer") { + this._hideLayerStream.next(iframeEvent.data); + } else if (iframeEvent.type === "setProperty") { + this._setPropertyStream.next(iframeEvent.data); + } else if (iframeEvent.type === "cameraSet") { + this._cameraSetStream.next(iframeEvent.data); + } else if (iframeEvent.type === "cameraFollowPlayer") { + this._cameraFollowPlayerStream.next(iframeEvent.data); + } else if (iframeEvent.type === "chat") { + scriptUtils.sendAnonymousChat(iframeEvent.data, iframe.contentWindow ?? undefined); + } else if (iframeEvent.type === "openPopup") { + this._openPopupStream.next(iframeEvent.data); + } else if (iframeEvent.type === "closePopup") { + this._closePopupStream.next(iframeEvent.data); + } else if (iframeEvent.type === "openTab") { + scriptUtils.openTab(iframeEvent.data.url); + } else if (iframeEvent.type === "goToPage") { + scriptUtils.goToPage(iframeEvent.data.url); + } else if (iframeEvent.type === "loadPage") { + this._loadPageStream.next(iframeEvent.data.url); + } else if (iframeEvent.type === "playSound") { + this._playSoundStream.next(iframeEvent.data); + } else if (iframeEvent.type === "stopSound") { + this._stopSoundStream.next(iframeEvent.data); + } else if (iframeEvent.type === "loadSound") { + this._loadSoundStream.next(iframeEvent.data); + } else if (iframeEvent.type === "disablePlayerControls") { this._disablePlayerControlStream.next(); - } else if (payload.type === "restorePlayerControls") { + } else if (iframeEvent.type === "restorePlayerControls") { this._enablePlayerControlStream.next(); - } else if (payload.type === "displayBubble") { + } else if (iframeEvent.type === "displayBubble") { this._displayBubbleStream.next(); - } else if (payload.type === "removeBubble") { + } else if (iframeEvent.type === "removeBubble") { this._removeBubbleStream.next(); - } else if (payload.type == "onPlayerMove") { + } else if (iframeEvent.type == "onPlayerMove") { this.sendPlayerMove = true; - } else if ( - payload.type == "addActionsMenuKeyToRemotePlayer" && - isAddActionsMenuKeyToRemotePlayerEvent(payload.data) - ) { - this._addActionsMenuKeyToRemotePlayerStream.next(payload.data); - } else if ( - payload.type == "removeActionsMenuKeyFromRemotePlayer" && - isRemoveActionsMenuKeyFromRemotePlayerEvent(payload.data) - ) { - this._removeActionsMenuKeyFromRemotePlayerEvent.next(payload.data); - } else if (payload.type == "onCameraUpdate") { + } else if (iframeEvent.type == "addActionsMenuKeyToRemotePlayer") { + this._addActionsMenuKeyToRemotePlayerStream.next(iframeEvent.data); + } else if (iframeEvent.type == "removeActionsMenuKeyFromRemotePlayer") { + this._removeActionsMenuKeyFromRemotePlayerEvent.next(iframeEvent.data); + } else if (iframeEvent.type == "onCameraUpdate") { this._trackCameraUpdateStream.next(); - } else if (payload.type == "setTiles" && isSetTilesEvent(payload.data)) { - this._setTilesStream.next(payload.data); - } else if (payload.type == "modifyEmbeddedWebsite" && isEmbeddedWebsiteEvent(payload.data)) { - this._modifyEmbeddedWebsiteStream.next(payload.data); - } else if (payload.type == "registerMenu" && isMenuRegisterEvent(payload.data)) { - const dataName = payload.data.name; + } else if (iframeEvent.type == "setTiles") { + this._setTilesStream.next(iframeEvent.data); + } else if (iframeEvent.type == "modifyEmbeddedWebsite") { + this._modifyEmbeddedWebsiteStream.next(iframeEvent.data); + } else if (iframeEvent.type == "registerMenu") { + const dataName = iframeEvent.data.name; this.iframeCloseCallbacks.get(iframe)?.push(() => { handleMenuUnregisterEvent(dataName); }); @@ -285,13 +285,16 @@ class IframeListener { foundSrc = this.getBaseUrl(foundSrc, message.source); handleMenuRegistrationEvent( - payload.data.name, - payload.data.iframe, + iframeEvent.data.name, + iframeEvent.data.iframe, foundSrc, - payload.data.options + iframeEvent.data.options ); - } else if (payload.type == "unregisterMenu" && isUnregisterMenuEvent(payload.data)) { - handleMenuUnregisterEvent(payload.data.name); + } else if (iframeEvent.type == "unregisterMenu") { + handleMenuUnregisterEvent(iframeEvent.data.name); + } else { + // Keep the line below. It will throw an error if we forget to handle one of the possible values. + const _exhaustiveCheck: never = iframeEvent; } } }, @@ -315,7 +318,7 @@ class IframeListener { } registerScript(scriptUrl: string, enableModuleMode: boolean = true): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { console.info("Loading map related script at ", scriptUrl); const iframe = document.createElement("iframe"); @@ -396,13 +399,20 @@ class IframeListener { this.scripts.delete(scriptUrl); } - sendUserInputChat(message: string) { - this.postMessage({ - type: "userInputChat", - data: { - message: message, - } as UserInputChatEvent, - }); + /** + * @param message The message to dispatch + * @param exceptOrigin Don't dispatch the message to exceptOrigin (to avoid infinite loops) + */ + sendUserInputChat(message: string, exceptOrigin?: Window) { + this.postMessage( + { + type: "userInputChat", + data: { + message: message, + } as UserInputChatEvent, + }, + exceptOrigin + ); } sendEnterEvent(name: string) { @@ -441,21 +451,21 @@ class IframeListener { }); } - sendEnterZoneEvent(zoneName: string) { + sendEnterAreaEvent(areaName: string) { this.postMessage({ - type: "enterZoneEvent", + type: "enterAreaEvent", data: { - name: zoneName, - } as ChangeZoneEvent, + name: areaName, + } as ChangeAreaEvent, }); } - sendLeaveZoneEvent(zoneName: string) { + sendLeaveAreaEvent(areaName: string) { this.postMessage({ - type: "leaveZoneEvent", + type: "leaveAreaEvent", data: { - name: zoneName, - } as ChangeZoneEvent, + name: areaName, + } as ChangeAreaEvent, }); } @@ -518,8 +528,11 @@ class IframeListener { /** * Sends the message... to all allowed iframes. */ - public postMessage(message: IframeResponseEvent) { + public postMessage(message: IframeResponseEvent, exceptOrigin?: Window) { for (const iframe of this.iframes) { + if (exceptOrigin === iframe.contentWindow) { + continue; + } iframe.contentWindow?.postMessage(message, "*"); } } diff --git a/front/src/Api/ScriptUtils.ts b/front/src/Api/ScriptUtils.ts index f0a0625a..d6d70e81 100644 --- a/front/src/Api/ScriptUtils.ts +++ b/front/src/Api/ScriptUtils.ts @@ -11,9 +11,9 @@ class ScriptUtils { window.location.href = url; } - public sendAnonymousChat(chatEvent: ChatEvent) { + public sendAnonymousChat(chatEvent: ChatEvent, origin?: Window) { const userId = playersStore.addFacticePlayer(chatEvent.author); - chatMessagesStore.addExternalMessage(userId, chatEvent.message); + chatMessagesStore.addExternalMessage(userId, chatEvent.message, origin); } } diff --git a/front/src/Api/desktop/index.ts b/front/src/Api/desktop/index.ts index 0b1ea9f9..239ec8cf 100644 --- a/front/src/Api/desktop/index.ts +++ b/front/src/Api/desktop/index.ts @@ -1,10 +1,10 @@ -import { isSilentStore, requestedCameraState, requestedMicrophoneState } from "../../Stores/MediaStore"; +import { requestedCameraState, requestedMicrophoneState, silentStore } from "../../Stores/MediaStore"; import { get } from "svelte/store"; import { WorkAdventureDesktopApi } from "@wa-preload-app"; declare global { interface Window { - WAD: WorkAdventureDesktopApi; + WAD?: WorkAdventureDesktopApi; } } @@ -36,8 +36,8 @@ class DesktopApi { } }); - isSilentStore.subscribe((value) => { - this.isSilent = value; + silentStore.subscribe((silent) => { + this.isSilent = silent; }); } } diff --git a/front/src/Api/iframe/IframeApiContribution.ts b/front/src/Api/iframe/IframeApiContribution.ts index 96548d5e..4e0ce71a 100644 --- a/front/src/Api/iframe/IframeApiContribution.ts +++ b/front/src/Api/iframe/IframeApiContribution.ts @@ -1,14 +1,8 @@ -import type * as tg from "generic-type-guard"; -import type { - IframeEvent, - IframeEventMap, - IframeQuery, - IframeQueryMap, - IframeResponseEventMap, -} from "../Events/IframeEvent"; +import { z } from "zod"; +import type { IframeEvent, IframeQuery, IframeQueryMap, IframeResponseEventMap } from "../Events/IframeEvent"; import type { IframeQueryWrapper } from "../Events/IframeEvent"; -export function sendToWorkadventure(content: IframeEvent) { +export function sendToWorkadventure(content: IframeEvent) { window.parent.postMessage(content, "*"); } @@ -48,12 +42,10 @@ export function queryWorkadventure( }); } -type GuardedType> = Guard extends tg.TypeGuard ? T : never; - export interface IframeCallback< Key extends keyof IframeResponseEventMap, T = IframeResponseEventMap[Key], - Guard = tg.TypeGuard + Guard = z.ZodType > { typeChecker: Guard; callback: (payloadData: T) => void; diff --git a/front/src/Api/iframe/Room/EmbeddedWebsite.ts b/front/src/Api/iframe/Room/EmbeddedWebsite.ts index d9c2d986..3f583194 100644 --- a/front/src/Api/iframe/Room/EmbeddedWebsite.ts +++ b/front/src/Api/iframe/Room/EmbeddedWebsite.ts @@ -1,9 +1,5 @@ import { sendToWorkadventure } from "../IframeApiContribution"; -import type { - CreateEmbeddedWebsiteEvent, - ModifyEmbeddedWebsiteEvent, - Rectangle, -} from "../../Events/EmbeddedWebsiteEvent"; +import type { CreateEmbeddedWebsiteEvent, Rectangle } from "../../Events/EmbeddedWebsiteEvent"; export class EmbeddedWebsite { public readonly name: string; diff --git a/front/src/Api/iframe/camera.ts b/front/src/Api/iframe/camera.ts index 38199e0d..c2d856f9 100644 --- a/front/src/Api/iframe/camera.ts +++ b/front/src/Api/iframe/camera.ts @@ -41,7 +41,7 @@ export class WorkAdventureCameraCommands extends IframeApiContribution { sendToWorkadventure({ type: "onCameraUpdate", - data: null, + data: undefined, }); return moveStream; } diff --git a/front/src/Api/iframe/controls.ts b/front/src/Api/iframe/controls.ts index a5f4c458..9fb53640 100644 --- a/front/src/Api/iframe/controls.ts +++ b/front/src/Api/iframe/controls.ts @@ -4,11 +4,11 @@ export class WorkadventureControlsCommands extends IframeApiContribution { diff --git a/front/src/Api/iframe/state.ts b/front/src/Api/iframe/state.ts index 278b208e..82aef735 100644 --- a/front/src/Api/iframe/state.ts +++ b/front/src/Api/iframe/state.ts @@ -1,13 +1,9 @@ import { Observable, Subject } from "rxjs"; -import { EnterLeaveEvent, isEnterLeaveEvent } from "../Events/EnterLeaveEvent"; - -import { IframeApiContribution, queryWorkadventure, sendToWorkadventure } from "./IframeApiContribution"; +import { IframeApiContribution, queryWorkadventure } from "./IframeApiContribution"; import { apiCallback } from "./registeredCallbacks"; import { isSetVariableEvent, SetVariableEvent } from "../Events/SetVariableEvent"; -import type { ITiledMap } from "../../Phaser/Map/ITiledMap"; - export class WorkadventureStateCommands extends IframeApiContribution { private setVariableResolvers = new Subject(); private variables = new Map(); @@ -17,7 +13,7 @@ export class WorkadventureStateCommands extends IframeApiContribution { - const oldValue = this.variables.get(event.key); + // const oldValue = this.variables.get(event.key); // If we are setting the same value, no need to do anything. // No need to do this check since it is already performed in SharedVariablesManager /*if (JSON.stringify(oldValue) === JSON.stringify(event.value)) { diff --git a/front/src/Api/iframe/ui.ts b/front/src/Api/iframe/ui.ts index 9b109654..15f0756c 100644 --- a/front/src/Api/iframe/ui.ts +++ b/front/src/Api/iframe/ui.ts @@ -34,14 +34,6 @@ interface MenuDescriptor { export type MenuOptions = RequireOnlyOne; -interface ZonedPopupOptions { - zone: string; - objectLayerName?: string; - popupText: string; - delay?: number; - popupOptions: Array; -} - export interface ActionMessageOptions { message: string; type?: "message" | "warning"; @@ -277,11 +269,11 @@ export class WorkAdventureUiCommands extends IframeApiContribution import type { Game } from "../Phaser/Game/Game"; import { chatVisibilityStore } from "../Stores/ChatStore"; - import { customCharacterSceneVisibleStore } from "../Stores/CustomCharacterStore"; import { errorStore } from "../Stores/ErrorStore"; + import { errorScreenStore } from "../Stores/ErrorScreenStore"; import { loginSceneVisibleStore } from "../Stores/LoginSceneStore"; import { enableCameraSceneVisibilityStore } from "../Stores/MediaStore"; import { selectCharacterSceneVisibleStore } from "../Stores/SelectCharacterStore"; import { selectCompanionSceneVisibleStore } from "../Stores/SelectCompanionStore"; import Chat from "./Chat/Chat.svelte"; - import CustomCharacterScene from "./CustomCharacterScene/CustomCharacterScene.svelte"; import EnableCameraScene from "./EnableCamera/EnableCameraScene.svelte"; import LoginScene from "./Login/LoginScene.svelte"; import MainLayout from "./MainLayout.svelte"; import SelectCharacterScene from "./selectCharacter/SelectCharacterScene.svelte"; import SelectCompanionScene from "./SelectCompanion/SelectCompanionScene.svelte"; import ErrorDialog from "./UI/ErrorDialog.svelte"; + import ErrorScreen from "./UI/ErrorScreen.svelte"; export let game: Game; -{#if $errorStore.length > 0} +{#if $errorScreenStore !== undefined} +
+ +
+{:else if $errorStore.length > 0}
@@ -31,10 +35,6 @@
-{:else if $customCharacterSceneVisibleStore} -
- -
{:else if $selectCompanionSceneVisibleStore}
diff --git a/front/src/Components/CameraControls.svelte b/front/src/Components/CameraControls.svelte index b9cb7801..fad3c3c1 100644 --- a/front/src/Components/CameraControls.svelte +++ b/front/src/Components/CameraControls.svelte @@ -1,6 +1,6 @@
@@ -94,7 +87,7 @@
@@ -103,7 +96,7 @@
@@ -113,26 +106,26 @@
- {#if $requestedScreenSharingState && !isSilent} + {#if $requestedScreenSharingState && !$silentStore} Start screen sharing {:else} Stop screen sharing {/if}
-
- {#if $requestedCameraState && !isSilent} +
+ {#if $requestedCameraState && !$silentStore} Turn on webcam {:else} Turn off webcam {/if}
-
- {#if $requestedMicrophoneState && !isSilent} +
+ {#if $requestedMicrophoneState && !$silentStore} Turn on microphone {:else} Turn off microphone diff --git a/front/src/Components/CustomCharacterScene/CustomCharacterScene.svelte b/front/src/Components/CustomCharacterScene/CustomCharacterScene.svelte deleted file mode 100644 index 52bccdac..00000000 --- a/front/src/Components/CustomCharacterScene/CustomCharacterScene.svelte +++ /dev/null @@ -1,142 +0,0 @@ - - -
-
-

{$LL.woka.customWoka.title()}

-
-
- - -
-
- {#if $activeRowStore === 0} - - {/if} - {#if $activeRowStore !== 0} - - {/if} - {#if $activeRowStore === 5} - - {/if} - {#if $activeRowStore !== 5} - - {/if} -
-
- - diff --git a/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte index d31aac89..95f3ef7c 100644 --- a/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte +++ b/front/src/Components/EmbedScreens/EmbedScreensContainer.svelte @@ -19,6 +19,5 @@ padding-top: 2%; height: 100%; position: relative; - z-index: 200; } diff --git a/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte index dbf7ee71..b483f6c4 100644 --- a/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte +++ b/front/src/Components/EmbedScreens/Layouts/PresentationLayout.svelte @@ -67,10 +67,11 @@ {/key} {:else if $highlightedEmbedScreen.type === "cowebsite"} {#key $highlightedEmbedScreen.embed.getId()} -
+
+
+ import("./Video/DesktopCapturerSourcePicker.svelte")} + /> + {#if $menuVisiblilityStore} {/if} diff --git a/front/src/Components/Menu/GuestSubMenu.svelte b/front/src/Components/Menu/GuestSubMenu.svelte index fbbc48a4..3afdfb51 100644 --- a/front/src/Components/Menu/GuestSubMenu.svelte +++ b/front/src/Components/Menu/GuestSubMenu.svelte @@ -47,7 +47,13 @@ {#if !canShare} {:else} diff --git a/front/src/Components/Menu/Menu.svelte b/front/src/Components/Menu/Menu.svelte index 21e62520..78419867 100644 --- a/front/src/Components/Menu/Menu.svelte +++ b/front/src/Components/Menu/Menu.svelte @@ -3,7 +3,6 @@ import SettingsSubMenu from "./SettingsSubMenu.svelte"; import ProfileSubMenu from "./ProfileSubMenu.svelte"; import AboutRoomSubMenu from "./AboutRoomSubMenu.svelte"; - import GlobalMessageSubMenu from "./GlobalMessagesSubMenu.svelte"; import ContactSubMenu from "./ContactSubMenu.svelte"; import CustomSubMenu from "./CustomSubMenu.svelte"; import GuestSubMenu from "./GuestSubMenu.svelte"; @@ -25,16 +24,16 @@ let props: { url: string; allowApi: boolean }; let unsubscriberSubMenuStore: Unsubscriber; - onMount(() => { + onMount(async () => { unsubscriberSubMenuStore = subMenusStore.subscribe(() => { if (!$subMenusStore.includes(activeSubMenu)) { - switchMenu($subMenusStore[0]); + void switchMenu($subMenusStore[0]); } }); checkSubMenuToShow(); - switchMenu($subMenusStore[0]); + await switchMenu($subMenusStore[0]); }); onDestroy(() => { @@ -43,7 +42,7 @@ } }); - function switchMenu(menu: MenuItem) { + async function switchMenu(menu: MenuItem) { if (menu.type === "translated") { activeSubMenu = menu; switch (menu.key) { @@ -60,7 +59,7 @@ activeComponent = AboutRoomSubMenu; break; case SubMenusInterface.globalMessages: - activeComponent = GlobalMessageSubMenu; + activeComponent = (await import("./GlobalMessagesSubMenu.svelte")).default; break; case SubMenusInterface.contact: activeComponent = ContactSubMenu; @@ -89,16 +88,11 @@ } } - function translateMenuName(menu: MenuItem) { - if (menu.type === "scripting") { - return menu.label; - } - - // Bypass the proxy of typesafe for getting the menu name : https://github.com/ivanhofer/typesafe-i18n/issues/156 - const getMenuName = $LL.menu.sub[menu.key]; - - return getMenuName(); - } + $: subMenuTranslations = $subMenusStore.map((subMenu) => + subMenu.type === "scripting" ? subMenu.label : $LL.menu.sub[subMenu.key]() + ); + $: activeSubMenuTranslation = + activeSubMenu.type === "scripting" ? activeSubMenu.label : $LL.menu.sub[activeSubMenu.key](); @@ -107,20 +101,20 @@
diff --git a/front/src/Components/Menu/ProfileSubMenu.svelte b/front/src/Components/Menu/ProfileSubMenu.svelte index 09237e36..1c6a744e 100644 --- a/front/src/Components/Menu/ProfileSubMenu.svelte +++ b/front/src/Components/Menu/ProfileSubMenu.svelte @@ -1,7 +1,13 @@
- {#if isSilent} + {#if $silentStore}
{$LL.camera.my.silentZone()}
{:else if $localStreamStore.type === "success" && $localStreamStore.stream}