@delight-rpc/child-process 0.6.3 → 0.6.5

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 CHANGED
@@ -71,6 +71,7 @@ function createClient<IAPI extends object>(
71
71
  parameterValidators?: DelightRPC.ParameterValidators<IAPI>
72
72
  expectedVersion?: string
73
73
  channel?: string
74
+ timeout?: number
74
75
  }
75
76
  ): [client: DelightRPC.ClientProxy<IAPI>, close: () => void]
76
77
  ```
@@ -82,6 +83,7 @@ function createBatchClient<DataType>(
82
83
  , options?: {
83
84
  expectedVersion?: string
84
85
  channel?: string
86
+ timeout?: number
85
87
  }
86
88
  ): [client: DelightRPC.BatchClient<DataType>, close: () => void]
87
89
  ```
package/lib/client.d.ts CHANGED
@@ -3,14 +3,16 @@
3
3
  import * as DelightRPC from 'delight-rpc';
4
4
  import { ChildProcess } from 'child_process';
5
5
  import { CustomError } from '@blackglory/errors';
6
- export declare function createClient<IAPI extends object>(process: ChildProcess | NodeJS.Process, { parameterValidators, expectedVersion, channel }?: {
6
+ export declare function createClient<IAPI extends object>(process: ChildProcess | NodeJS.Process, { parameterValidators, expectedVersion, channel, timeout }?: {
7
7
  parameterValidators?: DelightRPC.ParameterValidators<IAPI>;
8
8
  expectedVersion?: string;
9
9
  channel?: string;
10
+ timeout?: number;
10
11
  }): [client: DelightRPC.ClientProxy<IAPI>, close: () => void];
11
- export declare function createBatchClient<DataType>(process: ChildProcess | NodeJS.Process, { expectedVersion, channel }?: {
12
+ export declare function createBatchClient<DataType>(process: ChildProcess | NodeJS.Process, { expectedVersion, channel, timeout }?: {
12
13
  expectedVersion?: string;
13
14
  channel?: string;
15
+ timeout?: number;
14
16
  }): [client: DelightRPC.BatchClient<DataType>, close: () => void];
15
17
  export declare class ClientClosed extends CustomError {
16
18
  }
package/lib/client.js CHANGED
@@ -1,15 +1,25 @@
1
1
  import * as DelightRPC from 'delight-rpc';
2
2
  import { Deferred } from 'extra-promise';
3
3
  import { CustomError } from '@blackglory/errors';
4
- export function createClient(process, { parameterValidators, expectedVersion, channel } = {}) {
4
+ import { raceAbortSignals, timeoutSignal, withAbortSignal } from 'extra-abort';
5
+ import { isntUndefined } from '@blackglory/prelude';
6
+ export function createClient(process, { parameterValidators, expectedVersion, channel, timeout } = {}) {
5
7
  const pendings = new Map();
6
8
  process.on('message', handler);
7
- const client = DelightRPC.createClient(async function send(request) {
9
+ const client = DelightRPC.createClient(async function send(request, signal) {
8
10
  const res = new Deferred();
9
11
  pendings.set(request.id, res);
10
12
  try {
11
13
  process.send(request);
12
- return await res;
14
+ const mergedSignal = raceAbortSignals([
15
+ isntUndefined(timeout) && timeoutSignal(timeout),
16
+ signal
17
+ ]);
18
+ mergedSignal.addEventListener('abort', () => {
19
+ const abort = DelightRPC.createAbort(request.id, channel);
20
+ process.send(abort);
21
+ });
22
+ return await withAbortSignal(mergedSignal, () => res);
13
23
  }
14
24
  finally {
15
25
  pendings.delete(request.id);
@@ -22,7 +32,7 @@ export function createClient(process, { parameterValidators, expectedVersion, ch
22
32
  return [client, close];
23
33
  function close() {
24
34
  process.off('message', handler);
25
- for (const [key, deferred] of Object.entries(pendings)) {
35
+ for (const [key, deferred] of pendings.entries()) {
26
36
  deferred.reject(new ClientClosed());
27
37
  pendings.delete(key);
28
38
  }
@@ -34,7 +44,7 @@ export function createClient(process, { parameterValidators, expectedVersion, ch
34
44
  }
35
45
  }
36
46
  }
37
- export function createBatchClient(process, { expectedVersion, channel } = {}) {
47
+ export function createBatchClient(process, { expectedVersion, channel, timeout } = {}) {
38
48
  const pendings = new Map();
39
49
  process.on('message', handler);
40
50
  const client = new DelightRPC.BatchClient(async function send(request) {
@@ -42,7 +52,14 @@ export function createBatchClient(process, { expectedVersion, channel } = {}) {
42
52
  pendings.set(request.id, res);
43
53
  try {
44
54
  process.send(request);
45
- return await res;
55
+ const mergedSignal = raceAbortSignals([
56
+ isntUndefined(timeout) && timeoutSignal(timeout)
57
+ ]);
58
+ mergedSignal.addEventListener('abort', () => {
59
+ const abort = DelightRPC.createAbort(request.id, channel);
60
+ process.send(abort);
61
+ });
62
+ return await withAbortSignal(mergedSignal, () => res);
46
63
  }
47
64
  finally {
48
65
  pendings.delete(request.id);
@@ -54,7 +71,7 @@ export function createBatchClient(process, { expectedVersion, channel } = {}) {
54
71
  return [client, close];
55
72
  function close() {
56
73
  process.off('message', handler);
57
- for (const [key, deferred] of Object.entries(pendings)) {
74
+ for (const [key, deferred] of pendings.entries()) {
58
75
  deferred.reject(new ClientClosed());
59
76
  pendings.delete(key);
60
77
  }
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAEhD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD,MAAM,UAAU,YAAY,CAC1B,OAAsC,EACtC,EAAE,mBAAmB,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,KAKpD,EAAE;IAEN,MAAM,QAAQ,GAA8C,IAAI,GAAG,EAAE,CAAA;IAErE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAE9B,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CACpC,KAAK,UAAU,IAAI,CAAC,OAAO,EAAE,MAAM;QACjC,MAAM,GAAG,GAAG,IAAI,QAAQ,EAAsB,CAAA;QAC9C,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QAC7B,IAAI;YACF,OAAO,CAAC,IAAK,CAAC,OAAO,CAAC,CAAA;YAEtB,MAAM,YAAY,GAAG,gBAAgB,CAAC;gBACpC,aAAa,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC;gBAChD,MAAM;aACP,CAAC,CAAA;YACF,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;gBACzD,OAAO,CAAC,IAAK,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC,CAAC,CAAA;YAEF,OAAO,MAAM,eAAe,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;SACtD;gBAAS;YACR,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;SAC5B;IACH,CAAC,EACD;QACE,mBAAmB;QACnB,eAAe;QACf,OAAO;KACR,CACF,CAAA;IAED,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAEtB,SAAS,KAAK;QACZ,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAE/B,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE;YAChD,QAAQ,CAAC,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAA;YACnC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;SACrB;IACH,CAAC;IAED,SAAS,OAAO,CAAC,GAAY;;QAC3B,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACvD,MAAA,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,0CAAE,OAAO,CAAC,GAAG,CAAC,CAAA;SACnC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAsC,EACtC,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,KAI/B,EAAE;IAEN,MAAM,QAAQ,GAGV,IAAI,GAAG,EAAE,CAAA;IAEb,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAE9B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,CACvC,KAAK,UAAU,IAAI,CAAC,OAA+B;QACjD,MAAM,GAAG,GAAG,IAAI,QAAQ,EAGrB,CAAA;QACH,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QAC7B,IAAI;YACF,OAAO,CAAC,IAAK,CAAC,OAAO,CAAC,CAAA;YAEtB,MAAM,YAAY,GAAG,gBAAgB,CAAC;gBACpC,aAAa,CAAC,OAAO,CAAC,IAAI,aAAa,CAAC,OAAO,CAAC;aACjD,CAAC,CAAA;YACF,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;gBAC1C,MAAM,KAAK,GAAG,UAAU,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAA;gBACzD,OAAO,CAAC,IAAK,CAAC,KAAK,CAAC,CAAA;YACtB,CAAC,CAAC,CAAA;YAEF,OAAO,MAAM,eAAe,CAAC,YAAY,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAA;SACtD;gBAAS;YACR,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;SAC5B;IACH,CAAC,EACD;QACE,eAAe;QACf,OAAO;KACR,CACF,CAAA;IAED,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;IAEtB,SAAS,KAAK;QACZ,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;QAE/B,KAAK,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE;YAChD,QAAQ,CAAC,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC,CAAA;YACnC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;SACrB;IACH,CAAC;IAED,SAAS,OAAO,CAAC,GAAY;;QAC3B,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE;YAC9D,MAAA,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,0CAAE,OAAO,CAAC,GAAG,CAAC,CAAA;SACnC;IACH,CAAC;AACH,CAAC;AAED,MAAM,OAAO,YAAa,SAAQ,WAAW;CAAG"}
package/lib/server.js CHANGED
@@ -1,18 +1,40 @@
1
1
  import * as DelightRPC from 'delight-rpc';
2
2
  import { isntNull } from '@blackglory/prelude';
3
+ import { AbortController } from 'extra-abort';
3
4
  export function createServer(api, process, { parameterValidators, version, channel, ownPropsOnly } = {}) {
5
+ const idToController = new Map();
4
6
  process.on('message', handler);
7
+ process.on('disconnect', () => {
8
+ for (const controller of idToController.values()) {
9
+ controller.abort();
10
+ }
11
+ idToController.clear();
12
+ });
5
13
  return () => process.off('message', handler);
6
- async function handler(req) {
7
- if (DelightRPC.isRequest(req) || DelightRPC.isBatchRequest(req)) {
8
- const result = await DelightRPC.createResponse(api, req, {
9
- parameterValidators,
10
- version,
11
- channel,
12
- ownPropsOnly
13
- });
14
- if (isntNull(result)) {
15
- process.send(result);
14
+ async function handler(message) {
15
+ var _a;
16
+ if (DelightRPC.isRequest(message) || DelightRPC.isBatchRequest(message)) {
17
+ const controller = new AbortController();
18
+ idToController.set(message.id, controller);
19
+ try {
20
+ const result = await DelightRPC.createResponse(api, message, {
21
+ parameterValidators,
22
+ version,
23
+ channel,
24
+ ownPropsOnly
25
+ });
26
+ if (isntNull(result)) {
27
+ process.send(result);
28
+ }
29
+ }
30
+ finally {
31
+ idToController.delete(message.id);
32
+ }
33
+ }
34
+ else if (DelightRPC.isAbort(message)) {
35
+ if (DelightRPC.matchChannel(message, channel)) {
36
+ (_a = idToController.get(message.id)) === null || _a === void 0 ? void 0 : _a.abort();
37
+ idToController.delete(message.id);
16
38
  }
17
39
  }
18
40
  }
package/lib/server.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAE9C,MAAM,UAAU,YAAY,CAC1B,GAAsC,EACtC,OAAsC,EACtC,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,KAKjD,EAAE;IAEN,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC9B,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAE5C,KAAK,UAAU,OAAO,CAAC,GAAQ;QAC7B,IAAI,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE;YAC/D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,CAC5C,GAAG,EACH,GAAG,EACH;gBACE,mBAAmB;gBACnB,OAAO;gBACP,OAAO;gBACP,YAAY;aACb,CACF,CAAA;YAED,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE;gBACpB,OAAO,CAAC,IAAK,CAAC,MAAM,CAAC,CAAA;aACtB;SACF;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,MAAM,UAAU,YAAY,CAC1B,GAAsC,EACtC,OAAsC,EACtC,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,KAKjD,EAAE;IAEN,MAAM,cAAc,GAAiC,IAAI,GAAG,EAAE,CAAA;IAE9D,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAC9B,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;QAC5B,KAAK,MAAM,UAAU,IAAI,cAAc,CAAC,MAAM,EAAE,EAAE;YAChD,UAAU,CAAC,KAAK,EAAE,CAAA;SACnB;QAED,cAAc,CAAC,KAAK,EAAE,CAAA;IACxB,CAAC,CAAC,CAAA;IACF,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAE5C,KAAK,UAAU,OAAO,CAAC,OAAgB;;QACrC,IAAI,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,UAAU,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE;YACvE,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAA;YACxC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,UAAU,CAAC,CAAA;YAE1C,IAAI;gBACF,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,CAC5C,GAAG,EACH,OAAO,EACP;oBACE,mBAAmB;oBACnB,OAAO;oBACP,OAAO;oBACP,YAAY;iBACb,CACF,CAAA;gBAED,IAAI,QAAQ,CAAC,MAAM,CAAC,EAAE;oBACpB,OAAO,CAAC,IAAK,CAAC,MAAM,CAAC,CAAA;iBACtB;aACF;oBAAS;gBACR,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;aAClC;SACF;aAAM,IAAI,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YACtC,IAAI,UAAU,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE;gBAC7C,MAAA,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,0CAAE,KAAK,EAAE,CAAA;gBACvC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;aAClC;SACF;IACH,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delight-rpc/child-process",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "files": [
@@ -61,6 +61,7 @@
61
61
  "@blackglory/errors": "^3.0.0",
62
62
  "@blackglory/prelude": "^0.3.1",
63
63
  "@delight-rpc/protocol": "^4.0.0",
64
+ "extra-abort": "^0.3.2",
64
65
  "extra-promise": "^6.0.5"
65
66
  },
66
67
  "peerDependencies": {
package/src/client.ts CHANGED
@@ -2,14 +2,17 @@ import * as DelightRPC from 'delight-rpc'
2
2
  import { ChildProcess } from 'child_process'
3
3
  import { Deferred } from 'extra-promise'
4
4
  import { CustomError } from '@blackglory/errors'
5
- import { IRequest, IResponse, IError, IBatchRequest, IBatchResponse } from '@delight-rpc/protocol'
5
+ import { IResponse, IError, IBatchRequest, IBatchResponse } from '@delight-rpc/protocol'
6
+ import { raceAbortSignals, timeoutSignal, withAbortSignal } from 'extra-abort'
7
+ import { isntUndefined } from '@blackglory/prelude'
6
8
 
7
9
  export function createClient<IAPI extends object>(
8
10
  process: ChildProcess | NodeJS.Process
9
- , { parameterValidators, expectedVersion, channel }: {
11
+ , { parameterValidators, expectedVersion, channel, timeout }: {
10
12
  parameterValidators?: DelightRPC.ParameterValidators<IAPI>
11
13
  expectedVersion?: string
12
14
  channel?: string
15
+ timeout?: number
13
16
  } = {}
14
17
  ): [client: DelightRPC.ClientProxy<IAPI>, close: () => void] {
15
18
  const pendings: Map<string, Deferred<IResponse<unknown>>> = new Map()
@@ -17,12 +20,22 @@ export function createClient<IAPI extends object>(
17
20
  process.on('message', handler)
18
21
 
19
22
  const client = DelightRPC.createClient<IAPI>(
20
- async function send(request: IRequest<unknown>) {
23
+ async function send(request, signal) {
21
24
  const res = new Deferred<IResponse<unknown>>()
22
25
  pendings.set(request.id, res)
23
26
  try {
24
27
  process.send!(request)
25
- return await res
28
+
29
+ const mergedSignal = raceAbortSignals([
30
+ isntUndefined(timeout) && timeoutSignal(timeout)
31
+ , signal
32
+ ])
33
+ mergedSignal.addEventListener('abort', () => {
34
+ const abort = DelightRPC.createAbort(request.id, channel)
35
+ process.send!(abort)
36
+ })
37
+
38
+ return await withAbortSignal(mergedSignal, () => res)
26
39
  } finally {
27
40
  pendings.delete(request.id)
28
41
  }
@@ -39,13 +52,13 @@ export function createClient<IAPI extends object>(
39
52
  function close() {
40
53
  process.off('message', handler)
41
54
 
42
- for (const [key, deferred] of Object.entries(pendings)) {
55
+ for (const [key, deferred] of pendings.entries()) {
43
56
  deferred.reject(new ClientClosed())
44
57
  pendings.delete(key)
45
58
  }
46
59
  }
47
60
 
48
- function handler(res: any): void {
61
+ function handler(res: unknown): void {
49
62
  if (DelightRPC.isResult(res) || DelightRPC.isError(res)) {
50
63
  pendings.get(res.id)?.resolve(res)
51
64
  }
@@ -54,9 +67,10 @@ export function createClient<IAPI extends object>(
54
67
 
55
68
  export function createBatchClient<DataType>(
56
69
  process: ChildProcess | NodeJS.Process
57
- , { expectedVersion, channel }: {
70
+ , { expectedVersion, channel, timeout }: {
58
71
  expectedVersion?: string
59
72
  channel?: string
73
+ timeout?: number
60
74
  } = {}
61
75
  ): [client: DelightRPC.BatchClient<DataType>, close: () => void] {
62
76
  const pendings: Map<
@@ -75,7 +89,16 @@ export function createBatchClient<DataType>(
75
89
  pendings.set(request.id, res)
76
90
  try {
77
91
  process.send!(request)
78
- return await res
92
+
93
+ const mergedSignal = raceAbortSignals([
94
+ isntUndefined(timeout) && timeoutSignal(timeout)
95
+ ])
96
+ mergedSignal.addEventListener('abort', () => {
97
+ const abort = DelightRPC.createAbort(request.id, channel)
98
+ process.send!(abort)
99
+ })
100
+
101
+ return await withAbortSignal(mergedSignal, () => res)
79
102
  } finally {
80
103
  pendings.delete(request.id)
81
104
  }
@@ -91,13 +114,13 @@ export function createBatchClient<DataType>(
91
114
  function close() {
92
115
  process.off('message', handler)
93
116
 
94
- for (const [key, deferred] of Object.entries(pendings)) {
117
+ for (const [key, deferred] of pendings.entries()) {
95
118
  deferred.reject(new ClientClosed())
96
119
  pendings.delete(key)
97
120
  }
98
121
  }
99
122
 
100
- function handler(res: any): void {
123
+ function handler(res: unknown): void {
101
124
  if (DelightRPC.isError(res) || DelightRPC.isBatchResponse(res)) {
102
125
  pendings.get(res.id)?.resolve(res)
103
126
  }
package/src/server.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as DelightRPC from 'delight-rpc'
2
2
  import { ChildProcess } from 'child_process'
3
3
  import { isntNull } from '@blackglory/prelude'
4
+ import { AbortController } from 'extra-abort'
4
5
 
5
6
  export function createServer<IAPI extends object>(
6
7
  api: DelightRPC.ImplementationOf<IAPI>
@@ -12,24 +13,45 @@ export function createServer<IAPI extends object>(
12
13
  ownPropsOnly?: boolean
13
14
  } = {}
14
15
  ): () => void {
16
+ const idToController: Map<string, AbortController> = new Map()
17
+
15
18
  process.on('message', handler)
19
+ process.on('disconnect', () => {
20
+ for (const controller of idToController.values()) {
21
+ controller.abort()
22
+ }
23
+
24
+ idToController.clear()
25
+ })
16
26
  return () => process.off('message', handler)
17
27
 
18
- async function handler(req: any): Promise<void> {
19
- if (DelightRPC.isRequest(req) || DelightRPC.isBatchRequest(req)) {
20
- const result = await DelightRPC.createResponse(
21
- api
22
- , req
23
- , {
24
- parameterValidators
25
- , version
26
- , channel
27
- , ownPropsOnly
28
- }
29
- )
28
+ async function handler(message: unknown): Promise<void> {
29
+ if (DelightRPC.isRequest(message) || DelightRPC.isBatchRequest(message)) {
30
+ const controller = new AbortController()
31
+ idToController.set(message.id, controller)
30
32
 
31
- if (isntNull(result)) {
32
- process.send!(result)
33
+ try {
34
+ const result = await DelightRPC.createResponse(
35
+ api
36
+ , message
37
+ , {
38
+ parameterValidators
39
+ , version
40
+ , channel
41
+ , ownPropsOnly
42
+ }
43
+ )
44
+
45
+ if (isntNull(result)) {
46
+ process.send!(result)
47
+ }
48
+ } finally {
49
+ idToController.delete(message.id)
50
+ }
51
+ } else if (DelightRPC.isAbort(message)) {
52
+ if (DelightRPC.matchChannel(message, channel)) {
53
+ idToController.get(message.id)?.abort()
54
+ idToController.delete(message.id)
33
55
  }
34
56
  }
35
57
  }