rage-fw 0.2.0

sidebars
This commit is contained in:
Danya H 2025-02-05 15:56:38 +00:00
parent d8afe650e3
commit 6ae665ee64
26 changed files with 1729 additions and 310 deletions

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"tabWidth": 2,
"printWidth": 80,
"semi": false,
"singleQuote": true,
"trailingComma": "none"
}

View File

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

View File

@ -1,45 +1,134 @@
import { defineConfig } from 'vitepress' import { SidebarItem, defineConfig } from 'vitepress'
import { transformerTwoslash } from '@shikijs/vitepress-twoslash' import { transformerTwoslash } from '@shikijs/vitepress-twoslash'
import fs from 'node:fs'
import path from 'node:path'
// https://vitepress.dev/reference/site-config // https://vitepress.dev/reference/site-config
export default defineConfig({ export default defineConfig({
title: "Entity Seven Docs", title: 'Entity Seven Docs',
description: "Short and descriptive", description: 'Short and descriptive',
lastUpdated: true, lastUpdated: true,
markdown: {
codeTransformers: [
transformerTwoslash({
})
],
languages: ['js', 'ts']
},
themeConfig: { themeConfig: {
// https://vitepress.dev/reference/default-theme-config // https://vitepress.dev/reference/default-theme-config
sidebar: {
'/rage-fw-rpc/': [getVersionsByFolder('rage-fw-rpc')],
...getFwSidebar()
},
search: { search: {
provider: 'local' 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: [ socialLinks: [
{ icon: 'github', link: 'https://git.entityseven.com/entityseven' }, { icon: 'github', link: 'https://git.entityseven.com/entityseven' },
{ icon: 'discord', link: 'https://discord.com/qPb7CmDF4C' }, { icon: 'discord', link: 'https://discord.com/qPb7CmDF4C' }
], ],
footer: {
copyright: 'Copyright Entity Seven Group © 2024 - Present'
}
},
markdown: {
codeTransformers: [transformerTwoslash()],
languages: ['js', 'ts']
} }
}) })
function getFwSidebar() {
const dir = 'rage-fw'
const versions = getVersionsByFolder(dir)
const base = {
text: 'Documentation',
collapsed: false
}
const sidebar = {
[`/${dir}/`]: [versions]
// [`/${dir}`]: [documentation('..'), versions],
}
for (const version of versions.items) {
if (version.text.includes('latest')) {
const files = listChildFiles(path.resolve('docs', dir))
sidebar[`/${dir}/`] = [
{
...base,
items: files.map((f) => ({ text: formatFilename(f), link: `./${f}` }))
},
versions
]
continue
}
const v = version.text.replace('(latest)', '').trim()
const files = listChildFiles(path.resolve('docs', dir, v))
sidebar[`/${dir}/${v}/`] = [
{
...base,
items: files.map((f) => ({ text: formatFilename(f), link: `./${f}` }))
},
versions
]
}
return sidebar
function formatFilename(filename: string) {
filename = filename.split('.')[0].replace('-', ' ').replace('_', ' ')
return filename.charAt(0).toUpperCase() + filename.slice(1)
}
}
function getVersionsByFolder(folder: string) {
const folders = listChildFolders(path.resolve('docs', folder))
const versions: SidebarItem = {
text: 'Versions',
collapsed: true,
items: []
}
for (const v of folders) {
versions.items.push({
text: v,
link: `/${folder}/` + v
})
}
versions.items = versions.items.sort((a, b) => {
const vA = parseInt(a.text.replaceAll('.', ''), 10)
const vB = parseInt(b.text.replaceAll('.', ''), 10)
return vB - vA
})
versions.items[0].text += ' (latest)'
versions.items[0].link = `/${folder}/`
return versions
}
function listChildFolders(dir: string) {
const result: string[] = []
const items = fs.readdirSync(dir)
for (const item of items) {
const fullPath = path.join(dir, item)
const stats = fs.statSync(fullPath)
if (stats.isDirectory()) result.push(item)
}
return result
}
function listChildFiles(dir: string) {
const result: string[] = []
const items = fs.readdirSync(dir)
for (const item of items) {
const fullPath = path.join(dir, item)
const stats = fs.statSync(fullPath)
if (stats.isFile()) result.push(item)
}
return result
.filter((e) => !e.startsWith('index'))
.sort((a, b) => ('' + a.attr).localeCompare(b.attr))
}

View File

@ -8,5 +8,5 @@ export default {
extends: Theme, extends: Theme,
enhanceApp({ app }: EnhanceAppContext) { enhanceApp({ app }: EnhanceAppContext) {
app.use(TwoslashFloatingVue) app.use(TwoslashFloatingVue)
}, }
} }

View File

@ -3,8 +3,8 @@
layout: home layout: home
hero: hero:
name: "Entity Seven Docs" name: 'Entity Seven Docs'
text: "Short and descriptive" text: 'Short and descriptive'
tagline: welcome to the future tagline: welcome to the future
actions: actions:
- theme: brand - theme: brand
@ -28,4 +28,3 @@ features:
icon: ❔ icon: ❔
details: Where may I even put it? details: Where may I even put it?
--- ---

View File

@ -1,5 +1,4 @@
--- ---
lastUpdated: false
description: Use Rage FW CLI to minimize scaffolding issues description: Use Rage FW CLI to minimize scaffolding issues
prev: false prev: false
next: false next: false
@ -19,37 +18,43 @@ bun create @entityseven/rage-fw@latest
``` ```
## TL;DR ## TL;DR
- ``Initialize new project`` - create new template project
- ``Test our RPC`` - scaffold an example for ``@entityseven/rage-fw-rpc`` - `Initialize new project` - create new template project
- ``Install RAGE:MP updater`` - download and update RAGE:MP server files - `Test our RPC` - scaffold an example for `@entityseven/rage-fw-rpc`
- `Install RAGE:MP updater` - download and update RAGE:MP server files
## Options ## Options
For now, you will see a few available options. They are described in detail below For now, you will see a few available options. They are described in detail below
- ``Initialize new project`` - `Initialize new project`
- ``Test our RPC`` - `Test our RPC`
- ``Install RAGE:MP updater`` - `Install RAGE:MP updater`
### Initialize new project ### Initialize new project
Using this option will forward you to common project creation menu Using this option will forward you to common project creation menu
- ``Enter project name`` - `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*__ 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`` - `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)) 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 ### Test our RPC
Using this option will forward you to common project creation menu Using this option will forward you to common project creation menu
- ``Enter project name`` - `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** 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`` - `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 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 ### Install Rage:MP updater
This option will simplify installation and update process of Rage:MP server files required to start your server This option will simplify installation and update process of Rage:MP server files required to start your server
## Contribution ## 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) 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

@ -1,26 +1,30 @@
--- ---
lastUpdated: true
description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
prev: false prev: false
next: false next: false
outline: [1, 4] outline: [1, 4]
--- ---
# Rage-FW-RPC <Badge type="tip" text="0.2.5" /> # 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 is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
# Installation # Installation
``` shell
```shell
npm i @entityseven/rage-fw-rpc@0.2.5 npm i @entityseven/rage-fw-rpc@0.2.5
``` ```
```shell ```shell
pnpm i @entityseven/rage-fw-rpc@0.2.5 pnpm i @entityseven/rage-fw-rpc@0.2.5
``` ```
```shell ```shell
yarn add @entityseven/rage-fw-rpc@0.2.5 yarn add @entityseven/rage-fw-rpc@0.2.5
``` ```
Import installed package and initialize rpc: Import installed package and initialize rpc:
```ts ```ts
// lib/rpc.js // lib/rpc.js
@ -29,6 +33,7 @@ export const rpc = new Rpc(/* options */)
``` ```
On client-side you have to also specify the browser you want to refer to for events On client-side you have to also specify the browser you want to refer to for events
```ts ```ts
// client/index.js // client/index.js
@ -36,14 +41,17 @@ import { Rpc } from 'rage-fw-rpc'
export const rpc = new Rpc(/* options */) export const rpc = new Rpc(/* options */)
rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html') rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html')
``` ```
Also see [Rpc Config](#rpc-config) Also see [Rpc Config](#rpc-config)
# Motivation # 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 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) Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
# Features # Features
- Type-safe events via [TS generics](https://www.typescriptlang.org/docs/handbook/2/generics.html), avoiding type wrappers - 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 - Built-in logging options for each environment
- Error-safe developer mode for browser - Error-safe developer mode for browser
@ -51,17 +59,27 @@ Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
- Actual human-readable errors - Actual human-readable errors
# Points # 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. 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 ```ts
// client-side // client-side
rpc.callServer('event', [2, 3]) rpc.callServer('event', [2, 3])
``` ```
```ts ```ts
// server-side expects number[], but gets two separate numbers as arguments instead // server-side expects number[], but gets two separate numbers as arguments instead
rpc.register('event', (player, argument1: number[] /* (actual: number), argument2 (actual: number) */) => {}) rpc.register(
'event',
(
player,
argument1: number[] /* (actual: number), argument2 (actual: number) */
) => {}
)
``` ```
```ts ```ts
// this will save the day // this will save the day
rpc.callServer<[number[]]>('event', [2, 3]) // type-error rpc.callServer<[number[]]>('event', [2, 3]) // type-error
@ -69,27 +87,33 @@ rpc.callServer<[number[]]>('event', [[2, 3]]) // ✓
``` ```
- Keep in mind that chaining events this way - - Keep in mind that chaining events this way -
```ts ```ts
// eg. client called server // eg. client called server
rpc.register('customServerEvent', async (args: string) => { rpc.register('customServerEvent', async (args: string) => {
const response: string = await rpc.callBrowser('customCefEvent', [ const response: string = await rpc.callBrowser('customCefEvent', [
'hello from server', 'hello from server'
]) ])
// do something with response // do something with response
return 'response from server' return 'response from server'
}) })
``` ```
has two major issues: 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 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 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: 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) [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 - Every environment can call any environment and get a response via Promise
```ts ```ts
server <-> client <-> browser as well as server <-> browser server <-> client <-> browser as well as server <-> browser
``` ```
You can still use ``call<env>`` methods to refer to environment itself
You can still use `call<env>` methods to refer to environment itself
```ts ```ts
// server // server
rpc.callServer(...) rpc.callServer(...)
@ -98,9 +122,11 @@ rpc.callClient(...)
// browser // browser
rpc.callBrowser(...) 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
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 - (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 ```ts
// await it, but you will have to mark parent function as async // await it, but you will have to mark parent function as async
await rpc.callServer('event') await rpc.callServer('event')
@ -112,16 +138,20 @@ rpc.callServer('event').then()
# Docs # Docs
## Rpc Config ## 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 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 ```ts
interface RpcWrapperConfig { interface RpcWrapperConfig {
forceBrowserDevMode?: boolean // defaults to false forceBrowserDevMode?: boolean // defaults to false
debugLogs?: 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`` `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 ```ts
import { Rpc } from '@entityseven/rage-fw-rpc' import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc({ export const rpc = new Rpc({
@ -131,7 +161,9 @@ export const rpc = new Rpc({
``` ```
## register ## register
Registers a callback function for a specified event Registers a callback function for a specified event
```ts ```ts
rpc.register('playerJoin', (player) => { rpc.register('playerJoin', (player) => {
console.log(`Connected: ${player.socialClub}`) console.log(`Connected: ${player.socialClub}`)
@ -139,75 +171,95 @@ rpc.register('playerJoin', (player) => {
``` ```
## unregister ## unregister
Unregisters callback function for a specified event Unregisters callback function for a specified event
```ts ```ts
rpc.unregister('playerDamage') rpc.unregister('playerDamage')
``` ```
## callClient ## callClient
Calls a client-side event from server or browser Calls a client-side event from server or browser
From browser: From browser:
```ts ```ts
rpc.callClient('updatePlayerData', ['argument']).then(response => { rpc.callClient('updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
From server (requires player): From server (requires player):
```ts ```ts
rpc.callClient(player, 'updatePlayerData', ['argument']).then(response => { rpc.callClient(player, 'updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
## callServer ## callServer
Calls a server-side event from browser or client Calls a server-side event from browser or client
```ts ```ts
rpc.callServer('updatePlayerData', ['argument']).then(response => { rpc.callServer('updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
## callBrowser ## callBrowser
Calls a server-side event from browser or client Calls a server-side event from browser or client
From client: From client:
```ts ```ts
rpc.callBrowser('updatePlayerData', ['argument']).then(response => { rpc.callBrowser('updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
From client (requires player): From client (requires player):
```ts ```ts
rpc.callBrowser(player, 'updatePlayerData', ['argument']).then(response => { rpc.callBrowser(player, 'updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
## call ## call
Calls an event in current environment Calls an event in current environment
```ts ```ts
rpc.call('triggerSomething').then(response => { rpc.call('triggerSomething').then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
# Errors # Errors
- When error is thrown you will get a message of such form - When error is thrown you will get a message of such form
```ts ```ts
`${rpcData.knownError}\n` + // error message ;`${rpcData.knownError}\n` + // error message
`Caller: ${rpcData.calledFrom}\n` + // server/client/browser `Caller: ${rpcData.calledFrom}\n` + // server/client/browser
`Receiver: ${this.environment_}\n` + // server/client/browser `Receiver: ${this.environment_}\n` + // server/client/browser
`Event: ${rpcData.eventName}\n` + `Event: ${rpcData.eventName}\n` +
`Additional Info: ${error}` // actual error object, could be more than one `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 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) - 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) - 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 ## Codes
These should be clear enough themselves, in other cases refer to here 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) - `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
- ``NO_BROWSER`` - throws on client if you failed to specify valid browser for it to refer to when calling browser - `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)
- ``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 - `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,235 @@
---
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

@ -1,198 +1,7 @@
--- ---
lastUpdated: true
description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS description: Rage-FW-RPC is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
prev: false prev: false
next: false next: false
outline: [2, 4] outline: [2, 4]
--- ---
<!--@include: ./0.3.0/index.md-->
# 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,108 @@
---
outline: [2, 4]
---
# Browser <Badge type="tip" text="^0.2.0" />
Package used on a browser-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-browser'
```
Only usable in Browser environment. For usage in [Server](./server) and [Client](./client) refer to their docs
## Declaration
```ts
fw = {
event: Browser,
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Browser
Browser-side interactions
### debugLogs
Setter. Enables console debug logs for events
```ts
fw.event.debugLogs = true
```
### customLogger
Setter. Enables console debug logs for events
```ts
fw.event.customLogger =
() =>
(method: string, eventName: string, ...args: unknown[]) => {
// log with desired formatting
}
```
### register
Registers a browser event with an associated callback
```ts
fw.event.register('showNotification', (message, color) => {
// do something
})
```
### unregister
Unregisters a browser event, removing the associated callback
```ts
fw.event.unregister('showNotification')
```
### trigger
Triggers a browser event from the browser with arguments from shared types. Formerly known as `call` or `emit`
```ts
// without args
fw.event.trigger('browserEventName')
// with args
fw.event.trigger('browserEventName', ['message to me'])
```
### triggerServer
Triggers a server event from the browser with arguments from shared types. Formerly known as `callServer` or `emitServer`
```ts
// without args
fw.event.triggerServer('serverEventName')
// with args
fw.event.triggerServer('serverEventName', ['message to server'])
```
### triggerClient
Triggers a client event from the browser with arguments from shared types. Formerly known as `callClient` or `emitClient`
```ts
// without args
fw.event.triggerClient('clientEventName')
// with args
fw.event.triggerClient('clientEventName', ['message to client'])
```
### Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance
#### `forceBrowserDevMode`?
`rage-fw-rpc` has a setting which enables it to be ran in browser dev mode without MP context ([see Rpc Config](/rage-fw-rpc/#rpc-config)). As `rage-fw-browser` does not expose Rpc constructor, you can use `.env` with `RageFW_forceBrowserDevMode=true` to enable it

View File

@ -0,0 +1,150 @@
---
outline: [2, 4]
---
# Client <Badge type="tip" text="^0.2.0" />
Package used on a client-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-client'
```
Only usable in client environment. For usage in [Server](./server) and [Browser](./browser) refer to their docs
## Declaration
```ts
fw = {
event: Client,
player: Player,
system: {
log: Logger
},
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Client
Client-side interactions
### register
Registers a client event with an associated callback
```ts
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
})
// Registering an event with middlewares
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
}, {
middlewares: [...] // <- your middlewares here
})
// or
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
}, {
middlewares: {
executables: [...], // <- your middlewares here
onError: (msg) => void msg // <- error handling here
}
})
```
### unregister
Unregisters a client event, removing the associated callback
```ts
fw.event.unregister('playerDeath')
```
## Player
Handles event manipulations that require player to be present in context
### browser
Setter. Also shares browser with `rage-fw-rpc`
```ts
fw.player.browser = mp.browsers.new('package://index.html')
```
### trigger
Triggers registered client event with passed arguments. Formerly known as `call` or `emit`
```ts
// without args
fw.player.trigger('clientEventName')
// with args
fw.player.trigger('clientEventName', ['message to me'])
```
### triggerServer
Triggers a server event from the client with arguments from shared types. Formerly known as `callServer` or `emitServer`
```ts
// without args
fw.player.triggerServer('serverEventName')
// with args
fw.player.triggerServer('serverEventName', ['message to server'])
```
### triggerBrowser
Triggers a browser event from the client with arguments from shared types. Formerly known as `callBrowser` or `emitBrowser`
```ts
// without args
fw.player.triggerBrowser('browserEventName')
// with args
fw.player.triggerBrowser('browserEventName', ['message to browser'])
```
## System
Handles functions used to interact with the client environment
### Logger
Used to log to a client in-game console
### info
Informational logs. Colored in white
```ts
fw.system.log.info('some information to be logged')
```
### warn
Warning logs. Colored in yellow
```ts
fw.system.log.warn('warning message')
```
### error
Error logs. Colored in red
```ts
fw.system.log.info('some error information')
```
## Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance

View File

@ -0,0 +1,92 @@
---
outline: [2, 4]
---
# Features <Badge type="tip" text="^0.2.0" />
## Event Middlewares
Rage FW offers you to add middlewares when registering events in Client and Server environments, to check if callback should be executed or should not. Core class functionality is not exposed to user, but some types are for easier code managing. Here are some key points (in context of Server environment, but also applicable to Client)
### Declaration
```ts
register(
eventName,
callback,
options?: {
middlewares?: RageFW_MiddlewareOptions
},
)
type RageFW_MiddlewareOptions =
| RageFW_MiddlewareFunction[]
| {
executables: RageFW_MiddlewareFunction[]
onError: (error: string) => unknown
}
type RageFW_MiddlewareFunction = (...args: T.RageFW_ServerArgs) =>
Promise<RageFW_MiddlewareResponse>
type RageFW_MiddlewareResponse =
| {
success: boolean
message?: string
}
| boolean
```
### Usage
`RageFW_MiddlewareFunction` can be imported to type your middlewares, eg.:
```ts
import { type RageFW_MiddlewareFunction } from '@entityseven/rage-fw-server'
const isPlayerAdmin: RageFW_MiddlewareFunction<'yourEventName'> = async (
player,
...args
) => {
if (player.adminLvl >= 2) {
return true
} else {
return {
success: false,
message: 'You must have administrator rights for this action'
}
}
}
// or function-like if you want to omit some argument types or hoisting is required
async function isPlayerAdmin(
player: PlayerMp,
...args
): ReturnType<RageFW_MiddlewareFunction<'yourEventName'>> {
if (player.adminLvl >= 2) {
return true
} else {
return {
success: false,
message: 'You must have administrator rights for this action'
}
}
}
fw.event.register(
'yourEventName',
async (player, ...args) => {
// do an action which requires administrator rights
},
{
middlewares: {
executables: [isPlayerAdmin],
onError: (e) => {} // notify player about missing permissions
}
}
)
```
### Implementation TL;DR (why no next()?)
Unfortunately in Client-side of Rage:MP every thrown `Error` or `Promise.reject` is not `catch`able, meaning a naughty error window will pop-up on player's screen. Due to this implementation variant we were forced to not throw `Errors` from middlewares and just return middleware result. Server-side can handle errors, but to keep everything consistent we stick up to this variant

View File

@ -0,0 +1,59 @@
---
description: RageFW is a ty1pe-safe framework for developing Rage:MP servers
prev: false
next: false
outline: [2, 4]
---
# Rage Framework (RageFW) <Badge type="tip" text="^0.2.0" />
RageFW is a type-safe framework for developing Rage:MP servers. Designed with developers in mind, RageFW brings structure and efficiency to your Rage:MP servers, ensuring robust and maintainable code
## Features
- **Type-Safe Development:** Eliminate runtime errors and enhance code reliability with RageFW comprehensive type safety, making your RP server's development smoother than a Sunday drive through Los Santos
- **Wrapped RPC client:** Communicate effortlessly between server, client and cef with RPC system, wrapped in a cozy custom-typed blanket for your peace of mind
- **Logging System:** Keep track of server activities and debug like a pro with our built-in, feature-rich logging system. After all, even virtual cops need evidence
## Getting Started
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/)
You can find out more about our CLI [here](/rage-fw-cli/)
```shell
pnpm create @entityseven/rage-fw@latest
```
```shell
bun create @entityseven/rage-fw@latest
```
This will give you a few options, among them, you can find `Initialize new project`. Use that option to scaffold a new project for yourself using the preferred frontend framework
## Documentation
RageFW distibutes under a list of packages:
- [`@entityseven/rage-fw-server`](./server) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-server)
- [`@entityseven/rage-fw-client`](./client) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-client)
- [`@entityseven/rage-fw-browser`](./browser) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-browser)
- [`@entityseven/rage-fw-shared-types`](./shared-types) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-shared-types)
These are setup as-should if you are using our CLI, if you still want to setup yourself, please refer to [examples](https://git.entityseven.com/entityseven/rage-framework-example)
## Contributing
Join our community of developers and contribute to the ongoing development of RageFW. At the moment the only way to contribute is opening issues
## Support
Need help? Reach out via our community forums or contact us directly through our support channels. We're committed to help you as we can
## License
Licensed under **Custom Attribution-NoDerives Software License**
> _RageFW - because in the world of GTA:RP, nobody has time for type errors_

View File

@ -0,0 +1,139 @@
---
outline: [2, 4]
---
# Server <Badge type="tip" text="^0.2.0" />
Package used on a server-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-server'
```
Only usable in server environment. For usage in [Client](./client) and [Browser](./browser) refer to their sections
## Declaration
```ts
fw = {
event: Server,
player: Player,
system: {
log: Logger
},
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Server
Server-side interactions
### register
Registers a server event with an associated callback
```ts
fw.event.register("playerJoin", (player) => {
// do something
})
// Registering an event with middlewares
fw.event.register("playerJoin", (player) => {
// do something
}, {
middlewares: [...] // <- your middlewares here
})
// or
fw.event.register("playerJoin", (player) => {
// do something
}, {
middlewares: {
executables: [...], // <- your middlewares here
onError: (msg) => void msg // <- error handling here
}
})
```
### unregister
Unregisters a server event, removing the associated callback
```ts
fw.event.unregister('playerJoin')
```
### trigger
Triggers registered server event. Formerly known as `call` or `emit`
```ts
fw.event.trigger('serverEventName', ['arg1', 2])
```
## Player
Handles event manipulations that require player to be present in context
### triggerClient
Triggers a client event from the server with arguments from shared types. Formerly known as `callClient` or `emitClient`
```ts
// without args
fw.player.triggerClient('clientEventName')
// with args
fw.player.triggerClient('clientEventName', ['message to client'])
```
### triggerBrowser
Triggers a browser event from the server with arguments from shared types. Formerly known as `callBrowser` or `emitBrowser`
```ts
// without args
fw.player.triggerBrowser('browserEventName')
// with args
fw.player.triggerBrowser('browserEventName', ['message to browser'])
```
## System
Handles functions used to interact with system environment
### Logger
Used to log to a client in-game console
#### info
Informational logs. Colored in white
```ts
fw.system.log.info('some information to be logged')
```
#### warn
Warning logs. Colored in yellow
```ts
fw.system.log.warn('warning message')
```
#### error
Error logs. Colored in red
```ts
fw.system.log.info('some error information')
```
### Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance

View File

@ -0,0 +1,24 @@
---
outline: [2, 4]
---
# Shared types <Badge type="tip" text="^0.2.0" />
Core element of type-safety in our framework system. It allows you to manually type any **custom** events you have in your server system.
There are three interfaces, which share between the system to apply types:
- `RageFW_ICustomClientEvent`
- `RageFW_ICustomServerEvent`
- `RageFW_ICustomBrowserEvent`
To apply types for events we use the following system and below is a sample how it applies them your code
```ts
customEventName(arg1: string, arg2: number): boolean
```
```ts
register('customEventName', async (arg1 /*string*/, arg2 /*number*/) => {
// your logic
return true /*Promise<boolean>*/
})
```

View File

@ -0,0 +1,108 @@
---
outline: [2, 4]
---
# Browser <Badge type="tip" text="^0.3.0" />
Package used on a browser-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-browser'
```
Only usable in Browser environment. For usage in [Server](./server) and [Client](./client) refer to their docs
## Declaration
```ts
fw = {
event: Browser,
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Browser
Browser-side interactions
### debugLogs
Setter. Enables console debug logs for events
```ts
fw.event.debugLogs = true
```
### customLogger
Setter. Enables console debug logs for events
```ts
fw.event.customLogger =
() =>
(method: string, eventName: string, ...args: unknown[]) => {
// log with desired formatting
}
```
### register
Registers a browser event with an associated callback
```ts
fw.event.register('showNotification', (message, color) => {
// do something
})
```
### unregister
Unregisters a browser event, removing the associated callback
```ts
fw.event.unregister('showNotification')
```
### trigger
Triggers a browser event from the browser with arguments from shared types. Formerly known as `call` or `emit`
```ts
// without args
fw.event.trigger('browserEventName')
// with args
fw.event.trigger('browserEventName', ['message to me'])
```
### triggerServer
Triggers a server event from the browser with arguments from shared types. Formerly known as `callServer` or `emitServer`
```ts
// without args
fw.event.triggerServer('serverEventName')
// with args
fw.event.triggerServer('serverEventName', ['message to server'])
```
### triggerClient
Triggers a client event from the browser with arguments from shared types. Formerly known as `callClient` or `emitClient`
```ts
// without args
fw.event.triggerClient('clientEventName')
// with args
fw.event.triggerClient('clientEventName', ['message to client'])
```
### Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance
#### `forceBrowserDevMode`?
`rage-fw-rpc` has a setting which enables it to be ran in browser dev mode without MP context ([see Rpc Config](/rage-fw-rpc/#rpc-config)). As `rage-fw-browser` does not expose Rpc constructor, you can use `.env` with `RageFW_forceBrowserDevMode=true` to enable it

View File

@ -0,0 +1,150 @@
---
outline: [2, 4]
---
# Client <Badge type="tip" text="^0.3.0" />
Package used on a client-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-client'
```
Only usable in client environment. For usage in [Server](./server) and [Browser](./browser) refer to their docs
## Declaration
```ts
fw = {
event: Client,
player: Player,
system: {
log: Logger
},
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Client
Client-side interactions
### register
Registers a client event with an associated callback
```ts
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
})
// Registering an event with middlewares
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
}, {
middlewares: [...] // <- your middlewares here
})
// or
fw.event.register("playerDeath", (player, reason, killer) => {
// do something
}, {
middlewares: {
executables: [...], // <- your middlewares here
onError: (msg) => void msg // <- error handling here
}
})
```
### unregister
Unregisters a client event, removing the associated callback
```ts
fw.event.unregister('playerDeath')
```
## Player
Handles event manipulations that require player to be present in context
### browser
Setter. Also shares browser with `rage-fw-rpc`
```ts
fw.player.browser = mp.browsers.new('package://index.html')
```
### trigger
Triggers registered client event with passed arguments. Formerly known as `call` or `emit`
```ts
// without args
fw.player.trigger('clientEventName')
// with args
fw.player.trigger('clientEventName', ['message to me'])
```
### triggerServer
Triggers a server event from the client with arguments from shared types. Formerly known as `callServer` or `emitServer`
```ts
// without args
fw.player.triggerServer('serverEventName')
// with args
fw.player.triggerServer('serverEventName', ['message to server'])
```
### triggerBrowser
Triggers a browser event from the client with arguments from shared types. Formerly known as `callBrowser` or `emitBrowser`
```ts
// without args
fw.player.triggerBrowser('browserEventName')
// with args
fw.player.triggerBrowser('browserEventName', ['message to browser'])
```
## System
Handles functions used to interact with the client environment
### Logger
Used to log to a client in-game console
### info
Informational logs. Colored in white
```ts
fw.system.log.info('some information to be logged')
```
### warn
Warning logs. Colored in yellow
```ts
fw.system.log.warn('warning message')
```
### error
Error logs. Colored in red
```ts
fw.system.log.info('some error information')
```
## Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance

View File

@ -0,0 +1,92 @@
---
outline: [2, 4]
---
# Features <Badge type="tip" text="^0.3.0" />
## Event Middlewares
Rage FW offers you to add middlewares when registering events in Client and Server environments, to check if callback should be executed or should not. Core class functionality is not exposed to user, but some types are for easier code managing. Here are some key points (in context of Server environment, but also applicable to Client)
### Declaration
```ts
register(
eventName,
callback,
options?: {
middlewares?: RageFW_MiddlewareOptions
},
)
type RageFW_MiddlewareOptions =
| RageFW_MiddlewareFunction[]
| {
executables: RageFW_MiddlewareFunction[]
onError: (error: string) => unknown
}
type RageFW_MiddlewareFunction = (...args: T.RageFW_ServerArgs) =>
Promise<RageFW_MiddlewareResponse>
type RageFW_MiddlewareResponse =
| {
success: boolean
message?: string
}
| boolean
```
### Usage
`RageFW_MiddlewareFunction` can be imported to type your middlewares, eg.:
```ts
import { type RageFW_MiddlewareFunction } from '@entityseven/rage-fw-server'
const isPlayerAdmin: RageFW_MiddlewareFunction<'yourEventName'> = async (
player,
...args
) => {
if (player.adminLvl >= 2) {
return true
} else {
return {
success: false,
message: 'You must have administrator rights for this action'
}
}
}
// or function-like if you want to omit some argument types or hoisting is required
async function isPlayerAdmin(
player: PlayerMp,
...args
): ReturnType<RageFW_MiddlewareFunction<'yourEventName'>> {
if (player.adminLvl >= 2) {
return true
} else {
return {
success: false,
message: 'You must have administrator rights for this action'
}
}
}
fw.event.register(
'yourEventName',
async (player, ...args) => {
// do an action which requires administrator rights
},
{
middlewares: {
executables: [isPlayerAdmin],
onError: (e) => {} // notify player about missing permissions
}
}
)
```
### Implementation TL;DR (why no next()?)
Unfortunately in Client-side of Rage:MP every thrown `Error` or `Promise.reject` is not `catch`able, meaning a naughty error window will pop-up on player's screen. Due to this implementation variant we were forced to not throw `Errors` from middlewares and just return middleware result. Server-side can handle errors, but to keep everything consistent we stick up to this variant

View File

@ -0,0 +1,59 @@
---
description: RageFW is a ty1pe-safe framework for developing Rage:MP servers
prev: false
next: false
outline: [2, 4]
---
# Rage Framework (RageFW) <Badge type="tip" text="^0.3.0" />
RageFW is a type-safe framework for developing Rage:MP servers. Designed with developers in mind, RageFW brings structure and efficiency to your Rage:MP servers, ensuring robust and maintainable code
## Features
- **Type-Safe Development:** Eliminate runtime errors and enhance code reliability with RageFW comprehensive type safety, making your RP server's development smoother than a Sunday drive through Los Santos
- **Wrapped RPC client:** Communicate effortlessly between server, client and cef with RPC system, wrapped in a cozy custom-typed blanket for your peace of mind
- **Logging System:** Keep track of server activities and debug like a pro with our built-in, feature-rich logging system. After all, even virtual cops need evidence
## Getting Started
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/)
You can find out more about our CLI [here](/rage-fw-cli/)
```shell
pnpm create @entityseven/rage-fw@latest
```
```shell
bun create @entityseven/rage-fw@latest
```
This will give you a few options, among them, you can find `Initialize new project`. Use that option to scaffold a new project for yourself using the preferred frontend framework
## Documentation
RageFW distibutes under a list of packages:
- [`@entityseven/rage-fw-server`](./server) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-server)
- [`@entityseven/rage-fw-client`](./client) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-client)
- [`@entityseven/rage-fw-browser`](./browser) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-browser)
- [`@entityseven/rage-fw-shared-types`](./shared-types) [npmjs.com](https://www.npmjs.com/package/@entityseven/rage-fw-shared-types)
These are setup as-should if you are using our CLI, if you still want to setup yourself, please refer to [examples](https://git.entityseven.com/entityseven/rage-framework-example)
## Contributing
Join our community of developers and contribute to the ongoing development of RageFW. At the moment the only way to contribute is opening issues
## Support
Need help? Reach out via our community forums or contact us directly through our support channels. We're committed to help you as we can
## License
Licensed under **Custom Attribution-NoDerives Software License**
> _RageFW - because in the world of GTA:RP, nobody has time for type errors_

View File

@ -0,0 +1,139 @@
---
outline: [2, 4]
---
# Server <Badge type="tip" text="^0.3.0" />
Package used on a server-side of your Rage:MP Server
## Usage
```ts
import { fw } from '@entityseven/rage-fw-server'
```
Only usable in server environment. For usage in [Client](./client) and [Browser](./browser) refer to their sections
## Declaration
```ts
fw = {
event: Server,
player: Player,
system: {
log: Logger
},
rpc: Rpc
}
```
Further documentation will describe the fields included in `fw`
## Server
Server-side interactions
### register
Registers a server event with an associated callback
```ts
fw.event.register("playerJoin", (player) => {
// do something
})
// Registering an event with middlewares
fw.event.register("playerJoin", (player) => {
// do something
}, {
middlewares: [...] // <- your middlewares here
})
// or
fw.event.register("playerJoin", (player) => {
// do something
}, {
middlewares: {
executables: [...], // <- your middlewares here
onError: (msg) => void msg // <- error handling here
}
})
```
### unregister
Unregisters a server event, removing the associated callback
```ts
fw.event.unregister('playerJoin')
```
### trigger
Triggers registered server event. Formerly known as `call` or `emit`
```ts
fw.event.trigger('serverEventName', ['arg1', 2])
```
## Player
Handles event manipulations that require player to be present in context
### triggerClient
Triggers a client event from the server with arguments from shared types. Formerly known as `callClient` or `emitClient`
```ts
// without args
fw.player.triggerClient('clientEventName')
// with args
fw.player.triggerClient('clientEventName', ['message to client'])
```
### triggerBrowser
Triggers a browser event from the server with arguments from shared types. Formerly known as `callBrowser` or `emitBrowser`
```ts
// without args
fw.player.triggerBrowser('browserEventName')
// with args
fw.player.triggerBrowser('browserEventName', ['message to browser'])
```
## System
Handles functions used to interact with system environment
### Logger
Used to log to a client in-game console
#### info
Informational logs. Colored in white
```ts
fw.system.log.info('some information to be logged')
```
#### warn
Warning logs. Colored in yellow
```ts
fw.system.log.warn('warning message')
```
#### error
Error logs. Colored in red
```ts
fw.system.log.info('some error information')
```
### Rpc
`rage-fw-rpc` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance

View File

@ -0,0 +1,24 @@
---
outline: [2, 4]
---
# Shared types <Badge type="tip" text="^0.3.0" />
Core element of type-safety in our framework system. It allows you to manually type any **custom** events you have in your server system.
There are three interfaces, which share between the system to apply types:
- `RageFW_ICustomClientEvent`
- `RageFW_ICustomServerEvent`
- `RageFW_ICustomBrowserEvent`
To apply types for events we use the following system and below is a sample how it applies them your code
```ts
customEventName(arg1: string, arg2: number): boolean
```
```ts
register('customEventName', async (arg1 /*string*/, arg2 /*number*/) => {
// your logic
return true /*Promise<boolean>*/
})
```

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

@ -0,0 +1,8 @@
---
description: RageFW is a type-safe framework for developing Rage:MP servers
prev: false
next: false
outline: [2, 4]
---
<!--@include: ./0.3.0/index.md-->

View File

@ -1,5 +1,7 @@
<!-- #region installation --> <!-- #region installation -->
::: code-group ::: code-group
```ts twoslash [lib/rpc.ts] ```ts twoslash [lib/rpc.ts]
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts // @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
@ -7,11 +9,15 @@
import { Rpc } from '@entityseven/rage-fw-rpc' import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc(/* options */) export const rpc = new Rpc(/* options */)
``` ```
::: :::
<!-- #endregion installation --> <!-- #endregion installation -->
<!-- #region installationClient --> <!-- #region installationClient -->
::: code-group ::: code-group
```ts twoslash [client/index.ts] ```ts twoslash [client/index.ts]
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts // @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
@ -20,10 +26,13 @@ import { Rpc } from '@entityseven/rage-fw-rpc'
export const rpc = new Rpc(/* options */) export const rpc = new Rpc(/* options */)
rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html') rpc.browser = mp.browsers.new('package://path-to-your-cef-assets/index.html')
``` ```
::: :::
<!-- #endregion installationClient --> <!-- #endregion installationClient -->
<!-- #region syntax --> <!-- #region syntax -->
```ts twoslash ```ts twoslash
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -46,9 +55,11 @@ rpc.register('event', (player: PlayerMp, argument1: number, argument2: number) =
rpc.callServer('event', [2, 3]) // [!code --] rpc.callServer('event', [2, 3]) // [!code --]
rpc.callServer<[number[]]>('event', [[2, 3]]) // [!code ++] rpc.callServer<[number[]]>('event', [[2, 3]]) // [!code ++]
``` ```
<!-- #endregion syntax --> <!-- #endregion syntax -->
<!-- #region rpcConfig --> <!-- #region rpcConfig -->
```ts twoslash ```ts twoslash
// @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts // @filename: node_modules/@types/@entityseven/rage-fw-rpc/index.d.ts
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
@ -59,15 +70,19 @@ export const rpc = new Rpc({
debugLogs: true debugLogs: true
}) })
``` ```
<!-- #endregion rpcConfig --> <!-- #endregion rpcConfig -->
<!-- #region register --> <!-- #region register -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.register('playerJoin', (player: PlayerMp) => { rpc.register('playerJoin', (player: PlayerMp) => {
console.log(`Connected: ${player.socialClub}`) console.log(`Connected: ${player.socialClub}`)
}) })
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -77,31 +92,42 @@ rpc.register<
console.log(`Connected: ${player.socialClub}`) console.log(`Connected: ${player.socialClub}`)
}) })
``` ```
::: :::
<!-- #endregion register --> <!-- #endregion register -->
<!-- #region unregister --> <!-- #region unregister -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.unregister('playerJoin') rpc.unregister('playerJoin')
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
rpc.unregister<ServerEventNames>('playerJoin') rpc.unregister<ServerEventNames>('playerJoin')
``` ```
::: :::
<!-- #endregion unregister --> <!-- #endregion unregister -->
<!-- #region callClient --> <!-- #region callClient -->
::: code-group ::: code-group
```ts [Simple (browser)] ```ts [Simple (browser)]
rpc.callClient('updatePlayerData', ['argument']) rpc.callClient('updatePlayerData', ['argument'])
``` ```
```ts [Simple (server)] ```ts [Simple (server)]
const player = {} satisfies PlayerMp const player = {} satisfies PlayerMp
rpc.callClient(player, 'updatePlayerData', ['argument']) rpc.callClient(player, 'updatePlayerData', ['argument'])
``` ```
```ts twoslash [With types (browser)] ```ts twoslash [With types (browser)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -109,6 +135,7 @@ rpc.callClient<
[string], ClientEventNames [string], ClientEventNames
>('updatePlayerData', ['argument']) >('updatePlayerData', ['argument'])
``` ```
```ts twoslash [With types (server)] ```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -117,24 +144,30 @@ rpc.callClient<
[string], ClientEventNames [string], ClientEventNames
>(player, 'updatePlayerData', ['argument']) >(player, 'updatePlayerData', ['argument'])
``` ```
::: :::
<!-- #endregion callClient --> <!-- #endregion callClient -->
<!-- #region callClientAsync --> <!-- #region callClientAsync -->
::: code-group ::: code-group
```ts [Simple (browser)] ```ts [Simple (browser)]
rpc.callClientAsync('updatePlayerData', ['argument']) rpc.callClientAsync('updatePlayerData', ['argument']).then((response) => {
.then(response => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts [Simple (server)] ```ts [Simple (server)]
const player = {} satisfies PlayerMp const player = {} satisfies PlayerMp
rpc.callClientAsync(player, 'updatePlayerData', ['argument']) rpc
.then(response => { .callClientAsync(player, 'updatePlayerData', ['argument'])
.then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types (browser)] ```ts twoslash [With types (browser)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -145,6 +178,7 @@ rpc.callClientAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types (server)] ```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -156,14 +190,19 @@ rpc.callClientAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
::: :::
<!-- #endregion callClientAsync --> <!-- #endregion callClientAsync -->
<!-- #region callServer --> <!-- #region callServer -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.callServer('updatePlayerData', ['argument']) rpc.callServer('updatePlayerData', ['argument'])
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -171,17 +210,21 @@ rpc.callServer<
[string], ServerEventNames [string], ServerEventNames
>('updatePlayerData', ['argument']) >('updatePlayerData', ['argument'])
``` ```
::: :::
<!-- #endregion callServer --> <!-- #endregion callServer -->
<!-- #region callServerAsync --> <!-- #region callServerAsync -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.callServerAsync('updatePlayerData', ['argument']) rpc.callServerAsync('updatePlayerData', ['argument']).then((response) => {
.then(response => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -192,18 +235,24 @@ rpc.callServerAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
::: :::
<!-- #endregion callServerAsync --> <!-- #endregion callServerAsync -->
<!-- #region callBrowser --> <!-- #region callBrowser -->
::: code-group ::: code-group
```ts [Simple (client)] ```ts [Simple (client)]
rpc.callBrowser('updatePlayerData', ['argument']) rpc.callBrowser('updatePlayerData', ['argument'])
``` ```
```ts [Simple (server)] ```ts [Simple (server)]
const player = {} satisfies PlayerMp const player = {} satisfies PlayerMp
rpc.callBrowser('updatePlayerData', ['argument']) rpc.callBrowser('updatePlayerData', ['argument'])
``` ```
```ts twoslash [With types (client)] ```ts twoslash [With types (client)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -211,6 +260,7 @@ rpc.callBrowser<
[string], BrowserEventNames [string], BrowserEventNames
>('updatePlayerData', ['argument']) >('updatePlayerData', ['argument'])
``` ```
```ts twoslash [With types (server)] ```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -219,22 +269,28 @@ rpc.callBrowser<
[string], BrowserEventNames [string], BrowserEventNames
>(player, 'updatePlayerData', ['argument']) >(player, 'updatePlayerData', ['argument'])
``` ```
::: :::
<!-- #endregion callBrowser --> <!-- #endregion callBrowser -->
<!-- #region callBrowserAsync --> <!-- #region callBrowserAsync -->
::: code-group ::: code-group
```ts [Simple (client)] ```ts [Simple (client)]
rpc.callBrowserAsync('updatePlayerData', ['argument']).then(response => { rpc.callBrowserAsync('updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts [Simple (server)] ```ts [Simple (server)]
const player = {} satisfies PlayerMp const player = {} satisfies PlayerMp
rpc.callBrowserAsync('updatePlayerData', ['argument']).then(response => { rpc.callBrowserAsync('updatePlayerData', ['argument']).then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types (client)] ```ts twoslash [With types (client)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -245,6 +301,7 @@ rpc.callBrowserAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types (server)] ```ts twoslash [With types (server)]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -256,29 +313,39 @@ rpc.callBrowserAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
::: :::
<!-- #endregion callBrowserAsync --> <!-- #endregion callBrowserAsync -->
<!-- #region call --> <!-- #region call -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.call('triggerSomething') rpc.call('triggerSomething')
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
rpc.call<never, ClientEventNames>('triggerSomething') rpc.call<never, ClientEventNames>('triggerSomething')
``` ```
::: :::
<!-- #endregion call --> <!-- #endregion call -->
<!-- #region callAsync --> <!-- #region callAsync -->
::: code-group ::: code-group
```ts [Simple] ```ts [Simple]
rpc.callAsync('triggerSomething').then(response => { rpc.callAsync('triggerSomething').then((response) => {
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
```ts twoslash [With types] ```ts twoslash [With types]
<!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md--> <!--@include: @/snippets/rage-fw-rpc/0.3.0/declaration.md-->
// ---cut--- // ---cut---
@ -289,5 +356,7 @@ rpc.callAsync<
console.log(`Received: ${response}`) console.log(`Received: ${response}`)
}) })
``` ```
::: :::
<!-- #endregion callAsync --> <!-- #endregion callAsync -->

View File

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

View File

@ -5,6 +5,7 @@
"devDependencies": { "devDependencies": {
"@shikijs/vitepress-twoslash": "^2.3.0", "@shikijs/vitepress-twoslash": "^2.3.0",
"@types/bun": "latest", "@types/bun": "latest",
"prettier": "^3.4.2",
"vitepress": "^1.6.3" "vitepress": "^1.6.3"
}, },
"peerDependencies": { "peerDependencies": {
@ -13,7 +14,8 @@
"scripts": { "scripts": {
"docs:dev": "vitepress dev docs", "docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs", "docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs" "docs:preview": "vitepress preview docs",
"format": "prettier docs/snippets \"!**/declaration.*\" --write"
}, },
"dependencies": { "dependencies": {
"vitepress-versioning-plugin": "^1.3.0" "vitepress-versioning-plugin": "^1.3.0"

View File

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