cc-peer 1.5.3 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/adapters/node/alias-worker.cjs +48 -6
- package/dist/adapters/node/alias-worker.mjs +48 -6
- package/dist/alias-ipc-BPc2wfmz.cjs +97 -0
- package/dist/alias-ipc-BSh7Q4LL.mjs +68 -0
- package/dist/alias-pool.cjs +67 -11
- package/dist/alias-pool.d.cts +15 -1
- package/dist/alias-pool.d.mts +15 -1
- package/dist/alias-pool.mjs +67 -11
- package/dist/bin/cc-peer.cjs +2 -2
- package/dist/bin/cc-peer.mjs +2 -2
- package/dist/{cc-peer-CPPV05My.cjs → cc-peer-BvoaikwI.cjs} +5 -11
- package/dist/{cc-peer-D3maNn_Z.mjs → cc-peer-CQV4Qv_H.mjs} +3 -9
- package/dist/{cc-peer-B3i4ZlKV.d.cts → cc-peer-mYIVwlKe.d.cts} +3 -3
- package/dist/{cc-peer-B3i4ZlKV.d.mts → cc-peer-mYIVwlKe.d.mts} +3 -3
- package/dist/cc-peer.cjs +1 -1
- package/dist/cc-peer.d.cts +1 -1
- package/dist/cc-peer.d.mts +1 -1
- package/dist/cc-peer.mjs +1 -1
- package/dist/{errors-Dl_lSq1N.cjs → errors-BAbklcGw.cjs} +32 -0
- package/dist/{errors-Dcqq2MIW.mjs → errors-KYBco8pU.mjs} +15 -1
- package/package.json +1 -1
- package/dist/alias-ipc-Cjs5yivH.cjs +0 -48
- package/dist/alias-ipc-DkaozCo7.mjs +0 -31
package/README.md
CHANGED
|
@@ -78,11 +78,19 @@ aliases.on("message", (m) => {
|
|
|
78
78
|
// time, give it a reply-able name (idempotent; a no-op if already active).
|
|
79
79
|
await aliases.ensure("alice");
|
|
80
80
|
|
|
81
|
+
// Deliver alice's message to the relayed session from alice's own alias
|
|
82
|
+
// (starting it if needed), so the session sees alice as the sender and its
|
|
83
|
+
// own reply-to-sender comes back on the "message" handler above rather than
|
|
84
|
+
// to the relay. Rejects if the alias cannot start, or if it cannot send.
|
|
85
|
+
const { msgId } = await aliases.send("alice", { pid: relayedSessionPid }, "ping");
|
|
86
|
+
|
|
81
87
|
// …later, once a correspondent is no longer relevant:
|
|
82
88
|
await aliases.retire("alice");
|
|
83
89
|
await aliases.stopAll();
|
|
84
90
|
```
|
|
85
91
|
|
|
92
|
+
Sending from the alias rather than from the relay's own peer is what makes a relayed session's natural reply reach the right correspondent: a session replies to whoever sent it a message, so a message delivered from the relay comes back to the relay with nothing to say which correspondent it answers.
|
|
93
|
+
|
|
86
94
|
## Limitations
|
|
87
95
|
|
|
88
96
|
- **Same-process constraint**: receipts and idle notices only reach the process that owns the peer's listening socket (the protocol verifies return addresses via kernel peer-pids). Do not split `CcPeer` listening and sending across processes or differently-owned workers.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const require_rolldown_runtime = require("../../rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
-
const require_cc_peer = require("../../cc-peer-
|
|
3
|
-
const
|
|
2
|
+
const require_cc_peer = require("../../cc-peer-BvoaikwI.cjs");
|
|
3
|
+
const require_errors = require("../../errors-BAbklcGw.cjs");
|
|
4
|
+
const require_alias_ipc = require("../../alias-ipc-BPc2wfmz.cjs");
|
|
4
5
|
let node_process = require("node:process");
|
|
5
6
|
node_process = require_rolldown_runtime.__toESM(node_process, 1);
|
|
6
7
|
//#region src/adapters/node/alias-worker.ts
|
|
@@ -11,11 +12,25 @@ let peer;
|
|
|
11
12
|
node_process.default.on("message", (raw) => {
|
|
12
13
|
handleCommand(raw);
|
|
13
14
|
});
|
|
15
|
+
node_process.default.on("disconnect", () => {
|
|
16
|
+
shutdown();
|
|
17
|
+
});
|
|
18
|
+
async function shutdown() {
|
|
19
|
+
await peer?.stop();
|
|
20
|
+
node_process.default.exit(0);
|
|
21
|
+
}
|
|
22
|
+
/** Relays an event to the parent unless its channel has already closed, since a send on a closed channel raises an error event on the process that nothing handles. */
|
|
23
|
+
function relay(message) {
|
|
24
|
+
if (node_process.default.connected) node_process.default.send?.(message);
|
|
25
|
+
}
|
|
14
26
|
async function handleCommand(raw) {
|
|
15
27
|
if (!require_alias_ipc.AliasCommandSchema.is(raw)) return;
|
|
16
28
|
if (raw.type === "stop") {
|
|
17
|
-
await
|
|
18
|
-
|
|
29
|
+
await shutdown();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (raw.type === "send") {
|
|
33
|
+
await handleSend(raw);
|
|
19
34
|
return;
|
|
20
35
|
}
|
|
21
36
|
let created;
|
|
@@ -32,11 +47,38 @@ async function handleCommand(raw) {
|
|
|
32
47
|
}
|
|
33
48
|
peer = created;
|
|
34
49
|
peer.on("message", (message) => {
|
|
35
|
-
|
|
50
|
+
relay({
|
|
36
51
|
type: "message",
|
|
37
52
|
...message
|
|
38
53
|
});
|
|
39
54
|
});
|
|
40
|
-
|
|
55
|
+
relay({ type: "started" });
|
|
56
|
+
}
|
|
57
|
+
async function handleSend(command) {
|
|
58
|
+
const active = peer;
|
|
59
|
+
if (active === void 0) {
|
|
60
|
+
relay({
|
|
61
|
+
type: "send_failed",
|
|
62
|
+
requestId: command.requestId,
|
|
63
|
+
code: "NOT_STARTED",
|
|
64
|
+
message: "alias peer has not started"
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const { msgId } = await active.send(command.target, command.body);
|
|
70
|
+
relay({
|
|
71
|
+
type: "sent",
|
|
72
|
+
requestId: command.requestId,
|
|
73
|
+
msgId
|
|
74
|
+
});
|
|
75
|
+
} catch (error) {
|
|
76
|
+
relay({
|
|
77
|
+
type: "send_failed",
|
|
78
|
+
requestId: command.requestId,
|
|
79
|
+
code: error instanceof require_errors.CcPeerError ? error.code : "UNKNOWN",
|
|
80
|
+
message: error instanceof Error ? error.message : "unknown alias send failure"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
41
83
|
}
|
|
42
84
|
//#endregion
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { n as CcPeer } from "../../cc-peer-
|
|
2
|
-
import {
|
|
1
|
+
import { n as CcPeer } from "../../cc-peer-CQV4Qv_H.mjs";
|
|
2
|
+
import { r as CcPeerError } from "../../errors-KYBco8pU.mjs";
|
|
3
|
+
import { t as AliasCommandSchema } from "../../alias-ipc-BSh7Q4LL.mjs";
|
|
3
4
|
import process from "node:process";
|
|
4
5
|
//#region src/adapters/node/alias-worker.ts
|
|
5
6
|
/**
|
|
@@ -9,11 +10,25 @@ let peer;
|
|
|
9
10
|
process.on("message", (raw) => {
|
|
10
11
|
handleCommand(raw);
|
|
11
12
|
});
|
|
13
|
+
process.on("disconnect", () => {
|
|
14
|
+
shutdown();
|
|
15
|
+
});
|
|
16
|
+
async function shutdown() {
|
|
17
|
+
await peer?.stop();
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
/** Relays an event to the parent unless its channel has already closed, since a send on a closed channel raises an error event on the process that nothing handles. */
|
|
21
|
+
function relay(message) {
|
|
22
|
+
if (process.connected) process.send?.(message);
|
|
23
|
+
}
|
|
12
24
|
async function handleCommand(raw) {
|
|
13
25
|
if (!AliasCommandSchema.is(raw)) return;
|
|
14
26
|
if (raw.type === "stop") {
|
|
15
|
-
await
|
|
16
|
-
|
|
27
|
+
await shutdown();
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (raw.type === "send") {
|
|
31
|
+
await handleSend(raw);
|
|
17
32
|
return;
|
|
18
33
|
}
|
|
19
34
|
let created;
|
|
@@ -30,12 +45,39 @@ async function handleCommand(raw) {
|
|
|
30
45
|
}
|
|
31
46
|
peer = created;
|
|
32
47
|
peer.on("message", (message) => {
|
|
33
|
-
|
|
48
|
+
relay({
|
|
34
49
|
type: "message",
|
|
35
50
|
...message
|
|
36
51
|
});
|
|
37
52
|
});
|
|
38
|
-
|
|
53
|
+
relay({ type: "started" });
|
|
54
|
+
}
|
|
55
|
+
async function handleSend(command) {
|
|
56
|
+
const active = peer;
|
|
57
|
+
if (active === void 0) {
|
|
58
|
+
relay({
|
|
59
|
+
type: "send_failed",
|
|
60
|
+
requestId: command.requestId,
|
|
61
|
+
code: "NOT_STARTED",
|
|
62
|
+
message: "alias peer has not started"
|
|
63
|
+
});
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const { msgId } = await active.send(command.target, command.body);
|
|
68
|
+
relay({
|
|
69
|
+
type: "sent",
|
|
70
|
+
requestId: command.requestId,
|
|
71
|
+
msgId
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
relay({
|
|
75
|
+
type: "send_failed",
|
|
76
|
+
requestId: command.requestId,
|
|
77
|
+
code: error instanceof CcPeerError ? error.code : "UNKNOWN",
|
|
78
|
+
message: error instanceof Error ? error.message : "unknown alias send failure"
|
|
79
|
+
});
|
|
80
|
+
}
|
|
39
81
|
}
|
|
40
82
|
//#endregion
|
|
41
83
|
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const require_errors = require("./errors-BAbklcGw.cjs");
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
//#region src/schemas/alias-ipc.ts
|
|
4
|
+
/**
|
|
5
|
+
* The parent-to-child and child-to-parent IPC contract `AliasPool`'s Node adapter (`adapters/node/forked-alias-process.ts`) and worker (`adapters/node/alias-worker.ts`) exchange over `child_process.fork()`'s built-in channel. This is deliberately independent of the wire protocol schemas in `wire.ts`: it never touches a socket, it only carries commands and events between a pool and the real OS process backing one reply alias.
|
|
6
|
+
*/
|
|
7
|
+
const AliasStartCommandSchema = require_errors.defineSchema(zod.z.object({
|
|
8
|
+
type: zod.z.literal("start"),
|
|
9
|
+
name: zod.z.string().min(1),
|
|
10
|
+
homeDir: zod.z.string().optional(),
|
|
11
|
+
socketDir: zod.z.string().optional(),
|
|
12
|
+
sessionId: zod.z.string().optional()
|
|
13
|
+
}));
|
|
14
|
+
const AliasStopCommandSchema = require_errors.defineSchema(zod.z.object({ type: zod.z.literal("stop") }));
|
|
15
|
+
/**
|
|
16
|
+
* How an alias addresses an outbound send, mirroring `CcPeer`'s own `PeerRef` union. Each variant is strict so a target carrying fields from more than one variant is rejected outright rather than resolved by whichever branch happens to match first.
|
|
17
|
+
*/
|
|
18
|
+
const AliasSendTargetSchema = require_errors.defineSchema(zod.z.union([
|
|
19
|
+
zod.z.strictObject({ pid: zod.z.number() }),
|
|
20
|
+
zod.z.strictObject({ name: zod.z.string().min(1) }),
|
|
21
|
+
zod.z.strictObject({ address: zod.z.string().min(1) })
|
|
22
|
+
]));
|
|
23
|
+
/** Asks the alias's own CcPeer to send `body` to `target`; the worker answers with a sent or send_failed event carrying the same `requestId`. */
|
|
24
|
+
const AliasSendCommandSchema = require_errors.defineSchema(zod.z.object({
|
|
25
|
+
type: zod.z.literal("send"),
|
|
26
|
+
requestId: zod.z.string().min(1),
|
|
27
|
+
target: AliasSendTargetSchema,
|
|
28
|
+
body: zod.z.string()
|
|
29
|
+
}));
|
|
30
|
+
const AliasCommandSchema = require_errors.defineSchema(zod.z.union([
|
|
31
|
+
AliasStartCommandSchema,
|
|
32
|
+
AliasStopCommandSchema,
|
|
33
|
+
AliasSendCommandSchema
|
|
34
|
+
]));
|
|
35
|
+
/** Sent once the worker's own CcPeer is listening and registered. */
|
|
36
|
+
const AliasStartedEventSchema = require_errors.defineSchema(zod.z.object({ type: zod.z.literal("started") }));
|
|
37
|
+
/** Mirrors CcPeer's own InboundMessage shape, carried over IPC instead of an EventEmitter within one process. */
|
|
38
|
+
const AliasMessageEventSchema = require_errors.defineSchema(zod.z.object({
|
|
39
|
+
type: zod.z.literal("message"),
|
|
40
|
+
from: zod.z.string().optional(),
|
|
41
|
+
fromSession: zod.z.string().optional(),
|
|
42
|
+
fromName: zod.z.string().optional(),
|
|
43
|
+
fromMode: zod.z.enum(["bypass", "prompting"]).optional(),
|
|
44
|
+
hopChain: zod.z.array(zod.z.string()).optional(),
|
|
45
|
+
body: zod.z.string(),
|
|
46
|
+
msgId: zod.z.string()
|
|
47
|
+
}));
|
|
48
|
+
/** Acknowledges the send command with the same `requestId`, carrying the id the alias's own peer gave the message. */
|
|
49
|
+
const AliasSentEventSchema = require_errors.defineSchema(zod.z.object({
|
|
50
|
+
type: zod.z.literal("sent"),
|
|
51
|
+
requestId: zod.z.string().min(1),
|
|
52
|
+
msgId: zod.z.string().min(1)
|
|
53
|
+
}));
|
|
54
|
+
/** Reports a send the alias could not make; `code` is the originating `CcPeerError`'s own machine-readable code where one was thrown. */
|
|
55
|
+
const AliasSendFailedEventSchema = require_errors.defineSchema(zod.z.object({
|
|
56
|
+
type: zod.z.literal("send_failed"),
|
|
57
|
+
requestId: zod.z.string().min(1),
|
|
58
|
+
code: zod.z.string().min(1),
|
|
59
|
+
message: zod.z.string()
|
|
60
|
+
}));
|
|
61
|
+
require_errors.defineSchema(zod.z.union([
|
|
62
|
+
AliasStartedEventSchema,
|
|
63
|
+
AliasMessageEventSchema,
|
|
64
|
+
AliasSentEventSchema,
|
|
65
|
+
AliasSendFailedEventSchema
|
|
66
|
+
]));
|
|
67
|
+
//#endregion
|
|
68
|
+
Object.defineProperty(exports, "AliasCommandSchema", {
|
|
69
|
+
enumerable: true,
|
|
70
|
+
get: function() {
|
|
71
|
+
return AliasCommandSchema;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
Object.defineProperty(exports, "AliasMessageEventSchema", {
|
|
75
|
+
enumerable: true,
|
|
76
|
+
get: function() {
|
|
77
|
+
return AliasMessageEventSchema;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
Object.defineProperty(exports, "AliasSendFailedEventSchema", {
|
|
81
|
+
enumerable: true,
|
|
82
|
+
get: function() {
|
|
83
|
+
return AliasSendFailedEventSchema;
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
Object.defineProperty(exports, "AliasSentEventSchema", {
|
|
87
|
+
enumerable: true,
|
|
88
|
+
get: function() {
|
|
89
|
+
return AliasSentEventSchema;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
Object.defineProperty(exports, "AliasStartedEventSchema", {
|
|
93
|
+
enumerable: true,
|
|
94
|
+
get: function() {
|
|
95
|
+
return AliasStartedEventSchema;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { l as defineSchema } from "./errors-KYBco8pU.mjs";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
//#region src/schemas/alias-ipc.ts
|
|
4
|
+
/**
|
|
5
|
+
* The parent-to-child and child-to-parent IPC contract `AliasPool`'s Node adapter (`adapters/node/forked-alias-process.ts`) and worker (`adapters/node/alias-worker.ts`) exchange over `child_process.fork()`'s built-in channel. This is deliberately independent of the wire protocol schemas in `wire.ts`: it never touches a socket, it only carries commands and events between a pool and the real OS process backing one reply alias.
|
|
6
|
+
*/
|
|
7
|
+
const AliasStartCommandSchema = defineSchema(z.object({
|
|
8
|
+
type: z.literal("start"),
|
|
9
|
+
name: z.string().min(1),
|
|
10
|
+
homeDir: z.string().optional(),
|
|
11
|
+
socketDir: z.string().optional(),
|
|
12
|
+
sessionId: z.string().optional()
|
|
13
|
+
}));
|
|
14
|
+
const AliasStopCommandSchema = defineSchema(z.object({ type: z.literal("stop") }));
|
|
15
|
+
/**
|
|
16
|
+
* How an alias addresses an outbound send, mirroring `CcPeer`'s own `PeerRef` union. Each variant is strict so a target carrying fields from more than one variant is rejected outright rather than resolved by whichever branch happens to match first.
|
|
17
|
+
*/
|
|
18
|
+
const AliasSendTargetSchema = defineSchema(z.union([
|
|
19
|
+
z.strictObject({ pid: z.number() }),
|
|
20
|
+
z.strictObject({ name: z.string().min(1) }),
|
|
21
|
+
z.strictObject({ address: z.string().min(1) })
|
|
22
|
+
]));
|
|
23
|
+
/** Asks the alias's own CcPeer to send `body` to `target`; the worker answers with a sent or send_failed event carrying the same `requestId`. */
|
|
24
|
+
const AliasSendCommandSchema = defineSchema(z.object({
|
|
25
|
+
type: z.literal("send"),
|
|
26
|
+
requestId: z.string().min(1),
|
|
27
|
+
target: AliasSendTargetSchema,
|
|
28
|
+
body: z.string()
|
|
29
|
+
}));
|
|
30
|
+
const AliasCommandSchema = defineSchema(z.union([
|
|
31
|
+
AliasStartCommandSchema,
|
|
32
|
+
AliasStopCommandSchema,
|
|
33
|
+
AliasSendCommandSchema
|
|
34
|
+
]));
|
|
35
|
+
/** Sent once the worker's own CcPeer is listening and registered. */
|
|
36
|
+
const AliasStartedEventSchema = defineSchema(z.object({ type: z.literal("started") }));
|
|
37
|
+
/** Mirrors CcPeer's own InboundMessage shape, carried over IPC instead of an EventEmitter within one process. */
|
|
38
|
+
const AliasMessageEventSchema = defineSchema(z.object({
|
|
39
|
+
type: z.literal("message"),
|
|
40
|
+
from: z.string().optional(),
|
|
41
|
+
fromSession: z.string().optional(),
|
|
42
|
+
fromName: z.string().optional(),
|
|
43
|
+
fromMode: z.enum(["bypass", "prompting"]).optional(),
|
|
44
|
+
hopChain: z.array(z.string()).optional(),
|
|
45
|
+
body: z.string(),
|
|
46
|
+
msgId: z.string()
|
|
47
|
+
}));
|
|
48
|
+
/** Acknowledges the send command with the same `requestId`, carrying the id the alias's own peer gave the message. */
|
|
49
|
+
const AliasSentEventSchema = defineSchema(z.object({
|
|
50
|
+
type: z.literal("sent"),
|
|
51
|
+
requestId: z.string().min(1),
|
|
52
|
+
msgId: z.string().min(1)
|
|
53
|
+
}));
|
|
54
|
+
/** Reports a send the alias could not make; `code` is the originating `CcPeerError`'s own machine-readable code where one was thrown. */
|
|
55
|
+
const AliasSendFailedEventSchema = defineSchema(z.object({
|
|
56
|
+
type: z.literal("send_failed"),
|
|
57
|
+
requestId: z.string().min(1),
|
|
58
|
+
code: z.string().min(1),
|
|
59
|
+
message: z.string()
|
|
60
|
+
}));
|
|
61
|
+
defineSchema(z.union([
|
|
62
|
+
AliasStartedEventSchema,
|
|
63
|
+
AliasMessageEventSchema,
|
|
64
|
+
AliasSentEventSchema,
|
|
65
|
+
AliasSendFailedEventSchema
|
|
66
|
+
]));
|
|
67
|
+
//#endregion
|
|
68
|
+
export { AliasStartedEventSchema as a, AliasSentEventSchema as i, AliasMessageEventSchema as n, AliasSendFailedEventSchema as r, AliasCommandSchema as t };
|
package/dist/alias-pool.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_errors = require("./errors-
|
|
3
|
-
const require_alias_ipc = require("./alias-ipc-
|
|
2
|
+
const require_errors = require("./errors-BAbklcGw.cjs");
|
|
3
|
+
const require_alias_ipc = require("./alias-ipc-BPc2wfmz.cjs");
|
|
4
4
|
let node_events = require("node:events");
|
|
5
5
|
let node_child_process = require("node:child_process");
|
|
6
6
|
let node_url = require("node:url");
|
|
@@ -12,6 +12,7 @@ var ForkedAliasProcess = class {
|
|
|
12
12
|
events = new node_events.EventEmitter();
|
|
13
13
|
forkFn;
|
|
14
14
|
workerPath;
|
|
15
|
+
pendingSends = /* @__PURE__ */ new Map();
|
|
15
16
|
child;
|
|
16
17
|
constructor(deps) {
|
|
17
18
|
this.forkFn = deps.fork ?? node_child_process.fork;
|
|
@@ -21,9 +22,14 @@ var ForkedAliasProcess = class {
|
|
|
21
22
|
const child = this.forkFn(this.workerPath, [], {});
|
|
22
23
|
this.child = child;
|
|
23
24
|
child.on("message", (raw) => {
|
|
24
|
-
if (require_alias_ipc.AliasMessageEventSchema.is(raw))
|
|
25
|
+
if (require_alias_ipc.AliasMessageEventSchema.is(raw)) {
|
|
26
|
+
this.events.emit("message", toInboundMessage(raw));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.settleSend(raw);
|
|
25
30
|
});
|
|
26
31
|
child.on("exit", () => {
|
|
32
|
+
this.failPendingSends("alias worker exited before the send was acknowledged");
|
|
27
33
|
this.events.emit("exit");
|
|
28
34
|
});
|
|
29
35
|
await new Promise((resolve, reject) => {
|
|
@@ -49,10 +55,51 @@ var ForkedAliasProcess = class {
|
|
|
49
55
|
});
|
|
50
56
|
});
|
|
51
57
|
}
|
|
52
|
-
async
|
|
58
|
+
async send(target, body) {
|
|
59
|
+
const child = this.runningChild();
|
|
60
|
+
if (child === void 0) throw new require_errors.AliasSendError("alias worker is not running");
|
|
61
|
+
const requestId = require_errors.newMsgId();
|
|
62
|
+
return new Promise((resolve, reject) => {
|
|
63
|
+
this.pendingSends.set(requestId, {
|
|
64
|
+
resolve,
|
|
65
|
+
reject
|
|
66
|
+
});
|
|
67
|
+
child.send({
|
|
68
|
+
type: "send",
|
|
69
|
+
requestId,
|
|
70
|
+
target,
|
|
71
|
+
body
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Settles the one in-flight send an acknowledgement names. An acknowledgement for an unknown request is ignored: the send it belongs to was already settled by the worker exiting. */
|
|
76
|
+
settleSend(raw) {
|
|
77
|
+
if (require_alias_ipc.AliasSentEventSchema.is(raw)) {
|
|
78
|
+
this.takePendingSend(raw.requestId)?.resolve({ msgId: raw.msgId });
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (require_alias_ipc.AliasSendFailedEventSchema.is(raw)) this.takePendingSend(raw.requestId)?.reject(new require_errors.AliasSendError(`${raw.code}: ${raw.message}`));
|
|
82
|
+
}
|
|
83
|
+
takePendingSend(requestId) {
|
|
84
|
+
const pending = this.pendingSends.get(requestId);
|
|
85
|
+
this.pendingSends.delete(requestId);
|
|
86
|
+
return pending;
|
|
87
|
+
}
|
|
88
|
+
failPendingSends(reason) {
|
|
89
|
+
const pending = [...this.pendingSends.values()];
|
|
90
|
+
this.pendingSends.clear();
|
|
91
|
+
for (const send of pending) send.reject(new require_errors.AliasSendError(reason));
|
|
92
|
+
}
|
|
93
|
+
/** The forked child while it is still running, or undefined before start() and once it has ended: a command written past that point reaches a channel nothing is reading. */
|
|
94
|
+
runningChild() {
|
|
53
95
|
const child = this.child;
|
|
96
|
+
if (child === void 0) return void 0;
|
|
97
|
+
if (child.exitCode !== null || child.signalCode !== null) return void 0;
|
|
98
|
+
return child;
|
|
99
|
+
}
|
|
100
|
+
async stop() {
|
|
101
|
+
const child = this.runningChild();
|
|
54
102
|
if (child === void 0) return;
|
|
55
|
-
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
56
103
|
await new Promise((resolve) => {
|
|
57
104
|
child.once("exit", () => {
|
|
58
105
|
resolve();
|
|
@@ -106,16 +153,24 @@ var AliasPool = class AliasPool extends node_events.EventEmitter {
|
|
|
106
153
|
}
|
|
107
154
|
/** Idempotent: a no-op if the alias is already active, and dedup'd if another ensure() for the same name is already in flight. */
|
|
108
155
|
async ensure(name) {
|
|
109
|
-
|
|
156
|
+
await this.acquire(name);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Sends `body` to `target` from the named alias's own peer identity, starting that alias first if it is not already running, so the recipient sees the correspondent rather than the relay as the sender. Resolves with the id the alias gave the message; rejects with an `AliasStartError` if the alias could not be started, or an `AliasSendError` if it refused the send or its process ended before acknowledging it.
|
|
160
|
+
*/
|
|
161
|
+
async send(name, target, body) {
|
|
162
|
+
return (await this.acquire(name)).send(target, body);
|
|
163
|
+
}
|
|
164
|
+
/** The single start path behind ensure() and send(): returns the running process for the name, starting one only if neither an active nor an in-flight process already exists. */
|
|
165
|
+
async acquire(name) {
|
|
166
|
+
const active = this.active.get(name);
|
|
167
|
+
if (active !== void 0) return active;
|
|
110
168
|
const inFlight = this.pending.get(name);
|
|
111
|
-
if (inFlight !== void 0)
|
|
112
|
-
await inFlight;
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
169
|
+
if (inFlight !== void 0) return inFlight;
|
|
115
170
|
const started = this.startAlias(name);
|
|
116
171
|
this.pending.set(name, started);
|
|
117
172
|
try {
|
|
118
|
-
await started;
|
|
173
|
+
return await started;
|
|
119
174
|
} finally {
|
|
120
175
|
this.pending.delete(name);
|
|
121
176
|
}
|
|
@@ -139,6 +194,7 @@ var AliasPool = class AliasPool extends node_events.EventEmitter {
|
|
|
139
194
|
});
|
|
140
195
|
this.active.set(name, proc);
|
|
141
196
|
this.log(`alias ${name} active`);
|
|
197
|
+
return proc;
|
|
142
198
|
}
|
|
143
199
|
/** Waits for any in-flight ensure() of the same name to settle first, so a retire() issued while an alias is still starting stops it once (and if) it becomes active. A no-op for a name that is neither active nor pending. */
|
|
144
200
|
async retire(name) {
|
package/dist/alias-pool.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as InboundMessage, l as PathConfig } from "./cc-peer-
|
|
1
|
+
import { a as InboundMessage, l as PathConfig, o as PeerRef } from "./cc-peer-mYIVwlKe.cjs";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
//#region src/ports/alias-process.d.ts
|
|
4
4
|
interface AliasStartOptions extends PathConfig {
|
|
@@ -11,6 +11,12 @@ interface AliasStartOptions extends PathConfig {
|
|
|
11
11
|
interface AliasProcess {
|
|
12
12
|
readonly events: EventEmitter;
|
|
13
13
|
start: (options: Readonly<AliasStartOptions>) => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Sends `body` to `target` from the alias's own peer identity, so the recipient sees the alias as the sender and replies to it natively. Resolves with the id the alias's peer gave the message; rejects with an `AliasSendError` when the alias refuses the send or its process ends before acknowledging it.
|
|
16
|
+
*/
|
|
17
|
+
send: (target: Readonly<PeerRef>, body: string) => Promise<{
|
|
18
|
+
msgId: string;
|
|
19
|
+
}>;
|
|
14
20
|
stop: () => Promise<void>;
|
|
15
21
|
}
|
|
16
22
|
//#endregion
|
|
@@ -42,6 +48,14 @@ export declare class AliasPool extends EventEmitter {
|
|
|
42
48
|
static create(options?: Readonly<AliasPoolOptions>): AliasPool;
|
|
43
49
|
/** Idempotent: a no-op if the alias is already active, and dedup'd if another ensure() for the same name is already in flight. */
|
|
44
50
|
ensure(name: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Sends `body` to `target` from the named alias's own peer identity, starting that alias first if it is not already running, so the recipient sees the correspondent rather than the relay as the sender. Resolves with the id the alias gave the message; rejects with an `AliasStartError` if the alias could not be started, or an `AliasSendError` if it refused the send or its process ended before acknowledging it.
|
|
53
|
+
*/
|
|
54
|
+
send(name: string, target: Readonly<PeerRef>, body: string): Promise<{
|
|
55
|
+
msgId: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** The single start path behind ensure() and send(): returns the running process for the name, starting one only if neither an active nor an in-flight process already exists. */
|
|
58
|
+
private acquire;
|
|
45
59
|
private startAlias;
|
|
46
60
|
/** Waits for any in-flight ensure() of the same name to settle first, so a retire() issued while an alias is still starting stops it once (and if) it becomes active. A no-op for a name that is neither active nor pending. */
|
|
47
61
|
retire(name: string): Promise<void>;
|
package/dist/alias-pool.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as InboundMessage, l as PathConfig } from "./cc-peer-
|
|
1
|
+
import { a as InboundMessage, l as PathConfig, o as PeerRef } from "./cc-peer-mYIVwlKe.mjs";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
//#region src/ports/alias-process.d.ts
|
|
4
4
|
interface AliasStartOptions extends PathConfig {
|
|
@@ -11,6 +11,12 @@ interface AliasStartOptions extends PathConfig {
|
|
|
11
11
|
interface AliasProcess {
|
|
12
12
|
readonly events: EventEmitter;
|
|
13
13
|
start: (options: Readonly<AliasStartOptions>) => Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Sends `body` to `target` from the alias's own peer identity, so the recipient sees the alias as the sender and replies to it natively. Resolves with the id the alias's peer gave the message; rejects with an `AliasSendError` when the alias refuses the send or its process ends before acknowledging it.
|
|
16
|
+
*/
|
|
17
|
+
send: (target: Readonly<PeerRef>, body: string) => Promise<{
|
|
18
|
+
msgId: string;
|
|
19
|
+
}>;
|
|
14
20
|
stop: () => Promise<void>;
|
|
15
21
|
}
|
|
16
22
|
//#endregion
|
|
@@ -42,6 +48,14 @@ export declare class AliasPool extends EventEmitter {
|
|
|
42
48
|
static create(options?: Readonly<AliasPoolOptions>): AliasPool;
|
|
43
49
|
/** Idempotent: a no-op if the alias is already active, and dedup'd if another ensure() for the same name is already in flight. */
|
|
44
50
|
ensure(name: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Sends `body` to `target` from the named alias's own peer identity, starting that alias first if it is not already running, so the recipient sees the correspondent rather than the relay as the sender. Resolves with the id the alias gave the message; rejects with an `AliasStartError` if the alias could not be started, or an `AliasSendError` if it refused the send or its process ended before acknowledging it.
|
|
53
|
+
*/
|
|
54
|
+
send(name: string, target: Readonly<PeerRef>, body: string): Promise<{
|
|
55
|
+
msgId: string;
|
|
56
|
+
}>;
|
|
57
|
+
/** The single start path behind ensure() and send(): returns the running process for the name, starting one only if neither an active nor an in-flight process already exists. */
|
|
58
|
+
private acquire;
|
|
45
59
|
private startAlias;
|
|
46
60
|
/** Waits for any in-flight ensure() of the same name to settle first, so a retire() issued while an alias is still starting stops it once (and if) it becomes active. A no-op for a name that is neither active nor pending. */
|
|
47
61
|
retire(name: string): Promise<void>;
|
package/dist/alias-pool.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as AliasMessageEventSchema, r as
|
|
1
|
+
import { c as newMsgId, n as AliasStartError, t as AliasSendError } from "./errors-KYBco8pU.mjs";
|
|
2
|
+
import { a as AliasStartedEventSchema, i as AliasSentEventSchema, n as AliasMessageEventSchema, r as AliasSendFailedEventSchema } from "./alias-ipc-BSh7Q4LL.mjs";
|
|
3
3
|
import { EventEmitter } from "node:events";
|
|
4
4
|
import { fork } from "node:child_process";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,6 +11,7 @@ var ForkedAliasProcess = class {
|
|
|
11
11
|
events = new EventEmitter();
|
|
12
12
|
forkFn;
|
|
13
13
|
workerPath;
|
|
14
|
+
pendingSends = /* @__PURE__ */ new Map();
|
|
14
15
|
child;
|
|
15
16
|
constructor(deps) {
|
|
16
17
|
this.forkFn = deps.fork ?? fork;
|
|
@@ -20,9 +21,14 @@ var ForkedAliasProcess = class {
|
|
|
20
21
|
const child = this.forkFn(this.workerPath, [], {});
|
|
21
22
|
this.child = child;
|
|
22
23
|
child.on("message", (raw) => {
|
|
23
|
-
if (AliasMessageEventSchema.is(raw))
|
|
24
|
+
if (AliasMessageEventSchema.is(raw)) {
|
|
25
|
+
this.events.emit("message", toInboundMessage(raw));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.settleSend(raw);
|
|
24
29
|
});
|
|
25
30
|
child.on("exit", () => {
|
|
31
|
+
this.failPendingSends("alias worker exited before the send was acknowledged");
|
|
26
32
|
this.events.emit("exit");
|
|
27
33
|
});
|
|
28
34
|
await new Promise((resolve, reject) => {
|
|
@@ -48,10 +54,51 @@ var ForkedAliasProcess = class {
|
|
|
48
54
|
});
|
|
49
55
|
});
|
|
50
56
|
}
|
|
51
|
-
async
|
|
57
|
+
async send(target, body) {
|
|
58
|
+
const child = this.runningChild();
|
|
59
|
+
if (child === void 0) throw new AliasSendError("alias worker is not running");
|
|
60
|
+
const requestId = newMsgId();
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
this.pendingSends.set(requestId, {
|
|
63
|
+
resolve,
|
|
64
|
+
reject
|
|
65
|
+
});
|
|
66
|
+
child.send({
|
|
67
|
+
type: "send",
|
|
68
|
+
requestId,
|
|
69
|
+
target,
|
|
70
|
+
body
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/** Settles the one in-flight send an acknowledgement names. An acknowledgement for an unknown request is ignored: the send it belongs to was already settled by the worker exiting. */
|
|
75
|
+
settleSend(raw) {
|
|
76
|
+
if (AliasSentEventSchema.is(raw)) {
|
|
77
|
+
this.takePendingSend(raw.requestId)?.resolve({ msgId: raw.msgId });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (AliasSendFailedEventSchema.is(raw)) this.takePendingSend(raw.requestId)?.reject(new AliasSendError(`${raw.code}: ${raw.message}`));
|
|
81
|
+
}
|
|
82
|
+
takePendingSend(requestId) {
|
|
83
|
+
const pending = this.pendingSends.get(requestId);
|
|
84
|
+
this.pendingSends.delete(requestId);
|
|
85
|
+
return pending;
|
|
86
|
+
}
|
|
87
|
+
failPendingSends(reason) {
|
|
88
|
+
const pending = [...this.pendingSends.values()];
|
|
89
|
+
this.pendingSends.clear();
|
|
90
|
+
for (const send of pending) send.reject(new AliasSendError(reason));
|
|
91
|
+
}
|
|
92
|
+
/** The forked child while it is still running, or undefined before start() and once it has ended: a command written past that point reaches a channel nothing is reading. */
|
|
93
|
+
runningChild() {
|
|
52
94
|
const child = this.child;
|
|
95
|
+
if (child === void 0) return void 0;
|
|
96
|
+
if (child.exitCode !== null || child.signalCode !== null) return void 0;
|
|
97
|
+
return child;
|
|
98
|
+
}
|
|
99
|
+
async stop() {
|
|
100
|
+
const child = this.runningChild();
|
|
53
101
|
if (child === void 0) return;
|
|
54
|
-
if (child.exitCode !== null || child.signalCode !== null) return;
|
|
55
102
|
await new Promise((resolve) => {
|
|
56
103
|
child.once("exit", () => {
|
|
57
104
|
resolve();
|
|
@@ -105,16 +152,24 @@ var AliasPool = class AliasPool extends EventEmitter {
|
|
|
105
152
|
}
|
|
106
153
|
/** Idempotent: a no-op if the alias is already active, and dedup'd if another ensure() for the same name is already in flight. */
|
|
107
154
|
async ensure(name) {
|
|
108
|
-
|
|
155
|
+
await this.acquire(name);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Sends `body` to `target` from the named alias's own peer identity, starting that alias first if it is not already running, so the recipient sees the correspondent rather than the relay as the sender. Resolves with the id the alias gave the message; rejects with an `AliasStartError` if the alias could not be started, or an `AliasSendError` if it refused the send or its process ended before acknowledging it.
|
|
159
|
+
*/
|
|
160
|
+
async send(name, target, body) {
|
|
161
|
+
return (await this.acquire(name)).send(target, body);
|
|
162
|
+
}
|
|
163
|
+
/** The single start path behind ensure() and send(): returns the running process for the name, starting one only if neither an active nor an in-flight process already exists. */
|
|
164
|
+
async acquire(name) {
|
|
165
|
+
const active = this.active.get(name);
|
|
166
|
+
if (active !== void 0) return active;
|
|
109
167
|
const inFlight = this.pending.get(name);
|
|
110
|
-
if (inFlight !== void 0)
|
|
111
|
-
await inFlight;
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
168
|
+
if (inFlight !== void 0) return inFlight;
|
|
114
169
|
const started = this.startAlias(name);
|
|
115
170
|
this.pending.set(name, started);
|
|
116
171
|
try {
|
|
117
|
-
await started;
|
|
172
|
+
return await started;
|
|
118
173
|
} finally {
|
|
119
174
|
this.pending.delete(name);
|
|
120
175
|
}
|
|
@@ -138,6 +193,7 @@ var AliasPool = class AliasPool extends EventEmitter {
|
|
|
138
193
|
});
|
|
139
194
|
this.active.set(name, proc);
|
|
140
195
|
this.log(`alias ${name} active`);
|
|
196
|
+
return proc;
|
|
141
197
|
}
|
|
142
198
|
/** Waits for any in-flight ensure() of the same name to settle first, so a retire() issued while an alias is still starting stops it once (and if) it becomes active. A no-op for a name that is neither active nor pending. */
|
|
143
199
|
async retire(name) {
|
package/dist/bin/cc-peer.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const require_rolldown_runtime = require("../rolldown-runtime-VH7oDXx4.cjs");
|
|
3
|
-
const require_cc_peer = require("../cc-peer-
|
|
4
|
-
const require_errors = require("../errors-
|
|
3
|
+
const require_cc_peer = require("../cc-peer-BvoaikwI.cjs");
|
|
4
|
+
const require_errors = require("../errors-BAbklcGw.cjs");
|
|
5
5
|
let node_crypto = require("node:crypto");
|
|
6
6
|
let zod = require("zod");
|
|
7
7
|
let node_process = require("node:process");
|
package/dist/bin/cc-peer.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as RegistryEntrySchema, n as CcPeer, r as PrioritySchema } from "../cc-peer-
|
|
3
|
-
import {
|
|
2
|
+
import { i as RegistryEntrySchema, n as CcPeer, r as PrioritySchema } from "../cc-peer-CQV4Qv_H.mjs";
|
|
3
|
+
import { l as defineSchema } from "../errors-KYBco8pU.mjs";
|
|
4
4
|
import { randomBytes } from "node:crypto";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import process from "node:process";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_errors = require("./errors-
|
|
1
|
+
const require_errors = require("./errors-BAbklcGw.cjs");
|
|
2
2
|
let node_events = require("node:events");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let node_net = require("node:net");
|
|
@@ -8,7 +8,7 @@ let zod = require("zod");
|
|
|
8
8
|
let node_os = require("node:os");
|
|
9
9
|
let node_child_process = require("node:child_process");
|
|
10
10
|
//#region package.json
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.6.1";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/adapters/node/uds-transport.ts
|
|
14
14
|
/** macOS linger before close, matching the reference client's ~150ms. */
|
|
@@ -564,12 +564,6 @@ var Pacer = class {
|
|
|
564
564
|
}
|
|
565
565
|
};
|
|
566
566
|
//#endregion
|
|
567
|
-
//#region src/domain/ids.ts
|
|
568
|
-
/** Message ids are UUID v4, matching the reference client's `qM()`. */
|
|
569
|
-
function newMsgId() {
|
|
570
|
-
return (0, node_crypto.randomUUID)();
|
|
571
|
-
}
|
|
572
|
-
//#endregion
|
|
573
567
|
//#region src/domain/roster.ts
|
|
574
568
|
/**
|
|
575
569
|
* The receiver's own admission rules, verified live: an entry is listed when it has a socket, is not the caller's own, is not spare/parked, its socket accepts a live connect probe, and its pid is alive with a procStart that byte-matches the ps output. Mismatches classify as recycled and are silently skipped by the reference roster builder.
|
|
@@ -807,7 +801,7 @@ var CcPeer = class CcPeer extends node_events.EventEmitter {
|
|
|
807
801
|
const now = this.deps.clock.nowMs();
|
|
808
802
|
return {
|
|
809
803
|
pid: process.pid,
|
|
810
|
-
sessionId: this.options.sessionId ?? newMsgId(),
|
|
804
|
+
sessionId: this.options.sessionId ?? require_errors.newMsgId(),
|
|
811
805
|
cwd: process.cwd(),
|
|
812
806
|
startedAt: now,
|
|
813
807
|
procStart,
|
|
@@ -840,7 +834,7 @@ var CcPeer = class CcPeer extends node_events.EventEmitter {
|
|
|
840
834
|
if (this.stopped || this.listening === void 0 || this.ownKey === void 0) throw new require_errors.NotStartedError("peer is not running");
|
|
841
835
|
const socketPath = await this.resolveTarget(target);
|
|
842
836
|
const key = await this.deps.keys.readForSocket(socketPath);
|
|
843
|
-
const msgId = newMsgId();
|
|
837
|
+
const msgId = require_errors.newMsgId();
|
|
844
838
|
const from = `uds:${this.listening.socketPath}`;
|
|
845
839
|
const frame = {
|
|
846
840
|
msgV: 1,
|
|
@@ -884,7 +878,7 @@ var CcPeer = class CcPeer extends node_events.EventEmitter {
|
|
|
884
878
|
const socketPath = await this.resolveTarget(target);
|
|
885
879
|
const key = await this.deps.keys.readForSocket(socketPath);
|
|
886
880
|
if (key === void 0) throw new require_errors.NoLiveInboxError(`no auth key published for ${socketPath}`);
|
|
887
|
-
const msgId = newMsgId();
|
|
881
|
+
const msgId = require_errors.newMsgId();
|
|
888
882
|
const frame = {
|
|
889
883
|
msgV: 1,
|
|
890
884
|
msg_id: msgId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as NoLiveInboxError, c as newMsgId, i as MessageTooLargeError, l as defineSchema, o as NotStartedError, s as UnknownPeerError } from "./errors-KYBco8pU.mjs";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
|
-
import { createHash, randomBytes
|
|
3
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { connect, createServer } from "node:net";
|
|
5
5
|
import { mkdir, readFile, readdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
@@ -8,7 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
//#region package.json
|
|
11
|
-
var version = "1.
|
|
11
|
+
var version = "1.6.1";
|
|
12
12
|
//#endregion
|
|
13
13
|
//#region src/adapters/node/uds-transport.ts
|
|
14
14
|
/** macOS linger before close, matching the reference client's ~150ms. */
|
|
@@ -564,12 +564,6 @@ var Pacer = class {
|
|
|
564
564
|
}
|
|
565
565
|
};
|
|
566
566
|
//#endregion
|
|
567
|
-
//#region src/domain/ids.ts
|
|
568
|
-
/** Message ids are UUID v4, matching the reference client's `qM()`. */
|
|
569
|
-
function newMsgId() {
|
|
570
|
-
return randomUUID();
|
|
571
|
-
}
|
|
572
|
-
//#endregion
|
|
573
567
|
//#region src/domain/roster.ts
|
|
574
568
|
/**
|
|
575
569
|
* The receiver's own admission rules, verified live: an entry is listed when it has a socket, is not the caller's own, is not spare/parked, its socket accepts a live connect probe, and its pid is alive with a procStart that byte-matches the ps output. Mismatches classify as recycled and are silently skipped by the reference roster builder.
|
|
@@ -71,12 +71,12 @@ declare const RegistryEntrySchema: z.ZodObject<{
|
|
|
71
71
|
nameSince: z.ZodOptional<z.ZodNumber>;
|
|
72
72
|
updatedAt: z.ZodNumber;
|
|
73
73
|
status: z.ZodOptional<z.ZodEnum<{
|
|
74
|
-
idle: "idle";
|
|
75
74
|
busy: "busy";
|
|
76
75
|
shell: "shell";
|
|
76
|
+
idle: "idle";
|
|
77
77
|
waiting: "waiting";
|
|
78
78
|
}> & {
|
|
79
|
-
is(value: unknown): value is "
|
|
79
|
+
is(value: unknown): value is "busy" | "shell" | "idle" | "waiting";
|
|
80
80
|
}>;
|
|
81
81
|
statusUpdatedAt: z.ZodOptional<z.ZodNumber>;
|
|
82
82
|
bridgeSessionId: z.ZodOptional<z.ZodString>;
|
|
@@ -99,7 +99,7 @@ declare const RegistryEntrySchema: z.ZodObject<{
|
|
|
99
99
|
name?: string | undefined;
|
|
100
100
|
nameSource?: "user" | "peer" | "derived" | "collision" | "auto" | "hook" | undefined;
|
|
101
101
|
nameSince?: number | undefined;
|
|
102
|
-
status?: "
|
|
102
|
+
status?: "busy" | "shell" | "idle" | "waiting" | undefined;
|
|
103
103
|
statusUpdatedAt?: number | undefined;
|
|
104
104
|
bridgeSessionId?: string | undefined;
|
|
105
105
|
};
|
|
@@ -71,12 +71,12 @@ declare const RegistryEntrySchema: z.ZodObject<{
|
|
|
71
71
|
nameSince: z.ZodOptional<z.ZodNumber>;
|
|
72
72
|
updatedAt: z.ZodNumber;
|
|
73
73
|
status: z.ZodOptional<z.ZodEnum<{
|
|
74
|
-
idle: "idle";
|
|
75
74
|
busy: "busy";
|
|
76
75
|
shell: "shell";
|
|
76
|
+
idle: "idle";
|
|
77
77
|
waiting: "waiting";
|
|
78
78
|
}> & {
|
|
79
|
-
is(value: unknown): value is "
|
|
79
|
+
is(value: unknown): value is "busy" | "shell" | "idle" | "waiting";
|
|
80
80
|
}>;
|
|
81
81
|
statusUpdatedAt: z.ZodOptional<z.ZodNumber>;
|
|
82
82
|
bridgeSessionId: z.ZodOptional<z.ZodString>;
|
|
@@ -99,7 +99,7 @@ declare const RegistryEntrySchema: z.ZodObject<{
|
|
|
99
99
|
name?: string | undefined;
|
|
100
100
|
nameSource?: "user" | "peer" | "derived" | "collision" | "auto" | "hook" | undefined;
|
|
101
101
|
nameSince?: number | undefined;
|
|
102
|
-
status?: "
|
|
102
|
+
status?: "busy" | "shell" | "idle" | "waiting" | undefined;
|
|
103
103
|
statusUpdatedAt?: number | undefined;
|
|
104
104
|
bridgeSessionId?: string | undefined;
|
|
105
105
|
};
|
package/dist/cc-peer.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_cc_peer = require("./cc-peer-
|
|
2
|
+
const require_cc_peer = require("./cc-peer-BvoaikwI.cjs");
|
|
3
3
|
exports.CC_PEER_VERSION = require_cc_peer.CC_PEER_VERSION;
|
|
4
4
|
exports.CcPeer = require_cc_peer.CcPeer;
|
package/dist/cc-peer.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as InboundMessage, c as SendOptions, i as IdleNotice, n as CcPeer, o as PeerRef, r as CcPeerOptions, s as Receipt, t as CC_PEER_VERSION } from "./cc-peer-
|
|
1
|
+
import { a as InboundMessage, c as SendOptions, i as IdleNotice, n as CcPeer, o as PeerRef, r as CcPeerOptions, s as Receipt, t as CC_PEER_VERSION } from "./cc-peer-mYIVwlKe.cjs";
|
|
2
2
|
export { CC_PEER_VERSION, CcPeer, CcPeerOptions, IdleNotice, InboundMessage, PeerRef, Receipt, SendOptions };
|
package/dist/cc-peer.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as InboundMessage, c as SendOptions, i as IdleNotice, n as CcPeer, o as PeerRef, r as CcPeerOptions, s as Receipt, t as CC_PEER_VERSION } from "./cc-peer-
|
|
1
|
+
import { a as InboundMessage, c as SendOptions, i as IdleNotice, n as CcPeer, o as PeerRef, r as CcPeerOptions, s as Receipt, t as CC_PEER_VERSION } from "./cc-peer-mYIVwlKe.mjs";
|
|
2
2
|
export { CC_PEER_VERSION, CcPeer, CcPeerOptions, IdleNotice, InboundMessage, PeerRef, Receipt, SendOptions };
|
package/dist/cc-peer.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as CcPeer, t as CC_PEER_VERSION } from "./cc-peer-
|
|
1
|
+
import { n as CcPeer, t as CC_PEER_VERSION } from "./cc-peer-CQV4Qv_H.mjs";
|
|
2
2
|
export { CC_PEER_VERSION, CcPeer };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
let node_crypto = require("node:crypto");
|
|
1
2
|
//#region src/schemas/define-schema.ts
|
|
2
3
|
/**
|
|
3
4
|
* Attach an `.is()` type guard to a Zod schema so schema, inferred type, and runtime guard derive from one definition (single source of truth). `Schema.parse()` at JSON boundaries; `Schema.is()` for narrowing.
|
|
@@ -8,6 +9,12 @@ function defineSchema(schema) {
|
|
|
8
9
|
} });
|
|
9
10
|
}
|
|
10
11
|
//#endregion
|
|
12
|
+
//#region src/domain/ids.ts
|
|
13
|
+
/** Message ids are UUID v4, matching the reference client's `qM()`. */
|
|
14
|
+
function newMsgId() {
|
|
15
|
+
return (0, node_crypto.randomUUID)();
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
11
18
|
//#region src/errors.ts
|
|
12
19
|
/** Base error for every cc-peer failure; `code` is machine-readable. */
|
|
13
20
|
var CcPeerError = class extends Error {
|
|
@@ -49,13 +56,32 @@ var AliasStartError = class extends CcPeerError {
|
|
|
49
56
|
this.name = "AliasStartError";
|
|
50
57
|
}
|
|
51
58
|
};
|
|
59
|
+
/** A message could not be sent from a reply alias: its own peer refused the send, or its worker process was gone (or went away) before acknowledging the command. */
|
|
60
|
+
var AliasSendError = class extends CcPeerError {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super("ALIAS_SEND_FAILED", message);
|
|
63
|
+
this.name = "AliasSendError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
52
66
|
//#endregion
|
|
67
|
+
Object.defineProperty(exports, "AliasSendError", {
|
|
68
|
+
enumerable: true,
|
|
69
|
+
get: function() {
|
|
70
|
+
return AliasSendError;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
53
73
|
Object.defineProperty(exports, "AliasStartError", {
|
|
54
74
|
enumerable: true,
|
|
55
75
|
get: function() {
|
|
56
76
|
return AliasStartError;
|
|
57
77
|
}
|
|
58
78
|
});
|
|
79
|
+
Object.defineProperty(exports, "CcPeerError", {
|
|
80
|
+
enumerable: true,
|
|
81
|
+
get: function() {
|
|
82
|
+
return CcPeerError;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
59
85
|
Object.defineProperty(exports, "MessageTooLargeError", {
|
|
60
86
|
enumerable: true,
|
|
61
87
|
get: function() {
|
|
@@ -86,3 +112,9 @@ Object.defineProperty(exports, "defineSchema", {
|
|
|
86
112
|
return defineSchema;
|
|
87
113
|
}
|
|
88
114
|
});
|
|
115
|
+
Object.defineProperty(exports, "newMsgId", {
|
|
116
|
+
enumerable: true,
|
|
117
|
+
get: function() {
|
|
118
|
+
return newMsgId;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
//#region src/schemas/define-schema.ts
|
|
2
3
|
/**
|
|
3
4
|
* Attach an `.is()` type guard to a Zod schema so schema, inferred type, and runtime guard derive from one definition (single source of truth). `Schema.parse()` at JSON boundaries; `Schema.is()` for narrowing.
|
|
@@ -8,6 +9,12 @@ function defineSchema(schema) {
|
|
|
8
9
|
} });
|
|
9
10
|
}
|
|
10
11
|
//#endregion
|
|
12
|
+
//#region src/domain/ids.ts
|
|
13
|
+
/** Message ids are UUID v4, matching the reference client's `qM()`. */
|
|
14
|
+
function newMsgId() {
|
|
15
|
+
return randomUUID();
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
11
18
|
//#region src/errors.ts
|
|
12
19
|
/** Base error for every cc-peer failure; `code` is machine-readable. */
|
|
13
20
|
var CcPeerError = class extends Error {
|
|
@@ -49,5 +56,12 @@ var AliasStartError = class extends CcPeerError {
|
|
|
49
56
|
this.name = "AliasStartError";
|
|
50
57
|
}
|
|
51
58
|
};
|
|
59
|
+
/** A message could not be sent from a reply alias: its own peer refused the send, or its worker process was gone (or went away) before acknowledging the command. */
|
|
60
|
+
var AliasSendError = class extends CcPeerError {
|
|
61
|
+
constructor(message) {
|
|
62
|
+
super("ALIAS_SEND_FAILED", message);
|
|
63
|
+
this.name = "AliasSendError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
52
66
|
//#endregion
|
|
53
|
-
export {
|
|
67
|
+
export { NoLiveInboxError as a, newMsgId as c, MessageTooLargeError as i, defineSchema as l, AliasStartError as n, NotStartedError as o, CcPeerError as r, UnknownPeerError as s, AliasSendError as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-peer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Communicate with local Claude Code instances over their native cross-session peer messaging: send and receive messages, register as a named discoverable peer, receipts, idle subscriptions, and a REST facade via `npx cc-peer`.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const require_errors = require("./errors-Dl_lSq1N.cjs");
|
|
2
|
-
let zod = require("zod");
|
|
3
|
-
//#region src/schemas/alias-ipc.ts
|
|
4
|
-
/**
|
|
5
|
-
* The parent-to-child and child-to-parent IPC contract `AliasPool`'s Node adapter (`adapters/node/forked-alias-process.ts`) and worker (`adapters/node/alias-worker.ts`) exchange over `child_process.fork()`'s built-in channel. This is deliberately independent of the wire protocol schemas in `wire.ts`: it never touches a socket, it only carries commands and events between a pool and the real OS process backing one reply alias.
|
|
6
|
-
*/
|
|
7
|
-
const AliasStartCommandSchema = require_errors.defineSchema(zod.z.object({
|
|
8
|
-
type: zod.z.literal("start"),
|
|
9
|
-
name: zod.z.string().min(1),
|
|
10
|
-
homeDir: zod.z.string().optional(),
|
|
11
|
-
socketDir: zod.z.string().optional(),
|
|
12
|
-
sessionId: zod.z.string().optional()
|
|
13
|
-
}));
|
|
14
|
-
const AliasStopCommandSchema = require_errors.defineSchema(zod.z.object({ type: zod.z.literal("stop") }));
|
|
15
|
-
const AliasCommandSchema = require_errors.defineSchema(zod.z.union([AliasStartCommandSchema, AliasStopCommandSchema]));
|
|
16
|
-
/** Sent once the worker's own CcPeer is listening and registered. */
|
|
17
|
-
const AliasStartedEventSchema = require_errors.defineSchema(zod.z.object({ type: zod.z.literal("started") }));
|
|
18
|
-
/** Mirrors CcPeer's own InboundMessage shape, carried over IPC instead of an EventEmitter within one process. */
|
|
19
|
-
const AliasMessageEventSchema = require_errors.defineSchema(zod.z.object({
|
|
20
|
-
type: zod.z.literal("message"),
|
|
21
|
-
from: zod.z.string().optional(),
|
|
22
|
-
fromSession: zod.z.string().optional(),
|
|
23
|
-
fromName: zod.z.string().optional(),
|
|
24
|
-
fromMode: zod.z.enum(["bypass", "prompting"]).optional(),
|
|
25
|
-
hopChain: zod.z.array(zod.z.string()).optional(),
|
|
26
|
-
body: zod.z.string(),
|
|
27
|
-
msgId: zod.z.string()
|
|
28
|
-
}));
|
|
29
|
-
require_errors.defineSchema(zod.z.union([AliasStartedEventSchema, AliasMessageEventSchema]));
|
|
30
|
-
//#endregion
|
|
31
|
-
Object.defineProperty(exports, "AliasCommandSchema", {
|
|
32
|
-
enumerable: true,
|
|
33
|
-
get: function() {
|
|
34
|
-
return AliasCommandSchema;
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
Object.defineProperty(exports, "AliasMessageEventSchema", {
|
|
38
|
-
enumerable: true,
|
|
39
|
-
get: function() {
|
|
40
|
-
return AliasMessageEventSchema;
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
Object.defineProperty(exports, "AliasStartedEventSchema", {
|
|
44
|
-
enumerable: true,
|
|
45
|
-
get: function() {
|
|
46
|
-
return AliasStartedEventSchema;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { o as defineSchema } from "./errors-Dcqq2MIW.mjs";
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
//#region src/schemas/alias-ipc.ts
|
|
4
|
-
/**
|
|
5
|
-
* The parent-to-child and child-to-parent IPC contract `AliasPool`'s Node adapter (`adapters/node/forked-alias-process.ts`) and worker (`adapters/node/alias-worker.ts`) exchange over `child_process.fork()`'s built-in channel. This is deliberately independent of the wire protocol schemas in `wire.ts`: it never touches a socket, it only carries commands and events between a pool and the real OS process backing one reply alias.
|
|
6
|
-
*/
|
|
7
|
-
const AliasStartCommandSchema = defineSchema(z.object({
|
|
8
|
-
type: z.literal("start"),
|
|
9
|
-
name: z.string().min(1),
|
|
10
|
-
homeDir: z.string().optional(),
|
|
11
|
-
socketDir: z.string().optional(),
|
|
12
|
-
sessionId: z.string().optional()
|
|
13
|
-
}));
|
|
14
|
-
const AliasStopCommandSchema = defineSchema(z.object({ type: z.literal("stop") }));
|
|
15
|
-
const AliasCommandSchema = defineSchema(z.union([AliasStartCommandSchema, AliasStopCommandSchema]));
|
|
16
|
-
/** Sent once the worker's own CcPeer is listening and registered. */
|
|
17
|
-
const AliasStartedEventSchema = defineSchema(z.object({ type: z.literal("started") }));
|
|
18
|
-
/** Mirrors CcPeer's own InboundMessage shape, carried over IPC instead of an EventEmitter within one process. */
|
|
19
|
-
const AliasMessageEventSchema = defineSchema(z.object({
|
|
20
|
-
type: z.literal("message"),
|
|
21
|
-
from: z.string().optional(),
|
|
22
|
-
fromSession: z.string().optional(),
|
|
23
|
-
fromName: z.string().optional(),
|
|
24
|
-
fromMode: z.enum(["bypass", "prompting"]).optional(),
|
|
25
|
-
hopChain: z.array(z.string()).optional(),
|
|
26
|
-
body: z.string(),
|
|
27
|
-
msgId: z.string()
|
|
28
|
-
}));
|
|
29
|
-
defineSchema(z.union([AliasStartedEventSchema, AliasMessageEventSchema]));
|
|
30
|
-
//#endregion
|
|
31
|
-
export { AliasMessageEventSchema as n, AliasStartedEventSchema as r, AliasCommandSchema as t };
|