@rpgjs/vite 5.0.0-alpha.8 → 5.0.0-beta.1
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.
- package/dist/index-Bc9qRSkO.js +5496 -0
- package/dist/index-Bc9qRSkO.js.map +1 -0
- package/dist/index.js +4542 -863
- package/dist/index.js.map +1 -1
- package/dist/mmorpg-build-plugin.d.ts +8 -0
- package/dist/rpgjs-plugin.d.ts +8 -3
- package/dist/server-plugin.d.ts +2 -149
- package/package.json +14 -13
- package/src/mmorpg-build-plugin.ts +123 -0
- package/src/module-config.ts +13 -0
- package/src/rpgjs-plugin.ts +36 -4
- package/src/server-plugin.ts +15 -436
- package/tests/latency-simulation.spec.ts +209 -0
- package/tsconfig.json +2 -2
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
interface MmorpgBuildPluginOptions {
|
|
3
|
+
rpgType: string;
|
|
4
|
+
serverEntry: string;
|
|
5
|
+
adapterEntries?: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
export declare function mmorpgBuildPlugin({ rpgType, serverEntry, adapterEntries, }: MmorpgBuildPluginOptions): Plugin;
|
|
8
|
+
export {};
|
package/dist/rpgjs-plugin.d.ts
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
type MmorpgEntryPoints = string | {
|
|
2
|
+
client?: string;
|
|
3
|
+
server?: string;
|
|
4
|
+
adapters?: Record<string, string>;
|
|
5
|
+
};
|
|
1
6
|
interface RpgjsPluginOptions {
|
|
2
7
|
server: any;
|
|
3
8
|
entryPoints?: {
|
|
4
|
-
rpg
|
|
5
|
-
mmorpg
|
|
9
|
+
rpg?: string;
|
|
10
|
+
mmorpg?: MmorpgEntryPoints;
|
|
6
11
|
};
|
|
7
12
|
}
|
|
8
13
|
export declare function rpgjs({ server, entryPoints }: RpgjsPluginOptions): (import('vite').Plugin<any> | {
|
|
@@ -10,7 +15,7 @@ export declare function rpgjs({ server, entryPoints }: RpgjsPluginOptions): (imp
|
|
|
10
15
|
transform(code: string, id: string): {
|
|
11
16
|
code: string;
|
|
12
17
|
map: null;
|
|
13
|
-
} |
|
|
18
|
+
} | null;
|
|
14
19
|
} | {
|
|
15
20
|
name: string;
|
|
16
21
|
transform(code: string, id: string): string | undefined;
|
package/dist/server-plugin.d.ts
CHANGED
|
@@ -1,155 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RpgTransportServerConstructor } from '@rpgjs/server/node';
|
|
2
2
|
import { ViteDevServer } from 'vite';
|
|
3
|
-
|
|
4
|
-
readyState: number;
|
|
5
|
-
send(data: string): void;
|
|
6
|
-
close(): void;
|
|
7
|
-
on(event: string, callback: (...args: any[]) => void): void;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* PartyConnection class compatible with PartyKit's Party.Connection interface
|
|
11
|
-
*
|
|
12
|
-
* This class implements the Connection interface expected by RPG-JS server,
|
|
13
|
-
* providing WebSocket communication capabilities and connection state management.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* const connection = new PartyConnection(websocket, 'player123');
|
|
18
|
-
* connection.send('Hello player!');
|
|
19
|
-
* connection.setState({ username: 'Alice' });
|
|
20
|
-
* ```
|
|
21
|
-
*/
|
|
22
|
-
declare class PartyConnection {
|
|
23
|
-
private ws;
|
|
24
|
-
id: string;
|
|
25
|
-
uri: string;
|
|
26
|
-
private _state;
|
|
27
|
-
constructor(ws: WSConnection, id?: string, uri?: string);
|
|
28
|
-
/**
|
|
29
|
-
* Generates a unique identifier for the connection
|
|
30
|
-
*
|
|
31
|
-
* @returns {string} Unique identifier based on timestamp and random number
|
|
32
|
-
*/
|
|
33
|
-
private generateId;
|
|
34
|
-
/**
|
|
35
|
-
* Sends data to the client via WebSocket
|
|
36
|
-
*
|
|
37
|
-
* @param {any} data - Data to send (automatically serialized to JSON if not string)
|
|
38
|
-
*/
|
|
39
|
-
send(data: any): void;
|
|
40
|
-
/**
|
|
41
|
-
* Closes the WebSocket connection
|
|
42
|
-
*/
|
|
43
|
-
close(): void;
|
|
44
|
-
/**
|
|
45
|
-
* Sets state data for this connection
|
|
46
|
-
*
|
|
47
|
-
* @param {any} value - State data to store (max 2KB as per PartyKit spec)
|
|
48
|
-
*/
|
|
49
|
-
setState(value: any): void;
|
|
50
|
-
/**
|
|
51
|
-
* Gets the current state of this connection
|
|
52
|
-
*
|
|
53
|
-
* @returns {any} Current connection state
|
|
54
|
-
*/
|
|
55
|
-
get state(): any;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Room class compatible with PartyKit's Party.Room interface
|
|
59
|
-
*
|
|
60
|
-
* This class manages multiple WebSocket connections and provides broadcasting
|
|
61
|
-
* capabilities, storage, and connection management as expected by RPG-JS server.
|
|
62
|
-
*
|
|
63
|
-
* @example
|
|
64
|
-
* ```typescript
|
|
65
|
-
* const room = new Room('lobby-1');
|
|
66
|
-
* room.broadcast('Game started!');
|
|
67
|
-
* const playerCount = [...room.getConnections()].length;
|
|
68
|
-
* ```
|
|
69
|
-
*/
|
|
70
|
-
declare class Room {
|
|
71
|
-
id: string;
|
|
72
|
-
internalID: string;
|
|
73
|
-
env: Record<string, any>;
|
|
74
|
-
context: any;
|
|
75
|
-
private connections;
|
|
76
|
-
private storageData;
|
|
77
|
-
constructor(id: string);
|
|
78
|
-
/**
|
|
79
|
-
* Broadcasts a message to all connected clients
|
|
80
|
-
*
|
|
81
|
-
* @param {any} message - Message to broadcast
|
|
82
|
-
* @param {string[]} except - Array of connection IDs to exclude from broadcast
|
|
83
|
-
*/
|
|
84
|
-
broadcast(message: any, except?: string[]): void;
|
|
85
|
-
/**
|
|
86
|
-
* Gets a connection by its ID
|
|
87
|
-
*
|
|
88
|
-
* @param {string} id - Connection ID
|
|
89
|
-
* @returns {PartyConnection | undefined} The connection or undefined if not found
|
|
90
|
-
*/
|
|
91
|
-
getConnection(id: string): PartyConnection | undefined;
|
|
92
|
-
/**
|
|
93
|
-
* Gets all currently connected clients
|
|
94
|
-
*
|
|
95
|
-
* @param {string} tag - Optional tag to filter connections (not implemented yet)
|
|
96
|
-
* @returns {IterableIterator<PartyConnection>} Iterator of all connections
|
|
97
|
-
*/
|
|
98
|
-
getConnections(tag?: string): IterableIterator<PartyConnection>;
|
|
99
|
-
/**
|
|
100
|
-
* Adds a connection to this room
|
|
101
|
-
*
|
|
102
|
-
* @param {PartyConnection} connection - Connection to add
|
|
103
|
-
*/
|
|
104
|
-
addConnection(connection: PartyConnection): void;
|
|
105
|
-
/**
|
|
106
|
-
* Removes a connection from this room
|
|
107
|
-
*
|
|
108
|
-
* @param {string} connectionId - ID of connection to remove
|
|
109
|
-
*/
|
|
110
|
-
removeConnection(connectionId: string): void;
|
|
111
|
-
/**
|
|
112
|
-
* Simple key-value storage for the room
|
|
113
|
-
*/
|
|
114
|
-
get storage(): {
|
|
115
|
-
put: (key: string, value: any) => Promise<void>;
|
|
116
|
-
get: <T = any>(key: string) => Promise<T | undefined>;
|
|
117
|
-
delete: (key: string) => Promise<void>;
|
|
118
|
-
list: () => Promise<string[]>;
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Creates a Vite plugin for integrating RPG-JS server functionality
|
|
123
|
-
*
|
|
124
|
-
* This plugin configures the development server to automatically start
|
|
125
|
-
* an RPG-JS server instance when Vite's dev server starts. It handles
|
|
126
|
-
* the instantiation and initialization of the server module, and sets up
|
|
127
|
-
* HTTP request and WebSocket connection forwarding to the RPG-JS server.
|
|
128
|
-
*
|
|
129
|
-
* The plugin intercepts:
|
|
130
|
-
* - HTTP requests to `/parties/*` paths and forwards them to the RPG-JS server
|
|
131
|
-
* - WebSocket upgrade requests and establishes connections with the RPG-JS server
|
|
132
|
-
*
|
|
133
|
-
* @param {new () => RpgServerEngine} serverModule - A class constructor that extends RpgServerEngine
|
|
134
|
-
* @returns {Object} Vite plugin configuration object
|
|
135
|
-
*
|
|
136
|
-
* @example
|
|
137
|
-
* ```typescript
|
|
138
|
-
* // In vite.config.ts
|
|
139
|
-
* import { serverPlugin } from '@rpgjs/vite';
|
|
140
|
-
* import startServer from './src/server';
|
|
141
|
-
*
|
|
142
|
-
* export default defineConfig({
|
|
143
|
-
* plugins: [
|
|
144
|
-
* serverPlugin(startServer)
|
|
145
|
-
* ]
|
|
146
|
-
* });
|
|
147
|
-
* ```
|
|
148
|
-
*/
|
|
149
|
-
export declare function serverPlugin(serverModule: new (room: Room) => RpgServerEngine): {
|
|
3
|
+
export declare function serverPlugin(serverModule: RpgTransportServerConstructor): {
|
|
150
4
|
name: string;
|
|
151
5
|
configureServer(server: ViteDevServer): Promise<void>;
|
|
152
6
|
buildStart(): void;
|
|
153
7
|
buildEnd(): void;
|
|
154
8
|
};
|
|
155
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpgjs/vite",
|
|
3
|
-
"version": "5.0.0-
|
|
3
|
+
"version": "5.0.0-beta.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"keywords": [],
|
|
@@ -12,18 +12,19 @@
|
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@canvasengine/
|
|
16
|
-
"@
|
|
17
|
-
"@
|
|
18
|
-
"@
|
|
19
|
-
"
|
|
20
|
-
"acorn
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"vite
|
|
25
|
-
"
|
|
26
|
-
"
|
|
15
|
+
"@canvasengine/tiled": "2.0.0-beta.54",
|
|
16
|
+
"@canvasengine/compiler": "2.0.0-beta.54",
|
|
17
|
+
"@hono/vite-dev-server": "^0.25.0",
|
|
18
|
+
"@rpgjs/server": "5.0.0-beta.1",
|
|
19
|
+
"@types/node": "^25.3.5",
|
|
20
|
+
"acorn": "^8.16.0",
|
|
21
|
+
"acorn-walk": "^8.3.5",
|
|
22
|
+
"magic-string": "^0.30.21",
|
|
23
|
+
"typescript": "^5.9.3",
|
|
24
|
+
"vite": "^7.3.1",
|
|
25
|
+
"vite-plugin-dts": "^4.5.4",
|
|
26
|
+
"vitest": "^4.0.18",
|
|
27
|
+
"ws": "^8.19.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/ws": "^8.18.1"
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { build as viteBuild, type Plugin, type ResolvedConfig } from "vite";
|
|
4
|
+
|
|
5
|
+
interface MmorpgBuildPluginOptions {
|
|
6
|
+
rpgType: string;
|
|
7
|
+
serverEntry: string;
|
|
8
|
+
adapterEntries?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isBareImport(id: string): boolean {
|
|
12
|
+
return !id.startsWith(".") && !id.startsWith("/") && !id.startsWith("\0");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolveEntry(root: string, entry: string): string {
|
|
16
|
+
return resolve(root, entry);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function collectServerEntries(
|
|
20
|
+
root: string,
|
|
21
|
+
serverEntry: string,
|
|
22
|
+
adapterEntries: Record<string, string>,
|
|
23
|
+
): Record<string, string> {
|
|
24
|
+
const entries: Record<string, string> = {};
|
|
25
|
+
const resolvedServerEntry = resolveEntry(root, serverEntry);
|
|
26
|
+
|
|
27
|
+
if (!existsSync(resolvedServerEntry)) {
|
|
28
|
+
throw new Error(`[rpgjs:mmorpg-build] Missing server entry: ${serverEntry}`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
entries.server = resolvedServerEntry;
|
|
32
|
+
|
|
33
|
+
for (const [name, entry] of Object.entries(adapterEntries)) {
|
|
34
|
+
const resolvedAdapterEntry = resolveEntry(root, entry);
|
|
35
|
+
if (!existsSync(resolvedAdapterEntry)) {
|
|
36
|
+
throw new Error(`[rpgjs:mmorpg-build] Missing adapter entry "${name}": ${entry}`);
|
|
37
|
+
}
|
|
38
|
+
entries[name] = resolvedAdapterEntry;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return entries;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function mmorpgBuildPlugin({
|
|
45
|
+
rpgType,
|
|
46
|
+
serverEntry,
|
|
47
|
+
adapterEntries = {},
|
|
48
|
+
}: MmorpgBuildPluginOptions): Plugin {
|
|
49
|
+
let config: ResolvedConfig;
|
|
50
|
+
let didBuildServer = false;
|
|
51
|
+
let didCleanDist = false;
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
name: "rpgjs:mmorpg-build",
|
|
55
|
+
apply: "build",
|
|
56
|
+
enforce: "post",
|
|
57
|
+
config(_, env) {
|
|
58
|
+
if (env.command !== "build" || rpgType !== "mmorpg") {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
build: {
|
|
64
|
+
outDir: "dist/client",
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
configResolved(resolvedConfig) {
|
|
69
|
+
config = resolvedConfig;
|
|
70
|
+
},
|
|
71
|
+
buildStart() {
|
|
72
|
+
if (rpgType !== "mmorpg" || didCleanDist) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
didCleanDist = true;
|
|
76
|
+
rmSync(resolve(config.root, "dist"), { recursive: true, force: true });
|
|
77
|
+
},
|
|
78
|
+
async closeBundle() {
|
|
79
|
+
if (rpgType !== "mmorpg" || didBuildServer) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
didBuildServer = true;
|
|
83
|
+
|
|
84
|
+
const entries = collectServerEntries(config.root, serverEntry, adapterEntries);
|
|
85
|
+
console.log(
|
|
86
|
+
`[rpgjs:mmorpg-build] Building server bundle(s): ${Object.keys(entries).join(", ")}`,
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
await viteBuild({
|
|
90
|
+
configFile: false,
|
|
91
|
+
root: config.root,
|
|
92
|
+
define: config.define,
|
|
93
|
+
resolve: {
|
|
94
|
+
alias: config.resolve.alias,
|
|
95
|
+
dedupe: config.resolve.dedupe,
|
|
96
|
+
extensions: config.resolve.extensions,
|
|
97
|
+
mainFields: config.resolve.mainFields,
|
|
98
|
+
conditions: config.resolve.conditions,
|
|
99
|
+
},
|
|
100
|
+
publicDir: false,
|
|
101
|
+
build: {
|
|
102
|
+
emptyOutDir: true,
|
|
103
|
+
minify: false,
|
|
104
|
+
outDir: "dist/server",
|
|
105
|
+
sourcemap: config.build.sourcemap,
|
|
106
|
+
target: "node18",
|
|
107
|
+
lib: {
|
|
108
|
+
entry: entries,
|
|
109
|
+
formats: ["es"],
|
|
110
|
+
},
|
|
111
|
+
rollupOptions: {
|
|
112
|
+
external(id) {
|
|
113
|
+
return isBareImport(id);
|
|
114
|
+
},
|
|
115
|
+
output: {
|
|
116
|
+
entryFileNames: "[name].js",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
package/src/module-config.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defineConfig, build } from "vite";
|
|
2
2
|
import canvasengine from "@canvasengine/compiler";
|
|
3
3
|
import dts from "vite-plugin-dts";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { resolve } from "node:path";
|
|
4
6
|
import { directivePlugin, removeImportsPlugin } from "./index";
|
|
5
7
|
|
|
6
8
|
/**
|
|
@@ -22,6 +24,14 @@ import { directivePlugin, removeImportsPlugin } from "./index";
|
|
|
22
24
|
*/
|
|
23
25
|
function createBuildConfig({ side, watch }: { side: 'client' | 'server', watch: boolean }) {
|
|
24
26
|
const isClient = side === 'client';
|
|
27
|
+
const runtimeDir = resolve(process.cwd(), "runtime");
|
|
28
|
+
const resolveOptions = existsSync(runtimeDir)
|
|
29
|
+
? {
|
|
30
|
+
alias: {
|
|
31
|
+
"@common": runtimeDir,
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
: undefined;
|
|
25
35
|
|
|
26
36
|
const plugins = isClient
|
|
27
37
|
? [
|
|
@@ -36,6 +46,7 @@ function createBuildConfig({ side, watch }: { side: 'client' | 'server', watch:
|
|
|
36
46
|
|
|
37
47
|
return {
|
|
38
48
|
configFile: false as const, // Prevent using this config file
|
|
49
|
+
resolve: resolveOptions,
|
|
39
50
|
plugins: [
|
|
40
51
|
...plugins,
|
|
41
52
|
dts({
|
|
@@ -57,7 +68,9 @@ function createBuildConfig({ side, watch }: { side: 'client' | 'server', watch:
|
|
|
57
68
|
rollupOptions: {
|
|
58
69
|
external: [
|
|
59
70
|
/@rpgjs/,
|
|
71
|
+
/@signestack/,
|
|
60
72
|
"canvasengine",
|
|
73
|
+
"pixi.js",
|
|
61
74
|
"esbuild",
|
|
62
75
|
"@canvasengine/presets",
|
|
63
76
|
"rxjs",
|
package/src/rpgjs-plugin.ts
CHANGED
|
@@ -2,12 +2,37 @@ import canvasengine from "@canvasengine/compiler";
|
|
|
2
2
|
import { replaceConfigImport } from "./replace-config-import";
|
|
3
3
|
import { serverPlugin } from "./server-plugin";
|
|
4
4
|
import { entryPointPlugin } from "./entry-point-plugin";
|
|
5
|
+
import { mmorpgBuildPlugin } from "./mmorpg-build-plugin";
|
|
6
|
+
|
|
7
|
+
type MmorpgEntryPoints =
|
|
8
|
+
| string
|
|
9
|
+
| {
|
|
10
|
+
client?: string;
|
|
11
|
+
server?: string;
|
|
12
|
+
adapters?: Record<string, string>;
|
|
13
|
+
};
|
|
5
14
|
|
|
6
15
|
interface RpgjsPluginOptions {
|
|
7
16
|
server: any;
|
|
8
17
|
entryPoints?: {
|
|
9
|
-
rpg
|
|
10
|
-
mmorpg
|
|
18
|
+
rpg?: string;
|
|
19
|
+
mmorpg?: MmorpgEntryPoints;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalizeMmorpgEntryPoints(entryPoints?: MmorpgEntryPoints) {
|
|
24
|
+
if (!entryPoints || typeof entryPoints === "string") {
|
|
25
|
+
return {
|
|
26
|
+
client: entryPoints ?? "./src/client.ts",
|
|
27
|
+
server: "./src/server.ts",
|
|
28
|
+
adapters: {},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
client: entryPoints.client ?? "./src/client.ts",
|
|
34
|
+
server: entryPoints.server ?? "./src/server.ts",
|
|
35
|
+
adapters: entryPoints.adapters ?? {},
|
|
11
36
|
};
|
|
12
37
|
}
|
|
13
38
|
|
|
@@ -15,15 +40,22 @@ export function rpgjs({
|
|
|
15
40
|
server,
|
|
16
41
|
entryPoints
|
|
17
42
|
}: RpgjsPluginOptions) {
|
|
43
|
+
const mmorpgEntryPoints = normalizeMmorpgEntryPoints(entryPoints?.mmorpg);
|
|
44
|
+
|
|
18
45
|
return [
|
|
19
46
|
canvasengine(),
|
|
20
47
|
replaceConfigImport(),
|
|
21
48
|
serverPlugin(server),
|
|
49
|
+
mmorpgBuildPlugin({
|
|
50
|
+
rpgType: process.env.RPG_TYPE || "rpg",
|
|
51
|
+
serverEntry: mmorpgEntryPoints.server,
|
|
52
|
+
adapterEntries: mmorpgEntryPoints.adapters,
|
|
53
|
+
}),
|
|
22
54
|
entryPointPlugin({
|
|
23
55
|
entryPoints: {
|
|
24
56
|
rpg: entryPoints?.rpg ?? './src/standalone.ts',
|
|
25
|
-
mmorpg:
|
|
57
|
+
mmorpg: mmorpgEntryPoints.client,
|
|
26
58
|
}
|
|
27
59
|
})
|
|
28
60
|
]
|
|
29
|
-
}
|
|
61
|
+
}
|