@grest-ts/discovery-local 0.0.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.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/dist/src/index-node.d.ts +5 -0
  3. package/dist/src/index-node.d.ts.map +1 -0
  4. package/dist/src/index-node.js +5 -0
  5. package/dist/src/index-node.js.map +1 -0
  6. package/dist/src/local/GGDiscoveryIPC.d.ts +14 -0
  7. package/dist/src/local/GGDiscoveryIPC.d.ts.map +1 -0
  8. package/dist/src/local/GGDiscoveryIPC.js +9 -0
  9. package/dist/src/local/GGDiscoveryIPC.js.map +1 -0
  10. package/dist/src/local/GGLocalDiscoveryClient.d.ts +28 -0
  11. package/dist/src/local/GGLocalDiscoveryClient.d.ts.map +1 -0
  12. package/dist/src/local/GGLocalDiscoveryClient.js +77 -0
  13. package/dist/src/local/GGLocalDiscoveryClient.js.map +1 -0
  14. package/dist/src/local/GGLocalDiscoveryResilientClient.d.ts +15 -0
  15. package/dist/src/local/GGLocalDiscoveryResilientClient.d.ts.map +1 -0
  16. package/dist/src/local/GGLocalDiscoveryResilientClient.js +95 -0
  17. package/dist/src/local/GGLocalDiscoveryResilientClient.js.map +1 -0
  18. package/dist/src/local/GGLocalDiscoveryServer.d.ts +30 -0
  19. package/dist/src/local/GGLocalDiscoveryServer.d.ts.map +1 -0
  20. package/dist/src/local/GGLocalDiscoveryServer.js +123 -0
  21. package/dist/src/local/GGLocalDiscoveryServer.js.map +1 -0
  22. package/dist/src/local/routing/RoutingStrategy.d.ts +5 -0
  23. package/dist/src/local/routing/RoutingStrategy.d.ts.map +1 -0
  24. package/dist/src/local/routing/RoutingStrategy.js +2 -0
  25. package/dist/src/local/routing/RoutingStrategy.js.map +1 -0
  26. package/dist/src/local/routing/strategies/FirstStrategy.d.ts +9 -0
  27. package/dist/src/local/routing/strategies/FirstStrategy.d.ts.map +1 -0
  28. package/dist/src/local/routing/strategies/FirstStrategy.js +9 -0
  29. package/dist/src/local/routing/strategies/FirstStrategy.js.map +1 -0
  30. package/dist/src/local/routing/strategies/LastStrategy.d.ts +9 -0
  31. package/dist/src/local/routing/strategies/LastStrategy.d.ts.map +1 -0
  32. package/dist/src/local/routing/strategies/LastStrategy.js +9 -0
  33. package/dist/src/local/routing/strategies/LastStrategy.js.map +1 -0
  34. package/dist/src/local/routing/strategies/RandomStrategy.d.ts +9 -0
  35. package/dist/src/local/routing/strategies/RandomStrategy.d.ts.map +1 -0
  36. package/dist/src/local/routing/strategies/RandomStrategy.js +9 -0
  37. package/dist/src/local/routing/strategies/RandomStrategy.js.map +1 -0
  38. package/dist/src/local/routing/strategies/RoundRobinStrategy.d.ts +11 -0
  39. package/dist/src/local/routing/strategies/RoundRobinStrategy.d.ts.map +1 -0
  40. package/dist/src/local/routing/strategies/RoundRobinStrategy.js +14 -0
  41. package/dist/src/local/routing/strategies/RoundRobinStrategy.js.map +1 -0
  42. package/dist/src/tsconfig.json +16 -0
  43. package/dist/testkit/GGLocalRoutingStrategySelector.d.ts +12 -0
  44. package/dist/testkit/GGLocalRoutingStrategySelector.d.ts.map +1 -0
  45. package/dist/testkit/GGLocalRoutingStrategySelector.js +28 -0
  46. package/dist/testkit/GGLocalRoutingStrategySelector.js.map +1 -0
  47. package/dist/testkit/index-testkit.d.ts +2 -0
  48. package/dist/testkit/index-testkit.d.ts.map +1 -0
  49. package/dist/testkit/index-testkit.js +2 -0
  50. package/dist/testkit/index-testkit.js.map +1 -0
  51. package/dist/tsconfig.publish.tsbuildinfo +1 -0
  52. package/package.json +62 -0
  53. package/src/index-node.ts +4 -0
  54. package/src/local/GGDiscoveryIPC.ts +17 -0
  55. package/src/local/GGLocalDiscoveryClient.ts +94 -0
  56. package/src/local/GGLocalDiscoveryResilientClient.ts +104 -0
  57. package/src/local/GGLocalDiscoveryServer.ts +143 -0
  58. package/src/local/routing/RoutingStrategy.ts +7 -0
  59. package/src/local/routing/strategies/FirstStrategy.ts +11 -0
  60. package/src/local/routing/strategies/LastStrategy.ts +11 -0
  61. package/src/local/routing/strategies/RandomStrategy.ts +11 -0
  62. package/src/local/routing/strategies/RoundRobinStrategy.ts +17 -0
  63. package/src/tsconfig.json +16 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Grest Games OÜ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ export * from './local/GGLocalDiscoveryClient';
2
+ export * from './local/GGLocalDiscoveryServer';
3
+ export * from './local/routing/RoutingStrategy';
4
+ export * from './local/GGLocalDiscoveryResilientClient';
5
+ //# sourceMappingURL=index-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-node.d.ts","sourceRoot":"","sources":["../../src/index-node.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA"}
@@ -0,0 +1,5 @@
1
+ export * from './local/GGLocalDiscoveryClient.js';
2
+ export * from './local/GGLocalDiscoveryServer.js';
3
+ export * from './local/routing/RoutingStrategy.js';
4
+ export * from './local/GGLocalDiscoveryResilientClient.js';
5
+ //# sourceMappingURL=index-node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index-node.js","sourceRoot":"","sources":["../../src/index-node.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA"}
@@ -0,0 +1,14 @@
1
+ import { GGServiceDiscoveryEntry } from "./GGLocalDiscoveryClient";
2
+ export interface DiscoverApiResult {
3
+ success: boolean;
4
+ url?: string;
5
+ error?: string;
6
+ }
7
+ export declare const GGDiscoveryIPC: {
8
+ discoveryServer: {
9
+ register: import("@grest-ts/ipc").IPCServerRequest<GGServiceDiscoveryEntry[], void>;
10
+ unregister: import("@grest-ts/ipc").IPCServerRequest<GGServiceDiscoveryEntry[], void>;
11
+ discoverApi: import("@grest-ts/ipc").IPCServerRequest<string, DiscoverApiResult>;
12
+ };
13
+ };
14
+ //# sourceMappingURL=GGDiscoveryIPC.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGDiscoveryIPC.d.ts","sourceRoot":"","sources":["../../../src/local/GGDiscoveryIPC.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,uBAAuB,EAAC,MAAM,0BAA0B,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,cAAc;;;;;;CAM1B,CAAA"}
@@ -0,0 +1,9 @@
1
+ import { IPCServer } from "@grest-ts/ipc";
2
+ export const GGDiscoveryIPC = {
3
+ discoveryServer: {
4
+ register: IPCServer.defineRequest("discovery/register"),
5
+ unregister: IPCServer.defineRequest("discovery/unregister"),
6
+ discoverApi: IPCServer.defineRequest("discovery/discoverApi"),
7
+ }
8
+ };
9
+ //# sourceMappingURL=GGDiscoveryIPC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGDiscoveryIPC.js","sourceRoot":"","sources":["../../../src/local/GGDiscoveryIPC.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAUxC,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,eAAe,EAAE;QACb,QAAQ,EAAE,SAAS,CAAC,aAAa,CAAkC,oBAAoB,CAAC;QACxF,UAAU,EAAE,SAAS,CAAC,aAAa,CAAkC,sBAAsB,CAAC;QAC5F,WAAW,EAAE,SAAS,CAAC,aAAa,CAA4B,uBAAuB,CAAC;KAC3F;CACJ,CAAA"}
@@ -0,0 +1,28 @@
1
+ import { GGDiscoveryClient, GGServiceRegistration } from "@grest-ts/discovery";
2
+ import { IPCClient } from "@grest-ts/ipc";
3
+ /**
4
+ * ENV variable key when running in tests, for example - this would be PORT of the service discovery instance.
5
+ * If running in tests, the test itself also acts as a service discovery of sorts, allowing multiple instances to run in parallel.
6
+ */
7
+ export declare const GG_LOCAL_ROUTER_PORT = "GG_LOCAL_ROUTER_PORT";
8
+ export declare class GGLocalDiscoveryClient extends GGDiscoveryClient {
9
+ readonly isLocal = true;
10
+ readonly port: number;
11
+ protected readonly entries: GGServiceDiscoveryEntry[];
12
+ protected readonly client: IPCClient;
13
+ constructor(port?: number);
14
+ registerRoutes(registrations: GGServiceRegistration[]): void;
15
+ discoverApi(apiName: string): Promise<string>;
16
+ register(): Promise<void>;
17
+ unregister(): Promise<void>;
18
+ protected ensureConnected(): Promise<void>;
19
+ }
20
+ /**
21
+ * What consumers need to discover and connect to a service
22
+ */
23
+ export interface GGServiceDiscoveryEntry {
24
+ api: string;
25
+ baseUrl: string;
26
+ pathPrefix: string;
27
+ }
28
+ //# sourceMappingURL=GGLocalDiscoveryClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryClient.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAE,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAKxC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAE1D,qBAAa,sBAAuB,SAAQ,iBAAiB;IAEzD,SAAyB,OAAO,QAAQ;IACxC,SAAgB,IAAI,SAAC;IACrB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,EAAE,CAAM;IAC3D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;gBAEzB,IAAI,CAAC,EAAE,MAAM;IAgBlB,cAAc,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,IAAI;IAUtD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa7C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;cAWxB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAKnD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB"}
@@ -0,0 +1,77 @@
1
+ import { GG_DISCOVERY, GGDiscoveryClient } from "@grest-ts/discovery";
2
+ import { GGLog } from "@grest-ts/logger";
3
+ import { IPCClient } from "@grest-ts/ipc";
4
+ import { GGLocator, GGLocatorServiceType } from "@grest-ts/locator";
5
+ import { GGDiscoveryIPC } from "./GGDiscoveryIPC.js";
6
+ import { SERVER_ERROR } from "@grest-ts/schema";
7
+ /**
8
+ * ENV variable key when running in tests, for example - this would be PORT of the service discovery instance.
9
+ * If running in tests, the test itself also acts as a service discovery of sorts, allowing multiple instances to run in parallel.
10
+ */
11
+ export const GG_LOCAL_ROUTER_PORT = "GG_LOCAL_ROUTER_PORT";
12
+ export class GGLocalDiscoveryClient extends GGDiscoveryClient {
13
+ isLocal = true;
14
+ port;
15
+ entries = [];
16
+ client;
17
+ constructor(port) {
18
+ if (port === undefined) {
19
+ throw new Error("No port specified for local router");
20
+ }
21
+ super();
22
+ this.port = port;
23
+ this.client = new IPCClient(port);
24
+ GGLog.info(this, "Started on port: " + this.port);
25
+ GGLocator.getScope().setWithLifecycle(GG_DISCOVERY, this, {
26
+ type: GGLocatorServiceType.SERVICE_DISCOVERY,
27
+ start: () => this.register(),
28
+ teardown: () => this.unregister()
29
+ });
30
+ }
31
+ registerRoutes(registrations) {
32
+ for (const reg of registrations) {
33
+ this.entries.push({
34
+ api: reg.api,
35
+ baseUrl: `${reg.protocol}://localhost:${reg.port}`,
36
+ pathPrefix: reg.pathPrefix
37
+ });
38
+ }
39
+ }
40
+ async discoverApi(apiName) {
41
+ await this.ensureConnected();
42
+ const res = await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.discoverApi, apiName);
43
+ if (res.success && res.url) {
44
+ return res.url;
45
+ }
46
+ else {
47
+ throw new SERVER_ERROR({
48
+ displayMessage: res.error ?? "Unknown error",
49
+ debugData: { apiName }
50
+ });
51
+ }
52
+ }
53
+ async register() {
54
+ await this.ensureConnected();
55
+ if (this.entries.length > 0) {
56
+ await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.register, this.entries);
57
+ }
58
+ GGLog.info(this, `Registered ${this.entries.length} routes`);
59
+ }
60
+ async unregister() {
61
+ if (this.entries.length > 0 && this.client.isConnected()) {
62
+ try {
63
+ await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.unregister, this.entries);
64
+ }
65
+ catch (err) {
66
+ GGLog.error(this, err);
67
+ }
68
+ }
69
+ this.client.disconnect();
70
+ }
71
+ async ensureConnected() {
72
+ if (!this.client.isConnected()) {
73
+ await this.client.connect();
74
+ }
75
+ }
76
+ }
77
+ //# sourceMappingURL=GGLocalDiscoveryClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryClient.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,YAAY,EAAE,iBAAiB,EAAwB,MAAM,qBAAqB,CAAC;AAC3F,OAAO,EAAC,KAAK,EAAC,MAAM,kBAAkB,CAAC;AACvC,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AACxC,OAAO,EAAC,SAAS,EAAE,oBAAoB,EAAC,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,cAAc,EAAC,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAC,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAA;AAE1D,MAAM,OAAO,sBAAuB,SAAQ,iBAAiB;IAEhC,OAAO,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC;IACF,OAAO,GAA8B,EAAE,CAAC;IACxC,MAAM,CAAY;IAErC,YAAY,IAAa;QACrB,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACrB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QAC1D,CAAC;QACD,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;QAElD,SAAS,CAAC,QAAQ,EAAE,CAAC,gBAAgB,CAAC,YAAY,EAAE,IAAI,EAAE;YACtD,IAAI,EAAE,oBAAoB,CAAC,iBAAiB;YAC5C,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE;YAC5B,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE;SACpC,CAAC,CAAA;IACN,CAAC;IAEM,cAAc,CAAC,aAAsC;QACxD,KAAK,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;YAC9B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBACd,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO,EAAE,GAAG,GAAG,CAAC,QAAQ,gBAAgB,GAAG,CAAC,IAAI,EAAE;gBAClD,UAAU,EAAE,GAAG,CAAC,UAAU;aAC7B,CAAC,CAAC;QACP,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,OAAe;QACpC,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,eAAe,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACxG,IAAI,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC;YACzB,OAAO,GAAG,CAAC,GAAG,CAAC;QACnB,CAAC;aAAM,CAAC;YACJ,MAAM,IAAI,YAAY,CAAC;gBACnB,cAAc,EAAE,GAAG,CAAC,KAAK,IAAI,eAAe;gBAC5C,SAAS,EAAE,EAAC,OAAO,EAAC;aACvB,CAAC,CAAA;QACN,CAAC;IACL,CAAC;IAEM,KAAK,CAAC,QAAQ;QACjB,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAClG,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,IAAI,CAAC,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC;IACjE,CAAC;IAEM,KAAK,CAAC,UAAU;QACnB,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YACvD,IAAI,CAAC;gBACD,MAAM,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,cAAc,CAAC,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YACpG,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAChB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;IAES,KAAK,CAAC,eAAe;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAChC,CAAC;IACL,CAAC;CACJ"}
@@ -0,0 +1,15 @@
1
+ import { GGLocalDiscoveryClient } from "./GGLocalDiscoveryClient";
2
+ export declare class GGLocalDiscoveryResilientClient extends GGLocalDiscoveryClient {
3
+ private discoveryServer?;
4
+ private isLeader;
5
+ private isShuttingDown;
6
+ constructor(port?: number);
7
+ register(): Promise<void>;
8
+ unregister(): Promise<void>;
9
+ private becomeLeaderOrFollower;
10
+ private connectToLeader;
11
+ protected ensureConnected(): Promise<void>;
12
+ private delay;
13
+ private isConnectionError;
14
+ }
15
+ //# sourceMappingURL=GGLocalDiscoveryResilientClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryResilientClient.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryResilientClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAEhE,qBAAa,+BAAgC,SAAQ,sBAAsB;IAEvE,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;gBAEnB,IAAI,SAAO;IAID,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAUnC,sBAAsB;YAgBtB,eAAe;cAuBJ,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBzD,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,iBAAiB;CAQ5B"}
@@ -0,0 +1,95 @@
1
+ import { GGLog } from "@grest-ts/logger";
2
+ import { IPCServer } from "@grest-ts/ipc";
3
+ import { GGLocalDiscoveryServer } from "./GGLocalDiscoveryServer.js";
4
+ import { GGLocalDiscoveryClient } from "./GGLocalDiscoveryClient.js";
5
+ export class GGLocalDiscoveryResilientClient extends GGLocalDiscoveryClient {
6
+ discoveryServer;
7
+ isLeader = false;
8
+ isShuttingDown = false;
9
+ constructor(port = 9000) {
10
+ super(port);
11
+ }
12
+ async register() {
13
+ if (!this.isLeader && !this.discoveryServer && !this.client.isConnected()) {
14
+ await this.becomeLeaderOrFollower();
15
+ }
16
+ await super.register();
17
+ }
18
+ async unregister() {
19
+ this.isShuttingDown = true;
20
+ await super.unregister();
21
+ if (this.discoveryServer) {
22
+ await this.discoveryServer.teardown();
23
+ this.discoveryServer = undefined;
24
+ }
25
+ }
26
+ async becomeLeaderOrFollower() {
27
+ if (this.isShuttingDown)
28
+ return;
29
+ const server = new IPCServer(this.port);
30
+ const router = new GGLocalDiscoveryServer(server);
31
+ if (await router.start()) {
32
+ this.discoveryServer = router;
33
+ this.isLeader = true;
34
+ GGLog.info(this, "This instance is LEADER");
35
+ }
36
+ else {
37
+ this.isLeader = false;
38
+ GGLog.info(this, "This instance is FOLLOWER");
39
+ await this.connectToLeader();
40
+ }
41
+ }
42
+ async connectToLeader() {
43
+ if (this.isShuttingDown)
44
+ return;
45
+ try {
46
+ await this.client.connect();
47
+ this.client.onClose(async () => {
48
+ if (this.isShuttingDown)
49
+ return;
50
+ GGLog.warn(this, "Leader died");
51
+ await this.becomeLeaderOrFollower();
52
+ if (this.isLeader && this.entries.length > 0) {
53
+ await super.register();
54
+ }
55
+ });
56
+ GGLog.debug(this, "Connected to leader");
57
+ }
58
+ catch (err) {
59
+ GGLog.error(this, `Failed to connect to leader: ${err.message}`);
60
+ await this.delay(1000);
61
+ await this.connectToLeader();
62
+ }
63
+ }
64
+ async ensureConnected() {
65
+ const maxRetries = 20;
66
+ let retryCount = 0;
67
+ while (true) {
68
+ try {
69
+ await super.ensureConnected();
70
+ return;
71
+ }
72
+ catch (err) {
73
+ if (retryCount < maxRetries && this.isConnectionError(err)) {
74
+ GGLog.debug(this, `Waiting for router...`);
75
+ await this.delay(Math.min(500 * Math.pow(1.5, retryCount), 5000));
76
+ retryCount++;
77
+ continue;
78
+ }
79
+ throw err;
80
+ }
81
+ }
82
+ }
83
+ delay(ms) {
84
+ return new Promise(resolve => setTimeout(resolve, ms));
85
+ }
86
+ isConnectionError(err) {
87
+ const codes = ['ECONNREFUSED', 'ETIMEDOUT', 'ECONNRESET'];
88
+ const hasCode = (code) => code !== undefined && codes.includes(code);
89
+ return hasCode(err?.code) ||
90
+ hasCode(err?.cause?.code) ||
91
+ hasCode(err?.originalError?.code) ||
92
+ hasCode(err?.originalError?.cause?.code);
93
+ }
94
+ }
95
+ //# sourceMappingURL=GGLocalDiscoveryResilientClient.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryResilientClient.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryResilientClient.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { IPCServer } from "@grest-ts/ipc";
2
+ import { RoutingStrategy } from "./routing/RoutingStrategy";
3
+ import { FirstStrategy } from "./routing/strategies/FirstStrategy";
4
+ import { LastStrategy } from "./routing/strategies/LastStrategy";
5
+ import { RandomStrategy } from "./routing/strategies/RandomStrategy";
6
+ import { RoundRobinStrategy } from "./routing/strategies/RoundRobinStrategy";
7
+ import { GGServiceDiscoveryEntry } from "./GGLocalDiscoveryClient";
8
+ export declare const ROUTING_STRATEGIES: {
9
+ readonly first: FirstStrategy;
10
+ readonly last: LastStrategy;
11
+ readonly random: RandomStrategy;
12
+ readonly roundRobin: RoundRobinStrategy;
13
+ };
14
+ export type RoutingStrategyName = "first" | "last" | "roundRobin" | "random" | RoutingStrategy;
15
+ export declare class GGLocalDiscoveryServer {
16
+ private readonly server;
17
+ private readonly routes;
18
+ private readonly routingStrategies;
19
+ constructor(server: IPCServer);
20
+ start(): Promise<boolean>;
21
+ teardown(): Promise<void>;
22
+ setRoutingStrategy(api: string, strategy: RoutingStrategyName | RoutingStrategy): void;
23
+ private getRoutingStrategy;
24
+ getRoute(api: string): GGServiceDiscoveryEntry | undefined;
25
+ addRoute(route: GGServiceDiscoveryEntry): void;
26
+ removeRoute(api: string, baseUrl?: string): void;
27
+ getRoutingUrl(api: string): string;
28
+ private matchRoute;
29
+ }
30
+ //# sourceMappingURL=GGLocalDiscoveryServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryServer.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AACxC,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAC,aAAa,EAAC,MAAM,oCAAoC,CAAC;AACjE,OAAO,EAAC,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAC,kBAAkB,EAAC,MAAM,yCAAyC,CAAC;AAE3E,OAAO,EAAC,uBAAuB,EAAC,MAAM,0BAA0B,CAAC;AAEjE,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE/F,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqD;IAC5E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2C;gBAEjE,MAAM,EAAE,SAAS;IAwBhB,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAQzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe,GAAG,IAAI;IAM7F,OAAO,CAAC,kBAAkB;IAInB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAS1D,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAO9C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAqBhD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAUzC,OAAO,CAAC,UAAU;CAqBrB"}
@@ -0,0 +1,123 @@
1
+ import { GGLog } from "@grest-ts/logger";
2
+ import { FirstStrategy } from "./routing/strategies/FirstStrategy.js";
3
+ import { LastStrategy } from "./routing/strategies/LastStrategy.js";
4
+ import { RandomStrategy } from "./routing/strategies/RandomStrategy.js";
5
+ import { RoundRobinStrategy } from "./routing/strategies/RoundRobinStrategy.js";
6
+ import { GGDiscoveryIPC } from "./GGDiscoveryIPC.js";
7
+ export const ROUTING_STRATEGIES = {
8
+ first: new FirstStrategy(),
9
+ last: new LastStrategy(),
10
+ random: new RandomStrategy(),
11
+ roundRobin: new RoundRobinStrategy(),
12
+ };
13
+ export class GGLocalDiscoveryServer {
14
+ server;
15
+ routes = new Map();
16
+ routingStrategies = new Map();
17
+ constructor(server) {
18
+ this.server = server;
19
+ // Socket handlers for framework communication
20
+ this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.register, async (routes) => {
21
+ routes.forEach(route => this.addRoute(route));
22
+ });
23
+ this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.unregister, async (routes) => {
24
+ routes.forEach(route => this.removeRoute(route.api));
25
+ });
26
+ this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.discoverApi, async (apiName) => {
27
+ if (this.getRoute(apiName)) {
28
+ return { success: true, url: this.server.getUrl() };
29
+ }
30
+ return { success: false, error: "Service '" + apiName + "' is not registered! Did you forget to start it?" };
31
+ });
32
+ this.server.setRouteProxyResolver((path) => {
33
+ return this.matchRoute(path)?.baseUrl || undefined;
34
+ });
35
+ }
36
+ async start() {
37
+ const result = await this.server.start();
38
+ if (result) {
39
+ GGLog.info(this, `Router started on ${this.server.getUrl()}`);
40
+ }
41
+ return result;
42
+ }
43
+ async teardown() {
44
+ this.routes.clear();
45
+ this.routingStrategies.clear();
46
+ await this.server.teardown();
47
+ GGLog.info(this, 'Router stopped');
48
+ }
49
+ setRoutingStrategy(api, strategy) {
50
+ const strategyInstance = typeof strategy === 'string' ? ROUTING_STRATEGIES[strategy] : strategy;
51
+ this.routingStrategies.set(api, strategyInstance);
52
+ GGLog.debug(this, `Set routing strategy for ${api}: ${strategyInstance.constructor.name}`);
53
+ }
54
+ getRoutingStrategy(api) {
55
+ return this.routingStrategies.get(api) ?? ROUTING_STRATEGIES.roundRobin;
56
+ }
57
+ getRoute(api) {
58
+ const instances = this.routes.get(api);
59
+ if (!instances || instances.length === 0) {
60
+ return undefined;
61
+ }
62
+ const strategy = this.getRoutingStrategy(api);
63
+ return strategy.select(instances, api);
64
+ }
65
+ addRoute(route) {
66
+ const existing = this.routes.get(route.api) ?? [];
67
+ existing.push(route);
68
+ this.routes.set(route.api, existing);
69
+ GGLog.info(this, `Added route: ${route.pathPrefix} (${route.api}) -> ${route.baseUrl}`);
70
+ }
71
+ removeRoute(api, baseUrl) {
72
+ const instances = this.routes.get(api);
73
+ if (!instances)
74
+ return;
75
+ if (baseUrl) {
76
+ // Remove specific instance
77
+ const filtered = instances.filter(r => r.baseUrl !== baseUrl);
78
+ if (filtered.length === 0) {
79
+ this.routes.delete(api);
80
+ }
81
+ else {
82
+ this.routes.set(api, filtered);
83
+ }
84
+ GGLog.info(this, `Removed route instance: ${api} -> ${baseUrl}`);
85
+ }
86
+ else {
87
+ // Remove all instances for this API
88
+ const route = instances[0];
89
+ this.routes.delete(api);
90
+ GGLog.info(this, `Removed route: ${route?.pathPrefix} (${api})`);
91
+ }
92
+ }
93
+ getRoutingUrl(api) {
94
+ if (!this.getRoute(api)) {
95
+ throw new Error(`API '${api}' not registered in router`);
96
+ }
97
+ if (!this.server.getUrl()) {
98
+ throw new Error("Router not started yet!");
99
+ }
100
+ return this.server.getUrl();
101
+ }
102
+ matchRoute(path) {
103
+ let bestApi;
104
+ let longestMatch = 0;
105
+ // Find the best matching API based on path prefix
106
+ for (const [api, instances] of this.routes.entries()) {
107
+ if (instances.length === 0)
108
+ continue;
109
+ const pathPrefix = instances[0].pathPrefix;
110
+ if (path.startsWith(pathPrefix) && pathPrefix.length > longestMatch) {
111
+ bestApi = api;
112
+ longestMatch = pathPrefix.length;
113
+ }
114
+ }
115
+ if (!bestApi)
116
+ return undefined;
117
+ // Use routing strategy to select which instance, passing the full path
118
+ const instances = this.routes.get(bestApi);
119
+ const strategy = this.getRoutingStrategy(bestApi);
120
+ return strategy.select(instances, path);
121
+ }
122
+ }
123
+ //# sourceMappingURL=GGLocalDiscoveryServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GGLocalDiscoveryServer.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { GGServiceDiscoveryEntry } from "../GGLocalDiscoveryClient";
2
+ export interface RoutingStrategy {
3
+ select(instances: GGServiceDiscoveryEntry[], path: string): GGServiceDiscoveryEntry;
4
+ }
5
+ //# sourceMappingURL=RoutingStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoutingStrategy.d.ts","sourceRoot":"","sources":["../../../../src/local/routing/RoutingStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,uBAAuB,EAAC,MAAM,2BAA2B,CAAC;AAElE,MAAM,WAAW,eAAe;IAE5B,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAAC;CACvF"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=RoutingStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoutingStrategy.js","sourceRoot":"","sources":["../../../../src/local/routing/RoutingStrategy.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ import { RoutingStrategy } from "../RoutingStrategy";
2
+ import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
3
+ /**
4
+ * Always route to the first registered instance.
5
+ */
6
+ export declare class FirstStrategy implements RoutingStrategy {
7
+ select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
8
+ }
9
+ //# sourceMappingURL=FirstStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FirstStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/FirstStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,aAAc,YAAW,eAAe;IACjD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Always route to the first registered instance.
3
+ */
4
+ export class FirstStrategy {
5
+ select(instances) {
6
+ return instances[0];
7
+ }
8
+ }
9
+ //# sourceMappingURL=FirstStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FirstStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/FirstStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,aAAa;IACtB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;CACJ"}
@@ -0,0 +1,9 @@
1
+ import { RoutingStrategy } from "../RoutingStrategy";
2
+ import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
3
+ /**
4
+ * Always route to the last registered instance.
5
+ */
6
+ export declare class LastStrategy implements RoutingStrategy {
7
+ select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
8
+ }
9
+ //# sourceMappingURL=LastStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LastStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/LastStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,YAAa,YAAW,eAAe;IAChD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Always route to the last registered instance.
3
+ */
4
+ export class LastStrategy {
5
+ select(instances) {
6
+ return instances[instances.length - 1];
7
+ }
8
+ }
9
+ //# sourceMappingURL=LastStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LastStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/LastStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,YAAY;IACrB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;CACJ"}
@@ -0,0 +1,9 @@
1
+ import { RoutingStrategy } from "../RoutingStrategy";
2
+ import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
3
+ /**
4
+ * Randomly select an instance for each request.
5
+ */
6
+ export declare class RandomStrategy implements RoutingStrategy {
7
+ select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
8
+ }
9
+ //# sourceMappingURL=RandomStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RandomStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RandomStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IAClD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Randomly select an instance for each request.
3
+ */
4
+ export class RandomStrategy {
5
+ select(instances) {
6
+ return instances[Math.floor(Math.random() * instances.length)];
7
+ }
8
+ }
9
+ //# sourceMappingURL=RandomStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RandomStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RandomStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,cAAc;IACvB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;CACJ"}
@@ -0,0 +1,11 @@
1
+ import { RoutingStrategy } from "../RoutingStrategy";
2
+ import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
3
+ /**
4
+ * Cycle through instances in order, per path.
5
+ * Each unique path maintains its own counter.
6
+ */
7
+ export declare class RoundRobinStrategy implements RoutingStrategy {
8
+ private readonly counters;
9
+ select(instances: GGServiceDiscoveryEntry[], path: string): GGServiceDiscoveryEntry;
10
+ }
11
+ //# sourceMappingURL=RoundRobinStrategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoundRobinStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RoundRobinStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,uBAAuB;CAMtF"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cycle through instances in order, per path.
3
+ * Each unique path maintains its own counter.
4
+ */
5
+ export class RoundRobinStrategy {
6
+ counters = new Map();
7
+ select(instances, path) {
8
+ const counter = this.counters.get(path) ?? 0;
9
+ const instance = instances[counter % instances.length];
10
+ this.counters.set(path, counter + 1);
11
+ return instance;
12
+ }
13
+ }
14
+ //# sourceMappingURL=RoundRobinStrategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RoundRobinStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RoundRobinStrategy.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACV,QAAQ,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE3D,MAAM,CAAC,SAAoC,EAAE,IAAY;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;QACrC,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ"}