@skipruntime/helpers 0.0.12 → 0.0.13
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/src/external.d.ts +44 -69
- package/dist/src/external.d.ts.map +1 -1
- package/dist/src/external.js +23 -94
- package/dist/src/external.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/package.json +2 -2
- package/src/external.ts +59 -144
- package/src/index.ts +1 -7
package/dist/src/external.d.ts
CHANGED
|
@@ -1,46 +1,4 @@
|
|
|
1
1
|
import type { Entry, ExternalService, Json } from "@skipruntime/core";
|
|
2
|
-
/**
|
|
3
|
-
* Interface required by `GenericExternalService` for external resources.
|
|
4
|
-
*/
|
|
5
|
-
export interface ExternalResource {
|
|
6
|
-
open(instance: string, params: Json, callbacks: {
|
|
7
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
8
|
-
error: (error: Json) => void;
|
|
9
|
-
loading: () => void;
|
|
10
|
-
}): void;
|
|
11
|
-
close(instance: string): void;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* A generic external service providing external resources.
|
|
15
|
-
*
|
|
16
|
-
* `GenericExternalService` provides an implementation of `ExternalService` for external resources by lifting the `open` and `close` operations from `ExternalResource` to the `subscribe` and `unsubscribe` operations required by `ExternalService`.
|
|
17
|
-
*/
|
|
18
|
-
export declare class GenericExternalService implements ExternalService {
|
|
19
|
-
private readonly resources;
|
|
20
|
-
private readonly instances;
|
|
21
|
-
/**
|
|
22
|
-
* @param resources - Association of resource names to `ExternalResource`s.
|
|
23
|
-
*/
|
|
24
|
-
constructor(resources: {
|
|
25
|
-
[name: string]: ExternalResource;
|
|
26
|
-
});
|
|
27
|
-
subscribe(instance: string, resourceName: string, params: Json, callbacks: {
|
|
28
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
29
|
-
error: (error: Json) => void;
|
|
30
|
-
loading: () => void;
|
|
31
|
-
}): void;
|
|
32
|
-
unsubscribe(instance: string): void;
|
|
33
|
-
shutdown(): Promise<void>;
|
|
34
|
-
}
|
|
35
|
-
export declare class TimerResource implements ExternalResource {
|
|
36
|
-
private readonly intervals;
|
|
37
|
-
open(instance: string, params: Json, callbacks: {
|
|
38
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
39
|
-
error: (error: Json) => void;
|
|
40
|
-
loading: () => void;
|
|
41
|
-
}): void;
|
|
42
|
-
close(instance: string): void;
|
|
43
|
-
}
|
|
44
2
|
/**
|
|
45
3
|
* Encode params for external resource request.
|
|
46
4
|
*
|
|
@@ -51,45 +9,62 @@ export declare class TimerResource implements ExternalResource {
|
|
|
51
9
|
*/
|
|
52
10
|
export declare function defaultParamEncoder(params: Json): string;
|
|
53
11
|
/**
|
|
54
|
-
*
|
|
12
|
+
* Description of an external HTTP endpoint and how to poll it.
|
|
13
|
+
*
|
|
14
|
+
* The URL of the external resource is formed by appending the given base `url` and the result of `encodeParams(params)` where `params` are the parameters provided to [`Context#useExternalResource`](api/core/interfaces/Context#useexternalresource)
|
|
55
15
|
*
|
|
56
|
-
* @typeParam S - Type of data received from external resource.
|
|
57
|
-
* @typeParam K - Type of keys.
|
|
58
|
-
* @typeParam V - Type of values.
|
|
59
16
|
*/
|
|
60
|
-
export
|
|
61
|
-
private readonly url;
|
|
62
|
-
private readonly duration;
|
|
63
|
-
private readonly conv;
|
|
64
|
-
private readonly encodeParams;
|
|
65
|
-
private readonly options?;
|
|
66
|
-
private readonly intervals;
|
|
17
|
+
export interface PolledHTTPResource {
|
|
67
18
|
/**
|
|
68
|
-
*
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
*
|
|
19
|
+
* Base URL of resource to poll.
|
|
20
|
+
*/
|
|
21
|
+
url: string;
|
|
22
|
+
/**
|
|
23
|
+
* The interval of time to wait before refreshing the data, given in milliseconds
|
|
24
|
+
*/
|
|
25
|
+
interval: number;
|
|
26
|
+
/**
|
|
27
|
+
* Function to convert data received from external resource to `key`-`value` entries.
|
|
28
|
+
*/
|
|
29
|
+
conv: (data: Json) => Entry<Json, Json>[];
|
|
30
|
+
/**
|
|
31
|
+
* Function to use to encode params of type `Json` for external resource request.
|
|
73
32
|
*
|
|
74
|
-
*
|
|
75
|
-
* @param duration - Refresh interval, in milliseconds.
|
|
76
|
-
* @param conv - Function to convert data of type `S` received from external resource to `key`-`value` entries.
|
|
77
|
-
* @param encodeParams - Function to use to encode params of type `Json` for external resource request.
|
|
78
|
-
* @param options - Optional parameters.
|
|
79
|
-
* @param options.headers - Additional headers to add to request.
|
|
80
|
-
* @param options.timeout - Timeout for request, in milliseconds. Defaults to 1000ms.
|
|
33
|
+
* Note that the result of `encodeParams` may contain a `?` separator, but it need not be at the beginning of the returned string, so some parameters can be used in part of the URL preceding the `?`.
|
|
81
34
|
*/
|
|
82
|
-
|
|
35
|
+
encodeParams?: (params: Json) => string;
|
|
36
|
+
/**
|
|
37
|
+
* Optional parameters: additional `headers` to add to request, and `timeout` for request, in milliseconds. (default 1000ms)
|
|
38
|
+
*/
|
|
39
|
+
options?: {
|
|
83
40
|
headers?: {
|
|
84
41
|
[header: string]: string;
|
|
85
42
|
};
|
|
86
43
|
timeout?: number;
|
|
87
|
-
}
|
|
88
|
-
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* An external HTTP service that is kept up-to-date by polling.
|
|
48
|
+
*
|
|
49
|
+
* A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
|
|
50
|
+
*/
|
|
51
|
+
export declare class PolledExternalService implements ExternalService {
|
|
52
|
+
private readonly resources;
|
|
53
|
+
private readonly intervals;
|
|
54
|
+
/**
|
|
55
|
+
* Construct a polled external service.
|
|
56
|
+
*
|
|
57
|
+
* @param resources - Specification(s) of external resource(s) to poll
|
|
58
|
+
*/
|
|
59
|
+
constructor(resources: {
|
|
60
|
+
[resource: string]: PolledHTTPResource;
|
|
61
|
+
});
|
|
62
|
+
subscribe(instance: string, resourceName: string, params: Json, callbacks: {
|
|
89
63
|
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
90
64
|
error: (error: Json) => void;
|
|
91
65
|
loading: () => void;
|
|
92
66
|
}): void;
|
|
93
|
-
|
|
67
|
+
unsubscribe(instance: string): void;
|
|
68
|
+
shutdown(): Promise<void>;
|
|
94
69
|
}
|
|
95
70
|
//# sourceMappingURL=external.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external.d.ts","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"external.d.ts","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAMtE;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CASxD;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;OAEG;IACH,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;IAC1C;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,KAAK,MAAM,CAAC;IACxC;;OAEG;IACH,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE;YAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACxE;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,YAAW,eAAe;IASzD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAR5B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IAExD;;;;OAIG;gBAEgB,SAAS,EAAE;QAC1B,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,CAAC;KACxC;IAGH,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAC;QAC7B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB;IAwBH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAO1B"}
|
package/dist/src/external.js
CHANGED
|
@@ -1,70 +1,5 @@
|
|
|
1
1
|
import { SkipUnknownResourceError } from "@skipruntime/core";
|
|
2
2
|
import { fetchJSON } from "./rest.js";
|
|
3
|
-
/**
|
|
4
|
-
* A generic external service providing external resources.
|
|
5
|
-
*
|
|
6
|
-
* `GenericExternalService` provides an implementation of `ExternalService` for external resources by lifting the `open` and `close` operations from `ExternalResource` to the `subscribe` and `unsubscribe` operations required by `ExternalService`.
|
|
7
|
-
*/
|
|
8
|
-
export class GenericExternalService {
|
|
9
|
-
/**
|
|
10
|
-
* @param resources - Association of resource names to `ExternalResource`s.
|
|
11
|
-
*/
|
|
12
|
-
constructor(resources) {
|
|
13
|
-
this.resources = resources;
|
|
14
|
-
this.instances = new Map();
|
|
15
|
-
}
|
|
16
|
-
subscribe(instance, resourceName, params, callbacks) {
|
|
17
|
-
const resource = this.resources[resourceName];
|
|
18
|
-
if (!resource) {
|
|
19
|
-
throw new SkipUnknownResourceError(`Unknown resource named '${resourceName}'`);
|
|
20
|
-
}
|
|
21
|
-
this.instances.set(instance, resource);
|
|
22
|
-
resource.open(instance, params, callbacks);
|
|
23
|
-
}
|
|
24
|
-
unsubscribe(instance) {
|
|
25
|
-
const resource = this.instances.get(instance);
|
|
26
|
-
if (resource) {
|
|
27
|
-
resource.close(instance);
|
|
28
|
-
this.instances.delete(instance);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
shutdown() {
|
|
32
|
-
return Promise.resolve();
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
export class TimerResource {
|
|
36
|
-
constructor() {
|
|
37
|
-
this.intervals = new Map();
|
|
38
|
-
}
|
|
39
|
-
open(instance, params, callbacks) {
|
|
40
|
-
const time = new Date().getTime();
|
|
41
|
-
const values = [];
|
|
42
|
-
for (const name of Object.keys(params)) {
|
|
43
|
-
values.push([name, [time]]);
|
|
44
|
-
}
|
|
45
|
-
callbacks.update(values, true);
|
|
46
|
-
const intervals = {};
|
|
47
|
-
for (const [name, duration] of Object.entries(params)) {
|
|
48
|
-
const ms = Number(duration);
|
|
49
|
-
if (ms > 0) {
|
|
50
|
-
intervals[name] = setInterval(() => {
|
|
51
|
-
const newvalue = [name, [new Date().getTime()]];
|
|
52
|
-
callbacks.update([newvalue], true);
|
|
53
|
-
}, ms);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
this.intervals.set(instance, intervals);
|
|
57
|
-
}
|
|
58
|
-
close(instance) {
|
|
59
|
-
const intervals = this.intervals.get(instance);
|
|
60
|
-
if (intervals != null) {
|
|
61
|
-
for (const interval of Object.values(intervals)) {
|
|
62
|
-
clearInterval(interval);
|
|
63
|
-
}
|
|
64
|
-
this.intervals.delete(instance);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
3
|
/**
|
|
69
4
|
* Encode params for external resource request.
|
|
70
5
|
*
|
|
@@ -88,43 +23,30 @@ export function defaultParamEncoder(params) {
|
|
|
88
23
|
return `?params=${JSON.stringify(params)}`;
|
|
89
24
|
}
|
|
90
25
|
/**
|
|
91
|
-
* An external
|
|
26
|
+
* An external HTTP service that is kept up-to-date by polling.
|
|
92
27
|
*
|
|
93
|
-
*
|
|
94
|
-
* @typeParam K - Type of keys.
|
|
95
|
-
* @typeParam V - Type of values.
|
|
28
|
+
* A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
|
|
96
29
|
*/
|
|
97
|
-
export class
|
|
30
|
+
export class PolledExternalService {
|
|
98
31
|
/**
|
|
99
|
-
* Construct a
|
|
100
|
-
*
|
|
101
|
-
* The URL of the external resource is formed by appending the given base `url` and the result of `encodeParams(params)` where `params` are the parameters provided when instantiating the resource.
|
|
102
|
-
*
|
|
103
|
-
* Note that the result of `encodeParams` contains the `?` separator, but it need not be at the beginning of the returned string, so some parameters can be used in part of the URL preceding the `?`.
|
|
32
|
+
* Construct a polled external service.
|
|
104
33
|
*
|
|
105
|
-
* @param
|
|
106
|
-
* @param duration - Refresh interval, in milliseconds.
|
|
107
|
-
* @param conv - Function to convert data of type `S` received from external resource to `key`-`value` entries.
|
|
108
|
-
* @param encodeParams - Function to use to encode params of type `Json` for external resource request.
|
|
109
|
-
* @param options - Optional parameters.
|
|
110
|
-
* @param options.headers - Additional headers to add to request.
|
|
111
|
-
* @param options.timeout - Timeout for request, in milliseconds. Defaults to 1000ms.
|
|
34
|
+
* @param resources - Specification(s) of external resource(s) to poll
|
|
112
35
|
*/
|
|
113
|
-
constructor(
|
|
114
|
-
this.
|
|
115
|
-
this.duration = duration;
|
|
116
|
-
this.conv = conv;
|
|
117
|
-
this.encodeParams = encodeParams;
|
|
118
|
-
this.options = options;
|
|
36
|
+
constructor(resources) {
|
|
37
|
+
this.resources = resources;
|
|
119
38
|
this.intervals = new Map();
|
|
120
39
|
}
|
|
121
|
-
|
|
122
|
-
const
|
|
40
|
+
subscribe(instance, resourceName, params, callbacks) {
|
|
41
|
+
const resource = this.resources[resourceName];
|
|
42
|
+
if (!resource)
|
|
43
|
+
throw new SkipUnknownResourceError(`Unknown resource named '${resourceName}'`);
|
|
44
|
+
const url = `${resource.url}${(resource.encodeParams ?? defaultParamEncoder)(params)}`;
|
|
123
45
|
const call = () => {
|
|
124
46
|
callbacks.loading();
|
|
125
|
-
fetchJSON(url, "GET",
|
|
47
|
+
fetchJSON(url, "GET", resource.options ?? {})
|
|
126
48
|
.then((r) => {
|
|
127
|
-
callbacks.update(
|
|
49
|
+
callbacks.update(resource.conv(r[0] ?? []), true);
|
|
128
50
|
})
|
|
129
51
|
.catch((e) => {
|
|
130
52
|
callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
|
|
@@ -132,14 +54,21 @@ export class Polled {
|
|
|
132
54
|
});
|
|
133
55
|
};
|
|
134
56
|
call();
|
|
135
|
-
this.intervals.set(instance, setInterval(call,
|
|
57
|
+
this.intervals.set(instance, setInterval(call, resource.interval));
|
|
136
58
|
}
|
|
137
|
-
|
|
59
|
+
unsubscribe(instance) {
|
|
138
60
|
const interval = this.intervals.get(instance);
|
|
139
61
|
if (interval) {
|
|
140
62
|
clearInterval(interval);
|
|
141
63
|
this.intervals.delete(instance);
|
|
142
64
|
}
|
|
143
65
|
}
|
|
66
|
+
shutdown() {
|
|
67
|
+
for (const [instance, interval] of Object.entries(this.intervals)) {
|
|
68
|
+
clearInterval(interval);
|
|
69
|
+
this.intervals.delete(instance);
|
|
70
|
+
}
|
|
71
|
+
return Promise.resolve();
|
|
72
|
+
}
|
|
144
73
|
}
|
|
145
74
|
//# sourceMappingURL=external.js.map
|
package/dist/src/external.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
export { defaultParamEncoder,
|
|
6
|
+
export { defaultParamEncoder, PolledExternalService } from "./external.js";
|
|
7
7
|
export { SkipExternalService } from "./remote.js";
|
|
8
8
|
export { SkipServiceBroker, fetchJSON, type Entrypoint } from "./rest.js";
|
|
9
9
|
export { Count, Max, Min, Sum } from "./utils.js";
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
|
-
export { defaultParamEncoder,
|
|
6
|
+
export { defaultParamEncoder, PolledExternalService } from "./external.js";
|
|
7
7
|
export { SkipExternalService } from "./remote.js";
|
|
8
8
|
export { SkipServiceBroker, fetchJSON } from "./rest.js";
|
|
9
9
|
export { Count, Max, Min, Sum } from "./utils.js";
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skipruntime/helpers",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/src/index.js"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"eventsource": "^2.0.2",
|
|
21
21
|
"express": "^4.21.1",
|
|
22
|
-
"@skipruntime/core": "0.0.
|
|
22
|
+
"@skipruntime/core": "0.0.13"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/eventsource": "^1.1.15"
|
package/src/external.ts
CHANGED
|
@@ -2,117 +2,7 @@ import type { Entry, ExternalService, Json } from "@skipruntime/core";
|
|
|
2
2
|
import { SkipUnknownResourceError } from "@skipruntime/core";
|
|
3
3
|
import { fetchJSON } from "./rest.js";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Interface required by `GenericExternalService` for external resources.
|
|
7
|
-
*/
|
|
8
|
-
export interface ExternalResource {
|
|
9
|
-
open(
|
|
10
|
-
instance: string,
|
|
11
|
-
params: Json,
|
|
12
|
-
callbacks: {
|
|
13
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
14
|
-
error: (error: Json) => void;
|
|
15
|
-
loading: () => void;
|
|
16
|
-
},
|
|
17
|
-
): void;
|
|
18
|
-
|
|
19
|
-
close(instance: string): void;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* A generic external service providing external resources.
|
|
24
|
-
*
|
|
25
|
-
* `GenericExternalService` provides an implementation of `ExternalService` for external resources by lifting the `open` and `close` operations from `ExternalResource` to the `subscribe` and `unsubscribe` operations required by `ExternalService`.
|
|
26
|
-
*/
|
|
27
|
-
export class GenericExternalService implements ExternalService {
|
|
28
|
-
private readonly instances = new Map<string, ExternalResource>();
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* @param resources - Association of resource names to `ExternalResource`s.
|
|
32
|
-
*/
|
|
33
|
-
constructor(
|
|
34
|
-
private readonly resources: { [name: string]: ExternalResource },
|
|
35
|
-
) {}
|
|
36
|
-
|
|
37
|
-
subscribe(
|
|
38
|
-
instance: string,
|
|
39
|
-
resourceName: string,
|
|
40
|
-
params: Json,
|
|
41
|
-
callbacks: {
|
|
42
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
43
|
-
error: (error: Json) => void;
|
|
44
|
-
loading: () => void;
|
|
45
|
-
},
|
|
46
|
-
) {
|
|
47
|
-
const resource = this.resources[resourceName] as
|
|
48
|
-
| ExternalResource
|
|
49
|
-
| undefined;
|
|
50
|
-
if (!resource) {
|
|
51
|
-
throw new SkipUnknownResourceError(
|
|
52
|
-
`Unknown resource named '${resourceName}'`,
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
this.instances.set(instance, resource);
|
|
56
|
-
resource.open(instance, params, callbacks);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
unsubscribe(instance: string) {
|
|
60
|
-
const resource = this.instances.get(instance);
|
|
61
|
-
if (resource) {
|
|
62
|
-
resource.close(instance);
|
|
63
|
-
this.instances.delete(instance);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
shutdown(): Promise<void> {
|
|
68
|
-
return Promise.resolve();
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
5
|
type Timeout = ReturnType<typeof setInterval>;
|
|
73
|
-
type Timeouts = { [name: string]: Timeout };
|
|
74
|
-
|
|
75
|
-
export class TimerResource implements ExternalResource {
|
|
76
|
-
private readonly intervals = new Map<string, { [name: string]: Timeout }>();
|
|
77
|
-
|
|
78
|
-
open(
|
|
79
|
-
instance: string,
|
|
80
|
-
params: Json,
|
|
81
|
-
callbacks: {
|
|
82
|
-
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
83
|
-
error: (error: Json) => void;
|
|
84
|
-
loading: () => void;
|
|
85
|
-
},
|
|
86
|
-
) {
|
|
87
|
-
const time = new Date().getTime();
|
|
88
|
-
const values: Entry<string, number>[] = [];
|
|
89
|
-
for (const name of Object.keys(params)) {
|
|
90
|
-
values.push([name, [time]]);
|
|
91
|
-
}
|
|
92
|
-
callbacks.update(values, true);
|
|
93
|
-
const intervals: Timeouts = {};
|
|
94
|
-
for (const [name, duration] of Object.entries(params)) {
|
|
95
|
-
const ms = Number(duration);
|
|
96
|
-
if (ms > 0) {
|
|
97
|
-
intervals[name] = setInterval(() => {
|
|
98
|
-
const newvalue: Entry<Json, Json> = [name, [new Date().getTime()]];
|
|
99
|
-
callbacks.update([newvalue], true);
|
|
100
|
-
}, ms);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
this.intervals.set(instance, intervals);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
close(instance: string): void {
|
|
107
|
-
const intervals = this.intervals.get(instance);
|
|
108
|
-
if (intervals != null) {
|
|
109
|
-
for (const interval of Object.values(intervals)) {
|
|
110
|
-
clearInterval(interval);
|
|
111
|
-
}
|
|
112
|
-
this.intervals.delete(instance);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
6
|
|
|
117
7
|
/**
|
|
118
8
|
* Encode params for external resource request.
|
|
@@ -134,47 +24,58 @@ export function defaultParamEncoder(params: Json): string {
|
|
|
134
24
|
}
|
|
135
25
|
|
|
136
26
|
/**
|
|
137
|
-
*
|
|
27
|
+
* Description of an external HTTP endpoint and how to poll it.
|
|
28
|
+
*
|
|
29
|
+
* The URL of the external resource is formed by appending the given base `url` and the result of `encodeParams(params)` where `params` are the parameters provided to [`Context#useExternalResource`](api/core/interfaces/Context#useexternalresource)
|
|
138
30
|
*
|
|
139
|
-
* @typeParam S - Type of data received from external resource.
|
|
140
|
-
* @typeParam K - Type of keys.
|
|
141
|
-
* @typeParam V - Type of values.
|
|
142
31
|
*/
|
|
143
|
-
export
|
|
144
|
-
|
|
145
|
-
|
|
32
|
+
export interface PolledHTTPResource {
|
|
33
|
+
/**
|
|
34
|
+
* Base URL of resource to poll.
|
|
35
|
+
*/
|
|
36
|
+
url: string;
|
|
37
|
+
/**
|
|
38
|
+
* The interval of time to wait before refreshing the data, given in milliseconds
|
|
39
|
+
*/
|
|
40
|
+
interval: number;
|
|
41
|
+
/**
|
|
42
|
+
* Function to convert data received from external resource to `key`-`value` entries.
|
|
43
|
+
*/
|
|
44
|
+
conv: (data: Json) => Entry<Json, Json>[];
|
|
45
|
+
/**
|
|
46
|
+
* Function to use to encode params of type `Json` for external resource request.
|
|
47
|
+
*
|
|
48
|
+
* Note that the result of `encodeParams` may contain a `?` separator, but it need not be at the beginning of the returned string, so some parameters can be used in part of the URL preceding the `?`.
|
|
49
|
+
*/
|
|
50
|
+
encodeParams?: (params: Json) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Optional parameters: additional `headers` to add to request, and `timeout` for request, in milliseconds. (default 1000ms)
|
|
53
|
+
*/
|
|
54
|
+
options?: { headers?: { [header: string]: string }; timeout?: number };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* An external HTTP service that is kept up-to-date by polling.
|
|
59
|
+
*
|
|
60
|
+
* A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
|
|
61
|
+
*/
|
|
62
|
+
export class PolledExternalService implements ExternalService {
|
|
146
63
|
private readonly intervals = new Map<string, Timeout>();
|
|
147
64
|
|
|
148
65
|
/**
|
|
149
|
-
* Construct a
|
|
66
|
+
* Construct a polled external service.
|
|
150
67
|
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* Note that the result of `encodeParams` contains the `?` separator, but it need not be at the beginning of the returned string, so some parameters can be used in part of the URL preceding the `?`.
|
|
154
|
-
*
|
|
155
|
-
* @param url - HTTP endpoint of external resource to poll.
|
|
156
|
-
* @param duration - Refresh interval, in milliseconds.
|
|
157
|
-
* @param conv - Function to convert data of type `S` received from external resource to `key`-`value` entries.
|
|
158
|
-
* @param encodeParams - Function to use to encode params of type `Json` for external resource request.
|
|
159
|
-
* @param options - Optional parameters.
|
|
160
|
-
* @param options.headers - Additional headers to add to request.
|
|
161
|
-
* @param options.timeout - Timeout for request, in milliseconds. Defaults to 1000ms.
|
|
68
|
+
* @param resources - Specification(s) of external resource(s) to poll
|
|
162
69
|
*/
|
|
163
70
|
constructor(
|
|
164
|
-
private readonly
|
|
165
|
-
|
|
166
|
-
private readonly conv: (data: S) => Entry<K, V>[],
|
|
167
|
-
private readonly encodeParams: (
|
|
168
|
-
params: Json,
|
|
169
|
-
) => string = defaultParamEncoder,
|
|
170
|
-
private readonly options?: {
|
|
171
|
-
headers?: { [header: string]: string };
|
|
172
|
-
timeout?: number;
|
|
71
|
+
private readonly resources: {
|
|
72
|
+
[resource: string]: PolledHTTPResource;
|
|
173
73
|
},
|
|
174
74
|
) {}
|
|
175
75
|
|
|
176
|
-
|
|
76
|
+
subscribe(
|
|
177
77
|
instance: string,
|
|
78
|
+
resourceName: string,
|
|
178
79
|
params: Json,
|
|
179
80
|
callbacks: {
|
|
180
81
|
update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
|
|
@@ -182,12 +83,18 @@ export class Polled<S extends Json, K extends Json, V extends Json>
|
|
|
182
83
|
loading: () => void;
|
|
183
84
|
},
|
|
184
85
|
) {
|
|
185
|
-
const
|
|
86
|
+
const resource = this.resources[resourceName];
|
|
87
|
+
if (!resource)
|
|
88
|
+
throw new SkipUnknownResourceError(
|
|
89
|
+
`Unknown resource named '${resourceName}'`,
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const url = `${resource.url}${(resource.encodeParams ?? defaultParamEncoder)(params)}`;
|
|
186
93
|
const call = () => {
|
|
187
94
|
callbacks.loading();
|
|
188
|
-
fetchJSON(url, "GET",
|
|
95
|
+
fetchJSON(url, "GET", resource.options ?? {})
|
|
189
96
|
.then((r) => {
|
|
190
|
-
callbacks.update(
|
|
97
|
+
callbacks.update(resource.conv(r[0] ?? []), true);
|
|
191
98
|
})
|
|
192
99
|
.catch((e: unknown) => {
|
|
193
100
|
callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
|
|
@@ -195,14 +102,22 @@ export class Polled<S extends Json, K extends Json, V extends Json>
|
|
|
195
102
|
});
|
|
196
103
|
};
|
|
197
104
|
call();
|
|
198
|
-
this.intervals.set(instance, setInterval(call,
|
|
105
|
+
this.intervals.set(instance, setInterval(call, resource.interval));
|
|
199
106
|
}
|
|
200
107
|
|
|
201
|
-
|
|
108
|
+
unsubscribe(instance: string): void {
|
|
202
109
|
const interval = this.intervals.get(instance);
|
|
203
110
|
if (interval) {
|
|
204
111
|
clearInterval(interval);
|
|
205
112
|
this.intervals.delete(instance);
|
|
206
113
|
}
|
|
207
114
|
}
|
|
115
|
+
|
|
116
|
+
shutdown(): Promise<void> {
|
|
117
|
+
for (const [instance, interval] of Object.entries(this.intervals)) {
|
|
118
|
+
clearInterval(interval as Timeout);
|
|
119
|
+
this.intervals.delete(instance);
|
|
120
|
+
}
|
|
121
|
+
return Promise.resolve();
|
|
122
|
+
}
|
|
208
123
|
}
|
package/src/index.ts
CHANGED
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
export {
|
|
8
|
-
defaultParamEncoder,
|
|
9
|
-
type ExternalResource,
|
|
10
|
-
GenericExternalService,
|
|
11
|
-
Polled,
|
|
12
|
-
TimerResource,
|
|
13
|
-
} from "./external.js";
|
|
7
|
+
export { defaultParamEncoder, PolledExternalService } from "./external.js";
|
|
14
8
|
export { SkipExternalService } from "./remote.js";
|
|
15
9
|
export { SkipServiceBroker, fetchJSON, type Entrypoint } from "./rest.js";
|
|
16
10
|
export { Count, Max, Min, Sum } from "./utils.js";
|