@hmcs/sdk 1.0.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/README.md +30 -0
- package/dist/app.cjs +63 -0
- package/dist/app.js +63 -0
- package/dist/assets.cjs +52 -0
- package/dist/assets.js +52 -0
- package/dist/audio.cjs +159 -0
- package/dist/audio.js +159 -0
- package/dist/commands.cjs +298 -0
- package/dist/commands.d.ts +852 -0
- package/dist/commands.js +296 -0
- package/dist/coordinates.cjs +69 -0
- package/dist/coordinates.js +69 -0
- package/dist/displays.cjs +38 -0
- package/dist/displays.js +38 -0
- package/dist/effects.cjs +50 -0
- package/dist/effects.js +50 -0
- package/dist/entities.cjs +249 -0
- package/dist/entities.js +249 -0
- package/dist/host.cjs +297 -0
- package/dist/host.js +294 -0
- package/dist/index.cjs +98 -0
- package/dist/index.d.ts +2612 -0
- package/dist/index.js +17 -0
- package/dist/mods.cjs +207 -0
- package/dist/mods.js +207 -0
- package/dist/preferences.cjs +90 -0
- package/dist/preferences.js +90 -0
- package/dist/settings.cjs +46 -0
- package/dist/settings.js +46 -0
- package/dist/shadowPanel.cjs +46 -0
- package/dist/shadowPanel.js +46 -0
- package/dist/signals.cjs +158 -0
- package/dist/signals.js +158 -0
- package/dist/speech.cjs +48 -0
- package/dist/speech.js +48 -0
- package/dist/utils.cjs +13 -0
- package/dist/utils.js +11 -0
- package/dist/vrm.cjs +469 -0
- package/dist/vrm.js +466 -0
- package/dist/webviews.cjs +310 -0
- package/dist/webviews.js +302 -0
- package/package.json +61 -0
package/dist/host.cjs
ADDED
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Host API namespace for low-level HTTP communication with the Desktop Homunculus server.
|
|
5
|
+
*
|
|
6
|
+
* This module provides the foundational HTTP client functionality used internally
|
|
7
|
+
* by all other SDK modules. It handles the base URL configuration, URL construction,
|
|
8
|
+
* and HTTP methods with automatic error handling.
|
|
9
|
+
*
|
|
10
|
+
* **Note:** This module is primarily for internal SDK use. Most developers should
|
|
11
|
+
* use the higher-level namespaces like `vrm`, `signals`, etc.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* // Internal SDK usage (you typically won't need this directly)
|
|
16
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
17
|
+
* const vrms = await response.json();
|
|
18
|
+
*
|
|
19
|
+
* // URL construction with parameters
|
|
20
|
+
* const url = host.createUrl("vrm", { name: "MyCharacter" });
|
|
21
|
+
* // Results in: http://localhost:3100/vrm?name=MyCharacter
|
|
22
|
+
*
|
|
23
|
+
* // Configure the base URL (e.g., from an MCP server)
|
|
24
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
/** Error thrown when the Homunculus HTTP API returns a non-OK response. */
|
|
28
|
+
class HomunculusApiError extends Error {
|
|
29
|
+
/** HTTP status code (e.g. 404, 500) */
|
|
30
|
+
statusCode;
|
|
31
|
+
/** The request endpoint URL */
|
|
32
|
+
endpoint;
|
|
33
|
+
/** The response body text */
|
|
34
|
+
body;
|
|
35
|
+
constructor(statusCode, endpoint, body) {
|
|
36
|
+
super(`${endpoint}: ${statusCode} ${body}`);
|
|
37
|
+
this.name = "HomunculusApiError";
|
|
38
|
+
this.statusCode = statusCode;
|
|
39
|
+
this.endpoint = endpoint;
|
|
40
|
+
this.body = body;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Error thrown when an NDJSON stream contains malformed data. */
|
|
44
|
+
class HomunculusStreamError extends Error {
|
|
45
|
+
/** The raw line that failed to parse */
|
|
46
|
+
rawLine;
|
|
47
|
+
constructor(rawLine, cause) {
|
|
48
|
+
super(`Failed to parse NDJSON line: ${rawLine}`);
|
|
49
|
+
this.name = "HomunculusStreamError";
|
|
50
|
+
this.rawLine = rawLine;
|
|
51
|
+
if (cause)
|
|
52
|
+
this.cause = cause;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
exports.host = void 0;
|
|
56
|
+
(function (host) {
|
|
57
|
+
let _baseUrl = "http://localhost:3100";
|
|
58
|
+
/**
|
|
59
|
+
* Configures the SDK's base URL for the Desktop Homunculus HTTP server.
|
|
60
|
+
*
|
|
61
|
+
* @param options - Configuration options
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```typescript
|
|
65
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
function configure(options) {
|
|
69
|
+
_baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
70
|
+
}
|
|
71
|
+
host.configure = configure;
|
|
72
|
+
/** Returns the base URL for the Desktop Homunculus HTTP server. */
|
|
73
|
+
function base() {
|
|
74
|
+
return _baseUrl;
|
|
75
|
+
}
|
|
76
|
+
host.base = base;
|
|
77
|
+
/** Creates a new URL instance pointing to the base server. */
|
|
78
|
+
function baseUrl() {
|
|
79
|
+
return new URL(_baseUrl);
|
|
80
|
+
}
|
|
81
|
+
host.baseUrl = baseUrl;
|
|
82
|
+
/**
|
|
83
|
+
* Creates a URL for the Desktop Homunculus API with optional query parameters.
|
|
84
|
+
*
|
|
85
|
+
* @param path - The API endpoint path (relative to base URL)
|
|
86
|
+
* @param params - Optional query parameters to append to the URL
|
|
87
|
+
* @returns A URL instance ready for use in HTTP requests
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // Simple path
|
|
92
|
+
* const url = host.createUrl("vrm");
|
|
93
|
+
* // Result: http://localhost:3100/vrm
|
|
94
|
+
*
|
|
95
|
+
* // With query parameters
|
|
96
|
+
* const url = host.createUrl("entities", { name: "VRM", root: 123 });
|
|
97
|
+
* // Result: http://localhost:3100/entities?name=VRM&root=123
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
function createUrl(path, params) {
|
|
101
|
+
const url = new URL(path, base());
|
|
102
|
+
if (params) {
|
|
103
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
104
|
+
url.searchParams.append(key, String(value));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return url;
|
|
108
|
+
}
|
|
109
|
+
host.createUrl = createUrl;
|
|
110
|
+
/**
|
|
111
|
+
* Performs a GET request to the specified URL with automatic error handling.
|
|
112
|
+
*
|
|
113
|
+
* @param url - The URL to send the GET request to
|
|
114
|
+
* @returns The Response object if successful
|
|
115
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```typescript
|
|
119
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
120
|
+
* const data = await response.json();
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
async function get(url) {
|
|
124
|
+
const response = await fetch(url);
|
|
125
|
+
await throwIfError(response);
|
|
126
|
+
return response;
|
|
127
|
+
}
|
|
128
|
+
host.get = get;
|
|
129
|
+
/**
|
|
130
|
+
* Performs a POST request with JSON payload and automatic error handling.
|
|
131
|
+
*
|
|
132
|
+
* @param url - The URL to send the POST request to
|
|
133
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
134
|
+
* @returns The Response object if successful
|
|
135
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const response = await host.post(
|
|
140
|
+
* host.createUrl("vrm"),
|
|
141
|
+
* { asset: "my-mod::character.vrm" }
|
|
142
|
+
* );
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
async function post(url, body) {
|
|
146
|
+
const response = await fetch(url, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: {
|
|
149
|
+
"Content-Type": "application/json"
|
|
150
|
+
},
|
|
151
|
+
body: JSON.stringify(body ?? {})
|
|
152
|
+
});
|
|
153
|
+
await throwIfError(response);
|
|
154
|
+
return response;
|
|
155
|
+
}
|
|
156
|
+
host.post = post;
|
|
157
|
+
/**
|
|
158
|
+
* Performs a PUT request with JSON payload and automatic error handling.
|
|
159
|
+
*
|
|
160
|
+
* @param url - The URL to send the PUT request to
|
|
161
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
162
|
+
* @returns The Response object if successful
|
|
163
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
164
|
+
*
|
|
165
|
+
* @example
|
|
166
|
+
* ```typescript
|
|
167
|
+
* await host.put(
|
|
168
|
+
* host.createUrl("vrm/123/state"),
|
|
169
|
+
* { state: "idle" }
|
|
170
|
+
* );
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
async function put(url, body) {
|
|
174
|
+
const response = await fetch(url, {
|
|
175
|
+
method: "PUT",
|
|
176
|
+
headers: {
|
|
177
|
+
"Content-Type": "application/json"
|
|
178
|
+
},
|
|
179
|
+
body: JSON.stringify(body ?? {})
|
|
180
|
+
});
|
|
181
|
+
await throwIfError(response);
|
|
182
|
+
return response;
|
|
183
|
+
}
|
|
184
|
+
host.put = put;
|
|
185
|
+
/**
|
|
186
|
+
* Performs a PATCH request with JSON payload and automatic error handling.
|
|
187
|
+
*
|
|
188
|
+
* @param url - The URL to send the PATCH request to
|
|
189
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
190
|
+
* @returns The Response object if successful
|
|
191
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
192
|
+
*/
|
|
193
|
+
async function patch(url, body) {
|
|
194
|
+
const response = await fetch(url, {
|
|
195
|
+
method: "PATCH",
|
|
196
|
+
headers: {
|
|
197
|
+
"Content-Type": "application/json"
|
|
198
|
+
},
|
|
199
|
+
body: JSON.stringify(body ?? {})
|
|
200
|
+
});
|
|
201
|
+
await throwIfError(response);
|
|
202
|
+
return response;
|
|
203
|
+
}
|
|
204
|
+
host.patch = patch;
|
|
205
|
+
async function deleteMethod(url) {
|
|
206
|
+
const response = await fetch(url, {
|
|
207
|
+
method: "DELETE"
|
|
208
|
+
});
|
|
209
|
+
await throwIfError(response);
|
|
210
|
+
return response;
|
|
211
|
+
}
|
|
212
|
+
host.deleteMethod = deleteMethod;
|
|
213
|
+
/**
|
|
214
|
+
* Performs a POST request and returns an async generator that yields
|
|
215
|
+
* parsed NDJSON objects from the streaming response.
|
|
216
|
+
*
|
|
217
|
+
* @param url - The URL to send the POST request to
|
|
218
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
219
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
220
|
+
* @returns An async generator yielding parsed JSON objects of type T
|
|
221
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
222
|
+
* @throws {HomunculusStreamError} If an NDJSON line cannot be parsed
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const stream = host.postStream<MyEvent>(
|
|
227
|
+
* host.createUrl("mods/my-mod/commands/execute"),
|
|
228
|
+
* { command: "build" }
|
|
229
|
+
* );
|
|
230
|
+
* for await (const event of stream) {
|
|
231
|
+
* console.log(event);
|
|
232
|
+
* }
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
async function* postStream(url, body, signal) {
|
|
236
|
+
const response = await fetch(url, {
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: {
|
|
239
|
+
"Content-Type": "application/json"
|
|
240
|
+
},
|
|
241
|
+
body: JSON.stringify(body ?? {}),
|
|
242
|
+
signal,
|
|
243
|
+
});
|
|
244
|
+
await throwIfError(response);
|
|
245
|
+
if (!response.body) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const reader = response.body
|
|
249
|
+
.pipeThrough(new TextDecoderStream())
|
|
250
|
+
.getReader();
|
|
251
|
+
let buffer = "";
|
|
252
|
+
try {
|
|
253
|
+
for (;;) {
|
|
254
|
+
const { done, value } = await reader.read();
|
|
255
|
+
if (done)
|
|
256
|
+
break;
|
|
257
|
+
buffer += value;
|
|
258
|
+
const lines = buffer.split("\n");
|
|
259
|
+
// Keep the last (possibly incomplete) chunk in the buffer
|
|
260
|
+
buffer = lines.pop();
|
|
261
|
+
for (const line of lines) {
|
|
262
|
+
const trimmed = line.trim();
|
|
263
|
+
if (trimmed.length === 0)
|
|
264
|
+
continue;
|
|
265
|
+
try {
|
|
266
|
+
yield JSON.parse(trimmed);
|
|
267
|
+
}
|
|
268
|
+
catch (e) {
|
|
269
|
+
throw new HomunculusStreamError(trimmed, e);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
// Process any remaining data in the buffer
|
|
274
|
+
const trimmed = buffer.trim();
|
|
275
|
+
if (trimmed.length > 0) {
|
|
276
|
+
try {
|
|
277
|
+
yield JSON.parse(trimmed);
|
|
278
|
+
}
|
|
279
|
+
catch (e) {
|
|
280
|
+
throw new HomunculusStreamError(trimmed, e);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
reader.releaseLock();
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
host.postStream = postStream;
|
|
289
|
+
})(exports.host || (exports.host = {}));
|
|
290
|
+
async function throwIfError(response) {
|
|
291
|
+
if (!response.ok) {
|
|
292
|
+
throw new HomunculusApiError(response.status, response.url, await response.text());
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
exports.HomunculusApiError = HomunculusApiError;
|
|
297
|
+
exports.HomunculusStreamError = HomunculusStreamError;
|
package/dist/host.js
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Host API namespace for low-level HTTP communication with the Desktop Homunculus server.
|
|
3
|
+
*
|
|
4
|
+
* This module provides the foundational HTTP client functionality used internally
|
|
5
|
+
* by all other SDK modules. It handles the base URL configuration, URL construction,
|
|
6
|
+
* and HTTP methods with automatic error handling.
|
|
7
|
+
*
|
|
8
|
+
* **Note:** This module is primarily for internal SDK use. Most developers should
|
|
9
|
+
* use the higher-level namespaces like `vrm`, `signals`, etc.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* // Internal SDK usage (you typically won't need this directly)
|
|
14
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
15
|
+
* const vrms = await response.json();
|
|
16
|
+
*
|
|
17
|
+
* // URL construction with parameters
|
|
18
|
+
* const url = host.createUrl("vrm", { name: "MyCharacter" });
|
|
19
|
+
* // Results in: http://localhost:3100/vrm?name=MyCharacter
|
|
20
|
+
*
|
|
21
|
+
* // Configure the base URL (e.g., from an MCP server)
|
|
22
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/** Error thrown when the Homunculus HTTP API returns a non-OK response. */
|
|
26
|
+
class HomunculusApiError extends Error {
|
|
27
|
+
/** HTTP status code (e.g. 404, 500) */
|
|
28
|
+
statusCode;
|
|
29
|
+
/** The request endpoint URL */
|
|
30
|
+
endpoint;
|
|
31
|
+
/** The response body text */
|
|
32
|
+
body;
|
|
33
|
+
constructor(statusCode, endpoint, body) {
|
|
34
|
+
super(`${endpoint}: ${statusCode} ${body}`);
|
|
35
|
+
this.name = "HomunculusApiError";
|
|
36
|
+
this.statusCode = statusCode;
|
|
37
|
+
this.endpoint = endpoint;
|
|
38
|
+
this.body = body;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Error thrown when an NDJSON stream contains malformed data. */
|
|
42
|
+
class HomunculusStreamError extends Error {
|
|
43
|
+
/** The raw line that failed to parse */
|
|
44
|
+
rawLine;
|
|
45
|
+
constructor(rawLine, cause) {
|
|
46
|
+
super(`Failed to parse NDJSON line: ${rawLine}`);
|
|
47
|
+
this.name = "HomunculusStreamError";
|
|
48
|
+
this.rawLine = rawLine;
|
|
49
|
+
if (cause)
|
|
50
|
+
this.cause = cause;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
var host;
|
|
54
|
+
(function (host) {
|
|
55
|
+
let _baseUrl = "http://localhost:3100";
|
|
56
|
+
/**
|
|
57
|
+
* Configures the SDK's base URL for the Desktop Homunculus HTTP server.
|
|
58
|
+
*
|
|
59
|
+
* @param options - Configuration options
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* host.configure({ baseUrl: "http://localhost:4000" });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
function configure(options) {
|
|
67
|
+
_baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
68
|
+
}
|
|
69
|
+
host.configure = configure;
|
|
70
|
+
/** Returns the base URL for the Desktop Homunculus HTTP server. */
|
|
71
|
+
function base() {
|
|
72
|
+
return _baseUrl;
|
|
73
|
+
}
|
|
74
|
+
host.base = base;
|
|
75
|
+
/** Creates a new URL instance pointing to the base server. */
|
|
76
|
+
function baseUrl() {
|
|
77
|
+
return new URL(_baseUrl);
|
|
78
|
+
}
|
|
79
|
+
host.baseUrl = baseUrl;
|
|
80
|
+
/**
|
|
81
|
+
* Creates a URL for the Desktop Homunculus API with optional query parameters.
|
|
82
|
+
*
|
|
83
|
+
* @param path - The API endpoint path (relative to base URL)
|
|
84
|
+
* @param params - Optional query parameters to append to the URL
|
|
85
|
+
* @returns A URL instance ready for use in HTTP requests
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* // Simple path
|
|
90
|
+
* const url = host.createUrl("vrm");
|
|
91
|
+
* // Result: http://localhost:3100/vrm
|
|
92
|
+
*
|
|
93
|
+
* // With query parameters
|
|
94
|
+
* const url = host.createUrl("entities", { name: "VRM", root: 123 });
|
|
95
|
+
* // Result: http://localhost:3100/entities?name=VRM&root=123
|
|
96
|
+
* ```
|
|
97
|
+
*/
|
|
98
|
+
function createUrl(path, params) {
|
|
99
|
+
const url = new URL(path, base());
|
|
100
|
+
if (params) {
|
|
101
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
102
|
+
url.searchParams.append(key, String(value));
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
return url;
|
|
106
|
+
}
|
|
107
|
+
host.createUrl = createUrl;
|
|
108
|
+
/**
|
|
109
|
+
* Performs a GET request to the specified URL with automatic error handling.
|
|
110
|
+
*
|
|
111
|
+
* @param url - The URL to send the GET request to
|
|
112
|
+
* @returns The Response object if successful
|
|
113
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const response = await host.get(host.createUrl("vrm"));
|
|
118
|
+
* const data = await response.json();
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
async function get(url) {
|
|
122
|
+
const response = await fetch(url);
|
|
123
|
+
await throwIfError(response);
|
|
124
|
+
return response;
|
|
125
|
+
}
|
|
126
|
+
host.get = get;
|
|
127
|
+
/**
|
|
128
|
+
* Performs a POST request with JSON payload and automatic error handling.
|
|
129
|
+
*
|
|
130
|
+
* @param url - The URL to send the POST request to
|
|
131
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
132
|
+
* @returns The Response object if successful
|
|
133
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* const response = await host.post(
|
|
138
|
+
* host.createUrl("vrm"),
|
|
139
|
+
* { asset: "my-mod::character.vrm" }
|
|
140
|
+
* );
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
async function post(url, body) {
|
|
144
|
+
const response = await fetch(url, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: {
|
|
147
|
+
"Content-Type": "application/json"
|
|
148
|
+
},
|
|
149
|
+
body: JSON.stringify(body ?? {})
|
|
150
|
+
});
|
|
151
|
+
await throwIfError(response);
|
|
152
|
+
return response;
|
|
153
|
+
}
|
|
154
|
+
host.post = post;
|
|
155
|
+
/**
|
|
156
|
+
* Performs a PUT request with JSON payload and automatic error handling.
|
|
157
|
+
*
|
|
158
|
+
* @param url - The URL to send the PUT request to
|
|
159
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
160
|
+
* @returns The Response object if successful
|
|
161
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* await host.put(
|
|
166
|
+
* host.createUrl("vrm/123/state"),
|
|
167
|
+
* { state: "idle" }
|
|
168
|
+
* );
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
async function put(url, body) {
|
|
172
|
+
const response = await fetch(url, {
|
|
173
|
+
method: "PUT",
|
|
174
|
+
headers: {
|
|
175
|
+
"Content-Type": "application/json"
|
|
176
|
+
},
|
|
177
|
+
body: JSON.stringify(body ?? {})
|
|
178
|
+
});
|
|
179
|
+
await throwIfError(response);
|
|
180
|
+
return response;
|
|
181
|
+
}
|
|
182
|
+
host.put = put;
|
|
183
|
+
/**
|
|
184
|
+
* Performs a PATCH request with JSON payload and automatic error handling.
|
|
185
|
+
*
|
|
186
|
+
* @param url - The URL to send the PATCH request to
|
|
187
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
188
|
+
* @returns The Response object if successful
|
|
189
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
190
|
+
*/
|
|
191
|
+
async function patch(url, body) {
|
|
192
|
+
const response = await fetch(url, {
|
|
193
|
+
method: "PATCH",
|
|
194
|
+
headers: {
|
|
195
|
+
"Content-Type": "application/json"
|
|
196
|
+
},
|
|
197
|
+
body: JSON.stringify(body ?? {})
|
|
198
|
+
});
|
|
199
|
+
await throwIfError(response);
|
|
200
|
+
return response;
|
|
201
|
+
}
|
|
202
|
+
host.patch = patch;
|
|
203
|
+
async function deleteMethod(url) {
|
|
204
|
+
const response = await fetch(url, {
|
|
205
|
+
method: "DELETE"
|
|
206
|
+
});
|
|
207
|
+
await throwIfError(response);
|
|
208
|
+
return response;
|
|
209
|
+
}
|
|
210
|
+
host.deleteMethod = deleteMethod;
|
|
211
|
+
/**
|
|
212
|
+
* Performs a POST request and returns an async generator that yields
|
|
213
|
+
* parsed NDJSON objects from the streaming response.
|
|
214
|
+
*
|
|
215
|
+
* @param url - The URL to send the POST request to
|
|
216
|
+
* @param body - Optional request body that will be JSON-serialized
|
|
217
|
+
* @param signal - Optional AbortSignal for cancellation
|
|
218
|
+
* @returns An async generator yielding parsed JSON objects of type T
|
|
219
|
+
* @throws {HomunculusApiError} If the response status is >= 400
|
|
220
|
+
* @throws {HomunculusStreamError} If an NDJSON line cannot be parsed
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const stream = host.postStream<MyEvent>(
|
|
225
|
+
* host.createUrl("mods/my-mod/commands/execute"),
|
|
226
|
+
* { command: "build" }
|
|
227
|
+
* );
|
|
228
|
+
* for await (const event of stream) {
|
|
229
|
+
* console.log(event);
|
|
230
|
+
* }
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
async function* postStream(url, body, signal) {
|
|
234
|
+
const response = await fetch(url, {
|
|
235
|
+
method: "POST",
|
|
236
|
+
headers: {
|
|
237
|
+
"Content-Type": "application/json"
|
|
238
|
+
},
|
|
239
|
+
body: JSON.stringify(body ?? {}),
|
|
240
|
+
signal,
|
|
241
|
+
});
|
|
242
|
+
await throwIfError(response);
|
|
243
|
+
if (!response.body) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const reader = response.body
|
|
247
|
+
.pipeThrough(new TextDecoderStream())
|
|
248
|
+
.getReader();
|
|
249
|
+
let buffer = "";
|
|
250
|
+
try {
|
|
251
|
+
for (;;) {
|
|
252
|
+
const { done, value } = await reader.read();
|
|
253
|
+
if (done)
|
|
254
|
+
break;
|
|
255
|
+
buffer += value;
|
|
256
|
+
const lines = buffer.split("\n");
|
|
257
|
+
// Keep the last (possibly incomplete) chunk in the buffer
|
|
258
|
+
buffer = lines.pop();
|
|
259
|
+
for (const line of lines) {
|
|
260
|
+
const trimmed = line.trim();
|
|
261
|
+
if (trimmed.length === 0)
|
|
262
|
+
continue;
|
|
263
|
+
try {
|
|
264
|
+
yield JSON.parse(trimmed);
|
|
265
|
+
}
|
|
266
|
+
catch (e) {
|
|
267
|
+
throw new HomunculusStreamError(trimmed, e);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// Process any remaining data in the buffer
|
|
272
|
+
const trimmed = buffer.trim();
|
|
273
|
+
if (trimmed.length > 0) {
|
|
274
|
+
try {
|
|
275
|
+
yield JSON.parse(trimmed);
|
|
276
|
+
}
|
|
277
|
+
catch (e) {
|
|
278
|
+
throw new HomunculusStreamError(trimmed, e);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
reader.releaseLock();
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
host.postStream = postStream;
|
|
287
|
+
})(host || (host = {}));
|
|
288
|
+
async function throwIfError(response) {
|
|
289
|
+
if (!response.ok) {
|
|
290
|
+
throw new HomunculusApiError(response.status, response.url, await response.text());
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export { HomunculusApiError, HomunculusStreamError, host };
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var coordinates = require('./coordinates.cjs');
|
|
4
|
+
var displays = require('./displays.cjs');
|
|
5
|
+
var audio = require('./audio.cjs');
|
|
6
|
+
var effects = require('./effects.cjs');
|
|
7
|
+
var host = require('./host.cjs');
|
|
8
|
+
var preferences = require('./preferences.cjs');
|
|
9
|
+
var settings = require('./settings.cjs');
|
|
10
|
+
var shadowPanel = require('./shadowPanel.cjs');
|
|
11
|
+
var vrm = require('./vrm.cjs');
|
|
12
|
+
var speech = require('./speech.cjs');
|
|
13
|
+
var webviews = require('./webviews.cjs');
|
|
14
|
+
var signals = require('./signals.cjs');
|
|
15
|
+
var entities = require('./entities.cjs');
|
|
16
|
+
var app = require('./app.cjs');
|
|
17
|
+
var mods = require('./mods.cjs');
|
|
18
|
+
var assets = require('./assets.cjs');
|
|
19
|
+
var utils = require('./utils.cjs');
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
Object.defineProperty(exports, "coordinates", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return coordinates.coordinates; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "displays", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return displays.displays; }
|
|
30
|
+
});
|
|
31
|
+
Object.defineProperty(exports, "audio", {
|
|
32
|
+
enumerable: true,
|
|
33
|
+
get: function () { return audio.audio; }
|
|
34
|
+
});
|
|
35
|
+
Object.defineProperty(exports, "effects", {
|
|
36
|
+
enumerable: true,
|
|
37
|
+
get: function () { return effects.effects; }
|
|
38
|
+
});
|
|
39
|
+
exports.HomunculusApiError = host.HomunculusApiError;
|
|
40
|
+
exports.HomunculusStreamError = host.HomunculusStreamError;
|
|
41
|
+
Object.defineProperty(exports, "host", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function () { return host.host; }
|
|
44
|
+
});
|
|
45
|
+
Object.defineProperty(exports, "preferences", {
|
|
46
|
+
enumerable: true,
|
|
47
|
+
get: function () { return preferences.preferences; }
|
|
48
|
+
});
|
|
49
|
+
Object.defineProperty(exports, "settings", {
|
|
50
|
+
enumerable: true,
|
|
51
|
+
get: function () { return settings.settings; }
|
|
52
|
+
});
|
|
53
|
+
Object.defineProperty(exports, "shadowPanel", {
|
|
54
|
+
enumerable: true,
|
|
55
|
+
get: function () { return shadowPanel.shadowPanel; }
|
|
56
|
+
});
|
|
57
|
+
exports.Vrm = vrm.Vrm;
|
|
58
|
+
exports.VrmEventSource = vrm.VrmEventSource;
|
|
59
|
+
Object.defineProperty(exports, "repeat", {
|
|
60
|
+
enumerable: true,
|
|
61
|
+
get: function () { return vrm.repeat; }
|
|
62
|
+
});
|
|
63
|
+
Object.defineProperty(exports, "speech", {
|
|
64
|
+
enumerable: true,
|
|
65
|
+
get: function () { return speech.speech; }
|
|
66
|
+
});
|
|
67
|
+
exports.Webview = webviews.Webview;
|
|
68
|
+
exports.isWebviewSourceHtml = webviews.isWebviewSourceHtml;
|
|
69
|
+
exports.isWebviewSourceInfoHtml = webviews.isWebviewSourceInfoHtml;
|
|
70
|
+
exports.isWebviewSourceInfoLocal = webviews.isWebviewSourceInfoLocal;
|
|
71
|
+
exports.isWebviewSourceInfoUrl = webviews.isWebviewSourceInfoUrl;
|
|
72
|
+
exports.isWebviewSourceLocal = webviews.isWebviewSourceLocal;
|
|
73
|
+
exports.isWebviewSourceUrl = webviews.isWebviewSourceUrl;
|
|
74
|
+
Object.defineProperty(exports, "webviewSource", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
get: function () { return webviews.webviewSource; }
|
|
77
|
+
});
|
|
78
|
+
Object.defineProperty(exports, "signals", {
|
|
79
|
+
enumerable: true,
|
|
80
|
+
get: function () { return signals.signals; }
|
|
81
|
+
});
|
|
82
|
+
Object.defineProperty(exports, "entities", {
|
|
83
|
+
enumerable: true,
|
|
84
|
+
get: function () { return entities.entities; }
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(exports, "app", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
get: function () { return app.app; }
|
|
89
|
+
});
|
|
90
|
+
Object.defineProperty(exports, "mods", {
|
|
91
|
+
enumerable: true,
|
|
92
|
+
get: function () { return mods.mods; }
|
|
93
|
+
});
|
|
94
|
+
Object.defineProperty(exports, "assets", {
|
|
95
|
+
enumerable: true,
|
|
96
|
+
get: function () { return assets.assets; }
|
|
97
|
+
});
|
|
98
|
+
exports.sleep = utils.sleep;
|