@blockcast/mmt-container 0.4.1 → 0.5.0-main.34c7b9c2cfa0

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 (87) hide show
  1. package/README.md +2 -2
  2. package/dist/browser-runtime.js +3769 -364
  3. package/dist/browser-runtime.js.map +4 -4
  4. package/dist/cmcd-producer.d.ts +5 -1
  5. package/dist/cmcd-producer.d.ts.map +1 -1
  6. package/dist/cmcd-producer.js.map +2 -2
  7. package/dist/delivery-catalog.js +18 -2
  8. package/dist/delivery-catalog.js.map +2 -2
  9. package/dist/fec-manager.d.ts +21 -16
  10. package/dist/fec-manager.d.ts.map +1 -1
  11. package/dist/fec-manager.js +197 -80
  12. package/dist/fec-manager.js.map +3 -3
  13. package/dist/held-layer-admission.d.ts +58 -0
  14. package/dist/held-layer-admission.d.ts.map +1 -0
  15. package/dist/held-layer-admission.js +105 -0
  16. package/dist/held-layer-admission.js.map +7 -0
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js.map +2 -2
  20. package/dist/mmtp-container-parser.d.ts +10 -0
  21. package/dist/mmtp-container-parser.d.ts.map +1 -1
  22. package/dist/mmtp-container-parser.js +31 -1
  23. package/dist/mmtp-container-parser.js.map +2 -2
  24. package/dist/mmtp-container-parser.no-modules.js +2713 -1024
  25. package/dist/mmtp-container-parser.no-modules.js.map +4 -4
  26. package/dist/mmtp-decode-pipeline.js +31 -1
  27. package/dist/mmtp-decode-pipeline.js.map +2 -2
  28. package/dist/mmtp-fec-session.d.ts +36 -3
  29. package/dist/mmtp-fec-session.d.ts.map +1 -1
  30. package/dist/mmtp-fec-session.js +114 -5
  31. package/dist/mmtp-fec-session.js.map +3 -3
  32. package/dist/mmtp-router.d.ts +96 -29
  33. package/dist/mmtp-router.d.ts.map +1 -1
  34. package/dist/mmtp-router.js +522 -205
  35. package/dist/mmtp-router.js.map +2 -2
  36. package/dist/multicast-auth-catalog.d.ts +10 -2
  37. package/dist/multicast-auth-catalog.d.ts.map +1 -1
  38. package/dist/multicast-auth-catalog.js +422 -22
  39. package/dist/multicast-auth-catalog.js.map +4 -4
  40. package/dist/multicast-manager.d.ts +78 -11
  41. package/dist/multicast-manager.d.ts.map +1 -1
  42. package/dist/multicast-manager.js +3663 -333
  43. package/dist/multicast-manager.js.map +4 -4
  44. package/dist/multicast-transport.d.ts +4 -1
  45. package/dist/multicast-transport.d.ts.map +1 -1
  46. package/dist/multicast-transport.js +20 -3
  47. package/dist/multicast-transport.js.map +2 -2
  48. package/dist/no-modules.d.ts +1 -2
  49. package/dist/no-modules.d.ts.map +1 -1
  50. package/dist/no-modules.js +2699 -1008
  51. package/dist/no-modules.js.map +4 -4
  52. package/dist/repair-fetch.d.ts +50 -10
  53. package/dist/repair-fetch.d.ts.map +1 -1
  54. package/dist/repair-fetch.js +62 -20
  55. package/dist/repair-fetch.js.map +2 -2
  56. package/dist/wasm-mmtp-container-parser.js +31 -1
  57. package/dist/wasm-mmtp-container-parser.js.map +2 -2
  58. package/package.json +7 -15
  59. package/src/cmcd-producer.ts +6 -1
  60. package/src/fec-manager.ts +147 -131
  61. package/src/held-layer-admission.ts +161 -0
  62. package/src/index.ts +6 -9
  63. package/src/mmtp-container-parser.ts +48 -0
  64. package/src/mmtp-fec-session.ts +76 -3
  65. package/src/mmtp-router.ts +637 -274
  66. package/src/multicast-auth-catalog.ts +81 -8
  67. package/src/multicast-manager.ts +274 -49
  68. package/src/multicast-transport.ts +6 -2
  69. package/src/no-modules.ts +1 -6
  70. package/src/repair-fetch.ts +154 -34
  71. package/test-vectors/catalog/negative/multicast-auth-padded-key.json +0 -1
  72. package/test-vectors/catalog/negative/multicast-auth-reused-track-format.json +0 -1
  73. package/test-vectors/catalog/negative/multicast-auth-root-dotted-key.json +0 -1
  74. package/test-vectors/catalog/negative/multicast-auth-trailing-pad-bits.json +0 -1
  75. package/test-vectors/repair-policy-v1.json +113 -0
  76. package/dist/manifest-auth-plan.d.ts +0 -31
  77. package/dist/manifest-auth-plan.d.ts.map +0 -1
  78. package/dist/manifest-auth-plan.js +0 -426
  79. package/dist/manifest-auth-plan.js.map +0 -7
  80. package/dist/source-auth.d.ts +0 -2
  81. package/dist/source-auth.d.ts.map +0 -1
  82. package/dist/source-auth.js +0 -3912
  83. package/dist/source-auth.js.map +0 -7
  84. package/src/manifest-auth-plan.ts +0 -55
  85. package/src/source-auth.ts +0 -1
  86. package/test-vectors/generate-source-auth-fixture.mjs +0 -114
  87. package/test-vectors/source-auth-v1.json +0 -61
@@ -1,426 +0,0 @@
1
- // ../mmt-base/dist/mmtp.js
2
- var MPU_HEADER_SIZE = 8;
3
- var MPU_LENGTH_FIELD_SIZE = 2;
4
- var MPU_HEADER_REMAINDER_SIZE = MPU_HEADER_SIZE - MPU_LENGTH_FIELD_SIZE;
5
-
6
- // ../mmt-base/dist/ntp-short.js
7
- var NTP_SHORT_BITS = 32;
8
- var NTP_SHORT_MODULUS = 2 ** NTP_SHORT_BITS;
9
- var NTP_SHORT_HALF_RANGE = 2 ** (NTP_SHORT_BITS - 1);
10
-
11
- // ../mmt-base/dist/fec-block-profile.js
12
- var FEC_BLOCK_PROFILES = Object.freeze([
13
- "iso-ssbg1-v1"
14
- ]);
15
-
16
- // ../mmt-base/dist/catalog-fec-source.js
17
- var ALL_ROLES = Object.freeze(["video", "audio"]);
18
-
19
- // ../mmt-base/dist/multicast-catalog.js
20
- var ED25519_PUBLIC_KEY_BASE64URL = /^[A-Za-z0-9_-]{42}[AEIMQUYcgkosw048]$/;
21
- var UINT32_MAX = 4294967295;
22
- var AUTH_MEMBERS = /* @__PURE__ */ new Set(["scheme", "version", "sig", "keys", "minEpoch"]);
23
- var KEY_MEMBERS = /* @__PURE__ */ new Set(["kid", "publicKey", "firstEpoch"]);
24
- var ENDPOINT_AUTH_MEMBERS = /* @__PURE__ */ new Set([
25
- "manifestPort",
26
- "streamId",
27
- "senderAddress",
28
- "maxAuthDelayMs",
29
- "manifestTimerMs",
30
- "manifestTrack"
31
- ]);
32
- function isObject(value) {
33
- return typeof value === "object" && value !== null && !Array.isArray(value);
34
- }
35
- function isNonEmptyString(value) {
36
- return typeof value === "string" && value.trim().length > 0;
37
- }
38
- function isIntegerIn(value, min, max) {
39
- return Number.isSafeInteger(value) && value >= min && value <= max;
40
- }
41
- function multicastEndpointSource(endpoint) {
42
- if (!isObject(endpoint))
43
- return void 0;
44
- const sourceAddress = endpoint["sourceAddress"];
45
- if (sourceAddress !== void 0 && !isNonEmptyString(sourceAddress))
46
- return void 0;
47
- const mode = sourceAddress === void 0 ? "asm" : "ssm";
48
- const protocol = endpoint["protocol"];
49
- if (protocol !== void 0 && protocol !== mode)
50
- return void 0;
51
- const auth = endpoint["auth"];
52
- const senderAddress = isObject(auth) ? auth["senderAddress"] : void 0;
53
- if (mode === "ssm")
54
- return senderAddress === void 0 ? { mode, source: sourceAddress } : void 0;
55
- if (auth === void 0)
56
- return { mode };
57
- return isNonEmptyString(senderAddress) ? { mode, source: senderAddress } : void 0;
58
- }
59
- function authIssues(auth) {
60
- const base = "$.multicast.auth";
61
- const issue = (path, message) => [
62
- { code: "multicast_auth", path: `${base}${path}`, message }
63
- ];
64
- if (!isObject(auth))
65
- return issue("", "auth must be an object");
66
- const unknown = Object.keys(auth).filter((key) => !AUTH_MEMBERS.has(key));
67
- if (unknown.length > 0) {
68
- return issue("", `auth has unknown member(s) ${unknown.join(", ")}; draft -01 7.2.6 defines scheme, version, sig, keys and minEpoch`);
69
- }
70
- if (auth["scheme"] !== "bc-provenance")
71
- return issue(".scheme", 'scheme must be "bc-provenance"');
72
- if (auth["version"] !== 2)
73
- return issue(".version", "version must be 2 (bc-provenance version 2, draft -01 7.2)");
74
- if (auth["sig"] !== "ed25519")
75
- return issue(".sig", 'sig must be "ed25519"');
76
- const keys = auth["keys"];
77
- if (!Array.isArray(keys) || keys.length < 1 || keys.length > 4) {
78
- return issue(".keys", "keys must be an array of one to four {kid, publicKey, firstEpoch} objects");
79
- }
80
- const kids = /* @__PURE__ */ new Set();
81
- const firstEpochs = /* @__PURE__ */ new Set();
82
- for (let index = 0; index < keys.length; index++) {
83
- const key = keys[index];
84
- const at = `.keys[${index}]`;
85
- if (!isObject(key) || Object.keys(key).some((member) => !KEY_MEMBERS.has(member))) {
86
- return issue(at, "a key is exactly {kid, publicKey, firstEpoch}");
87
- }
88
- if (!isIntegerIn(key["kid"], 0, UINT32_MAX))
89
- return issue(`${at}.kid`, "kid must be an unsigned 32-bit integer");
90
- if (typeof key["publicKey"] !== "string" || !ED25519_PUBLIC_KEY_BASE64URL.test(key["publicKey"])) {
91
- return issue(`${at}.publicKey`, "publicKey must be a 32-octet Ed25519 key in canonical unpadded base64url");
92
- }
93
- if (!isIntegerIn(key["firstEpoch"], 0, UINT32_MAX)) {
94
- return issue(`${at}.firstEpoch`, "firstEpoch must be an unsigned 32-bit integer");
95
- }
96
- if (kids.has(key["kid"]))
97
- return issue(`${at}.kid`, `kid ${key["kid"]} is repeated; the catalog holds no key set`);
98
- if (firstEpochs.has(key["firstEpoch"])) {
99
- return issue(`${at}.firstEpoch`, `firstEpoch ${key["firstEpoch"]} is repeated; the catalog holds no key set`);
100
- }
101
- kids.add(key["kid"]);
102
- firstEpochs.add(key["firstEpoch"]);
103
- }
104
- if (!isIntegerIn(auth["minEpoch"], 0, UINT32_MAX)) {
105
- return issue(".minEpoch", "minEpoch must be an unsigned 32-bit integer");
106
- }
107
- return [];
108
- }
109
- function endpointAuthIssue(endpoint, mode, at) {
110
- const auth = endpoint["auth"];
111
- if (!isObject(auth))
112
- return { path: `${at}.auth`, message: "auth must be an object" };
113
- const unknown = Object.keys(auth).filter((key) => !ENDPOINT_AUTH_MEMBERS.has(key));
114
- if (unknown.length > 0)
115
- return { path: `${at}.auth`, message: `auth has unknown member(s) ${unknown.join(", ")}` };
116
- if (!isIntegerIn(auth["manifestPort"], 1, 65535)) {
117
- return { path: `${at}.auth.manifestPort`, message: "manifestPort must be an integer from 1 to 65535" };
118
- }
119
- if (!isIntegerIn(auth["streamId"], 0, UINT32_MAX)) {
120
- return { path: `${at}.auth.streamId`, message: "streamId must be an unsigned 32-bit integer" };
121
- }
122
- if (mode === "ssm" && auth["senderAddress"] !== void 0) {
123
- return { path: `${at}.auth.senderAddress`, message: "senderAddress must not appear on an SSM endpoint; S is sourceAddress" };
124
- }
125
- if (mode === "asm" && !isNonEmptyString(auth["senderAddress"])) {
126
- return { path: `${at}.auth.senderAddress`, message: "a protected ASM endpoint requires senderAddress" };
127
- }
128
- if (auth["maxAuthDelayMs"] !== void 0 && !isIntegerIn(auth["maxAuthDelayMs"], 50, 1e3)) {
129
- return { path: `${at}.auth.maxAuthDelayMs`, message: "maxAuthDelayMs must be an integer from 50 to 1000" };
130
- }
131
- if (auth["manifestTimerMs"] !== void 0 && !isIntegerIn(auth["manifestTimerMs"], 1, Number.MAX_SAFE_INTEGER)) {
132
- return { path: `${at}.auth.manifestTimerMs`, message: "manifestTimerMs must be an integer of at least 1" };
133
- }
134
- if (auth["manifestTrack"] !== void 0 && !isNonEmptyString(auth["manifestTrack"])) {
135
- return { path: `${at}.auth.manifestTrack`, message: "manifestTrack must be a non-empty string" };
136
- }
137
- if (!isIntegerIn(endpoint["bandwidth"], 1, Number.MAX_SAFE_INTEGER)) {
138
- return { path: `${at}.bandwidth`, message: "a protected endpoint requires bandwidth, which bounds the receiver's hold queues" };
139
- }
140
- return void 0;
141
- }
142
- var CATALOG_NAMESPACE = /* @__PURE__ */ Symbol.for("@blockcast/mmt-base/catalogNamespace");
143
- function multicastCatalogIssues(catalog, options = {}) {
144
- if (!isObject(catalog))
145
- return [];
146
- const issues = [];
147
- if ("multicast.auth" in catalog) {
148
- issues.push({
149
- code: "multicast_auth",
150
- path: '$["multicast.auth"]',
151
- message: 'the root "multicast.auth" key is retired; declare auth as multicast.auth (draft -01 7.2.6)'
152
- });
153
- }
154
- const multicast = catalog["multicast"];
155
- if (!isObject(multicast))
156
- return issues;
157
- const protectedCatalog = multicast["auth"] !== void 0;
158
- if (protectedCatalog)
159
- issues.push(...authIssues(multicast["auth"]));
160
- const endpoints = multicast["endpoints"];
161
- if (!Array.isArray(endpoints))
162
- return issues;
163
- const tracks = Array.isArray(catalog["tracks"]) ? catalog["tracks"] : [];
164
- const namespaceOf = /* @__PURE__ */ new Map();
165
- for (const track of tracks) {
166
- if (isObject(track) && typeof track["name"] === "string")
167
- namespaceOf.set(track["name"], track["namespace"]);
168
- }
169
- const tagged = catalog[CATALOG_NAMESPACE];
170
- let referenceNamespace = options.catalogNamespace ?? (typeof tagged === "string" ? tagged : void 0);
171
- const sources = [];
172
- for (let index = 0; index < endpoints.length; index++) {
173
- const endpoint = endpoints[index];
174
- const at = `$.multicast.endpoints[${index}]`;
175
- const fail = (code, path, message) => {
176
- issues.push({ code, path, message, endpointIndex: index });
177
- };
178
- sources.push(void 0);
179
- if (!isObject(endpoint)) {
180
- fail("multicast_endpoint", at, "endpoint must be an object");
181
- continue;
182
- }
183
- const protocol = endpoint["protocol"];
184
- if (protocol !== void 0 && protocol !== "ssm" && protocol !== "asm") {
185
- fail("multicast_endpoint", `${at}.protocol`, `protocol must be "ssm" or "asm"; a bearer such as ${JSON.stringify(protocol)} is a networkSource entry (draft -01 4.2)`);
186
- continue;
187
- }
188
- const hasAuth = endpoint["auth"] !== void 0;
189
- if (protectedCatalog !== hasAuth) {
190
- fail("multicast_endpoint_auth", `${at}.auth`, protectedCatalog ? "every endpoint requires auth when multicast carries auth; a receiver ignores this endpoint" : "auth names no key without multicast.auth; a receiver ignores this endpoint");
191
- continue;
192
- }
193
- const sourceAddress = endpoint["sourceAddress"];
194
- if (sourceAddress !== void 0 && !isNonEmptyString(sourceAddress)) {
195
- fail("multicast_endpoint", `${at}.sourceAddress`, "sourceAddress must be a non-empty string");
196
- continue;
197
- }
198
- const mode = sourceAddress === void 0 ? "asm" : "ssm";
199
- if (protocol !== void 0 && protocol !== mode) {
200
- fail("multicast_endpoint", `${at}.protocol`, `protocol ${JSON.stringify(protocol)} disagrees with sourceAddress, which selects ${mode}`);
201
- continue;
202
- }
203
- if (!isIntegerIn(endpoint["port"], 1, 65535)) {
204
- fail("multicast_endpoint", `${at}.port`, "port must be an integer from 1 to 65535");
205
- continue;
206
- }
207
- if (hasAuth) {
208
- const authIssue = endpointAuthIssue(endpoint, mode, at);
209
- if (authIssue) {
210
- fail("multicast_endpoint_auth", authIssue.path, authIssue.message);
211
- continue;
212
- }
213
- }
214
- sources[index] = multicastEndpointSource(endpoint);
215
- const refs = Array.isArray(endpoint["tracks"]) ? endpoint["tracks"] : [];
216
- for (let refIndex = 0; refIndex < refs.length; refIndex++) {
217
- const ref = refs[refIndex];
218
- const name = isObject(ref) ? ref["name"] : ref;
219
- if (typeof name !== "string")
220
- continue;
221
- const namespace = namespaceOf.get(name);
222
- if (typeof namespace !== "string")
223
- continue;
224
- referenceNamespace ??= namespace;
225
- if (namespace !== referenceNamespace) {
226
- fail("multicast_track", `${at}.tracks[${refIndex}].name`, `track ${JSON.stringify(name)} declares namespace ${JSON.stringify(namespace)}, not the catalog track's ${JSON.stringify(referenceNamespace)}`);
227
- }
228
- }
229
- }
230
- const tupleOf = (index) => {
231
- const endpoint = endpoints[index];
232
- const auth = endpoint["auth"];
233
- return {
234
- sg: JSON.stringify([sources[index].source ?? null, endpoint["groupAddress"]]),
235
- port: endpoint["port"],
236
- manifestPort: isObject(auth) ? auth["manifestPort"] : void 0
237
- };
238
- };
239
- for (let index = 0; index < endpoints.length; index++) {
240
- if (!sources[index])
241
- continue;
242
- const own = tupleOf(index);
243
- const at = `$.multicast.endpoints[${index}]`;
244
- if (own.manifestPort !== void 0 && own.manifestPort === own.port) {
245
- issues.push({ code: "multicast_endpoint_auth", path: `${at}.auth.manifestPort`, message: "manifestPort must differ from the endpoint's own port", endpointIndex: index });
246
- continue;
247
- }
248
- for (let other = 0; other < endpoints.length; other++) {
249
- if (other === index || !sources[other])
250
- continue;
251
- const peer = tupleOf(other);
252
- if (peer.sg !== own.sg)
253
- continue;
254
- if (peer.port === own.port) {
255
- issues.push({ code: "multicast_endpoint", path: `${at}.port`, message: `(S, G, port) is shared with endpoint ${other}; one endpoint object per multicast tuple`, endpointIndex: index });
256
- break;
257
- }
258
- if (own.manifestPort !== void 0 && (own.manifestPort === peer.port || own.manifestPort === peer.manifestPort)) {
259
- issues.push({ code: "multicast_endpoint_auth", path: `${at}.auth.manifestPort`, message: `manifestPort is a port or manifestPort of endpoint ${other} on the same (S, G)`, endpointIndex: index });
260
- break;
261
- }
262
- }
263
- }
264
- return issues;
265
- }
266
-
267
- // ../mmt-manifest-verify/dist/source-auth.js
268
- var SOURCE_AUTH_MAX_TRUE_LENGTH = 16 * 1024 * 1024;
269
- var SIGNATURE_DOMAIN = new TextEncoder().encode("blockcast-mmt-root-v1\0\0\0");
270
-
271
- // ../mmt-manifest-verify/dist/verifier.js
272
- function manifestKeyFor(keys, epoch, kid) {
273
- if (new Set(keys.map((key) => key.kid)).size !== keys.length)
274
- return void 0;
275
- if (new Set(keys.map((key) => key.firstEpoch)).size !== keys.length)
276
- return void 0;
277
- let signer;
278
- for (const key of keys) {
279
- if (key.firstEpoch <= epoch && (signer === void 0 || key.firstEpoch > signer.firstEpoch))
280
- signer = key;
281
- }
282
- if (signer === void 0 || kid !== void 0 && signer.kid !== kid)
283
- return void 0;
284
- return signer.publicKey;
285
- }
286
-
287
- // ../mmt-manifest-verify/dist/bc-provenance-v2.js
288
- var BCPV2_HEADER_LENGTH = 68;
289
- var BCPV2_SIGNATURE_LENGTH = 64;
290
- var BCPV2_MIN_RECORD_LENGTH = BCPV2_HEADER_LENGTH + 32 + BCPV2_SIGNATURE_LENGTH;
291
- var text = new TextEncoder();
292
- var MAGIC = Uint8Array.from([77, 72, 77, 50]);
293
- var SIGNING_DOMAIN = text.encode("mcast-manifest-v2\0");
294
-
295
- // src/multicast-auth-catalog.ts
296
- var RAW_ED25519_KEY_LENGTH = 32;
297
- var DEFAULT_MAX_AUTH_DELAY_MS = 200;
298
- var DEFAULT_MANIFEST_TIMER_MS = 20;
299
- var BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
300
- function encodeBase64Url(bytes) {
301
- let output = "";
302
- for (let i = 0; i < bytes.length; i += 3) {
303
- const b0 = bytes[i];
304
- const b1 = bytes[i + 1];
305
- const b2 = bytes[i + 2];
306
- output += BASE64URL_ALPHABET[b0 >> 2];
307
- output += BASE64URL_ALPHABET[(b0 & 3) << 4 | (b1 === void 0 ? 0 : b1 >> 4)];
308
- if (b1 === void 0) break;
309
- output += BASE64URL_ALPHABET[(b1 & 15) << 2 | (b2 === void 0 ? 0 : b2 >> 6)];
310
- if (b2 === void 0) break;
311
- output += BASE64URL_ALPHABET[b2 & 63];
312
- }
313
- return output;
314
- }
315
- var BASE64URL_DECODE_TABLE = (() => {
316
- const table = new Int8Array(128).fill(-1);
317
- for (let i = 0; i < BASE64URL_ALPHABET.length; i++) {
318
- table[BASE64URL_ALPHABET.charCodeAt(i)] = i;
319
- }
320
- return table;
321
- })();
322
- function decodeBase64Url(text2) {
323
- if (text2.length % 4 === 1) {
324
- throw new Error(`[multicast-auth-catalog] invalid unpadded base64url length for "${text2}"`);
325
- }
326
- const bytes = [];
327
- let buffer = 0;
328
- let bits = 0;
329
- for (let i = 0; i < text2.length; i++) {
330
- const code = text2.charCodeAt(i);
331
- const value = code < 128 ? BASE64URL_DECODE_TABLE[code] : -1;
332
- if (value === void 0 || value < 0) {
333
- throw new Error(`[multicast-auth-catalog] invalid base64url character in "${text2}"`);
334
- }
335
- buffer = buffer << 6 | value;
336
- bits += 6;
337
- if (bits >= 8) {
338
- bits -= 8;
339
- bytes.push(buffer >> bits & 255);
340
- }
341
- }
342
- const decoded = Uint8Array.from(bytes);
343
- if (encodeBase64Url(decoded) !== text2) {
344
- throw new Error(`[multicast-auth-catalog] non-canonical base64url encoding "${text2}"`);
345
- }
346
- return decoded;
347
- }
348
- function decodeEd25519PublicKey(publicKey) {
349
- const bytes = decodeBase64Url(publicKey);
350
- if (bytes.byteLength !== RAW_ED25519_KEY_LENGTH) {
351
- throw new Error(
352
- `[multicast-auth-catalog] public key must decode to ${RAW_ED25519_KEY_LENGTH} raw bytes, got ${bytes.byteLength}`
353
- );
354
- }
355
- return bytes;
356
- }
357
- function resolveMulticastAuthCatalog(catalog, options = {}) {
358
- if (typeof catalog !== "object" || catalog === null || Array.isArray(catalog)) {
359
- throw new Error("[multicast-auth-catalog] catalog must be an object");
360
- }
361
- const issues = multicastCatalogIssues(catalog, options);
362
- const fatal = issues.find((issue) => issue.endpointIndex === void 0);
363
- if (fatal) throw new Error(`[multicast-auth-catalog] ${fatal.path}: ${fatal.message}`);
364
- const multicast = catalog["multicast"];
365
- const auth = multicast?.["auth"];
366
- if (auth === void 0) {
367
- if (options.requireAuth) {
368
- throw new Error("[multicast-auth-catalog] authentication is pinned but the catalog declares no multicast.auth");
369
- }
370
- return void 0;
371
- }
372
- const ignored = new Set(issues.map((issue) => issue.endpointIndex));
373
- const endpoints = multicast["endpoints"] ?? [];
374
- const flows = [];
375
- endpoints.forEach((endpoint, endpointIndex) => {
376
- if (ignored.has(endpointIndex)) return;
377
- const flowAuth = endpoint["auth"];
378
- flows.push({
379
- endpointIndex,
380
- source: endpoint["sourceAddress"] ?? flowAuth.senderAddress,
381
- groupAddress: endpoint["groupAddress"],
382
- port: endpoint["port"],
383
- bandwidth: endpoint["bandwidth"],
384
- manifestPort: flowAuth.manifestPort,
385
- streamId: flowAuth.streamId,
386
- maxAuthDelayMs: flowAuth.maxAuthDelayMs ?? DEFAULT_MAX_AUTH_DELAY_MS,
387
- manifestTimerMs: flowAuth.manifestTimerMs ?? DEFAULT_MANIFEST_TIMER_MS,
388
- ...flowAuth.manifestTrack === void 0 ? {} : { manifestTrack: flowAuth.manifestTrack },
389
- tracks: (endpoint["tracks"] ?? []).map(({ name, packetId }) => ({
390
- name,
391
- packetId
392
- }))
393
- });
394
- });
395
- return {
396
- keys: auth.keys.map((key) => ({ kid: key.kid, publicKey: decodeEd25519PublicKey(key.publicKey), firstEpoch: key.firstEpoch })).sort((a, b) => a.firstEpoch - b.firstEpoch),
397
- minEpoch: auth.minEpoch,
398
- flows
399
- };
400
- }
401
- function multicastAuthKeyFor(resolved, kid, epoch) {
402
- return manifestKeyFor(resolved.keys, epoch, kid);
403
- }
404
-
405
- // src/manifest-auth-plan.ts
406
- function createManifestAuthPlan(catalog, options = {}) {
407
- const resolved = resolveMulticastAuthCatalog(catalog, options);
408
- if (!resolved) return void 0;
409
- const byManifestTrack = /* @__PURE__ */ new Map();
410
- for (const flow of resolved.flows) {
411
- if (flow.manifestTrack !== void 0) byManifestTrack.set(flow.manifestTrack, flow);
412
- }
413
- return {
414
- keys: resolved.keys,
415
- minEpoch: resolved.minEpoch,
416
- flows: resolved.flows,
417
- manifestTracks: [...byManifestTrack.keys()],
418
- keyFor: (kid, epoch) => multicastAuthKeyFor(resolved, kid, epoch),
419
- flowForManifestPort: (source, groupAddress, manifestPort) => resolved.flows.find((flow) => flow.source === source && flow.groupAddress === groupAddress && flow.manifestPort === manifestPort),
420
- flowForManifestTrack: (manifestTrack) => byManifestTrack.get(manifestTrack)
421
- };
422
- }
423
- export {
424
- createManifestAuthPlan
425
- };
426
- //# sourceMappingURL=manifest-auth-plan.js.map