4 Commits
Author SHA1 Message Date
rilaxik 3f7311ba17 readme wip 2025-07-16 20:41:35 +01:00
rilaxik 00b8edc16b docs 2025-07-09 16:07:02 +01:00
rilaxik 91a72c46e8 docs 2025-07-09 00:36:26 +01:00
rilaxik 8a361f67ec cleanup + better descriptions 2025-07-08 23:52:42 +01:00
6 changed files with 511 additions and 5 deletions
+41
View File
@@ -0,0 +1,41 @@
# FiveM RPC
is an all-in-one package with asynchronous RPC implementation for FiveM servers in JS/TS
## Installation
```bash
pnpm i @entityseven/fivem-rpc
```
```bash
yarn add @entityseven/fivem-rpc
```
```bash
bun add @entityseven/fivem-rpc
```
It is highly recommended to also install additional package for enhanced typing
```bash
pnpm i @entityseven/fivem-rpc-shared-types -D
```
```bash
yarn add @entityseven/fivem-rpc-shared-types --dev
```
```bash
bun add @entityseven/fivem-rpc-shared-types -d
```
## Docs
Can be found in [/rpc/readme.md](https://github.com/rilaxik/fivem-rpc/blob/master/rpc/readme.md)
## Features
- Type-Safe Development: Eliminate runtime errors and enhance code reliability with comprehensive type safety
- All-in-one package: Communicate effortlessly between server, client and webview
## Contributing
Issues and pull requests are very welcome
## License
Licensed under Custom Attribution-NoDerivs Software License
## WIP
- client observers to catch events between server and webview (subscribe-like behaviour)
- client observers to prevent events (middleware-like behaviour)
- player manager (transform player id to desired data straight from a listener)
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@entityseven/fivem-rpc",
"description": "FiveM RPC is an abstraction for handling events in GTA V FiveM servers in JS/TS",
"description": "FiveM RPC is an all-in-one package with asynchronous RPC implementation for FiveM servers in JS/TS",
"version": "0.1.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+300
View File
@@ -0,0 +1,300 @@
# FiveM RPC
is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS. [Extra info](https://github.com/rilaxik/fivem-rpc/blob/master/readme.md)
# Motivation
The idea was to create an extensible package, with various features to simplify the development process and provide as much comfort as possible. Inspired by usage of [altv-xrpc](https://github.com/xxshady/altv-xrpc)
# Installation
```bash
pnpm i @entityseven/fivem-rpc
```
```bash
yarn add @entityseven/fivem-rpc
```
```bash
bun add @entityseven/fivem-rpc
```
It is highly recommended to also install additional package for enhanced typing
```bash
pnpm i @entityseven/fivem-rpc-shared-types -D
```
```bash
yarn add @entityseven/fivem-rpc-shared-types --dev
```
```bash
bun add @entityseven/fivem-rpc-shared-types -d
```
## Usage
FiveM RPC is meant to be a singletone per environment. This means you _must create only one_ `RPCFactory` per your server/client/web. This also enables modifying `const rpc` to your needs, adding new methods or variables by forcing you to import it from file instead of library reference
```ts
// lib/rpc.ts
import { RPCFactory } from '@entityseven/fivem-rpc'
export const rpc = new RPCFactory(/* options */).get()
```
# Docs
## Extras
Along with `RPCFactory` you can also import all the types used internally, types for native client/server events and lists of native client/server events. All of that is documented in JSDoc, so no need to duplicate it here
## RPCConfig
```ts
type RPCConfig<T extends RPCEnvironment | unknown> = {
env: T
debug?: boolean
}
```
Failing to set `env` to provided type will result in `RPCErrors.UNKNOWN_ENVIRONMENT`
`debug` adds additional console logs to events
## Errors
Known errors could be one of following or an error throw by a callback specifically
```ts
enum RPCErrors {
EVENT_NOT_REGISTERED = 'Event not registered',
INVALID_DATA = 'Invalid data (possibly broken JSON)',
NO_PLAYER = 'No player (failed to resolve from local index)',
UNKNOWN_NATIVE = 'Unknown native event (if you are sure this exists - use native handler)',
UNKNOWN_ENVIRONMENT = 'Unknown environment (must be either "server", "client" or "webview")',
}
```
### Example error
Values wrapped in `<>` always exist, just not relevant for an example. Keep in mind that some errors are thrown in their destination(`To`) point: this example will throw on server
```
Error: No player (failed to resolve from local index)
Event: 'clientServerEvent'
Uuid: <uuid>
From: 'client'
To: 'server'
Player: <non-existent-player>
Type: 'event'
Data: [<data>]
```
## Server ([source](https://github.com/rilaxik/fivem-rpc/blob/master/rpc/src/core/server.ts))
### onClient
Listens to client event
```ts
rpc.onClient('clientServerEvent', (player, arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offClient
Stops listening to client event
```ts
rpc.offClient('clientServerEvent')
```
### emitClient
Sends event to specified client
```ts
const response = await rpc.emitClient(playerServerId, 'serverClientEvent', someData)
// response will come from client listener with returned data
```
### emitClientEveryone
Sends event to all clients
```ts
rpc.emitClientEveryone('serverClientEvent', someData)
```
### onWebview
Listens to webview event
```ts
rpc.onWebview('webviewServerEvent', (player, arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offWebview
Stops listening to webview event
```ts
rpc.offWebview('webviewServerEvent')
```
### emitWebview
Sends event to specified webview
```ts
const response = await rpc.emitWebview(playerServerId, 'serverWebviewEvent', someData)
// response will come from webview listener with returned data
```
### onSelf
Listens to server event
```ts
rpc.onSelf('serverEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offSelf
Stops listening to server event
```ts
rpc.offSelf('serverEvent')
```
### emitSelf
Sends event to server
```ts
const response = await rpc.emitSelf('serverEvent', someData)
// response will come from server listener with returned data
```
### onCommand
Registers chat command. Since arguments are untyped you must validate them yourself
```ts
rpc.onCommand('serverCommand', (player, args, commandRaw) => {
// logic
})
```
### onNativeEvent
Listens to native server event ([reference](https://docs.fivem.net/docs/scripting-reference/events/server-events/))
```ts
rpc.onNativeEvent('playerJoining', (source, oldId) => {
// logic
})
```
## Client ([source](https://github.com/rilaxik/fivem-rpc/blob/master/rpc/src/core/client.ts))
### onServer
Listens to server event
```ts
rpc.onServer('serverClientEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offServer
Stops listening to server event
```ts
rpc.offServer('serverClientEvent')
```
### emitServer
Sends event to server
```ts
const response = await rpc.emitServer('clientServerEvent', someData)
// response will come from webview listener with returned data
```
### onWebview
Listens to webview event
```ts
rpc.onWebview('webviewClientEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offWebview
Stops listening to webview event
```ts
rpc.offWebview('webviewClientEvent')
```
### emitWebview
Sends event to specified webview
```ts
const response = await rpc.emitWebview('clientWebviewEvent', someData)
// response will come from webview listener with returned data
```
### onSelf
Listens to client event
```ts
rpc.onSelf('clientEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offSelf
Stops listening to client event
```ts
rpc.offSelf('clientEvent')
```
### emitSelf
Sends event to client
```ts
const response = await rpc.emitSelf('clientEvent', someData)
// response will come from client listener with returned data
```
### onCommand
Registers chat command. Since arguments are untyped you must validate them yourself
```ts
rpc.onCommand('clientCommand', (player, args, commandRaw) => {
// logic
})
```
### onNativeEvent
Listens to native client event ([reference](https://docs.fivem.net/docs/scripting-reference/events/client-events/))
```ts
rpc.onNativeEvent('entityDamaged', (victim, culprit, weapon, baseDamage) => {
// logic
})
```
### onNativeNetworkEvent
Listens to native client network event ([reference](https://docs.fivem.net/docs/game-references/game-events/))
```ts
rpc.onNativeNetworkEvent('CEventShockingCarCrash', (entities, eventEntity, data) => {
// logic
})
```
### setWebviewFocus
Sets or removes focus and cursor from own webview
```ts
rpc.setWebviewFocus(true /* focus */, true /* show cursor */)
```
## Webview ([source](https://github.com/rilaxik/fivem-rpc/blob/master/rpc/src/core/webview.ts))
### onClient
Listens to client event
```ts
rpc.onClient('clientWebviewEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offClient
Stops listening to client event
```ts
rpc.offClient('clientWebviewEvent')
```
### emitClient
Sends event to own client
```ts
const response = await rpc.emitClient('webviewClientEvent', someData)
// response will come from client listener with returned data
```
### onServer
Listens to server event
```ts
rpc.onServer('serverWebviewEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offServer
Stops listening to server event
```ts
rpc.offServer('serverWebviewEvent')
```
### emitServer
Sends event to server
```ts
const response = await rpc.emitServer('webviewServerEvent', someData)
// response will come from webview listener with returned data
```
### onSelf
Listens to webview event
```ts
rpc.onSelf('webviewEvent', (arg1, arg2, ...rest) => {
// logic
return someData // this will be forwarded back to caller
})
```
### offSelf
Stops listening to webview event
```ts
rpc.offSelf('webviewEvent')
```
### emitSelf
Sends event to webview
```ts
const response = await rpc.emitSelf('webviewEvent', someData)
// response will come from webview listener with returned data
```
# License
Licensed under Custom Attribution-NoDerivs Software License
-3
View File
@@ -64,9 +64,6 @@ class RPCFactory<T extends RPCEnvironment> extends Wrapper {
}
export { RPCFactory }
// export const rpcClient = new RPCFactory({ env: "client" }).get();
// export const rpcServer = new RPCFactory({ env: "server" }).get();
// export const rpcWebview = new RPCFactory({ env: "webview" }).get();
export * from './utils/types'
export * from './utils/native'
export type * from './core/server'
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@entityseven/fivem-rpc-shared-types",
"description": "Shared types for @entityseven/fivem-rpc. Highly recommended to install together",
"description": "Shared (enhanced) types for @entityseven/fivem-rpc. Highly recommended to install together",
"version": "0.1.0",
"types": "types/types/index.d.ts",
"files": [
+168
View File
@@ -0,0 +1,168 @@
# FiveM RPC Shared Types
### [Docs & Info](https://github.com/rilaxik/fivem-rpc/blob/master/readme.md)
## Installation
```bash
pnpm i @entityseven/fivem-rpc-shared-types -D
```
```bash
yarn add @entityseven/fivem-rpc-shared-types --dev
```
```bash
bun add @entityseven/fivem-rpc-shared-types -d
```
## Usage
This package is an enhanced type support for `@entityseven/fivem-rpc`. It provides ability to strictly type your events for better dx.
## Example
This example is neat way to follow up but you can change it as you wish. It will use bun workspaces, pnpm workspaces work in a similar manner. Referring the following folder structure:
```markdown
apps/
- server/
- package.json
- tsconfig.json
- client/
- package.json
- tsconfig.json
- webview/
- package.json
- tsconfig.json
- shared/ (this must be available in server, client and webview)
- package.json
- package.json (root package)
- pnpm-workspace.yaml (only if using pnpm)
```
- Environment folder: folder with server, client or webview code in it
1. Install this package as dev dependency in your root package or in each environment folder separately
```markdown
apps/
- server/ <- (if not installed root)
- client/ <- (if not installed root)
- webview/ <- (if not installed root)
- shared/
- package.json <- here
```
2. In `shared/` create folder `fivem-rpc` (or similar), inside it create `index.d.ts`
```markdown
apps/
- server/
- client/
- webview/
- shared/
- fivem-rpc/
- index.d.ts <- here
- package.json
```
3. In `index.d.ts` add following:
```ts
declare module '@entityseven/fivem-rpc-shared-types' {
// Client commands names
export type RPCCommands_Client = ''
// Server commands names
export type RPCCommands_Server = ''
// Client -> Client events
export interface RPCEvents_Client {}
// Client -> Server events
export interface RPCEvents_ClientServer {}
// Client -> Webview events
export interface RPCEvents_ClientWebview {}
// Server -> Server events
export interface RPCEvents_Server {}
// Server -> Client events
export interface RPCEvents_ServerClient {}
// Server -> Server events
export interface RPCEvents_ServerWebview {}
// Webview -> Webview events
export interface RPCEvents_Webview {}
// Webview -> Client events
export interface RPCEvents_WebviewClient {}
// Webview -> Server events
export interface RPCEvents_WebviewServer {}
}
```
4. We just created a declaration which will overwrite types from the package. Now we need our packages to refer to these types when linting `rpc` functions. To do this in each environment folder of your project in `tsconfig.json` do these:
```json5
{
"compilerOptions": {
"types": [
"../shared/fivem-rpc/" // or your specific folder
]
}
}
```
5. We also need to populate interfaces we created in step 3.
- `RPCCommands_Client` and `RPCCommands_Server` will include your commands names an union strings:
```ts
export type RPCCommands_Client = 'afk' | 'vanish' | '...' // example names
export type RPCCommands_Server = 'report' | 'ban' | '...' // example names
```
- Other interfaces will include your events types. The example will show one but all of the work same way
```ts
export interface RPCEvents_ClientServer {
clientToServerEventName(data: string, moreData: boolean): number
"client-to-server-event-name"(data: string, moreData: boolean): number // can also include characters you cannot use as variable or function names
}
```
- `clientToServerEventName` or `client-to-server-event-name` is an event name
- `data` and `moreData` are the arguments you need to pass when calling an event and argument you will receive when listening (may also include extra, as player, check type hints)
- `number` is a return type that will be forwarded back to caller
Doing this will create type hints for you:
```ts
// assuming this is in client
const response /* number */ = await rpc.emitServer(
'clientToServerEventName', /* suggested name */
'data', /* will pass typecheck */
'moreData', /* will NOT pass typecheck, since required type is `boolean` */
)
```
## Example (alternative)
If previous example does not work or you do not like you can also try it this way. Steps that are not mentioned are the same as previous
2. In `shared/` create folders `declarations/fivem-rpc`, inside it create `index.d.ts`
```markdown
apps/
- server/
- client/
- webview/
- shared/
- declarations/
- fivem-rpc/
- index.d.ts <- here
- package.json
```
4. We just created a declaration which will overwrite types from the package. Now we need our packages to refer to these types when linting `rpc` functions. To do this in each environment folder of your project in `tsconfig.json` do these:
```json5
{
"compilerOptions": {
"typeRoots": [
"../shared/declarations/", // or your specific folder
"../../node_modules/@types", // you may also want to add this if some of your other libraries are not showing types now
]
}
}
```
If a any point this stops working for you, do your research on how to redeclare library types and refer to it