refactor: Add GitDataSource, FileDataSource, toast for errors (#18385)

* refactor: Add GitDataSource, FileDataSource, toast for errors

* Fix

* fix

* Fix: use frontend-shared for common optimizeDeps

* schema/type fixes

* add debug for circle job

* add debug for circle job

* Attempting to debug CI flake

* Fix types

* Attempt to fix

* Revert "Attempt to fix"

This reverts commit 12a8db455a.

* Just use more parallelization?

* See if this fixes it

* remove debug

* Force browser relaunch?

* use internal ENV var
This commit is contained in:
Tim Griesser
2021-10-07 20:47:02 -04:00
committed by GitHub
parent 98a9c06c40
commit bda7e5eec6
30 changed files with 340 additions and 267 deletions
+8 -1
View File
@@ -398,10 +398,16 @@ commands:
description: ct or e2e
type: enum
enum: ['ct', 'e2e']
debug:
description: debug option
type: string
default: ''
steps:
- restore_cached_workspace
- run:
command: |
DEBUG=<<parameters.debug>> \
CYPRESS_INTERNAL_FORCE_BROWSER_RELAUNCH='true' \
CYPRESS_KONFIG_ENV=production \
CYPRESS_RECORD_KEY=$TEST_LAUNCHPAD_RECORD_KEY \
yarn workspace @packages/<<parameters.package>> cypress:run:<<parameters.type>> --browser <<parameters.browser>> --record --parallel --group <<parameters.package>>-<<parameters.type>>
@@ -1184,12 +1190,13 @@ jobs:
run-launchpad-component-tests-chrome:
<<: *defaults
parallelism: 3
parallelism: 7
steps:
- run-new-ui-tests:
browser: chrome
package: launchpad
type: ct
# debug: cypress:*,engine:socket
run-launchpad-integration-tests-chrome:
<<: *defaults
+1
View File
@@ -101,6 +101,7 @@
"@types/detect-port": "^1.3.1",
"@types/enzyme-adapter-react-16": "1.0.5",
"@types/execa": "0.9.0",
"@types/fluent-ffmpeg": "^2.1.18",
"@types/fs-extra": "^8.0.1",
"@types/getenv": "^1.0.0",
"@types/glob": "7.1.1",
@@ -1,8 +1,3 @@
/**
* @type {import('@cypress/vite-dev-server')}
*/
const { startDevServer } = require('@cypress/vite-dev-server')
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
@@ -20,23 +15,4 @@ const { startDevServer } = require('@cypress/vite-dev-server')
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
if (config.testingType === 'component') {
on('dev-server:start', async (options) => {
return startDevServer({
options,
viteConfig: {
// TODO(tim): Figure out why this isn't being picked up
optimizeDeps: {
include: ['@headlessui/vue'],
},
},
})
})
}
return config // IMPORTANT to return a config
}
module.exports = require('@packages/frontend-shared/cypress/plugins/index')
+32 -11
View File
@@ -1,17 +1,21 @@
import type { LaunchArgs, OpenProjectLaunchOptions } from '@packages/types'
import type { AppApiShape, ProjectApiShape } from './actions'
import type { NexusGenAbstractTypeMembers } from '@packages/graphql/src/gen/nxs.gen'
import type { AuthApiShape } from './actions/AuthActions'
import debugLib from 'debug'
import fsExtra from 'fs-extra'
import type { AuthApiShape } from './actions/AuthActions'
import { CoreDataShape, makeCoreData } from './data/coreDataShape'
import { DataActions } from './DataActions'
import { AppDataSource } from './sources/AppDataSource'
import { ProjectDataSource } from './sources/ProjectDataSource'
import {
AppDataSource,
GitDataSource,
FileDataSource,
ProjectDataSource,
WizardDataSource,
BrowserDataSource,
UtilDataSource,
} from './sources/'
import { cached } from './util/cached'
import { WizardDataSource } from './sources'
import type { AppApiShape, ProjectApiShape } from './actions'
import { makeLoaders } from './data/loaders'
import { BrowserDataSource } from './sources/BrowserDataSource'
import type { NexusGenAbstractTypeMembers } from '@packages/graphql/src/gen/nxs.gen'
export interface DataContextConfig {
launchArgs: LaunchArgs
@@ -37,8 +41,6 @@ export class DataContext {
this._coreData = config.coreData ?? makeCoreData()
}
loaders = makeLoaders(this)
get launchArgs () {
return this.config.launchArgs
}
@@ -59,6 +61,21 @@ export class DataContext {
return this.coreData.app.browsers
}
@cached
get util () {
return new UtilDataSource(this)
}
@cached
get file () {
return new FileDataSource(this)
}
@cached
get git () {
return new GitDataSource(this)
}
@cached
get browser () {
return new BrowserDataSource(this)
@@ -138,6 +155,10 @@ export class DataContext {
}
dispose () {
this.loaders.dispose()
this.util.disposeLoaders()
}
get loader () {
return this.util.loader
}
}
@@ -0,0 +1,5 @@
import type { DataContext } from '..'
export class FileActions {
constructor (private ctx: DataContext) {}
}
@@ -55,8 +55,8 @@ export class ProjectActions {
return this
}
async findSpecs (projectRoot: string, specType: Maybe<SpecType>): Promise<FoundSpec[]> {
const config = await this.ctx.loaders.projectConfig(projectRoot)
async findSpecs (projectRoot: string, specType: Maybe<SpecType>) {
const config = await this.ctx.project.getConfig(projectRoot)
const specs = await this.api.findSpecs({
projectRoot,
fixturesFolder: config.fixturesFolder ?? false,
@@ -3,5 +3,6 @@
export * from './AppActions'
export * from './AuthActions'
export * from './FileActions'
export * from './ProjectActions'
export * from './WizardActions'
-2
View File
@@ -3,5 +3,3 @@
export * from './DataEmitter'
export * from './coreDataShape'
export * from './loaders'
export * from './util/'
-81
View File
@@ -1,81 +0,0 @@
import type { FullConfig } from '@packages/types'
import DataLoader from 'dataloader'
import fs from 'fs-extra'
import type { DataContext } from '..'
import { GitInfo, getGitInfo } from './util'
/**
* Centralized location to load files. Allows us to consolidate
* file watching & cache invalidation in a single location
*/
export class DataLoaders {
constructor (private ctx: DataContext) {}
private _allLoaders: DataLoader<any, any>[] = []
file (fileName: string) {
return this.fileLoader.load(fileName)
}
maybeFile (fileName: string) {
return this.file(fileName).catch(() => null)
}
jsonFile<Result = unknown> (fileName: string) {
return this.jsonFileLoader.load(fileName) as Promise<Result>
}
projectConfig (projectRoot: string) {
return this.configLoader.load(projectRoot)
}
gitInfo (path: string) {
return this.gitLoader.load(path)
}
private gitLoader = this.loader<string, GitInfo>((absolutePaths) => {
return getGitInfo(absolutePaths)
})
private configLoader = this.loader<string, FullConfig>((projectRoots) => {
return Promise.all(projectRoots.map((root) => this.ctx._apis.projectApi.getConfig(root)))
})
private fileLoader = this.loader<string, string>((files) => {
return Promise.all(files.map((f) => fs.readFile(f, 'utf8')))
})
private jsonFileLoader = this.loader<string, unknown>(async (jsonFiles) => {
const files = await this.fileLoader.loadMany(jsonFiles)
return files.map((file) => {
if (file instanceof Error) {
return file
}
try {
return JSON.parse(file)
} catch (e) {
return e
}
})
})
private loader<K, V, C = K> (batchLoadFn: DataLoader.BatchLoadFn<K, V>) {
const loader = new DataLoader<K, V, C>(batchLoadFn, { cache: false })
this._allLoaders.push(loader)
return loader
}
dispose () {
for (const loader of this._allLoaders) {
loader.clearAll()
}
}
}
export function makeLoaders (ctx: DataContext) {
return new DataLoaders(ctx)
}
@@ -1,105 +0,0 @@
import execa from 'execa'
import path from 'path'
import os from 'os'
import Debug from 'debug'
export interface GitInfo {
author: string | null
lastModifiedTimestamp: string | null
lastModifiedHumanReadable: string | null
}
const debug = Debug('cypress:data-context:git-info')
// matches <timestamp> <when> <author>
// $ git log -1 --pretty=format:%ci %ar %an <file>
// eg '2021-09-14 13:43:19 +1000 2 days ago Lachlan Miller
const GIT_LOG_REGEXP = /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-+].+?)\s(.+ago)\s(.*)/
const GIT_LOG_COMMAND = `git log -1 --pretty="format:%ci %ar %an"`
const getInfoWindows = async (absolutePaths: readonly string[]) => {
const paths = absolutePaths.map((x) => path.resolve(x)).join(',')
const cmd = `FOR %x in (${paths}) DO (${GIT_LOG_COMMAND} %x)`
const result = await execa(cmd, { shell: true })
const split = result.stdout
.split('\r\n') // windows uses CRLF for carriage returns
.filter((str) => !str.includes('git log')) // windows stdout contains [cmd,output]. So we remove the code containing the executed command, `git log`
// windows returns a leading carriage return, remove it
const [, ...stdout] = split
if (stdout.length !== absolutePaths.length) {
debug('stdout', stdout)
throw Error(`Expect result array to have same length as input. Input: ${absolutePaths.length} Output: ${stdout.length}`)
}
return stdout
}
const getInfoPosix = async (absolutePaths: readonly string[]) => {
debug('getting git info for %o:', absolutePaths)
const paths = absolutePaths.map((x) => path.resolve(x)).join(',')
// for file in {one,two} is valid in bash, but for file {one} is not
// no need to use a for loop for a single file
const cmd = absolutePaths.length === 1
? `${GIT_LOG_COMMAND} ${absolutePaths[0]}`
: `for file in {${paths}}; do echo $(${GIT_LOG_COMMAND} $file); done`
debug('executing command `%s`:', cmd)
const result = await execa(cmd, { shell: true })
const stdout = result.stdout.split('\n')
if (stdout.length !== absolutePaths.length) {
debug('error... stdout:', stdout)
throw Error(`Expect result array to have same length as input. Input: ${absolutePaths.length} Output: ${stdout.length}`)
}
debug('stdout for git info', stdout)
return stdout
}
export const getGitInfo = async (absolutePaths: readonly string[]): Promise<GitInfo[]> => {
if (absolutePaths.length === 0) {
return []
}
try {
const stdout = await (
os.platform() === 'win32'
? getInfoWindows(absolutePaths)
: getInfoPosix(absolutePaths)
)
const output: GitInfo[] = []
debug('stdout %s', stdout)
for (let i = 0; i < absolutePaths.length; i++) {
const file = absolutePaths[i]
const data = stdout[i]
const info = data?.match(GIT_LOG_REGEXP)
if (file && info && info[1] && info[2] && info[3]) {
output.push({
lastModifiedTimestamp: info[1],
lastModifiedHumanReadable: info[2],
author: info[3],
})
}
}
return output
} catch (e) {
debug('Error getting git info: %s', e.message)
// does not have git installed,
// file is not under source control
// ... etc ...
// just return an empty map
return []
}
}
@@ -1,4 +0,0 @@
/* eslint-disable padding-line-between-statements */
// created by autobarrel, do not modify directly
export * from './gitInfo'
@@ -0,0 +1,47 @@
import type { DataContext } from '..'
export class FileDataSource {
private watchedFilePaths = new Set<string>()
constructor (private ctx: DataContext) {}
readFile (absoluteFilePath: string) {
return this.fileLoader.load(absoluteFilePath).catch((e) => {
this.fileLoader.clear(absoluteFilePath)
throw e
})
}
readJsonFile<Result = unknown> (absoluteFilePath: string) {
return this.jsonFileLoader.load(absoluteFilePath).catch((e) => {
this.jsonFileLoader.clear(e)
throw e
}) as Promise<Result>
}
private trackFile () {
// this.watchedFilePaths.clear()
// this.fileLoader.clear()
// this.jsonFileLoader.clear()
}
private fileLoader = this.ctx.loader<string, string>((files) => {
return this.ctx.util.settleAll(files.map((f) => this.ctx.fs.readFile(f, 'utf8')))
})
private jsonFileLoader = this.ctx.loader<string, unknown>(async (jsonFiles) => {
const files = await this.fileLoader.loadMany(jsonFiles)
return files.map((file) => {
if (file instanceof Error) {
return file
}
try {
return JSON.parse(file)
} catch (e) {
return e
}
})
})
}
@@ -0,0 +1,116 @@
import execa from 'execa'
import path from 'path'
import os from 'os'
import type { DataContext } from '..'
// matches <timestamp> <when> <author>
// $ git log -1 --pretty=format:%ci %ar %an <file>
// eg '2021-09-14 13:43:19 +1000 2 days ago Lachlan Miller
const GIT_LOG_REGEXP = /(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-+].+?)\s(.+ago)\s(.*)/
const GIT_LOG_COMMAND = `git log -1 --pretty="format:%ci %ar %an"`
export interface GitInfo {
author: string | null
lastModifiedTimestamp: string | null
lastModifiedHumanReadable: string | null
}
export class GitDataSource {
constructor (private ctx: DataContext) {}
gitInfo (path: string): Promise<GitInfo> {
return this.gitInfoLoader.load(path)
}
private gitInfoLoader = this.ctx.loader<string, GitInfo>((paths) => {
return this.bulkGitInfo(paths)
})
private async bulkGitInfo (absolutePaths: readonly string[]) {
if (absolutePaths.length === 0) {
return []
}
try {
const stdout = await (
os.platform() === 'win32'
? this.getInfoWindows(absolutePaths)
: this.getInfoPosix(absolutePaths)
)
const output: GitInfo[] = []
this.ctx.debug('stdout %s', stdout)
for (let i = 0; i < absolutePaths.length; i++) {
const file = absolutePaths[i]
const data = stdout[i]
const info = data?.match(GIT_LOG_REGEXP)
if (file && info && info[1] && info[2] && info[3]) {
output.push({
lastModifiedTimestamp: info[1],
lastModifiedHumanReadable: info[2],
author: info[3],
})
}
}
return output
} catch (e) {
this.ctx.debug('Error getting git info: %s', (e as Error).message)
// does not have git installed,
// file is not under source control
// ... etc ...
// just return an empty map
return []
}
}
private async getInfoPosix (absolutePaths: readonly string[]) {
this.ctx.debug('getting git info for %o:', absolutePaths)
const paths = absolutePaths.map((x) => path.resolve(x)).join(',')
// for file in {one,two} is valid in bash, but for file {one} is not
// no need to use a for loop for a single file
const cmd = absolutePaths.length === 1
? `${GIT_LOG_COMMAND} ${absolutePaths[0]}`
: `for file in {${paths}}; do echo $(${GIT_LOG_COMMAND} $file); done`
this.ctx.debug('executing command `%s`:', cmd)
const result = await execa(cmd, { shell: true })
const stdout = result.stdout.split('\n')
if (stdout.length !== absolutePaths.length) {
this.ctx.debug('error... stdout:', stdout)
throw Error(`Expect result array to have same length as input. Input: ${absolutePaths.length} Output: ${stdout.length}`)
}
this.ctx.debug('stdout for git info', stdout)
return stdout
}
private async getInfoWindows (absolutePaths: readonly string[]) {
const paths = absolutePaths.map((x) => path.resolve(x)).join(',')
const cmd = `FOR %x in (${paths}) DO (${GIT_LOG_COMMAND} %x)`
const result = await execa(cmd, { shell: true })
const split = result.stdout
.split('\r\n') // windows uses CRLF for carriage returns
.filter((str) => !str.includes('git log')) // windows stdout contains [cmd,output]. So we remove the code containing the executed command, `git log`
// windows returns a leading carriage return, remove it
const [, ...stdout] = split
if (stdout.length !== absolutePaths.length) {
this.ctx.debug('stdout', stdout)
throw Error(`Expect result array to have same length as input. Input: ${absolutePaths.length} Output: ${stdout.length}`)
}
return stdout
}
}
@@ -1,3 +1,4 @@
import type { FullConfig } from '@packages/types'
import path from 'path'
import type { DataContext } from '..'
@@ -16,12 +17,16 @@ export class ProjectDataSource {
}
getConfig (projectRoot: string) {
return this.ctx.loaders.projectConfig(projectRoot)
return this.configLoader.load(projectRoot)
}
private configLoader = this.ctx.loader<string, FullConfig>((projectRoots) => {
return Promise.all(projectRoots.map((root) => this.ctx._apis.projectApi.getConfig(root)))
})
async isFirstTimeAccessing (projectRoot: string, testingType: 'e2e' | 'component') {
try {
const config = await this.ctx.loaders.jsonFile<{ e2e?: object, component?: object }>(path.join(projectRoot, 'cypress.json'))
const config = await this.ctx.file.readJsonFile<{ e2e?: object, component?: object }>(path.join(projectRoot, 'cypress.json'))
const type = testingType === 'e2e' ? 'e2e' : 'component'
const overrides = config[type] || {}
@@ -0,0 +1,38 @@
import DataLoader from 'dataloader'
import type { DataContext } from '..'
/**
* this.ctx.util....
*
* Used as a central location for grab-bag utilities used
* within the DataContext layer
*/
export class UtilDataSource {
constructor (private ctx: DataContext) {}
private _allLoaders: DataLoader<any, any>[] = []
async settleAll<T> (promises: Promise<T>[]) {
const vals = await Promise.allSettled(promises)
return vals.map((v) => v.status === 'fulfilled' ? v.value : this.ensureError(v.reason))
}
ensureError (val: any): Error {
return val instanceof Error ? val : new Error(val)
}
loader = <K, V, C = K>(batchLoadFn: DataLoader.BatchLoadFn<K, V>) => {
const loader = new DataLoader<K, V, C>(batchLoadFn, { cache: false })
this._allLoaders.push(loader)
return loader
}
disposeLoaders () {
for (const loader of this._allLoaders) {
loader.clearAll()
}
}
}
@@ -3,5 +3,8 @@
export * from './AppDataSource'
export * from './BrowserDataSource'
export * from './FileDataSource'
export * from './GitDataSource'
export * from './ProjectDataSource'
export * from './UtilDataSource'
export * from './WizardDataSource'
+1
View File
@@ -6,6 +6,7 @@
"script"
],
"compilerOptions": {
"lib": ["es2020"],
"importHelpers": true,
"strict": true,
"allowJs": false,
@@ -31,7 +31,14 @@ module.exports = (on, config) => {
viteConfig: {
// TODO(tim): Figure out why this isn't being picked up
optimizeDeps: {
include: ['@headlessui/vue', 'vue-prism-component', 'vue3-file-selector'],
include: [
'@headlessui/vue',
'vue-prism-component',
'vue3-file-selector',
'just-my-luck',
'combine-properties',
'faker',
],
},
},
})
+1
View File
@@ -51,6 +51,7 @@
"vue": "3.2.6",
"vue-eslint-parser": "7.11.0",
"vue-i18n": "^9.2.0-beta.7",
"vue-toast-notification": "2.0.1",
"vue-tsc": "^0.3.0",
"windicss": "3.1.8",
"windicss-analysis": "^0.3.4",
@@ -7,9 +7,21 @@ import {
fetchExchange,
} from '@urql/core'
import { devtoolsExchange } from '@urql/devtools'
import VueToast, { ToastPluginApi } from 'vue-toast-notification'
import 'vue-toast-notification/dist/theme-sugar.css'
export { VueToast }
import { cacheExchange as graphcacheExchange } from '@urql/exchange-graphcache'
import { GRAPHQL_URL } from '../utils/env'
declare global {
interface Window {
$app?: { $toast: ToastPluginApi }
}
}
export function makeCacheExchange () {
return graphcacheExchange({
keys: {
@@ -22,10 +34,19 @@ export function makeCacheExchange () {
export function makeUrqlClient (): Client {
const exchanges: Exchange[] = [
devtoolsExchange,
dedupExchange,
errorExchange({
onError (error) {
const message = `
GraphQL Field Path: [${error.graphQLErrors[0].path?.join(', ')}]:<br>
${error.message}<br>
`
window.$app?.$toast.error(message, {
message,
duration: 0,
})
// eslint-disable-next-line
console.error(error)
},
+5
View File
@@ -464,6 +464,11 @@ type Spec implements Node {
"""
absolute: String!
"""
Full name of spec file (e.g. MySpec.test.tsx) without the spec extension
"""
baseName: String!
"""The file extension (e.g. tsx, jsx)"""
fileExtension: String!
@@ -44,7 +44,7 @@ export const Spec = objectType({
type: GitInfo,
description: 'Git information about the spec file',
resolve: async (source, args, ctx) => {
return ctx.loaders.gitInfo(source.absolute)
return ctx.git.gitInfo(source.absolute)
},
})
},
+2
View File
@@ -9,10 +9,12 @@
"script"
],
"compilerOptions": {
"lib": ["ES2020"],
"importHelpers": true,
"strict": true,
"allowJs": false,
"noImplicitAny": true,
"noUnusedLocals": false,
"resolveJsonModule": true,
"experimentalDecorators": true,
"noUncheckedIndexedAccess": true,
@@ -1,8 +1,3 @@
/**
* @type {import('@cypress/vite-dev-server')}
*/
const { startDevServer } = require('@cypress/vite-dev-server')
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
@@ -20,23 +15,4 @@ const { startDevServer } = require('@cypress/vite-dev-server')
* @type {Cypress.PluginConfig}
*/
// eslint-disable-next-line no-unused-vars
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
if (config.testingType === 'component') {
on('dev-server:start', async (options) => {
return startDevServer({
options,
viteConfig: {
// TODO(tim): Figure out why this isn't being picked up
optimizeDeps: {
include: ['@headlessui/vue', 'vue-prism-component'],
},
},
})
})
}
return config // IMPORTANT to return a config
}
module.exports = require('@packages/frontend-shared/cypress/plugins/index')
+3 -2
View File
@@ -3,12 +3,13 @@ import './main.scss'
import 'virtual:windi.css'
import urql from '@urql/vue'
import App from './App.vue'
import { makeUrqlClient } from '@packages/frontend-shared/src/graphql/urqlClient'
import { makeUrqlClient, VueToast } from '@packages/frontend-shared/src/graphql/urqlClient'
import { createI18n } from '@cy/i18n'
const app = createApp(App)
app.use(VueToast)
app.use(urql, makeUrqlClient())
app.use(createI18n())
app.mount('#app')
window.$app = app.mount('#app')
+2 -1
View File
@@ -1464,7 +1464,8 @@ module.exports = {
socketId: options.socketId,
webSecurity: options.webSecurity,
projectRoot: options.projectRoot,
}, options.testingType === 'e2e' || firstSpec),
// TODO(tim): investigate the socket disconnect
}, process.env.CYPRESS_INTERNAL_FORCE_BROWSER_RELAUNCH || options.testingType === 'e2e' || firstSpec),
})
})
},
+15 -1
View File
@@ -15,6 +15,8 @@ import { openFile } from './util/file-opener'
import open from './util/open'
import type { DestroyableHttpServer } from './util/server_destroy'
import * as session from './session'
// eslint-disable-next-line no-duplicate-imports
import type { Socket } from '@packages/socket'
type StartListeningCallbacks = {
onSocketConnection: (socket: any) => void
@@ -184,9 +186,21 @@ export class SocketBase {
const getFixture = (path, opts) => fixture.get(config.fixturesFolder, path, opts)
this.io.on('connection', (socket: any) => {
this.io.on('connection', (socket: Socket & { inReporterRoom?: boolean, inRunnerRoom?: boolean }) => {
debug('socket connected')
socket.on('disconnecting', (reason) => {
debug(`socket-disconnecting ${reason}`)
})
socket.on('disconnect', (reason) => {
debug(`socket-disconnect ${reason}`)
})
socket.on('error', (err) => {
debug(`socket-error ${err.message}`)
})
// cache the headers so we can access
// them at any time
const headers = socket.request?.headers ?? {}
+3 -1
View File
@@ -8,8 +8,10 @@
"./../ts/index.d.ts"
],
"compilerOptions": {
"lib": ["ES2020"],
"types": ["mocha", "node"],
"importHelpers": true,
"resolveJsonModule": true
"resolveJsonModule": true,
"noUnusedLocals": false,
}
}
+3 -1
View File
@@ -1,8 +1,10 @@
import fs from 'fs'
import type http from 'http'
import server, { Server as SocketIOBaseServer, ServerOptions } from 'socket.io'
import server, { Server as SocketIOBaseServer, ServerOptions, Socket } from 'socket.io'
import { client } from './browser'
export type { Socket }
const HUNDRED_MEGABYTES = 1e8 // 100000000
const { version } = require('socket.io-client/package.json')
+12
View File
@@ -8488,6 +8488,13 @@
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
integrity sha1-wFTor02d11205jq8dviFFocU1LM=
"@types/fluent-ffmpeg@^2.1.18":
version "2.1.18"
resolved "https://registry.yarnpkg.com/@types/fluent-ffmpeg/-/fluent-ffmpeg-2.1.18.tgz#72246c2f8c0f0a590aefc1cdbe13736c73f22a81"
integrity sha512-LTteOx3RUmnPlKkvhvW9aGOHdJYyEtIiRBVbYVO/zPU65ZYQelbPJ+zBBT+IXup7doMvxVstX7NMoUTWKZOhww==
dependencies:
"@types/node" "*"
"@types/fs-extra@^8.0.1":
version "8.1.1"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.1.1.tgz#1e49f22d09aa46e19b51c0b013cb63d0d923a068"
@@ -41699,6 +41706,11 @@ vue-template-es2015-compiler@^1.9.0, vue-template-es2015-compiler@^1.9.1:
resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
vue-toast-notification@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/vue-toast-notification/-/vue-toast-notification-2.0.1.tgz#5fe607c493b5dc9b238bf49bc3bcf80366edd4e4"
integrity sha512-8GPJq1J6lsTPTCxSgPhnM8d0v+ivwT+u4R/xmtaDXeYNRkaRxqFOn3ewaVqmm+aCT8Y3/PQQS8dFqkMV7JOf/A==
vue-tsc@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.3.0.tgz#3b3872bf4f1d2e4409b57adbd826032e253db406"