Stubs initial API for coop with Pusher
This commit is contained in:
parent
ad0aff9fea
commit
36fc386269
12 changed files with 301 additions and 29 deletions
|
@ -1,5 +1,5 @@
|
||||||
import React, { useRef, memo, useEffect } from 'react'
|
import React, { useRef, memo, useEffect, useState } from 'react'
|
||||||
import { useSelector } from 'state'
|
import state, { useSelector } from 'state'
|
||||||
import styled from 'styles'
|
import styled from 'styles'
|
||||||
import { getShapeUtils } from 'state/shape-utils'
|
import { getShapeUtils } from 'state/shape-utils'
|
||||||
import { deepCompareArrays, getPage, getShape } from 'utils'
|
import { deepCompareArrays, getPage, getShape } from 'utils'
|
||||||
|
@ -16,34 +16,30 @@ interface ShapeProps {
|
||||||
function Shape({ id, isSelecting }: ShapeProps): JSX.Element {
|
function Shape({ id, isSelecting }: ShapeProps): JSX.Element {
|
||||||
const rGroup = useRef<SVGGElement>(null)
|
const rGroup = useRef<SVGGElement>(null)
|
||||||
|
|
||||||
const shapeUtils = useSelector((s) => {
|
|
||||||
const shape = getShape(s.data, id)
|
|
||||||
return getShapeUtils(shape)
|
|
||||||
})
|
|
||||||
|
|
||||||
const isHidden = useSelector((s) => {
|
const isHidden = useSelector((s) => {
|
||||||
const shape = getShape(s.data, id)
|
const shape = getShape(s.data, id)
|
||||||
return shape.isHidden
|
return shape?.isHidden || false
|
||||||
})
|
})
|
||||||
|
|
||||||
const children = useSelector((s) => {
|
const children = useSelector((s) => {
|
||||||
const shape = getShape(s.data, id)
|
const shape = getShape(s.data, id)
|
||||||
return shape.children
|
return shape?.children || []
|
||||||
}, deepCompareArrays)
|
}, deepCompareArrays)
|
||||||
|
|
||||||
const isParent = shapeUtils.isParent
|
|
||||||
|
|
||||||
const isForeignObject = shapeUtils.isForeignObject
|
|
||||||
|
|
||||||
const strokeWidth = useSelector((s) => {
|
const strokeWidth = useSelector((s) => {
|
||||||
const shape = getShape(s.data, id)
|
const shape = getShape(s.data, id)
|
||||||
const style = getShapeStyle(shape.style)
|
const style = getShapeStyle(shape.style)
|
||||||
return +style.strokeWidth
|
return +style.strokeWidth
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const shapeUtils = useSelector((s) => {
|
||||||
|
const shape = getShape(s.data, id)
|
||||||
|
return getShapeUtils(shape)
|
||||||
|
})
|
||||||
|
|
||||||
const transform = useSelector((s) => {
|
const transform = useSelector((s) => {
|
||||||
const shape = getShape(s.data, id)
|
const shape = getShape(s.data, id)
|
||||||
const center = shapeUtils.getCenter(shape)
|
const center = getShapeUtils(shape).getCenter(shape)
|
||||||
const rotation = shape.rotation * (180 / Math.PI)
|
const rotation = shape.rotation * (180 / Math.PI)
|
||||||
const parentPoint = getShape(s.data, shape.parentId)?.point || [0, 0]
|
const parentPoint = getShape(s.data, shape.parentId)?.point || [0, 0]
|
||||||
|
|
||||||
|
@ -54,7 +50,15 @@ function Shape({ id, isSelecting }: ShapeProps): JSX.Element {
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
|
||||||
const events = useShapeEvents(id, isParent, rGroup)
|
const events = useShapeEvents(id, shapeUtils?.isParent, rGroup)
|
||||||
|
|
||||||
|
const hasShape = useMissingShapeTest(id)
|
||||||
|
|
||||||
|
if (!hasShape) return null
|
||||||
|
|
||||||
|
const isParent = shapeUtils.isParent
|
||||||
|
|
||||||
|
const isForeignObject = shapeUtils.isForeignObject
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledGroup
|
<StyledGroup
|
||||||
|
@ -192,3 +196,17 @@ const StyledGroup = styled('g', {
|
||||||
})
|
})
|
||||||
|
|
||||||
export default memo(Shape)
|
export default memo(Shape)
|
||||||
|
|
||||||
|
function useMissingShapeTest(id: string) {
|
||||||
|
const [isShape, setIsShape] = useState(true)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return state.onUpdate((s) => {
|
||||||
|
if (isShape && !getShape(s.data, id)) {
|
||||||
|
setIsShape(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [isShape, id])
|
||||||
|
|
||||||
|
return isShape
|
||||||
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import PagePanel from './page-panel/page-panel'
|
||||||
import CodePanel from './code-panel/code-panel'
|
import CodePanel from './code-panel/code-panel'
|
||||||
import ControlsPanel from './controls-panel/controls-panel'
|
import ControlsPanel from './controls-panel/controls-panel'
|
||||||
|
|
||||||
export default function Editor(): JSX.Element {
|
export default function Editor({ roomId }: { roomId?: string }): JSX.Element {
|
||||||
useKeyboardEvents()
|
useKeyboardEvents()
|
||||||
useLoadOnMount()
|
useLoadOnMount(roomId)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
|
|
|
@ -2,6 +2,8 @@ import { useStateDesigner } from '@state-designer/react'
|
||||||
import state from 'state'
|
import state from 'state'
|
||||||
import styled from 'styles'
|
import styled from 'styles'
|
||||||
|
|
||||||
|
const size: any = { '@sm': 'small' }
|
||||||
|
|
||||||
export default function StatusBar(): JSX.Element {
|
export default function StatusBar(): JSX.Element {
|
||||||
const local = useStateDesigner(state)
|
const local = useStateDesigner(state)
|
||||||
|
|
||||||
|
@ -9,16 +11,13 @@ export default function StatusBar(): JSX.Element {
|
||||||
const states = s.split('.')
|
const states = s.split('.')
|
||||||
return states[states.length - 1]
|
return states[states.length - 1]
|
||||||
})
|
})
|
||||||
|
|
||||||
const log = local.log[0]
|
const log = local.log[0]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StatusBarContainer
|
<StatusBarContainer size={size}>
|
||||||
size={{
|
|
||||||
'@sm': 'small',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Section>
|
<Section>
|
||||||
{active.join(' | ')} | {log}
|
{active.join(' | ')} | {log} | {local.data.room?.status}
|
||||||
</Section>
|
</Section>
|
||||||
</StatusBarContainer>
|
</StatusBarContainer>
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,16 +2,18 @@
|
||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import state from 'state'
|
import state from 'state'
|
||||||
|
|
||||||
export default function useLoadOnMount() {
|
export default function useLoadOnMount(roomId: string) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fonts = (document as any).fonts
|
const fonts = (document as any).fonts
|
||||||
|
|
||||||
fonts
|
fonts.load('12px Verveine Regular', 'Fonts are loaded!').then(() => {
|
||||||
.load('12px Verveine Regular', 'Fonts are loaded!')
|
state.send('MOUNTED')
|
||||||
.then(() => state.send('MOUNTED'))
|
state.send('RT_LOADED_ROOM', { id: roomId })
|
||||||
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
state.send('UNMOUNTED')
|
state.send('UNMOUNTED')
|
||||||
|
state.send('RT_UNLOADED_ROOM', { id: roomId })
|
||||||
}
|
}
|
||||||
}, [])
|
}, [roomId])
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@
|
||||||
"next-auth": "^3.27.0",
|
"next-auth": "^3.27.0",
|
||||||
"next-pwa": "^5.2.21",
|
"next-pwa": "^5.2.21",
|
||||||
"perfect-freehand": "^0.4.91",
|
"perfect-freehand": "^0.4.91",
|
||||||
|
"pusher-js": "^7.0.3",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^3.1.3",
|
"react-error-boundary": "^3.1.3",
|
||||||
|
|
22
pages/room/[id].tsx
Normal file
22
pages/room/[id].tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import { GetServerSideProps } from 'next'
|
||||||
|
import { getSession } from 'next-auth/client'
|
||||||
|
|
||||||
|
const Editor = dynamic(() => import('components/editor'), { ssr: false })
|
||||||
|
|
||||||
|
export default function Room({ id }: { id: string }): JSX.Element {
|
||||||
|
return <Editor roomId={id} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||||
|
const session = await getSession(context)
|
||||||
|
|
||||||
|
const { id } = context.query
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
session,
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
23
pages/room/index.tsx
Normal file
23
pages/room/index.tsx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { GetServerSideProps } from 'next'
|
||||||
|
import { getSession } from 'next-auth/client'
|
||||||
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
|
export default function Home(): JSX.Element {
|
||||||
|
return <div>You should not see this one</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||||
|
const session = await getSession(context)
|
||||||
|
|
||||||
|
if (!session?.user) {
|
||||||
|
context.res.setHeader('Location', `/sponsorware`)
|
||||||
|
context.res.statusCode = 307
|
||||||
|
}
|
||||||
|
|
||||||
|
context.res.setHeader('Location', `/room/${uuid()}`)
|
||||||
|
context.res.statusCode = 307
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {},
|
||||||
|
}
|
||||||
|
}
|
110
state/pusher/client.ts
Normal file
110
state/pusher/client.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import Pusher from 'pusher-js'
|
||||||
|
import * as PusherTypes from 'pusher-js'
|
||||||
|
import state from 'state/state'
|
||||||
|
import { Shape } from 'types'
|
||||||
|
import { v4 as uuid } from 'uuid'
|
||||||
|
|
||||||
|
class RoomClient {
|
||||||
|
room: string
|
||||||
|
pusher: Pusher
|
||||||
|
channel: PusherTypes.Channel
|
||||||
|
lastCursorEventTime = 0
|
||||||
|
id = uuid()
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
// Create pusher instance and bind events
|
||||||
|
|
||||||
|
this.pusher = new Pusher('5dc87c88b8684bda655a', { cluster: 'eu' })
|
||||||
|
|
||||||
|
this.pusher.connection.bind('connecting', () =>
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'connecting' })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.pusher.connection.bind('connected', () =>
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'connected' })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.pusher.connection.bind('unavailable', () =>
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'unavailable' })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.pusher.connection.bind('failed', () =>
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'failed' })
|
||||||
|
)
|
||||||
|
|
||||||
|
this.pusher.connection.bind('disconnected', () =>
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'disconnected' })
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(room: string) {
|
||||||
|
this.room = room
|
||||||
|
|
||||||
|
// Subscribe to channel
|
||||||
|
|
||||||
|
this.channel = this.pusher.subscribe(this.room)
|
||||||
|
|
||||||
|
this.channel.bind('pusher:subscription_error', () => {
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'subscription-error' })
|
||||||
|
})
|
||||||
|
|
||||||
|
this.channel.bind('pusher:subscription_succeeded', () => {
|
||||||
|
state.send('RT_CHANGED_STATUS', { status: 'subscribed' })
|
||||||
|
})
|
||||||
|
|
||||||
|
this.channel.bind(
|
||||||
|
'created_shape',
|
||||||
|
(payload: { id: string; pageId: string; shape: Shape }) => {
|
||||||
|
state.send('RT_CREATED_SHAPE', payload)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.channel.bind(
|
||||||
|
'deleted_shape',
|
||||||
|
(payload: { id: string; pageId: string; shape: Shape }) => {
|
||||||
|
state.send('RT_DELETED_SHAPE', payload)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.channel.bind(
|
||||||
|
'edited_shape',
|
||||||
|
(payload: { id: string; pageId: string; change: Partial<Shape> }) => {
|
||||||
|
state.send('RT_EDITED_SHAPE', payload)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
this.channel.bind(
|
||||||
|
'moved_cursor',
|
||||||
|
(payload: { id: string; pageId: string; point: number[] }) => {
|
||||||
|
if (payload.id === this.id) return
|
||||||
|
state.send('RT_MOVED_CURSOR', payload)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnect() {
|
||||||
|
this.pusher.unsubscribe(this.room)
|
||||||
|
}
|
||||||
|
|
||||||
|
reconnect() {
|
||||||
|
this.pusher.subscribe(this.room)
|
||||||
|
}
|
||||||
|
|
||||||
|
moveCursor(pageId: string, point: number[]) {
|
||||||
|
if (!this.channel) return
|
||||||
|
|
||||||
|
const now = Date.now()
|
||||||
|
|
||||||
|
if (now - this.lastCursorEventTime > 42) {
|
||||||
|
this.lastCursorEventTime = now
|
||||||
|
|
||||||
|
this.channel?.trigger('RT_MOVED_CURSOR', {
|
||||||
|
id: this.id,
|
||||||
|
pageId,
|
||||||
|
point,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new RoomClient()
|
1
state/pusher/server.ts
Normal file
1
state/pusher/server.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export {}
|
|
@ -7,6 +7,7 @@ import history from './history'
|
||||||
import storage from './storage'
|
import storage from './storage'
|
||||||
import clipboard from './clipboard'
|
import clipboard from './clipboard'
|
||||||
import * as Sessions from './sessions'
|
import * as Sessions from './sessions'
|
||||||
|
import pusher from './pusher/client'
|
||||||
import commands from './commands'
|
import commands from './commands'
|
||||||
import {
|
import {
|
||||||
getChildren,
|
getChildren,
|
||||||
|
@ -28,6 +29,7 @@ import {
|
||||||
setToArray,
|
setToArray,
|
||||||
deepClone,
|
deepClone,
|
||||||
pointInBounds,
|
pointInBounds,
|
||||||
|
uniqueId,
|
||||||
} from 'utils'
|
} from 'utils'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -173,6 +175,19 @@ const state = createState({
|
||||||
else: ['zoomCameraToActual'],
|
else: ['zoomCameraToActual'],
|
||||||
},
|
},
|
||||||
on: {
|
on: {
|
||||||
|
// Network-Related
|
||||||
|
RT_LOADED_ROOM: [
|
||||||
|
'clearRoom',
|
||||||
|
{ if: 'hasRoom', do: ['clearDocument', 'connectToRoom'] },
|
||||||
|
],
|
||||||
|
RT_UNLOADED_ROOM: ['clearRoom', 'clearDocument'],
|
||||||
|
RT_DISCONNECTED_ROOM: ['clearRoom', 'clearDocument'],
|
||||||
|
RT_CREATED_SHAPE: 'addRtShape',
|
||||||
|
RT_CHANGED_STATUS: 'setRtStatus',
|
||||||
|
RT_DELETED_SHAPE: 'deleteRtShape',
|
||||||
|
RT_EDITED_SHAPE: 'editRtShape',
|
||||||
|
RT_MOVED_CURSOR: 'moveRtCursor',
|
||||||
|
// Client
|
||||||
RESIZED_WINDOW: 'resetPageState',
|
RESIZED_WINDOW: 'resetPageState',
|
||||||
RESET_PAGE: 'resetPage',
|
RESET_PAGE: 'resetPage',
|
||||||
TOGGLED_READ_ONLY: 'toggleReadOnly',
|
TOGGLED_READ_ONLY: 'toggleReadOnly',
|
||||||
|
@ -1032,6 +1047,9 @@ const state = createState({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
conditions: {
|
conditions: {
|
||||||
|
hasRoom(_, payload: { id?: string }) {
|
||||||
|
return payload.id !== undefined
|
||||||
|
},
|
||||||
shouldDeleteShape(data, payload, shape: Shape) {
|
shouldDeleteShape(data, payload, shape: Shape) {
|
||||||
return getShapeUtils(shape).shouldDelete(shape)
|
return getShapeUtils(shape).shouldDelete(shape)
|
||||||
},
|
},
|
||||||
|
@ -1124,6 +1142,68 @@ const state = createState({
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
// Networked Room
|
||||||
|
setRtStatus(data, payload: { id: string; status: string }) {
|
||||||
|
const { status } = payload
|
||||||
|
if (!data.room) {
|
||||||
|
data.room = { id: null, status: '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
data.room.status = status
|
||||||
|
},
|
||||||
|
addRtShape(data, payload: { pageId: string; shape: Shape }) {
|
||||||
|
const { pageId, shape } = payload
|
||||||
|
// What if the page is in storage?
|
||||||
|
data.document.pages[pageId].shapes[shape.id] = shape
|
||||||
|
},
|
||||||
|
deleteRtShape(data, payload: { pageId: string; shapeId: string }) {
|
||||||
|
const { pageId, shapeId } = payload
|
||||||
|
// What if the page is in storage?
|
||||||
|
delete data.document[pageId].shapes[shapeId]
|
||||||
|
},
|
||||||
|
editRtShape(data, payload: { pageId: string; shape: Shape }) {
|
||||||
|
const { pageId, shape } = payload
|
||||||
|
// What if the page is in storage?
|
||||||
|
Object.assign(data.document[pageId].shapes[shape.id], shape)
|
||||||
|
},
|
||||||
|
moveRtCursor() {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
clearRoom(data) {
|
||||||
|
data.room = undefined
|
||||||
|
},
|
||||||
|
clearDocument(data) {
|
||||||
|
data.document.id = uniqueId()
|
||||||
|
|
||||||
|
const newId = 'page1'
|
||||||
|
|
||||||
|
data.currentPageId = newId
|
||||||
|
|
||||||
|
data.document.pages = {
|
||||||
|
[newId]: {
|
||||||
|
id: newId,
|
||||||
|
name: 'Page 1',
|
||||||
|
type: 'page',
|
||||||
|
shapes: {},
|
||||||
|
childIndex: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
data.pageStates = {
|
||||||
|
[newId]: {
|
||||||
|
id: newId,
|
||||||
|
selectedIds: new Set(),
|
||||||
|
camera: {
|
||||||
|
point: [0, 0],
|
||||||
|
zoom: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
connectToRoom(data, payload: { id: string }) {
|
||||||
|
data.room = { id: payload.id, status: 'connecting' }
|
||||||
|
pusher.connect(payload.id)
|
||||||
|
},
|
||||||
resetPageState(data) {
|
resetPageState(data) {
|
||||||
const pageState = data.pageStates[data.currentPageId]
|
const pageState = data.pageStates[data.currentPageId]
|
||||||
data.pageStates[data.currentPageId] = { ...pageState }
|
data.pageStates[data.currentPageId] = { ...pageState }
|
||||||
|
@ -1893,7 +1973,7 @@ const state = createState({
|
||||||
.sort((a, b) => a.childIndex - b.childIndex)
|
.sort((a, b) => a.childIndex - b.childIndex)
|
||||||
},
|
},
|
||||||
selectedStyle(data) {
|
selectedStyle(data) {
|
||||||
const selectedIds = Array.from(getSelectedIds(data).values())
|
const selectedIds = setToArray(getSelectedIds(data))
|
||||||
const { currentStyle } = data
|
const { currentStyle } = data
|
||||||
|
|
||||||
if (selectedIds.length === 0) {
|
if (selectedIds.length === 0) {
|
||||||
|
|
4
types.ts
4
types.ts
|
@ -14,6 +14,10 @@ export interface Data {
|
||||||
isToolLocked: boolean
|
isToolLocked: boolean
|
||||||
isPenLocked: boolean
|
isPenLocked: boolean
|
||||||
}
|
}
|
||||||
|
room?: {
|
||||||
|
id: string
|
||||||
|
status: string
|
||||||
|
}
|
||||||
currentStyle: ShapeStyles
|
currentStyle: ShapeStyles
|
||||||
activeTool: ShapeType | 'select'
|
activeTool: ShapeType | 'select'
|
||||||
brush?: Bounds
|
brush?: Bounds
|
||||||
|
|
12
yarn.lock
12
yarn.lock
|
@ -6651,6 +6651,13 @@ punycode@^2.1.0, punycode@^2.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||||
|
|
||||||
|
pusher-js@^7.0.3:
|
||||||
|
version "7.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/pusher-js/-/pusher-js-7.0.3.tgz#f81c78cdf2ad32f546caa7532ec7f9081ef00b8d"
|
||||||
|
integrity sha512-HIfCvt00CAqgO4W0BrdpPsDcAwy51rB6DN0VMC+JeVRRbo8mn3XTeUeIFjmmlRLZLX8rPhUtLRo7vPag6b8GCw==
|
||||||
|
dependencies:
|
||||||
|
tweetnacl "^1.0.3"
|
||||||
|
|
||||||
querystring-es3@0.2.1, querystring-es3@^0.2.0:
|
querystring-es3@0.2.1, querystring-es3@^0.2.0:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||||
|
@ -7815,6 +7822,11 @@ tty-browserify@0.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
|
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811"
|
||||||
integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==
|
integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==
|
||||||
|
|
||||||
|
tweetnacl@^1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
|
||||||
|
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
|
||||||
|
|
||||||
type-check@^0.4.0, type-check@~0.4.0:
|
type-check@^0.4.0, type-check@~0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||||
|
|
Loading…
Reference in a new issue