@skipruntime/helpers 0.0.13 → 0.0.15

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.
@@ -11,8 +11,7 @@ export declare function defaultParamEncoder(params: Json): string;
11
11
  /**
12
12
  * Description of an external HTTP endpoint and how to poll it.
13
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)
15
- *
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`](https://skiplabs.io/docs/api/core/interfaces/Context#useexternalresource)
16
15
  */
17
16
  export interface PolledHTTPResource {
18
17
  /**
@@ -46,7 +45,7 @@ export interface PolledHTTPResource {
46
45
  /**
47
46
  * An external HTTP service that is kept up-to-date by polling.
48
47
  *
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.
48
+ * A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](https://skiplabs.io/docs/api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
50
49
  */
51
50
  export declare class PolledExternalService implements ExternalService {
52
51
  private readonly resources;
@@ -60,10 +59,9 @@ export declare class PolledExternalService implements ExternalService {
60
59
  [resource: string]: PolledHTTPResource;
61
60
  });
62
61
  subscribe(instance: string, resourceName: string, params: Json, callbacks: {
63
- update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
64
- error: (error: Json) => void;
65
- loading: () => void;
66
- }): void;
62
+ update: (updates: Entry<Json, Json>[], isInit: boolean) => Promise<void>;
63
+ error: (error: unknown) => void;
64
+ }): Promise<void>;
67
65
  unsubscribe(instance: string): void;
68
66
  shutdown(): Promise<void>;
69
67
  }
@@ -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;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"}
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;;;;GAIG;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;IAGG,SAAS,CACb,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,OAAO,CAAC,IAAI,CAAC,CAAC;QACzE,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;KACjC,GACA,OAAO,CAAC,IAAI,CAAC;IAuBhB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAQnC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAO1B"}
@@ -25,7 +25,7 @@ export function defaultParamEncoder(params) {
25
25
  /**
26
26
  * An external HTTP service that is kept up-to-date by polling.
27
27
  *
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.
28
+ * A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](https://skiplabs.io/docs/api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
29
29
  */
30
30
  export class PolledExternalService {
31
31
  /**
@@ -37,24 +37,22 @@ export class PolledExternalService {
37
37
  this.resources = resources;
38
38
  this.intervals = new Map();
39
39
  }
40
- subscribe(instance, resourceName, params, callbacks) {
40
+ async subscribe(instance, resourceName, params, callbacks) {
41
41
  const resource = this.resources[resourceName];
42
42
  if (!resource)
43
43
  throw new SkipUnknownResourceError(`Unknown resource named '${resourceName}'`);
44
44
  const url = `${resource.url}${(resource.encodeParams ?? defaultParamEncoder)(params)}`;
45
- const call = () => {
46
- callbacks.loading();
47
- fetchJSON(url, "GET", resource.options ?? {})
48
- .then((r) => {
49
- callbacks.update(resource.conv(r[0] ?? []), true);
50
- })
51
- .catch((e) => {
52
- callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
45
+ const call = async (init) => {
46
+ const [data, _] = await fetchJSON(url, "GET", resource.options ?? {});
47
+ await callbacks.update(resource.conv(data ?? []), init);
48
+ };
49
+ await call(true);
50
+ this.intervals.set(instance, setInterval(() => {
51
+ call(false).catch((e) => {
52
+ callbacks.error(e);
53
53
  console.error(e);
54
54
  });
55
- };
56
- call();
57
- this.intervals.set(instance, setInterval(call, resource.interval));
55
+ }, resource.interval));
58
56
  }
59
57
  unsubscribe(instance) {
60
58
  const interval = this.intervals.get(instance);
@@ -1 +1 @@
1
- {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/external.ts"],"names":[],"mappings":"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"}
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
- export { defaultParamEncoder, PolledExternalService } from "./external.js";
7
- export { SkipExternalService } from "./remote.js";
6
+ export { defaultParamEncoder, PolledExternalService, type PolledHTTPResource, } from "./external.js";
7
+ export { SkipExternalService, asLeader, asFollower } from "./remote.js";
8
8
  export { SkipServiceBroker, fetchJSON, type Entrypoint } from "./rest.js";
9
9
  export { Count, Max, Min, Sum } from "./utils.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,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,8 +3,8 @@
3
3
  *
4
4
  * @packageDocumentation
5
5
  */
6
- export { defaultParamEncoder, PolledExternalService } from "./external.js";
7
- export { SkipExternalService } from "./remote.js";
6
+ export { defaultParamEncoder, PolledExternalService, } from "./external.js";
7
+ export { SkipExternalService, asLeader, asFollower } from "./remote.js";
8
8
  export { SkipServiceBroker, fetchJSON } from "./rest.js";
9
9
  export { Count, Max, Min, Sum } from "./utils.js";
10
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GAEtB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { Entry, ExternalService, Json } from "@skipruntime/core";
1
+ import type { Entry, ExternalService, Json, SkipService } from "@skipruntime/core";
2
2
  import type { Entrypoint } from "./rest.js";
3
3
  /**
4
4
  * An external Skip reactive service.
@@ -22,11 +22,33 @@ export declare class SkipExternalService implements ExternalService {
22
22
  */
23
23
  static direct(entrypoint: Entrypoint): SkipExternalService;
24
24
  subscribe(instance: string, resource: string, params: Json, callbacks: {
25
- update: (updates: Entry<Json, Json>[], isInitial: boolean) => void;
26
- error: (error: Json) => void;
27
- loading: () => void;
28
- }): void;
25
+ update: (updates: Entry<Json, Json>[], isInitial: boolean) => Promise<void>;
26
+ error: (error: unknown) => void;
27
+ }): Promise<void>;
29
28
  unsubscribe(instance: string): void;
30
29
  shutdown(): Promise<void>;
31
30
  }
31
+ /**
32
+ * Run a `SkipService` as the *leader* in a leader-follower topology.
33
+ *
34
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
35
+ *
36
+ * @returns The *leader* component to run `service` in such a configuration.
37
+ */
38
+ export declare function asLeader(service: SkipService): SkipService;
39
+ /**
40
+ * Run a `SkipService` as a *follower* in a leader-follower topology.
41
+ *
42
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
43
+ *
44
+ * @returns The *follower* component to run `service` in such a configuration, given the leader's address and the names of the shared computation graph collections to be mirrored from it (typically the `ResourceInputs` of `service`).
45
+ */
46
+ export declare function asFollower(service: SkipService, leader: {
47
+ leader: {
48
+ host: string;
49
+ streaming_port: number;
50
+ control_port: number;
51
+ };
52
+ collections: string[];
53
+ }): SkipService;
32
54
  //# sourceMappingURL=remote.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAM5C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAQvD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAR9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IAEzD;;;OAGG;gBAEgB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM;IAGtC;;;;;OAKG;IAEH,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,mBAAmB;IAU1D,SAAS,CACP,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE;QACT,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;QAEnE,KAAK,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,IAAI,CAAC;QAE7B,OAAO,EAAE,MAAM,IAAI,CAAC;KACrB,GACA,IAAI;IA8BP,WAAW,CAAC,QAAQ,EAAE,MAAM;IAQ5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAM1B"}
1
+ {"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAGV,KAAK,EACL,eAAe,EACf,IAAI,EAGJ,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAG3B,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAM5C;;;;GAIG;AACH,qBAAa,mBAAoB,YAAW,eAAe;IAQvD,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAR9B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA+B;IAEzD;;;OAGG;gBAEgB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM;IAGtC;;;;;OAKG;IAEH,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,mBAAmB;IAUpD,SAAS,CACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,EACZ,SAAS,EAAE;QACT,MAAM,EAAE,CACN,OAAO,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAC5B,SAAS,EAAE,OAAO,KACf,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,KAAK,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;KACjC,GACA,OAAO,CAAC,IAAI,CAAC;IA8BhB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAQ5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAM1B;AAqBD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,WAAW,CAM1D;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE;IACN,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;IACvE,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB,GACA,WAAW,CAoBb"}
@@ -1,6 +1,7 @@
1
1
  // TODO: Remove once global `EventSource` makes it out of experimental
2
2
  // in nodejs LTS.
3
3
  import EventSource from "eventsource";
4
+ import { SkipError } from "@skipruntime/core";
4
5
  /**
5
6
  * An external Skip reactive service.
6
7
  *
@@ -32,33 +33,35 @@ export class SkipExternalService {
32
33
  }
33
34
  return new SkipExternalService(url, control_url);
34
35
  }
35
- subscribe(instance, resource, params, callbacks) {
36
- // TODO Manage Status
37
- fetch(`${this.control_url}/v1/streams/${resource}`, {
36
+ async subscribe(instance, resource, params, callbacks) {
37
+ const resp = await fetch(`${this.control_url}/v1/streams/${resource}`, {
38
38
  method: "POST",
39
39
  headers: {
40
40
  "Content-Type": "application/json",
41
41
  },
42
42
  body: JSON.stringify(params),
43
- })
44
- .then((resp) => resp.text())
45
- .then((uuid) => {
43
+ });
44
+ const uuid = await resp.text();
45
+ return new Promise((resolve, reject) => {
46
46
  const evSource = new EventSource(`${this.url}/v1/streams/${uuid}`);
47
+ evSource.addEventListener("open", () => {
48
+ this.resources.set(instance, evSource);
49
+ resolve();
50
+ });
47
51
  evSource.addEventListener("init", (e) => {
48
52
  const updates = JSON.parse(e.data);
49
- callbacks.update(updates, true);
53
+ callbacks.update(updates, true).catch(console.error);
50
54
  });
51
55
  evSource.addEventListener("update", (e) => {
52
56
  const updates = JSON.parse(e.data);
53
- callbacks.update(updates, false);
57
+ callbacks.update(updates, false).catch(console.error);
58
+ });
59
+ evSource.addEventListener("error", (e) => {
60
+ if (this.resources.has(instance))
61
+ callbacks.error(e.data);
62
+ else
63
+ reject(e.data);
54
64
  });
55
- evSource.onerror = (e) => {
56
- console.log(e);
57
- };
58
- this.resources.set(instance, evSource);
59
- })
60
- .catch((e) => {
61
- console.log(e);
62
65
  });
63
66
  }
64
67
  unsubscribe(instance) {
@@ -75,4 +78,59 @@ export class SkipExternalService {
75
78
  return Promise.resolve();
76
79
  }
77
80
  }
81
+ class LeaderResource {
82
+ constructor(param) {
83
+ if (typeof param == "string")
84
+ this.collection = param;
85
+ else
86
+ throw new SkipError("Followers must specify a shared collection to mirror from leader.");
87
+ }
88
+ instantiate(collections) {
89
+ if (this.collection in collections)
90
+ return collections[this.collection];
91
+ throw new SkipError(`Unknown shared collection in leader: ${this.collection}`);
92
+ }
93
+ }
94
+ /**
95
+ * Run a `SkipService` as the *leader* in a leader-follower topology.
96
+ *
97
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
98
+ *
99
+ * @returns The *leader* component to run `service` in such a configuration.
100
+ */
101
+ export function asLeader(service) {
102
+ //TODO: add mechanism to split externals between leader/follower
103
+ return {
104
+ ...service,
105
+ resources: { leader: LeaderResource },
106
+ };
107
+ }
108
+ /**
109
+ * Run a `SkipService` as a *follower* in a leader-follower topology.
110
+ *
111
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
112
+ *
113
+ * @returns The *follower* component to run `service` in such a configuration, given the leader's address and the names of the shared computation graph collections to be mirrored from it (typically the `ResourceInputs` of `service`).
114
+ */
115
+ export function asFollower(service, leader) {
116
+ return {
117
+ ...service,
118
+ initialData: {},
119
+ externalServices: {
120
+ ...service.externalServices,
121
+ __skip_leader: SkipExternalService.direct(leader.leader),
122
+ },
123
+ createGraph(_inputs, context) {
124
+ const mirroredCollections = {};
125
+ for (const collection of leader.collections) {
126
+ mirroredCollections[collection] = context.useExternalResource({
127
+ service: "__skip_leader",
128
+ identifier: "leader",
129
+ params: collection,
130
+ });
131
+ }
132
+ return mirroredCollections;
133
+ },
134
+ };
135
+ }
78
136
  //# sourceMappingURL=remote.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote.js","sourceRoot":"","sources":["../../src/remote.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skipruntime/helpers",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
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.13"
22
+ "@skipruntime/core": "0.0.15"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/eventsource": "^1.1.15"
package/src/external.ts CHANGED
@@ -26,8 +26,7 @@ export function defaultParamEncoder(params: Json): string {
26
26
  /**
27
27
  * Description of an external HTTP endpoint and how to poll it.
28
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)
30
- *
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`](https://skiplabs.io/docs/api/core/interfaces/Context#useexternalresource)
31
30
  */
32
31
  export interface PolledHTTPResource {
33
32
  /**
@@ -57,7 +56,7 @@ export interface PolledHTTPResource {
57
56
  /**
58
57
  * An external HTTP service that is kept up-to-date by polling.
59
58
  *
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.
59
+ * A `PolledExternalService` may be composed of one or more [`PolledHTTPResource`](https://skiplabs.io/docs/api/helpers/interfaces/PolledHTTPResource)s, each of which describes a single endpoint and how to poll it.
61
60
  */
62
61
  export class PolledExternalService implements ExternalService {
63
62
  private readonly intervals = new Map<string, Timeout>();
@@ -73,36 +72,35 @@ export class PolledExternalService implements ExternalService {
73
72
  },
74
73
  ) {}
75
74
 
76
- subscribe(
75
+ async subscribe(
77
76
  instance: string,
78
77
  resourceName: string,
79
78
  params: Json,
80
79
  callbacks: {
81
- update: (updates: Entry<Json, Json>[], isInit: boolean) => void;
82
- error: (error: Json) => void;
83
- loading: () => void;
80
+ update: (updates: Entry<Json, Json>[], isInit: boolean) => Promise<void>;
81
+ error: (error: unknown) => void;
84
82
  },
85
- ) {
83
+ ): Promise<void> {
86
84
  const resource = this.resources[resourceName];
87
85
  if (!resource)
88
86
  throw new SkipUnknownResourceError(
89
87
  `Unknown resource named '${resourceName}'`,
90
88
  );
91
-
92
89
  const url = `${resource.url}${(resource.encodeParams ?? defaultParamEncoder)(params)}`;
93
- const call = () => {
94
- callbacks.loading();
95
- fetchJSON(url, "GET", resource.options ?? {})
96
- .then((r) => {
97
- callbacks.update(resource.conv(r[0] ?? []), true);
98
- })
99
- .catch((e: unknown) => {
100
- callbacks.error(e instanceof Error ? e.message : JSON.stringify(e));
90
+ const call = async (init: boolean) => {
91
+ const [data, _] = await fetchJSON(url, "GET", resource.options ?? {});
92
+ await callbacks.update(resource.conv(data ?? []), init);
93
+ };
94
+ await call(true);
95
+ this.intervals.set(
96
+ instance,
97
+ setInterval(() => {
98
+ call(false).catch((e: unknown) => {
99
+ callbacks.error(e);
101
100
  console.error(e);
102
101
  });
103
- };
104
- call();
105
- this.intervals.set(instance, setInterval(call, resource.interval));
102
+ }, resource.interval),
103
+ );
106
104
  }
107
105
 
108
106
  unsubscribe(instance: string): void {
package/src/index.ts CHANGED
@@ -4,7 +4,11 @@
4
4
  * @packageDocumentation
5
5
  */
6
6
 
7
- export { defaultParamEncoder, PolledExternalService } from "./external.js";
8
- export { SkipExternalService } from "./remote.js";
7
+ export {
8
+ defaultParamEncoder,
9
+ PolledExternalService,
10
+ type PolledHTTPResource,
11
+ } from "./external.js";
12
+ export { SkipExternalService, asLeader, asFollower } from "./remote.js";
9
13
  export { SkipServiceBroker, fetchJSON, type Entrypoint } from "./rest.js";
10
14
  export { Count, Max, Min, Sum } from "./utils.js";
package/src/remote.ts CHANGED
@@ -2,7 +2,17 @@
2
2
  // in nodejs LTS.
3
3
  import EventSource from "eventsource";
4
4
 
5
- import type { Entry, ExternalService, Json } from "@skipruntime/core";
5
+ import type {
6
+ Context,
7
+ EagerCollection,
8
+ Entry,
9
+ ExternalService,
10
+ Json,
11
+ NamedCollections,
12
+ Resource,
13
+ SkipService,
14
+ } from "@skipruntime/core";
15
+ import { SkipError } from "@skipruntime/core";
6
16
 
7
17
  import type { Entrypoint } from "./rest.js";
8
18
 
@@ -44,45 +54,45 @@ export class SkipExternalService implements ExternalService {
44
54
  return new SkipExternalService(url, control_url);
45
55
  }
46
56
 
47
- subscribe(
57
+ async subscribe(
48
58
  instance: string,
49
59
  resource: string,
50
60
  params: Json,
51
61
  callbacks: {
52
- update: (updates: Entry<Json, Json>[], isInitial: boolean) => void;
53
- // FIXME: What is `error()` used for?
54
- error: (error: Json) => void;
55
- // FIXME: What is `loading()` used for?
56
- loading: () => void;
62
+ update: (
63
+ updates: Entry<Json, Json>[],
64
+ isInitial: boolean,
65
+ ) => Promise<void>;
66
+ error: (error: unknown) => void;
57
67
  },
58
- ): void {
59
- // TODO Manage Status
60
- fetch(`${this.control_url}/v1/streams/${resource}`, {
68
+ ): Promise<void> {
69
+ const resp = await fetch(`${this.control_url}/v1/streams/${resource}`, {
61
70
  method: "POST",
62
71
  headers: {
63
72
  "Content-Type": "application/json",
64
73
  },
65
74
  body: JSON.stringify(params),
66
- })
67
- .then((resp) => resp.text())
68
- .then((uuid) => {
69
- const evSource = new EventSource(`${this.url}/v1/streams/${uuid}`);
70
- evSource.addEventListener("init", (e: MessageEvent<string>) => {
71
- const updates = JSON.parse(e.data) as Entry<Json, Json>[];
72
- callbacks.update(updates, true);
73
- });
74
- evSource.addEventListener("update", (e: MessageEvent<string>) => {
75
- const updates = JSON.parse(e.data) as Entry<Json, Json>[];
76
- callbacks.update(updates, false);
77
- });
78
- evSource.onerror = (e) => {
79
- console.log(e);
80
- };
75
+ });
76
+ const uuid = await resp.text();
77
+ return new Promise<void>((resolve, reject) => {
78
+ const evSource = new EventSource(`${this.url}/v1/streams/${uuid}`);
79
+ evSource.addEventListener("open", () => {
81
80
  this.resources.set(instance, evSource);
82
- })
83
- .catch((e: unknown) => {
84
- console.log(e);
81
+ resolve();
82
+ });
83
+ evSource.addEventListener("init", (e: MessageEvent<string>) => {
84
+ const updates = JSON.parse(e.data) as Entry<Json, Json>[];
85
+ callbacks.update(updates, true).catch(console.error);
86
+ });
87
+ evSource.addEventListener("update", (e: MessageEvent<string>) => {
88
+ const updates = JSON.parse(e.data) as Entry<Json, Json>[];
89
+ callbacks.update(updates, false).catch(console.error);
85
90
  });
91
+ evSource.addEventListener("error", (e) => {
92
+ if (this.resources.has(instance)) callbacks.error(e.data);
93
+ else reject(e.data as Error);
94
+ });
95
+ });
86
96
  }
87
97
 
88
98
  unsubscribe(instance: string) {
@@ -100,3 +110,72 @@ export class SkipExternalService implements ExternalService {
100
110
  return Promise.resolve();
101
111
  }
102
112
  }
113
+
114
+ class LeaderResource implements Resource {
115
+ private collection: string;
116
+
117
+ constructor(param: Json) {
118
+ if (typeof param == "string") this.collection = param;
119
+ else
120
+ throw new SkipError(
121
+ "Followers must specify a shared collection to mirror from leader.",
122
+ );
123
+ }
124
+
125
+ instantiate(collections: NamedCollections): EagerCollection<Json, Json> {
126
+ if (this.collection in collections) return collections[this.collection]!;
127
+ throw new SkipError(
128
+ `Unknown shared collection in leader: ${this.collection}`,
129
+ );
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Run a `SkipService` as the *leader* in a leader-follower topology.
135
+ *
136
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
137
+ *
138
+ * @returns The *leader* component to run `service` in such a configuration.
139
+ */
140
+ export function asLeader(service: SkipService): SkipService {
141
+ //TODO: add mechanism to split externals between leader/follower
142
+ return {
143
+ ...service,
144
+ resources: { leader: LeaderResource },
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Run a `SkipService` as a *follower* in a leader-follower topology.
150
+ *
151
+ * Instead of running a `service` on one machine, it can be distributed across multiple in a leader-follower architecture, with one "leader" maintaining the shared computation graph and one or more "followers" across which client-requested resource instances are distributed.
152
+ *
153
+ * @returns The *follower* component to run `service` in such a configuration, given the leader's address and the names of the shared computation graph collections to be mirrored from it (typically the `ResourceInputs` of `service`).
154
+ */
155
+ export function asFollower(
156
+ service: SkipService,
157
+ leader: {
158
+ leader: { host: string; streaming_port: number; control_port: number };
159
+ collections: string[];
160
+ },
161
+ ): SkipService {
162
+ return {
163
+ ...service,
164
+ initialData: {},
165
+ externalServices: {
166
+ ...service.externalServices,
167
+ __skip_leader: SkipExternalService.direct(leader.leader),
168
+ },
169
+ createGraph(_inputs: object, context: Context): NamedCollections {
170
+ const mirroredCollections: NamedCollections = {};
171
+ for (const collection of leader.collections) {
172
+ mirroredCollections[collection] = context.useExternalResource({
173
+ service: "__skip_leader",
174
+ identifier: "leader",
175
+ params: collection,
176
+ });
177
+ }
178
+ return mirroredCollections;
179
+ },
180
+ };
181
+ }