@discord-mcbe/client 0.0.1 → 4.0.0-beta.0
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/LICENSE +21 -0
- package/dist/bds.d.ts +16 -0
- package/dist/bds.js +33 -0
- package/dist/client-DgUd3XAf.js +360 -0
- package/dist/index-CzbgOaig.d.ts +112 -0
- package/dist/local.d.ts +12 -0
- package/dist/local.js +277 -0
- package/package.json +41 -8
- package/README.md +0 -45
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 tutinoko2048/RetoRuto9900K
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/bds.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { n as ClientType, t as BaseClient } from "./index-CzbgOaig.js";
|
|
2
|
+
import { ScriptBridgeClient } from "@script-bridge/client";
|
|
3
|
+
|
|
4
|
+
//#region src/bds.d.ts
|
|
5
|
+
interface BridgeClientOptions {
|
|
6
|
+
host?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
clientId?: string | (() => string);
|
|
9
|
+
}
|
|
10
|
+
declare class BridgeClient extends BaseClient<ScriptBridgeClient> {
|
|
11
|
+
readonly type = ClientType.BDS;
|
|
12
|
+
constructor(options?: BridgeClientOptions);
|
|
13
|
+
start(): Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { BridgeClient, BridgeClientOptions };
|
package/dist/bds.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { n as ClientType, t as BaseClient } from "./client-DgUd3XAf.js";
|
|
2
|
+
import { world } from "@minecraft/server";
|
|
3
|
+
import { ScriptBridgeClient } from "@script-bridge/client";
|
|
4
|
+
|
|
5
|
+
//#region src/bds.ts
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
host: "localhost",
|
|
8
|
+
port: 23191,
|
|
9
|
+
clientId: () => world.getDynamicProperty("clientId") ?? "discord-mcbe-bds"
|
|
10
|
+
};
|
|
11
|
+
var BridgeClient = class extends BaseClient {
|
|
12
|
+
type = ClientType.BDS;
|
|
13
|
+
constructor(options = {}) {
|
|
14
|
+
const mergedOptions = {
|
|
15
|
+
...defaultOptions,
|
|
16
|
+
...options
|
|
17
|
+
};
|
|
18
|
+
const bridge = new ScriptBridgeClient({
|
|
19
|
+
url: `http://${mergedOptions.host}:${mergedOptions.port}`,
|
|
20
|
+
clientId: mergedOptions.clientId
|
|
21
|
+
});
|
|
22
|
+
super(bridge);
|
|
23
|
+
}
|
|
24
|
+
async start() {
|
|
25
|
+
console.log("[discord-mcbe] Connecting to discord-mcbe server...");
|
|
26
|
+
const requestedAt = Date.now();
|
|
27
|
+
await this.bridge.connect();
|
|
28
|
+
console.log(`[discord-mcbe] Connection established! (${Date.now() - requestedAt}ms)`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
export { BridgeClient };
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { CommandPermissionLevel, CustomCommandParamType, CustomCommandStatus, ObjectiveSortOrder, Player, ScoreboardIdentityType, system, world } from "@minecraft/server";
|
|
2
|
+
import { ActionId } from "@discord-mcbe/shared";
|
|
3
|
+
import { ModalFormData } from "@minecraft/server-ui";
|
|
4
|
+
|
|
5
|
+
//#region src/client/descriptors.ts
|
|
6
|
+
function createPlayerDescriptor(player) {
|
|
7
|
+
return {
|
|
8
|
+
name: player.name,
|
|
9
|
+
nameTag: player.nameTag,
|
|
10
|
+
uniqueId: player.id,
|
|
11
|
+
platformType: player.clientSystemInfo.platformType
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function createDimensionDescriptor(dimension) {
|
|
15
|
+
return {
|
|
16
|
+
id: dimension.id,
|
|
17
|
+
heightRange: dimension.heightRange
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createScoreboardObjectiveDescriptor(objective) {
|
|
21
|
+
return {
|
|
22
|
+
id: objective.id,
|
|
23
|
+
displayName: objective.displayName
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function createScoreboardIdentityDescriptor(identity) {
|
|
27
|
+
let entityUniqueId;
|
|
28
|
+
if ((identity.type === ScoreboardIdentityType.Entity || identity.type === ScoreboardIdentityType.Player) && identity.displayName !== "commands.scoreboard.players.offlinePlayerName") entityUniqueId = identity.getEntity()?.id;
|
|
29
|
+
return {
|
|
30
|
+
type: identity.type,
|
|
31
|
+
id: identity.id,
|
|
32
|
+
displayName: identity.displayName,
|
|
33
|
+
entityUniqueId
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function createScoreboardScoreInfoDescriptor(info) {
|
|
37
|
+
return {
|
|
38
|
+
score: info.score,
|
|
39
|
+
participant: createScoreboardIdentityDescriptor(info.participant)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/client/util.ts
|
|
45
|
+
let lastTick;
|
|
46
|
+
const deltaTimes = [];
|
|
47
|
+
system.runInterval(() => {
|
|
48
|
+
const now = Date.now();
|
|
49
|
+
if (lastTick) {
|
|
50
|
+
if (deltaTimes.length > 60) deltaTimes.shift();
|
|
51
|
+
deltaTimes.push(now - lastTick);
|
|
52
|
+
}
|
|
53
|
+
lastTick = now;
|
|
54
|
+
});
|
|
55
|
+
function getTPS() {
|
|
56
|
+
if (deltaTimes.length === 0) return 20;
|
|
57
|
+
const tps = 1e3 / (deltaTimes.reduce((sum, delta) => sum + delta, 0) / deltaTimes.length);
|
|
58
|
+
return Math.floor(tps * 100) / 100;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region src/client/handler.ts
|
|
63
|
+
function registerHandlers(bridge) {
|
|
64
|
+
bridge.registerHandler(ActionId.SendMessage, (action) => {
|
|
65
|
+
const { message, playerUniqueId } = action.data;
|
|
66
|
+
if (playerUniqueId) {
|
|
67
|
+
const player = world.getEntity(playerUniqueId);
|
|
68
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
69
|
+
player.sendMessage(message);
|
|
70
|
+
} else world.sendMessage(message);
|
|
71
|
+
action.respond();
|
|
72
|
+
});
|
|
73
|
+
bridge.registerHandler(ActionId.RunCommand, (action) => {
|
|
74
|
+
const { command } = action.data;
|
|
75
|
+
const { successCount } = world.getDimension("overworld").runCommand(command);
|
|
76
|
+
action.respond({ successCount });
|
|
77
|
+
});
|
|
78
|
+
bridge.registerHandler(ActionId.SendScriptEvent, (action) => {
|
|
79
|
+
const { id, message } = action.data;
|
|
80
|
+
system.sendScriptEvent(id, message);
|
|
81
|
+
action.respond();
|
|
82
|
+
});
|
|
83
|
+
bridge.registerHandler(ActionId.GetTPS, (action) => {
|
|
84
|
+
const tps = getTPS();
|
|
85
|
+
action.respond({ tps });
|
|
86
|
+
});
|
|
87
|
+
bridge.registerHandler(ActionId.GetEntityLocation, (action) => {
|
|
88
|
+
const { entityUniqueId } = action.data;
|
|
89
|
+
const entity = world.getEntity(entityUniqueId);
|
|
90
|
+
if (!entity) throw new Error("Entity not found");
|
|
91
|
+
action.respond({ location: entity.location });
|
|
92
|
+
});
|
|
93
|
+
bridge.registerHandler(ActionId.GetEntityDimension, (action) => {
|
|
94
|
+
const { entityUniqueId } = action.data;
|
|
95
|
+
const entity = world.getEntity(entityUniqueId);
|
|
96
|
+
if (!entity) throw new Error("Entity not found");
|
|
97
|
+
action.respond({ dimension: createDimensionDescriptor(entity.dimension) });
|
|
98
|
+
});
|
|
99
|
+
bridge.registerHandler(ActionId.GetGameMode, (action) => {
|
|
100
|
+
const { playerUniqueId } = action.data;
|
|
101
|
+
const player = world.getEntity(playerUniqueId);
|
|
102
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
103
|
+
action.respond({ gameMode: player.getGameMode() });
|
|
104
|
+
});
|
|
105
|
+
bridge.registerHandler(ActionId.SetGameMode, (action) => {
|
|
106
|
+
const { playerUniqueId, gameMode } = action.data;
|
|
107
|
+
const player = world.getEntity(playerUniqueId);
|
|
108
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
109
|
+
player.setGameMode(gameMode);
|
|
110
|
+
action.respond();
|
|
111
|
+
});
|
|
112
|
+
bridge.registerHandler(ActionId.SetTitle, (action) => {
|
|
113
|
+
const { playerUniqueId, title, options } = action.data;
|
|
114
|
+
const player = world.getEntity(playerUniqueId);
|
|
115
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
116
|
+
player.onScreenDisplay.setTitle(title, options);
|
|
117
|
+
action.respond();
|
|
118
|
+
});
|
|
119
|
+
bridge.registerHandler(ActionId.UpdateSubtitle, (action) => {
|
|
120
|
+
const { playerUniqueId, subtitle } = action.data;
|
|
121
|
+
const player = world.getEntity(playerUniqueId);
|
|
122
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
123
|
+
player.onScreenDisplay.updateSubtitle(subtitle);
|
|
124
|
+
action.respond();
|
|
125
|
+
});
|
|
126
|
+
bridge.registerHandler(ActionId.SetActionBar, (action) => {
|
|
127
|
+
const { playerUniqueId, text } = action.data;
|
|
128
|
+
const player = world.getEntity(playerUniqueId);
|
|
129
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
130
|
+
player.onScreenDisplay.setActionBar(text);
|
|
131
|
+
action.respond();
|
|
132
|
+
});
|
|
133
|
+
bridge.registerHandler(ActionId.KickPlayer, (action) => {
|
|
134
|
+
const { playerUniqueId, reason } = action.data;
|
|
135
|
+
const player = world.getEntity(playerUniqueId);
|
|
136
|
+
if (!(player instanceof Player)) throw new Error("Player not found");
|
|
137
|
+
player.runCommand(`kick @s ${reason ? reason : ""}`);
|
|
138
|
+
action.respond();
|
|
139
|
+
});
|
|
140
|
+
bridge.registerHandler(ActionId.GetScore, (action) => {
|
|
141
|
+
const { objectiveId, participant } = action.data;
|
|
142
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
143
|
+
if (!objective) throw new Error(`Objective '${objectiveId}' not found`);
|
|
144
|
+
const target = participant.uniqueId ? world.getEntity(participant.uniqueId) : participant.fakePlayer;
|
|
145
|
+
if (!target) throw new Error(`Participant '${participant.uniqueId}' not found`);
|
|
146
|
+
action.respond({ value: target ? objective.getScore(target) ?? null : null });
|
|
147
|
+
});
|
|
148
|
+
bridge.registerHandler(ActionId.UpdateScore, (action) => {
|
|
149
|
+
const { objectiveId, participant, type, score } = action.data;
|
|
150
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
151
|
+
if (!objective) throw new Error(`Objective '${objectiveId}' not found`);
|
|
152
|
+
const target = participant.uniqueId ? world.getEntity(participant.uniqueId) : participant.fakePlayer;
|
|
153
|
+
if (!target) throw new Error(`Participant '${participant.uniqueId}' not found`);
|
|
154
|
+
let newScore = score;
|
|
155
|
+
if (type === "set") objective.setScore(target, score);
|
|
156
|
+
else if (type === "add") newScore = objective.addScore(target, score);
|
|
157
|
+
action.respond({ value: newScore });
|
|
158
|
+
});
|
|
159
|
+
bridge.registerHandler(ActionId.GetAllScores, (action) => {
|
|
160
|
+
const { objectiveId } = action.data;
|
|
161
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
162
|
+
if (!objective) throw new Error(`Objective '${objectiveId}' not found`);
|
|
163
|
+
const scores = objective.getScores().map(createScoreboardScoreInfoDescriptor);
|
|
164
|
+
action.respond({ scores });
|
|
165
|
+
});
|
|
166
|
+
bridge.registerHandler(ActionId.RemoveParticipant, (action) => {
|
|
167
|
+
const { objectiveId, participant } = action.data;
|
|
168
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
169
|
+
if (!objective) throw new Error(`Objective '${objectiveId}' not found`);
|
|
170
|
+
const target = participant.uniqueId ? world.getEntity(participant.uniqueId) : participant.fakePlayer;
|
|
171
|
+
if (!target) throw new Error(`Participant '${participant.uniqueId}' not found`);
|
|
172
|
+
action.respond({ result: objective.removeParticipant(target) });
|
|
173
|
+
});
|
|
174
|
+
bridge.registerHandler(ActionId.GetObjective, (action) => {
|
|
175
|
+
const { objectiveId } = action.data;
|
|
176
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
177
|
+
action.respond({ objective: objective ? createScoreboardObjectiveDescriptor(objective) : void 0 });
|
|
178
|
+
});
|
|
179
|
+
bridge.registerHandler(ActionId.GetAllObjectives, (action) => {
|
|
180
|
+
const objectiveDescriptors = world.scoreboard.getObjectives().map(createScoreboardObjectiveDescriptor);
|
|
181
|
+
action.respond({ objectives: objectiveDescriptors });
|
|
182
|
+
});
|
|
183
|
+
bridge.registerHandler(ActionId.UpdateObjective, (action) => {
|
|
184
|
+
const { type, objectiveId, displayName } = action.data;
|
|
185
|
+
let objective;
|
|
186
|
+
if (type === "add") objective = world.scoreboard.addObjective(objectiveId, displayName);
|
|
187
|
+
else if (type === "remove") world.scoreboard.removeObjective(objectiveId);
|
|
188
|
+
action.respond({ objective: objective ? createScoreboardObjectiveDescriptor(objective) : void 0 });
|
|
189
|
+
});
|
|
190
|
+
bridge.registerHandler(ActionId.SetObjectiveDisplay, (action) => {
|
|
191
|
+
const { displaySlotId, objectiveId, sortOrder } = action.data;
|
|
192
|
+
if (objectiveId) {
|
|
193
|
+
const objective = world.scoreboard.getObjective(objectiveId);
|
|
194
|
+
if (!objective) throw new Error(`Objective '${objectiveId}' not found`);
|
|
195
|
+
world.scoreboard.setObjectiveAtDisplaySlot(displaySlotId, {
|
|
196
|
+
objective,
|
|
197
|
+
sortOrder: sortOrder ? ObjectiveSortOrder[sortOrder] : void 0
|
|
198
|
+
});
|
|
199
|
+
} else world.scoreboard.clearObjectiveAtDisplaySlot(displaySlotId);
|
|
200
|
+
action.respond();
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/client/event.ts
|
|
206
|
+
function registerEvents(bridge) {
|
|
207
|
+
world.afterEvents.playerSpawn.subscribe((ev) => {
|
|
208
|
+
if (!bridge.isConnected || !ev.initialSpawn) return;
|
|
209
|
+
bridge.send(ActionId.PlayerJoin, { player: createPlayerDescriptor(ev.player) });
|
|
210
|
+
});
|
|
211
|
+
world.afterEvents.playerLeave.subscribe((ev) => {
|
|
212
|
+
if (!bridge.isConnected) return;
|
|
213
|
+
bridge.send(ActionId.PlayerLeave, { playerUniqueId: ev.playerId });
|
|
214
|
+
});
|
|
215
|
+
world.afterEvents.chatSend.subscribe((ev) => {
|
|
216
|
+
if (!bridge.isConnected) return;
|
|
217
|
+
bridge.send(ActionId.ChatSend, {
|
|
218
|
+
senderName: ev.sender.name,
|
|
219
|
+
senderUniqueId: ev.sender.id,
|
|
220
|
+
message: ev.message
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/client/features/settings.ts
|
|
227
|
+
var SettingsForm = class SettingsForm {
|
|
228
|
+
constructor(player, client) {
|
|
229
|
+
this.player = player;
|
|
230
|
+
this.client = client;
|
|
231
|
+
}
|
|
232
|
+
static async show(player, client) {
|
|
233
|
+
await new SettingsForm(player, client).main();
|
|
234
|
+
}
|
|
235
|
+
async main() {
|
|
236
|
+
const res = await new ModalFormData().title("discord-mcbe settings").textField("clientId", "Client ID", { defaultValue: this.client.getClientId() }).show(this.player);
|
|
237
|
+
if (res.canceled || !res.formValues) return;
|
|
238
|
+
const newClientId = res.formValues[0];
|
|
239
|
+
this.client.setClientId(newClientId);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/client/command.ts
|
|
245
|
+
function registerCommands(registry, client) {
|
|
246
|
+
for (const commandName of ["dmc:dmc", "dmc:discord-mcbe"]) registry.registerCommand({
|
|
247
|
+
name: commandName,
|
|
248
|
+
description: "Open discord-mcbe settings",
|
|
249
|
+
permissionLevel: CommandPermissionLevel.Admin
|
|
250
|
+
}, (origin) => {
|
|
251
|
+
const player = origin.sourceEntity;
|
|
252
|
+
if (!(player instanceof Player)) return {
|
|
253
|
+
status: CustomCommandStatus.Failure,
|
|
254
|
+
message: "This command can only be used by players."
|
|
255
|
+
};
|
|
256
|
+
system.run(() => SettingsForm.show(player, client));
|
|
257
|
+
return { status: CustomCommandStatus.Success };
|
|
258
|
+
});
|
|
259
|
+
registry.registerCommand({
|
|
260
|
+
name: "dmc:setid",
|
|
261
|
+
description: "Set the clientId for discord-mcbe (requires reconnect)",
|
|
262
|
+
permissionLevel: CommandPermissionLevel.Host,
|
|
263
|
+
mandatoryParameters: [{
|
|
264
|
+
type: CustomCommandParamType.String,
|
|
265
|
+
name: "clientId"
|
|
266
|
+
}]
|
|
267
|
+
}, (_, clientId) => {
|
|
268
|
+
client.setClientId(clientId);
|
|
269
|
+
return {
|
|
270
|
+
status: CustomCommandStatus.Success,
|
|
271
|
+
message: `Updated clientId to "${clientId}".`
|
|
272
|
+
};
|
|
273
|
+
});
|
|
274
|
+
registry.registerCommand({
|
|
275
|
+
name: "dmc:disconnect",
|
|
276
|
+
description: "Disconnect from discord-mcbe server",
|
|
277
|
+
permissionLevel: CommandPermissionLevel.Admin
|
|
278
|
+
}, () => {
|
|
279
|
+
if (client.bridge.isConnected) {
|
|
280
|
+
client.bridge.disconnect();
|
|
281
|
+
return {
|
|
282
|
+
status: CustomCommandStatus.Success,
|
|
283
|
+
message: "Disconnecting from discord-mcbe server..."
|
|
284
|
+
};
|
|
285
|
+
} else return {
|
|
286
|
+
status: CustomCommandStatus.Failure,
|
|
287
|
+
message: "discord-mcbe is not connected now."
|
|
288
|
+
};
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
//#endregion
|
|
293
|
+
//#region src/utils/logger.ts
|
|
294
|
+
var Logger = class {
|
|
295
|
+
constructor(name) {
|
|
296
|
+
this.name = name;
|
|
297
|
+
}
|
|
298
|
+
log(...message) {
|
|
299
|
+
console.log(`[${this.name}] ${this.formatMessage(message)}`);
|
|
300
|
+
}
|
|
301
|
+
info(...message) {
|
|
302
|
+
console.info(`[${this.name}] ${this.formatMessage(message)}`);
|
|
303
|
+
}
|
|
304
|
+
warn(...message) {
|
|
305
|
+
console.warn(`[${this.name}] ${this.formatMessage(message)}`);
|
|
306
|
+
}
|
|
307
|
+
error(...message) {
|
|
308
|
+
console.error(`[${this.name}] ${this.formatMessage(message)}`);
|
|
309
|
+
}
|
|
310
|
+
debug(...message) {}
|
|
311
|
+
formatMessage(message) {
|
|
312
|
+
return message.map((msg) => {
|
|
313
|
+
if (msg instanceof Error) return msg.stack ?? msg;
|
|
314
|
+
else if (typeof msg !== "string") return JSON.stringify(msg, null, 2);
|
|
315
|
+
return msg;
|
|
316
|
+
}).join(" ");
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
//#endregion
|
|
321
|
+
//#region src/client/base-client.ts
|
|
322
|
+
let ClientType = /* @__PURE__ */ function(ClientType$1) {
|
|
323
|
+
ClientType$1["Local"] = "Local";
|
|
324
|
+
ClientType$1["BDS"] = "BDS";
|
|
325
|
+
return ClientType$1;
|
|
326
|
+
}({});
|
|
327
|
+
var BaseClient = class {
|
|
328
|
+
bridge;
|
|
329
|
+
logger = new Logger("discord-mcbe");
|
|
330
|
+
constructor(bridge) {
|
|
331
|
+
this.bridge = bridge;
|
|
332
|
+
registerHandlers(this.bridge);
|
|
333
|
+
registerEvents(this.bridge);
|
|
334
|
+
system.beforeEvents.startup.subscribe((ev) => registerCommands(ev.customCommandRegistry, this));
|
|
335
|
+
this.bridge.on("connect", this.onConnect.bind(this));
|
|
336
|
+
}
|
|
337
|
+
setClientId(clientId) {
|
|
338
|
+
world.setDynamicProperty("clientId", clientId);
|
|
339
|
+
}
|
|
340
|
+
getClientId() {
|
|
341
|
+
return world.getDynamicProperty("clientId");
|
|
342
|
+
}
|
|
343
|
+
async onConnect() {
|
|
344
|
+
const players = world.getPlayers();
|
|
345
|
+
try {
|
|
346
|
+
await this.bridge.send(ActionId.WorldInitialize, { players: players.map(createPlayerDescriptor) });
|
|
347
|
+
} catch (error) {
|
|
348
|
+
this.logger.error("Failed to send WorldInitializeAction:", error);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
isLocal() {
|
|
352
|
+
return this.type === ClientType.Local;
|
|
353
|
+
}
|
|
354
|
+
isBDS() {
|
|
355
|
+
return this.type === ClientType.BDS;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
//#endregion
|
|
360
|
+
export { ClientType as n, Logger as r, BaseClient as t };
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ActionId } from "@discord-mcbe/shared";
|
|
2
|
+
import { ActionHandler, ScriptBridgeClient } from "@script-bridge/client";
|
|
3
|
+
import { BaseAction, DisconnectReason } from "@script-bridge/protocol";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/emitter.d.ts
|
|
6
|
+
type Listener$1<T> = (data: T) => void;
|
|
7
|
+
declare class Emitter<T> {
|
|
8
|
+
private listeners;
|
|
9
|
+
on<K extends keyof T>(event: K, listener: Listener$1<T[K]>): void;
|
|
10
|
+
once<K extends keyof T>(event: K, listener: Listener$1<T[K]>): void;
|
|
11
|
+
emit<K extends keyof T>(event: K, data: T[K]): void;
|
|
12
|
+
off<K extends keyof T>(event: K, listener: Listener$1<T[K]>): void;
|
|
13
|
+
removeAllListeners<K extends keyof T>(event: K): void;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region src/utils/logger.d.ts
|
|
17
|
+
declare class Logger {
|
|
18
|
+
private readonly name;
|
|
19
|
+
constructor(name: string);
|
|
20
|
+
log(...message: unknown[]): void;
|
|
21
|
+
info(...message: unknown[]): void;
|
|
22
|
+
warn(...message: unknown[]): void;
|
|
23
|
+
error(...message: unknown[]): void;
|
|
24
|
+
debug(...message: unknown[]): void;
|
|
25
|
+
private formatMessage;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region src/transport/interfaces.d.ts
|
|
29
|
+
type Listener<T> = (data: T) => void;
|
|
30
|
+
type IResponse<T = unknown> = {
|
|
31
|
+
error?: false;
|
|
32
|
+
data: T;
|
|
33
|
+
} | {
|
|
34
|
+
error: true;
|
|
35
|
+
message: string;
|
|
36
|
+
};
|
|
37
|
+
interface IBridgeClient {
|
|
38
|
+
isConnected: boolean;
|
|
39
|
+
send<T extends BaseAction = BaseAction>(channelId: ActionId, data?: T['request']): Promise<IResponse<T['response']>>;
|
|
40
|
+
registerHandler<A extends BaseAction = BaseAction>(channelId: A['id'], handler: ActionHandler<A>): void;
|
|
41
|
+
disconnect(reason?: DisconnectReason): Promise<void>;
|
|
42
|
+
on(event: 'connect', listener: Listener<{
|
|
43
|
+
sessionId: string;
|
|
44
|
+
}>): void;
|
|
45
|
+
on(event: 'disconnect', listener: Listener<{
|
|
46
|
+
reason: DisconnectReason;
|
|
47
|
+
}>): void;
|
|
48
|
+
}
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/transport/socket.d.ts
|
|
51
|
+
interface SocketEvents {
|
|
52
|
+
ready: {};
|
|
53
|
+
connect: {
|
|
54
|
+
sessionId: string;
|
|
55
|
+
};
|
|
56
|
+
disconnect: {
|
|
57
|
+
reason: DisconnectReason;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
interface ClientOptions {
|
|
61
|
+
clientId: string | (() => string);
|
|
62
|
+
}
|
|
63
|
+
declare class SocketBridgeClient extends Emitter<SocketEvents> implements IBridgeClient {
|
|
64
|
+
static readonly PROTOCOL_VERSION = 1;
|
|
65
|
+
private readonly _clientId;
|
|
66
|
+
private readonly sendQueue;
|
|
67
|
+
private readonly awaitingResponses;
|
|
68
|
+
private readonly actionHandlers;
|
|
69
|
+
private readonly deltaTimes;
|
|
70
|
+
private readonly logger;
|
|
71
|
+
private previousRequestId;
|
|
72
|
+
private currentSessionId;
|
|
73
|
+
private lastQueryReceivedAt;
|
|
74
|
+
constructor(options: ClientOptions);
|
|
75
|
+
get isConnected(): boolean;
|
|
76
|
+
get clientId(): string;
|
|
77
|
+
send<A extends BaseAction = BaseAction>(channelId: A['id'], data?: A['request']): Promise<IResponse<A['response']>>;
|
|
78
|
+
registerHandler<A extends BaseAction = BaseAction>(channelId: A['id'], handler: ActionHandler<A>): void;
|
|
79
|
+
disconnect(reason?: DisconnectReason): Promise<void>;
|
|
80
|
+
destroy(): void;
|
|
81
|
+
private clearResponses;
|
|
82
|
+
private handleConnection;
|
|
83
|
+
private handleResponse;
|
|
84
|
+
private handleRequest;
|
|
85
|
+
private getQueue;
|
|
86
|
+
private onQuery;
|
|
87
|
+
/** Process incoming messages from server */
|
|
88
|
+
private onMessage;
|
|
89
|
+
/**
|
|
90
|
+
* Register internal commands
|
|
91
|
+
*/
|
|
92
|
+
private onStartup;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/client/base-client.d.ts
|
|
96
|
+
declare enum ClientType {
|
|
97
|
+
Local = "Local",
|
|
98
|
+
BDS = "BDS",
|
|
99
|
+
}
|
|
100
|
+
declare abstract class BaseClient<T extends IBridgeClient = IBridgeClient> {
|
|
101
|
+
readonly bridge: T;
|
|
102
|
+
readonly logger: Logger;
|
|
103
|
+
abstract readonly type: ClientType;
|
|
104
|
+
constructor(bridge: T);
|
|
105
|
+
setClientId(clientId: string): void;
|
|
106
|
+
getClientId(): string | undefined;
|
|
107
|
+
private onConnect;
|
|
108
|
+
isLocal(): this is BaseClient<SocketBridgeClient>;
|
|
109
|
+
isBDS(): this is BaseClient<ScriptBridgeClient>;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { ClientType as n, SocketBridgeClient as r, BaseClient as t };
|
package/dist/local.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { n as ClientType, r as SocketBridgeClient, t as BaseClient } from "./index-CzbgOaig.js";
|
|
2
|
+
|
|
3
|
+
//#region src/local.d.ts
|
|
4
|
+
interface BridgeClientOptions {
|
|
5
|
+
clientId?: string | (() => string);
|
|
6
|
+
}
|
|
7
|
+
declare class BridgeClient extends BaseClient<SocketBridgeClient> {
|
|
8
|
+
readonly type = ClientType.Local;
|
|
9
|
+
constructor(options?: BridgeClientOptions);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { BridgeClient, BridgeClientOptions };
|
package/dist/local.js
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { n as ClientType, r as Logger, t as BaseClient } from "./client-DgUd3XAf.js";
|
|
2
|
+
import { CommandPermissionLevel, CustomCommandParamType, CustomCommandStatus, system, world } from "@minecraft/server";
|
|
3
|
+
import { SocketBridge } from "@discord-mcbe/shared";
|
|
4
|
+
import { DisconnectReason, InternalAction, PayloadType, ResponseErrorReason } from "@script-bridge/protocol";
|
|
5
|
+
|
|
6
|
+
//#region src/utils/emitter.ts
|
|
7
|
+
var Emitter = class {
|
|
8
|
+
listeners = /* @__PURE__ */ new Map();
|
|
9
|
+
on(event, listener) {
|
|
10
|
+
let listeners = this.listeners.get(event);
|
|
11
|
+
if (!listeners) {
|
|
12
|
+
listeners = [];
|
|
13
|
+
this.listeners.set(event, listeners);
|
|
14
|
+
}
|
|
15
|
+
listeners.push(listener);
|
|
16
|
+
}
|
|
17
|
+
once(event, listener) {
|
|
18
|
+
const onceListener = (data) => {
|
|
19
|
+
listener(data);
|
|
20
|
+
this.off(event, onceListener);
|
|
21
|
+
};
|
|
22
|
+
this.on(event, onceListener);
|
|
23
|
+
}
|
|
24
|
+
emit(event, data) {
|
|
25
|
+
for (const listener of this.listeners.get(event) ?? []) listener(data);
|
|
26
|
+
}
|
|
27
|
+
off(event, listener) {
|
|
28
|
+
const currentListeners = this.listeners.get(event);
|
|
29
|
+
if (currentListeners) this.listeners.set(event, currentListeners.filter((l) => l !== listener));
|
|
30
|
+
}
|
|
31
|
+
removeAllListeners(event) {
|
|
32
|
+
this.listeners.set(event, []);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/transport/socket.ts
|
|
38
|
+
var SocketBridgeClient = class SocketBridgeClient extends Emitter {
|
|
39
|
+
static PROTOCOL_VERSION = SocketBridge.PROTOCOL_VERSION;
|
|
40
|
+
_clientId;
|
|
41
|
+
sendQueue = [];
|
|
42
|
+
awaitingResponses = /* @__PURE__ */ new Map();
|
|
43
|
+
actionHandlers = /* @__PURE__ */ new Map();
|
|
44
|
+
deltaTimes = [];
|
|
45
|
+
logger = new Logger("discord-mcbe");
|
|
46
|
+
previousRequestId = 0;
|
|
47
|
+
currentSessionId = null;
|
|
48
|
+
lastQueryReceivedAt = null;
|
|
49
|
+
constructor(options) {
|
|
50
|
+
super();
|
|
51
|
+
this._clientId = options.clientId;
|
|
52
|
+
system.beforeEvents.startup.subscribe(this.onStartup.bind(this));
|
|
53
|
+
system.afterEvents.scriptEventReceive.subscribe((event) => {
|
|
54
|
+
if (event.id === "bridge:message") this.onMessage(event.message.trim());
|
|
55
|
+
}, { namespaces: ["bridge"] });
|
|
56
|
+
world.afterEvents.worldLoad.subscribe(() => {
|
|
57
|
+
this.emit("ready", {});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
get isConnected() {
|
|
61
|
+
return this.currentSessionId !== null;
|
|
62
|
+
}
|
|
63
|
+
get clientId() {
|
|
64
|
+
return typeof this._clientId === "function" ? this._clientId() : this._clientId;
|
|
65
|
+
}
|
|
66
|
+
async send(channelId, data) {
|
|
67
|
+
if (!this.currentSessionId) throw new Error("No active session");
|
|
68
|
+
const requestId = ++this.previousRequestId;
|
|
69
|
+
this.sendQueue.push({
|
|
70
|
+
type: PayloadType.Request,
|
|
71
|
+
channelId,
|
|
72
|
+
data,
|
|
73
|
+
sessionId: this.currentSessionId,
|
|
74
|
+
requestId
|
|
75
|
+
});
|
|
76
|
+
return new Promise((resolve) => {
|
|
77
|
+
this.awaitingResponses.set(requestId, (response) => {
|
|
78
|
+
resolve(response);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
registerHandler(channelId, handler) {
|
|
83
|
+
if (this.actionHandlers.has(channelId)) console.warn("[SocketBridge] Overwriting existing handler for channel:", channelId);
|
|
84
|
+
this.actionHandlers.set(channelId, handler);
|
|
85
|
+
}
|
|
86
|
+
async disconnect(reason = DisconnectReason.Disconnect) {
|
|
87
|
+
try {
|
|
88
|
+
await this.send(InternalAction.Disconnect, { reason });
|
|
89
|
+
} catch (e) {
|
|
90
|
+
this.logger.warn("Failed to send disconnect message", e);
|
|
91
|
+
}
|
|
92
|
+
this.destroy();
|
|
93
|
+
this.emit("disconnect", { reason });
|
|
94
|
+
}
|
|
95
|
+
destroy() {
|
|
96
|
+
this.clearResponses();
|
|
97
|
+
this.sendQueue.length = 0;
|
|
98
|
+
this.deltaTimes.length = 0;
|
|
99
|
+
this.lastQueryReceivedAt = null;
|
|
100
|
+
this.currentSessionId = null;
|
|
101
|
+
}
|
|
102
|
+
clearResponses() {
|
|
103
|
+
for (const [requestId, resolve] of this.awaitingResponses.entries()) resolve({
|
|
104
|
+
type: PayloadType.Response,
|
|
105
|
+
error: true,
|
|
106
|
+
message: "Session disconnected before response was received",
|
|
107
|
+
errorReason: ResponseErrorReason.Abort,
|
|
108
|
+
sessionId: this.currentSessionId,
|
|
109
|
+
requestId
|
|
110
|
+
});
|
|
111
|
+
this.awaitingResponses.clear();
|
|
112
|
+
}
|
|
113
|
+
handleConnection(protocolVersion, sessionId) {
|
|
114
|
+
let body;
|
|
115
|
+
if (SocketBridgeClient.PROTOCOL_VERSION > protocolVersion) body = {
|
|
116
|
+
error: true,
|
|
117
|
+
errorReason: DisconnectReason.OutdatedServer
|
|
118
|
+
};
|
|
119
|
+
else if (SocketBridgeClient.PROTOCOL_VERSION < protocolVersion) body = {
|
|
120
|
+
error: true,
|
|
121
|
+
errorReason: DisconnectReason.OutdatedClient
|
|
122
|
+
};
|
|
123
|
+
else {
|
|
124
|
+
body = {
|
|
125
|
+
protocolVersion: SocketBridgeClient.PROTOCOL_VERSION,
|
|
126
|
+
clientId: this.clientId
|
|
127
|
+
};
|
|
128
|
+
this.destroy();
|
|
129
|
+
this.currentSessionId = sessionId;
|
|
130
|
+
this.emit("connect", { sessionId });
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
status: CustomCommandStatus.Success,
|
|
134
|
+
message: JSON.stringify(body)
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
async handleResponse(response) {
|
|
138
|
+
const { requestId } = response;
|
|
139
|
+
const resolve = this.awaitingResponses.get(requestId);
|
|
140
|
+
if (resolve) {
|
|
141
|
+
resolve(response);
|
|
142
|
+
this.awaitingResponses.delete(requestId);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async handleRequest(request) {
|
|
146
|
+
const { requestId, sessionId, channelId } = request;
|
|
147
|
+
const handler = this.actionHandlers.get(channelId);
|
|
148
|
+
if (!handler) {
|
|
149
|
+
console.error("[SocketBridge] No handler for channel:", channelId);
|
|
150
|
+
this.sendQueue.push({
|
|
151
|
+
type: PayloadType.Response,
|
|
152
|
+
error: true,
|
|
153
|
+
errorReason: ResponseErrorReason.UnhandledRequest,
|
|
154
|
+
message: `No handler found for channel: ${channelId}`,
|
|
155
|
+
requestId,
|
|
156
|
+
sessionId
|
|
157
|
+
});
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
await handler({
|
|
162
|
+
data: request.data,
|
|
163
|
+
respond: (data) => {
|
|
164
|
+
this.sendQueue.push({
|
|
165
|
+
type: PayloadType.Response,
|
|
166
|
+
data,
|
|
167
|
+
requestId,
|
|
168
|
+
sessionId
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
} catch (err) {
|
|
173
|
+
console.error("[SocketBridge] Error while handling request:", channelId, err);
|
|
174
|
+
this.sendQueue.push({
|
|
175
|
+
type: PayloadType.Response,
|
|
176
|
+
error: true,
|
|
177
|
+
errorReason: ResponseErrorReason.InternalError,
|
|
178
|
+
message: `An error occurred while handling the request\n${String(err)}`,
|
|
179
|
+
requestId,
|
|
180
|
+
sessionId
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
getQueue() {
|
|
185
|
+
const queue = this.sendQueue.slice();
|
|
186
|
+
this.sendQueue.length = 0;
|
|
187
|
+
return queue;
|
|
188
|
+
}
|
|
189
|
+
onQuery(sessionId) {
|
|
190
|
+
let result;
|
|
191
|
+
if (this.currentSessionId === sessionId) {
|
|
192
|
+
result = {
|
|
193
|
+
error: false,
|
|
194
|
+
data: this.getQueue()
|
|
195
|
+
};
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
if (this.lastQueryReceivedAt !== null) {
|
|
198
|
+
this.deltaTimes.push(now - this.lastQueryReceivedAt);
|
|
199
|
+
if (this.deltaTimes.length > 20) this.deltaTimes.shift();
|
|
200
|
+
}
|
|
201
|
+
this.lastQueryReceivedAt = now;
|
|
202
|
+
} else result = {
|
|
203
|
+
error: true,
|
|
204
|
+
errorReason: ResponseErrorReason.InvalidSession
|
|
205
|
+
};
|
|
206
|
+
return {
|
|
207
|
+
status: CustomCommandStatus.Success,
|
|
208
|
+
message: JSON.stringify(result)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/** Process incoming messages from server */
|
|
212
|
+
onMessage(rawMessage) {
|
|
213
|
+
let message;
|
|
214
|
+
try {
|
|
215
|
+
message = JSON.parse(rawMessage);
|
|
216
|
+
} catch (e) {
|
|
217
|
+
console.error("[SocketBridge] Failed to parse message from bridge:", e);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (message.type === PayloadType.Response) this.handleResponse(message).catch((error) => {
|
|
221
|
+
console.error("[SocketBridge] Failed to handle response:", error);
|
|
222
|
+
});
|
|
223
|
+
else if (message.type === PayloadType.Request) this.handleRequest(message).catch((error) => {
|
|
224
|
+
console.error("[SocketBridge] Failed to handle request:", error);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Register internal commands
|
|
229
|
+
*/
|
|
230
|
+
onStartup(ev) {
|
|
231
|
+
const registry = ev.customCommandRegistry;
|
|
232
|
+
registry.registerCommand({
|
|
233
|
+
name: "dmc:__query__",
|
|
234
|
+
description: "§8[internal] query messages for SocketBridge",
|
|
235
|
+
permissionLevel: CommandPermissionLevel.Host,
|
|
236
|
+
mandatoryParameters: [{
|
|
237
|
+
name: "sessionId",
|
|
238
|
+
type: CustomCommandParamType.String
|
|
239
|
+
}]
|
|
240
|
+
}, (_, sessionId) => this.onQuery(sessionId));
|
|
241
|
+
registry.registerCommand({
|
|
242
|
+
name: "dmc:__connect__",
|
|
243
|
+
description: "§8[internal] initialize connection for SocketBridge",
|
|
244
|
+
permissionLevel: CommandPermissionLevel.Host,
|
|
245
|
+
mandatoryParameters: [{
|
|
246
|
+
name: "protocolVersion",
|
|
247
|
+
type: CustomCommandParamType.Integer
|
|
248
|
+
}, {
|
|
249
|
+
name: "sessionId",
|
|
250
|
+
type: CustomCommandParamType.String
|
|
251
|
+
}]
|
|
252
|
+
}, (_, protocolVersion, sessionId) => this.handleConnection(protocolVersion, sessionId));
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
//#endregion
|
|
257
|
+
//#region src/local.ts
|
|
258
|
+
const defaultOptions = { clientId: () => world.getDynamicProperty("clientId") ?? "discord-mcbe-local" };
|
|
259
|
+
var BridgeClient = class extends BaseClient {
|
|
260
|
+
type = ClientType.Local;
|
|
261
|
+
constructor(options = {}) {
|
|
262
|
+
const bridge = new SocketBridgeClient({
|
|
263
|
+
...defaultOptions,
|
|
264
|
+
...options
|
|
265
|
+
});
|
|
266
|
+
super(bridge);
|
|
267
|
+
bridge.on("ready", () => {
|
|
268
|
+
console.info("[discord-mcbe] Listening connection from discord-mcbe server...");
|
|
269
|
+
});
|
|
270
|
+
bridge.on("connect", () => {
|
|
271
|
+
console.info("[discord-mcbe] Connection established!");
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
//#endregion
|
|
277
|
+
export { BridgeClient };
|
package/package.json
CHANGED
|
@@ -1,10 +1,43 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@discord-mcbe/client",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
"version": "4.0.0-beta.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/tutinoko2048/discord-mcbe.git",
|
|
7
|
+
"directory": "packages/client"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"type": "module",
|
|
13
|
+
"exports": {
|
|
14
|
+
"./bds": {
|
|
15
|
+
"default": "./dist/bds.js",
|
|
16
|
+
"types": "./dist/bds.d.ts"
|
|
17
|
+
},
|
|
18
|
+
"./local": {
|
|
19
|
+
"default": "./dist/local.js",
|
|
20
|
+
"types": "./dist/local.d.ts"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@minecraft/server": "2.5.0-beta.1.21.130-stable",
|
|
25
|
+
"@minecraft/server-ui": "2.0.0",
|
|
26
|
+
"@script-bridge/client": "^0.5.0",
|
|
27
|
+
"@script-bridge/protocol": "^0.5.0",
|
|
28
|
+
"@discord-mcbe/shared": "4.0.0-beta.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@bedrock-apis/env-types": "1.0.0-beta.6",
|
|
32
|
+
"@discord-mcbe/internal-config": "0.1.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsdown",
|
|
36
|
+
"watch": "tsdown --watch",
|
|
37
|
+
"lint": "vp lint",
|
|
38
|
+
"lint:fix": "vp lint --fix",
|
|
39
|
+
"format": "vp fmt",
|
|
40
|
+
"check": "vp check",
|
|
41
|
+
"clean": "rimraf dist .turbo tsconfig.tsbuildinfo"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/README.md
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# @discord-mcbe/client
|
|
2
|
-
|
|
3
|
-
## ⚠️ IMPORTANT NOTICE ⚠️
|
|
4
|
-
|
|
5
|
-
**This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
|
|
6
|
-
|
|
7
|
-
This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
|
|
8
|
-
|
|
9
|
-
## Purpose
|
|
10
|
-
|
|
11
|
-
This package exists to:
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@discord-mcbe/client`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
15
|
-
|
|
16
|
-
## What is OIDC Trusted Publishing?
|
|
17
|
-
|
|
18
|
-
OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
|
|
19
|
-
|
|
20
|
-
## Setup Instructions
|
|
21
|
-
|
|
22
|
-
To properly configure OIDC trusted publishing for this package:
|
|
23
|
-
|
|
24
|
-
1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
28
|
-
|
|
29
|
-
## DO NOT USE THIS PACKAGE
|
|
30
|
-
|
|
31
|
-
This package is a placeholder for OIDC configuration only. It:
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
36
|
-
|
|
37
|
-
## More Information
|
|
38
|
-
|
|
39
|
-
For more details about npm's trusted publishing feature, see:
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
42
|
-
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
**Maintained for OIDC setup purposes only**
|