yeow-api 0.2.113 → 0.2.114

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yeow-api",
3
- "version": "0.2.113",
3
+ "version": "0.2.114",
4
4
  "description": "Yeow API",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
package/src/core.ts CHANGED
@@ -92,3 +92,7 @@ export { registerService, registerNativeService, request as serviceRequest, subs
92
92
  export type { ServiceResult, NativeServiceResult } from './service.js';
93
93
  export { log, Logger } from './log.js';
94
94
  export type { Message } from './message.js';
95
+ export { getEnv } from './env.js';
96
+ export type { EnvInfo } from './env.js';
97
+ export { createWorker, Worker, onMessage, postMessage } from './worker.js';
98
+ export type { WorkerOptions } from './worker.js';
package/src/env.ts ADDED
@@ -0,0 +1,20 @@
1
+ /** env 通道返回的运行时环境信息(同步)。 */
2
+ export interface EnvInfo {
3
+ /** CPU 逻辑核心数。 */
4
+ cpus: number;
5
+ /** JVM 总内存(字节)。 */
6
+ memory: number;
7
+ /** 系统架构(如 `windows-x64` / `linux-x64` / `linux-arm64`)。 */
8
+ arch: string;
9
+ /** Minecraft 版本(如 `1.21.4`)。 */
10
+ minecraftVersion: string;
11
+ /** 运行时信息。 */
12
+ yeow: { platform: string; version: string };
13
+ /** epoch 微秒时间戳。 */
14
+ now: number;
15
+ }
16
+
17
+ /** 获取运行时环境信息(同步;含微秒时间戳)。 */
18
+ export function getEnv(): EnvInfo {
19
+ return $send('env', {}) as EnvInfo;
20
+ }
package/src/global.d.ts CHANGED
@@ -11,6 +11,7 @@ declare global {
11
11
  function _unregisterCallback(id: string): void;
12
12
  function _getCurrentCbStack(): { stack: string; outer: unknown } | null;
13
13
  function _attachCbStack(err: unknown): void;
14
+ function reportError(e: unknown): void;
14
15
 
15
16
  // ── init.js 注入的标准环境(lib 为 ESNext,不含 DOM——自行声明)──
16
17
  interface YeowConsole {
package/src/player.ts CHANGED
@@ -141,6 +141,13 @@ export class Player {
141
141
  hasPermissionSync(node: string, options?: TaskOptions): boolean {
142
142
  return call<boolean>('player.hasPermission', { uuid: this.uuid, permission: node }, options);
143
143
  }
144
+ /** 以玩家身份执行命令(**不含 `/` 前缀**,如 `say hi`;前缀会自动剥离;与服务器 `dispatchCommand`(控制台)相对)。 */
145
+ performCommand(cmd: string, options?: TaskOptions): Promise<boolean> {
146
+ return post<boolean>('player.performCommand', { uuid: this.uuid, command: cmd.replace(/^\//, '') }, options);
147
+ }
148
+ performCommandSync(cmd: string, options?: TaskOptions): boolean {
149
+ return call<boolean>('player.performCommand', { uuid: this.uuid, command: cmd.replace(/^\//, '') }, options);
150
+ }
144
151
  teleport(loc: Location, options?: TaskOptions): Promise<void> { return post('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
145
152
  teleportSync(loc: Location, options?: TaskOptions): void { call('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
146
153
  sendActionBar(message: string | Message, options?: TaskOptions): Promise<void> { return post('player.sendActionBar', { uuid: this.uuid, message }, options); }
package/src/worker.ts ADDED
@@ -0,0 +1,150 @@
1
+ export interface WorkerOptions {
2
+ /** Worker 名(必填;不允许 'main';同一主插件内不重复,全局可重复)。 */
3
+ name: string;
4
+ /** 资源路径(通过 `getAssetsPath` 获取);与 `code` 互斥(不可同时传递)。 */
5
+ entry?: string;
6
+ /** 代码字符串;与 `entry` 互斥。 */
7
+ code?: string;
8
+ }
9
+
10
+ let _seq = 0;
11
+ /** 本主插件已创建的 worker 名(同主插件内唯一校验;unload 后允许重建)。 */
12
+ const _created: Record<string, boolean> = {};
13
+ /** 主插件侧:每个 worker 的 onMessage 回调 id。 */
14
+ const _msgCbs: Record<string, string> = {};
15
+
16
+ function _sendWorker(payload: Record<string, unknown>): unknown {
17
+ const r = $send('worker', payload);
18
+ if (r == null) return undefined;
19
+ if ((r as any)?.err) throw new Error((r as any).err);
20
+ return r;
21
+ }
22
+
23
+ /** 内部:异步调用 worker 通道(cb 回调)。 */
24
+ function _sendWorkerAsync(t: string, p: Record<string, unknown>): Promise<void> {
25
+ return new Promise((resolve, reject) => {
26
+ const cbId = _registerCallback((result: unknown) => {
27
+ if ((result as any)?.err) reject(new Error((result as any).err));
28
+ else resolve();
29
+ });
30
+ _sendWorker({ t, p: { ...p, cb: cbId } });
31
+ });
32
+ }
33
+
34
+ /**
35
+ * Worker —— 虚拟插件(独立 QuickJS 上下文 + 线程)。
36
+ *
37
+ * - 事件/命令/服务以独立实体注册;调度器任务独立统计
38
+ * - 共享主插件的**数据目录**与**权限**
39
+ * - 不能创建新的 Worker(嵌套被拒绝)
40
+ * - **创建后无法销毁,只能卸载**(卸载物理销毁 JS 上下文,句柄保留——可重新 load)
41
+ * - 主插件卸载时连带卸载;/yeow 管理命令不覆盖 Worker;profiler 会统计(标记 created by 主插件)
42
+ * - Worker 的 JS 错误与主插件同样回传(dev 模式经 source-map 定位)
43
+ */
44
+ export class Worker {
45
+ private readonly name: string;
46
+ private readonly entry?: string;
47
+ private readonly code?: string;
48
+ private readonly key: string;
49
+ private _loaded = false;
50
+ private _onMessage: ((msg: any) => void) | null = null;
51
+ /** 内部 workerId(主插件 JS 侧分配;跨主插件可重复)。 */
52
+ readonly id: string;
53
+
54
+ constructor(name: string, entry: string | undefined, code: string | undefined) {
55
+ this.name = name;
56
+ this.entry = entry;
57
+ this.code = code;
58
+ this.id = 'worker_' + (++_seq);
59
+ this.key = (__plugin?.name || 'unknown') + ':' + name;
60
+ // 主插件侧 onMessage 回调(worker → main 时 Java 投递到这里)
61
+ _msgCbs[this.id] = _registerCallback((msg: unknown) => {
62
+ const cb = this._onMessage;
63
+ if (cb) { try { cb(msg); } catch (e) { console.error('[worker] onMessage error', e); } }
64
+ }, { persistent: true });
65
+ }
66
+
67
+ /** 注册接收 Worker 发来的消息。 */
68
+ onMessage(cb: (msg: any) => void): void {
69
+ this._onMessage = cb;
70
+ }
71
+
72
+ /** 启动 Worker:执行 init.js → worker-inject.js → Worker 代码 → INIT → LOAD(已加载为 no-op)。 */
73
+ load(): Promise<void> {
74
+ if (this._loaded) return Promise.resolve();
75
+ this._loaded = true;
76
+ return _sendWorkerAsync('load', { name: this.name });
77
+ }
78
+
79
+ /** 卸载 Worker(物理销毁 JS 上下文并清理其事件/命令/服务/任务;句柄保留,可重新 load)。 */
80
+ unload(): Promise<void> {
81
+ this._loaded = false;
82
+ return _sendWorkerAsync('unload', { name: this.name });
83
+ }
84
+
85
+ /** 向 Worker 发送消息(其 onMessage 回调接收;未 load 时抛错)。 */
86
+ postMessage(msg: Record<string, unknown>): Promise<void> {
87
+ return _sendWorkerAsync('post', { name: this.name, msg });
88
+ }
89
+
90
+ /** 重载 Worker 代码(需已 load;旧上下文销毁、新代码重新加载)。 */
91
+ reload(): Promise<void> {
92
+ const p: Record<string, unknown> = { name: this.name };
93
+ if (this.entry) p.entry = this.entry;
94
+ else p.code = this.code;
95
+ return _sendWorkerAsync('reload', p);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * 创建 Worker(虚拟插件):**仅注册到注册表并返回句柄**——`worker.load()` 才真正启动
101
+ * (执行 init.js → worker-inject.js → Worker 代码 → INIT → LOAD)。
102
+ *
103
+ * `entry`(资源路径,经 getAssetsPath)与 `code` 二选一,同时传递抛错;
104
+ * `name` 必填、非 'main'、同主插件内不重复。
105
+ */
106
+ export function createWorker(options: WorkerOptions): Worker {
107
+ const name = options?.name;
108
+ if (!name || typeof name !== 'string' || name.trim() === '') {
109
+ throw new Error('createWorker: name is required');
110
+ }
111
+ if (name === 'main') {
112
+ throw new Error('createWorker: name must not be "main"');
113
+ }
114
+ if (options.entry && options.code) {
115
+ throw new Error('createWorker: entry and code cannot be passed together');
116
+ }
117
+ if (!options.entry && !options.code) {
118
+ throw new Error('createWorker: either entry or code is required');
119
+ }
120
+ const key = (__plugin?.name || 'unknown') + ':' + name;
121
+ if (_created[key]) {
122
+ throw new Error('createWorker: duplicate worker name "' + name + '" in plugin ' + (__plugin?.name || 'unknown'));
123
+ }
124
+ _created[key] = true;
125
+ const w = new Worker(name, options.entry, options.code);
126
+ // 注册到运行时注册表(同步;重复/非法名抛错)
127
+ const p: Record<string, unknown> = { name, msgCb: _msgCbs[w.id] };
128
+ if (options.entry) p.entry = options.entry;
129
+ else p.code = options.code;
130
+ _sendWorker({ t: 'create', p });
131
+ return w;
132
+ }
133
+
134
+ // ── Worker 侧 API(仅 Worker 环境可用)──────────────────────────────
135
+
136
+ const _isWorker = typeof (globalThis as any).__workerId !== 'undefined';
137
+
138
+ /** Worker 侧:注册消息接收回调(主插件 `worker.postMessage` 触发)。主插件环境调用抛错。 */
139
+ export function onMessage(cb: (msg: any) => void): void {
140
+ if (!_isWorker) throw new Error('onMessage is only available inside a Worker');
141
+ (globalThis as any)._workerOnMessage = (msg: any) => {
142
+ try { cb(msg); } catch (e) { reportError(e); }
143
+ };
144
+ }
145
+
146
+ /** Worker 侧:向主插件发送消息(主插件侧 `worker.onMessage` 回调接收)。主插件环境调用抛错。 */
147
+ export function postMessage(msg: Record<string, unknown>): void {
148
+ if (!_isWorker) throw new Error('postMessage is only available inside a Worker');
149
+ _sendWorker({ t: 'postToMain', p: { msg } });
150
+ }