@masons/agent-network 0.5.29 → 0.5.30
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/broker/broker-daemon.d.ts +13 -3
- package/dist/broker/broker-daemon.d.ts.map +1 -1
- package/dist/broker/broker-daemon.js +294 -52
- package/dist/broker/closed-endpoint-lookup.d.ts +25 -0
- package/dist/broker/closed-endpoint-lookup.d.ts.map +1 -0
- package/dist/broker/closed-endpoint-lookup.js +59 -0
- package/dist/broker/control-event-dispatcher.d.ts +20 -0
- package/dist/broker/control-event-dispatcher.d.ts.map +1 -0
- package/dist/broker/control-event-dispatcher.js +45 -0
- package/dist/broker/control-event-types.d.ts +30 -0
- package/dist/broker/control-event-types.d.ts.map +1 -0
- package/dist/broker/control-event-types.js +1 -0
- package/dist/broker/endpoint-registry.d.ts +17 -1
- package/dist/broker/endpoint-registry.d.ts.map +1 -1
- package/dist/broker/endpoint-registry.js +39 -0
- package/dist/broker/endpoint-state-machine.d.ts +40 -0
- package/dist/broker/endpoint-state-machine.d.ts.map +1 -0
- package/dist/broker/endpoint-state-machine.js +92 -0
- package/dist/broker/entry.d.ts +3 -0
- package/dist/broker/entry.d.ts.map +1 -1
- package/dist/broker/entry.js +41 -3
- package/dist/broker/grace-timer.d.ts +9 -0
- package/dist/broker/grace-timer.d.ts.map +1 -0
- package/dist/broker/grace-timer.js +34 -0
- package/dist/broker/ipc-server.d.ts +8 -1
- package/dist/broker/ipc-server.d.ts.map +1 -1
- package/dist/broker/ipc-server.js +31 -0
- package/dist/broker/paths.d.ts +1 -0
- package/dist/broker/paths.d.ts.map +1 -1
- package/dist/broker/paths.js +2 -0
- package/dist/broker/plugin-liveness.d.ts +2 -0
- package/dist/broker/plugin-liveness.d.ts.map +1 -0
- package/dist/broker/plugin-liveness.js +15 -0
- package/dist/broker/reconnecting-buffer.d.ts +23 -0
- package/dist/broker/reconnecting-buffer.d.ts.map +1 -0
- package/dist/broker/reconnecting-buffer.js +107 -0
- package/dist/broker/routing-table.d.ts.map +1 -1
- package/dist/broker/routing-table.js +1 -1
- package/dist/broker/runtime-endpoint-port.d.ts +2 -1
- package/dist/broker/runtime-endpoint-port.d.ts.map +1 -1
- package/dist/broker/undispatched-inbox.d.ts +26 -0
- package/dist/broker/undispatched-inbox.d.ts.map +1 -0
- package/dist/broker/undispatched-inbox.js +53 -0
- package/dist/runtime-endpoint-client.d.ts +7 -0
- package/dist/runtime-endpoint-client.d.ts.map +1 -1
- package/dist/runtime-endpoint-client.js +11 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-event-types.d.ts","sourceRoot":"","sources":["../../src/broker/control-event-types.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,YAAY,GACpB,yBAAyB,GACzB,iBAAiB,GACjB,oBAAoB,CAAC;AAGzB,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,uBAAuB,CAAC;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAGD,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC;CAC1B;AAGD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,CAAC,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,UAAU;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -13,8 +13,9 @@ export interface BrokerEndpointEntry {
|
|
|
13
13
|
agent_id: string;
|
|
14
14
|
plugin_pid: number;
|
|
15
15
|
ipc_ws: WebSocket;
|
|
16
|
-
state: "active";
|
|
16
|
+
state: "active" | "reconnecting";
|
|
17
17
|
state_since: Date;
|
|
18
|
+
grace_deadline?: Date;
|
|
18
19
|
display_metadata: DisplayMetadata;
|
|
19
20
|
correlation_ring: CorrelationRingBuffer;
|
|
20
21
|
}
|
|
@@ -30,7 +31,22 @@ export declare class EndpointRegistry {
|
|
|
30
31
|
register(args: RegisterArgs): BrokerEndpointEntry;
|
|
31
32
|
get(endpoint_id: string): BrokerEndpointEntry | undefined;
|
|
32
33
|
unregister(endpoint_id: string): BrokerEndpointEntry | undefined;
|
|
34
|
+
markReconnecting(endpoint_id: string, grace_deadline: Date): BrokerEndpointEntry;
|
|
35
|
+
markActive(endpoint_id: string, new_ws: WebSocket): BrokerEndpointEntry;
|
|
33
36
|
preconditionForReattach(endpoint_id: string, plugin_pid: number): BrokerEndpointEntry | undefined;
|
|
37
|
+
getReattachStatus(endpoint_id: string, plugin_pid: number): {
|
|
38
|
+
ok: true;
|
|
39
|
+
entry: BrokerEndpointEntry;
|
|
40
|
+
} | {
|
|
41
|
+
ok: false;
|
|
42
|
+
reason: "endpoint_unknown";
|
|
43
|
+
} | {
|
|
44
|
+
ok: false;
|
|
45
|
+
reason: "reattach_pid_mismatch";
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
reason: "endpoint_not_reconnecting";
|
|
49
|
+
};
|
|
34
50
|
list(): BrokerEndpointEntry[];
|
|
35
51
|
size(): number;
|
|
36
52
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint-registry.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"endpoint-registry.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-registry.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,SAAS,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG9D,MAAM,WAAW,eAAe;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,cAAc,CAAC;IACjC,WAAW,EAAE,IAAI,CAAC;IAElB,cAAc,CAAC,EAAE,IAAI,CAAC;IACtB,gBAAgB,EAAE,eAAe,CAAC;IAClC,gBAAgB,EAAE,qBAAqB,CAAC;CACzC;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,CAAC;IAClB,gBAAgB,EAAE,eAAe,CAAC;CACnC;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0C;IAG/D,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,mBAAmB;IAkBjD,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAKzD,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAWhE,gBAAgB,CACd,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,IAAI,GACnB,mBAAmB;IAoBtB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,mBAAmB;IA8BvE,uBAAuB,CACrB,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,mBAAmB,GAAG,SAAS;IAYlC,iBAAiB,CACf,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAEhB;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,mBAAmB,CAAA;KAAE,GACxC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAA;KAAE,GACzC;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,uBAAuB,CAAA;KAAE,GAC9C;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,2BAA2B,CAAA;KAAE;IAWtD,IAAI,IAAI,mBAAmB,EAAE;IAK7B,IAAI,IAAI,MAAM;CAGf"}
|
|
@@ -27,14 +27,53 @@ export class EndpointRegistry {
|
|
|
27
27
|
this.byId.delete(endpoint_id);
|
|
28
28
|
return entry;
|
|
29
29
|
}
|
|
30
|
+
markReconnecting(endpoint_id, grace_deadline) {
|
|
31
|
+
const entry = this.byId.get(endpoint_id);
|
|
32
|
+
if (!entry) {
|
|
33
|
+
throw new Error(`unknown endpoint_id: ${endpoint_id}`);
|
|
34
|
+
}
|
|
35
|
+
if (entry.state !== "active") {
|
|
36
|
+
throw new Error(`markReconnecting requires state=active, got state=${entry.state}`);
|
|
37
|
+
}
|
|
38
|
+
entry.state = "reconnecting";
|
|
39
|
+
entry.state_since = new Date();
|
|
40
|
+
entry.grace_deadline = grace_deadline;
|
|
41
|
+
return entry;
|
|
42
|
+
}
|
|
43
|
+
markActive(endpoint_id, new_ws) {
|
|
44
|
+
const entry = this.byId.get(endpoint_id);
|
|
45
|
+
if (!entry) {
|
|
46
|
+
throw new Error(`unknown endpoint_id: ${endpoint_id}`);
|
|
47
|
+
}
|
|
48
|
+
if (entry.state !== "reconnecting") {
|
|
49
|
+
throw new Error(`markActive requires state=reconnecting, got state=${entry.state}`);
|
|
50
|
+
}
|
|
51
|
+
entry.state = "active";
|
|
52
|
+
entry.state_since = new Date();
|
|
53
|
+
entry.grace_deadline = undefined;
|
|
54
|
+
entry.ipc_ws = new_ws;
|
|
55
|
+
return entry;
|
|
56
|
+
}
|
|
30
57
|
preconditionForReattach(endpoint_id, plugin_pid) {
|
|
31
58
|
const entry = this.byId.get(endpoint_id);
|
|
32
59
|
if (!entry)
|
|
33
60
|
return undefined;
|
|
34
61
|
if (entry.plugin_pid !== plugin_pid)
|
|
35
62
|
return undefined;
|
|
63
|
+
if (entry.state !== "reconnecting")
|
|
64
|
+
return undefined;
|
|
36
65
|
return entry;
|
|
37
66
|
}
|
|
67
|
+
getReattachStatus(endpoint_id, plugin_pid) {
|
|
68
|
+
const entry = this.byId.get(endpoint_id);
|
|
69
|
+
if (!entry)
|
|
70
|
+
return { ok: false, reason: "endpoint_unknown" };
|
|
71
|
+
if (entry.plugin_pid !== plugin_pid)
|
|
72
|
+
return { ok: false, reason: "reattach_pid_mismatch" };
|
|
73
|
+
if (entry.state !== "reconnecting")
|
|
74
|
+
return { ok: false, reason: "endpoint_not_reconnecting" };
|
|
75
|
+
return { ok: true, entry };
|
|
76
|
+
}
|
|
38
77
|
list() {
|
|
39
78
|
return Array.from(this.byId.values());
|
|
40
79
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const DEFAULT_GRACE_MS: number;
|
|
2
|
+
export type EndpointState = "active" | "reconnecting" | "closed";
|
|
3
|
+
export type TransitionEvent = {
|
|
4
|
+
type: "register";
|
|
5
|
+
} | {
|
|
6
|
+
type: "ipc_close";
|
|
7
|
+
plugin_alive: boolean;
|
|
8
|
+
} | {
|
|
9
|
+
type: "reattach";
|
|
10
|
+
} | {
|
|
11
|
+
type: "grace_expired";
|
|
12
|
+
} | {
|
|
13
|
+
type: "explicit_unregister";
|
|
14
|
+
};
|
|
15
|
+
export type TransitionEffect = {
|
|
16
|
+
type: "start_grace_timer";
|
|
17
|
+
deadline_ms: number;
|
|
18
|
+
} | {
|
|
19
|
+
type: "cancel_grace_timer";
|
|
20
|
+
} | {
|
|
21
|
+
type: "emit_state";
|
|
22
|
+
state: EndpointState;
|
|
23
|
+
reason: string;
|
|
24
|
+
} | {
|
|
25
|
+
type: "drain_buffer";
|
|
26
|
+
} | {
|
|
27
|
+
type: "remove_from_registry";
|
|
28
|
+
} | {
|
|
29
|
+
type: "delete_buffer";
|
|
30
|
+
};
|
|
31
|
+
export interface TransitionResult {
|
|
32
|
+
next: EndpointState;
|
|
33
|
+
effects: readonly TransitionEffect[];
|
|
34
|
+
ignored?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export interface TransitionOptions {
|
|
37
|
+
graceMs?: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function transition(current: EndpointState, event: TransitionEvent, opts?: TransitionOptions): TransitionResult;
|
|
40
|
+
//# sourceMappingURL=endpoint-state-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-state-machine.d.ts","sourceRoot":"","sources":["../../src/broker/endpoint-state-machine.ts"],"names":[],"mappings":"AA2BA,eAAO,MAAM,gBAAgB,QAAiB,CAAC;AAE/C,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,cAAc,GAAG,QAAQ,CAAC;AAEjE,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAOpB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,GAE5C;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GAEpB;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,GAEzB;IAAE,IAAI,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEpC,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAMrC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IAEhC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,UAAU,CACxB,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE,iBAAsB,GAC3B,gBAAgB,CAiGlB"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export const DEFAULT_GRACE_MS = 10 * 60 * 1000;
|
|
2
|
+
export function transition(current, event, opts = {}) {
|
|
3
|
+
const graceMs = opts.graceMs ?? DEFAULT_GRACE_MS;
|
|
4
|
+
switch (current) {
|
|
5
|
+
case "active": {
|
|
6
|
+
switch (event.type) {
|
|
7
|
+
case "ipc_close":
|
|
8
|
+
if (event.plugin_alive) {
|
|
9
|
+
return {
|
|
10
|
+
next: "reconnecting",
|
|
11
|
+
effects: [
|
|
12
|
+
{ type: "start_grace_timer", deadline_ms: graceMs },
|
|
13
|
+
{
|
|
14
|
+
type: "emit_state",
|
|
15
|
+
state: "reconnecting",
|
|
16
|
+
reason: "ipc_close",
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
next: "closed",
|
|
23
|
+
effects: [
|
|
24
|
+
{ type: "emit_state", state: "closed", reason: "plugin_exit" },
|
|
25
|
+
{ type: "delete_buffer" },
|
|
26
|
+
{ type: "remove_from_registry" },
|
|
27
|
+
],
|
|
28
|
+
};
|
|
29
|
+
case "explicit_unregister":
|
|
30
|
+
return {
|
|
31
|
+
next: "closed",
|
|
32
|
+
effects: [
|
|
33
|
+
{
|
|
34
|
+
type: "emit_state",
|
|
35
|
+
state: "closed",
|
|
36
|
+
reason: "explicit_unregister",
|
|
37
|
+
},
|
|
38
|
+
{ type: "delete_buffer" },
|
|
39
|
+
{ type: "remove_from_registry" },
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
case "register":
|
|
43
|
+
case "reattach":
|
|
44
|
+
case "grace_expired":
|
|
45
|
+
return { next: "active", effects: [], ignored: true };
|
|
46
|
+
}
|
|
47
|
+
return { next: current, effects: [], ignored: true };
|
|
48
|
+
}
|
|
49
|
+
case "reconnecting": {
|
|
50
|
+
switch (event.type) {
|
|
51
|
+
case "reattach":
|
|
52
|
+
return {
|
|
53
|
+
next: "active",
|
|
54
|
+
effects: [
|
|
55
|
+
{ type: "cancel_grace_timer" },
|
|
56
|
+
{ type: "drain_buffer" },
|
|
57
|
+
{ type: "emit_state", state: "active", reason: "reattach" },
|
|
58
|
+
],
|
|
59
|
+
};
|
|
60
|
+
case "grace_expired":
|
|
61
|
+
return {
|
|
62
|
+
next: "closed",
|
|
63
|
+
effects: [
|
|
64
|
+
{ type: "emit_state", state: "closed", reason: "grace_timeout" },
|
|
65
|
+
{ type: "delete_buffer" },
|
|
66
|
+
{ type: "remove_from_registry" },
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
case "explicit_unregister":
|
|
70
|
+
return {
|
|
71
|
+
next: "closed",
|
|
72
|
+
effects: [
|
|
73
|
+
{ type: "cancel_grace_timer" },
|
|
74
|
+
{
|
|
75
|
+
type: "emit_state",
|
|
76
|
+
state: "closed",
|
|
77
|
+
reason: "explicit_unregister",
|
|
78
|
+
},
|
|
79
|
+
{ type: "delete_buffer" },
|
|
80
|
+
{ type: "remove_from_registry" },
|
|
81
|
+
],
|
|
82
|
+
};
|
|
83
|
+
case "ipc_close":
|
|
84
|
+
case "register":
|
|
85
|
+
return { next: "reconnecting", effects: [], ignored: true };
|
|
86
|
+
}
|
|
87
|
+
return { next: current, effects: [], ignored: true };
|
|
88
|
+
}
|
|
89
|
+
case "closed":
|
|
90
|
+
return { next: "closed", effects: [], ignored: true };
|
|
91
|
+
}
|
|
92
|
+
}
|
package/dist/broker/entry.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
import { type BrokerLogger } from "./logger.js";
|
|
2
|
+
import type { RuntimeEndpointPort } from "./runtime-endpoint-port.js";
|
|
3
|
+
export declare function buildApiPort(apiHost: string, runtimeKey: string, logger: BrokerLogger): RuntimeEndpointPort;
|
|
1
4
|
export declare function main(): Promise<void>;
|
|
2
5
|
//# sourceMappingURL=entry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/broker/entry.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAE,KAAK,YAAY,EAAsB,MAAM,aAAa,CAAC;AAEpE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAsDtE,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,YAAY,GACnB,mBAAmB,CAkErB;AAYD,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAgD1C"}
|
package/dist/broker/entry.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { pathToFileURL } from "node:url";
|
|
2
2
|
import { readConfig } from "../config-fs.js";
|
|
3
3
|
import { DEFAULT_API_HOST } from "../platform-client.js";
|
|
4
|
-
import { heartbeatRuntimeEndpoint, registerRuntimeEndpoint, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
|
|
4
|
+
import { heartbeatRuntimeEndpoint, registerRuntimeEndpoint, transitionRuntimeEndpointState, unregisterRuntimeEndpoint, } from "../runtime-endpoint-client.js";
|
|
5
5
|
import { startBrokerDaemon } from "./broker-daemon.js";
|
|
6
6
|
import { ConnectorWS } from "./connector-ws.js";
|
|
7
7
|
import { createBrokerLogger } from "./logger.js";
|
|
@@ -23,7 +23,7 @@ async function resolveCredentials(accountId, envApiHost) {
|
|
|
23
23
|
}
|
|
24
24
|
return { accountId, connectorUrl, token, apiHost };
|
|
25
25
|
}
|
|
26
|
-
function buildApiPort(apiHost, runtimeKey) {
|
|
26
|
+
export function buildApiPort(apiHost, runtimeKey, logger) {
|
|
27
27
|
return {
|
|
28
28
|
async register(params) {
|
|
29
29
|
return registerRuntimeEndpoint({ apiHost }, runtimeKey, params);
|
|
@@ -34,8 +34,46 @@ function buildApiPort(apiHost, runtimeKey) {
|
|
|
34
34
|
async unregister(endpointId, asNodeId) {
|
|
35
35
|
await unregisterRuntimeEndpoint({ apiHost }, runtimeKey, endpointId, asNodeId);
|
|
36
36
|
},
|
|
37
|
+
async transitionState(endpointId, params) {
|
|
38
|
+
try {
|
|
39
|
+
await transitionRuntimeEndpointState({ apiHost }, runtimeKey, endpointId, params);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
const status = errorStatus(err);
|
|
43
|
+
if (status === 404) {
|
|
44
|
+
logger.info("transitionState_404_degraded", {
|
|
45
|
+
endpoint_id: endpointId,
|
|
46
|
+
state: params.state,
|
|
47
|
+
reason: params.reason,
|
|
48
|
+
note: "apps/api state endpoint not yet shipped (PR-B1 in flight); state propagation skipped",
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
await sleep(500);
|
|
53
|
+
try {
|
|
54
|
+
await transitionRuntimeEndpointState({ apiHost }, runtimeKey, endpointId, params);
|
|
55
|
+
}
|
|
56
|
+
catch (err2) {
|
|
57
|
+
logger.warn("transitionState_failed", {
|
|
58
|
+
endpoint_id: endpointId,
|
|
59
|
+
state: params.state,
|
|
60
|
+
reason: params.reason,
|
|
61
|
+
err: err2 instanceof Error ? err2.message : String(err2),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
37
66
|
};
|
|
38
67
|
}
|
|
68
|
+
function errorStatus(err) {
|
|
69
|
+
if (typeof err !== "object" || err === null)
|
|
70
|
+
return null;
|
|
71
|
+
const status = err.status;
|
|
72
|
+
return typeof status === "number" ? status : null;
|
|
73
|
+
}
|
|
74
|
+
function sleep(ms) {
|
|
75
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
76
|
+
}
|
|
39
77
|
export async function main() {
|
|
40
78
|
const accountId = process.env.MASONS_BROKER_ACCOUNT_ID ?? DEFAULT_ACCOUNT_ID;
|
|
41
79
|
const envApiHost = process.env.MASONS_BROKER_API_HOST;
|
|
@@ -55,7 +93,7 @@ export async function main() {
|
|
|
55
93
|
url: creds.connectorUrl,
|
|
56
94
|
token: creds.token,
|
|
57
95
|
});
|
|
58
|
-
const apiPort = buildApiPort(creds.apiHost, creds.token);
|
|
96
|
+
const apiPort = buildApiPort(creds.apiHost, creds.token, logger);
|
|
59
97
|
const broker = await startBrokerDaemon({
|
|
60
98
|
paths,
|
|
61
99
|
asNodeId,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface GraceTimerManager {
|
|
2
|
+
start(endpoint_id: string, ms: number, onExpire: () => void): void;
|
|
3
|
+
cancel(endpoint_id: string): void;
|
|
4
|
+
has(endpoint_id: string): boolean;
|
|
5
|
+
cancelAll(): void;
|
|
6
|
+
active(): readonly string[];
|
|
7
|
+
}
|
|
8
|
+
export declare function createGraceTimerManager(): GraceTimerManager;
|
|
9
|
+
//# sourceMappingURL=grace-timer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grace-timer.d.ts","sourceRoot":"","sources":["../../src/broker/grace-timer.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,iBAAiB;IAGhC,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAEnE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAElC,SAAS,IAAI,IAAI,CAAC;IAElB,MAAM,IAAI,SAAS,MAAM,EAAE,CAAC;CAC7B;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAmC3D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export function createGraceTimerManager() {
|
|
2
|
+
const timers = new Map();
|
|
3
|
+
return {
|
|
4
|
+
start(endpoint_id, ms, onExpire) {
|
|
5
|
+
const existing = timers.get(endpoint_id);
|
|
6
|
+
if (existing)
|
|
7
|
+
clearTimeout(existing);
|
|
8
|
+
const handle = setTimeout(() => {
|
|
9
|
+
timers.delete(endpoint_id);
|
|
10
|
+
onExpire();
|
|
11
|
+
}, ms);
|
|
12
|
+
handle.unref?.();
|
|
13
|
+
timers.set(endpoint_id, handle);
|
|
14
|
+
},
|
|
15
|
+
cancel(endpoint_id) {
|
|
16
|
+
const handle = timers.get(endpoint_id);
|
|
17
|
+
if (handle) {
|
|
18
|
+
clearTimeout(handle);
|
|
19
|
+
timers.delete(endpoint_id);
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
has(endpoint_id) {
|
|
23
|
+
return timers.has(endpoint_id);
|
|
24
|
+
},
|
|
25
|
+
cancelAll() {
|
|
26
|
+
for (const [, handle] of timers)
|
|
27
|
+
clearTimeout(handle);
|
|
28
|
+
timers.clear();
|
|
29
|
+
},
|
|
30
|
+
active() {
|
|
31
|
+
return Array.from(timers.keys());
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -5,8 +5,15 @@ export interface IPCServerHandlers {
|
|
|
5
5
|
heartbeatEndpoint(endpoint_id: string): Promise<void>;
|
|
6
6
|
unregisterEndpoint(endpoint_id: string): Promise<void>;
|
|
7
7
|
send(body: SendBody): Promise<SendResponse>;
|
|
8
|
-
reattachEndpoint(endpoint_id: string, plugin_pid: number, ipcWs: WebSocket): Promise<
|
|
8
|
+
reattachEndpoint(endpoint_id: string, plugin_pid: number, ipcWs: WebSocket): Promise<ReattachResponse>;
|
|
9
|
+
listUndispatched(): Promise<UndispatchedListResponse>;
|
|
10
|
+
dispatch(undispatched_id: string, target_endpoint_id: string): Promise<void>;
|
|
9
11
|
}
|
|
12
|
+
export interface ReattachResponse {
|
|
13
|
+
restored: true;
|
|
14
|
+
reconnecting_buffer_count: number;
|
|
15
|
+
}
|
|
16
|
+
export type UndispatchedListResponse = import("./undispatched-inbox.js").UndispatchedMessage[];
|
|
10
17
|
export interface RegisterEndpointBody {
|
|
11
18
|
agent_id: string;
|
|
12
19
|
plugin_pid: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,KAAK,OAAO,EAAE,SAAS,EAAmB,MAAM,IAAI,CAAC;AAE9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQhD,MAAM,WAAW,iBAAiB;IAEhC,gBAAgB,CACd,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAErC,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtD,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvD,IAAI,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ipc-server.d.ts","sourceRoot":"","sources":["../../src/broker/ipc-server.ts"],"names":[],"mappings":"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"}
|
|
@@ -94,6 +94,17 @@ async function routeHttp(req, res, bearerToken, handlers, logger) {
|
|
|
94
94
|
sendJson(res, 200, { ok: true });
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
|
+
const reattachMatch = /^\/v1\/endpoint\/([^/]+)\/reattach$/.exec(url);
|
|
98
|
+
if (method === "POST" && reattachMatch && reattachMatch[1]) {
|
|
99
|
+
const body = await readJson(req);
|
|
100
|
+
const pid = typeof body.plugin_pid === "number" ? body.plugin_pid : Number.NaN;
|
|
101
|
+
if (!Number.isFinite(pid) || pid <= 0) {
|
|
102
|
+
throw new BrokerHttpError(400, "plugin_pid_invalid", "plugin_pid is required and must be a positive number");
|
|
103
|
+
}
|
|
104
|
+
const out = await handlers.reattachEndpoint(decodeURIComponent(reattachMatch[1]), pid, null);
|
|
105
|
+
sendJson(res, 200, out);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
97
108
|
const unregisterMatch = /^\/v1\/endpoint\/([^/]+)$/.exec(url);
|
|
98
109
|
if (method === "DELETE" && unregisterMatch && unregisterMatch[1]) {
|
|
99
110
|
await handlers.unregisterEndpoint(decodeURIComponent(unregisterMatch[1]));
|
|
@@ -106,6 +117,26 @@ async function routeHttp(req, res, bearerToken, handlers, logger) {
|
|
|
106
117
|
sendJson(res, 200, out);
|
|
107
118
|
return;
|
|
108
119
|
}
|
|
120
|
+
if (method === "GET" && url === "/v1/undispatched") {
|
|
121
|
+
const items = await handlers.listUndispatched();
|
|
122
|
+
sendJson(res, 200, { items });
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (method === "POST" && url === "/v1/dispatch") {
|
|
126
|
+
const body = await readJson(req);
|
|
127
|
+
const uid = typeof body.undispatched_id === "string"
|
|
128
|
+
? body.undispatched_id
|
|
129
|
+
: undefined;
|
|
130
|
+
const tid = typeof body.target_endpoint_id === "string"
|
|
131
|
+
? body.target_endpoint_id
|
|
132
|
+
: undefined;
|
|
133
|
+
if (!uid || !tid) {
|
|
134
|
+
throw new BrokerHttpError(400, "dispatch_body_invalid", "POST /v1/dispatch requires { undispatched_id, target_endpoint_id }");
|
|
135
|
+
}
|
|
136
|
+
await handlers.dispatch(uid, tid);
|
|
137
|
+
sendJson(res, 200, { ok: true });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
109
140
|
sendJson(res, 404, { error: "not_found", path: url });
|
|
110
141
|
}
|
|
111
142
|
catch (err) {
|
package/dist/broker/paths.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface BrokerPaths {
|
|
|
5
5
|
discoveryFile: string;
|
|
6
6
|
discoveryDir: string;
|
|
7
7
|
logDir: string;
|
|
8
|
+
buffersDir: string;
|
|
8
9
|
}
|
|
9
10
|
export declare function resolveBrokerPaths(principal: string, runtimeToken: string, opts?: BrokerPathOptions): BrokerPaths;
|
|
10
11
|
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/broker/paths.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAE1B,aAAa,EAAE,MAAM,CAAC;IAEtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/broker/paths.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iBAAiB;IAEhC,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAE1B,aAAa,EAAE,MAAM,CAAC;IAEtB,YAAY,EAAE,MAAM,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC;IAQf,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,IAAI,GAAE,iBAAsB,GAC3B,WAAW,CAgCb"}
|
package/dist/broker/paths.js
CHANGED
|
@@ -17,10 +17,12 @@ export function resolveBrokerPaths(principal, runtimeToken, opts = {}) {
|
|
|
17
17
|
.slice(0, AGENT_IDENTITY_HEX_LEN);
|
|
18
18
|
const discoveryDir = join(userData, "runtime-broker", sanitizeSegment(principal), agentIdentity);
|
|
19
19
|
const logDir = join(userData, "runtime-broker", "log");
|
|
20
|
+
const buffersDir = join(discoveryDir, "buffers");
|
|
20
21
|
return {
|
|
21
22
|
discoveryFile: join(discoveryDir, "discovery.json"),
|
|
22
23
|
discoveryDir,
|
|
23
24
|
logDir,
|
|
25
|
+
buffersDir,
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
function sanitizeSegment(segment) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-liveness.d.ts","sourceRoot":"","sources":["../../src/broker/plugin-liveness.ts"],"names":[],"mappings":"AAyBA,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAiBzD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function isPluginAlive(plugin_pid) {
|
|
2
|
+
if (!Number.isFinite(plugin_pid) || plugin_pid <= 0) {
|
|
3
|
+
return false;
|
|
4
|
+
}
|
|
5
|
+
try {
|
|
6
|
+
process.kill(plugin_pid, 0);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
catch (err) {
|
|
10
|
+
const code = err.code;
|
|
11
|
+
if (code === "ESRCH")
|
|
12
|
+
return false;
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface BufferedMessage {
|
|
2
|
+
id: string;
|
|
3
|
+
arrived_at: string;
|
|
4
|
+
envelope: {
|
|
5
|
+
from: string;
|
|
6
|
+
content: string;
|
|
7
|
+
contentType: string;
|
|
8
|
+
metadata?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface ReconnectingBuffer {
|
|
12
|
+
append(msg: BufferedMessage): void;
|
|
13
|
+
read(): BufferedMessage[];
|
|
14
|
+
drain(): BufferedMessage[];
|
|
15
|
+
delete(): void;
|
|
16
|
+
size(): number;
|
|
17
|
+
}
|
|
18
|
+
export interface ReconnectingBufferManager {
|
|
19
|
+
forEndpoint(endpoint_id: string): ReconnectingBuffer;
|
|
20
|
+
cleanup(endpoint_id: string): void;
|
|
21
|
+
}
|
|
22
|
+
export declare function createReconnectingBufferManager(buffersDir: string): ReconnectingBufferManager;
|
|
23
|
+
//# sourceMappingURL=reconnecting-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconnecting-buffer.d.ts","sourceRoot":"","sources":["../../src/broker/reconnecting-buffer.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,eAAe;IAE9B,EAAE,EAAE,MAAM,CAAC;IAEX,UAAU,EAAE,MAAM,CAAC;IAEnB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IAEjC,MAAM,CAAC,GAAG,EAAE,eAAe,GAAG,IAAI,CAAC;IAEnC,IAAI,IAAI,eAAe,EAAE,CAAC;IAE1B,KAAK,IAAI,eAAe,EAAE,CAAC;IAE3B,MAAM,IAAI,IAAI,CAAC;IAEf,IAAI,IAAI,MAAM,CAAC;CAChB;AA8ED,MAAM,WAAW,yBAAyB;IAExC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAAC;IAErD,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAED,wBAAgB,+BAA+B,CAC7C,UAAU,EAAE,MAAM,GACjB,yBAAyB,CAmB3B"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { closeSync, fdatasyncSync, mkdirSync, openSync, readFileSync, unlinkSync, writeSync, } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
class FileBackedBuffer {
|
|
4
|
+
path;
|
|
5
|
+
cached = null;
|
|
6
|
+
constructor(path) {
|
|
7
|
+
this.path = path;
|
|
8
|
+
}
|
|
9
|
+
append(msg) {
|
|
10
|
+
const line = `${JSON.stringify(msg)}\n`;
|
|
11
|
+
try {
|
|
12
|
+
mkdirSync(dirname(this.path), { recursive: true, mode: 0o700 });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
}
|
|
16
|
+
const fd = openSync(this.path, "a", 0o600);
|
|
17
|
+
try {
|
|
18
|
+
writeSync(fd, line);
|
|
19
|
+
fdatasyncSync(fd);
|
|
20
|
+
}
|
|
21
|
+
finally {
|
|
22
|
+
closeSync(fd);
|
|
23
|
+
}
|
|
24
|
+
this.cached = null;
|
|
25
|
+
}
|
|
26
|
+
read() {
|
|
27
|
+
if (this.cached !== null)
|
|
28
|
+
return [...this.cached];
|
|
29
|
+
let raw;
|
|
30
|
+
try {
|
|
31
|
+
raw = readFileSync(this.path, "utf8");
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
if (isNodeErr(err, "ENOENT")) {
|
|
35
|
+
this.cached = [];
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
const lines = raw.split("\n").filter((l) => l.length > 0);
|
|
41
|
+
const parsed = [];
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
try {
|
|
44
|
+
parsed.push(JSON.parse(line));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
this.cached = parsed;
|
|
50
|
+
return [...parsed];
|
|
51
|
+
}
|
|
52
|
+
drain() {
|
|
53
|
+
const out = this.read();
|
|
54
|
+
this.delete();
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
delete() {
|
|
58
|
+
try {
|
|
59
|
+
unlinkSync(this.path);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (isNodeErr(err, "ENOENT")) {
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
this.cached = [];
|
|
69
|
+
}
|
|
70
|
+
size() {
|
|
71
|
+
if (this.cached !== null)
|
|
72
|
+
return this.cached.length;
|
|
73
|
+
return this.read().length;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function createReconnectingBufferManager(buffersDir) {
|
|
77
|
+
const cache = new Map();
|
|
78
|
+
return {
|
|
79
|
+
forEndpoint(endpoint_id) {
|
|
80
|
+
let buf = cache.get(endpoint_id);
|
|
81
|
+
if (!buf) {
|
|
82
|
+
buf = new FileBackedBuffer(join(buffersDir, `${sanitizeId(endpoint_id)}.ndjson`));
|
|
83
|
+
cache.set(endpoint_id, buf);
|
|
84
|
+
}
|
|
85
|
+
return buf;
|
|
86
|
+
},
|
|
87
|
+
cleanup(endpoint_id) {
|
|
88
|
+
const buf = cache.get(endpoint_id);
|
|
89
|
+
if (buf)
|
|
90
|
+
buf.delete();
|
|
91
|
+
cache.delete(endpoint_id);
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function sanitizeId(id) {
|
|
96
|
+
return id.replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
97
|
+
}
|
|
98
|
+
function dirname(p) {
|
|
99
|
+
const idx = p.lastIndexOf("/");
|
|
100
|
+
return idx >= 0 ? p.slice(0, idx) : ".";
|
|
101
|
+
}
|
|
102
|
+
function isNodeErr(err, code) {
|
|
103
|
+
return (typeof err === "object" &&
|
|
104
|
+
err !== null &&
|
|
105
|
+
"code" in err &&
|
|
106
|
+
err.code === code);
|
|
107
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing-table.d.ts","sourceRoot":"","sources":["../../src/broker/routing-table.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GACnB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,GAAG,EAAE,oBAAoB,GAAG,gBAAgB,CAAC;CAC9C,GACD;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAElC,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,GAAE,mBAAwB;IASjD,KAAK,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW;
|
|
1
|
+
{"version":3,"file":"routing-table.d.ts","sourceRoot":"","sources":["../../src/broker/routing-table.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,wBAAwB,CAAC;AAEhC,MAAM,WAAW,kBAAkB;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GACnB;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,GAAG,EAAE,oBAAoB,GAAG,gBAAgB,CAAC;CAC9C,GACD;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB,MAAM,WAAW,mBAAmB;IAElC,WAAW,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/D;AAED,qBAAa,YAAY;IAErB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBADJ,QAAQ,EAAE,gBAAgB,EAC1B,IAAI,GAAE,mBAAwB;IASjD,KAAK,CAAC,IAAI,EAAE,kBAAkB,GAAG,WAAW;CAmC7C"}
|