@syllm/brickly-test-host 0.11.0 → 0.12.1

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/host.cjs CHANGED
@@ -24210,14 +24210,14 @@ var require_varint = __commonJS({
24210
24210
  "../../node_modules/@bufbuild/protobuf/dist/commonjs/wire/varint.js"(exports2) {
24211
24211
  "use strict";
24212
24212
  Object.defineProperty(exports2, "__esModule", { value: true });
24213
- exports2.varint64read = varint64read;
24213
+ exports2.varint64read = varint64read2;
24214
24214
  exports2.varint64write = varint64write;
24215
24215
  exports2.int64FromString = int64FromString2;
24216
24216
  exports2.int64ToString = int64ToString2;
24217
24217
  exports2.uInt64ToString = uInt64ToString2;
24218
24218
  exports2.varint32write = varint32write;
24219
- exports2.varint32read = varint32read;
24220
- function varint64read() {
24219
+ exports2.varint32read = varint32read2;
24220
+ function varint64read2() {
24221
24221
  const buf = this.buf;
24222
24222
  let pos = this.pos;
24223
24223
  let lo = 0;
@@ -24376,7 +24376,7 @@ var require_varint = __commonJS({
24376
24376
  bytes.push(1);
24377
24377
  }
24378
24378
  }
24379
- function varint32read() {
24379
+ function varint32read2() {
24380
24380
  let b = this.buf[this.pos++];
24381
24381
  if ((b & 128) === 0) {
24382
24382
  this.assertBounds();
@@ -36412,6 +36412,45 @@ var import_grpc_js2 = __toESM(require_src3());
36412
36412
  var import_grpc_js = __toESM(require_src3());
36413
36413
 
36414
36414
  // ../../node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js
36415
+ function varint64read() {
36416
+ const buf = this.buf;
36417
+ let pos = this.pos;
36418
+ let lo = 0;
36419
+ let hi = 0;
36420
+ for (let shift = 0; shift < 28; shift += 7) {
36421
+ const b = buf[pos++];
36422
+ lo |= (b & 127) << shift;
36423
+ if ((b & 128) == 0) {
36424
+ this.pos = pos;
36425
+ this.assertBounds();
36426
+ this.varint64Lo = lo;
36427
+ this.varint64Hi = hi;
36428
+ return;
36429
+ }
36430
+ }
36431
+ const middleByte = buf[pos++];
36432
+ lo |= (middleByte & 15) << 28;
36433
+ hi = (middleByte & 112) >> 4;
36434
+ if ((middleByte & 128) == 0) {
36435
+ this.pos = pos;
36436
+ this.assertBounds();
36437
+ this.varint64Lo = lo;
36438
+ this.varint64Hi = hi;
36439
+ return;
36440
+ }
36441
+ for (let shift = 3; shift <= 31; shift += 7) {
36442
+ const b = buf[pos++];
36443
+ hi |= (b & 127) << shift;
36444
+ if ((b & 128) == 0) {
36445
+ this.pos = pos;
36446
+ this.assertBounds();
36447
+ this.varint64Lo = lo;
36448
+ this.varint64Hi = hi;
36449
+ return;
36450
+ }
36451
+ }
36452
+ throw new Error("invalid varint");
36453
+ }
36415
36454
  var TWO_PWR_32_DBL = 4294967296;
36416
36455
  function int64FromString(dec) {
36417
36456
  const minus = dec[0] === "-";
@@ -36486,6 +36525,40 @@ var decimalFrom1e7WithLeadingZeros = (digit1e7) => {
36486
36525
  const partial = String(digit1e7);
36487
36526
  return "0000000".slice(partial.length) + partial;
36488
36527
  };
36528
+ function varint32read() {
36529
+ let b = this.buf[this.pos++];
36530
+ if ((b & 128) === 0) {
36531
+ this.assertBounds();
36532
+ return b;
36533
+ }
36534
+ let result = b & 127;
36535
+ b = this.buf[this.pos++];
36536
+ result |= (b & 127) << 7;
36537
+ if ((b & 128) === 0) {
36538
+ this.assertBounds();
36539
+ return result;
36540
+ }
36541
+ b = this.buf[this.pos++];
36542
+ result |= (b & 127) << 14;
36543
+ if ((b & 128) === 0) {
36544
+ this.assertBounds();
36545
+ return result;
36546
+ }
36547
+ b = this.buf[this.pos++];
36548
+ result |= (b & 127) << 21;
36549
+ if ((b & 128) === 0) {
36550
+ this.assertBounds();
36551
+ return result;
36552
+ }
36553
+ b = this.buf[this.pos++];
36554
+ result |= (b & 15) << 28;
36555
+ for (let readBytes = 5; (b & 128) !== 0 && readBytes < 10; readBytes++)
36556
+ b = this.buf[this.pos++];
36557
+ if ((b & 128) !== 0)
36558
+ throw new Error("invalid varint");
36559
+ this.assertBounds();
36560
+ return result >>> 0;
36561
+ }
36489
36562
 
36490
36563
  // ../../node_modules/@bufbuild/protobuf/dist/esm/proto-int64.js
36491
36564
  var protoInt64 = /* @__PURE__ */ makeInt64Support();
@@ -36988,6 +37061,206 @@ function varint32Size(value) {
36988
37061
  return 4;
36989
37062
  return 5;
36990
37063
  }
37064
+ var BinaryReader = class {
37065
+ constructor(buf, decodeUtf8 = getTextEncoding().decodeUtf8) {
37066
+ this.decodeUtf8 = decodeUtf8;
37067
+ this.varint64Lo = 0;
37068
+ this.varint64Hi = 0;
37069
+ this.varint64 = varint64read;
37070
+ this.uint32 = varint32read;
37071
+ this.buf = buf;
37072
+ this.len = buf.length;
37073
+ this.pos = 0;
37074
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
37075
+ }
37076
+ /**
37077
+ * Reads a tag - field number and wire type. Tags are uint32 varints; values
37078
+ * that do not fit in uint32 are rejected.
37079
+ */
37080
+ tag() {
37081
+ const start = this.pos;
37082
+ const tag = this.uint32();
37083
+ const bytesRead = this.pos - start;
37084
+ if (bytesRead > 5 || bytesRead == 5 && this.buf[this.pos - 1] > 15) {
37085
+ throw new Error("illegal tag: varint overflows uint32");
37086
+ }
37087
+ const fieldNo = tag >>> 3;
37088
+ const wireType = tag & 7;
37089
+ if (fieldNo <= 0 || wireType > 5) {
37090
+ throw new Error("illegal tag: field no " + fieldNo + " wire type " + wireType);
37091
+ }
37092
+ return [fieldNo, wireType];
37093
+ }
37094
+ /**
37095
+ * Skip one element and return the skipped data.
37096
+ *
37097
+ * When skipping StartGroup, provide the tags field number to check for
37098
+ * matching field number in the EndGroup tag. Recursion into nested groups
37099
+ * is guarded by the `recursionLimit` argument: When the limit is reached,
37100
+ * this method throws.
37101
+ */
37102
+ skip(wireType, fieldNo, recursionLimit = 100) {
37103
+ let start = this.pos;
37104
+ switch (wireType) {
37105
+ case WireType.Varint:
37106
+ while (this.buf[this.pos++] & 128) {
37107
+ }
37108
+ break;
37109
+ // @ts-ignore TS7029: Fallthrough case in switch -- ignore instead of expect-error for compiler settings without noFallthroughCasesInSwitch: true
37110
+ case WireType.Bit64:
37111
+ this.pos += 4;
37112
+ case WireType.Bit32:
37113
+ this.pos += 4;
37114
+ break;
37115
+ case WireType.LengthDelimited:
37116
+ let len = this.uint32();
37117
+ this.pos += len;
37118
+ break;
37119
+ case WireType.StartGroup:
37120
+ if (recursionLimit <= 0) {
37121
+ throw new Error("maximum recursion depth reached");
37122
+ }
37123
+ for (; ; ) {
37124
+ const [fn, wt] = this.tag();
37125
+ if (wt === WireType.EndGroup) {
37126
+ if (fieldNo !== void 0 && fn !== fieldNo) {
37127
+ throw new Error("invalid end group tag");
37128
+ }
37129
+ break;
37130
+ }
37131
+ this.skip(wt, fn, recursionLimit - 1);
37132
+ }
37133
+ break;
37134
+ default:
37135
+ throw new Error("cant skip wire type " + wireType);
37136
+ }
37137
+ this.assertBounds();
37138
+ return this.buf.subarray(start, this.pos);
37139
+ }
37140
+ /**
37141
+ * Throws error if position in byte array is out of range.
37142
+ */
37143
+ assertBounds() {
37144
+ if (this.pos > this.len)
37145
+ throw new RangeError("premature EOF");
37146
+ }
37147
+ /**
37148
+ * Read a `int32` field, a signed 32 bit varint.
37149
+ */
37150
+ int32() {
37151
+ return this.uint32() | 0;
37152
+ }
37153
+ /**
37154
+ * Read a `sint32` field, a signed, zigzag-encoded 32-bit varint.
37155
+ */
37156
+ sint32() {
37157
+ let zze = this.uint32();
37158
+ return zze >>> 1 ^ -(zze & 1);
37159
+ }
37160
+ /**
37161
+ * Read a `int64` field, a signed 64-bit varint.
37162
+ */
37163
+ int64() {
37164
+ this.varint64();
37165
+ return protoInt64.dec(this.varint64Lo, this.varint64Hi);
37166
+ }
37167
+ /**
37168
+ * Read a `uint64` field, an unsigned 64-bit varint.
37169
+ */
37170
+ uint64() {
37171
+ this.varint64();
37172
+ return protoInt64.uDec(this.varint64Lo, this.varint64Hi);
37173
+ }
37174
+ /**
37175
+ * Read a `sint64` field, a signed, zig-zag-encoded 64-bit varint.
37176
+ */
37177
+ sint64() {
37178
+ this.varint64();
37179
+ let lo = this.varint64Lo;
37180
+ let hi = this.varint64Hi;
37181
+ let s = -(lo & 1);
37182
+ lo = (lo >>> 1 | (hi & 1) << 31) ^ s;
37183
+ hi = hi >>> 1 ^ s;
37184
+ return protoInt64.dec(lo, hi);
37185
+ }
37186
+ /**
37187
+ * Read a `bool` field, a variant.
37188
+ */
37189
+ bool() {
37190
+ const b = this.buf[this.pos];
37191
+ if (b < 128) {
37192
+ this.pos++;
37193
+ return b !== 0;
37194
+ }
37195
+ this.varint64();
37196
+ return this.varint64Lo !== 0 || this.varint64Hi !== 0;
37197
+ }
37198
+ /**
37199
+ * Read a `fixed32` field, an unsigned, fixed-length 32-bit integer.
37200
+ */
37201
+ fixed32() {
37202
+ return this.view.getUint32((this.pos += 4) - 4, true);
37203
+ }
37204
+ /**
37205
+ * Read a `sfixed32` field, a signed, fixed-length 32-bit integer.
37206
+ */
37207
+ sfixed32() {
37208
+ return this.view.getInt32((this.pos += 4) - 4, true);
37209
+ }
37210
+ /**
37211
+ * Read a `fixed64` field, an unsigned, fixed-length 64 bit integer.
37212
+ */
37213
+ fixed64() {
37214
+ return protoInt64.uDec(this.sfixed32(), this.sfixed32());
37215
+ }
37216
+ /**
37217
+ * Read a `fixed64` field, a signed, fixed-length 64-bit integer.
37218
+ */
37219
+ sfixed64() {
37220
+ return protoInt64.dec(this.sfixed32(), this.sfixed32());
37221
+ }
37222
+ /**
37223
+ * Read a `float` field, 32-bit floating point number.
37224
+ */
37225
+ float() {
37226
+ return this.view.getFloat32((this.pos += 4) - 4, true);
37227
+ }
37228
+ /**
37229
+ * Read a `double` field, a 64-bit floating point number.
37230
+ */
37231
+ double() {
37232
+ return this.view.getFloat64((this.pos += 8) - 8, true);
37233
+ }
37234
+ /**
37235
+ * Read a `bytes` field, length-delimited arbitrary data.
37236
+ */
37237
+ bytes() {
37238
+ let len = this.uint32(), start = this.pos;
37239
+ this.pos += len;
37240
+ this.assertBounds();
37241
+ return this.buf.subarray(start, start + len);
37242
+ }
37243
+ /**
37244
+ * Read a `string` field, length-delimited data converted to UTF-8 text. If
37245
+ * `strict` is true, throw on invalid UTF-8 instead of substituting U+FFFD.
37246
+ */
37247
+ string(strict) {
37248
+ const bytes = this.bytes();
37249
+ const len = bytes.length;
37250
+ if (len <= ASCII_MAX_LENGTH) {
37251
+ const codes = new Array(len);
37252
+ for (let i = 0; i < len; i++) {
37253
+ const byte = bytes[i];
37254
+ if (byte > 127) {
37255
+ return this.decodeUtf8(bytes, strict);
37256
+ }
37257
+ codes[i] = byte;
37258
+ }
37259
+ return String.fromCharCode.apply(String, codes);
37260
+ }
37261
+ return this.decodeUtf8(bytes, strict);
37262
+ }
37263
+ };
36991
37264
  function assertInt32(arg) {
36992
37265
  if (typeof arg == "string") {
36993
37266
  arg = Number(arg);
@@ -37086,6 +37359,17 @@ function toBrickGrpcStatus(error) {
37086
37359
  metadata
37087
37360
  };
37088
37361
  }
37362
+ function unpackBrickError(error) {
37363
+ const bin = error.metadata?.get("grpc-status-details-bin")[0];
37364
+ if (!bin) return void 0;
37365
+ const bytes = typeof bin === "string" ? Buffer.from(bin, "utf8") : bin;
37366
+ for (const item of decodeRpcStatus(bytes)) {
37367
+ if (item.typeUrl === BRICK_ERROR_TYPE_URL || item.typeUrl.endsWith("BrickError")) {
37368
+ return import_error.BrickError.decode(item.value);
37369
+ }
37370
+ }
37371
+ return void 0;
37372
+ }
37089
37373
  function registeredDetail(code, error) {
37090
37374
  const extra = error && typeof error === "object" && "detail" in error && error.detail && typeof error.detail === "object" ? error.detail : {};
37091
37375
  const text = (key, fallback) => typeof extra[key] === "string" ? extra[key] : fallback;
@@ -37256,6 +37540,19 @@ function encodeRpcStatus(code, message, details) {
37256
37540
  }
37257
37541
  return Buffer.from(writer.finish());
37258
37542
  }
37543
+ function decodeRpcStatus(bytes) {
37544
+ const reader = new BinaryReader(bytes);
37545
+ const details = [];
37546
+ while (reader.pos < reader.len) {
37547
+ const tag = reader.uint32();
37548
+ const field = tag >>> 3;
37549
+ if (field === 3) details.push(import_any.Any.decode(reader.bytes()));
37550
+ else if (field === 1) reader.int32();
37551
+ else if (field === 2) reader.string();
37552
+ else reader.skip(tag & 7);
37553
+ }
37554
+ return details;
37555
+ }
37259
37556
 
37260
37557
  // ../../src/main/runtime/transport/connector-interact-relay.ts
37261
37558
  function relayConnectorInteract(call, openInteract) {
@@ -40403,19 +40700,30 @@ var HostGrpcServer = class {
40403
40700
  });
40404
40701
  this.server.addService(
40405
40702
  import_resource.ResourceServiceService,
40406
- createResourceServiceImplementation(this.resources, this.spawns, this.resourceContext, this.helperAccess)
40703
+ createResourceServiceImplementation(
40704
+ this.resources,
40705
+ this.spawns,
40706
+ this.resourceContext,
40707
+ this.helperAccess
40708
+ )
40407
40709
  );
40408
40710
  this.server.addService(
40409
40711
  import_event.EventServiceService,
40410
40712
  createEventServiceImplementation(this.events, this.spawns, () => this.eventRouter)
40411
40713
  );
40412
- this.server.addService(import_storage.StorageServiceService, createStorageServiceImplementation(this.storage, this.spawns));
40714
+ this.server.addService(
40715
+ import_storage.StorageServiceService,
40716
+ createStorageServiceImplementation(this.storage, this.spawns)
40717
+ );
40413
40718
  this.server.addService(
40414
40719
  import_brick_storage.BrickStorageServiceService,
40415
40720
  createBrickStorageServiceImplementation(() => this.brickStorageService, this.spawns)
40416
40721
  );
40417
40722
  this.server.addService(import_system.SystemServiceService, createSystemServiceImplementation(this.spawns));
40418
- this.server.addService(import_window.WindowServiceService, createWindowServiceImplementation(this.windows, this.spawns));
40723
+ this.server.addService(
40724
+ import_window.WindowServiceService,
40725
+ createWindowServiceImplementation(this.windows, this.spawns)
40726
+ );
40419
40727
  this.server.addService(
40420
40728
  import_connector.BrickConnectorServiceService,
40421
40729
  createConnectorServiceImplementation(this.connector, this.spawns)
@@ -40473,6 +40781,10 @@ var HostGrpcServer = class {
40473
40781
  getHandle(runtimeHandleId) {
40474
40782
  return this.handles.get(runtimeHandleId);
40475
40783
  }
40784
+ /** 已注册 runtime 句柄快照(测试驱动面用,只读)。 */
40785
+ listHandles() {
40786
+ return [...this.handles.values()];
40787
+ }
40476
40788
  async listen(host = "127.0.0.1", port = 0) {
40477
40789
  assertLoopbackHost(host);
40478
40790
  if (this.started) {
@@ -40480,13 +40792,17 @@ var HostGrpcServer = class {
40480
40792
  return this.endpoint;
40481
40793
  }
40482
40794
  const bound = await new Promise((resolve2, reject) => {
40483
- this.server.bindAsync(`${host}:${port}`, import_grpc_js12.ServerCredentials.createInsecure(), (error, boundPort) => {
40484
- if (error) {
40485
- reject(error);
40486
- return;
40795
+ this.server.bindAsync(
40796
+ `${host}:${port}`,
40797
+ import_grpc_js12.ServerCredentials.createInsecure(),
40798
+ (error, boundPort) => {
40799
+ if (error) {
40800
+ reject(error);
40801
+ return;
40802
+ }
40803
+ resolve2(`${host}:${boundPort}`);
40487
40804
  }
40488
- resolve2(`${host}:${boundPort}`);
40489
- });
40805
+ );
40490
40806
  });
40491
40807
  this.endpoint = bound;
40492
40808
  this.started = true;
@@ -40691,11 +41007,174 @@ async function startTestHost(options = {}) {
40691
41007
  };
40692
41008
  }
40693
41009
 
41010
+ // ../../src/main/runtime/transport/test-host/drive.ts
41011
+ var CANNED_UI_METHODS = [
41012
+ "createBrowserWindow",
41013
+ "callWindow",
41014
+ "closeWindow",
41015
+ "forceCloseWindow",
41016
+ "listWindows",
41017
+ "sendToChild",
41018
+ "replyToChild",
41019
+ "emitToChild"
41020
+ ];
41021
+ var HostDriver = class {
41022
+ constructor(testHost) {
41023
+ this.testHost = testHost;
41024
+ }
41025
+ cannedUi = /* @__PURE__ */ new Map();
41026
+ uiCallLog = [];
41027
+ uiHandlerInstalled = false;
41028
+ /** 再铸一套 spawn 凭据(依赖 invoke 等需要多个 runtime 的用例)。 */
41029
+ spawn(input) {
41030
+ const credentials2 = this.testHost.host.createSpawn({
41031
+ brickId: input.brickId,
41032
+ instanceId: input.instanceId,
41033
+ origin: input.origin ?? "development",
41034
+ version: input.version ?? "0.0.0"
41035
+ });
41036
+ const record = this.testHost.host.spawns.get(credentials2.spawnId);
41037
+ return {
41038
+ ...credentials2,
41039
+ brickId: record?.brickId ?? input.brickId,
41040
+ instanceId: record?.instanceId ?? credentials2.spawnId
41041
+ };
41042
+ }
41043
+ /** 已注册 runtime 句柄快照(测试等待/断言用)。 */
41044
+ runtimes() {
41045
+ return this.testHost.host.listHandles().map((handle) => ({
41046
+ spawnId: handle.runtimeHandleId,
41047
+ brickId: handle.brickId,
41048
+ instanceId: handle.instanceId
41049
+ }));
41050
+ }
41051
+ /** 等待 runtime 完成注册,拿到 host→runtime 通道句柄。 */
41052
+ async waitHandle(spawnId, timeoutMs = 1e4) {
41053
+ const id = spawnId ?? this.testHost.spawnCredentials.spawnId;
41054
+ const deadline = Date.now() + timeoutMs;
41055
+ while (Date.now() < deadline) {
41056
+ const handle = this.testHost.host.getHandle(id);
41057
+ if (handle) return handle;
41058
+ await sleep(40);
41059
+ }
41060
+ throw new Error(`\u7B49\u5F85 runtime \u6CE8\u518C\u8D85\u65F6\uFF1AspawnId=${id}`);
41061
+ }
41062
+ /** host→runtime 单向 invoke;错误按 brick 码结构化返回而不抛出。 */
41063
+ async invoke(input) {
41064
+ try {
41065
+ const handle = await this.waitHandle(input.spawnId, input.timeoutMs);
41066
+ const result = await handle.channel.invoke(
41067
+ { commandId: input.commandId, input: jsToBrickValue(input.input ?? null) },
41068
+ { deadlineMs: input.timeoutMs }
41069
+ );
41070
+ return { ok: true, result: brickValueToJs(result.result) };
41071
+ } catch (error) {
41072
+ return { ok: false, error: serializeError(error) };
41073
+ }
41074
+ }
41075
+ /** host→runtime interact 批量模式:open → closeInput → 收 events 与 final。 */
41076
+ async interact(input) {
41077
+ try {
41078
+ const handle = await this.waitHandle(input.spawnId, input.timeoutMs);
41079
+ const signal = input.timeoutMs ? AbortSignal.timeout(input.timeoutMs) : void 0;
41080
+ const { events, result } = await handle.channel.stream(
41081
+ input.commandId,
41082
+ jsToBrickValue(input.input ?? null),
41083
+ { signal }
41084
+ );
41085
+ return { ok: true, events: events.map(brickValueToJs), result: brickValueToJs(result) };
41086
+ } catch (error) {
41087
+ return { ok: false, error: serializeError(error) };
41088
+ }
41089
+ }
41090
+ /** 往指定 runtime 推 domain event(经真 HostEventBus 投递到订阅流)。 */
41091
+ async pushEvent(input) {
41092
+ const spawnId = input.spawnId ?? this.testHost.spawnCredentials.spawnId;
41093
+ const record = this.testHost.host.spawns.get(spawnId);
41094
+ const instanceId = record?.instanceId ?? spawnId;
41095
+ this.testHost.host.events.publishTo(
41096
+ instanceId,
41097
+ input.topic,
41098
+ jsToBrickValue(input.payload ?? null)
41099
+ );
41100
+ }
41101
+ /**
41102
+ * 注册 UI 方法罐头响应(重复注册后者覆盖前者)。
41103
+ * method 取 HostUiHandler 方法名,如 createBrowserWindow / callWindow。
41104
+ */
41105
+ setUiResponse(method, result) {
41106
+ if (!CANNED_UI_METHODS.includes(method)) {
41107
+ throw new Error(`\u672A\u77E5 UI \u65B9\u6CD5\uFF1A${method}\uFF08\u53EF\u9009\uFF1A${CANNED_UI_METHODS.join(", ")}\uFF09`);
41108
+ }
41109
+ this.cannedUi.set(method, result);
41110
+ if (!this.uiHandlerInstalled) {
41111
+ this.installUiHandler();
41112
+ this.uiHandlerInstalled = true;
41113
+ }
41114
+ }
41115
+ /** UI handler 被调记录(按序),/reset 清空。 */
41116
+ uiCalls() {
41117
+ return [...this.uiCallLog];
41118
+ }
41119
+ /** 清驱动面状态:罐头响应与 UI 调用记录(不动 storage/故障规则,那些归 control)。 */
41120
+ reset() {
41121
+ this.cannedUi.clear();
41122
+ this.uiCallLog.length = 0;
41123
+ }
41124
+ installUiHandler() {
41125
+ const dispatch = (method, args) => {
41126
+ this.uiCallLog.push({ method, args, at: Date.now() });
41127
+ if (!this.cannedUi.has(method)) {
41128
+ throw new Error(`UI \u65B9\u6CD5 ${method} \u672A\u6CE8\u518C\u7F50\u5934\u54CD\u5E94`);
41129
+ }
41130
+ return this.cannedUi.get(method);
41131
+ };
41132
+ const handler = {
41133
+ createBrowserWindow: (...args) => dispatch("createBrowserWindow", args),
41134
+ callWindow: (...args) => dispatch("callWindow", args),
41135
+ closeWindow: (...args) => dispatch("closeWindow", args),
41136
+ forceCloseWindow: (...args) => dispatch("forceCloseWindow", args),
41137
+ listWindows: (...args) => dispatch("listWindows", args),
41138
+ sendToChild: (...args) => dispatch("sendToChild", args),
41139
+ replyToChild: (...args) => dispatch("replyToChild", args),
41140
+ emitToChild: (...args) => dispatch("emitToChild", args)
41141
+ };
41142
+ this.testHost.host.setUiHandler(handler);
41143
+ }
41144
+ };
41145
+ function createHostDriver(testHost) {
41146
+ return new HostDriver(testHost);
41147
+ }
41148
+ function serializeError(error) {
41149
+ const serviceError = error;
41150
+ let brick;
41151
+ try {
41152
+ brick = unpackBrickError(serviceError);
41153
+ } catch {
41154
+ brick = void 0;
41155
+ }
41156
+ return {
41157
+ brickCode: brick?.code,
41158
+ message: serviceError?.message ?? String(error),
41159
+ grpcStatus: serviceError?.code
41160
+ };
41161
+ }
41162
+ function sleep(ms) {
41163
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
41164
+ }
41165
+
40694
41166
  // ../../src/main/runtime/transport/test-host/main.ts
40695
41167
  async function main() {
40696
41168
  const testHost = await startTestHost();
41169
+ const driver = createHostDriver(testHost);
40697
41170
  const control = (0, import_node_http.createServer)((request, response) => {
40698
- void handle(request, response).catch(() => reply(response, 500, { error: "control internal error" }));
41171
+ void handle(request, response).catch((error) => {
41172
+ process.stderr.write(
41173
+ `[test-host] \u63A7\u5236\u9762\u5185\u90E8\u9519\u8BEF: ${error instanceof Error ? error.stack ?? error.message : String(error)}
41174
+ `
41175
+ );
41176
+ reply(response, 500, { error: "control internal error" });
41177
+ });
40699
41178
  });
40700
41179
  async function handle(request, response) {
40701
41180
  const url = request.url ?? "/";
@@ -40716,6 +41195,7 @@ async function main() {
40716
41195
  }
40717
41196
  if (request.method === "POST" && url === "/reset") {
40718
41197
  testHost.control.reset();
41198
+ driver.reset();
40719
41199
  reply(response, 200, { ok: true });
40720
41200
  return;
40721
41201
  }
@@ -40723,6 +41203,97 @@ async function main() {
40723
41203
  reply(response, 200, { calls: testHost.control.recordedCalls() });
40724
41204
  return;
40725
41205
  }
41206
+ if (request.method === "POST" && url === "/spawn") {
41207
+ const body = await readBody(request);
41208
+ if (typeof body.brickId !== "string" || body.brickId.length === 0) {
41209
+ reply(response, 400, { error: "spawn \u9700\u8981 brickId" });
41210
+ return;
41211
+ }
41212
+ reply(
41213
+ response,
41214
+ 200,
41215
+ driver.spawn({
41216
+ brickId: body.brickId,
41217
+ instanceId: typeof body.instanceId === "string" ? body.instanceId : void 0,
41218
+ origin: body.origin === "installed" || body.origin === "review" || body.origin === "platform" ? body.origin : "development",
41219
+ version: typeof body.version === "string" ? body.version : void 0
41220
+ })
41221
+ );
41222
+ return;
41223
+ }
41224
+ if (request.method === "POST" && url === "/invoke") {
41225
+ const body = await readBody(request);
41226
+ if (typeof body.commandId !== "string" || body.commandId.length === 0) {
41227
+ reply(response, 400, { error: "invoke \u9700\u8981 commandId" });
41228
+ return;
41229
+ }
41230
+ reply(
41231
+ response,
41232
+ 200,
41233
+ await driver.invoke({
41234
+ spawnId: typeof body.spawnId === "string" ? body.spawnId : void 0,
41235
+ commandId: body.commandId,
41236
+ input: body.input,
41237
+ timeoutMs: typeof body.timeoutMs === "number" ? body.timeoutMs : void 0
41238
+ })
41239
+ );
41240
+ return;
41241
+ }
41242
+ if (request.method === "POST" && url === "/interact") {
41243
+ const body = await readBody(request);
41244
+ if (typeof body.commandId !== "string" || body.commandId.length === 0) {
41245
+ reply(response, 400, { error: "interact \u9700\u8981 commandId" });
41246
+ return;
41247
+ }
41248
+ reply(
41249
+ response,
41250
+ 200,
41251
+ await driver.interact({
41252
+ spawnId: typeof body.spawnId === "string" ? body.spawnId : void 0,
41253
+ commandId: body.commandId,
41254
+ input: body.input,
41255
+ timeoutMs: typeof body.timeoutMs === "number" ? body.timeoutMs : void 0
41256
+ })
41257
+ );
41258
+ return;
41259
+ }
41260
+ if (request.method === "POST" && url === "/events/push") {
41261
+ const body = await readBody(request);
41262
+ if (typeof body.topic !== "string" || body.topic.length === 0) {
41263
+ reply(response, 400, { error: "events/push \u9700\u8981 topic" });
41264
+ return;
41265
+ }
41266
+ await driver.pushEvent({
41267
+ spawnId: typeof body.spawnId === "string" ? body.spawnId : void 0,
41268
+ topic: body.topic,
41269
+ payload: body.payload
41270
+ });
41271
+ reply(response, 200, { ok: true });
41272
+ return;
41273
+ }
41274
+ if (request.method === "POST" && url === "/ui-handler") {
41275
+ const body = await readBody(request);
41276
+ if (typeof body.method !== "string" || body.method.length === 0) {
41277
+ reply(response, 400, { error: "ui-handler \u9700\u8981 method \u4E0E result" });
41278
+ return;
41279
+ }
41280
+ try {
41281
+ driver.setUiResponse(body.method, body.result);
41282
+ } catch (error) {
41283
+ reply(response, 400, { error: error instanceof Error ? error.message : String(error) });
41284
+ return;
41285
+ }
41286
+ reply(response, 200, { ok: true });
41287
+ return;
41288
+ }
41289
+ if (request.method === "GET" && url === "/ui-calls") {
41290
+ reply(response, 200, { calls: driver.uiCalls() });
41291
+ return;
41292
+ }
41293
+ if (request.method === "GET" && url === "/runtimes") {
41294
+ reply(response, 200, { runtimes: driver.runtimes() });
41295
+ return;
41296
+ }
40726
41297
  reply(response, 404, { error: `\u672A\u77E5\u63A7\u5236\u9762\u8DEF\u5F84\uFF1A${request.method} ${url}` });
40727
41298
  }
40728
41299
  await new Promise((resolve2) => {