@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.
- package/build/_fixtures/joinTokenVectors.json +103 -0
- package/build/claims.d.ts +327 -0
- package/build/claims.d.ts.map +1 -0
- package/build/claims.js +91 -0
- package/build/claims.js.map +1 -0
- package/build/codecs.d.ts +102 -0
- package/build/codecs.d.ts.map +1 -0
- package/build/codecs.js +138 -0
- package/build/codecs.js.map +1 -0
- package/build/errorSchema.d.ts +8 -0
- package/build/errorSchema.d.ts.map +1 -0
- package/build/errorSchema.js +12 -0
- package/build/errorSchema.js.map +1 -0
- package/build/errors.d.ts +18 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +47 -0
- package/build/errors.js.map +1 -0
- package/build/frames.d.ts +1291 -0
- package/build/frames.d.ts.map +1 -0
- package/build/frames.js +222 -0
- package/build/frames.js.map +1 -0
- package/build/grants.d.ts +307 -0
- package/build/grants.d.ts.map +1 -0
- package/build/grants.js +228 -0
- package/build/grants.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +40 -0
- package/build/index.js.map +1 -0
- package/build/mp-build/_fixtures/joinTokenVectors.json +103 -0
- package/build/mp-build/claims.d.ts +299 -0
- package/build/mp-build/claims.d.ts.map +1 -0
- package/build/mp-build/claims.js +60 -0
- package/build/mp-build/claims.js.map +1 -0
- package/build/mp-build/errorSchema.d.ts +8 -0
- package/build/mp-build/errorSchema.d.ts.map +1 -0
- package/build/mp-build/errorSchema.js +12 -0
- package/build/mp-build/errorSchema.js.map +1 -0
- package/build/mp-build/errors.d.ts +18 -0
- package/build/mp-build/errors.d.ts.map +1 -0
- package/build/mp-build/errors.js +47 -0
- package/build/mp-build/errors.js.map +1 -0
- package/build/mp-build/frames.d.ts +786 -0
- package/build/mp-build/frames.d.ts.map +1 -0
- package/build/mp-build/frames.js +153 -0
- package/build/mp-build/frames.js.map +1 -0
- package/build/mp-build/grants.d.ts +245 -0
- package/build/mp-build/grants.d.ts.map +1 -0
- package/build/mp-build/grants.js +135 -0
- package/build/mp-build/grants.js.map +1 -0
- package/build/mp-build/index.d.ts +23 -0
- package/build/mp-build/index.d.ts.map +1 -0
- package/build/mp-build/index.js +39 -0
- package/build/mp-build/index.js.map +1 -0
- package/build/mp-build/token.d.ts +66 -0
- package/build/mp-build/token.d.ts.map +1 -0
- package/build/mp-build/token.js +208 -0
- package/build/mp-build/token.js.map +1 -0
- package/build/mp-build/version.d.ts +9 -0
- package/build/mp-build/version.d.ts.map +1 -0
- package/build/mp-build/version.js +12 -0
- package/build/mp-build/version.js.map +1 -0
- package/build/token.d.ts +66 -0
- package/build/token.d.ts.map +1 -0
- package/build/token.js +208 -0
- package/build/token.js.map +1 -0
- package/build/version.d.ts +9 -0
- package/build/version.d.ts.map +1 -0
- package/build/version.js +12 -0
- package/build/version.js.map +1 -0
- package/package.json +53 -0
- package/src/_fixtures/joinTokenVectors.json +103 -0
- package/src/_tests/codecs.spec.ts +66 -0
- package/src/_tests/publishGrants.spec.ts +109 -0
- package/src/_tests/token.spec.ts +272 -0
- package/src/claims.ts +116 -0
- package/src/codecs.ts +165 -0
- package/src/errorSchema.ts +9 -0
- package/src/errors.ts +44 -0
- package/src/frames.ts +234 -0
- package/src/grants.ts +248 -0
- package/src/index.ts +23 -0
- package/src/token.ts +237 -0
- 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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAmB1C,4DAA4D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuC9D,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuBlC,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;;;;;;;;;;;;;;;IA7D1B;gFAC4E;;;;;;;;;;;;;;;;;IAsB5E,4EAA4E;;;;;;;;;;;;;;;IAG5E;;qCAEiC;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGjC;oCACgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA6B6C,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,153 @@
|
|
|
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
|
+
zod_1.z.object({
|
|
43
|
+
method: zod_1.z.literal("connectTransport"),
|
|
44
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
45
|
+
transportId: zod_1.z.string(),
|
|
46
|
+
dtlsParameters: zod_1.z.unknown(),
|
|
47
|
+
}),
|
|
48
|
+
zod_1.z.object({
|
|
49
|
+
method: zod_1.z.literal("produce"),
|
|
50
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
51
|
+
transportId: zod_1.z.string(),
|
|
52
|
+
kind: zod_1.z.enum(["audio", "video"]),
|
|
53
|
+
/** Opaque to this package: only mediasoup interprets it. */
|
|
54
|
+
rtpParameters: zod_1.z.unknown(),
|
|
55
|
+
appData: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
56
|
+
}),
|
|
57
|
+
zod_1.z.object({
|
|
58
|
+
method: zod_1.z.literal("consume"),
|
|
59
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
60
|
+
transportId: zod_1.z.string(),
|
|
61
|
+
producerId: zod_1.z.string(),
|
|
62
|
+
rtpCapabilities: zod_1.z.unknown(),
|
|
63
|
+
}),
|
|
64
|
+
zod_1.z.object({
|
|
65
|
+
method: zod_1.z.literal("pauseProducer"),
|
|
66
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
67
|
+
producerId: zod_1.z.string(),
|
|
68
|
+
}),
|
|
69
|
+
zod_1.z.object({
|
|
70
|
+
method: zod_1.z.literal("resumeProducer"),
|
|
71
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
72
|
+
producerId: zod_1.z.string(),
|
|
73
|
+
}),
|
|
74
|
+
zod_1.z.object({
|
|
75
|
+
method: zod_1.z.literal("resumeConsumer"),
|
|
76
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
77
|
+
consumerId: zod_1.z.string(),
|
|
78
|
+
}),
|
|
79
|
+
zod_1.z.object({
|
|
80
|
+
method: zod_1.z.literal("closeProducer"),
|
|
81
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
82
|
+
producerId: zod_1.z.string(),
|
|
83
|
+
}),
|
|
84
|
+
/** A keyframe request. Without it every active-speaker switch shows garbage
|
|
85
|
+
* until the encoder happens to send one. */
|
|
86
|
+
zod_1.z.object({
|
|
87
|
+
method: zod_1.z.literal("requestKeyFrame"),
|
|
88
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
89
|
+
consumerId: zod_1.z.string(),
|
|
90
|
+
}),
|
|
91
|
+
zod_1.z.object({ method: zod_1.z.literal("leave"), id: zod_1.z.number().int().nonnegative() }),
|
|
92
|
+
]);
|
|
93
|
+
exports.responseFrameSchema = zod_1.z.union([
|
|
94
|
+
zod_1.z.object({ id: zod_1.z.number().int().nonnegative(), ok: zod_1.z.literal(true), data: zod_1.z.unknown() }),
|
|
95
|
+
zod_1.z.object({
|
|
96
|
+
id: zod_1.z.number().int().nonnegative(),
|
|
97
|
+
ok: zod_1.z.literal(false),
|
|
98
|
+
/** The client sees a CODE, never why a token was refused. Telling a caller
|
|
99
|
+
* whether the signature or the room was wrong turns this into an oracle. */
|
|
100
|
+
code: errorSchema_1.mediaErrorCodeSchema,
|
|
101
|
+
message: zod_1.z.string().optional(),
|
|
102
|
+
}),
|
|
103
|
+
]);
|
|
104
|
+
/** A participant as everyone else sees them. Grants are NOT included: what
|
|
105
|
+
* someone else is permitted to do is not the room's business. */
|
|
106
|
+
exports.peerSchema = zod_1.z.object({
|
|
107
|
+
identity: zod_1.z.string(),
|
|
108
|
+
name: zod_1.z.string().optional(),
|
|
109
|
+
kind: grants_1.participantKindSchema,
|
|
110
|
+
});
|
|
111
|
+
exports.eventFrameSchema = zod_1.z.discriminatedUnion("event", [
|
|
112
|
+
zod_1.z.object({
|
|
113
|
+
event: zod_1.z.literal("joined"),
|
|
114
|
+
identity: zod_1.z.string(),
|
|
115
|
+
room: zod_1.z.string(),
|
|
116
|
+
/** Everything the client needs to build its device before any transport. */
|
|
117
|
+
routerRtpCapabilities: zod_1.z.unknown(),
|
|
118
|
+
peers: zod_1.z.array(exports.peerSchema),
|
|
119
|
+
/** Producers this participant is ALLOWED to see. The barrier is applied to
|
|
120
|
+
* the snapshot, not only at consume: an identity it may not receive must
|
|
121
|
+
* not be discoverable either. */
|
|
122
|
+
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"]) })),
|
|
123
|
+
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() })),
|
|
124
|
+
/** True while any `kind: "egress"` participant is present. A consent
|
|
125
|
+
* requirement, not a nicety. */
|
|
126
|
+
recording: zod_1.z.boolean(),
|
|
127
|
+
}),
|
|
128
|
+
zod_1.z.object({ event: zod_1.z.literal("peerJoined"), peer: exports.peerSchema }),
|
|
129
|
+
zod_1.z.object({ event: zod_1.z.literal("peerLeft"), identity: zod_1.z.string() }),
|
|
130
|
+
zod_1.z.object({
|
|
131
|
+
event: zod_1.z.literal("producerAppeared"),
|
|
132
|
+
producerId: zod_1.z.string(),
|
|
133
|
+
identity: zod_1.z.string(),
|
|
134
|
+
kind: zod_1.z.enum(["audio", "video"]),
|
|
135
|
+
}),
|
|
136
|
+
zod_1.z.object({ event: zod_1.z.literal("producerClosed"), producerId: zod_1.z.string() }),
|
|
137
|
+
zod_1.z.object({ event: zod_1.z.literal("producerPaused"), producerId: zod_1.z.string(), paused: zod_1.z.boolean() }),
|
|
138
|
+
/** The active set the node wants this client to consume. How a 1,000-person
|
|
139
|
+
* room stays survivable: the server decides, the client follows. */
|
|
140
|
+
zod_1.z.object({ event: zod_1.z.literal("activeSpeakers"), producerIds: zod_1.z.array(zod_1.z.string()) }),
|
|
141
|
+
zod_1.z.object({ event: zod_1.z.literal("recordingChanged"), recording: zod_1.z.boolean() }),
|
|
142
|
+
/** This node is going away. Reconnect through MEDIA_URL; do not retry here. */
|
|
143
|
+
zod_1.z.object({ event: zod_1.z.literal("draining"), reconnectAfterMs: zod_1.z.number().int().nonnegative() }),
|
|
144
|
+
zod_1.z.object({ event: zod_1.z.literal("roomClosed"), reason: zod_1.z.string() }),
|
|
145
|
+
/** Barrier changes are pushed, because a rule that only applies at join is a
|
|
146
|
+
* rule that does not apply to anyone already in the room. */
|
|
147
|
+
zod_1.z.object({ event: zod_1.z.literal("subscribeRuleChanged"), subscribe: grants_1.subscribeRuleSchema }),
|
|
148
|
+
]);
|
|
149
|
+
/** Anything arriving from a node. */
|
|
150
|
+
exports.serverFrameSchema = zod_1.z.union([exports.responseFrameSchema, exports.eventFrameSchema]);
|
|
151
|
+
const isEvent = (frame) => "event" in frame;
|
|
152
|
+
exports.isEvent = isEvent;
|
|
153
|
+
//# 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,245 @@
|
|
|
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
|
+
export declare const mediaGrantsSchema: z.ZodObject<{
|
|
77
|
+
canPublish: z.ZodBoolean;
|
|
78
|
+
canSubscribe: z.ZodBoolean;
|
|
79
|
+
canPublishData: z.ZodBoolean;
|
|
80
|
+
/** Who I may receive. Omitted means `{ mode: "all" }`. */
|
|
81
|
+
subscribe: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
|
|
82
|
+
mode: z.ZodLiteral<"all">;
|
|
83
|
+
}, "strict", z.ZodTypeAny, {
|
|
84
|
+
mode: "all";
|
|
85
|
+
}, {
|
|
86
|
+
mode: "all";
|
|
87
|
+
}>, z.ZodObject<{
|
|
88
|
+
mode: z.ZodLiteral<"none">;
|
|
89
|
+
}, "strict", z.ZodTypeAny, {
|
|
90
|
+
mode: "none";
|
|
91
|
+
}, {
|
|
92
|
+
mode: "none";
|
|
93
|
+
}>, z.ZodObject<{
|
|
94
|
+
mode: z.ZodLiteral<"allow">;
|
|
95
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
96
|
+
}, "strict", z.ZodTypeAny, {
|
|
97
|
+
mode: "allow";
|
|
98
|
+
identities: string[];
|
|
99
|
+
}, {
|
|
100
|
+
mode: "allow";
|
|
101
|
+
identities: string[];
|
|
102
|
+
}>, z.ZodObject<{
|
|
103
|
+
mode: z.ZodLiteral<"deny">;
|
|
104
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
105
|
+
}, "strict", z.ZodTypeAny, {
|
|
106
|
+
mode: "deny";
|
|
107
|
+
identities: string[];
|
|
108
|
+
}, {
|
|
109
|
+
mode: "deny";
|
|
110
|
+
identities: string[];
|
|
111
|
+
}>]>>;
|
|
112
|
+
/**
|
|
113
|
+
* Who may receive ME. Enforced on the PRODUCER side from the owner's stored
|
|
114
|
+
* grants, so a barrier holds even if the other party's token is generous.
|
|
115
|
+
*/
|
|
116
|
+
visibleTo: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
|
|
117
|
+
mode: z.ZodLiteral<"all">;
|
|
118
|
+
}, "strict", z.ZodTypeAny, {
|
|
119
|
+
mode: "all";
|
|
120
|
+
}, {
|
|
121
|
+
mode: "all";
|
|
122
|
+
}>, z.ZodObject<{
|
|
123
|
+
mode: z.ZodLiteral<"none">;
|
|
124
|
+
}, "strict", z.ZodTypeAny, {
|
|
125
|
+
mode: "none";
|
|
126
|
+
}, {
|
|
127
|
+
mode: "none";
|
|
128
|
+
}>, z.ZodObject<{
|
|
129
|
+
mode: z.ZodLiteral<"allow">;
|
|
130
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
131
|
+
}, "strict", z.ZodTypeAny, {
|
|
132
|
+
mode: "allow";
|
|
133
|
+
identities: string[];
|
|
134
|
+
}, {
|
|
135
|
+
mode: "allow";
|
|
136
|
+
identities: string[];
|
|
137
|
+
}>, z.ZodObject<{
|
|
138
|
+
mode: z.ZodLiteral<"deny">;
|
|
139
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
140
|
+
}, "strict", z.ZodTypeAny, {
|
|
141
|
+
mode: "deny";
|
|
142
|
+
identities: string[];
|
|
143
|
+
}, {
|
|
144
|
+
mode: "deny";
|
|
145
|
+
identities: string[];
|
|
146
|
+
}>]>>;
|
|
147
|
+
publishKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["audio", "video", "screen"]>, "many">>;
|
|
148
|
+
/**
|
|
149
|
+
* Bypasses the top-N active-speaker refusal. Mintable ONLY for a non-human
|
|
150
|
+
* kind: a recorder needs every track, a human asking for 1,000 does not.
|
|
151
|
+
*/
|
|
152
|
+
subscribeExempt: z.ZodOptional<z.ZodBoolean>;
|
|
153
|
+
/** Hard ceiling on concurrent consumers, for a non-human participant. */
|
|
154
|
+
maxSubscriptions: z.ZodOptional<z.ZodNumber>;
|
|
155
|
+
}, "strict", z.ZodTypeAny, {
|
|
156
|
+
canPublish: boolean;
|
|
157
|
+
canSubscribe: boolean;
|
|
158
|
+
canPublishData: boolean;
|
|
159
|
+
subscribe?: {
|
|
160
|
+
mode: "all";
|
|
161
|
+
} | {
|
|
162
|
+
mode: "none";
|
|
163
|
+
} | {
|
|
164
|
+
mode: "allow";
|
|
165
|
+
identities: string[];
|
|
166
|
+
} | {
|
|
167
|
+
mode: "deny";
|
|
168
|
+
identities: string[];
|
|
169
|
+
} | undefined;
|
|
170
|
+
visibleTo?: {
|
|
171
|
+
mode: "all";
|
|
172
|
+
} | {
|
|
173
|
+
mode: "none";
|
|
174
|
+
} | {
|
|
175
|
+
mode: "allow";
|
|
176
|
+
identities: string[];
|
|
177
|
+
} | {
|
|
178
|
+
mode: "deny";
|
|
179
|
+
identities: string[];
|
|
180
|
+
} | undefined;
|
|
181
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
182
|
+
subscribeExempt?: boolean | undefined;
|
|
183
|
+
maxSubscriptions?: number | undefined;
|
|
184
|
+
}, {
|
|
185
|
+
canPublish: boolean;
|
|
186
|
+
canSubscribe: boolean;
|
|
187
|
+
canPublishData: boolean;
|
|
188
|
+
subscribe?: {
|
|
189
|
+
mode: "all";
|
|
190
|
+
} | {
|
|
191
|
+
mode: "none";
|
|
192
|
+
} | {
|
|
193
|
+
mode: "allow";
|
|
194
|
+
identities: string[];
|
|
195
|
+
} | {
|
|
196
|
+
mode: "deny";
|
|
197
|
+
identities: string[];
|
|
198
|
+
} | undefined;
|
|
199
|
+
visibleTo?: {
|
|
200
|
+
mode: "all";
|
|
201
|
+
} | {
|
|
202
|
+
mode: "none";
|
|
203
|
+
} | {
|
|
204
|
+
mode: "allow";
|
|
205
|
+
identities: string[];
|
|
206
|
+
} | {
|
|
207
|
+
mode: "deny";
|
|
208
|
+
identities: string[];
|
|
209
|
+
} | undefined;
|
|
210
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
211
|
+
subscribeExempt?: boolean | undefined;
|
|
212
|
+
maxSubscriptions?: number | undefined;
|
|
213
|
+
}>;
|
|
214
|
+
export type MediaGrants = z.infer<typeof mediaGrantsSchema>;
|
|
215
|
+
/**
|
|
216
|
+
* May `consumer` receive `producer`? Two-sided, and deny wins.
|
|
217
|
+
*
|
|
218
|
+
* One-sided is not enough. If only the consumer's rule were consulted, a
|
|
219
|
+
* participant whose own token was minted generously could receive someone who
|
|
220
|
+
* had been explicitly walled off from them. So the producer's `visibleTo` is
|
|
221
|
+
* checked from the OWNER's stored grants, not from anything the consumer
|
|
222
|
+
* presents.
|
|
223
|
+
*
|
|
224
|
+
* **An unreadable owner is `false`.** If the producer's grants cannot be found,
|
|
225
|
+
* this refuses rather than falling through to the permissive default. A missing
|
|
226
|
+
* record is exactly the state a race or a partial failure produces, and in a
|
|
227
|
+
* room with an information barrier the safe reading of "I do not know" is "no".
|
|
228
|
+
* Note this differs deliberately from an ABSENT RULE on a record that WAS
|
|
229
|
+
* found, which means everyone.
|
|
230
|
+
*/
|
|
231
|
+
export declare function maySubscribe(input: {
|
|
232
|
+
consumerIdentity: string;
|
|
233
|
+
consumerGrants: MediaGrants;
|
|
234
|
+
producerIdentity: string;
|
|
235
|
+
/** `undefined` when the owner's record could not be read. */
|
|
236
|
+
ownerGrants: MediaGrants | undefined;
|
|
237
|
+
}): boolean;
|
|
238
|
+
/**
|
|
239
|
+
* `subscribeExempt` and `maxSubscriptions` are meaningless for a human and
|
|
240
|
+
* dangerous if mintable for one: exemption is what lets a recorder take every
|
|
241
|
+
* track, and a human with it can pull a thousand streams through a node.
|
|
242
|
+
* Checked at MINT time so a bad token never exists.
|
|
243
|
+
*/
|
|
244
|
+
export declare function grantsAreValidForKind(grants: MediaGrants, kind: ParticipantKind): true | string;
|
|
245
|
+
//# 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,eAAO,MAAM,iBAAiB;;;;IAK1B,0DAA0D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAE1D;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAGH;;;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"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mediaGrantsSchema = exports.transportKindSchema = exports.participantKindSchema = exports.subscribeRuleSchema = void 0;
|
|
4
|
+
exports.maySubscribe = maySubscribe;
|
|
5
|
+
exports.grantsAreValidForKind = grantsAreValidForKind;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
/**
|
|
8
|
+
* What a participant is allowed to do, and - the part that matters most - who
|
|
9
|
+
* they may receive.
|
|
10
|
+
*
|
|
11
|
+
* ## Why the schema is `.strict()`
|
|
12
|
+
*
|
|
13
|
+
* This is the single line that stops the information barrier failing open.
|
|
14
|
+
*
|
|
15
|
+
* Ten phase plans were written in parallel and two of them disagreed on a name:
|
|
16
|
+
* one minted `grants.subscribeOnly`, the other read `grants.subscribe`. The
|
|
17
|
+
* reader would have found nothing, applied its documented default ("an absent
|
|
18
|
+
* rule means everyone"), and two Mandanten in one room would have received each
|
|
19
|
+
* other with nothing anywhere erroring. That is a §203 incident whose start
|
|
20
|
+
* date is unrecoverable from logs.
|
|
21
|
+
*
|
|
22
|
+
* `.strict()` turns that class of mistake from silent permissiveness into a
|
|
23
|
+
* loud verification failure: a token carrying an unknown grant key is rejected
|
|
24
|
+
* with `bad_claims` rather than partially understood. Any future rename fails
|
|
25
|
+
* the same way, at mint time, in a test.
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Who a participant may receive, or be received by.
|
|
29
|
+
*
|
|
30
|
+
* A boolean cannot express an information barrier. "A and B are in one room and
|
|
31
|
+
* must not receive each other, while C may receive both" is the actual
|
|
32
|
+
* requirement for a Kanzlei, and it is a per-identity rule rather than a
|
|
33
|
+
* per-room one.
|
|
34
|
+
*/
|
|
35
|
+
exports.subscribeRuleSchema = zod_1.z.discriminatedUnion("mode", [
|
|
36
|
+
zod_1.z.object({ mode: zod_1.z.literal("all") }).strict(),
|
|
37
|
+
zod_1.z.object({ mode: zod_1.z.literal("none") }).strict(),
|
|
38
|
+
zod_1.z.object({ mode: zod_1.z.literal("allow"), identities: zod_1.z.array(zod_1.z.string()).max(500) }).strict(),
|
|
39
|
+
zod_1.z.object({ mode: zod_1.z.literal("deny"), identities: zod_1.z.array(zod_1.z.string()).max(500) }).strict(),
|
|
40
|
+
]);
|
|
41
|
+
exports.participantKindSchema = zod_1.z.enum(["human", "agent", "egress", "sip", "ingress"]);
|
|
42
|
+
/**
|
|
43
|
+
* Transport authority is NOT media authority, which is why this is its own
|
|
44
|
+
* claim rather than something inferred from `kind`.
|
|
45
|
+
*
|
|
46
|
+
* A browser holding a perfectly valid join token must not be able to ask for a
|
|
47
|
+
* `PlainTransport` pointed at an address of its choosing. That is an RTP
|
|
48
|
+
* reflector and an unauthenticated publish path into whatever room the token
|
|
49
|
+
* names. Three phases independently needed to refuse it and none could, because
|
|
50
|
+
* nothing carried the fact.
|
|
51
|
+
*/
|
|
52
|
+
exports.transportKindSchema = zod_1.z.enum(["webrtc", "plain", "pipe"]);
|
|
53
|
+
exports.mediaGrantsSchema = zod_1.z
|
|
54
|
+
.object({
|
|
55
|
+
canPublish: zod_1.z.boolean(),
|
|
56
|
+
canSubscribe: zod_1.z.boolean(),
|
|
57
|
+
canPublishData: zod_1.z.boolean(),
|
|
58
|
+
/** Who I may receive. Omitted means `{ mode: "all" }`. */
|
|
59
|
+
subscribe: exports.subscribeRuleSchema.optional(),
|
|
60
|
+
/**
|
|
61
|
+
* Who may receive ME. Enforced on the PRODUCER side from the owner's stored
|
|
62
|
+
* grants, so a barrier holds even if the other party's token is generous.
|
|
63
|
+
*/
|
|
64
|
+
visibleTo: exports.subscribeRuleSchema.optional(),
|
|
65
|
+
publishKinds: zod_1.z.array(zod_1.z.enum(["audio", "video", "screen"])).optional(),
|
|
66
|
+
/**
|
|
67
|
+
* Bypasses the top-N active-speaker refusal. Mintable ONLY for a non-human
|
|
68
|
+
* kind: a recorder needs every track, a human asking for 1,000 does not.
|
|
69
|
+
*/
|
|
70
|
+
subscribeExempt: zod_1.z.boolean().optional(),
|
|
71
|
+
/** Hard ceiling on concurrent consumers, for a non-human participant. */
|
|
72
|
+
maxSubscriptions: zod_1.z.number().int().positive().max(5000).optional(),
|
|
73
|
+
})
|
|
74
|
+
.strict();
|
|
75
|
+
/** An omitted rule means everyone. Stated once so both sides agree. */
|
|
76
|
+
const DEFAULT_RULE = { mode: "all" };
|
|
77
|
+
function ruleAllows(rule, identity) {
|
|
78
|
+
const r = rule ?? DEFAULT_RULE;
|
|
79
|
+
switch (r.mode) {
|
|
80
|
+
case "all":
|
|
81
|
+
return true;
|
|
82
|
+
case "none":
|
|
83
|
+
return false;
|
|
84
|
+
case "allow":
|
|
85
|
+
return r.identities.includes(identity);
|
|
86
|
+
case "deny":
|
|
87
|
+
return !r.identities.includes(identity);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* May `consumer` receive `producer`? Two-sided, and deny wins.
|
|
92
|
+
*
|
|
93
|
+
* One-sided is not enough. If only the consumer's rule were consulted, a
|
|
94
|
+
* participant whose own token was minted generously could receive someone who
|
|
95
|
+
* had been explicitly walled off from them. So the producer's `visibleTo` is
|
|
96
|
+
* checked from the OWNER's stored grants, not from anything the consumer
|
|
97
|
+
* presents.
|
|
98
|
+
*
|
|
99
|
+
* **An unreadable owner is `false`.** If the producer's grants cannot be found,
|
|
100
|
+
* this refuses rather than falling through to the permissive default. A missing
|
|
101
|
+
* record is exactly the state a race or a partial failure produces, and in a
|
|
102
|
+
* room with an information barrier the safe reading of "I do not know" is "no".
|
|
103
|
+
* Note this differs deliberately from an ABSENT RULE on a record that WAS
|
|
104
|
+
* found, which means everyone.
|
|
105
|
+
*/
|
|
106
|
+
function maySubscribe(input) {
|
|
107
|
+
if (!input.consumerGrants.canSubscribe)
|
|
108
|
+
return false;
|
|
109
|
+
// Nobody subscribes to themselves; asking is a client bug, not a denial.
|
|
110
|
+
if (input.consumerIdentity === input.producerIdentity)
|
|
111
|
+
return false;
|
|
112
|
+
if (!input.ownerGrants)
|
|
113
|
+
return false;
|
|
114
|
+
return (ruleAllows(input.consumerGrants.subscribe, input.producerIdentity) &&
|
|
115
|
+
ruleAllows(input.ownerGrants.visibleTo, input.consumerIdentity));
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `subscribeExempt` and `maxSubscriptions` are meaningless for a human and
|
|
119
|
+
* dangerous if mintable for one: exemption is what lets a recorder take every
|
|
120
|
+
* track, and a human with it can pull a thousand streams through a node.
|
|
121
|
+
* Checked at MINT time so a bad token never exists.
|
|
122
|
+
*/
|
|
123
|
+
function grantsAreValidForKind(grants, kind) {
|
|
124
|
+
if (kind === "human" && grants.subscribeExempt) {
|
|
125
|
+
return "subscribeExempt may not be minted for a human participant";
|
|
126
|
+
}
|
|
127
|
+
if (!grants.canSubscribe && (grants.subscribe || grants.subscribeExempt || grants.maxSubscriptions)) {
|
|
128
|
+
return "subscribe rules are meaningless when canSubscribe is false";
|
|
129
|
+
}
|
|
130
|
+
if (!grants.canPublish && grants.publishKinds?.length) {
|
|
131
|
+
return "publishKinds is meaningless when canPublish is false";
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=grants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grants.js","sourceRoot":"","sources":["../src/grants.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The contract between the backend, the media plane and every client.
|
|
3
|
+
*
|
|
4
|
+
* The root export is ISOMORPHIC: types, zod schemas, wire frames and the pure
|
|
5
|
+
* `maySubscribe` decision. It pulls in no `node:crypto`, no mediasoup, no DOM,
|
|
6
|
+
* so a browser SDK can import it.
|
|
7
|
+
*
|
|
8
|
+
* Signing and verifying live at `@tribe-nest/media-protocol/token`, which is
|
|
9
|
+
* Node-only. Keeping them apart is what stops importing a frame type from
|
|
10
|
+
* dragging crypto into a browser bundle.
|
|
11
|
+
*
|
|
12
|
+
* This package exists because `apps/backend` and `apps/media-server` may not
|
|
13
|
+
* import each other (there is a test), and six independently written phase
|
|
14
|
+
* plans each invented a different wire envelope for want of somewhere neutral
|
|
15
|
+
* to put one.
|
|
16
|
+
*/
|
|
17
|
+
export * from "./version";
|
|
18
|
+
export * from "./errors";
|
|
19
|
+
export * from "./errorSchema";
|
|
20
|
+
export * from "./grants";
|
|
21
|
+
export * from "./claims";
|
|
22
|
+
export * from "./frames";
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
/**
|
|
18
|
+
* The contract between the backend, the media plane and every client.
|
|
19
|
+
*
|
|
20
|
+
* The root export is ISOMORPHIC: types, zod schemas, wire frames and the pure
|
|
21
|
+
* `maySubscribe` decision. It pulls in no `node:crypto`, no mediasoup, no DOM,
|
|
22
|
+
* so a browser SDK can import it.
|
|
23
|
+
*
|
|
24
|
+
* Signing and verifying live at `@tribe-nest/media-protocol/token`, which is
|
|
25
|
+
* Node-only. Keeping them apart is what stops importing a frame type from
|
|
26
|
+
* dragging crypto into a browser bundle.
|
|
27
|
+
*
|
|
28
|
+
* This package exists because `apps/backend` and `apps/media-server` may not
|
|
29
|
+
* import each other (there is a test), and six independently written phase
|
|
30
|
+
* plans each invented a different wire envelope for want of somewhere neutral
|
|
31
|
+
* to put one.
|
|
32
|
+
*/
|
|
33
|
+
__exportStar(require("./version"), exports);
|
|
34
|
+
__exportStar(require("./errors"), exports);
|
|
35
|
+
__exportStar(require("./errorSchema"), exports);
|
|
36
|
+
__exportStar(require("./grants"), exports);
|
|
37
|
+
__exportStar(require("./claims"), exports);
|
|
38
|
+
__exportStar(require("./frames"), exports);
|
|
39
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;;GAeG;AACH,4CAA0B;AAC1B,2CAAyB;AACzB,gDAA8B;AAC9B,2CAAyB;AACzB,2CAAyB;AACzB,2CAAyB"}
|