yeow-api 0.4.1 → 0.4.3

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.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "Yeow API",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
package/src/core.ts CHANGED
@@ -57,8 +57,8 @@ export { assets, read as assetsRead, readSync as assetsReadSync,
57
57
  export { path } from './path.js';
58
58
  export { createReadStream, createWriteStream } from './fs.js';
59
59
  export type { ReadStream, WriteStream, ReadStreamOptions, WriteStreamOptions } from './fs.js';
60
- export { listen, respond, close, request, requestSync } from './http.js';
61
- export type { RespondOptions } from './http.js';
60
+ export { listen, respond, close, request } from './http.js';
61
+ export type { RespondOptions, RequestOptions, HttpResponse } from './http.js';
62
62
  export { logError } from './log-error.js';
63
63
  export { InstanceId, BossBarHandle, InventoryHandle } from './instance-id.js';
64
64
  export { ItemStack } from './item.js';
package/src/http.ts CHANGED
@@ -22,6 +22,42 @@ export interface RespondOptions {
22
22
  headers?: Record<string, string>;
23
23
  }
24
24
 
25
+ /** HTTP 请求选项(request)。 */
26
+ export interface RequestOptions {
27
+ /** HTTP 方法(默认 `"GET"`)。 */
28
+ method?: string;
29
+ /** 请求头。 */
30
+ headers?: Record<string, string>;
31
+ /**
32
+ * 请求体(与 `fs.writeFile` 同语义):`Uint8Array` 直接作为二进制;
33
+ * 字符串按 `encoding` 解释——缺省 UTF-8 文本,`'base64'` 时视为 base64 编码的二进制。
34
+ */
35
+ body?: string | Uint8Array;
36
+ /**
37
+ * 请求体(body 为字符串时)解释:`'utf8'`(默认)文本 / `'base64'` base64 二进制
38
+ * (与 `fs.writeFile` 同语义)。
39
+ */
40
+ encoding?: 'utf8' | 'base64';
41
+ /**
42
+ * 响应体形态:缺省 `Uint8Array`(原始字节,可在收到后自行解码,
43
+ * 如 `bytesToString(body)` 或 `new TextDecoder().decode(body)`);
44
+ * `'utf8'` → UTF-8 字符串;`'base64'` → base64 字符串(原样返回,不解码)。
45
+ */
46
+ responseEncoding?: 'utf8' | 'base64';
47
+ /** 超时(毫秒);缺省运行时默认(连接 5s / 读取 10s)。 */
48
+ timeout?: number;
49
+ }
50
+
51
+ /** HTTP 响应(request)。 */
52
+ export interface HttpResponse {
53
+ /** HTTP 状态码。 */
54
+ status: number;
55
+ /** 响应头(键小写)。 */
56
+ headers: Record<string, string>;
57
+ /** 响应体:缺省 `Uint8Array`;`encoding: 'utf8' | 'base64'` 时为字符串。 */
58
+ body: string | Uint8Array;
59
+ }
60
+
25
61
  function _sendHttp(payload: Record<string, unknown>): HttpResult {
26
62
  const r = $send('http', payload);
27
63
  if (!r) return {};
@@ -75,25 +111,49 @@ _registerCallback(() => {
75
111
 
76
112
  /**
77
113
  * 异步 HTTP 请求(不阻塞 JS 线程)——底层走 `http:requestAsync` 通道。
78
- * 推荐用于事件处理器与高频场景。需要同步阻塞返回的用 `requestSync`。
114
+ *
115
+ * 请求体与 `fs.writeFile` 同语义(`body: string | Uint8Array`,字符串按
116
+ * `encoding` 解释);响应体默认 `Uint8Array`(原始字节),可用
117
+ * `responseEncoding` 直接得到字符串(`'utf8'` / `'base64'`),也可在收到后
118
+ * 用 `bytesToString` 自行解码。`timeout` 指定超时毫秒数(连接与读取,缺省
119
+ * 运行时默认)。
79
120
  */
80
- export function request(url: string, opts: Record<string, unknown> = {}): Promise<HttpResult> {
121
+ export function request(url: string, opts: RequestOptions = {}): Promise<HttpResponse> {
81
122
  return new Promise((resolve, reject) => {
82
123
  const cbId = _registerCallback((result: unknown) => {
83
- if ((result as any)?.err) reject(new Error((result as any).err));
84
- else resolve(result as HttpResult);
124
+ const r = result as HttpResult;
125
+ if (r?.err || (r as any)?.error) {
126
+ reject(new Error(r?.err || (r as any).error));
127
+ return;
128
+ }
129
+ const body = r.body ?? '';
130
+ resolve({
131
+ status: r.status ?? 0,
132
+ headers: r.headers ?? {},
133
+ // 底层始终以 base64 承载原始字节;'utf8' 时 Java 侧已解码为文本,其余形态本地转换
134
+ body: opts.responseEncoding === 'utf8' ? body
135
+ : opts.responseEncoding === 'base64' ? body
136
+ : Uint8Array.fromBase64(body),
137
+ });
85
138
  });
86
139
  try {
87
- _sendHttp({ t: 'requestAsync', p: { url, ...opts, cb: String(cbId) } });
140
+ const p: Record<string, unknown> = {
141
+ url,
142
+ method: opts.method || 'GET',
143
+ headers: opts.headers || {},
144
+ };
145
+ // 请求体与 fs.writeFile 同语义:Uint8Array 直接二进制(base64 承载);
146
+ // 字符串按 encoding——缺省 UTF-8 文本,'base64' 视为 base64 二进制
147
+ if (opts.body instanceof Uint8Array) {
148
+ p.body = opts.body.toBase64();
149
+ p.encoding = 'base64';
150
+ } else {
151
+ p.body = opts.body ?? null;
152
+ if (opts.encoding === 'base64') p.encoding = 'base64';
153
+ }
154
+ p.responseType = opts.responseEncoding === 'utf8' ? 'text' : 'base64';
155
+ if (opts.timeout !== undefined) p.timeout = opts.timeout;
156
+ _sendHttp({ t: 'requestAsync', p: { ...p, cb: String(cbId) } });
88
157
  } catch (e) { reject(e); }
89
158
  });
90
159
  }
91
-
92
- /**
93
- * 同步 HTTP 请求(**阻塞 JS 线程**直到响应返回)——底层走 `http:request` 通道。
94
- * 阻塞期间 JS 线程无法处理事件/命令/回调(可能触发 event.timeout 告警);
95
- * 仅适合低频、非事件上下文。事件处理器或高频场景请用 `request`(异步)或全局 `fetch`。
96
- */
97
- export function requestSync(url: string, opts: Record<string, unknown> = {}): HttpResult {
98
- return _sendHttp({ t: 'request', p: { url, ...opts } });
99
- }
package/src/player.ts CHANGED
@@ -2,6 +2,7 @@ import { call, post } from './task.js';
2
2
  import type { TaskOptions } from './task.js';
3
3
  import { Location, LocationData } from './location.js';
4
4
  import type { ItemStack } from './item.js';
5
+ import { Block } from './block.js';
5
6
  import type { Message } from './message.js';
6
7
  import type { Permission } from './permission.js';
7
8
  import { Inventory } from './inventory.js';
@@ -170,6 +171,27 @@ export class Player {
170
171
  }
171
172
  teleport(loc: Location, options?: TaskOptions): Promise<void> { return post('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
172
173
  teleportSync(loc: Location, options?: TaskOptions): void { call('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
174
+ /** 向玩家发送假方块变化(仅客户端视觉,不改变真实世界)。block 为 Block 对象或字符串(同 world.setBlock,字符串无状态)。 */
175
+ sendBlockChange(location: Location, block: Block | string, options?: TaskOptions): Promise<void> {
176
+ const p: Record<string, unknown> = { uuid: this.uuid, ...location.toObject() };
177
+ if (typeof block === 'string') {
178
+ p.blockType = block;
179
+ } else {
180
+ p.blockType = block.type;
181
+ if (block.state && Object.keys(block.state).length > 0) p.state = block.state;
182
+ }
183
+ return post('player.sendBlockChange', p, options);
184
+ }
185
+ sendBlockChangeSync(location: Location, block: Block | string, options?: TaskOptions): void {
186
+ const p: Record<string, unknown> = { uuid: this.uuid, ...location.toObject() };
187
+ if (typeof block === 'string') {
188
+ p.blockType = block;
189
+ } else {
190
+ p.blockType = block.type;
191
+ if (block.state && Object.keys(block.state).length > 0) p.state = block.state;
192
+ }
193
+ call('player.sendBlockChange', p, options);
194
+ }
173
195
  sendActionBar(message: string | Message, options?: TaskOptions): Promise<void> { return post('player.sendActionBar', { uuid: this.uuid, message }, options); }
174
196
  sendActionBarSync(message: string | Message, options?: TaskOptions): void { call('player.sendActionBar', { uuid: this.uuid, message }, options); }
175
197
  sendResourcePack(url: string, hash?: string, prompt?: string | Message, force?: boolean, options?: TaskOptions): Promise<void> {