@tribe-nest/media-protocol 1.0.0

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 (84) hide show
  1. package/build/_fixtures/joinTokenVectors.json +103 -0
  2. package/build/claims.d.ts +327 -0
  3. package/build/claims.d.ts.map +1 -0
  4. package/build/claims.js +91 -0
  5. package/build/claims.js.map +1 -0
  6. package/build/codecs.d.ts +102 -0
  7. package/build/codecs.d.ts.map +1 -0
  8. package/build/codecs.js +138 -0
  9. package/build/codecs.js.map +1 -0
  10. package/build/errorSchema.d.ts +8 -0
  11. package/build/errorSchema.d.ts.map +1 -0
  12. package/build/errorSchema.js +12 -0
  13. package/build/errorSchema.js.map +1 -0
  14. package/build/errors.d.ts +18 -0
  15. package/build/errors.d.ts.map +1 -0
  16. package/build/errors.js +47 -0
  17. package/build/errors.js.map +1 -0
  18. package/build/frames.d.ts +1291 -0
  19. package/build/frames.d.ts.map +1 -0
  20. package/build/frames.js +222 -0
  21. package/build/frames.js.map +1 -0
  22. package/build/grants.d.ts +307 -0
  23. package/build/grants.d.ts.map +1 -0
  24. package/build/grants.js +228 -0
  25. package/build/grants.js.map +1 -0
  26. package/build/index.d.ts +24 -0
  27. package/build/index.d.ts.map +1 -0
  28. package/build/index.js +40 -0
  29. package/build/index.js.map +1 -0
  30. package/build/mp-build/_fixtures/joinTokenVectors.json +103 -0
  31. package/build/mp-build/claims.d.ts +299 -0
  32. package/build/mp-build/claims.d.ts.map +1 -0
  33. package/build/mp-build/claims.js +60 -0
  34. package/build/mp-build/claims.js.map +1 -0
  35. package/build/mp-build/errorSchema.d.ts +8 -0
  36. package/build/mp-build/errorSchema.d.ts.map +1 -0
  37. package/build/mp-build/errorSchema.js +12 -0
  38. package/build/mp-build/errorSchema.js.map +1 -0
  39. package/build/mp-build/errors.d.ts +18 -0
  40. package/build/mp-build/errors.d.ts.map +1 -0
  41. package/build/mp-build/errors.js +47 -0
  42. package/build/mp-build/errors.js.map +1 -0
  43. package/build/mp-build/frames.d.ts +786 -0
  44. package/build/mp-build/frames.d.ts.map +1 -0
  45. package/build/mp-build/frames.js +153 -0
  46. package/build/mp-build/frames.js.map +1 -0
  47. package/build/mp-build/grants.d.ts +245 -0
  48. package/build/mp-build/grants.d.ts.map +1 -0
  49. package/build/mp-build/grants.js +135 -0
  50. package/build/mp-build/grants.js.map +1 -0
  51. package/build/mp-build/index.d.ts +23 -0
  52. package/build/mp-build/index.d.ts.map +1 -0
  53. package/build/mp-build/index.js +39 -0
  54. package/build/mp-build/index.js.map +1 -0
  55. package/build/mp-build/token.d.ts +66 -0
  56. package/build/mp-build/token.d.ts.map +1 -0
  57. package/build/mp-build/token.js +208 -0
  58. package/build/mp-build/token.js.map +1 -0
  59. package/build/mp-build/version.d.ts +9 -0
  60. package/build/mp-build/version.d.ts.map +1 -0
  61. package/build/mp-build/version.js +12 -0
  62. package/build/mp-build/version.js.map +1 -0
  63. package/build/token.d.ts +66 -0
  64. package/build/token.d.ts.map +1 -0
  65. package/build/token.js +208 -0
  66. package/build/token.js.map +1 -0
  67. package/build/version.d.ts +9 -0
  68. package/build/version.d.ts.map +1 -0
  69. package/build/version.js +12 -0
  70. package/build/version.js.map +1 -0
  71. package/package.json +53 -0
  72. package/src/_fixtures/joinTokenVectors.json +103 -0
  73. package/src/_tests/codecs.spec.ts +66 -0
  74. package/src/_tests/publishGrants.spec.ts +109 -0
  75. package/src/_tests/token.spec.ts +272 -0
  76. package/src/claims.ts +116 -0
  77. package/src/codecs.ts +165 -0
  78. package/src/errorSchema.ts +9 -0
  79. package/src/errors.ts +44 -0
  80. package/src/frames.ts +234 -0
  81. package/src/grants.ts +248 -0
  82. package/src/index.ts +23 -0
  83. package/src/token.ts +237 -0
  84. package/src/version.ts +8 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frames.d.ts","sourceRoot":"","sources":["../src/frames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,eAAO,MAAM,kBAAkB;;;;IAK3B;;8CAE0C;;;;;;;;;;;;;;;;IAO1C;;;;;;;;;;;OAWG;;;;;;;;;;;;;;;;IAOH,cAAc;;IAEd;;;;;;OAMG;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAWH,4DAA4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAqD9D,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,aAAa,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;AAEnD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;IAK5B;gFAC4E;;;;;;;;;;;;;IAI9E,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;iEACiE;AACjE,eAAO,MAAM,UAAU;;;;;;;;;;;;EAIrB,CAAC;AACH,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAE9C,eAAO,MAAM,gBAAgB;;;;IAKzB,4EAA4E;;;;;;;;;;;;;;;IAG5E;;qCAEiC;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGjC;oCACgC;;IAEhC;;;;;;;;OAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA2CL,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;AAE5C,qCAAqC;AACrC,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;IA3F1B;gFAC4E;;;;;;;;;;;;;;;;;IAsB5E,4EAA4E;;;;;;;;;;;;;;;IAG5E;;qCAEiC;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGjC;oCACgC;;IAEhC;;;;;;;;OAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAiD0E,CAAC;AAClF,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,eAAO,MAAM,OAAO,GAAI,OAAO,WAAW,KAAG,KAAK,IAAI,UAA8B,CAAC"}
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isEvent = exports.serverFrameSchema = exports.eventFrameSchema = exports.peerSchema = exports.responseFrameSchema = exports.requestFrameSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const errorSchema_1 = require("./errorSchema");
6
+ const grants_1 = require("./grants");
7
+ /**
8
+ * The client <-> node signalling wire.
9
+ *
10
+ * One envelope, stated once. Six phase plans independently invented four
11
+ * different ones (`m` / `type` / `method` / `action`, numeric versus string
12
+ * ids, `result` versus `data`), and every mismatch is a hard parse failure
13
+ * discovered at integration by a different pair of people.
14
+ *
15
+ * ## Shape
16
+ *
17
+ * Requests carry an `id` and get exactly one reply with the same `id`. Events
18
+ * carry no `id` and are never replied to. That is the whole protocol; anything
19
+ * needing more structure is a request that returns a handle.
20
+ *
21
+ * ## What is deliberately NOT here
22
+ *
23
+ * No pipe verb, no node id, no mesh address. A client cannot express "pipe this
24
+ * producer to that node", because piping is a side effect of `consume` and the
25
+ * only way to keep it lazy is for eager piping to be unsayable.
26
+ */
27
+ exports.requestFrameSchema = zod_1.z.discriminatedUnion("method", [
28
+ zod_1.z.object({
29
+ method: zod_1.z.literal("join"),
30
+ id: zod_1.z.number().int().nonnegative(),
31
+ protocolVersion: zod_1.z.number().int(),
32
+ /** The token travels in the first frame, NEVER in the URL: a query string
33
+ * lands in load-balancer access logs, and a join ticket in a log is a join
34
+ * ticket for anyone who can read logs. */
35
+ token: zod_1.z.string().min(1),
36
+ }),
37
+ zod_1.z.object({
38
+ method: zod_1.z.literal("createTransport"),
39
+ id: zod_1.z.number().int().nonnegative(),
40
+ direction: zod_1.z.enum(["send", "recv"]),
41
+ /**
42
+ * Deliberately absent: which KIND of transport this is.
43
+ *
44
+ * The kind comes from the token's `transport` claim and from nowhere else.
45
+ * Letting a client ask would mean a browser holding a valid join token
46
+ * could request a PlainTransport pointed at an address of its choosing -
47
+ * an RTP reflector, plus an unauthenticated publish path into whatever room
48
+ * the token names. Three phases independently needed to refuse that and
49
+ * none could, because nothing carried the fact.
50
+ *
51
+ * So there is no field here to refuse. The claim decides.
52
+ */
53
+ sctp: zod_1.z.boolean().optional(),
54
+ }),
55
+ zod_1.z.object({
56
+ method: zod_1.z.literal("connectTransport"),
57
+ id: zod_1.z.number().int().nonnegative(),
58
+ transportId: zod_1.z.string(),
59
+ /** WebRTC. */
60
+ dtlsParameters: zod_1.z.unknown().optional(),
61
+ /**
62
+ * Plain and pipe transports have no DTLS handshake to carry the address, so
63
+ * a server-side participant names where its RTP comes from. This is the
64
+ * half the token claim cannot cover: the claim says WHO may create a plain
65
+ * transport, and `MEDIA_SERVER_PEER_CIDRS` says WHERE its media may be
66
+ * pointed. Both are required; either alone leaves a reflector.
67
+ */
68
+ ip: zod_1.z.string().optional(),
69
+ port: zod_1.z.number().int().positive().max(65535).optional(),
70
+ rtcpPort: zod_1.z.number().int().positive().max(65535).optional(),
71
+ srtpParameters: zod_1.z.unknown().optional(),
72
+ }),
73
+ zod_1.z.object({
74
+ method: zod_1.z.literal("produce"),
75
+ id: zod_1.z.number().int().nonnegative(),
76
+ transportId: zod_1.z.string(),
77
+ kind: zod_1.z.enum(["audio", "video"]),
78
+ /** Opaque to this package: only mediasoup interprets it. */
79
+ rtpParameters: zod_1.z.unknown(),
80
+ appData: zod_1.z.record(zod_1.z.unknown()).optional(),
81
+ }),
82
+ zod_1.z.object({
83
+ method: zod_1.z.literal("consume"),
84
+ id: zod_1.z.number().int().nonnegative(),
85
+ transportId: zod_1.z.string(),
86
+ producerId: zod_1.z.string(),
87
+ rtpCapabilities: zod_1.z.unknown(),
88
+ }),
89
+ zod_1.z.object({
90
+ method: zod_1.z.literal("pauseProducer"),
91
+ id: zod_1.z.number().int().nonnegative(),
92
+ producerId: zod_1.z.string(),
93
+ }),
94
+ zod_1.z.object({
95
+ method: zod_1.z.literal("resumeProducer"),
96
+ id: zod_1.z.number().int().nonnegative(),
97
+ producerId: zod_1.z.string(),
98
+ }),
99
+ zod_1.z.object({
100
+ method: zod_1.z.literal("resumeConsumer"),
101
+ id: zod_1.z.number().int().nonnegative(),
102
+ consumerId: zod_1.z.string(),
103
+ }),
104
+ /**
105
+ * Drop a subscription.
106
+ *
107
+ * Needed because the active set CHURNS: as the conversation moves, a client
108
+ * following it stops wanting producers it wanted a moment ago. Closing only
109
+ * the client's own consumer leaves the node holding a Consumer object per
110
+ * dropped subscription, and in a large room that accumulates for the life of
111
+ * the call - on the node, which is the side with the ceiling.
112
+ */
113
+ zod_1.z.object({
114
+ method: zod_1.z.literal("closeConsumer"),
115
+ id: zod_1.z.number().int().nonnegative(),
116
+ consumerId: zod_1.z.string(),
117
+ }),
118
+ zod_1.z.object({
119
+ method: zod_1.z.literal("closeProducer"),
120
+ id: zod_1.z.number().int().nonnegative(),
121
+ producerId: zod_1.z.string(),
122
+ }),
123
+ /** A keyframe request. Without it every active-speaker switch shows garbage
124
+ * until the encoder happens to send one. */
125
+ zod_1.z.object({
126
+ method: zod_1.z.literal("requestKeyFrame"),
127
+ id: zod_1.z.number().int().nonnegative(),
128
+ consumerId: zod_1.z.string(),
129
+ }),
130
+ zod_1.z.object({ method: zod_1.z.literal("leave"), id: zod_1.z.number().int().nonnegative() }),
131
+ ]);
132
+ exports.responseFrameSchema = zod_1.z.union([
133
+ zod_1.z.object({ id: zod_1.z.number().int().nonnegative(), ok: zod_1.z.literal(true), data: zod_1.z.unknown() }),
134
+ zod_1.z.object({
135
+ id: zod_1.z.number().int().nonnegative(),
136
+ ok: zod_1.z.literal(false),
137
+ /** The client sees a CODE, never why a token was refused. Telling a caller
138
+ * whether the signature or the room was wrong turns this into an oracle. */
139
+ code: errorSchema_1.mediaErrorCodeSchema,
140
+ message: zod_1.z.string().optional(),
141
+ }),
142
+ ]);
143
+ /** A participant as everyone else sees them. Grants are NOT included: what
144
+ * someone else is permitted to do is not the room's business. */
145
+ exports.peerSchema = zod_1.z.object({
146
+ identity: zod_1.z.string(),
147
+ name: zod_1.z.string().optional(),
148
+ kind: grants_1.participantKindSchema,
149
+ });
150
+ exports.eventFrameSchema = zod_1.z.discriminatedUnion("event", [
151
+ zod_1.z.object({
152
+ event: zod_1.z.literal("joined"),
153
+ identity: zod_1.z.string(),
154
+ room: zod_1.z.string(),
155
+ /** Everything the client needs to build its device before any transport. */
156
+ routerRtpCapabilities: zod_1.z.unknown(),
157
+ peers: zod_1.z.array(exports.peerSchema),
158
+ /** Producers this participant is ALLOWED to see. The barrier is applied to
159
+ * the snapshot, not only at consume: an identity it may not receive must
160
+ * not be discoverable either. */
161
+ producers: zod_1.z.array(zod_1.z.object({ producerId: zod_1.z.string(), identity: zod_1.z.string(), kind: zod_1.z.enum(["audio", "video"]) })),
162
+ iceServers: zod_1.z.array(zod_1.z.object({ urls: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]), username: zod_1.z.string().optional(), credential: zod_1.z.string().optional() })),
163
+ /** True while any `kind: "egress"` participant is present. A consent
164
+ * requirement, not a nicety. */
165
+ recording: zod_1.z.boolean(),
166
+ /**
167
+ * What this token was minted with, echoed back.
168
+ *
169
+ * The client already holds the token but must not parse it: a signed blob
170
+ * a client reads is a signed blob a client eventually trusts its own
171
+ * reading of. This is the node's understanding of the grants, which is the
172
+ * one that will actually be enforced, so a UI built from it cannot offer a
173
+ * control the node is about to refuse.
174
+ */
175
+ grants: grants_1.mediaGrantsSchema.optional(),
176
+ }),
177
+ zod_1.z.object({ event: zod_1.z.literal("peerJoined"), peer: exports.peerSchema }),
178
+ zod_1.z.object({ event: zod_1.z.literal("peerLeft"), identity: zod_1.z.string() }),
179
+ zod_1.z.object({
180
+ event: zod_1.z.literal("producerAppeared"),
181
+ producerId: zod_1.z.string(),
182
+ identity: zod_1.z.string(),
183
+ kind: zod_1.z.enum(["audio", "video"]),
184
+ }),
185
+ zod_1.z.object({ event: zod_1.z.literal("producerClosed"), producerId: zod_1.z.string() }),
186
+ zod_1.z.object({ event: zod_1.z.literal("producerPaused"), producerId: zod_1.z.string(), paused: zod_1.z.boolean() }),
187
+ /**
188
+ * The active set the node wants this client to consume. How a 1,000-person
189
+ * room stays survivable: the server decides, the client follows.
190
+ *
191
+ * `producerIds` is the whole set and is what a simple client renders.
192
+ * `audio` and `video` are the same set split, because the two limits differ
193
+ * (you can follow more voices than you can fit faces). `enforced` says
194
+ * whether a consume outside the set will actually be REFUSED - below the
195
+ * threshold the set is advisory and a client that ignores it is not wrong.
196
+ *
197
+ * `speakers` carries the ordering and the levels, which is what drives a
198
+ * layout switch and a level meter. Ordered loudest first.
199
+ */
200
+ zod_1.z.object({
201
+ event: zod_1.z.literal("activeSpeakers"),
202
+ producerIds: zod_1.z.array(zod_1.z.string()),
203
+ audio: zod_1.z.array(zod_1.z.string()).optional(),
204
+ video: zod_1.z.array(zod_1.z.string()).optional(),
205
+ enforced: zod_1.z.boolean().optional(),
206
+ speakers: zod_1.z
207
+ .array(zod_1.z.object({ identity: zod_1.z.string(), producerId: zod_1.z.string(), volumeDb: zod_1.z.number() }))
208
+ .optional(),
209
+ }),
210
+ zod_1.z.object({ event: zod_1.z.literal("recordingChanged"), recording: zod_1.z.boolean() }),
211
+ /** This node is going away. Reconnect through MEDIA_URL; do not retry here. */
212
+ zod_1.z.object({ event: zod_1.z.literal("draining"), reconnectAfterMs: zod_1.z.number().int().nonnegative() }),
213
+ zod_1.z.object({ event: zod_1.z.literal("roomClosed"), reason: zod_1.z.string() }),
214
+ /** Barrier changes are pushed, because a rule that only applies at join is a
215
+ * rule that does not apply to anyone already in the room. */
216
+ zod_1.z.object({ event: zod_1.z.literal("subscribeRuleChanged"), subscribe: grants_1.subscribeRuleSchema }),
217
+ ]);
218
+ /** Anything arriving from a node. */
219
+ exports.serverFrameSchema = zod_1.z.union([exports.responseFrameSchema, exports.eventFrameSchema]);
220
+ const isEvent = (frame) => "event" in frame;
221
+ exports.isEvent = isEvent;
222
+ //# sourceMappingURL=frames.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frames.js","sourceRoot":"","sources":["../src/frames.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,307 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * What a participant is allowed to do, and - the part that matters most - who
4
+ * they may receive.
5
+ *
6
+ * ## Why the schema is `.strict()`
7
+ *
8
+ * This is the single line that stops the information barrier failing open.
9
+ *
10
+ * Ten phase plans were written in parallel and two of them disagreed on a name:
11
+ * one minted `grants.subscribeOnly`, the other read `grants.subscribe`. The
12
+ * reader would have found nothing, applied its documented default ("an absent
13
+ * rule means everyone"), and two Mandanten in one room would have received each
14
+ * other with nothing anywhere erroring. That is a §203 incident whose start
15
+ * date is unrecoverable from logs.
16
+ *
17
+ * `.strict()` turns that class of mistake from silent permissiveness into a
18
+ * loud verification failure: a token carrying an unknown grant key is rejected
19
+ * with `bad_claims` rather than partially understood. Any future rename fails
20
+ * the same way, at mint time, in a test.
21
+ */
22
+ /**
23
+ * Who a participant may receive, or be received by.
24
+ *
25
+ * A boolean cannot express an information barrier. "A and B are in one room and
26
+ * must not receive each other, while C may receive both" is the actual
27
+ * requirement for a Kanzlei, and it is a per-identity rule rather than a
28
+ * per-room one.
29
+ */
30
+ export declare const subscribeRuleSchema: z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
31
+ mode: z.ZodLiteral<"all">;
32
+ }, "strict", z.ZodTypeAny, {
33
+ mode: "all";
34
+ }, {
35
+ mode: "all";
36
+ }>, z.ZodObject<{
37
+ mode: z.ZodLiteral<"none">;
38
+ }, "strict", z.ZodTypeAny, {
39
+ mode: "none";
40
+ }, {
41
+ mode: "none";
42
+ }>, z.ZodObject<{
43
+ mode: z.ZodLiteral<"allow">;
44
+ identities: z.ZodArray<z.ZodString, "many">;
45
+ }, "strict", z.ZodTypeAny, {
46
+ mode: "allow";
47
+ identities: string[];
48
+ }, {
49
+ mode: "allow";
50
+ identities: string[];
51
+ }>, z.ZodObject<{
52
+ mode: z.ZodLiteral<"deny">;
53
+ identities: z.ZodArray<z.ZodString, "many">;
54
+ }, "strict", z.ZodTypeAny, {
55
+ mode: "deny";
56
+ identities: string[];
57
+ }, {
58
+ mode: "deny";
59
+ identities: string[];
60
+ }>]>;
61
+ export type SubscribeRule = z.infer<typeof subscribeRuleSchema>;
62
+ export declare const participantKindSchema: z.ZodEnum<["human", "agent", "egress", "sip", "ingress"]>;
63
+ export type ParticipantKind = z.infer<typeof participantKindSchema>;
64
+ /**
65
+ * Transport authority is NOT media authority, which is why this is its own
66
+ * claim rather than something inferred from `kind`.
67
+ *
68
+ * A browser holding a perfectly valid join token must not be able to ask for a
69
+ * `PlainTransport` pointed at an address of its choosing. That is an RTP
70
+ * reflector and an unauthenticated publish path into whatever room the token
71
+ * names. Three phases independently needed to refuse it and none could, because
72
+ * nothing carried the fact.
73
+ */
74
+ export declare const transportKindSchema: z.ZodEnum<["webrtc", "plain", "pipe"]>;
75
+ export type TransportKind = z.infer<typeof transportKindSchema>;
76
+ /**
77
+ * The two vocabularies, and the ONE place they are reconciled.
78
+ *
79
+ * A grant is written in kinds - "audio", "video", "screen" - because that is
80
+ * what a person minting a token thinks in: may this seat talk, may it be seen,
81
+ * may it present. A publisher labels its track with a SOURCE, because that is
82
+ * what it knows and what the other side renders: "microphone", "camera",
83
+ * "screen", "rtmp". The two lists overlap on one word and disagree on the rest.
84
+ *
85
+ * That disagreement shipped as a defect. The node compared the declared source
86
+ * against `publishKinds` directly, so a booking token minted with the full
87
+ * `["audio", "video", "screen"]` refused every microphone and every camera the
88
+ * browser SDK offered it - "microphone" is not in the list - and the only thing
89
+ * a coaching call could publish was a screen share. It refused the RTMP ingress
90
+ * for the same reason, whose source is "rtmp".
91
+ *
92
+ * So the translation lives here, next to the schema that creates the need for
93
+ * it, and both the node and the UI read it. An unrecognised source falls back to
94
+ * the TRACK's kind, which is a fact about the media rather than a claim: that is
95
+ * what lets a new source ("rtmp") work without a protocol change while a token
96
+ * granting audio only still cannot send video by inventing a label for it. The
97
+ * one thing a client can never do is send a screen share on an audio-or-video
98
+ * grant, because "screen" is only ever reachable by declaring it.
99
+ *
100
+ * ## A declaration is only honoured when the track could carry it
101
+ *
102
+ * The label is the client's claim; the track's kind is a fact mediasoup already
103
+ * knows. Translating the claim UNCONDITIONALLY made the claim outrank the fact,
104
+ * which is the bypass restated: `{ source: "microphone", kind: "video" }`
105
+ * resolved to "audio", so a seat minted `publishKinds: ["audio"]` published a
106
+ * camera and the node created a video producer with the real kind. The two
107
+ * audio-only grants in the product are a SIP gateway and an assistant runtime,
108
+ * and `publishKinds` is precisely the claim that has to survive the holder being
109
+ * compromised.
110
+ *
111
+ * So a source is translated only when it can actually carry the track in hand
112
+ * (a microphone carries audio, a camera carries video, a screen share carries
113
+ * either, because a shared window may bring system audio with it). A declaration
114
+ * the track contradicts is not a translation, it is a relabelling, and it is
115
+ * discarded in favour of the fact.
116
+ */
117
+ export declare const publishKindSchema: z.ZodEnum<["audio", "video", "screen"]>;
118
+ export type PublishKind = z.infer<typeof publishKindSchema>;
119
+ /** The sources the browser SDK publishes with. Others are legal on the wire. */
120
+ export declare const publishSourceSchema: z.ZodEnum<["microphone", "camera", "screen"]>;
121
+ export type PublishSource = z.infer<typeof publishSourceSchema>;
122
+ /** Which grant a publish needs, from what it declares and what it carries. */
123
+ export declare function requiredPublishKind(source: string | undefined, trackKind: "audio" | "video"): PublishKind;
124
+ /**
125
+ * May this token publish this? The node's decision, and the UI's hint, from one
126
+ * function so the button and the enforcement cannot disagree.
127
+ */
128
+ export declare function mayPublish(grants: MediaGrants | undefined, input: {
129
+ source: string | undefined;
130
+ trackKind: "audio" | "video";
131
+ }): boolean;
132
+ export declare const mediaGrantsSchema: z.ZodObject<{
133
+ canPublish: z.ZodBoolean;
134
+ canSubscribe: z.ZodBoolean;
135
+ canPublishData: z.ZodBoolean;
136
+ /** Who I may receive. Omitted means `{ mode: "all" }`. */
137
+ subscribe: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
138
+ mode: z.ZodLiteral<"all">;
139
+ }, "strict", z.ZodTypeAny, {
140
+ mode: "all";
141
+ }, {
142
+ mode: "all";
143
+ }>, z.ZodObject<{
144
+ mode: z.ZodLiteral<"none">;
145
+ }, "strict", z.ZodTypeAny, {
146
+ mode: "none";
147
+ }, {
148
+ mode: "none";
149
+ }>, z.ZodObject<{
150
+ mode: z.ZodLiteral<"allow">;
151
+ identities: z.ZodArray<z.ZodString, "many">;
152
+ }, "strict", z.ZodTypeAny, {
153
+ mode: "allow";
154
+ identities: string[];
155
+ }, {
156
+ mode: "allow";
157
+ identities: string[];
158
+ }>, z.ZodObject<{
159
+ mode: z.ZodLiteral<"deny">;
160
+ identities: z.ZodArray<z.ZodString, "many">;
161
+ }, "strict", z.ZodTypeAny, {
162
+ mode: "deny";
163
+ identities: string[];
164
+ }, {
165
+ mode: "deny";
166
+ identities: string[];
167
+ }>]>>;
168
+ /**
169
+ * Who may receive ME. Enforced on the PRODUCER side from the owner's stored
170
+ * grants, so a barrier holds even if the other party's token is generous.
171
+ */
172
+ visibleTo: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
173
+ mode: z.ZodLiteral<"all">;
174
+ }, "strict", z.ZodTypeAny, {
175
+ mode: "all";
176
+ }, {
177
+ mode: "all";
178
+ }>, z.ZodObject<{
179
+ mode: z.ZodLiteral<"none">;
180
+ }, "strict", z.ZodTypeAny, {
181
+ mode: "none";
182
+ }, {
183
+ mode: "none";
184
+ }>, z.ZodObject<{
185
+ mode: z.ZodLiteral<"allow">;
186
+ identities: z.ZodArray<z.ZodString, "many">;
187
+ }, "strict", z.ZodTypeAny, {
188
+ mode: "allow";
189
+ identities: string[];
190
+ }, {
191
+ mode: "allow";
192
+ identities: string[];
193
+ }>, z.ZodObject<{
194
+ mode: z.ZodLiteral<"deny">;
195
+ identities: z.ZodArray<z.ZodString, "many">;
196
+ }, "strict", z.ZodTypeAny, {
197
+ mode: "deny";
198
+ identities: string[];
199
+ }, {
200
+ mode: "deny";
201
+ identities: string[];
202
+ }>]>>;
203
+ /**
204
+ * Which kinds of media this token may send, in the vocabulary of
205
+ * `publishKindSchema`. A publisher labels its track with a SOURCE
206
+ * ("microphone", "camera", "screen", "rtmp", ...) and those are not the same
207
+ * words: `requiredPublishKind` below is the one translation between them.
208
+ */
209
+ publishKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["audio", "video", "screen"]>, "many">>;
210
+ /**
211
+ * Bypasses the top-N active-speaker refusal. Mintable ONLY for a non-human
212
+ * kind: a recorder needs every track, a human asking for 1,000 does not.
213
+ */
214
+ subscribeExempt: z.ZodOptional<z.ZodBoolean>;
215
+ /** Hard ceiling on concurrent consumers, for a non-human participant. */
216
+ maxSubscriptions: z.ZodOptional<z.ZodNumber>;
217
+ }, "strict", z.ZodTypeAny, {
218
+ canPublish: boolean;
219
+ canSubscribe: boolean;
220
+ canPublishData: boolean;
221
+ subscribe?: {
222
+ mode: "all";
223
+ } | {
224
+ mode: "none";
225
+ } | {
226
+ mode: "allow";
227
+ identities: string[];
228
+ } | {
229
+ mode: "deny";
230
+ identities: string[];
231
+ } | undefined;
232
+ visibleTo?: {
233
+ mode: "all";
234
+ } | {
235
+ mode: "none";
236
+ } | {
237
+ mode: "allow";
238
+ identities: string[];
239
+ } | {
240
+ mode: "deny";
241
+ identities: string[];
242
+ } | undefined;
243
+ publishKinds?: ("audio" | "video" | "screen")[] | undefined;
244
+ subscribeExempt?: boolean | undefined;
245
+ maxSubscriptions?: number | undefined;
246
+ }, {
247
+ canPublish: boolean;
248
+ canSubscribe: boolean;
249
+ canPublishData: boolean;
250
+ subscribe?: {
251
+ mode: "all";
252
+ } | {
253
+ mode: "none";
254
+ } | {
255
+ mode: "allow";
256
+ identities: string[];
257
+ } | {
258
+ mode: "deny";
259
+ identities: string[];
260
+ } | undefined;
261
+ visibleTo?: {
262
+ mode: "all";
263
+ } | {
264
+ mode: "none";
265
+ } | {
266
+ mode: "allow";
267
+ identities: string[];
268
+ } | {
269
+ mode: "deny";
270
+ identities: string[];
271
+ } | undefined;
272
+ publishKinds?: ("audio" | "video" | "screen")[] | undefined;
273
+ subscribeExempt?: boolean | undefined;
274
+ maxSubscriptions?: number | undefined;
275
+ }>;
276
+ export type MediaGrants = z.infer<typeof mediaGrantsSchema>;
277
+ /**
278
+ * May `consumer` receive `producer`? Two-sided, and deny wins.
279
+ *
280
+ * One-sided is not enough. If only the consumer's rule were consulted, a
281
+ * participant whose own token was minted generously could receive someone who
282
+ * had been explicitly walled off from them. So the producer's `visibleTo` is
283
+ * checked from the OWNER's stored grants, not from anything the consumer
284
+ * presents.
285
+ *
286
+ * **An unreadable owner is `false`.** If the producer's grants cannot be found,
287
+ * this refuses rather than falling through to the permissive default. A missing
288
+ * record is exactly the state a race or a partial failure produces, and in a
289
+ * room with an information barrier the safe reading of "I do not know" is "no".
290
+ * Note this differs deliberately from an ABSENT RULE on a record that WAS
291
+ * found, which means everyone.
292
+ */
293
+ export declare function maySubscribe(input: {
294
+ consumerIdentity: string;
295
+ consumerGrants: MediaGrants;
296
+ producerIdentity: string;
297
+ /** `undefined` when the owner's record could not be read. */
298
+ ownerGrants: MediaGrants | undefined;
299
+ }): boolean;
300
+ /**
301
+ * `subscribeExempt` and `maxSubscriptions` are meaningless for a human and
302
+ * dangerous if mintable for one: exemption is what lets a recorder take every
303
+ * track, and a human with it can pull a thousand streams through a node.
304
+ * Checked at MINT time so a bad token never exists.
305
+ */
306
+ export declare function grantsAreValidForKind(grants: MediaGrants, kind: ParticipantKind): true | string;
307
+ //# sourceMappingURL=grants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAK9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,qBAAqB,2DAAyD,CAAC;AAC5F,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,wCAAsC,CAAC;AACvE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,eAAO,MAAM,iBAAiB,yCAAuC,CAAC;AACtE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,+CAA6C,CAAC;AAC9E,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAqBhE,8EAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,WAAW,CASzG;AAED;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,KAAK,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAA;CAAE,GAClE,OAAO,CAIT;AAED,eAAO,MAAM,iBAAiB;;;;IAK1B,0DAA0D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE1D;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAEH;;;;;OAKG;;IAEH;;;OAGG;;IAEH,yEAAyE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAGlE,CAAC;AAEZ,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAmB5D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,WAAW,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,WAAW,EAAE,WAAW,GAAG,SAAS,CAAC;CACtC,GAAG,OAAO,CAUV;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,eAAe,GAAG,IAAI,GAAG,MAAM,CAW/F"}