@open-core/ragemp-adapter 0.1.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/.tsbuildinfo/client.tsbuildinfo +1 -1
  2. package/dist/.tsbuildinfo/root.tsbuildinfo +1 -1
  3. package/dist/.tsbuildinfo/server.tsbuildinfo +1 -1
  4. package/dist/.tsbuildinfo/shared.tsbuildinfo +1 -1
  5. package/dist/client/create-ragemp-client-adapter.js +10 -3
  6. package/dist/client/native-chat.d.ts +10 -0
  7. package/dist/client/native-chat.js +69 -6
  8. package/dist/client/ragemp-camera-port.d.ts +19 -0
  9. package/dist/client/ragemp-camera-port.js +72 -0
  10. package/dist/client/ragemp-local-player-bridge.d.ts +3 -0
  11. package/dist/client/ragemp-local-player-bridge.js +10 -0
  12. package/dist/client/ragemp-ped-port.d.ts +23 -0
  13. package/dist/client/ragemp-ped-port.js +107 -0
  14. package/dist/client/ragemp-platform-bridge.js +1 -1
  15. package/dist/client/ragemp-progress-port.d.ts +21 -0
  16. package/dist/client/ragemp-progress-port.js +169 -0
  17. package/dist/client/ragemp-runtime-bridge.d.ts +2 -4
  18. package/dist/client/ragemp-runtime-bridge.js +3 -0
  19. package/dist/client/ragemp-spawn-bridge.d.ts +4 -4
  20. package/dist/client/ragemp-spawn-bridge.js +5 -3
  21. package/dist/client/ragemp-vehicle-port.d.ts +34 -0
  22. package/dist/client/ragemp-vehicle-port.js +272 -0
  23. package/dist/client/ragemp-webview-bridge.d.ts +5 -0
  24. package/dist/client/ragemp-webview-bridge.js +54 -12
  25. package/dist/server/ragemp-engine-events.d.ts +2 -5
  26. package/dist/server/ragemp-engine-events.js +3 -15
  27. package/dist/server/ragemp-entity-server.js +14 -1
  28. package/dist/server/ragemp-exports.d.ts +51 -0
  29. package/dist/server/ragemp-exports.js +202 -1
  30. package/dist/server/ragemp-player-appearance-lifecycle-server.js +4 -3
  31. package/dist/server/ragemp-resourceinfo.js +3 -0
  32. package/dist/shared/exports-registry.d.ts +2 -2
  33. package/dist/shared/transport/helpers.d.ts +3 -3
  34. package/dist/shared/transport/helpers.js +33 -7
  35. package/dist/shared/transport/ragemp.events.d.ts +3 -3
  36. package/dist/shared/transport/ragemp.events.js +4 -2
  37. package/dist/shared/transport/ragemp.rpc.d.ts +4 -8
  38. package/dist/shared/transport/ragemp.rpc.js +29 -5
  39. package/package.json +5 -7
@@ -16,17 +16,218 @@ exports.RageMPExports = void 0;
16
16
  const tsyringe_1 = require("tsyringe");
17
17
  const server_1 = require("@open-core/framework/contracts/server");
18
18
  const exports_registry_1 = require("../shared/exports-registry");
19
+ const REQUEST_EVENT_PREFIX = '__oc:exports:req:';
20
+ const RESPONSE_EVENT_PREFIX = '__oc:exports:res:';
21
+ const EXPORTS_TIMEOUT_MS = 7500;
22
+ const WAIT_INTERVAL_MS = 150;
23
+ const META_HAS_EXPORT = '__oc_meta_has_export__';
24
+ function isObjectRecord(value) {
25
+ return typeof value === 'object' && value !== null;
26
+ }
27
+ function isPlayerMpLike(value) {
28
+ return isObjectRecord(value) && 'id' in value && 'serial' in value;
29
+ }
30
+ function isExportRequestPayload(value) {
31
+ return (isObjectRecord(value) &&
32
+ typeof value.requestId === 'string' &&
33
+ typeof value.callerResource === 'string' &&
34
+ typeof value.exportName === 'string' &&
35
+ Array.isArray(value.args));
36
+ }
37
+ function isExportResponsePayload(value) {
38
+ if (!isObjectRecord(value) ||
39
+ typeof value.requestId !== 'string' ||
40
+ typeof value.ok !== 'boolean') {
41
+ return false;
42
+ }
43
+ if (value.ok) {
44
+ return true;
45
+ }
46
+ return (isObjectRecord(value.error) &&
47
+ typeof value.error.name === 'string' &&
48
+ typeof value.error.message === 'string');
49
+ }
19
50
  let RageMPExports = class RageMPExports extends server_1.IExports {
20
51
  constructor(resourceInfo) {
21
52
  super();
22
53
  this.resourceInfo = resourceInfo;
54
+ this.pendingRequests = new Map();
55
+ this.localHandlers = new Map();
56
+ this.currentResourceName = this.resourceInfo.getCurrentResourceName();
57
+ this.requestEventName = `${REQUEST_EVENT_PREFIX}${this.currentResourceName}`;
58
+ this.responseEventName = `${RESPONSE_EVENT_PREFIX}${this.currentResourceName}`;
59
+ this.registerTransportListeners();
23
60
  }
24
61
  register(exportName, handler) {
25
- exports_registry_1.exportsRegistry.register(this.resourceInfo.getCurrentResourceName(), exportName, handler);
62
+ this.localHandlers.set(exportName, handler);
63
+ exports_registry_1.exportsRegistry.register(this.currentResourceName, exportName, handler);
26
64
  }
65
+ /**
66
+ * Resolves exports through the local registry shared by the current adapter runtime.
67
+ */
27
68
  getResource(resourceName) {
28
69
  return exports_registry_1.exportsRegistry.resourceProxy(resourceName);
29
70
  }
71
+ /**
72
+ * Returns an async proxy that forwards method calls to another server resource.
73
+ *
74
+ * @remarks
75
+ * The proxy intentionally ignores Promise-like properties (`then`, `catch`, `finally`)
76
+ * so `await` does not accidentally treat the proxy itself as a thenable.
77
+ */
78
+ getRemoteResource(resourceName) {
79
+ return new Proxy({}, {
80
+ get: (_, exportName) => {
81
+ if (typeof exportName !== 'string' ||
82
+ exportName === 'then' ||
83
+ exportName === 'catch' ||
84
+ exportName === 'finally') {
85
+ return undefined;
86
+ }
87
+ return (...args) => this.callRemoteExport(resourceName, exportName, ...args);
88
+ },
89
+ });
90
+ }
91
+ /**
92
+ * Invokes a remote export by sending a server-side RageMP event to the target resource.
93
+ */
94
+ callRemoteExport(resourceName, exportName, ...args) {
95
+ const requestId = this.createRequestId(resourceName, exportName);
96
+ const requestEventName = `${REQUEST_EVENT_PREFIX}${resourceName}`;
97
+ return new Promise((resolve, reject) => {
98
+ const timeout = setTimeout(() => {
99
+ this.pendingRequests.delete(requestId);
100
+ reject(new Error(`[exports] Timed out calling "${exportName}" on resource "${resourceName}".`));
101
+ }, EXPORTS_TIMEOUT_MS);
102
+ this.pendingRequests.set(requestId, { resolve, reject, timeout });
103
+ mp.events.call(requestEventName, {
104
+ requestId,
105
+ callerResource: this.currentResourceName,
106
+ exportName,
107
+ args,
108
+ });
109
+ });
110
+ }
111
+ /**
112
+ * Waits for a remote resource to expose a matching export before returning the async proxy.
113
+ */
114
+ async waitForRemoteResource(resourceName, options) {
115
+ const timeoutMs = options?.timeoutMs ?? EXPORTS_TIMEOUT_MS;
116
+ const intervalMs = options?.intervalMs ?? WAIT_INTERVAL_MS;
117
+ const startedAt = Date.now();
118
+ while (Date.now() - startedAt < timeoutMs) {
119
+ try {
120
+ const isAvailable = await this.callRemoteExport(resourceName, META_HAS_EXPORT, options?.exportName);
121
+ if (isAvailable) {
122
+ return this.getRemoteResource(resourceName);
123
+ }
124
+ }
125
+ catch {
126
+ // Ignore transient availability failures while waiting.
127
+ }
128
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
129
+ }
130
+ throw new Error(`[exports] Timed out waiting for resource "${resourceName}" remote exports.`);
131
+ }
132
+ /**
133
+ * Installs the request/response listeners used by the optional remote export helper layer.
134
+ *
135
+ * @remarks
136
+ * The listeners reject payloads that look like player-originated server events so clients
137
+ * cannot invoke server resource exports through this transport.
138
+ */
139
+ registerTransportListeners() {
140
+ mp.events.add(this.requestEventName, (...args) => {
141
+ const payload = args[0];
142
+ if (isPlayerMpLike(payload) || !isExportRequestPayload(payload)) {
143
+ return;
144
+ }
145
+ void this.handleExportRequest(payload);
146
+ });
147
+ mp.events.add(this.responseEventName, (...args) => {
148
+ const payload = args[0];
149
+ if (isPlayerMpLike(payload) || !isExportResponsePayload(payload)) {
150
+ return;
151
+ }
152
+ this.handleExportResponse(payload);
153
+ });
154
+ }
155
+ /**
156
+ * Executes one remote export request against handlers registered in the current resource.
157
+ */
158
+ async handleExportRequest(payload) {
159
+ const responseEventName = `${RESPONSE_EVENT_PREFIX}${payload.callerResource}`;
160
+ try {
161
+ const result = await this.executeLocalExport(payload.exportName, payload.args);
162
+ mp.events.call(responseEventName, {
163
+ requestId: payload.requestId,
164
+ ok: true,
165
+ result,
166
+ });
167
+ }
168
+ catch (error) {
169
+ mp.events.call(responseEventName, {
170
+ requestId: payload.requestId,
171
+ ok: false,
172
+ error: this.serializeError(error),
173
+ });
174
+ }
175
+ }
176
+ /**
177
+ * Resolves or rejects the pending promise associated with a remote export response.
178
+ */
179
+ handleExportResponse(payload) {
180
+ const pendingRequest = this.pendingRequests.get(payload.requestId);
181
+ if (!pendingRequest) {
182
+ return;
183
+ }
184
+ clearTimeout(pendingRequest.timeout);
185
+ this.pendingRequests.delete(payload.requestId);
186
+ if (payload.ok) {
187
+ pendingRequest.resolve(payload.result);
188
+ return;
189
+ }
190
+ pendingRequest.reject(this.deserializeError(payload.error));
191
+ }
192
+ /**
193
+ * Executes an export from the current resource without going back through the shared registry.
194
+ */
195
+ async executeLocalExport(exportName, args) {
196
+ if (exportName === META_HAS_EXPORT) {
197
+ const requestedExportName = typeof args[0] === 'string' ? args[0] : undefined;
198
+ if (!requestedExportName) {
199
+ return this.localHandlers.size > 0;
200
+ }
201
+ return this.localHandlers.has(requestedExportName);
202
+ }
203
+ const handler = this.localHandlers.get(exportName);
204
+ if (!handler) {
205
+ throw new Error(`[exports] Export "${exportName}" not found in resource "${this.currentResourceName}".`);
206
+ }
207
+ return Promise.resolve(handler(...args));
208
+ }
209
+ createRequestId(resourceName, exportName) {
210
+ return `${this.currentResourceName}:${resourceName}:${exportName}:${Date.now()}:${Math.random()}`;
211
+ }
212
+ serializeError(error) {
213
+ if (error instanceof Error) {
214
+ return {
215
+ name: error.name,
216
+ message: error.message,
217
+ stack: error.stack,
218
+ };
219
+ }
220
+ return {
221
+ name: 'Error',
222
+ message: String(error),
223
+ };
224
+ }
225
+ deserializeError(error) {
226
+ const result = new Error(error.message);
227
+ result.name = error.name;
228
+ result.stack = error.stack;
229
+ return result;
230
+ }
30
231
  };
31
232
  exports.RageMPExports = RageMPExports;
32
233
  exports.RageMPExports = RageMPExports = __decorate([
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.RageMPPlayerAppearanceLifecycleServer = void 0;
16
16
  const tsyringe_1 = require("tsyringe");
17
17
  const contracts_1 = require("@open-core/framework/contracts");
18
+ const framework_1 = require("@open-core/framework");
18
19
  const server_1 = require("@open-core/framework/server");
19
20
  const server_2 = require("@open-core/framework/contracts/server");
20
21
  const server_3 = require("@open-core/framework/contracts/server");
@@ -33,21 +34,21 @@ let RageMPPlayerAppearanceLifecycleServer = class RageMPPlayerAppearanceLifecycl
33
34
  if (appearance.model) {
34
35
  this.playerServer.setModel(playerSrc, appearance.model);
35
36
  }
36
- this.events.emit('opencore:appearance:apply', target, appearance);
37
+ this.events.emit(framework_1.SYSTEM_EVENTS.appearance.apply, target, appearance);
37
38
  return { success: true, appearance };
38
39
  }
39
40
  applyClothing(playerSrc, appearance) {
40
41
  const target = this.resolveTarget(playerSrc);
41
42
  if (!target)
42
43
  return false;
43
- this.events.emit('opencore:appearance:apply', target, appearance);
44
+ this.events.emit(framework_1.SYSTEM_EVENTS.appearance.apply, target, appearance);
44
45
  return true;
45
46
  }
46
47
  reset(playerSrc) {
47
48
  const target = this.resolveTarget(playerSrc);
48
49
  if (!target)
49
50
  return false;
50
- this.events.emit('opencore:appearance:reset', target);
51
+ this.events.emit(framework_1.SYSTEM_EVENTS.appearance.reset, target);
51
52
  return true;
52
53
  }
53
54
  resolveTarget(playerSrc) {
@@ -4,6 +4,9 @@ exports.RageMPResourceInfo = void 0;
4
4
  const server_1 = require("@open-core/framework/contracts/server");
5
5
  class RageMPResourceInfo extends server_1.IResourceInfo {
6
6
  getCurrentResourceName() {
7
+ if (typeof __OPENCORE_RESOURCE_NAME__ === 'string' && __OPENCORE_RESOURCE_NAME__.trim()) {
8
+ return __OPENCORE_RESOURCE_NAME__;
9
+ }
7
10
  if (typeof __dirname !== 'string')
8
11
  return 'default';
9
12
  const normalized = __dirname.replace(/\\/g, '/');
@@ -11,7 +11,7 @@ export type ExportsProxy = {
11
11
  export declare class ExportsRegistry {
12
12
  private readonly registry;
13
13
  private readonly namespaceProxyCache;
14
- register(resource: string, name: string, handler: ExportHandler): void;
14
+ register<TArgs extends readonly unknown[], TResult = unknown>(resource: string, name: string, handler: (...args: TArgs) => TResult): void;
15
15
  call(resource: string, name: string, ...args: ExportArgs): unknown;
16
16
  private createNamespaceProxy;
17
17
  private getOrCreateNamespaceProxy;
@@ -24,6 +24,6 @@ export declare class ExportsRegistry {
24
24
  list(resource: string): string[];
25
25
  }
26
26
  export declare const exportsRegistry: ExportsRegistry;
27
- export declare function registerExport(resource: string, name: string, handler: ExportHandler): void;
27
+ export declare function registerExport<TArgs extends readonly unknown[], TResult = unknown>(resource: string, name: string, handler: (...args: TArgs) => TResult): void;
28
28
  export declare function callExport(resource: string, name: string, ...args: ExportArgs): unknown;
29
29
  export {};
@@ -5,10 +5,10 @@ import type { RuntimeContext } from '@open-core/framework/contracts';
5
5
  *
6
6
  * Analogous to FiveM's `onNet`:
7
7
  * - Server: RageMP prepends the PlayerMp as the first native argument.
8
- * We expose it as-is so callers can read player.id before any await.
8
+ * We expose it as-is so callers can read player.id before awaiting.
9
9
  * - Client: no source argument; we pass undefined to keep the signature uniform.
10
10
  */
11
- export declare function onNet(context: RuntimeContext, event: string, handler: (source: PlayerMp | undefined, ...args: any[]) => void): void;
11
+ export declare function onNet<TArgs extends readonly unknown[]>(context: RuntimeContext, event: string, handler: (source: PlayerMp | undefined, ...args: TArgs) => void): void;
12
12
  /**
13
13
  * Normalizes RageMP's server/client event emission into a single interface.
14
14
  *
@@ -21,4 +21,4 @@ export declare function onNet(context: RuntimeContext, event: string, handler: (
21
21
  * NOTE: Only player targets are supported — vehicles/peds are not valid
22
22
  * network targets, matching FiveM's TriggerClientEvent semantics.
23
23
  */
24
- export declare function emitNet(context: RuntimeContext, event: string, target: number | number[] | -1, ...payload: any[]): void;
24
+ export declare function emitNet(context: RuntimeContext, event: string, target: number | number[] | -1, ...payload: unknown[]): void;
@@ -2,6 +2,29 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onNet = onNet;
4
4
  exports.emitNet = emitNet;
5
+ const JSON_WIRE_PREFIX = '__OPENCORE_JSON__:';
6
+ function serializeWireValue(value) {
7
+ if (value === null || value === undefined)
8
+ return value;
9
+ if (Array.isArray(value) || (typeof value === 'object' && value.constructor === Object)) {
10
+ return `${JSON_WIRE_PREFIX}${JSON.stringify(value)}`;
11
+ }
12
+ return value;
13
+ }
14
+ function deserializeWireValue(value) {
15
+ if (typeof value !== 'string' || !value.startsWith(JSON_WIRE_PREFIX)) {
16
+ return value;
17
+ }
18
+ try {
19
+ return JSON.parse(value.slice(JSON_WIRE_PREFIX.length));
20
+ }
21
+ catch {
22
+ return value;
23
+ }
24
+ }
25
+ function deserializeWireArgs(args) {
26
+ return args.map((arg) => deserializeWireValue(arg));
27
+ }
5
28
  /**
6
29
  * Resolves a player by numeric ID, returning undefined when the player no
7
30
  * longer exists (disconnected, invalid handle, etc.).
@@ -21,7 +44,7 @@ function resolvePlayer(id) {
21
44
  *
22
45
  * Analogous to FiveM's `onNet`:
23
46
  * - Server: RageMP prepends the PlayerMp as the first native argument.
24
- * We expose it as-is so callers can read player.id before any await.
47
+ * We expose it as-is so callers can read player.id before awaiting.
25
48
  * - Client: no source argument; we pass undefined to keep the signature uniform.
26
49
  */
27
50
  function onNet(context, event, handler) {
@@ -32,11 +55,13 @@ function onNet(context, event, handler) {
32
55
  // all other events should be safe to guard this way.
33
56
  if (!mp.players.exists(player.id))
34
57
  return;
35
- handler(player, ...args);
58
+ handler(player, ...deserializeWireArgs(args));
36
59
  });
37
60
  }
38
61
  else {
39
- mp.events.add(event, (...args) => handler(undefined, ...args));
62
+ mp.events.add(event, (...args) => {
63
+ handler(undefined, ...deserializeWireArgs(args));
64
+ });
40
65
  }
41
66
  }
42
67
  /**
@@ -52,19 +77,20 @@ function onNet(context, event, handler) {
52
77
  * network targets, matching FiveM's TriggerClientEvent semantics.
53
78
  */
54
79
  function emitNet(context, event, target, ...payload) {
80
+ const serializedPayload = payload.map((item) => serializeWireValue(item));
55
81
  if (context !== 'server') {
56
- mp.events.callRemote(event, ...payload);
82
+ mp.events.callRemote(event, ...serializedPayload);
57
83
  return;
58
84
  }
59
85
  if (target === -1) {
60
- mp.players.call(event, payload);
86
+ mp.players.call(event, serializedPayload);
61
87
  return;
62
88
  }
63
89
  if (Array.isArray(target)) {
64
90
  for (const id of target) {
65
- resolvePlayer(id)?.call(event, payload);
91
+ resolvePlayer(id)?.call(event, serializedPayload);
66
92
  }
67
93
  return;
68
94
  }
69
- resolvePlayer(target)?.call(event, payload);
95
+ resolvePlayer(target)?.call(event, serializedPayload);
70
96
  }
@@ -2,9 +2,9 @@ import { EventsAPI, type RuntimeContext } from '@open-core/framework/contracts';
2
2
  export declare class RageMPEvents extends EventsAPI<RuntimeContext> {
3
3
  private readonly context;
4
4
  constructor(context: RuntimeContext);
5
- on(event: string, handler: (source: {
5
+ on<TArgs extends readonly unknown[]>(event: string, handler: (source: {
6
6
  clientId: number | undefined;
7
7
  raw: PlayerMp | undefined;
8
- }, ...args: any[]) => void): void;
9
- emit(event: string, ...args: any[]): void;
8
+ }, ...args: TArgs) => void | Promise<void>): void;
9
+ emit(event: string, ...args: unknown[]): void;
10
10
  }
@@ -16,7 +16,7 @@ class RageMPEvents extends contracts_1.EventsAPI {
16
16
  }
17
17
  on(event, handler) {
18
18
  (0, helpers_1.onNet)(this.context, event, (source, ...args) => {
19
- handler({ clientId: source?.id, raw: source }, ...args);
19
+ void handler({ clientId: source?.id, raw: source }, ...args);
20
20
  });
21
21
  }
22
22
  emit(event, ...args) {
@@ -39,7 +39,9 @@ class RageMPEvents extends contracts_1.EventsAPI {
39
39
  (0, helpers_1.emitNet)(this.context, event, target.clientID, ...payload);
40
40
  return;
41
41
  }
42
- (0, helpers_1.emitNet)(this.context, event, target, ...payload);
42
+ if (typeof target === 'number') {
43
+ (0, helpers_1.emitNet)(this.context, event, target, ...payload);
44
+ }
43
45
  }
44
46
  }
45
47
  exports.RageMPEvents = RageMPEvents;
@@ -1,4 +1,4 @@
1
- import { RpcAPI, type RuntimeContext } from '@open-core/framework/contracts';
1
+ import { RpcAPI, type RpcContext, type RuntimeContext } from '@open-core/framework/contracts';
2
2
  export declare class RageMPRpc<C extends RuntimeContext = RuntimeContext> extends RpcAPI<C> {
3
3
  private readonly context;
4
4
  private readonly pending;
@@ -9,13 +9,9 @@ export declare class RageMPRpc<C extends RuntimeContext = RuntimeContext> extend
9
9
  private readonly responseEvent;
10
10
  private readonly defaultTimeoutMs;
11
11
  constructor(context: C);
12
- on<TArgs extends any[], TResult>(name: string, handler: (ctx: {
13
- requestId: string;
14
- clientId?: number;
15
- raw?: unknown;
16
- }, ...args: TArgs) => TResult | Promise<TResult>): void;
17
- call<TResult = unknown>(name: string, ...args: any[]): Promise<TResult>;
18
- notify(name: string, ...args: any[]): Promise<void>;
12
+ on<TArgs extends readonly unknown[], TResult>(name: string, handler: (ctx: RpcContext, ...args: TArgs) => TResult | Promise<TResult>): void;
13
+ call<TResult = unknown>(name: string, ...args: unknown[]): Promise<TResult>;
14
+ notify(name: string, ...args: unknown[]): Promise<void>;
19
15
  private normalizeInvocation;
20
16
  private isValidTarget;
21
17
  private sendAndWait;
@@ -3,7 +3,24 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RageMPRpc = void 0;
4
4
  const contracts_1 = require("@open-core/framework/contracts");
5
5
  const helpers_1 = require("./helpers");
6
+ function serializeRpcError(error) {
7
+ if (typeof error === 'object' &&
8
+ error !== null &&
9
+ 'message' in error &&
10
+ typeof error.message === 'string' &&
11
+ 'expose' in error &&
12
+ error.expose === true) {
13
+ return {
14
+ message: error.message,
15
+ name: 'name' in error && typeof error.name === 'string' ? error.name : undefined,
16
+ };
17
+ }
18
+ return { message: 'An internal server error occurred' };
19
+ }
6
20
  function getCurrentResourceNameSafe() {
21
+ if (typeof __OPENCORE_RESOURCE_NAME__ === 'string' && __OPENCORE_RESOURCE_NAME__.trim()) {
22
+ return __OPENCORE_RESOURCE_NAME__;
23
+ }
7
24
  if (typeof __dirname !== 'string')
8
25
  return 'default';
9
26
  const parts = __dirname.replace(/\\/g, '/').split('/');
@@ -28,7 +45,7 @@ class RageMPRpc extends contracts_1.RpcAPI {
28
45
  });
29
46
  }
30
47
  on(name, handler) {
31
- this.handlers.set(name, handler);
48
+ this.handlers.set(name, (ctx, ...args) => handler(ctx, ...args));
32
49
  }
33
50
  call(name, ...args) {
34
51
  const { target, payload } = this.normalizeInvocation(name, 'call', args);
@@ -76,7 +93,7 @@ class RageMPRpc extends contracts_1.RpcAPI {
76
93
  this.pending.delete(id);
77
94
  reject(new Error(`RageMPRpc: timeout waiting for '${input.kind}' response for '${input.name}' (${id})`));
78
95
  }, this.defaultTimeoutMs);
79
- this.pending.set(id, { resolve: resolve, reject, timeout });
96
+ this.pending.set(id, { resolve: (value) => resolve(value), reject, timeout });
80
97
  if (this.context === 'server') {
81
98
  const resolvedTarget = this.resolveServerTarget(target, input.kind, input.name);
82
99
  (0, helpers_1.emitNet)(this.context, this.requestEvent, resolvedTarget, msg);
@@ -139,6 +156,7 @@ class RageMPRpc extends contracts_1.RpcAPI {
139
156
  }
140
157
  }
141
158
  catch (err) {
159
+ const errorInfo = serializeRpcError(err);
142
160
  if (msg.kind === 'notify') {
143
161
  this.emitResponse(replyTarget, { kind: 'ack', id: msg.id });
144
162
  return;
@@ -148,8 +166,8 @@ class RageMPRpc extends contracts_1.RpcAPI {
148
166
  id: msg.id,
149
167
  ok: false,
150
168
  error: {
151
- message: err?.message ? String(err.message) : String(err),
152
- name: err?.name ? String(err.name) : undefined,
169
+ message: errorInfo.message,
170
+ name: errorInfo.name,
153
171
  },
154
172
  });
155
173
  }
@@ -171,7 +189,13 @@ class RageMPRpc extends contracts_1.RpcAPI {
171
189
  return;
172
190
  }
173
191
  const error = new Error(msg.error?.message ?? 'RageMPRpc: remote error');
174
- error.name = msg.error?.name ?? error.name;
192
+ if (msg.error?.name) {
193
+ Object.defineProperty(error, 'name', {
194
+ value: msg.error.name,
195
+ configurable: true,
196
+ writable: true,
197
+ });
198
+ }
175
199
  pending.reject(error);
176
200
  }
177
201
  emitResponse(target, msg) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-core/ragemp-adapter",
3
- "version": "0.1.1",
3
+ "version": "1.0.2",
4
4
  "description": "External Rage Multiplayer adapter for OpenCore framework.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -37,20 +37,18 @@
37
37
  "adapter"
38
38
  ],
39
39
  "license": "MPL-2.0",
40
- "dependencies": {
41
- "@open-core/framework": "v1.0.5-beta.2"
42
- },
43
40
  "peerDependencies": {
44
41
  "reflect-metadata": "^0.2.2",
45
42
  "tsyringe": "^4.10.0",
46
43
  "zod": "^4.3.5"
47
44
  },
48
45
  "devDependencies": {
49
- "@biomejs/biome": "^2.3.11",
46
+ "@biomejs/biome": "^2.4.10",
47
+ "@open-core/framework": "latest",
50
48
  "@ragempcommunity/types-client": "^2.1.9",
51
49
  "@ragempcommunity/types-server": "^2.1.9",
52
- "@types/node": "^25.0.3",
53
- "typescript": "^5.9.3"
50
+ "@types/node": "^25.5.0",
51
+ "typescript": "^6.0.2"
54
52
  },
55
53
  "scripts": {
56
54
  "build": "tsc -b",