@shirokasoke/webapi-sdk 2.9.0-beta2-0.11-pre
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/client.d.ts +576 -0
- package/dist/client.js +668 -0
- package/dist/esm/client.js +663 -0
- package/dist/esm/index.js +3 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/test.js +6 -0
- package/dist/esm/types/ae2.js +1 -0
- package/dist/esm/types/block.js +1 -0
- package/dist/esm/types/chunk.js +1 -0
- package/dist/esm/types/common.js +1 -0
- package/dist/esm/types/entity.js +1 -0
- package/dist/esm/types/fluid.js +1 -0
- package/dist/esm/types/fmp.js +1 -0
- package/dist/esm/types/gt5.js +1 -0
- package/dist/esm/types/index.js +13 -0
- package/dist/esm/types/item.js +1 -0
- package/dist/esm/types/rawInfo.js +1 -0
- package/dist/esm/types/recipe.js +1 -0
- package/dist/esm/types/threeD.js +1 -0
- package/dist/esm/types/world.js +1 -0
- package/dist/esm/validators/ae2.js +163 -0
- package/dist/esm/validators/block.js +85 -0
- package/dist/esm/validators/chunk.js +58 -0
- package/dist/esm/validators/common.js +28 -0
- package/dist/esm/validators/entity.js +117 -0
- package/dist/esm/validators/fluid.js +24 -0
- package/dist/esm/validators/fmp.js +34 -0
- package/dist/esm/validators/gt5.js +186 -0
- package/dist/esm/validators/index.js +13 -0
- package/dist/esm/validators/item.js +31 -0
- package/dist/esm/validators/rawInfo.js +25 -0
- package/dist/esm/validators/recipe.js +77 -0
- package/dist/esm/validators/threeD.js +34 -0
- package/dist/esm/validators/world.js +59 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +22 -0
- package/dist/test.d.ts +1 -0
- package/dist/test.js +8 -0
- package/dist/types/ae2.d.ts +162 -0
- package/dist/types/ae2.js +2 -0
- package/dist/types/block.d.ts +87 -0
- package/dist/types/block.js +2 -0
- package/dist/types/chunk.d.ts +57 -0
- package/dist/types/chunk.js +2 -0
- package/dist/types/common.d.ts +27 -0
- package/dist/types/common.js +2 -0
- package/dist/types/entity.d.ts +114 -0
- package/dist/types/entity.js +2 -0
- package/dist/types/fluid.d.ts +23 -0
- package/dist/types/fluid.js +2 -0
- package/dist/types/fmp.d.ts +33 -0
- package/dist/types/fmp.js +2 -0
- package/dist/types/gt5.d.ts +210 -0
- package/dist/types/gt5.js +2 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.js +29 -0
- package/dist/types/item.d.ts +38 -0
- package/dist/types/item.js +2 -0
- package/dist/types/rawInfo.d.ts +25 -0
- package/dist/types/rawInfo.js +2 -0
- package/dist/types/recipe.d.ts +114 -0
- package/dist/types/recipe.js +2 -0
- package/dist/types/threeD.d.ts +43 -0
- package/dist/types/threeD.js +2 -0
- package/dist/types/world.d.ts +58 -0
- package/dist/types/world.js +2 -0
- package/dist/validators/ae2.d.ts +63 -0
- package/dist/validators/ae2.js +169 -0
- package/dist/validators/block.d.ts +12 -0
- package/dist/validators/block.js +91 -0
- package/dist/validators/chunk.d.ts +9 -0
- package/dist/validators/chunk.js +64 -0
- package/dist/validators/common.d.ts +8 -0
- package/dist/validators/common.js +36 -0
- package/dist/validators/entity.d.ts +9 -0
- package/dist/validators/entity.js +123 -0
- package/dist/validators/fluid.d.ts +4 -0
- package/dist/validators/fluid.js +30 -0
- package/dist/validators/fmp.d.ts +4 -0
- package/dist/validators/fmp.js +40 -0
- package/dist/validators/gt5.d.ts +24 -0
- package/dist/validators/gt5.js +192 -0
- package/dist/validators/index.d.ts +13 -0
- package/dist/validators/index.js +29 -0
- package/dist/validators/item.d.ts +13 -0
- package/dist/validators/item.js +37 -0
- package/dist/validators/rawInfo.d.ts +6 -0
- package/dist/validators/rawInfo.js +31 -0
- package/dist/validators/recipe.d.ts +30 -0
- package/dist/validators/recipe.js +83 -0
- package/dist/validators/threeD.d.ts +8 -0
- package/dist/validators/threeD.js +40 -0
- package/dist/validators/world.d.ts +5 -0
- package/dist/validators/world.js +65 -0
- package/package.json +49 -0
package/dist/client.js
ADDED
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebApiError = exports.WebApiClient = void 0;
|
|
4
|
+
const fetch_event_source_1 = require("@microsoft/fetch-event-source");
|
|
5
|
+
function buildQuery(params) {
|
|
6
|
+
const record = params;
|
|
7
|
+
const qs = Object.entries(record)
|
|
8
|
+
.filter(([, v]) => v !== undefined)
|
|
9
|
+
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`)
|
|
10
|
+
.join("&");
|
|
11
|
+
return qs ? `?${qs}` : "";
|
|
12
|
+
}
|
|
13
|
+
/** 解包 `ApiResponse<T>`(如 SSE 事件帧),业务失败(success=false)时抛 {@link WebApiError} */
|
|
14
|
+
function unwrapApiResponse(body) {
|
|
15
|
+
if (!body.success) {
|
|
16
|
+
throw new WebApiError(body.message, 200, body);
|
|
17
|
+
}
|
|
18
|
+
return body.data;
|
|
19
|
+
}
|
|
20
|
+
class WebApiClient {
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
23
|
+
this.authToken = options.authToken;
|
|
24
|
+
const globalFetch = typeof globalThis !== "undefined" ? globalThis.fetch : undefined;
|
|
25
|
+
this.fetchImpl = options.fetch || globalFetch || undefined;
|
|
26
|
+
if (!this.fetchImpl) {
|
|
27
|
+
throw new Error("No fetch implementation provided. Pass one via options.fetch or run in an environment with global fetch.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async request(path, init) {
|
|
31
|
+
const req = new Request(`${this.baseUrl}${path}`, init);
|
|
32
|
+
if (this.authToken) {
|
|
33
|
+
req.headers.set("Authorization", this.authToken);
|
|
34
|
+
}
|
|
35
|
+
const res = await this.fetchImpl(req);
|
|
36
|
+
const contentType = res.headers.get("content-type") || "";
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
if (contentType.includes("application/json")) {
|
|
39
|
+
const body = await res.json().catch(() => ({ message: res.statusText }));
|
|
40
|
+
throw new WebApiError(body.message || res.statusText, res.status, body);
|
|
41
|
+
}
|
|
42
|
+
throw new WebApiError(res.statusText, res.status);
|
|
43
|
+
}
|
|
44
|
+
if (contentType.includes("application/json")) {
|
|
45
|
+
const body = await res.json();
|
|
46
|
+
if (body.success) {
|
|
47
|
+
return body.data;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new WebApiError(body.message, res.status, body);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return res.arrayBuffer();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* SSE 订阅模板:统一处理鉴权头、响应校验、事件过滤与错误上报(基于 fetchEventSource,可携带
|
|
57
|
+
* Authorization 头,原生 EventSource 不支持)。服务端推送的 `error` 事件(纯文本消息)会转为
|
|
58
|
+
* {@link Error} 上报;连接建立后发生异常时同样上报并停止库内自动重连,由调用方决定是否重新订阅。
|
|
59
|
+
* @param url 完整订阅地址(含 query)
|
|
60
|
+
* @param eventName 业务事件名,其余事件将被忽略
|
|
61
|
+
* @param callback 业务数据回调
|
|
62
|
+
* @param errorCallback 出错回调,接收模板抛出或 `parse` 抛出的异常(如 {@link WebApiError})
|
|
63
|
+
* @param parse 解析事件的 data 文本为业务数据,抛出异常表示该帧无效
|
|
64
|
+
* @returns AbortController,调用 `abort()` 可停止订阅
|
|
65
|
+
*/
|
|
66
|
+
subscribeSse(url, eventName, callback, errorCallback, parse) {
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const headers = {};
|
|
69
|
+
if (this.authToken) {
|
|
70
|
+
headers["Authorization"] = this.authToken;
|
|
71
|
+
}
|
|
72
|
+
(0, fetch_event_source_1.fetchEventSource)(url, {
|
|
73
|
+
signal: controller.signal,
|
|
74
|
+
headers,
|
|
75
|
+
openWhenHidden: true,
|
|
76
|
+
fetch: this.fetchImpl,
|
|
77
|
+
onopen: async (response) => {
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
const body = (await response.json().catch(() => null));
|
|
80
|
+
throw new WebApiError(body?.message || response.statusText, response.status, body);
|
|
81
|
+
}
|
|
82
|
+
const contentType = response.headers.get("content-type") || "";
|
|
83
|
+
if (!contentType.includes("text/event-stream")) {
|
|
84
|
+
throw new WebApiError(`Expected content-type to be text/event-stream, actual: ${contentType}`, response.status);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
onmessage: (event) => {
|
|
88
|
+
if (event.event === "error") {
|
|
89
|
+
errorCallback(new Error(event.data));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (event.event !== eventName)
|
|
93
|
+
return;
|
|
94
|
+
try {
|
|
95
|
+
callback(parse(event.data));
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
errorCallback(err instanceof Error ? err : new Error(String(err)));
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
onerror: (err) => {
|
|
102
|
+
errorCallback(err instanceof Error ? err : new Error(String(err)));
|
|
103
|
+
// 停止库内自动重连,由调用方决定是否重新订阅
|
|
104
|
+
throw err;
|
|
105
|
+
},
|
|
106
|
+
}).catch(() => { });
|
|
107
|
+
return controller;
|
|
108
|
+
}
|
|
109
|
+
// region Root / Status
|
|
110
|
+
/**
|
|
111
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/RootHandler.java)
|
|
112
|
+
* @returns 使用 {@link RootInfoSchema} 验证
|
|
113
|
+
*/
|
|
114
|
+
getRoot() {
|
|
115
|
+
return this.request("/version");
|
|
116
|
+
}
|
|
117
|
+
// region TPS / Performance
|
|
118
|
+
/**
|
|
119
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/TPSHandler.java)
|
|
120
|
+
* @returns 使用 `Joi.object().pattern(Joi.string(), {@link TPSInfoSchema})` 验证
|
|
121
|
+
*/
|
|
122
|
+
getTPS() {
|
|
123
|
+
return this.request("/tps");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ProfilerHandler.java)
|
|
127
|
+
* @returns 使用 {@link ProfilerDataSchema} 验证
|
|
128
|
+
*/
|
|
129
|
+
getProfiler() {
|
|
130
|
+
return this.request("/profiler");
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/LagAnalyzerHandler.java)
|
|
134
|
+
* @returns 使用 {@link LagAnalyzerDataSchema} 验证
|
|
135
|
+
*/
|
|
136
|
+
getLagAnalyzer() {
|
|
137
|
+
return this.request("/lag-analyzer");
|
|
138
|
+
}
|
|
139
|
+
// region World
|
|
140
|
+
/**
|
|
141
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/WorldInfoHandler.java)
|
|
142
|
+
* @returns 使用 `Joi.object().pattern(Joi.string(), {@link WorldInfoDataSchema})` 验证
|
|
143
|
+
*/
|
|
144
|
+
getWorldInfo() {
|
|
145
|
+
return this.request("/WorldInfo");
|
|
146
|
+
}
|
|
147
|
+
// region Blocks
|
|
148
|
+
/**
|
|
149
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BlocksHandler.java)
|
|
150
|
+
* @returns 使用 `Joi.array().items(`{@link BlockSchema}`)` 验证
|
|
151
|
+
*/
|
|
152
|
+
getBlocks() {
|
|
153
|
+
return this.request("/blocks");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BlockHandler.java)
|
|
157
|
+
* @returns 使用 {@link BlockDetailSchema} 验证
|
|
158
|
+
*/
|
|
159
|
+
getBlock(params) {
|
|
160
|
+
return this.request(`/block${buildQuery(params)}`);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/SetBlockHandler.java)
|
|
164
|
+
* @param body 使用 {@link SetBlockBodySchema} 验证
|
|
165
|
+
* @returns 使用 {@link SetBlockResultSchema} 验证
|
|
166
|
+
*/
|
|
167
|
+
setBlock(params, body) {
|
|
168
|
+
return this.request(`/setblock${buildQuery(params)}`, {
|
|
169
|
+
method: "POST",
|
|
170
|
+
headers: { "Content-Type": "application/json" },
|
|
171
|
+
body: JSON.stringify(body),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 提交批量 setblock 任务到慢队列,异步执行。
|
|
176
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BatchSetBlockHandler.java)
|
|
177
|
+
* @param tasks 使用 `Joi.array().items(`{@link BatchSetBlockTaskSchema} ) 验证
|
|
178
|
+
* @returns 使用 {@link BatchSetBlockSubmitResultSchema} 验证
|
|
179
|
+
*/
|
|
180
|
+
batchSetBlock(tasks) {
|
|
181
|
+
return this.request("/batchsetblock", {
|
|
182
|
+
method: "POST",
|
|
183
|
+
headers: { "Content-Type": "application/json" },
|
|
184
|
+
body: JSON.stringify(tasks),
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 查询批量 setblock 任务执行结果。
|
|
189
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BatchSetBlockHandler.java)
|
|
190
|
+
* @returns 使用 {@link BatchSetBlockJobResultSchema} 验证
|
|
191
|
+
*/
|
|
192
|
+
getBatchSetBlockJob(params) {
|
|
193
|
+
return this.request(`/batchsetblock${buildQuery(params)}`);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* 轮询等待批量 setblock 任务完成。
|
|
197
|
+
* @param jobId 任务 ID(由 batchSetBlock 返回)
|
|
198
|
+
* @param intervalMs 轮询间隔 (ms),默认 100
|
|
199
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BatchSetBlockHandler.java)
|
|
200
|
+
* @returns 使用 {@link BatchSetBlockJobResultSchema} 验证
|
|
201
|
+
*/
|
|
202
|
+
async waitForBatchSetBlockJob(jobId, intervalMs = 100) {
|
|
203
|
+
while (true) {
|
|
204
|
+
const job = await this.getBatchSetBlockJob({ id: jobId });
|
|
205
|
+
if (job.status === "completed")
|
|
206
|
+
return job;
|
|
207
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/FMPHandler.java)
|
|
212
|
+
* @returns 使用 `Joi.array().items(`{@link FMPPartSchema}`)` 验证
|
|
213
|
+
*/
|
|
214
|
+
getBlockFMP(params) {
|
|
215
|
+
return this.request(`/block/fmp${buildQuery(params)}`);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/block/BlockTileHandler.java)
|
|
219
|
+
* @returns 二进制数据,无 JSON Schema
|
|
220
|
+
*/
|
|
221
|
+
getBlockTile(params) {
|
|
222
|
+
return this.request(`/block/tile${buildQuery(params)}`);
|
|
223
|
+
}
|
|
224
|
+
// region Items
|
|
225
|
+
/**
|
|
226
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/item/ItemsHandler.java)
|
|
227
|
+
* @returns 使用 `Joi.array().items(`{@link ItemSchema}`)` 验证
|
|
228
|
+
*/
|
|
229
|
+
getItems() {
|
|
230
|
+
return this.request("/items");
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/item/ItemHandler.java)
|
|
234
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/item/ItemStaticHandler.java)
|
|
235
|
+
* @returns 使用 {@link ItemDetailSchema} 验证
|
|
236
|
+
*/
|
|
237
|
+
getItem(params) {
|
|
238
|
+
return this.request(`/item${buildQuery(params)}`);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/item/ItemIconHandler.java)
|
|
242
|
+
* @param params.id 物品 ID(对应 ItemStack 的 id)
|
|
243
|
+
* @param params.damage 物品损伤值/元数据(可选,默认 0)
|
|
244
|
+
* @param params.tag Base64 编码的 NBTTagCompound(可选)
|
|
245
|
+
* @returns 二进制 PNG 图片数据 (ArrayBuffer)
|
|
246
|
+
*/
|
|
247
|
+
getItemIcon(params) {
|
|
248
|
+
return this.request(`/item/icon${buildQuery(params)}`);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/item/AEHandler.java)
|
|
252
|
+
* @returns 使用 {@link AEItemDefinitionsSchema} 验证
|
|
253
|
+
*/
|
|
254
|
+
getAEItemsDef() {
|
|
255
|
+
return this.request("/items/ae");
|
|
256
|
+
}
|
|
257
|
+
// region Fluids
|
|
258
|
+
/**
|
|
259
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/fluid/FluidsHandler.java)
|
|
260
|
+
* @returns 使用 `Joi.array().items(`{@link FluidSchema}`)` 验证
|
|
261
|
+
*/
|
|
262
|
+
getFluids() {
|
|
263
|
+
return this.request("/fluids");
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/fluid/FluidContainersHandler.java)
|
|
267
|
+
* @returns 使用 `Joi.array().items(`{@link FluidContainerSchema}`)` 验证
|
|
268
|
+
*/
|
|
269
|
+
getFluidContainers() {
|
|
270
|
+
return this.request("/fluidContainers");
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/fluid/FluidIconHandler.java)
|
|
274
|
+
* @param params.id 流体 ID(对应 Fluid 的 id)
|
|
275
|
+
* @param params.name 流体名称(对应 Fluid 的 name)
|
|
276
|
+
* @returns 二进制 PNG 图片数据 (ArrayBuffer)
|
|
277
|
+
*/
|
|
278
|
+
getFluidIcon(params) {
|
|
279
|
+
return this.request(`/fluid/icon${buildQuery(params)}`);
|
|
280
|
+
}
|
|
281
|
+
// region Entities
|
|
282
|
+
/**
|
|
283
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/entity/EntitiesHandler.java)
|
|
284
|
+
* @returns 使用 `Joi.object().pattern(Joi.string(),`{@link EntitiesByDimensionSchema}`)` 验证
|
|
285
|
+
*
|
|
286
|
+
* 其中实体为 {@link EntitySummarySchema} 精简结构
|
|
287
|
+
*/
|
|
288
|
+
getEntities() {
|
|
289
|
+
return this.request("/entities");
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/entity/EntityHandler.java)
|
|
293
|
+
* @returns 使用 {@link EntitySchema} 验证
|
|
294
|
+
*/
|
|
295
|
+
getEntity(params) {
|
|
296
|
+
return this.request(`/entity${buildQuery(params)}`);
|
|
297
|
+
}
|
|
298
|
+
// region Chunks
|
|
299
|
+
/**
|
|
300
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunksHandler.java)
|
|
301
|
+
* @returns 使用 `Joi.object().pattern(Joi.string(),`{@link ChunksByDimensionSchema}`)` 验证
|
|
302
|
+
*/
|
|
303
|
+
getChunks() {
|
|
304
|
+
return this.request("/chunks");
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunkHandler.java)
|
|
308
|
+
* @returns 使用 {@link ChunkWithDimensionSchema} 验证
|
|
309
|
+
*/
|
|
310
|
+
getChunk(params) {
|
|
311
|
+
return this.request(`/chunk${buildQuery(params)}`);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunkMapHandler.java)
|
|
315
|
+
* @returns JSON 模式使用 `Joi.array().items(Joi.array().items(`{@link ChunkMapCellSchema}`)` 验证;raw 模式为 ArrayBuffer
|
|
316
|
+
*/
|
|
317
|
+
getChunkMap(params, raw) {
|
|
318
|
+
const q = buildQuery({
|
|
319
|
+
...params,
|
|
320
|
+
raw: raw == true ? String(raw) : undefined,
|
|
321
|
+
});
|
|
322
|
+
return this.request(`/chunk/map${q}`);
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunkForceHandler.java)
|
|
326
|
+
* @returns 使用 {@link ChunkForceListSchema} 验证
|
|
327
|
+
*/
|
|
328
|
+
getChunkForceList() {
|
|
329
|
+
return this.request("/chunk/force");
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunkForceHandler.java)
|
|
333
|
+
* @returns 使用 {@link ChunkLoadResultSchema} 验证
|
|
334
|
+
*/
|
|
335
|
+
loadChunk(params) {
|
|
336
|
+
return this.request(`/chunk/force${buildQuery({ action: "load", ...params })}`, {
|
|
337
|
+
method: "POST",
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/chunk/ChunkForceHandler.java)
|
|
342
|
+
* @returns 使用 {@link ChunkLoadResultSchema} 验证
|
|
343
|
+
*/
|
|
344
|
+
unloadChunk(params) {
|
|
345
|
+
return this.request(`/chunk/force${buildQuery({ action: "unload", ...params })}`, {
|
|
346
|
+
method: "POST",
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
// region GT5
|
|
350
|
+
/**
|
|
351
|
+
* 查询单个 GT5 机器信息。
|
|
352
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5BaseHandler.java)
|
|
353
|
+
* @returns 使用 {@link GT5MachineInfoSchema} 验证
|
|
354
|
+
*/
|
|
355
|
+
getGT5Machine(params) {
|
|
356
|
+
return this.request(`/gt5${buildQuery(params)}`);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* 提交批量 GT5 机器查询任务。
|
|
360
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5BatchHandler.java)
|
|
361
|
+
* @param machines 使用 `Joi.array().items(`{@link GT5BatchMachineCoordSchema}`)` 验证
|
|
362
|
+
* @returns 使用 {@link GT5BatchSubmitResultSchema} 验证
|
|
363
|
+
*/
|
|
364
|
+
submitGT5Batch(machines) {
|
|
365
|
+
return this.request("/gt5/batch", {
|
|
366
|
+
method: "POST",
|
|
367
|
+
headers: { "Content-Type": "application/json" },
|
|
368
|
+
body: JSON.stringify(machines),
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* 查询批量 GT5 机器任务状态。
|
|
373
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5BatchHandler.java)
|
|
374
|
+
* @returns 使用 {@link GT5BatchJobResultSchema} 验证
|
|
375
|
+
*/
|
|
376
|
+
getGT5BatchJob(params) {
|
|
377
|
+
return this.request(`/gt5/batch${buildQuery(params)}`);
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* 重新执行已有的批量 GT5 机器查询任务。
|
|
381
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5BatchHandler.java)
|
|
382
|
+
* @returns 使用 {@link GT5BatchRerunResultSchema} 验证
|
|
383
|
+
*/
|
|
384
|
+
rerunGT5Batch(params) {
|
|
385
|
+
return this.request(`/gt5/batch${buildQuery(params)}`, {
|
|
386
|
+
method: "PATCH",
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* 轮询等待批量 GT5 机器任务完成。
|
|
391
|
+
* @param jobId 任务 ID(由 submitGT5Batch 返回)
|
|
392
|
+
* @param intervalMs 轮询间隔 (ms),默认 100
|
|
393
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5BatchHandler.java)
|
|
394
|
+
* @returns 使用 {@link GT5BatchJobResultSchema} 验证
|
|
395
|
+
*/
|
|
396
|
+
async waitForGT5BatchJob(jobId, intervalMs = 100) {
|
|
397
|
+
while (true) {
|
|
398
|
+
const job = await this.getGT5BatchJob({ id: jobId });
|
|
399
|
+
if (job.status === "completed")
|
|
400
|
+
return job;
|
|
401
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* 提交区块扫描任务,异步扫描指定区块内所有 GT5 机器。
|
|
406
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5ChunkScanHandler.java)
|
|
407
|
+
* @returns 使用 {@link GT5ScanSubmitResultSchema} 验证
|
|
408
|
+
*/
|
|
409
|
+
submitGT5ChunkScan(params) {
|
|
410
|
+
return this.request(`/gt5/scan${buildQuery(params)}`, {
|
|
411
|
+
method: "POST",
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* 查询区块扫描任务状态。
|
|
416
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5ChunkScanHandler.java)
|
|
417
|
+
* @returns 使用 {@link GT5ScanJobResultSchema} 验证
|
|
418
|
+
*/
|
|
419
|
+
getGT5ScanJob(params) {
|
|
420
|
+
return this.request(`/gt5/scan${buildQuery(params)}`);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* 轮询等待区块扫描任务完成。
|
|
424
|
+
* @param jobId 任务 ID(由 submitGT5ChunkScan 返回)
|
|
425
|
+
* @param intervalMs 轮询间隔 (ms),默认 100
|
|
426
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/gt5/GT5ChunkScanHandler.java)
|
|
427
|
+
* @returns 使用 {@link GT5ScanJobResultSchema} 验证
|
|
428
|
+
*/
|
|
429
|
+
async waitForGT5ScanJob(jobId, intervalMs = 100) {
|
|
430
|
+
while (true) {
|
|
431
|
+
const job = await this.getGT5ScanJob({ id: jobId });
|
|
432
|
+
if (job.status === "completed")
|
|
433
|
+
return job;
|
|
434
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
// region AE2
|
|
438
|
+
/**
|
|
439
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEBaseHandler.java)
|
|
440
|
+
* @returns 使用 {@link AEHitResultSchema} 验证
|
|
441
|
+
*/
|
|
442
|
+
aeHit(params) {
|
|
443
|
+
return this.request(`/ae${buildQuery(params)}`);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AENodesHandler.java)
|
|
447
|
+
* @returns 使用 `Joi.array().items(`{@link AENodeSchema}`)` 验证
|
|
448
|
+
*/
|
|
449
|
+
aeNodes(params) {
|
|
450
|
+
return this.request(`/ae/nodes${buildQuery(params)}`);
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AECPUHandler.java)
|
|
454
|
+
* @returns 使用 `Joi.array().items(`{@link AECPUSchema}`)` 验证
|
|
455
|
+
*/
|
|
456
|
+
aeCPUs(params) {
|
|
457
|
+
return this.request(`/ae/cpu${buildQuery(params)}`);
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEMEHandler.java)
|
|
461
|
+
* @returns 使用 `Joi.array().items(`{@link AE2PatternSchema}`.append({ slot: Joi.number().required(), direction: Joi.string().optional() }))` 验证
|
|
462
|
+
*/
|
|
463
|
+
aeME(params) {
|
|
464
|
+
return this.request(`/ae/me${buildQuery(params)}`);
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEMEsHandler.java)
|
|
468
|
+
* @returns 使用 `Joi.array().items(`{@link AEMEInterfaceSchema}`)` 验证
|
|
469
|
+
*/
|
|
470
|
+
aeMEs(params) {
|
|
471
|
+
if (params.load || params.world) {
|
|
472
|
+
params.pattern = true;
|
|
473
|
+
}
|
|
474
|
+
return this.request(`/ae/mes${buildQuery(params)}`);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEMEsupportHandler.java)
|
|
478
|
+
* @returns 字符串数组,无专用 Schema
|
|
479
|
+
*/
|
|
480
|
+
aeMESupport() {
|
|
481
|
+
return this.request("/ae/me/support");
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEItemHandler.java)
|
|
485
|
+
* @returns 使用 {@link AEItemsResultSchema} 验证
|
|
486
|
+
*/
|
|
487
|
+
aeItems(params) {
|
|
488
|
+
return this.request(`/ae/item${buildQuery(params)}`);
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AECPUTaskHandler.java)
|
|
492
|
+
* @param body 使用 {@link AECraftingTaskBodySchema} 验证
|
|
493
|
+
* @returns 使用 {@link AECraftingTaskResultSchema} 验证
|
|
494
|
+
*/
|
|
495
|
+
aeCraft(params, body) {
|
|
496
|
+
return this.request(`/ae/cpu/task${buildQuery(params)}`, {
|
|
497
|
+
method: "POST",
|
|
498
|
+
headers: { "Content-Type": "application/json" },
|
|
499
|
+
body: JSON.stringify(body),
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AECPUCancelHandler.java)
|
|
504
|
+
* @param body 使用 {@link AECPUCancelBodySchema} 验证
|
|
505
|
+
* @returns 使用 {@link AECPUCancelResultSchema} 验证
|
|
506
|
+
*/
|
|
507
|
+
aeCancel(params, body) {
|
|
508
|
+
return this.request(`/ae/cpu/cancel${buildQuery(params)}`, {
|
|
509
|
+
method: "DELETE",
|
|
510
|
+
headers: { "Content-Type": "application/json" },
|
|
511
|
+
body: JSON.stringify(body),
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* 构建 AE 库存 SSE(Server-Sent Events)订阅地址。
|
|
516
|
+
* 注意:仅当服务端启用虚拟线程(useVirtualThreads)时该路由才会注册。
|
|
517
|
+
* 返回 EventSource 可直接使用的完整 URL。
|
|
518
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEItemSSEHandler.java)
|
|
519
|
+
*/
|
|
520
|
+
aeItemsSseUrl(params) {
|
|
521
|
+
return `${this.baseUrl}/ae/item/sse${buildQuery(params)}`;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* 以回调方式订阅 AE 库存 SSE 推送(基于 fetchEventSource,可携带 Authorization 头,原生 EventSource 不支持)。
|
|
525
|
+
* 服务端周期性推送 `aeitem` 事件(`ApiResponse<{@link AEItemsResult}>` JSON,间隔由服务端 AE2Config.item.interval 决定),
|
|
526
|
+
* 回调收到解包后的 {@link AEItemsResult},业务失败(success=false)时以 {@link WebApiError} 上报;
|
|
527
|
+
* 连接建立后发生异常时推送 `error` 事件(纯文本消息)并关闭连接。
|
|
528
|
+
* @param params 目标方块坐标
|
|
529
|
+
* @param callback 每次收到库存快照时调用
|
|
530
|
+
* @param errorCallback 出错(网络错误、鉴权失败、服务端 error 事件、业务失败、数据解析失败)时调用,库内自动重连会随之停止
|
|
531
|
+
* @returns AbortController,调用 `abort()` 可停止订阅
|
|
532
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AEItemSSEHandler.java)
|
|
533
|
+
*/
|
|
534
|
+
aeItemSseCallback(params, callback, errorCallback) {
|
|
535
|
+
return this.subscribeSse(`${this.baseUrl}/ae/item/sse${buildQuery(params)}`, "aeitem", callback, errorCallback, raw => unwrapApiResponse(JSON.parse(raw)));
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* 构建 AE 合成 CPU 状态 SSE(Server-Sent Events)订阅地址。
|
|
539
|
+
* 注意:仅当服务端启用虚拟线程(useVirtualThreads)时该路由才会注册。
|
|
540
|
+
* 返回 EventSource 可直接使用的完整 URL。
|
|
541
|
+
* @param params 目标方块坐标;interval 为推送间隔(秒),省略时由服务端取默认值 5
|
|
542
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AECPUSSEHandler.java)
|
|
543
|
+
*/
|
|
544
|
+
aeCpuSseUrl(params) {
|
|
545
|
+
return `${this.baseUrl}/ae/cpu/sse${buildQuery(params)}`;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* 以回调方式订阅 AE 合成 CPU 状态 SSE 推送(基于 fetchEventSource,可携带 Authorization 头,原生 EventSource 不支持)。
|
|
549
|
+
* 服务端周期性推送 `aecpu` 事件({@link AECPU} 数组 JSON,间隔由 interval 参数(秒)决定,服务端默认 5),
|
|
550
|
+
* 回调收到 CPU 状态列表;连接建立后发生异常时推送 `error` 事件(纯文本消息)并关闭连接。
|
|
551
|
+
* @param params 目标方块坐标;interval 为推送间隔(秒),省略时由服务端取默认值
|
|
552
|
+
* @param callback 每次收到 CPU 状态快照时调用
|
|
553
|
+
* @param errorCallback 出错(网络错误、鉴权失败、服务端 error 事件、业务失败、数据解析失败)时调用,库内自动重连会随之停止
|
|
554
|
+
* @returns AbortController,调用 `abort()` 可停止订阅
|
|
555
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ae2/AECPUSSEHandler.java)
|
|
556
|
+
*/
|
|
557
|
+
aeCpuSseCallback(params, callback, errorCallback) {
|
|
558
|
+
return this.subscribeSse(`${this.baseUrl}/ae/cpu/sse${buildQuery(params)}`, "aecpu", callback, errorCallback, raw => {
|
|
559
|
+
const body = JSON.parse(raw);
|
|
560
|
+
// 服务端当前推送裸数组,同时兼容 ApiResponse 包装形式
|
|
561
|
+
return Array.isArray(body) ? body : unwrapApiResponse(body);
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
// region Recipes
|
|
565
|
+
/**
|
|
566
|
+
* 查询工作台合成配方(有序/无序)。
|
|
567
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/recipe/CraftingRecipesHandler.java)
|
|
568
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/recipe/IndexedCraftingRecipesHandler.java)
|
|
569
|
+
* @returns 使用 {@link CraftingRecipesResultSchema} 验证
|
|
570
|
+
*/
|
|
571
|
+
getCraftingRecipes(params) {
|
|
572
|
+
return this.request(`/recipes/crafting${buildQuery(params ?? {})}`);
|
|
573
|
+
}
|
|
574
|
+
/**
|
|
575
|
+
* 查询熔炉熔炼配方。
|
|
576
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/recipe/FurnaceRecipesHandler.java)
|
|
577
|
+
* @returns 使用 {@link FurnaceRecipesResultSchema} 验证
|
|
578
|
+
*/
|
|
579
|
+
getFurnaceRecipes(params) {
|
|
580
|
+
return this.request(`/recipes/furnace${buildQuery(params ?? {})}`);
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* 查询 GT5 配方表的映射表(unlocalizedName → 显示名)。
|
|
584
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/recipe/GTmaps.java)
|
|
585
|
+
* @returns 使用 `Joi.array().items(`{@link GTRecipeMapSchema}`)` 验证
|
|
586
|
+
*/
|
|
587
|
+
getGTRecipeMaps() {
|
|
588
|
+
return this.request("/recipes/gt/maps");
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* 查询 GT5 机器配方。
|
|
592
|
+
* 注意:必须至少提供 id/damage(物品)、fluid(流体)或 map(单个配方表)之一。
|
|
593
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/recipe/GTRecipesHandler.java)
|
|
594
|
+
* @returns 使用 {@link GTRecipesResultSchema} 验证
|
|
595
|
+
*/
|
|
596
|
+
getGTRecipes(params) {
|
|
597
|
+
return this.request(`/recipes/gt${buildQuery(params)}`);
|
|
598
|
+
}
|
|
599
|
+
// region 3D Print
|
|
600
|
+
/**
|
|
601
|
+
* 上传图片 → OC 3D 打印件,投递到玩家背包(多余掉落在玩家附近)。
|
|
602
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ThreeD/PlayerPrintHandler.java)
|
|
603
|
+
* @param params 二选一:id(实体 ID)或 name(玩家名)
|
|
604
|
+
* @param image 图片二进制数据(png/jpg 等)
|
|
605
|
+
* @returns 使用 {@link PlayerPrintResultSchema} 验证
|
|
606
|
+
*/
|
|
607
|
+
printToPlayer(params, image) {
|
|
608
|
+
return this.request(`/3d/player${buildQuery(params)}`, {
|
|
609
|
+
method: "PUT",
|
|
610
|
+
body: image,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* 上传图片 → 在世界中铺设 OC 3D 打印像素画(慢队列逐块执行)。
|
|
615
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ThreeD/WorldPrintHandler.java)
|
|
616
|
+
* @returns 使用 {@link WorldPrintSubmitResultSchema} 验证
|
|
617
|
+
*/
|
|
618
|
+
submitWorldPrint(params, image) {
|
|
619
|
+
return this.request(`/3d/world${buildQuery(params)}`, {
|
|
620
|
+
method: "PUT",
|
|
621
|
+
body: image,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
/**
|
|
625
|
+
* 查询世界 3D 打印任务进度。
|
|
626
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ThreeD/WorldPrintHandler.java)
|
|
627
|
+
* @returns 使用 {@link WorldPrintJobResultSchema} 验证
|
|
628
|
+
*/
|
|
629
|
+
getWorldPrintJob(params) {
|
|
630
|
+
return this.request(`/3d/world${buildQuery(params)}`);
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* 轮询等待世界 3D 打印任务完成。
|
|
634
|
+
* @param jobId 任务 ID(由 submitWorldPrint 返回)
|
|
635
|
+
* @param intervalMs 轮询间隔 (ms),默认 100
|
|
636
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ThreeD/WorldPrintHandler.java)
|
|
637
|
+
* @returns 使用 {@link WorldPrintJobResultSchema} 验证
|
|
638
|
+
*/
|
|
639
|
+
async waitForWorldPrintJob(jobId, intervalMs = 100) {
|
|
640
|
+
while (true) {
|
|
641
|
+
const job = await this.getWorldPrintJob({ id: jobId });
|
|
642
|
+
if (job.status === "completed")
|
|
643
|
+
return job;
|
|
644
|
+
await new Promise(r => setTimeout(r, intervalMs));
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* 上传图片,估算生成的 3D 打印件 NBT 大小(不实际打印)。
|
|
649
|
+
* @java [java](../../../src/main/java/love/shirokasoke/webapi/webserver/handlers/ThreeD/PrintSizeHandler.java)
|
|
650
|
+
* @returns 使用 {@link PrintSizeResultSchema} 验证
|
|
651
|
+
*/
|
|
652
|
+
getPrintSize(image, params) {
|
|
653
|
+
return this.request(`/3d/size${buildQuery(params ?? {})}`, {
|
|
654
|
+
method: "PUT",
|
|
655
|
+
body: image,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
exports.WebApiClient = WebApiClient;
|
|
660
|
+
class WebApiError extends Error {
|
|
661
|
+
constructor(message, status, body) {
|
|
662
|
+
super(message);
|
|
663
|
+
this.name = "WebApiError";
|
|
664
|
+
this.status = status;
|
|
665
|
+
this.body = body;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
exports.WebApiError = WebApiError;
|