appium-ios-remotexpc 1.1.4 → 1.1.6

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/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ ## [1.1.6](https://github.com/appium/appium-ios-remotexpc/compare/v1.1.5...v1.1.6) (2026-05-06)
2
+
3
+ ### Bug Fixes
4
+
5
+ * **packet-stream-server:** only evict client on actual broadcast write error ([#202](https://github.com/appium/appium-ios-remotexpc/issues/202)) ([0d9595e](https://github.com/appium/appium-ios-remotexpc/commit/0d9595e8b4ac2e6582b9f84ed6ac8516fb20006e))
6
+
7
+ ## [1.1.5](https://github.com/appium/appium-ios-remotexpc/compare/v1.1.4...v1.1.5) (2026-05-06)
8
+
9
+ ### Bug Fixes
10
+
11
+ * **tunnel:** resolve PacketStreamServer.stop() hang on Ctrl+C ([#201](https://github.com/appium/appium-ios-remotexpc/issues/201)) ([17a1afa](https://github.com/appium/appium-ios-remotexpc/commit/17a1afaa81ec087d825e3d070e9509bd1d8ce33f))
12
+
1
13
  ## [1.1.4](https://github.com/appium/appium-ios-remotexpc/compare/v1.1.3...v1.1.4) (2026-05-06)
2
14
 
3
15
  ### Bug Fixes
@@ -29,6 +29,10 @@ export declare class PacketStreamServer extends EventEmitter {
29
29
  * Broadcast packet to all connected clients
30
30
  */
31
31
  private broadcastPacket;
32
+ /**
33
+ * Promisified wrapper around `socket.write` so callers can use async/await.
34
+ */
35
+ private writeToClient;
32
36
  /**
33
37
  * Create a message buffer with length prefix
34
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"packet-stream-server.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAKtC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,cAAc,CAA+B;gBAExB,IAAI,EAAE,MAAM;IAIzC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAI1C;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;OAEG;IACH,OAAO,CAAC,eAAe;IAmBvB;;OAEG;IACH,OAAO,CAAC,aAAa;CAItB"}
1
+ {"version":3,"file":"packet-stream-server.d.ts","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAKtC,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,cAAc,CAA+B;gBAExB,IAAI,EAAE,MAAM;IAIzC;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB3B,iBAAiB,IAAI,cAAc,GAAG,IAAI;IAI1C;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;OAEG;YACW,eAAe;IAwB7B;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,OAAO,CAAC,aAAa;CAItB"}
@@ -43,7 +43,7 @@ export class PacketStreamServer extends EventEmitter {
43
43
  const server = this.server;
44
44
  await new Promise((resolve, reject) => {
45
45
  server.once('error', reject);
46
- server.close(() => resolve);
46
+ server.close(() => resolve());
47
47
  });
48
48
  this.server = null;
49
49
  }
@@ -72,31 +72,50 @@ export class PacketStreamServer extends EventEmitter {
72
72
  createPacketConsumer() {
73
73
  return {
74
74
  onPacket: (packet) => {
75
- this.broadcastPacket(packet);
75
+ void this.broadcastPacket(packet);
76
76
  },
77
77
  };
78
78
  }
79
79
  /**
80
80
  * Broadcast packet to all connected clients
81
81
  */
82
- broadcastPacket(packet) {
82
+ async broadcastPacket(packet) {
83
83
  try {
84
84
  const serialized = JSON.stringify(packet);
85
85
  const message = this.createMessage(serialized);
86
- for (const client of this.clients) {
87
- const onError = (err) => {
86
+ await Promise.all(Array.from(this.clients).map(async (client) => {
87
+ if (!client.writable) {
88
+ this.clients.delete(client);
89
+ return;
90
+ }
91
+ try {
92
+ await this.writeToClient(client, message);
93
+ }
94
+ catch (err) {
88
95
  log.error(`Failed to write to client: ${err}`);
89
96
  this.clients.delete(client);
90
- };
91
- if (!client.destroyed) {
92
- client.write(message, onError);
93
97
  }
94
- }
98
+ }));
95
99
  }
96
100
  catch (err) {
97
101
  log.error(`Failed to broadcast packet: ${err}`);
98
102
  }
99
103
  }
104
+ /**
105
+ * Promisified wrapper around `socket.write` so callers can use async/await.
106
+ */
107
+ writeToClient(client, message) {
108
+ return new Promise((resolve, reject) => {
109
+ const onWriteComplete = (err) => {
110
+ if (err) {
111
+ reject(err);
112
+ return;
113
+ }
114
+ resolve();
115
+ };
116
+ client.write(message, onWriteComplete);
117
+ });
118
+ }
100
119
  /**
101
120
  * Create a message buffer with length prefix
102
121
  */
@@ -1 +1 @@
1
- {"version":3,"file":"packet-stream-server.js","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"packet-stream-server.js","sourceRoot":"","sources":["../../../../src/lib/tunnel/packet-stream-server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAA4B,YAAY,EAAE,MAAM,UAAU,CAAC;AAElE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,GAAG,GAAG,SAAS,CAAC,oBAAoB,CAAC,CAAC;AAE5C;;;GAGG;AACH,MAAM,OAAO,kBAAmB,SAAQ,YAAY;IAKrB;IAJrB,MAAM,GAAkB,IAAI,CAAC;IACpB,OAAO,GAAgB,IAAI,GAAG,EAAE,CAAC;IAC1C,cAAc,GAA0B,IAAI,CAAC;IAErD,YAA6B,IAAY;QACvC,KAAK,EAAE,CAAC;QADmB,SAAI,GAAJ,IAAI,CAAQ;IAEzC,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK;QACT,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE;YACpC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAE3B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAElD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,0CAA0C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,KAAK,CAAC,IAAI;QACR,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAErB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAC3B,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;YAChC,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,CAAC;IACH,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,MAAc;QAC3C,GAAG,CAAC,IAAI,CAAC,yBAAyB,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEzB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,GAAG,CAAC,IAAI,CAAC,4BAA4B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;YAC7D,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,GAAG,CAAC,KAAK,CAAC,iBAAiB,GAAG,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,oBAAoB;QAC1B,OAAO;YACL,QAAQ,EAAE,CAAC,MAAkB,EAAE,EAAE;gBAC/B,KAAK,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YACpC,CAAC;SACF,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,eAAe,CAAC,MAAkB;QAC9C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC;YAE/C,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBAC5C,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;oBACrB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBAC5B,OAAO;gBACT,CAAC;gBACD,IAAI,CAAC;oBACH,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAC5C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,KAAK,CAAC,8BAA8B,GAAG,EAAE,CAAC,CAAC;oBAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC,CAAC,CACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,MAAc,EAAE,OAAe;QACnD,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,MAAM,eAAe,GAAG,CAAC,GAAkB,EAAQ,EAAE;gBACnD,IAAI,GAAG,EAAE,CAAC;oBACR,MAAM,CAAC,GAAG,CAAC,CAAC;oBACZ,OAAO;gBACT,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YACF,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,IAAY;QAChC,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QAC9D,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appium-ios-remotexpc",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "main": "build/src/index.js",
5
5
  "types": "build/src/index.d.ts",
6
6
  "type": "module",
@@ -52,7 +52,7 @@ export class PacketStreamServer extends EventEmitter {
52
52
  const server = this.server;
53
53
  await new Promise<void>((resolve, reject) => {
54
54
  server.once('error', reject);
55
- server.close(() => resolve);
55
+ server.close(() => resolve());
56
56
  });
57
57
  this.server = null;
58
58
  }
@@ -86,7 +86,7 @@ export class PacketStreamServer extends EventEmitter {
86
86
  private createPacketConsumer(): PacketConsumer {
87
87
  return {
88
88
  onPacket: (packet: PacketData) => {
89
- this.broadcastPacket(packet);
89
+ void this.broadcastPacket(packet);
90
90
  },
91
91
  };
92
92
  }
@@ -94,25 +94,46 @@ export class PacketStreamServer extends EventEmitter {
94
94
  /**
95
95
  * Broadcast packet to all connected clients
96
96
  */
97
- private broadcastPacket(packet: PacketData): void {
97
+ private async broadcastPacket(packet: PacketData): Promise<void> {
98
98
  try {
99
99
  const serialized = JSON.stringify(packet);
100
100
  const message = this.createMessage(serialized);
101
101
 
102
- for (const client of this.clients) {
103
- const onError = (err: Error) => {
104
- log.error(`Failed to write to client: ${err}`);
105
- this.clients.delete(client);
106
- };
107
- if (!client.destroyed) {
108
- client.write(message, onError);
109
- }
110
- }
102
+ await Promise.all(
103
+ Array.from(this.clients).map(async (client) => {
104
+ if (!client.writable) {
105
+ this.clients.delete(client);
106
+ return;
107
+ }
108
+ try {
109
+ await this.writeToClient(client, message);
110
+ } catch (err) {
111
+ log.error(`Failed to write to client: ${err}`);
112
+ this.clients.delete(client);
113
+ }
114
+ }),
115
+ );
111
116
  } catch (err) {
112
117
  log.error(`Failed to broadcast packet: ${err}`);
113
118
  }
114
119
  }
115
120
 
121
+ /**
122
+ * Promisified wrapper around `socket.write` so callers can use async/await.
123
+ */
124
+ private writeToClient(client: Socket, message: Buffer): Promise<void> {
125
+ return new Promise<void>((resolve, reject) => {
126
+ const onWriteComplete = (err?: Error | null): void => {
127
+ if (err) {
128
+ reject(err);
129
+ return;
130
+ }
131
+ resolve();
132
+ };
133
+ client.write(message, onWriteComplete);
134
+ });
135
+ }
136
+
116
137
  /**
117
138
  * Create a message buffer with length prefix
118
139
  */