feat pure rpc example

This commit is contained in:
Danya H 2024-10-28 10:28:56 +00:00
parent 67be91538b
commit e7e423adc6
38 changed files with 161 additions and 707 deletions

12
.gitignore vendored
View File

@ -1,8 +1,8 @@
# Editor # Editor
.vscode .vscode/
.idea .idea/
.git .git/
# Server Files # Server Files
server/bin server/bin
@ -18,4 +18,8 @@ server/ragemp-server.exe
# Development # Development
node_modules node_modules
pnpm-lock.yaml pnpm-lock.yaml
dist
# Build
build/
dist/
out/

View File

@ -1,10 +1,6 @@
{ {
"name": "rage-fw-example-cef", "name": "rage-fw-example-browser",
"version": "0.0.0", "description": "Browser side of Rage-FW example",
"type": "module",
"author": "Entity Seven Group",
"license": "CC BY-ND",
"description": "CEF side of rage-fw example",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
@ -12,9 +8,10 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"dependencies": { "dependencies": {
"@rage-fw/shared": "workspace:^",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"rpc": "workspace:^" "rage-fw-rpc": "file:../../../rage-framework/rpc"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.2.66", "@types/react": "^18.2.66",
@ -25,7 +22,11 @@
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6", "eslint-plugin-react-refresh": "^0.4.6",
"typescript": "^5.2.2", "typescript": "^5.6.3",
"vite": "^5.2.0" "vite": "^5.4.10"
} },
"type": "module",
"license": "CC BY-ND",
"author": "Entity Seven Group",
"version": "0.1.0"
} }

View File

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

24
apps/browser/src/App.tsx Normal file
View File

@ -0,0 +1,24 @@
import { useEffect, useState } from 'react'
import { events } from '@rage-fw/shared'
import { rpc } from '@/lib'
function App() {
const [data, setData] = useState<string>('')
useEffect(() => {
rpc.register(events.browser.customBrowserEvent, (args: string) => {
setData(prev => prev + ' | ' + args)
return 'response from cef'
})
rpc.callClient(events.client.cefReady, ['hello from cef'])
}, [])
return (
<div style={{ width: '100%', color: 'white', textAlign: 'center' }}>
<h1>Hello World!</h1>
<h2>{data}</h2>
</div>
)
}
export default App

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,5 @@
import { Rpc } from 'rage-fw-rpc'
export const rpc = new Rpc({
debugLogs: true,
})

View File

@ -22,7 +22,11 @@
"types": [ "types": [
"../../node_modules/@ragempcommunity/types-cef", "../../node_modules/@ragempcommunity/types-cef",
"../shared/declarations/rage-fw-shared-types/" "../shared/declarations/rage-fw-shared-types/"
] ],
"paths": {
"@": ["./src"],
"@/*": ["./src/*"],
}
}, },
"include": ["src"], "include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]

View File

@ -0,0 +1,17 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
outDir: '../../server/client_packages/cef',
emptyOutDir: true,
},
resolve: {
alias: {
'@': './src',
'@/*': './src/*',
},
},
})

View File

@ -1,20 +0,0 @@
import { useEffect, useState } from 'react'
import { rpc } from 'rpc'
function App() {
const [data, setData] = useState<unknown>('')
useEffect(() => {
rpc.callClient('cefReady')
rpc.register('customCefEvent', args => setData(args))
}, [])
return (
<div style={{ width: '100%', color: 'white', textAlign: 'center' }}>
<h1>Hello World!</h1>
<h2>{data!.toString()}</h2>
</div>
)
}
export default App

View File

@ -1,11 +0,0 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
outDir: '../../server/client_packages/cef',
emptyOutDir: true
}
})

View File

@ -1,13 +1,14 @@
{ {
"name": "rage-fw-example-client", "name": "rage-fw-example-client",
"version": "0.1.0", "description": "Client side of Rage-FW example",
"author": "Entity Seven Group",
"license": "CC BY-ND",
"description": "Client side of rage-fw example",
"scripts": { "scripts": {
"build": "esbuild src/index.ts --bundle --platform=node --outfile=../../server/client_packages/index.js --format=esm" "build": "esbuild src/index.ts --bundle --platform=node --outfile=../../server/client_packages/index.js --format=esm"
}, },
"dependencies": { "dependencies": {
"rpc": "workspace:^" "@rage-fw/shared": "workspace:^",
} "rage-fw-rpc": "file:../../../rage-framework/rpc"
},
"license": "CC BY-ND",
"author": "Entity Seven Group",
"version": "0.1.0"
} }

View File

@ -1,15 +1,22 @@
import { rpc, client } from 'rpc' import { events } from '@rage-fw/shared'
import { rpc } from './lib'
client.browser = mp.browsers.new('package://cef/index.html') rpc.browser = mp.browsers.new('package://cef/index.html')
rpc.register('cefReady', async () => { rpc.register(events.client.cefReady, async (args: string) => {
mp.console.logInfo('cef to client') mp.console.logInfo(args)
const res = (await rpc.callServer(events.server.customServerEvent, [
rpc.callServer('customServerEvent', ['client to server']) 'hello from client',
])) as string
mp.console.logInfo(res)
return 'response from client'
}) })
rpc.register('customClientEvent', async data => { rpc.register(events.client.cefReady, async (args: string) => {
mp.console.logInfo(JSON.stringify(data)) mp.console.logInfo(args)
const res = (await rpc.callBrowser(events.browser.customBrowserEvent, [
rpc.callBrowser('customCefEvent', ['client to cef']) 'hello from client',
])) as string
mp.console.logInfo(res)
return 'response from client'
}) })

View File

@ -0,0 +1,5 @@
import { Rpc } from 'rage-fw-rpc'
export const rpc = new Rpc({
debugLogs: true,
})

View File

@ -1,6 +0,0 @@
tabWidth: 4
printWidth: 80
singleQuote: true
semi: false
arrowParens: avoid
endOfLine: auto

22
apps/rpc/index.d.ts vendored
View File

@ -1,22 +0,0 @@
export {}
interface Mp {
trigger(event: string, data?: any): void
events: {
add(event: string, data: any): void
call(event: string, data: any): void
callRemote(event: string, data: any): void
}
joaat?: unknown
game: {
joaat?: unknown
}
}
declare global {
const mp: Mp
const global: Record<string, (...args: any[]) => unknown>
interface Window {
[p: string]: any
}
}

View File

@ -1,32 +0,0 @@
{
"name": "rpc",
"version": "0.1.0",
"main": "src/index.ts",
"types": "dist/src/index.d.ts",
"scripts": {
"build": "tsup",
"start": "npx ./dist create"
},
"files": [
"dist/**/*"
],
"devDependencies": {
"@microsoft/api-extractor": "^7.47.9",
"prettier": "^3.3.2",
"tsup": "^8.3.0"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"description": "RageFW RPC",
"keywords": [],
"author": "SashaGoncharov19",
"contributors": [
{
"name": "rilaxik",
"email": "dev.rilaxik@gmail.com",
"url": "https://github.com/rilaxik"
}
],
"license": "MIT"
}

View File

@ -1,44 +0,0 @@
import { Wrapper } from './wrapper'
import { Environment, Errors, Events, RPCState, Utils } from './utils'
class Browser extends Wrapper {
constructor() {
super()
}
public resolveEmitDestination(dataRaw: string) {
if (!dataRaw) throw new Error(Errors.NO_DATA)
let state = Utils.prepareExecution(dataRaw)
switch (state.calledTo) {
case Environment.BROWSER:
this.emit(dataRaw)
break
default:
this.emitClient(dataRaw)
break
}
}
private emitClient(dataRaw: string) {
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
private emit(dataRaw: string) {
let state = Utils.prepareExecution(dataRaw)
state = this.verifyEvent_(state)
if (state.knownError) {
this.triggerError_(state, state.knownError)
return
}
const { eventName, data } = Utils.prepareExecution(dataRaw)
this.state_[eventName](...data)
}
}
const browser = new Browser()
export { browser }

View File

@ -1,67 +0,0 @@
import { Wrapper } from './wrapper'
import { Environment, Errors, Events, Utils } from './utils'
import type { RPCState } from './utils'
class Client extends Wrapper {
private _browser: any = null
constructor() {
super()
}
set browser(browser: any) {
this._browser = browser
}
public resolveEmitDestination(dataRaw: string) {
if (!dataRaw) throw new Error(Errors.NO_DATA)
const state = Utils.prepareExecution(dataRaw)
switch (state.calledTo) {
case Environment.SERVER:
this.emitServer(dataRaw)
break
case Environment.BROWSER:
this.emitBrowser(dataRaw, state)
break
case Environment.CLIENT:
this.emit(state)
break
default:
this.triggerError_(state, Errors.UNKNOWN_ENVIRONMENT)
break
}
}
private emit(state: RPCState) {
state = this.verifyEvent_(state)
if (state.knownError) {
this.triggerError_(state, state.knownError)
return
}
this.state_[state.eventName](
...(Array.isArray(state.data) ? state.data : []),
)
}
private emitServer(dataRaw: string) {
mp.events.callRemote(Events.SERVER_EVENT_LISTENER, dataRaw)
}
private emitBrowser(dataRaw: string, state: RPCState) {
if (!this._browser) {
this.triggerError_(state, Errors.NO_BROWSER)
return
}
this._browser.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
}
const client = new Client()
export { client }

View File

@ -1,225 +0,0 @@
import { Wrapper } from './wrapper'
import {
Environment,
Errors,
Events,
RPCState,
Utils,
type PlayerMp,
} from './utils'
import { server } from './server'
import { client } from './client'
import { browser } from './browser'
export { server } from './server'
export { client } from './client'
export { browser } from './browser'
class Rpc extends Wrapper {
constructor() {
super()
if (this.environment_ === Environment.UNKNOWN)
throw new Error(Errors.UNKNOWN_ENVIRONMENT)
mp.events.add(
Events.LOCAL_EVENT_LISTENER,
async (player: PlayerMp | string, dataRaw: string) => {
switch (this.environment_) {
case Environment.SERVER:
server.resolveEmitDestination(
player as PlayerMp,
dataRaw,
)
break
case Environment.CLIENT:
dataRaw = player as string
client.resolveEmitDestination(dataRaw)
break
case Environment.BROWSER:
dataRaw = player as string
browser.resolveEmitDestination(dataRaw)
break
default:
void { player, dataRaw }
break
}
},
)
}
public register<
CallbackArguments extends unknown[] = unknown[],
CallbackReturn extends unknown = unknown,
EventName extends string = string,
>(
eventName: EventName,
cb: (...args: CallbackArguments) => CallbackReturn,
): void {
Utils.errorUnknownEnvironment(this.environment_)
this.state_[eventName] = cb
}
public unregister<EventName extends string = string>(
eventName: EventName,
): void {
Utils.errorUnknownEnvironment(this.environment_)
delete this.state_[eventName]
}
public callClient<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments): void
public callClient<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(player: PlayerMp, eventName: EventName, args?: Arguments): void
public callClient(
playerOrEventName: PlayerMp | string,
eventNameOrArgs?: string | unknown[],
args?: unknown[],
): void {
Utils.errorUnknownEnvironment(this.environment_)
function _is1StParamPlayer(x: unknown): x is PlayerMp {
return typeof x === 'object'
}
function _is2NdParamEventName(x: unknown): x is string {
return !Array.isArray(x) && typeof x === 'string'
}
// client
if (this.environment_ === Environment.CLIENT) {
this.call(playerOrEventName as string, args as unknown[])
return
}
// server
if (
this.environment_ === Environment.SERVER &&
_is1StParamPlayer(playerOrEventName) &&
_is2NdParamEventName(eventNameOrArgs)
) {
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName: eventNameOrArgs,
calledTo: Environment.CLIENT,
calledFrom: this.environment_,
knownError: undefined,
data: args as unknown[],
}
const dataRaw = Utils.prepareTransfer(state)
playerOrEventName.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
return
}
// browser
if (
this.environment_ === Environment.BROWSER &&
!_is1StParamPlayer(playerOrEventName) &&
!_is2NdParamEventName(eventNameOrArgs)
) {
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName: playerOrEventName,
calledTo: Environment.CLIENT,
calledFrom: this.environment_,
knownError: undefined,
data: eventNameOrArgs,
}
const dataRaw = Utils.prepareTransfer(state)
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
return
}
}
public callServer<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName,
calledTo: Environment.SERVER,
calledFrom: this.environment_,
knownError: undefined,
data: args,
}
if (state.calledFrom === Environment.SERVER) {
this.callSelf(state)
} else {
const dataRaw = Utils.prepareTransfer(state)
mp.events.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
}
public callBrowser<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
const state: RPCState = {
uuid: Utils.generateUUID(),
eventName,
calledTo: Environment.BROWSER,
calledFrom: this.environment_,
knownError: undefined,
data: args,
}
if (state.calledFrom === Environment.BROWSER) {
this.callSelf(state)
} else {
const dataRaw = Utils.prepareTransfer(state)
mp.events.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
}
}
public call<
Arguments extends unknown[] = unknown[],
EventName extends string = string,
>(eventName: EventName, args?: Arguments) {
Utils.errorUnknownEnvironment(this.environment_)
let state: RPCState = {
uuid: Utils.generateUUID(),
eventName,
calledTo: this.environment_,
calledFrom: this.environment_,
knownError: undefined,
data: args,
}
this.callSelf(state)
}
private callSelf(state: RPCState) {
state = this.verifyEvent_(state)
if (state.knownError) {
this.triggerError_(state, state.knownError)
return
}
this.state_[state.eventName](...state.data)
}
}
const rpc = new Rpc()
export { rpc }

View File

@ -1,49 +0,0 @@
import { Wrapper } from './wrapper'
import { Environment, Events, Utils, type PlayerMp } from './utils'
class Server extends Wrapper {
constructor() {
super()
mp.events.add(
Events.SERVER_EVENT_LISTENER,
async (player: PlayerMp, dataRaw: string) => {
this.emit(player, dataRaw)
},
)
}
public resolveEmitDestination(player: PlayerMp, dataRaw: string) {
let state = Utils.prepareExecution(dataRaw)
switch (state.calledTo) {
case Environment.SERVER:
this.emit(player, dataRaw)
break
default:
this.emitClient(player as PlayerMp, dataRaw)
break
}
}
private emitClient(player: PlayerMp, dataRaw: string) {
player.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
}
private emit(player: PlayerMp, dataRaw: string) {
let state = Utils.prepareExecution(dataRaw)
state = this.verifyEvent_(state)
if (state.knownError) {
this.triggerError_(state, state.knownError)
return
}
const { eventName, data } = Utils.prepareExecution(dataRaw)
this.state_[eventName](player, ...data)
}
}
const server = new Server()
export { server }

View File

@ -1,82 +0,0 @@
export enum Environment {
BROWSER = 'BROWSER',
CLIENT = 'CLIENT',
SERVER = 'SERVER',
UNKNOWN = 'UNKNOWN',
}
export enum Events {
LOCAL_EVENT_LISTENER = '__rpc:listener',
CLIENT_EVENT_LISTENER = '__rpc:clientListener',
SERVER_EVENT_LISTENER = '__rpc:serverListener',
EVENT_RESPONSE = '__rpc:response',
}
export enum Errors {
EVENT_NOT_REGISTERED = 'Event not registered',
UNKNOWN_ENVIRONMENT = 'Unknown environment',
NO_DATA = 'No data',
NO_BROWSER = 'You need to initialize browser first',
}
export class Utils {
public static getEnvironment(): Environment {
if ('joaat' in mp) return Environment.SERVER
if (
'game' in mp &&
'joaat' in (mp as { game: { joaat?: unknown } }).game
)
return Environment.CLIENT
if (window && 'mp' in window) return Environment.BROWSER
return Environment.UNKNOWN
}
public static prepareExecution(data: string): RPCState {
return JSON.parse(data)
}
public static prepareTransfer(data: RPCState): string {
return JSON.stringify(data)
}
public static generateUUID(): string {
let uuid = '',
random
for (let i = 0; i < 32; i++) {
random = (Math.random() * 16) | 0
if (i === 8 || i === 12 || i === 16 || i === 20) {
uuid += '-'
}
uuid += (
i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random
).toString(16)
}
return uuid
}
public static generateResponseEventName(uuid: string): string {
return `${Events.EVENT_RESPONSE}_${uuid}`
}
public static errorUnknownEnvironment(environment: Environment) {
if (environment === Environment.UNKNOWN)
throw new Error(Errors.UNKNOWN_ENVIRONMENT)
}
}
export type RPCState = {
eventName: string
uuid: string
knownError?: string
data?: any
calledFrom: Environment
calledTo: Environment
}
export type PlayerMp = {
call(event: string, args?: unknown[]): void
}

View File

@ -1,33 +0,0 @@
import { Environment, Errors, RPCState, Utils } from './utils'
export class Wrapper {
protected environment_ = Utils.getEnvironment()
protected state_ =
this.environment_ === Environment.BROWSER ? window : global
protected verifyEvent_(data: string | RPCState): RPCState {
let rpcData =
typeof data === 'string' ? Utils.prepareExecution(data) : data
if (!this.state_[rpcData.eventName]) {
rpcData.knownError = Errors.EVENT_NOT_REGISTERED
}
return rpcData
}
protected triggerError_(rpcData: RPCState, error?: any) {
const errorMessage = [
`${rpcData.knownError}`,
`Caller: ${rpcData.calledFrom}`,
`Receiver: ${this.environment_}`,
`Event: ${rpcData.eventName}`,
]
if (error) {
errorMessage.push(`Additional Info: ${error}`)
}
throw new Error(errorMessage.join('\n | '))
}
}

View File

@ -1,29 +0,0 @@
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"lib": [
"ES6",
"dom"
],
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"outDir": "bin",
"esModuleInterop": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": true,
},
"include": [
"src/**/*",
"./index.d.ts"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@ -1,11 +0,0 @@
import { defineConfig } from 'tsup'
export default defineConfig({
entry: ['src/index.ts'],
outDir: './dist',
format: ['cjs'],
experimentalDts: true,
splitting: false,
sourcemap: false,
clean: true,
})

View File

@ -1,13 +1,14 @@
{ {
"name": "rage-fw-example-server", "name": "rage-fw-example-server",
"version": "0.1.0", "description": "Server side of Rage-FW example",
"author": "Entity Seven Group",
"license": "CC BY-ND",
"description": "Server side of rage-fw example",
"scripts": { "scripts": {
"build": "esbuild src/index.ts --bundle --platform=node --target=node10.4 --outfile=../../server/packages/server/index.js" "build": "esbuild src/index.ts --bundle --platform=node --target=node10.4 --outfile=../../server/packages/server/index.js"
}, },
"dependencies": { "dependencies": {
"rpc": "workspace:^" "@rage-fw/shared": "workspace:^",
} "rage-fw-rpc": "file:../../../rage-framework/rpc"
},
"license": "CC BY-ND",
"author": "Entity Seven Group",
"version": "0.1.0"
} }

View File

@ -1,11 +1,20 @@
import { rpc } from 'rpc' import { events } from '@rage-fw/shared'
import { rpc } from './lib'
rpc.register('playerJoin', async (player: PlayerMp) => { rpc.register('playerJoin', async (player: PlayerMp) => {
console.log(`Connected: ${player.socialClub}`) console.log(`[Server] ${player.socialClub} connected`)
}) })
rpc.register('customServerEvent', (player: PlayerMp, data) => { rpc.register(
console.log(player, data) events.server.customServerEvent,
async (player: PlayerMp, args: string) => {
rpc.callClient(player, 'customClientEvent', ['server to client']) console.log(args)
}) const res = await rpc.callClient(
player,
events.client.customClientEvent,
['hello from server'],
)
console.log(res)
return 'response from server'
},
)

View File

@ -0,0 +1,5 @@
import { Rpc } from 'rage-fw-rpc'
export const rpc = new Rpc({
debugLogs: true,
})

View File

@ -1,13 +0,0 @@
declare module 'rage-fw-shared-types' {
export interface RageFW_ICustomClientEvent {
customClientEvent(greetings: string): void
}
export interface RageFW_ICustomServerEvent {
customServerEvent(greetings: string): void
}
export interface RageFW_ICustomCefEvent {
customCefEvent(greetings: string): void
}
}

12
apps/shared/index.ts Normal file
View File

@ -0,0 +1,12 @@
export const events = {
server: {
customServerEvent: 'customServerEvent',
},
client: {
cefReady: 'cefReady',
customClientEvent: 'customClientEvent',
},
browser: {
customBrowserEvent: 'customBrowserEvent',
},
}

6
apps/shared/package.json Normal file
View File

@ -0,0 +1,6 @@
{
"name": "@rage-fw/shared",
"description": "Shared data for Rage-FW example",
"version": "0.1.0",
"main": "index.ts"
}

View File

@ -1,29 +1,30 @@
{ {
"name": "framework-example", "name": "framework-example",
"version": "0.1.0", "description": "This project is an example of RAGE-FW usage",
"author": "Entity Seven Group", "workspaces": [
"license": "CC BY-ND", "apps/*"
"description": "This project is example of RAGE FW usage.", ],
"scripts": { "scripts": {
"server:update": "cd server && rage-win64.exe", "server:update": "cd server && rage-win64.exe",
"server:run": "cd server && ragemp-server.exe",
"i:client": "cd apps/client && pnpm i rpc", "i:client": "cd apps/client && pnpm i",
"i:server": "cd apps/server && pnpm i rpc", "i:server": "cd apps/server && pnpm i",
"i:cef": "cd apps/cef && pnpm i rpc", "i:browser": "cd apps/browser && pnpm i",
"i:all": "pnpm i:client && pnpm i:server && pnpm i:cef",
"build:client": "cd apps/client && pnpm build", "build:client": "cd apps/client && pnpm build",
"build:server": "cd apps/server && pnpm build", "build:server": "cd apps/server && pnpm build",
"build:cef": "cd apps/cef && pnpm build", "build:browser": "cd apps/cef && pnpm build",
"build:all": "pnpm build:client && pnpm build:server && pnpm build:cef" "build:all": "pnpm build:client && pnpm build:server && pnpm build:browser",
"build": "pnpm build:all"
}, },
"devDependencies": { "devDependencies": {
"@ragempcommunity/types-client": "^2.1.8", "@ragempcommunity/types-client": "^2.1.8",
"@ragempcommunity/types-server": "^2.1.8", "@ragempcommunity/types-server": "^2.1.8",
"@ragempcommunity/types-cef": "^2.1.8", "@ragempcommunity/types-cef": "^2.1.8",
"rage-fw-shared-types": "latest",
"esbuild": "^0.21.5", "esbuild": "^0.21.5",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"prettier": "^3.3.2" "prettier": "^3.3.2"
} },
"license": "CC BY-ND",
"author": "Entity Seven Group",
"version": "0.1.0"
} }

View File

@ -1,6 +1,2 @@
packages: packages:
- "apps/cef" - "apps/*"
- "apps/client"
- "apps/server"
- "apps/shared"
- "apps/rpc"