This commit is contained in:
Danya H 2025-02-04 23:29:50 +00:00
commit b7f97d22da
16 changed files with 1321 additions and 0 deletions

10
.dockerignore Normal file
View File

@ -0,0 +1,10 @@
.idea
.vscode
.git
docs/.vitepress/dist/
docs/.vitepress/cache/
node_modules
readme.md
.dockerignore

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.idea/
.vscode/
docs/.vitepress/dist/
docs/.vitepress/cache/
.gitea
bun.lock
node_modules

18
Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM oven/bun:1.2.2-alpine AS build
WORKDIR /docs
# Copy package
COPY package.json ./
# Clean install dependencies based package-lock
RUN bun install
# Copy files
COPY . .
RUN npm run build
FROM httpd:latest
COPY --from=build /docs/.vitepress/dist /usr/local/apache2/htdocs/

7
docker-compose.yml Normal file
View File

@ -0,0 +1,7 @@
services:
entity-seven-docs:
# image: uristri/entity-seven-docs
container_name: entity-seven-docs
ports:
- 1339:80 # <Host Port>:<Container Port>
restart: always

View File

@ -0,0 +1,45 @@
import { defineConfig } from 'vitepress'
import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "Entity Seven Docs",
description: "Short and descriptive",
lastUpdated: true,
markdown: {
codeTransformers: [
transformerTwoslash({
})
],
languages: ['js', 'ts']
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
search: {
provider: 'local'
},
sidebar: {
'/rage-fw-rpc/': [
{
text: 'Versions',
collapsed: true,
items: [
{ text: '0.3.0 (latest)', link: '/rage-fw-rpc/' },
{ text: '0.2.5', link: '/rage-fw-rpc/0.2.5' },
]
}
],
},
socialLinks: [
{ icon: 'github', link: 'https://git.entityseven.com/entityseven' },
{ icon: 'discord', link: 'https://discord.com/qPb7CmDF4C' },
],
}
})

View File

@ -0,0 +1,12 @@
import type { EnhanceAppContext } from 'vitepress'
import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client'
import Theme from 'vitepress/theme'
import '@shikijs/vitepress-twoslash/style.css'
export default {
extends: Theme,
enhanceApp({ app }: EnhanceAppContext) {
app.use(TwoslashFloatingVue)
},
}

31
docs/index.md Normal file
View File

@ -0,0 +1,31 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home
hero:
name: "Entity Seven Docs"
text: "Short and descriptive"
tagline: welcome to the future
actions:
- theme: brand
text: Rage Framework *
link: /rage-fw/
- theme: alt
text: Rage FW RPC
link: /rage-fw-rpc/
- theme: alt
text: Rage FW CLI
link: /rage-fw-cli/
features:
- title: Various Examples
icon: ✍️
details: Copy-paste examples that will just work in your project
- title: Verbal descriptions
icon: 🗣️
details: Detailed information about methods and variables with some inner details
- title: Use cases
icon: ❔
details: Where may I even put it?
---

55
docs/rage-fw-cli/index.md Normal file
View File

@ -0,0 +1,55 @@
---
lastUpdated: false
description: Use Rage FW CLI to minimize scaffolding issues
prev: false
next: false
outline: [2, 4]
---
# Rage FW CLI <Badge type="tip" text="^0.1.3" />
To make you life easier while using RageFW we created a basic CLI. At the moment automation we have only works via [pnpm](https://pnpm.io/) and [bun](https://bun.sh/)
```shell
pnpm create @entityseven/rage-fw@latest
```
```shell
bun create @entityseven/rage-fw@latest
```
## TL;DR
- ``Initialize new project`` - create new template project
- ``Test our RPC`` - scaffold an example for ``@entityseven/rage-fw-rpc``
- ``Install RAGE:MP updater`` - download and update RAGE:MP server files
## Options
For now, you will see a few available options. They are described in detail below
- ``Initialize new project``
- ``Test our RPC``
- ``Install RAGE:MP updater``
### Initialize new project
Using this option will forward you to common project creation menu
- ``Enter project name``
This option will specify a name for your project which is used as a folder name too. Defaults to __*rage-fw-example*__
- ``Select front-end``
Use selector menu to choose which front-end framework you want to use. We will do our best to expand this menu with various solutions (Also [Contribution](#contribution))
### Test our RPC
Using this option will forward you to common project creation menu
- ``Enter project name``
This option will specify a name for your project which is used as a folder name too. Defaults to **rage-fw-rpc-example**
- ``Select front-end``
Use selector menu to choose which front-end framework you want to use. We will do our best to expand this menu with various solutions
### Install Rage:MP updater
This option will simplify installation and update process of Rage:MP server files required to start your server
## Contribution
If you wish to help us in expanding examples selection with different framework you are very welcome to [open PRs and Issues](https://git.entityseven.com/entityseven/rage-framework)

View File

@ -0,0 +1,213 @@
---
lastUpdated: true
description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
prev: false
next: false
outline: [1, 4]
---
# Rage-FW-RPC <Badge type="tip" text="0.2.5" />
is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
# Installation
``` shell
npm i @entityseven/rage-fw-rpc@0.2.5
```
```shell
pnpm i @entityseven/rage-fw-rpc@0.2.5
```
```shell
yarn add @entityseven/rage-fw-rpc@0.2.5
```
Import installed package and initialize rpc:
```ts
// lib/rpc.js
import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc(/* options */)
```
On client-side you have to also specify the browser you want to refer to for events
```ts
// client/index.js
import { Rpc } from 'rage-fw-rpc'
export const rpc = new Rpc(/* options */)
rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html')
```
Also see [Rpc Config](#rpc-config)
# Motivation
The idea was to create an extensible package, with various features to simplify the development process and provide as much comfort as possible. It should also be using similar architecture as the framework it was specially built for
Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
# Features
- Type-safe events via [TS generics](https://www.typescriptlang.org/docs/handbook/2/generics.html), avoiding type wrappers
- Built-in logging options for each environment
- Error-safe developer mode for browser
- Calls can receive response from called environments via Promises (browser -> server -> browser, etc.)
- Actual human-readable errors
# Points
Before reading docs you should at least barely be acknowledged about the patterns used and how ``rage-fw-rpc`` is different in usage than community favorite ``rage-rpc``
- Arguments when calling any event must be wrapped in an array. This is done for proper argument typing. Be aware that as of now arguments in ``register`` are SPREAD and not wrapped in array. It is recommended to at least loosely type events, that require passing arrays as arguments to avoid unwanted outcomes.
```ts
// client-side
rpc.callServer('event', [2, 3])
```
```ts
// server-side expects number[], but gets two separate numbers as arguments instead
rpc.register('event', (player, argument1: number[] /* (actual: number), argument2 (actual: number) */) => {})
```
```ts
// this will save the day
rpc.callServer<[number[]]>('event', [2, 3]) // type-error
rpc.callServer<[number[]]>('event', [[2, 3]]) // ✓
```
- Keep in mind that chaining events this way -
```ts
// eg. client called server
rpc.register('customServerEvent', async (args: string) => {
const response: string = await rpc.callBrowser('customCefEvent', [
'hello from server',
])
// do something with response
return 'response from server'
})
```
has two major issues:
1. Events are marked as timed out after 10s and are throwing if no response was received. This can occur when player has high ping or browser delays the response in any way. Means your event chain may not continue in those cases. Your codebase is entirely up to you, but avoid such issues try not to chain events inside one another
2. await stops function execution. This means any operations in place of ``do something with res`` that do not rely on response are unnecessarily stopped. This can be avoided using ``.then(response => ...)`` giving function an opportunity to execute side-operations in parallel with promises
[Ref: await docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#description)
[Ref: in detail](https://dev.to/masteringjs/using-then-vs-async-await-in-javascript-2pma)
- Every environment can call any environment and get a response via Promise
```ts
server <-> client <-> browser as well as server <-> browser
```
You can still use ``call<env>`` methods to refer to environment itself
```ts
// server
rpc.callServer(...)
// client
rpc.callClient(...)
// browser
rpc.callBrowser(...)
```
It will behave the same way as using ``call`` by just being redirected to it. For better code clearance we do recommend using ``call`` instead of ``call<env>`` to also same a tiny bit of computation resources
- (Extra) Due to async-based logic some IDEs or tools like ESlint can soft-warn you for ignoring promises on events you do not want response from. In that cases you can either
```ts
// await it, but you will have to mark parent function as async
await rpc.callServer('event')
// or use .then() to just remove the noisy underline in rare cases you do not want/unable to mark it as async (eg. React.useEffect)
rpc.callServer('event').then()
```
# Docs
## Rpc Config
These are the options you can specify when creating Rpc instance. Options can be omitted at all if you want so. All options only have effect in current context and have to be specified individually on server/client/browser
```ts
interface RpcWrapperConfig {
forceBrowserDevMode?: boolean // defaults to false
debugLogs?: boolean // defaults to false
}
```
``forceBrowserDevMode`` - only has effect on browser-side. Fallback for browser to launch without mp context and without errors (eg. for development in browser). Keep in mind that using this makes browser-side unavailable at all preventing from all operations except logging. Therefore is recommended to use in pair with ``debugLogs``
``debugLogs`` - enables logging all exposed methods to available console. Server/browser: ``console.log``; client: ``mp.console.logInfo``
```ts
import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc({
forceBrowserDevMode: false,
debugLogs: true
})
```
## register
Registers a callback function for a specified event
```ts
rpc.register('playerJoin', (player) => {
console.log(`Connected: ${player.socialClub}`)
})
```
## unregister
Unregisters callback function for a specified event
```ts
rpc.unregister('playerDamage')
```
## callClient
Calls a client-side event from server or browser
From browser:
```ts
rpc.callClient('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
From server (requires player):
```ts
rpc.callClient(player, 'updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
## callServer
Calls a server-side event from browser or client
```ts
rpc.callServer('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
## callBrowser
Calls a server-side event from browser or client
From client:
```ts
rpc.callBrowser('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
From client (requires player):
```ts
rpc.callBrowser(player, 'updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
## call
Calls an event in current environment
```ts
rpc.call('triggerSomething').then(response => {
console.log(`Received: ${response}`)
})
```
# Errors
- When error is thrown you will get a message of such form
```ts
`${rpcData.knownError}\n` + // error message
`Caller: ${rpcData.calledFrom}\n` + // server/client/browser
`Receiver: ${this.environment_}\n` + // server/client/browser
`Event: ${rpcData.eventName}\n` +
`Additional Info: ${error}` // actual error object, could be more than one
```
Hopefully this will give you enough information about the event which throws. Error information is definitely subject to change in future
- Keep in mind that event timeouts are throwing with almost no information due to their current implementation (at least your console can show line number)
- Under the hood we use ``JSON.stringify`` to pass data between environments, but in JS there are a few which [cannot be serialized](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description)
## Codes
These should be clear enough themselves, in other cases refer to here
- ``EVENT_NOT_REGISTERED`` - throws in Promise (rejects) in called environment when event is either already unregistered or not registered yet. If you see this its almost always calling an event before registering
- ``UNKNOWN_ENVIRONMENT`` - throws in any environment that is not recognized as server/client/browser in Rage. Unlike ``rage-rpc`` this is not thrown in browser when launched without mp context IF you specify it in browser [Rpc Config](#rpc-config)
- ``NO_BROWSER`` - throws on client if you failed to specify valid browser for it to refer to when calling browser
- ``EVENT_RESPONSE_TIMEOUT`` - throws in Promise (rejects) when failed to receive a response data from called environment. You may not always want to receive it at all, for now it just works like this. Prefer adding ``catch`` on your events

198
docs/rage-fw-rpc/index.md Normal file
View File

@ -0,0 +1,198 @@
---
lastUpdated: true
description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
prev: false
next: false
outline: [2, 4]
---
# Rage FW RPC <Badge type="tip" text="^0.3.0" />
is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
## Installation
```shell
npm i @entityseven/rage-fw-rpc
```
```shell
pnpm i @entityseven/rage-fw-rpc
```
```shell
yarn add @entityseven/rage-fw-rpc
```
Import installed package and initialize rpc:
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#installation-->
On client-side you have to also specify the browser you want to refer to for events
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#installationClient-->
::: info
Also see [Rpc Config](#rpc-config)
:::
## Motivation
The idea was to create an extensible package, with various features to simplify the development process and provide as much comfort as possible. It should also be using similar architecture as the framework it was specially built for
Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
## Features
- Type-safe events via [TS generics](https://www.typescriptlang.org/docs/handbook/2/generics.html), avoiding type wrappers
- Built-in logging options for each environment
- Error-safe developer mode for browser
- Calls can receive response from called environments via Promises (browser -> server -> browser, etc.)
- Actual human-readable errors
## Points
Before reading docs you should at least barely be acknowledged about the patterns used and how ``rage-fw-rpc`` is different in usage than community favorite ``rage-rpc``
### Syntax
Arguments when calling any event must be wrapped in an array. This is done for proper argument typing. Be aware that as of now arguments in ``register`` are SPREAD and not wrapped in array. It is recommended to at least loosely type events, that require passing arrays as arguments to avoid unwanted outcomes.
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#syntax-->
### Asynchronous events
Keep in mind that chaining events this way:
```ts
// eg. client called server
rpc.register('customServerEvent', async (args: string) => {
const response: string = await rpc.callBrowserAsync('customBrowserEvent', [
'hello from server',
])
// do something with response
return 'response from server'
})
```
has two major issues:
1. Asynchronous events are marked as timed out after 10s and are throwing error if no response was received. This can occur when player has high ping or browser delays the response in any way. Means your event chain may not continue in those cases. Your codebase is entirely up to you, but avoid such issues try not to chain events inside one another
2. [``await``](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await#description) stops function execution. This means any operations in place of ``do something with response`` that do not rely on response are unnecessarily stopped. This can be avoided using [``.then(response => ...)``](https://dev.to/masteringjs/using-then-vs-async-await-in-javascript-2pma) giving function an opportunity to execute side-operations in parallel with promises
### Cross-env communication
Every environment can call any environment and get a response via Promise
```
server <-> client <-> browser AND server <-> browser
```
You can still use ``call<env>`` methods to refer to environment itself
```ts
// server
rpc.callServer(...)
rpc.callServerAsync(...)
// client
rpc.callClient(...)
rpc.callClientAsync(...)
// browser
rpc.callBrowser(...)
rpc.callBrowserAsync(...)
```
It will behave the same way as using ``call/callAsync`` by just being redirected to it. For better code clearance we do recommend using ``call/callAsync`` instead of ``call<env>/call<env>Async`` to also same a tiny bit of computation resources
- (Extra) Due to async-based logic some IDEs or tools like ESlint can soft-warn you for ignoring promises on events you do not want response from. In that cases you can either
```ts twoslash
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
await rpc.callServerAsync('event')
// @annotate: await it, but you will have to mark parent function as async
rpc.callServerAsync('event').then()
// @annotate: or use .then() in cases you do not want/unable to mark it as async (eg. React.useEffect)
```
## Docs
### Rpc Config
These are the options you can specify when creating Rpc instance. Options can be omitted at all if you want so. All options only have effect in current context and have to be specified individually on server/client/browser
```ts
interface RpcWrapperConfig {
forceBrowserDevMode?: boolean // defaults to false
debugLogs?: boolean // defaults to false
}
```
``forceBrowserDevMode`` - only has effect on browser-side. Fallback for browser to launch without mp context and without errors (e.g. for development in browser). Keep in mind that using this makes browser-side unavailable at all preventing from all operations except logging. Therefore, is recommended to use in pair with ``debugLogs``
``debugLogs`` - enables logging all exposed methods to available console.
::: info Console methods used in different environments
Server/browser: ``console.log``
Client: [``mp.console.logInfo``](https://wiki.rage.mp/wiki/Console::logInfo)
:::
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#rpcConfig-->
### register
Registers a callback function for a specified event
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#register-->
### unregister
Unregisters callback function for a specified event
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#unregister-->
### callClient
Calls a synchronous client-side event from server or browser. Won't return any response from client
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callClient-->
### callClientAsync
Calls a synchronous client-side event from server or browser. Will return a response from client
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callClientAsync-->
### callServer
Calls a synchronous server-side event from browser or client. Won't return any response from server
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callServer-->
### callServerAsync
Calls an asynchronous server-side event from browser or client. Will return a response from server
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callServerAsync-->
### callBrowser
Calls a synchronous server-side event from browser or client. Won't return any response from browser
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callBrowser-->
### callBrowserAsync
Calls a synchronous server-side event from browser or client. Will return a response from browser
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callBrowserAsync-->
### call
Calls a synchronous event in current environment. Won't return any response.
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#call-->
::: warning
You cannot call server on itself
:::
### callAsync
Calls an asynchronous event in current environment. Will return a response. You cannot call server on itself
<!--@include: @/snippets/rage-fw-rpc/0.3.0/snippets.md#callAsync-->
::: warning
You cannot call server on itself
:::
## Errors
- When error is thrown you will get a message of such form
```ts
`${rpcData.knownError}\n` + // error message
`Caller: ${rpcData.calledFrom}\n` + // server/client/browser
`Receiver: ${this.environment_}\n` + // server/client/browser
`Event: ${rpcData.eventName}\n` +
`Additional Info: ${error}` // actual error object, could be more than one
```
Hopefully this will give you enough information about the event which throws. Error information is definitely subject to change in future
- Keep in mind that event timeouts are throwing with almost no information due to their current implementation (at least your console can show line number)
- Under the hood we use ``JSON.stringify`` to pass data between environments, but in JS there are a few which [cannot be serialized](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description)
### Codes
These should be clear enough themselves, in other cases refer to here
- ``EVENT_NOT_REGISTERED`` - throws in Promise (rejects) in called environment when event is either already unregistered or not registered yet. If you see this its almost always calling an event before registering
- ``UNKNOWN_ENVIRONMENT`` - throws in any environment that is not recognized as server/client/browser in Rage. Unlike ``rage-rpc`` this is not thrown in browser when launched without mp context IF you specify it in browser [Rpc Config](#rpc-config)
- ``NO_BROWSER`` - throws on client if you failed to specify valid browser for it to refer to when calling browser
- ``EVENT_RESPONSE_TIMEOUT`` - throws in Promise (rejects) when failed to receive a response data from called environment. You may not always want to receive it at all, for now it just works like this. Prefer adding ``catch`` on your events

View File

@ -0,0 +1,377 @@
/** @ragempcommunity */
export declare type PlayerMp = any
export declare type BrowserEventNames = 'updatePlayerData' | 'triggerSomething'
export declare type ClientEventNames = 'updatePlayerData' | 'triggerSomething'
export declare type ServerEventNames = 'playerJoin' | 'updatePlayerData' | 'triggerSomething'
// ======================================
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
export declare class Browser extends Wrapper {
constructor(options?: RpcWrapperConfig);
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
_resolveEmitDestination(dataRaw: string): void;
private emitClient;
private emit;
}
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
export declare class Client extends Wrapper {
private _browser;
constructor(options?: RpcWrapperConfig);
set browser(browser: any);
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
_resolveEmitDestination(dataRaw: string): void;
private emit;
private emitServer;
private emitBrowser;
private errorNoBrowser;
}
export declare enum Environment {
BROWSER = "BROWSER",
CLIENT = "CLIENT",
SERVER = "SERVER",
UNKNOWN = "UNKNOWN"
}
export declare enum Errors {
EVENT_NOT_REGISTERED = "Event not registered",
UNKNOWN_ENVIRONMENT = "Unknown environment",
NO_BROWSER = "You need to initialize browser first",
EVENT_RESPONSE_TIMEOUT = "Response was timed out after 10s of inactivity"
}
export declare enum Events {
LOCAL_EVENT_LISTENER = "__rpc:listener",
SERVER_EVENT_LISTENER = "__rpc:serverListener",
EVENT_RESPONSE = "__rpc:response"
}
export declare const nativeClientEvents: Set<string>;
export declare const nativeServerEvents: Set<string>;
export declare class Rpc extends Wrapper {
private _server;
private _client;
private _browser;
constructor(options?: RpcConfig);
set browser(browser: any);
/**
* Registers a callback function for a specified event
*
* @template CallbackArguments - An array of argument types that the callback function accepts
* @template CallbackReturn - The type of the value returned by the callback function
* @template EventName - A string or union representing the event name
*
* @param {EventName} eventName - The name of the event to register the callback for
* @param {(...args: CallbackArguments) => CallbackReturn} cb - The callback function that is called when the event is triggered
*
* @returns {void}
*
* @example
* register<[PlayerMp]>('playerJoin', (player) => {
* console.log(`Connected: ${player.socialClub}`)
* })
*/
register<CallbackArguments extends unknown[] = unknown[], CallbackReturn = unknown, EventName extends string = string>(eventName: EventName, cb: (...args: CallbackArguments) => CallbackReturn): void;
/**
* Unregisters callback function for a specified event
*
* @template EventName - A string or union representing the event name
*
* @param {EventName} eventName - The name of the event to register the callback for
*
* @returns {void}
*
* @example
* unregister('playerJoin')
*/
unregister<EventName extends string = string>(eventName: EventName): void;
/**
* Calls a client-side event from browser or server. Use 'call' to call client from client
*
* @template Arguments - An array of argument types to be passed to the client event
* @template EventName - A string or union representing the client event name
*
* @param {EventName} eventName - The name of the client event to be called
* @param {Arguments} [args] - Optional arguments to pass to the client event
* @returns {void}
*
* @example
* // Calls an event on a client without specifying a player
* callClient<[], string, object>('onDataRequest')
*/
callClient<Arguments extends unknown[] = unknown[], EventName extends string = string>(eventName: EventName, args?: Arguments): void;
/**
* Calls a client-side event from server or server. Use 'call' to call client from client
*
* @template Arguments - An array of argument types to be passed to the client event
* @template EventName - A string or union representing the client event name
*
* @param {PlayerMp} player - The player for whom the client event is called
* @param {EventName} eventName - The name of the client event to be called
* @param {Arguments} [args] - Optional arguments to pass to the client event
* @returns {void} A promise resolving to the return value of the client event
*
* @example
* // Calls an event on a client for a specific player
* callClient<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2])
*/
callClient<Arguments extends unknown[] = unknown[], EventName extends string = string>(player: PlayerMp, eventName: EventName, args?: Arguments): void;
/**
* Calls an asynchronous client-side event from server or browser, expecting a response. Use 'callAsync' to call client from client
*
* @template Arguments - An array of argument types to be passed to the client event
* @template EventName - A string or union representing the client event name
* @template Return - The type of the value returned by the client event
*
* @param {EventName} eventName - The name of the client event to be called
* @param {Arguments} [args] - Optional arguments to pass to the client event
* @returns {Promise<Return>} A promise resolving to the return value of the client event
*
* @example
* // Calls an event on a client without specifying a player
* callClient<[], string, object>('onDataRequest').then(response => {
* console.log(`Received: ${response}`) // ^ object
* })
*/
callClientAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(eventName: EventName, args?: Arguments): Promise<Return>;
/**
* Calls an asynchronous client-side event from server or browser, expecting a response. Use 'callAsync' to call client from client
*
* @template Arguments - An array of argument types to be passed to the client event
* @template EventName - A string or union representing the client event name
* @template Return - The type of the value returned by the client event
*
* @param {PlayerMp} player - The player for whom the client event is called
* @param {EventName} eventName - The name of the client event to be called
* @param {Arguments} [args] - Optional arguments to pass to the client event
* @returns {Promise<Return>} A promise resolving to the return value of the client event
*
* @example
* // Calls an event on a client for a specific player
* callClient<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2]).then(result => {
* console.log(`Action success: ${result}`) // ^ boolean
* })
*/
callClientAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(player: PlayerMp, eventName: EventName, args?: Arguments): Promise<Return>;
/**
* Calls a server-side event from browser or client. Use 'call' to call server from server
*
* @template Arguments - An array of argument types to be passed to the server event
* @template EventName - A string or union representing the server event name
*
* @param {EventName} eventName - The name of the server event to be called
* @param {Arguments} [args] - Optional arguments to pass to the server event
* @returns {void}
*
* @example
* // Calls an event on a server
* callServer<[], string, object>('onDataRequest')
*/
callServer<Arguments extends unknown[] = unknown[], EventName extends string = string>(eventName: EventName, args?: Arguments): void;
/**
* Calls an asynchronous server-side event from browser or client, expecting a response. Use 'callAsync' to call server from server
*
* @template Arguments - An array of argument types to be passed to the server event
* @template EventName - A string or union representing the server event name
* @template Return - The type of the value returned by the server event
*
* @param {EventName} eventName - The name of the server event to be called
* @param {Arguments} [args] - Optional arguments to pass to the server event
* @returns {Promise<Return>} A promise resolving to the return value of the server event
*
* @example
* // Calls an event on a server
* callServer<[], string, object>('onDataRequest').then(response => {
* console.log(`Received: ${response}`) // ^ object
* })
*/
callServerAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(eventName: EventName, args?: Arguments): Promise<Return>;
/**
* Calls a browser-side event from client or server. Use 'call' to call browser from browser
*
* @template Arguments - An array of argument types to be passed to the browser event
* @template EventName - A string or union representing the browser event name
*
* @param {EventName} eventName - The name of the browser event to be called
* @param {Arguments} [args] - Optional arguments to pass to the browser event
* @returns {void}
*
* @example
* // Calls an event on a browser without specifying a player
* callBrowser<[], string, object>('onDataRequest')
*/
callBrowser<Arguments extends unknown[] = unknown[], EventName extends string = string>(eventName: EventName, args?: Arguments): void;
/**
* Calls a browser-side event from client or server. Use 'call' to call browser from browser
*
* @template Arguments - An array of argument types to be passed to the browser event
* @template EventName - A string representing the browser event name or union of names
*
* @param {PlayerMp} player - The player for whom the browser event is called
* @param {EventName} eventName - The name of the browser event to be called
* @param {Arguments} [args] - Optional arguments to pass to the browser event
* @returns {void}
*
* @example
* // Calls an event on a browser for a specific player
* callBrowser<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2])
*/
callBrowser<Arguments extends unknown[] = unknown[], EventName extends string = string>(player: PlayerMp, eventName: EventName, args?: Arguments): void;
/**
* Calls an asynchronous browser-side event from client or server, expecting response. Use 'callAsync' to call browser from browser
*
* @template Arguments - An array of argument types to be passed to the browser event
* @template EventName - A string or union representing the browser event name
* @template Return - The type of the value returned by the browser event
*
* @param {EventName} eventName - The name of the browser event to be called
* @param {Arguments} [args] - Optional arguments to pass to the browser event
* @returns {Promise<Return>} A promise resolving to the return value of the browser event
*
* @example
* // Calls an event on a browser without specifying a player
* callBrowser<[], string, object>('onDataRequest').then(response => {
* console.log(`Received: ${response}`) // ^ object
* })
*/
callBrowserAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(eventName: EventName, args?: Arguments): Promise<Return>;
/**
* Calls an asynchronous browser-side event from client or server, expecting response. Use 'callAsync' to call browser from browser
*
* @template Arguments - An array of argument types to be passed to the browser event
* @template EventName - A string representing the browser event name or union of names
* @template Return - The type of the value returned by the browser event
*
* @param {PlayerMp} player - The player for whom the browser event is called
* @param {EventName} eventName - The name of the browser event to be called
* @param {Arguments} [args] - Optional arguments to pass to the browser event
* @returns {Promise<Return>} A promise resolving to the return value of the browser event
*
* @example
* // Calls an asynchronous event on a browser for a specific player
* callBrowser<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2]).then(result => {
* console.log(`Action success: ${result}`) // ^ boolean
* })
*/
callBrowserAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(player: PlayerMp, eventName: EventName, args?: Arguments): Promise<Return>;
/**
* Calls an event in current environment
*
* @template Arguments - An array of argument types to be passed to the event
* @template EventName - A string or union representing the event name
*
* @param {EventName} eventName - The name of the event to be called
* @param {Arguments} [args] - Optional arguments to pass to the event
* @returns {void}
*
* @example
* // Calls an event in current environment
* call<[], string>('getSomething')
*/
call<Arguments extends unknown[] = unknown[], EventName extends string = string>(eventName: EventName, args?: Arguments): void;
/**
* Calls an asynchronous event in current environment, expecting a response
*
* @template Arguments - An array of argument types to be passed to the event
* @template EventName - A string or union representing the event name
* @template Return - The type of the value returned by the event
*
* @param {EventName} eventName - The name of the event to be called
* @param {Arguments} [args] - Optional arguments to pass to the event
* @returns {Promise<Return>} A promise resolving to the return value of the event
*
* @example
* // Calls an event in current environment
* call<[], string, number>('getSomething').then(response => {
* console.log(`Received: ${response}`) // ^ number
* })
*/
callAsync<Arguments extends unknown[] = unknown[], EventName extends string = string, Return = unknown>(eventName: EventName, args?: Arguments): Promise<Return>;
/**
* redirects an event in cases of it calling its own environment
*/
private callSelf;
/**
* redirects an asynchronous event in cases of it calling its own environment
*/
private callSelfAsync;
/**
* returns cross-environment response
*/
private responseHandler;
}
export declare interface RpcConfig extends RpcWrapperConfig {
debugLogs?: boolean;
}
export declare enum RPCEventType {
EVENT = "event",
RESPONSE = "response"
}
export declare type RPCState = {
eventName: string;
uuid: string;
calledFrom: Environment;
calledTo: Environment;
knownError?: string;
data?: any;
type: RPCEventType;
};
export declare interface RpcWrapperConfig {
forceBrowserDevMode?: boolean;
}
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
export declare class Server extends Wrapper {
constructor(options?: RpcWrapperConfig);
/**
* NOT INTENDED FOR OUT-OF-CONTEXT USE
*/
_resolveEmitDestination(player: PlayerMp, dataRaw: string): void;
private emitClient;
private emit;
}
export declare class Utils {
static getEnvironment(): Environment;
static prepareExecution(data: string): RPCState;
static prepareTransfer(data: RPCState): string;
static generateUUID(): string;
static generateResponseEventName(uuid: string): string;
static errorUnknownEnvironment(environment: Environment): void;
}
export declare class Wrapper {
protected environment_: Environment;
protected state_: any;
protected console_: {
(...data: any[]): void;
(message?: any, ...optionalParams: any[]): void;
};
protected debug_: boolean;
protected forceBrowserDevMode_: boolean;
constructor(options?: RpcWrapperConfig);
protected verifyEvent_(data: string | RPCState): RPCState;
protected triggerError_(rpcData: RPCState, error?: any): void;
protected log(method: string, eventName: string, ...args: unknown[]): void;
}
export declare const rpc: Rpc

View File

@ -0,0 +1,293 @@
<!-- #region installation -->
::: code-group
```ts twoslash [lib/rpc.ts]
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc(/* options */)
```
:::
<!-- #endregion installation -->
<!-- #region installationClient -->
::: code-group
```ts twoslash [client/index.ts]
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc(/* options */)
rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html')
```
:::
<!-- #endregion installationClient -->
<!-- #region syntax -->
```ts twoslash
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
// server-side
// @log: Server expects one argument and requires it to be an array
rpc.register('event', (player: PlayerMp, argument1: number[]) => {})
// client-side
// @log: Client sends two arguments
rpc.callServer('event', [2, 3])
// @warn: But this call is satisfied by the following register, instead of what we wanted previously
rpc.register('event', (player: PlayerMp, argument1: number, argument2: number) => {})
// @log: To avoid such mismatches you have to properly type your arguments:
rpc.callServer('event', [2, 3]) // [!code --]
rpc.callServer<[number[]]>('event', [[2, 3]]) // [!code ++]
```
<!-- #endregion syntax -->
<!-- #region rpcConfig -->
```ts twoslash
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc({
forceBrowserDevMode: false,
debugLogs: true
})
```
<!-- #endregion rpcConfig -->
<!-- #region register -->
::: code-group
```ts [Simple]
rpc.register('playerJoin', (player: PlayerMp) => {
console.log(`Connected: ${player.socialClub}`)
})
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.register<
[player: PlayerMp], void, ServerEventNames
>('playerJoin', (player) => {
console.log(`Connected: ${player.socialClub}`)
})
```
:::
<!-- #endregion register -->
<!-- #region unregister -->
::: code-group
```ts [Simple]
rpc.unregister('playerJoin')
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.unregister<ServerEventNames>('playerJoin')
```
:::
<!-- #endregion unregister -->
<!-- #region callClient -->
::: code-group
```ts [Simple (browser)]
rpc.callClient('updatePlayerData', ['argument'])
```
```ts [Simple (server)]
const player = {} satisfies PlayerMp
rpc.callClient(player, 'updatePlayerData', ['argument'])
```
```ts twoslash [With types (browser)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callClient<
[string], ClientEventNames
>('updatePlayerData', ['argument'])
```
```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
const player = {} satisfies PlayerMp
rpc.callClient<
[string], ClientEventNames
>(player, 'updatePlayerData', ['argument'])
```
:::
<!-- #endregion callClient -->
<!-- #region callClientAsync -->
::: code-group
```ts [Simple (browser)]
rpc.callClientAsync('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
```ts [Simple (server)]
const player = {} satisfies PlayerMp
rpc.callClientAsync(player, 'updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types (browser)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callClientAsync<
[string], ClientEventNames, boolean
>('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
const player = {} satisfies PlayerMp
rpc.callClientAsync<
[string], ClientEventNames, boolean
>(player, 'updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
:::
<!-- #endregion callClientAsync -->
<!-- #region callServer -->
::: code-group
```ts [Simple]
rpc.callServer('updatePlayerData', ['argument'])
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callServer<
[string], ServerEventNames
>('updatePlayerData', ['argument'])
```
:::
<!-- #endregion callServer -->
<!-- #region callServerAsync -->
::: code-group
```ts [Simple]
rpc.callServerAsync('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callServerAsync<
[string], ServerEventNames, boolean
>('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
:::
<!-- #endregion callServerAsync -->
<!-- #region callBrowser -->
::: code-group
```ts [Simple (client)]
rpc.callBrowser('updatePlayerData', ['argument'])
```
```ts [Simple (server)]
const player = {} satisfies PlayerMp
rpc.callBrowser('updatePlayerData', ['argument'])
```
```ts twoslash [With types (client)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callBrowser<
[string], BrowserEventNames
>('updatePlayerData', ['argument'])
```
```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
const player = {} satisfies PlayerMp
rpc.callBrowser<
[string], BrowserEventNames
>(player, 'updatePlayerData', ['argument'])
```
:::
<!-- #endregion callBrowser -->
<!-- #region callBrowserAsync -->
::: code-group
```ts [Simple (client)]
rpc.callBrowserAsync('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
```ts [Simple (server)]
const player = {} satisfies PlayerMp
rpc.callBrowserAsync('updatePlayerData', ['argument']).then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types (client)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callBrowserAsync<
[string], BrowserEventNames, boolean
>('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
const player = {} satisfies PlayerMp
rpc.callBrowserAsync<
[string], BrowserEventNames, boolean
>('updatePlayerData', ['argument'])
.then(response => {
console.log(`Received: ${response}`)
})
```
:::
<!-- #endregion callBrowserAsync -->
<!-- #region call -->
::: code-group
```ts [Simple]
rpc.call('triggerSomething')
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.call<never, ClientEventNames>('triggerSomething')
```
:::
<!-- #endregion call -->
<!-- #region callAsync -->
::: code-group
```ts [Simple]
rpc.callAsync('triggerSomething').then(response => {
console.log(`Received: ${response}`)
})
```
```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut---
rpc.callAsync<
never, ClientEventNames, boolean
>('triggerSomething')
.then(response => {
console.log(`Received: ${response}`)
})
```
:::
<!-- #endregion callAsync -->

1
index.ts Normal file
View File

@ -0,0 +1 @@
console.log("Hello via Bun!");

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "rage-framework-docs",
"module": "index.ts",
"type": "module",
"devDependencies": {
"@shikijs/vitepress-twoslash": "^2.3.0",
"@types/bun": "latest",
"vitepress": "^1.6.3"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
},
"dependencies": {
"vitepress-versioning-plugin": "^1.3.0"
}
}

4
readme.md Normal file
View File

@ -0,0 +1,4 @@
# Entity Seven Docs
Documentation vault for projects under Entity Seven
Built with [VitePress](https://vitepress.dev/)

27
tsconfig.json Normal file
View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}