@react-native-windows/automation-channel 0.81.34 → 0.81.36

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.
@@ -26,6 +26,8 @@ export declare class AutomationClient {
26
26
  private onEnd;
27
27
  private onError;
28
28
  private onMessage;
29
+ private rejectPendingRequest;
30
+ private failAllPendingRequests;
29
31
  }
30
32
  export declare function waitForConnection(opts: {
31
33
  port: number;
@@ -50,19 +50,26 @@ class AutomationClient {
50
50
  }
51
51
  onData(chunk) {
52
52
  this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
53
- if (this.receiveBuffer.length >= 4) {
53
+ // Localhost TCP can coalesce responses into one chunk, so drain every
54
+ // complete frame and advance past it; stopping after one leaves later
55
+ // responses stuck behind it and wedges the channel.
56
+ while (this.receiveBuffer.length >= 4) {
54
57
  const messageLength = this.receiveBuffer.readUInt32LE();
55
58
  const totalLength = messageLength + 4;
56
- if (this.receiveBuffer.length >= totalLength) {
57
- const messageBuffer = this.receiveBuffer.slice(4, totalLength);
58
- if (totalLength < this.receiveBuffer.length) {
59
- this.receiveBuffer = Buffer.from(this.receiveBuffer, totalLength);
60
- }
61
- else {
62
- this.receiveBuffer = Buffer.alloc(0);
63
- }
59
+ if (this.receiveBuffer.length < totalLength) {
60
+ break;
61
+ }
62
+ const messageBuffer = this.receiveBuffer.subarray(4, totalLength);
63
+ this.receiveBuffer = this.receiveBuffer.subarray(totalLength);
64
+ // One bad frame can't be tied to a specific request, so fail every
65
+ // in-flight request rather than let any hang forever (invoke has no timeout).
66
+ try {
64
67
  this.onMessage(messageBuffer);
65
68
  }
69
+ catch (err) {
70
+ this.failAllPendingRequests(new Error('Unexpected error handling automation-channel message: ' +
71
+ (err instanceof Error ? err.message : String(err))));
72
+ }
66
73
  }
67
74
  }
68
75
  onEnd() {
@@ -74,36 +81,74 @@ class AutomationClient {
74
81
  onMessage(message) {
75
82
  const response = jsonrpc_lite_1.default.parseJsonRpcString(message.toString('utf8'));
76
83
  if (Array.isArray(response)) {
77
- throw new Error('Expected single message');
84
+ this.failAllPendingRequests(new Error('Unexpected JSON-RPC batch response'));
85
+ return;
78
86
  }
79
87
  switch (response.type) {
88
+ // The server only ever sends responses; a request/notification frame means
89
+ // the stream is out of sync, so fail all in-flight requests rather than
90
+ // silently ignore it (invoke has no timeout).
80
91
  case "request" /* RpcStatusType.request */:
81
- throw new Error('Received JSON-RPC request instead of response');
82
92
  case "notification" /* RpcStatusType.notification */:
83
- throw new Error('Unexpected JSON-RPC notification');
84
- case "invalid" /* RpcStatusType.invalid */:
85
- throw new Error('Invalid JSON-RPC2 response: ' +
86
- JSON.stringify(response.payload, null, 2));
93
+ this.failAllPendingRequests(new Error('Unexpected JSON-RPC message from server'));
94
+ return;
95
+ case "invalid" /* RpcStatusType.invalid */: {
96
+ // jsonrpc-lite keeps the raw response under `data`; use its id to reject
97
+ // the matching request so its caller fails fast instead of hanging.
98
+ const rawId = response.payload?.data?.id;
99
+ this.rejectPendingRequest(rawId, new Error('Invalid JSON-RPC2 response: ' +
100
+ JSON.stringify(response.payload, null, 2)));
101
+ return;
102
+ }
87
103
  case "success" /* RpcStatusType.success */: {
88
104
  const pendingReq = this.pendingRequests.get(response.payload.id);
89
- if (!pendingReq) {
90
- throw new Error('Could not find pending request from response ID');
105
+ if (pendingReq) {
106
+ this.pendingRequests.delete(response.payload.id);
107
+ pendingReq({ type: 'success', result: response.payload.result }, null);
91
108
  }
92
- this.pendingRequests.delete(response.payload.id);
93
- pendingReq({ type: 'success', result: response.payload.result }, null);
94
- break;
109
+ return;
95
110
  }
96
111
  case "error" /* RpcStatusType.error */: {
97
- const pendingReq = this.pendingRequests.get(response.payload.id);
98
- if (!pendingReq) {
99
- throw new Error('Could not find pending request from response ID');
112
+ const id = response.payload.id;
113
+ const pendingReq = id === null ? undefined : this.pendingRequests.get(id);
114
+ if (pendingReq) {
115
+ this.pendingRequests.delete(id);
116
+ pendingReq({ type: 'error', ...response.payload.error }, null);
100
117
  }
101
- this.pendingRequests.delete(response.payload.id);
102
- pendingReq({ type: 'error', ...response.payload.error }, null);
103
- break;
118
+ else if (id === null) {
119
+ // A null id means the server couldn't attribute the error to a
120
+ // request (e.g. a parse error on our stream); fail all so none hang.
121
+ this.failAllPendingRequests(new Error('JSON-RPC error with null id: ' +
122
+ JSON.stringify(response.payload.error)));
123
+ }
124
+ return;
104
125
  }
105
126
  }
106
127
  }
128
+ rejectPendingRequest(id, err) {
129
+ // This client only issues numeric ids, so a non-numeric id can't match a
130
+ // pending request; treat it as unattributable and fail all (invoke has no timeout).
131
+ if (typeof id !== 'number') {
132
+ this.failAllPendingRequests(err);
133
+ return;
134
+ }
135
+ const pendingReq = this.pendingRequests.get(id);
136
+ if (pendingReq) {
137
+ this.pendingRequests.delete(id);
138
+ pendingReq(null, err);
139
+ }
140
+ else {
141
+ // Valid numeric id, but already settled (stale/duplicate) — ignore.
142
+ console.error(err.message);
143
+ }
144
+ }
145
+ failAllPendingRequests(err) {
146
+ const pending = Array.from(this.pendingRequests.values());
147
+ this.pendingRequests.clear();
148
+ for (const req of pending) {
149
+ req(null, err);
150
+ }
151
+ }
107
152
  }
108
153
  exports.AutomationClient = AutomationClient;
109
154
  function waitForConnection(opts) {
@@ -1 +1 @@
1
- {"version":3,"file":"automationChannel.js","sourceRoot":"","sources":["../src/automationChannel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Copyright (c) Microsoft Corporation.\n * Licensed under the MIT License.\n *\n * @format\n */\n\nimport {Server, Socket} from 'net';\nimport jsonrpc from 'jsonrpc-lite';\nimport {RpcStatusType} from 'jsonrpc-lite';\n\nlet incrementingId = 0;\n\nexport type InvokeResult =\n | {type: 'error'; code: any; message: string}\n | {type: 'success'; result?: any};\n\nexport class AutomationClient {\n private readonly socket: Socket;\n private readonly server: Server;\n private readonly pendingRequests: Map<\n any,\n (result: InvokeResult | null, err: Error | null) => void\n >;\n private receiveBuffer: Buffer;\n\n constructor(socket: Socket, server: Server) {\n this.socket = socket;\n this.server = server;\n\n this.pendingRequests = new Map();\n this.receiveBuffer = Buffer.alloc(0);\n\n this.socket.on('data', this.onData.bind(this));\n this.socket.on('end', this.onEnd.bind(this));\n this.socket.on('error', this.onError.bind(this));\n }\n\n invoke(\n methodName: string,\n params: any[] | Record<string, any>,\n ): Promise<InvokeResult> {\n return new Promise((resolve, reject) => {\n const messageId = ++incrementingId;\n this.pendingRequests.set(messageId, (result, err) => {\n if (err) {\n reject(err);\n }\n if (result) {\n resolve(result);\n }\n });\n\n const requestString = jsonrpc\n .request(messageId, methodName, params)\n .serialize();\n\n const requestBuffer = Buffer.from(requestString, 'utf-8');\n const sizeBuffer = Buffer.alloc(4);\n sizeBuffer.writeUInt32LE(requestBuffer.length);\n\n this.socket.write(sizeBuffer);\n this.socket.write(requestBuffer);\n });\n }\n\n close() {\n this.socket.destroy();\n this.server.close();\n }\n\n private onData(chunk: Buffer) {\n this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);\n if (this.receiveBuffer.length >= 4) {\n const messageLength = this.receiveBuffer.readUInt32LE();\n const totalLength = messageLength + 4;\n\n if (this.receiveBuffer.length >= totalLength) {\n const messageBuffer = this.receiveBuffer.slice(4, totalLength);\n\n if (totalLength < this.receiveBuffer.length) {\n this.receiveBuffer = Buffer.from(this.receiveBuffer, totalLength);\n } else {\n this.receiveBuffer = Buffer.alloc(0);\n }\n\n this.onMessage(messageBuffer);\n }\n }\n }\n\n private onEnd() {\n this.pendingRequests.forEach(req =>\n req(null, new Error('Unexpected disconnect from RPC server')),\n );\n }\n\n private onError(error: Error) {\n this.pendingRequests.forEach(req => req(null, error));\n }\n\n private onMessage(message: Buffer) {\n const response = jsonrpc.parseJsonRpcString(message.toString('utf8'));\n if (Array.isArray(response)) {\n throw new Error('Expected single message');\n }\n\n switch (response.type) {\n case RpcStatusType.request:\n throw new Error('Received JSON-RPC request instead of response');\n case RpcStatusType.notification:\n throw new Error('Unexpected JSON-RPC notification');\n case RpcStatusType.invalid:\n throw new Error(\n 'Invalid JSON-RPC2 response: ' +\n JSON.stringify(response.payload, null, 2),\n );\n\n case RpcStatusType.success: {\n const pendingReq = this.pendingRequests.get(response.payload.id);\n if (!pendingReq) {\n throw new Error('Could not find pending request from response ID');\n }\n\n this.pendingRequests.delete(response.payload.id);\n pendingReq({type: 'success', result: response.payload.result}, null);\n break;\n }\n\n case RpcStatusType.error: {\n const pendingReq = this.pendingRequests.get(response.payload.id);\n if (!pendingReq) {\n throw new Error('Could not find pending request from response ID');\n }\n\n this.pendingRequests.delete(response.payload.id);\n pendingReq({type: 'error', ...response.payload.error}, null);\n break;\n }\n }\n }\n}\n\nexport function waitForConnection(opts: {\n port: number;\n}): Promise<AutomationClient> {\n return new Promise((resolve, reject) => {\n const server = new Server();\n server.listen(opts.port);\n\n const onError = (err: Error) => reject(err);\n server.on('error', onError);\n server.on('connection', socket => {\n server.off('error', onError);\n resolve(new AutomationClient(socket, server));\n });\n });\n}\n"]}
1
+ {"version":3,"file":"automationChannel.js","sourceRoot":"","sources":["../src/automationChannel.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,6BAAmC;AACnC,gEAAmC;AAGnC,IAAI,cAAc,GAAG,CAAC,CAAC;AAMvB,MAAa,gBAAgB;IAS3B,YAAY,MAAc,EAAE,MAAc;QACxC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;QACjC,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAErC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,CACJ,UAAkB,EAClB,MAAmC;QAEnC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,SAAS,GAAG,EAAE,cAAc,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBAClD,IAAI,GAAG,EAAE;oBACP,MAAM,CAAC,GAAG,CAAC,CAAC;iBACb;gBACD,IAAI,MAAM,EAAE;oBACV,OAAO,CAAC,MAAM,CAAC,CAAC;iBACjB;YACH,CAAC,CAAC,CAAC;YAEH,MAAM,aAAa,GAAG,sBAAO;iBAC1B,OAAO,CAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC;iBACtC,SAAS,EAAE,CAAC;YAEf,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACnC,UAAU,CAAC,aAAa,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;YAE/C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;YAC9B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CAAC;QAEhE,sEAAsE;QACtE,sEAAsE;QACtE,oDAAoD;QACpD,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,IAAI,CAAC,EAAE;YACrC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,CAAC;YACxD,MAAM,WAAW,GAAG,aAAa,GAAG,CAAC,CAAC;YACtC,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,WAAW,EAAE;gBAC3C,MAAM;aACP;YAED,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;YAClE,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAE9D,mEAAmE;YACnE,8EAA8E;YAC9E,IAAI;gBACF,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;aAC/B;YAAC,OAAO,GAAG,EAAE;gBACZ,IAAI,CAAC,sBAAsB,CACzB,IAAI,KAAK,CACP,wDAAwD;oBACtD,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CACrD,CACF,CAAC;aACH;SACF;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CACjC,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC,CAC9D,CAAC;IACJ,CAAC;IAEO,OAAO,CAAC,KAAY;QAC1B,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IACxD,CAAC;IAEO,SAAS,CAAC,OAAe;QAC/B,MAAM,QAAQ,GAAG,sBAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACtE,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC3B,IAAI,CAAC,sBAAsB,CACzB,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAChD,CAAC;YACF,OAAO;SACR;QAED,QAAQ,QAAQ,CAAC,IAAI,EAAE;YACrB,2EAA2E;YAC3E,wEAAwE;YACxE,8CAA8C;YAC9C,2CAA2B;YAC3B;gBACE,IAAI,CAAC,sBAAsB,CACzB,IAAI,KAAK,CAAC,yCAAyC,CAAC,CACrD,CAAC;gBACF,OAAO;YAET,0CAA0B,CAAC,CAAC;gBAC1B,yEAAyE;gBACzE,oEAAoE;gBACpE,MAAM,KAAK,GAAI,QAAQ,CAAC,OAAe,EAAE,IAAI,EAAE,EAAE,CAAC;gBAClD,IAAI,CAAC,oBAAoB,CACvB,KAAK,EACL,IAAI,KAAK,CACP,8BAA8B;oBAC5B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAC5C,CACF,CAAC;gBACF,OAAO;aACR;YAED,0CAA0B,CAAC,CAAC;gBAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBACjE,IAAI,UAAU,EAAE;oBACd,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBACjD,UAAU,CAAC,EAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,EAAC,EAAE,IAAI,CAAC,CAAC;iBACtE;gBACD,OAAO;aACR;YAED,sCAAwB,CAAC,CAAC;gBACxB,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC/B,MAAM,UAAU,GACd,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACzD,IAAI,UAAU,EAAE;oBACd,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAChC,UAAU,CAAC,EAAC,IAAI,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAC,EAAE,IAAI,CAAC,CAAC;iBAC9D;qBAAM,IAAI,EAAE,KAAK,IAAI,EAAE;oBACtB,+DAA+D;oBAC/D,qEAAqE;oBACrE,IAAI,CAAC,sBAAsB,CACzB,IAAI,KAAK,CACP,+BAA+B;wBAC7B,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CACzC,CACF,CAAC;iBACH;gBACD,OAAO;aACR;SACF;IACH,CAAC;IAEO,oBAAoB,CAAC,EAAO,EAAE,GAAU;QAC9C,yEAAyE;QACzE,oFAAoF;QACpF,IAAI,OAAO,EAAE,KAAK,QAAQ,EAAE;YAC1B,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC;YACjC,OAAO;SACR;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChD,IAAI,UAAU,EAAE;YACd,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;SACvB;aAAM;YACL,oEAAoE;YACpE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;SAC5B;IACH,CAAC;IAEO,sBAAsB,CAAC,GAAU;QACvC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE;YACzB,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;SAChB;IACH,CAAC;CACF;AAzLD,4CAyLC;AAED,SAAgB,iBAAiB,CAAC,IAEjC;IACC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,IAAI,YAAM,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEzB,MAAM,OAAO,GAAG,CAAC,GAAU,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC5B,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE;YAC/B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7B,OAAO,CAAC,IAAI,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAdD,8CAcC","sourcesContent":["/**\n * Copyright (c) Microsoft Corporation.\n * Licensed under the MIT License.\n *\n * @format\n */\n\nimport {Server, Socket} from 'net';\nimport jsonrpc from 'jsonrpc-lite';\nimport {RpcStatusType} from 'jsonrpc-lite';\n\nlet incrementingId = 0;\n\nexport type InvokeResult =\n | {type: 'error'; code: any; message: string}\n | {type: 'success'; result?: any};\n\nexport class AutomationClient {\n private readonly socket: Socket;\n private readonly server: Server;\n private readonly pendingRequests: Map<\n any,\n (result: InvokeResult | null, err: Error | null) => void\n >;\n private receiveBuffer: Buffer;\n\n constructor(socket: Socket, server: Server) {\n this.socket = socket;\n this.server = server;\n\n this.pendingRequests = new Map();\n this.receiveBuffer = Buffer.alloc(0);\n\n this.socket.on('data', this.onData.bind(this));\n this.socket.on('end', this.onEnd.bind(this));\n this.socket.on('error', this.onError.bind(this));\n }\n\n invoke(\n methodName: string,\n params: any[] | Record<string, any>,\n ): Promise<InvokeResult> {\n return new Promise((resolve, reject) => {\n const messageId = ++incrementingId;\n this.pendingRequests.set(messageId, (result, err) => {\n if (err) {\n reject(err);\n }\n if (result) {\n resolve(result);\n }\n });\n\n const requestString = jsonrpc\n .request(messageId, methodName, params)\n .serialize();\n\n const requestBuffer = Buffer.from(requestString, 'utf-8');\n const sizeBuffer = Buffer.alloc(4);\n sizeBuffer.writeUInt32LE(requestBuffer.length);\n\n this.socket.write(sizeBuffer);\n this.socket.write(requestBuffer);\n });\n }\n\n close() {\n this.socket.destroy();\n this.server.close();\n }\n\n private onData(chunk: Buffer) {\n this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);\n\n // Localhost TCP can coalesce responses into one chunk, so drain every\n // complete frame and advance past it; stopping after one leaves later\n // responses stuck behind it and wedges the channel.\n while (this.receiveBuffer.length >= 4) {\n const messageLength = this.receiveBuffer.readUInt32LE();\n const totalLength = messageLength + 4;\n if (this.receiveBuffer.length < totalLength) {\n break;\n }\n\n const messageBuffer = this.receiveBuffer.subarray(4, totalLength);\n this.receiveBuffer = this.receiveBuffer.subarray(totalLength);\n\n // One bad frame can't be tied to a specific request, so fail every\n // in-flight request rather than let any hang forever (invoke has no timeout).\n try {\n this.onMessage(messageBuffer);\n } catch (err) {\n this.failAllPendingRequests(\n new Error(\n 'Unexpected error handling automation-channel message: ' +\n (err instanceof Error ? err.message : String(err)),\n ),\n );\n }\n }\n }\n\n private onEnd() {\n this.pendingRequests.forEach(req =>\n req(null, new Error('Unexpected disconnect from RPC server')),\n );\n }\n\n private onError(error: Error) {\n this.pendingRequests.forEach(req => req(null, error));\n }\n\n private onMessage(message: Buffer) {\n const response = jsonrpc.parseJsonRpcString(message.toString('utf8'));\n if (Array.isArray(response)) {\n this.failAllPendingRequests(\n new Error('Unexpected JSON-RPC batch response'),\n );\n return;\n }\n\n switch (response.type) {\n // The server only ever sends responses; a request/notification frame means\n // the stream is out of sync, so fail all in-flight requests rather than\n // silently ignore it (invoke has no timeout).\n case RpcStatusType.request:\n case RpcStatusType.notification:\n this.failAllPendingRequests(\n new Error('Unexpected JSON-RPC message from server'),\n );\n return;\n\n case RpcStatusType.invalid: {\n // jsonrpc-lite keeps the raw response under `data`; use its id to reject\n // the matching request so its caller fails fast instead of hanging.\n const rawId = (response.payload as any)?.data?.id;\n this.rejectPendingRequest(\n rawId,\n new Error(\n 'Invalid JSON-RPC2 response: ' +\n JSON.stringify(response.payload, null, 2),\n ),\n );\n return;\n }\n\n case RpcStatusType.success: {\n const pendingReq = this.pendingRequests.get(response.payload.id);\n if (pendingReq) {\n this.pendingRequests.delete(response.payload.id);\n pendingReq({type: 'success', result: response.payload.result}, null);\n }\n return;\n }\n\n case RpcStatusType.error: {\n const id = response.payload.id;\n const pendingReq =\n id === null ? undefined : this.pendingRequests.get(id);\n if (pendingReq) {\n this.pendingRequests.delete(id);\n pendingReq({type: 'error', ...response.payload.error}, null);\n } else if (id === null) {\n // A null id means the server couldn't attribute the error to a\n // request (e.g. a parse error on our stream); fail all so none hang.\n this.failAllPendingRequests(\n new Error(\n 'JSON-RPC error with null id: ' +\n JSON.stringify(response.payload.error),\n ),\n );\n }\n return;\n }\n }\n }\n\n private rejectPendingRequest(id: any, err: Error) {\n // This client only issues numeric ids, so a non-numeric id can't match a\n // pending request; treat it as unattributable and fail all (invoke has no timeout).\n if (typeof id !== 'number') {\n this.failAllPendingRequests(err);\n return;\n }\n\n const pendingReq = this.pendingRequests.get(id);\n if (pendingReq) {\n this.pendingRequests.delete(id);\n pendingReq(null, err);\n } else {\n // Valid numeric id, but already settled (stale/duplicate) — ignore.\n console.error(err.message);\n }\n }\n\n private failAllPendingRequests(err: Error) {\n const pending = Array.from(this.pendingRequests.values());\n this.pendingRequests.clear();\n for (const req of pending) {\n req(null, err);\n }\n }\n}\n\nexport function waitForConnection(opts: {\n port: number;\n}): Promise<AutomationClient> {\n return new Promise((resolve, reject) => {\n const server = new Server();\n server.listen(opts.port);\n\n const onError = (err: Error) => reject(err);\n server.on('error', onError);\n server.on('connection', socket => {\n server.off('error', onError);\n resolve(new AutomationClient(socket, server));\n });\n });\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-native-windows/automation-channel",
3
- "version": "0.81.34",
3
+ "version": "0.81.36",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "prettier": "2.8.8",
34
34
  "react": "19.1.4",
35
35
  "react-native": "0.81.6",
36
- "react-native-windows": "0.81.34",
36
+ "react-native-windows": "0.81.36",
37
37
  "typescript": "5.0.4"
38
38
  },
39
39
  "files": [
@@ -86,6 +86,9 @@ IAsyncOperation<IJsonValue> CommandHandler::Invoke(const winrt::hstring &methodN
86
86
  auto result = co_await asyncOperation->second(params);
87
87
  co_return result;
88
88
  }
89
+
90
+ // Unknown methods surface as JSON-RPC MethodNotFound in the request processor; this guards direct callers.
91
+ throw winrt::hresult_invalid_argument(L"No automation-channel handler registered for method '" + methodName + L"'");
89
92
  }
90
93
 
91
94
  } // namespace winrt::AutomationChannel::implementation
@@ -19,6 +19,8 @@ namespace AutomationChannel {
19
19
  CommandHandler BindOperation(String methodName, SyncOperation operation);
20
20
  CommandHandler BindAsyncOperation(String methodName, AsyncOperation operation);
21
21
 
22
+ Boolean IsMethodRegistered(String methodName);
23
+
22
24
  // May throw on delegate error
23
25
  Windows.Foundation.IAsyncOperation<Windows.Data.Json.IJsonValue> Invoke(String methodName, Windows.Data.Json.JsonValue params);
24
26
  };
@@ -29,7 +29,13 @@ winrt::fire_and_forget JsonRpcRequestProcessor::HandleRequest(
29
29
  winrt::hstring errorMessage;
30
30
 
31
31
  try {
32
- auto result = co_await handler.Invoke(message.GetNamedString(L"method"), message.GetNamedValue(L"params"));
32
+ auto method = message.GetNamedString(L"method");
33
+ if (!handler.IsMethodRegistered(method)) {
34
+ co_await EmitError(
35
+ JsonRpcErrorCode::MethodNotFound, L"Method not found: " + method, message.GetNamedValue(L"id"), output);
36
+ co_return;
37
+ }
38
+ auto result = co_await handler.Invoke(method, message.GetNamedValue(L"params"));
33
39
  co_await EmitResult(result, message.GetNamedValue(L"id"), output);
34
40
  co_return;
35
41
  } catch (const winrt::hresult_error &ex) {
@@ -62,14 +68,23 @@ IAsyncAction JsonRpcRequestProcessor::EmitError(
62
68
  winrt::hstring message,
63
69
  JsonValue id,
64
70
  IOutputStream output) noexcept {
65
- JsonObject err;
66
- err.SetNamedValue(L"code", JsonValue::CreateNumberValue(static_cast<int32_t>(code)));
67
- err.SetNamedValue(L"message", JsonValue::CreateStringValue(message));
68
- co_await EmitResponse(err, id, output);
71
+ JsonObject error;
72
+ error.SetNamedValue(L"code", JsonValue::CreateNumberValue(static_cast<int32_t>(code)));
73
+ error.SetNamedValue(L"message", JsonValue::CreateStringValue(message));
74
+
75
+ // JSON-RPC 2.0 requires code/message under an "error" member; at top level the client rejects it as invalid.
76
+ JsonObject res;
77
+ res.SetNamedValue(L"error", error);
78
+ co_await EmitResponse(res, id, output);
69
79
  }
70
80
 
71
81
  IAsyncAction JsonRpcRequestProcessor::EmitResult(IJsonValue result, JsonValue id, IOutputStream output) noexcept {
72
82
  JsonObject res;
83
+ // A null result must still serialize as "result": null. SetNamedValue with a
84
+ // null value drops the key, producing a response the client rejects as invalid.
85
+ if (!result) {
86
+ result = JsonValue::CreateNullValue();
87
+ }
73
88
  res.SetNamedValue(L"result", result);
74
89
  co_await EmitResponse(res, id, output);
75
90
  }
@@ -8,13 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutomationChannel", "Automa
8
8
  {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136}
9
9
  EndProjectSection
10
10
  EndProject
11
- Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}"
12
- EndProject
13
- Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fmt", "..\..\..\..\vnext\fmt\fmt.vcxproj", "{14B93DC8-FD93-4A6D-81CB-8BC96644501C}"
14
- EndProject
15
11
  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}"
16
12
  ProjectSection(ProjectDependencies) = postProject
17
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D}
18
13
  EndProjectSection
19
14
  EndProject
20
15
  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\..\..\..\vnext\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}"
@@ -72,18 +67,6 @@ Global
72
67
  {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.ActiveCfg = Release|Win32
73
68
  {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Build.0 = Release|Win32
74
69
  {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Deploy.0 = Release|Win32
75
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64
76
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64
77
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64
78
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64
79
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32
80
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32
81
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64
82
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64
83
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64
84
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64
85
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32
86
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32
87
70
  {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64
88
71
  {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64
89
72
  {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64
@@ -120,26 +103,11 @@ Global
120
103
  {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64
121
104
  {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32
122
105
  {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32
123
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.ActiveCfg = Debug|ARM64
124
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|ARM64.Build.0 = Debug|ARM64
125
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.ActiveCfg = Debug|x64
126
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x64.Build.0 = Debug|x64
127
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.ActiveCfg = Debug|Win32
128
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Build.0 = Debug|Win32
129
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Debug|x86.Deploy.0 = Debug|Win32
130
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.ActiveCfg = Release|ARM64
131
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|ARM64.Build.0 = Release|ARM64
132
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.ActiveCfg = Release|x64
133
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x64.Build.0 = Release|x64
134
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.ActiveCfg = Release|Win32
135
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Build.0 = Release|Win32
136
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C}.Release|x86.Deploy.0 = Release|Win32
137
106
  EndGlobalSection
138
107
  GlobalSection(SolutionProperties) = preSolution
139
108
  HideSolutionNode = FALSE
140
109
  EndGlobalSection
141
110
  GlobalSection(NestedProjects) = preSolution
142
- {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
143
111
  {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
144
112
  {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
145
113
  {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
@@ -148,7 +116,6 @@ Global
148
116
  {2049DBE9-8D13-42C9-AE4B-413AE38FFFD0} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
149
117
  {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
150
118
  {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
151
- {14B93DC8-FD93-4A6D-81CB-8BC96644501C} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1}
152
119
  EndGlobalSection
153
120
  GlobalSection(ExtensibilityGlobals) = postSolution
154
121
  SolutionGuid = {D43FAD39-F619-437D-BB40-04A3982ACB6A}