@mafly/bdev-cli 0.0.0-stage → 0.1.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/README.md +225 -2
- package/dist/commands/build.d.ts +6 -0
- package/dist/commands/build.js +94 -0
- package/dist/commands/config.d.ts +7 -0
- package/dist/commands/config.js +46 -0
- package/dist/commands/dev.d.ts +8 -0
- package/dist/commands/dev.js +165 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +84 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +164 -0
- package/dist/commands/package.d.ts +5 -0
- package/dist/commands/package.js +103 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +148 -0
- package/dist/utils/bundler.d.ts +2 -0
- package/dist/utils/bundler.js +29 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.js +58 -0
- package/dist/utils/logger.d.ts +8 -0
- package/dist/utils/logger.js +19 -0
- package/dist/utils/manifest.d.ts +42 -0
- package/dist/utils/manifest.js +146 -0
- package/dist/utils/mojang.d.ts +8 -0
- package/dist/utils/mojang.js +122 -0
- package/dist/utils/wsserver.d.ts +25 -0
- package/dist/utils/wsserver.js +109 -0
- package/package.json +52 -4
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { v4 as uuidv4, validate as validateUuid } from "uuid";
|
|
3
|
+
export function validateManifest(manifestPath) {
|
|
4
|
+
const errors = [];
|
|
5
|
+
if (!fs.existsSync(manifestPath)) {
|
|
6
|
+
return { valid: false, errors: [`File not found: ${manifestPath}`] };
|
|
7
|
+
}
|
|
8
|
+
let raw;
|
|
9
|
+
try {
|
|
10
|
+
const content = fs.readFileSync(manifestPath, "utf-8");
|
|
11
|
+
raw = JSON.parse(content);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
return {
|
|
15
|
+
valid: false,
|
|
16
|
+
errors: [`Invalid JSON in ${manifestPath}: ${err.message}`],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (raw.format_version !== 2) {
|
|
20
|
+
errors.push(`'format_version' should be 2 (found ${raw.format_version})`);
|
|
21
|
+
}
|
|
22
|
+
if (!raw.header) {
|
|
23
|
+
errors.push("Missing 'header' object");
|
|
24
|
+
return { valid: false, errors };
|
|
25
|
+
}
|
|
26
|
+
if (!raw.header.name || typeof raw.header.name !== "string") {
|
|
27
|
+
errors.push("Missing or invalid 'header.name'");
|
|
28
|
+
}
|
|
29
|
+
if (!raw.header.uuid || !validateUuid(raw.header.uuid)) {
|
|
30
|
+
errors.push(`Invalid 'header.uuid': ${raw.header.uuid}`);
|
|
31
|
+
}
|
|
32
|
+
if (!Array.isArray(raw.header.version) || raw.header.version.length !== 3) {
|
|
33
|
+
errors.push("'header.version' must be [major, minor, patch] array");
|
|
34
|
+
}
|
|
35
|
+
const seenUuids = new Set();
|
|
36
|
+
if (raw.header.uuid) {
|
|
37
|
+
seenUuids.add(raw.header.uuid.toLowerCase());
|
|
38
|
+
}
|
|
39
|
+
if (!Array.isArray(raw.modules) || raw.modules.length === 0) {
|
|
40
|
+
errors.push("'modules' array must contain at least one module");
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
raw.modules.forEach((mod, idx) => {
|
|
44
|
+
if (!mod.type) {
|
|
45
|
+
errors.push(`Module[${idx}]: missing 'type'`);
|
|
46
|
+
}
|
|
47
|
+
if (!mod.uuid || !validateUuid(mod.uuid)) {
|
|
48
|
+
errors.push(`Module[${idx}]: invalid 'uuid': ${mod.uuid}`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
const lowerUuid = mod.uuid.toLowerCase();
|
|
52
|
+
if (seenUuids.has(lowerUuid)) {
|
|
53
|
+
errors.push(`Duplicate UUID in manifest: ${mod.uuid}`);
|
|
54
|
+
}
|
|
55
|
+
seenUuids.add(lowerUuid);
|
|
56
|
+
}
|
|
57
|
+
if (!Array.isArray(mod.version) || mod.version.length !== 3) {
|
|
58
|
+
errors.push(`Module[${idx}]: 'version' must be [major, minor, patch]`);
|
|
59
|
+
}
|
|
60
|
+
if (mod.type === "script") {
|
|
61
|
+
if (!mod.entry) {
|
|
62
|
+
errors.push(`Script module[${idx}]: missing 'entry' script path`);
|
|
63
|
+
}
|
|
64
|
+
if (mod.language && mod.language !== "javascript") {
|
|
65
|
+
errors.push(`Script module[${idx}]: language should be 'javascript'`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
valid: errors.length === 0,
|
|
72
|
+
errors,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export function generateManifests(opts) {
|
|
76
|
+
const minEngineVersion = opts.minEngineVersion || [1, 21, 0];
|
|
77
|
+
const bpHeaderUuid = uuidv4();
|
|
78
|
+
const bpDataModuleUuid = uuidv4();
|
|
79
|
+
const bpScriptModuleUuid = uuidv4();
|
|
80
|
+
const rpHeaderUuid = uuidv4();
|
|
81
|
+
const rpModuleUuid = uuidv4();
|
|
82
|
+
const bpModules = [
|
|
83
|
+
{
|
|
84
|
+
type: "data",
|
|
85
|
+
uuid: bpDataModuleUuid,
|
|
86
|
+
version: [1, 0, 0],
|
|
87
|
+
},
|
|
88
|
+
];
|
|
89
|
+
if (opts.hasScript) {
|
|
90
|
+
bpModules.push({
|
|
91
|
+
description: "Script Resources",
|
|
92
|
+
language: "javascript",
|
|
93
|
+
type: "script",
|
|
94
|
+
uuid: bpScriptModuleUuid,
|
|
95
|
+
version: [1, 0, 0],
|
|
96
|
+
entry: "scripts/main.js",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
const bpDependencies = [];
|
|
100
|
+
if (opts.hasScript) {
|
|
101
|
+
bpDependencies.push({
|
|
102
|
+
module_name: "@minecraft/server",
|
|
103
|
+
version: opts.serverVersion || "1.16.0",
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (opts.hasRp) {
|
|
107
|
+
bpDependencies.push({
|
|
108
|
+
uuid: rpHeaderUuid,
|
|
109
|
+
version: [1, 0, 0],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
const bpManifest = {
|
|
113
|
+
format_version: 2,
|
|
114
|
+
header: {
|
|
115
|
+
name: `${opts.name} (BP)`,
|
|
116
|
+
description: opts.description || `${opts.name} Behavior Pack`,
|
|
117
|
+
uuid: bpHeaderUuid,
|
|
118
|
+
version: [1, 0, 0],
|
|
119
|
+
min_engine_version: minEngineVersion,
|
|
120
|
+
},
|
|
121
|
+
modules: bpModules,
|
|
122
|
+
dependencies: bpDependencies,
|
|
123
|
+
};
|
|
124
|
+
let rpManifest;
|
|
125
|
+
if (opts.hasRp) {
|
|
126
|
+
rpManifest = {
|
|
127
|
+
format_version: 2,
|
|
128
|
+
header: {
|
|
129
|
+
name: `${opts.name} (RP)`,
|
|
130
|
+
description: opts.description || `${opts.name} Resource Pack`,
|
|
131
|
+
uuid: rpHeaderUuid,
|
|
132
|
+
version: [1, 0, 0],
|
|
133
|
+
min_engine_version: minEngineVersion,
|
|
134
|
+
},
|
|
135
|
+
modules: [
|
|
136
|
+
{
|
|
137
|
+
description: "Resource Pack Modules",
|
|
138
|
+
type: "resources",
|
|
139
|
+
uuid: rpModuleUuid,
|
|
140
|
+
version: [1, 0, 0],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return { bpManifest, rpManifest };
|
|
146
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface MojangLocations {
|
|
2
|
+
root: string;
|
|
3
|
+
devBehaviorPacks: string;
|
|
4
|
+
devResourcePacks: string;
|
|
5
|
+
type: "retail" | "preview" | "custom" | "wsl" | "linux" | "config";
|
|
6
|
+
}
|
|
7
|
+
export declare function findMojangPath(customPath?: string, projectDir?: string): MojangLocations | null;
|
|
8
|
+
export declare function linkPack(sourceDir: string, destDir: string): void;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { loadMergedConfig } from "./config.js";
|
|
5
|
+
export function findMojangPath(customPath, projectDir = process.cwd()) {
|
|
6
|
+
// 1. Direct custom CLI path argument
|
|
7
|
+
if (customPath) {
|
|
8
|
+
const resolved = path.resolve(customPath);
|
|
9
|
+
if (fs.existsSync(resolved)) {
|
|
10
|
+
return makeLocations(resolved, "custom");
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
// 2. Config file (local bdev.json or global ~/.bdev/config.json)
|
|
15
|
+
const config = loadMergedConfig(projectDir);
|
|
16
|
+
if (config.mojangPath && typeof config.mojangPath === "string") {
|
|
17
|
+
const confPath = path.resolve(config.mojangPath);
|
|
18
|
+
if (fs.existsSync(confPath)) {
|
|
19
|
+
return makeLocations(confPath, "config");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// 3. Environment variable
|
|
23
|
+
if (process.env.BEDROCK_MOJANG_PATH) {
|
|
24
|
+
const envPath = path.resolve(process.env.BEDROCK_MOJANG_PATH);
|
|
25
|
+
if (fs.existsSync(envPath)) {
|
|
26
|
+
return makeLocations(envPath, "custom");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const platform = os.platform();
|
|
30
|
+
if (platform === "win32") {
|
|
31
|
+
const localAppData = process.env.LOCALAPPDATA ||
|
|
32
|
+
path.join(os.homedir(), "AppData", "Local");
|
|
33
|
+
const retail = path.join(localAppData, "Packages", "Microsoft.MinecraftUWP_8wekyb3d8bbwe", "LocalState", "games", "com.mojang");
|
|
34
|
+
if (fs.existsSync(retail)) {
|
|
35
|
+
return makeLocations(retail, "retail");
|
|
36
|
+
}
|
|
37
|
+
const preview = path.join(localAppData, "Packages", "Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe", "LocalState", "games", "com.mojang");
|
|
38
|
+
if (fs.existsSync(preview)) {
|
|
39
|
+
return makeLocations(preview, "preview");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Check WSL
|
|
43
|
+
if (platform === "linux") {
|
|
44
|
+
try {
|
|
45
|
+
const isWsl = Boolean(process.env.WSL_DISTRO_NAME) ||
|
|
46
|
+
fs.readFileSync("/proc/version", "utf-8").toLowerCase().includes("microsoft");
|
|
47
|
+
if (isWsl) {
|
|
48
|
+
const mntCUsers = "/mnt/c/Users";
|
|
49
|
+
if (fs.existsSync(mntCUsers)) {
|
|
50
|
+
const users = fs.readdirSync(mntCUsers);
|
|
51
|
+
for (const u of users) {
|
|
52
|
+
const retail = path.join(mntCUsers, u, "AppData", "Local", "Packages", "Microsoft.MinecraftUWP_8wekyb3d8bbwe", "LocalState", "games", "com.mojang");
|
|
53
|
+
if (fs.existsSync(retail)) {
|
|
54
|
+
return makeLocations(retail, "wsl");
|
|
55
|
+
}
|
|
56
|
+
const preview = path.join(mntCUsers, u, "AppData", "Local", "Packages", "Microsoft.MinecraftWindowsBeta_8wekyb3d8bbwe", "LocalState", "games", "com.mojang");
|
|
57
|
+
if (fs.existsSync(preview)) {
|
|
58
|
+
return makeLocations(preview, "wsl");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Ignore read errors
|
|
66
|
+
}
|
|
67
|
+
// Native Linux launcher locations
|
|
68
|
+
const linuxMcpelauncherPaths = [
|
|
69
|
+
path.join(os.homedir(), ".var", "app", "io.mrarm.mcpelauncher", "data", "mcpelauncher", "games", "com.mojang"),
|
|
70
|
+
path.join(os.homedir(), ".local", "share", "mcpelauncher", "games", "com.mojang"),
|
|
71
|
+
];
|
|
72
|
+
for (const p of linuxMcpelauncherPaths) {
|
|
73
|
+
if (fs.existsSync(p)) {
|
|
74
|
+
return makeLocations(p, "linux");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
function makeLocations(root, type) {
|
|
81
|
+
return {
|
|
82
|
+
root,
|
|
83
|
+
devBehaviorPacks: path.join(root, "development_behavior_packs"),
|
|
84
|
+
devResourcePacks: path.join(root, "development_resource_packs"),
|
|
85
|
+
type,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
export function linkPack(sourceDir, destDir) {
|
|
89
|
+
const resolvedSource = path.resolve(sourceDir);
|
|
90
|
+
const resolvedDest = path.resolve(destDir);
|
|
91
|
+
if (!fs.existsSync(resolvedSource)) {
|
|
92
|
+
throw new Error(`Source pack directory not found: ${resolvedSource}`);
|
|
93
|
+
}
|
|
94
|
+
// Ensure parent directory exists
|
|
95
|
+
const parent = path.dirname(resolvedDest);
|
|
96
|
+
if (!fs.existsSync(parent)) {
|
|
97
|
+
fs.mkdirSync(parent, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
if (fs.existsSync(resolvedDest) || isSymlink(resolvedDest)) {
|
|
100
|
+
const stat = fs.lstatSync(resolvedDest);
|
|
101
|
+
if (stat.isSymbolicLink()) {
|
|
102
|
+
const currentTarget = path.resolve(path.dirname(resolvedDest), fs.readlinkSync(resolvedDest));
|
|
103
|
+
if (currentTarget === resolvedSource) {
|
|
104
|
+
return; // Already linked
|
|
105
|
+
}
|
|
106
|
+
fs.unlinkSync(resolvedDest);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
throw new Error(`Destination path exists and is not a symlink: ${resolvedDest}. Remove or rename it manually.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const symlinkType = os.platform() === "win32" ? "junction" : "dir";
|
|
113
|
+
fs.symlinkSync(resolvedSource, resolvedDest, symlinkType);
|
|
114
|
+
}
|
|
115
|
+
function isSymlink(filePath) {
|
|
116
|
+
try {
|
|
117
|
+
return fs.lstatSync(filePath).isSymbolicLink();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface BedrockCommandRequest {
|
|
2
|
+
header: {
|
|
3
|
+
version: number;
|
|
4
|
+
requestId: string;
|
|
5
|
+
messagePurpose: "commandRequest";
|
|
6
|
+
};
|
|
7
|
+
body: {
|
|
8
|
+
commandLine: string;
|
|
9
|
+
version: number;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export declare class BedrockHotReloadServer {
|
|
13
|
+
private wss;
|
|
14
|
+
private clients;
|
|
15
|
+
private port;
|
|
16
|
+
constructor(port?: number);
|
|
17
|
+
start(): Promise<number>;
|
|
18
|
+
private setupHandlers;
|
|
19
|
+
sendCommand(commandLine: string): void;
|
|
20
|
+
private sendCommandToSocket;
|
|
21
|
+
reload(): void;
|
|
22
|
+
get clientCount(): number;
|
|
23
|
+
get currentPort(): number;
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { WebSocketServer, WebSocket } from "ws";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import pc from "picocolors";
|
|
4
|
+
import { logger } from "./logger.js";
|
|
5
|
+
export class BedrockHotReloadServer {
|
|
6
|
+
wss = null;
|
|
7
|
+
clients = new Set();
|
|
8
|
+
port;
|
|
9
|
+
constructor(port = 8000) {
|
|
10
|
+
this.port = port;
|
|
11
|
+
}
|
|
12
|
+
start() {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const tryListen = (attemptPort) => {
|
|
15
|
+
const server = new WebSocketServer({ port: attemptPort }, () => {
|
|
16
|
+
this.port = attemptPort;
|
|
17
|
+
this.wss = server;
|
|
18
|
+
this.setupHandlers(server);
|
|
19
|
+
resolve(attemptPort);
|
|
20
|
+
});
|
|
21
|
+
server.on("error", (err) => {
|
|
22
|
+
if (err.code === "EADDRINUSE") {
|
|
23
|
+
logger.warn(`Port ${attemptPort} is in use, trying ${attemptPort + 1}...`);
|
|
24
|
+
tryListen(attemptPort + 1);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
reject(err);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
tryListen(this.port);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
setupHandlers(server) {
|
|
35
|
+
server.on("connection", (socket) => {
|
|
36
|
+
this.clients.add(socket);
|
|
37
|
+
logger.success(pc.green("Minecraft connected to WebSocket hot reload!"));
|
|
38
|
+
// Send welcome message in Minecraft chat
|
|
39
|
+
this.sendCommandToSocket(socket, 'tellraw @a {"rawtext":[{"text":"§a[bdev] Connected to hot reload server!"}]}');
|
|
40
|
+
socket.on("message", (data) => {
|
|
41
|
+
try {
|
|
42
|
+
const res = JSON.parse(data.toString());
|
|
43
|
+
if (res?.body?.statusCode && res.body.statusCode !== 0) {
|
|
44
|
+
logger.warn(`Minecraft command warning: ${res.body.statusMessage || "Error"}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Ignore non-json responses
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
socket.on("close", () => {
|
|
52
|
+
this.clients.delete(socket);
|
|
53
|
+
logger.info("Minecraft disconnected from WebSocket.");
|
|
54
|
+
});
|
|
55
|
+
socket.on("error", () => {
|
|
56
|
+
this.clients.delete(socket);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
sendCommand(commandLine) {
|
|
61
|
+
for (const client of this.clients) {
|
|
62
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
63
|
+
this.sendCommandToSocket(client, commandLine);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
sendCommandToSocket(socket, commandLine) {
|
|
68
|
+
const payload = {
|
|
69
|
+
header: {
|
|
70
|
+
version: 1,
|
|
71
|
+
requestId: uuidv4(),
|
|
72
|
+
messagePurpose: "commandRequest",
|
|
73
|
+
},
|
|
74
|
+
body: {
|
|
75
|
+
commandLine,
|
|
76
|
+
version: 1,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
socket.send(JSON.stringify(payload));
|
|
80
|
+
}
|
|
81
|
+
reload() {
|
|
82
|
+
if (this.clients.size === 0) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
// Notify in game chat and execute reload command
|
|
86
|
+
this.sendCommand('tellraw @a {"rawtext":[{"text":"§e[bdev] Reloading scripts..."}]}');
|
|
87
|
+
this.sendCommand("reload");
|
|
88
|
+
}
|
|
89
|
+
get clientCount() {
|
|
90
|
+
return this.clients.size;
|
|
91
|
+
}
|
|
92
|
+
get currentPort() {
|
|
93
|
+
return this.port;
|
|
94
|
+
}
|
|
95
|
+
stop() {
|
|
96
|
+
return new Promise((resolve) => {
|
|
97
|
+
if (this.wss) {
|
|
98
|
+
for (const client of this.clients) {
|
|
99
|
+
client.terminate();
|
|
100
|
+
}
|
|
101
|
+
this.clients.clear();
|
|
102
|
+
this.wss.close(() => resolve());
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
resolve();
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mafly/bdev-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Modern CLI tool for Minecraft Bedrock Edition Addon development",
|
|
5
|
+
"author": "Mafly",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"bdev": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"keywords": [
|
|
20
|
+
"minecraft",
|
|
21
|
+
"bedrock",
|
|
22
|
+
"addon",
|
|
23
|
+
"cli",
|
|
24
|
+
"esbuild",
|
|
25
|
+
"typescript",
|
|
26
|
+
"hot-reload"
|
|
27
|
+
],
|
|
28
|
+
"scripts": {
|
|
29
|
+
"dev": "bun run src/index.ts",
|
|
30
|
+
"build": "bun run build:binary",
|
|
31
|
+
"build:binary": "bun build ./src/index.ts --compile --outfile bdev",
|
|
32
|
+
"build:npm": "tsc --outDir dist",
|
|
33
|
+
"prepack": "npm run build:npm",
|
|
34
|
+
"typecheck": "tsc --noEmit"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"archiver": "^7.0.1",
|
|
38
|
+
"chokidar": "^4.0.3",
|
|
39
|
+
"commander": "^13.1.0",
|
|
40
|
+
"esbuild": "^0.25.0",
|
|
41
|
+
"esbuild-wasm": "^0.28.2",
|
|
42
|
+
"ora": "^8.2.0",
|
|
43
|
+
"picocolors": "^1.1.1",
|
|
44
|
+
"uuid": "^11.1.0",
|
|
45
|
+
"ws": "^8.22.2"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/archiver": "^6.0.3",
|
|
49
|
+
"@types/node": "^22.13.8",
|
|
50
|
+
"@types/uuid": "^10.0.0",
|
|
51
|
+
"@types/ws": "^8.18.2",
|
|
52
|
+
"typescript": "^5.7.3"
|
|
53
|
+
}
|
|
54
|
+
}
|