@ziplayer/net 0.0.0-stage → 0.0.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.
Files changed (56) hide show
  1. package/README.md +136 -2
  2. package/dist/NetNode.d.ts +124 -0
  3. package/dist/NetNode.js +593 -0
  4. package/dist/NetNode.js.map +1 -0
  5. package/dist/ZiNet.d.ts +165 -0
  6. package/dist/ZiNet.js +599 -0
  7. package/dist/ZiNet.js.map +1 -0
  8. package/dist/crypto/handshake.d.ts +84 -0
  9. package/dist/crypto/handshake.js +204 -0
  10. package/dist/crypto/handshake.js.map +1 -0
  11. package/dist/crypto/identity.d.ts +44 -0
  12. package/dist/crypto/identity.js +92 -0
  13. package/dist/crypto/identity.js.map +1 -0
  14. package/dist/crypto/session.d.ts +56 -0
  15. package/dist/crypto/session.js +148 -0
  16. package/dist/crypto/session.js.map +1 -0
  17. package/dist/debug.d.ts +56 -0
  18. package/dist/debug.js +51 -0
  19. package/dist/debug.js.map +1 -0
  20. package/dist/ext/NetExtension.d.ts +15 -0
  21. package/dist/ext/NetExtension.js +39 -0
  22. package/dist/ext/NetExtension.js.map +1 -0
  23. package/dist/index.d.ts +28 -0
  24. package/dist/index.js +52 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/protocol/frames.d.ts +22 -0
  27. package/dist/protocol/frames.js +45 -0
  28. package/dist/protocol/frames.js.map +1 -0
  29. package/dist/router.d.ts +38 -0
  30. package/dist/router.js +51 -0
  31. package/dist/router.js.map +1 -0
  32. package/dist/search.d.ts +72 -0
  33. package/dist/search.js +94 -0
  34. package/dist/search.js.map +1 -0
  35. package/dist/stream/StreamImporter.d.ts +37 -0
  36. package/dist/stream/StreamImporter.js +138 -0
  37. package/dist/stream/StreamImporter.js.map +1 -0
  38. package/dist/stream/StreamProvider.d.ts +49 -0
  39. package/dist/stream/StreamProvider.js +157 -0
  40. package/dist/stream/StreamProvider.js.map +1 -0
  41. package/dist/transport/MemoryTransport.d.ts +36 -0
  42. package/dist/transport/MemoryTransport.js +84 -0
  43. package/dist/transport/MemoryTransport.js.map +1 -0
  44. package/dist/transport/MqttTransport.d.ts +26 -0
  45. package/dist/transport/MqttTransport.js +104 -0
  46. package/dist/transport/MqttTransport.js.map +1 -0
  47. package/dist/transport/Transport.d.ts +21 -0
  48. package/dist/transport/Transport.js +18 -0
  49. package/dist/transport/Transport.js.map +1 -0
  50. package/dist/voice/Gateway.d.ts +16 -0
  51. package/dist/voice/Gateway.js +35 -0
  52. package/dist/voice/Gateway.js.map +1 -0
  53. package/dist/voice/RemoteVoice.d.ts +29 -0
  54. package/dist/voice/RemoteVoice.js +80 -0
  55. package/dist/voice/RemoteVoice.js.map +1 -0
  56. package/package.json +53 -5
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/crypto/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Debug trace of everything a {@link NetNode} puts on (or takes from) the broker.
3
+ *
4
+ * `node.on("debug", (event) => ...)` receives {@link NetDebugEvent}s on three layers:
5
+ *
6
+ * - `wire`: the exact MQTT message the broker sees: topic, qos, retain, size and the first bytes in hex.
7
+ * Control frames are ciphertext here, so this is what an attacker with broker access can read.
8
+ * - `message`: the same traffic one level up, before it is encrypted / after it is decrypted: message type,
9
+ * request id, and body (sensitive keys redacted). This is "what net sends".
10
+ * - `info`: free-form notes from routing code (for example which node a search was sent to).
11
+ */
12
+ export type NetDebugLayer = "wire" | "message" | "info";
13
+ export type NetDebugKind = "presence" | "handshake" | "control" | "audio" | "audio-encrypted" | "unknown";
14
+ export interface NetDebugEvent {
15
+ at: number;
16
+ /** Node that emitted the event. */
17
+ node: string;
18
+ layer: NetDebugLayer;
19
+ /** `out` = sent by this node, `in` = received, `info` = not a message. */
20
+ dir: "out" | "in" | "info";
21
+ kind?: NetDebugKind;
22
+ /** wire: MQTT topic. */
23
+ topic?: string;
24
+ /** The other node, when known (recipient for `out`, sender for decrypted `in` messages). */
25
+ peer?: string;
26
+ qos?: number;
27
+ retain?: boolean;
28
+ /** Size of the MQTT payload (wire) or of the frame (message). */
29
+ bytes?: number;
30
+ /** wire: first bytes of the payload in hex. */
31
+ hex?: string;
32
+ /** True when the payload on the wire is ciphertext. */
33
+ encrypted?: boolean;
34
+ sessionId?: string;
35
+ /** message: request/notify type (`net.search`, `voice.event`...), `reply` for replies, `hs1`/`hs2`/`hs3` for handshakes. */
36
+ type?: string;
37
+ /** message: request id. */
38
+ id?: number;
39
+ /** message: id of the request this replies to. */
40
+ re?: number;
41
+ /** message: decoded body (redacted copy). */
42
+ body?: unknown;
43
+ /** audio frames. */
44
+ streamId?: number;
45
+ seq?: number;
46
+ flags?: number;
47
+ /** info: text. */
48
+ note?: string;
49
+ /** wire: the publish failed. */
50
+ error?: string;
51
+ }
52
+ /** Copy of `value` that is safe to print: sensitive keys hidden, long strings and arrays shortened. */
53
+ export declare function redact(value: unknown, depth?: number): unknown;
54
+ export declare function hexPreview(buf: Uint8Array, max?: number): string;
55
+ /** One-line, human readable rendering of a debug event. */
56
+ export declare function formatNetDebug(e: NetDebugEvent): string;
package/dist/debug.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.redact = redact;
4
+ exports.hexPreview = hexPreview;
5
+ exports.formatNetDebug = formatNetDebug;
6
+ const SENSITIVE_KEY = /token|secret|password|passwd|private|session_?id|authorization|cookie/i;
7
+ const MAX_DEPTH = 6;
8
+ const MAX_STRING = 300;
9
+ const MAX_ARRAY = 20;
10
+ /** Copy of `value` that is safe to print: sensitive keys hidden, long strings and arrays shortened. */
11
+ function redact(value, depth = 0) {
12
+ if (typeof value === "string")
13
+ return value.length > MAX_STRING ? `${value.slice(0, MAX_STRING)}…(+${value.length - MAX_STRING} chars)` : value;
14
+ if (value === null || typeof value !== "object")
15
+ return typeof value === "bigint" ? value.toString() : value;
16
+ if (depth >= MAX_DEPTH)
17
+ return "[…]";
18
+ if (Array.isArray(value)) {
19
+ const head = value.slice(0, MAX_ARRAY).map((v) => redact(v, depth + 1));
20
+ return value.length > MAX_ARRAY ? [...head, `…(+${value.length - MAX_ARRAY} items)`] : head;
21
+ }
22
+ const out = {};
23
+ for (const [key, v] of Object.entries(value)) {
24
+ out[key] = SENSITIVE_KEY.test(key) ? "[redacted]" : redact(v, depth + 1);
25
+ }
26
+ return out;
27
+ }
28
+ function hexPreview(buf, max = 24) {
29
+ const head = Buffer.from(buf.subarray(0, max)).toString("hex");
30
+ return buf.length > max ? `${head}…` : head;
31
+ }
32
+ /** One-line, human readable rendering of a debug event. */
33
+ function formatNetDebug(e) {
34
+ const arrow = e.dir === "out" ? "→" : e.dir === "in" ? "←" : "•";
35
+ if (e.layer === "info")
36
+ return `[net:${e.node}] ${arrow} ${e.note ?? ""}`;
37
+ if (e.layer === "wire") {
38
+ const flags = `${e.qos !== undefined ? ` qos${e.qos}` : ""}${e.retain ? " retain" : ""}`;
39
+ const detail = e.body !== undefined ? ` ${JSON.stringify(e.body)}` : e.type ? ` ${e.type}` : "";
40
+ return (`[net:${e.node}] ${arrow} MQTT ${e.dir === "out" ? "PUBLISH" : "MESSAGE"} ${e.topic}${flags} ${e.bytes}B ` +
41
+ `${e.kind}${e.encrypted ? "(encrypted)" : ""}${detail}${e.hex ? ` [${e.hex}]` : ""}${e.error ? ` FAILED: ${e.error}` : ""}`);
42
+ }
43
+ if (e.kind === "audio" || e.kind === "audio-encrypted") {
44
+ return `[net:${e.node}] ${arrow} audio ${e.dir === "out" ? "to" : "from"} ${e.peer ?? "?"} stream#${e.streamId} seq ${e.seq} ${e.bytes}B${e.flags ? ` flags ${e.flags}` : ""}`;
45
+ }
46
+ const who = e.peer ? ` ${e.dir === "out" ? "to" : "from"} ${e.peer}` : "";
47
+ const ref = e.re !== undefined ? ` re#${e.re}` : e.id !== undefined ? ` #${e.id}` : "";
48
+ const body = e.body !== undefined ? ` ${JSON.stringify(e.body)}` : "";
49
+ return `[net:${e.node}] ${arrow} ${e.kind ?? "msg"}${who} ${e.type ?? ""}${ref}${e.bytes !== undefined ? ` ${e.bytes}B` : ""}${body}`;
50
+ }
51
+ //# sourceMappingURL=debug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../src/debug.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { BaseExtension, type ExtensionContext, type ExtensionStreamRequest, type Player, type StreamInfo } from "ziplayer";
2
+ import type { ZiNet } from "../ZiNet";
3
+ /**
4
+ * Per-player extension. Supplies streams from another node (`track.metadata.net.owner`) and, when the
5
+ * player's voice has been delegated, a remote playback handle that drives the executor.
6
+ */
7
+ export declare class NetExtension extends BaseExtension {
8
+ private readonly net;
9
+ name: string;
10
+ version: string;
11
+ player: Player | null;
12
+ constructor(net: ZiNet, player?: Player | null);
13
+ active(): boolean;
14
+ provideStream(context: ExtensionContext, payload: ExtensionStreamRequest): Promise<StreamInfo | null>;
15
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NetExtension = void 0;
4
+ const ziplayer_1 = require("ziplayer");
5
+ /**
6
+ * Per-player extension. Supplies streams from another node (`track.metadata.net.owner`) and, when the
7
+ * player's voice has been delegated, a remote playback handle that drives the executor.
8
+ */
9
+ class NetExtension extends ziplayer_1.BaseExtension {
10
+ net;
11
+ name = "ziplayer-net";
12
+ version = "0.1.0";
13
+ player;
14
+ constructor(net, player = null) {
15
+ super();
16
+ this.net = net;
17
+ this.player = player;
18
+ }
19
+ active() {
20
+ return true;
21
+ }
22
+ async provideStream(context, payload) {
23
+ const player = (context.player ?? this.player);
24
+ const track = payload.track;
25
+ if (!player)
26
+ return null;
27
+ if (this.net.delegationFor(player.guildId)) {
28
+ return this.net.buildRemoteStream(player, track);
29
+ }
30
+ const owner = track.metadata?.net?.owner;
31
+ if (owner && owner !== this.net.nodeId) {
32
+ const info = await this.net.openRemoteStream(owner, track, 0, context.signal);
33
+ return info;
34
+ }
35
+ return null;
36
+ }
37
+ }
38
+ exports.NetExtension = NetExtension;
39
+ //# sourceMappingURL=NetExtension.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NetExtension.js","sourceRoot":"","sources":["../../src/ext/NetExtension.ts"],"names":[],"mappings":";;;AAAA,uCAA2H;AAG3H;;;GAGG;AACH,MAAa,YAAa,SAAQ,wBAAa;IAM5B;IALlB,IAAI,GAAG,cAAc,CAAC;IACtB,OAAO,GAAG,OAAO,CAAC;IAClB,MAAM,CAAgB;IAEtB,YACkB,GAAU,EAC3B,SAAwB,IAAI;QAE5B,KAAK,EAAE,CAAC;QAHS,QAAG,GAAH,GAAG,CAAO;QAI3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACtB,CAAC;IAED,MAAM;QACL,OAAO,IAAI,CAAC;IACb,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAyB,EAAE,OAA+B;QAC7E,MAAM,MAAM,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAkB,CAAC;QAChE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAEzB,IAAI,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,OAAO,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAiC,CAAC;QAClF,CAAC;QAED,MAAM,KAAK,GAAI,KAAK,CAAC,QAAgB,EAAE,GAAG,EAAE,KAA2B,CAAC;QACxE,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;YAC9E,OAAO,IAA6B,CAAC;QACtC,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;CACD;AAjCD,oCAiCC"}
@@ -0,0 +1,28 @@
1
+ export { NetNode, NetError } from "./NetNode";
2
+ export type { NetNodeOptions, RequestContext, RequestHandler } from "./NetNode";
3
+ export { ZiNet, markTrack } from "./ZiNet";
4
+ export type { ZiNetOptions, DelegateVoiceOptions } from "./ZiNet";
5
+ export { parseSearchQuery, DEFAULT_SEARCH_ALIASES } from "./search";
6
+ export type { NetSearchOptions, NetSearchResult, ServeSearchOptions, WireSearchResult } from "./search";
7
+ export { formatNetDebug, redact } from "./debug";
8
+ export type { NetDebugEvent, NetDebugKind, NetDebugLayer } from "./debug";
9
+ export { NetExtension } from "./ext/NetExtension";
10
+ export { generateIdentity, loadIdentity, loadOrCreateIdentity, fingerprint, TrustStore } from "./crypto/identity";
11
+ export type { NodeIdentity, TrustedPeer, NetRole, GeneratedIdentity } from "./crypto/identity";
12
+ export { HandshakeError, HandshakeInitiator, HandshakeResponder, PROTOCOL_VERSION } from "./crypto/handshake";
13
+ export { SecureChannel, SessionError, ReplayWindow } from "./crypto/session";
14
+ export type { Transport, PublishOptions } from "./transport/Transport";
15
+ export { topicMatches } from "./transport/Transport";
16
+ export { MemoryBroker, MemoryTransport } from "./transport/MemoryTransport";
17
+ export { MqttTransport } from "./transport/MqttTransport";
18
+ export type { MqttTransportOptions } from "./transport/MqttTransport";
19
+ export { StreamProvider, DEFAULT_ALLOWED_STREAM_TYPES } from "./stream/StreamProvider";
20
+ export type { StreamProviderOptions, ProvidedStreamInfo } from "./stream/StreamProvider";
21
+ export { StreamImporter } from "./stream/StreamImporter";
22
+ export type { RemoteStream, StreamImporterOptions } from "./stream/StreamImporter";
23
+ export { RemoteVoiceHub, serializeTrack } from "./voice/RemoteVoice";
24
+ export type { RemoteVoiceChannel } from "./voice/RemoteVoice";
25
+ export { discordJsGateway } from "./voice/Gateway";
26
+ export type { GatewayLike } from "./voice/Gateway";
27
+ export { planRoute } from "./router";
28
+ export type { RoutePlan, RoutePeer, RouteTrack, PlanRouteInput } from "./router";
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.planRoute = exports.discordJsGateway = exports.serializeTrack = exports.RemoteVoiceHub = exports.StreamImporter = exports.DEFAULT_ALLOWED_STREAM_TYPES = exports.StreamProvider = exports.MqttTransport = exports.MemoryTransport = exports.MemoryBroker = exports.topicMatches = exports.ReplayWindow = exports.SessionError = exports.SecureChannel = exports.PROTOCOL_VERSION = exports.HandshakeResponder = exports.HandshakeInitiator = exports.HandshakeError = exports.TrustStore = exports.fingerprint = exports.loadOrCreateIdentity = exports.loadIdentity = exports.generateIdentity = exports.NetExtension = exports.redact = exports.formatNetDebug = exports.DEFAULT_SEARCH_ALIASES = exports.parseSearchQuery = exports.markTrack = exports.ZiNet = exports.NetError = exports.NetNode = void 0;
4
+ var NetNode_1 = require("./NetNode");
5
+ Object.defineProperty(exports, "NetNode", { enumerable: true, get: function () { return NetNode_1.NetNode; } });
6
+ Object.defineProperty(exports, "NetError", { enumerable: true, get: function () { return NetNode_1.NetError; } });
7
+ var ZiNet_1 = require("./ZiNet");
8
+ Object.defineProperty(exports, "ZiNet", { enumerable: true, get: function () { return ZiNet_1.ZiNet; } });
9
+ Object.defineProperty(exports, "markTrack", { enumerable: true, get: function () { return ZiNet_1.markTrack; } });
10
+ var search_1 = require("./search");
11
+ Object.defineProperty(exports, "parseSearchQuery", { enumerable: true, get: function () { return search_1.parseSearchQuery; } });
12
+ Object.defineProperty(exports, "DEFAULT_SEARCH_ALIASES", { enumerable: true, get: function () { return search_1.DEFAULT_SEARCH_ALIASES; } });
13
+ var debug_1 = require("./debug");
14
+ Object.defineProperty(exports, "formatNetDebug", { enumerable: true, get: function () { return debug_1.formatNetDebug; } });
15
+ Object.defineProperty(exports, "redact", { enumerable: true, get: function () { return debug_1.redact; } });
16
+ var NetExtension_1 = require("./ext/NetExtension");
17
+ Object.defineProperty(exports, "NetExtension", { enumerable: true, get: function () { return NetExtension_1.NetExtension; } });
18
+ var identity_1 = require("./crypto/identity");
19
+ Object.defineProperty(exports, "generateIdentity", { enumerable: true, get: function () { return identity_1.generateIdentity; } });
20
+ Object.defineProperty(exports, "loadIdentity", { enumerable: true, get: function () { return identity_1.loadIdentity; } });
21
+ Object.defineProperty(exports, "loadOrCreateIdentity", { enumerable: true, get: function () { return identity_1.loadOrCreateIdentity; } });
22
+ Object.defineProperty(exports, "fingerprint", { enumerable: true, get: function () { return identity_1.fingerprint; } });
23
+ Object.defineProperty(exports, "TrustStore", { enumerable: true, get: function () { return identity_1.TrustStore; } });
24
+ var handshake_1 = require("./crypto/handshake");
25
+ Object.defineProperty(exports, "HandshakeError", { enumerable: true, get: function () { return handshake_1.HandshakeError; } });
26
+ Object.defineProperty(exports, "HandshakeInitiator", { enumerable: true, get: function () { return handshake_1.HandshakeInitiator; } });
27
+ Object.defineProperty(exports, "HandshakeResponder", { enumerable: true, get: function () { return handshake_1.HandshakeResponder; } });
28
+ Object.defineProperty(exports, "PROTOCOL_VERSION", { enumerable: true, get: function () { return handshake_1.PROTOCOL_VERSION; } });
29
+ var session_1 = require("./crypto/session");
30
+ Object.defineProperty(exports, "SecureChannel", { enumerable: true, get: function () { return session_1.SecureChannel; } });
31
+ Object.defineProperty(exports, "SessionError", { enumerable: true, get: function () { return session_1.SessionError; } });
32
+ Object.defineProperty(exports, "ReplayWindow", { enumerable: true, get: function () { return session_1.ReplayWindow; } });
33
+ var Transport_1 = require("./transport/Transport");
34
+ Object.defineProperty(exports, "topicMatches", { enumerable: true, get: function () { return Transport_1.topicMatches; } });
35
+ var MemoryTransport_1 = require("./transport/MemoryTransport");
36
+ Object.defineProperty(exports, "MemoryBroker", { enumerable: true, get: function () { return MemoryTransport_1.MemoryBroker; } });
37
+ Object.defineProperty(exports, "MemoryTransport", { enumerable: true, get: function () { return MemoryTransport_1.MemoryTransport; } });
38
+ var MqttTransport_1 = require("./transport/MqttTransport");
39
+ Object.defineProperty(exports, "MqttTransport", { enumerable: true, get: function () { return MqttTransport_1.MqttTransport; } });
40
+ var StreamProvider_1 = require("./stream/StreamProvider");
41
+ Object.defineProperty(exports, "StreamProvider", { enumerable: true, get: function () { return StreamProvider_1.StreamProvider; } });
42
+ Object.defineProperty(exports, "DEFAULT_ALLOWED_STREAM_TYPES", { enumerable: true, get: function () { return StreamProvider_1.DEFAULT_ALLOWED_STREAM_TYPES; } });
43
+ var StreamImporter_1 = require("./stream/StreamImporter");
44
+ Object.defineProperty(exports, "StreamImporter", { enumerable: true, get: function () { return StreamImporter_1.StreamImporter; } });
45
+ var RemoteVoice_1 = require("./voice/RemoteVoice");
46
+ Object.defineProperty(exports, "RemoteVoiceHub", { enumerable: true, get: function () { return RemoteVoice_1.RemoteVoiceHub; } });
47
+ Object.defineProperty(exports, "serializeTrack", { enumerable: true, get: function () { return RemoteVoice_1.serializeTrack; } });
48
+ var Gateway_1 = require("./voice/Gateway");
49
+ Object.defineProperty(exports, "discordJsGateway", { enumerable: true, get: function () { return Gateway_1.discordJsGateway; } });
50
+ var router_1 = require("./router");
51
+ Object.defineProperty(exports, "planRoute", { enumerable: true, get: function () { return router_1.planRoute; } });
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,qCAA8C;AAArC,kGAAA,OAAO,OAAA;AAAE,mGAAA,QAAQ,OAAA;AAE1B,iCAA2C;AAAlC,8FAAA,KAAK,OAAA;AAAE,kGAAA,SAAS,OAAA;AAEzB,mCAAoE;AAA3D,0GAAA,gBAAgB,OAAA;AAAE,gHAAA,sBAAsB,OAAA;AAEjD,iCAAiD;AAAxC,uGAAA,cAAc,OAAA;AAAE,+FAAA,MAAM,OAAA;AAE/B,mDAAkD;AAAzC,4GAAA,YAAY,OAAA;AACrB,8CAAkH;AAAzG,4GAAA,gBAAgB,OAAA;AAAE,wGAAA,YAAY,OAAA;AAAE,gHAAA,oBAAoB,OAAA;AAAE,uGAAA,WAAW,OAAA;AAAE,sGAAA,UAAU,OAAA;AAEtF,gDAA8G;AAArG,2GAAA,cAAc,OAAA;AAAE,+GAAA,kBAAkB,OAAA;AAAE,+GAAA,kBAAkB,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AACjF,4CAA6E;AAApE,wGAAA,aAAa,OAAA;AAAE,uGAAA,YAAY,OAAA;AAAE,uGAAA,YAAY,OAAA;AAElD,mDAAqD;AAA5C,yGAAA,YAAY,OAAA;AACrB,+DAA4E;AAAnE,+GAAA,YAAY,OAAA;AAAE,kHAAA,eAAe,OAAA;AACtC,2DAA0D;AAAjD,8GAAA,aAAa,OAAA;AAEtB,0DAAuF;AAA9E,gHAAA,cAAc,OAAA;AAAE,8HAAA,4BAA4B,OAAA;AAErD,0DAAyD;AAAhD,gHAAA,cAAc,OAAA;AAEvB,mDAAqE;AAA5D,6GAAA,cAAc,OAAA;AAAE,6GAAA,cAAc,OAAA;AAEvC,2CAAmD;AAA1C,2GAAA,gBAAgB,OAAA;AAEzB,mCAAqC;AAA5B,mGAAA,SAAS,OAAA"}
@@ -0,0 +1,22 @@
1
+ /** Plain (unencrypted) audio frame: `[KIND.AUDIO][sid 8][streamId 4][seq 4][flags 1][payload]`. */
2
+ export declare const AUDIO_FLAG_EOS = 1;
3
+ export declare const AUDIO_HEADER_BYTES = 18;
4
+ export interface AudioFrame {
5
+ streamId: number;
6
+ seq: number;
7
+ flags: number;
8
+ payload: Buffer;
9
+ }
10
+ export declare function encodePlainAudio(sessionId: string, frame: AudioFrame): Buffer;
11
+ export declare function decodePlainAudio(buf: Buffer): {
12
+ sessionId: string;
13
+ frame: AudioFrame;
14
+ };
15
+ export declare function sessionIdOf(buf: Buffer): string | null;
16
+ /** Topic layout. Everything lives under `zi/v1/<network>`. */
17
+ export declare const topics: {
18
+ presence: (net: string, node: string) => string;
19
+ presenceAll: (net: string) => string;
20
+ inbox: (net: string, node: string) => string;
21
+ audio: (net: string, node: string) => string;
22
+ };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.topics = exports.AUDIO_HEADER_BYTES = exports.AUDIO_FLAG_EOS = void 0;
4
+ exports.encodePlainAudio = encodePlainAudio;
5
+ exports.decodePlainAudio = decodePlainAudio;
6
+ exports.sessionIdOf = sessionIdOf;
7
+ const session_1 = require("../crypto/session");
8
+ /** Plain (unencrypted) audio frame: `[KIND.AUDIO][sid 8][streamId 4][seq 4][flags 1][payload]`. */
9
+ exports.AUDIO_FLAG_EOS = 0x01;
10
+ exports.AUDIO_HEADER_BYTES = 18;
11
+ function encodePlainAudio(sessionId, frame) {
12
+ const header = Buffer.alloc(exports.AUDIO_HEADER_BYTES);
13
+ header[0] = session_1.KIND.AUDIO;
14
+ Buffer.from(sessionId, "hex").copy(header, 1);
15
+ header.writeUInt32BE(frame.streamId >>> 0, 9);
16
+ header.writeUInt32BE(frame.seq >>> 0, 13);
17
+ header[17] = frame.flags & 0xff;
18
+ return Buffer.concat([header, frame.payload]);
19
+ }
20
+ function decodePlainAudio(buf) {
21
+ if (buf.length < exports.AUDIO_HEADER_BYTES || buf[0] !== session_1.KIND.AUDIO)
22
+ throw new Error("Malformed audio frame");
23
+ return {
24
+ sessionId: buf.subarray(1, 9).toString("hex"),
25
+ frame: {
26
+ streamId: buf.readUInt32BE(9),
27
+ seq: buf.readUInt32BE(13),
28
+ flags: buf[17],
29
+ payload: buf.subarray(exports.AUDIO_HEADER_BYTES),
30
+ },
31
+ };
32
+ }
33
+ function sessionIdOf(buf) {
34
+ if (buf.length < 9)
35
+ return null;
36
+ return buf.subarray(1, 9).toString("hex");
37
+ }
38
+ /** Topic layout. Everything lives under `zi/v1/<network>`. */
39
+ exports.topics = {
40
+ presence: (net, node) => `zi/v1/${net}/presence/${node}`,
41
+ presenceAll: (net) => `zi/v1/${net}/presence/+`,
42
+ inbox: (net, node) => `zi/v1/${net}/node/${node}/in`,
43
+ audio: (net, node) => `zi/v1/${net}/node/${node}/au`,
44
+ };
45
+ //# sourceMappingURL=frames.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frames.js","sourceRoot":"","sources":["../../src/protocol/frames.ts"],"names":[],"mappings":";;;AAaA,4CAQC;AAED,4CAWC;AAED,kCAGC;AAvCD,+CAAyC;AAEzC,mGAAmG;AACtF,QAAA,cAAc,GAAG,IAAI,CAAC;AACtB,QAAA,kBAAkB,GAAG,EAAE,CAAC;AASrC,SAAgB,gBAAgB,CAAC,SAAiB,EAAE,KAAiB;IACpE,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,0BAAkB,CAAC,CAAC;IAChD,MAAM,CAAC,CAAC,CAAC,GAAG,cAAI,CAAC,KAAK,CAAC;IACvB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC;IAChC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,SAAgB,gBAAgB,CAAC,GAAW;IAC3C,IAAI,GAAG,CAAC,MAAM,GAAG,0BAAkB,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,cAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACvG,OAAO;QACN,SAAS,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QAC7C,KAAK,EAAE;YACN,QAAQ,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC;YAC7B,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACzB,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;YACd,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,0BAAkB,CAAC;SACzC;KACD,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,GAAW;IACtC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AAED,8DAA8D;AACjD,QAAA,MAAM,GAAG;IACrB,QAAQ,EAAE,CAAC,GAAW,EAAE,IAAY,EAAE,EAAE,CAAC,SAAS,GAAG,aAAa,IAAI,EAAE;IACxE,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,SAAS,GAAG,aAAa;IACvD,KAAK,EAAE,CAAC,GAAW,EAAE,IAAY,EAAE,EAAE,CAAC,SAAS,GAAG,SAAS,IAAI,KAAK;IACpE,KAAK,EAAE,CAAC,GAAW,EAAE,IAAY,EAAE,EAAE,CAAC,SAAS,GAAG,SAAS,IAAI,KAAK;CACpE,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Route planning: decide, for a batch of tracks, whether to keep the voice here and pull audio from other
3
+ * nodes ("relay"), or move the voice to the node that can play most of them itself ("handoff").
4
+ *
5
+ * Rule of thumb from the design discussion: if most tracks can only be resolved elsewhere (e.g. this node
6
+ * only has SoundCloud and a 50-song YouTube playlist is added) moving the voice is cheaper than relaying
7
+ * every packet; if only a few tracks are foreign, relaying them keeps the voice where it is.
8
+ */
9
+ export interface RoutePeer {
10
+ id: string;
11
+ /** Plugin / source names the peer can resolve streams for (e.g. "youtube"). */
12
+ sources: Iterable<string>;
13
+ /** Optional load hint (lower is better), used to break ties. */
14
+ load?: number;
15
+ }
16
+ export interface RouteTrack {
17
+ source?: string;
18
+ }
19
+ export interface RoutePlan {
20
+ mode: "local" | "relay" | "handoff";
21
+ /** Handoff target. */
22
+ executor?: string;
23
+ /** For each track, the node that should resolve its stream. */
24
+ owners: string[];
25
+ /** Fraction of tracks this node cannot resolve itself. */
26
+ foreignShare: number;
27
+ /** Indices nobody can resolve. */
28
+ unresolvable: number[];
29
+ }
30
+ export interface PlanRouteInput {
31
+ selfId: string;
32
+ selfSources: Iterable<string>;
33
+ peers: RoutePeer[];
34
+ tracks: RouteTrack[];
35
+ /** Foreign share at or above which the voice is handed off. Default 0.5. */
36
+ handoffThreshold?: number;
37
+ }
38
+ export declare function planRoute(input: PlanRouteInput): RoutePlan;
package/dist/router.js ADDED
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.planRoute = planRoute;
4
+ function planRoute(input) {
5
+ const selfSources = new Set(input.selfSources);
6
+ const peers = input.peers.map((p) => ({ ...p, set: new Set(p.sources) }));
7
+ const tracks = input.tracks;
8
+ const canSelf = (t) => !t.source || selfSources.has(t.source);
9
+ const canPeer = (p, t) => !t.source || p.set.has(t.source);
10
+ const foreign = tracks.map((t, i) => (canSelf(t) ? -1 : i)).filter((i) => i >= 0);
11
+ const owners = tracks.map(() => input.selfId);
12
+ const unresolvable = [];
13
+ const share = tracks.length ? foreign.length / tracks.length : 0;
14
+ if (foreign.length === 0)
15
+ return { mode: "local", owners, foreignShare: 0, unresolvable };
16
+ // Best single node for the foreign tracks (most coverage, then lowest load).
17
+ const ranked = peers
18
+ .map((p) => ({ p, covered: foreign.filter((i) => canPeer(p, tracks[i])).length }))
19
+ .filter((x) => x.covered > 0)
20
+ .sort((a, b) => b.covered - a.covered || (a.p.load ?? 0) - (b.p.load ?? 0));
21
+ const pickFor = (i, preferred) => {
22
+ const cands = peers.filter((p) => canPeer(p, tracks[i]));
23
+ if (!cands.length)
24
+ return null;
25
+ return (cands.find((p) => p.id === preferred) ?? cands.sort((a, b) => (a.load ?? 0) - (b.load ?? 0))[0]).id;
26
+ };
27
+ const best = ranked[0];
28
+ const threshold = input.handoffThreshold ?? 0.5;
29
+ if (best && share >= threshold) {
30
+ const executor = best.p.id;
31
+ tracks.forEach((t, i) => {
32
+ if (canPeer(best.p, t))
33
+ return void (owners[i] = executor);
34
+ const other = canSelf(t) ? input.selfId : pickFor(i);
35
+ if (other)
36
+ owners[i] = other;
37
+ else
38
+ unresolvable.push(i);
39
+ });
40
+ return { mode: "handoff", executor, owners, foreignShare: share, unresolvable };
41
+ }
42
+ for (const i of foreign) {
43
+ const owner = pickFor(i, best?.p.id);
44
+ if (owner)
45
+ owners[i] = owner;
46
+ else
47
+ unresolvable.push(i);
48
+ }
49
+ return { mode: "relay", owners, foreignShare: share, unresolvable };
50
+ }
51
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,72 @@
1
+ /** Wire shape of a search result. Tracks are plain JSON; `metadata.net.owner` is set by the receiver, never trusted from the wire. */
2
+ export interface WireSearchResult {
3
+ tracks: any[];
4
+ playlist?: {
5
+ name: string;
6
+ url?: string;
7
+ thumbnail?: string;
8
+ } | null;
9
+ query?: string;
10
+ source?: string;
11
+ }
12
+ export interface NetSearchOptions {
13
+ /** Forwarded as `requestedBy` of the returned tracks. */
14
+ requestedBy?: unknown;
15
+ /** Restrict to one source (plugin name or alias such as `yt`). A `yt:` prefix in the query does the same. */
16
+ source?: string;
17
+ /** Only ask these nodes (default: every online, trusted node that serves search). */
18
+ peers?: string[];
19
+ /**
20
+ * Where this node's own plugins come in. `first` (default): try them first, ask the others only when nothing is found.
21
+ * `last`: ask the others first. `only`: never leave this node. `never`: skip them.
22
+ */
23
+ local?: "first" | "last" | "only" | "never";
24
+ /** `true`: ask every candidate and merge the tracks (de-duplicated). Default `false`: the first non-empty answer wins. */
25
+ merge?: boolean;
26
+ /** Max tracks returned (default 10). */
27
+ limit?: number;
28
+ timeoutMs?: number;
29
+ signal?: AbortSignal;
30
+ }
31
+ export interface NetSearchResult {
32
+ tracks: any[];
33
+ playlist?: {
34
+ name: string;
35
+ url?: string;
36
+ thumbnail?: string;
37
+ } | null;
38
+ query?: string;
39
+ source?: string;
40
+ /** Node whose plugins produced the tracks (this node for local results). With `merge`, the first contributor. */
41
+ node: string;
42
+ /** Every node that contributed tracks. */
43
+ nodes: string[];
44
+ }
45
+ export interface ServeSearchOptions {
46
+ /** Decide per query / caller. Throw or return `false` to refuse. */
47
+ allow?: (query: string, peerId: string) => boolean | Promise<boolean>;
48
+ /** Max tracks sent back per request (default 25). */
49
+ maxResults?: number;
50
+ /** Soft cap for the JSON size of one answer, trailing tracks are dropped (default 200 000). */
51
+ maxResponseBytes?: number;
52
+ }
53
+ export declare const DEFAULT_SEARCH_ALIASES: Record<string, string>;
54
+ export declare const MAX_QUERY_CHARS = 512;
55
+ export declare const MAX_IMPORTED_TRACKS = 100;
56
+ /**
57
+ * `yt:lofi` → `{ source: "youtube", query: "lofi" }`. The `tts:` prefix stays in the query because the TTS plugin needs it.
58
+ * Anything without a known prefix (including `https://…`) has no source.
59
+ */
60
+ export declare function parseSearchQuery(text: string, aliases?: Record<string, string>, explicitSource?: string): {
61
+ source?: string;
62
+ query: string;
63
+ };
64
+ /** Provider side: turn a plugin SearchResult into something safe and small enough for one control frame. */
65
+ export declare function toWireResult(result: any, limit: number, maxBytes: number): WireSearchResult;
66
+ /**
67
+ * Consumer side: validate what a peer answered and stamp the ONLY owner that matters, the node that answered.
68
+ * The peer cannot point playback at a different node by writing `metadata.net.owner` itself.
69
+ */
70
+ export declare function importWireResult(raw: any, owner: string, requestedBy?: unknown, limit?: number): WireSearchResult;
71
+ /** Order-preserving de-duplication of tracks that came from the same node with the same id / url. */
72
+ export declare function dedupeNetTracks(tracks: any[]): any[];
package/dist/search.js ADDED
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_IMPORTED_TRACKS = exports.MAX_QUERY_CHARS = exports.DEFAULT_SEARCH_ALIASES = void 0;
4
+ exports.parseSearchQuery = parseSearchQuery;
5
+ exports.toWireResult = toWireResult;
6
+ exports.importWireResult = importWireResult;
7
+ exports.dedupeNetTracks = dedupeNetTracks;
8
+ const RemoteVoice_1 = require("./voice/RemoteVoice");
9
+ exports.DEFAULT_SEARCH_ALIASES = {
10
+ yt: "youtube",
11
+ youtube: "youtube",
12
+ sc: "soundcloud",
13
+ soundcloud: "soundcloud",
14
+ sp: "spotify",
15
+ spotify: "spotify",
16
+ tts: "tts",
17
+ };
18
+ exports.MAX_QUERY_CHARS = 512;
19
+ exports.MAX_IMPORTED_TRACKS = 100;
20
+ /**
21
+ * `yt:lofi` → `{ source: "youtube", query: "lofi" }`. The `tts:` prefix stays in the query because the TTS plugin needs it.
22
+ * Anything without a known prefix (including `https://…`) has no source.
23
+ */
24
+ function parseSearchQuery(text, aliases = exports.DEFAULT_SEARCH_ALIASES, explicitSource) {
25
+ const resolve = (name) => aliases[name.toLowerCase()] ?? name.toLowerCase();
26
+ if (explicitSource)
27
+ return { source: resolve(explicitSource), query: text.trim() };
28
+ const m = text.match(/^(\w+):([\s\S]*)$/);
29
+ const source = m ? aliases[m[1].toLowerCase()] : undefined;
30
+ if (!m || !source)
31
+ return { query: text.trim() };
32
+ return { source, query: source === "tts" ? text.trim() : m[2].trim() };
33
+ }
34
+ /** Provider side: turn a plugin SearchResult into something safe and small enough for one control frame. */
35
+ function toWireResult(result, limit, maxBytes) {
36
+ const tracks = [];
37
+ let bytes = 0;
38
+ for (const track of (result?.tracks ?? []).slice(0, limit)) {
39
+ const wire = (0, RemoteVoice_1.serializeTrack)(track);
40
+ if (!wire || typeof wire !== "object")
41
+ continue;
42
+ // Whoever asked is the requester; the provider's requester (a Discord user object...) is meaningless over there.
43
+ delete wire.requestedBy;
44
+ if (wire.metadata?.net)
45
+ delete wire.metadata.net;
46
+ const size = Buffer.byteLength(JSON.stringify(wire));
47
+ if (tracks.length && bytes + size > maxBytes)
48
+ break;
49
+ tracks.push(wire);
50
+ bytes += size;
51
+ }
52
+ const playlist = result?.playlist ? (0, RemoteVoice_1.serializeTrack)(result.playlist) : null;
53
+ return { tracks, playlist, query: typeof result?.query === "string" ? result.query : undefined, source: result?.source };
54
+ }
55
+ /**
56
+ * Consumer side: validate what a peer answered and stamp the ONLY owner that matters, the node that answered.
57
+ * The peer cannot point playback at a different node by writing `metadata.net.owner` itself.
58
+ */
59
+ function importWireResult(raw, owner, requestedBy, limit = 10) {
60
+ const tracks = [];
61
+ if (Array.isArray(raw?.tracks)) {
62
+ for (const item of raw.tracks.slice(0, Math.min(limit, exports.MAX_IMPORTED_TRACKS))) {
63
+ if (!item || typeof item !== "object" || Array.isArray(item))
64
+ continue;
65
+ if (item.id === undefined && typeof item.url !== "string")
66
+ continue;
67
+ const metadata = item.metadata && typeof item.metadata === "object" && !Array.isArray(item.metadata) ? item.metadata : {};
68
+ const track = { ...item, metadata: { ...metadata, net: { owner } } };
69
+ if (requestedBy !== undefined)
70
+ track.requestedBy = requestedBy;
71
+ tracks.push(track);
72
+ }
73
+ }
74
+ const p = raw?.playlist;
75
+ const playlist = p && typeof p === "object" && typeof p.name === "string" ? { name: p.name, url: p.url, thumbnail: p.thumbnail } : null;
76
+ return {
77
+ tracks,
78
+ playlist,
79
+ query: typeof raw?.query === "string" ? raw.query : undefined,
80
+ source: typeof raw?.source === "string" ? raw.source : undefined,
81
+ };
82
+ }
83
+ /** Order-preserving de-duplication of tracks that came from the same node with the same id / url. */
84
+ function dedupeNetTracks(tracks) {
85
+ const seen = new Set();
86
+ return tracks.filter((t) => {
87
+ const key = `${t?.metadata?.net?.owner ?? ""}|${t?.id ?? ""}|${t?.url ?? ""}`;
88
+ if (seen.has(key))
89
+ return false;
90
+ seen.add(key);
91
+ return true;
92
+ });
93
+ }
94
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"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"}