@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,103 @@
1
+ {
2
+ "_comment": "GENERATED by scripts/generateVectors.ts - do not hand-edit. One fixture read by BOTH the backend minter spec and the media-server verifier spec, so the two cannot drift. The keys are test keys and are committed on purpose.",
3
+ "nowSeconds": 1760000000,
4
+ "issuer": "legal-de",
5
+ "kid": "test-v1",
6
+ "keys": {
7
+ "test-v1": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEADDA6KSONGhJqPWozH6py1Gu6M53ZpupI9cLMN/RZtws=\n-----END PUBLIC KEY-----\n"
8
+ },
9
+ "privateKeyForMinterTests": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIO8H96J+s7hghw0TR4cDCVjjaBwMciXpPte0hx7WSFf3\n-----END PRIVATE KEY-----\n",
10
+ "vectors": [
11
+ {
12
+ "name": "valid_human",
13
+ "why": "the ordinary case: a human joining over webrtc",
14
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.cHwZ_nFkDQoHVtB6-mA2Rg-KcuVTralgw1cS908OQh7_8JUOKAP9l6kFiKpmfHFMEz6aBt7yXeIRKnBvTfJlBw",
15
+ "expect": "ok"
16
+ },
17
+ {
18
+ "name": "valid_agent_exempt",
19
+ "why": "a non-human may be exempt from the active-set ceiling; a human may not",
20
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoidHJhbnNjcmliZXIiLCJraW5kIjoiYWdlbnQiLCJ0cmFuc3BvcnQiOiJwbGFpbiIsImdyYW50cyI6eyJjYW5QdWJsaXNoIjpmYWxzZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6ZmFsc2UsInN1YnNjcmliZUV4ZW1wdCI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.Mc3KKrczwe0j6YYpe-HXBiYn5C8CeOhYaE2HI64tANDzhucO0BxAgTg9fTdJAGKW8W9RymwV6j83HRWZr854AQ",
21
+ "expect": "ok"
22
+ },
23
+ {
24
+ "name": "valid_barrier",
25
+ "why": "an information barrier: alice may receive only carol, and only carol may receive alice",
26
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlIjp7Im1vZGUiOiJhbGxvdyIsImlkZW50aXRpZXMiOlsiY2Fyb2wiXX0sInZpc2libGVUbyI6eyJtb2RlIjoiYWxsb3ciLCJpZGVudGl0aWVzIjpbImNhcm9sIl19fSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.1jx23AACBL-tvtUFSUGQAjjBCuEs6pv7MHSeqAfy7HY-ki65Rf-YadxsPk5Nzg-OrOopu08J6m_Wdm5YA3TMDw",
27
+ "expect": "ok"
28
+ },
29
+ {
30
+ "name": "unknown_grant_key",
31
+ "why": "THE fail-open case. One phase minted `subscribeOnly` while another read `subscribe`; a lenient schema would have read 'no rule' as 'everyone' and put two Mandanten in one room.",
32
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlT25seSI6WyJjYXJvbCJdfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.uda5k_gP-zizkivazZkx1QoSj-54DgnTzCMoTBZ-Pzfyn1jZdw49IvPbAD-88yOfn7ukVYCOko0DRHkxmfu8Aw",
33
+ "expect": "bad_claims"
34
+ },
35
+ {
36
+ "name": "human_with_subscribe_exempt",
37
+ "why": "exemption bypasses the active-set ceiling; a human holding it can pull every track in a 1,000-person room",
38
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlRXhlbXB0Ijp0cnVlfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.o34OTK5D0qRD5enDABkljr_aFerqzoZYLR_uqgTKwO1DsszjDkIG8gUxvjucYZ9apvwWIq3tuwAPVRSAotqYCA",
39
+ "expect": "bad_claims"
40
+ },
41
+ {
42
+ "name": "expired",
43
+ "why": "a join ticket outlives its window",
44
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc1OTk5OTQwMCwiZXhwIjoxNzU5OTk5NzAwfQ.hTM23tP-4IP044XhjXNSmzpXMWzi1GC7LrV5vLN_H1SnnI0ZFgLmg8VTW34cPbZy6yIs8mXRZT8uNJ6xsCAQDQ",
45
+ "expect": "expired"
46
+ },
47
+ {
48
+ "name": "not_yet_valid",
49
+ "why": "nbf in the future",
50
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwibmJmIjoxNzYwMDAwNjAwLCJleHAiOjE3NjAwMDA5MDB9.xpFjHBt5XYyG6pP9_3j5C-h0FS5Y7byfo_M8qkkGn33iK9i4qO3L_SzFxYebTEoX-jmlTu8Y8MCPlhLzb3MFCw",
51
+ "expect": "not_yet_valid"
52
+ },
53
+ {
54
+ "name": "ttl_too_long",
55
+ "why": "enforced at VERIFY as well as mint, because a compromised minter would simply skip the mint check",
56
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDg2NDAwfQ.UCA0foITm9CL3z1ZslwGf4Dvmqe0xkOpYhN9l13-DKRPjje6pGez4jcvhKDGwPuy8f7lovvUfoRwCWG4UGYWCg",
57
+ "expect": "ttl_too_long"
58
+ },
59
+ {
60
+ "name": "wrong_issuer",
61
+ "why": "a token minted for the main instance must be worthless on the legal one",
62
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJtYWluIiwiYXVkIjoibWVkaWEiLCJyb29tIjoicm9vbS0xIiwiaWRlbnRpdHkiOiJhbGljZSIsImtpbmQiOiJodW1hbiIsInRyYW5zcG9ydCI6IndlYnJ0YyIsImdyYW50cyI6eyJjYW5QdWJsaXNoIjp0cnVlLCJjYW5TdWJzY3JpYmUiOnRydWUsImNhblB1Ymxpc2hEYXRhIjp0cnVlfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.Z33LRIVYrY7KlvUUsQCZ52x7HBxPKWBuJSKySb6d0Ncmenu8CpFSxC2JRm_s7NPbuMwBymgQjKUiFmTeUm_FCA",
63
+ "expect": "wrong_issuer"
64
+ },
65
+ {
66
+ "name": "wrong_audience_control_as_join",
67
+ "why": "a control token replayed as a join",
68
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6ImNvbnRyb2wiLCJqdGkiOiJqdGktY29udHJvbC0xIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.q9LAV0vxFy95CqICQ9jl5dm7ll_iD8HSDADK0cQu85wJxVx1roQL-RZggjcrxhShH2uzfKufTW9211pF56caDA",
69
+ "expect": "wrong_audience"
70
+ },
71
+ {
72
+ "name": "unknown_kid",
73
+ "why": "signed by a key this node does not carry",
74
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InJvdGF0ZWQtYXdheSJ9.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.W_BZBx_p9W245Xw89H3Dy_MEYf5JfNb8KpSeLok4ZjYUc_EWx8wxvghDrWjaidXp6yxOK3Su_r_b_QHOis7tCA",
75
+ "expect": "unknown_kid"
76
+ },
77
+ {
78
+ "name": "bad_signature",
79
+ "why": "correct kid, wrong key - a forgery attempt rather than a rotation",
80
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.Chdv_Jl7v6HTE5u1TpP6f7j2mqFPocPKfBSdwgbL_lNIN708mHHA5oGeR8AOjPakn16WLTW6jODEUnbj_KTLAA",
81
+ "expect": "bad_signature"
82
+ },
83
+ {
84
+ "name": "alg_none",
85
+ "why": "classic JWT algorithm confusion. Only EdDSA is ever accepted.",
86
+ "token": "eyJhbGciOiJub25lIiwidHlwIjoiSldUIiwia2lkIjoidGVzdC12MSJ9.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.",
87
+ "expect": "malformed"
88
+ },
89
+ {
90
+ "name": "wrong_room",
91
+ "why": "a valid token for a different room",
92
+ "token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMiIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.EWEv-Np5ECbj4TZXt3KTgcPUHEoDM2G4Wx-M0L25pTkE0onIRMm5vmbVBypULUtIWtKxOxsdDNBezcl8Nqy8Bg",
93
+ "expect": "wrong_room",
94
+ "room": "room-1"
95
+ },
96
+ {
97
+ "name": "malformed",
98
+ "why": "not three segments",
99
+ "token": "not.a.token.at.all",
100
+ "expect": "malformed"
101
+ }
102
+ ]
103
+ }
@@ -0,0 +1,327 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * The join token's claims: the whole authorization decision, made once by the
4
+ * backend and carried to a media plane that never asks it anything.
5
+ *
6
+ * Names here were contested by the parallel phase plans; each disagreement is
7
+ * resolved once, in this file, and everything else imports it.
8
+ */
9
+ /**
10
+ * The longest display name a join token may carry.
11
+ *
12
+ * Exported because it is a MINT-TIME refusal, not a preference: `signJoinToken`
13
+ * hard-parses these claims, so a caller that builds a name out of stored text
14
+ * and does not clamp it throws instead of minting. Every such caller has to
15
+ * know the bound, and a caller that hard-codes 200 is a caller that will not
16
+ * follow this number if it ever moves.
17
+ */
18
+ export declare const MEDIA_PARTICIPANT_NAME_MAX_LENGTH = 200;
19
+ /**
20
+ * A display name cut to what a token may carry.
21
+ *
22
+ * Lives HERE, beside the bound it enforces, rather than in each surface that
23
+ * mints. Two reasons, and the second is the one that matters.
24
+ *
25
+ * A minting surface builds the name out of stored text (a buyer's name off a
26
+ * booking, a seat's display name off a roster) and cannot promise a length, so
27
+ * every one of them needs this. And a surface that instead compared against the
28
+ * exported NUMBER would go silently unclamped the moment it read a stale build
29
+ * of this package: `value.length > undefined` is `false`, so the clamp
30
+ * evaporates and the failure only shows up as a 500 from `signJoinToken` in
31
+ * production. A missing FUNCTION throws on the first call instead.
32
+ *
33
+ * Truncation rather than refusal is deliberate. A name is a label on a tile,
34
+ * and no call should fail to open over one.
35
+ */
36
+ export declare function clampParticipantName(value: string): string;
37
+ /**
38
+ * `iss` IS the instance id (`legal-de`, `main`), not a service name.
39
+ *
40
+ * One plan proposed `iss: "tribenest-backend"` with the instance in a separate
41
+ * `inst` claim. That displaces the one value a verifier actually checks, and a
42
+ * legal-de token would then verify happily on the main instance - which is the
43
+ * whole reason instances are separate.
44
+ */
45
+ export declare const mediaJoinClaimsSchema: z.ZodObject<{
46
+ v: z.ZodLiteral<1>;
47
+ iss: z.ZodString;
48
+ aud: z.ZodLiteral<"media">;
49
+ room: z.ZodString;
50
+ /** `identity`, not `sub`: it is a first-class concept the barrier rules name. */
51
+ identity: z.ZodString;
52
+ name: z.ZodOptional<z.ZodString>;
53
+ /** Top level, NOT inside grants - it decides what may be minted at all. */
54
+ kind: z.ZodEnum<["human", "agent", "egress", "sip", "ingress"]>;
55
+ /** Top level. Transport authority is not media authority. */
56
+ transport: z.ZodEnum<["webrtc", "plain", "pipe"]>;
57
+ grants: z.ZodObject<{
58
+ canPublish: z.ZodBoolean;
59
+ canSubscribe: z.ZodBoolean;
60
+ canPublishData: z.ZodBoolean;
61
+ subscribe: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
62
+ mode: z.ZodLiteral<"all">;
63
+ }, "strict", z.ZodTypeAny, {
64
+ mode: "all";
65
+ }, {
66
+ mode: "all";
67
+ }>, z.ZodObject<{
68
+ mode: z.ZodLiteral<"none">;
69
+ }, "strict", z.ZodTypeAny, {
70
+ mode: "none";
71
+ }, {
72
+ mode: "none";
73
+ }>, z.ZodObject<{
74
+ mode: z.ZodLiteral<"allow">;
75
+ identities: z.ZodArray<z.ZodString, "many">;
76
+ }, "strict", z.ZodTypeAny, {
77
+ mode: "allow";
78
+ identities: string[];
79
+ }, {
80
+ mode: "allow";
81
+ identities: string[];
82
+ }>, z.ZodObject<{
83
+ mode: z.ZodLiteral<"deny">;
84
+ identities: z.ZodArray<z.ZodString, "many">;
85
+ }, "strict", z.ZodTypeAny, {
86
+ mode: "deny";
87
+ identities: string[];
88
+ }, {
89
+ mode: "deny";
90
+ identities: string[];
91
+ }>]>>;
92
+ visibleTo: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
93
+ mode: z.ZodLiteral<"all">;
94
+ }, "strict", z.ZodTypeAny, {
95
+ mode: "all";
96
+ }, {
97
+ mode: "all";
98
+ }>, z.ZodObject<{
99
+ mode: z.ZodLiteral<"none">;
100
+ }, "strict", z.ZodTypeAny, {
101
+ mode: "none";
102
+ }, {
103
+ mode: "none";
104
+ }>, z.ZodObject<{
105
+ mode: z.ZodLiteral<"allow">;
106
+ identities: z.ZodArray<z.ZodString, "many">;
107
+ }, "strict", z.ZodTypeAny, {
108
+ mode: "allow";
109
+ identities: string[];
110
+ }, {
111
+ mode: "allow";
112
+ identities: string[];
113
+ }>, z.ZodObject<{
114
+ mode: z.ZodLiteral<"deny">;
115
+ identities: z.ZodArray<z.ZodString, "many">;
116
+ }, "strict", z.ZodTypeAny, {
117
+ mode: "deny";
118
+ identities: string[];
119
+ }, {
120
+ mode: "deny";
121
+ identities: string[];
122
+ }>]>>;
123
+ publishKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["audio", "video", "screen"]>, "many">>;
124
+ subscribeExempt: z.ZodOptional<z.ZodBoolean>;
125
+ maxSubscriptions: z.ZodOptional<z.ZodNumber>;
126
+ }, "strict", z.ZodTypeAny, {
127
+ canPublish: boolean;
128
+ canSubscribe: boolean;
129
+ canPublishData: boolean;
130
+ subscribe?: {
131
+ mode: "all";
132
+ } | {
133
+ mode: "none";
134
+ } | {
135
+ mode: "allow";
136
+ identities: string[];
137
+ } | {
138
+ mode: "deny";
139
+ identities: string[];
140
+ } | undefined;
141
+ visibleTo?: {
142
+ mode: "all";
143
+ } | {
144
+ mode: "none";
145
+ } | {
146
+ mode: "allow";
147
+ identities: string[];
148
+ } | {
149
+ mode: "deny";
150
+ identities: string[];
151
+ } | undefined;
152
+ publishKinds?: ("audio" | "video" | "screen")[] | undefined;
153
+ subscribeExempt?: boolean | undefined;
154
+ maxSubscriptions?: number | undefined;
155
+ }, {
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
+ jti: z.ZodString;
186
+ iat: z.ZodNumber;
187
+ nbf: z.ZodOptional<z.ZodNumber>;
188
+ exp: z.ZodNumber;
189
+ }, "strict", z.ZodTypeAny, {
190
+ v: 1;
191
+ iss: string;
192
+ aud: "media";
193
+ room: string;
194
+ identity: string;
195
+ kind: "human" | "agent" | "egress" | "sip" | "ingress";
196
+ transport: "webrtc" | "plain" | "pipe";
197
+ grants: {
198
+ canPublish: boolean;
199
+ canSubscribe: boolean;
200
+ canPublishData: boolean;
201
+ subscribe?: {
202
+ mode: "all";
203
+ } | {
204
+ mode: "none";
205
+ } | {
206
+ mode: "allow";
207
+ identities: string[];
208
+ } | {
209
+ mode: "deny";
210
+ identities: string[];
211
+ } | undefined;
212
+ visibleTo?: {
213
+ mode: "all";
214
+ } | {
215
+ mode: "none";
216
+ } | {
217
+ mode: "allow";
218
+ identities: string[];
219
+ } | {
220
+ mode: "deny";
221
+ identities: string[];
222
+ } | undefined;
223
+ publishKinds?: ("audio" | "video" | "screen")[] | undefined;
224
+ subscribeExempt?: boolean | undefined;
225
+ maxSubscriptions?: number | undefined;
226
+ };
227
+ jti: string;
228
+ iat: number;
229
+ exp: number;
230
+ name?: string | undefined;
231
+ nbf?: number | undefined;
232
+ }, {
233
+ v: 1;
234
+ iss: string;
235
+ aud: "media";
236
+ room: string;
237
+ identity: string;
238
+ kind: "human" | "agent" | "egress" | "sip" | "ingress";
239
+ transport: "webrtc" | "plain" | "pipe";
240
+ grants: {
241
+ canPublish: boolean;
242
+ canSubscribe: boolean;
243
+ canPublishData: boolean;
244
+ subscribe?: {
245
+ mode: "all";
246
+ } | {
247
+ mode: "none";
248
+ } | {
249
+ mode: "allow";
250
+ identities: string[];
251
+ } | {
252
+ mode: "deny";
253
+ identities: string[];
254
+ } | undefined;
255
+ visibleTo?: {
256
+ mode: "all";
257
+ } | {
258
+ mode: "none";
259
+ } | {
260
+ mode: "allow";
261
+ identities: string[];
262
+ } | {
263
+ mode: "deny";
264
+ identities: string[];
265
+ } | undefined;
266
+ publishKinds?: ("audio" | "video" | "screen")[] | undefined;
267
+ subscribeExempt?: boolean | undefined;
268
+ maxSubscriptions?: number | undefined;
269
+ };
270
+ jti: string;
271
+ iat: number;
272
+ exp: number;
273
+ name?: string | undefined;
274
+ nbf?: number | undefined;
275
+ }>;
276
+ export type MediaJoinClaims = z.infer<typeof mediaJoinClaimsSchema>;
277
+ /**
278
+ * Server-to-server control calls (create room, end room, attach an agent).
279
+ *
280
+ * A separate audience so a join token can never be replayed as a control call.
281
+ * It carries no room, identity, kind, transport or grants: a control caller is
282
+ * not a participant, and giving it participant-shaped claims invites code that
283
+ * treats it as one.
284
+ */
285
+ export declare const mediaControlClaimsSchema: z.ZodObject<{
286
+ v: z.ZodLiteral<1>;
287
+ iss: z.ZodString;
288
+ aud: z.ZodLiteral<"control">;
289
+ jti: z.ZodString;
290
+ iat: z.ZodNumber;
291
+ nbf: z.ZodOptional<z.ZodNumber>;
292
+ exp: z.ZodNumber;
293
+ }, "strict", z.ZodTypeAny, {
294
+ v: 1;
295
+ iss: string;
296
+ aud: "control";
297
+ jti: string;
298
+ iat: number;
299
+ exp: number;
300
+ nbf?: number | undefined;
301
+ }, {
302
+ v: 1;
303
+ iss: string;
304
+ aud: "control";
305
+ jti: string;
306
+ iat: number;
307
+ exp: number;
308
+ nbf?: number | undefined;
309
+ }>;
310
+ export type MediaControlClaims = z.infer<typeof mediaControlClaimsSchema>;
311
+ /**
312
+ * Why a token was refused.
313
+ *
314
+ * Deliberately granular for the SERVER's logs and deliberately NOT returned to
315
+ * the client, which gets `unauthorized` and nothing else. Telling a caller
316
+ * whether the signature or the room was wrong is an oracle.
317
+ */
318
+ export type JoinTokenRejection = "malformed" | "unknown_kid" | "bad_signature" | "expired" | "not_yet_valid" | "ttl_too_long" | "wrong_audience" | "wrong_issuer" | "wrong_room" | "bad_claims";
319
+ export type VerifyResult<T> = {
320
+ ok: true;
321
+ claims: T;
322
+ kid: string;
323
+ } | {
324
+ ok: false;
325
+ reason: JoinTokenRejection;
326
+ };
327
+ //# sourceMappingURL=claims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;IAM9B,iFAAiF;;;IAGjF,2EAA2E;;IAE3E,6DAA6D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtD,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,aAAa,GACb,eAAe,GACf,SAAS,GACT,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC"}
@@ -0,0 +1,91 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mediaControlClaimsSchema = exports.mediaJoinClaimsSchema = exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH = void 0;
4
+ exports.clampParticipantName = clampParticipantName;
5
+ const zod_1 = require("zod");
6
+ const grants_1 = require("./grants");
7
+ /**
8
+ * The join token's claims: the whole authorization decision, made once by the
9
+ * backend and carried to a media plane that never asks it anything.
10
+ *
11
+ * Names here were contested by the parallel phase plans; each disagreement is
12
+ * resolved once, in this file, and everything else imports it.
13
+ */
14
+ /**
15
+ * The longest display name a join token may carry.
16
+ *
17
+ * Exported because it is a MINT-TIME refusal, not a preference: `signJoinToken`
18
+ * hard-parses these claims, so a caller that builds a name out of stored text
19
+ * and does not clamp it throws instead of minting. Every such caller has to
20
+ * know the bound, and a caller that hard-codes 200 is a caller that will not
21
+ * follow this number if it ever moves.
22
+ */
23
+ exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH = 200;
24
+ /**
25
+ * A display name cut to what a token may carry.
26
+ *
27
+ * Lives HERE, beside the bound it enforces, rather than in each surface that
28
+ * mints. Two reasons, and the second is the one that matters.
29
+ *
30
+ * A minting surface builds the name out of stored text (a buyer's name off a
31
+ * booking, a seat's display name off a roster) and cannot promise a length, so
32
+ * every one of them needs this. And a surface that instead compared against the
33
+ * exported NUMBER would go silently unclamped the moment it read a stale build
34
+ * of this package: `value.length > undefined` is `false`, so the clamp
35
+ * evaporates and the failure only shows up as a 500 from `signJoinToken` in
36
+ * production. A missing FUNCTION throws on the first call instead.
37
+ *
38
+ * Truncation rather than refusal is deliberate. A name is a label on a tile,
39
+ * and no call should fail to open over one.
40
+ */
41
+ function clampParticipantName(value) {
42
+ return value.length > exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH ? value.slice(0, exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH) : value;
43
+ }
44
+ /**
45
+ * `iss` IS the instance id (`legal-de`, `main`), not a service name.
46
+ *
47
+ * One plan proposed `iss: "tribenest-backend"` with the instance in a separate
48
+ * `inst` claim. That displaces the one value a verifier actually checks, and a
49
+ * legal-de token would then verify happily on the main instance - which is the
50
+ * whole reason instances are separate.
51
+ */
52
+ exports.mediaJoinClaimsSchema = zod_1.z
53
+ .object({
54
+ v: zod_1.z.literal(1),
55
+ iss: zod_1.z.string().min(1),
56
+ aud: zod_1.z.literal("media"),
57
+ room: zod_1.z.string().min(1).max(200),
58
+ /** `identity`, not `sub`: it is a first-class concept the barrier rules name. */
59
+ identity: zod_1.z.string().min(1).max(200),
60
+ name: zod_1.z.string().max(exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH).optional(),
61
+ /** Top level, NOT inside grants - it decides what may be minted at all. */
62
+ kind: grants_1.participantKindSchema,
63
+ /** Top level. Transport authority is not media authority. */
64
+ transport: grants_1.transportKindSchema,
65
+ grants: grants_1.mediaGrantsSchema,
66
+ jti: zod_1.z.string().min(8),
67
+ iat: zod_1.z.number().int().positive(),
68
+ nbf: zod_1.z.number().int().positive().optional(),
69
+ exp: zod_1.z.number().int().positive(),
70
+ })
71
+ .strict();
72
+ /**
73
+ * Server-to-server control calls (create room, end room, attach an agent).
74
+ *
75
+ * A separate audience so a join token can never be replayed as a control call.
76
+ * It carries no room, identity, kind, transport or grants: a control caller is
77
+ * not a participant, and giving it participant-shaped claims invites code that
78
+ * treats it as one.
79
+ */
80
+ exports.mediaControlClaimsSchema = zod_1.z
81
+ .object({
82
+ v: zod_1.z.literal(1),
83
+ iss: zod_1.z.string().min(1),
84
+ aud: zod_1.z.literal("control"),
85
+ jti: zod_1.z.string().min(8),
86
+ iat: zod_1.z.number().int().positive(),
87
+ nbf: zod_1.z.number().int().positive().optional(),
88
+ exp: zod_1.z.number().int().positive(),
89
+ })
90
+ .strict();
91
+ //# sourceMappingURL=claims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claims.js","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":";;;AAuCA,oDAEC;AAzCD,6BAAwB;AACxB,qCAAyF;AAEzF;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACU,QAAA,iCAAiC,GAAG,GAAG,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,oBAAoB,CAAC,KAAa;IAChD,OAAO,KAAK,CAAC,MAAM,GAAG,yCAAiC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,yCAAiC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACtH,CAAC;AAED;;;;;;;GAOG;AACU,QAAA,qBAAqB,GAAG,OAAC;KACnC,MAAM,CAAC;IACN,CAAC,EAAE,OAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACvB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,iFAAiF;IACjF,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACpC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,yCAAiC,CAAC,CAAC,QAAQ,EAAE;IAClE,2EAA2E;IAC3E,IAAI,EAAE,8BAAqB;IAC3B,6DAA6D;IAC7D,SAAS,EAAE,4BAAmB;IAC9B,MAAM,EAAE,0BAAiB;IACzB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,MAAM,EAAE,CAAC;AAIZ;;;;;;;GAOG;AACU,QAAA,wBAAwB,GAAG,OAAC;KACtC,MAAM,CAAC;IACN,CAAC,EAAE,OAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACzB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,MAAM,EAAE,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * THE codec list. Every Router in the fleet is created from this array and no
3
+ * other, and every server-side participant derives what it can receive FROM it.
4
+ *
5
+ * ## Why it is pinned rather than left to mediasoup's defaults
6
+ *
7
+ * Two Routers that disagree about codecs cannot be piped. `pipeToRouter` and
8
+ * the hand-rolled equivalent in the node's `pipe.ts` both require the receiving
9
+ * Router to be able to consume the producer, and "able" is decided by this
10
+ * list. A node booted from a different build with one extra codec still pipes
11
+ * fine until the day a client happens to negotiate that codec, and then exactly
12
+ * one leg of one room goes silent, which reads as a network fault.
13
+ *
14
+ * So the list lives in one place and every Router in the fleet is created from
15
+ * it. A change here is a fleet-wide change and a deploy that mixes versions is
16
+ * a deploy that mixes codec sets, which is why `DEPLOYMENT.md` says drain
17
+ * before upgrade rather than rolling.
18
+ *
19
+ * ## Why it lives in the PROTOCOL package
20
+ *
21
+ * The node is not the only party that has to agree. A room agent, the SIP
22
+ * gateway and the RTMP ingress are participants, not nodes: each one has to
23
+ * declare RTP capabilities on `consume`, each one runs in its own app, and none
24
+ * of them may import `apps/media-server`. Every phase that needed this list
25
+ * from outside the node had exactly one alternative, which is to write a second
26
+ * copy - and a second copy is the failure the pinning exists to prevent. The
27
+ * earlier agent plan proved it: its contract test compared two hand-written
28
+ * lists to EACH OTHER and never to this one, so both could drift together and
29
+ * stay green.
30
+ *
31
+ * Codec agreement is a wire contract between parties that cannot import each
32
+ * other, which is the same reason the frames and the claims are here.
33
+ *
34
+ * ## Zero mediasoup, deliberately
35
+ *
36
+ * The types below are declared structurally rather than imported from
37
+ * mediasoup, because this package is isomorphic and a browser must be able to
38
+ * import a frame type without pulling in a C++ addon. `apps/media-server`
39
+ * re-exports these values through explicitly mediasoup-typed bindings, so if
40
+ * the two shapes ever diverge the node fails to COMPILE rather than failing to
41
+ * pipe at three in the morning.
42
+ *
43
+ * ## What is in it, and what is deliberately not
44
+ *
45
+ * Opus for audio, because it is the only audio codec every browser publishes
46
+ * and the only one worth transcoding to for SIP and for agents.
47
+ *
48
+ * VP8 and H.264 for video. VP8 is universal and simple; H.264 is what Safari
49
+ * and every hardware encoder produce, and its absence is not a quality loss but
50
+ * a "video does not work on iPhone" bug. Both are listed with the RTCP feedback
51
+ * mediasoup needs for keyframes and bandwidth estimation: `nack`, `pli` and
52
+ * `transport-cc`. Drop `pli` and a keyframe request has no wire representation,
53
+ * so every active-speaker switch shows macroblocks until the encoder happens to
54
+ * send an IDR on its own schedule.
55
+ *
56
+ * VP9 and AV1 are deliberately absent. Both are real wins and both are a
57
+ * separate decision with a measurement behind it: SVC changes what
58
+ * `setPreferredLayers` means, and adding a codec that only some clients
59
+ * negotiate widens the "one leg is silent" surface above.
60
+ */
61
+ export type MediaKind = "audio" | "video";
62
+ export type MediaRtcpFeedback = {
63
+ type: string;
64
+ parameter?: string;
65
+ };
66
+ /** Structurally identical to mediasoup's `RouterRtpCodecCapability`. */
67
+ export type MediaCodecCapability = {
68
+ kind: MediaKind;
69
+ mimeType: string;
70
+ clockRate: number;
71
+ channels?: number;
72
+ parameters?: Record<string, unknown>;
73
+ rtcpFeedback?: MediaRtcpFeedback[];
74
+ preferredPayloadType?: number;
75
+ };
76
+ /** Structurally identical to mediasoup's `RtpCapabilities`. */
77
+ export type MediaRtpCapabilities = {
78
+ codecs: Array<MediaCodecCapability & {
79
+ preferredPayloadType: number;
80
+ }>;
81
+ /**
82
+ * Always empty, and typed as the empty tuple rather than an array of some
83
+ * element type.
84
+ *
85
+ * A server-side participant declares no header extensions: it reads the RTP
86
+ * header itself and wants nothing negotiated on top of it. Typing it this way
87
+ * also means this package never has to describe mediasoup's header-extension
88
+ * union in order for the node's mediasoup-typed re-export to stay assignable.
89
+ */
90
+ headerExtensions: [];
91
+ };
92
+ export declare const MEDIA_CODECS: MediaCodecCapability[];
93
+ /**
94
+ * The audio half, for a participant that has no video at all.
95
+ *
96
+ * DERIVED, never written beside the list above. A hand-written copy for agents
97
+ * and SIP was compared against another hand-written copy in an earlier plan and
98
+ * never against this list, which is precisely the drift the pinning exists to
99
+ * prevent: both copies agree with each other and neither agrees with the fleet.
100
+ */
101
+ export declare function audioOnlyCapabilities(codecs?: MediaCodecCapability[]): MediaRtpCapabilities;
102
+ //# sourceMappingURL=codecs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codecs.d.ts","sourceRoot":"","sources":["../src/codecs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,wEAAwE;AACxE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,KAAK,CAAC,oBAAoB,GAAG;QAAE,oBAAoB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE;;;;;;;;OAQG;IACH,gBAAgB,EAAE,EAAE,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,oBAAoB,EA8C9C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,oBAAoB,EAAiB,GAAG,oBAAoB,CAiBzG"}