@tomgiee/tsdp 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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/src/builder/media-builder.d.ts +221 -0
  4. package/dist/src/builder/media-builder.d.ts.map +1 -0
  5. package/dist/src/builder/media-builder.js +385 -0
  6. package/dist/src/builder/session-builder.d.ts +195 -0
  7. package/dist/src/builder/session-builder.d.ts.map +1 -0
  8. package/dist/src/builder/session-builder.js +366 -0
  9. package/dist/src/index.d.ts +67 -0
  10. package/dist/src/index.d.ts.map +1 -0
  11. package/dist/src/index.js +250 -0
  12. package/dist/src/parser/attribute-parser.d.ts +100 -0
  13. package/dist/src/parser/attribute-parser.d.ts.map +1 -0
  14. package/dist/src/parser/attribute-parser.js +217 -0
  15. package/dist/src/parser/field-parser.d.ts +124 -0
  16. package/dist/src/parser/field-parser.d.ts.map +1 -0
  17. package/dist/src/parser/field-parser.js +335 -0
  18. package/dist/src/parser/media-parser.d.ts +45 -0
  19. package/dist/src/parser/media-parser.d.ts.map +1 -0
  20. package/dist/src/parser/media-parser.js +157 -0
  21. package/dist/src/parser/primitive-parser.d.ts +138 -0
  22. package/dist/src/parser/primitive-parser.d.ts.map +1 -0
  23. package/dist/src/parser/primitive-parser.js +316 -0
  24. package/dist/src/parser/scanner.d.ts +142 -0
  25. package/dist/src/parser/scanner.d.ts.map +1 -0
  26. package/dist/src/parser/scanner.js +284 -0
  27. package/dist/src/parser/session-parser.d.ts +35 -0
  28. package/dist/src/parser/session-parser.d.ts.map +1 -0
  29. package/dist/src/parser/session-parser.js +207 -0
  30. package/dist/src/parser/time-parser.d.ts +74 -0
  31. package/dist/src/parser/time-parser.d.ts.map +1 -0
  32. package/dist/src/parser/time-parser.js +168 -0
  33. package/dist/src/serializer/attribute-serializer.d.ts +18 -0
  34. package/dist/src/serializer/attribute-serializer.d.ts.map +1 -0
  35. package/dist/src/serializer/attribute-serializer.js +34 -0
  36. package/dist/src/serializer/field-serializer.d.ts +112 -0
  37. package/dist/src/serializer/field-serializer.d.ts.map +1 -0
  38. package/dist/src/serializer/field-serializer.js +212 -0
  39. package/dist/src/serializer/media-serializer.d.ts +31 -0
  40. package/dist/src/serializer/media-serializer.d.ts.map +1 -0
  41. package/dist/src/serializer/media-serializer.js +83 -0
  42. package/dist/src/serializer/session-serializer.d.ts +29 -0
  43. package/dist/src/serializer/session-serializer.d.ts.map +1 -0
  44. package/dist/src/serializer/session-serializer.js +99 -0
  45. package/dist/src/serializer/time-serializer.d.ts +46 -0
  46. package/dist/src/serializer/time-serializer.d.ts.map +1 -0
  47. package/dist/src/serializer/time-serializer.js +86 -0
  48. package/dist/src/types/attributes.d.ts +318 -0
  49. package/dist/src/types/attributes.d.ts.map +1 -0
  50. package/dist/src/types/attributes.js +225 -0
  51. package/dist/src/types/errors.d.ts +129 -0
  52. package/dist/src/types/errors.d.ts.map +1 -0
  53. package/dist/src/types/errors.js +186 -0
  54. package/dist/src/types/fields.d.ts +100 -0
  55. package/dist/src/types/fields.d.ts.map +1 -0
  56. package/dist/src/types/fields.js +48 -0
  57. package/dist/src/types/media.d.ts +148 -0
  58. package/dist/src/types/media.d.ts.map +1 -0
  59. package/dist/src/types/media.js +137 -0
  60. package/dist/src/types/network.d.ts +136 -0
  61. package/dist/src/types/network.d.ts.map +1 -0
  62. package/dist/src/types/network.js +130 -0
  63. package/dist/src/types/primitives.d.ts +193 -0
  64. package/dist/src/types/primitives.d.ts.map +1 -0
  65. package/dist/src/types/primitives.js +195 -0
  66. package/dist/src/types/session.d.ts +122 -0
  67. package/dist/src/types/session.d.ts.map +1 -0
  68. package/dist/src/types/session.js +81 -0
  69. package/dist/src/types/time.d.ts +129 -0
  70. package/dist/src/types/time.d.ts.map +1 -0
  71. package/dist/src/types/time.js +84 -0
  72. package/dist/src/utils/address-parser.d.ts +100 -0
  73. package/dist/src/utils/address-parser.d.ts.map +1 -0
  74. package/dist/src/utils/address-parser.js +338 -0
  75. package/dist/src/utils/format-validators.d.ts +77 -0
  76. package/dist/src/utils/format-validators.d.ts.map +1 -0
  77. package/dist/src/utils/format-validators.js +504 -0
  78. package/dist/src/utils/line-reader.d.ts +84 -0
  79. package/dist/src/utils/line-reader.d.ts.map +1 -0
  80. package/dist/src/utils/line-reader.js +169 -0
  81. package/dist/src/utils/time-converter.d.ts +99 -0
  82. package/dist/src/utils/time-converter.d.ts.map +1 -0
  83. package/dist/src/utils/time-converter.js +195 -0
  84. package/dist/src/validator/media-validator.d.ts +27 -0
  85. package/dist/src/validator/media-validator.d.ts.map +1 -0
  86. package/dist/src/validator/media-validator.js +241 -0
  87. package/dist/src/validator/semantic-validator.d.ts +47 -0
  88. package/dist/src/validator/semantic-validator.d.ts.map +1 -0
  89. package/dist/src/validator/semantic-validator.js +207 -0
  90. package/dist/src/validator/session-validator.d.ts +36 -0
  91. package/dist/src/validator/session-validator.d.ts.map +1 -0
  92. package/dist/src/validator/session-validator.js +280 -0
  93. package/dist/tests/integration/round-trip.test.d.ts +5 -0
  94. package/dist/tests/integration/round-trip.test.d.ts.map +1 -0
  95. package/dist/tests/integration/round-trip.test.js +320 -0
  96. package/dist/tests/integration/voip-examples.test.d.ts +5 -0
  97. package/dist/tests/integration/voip-examples.test.d.ts.map +1 -0
  98. package/dist/tests/integration/voip-examples.test.js +361 -0
  99. package/dist/tests/unit/builder/media-builder.test.d.ts +5 -0
  100. package/dist/tests/unit/builder/media-builder.test.d.ts.map +1 -0
  101. package/dist/tests/unit/builder/media-builder.test.js +524 -0
  102. package/dist/tests/unit/builder/session-builder.test.d.ts +5 -0
  103. package/dist/tests/unit/builder/session-builder.test.d.ts.map +1 -0
  104. package/dist/tests/unit/builder/session-builder.test.js +367 -0
  105. package/dist/tests/unit/parser/attribute-parser.test.d.ts +5 -0
  106. package/dist/tests/unit/parser/attribute-parser.test.d.ts.map +1 -0
  107. package/dist/tests/unit/parser/attribute-parser.test.js +319 -0
  108. package/dist/tests/unit/parser/field-parser.test.d.ts +5 -0
  109. package/dist/tests/unit/parser/field-parser.test.d.ts.map +1 -0
  110. package/dist/tests/unit/parser/field-parser.test.js +355 -0
  111. package/dist/tests/unit/parser/media-parser.test.d.ts +5 -0
  112. package/dist/tests/unit/parser/media-parser.test.d.ts.map +1 -0
  113. package/dist/tests/unit/parser/media-parser.test.js +241 -0
  114. package/dist/tests/unit/parser/primitive-parser.test.d.ts +5 -0
  115. package/dist/tests/unit/parser/primitive-parser.test.d.ts.map +1 -0
  116. package/dist/tests/unit/parser/primitive-parser.test.js +261 -0
  117. package/dist/tests/unit/parser/scanner.test.d.ts +5 -0
  118. package/dist/tests/unit/parser/scanner.test.d.ts.map +1 -0
  119. package/dist/tests/unit/parser/scanner.test.js +241 -0
  120. package/dist/tests/unit/parser/session-parser.test.d.ts +5 -0
  121. package/dist/tests/unit/parser/session-parser.test.d.ts.map +1 -0
  122. package/dist/tests/unit/parser/session-parser.test.js +346 -0
  123. package/dist/tests/unit/parser/time-parser.test.d.ts +5 -0
  124. package/dist/tests/unit/parser/time-parser.test.d.ts.map +1 -0
  125. package/dist/tests/unit/parser/time-parser.test.js +173 -0
  126. package/dist/tests/unit/serializer/attribute-serializer.test.d.ts +5 -0
  127. package/dist/tests/unit/serializer/attribute-serializer.test.d.ts.map +1 -0
  128. package/dist/tests/unit/serializer/attribute-serializer.test.js +78 -0
  129. package/dist/tests/unit/serializer/field-serializer.test.d.ts +5 -0
  130. package/dist/tests/unit/serializer/field-serializer.test.d.ts.map +1 -0
  131. package/dist/tests/unit/serializer/field-serializer.test.js +159 -0
  132. package/dist/tests/unit/serializer/media-serializer.test.d.ts +5 -0
  133. package/dist/tests/unit/serializer/media-serializer.test.d.ts.map +1 -0
  134. package/dist/tests/unit/serializer/media-serializer.test.js +155 -0
  135. package/dist/tests/unit/serializer/session-serializer.test.d.ts +5 -0
  136. package/dist/tests/unit/serializer/session-serializer.test.d.ts.map +1 -0
  137. package/dist/tests/unit/serializer/session-serializer.test.js +317 -0
  138. package/dist/tests/unit/serializer/time-serializer.test.d.ts +5 -0
  139. package/dist/tests/unit/serializer/time-serializer.test.d.ts.map +1 -0
  140. package/dist/tests/unit/serializer/time-serializer.test.js +115 -0
  141. package/dist/tests/unit/types/errors.test.d.ts +5 -0
  142. package/dist/tests/unit/types/errors.test.d.ts.map +1 -0
  143. package/dist/tests/unit/types/errors.test.js +127 -0
  144. package/dist/tests/unit/types/network.test.d.ts +5 -0
  145. package/dist/tests/unit/types/network.test.d.ts.map +1 -0
  146. package/dist/tests/unit/types/network.test.js +132 -0
  147. package/dist/tests/unit/types/primitives.test.d.ts +5 -0
  148. package/dist/tests/unit/types/primitives.test.d.ts.map +1 -0
  149. package/dist/tests/unit/types/primitives.test.js +108 -0
  150. package/dist/tests/unit/utils/address-parser.test.d.ts +5 -0
  151. package/dist/tests/unit/utils/address-parser.test.d.ts.map +1 -0
  152. package/dist/tests/unit/utils/address-parser.test.js +203 -0
  153. package/dist/tests/unit/utils/format-validators.test.d.ts +5 -0
  154. package/dist/tests/unit/utils/format-validators.test.d.ts.map +1 -0
  155. package/dist/tests/unit/utils/format-validators.test.js +224 -0
  156. package/dist/tests/unit/utils/line-reader.test.d.ts +5 -0
  157. package/dist/tests/unit/utils/line-reader.test.d.ts.map +1 -0
  158. package/dist/tests/unit/utils/line-reader.test.js +157 -0
  159. package/dist/tests/unit/utils/time-converter.test.d.ts +5 -0
  160. package/dist/tests/unit/utils/time-converter.test.d.ts.map +1 -0
  161. package/dist/tests/unit/utils/time-converter.test.js +190 -0
  162. package/dist/tests/unit/validator/media-validator.test.d.ts +5 -0
  163. package/dist/tests/unit/validator/media-validator.test.d.ts.map +1 -0
  164. package/dist/tests/unit/validator/media-validator.test.js +313 -0
  165. package/dist/tests/unit/validator/semantic-validator.test.d.ts +5 -0
  166. package/dist/tests/unit/validator/semantic-validator.test.d.ts.map +1 -0
  167. package/dist/tests/unit/validator/semantic-validator.test.js +262 -0
  168. package/dist/tests/unit/validator/session-validator.test.d.ts +5 -0
  169. package/dist/tests/unit/validator/session-validator.test.d.ts.map +1 -0
  170. package/dist/tests/unit/validator/session-validator.test.js +447 -0
  171. package/package.json +50 -0
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * Line reading utilities for SDP (RFC 8866)
4
+ *
5
+ * RFC 8866 specifies CRLF as the standard line terminator, but parsers
6
+ * SHOULD accept LF alone for robustness. This module handles all three
7
+ * cases: CRLF, LF, and CR.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.splitLines = splitLines;
11
+ exports.parseLine = parseLine;
12
+ exports.parseLines = parseLines;
13
+ exports.joinLines = joinLines;
14
+ exports.formatLine = formatLine;
15
+ exports.isValidLineType = isValidLineType;
16
+ exports.getLineTypeName = getLineTypeName;
17
+ /**
18
+ * Split input text into lines, handling CRLF, LF, and CR
19
+ *
20
+ * RFC 8866 Section 5: Text fields use UTF-8 encoding, line ending is CRLF,
21
+ * but parsers SHOULD accept LF alone for compatibility.
22
+ *
23
+ * @param input - Raw SDP text
24
+ * @returns Array of lines (line endings removed)
25
+ */
26
+ function splitLines(input) {
27
+ const lines = [];
28
+ let current = '';
29
+ for (let i = 0; i < input.length; i++) {
30
+ const ch = input[i];
31
+ if (ch === '\r' && input[i + 1] === '\n') {
32
+ // CRLF (standard)
33
+ lines.push(current);
34
+ current = '';
35
+ i++; // Skip the \n
36
+ }
37
+ else if (ch === '\n') {
38
+ // LF alone (tolerant)
39
+ lines.push(current);
40
+ current = '';
41
+ }
42
+ else if (ch === '\r') {
43
+ // CR alone (tolerant, rare)
44
+ lines.push(current);
45
+ current = '';
46
+ }
47
+ else {
48
+ current += ch;
49
+ }
50
+ }
51
+ // Add final line if input doesn't end with line terminator
52
+ if (current.length > 0) {
53
+ lines.push(current);
54
+ }
55
+ return lines;
56
+ }
57
+ /**
58
+ * Parse a single SDP line into type and value
59
+ *
60
+ * SDP line format: <type>=<value>
61
+ * where <type> is a single character
62
+ *
63
+ * @param line - Single SDP line
64
+ * @returns Parsed line with type and value, or null if invalid
65
+ */
66
+ function parseLine(line) {
67
+ // Empty lines are ignored
68
+ if (line.length === 0) {
69
+ return null;
70
+ }
71
+ // Valid SDP lines must have at least "x=" (3 characters minimum)
72
+ if (line.length < 2) {
73
+ return null;
74
+ }
75
+ // Second character must be '='
76
+ if (line[1] !== '=') {
77
+ return null;
78
+ }
79
+ return {
80
+ type: line[0],
81
+ value: line.substring(2)
82
+ };
83
+ }
84
+ /**
85
+ * Parse all lines in SDP input into structured format
86
+ *
87
+ * @param input - Raw SDP text
88
+ * @returns Array of parsed lines (skips empty/invalid lines)
89
+ */
90
+ function parseLines(input) {
91
+ const rawLines = splitLines(input);
92
+ const parsedLines = [];
93
+ for (let i = 0; i < rawLines.length; i++) {
94
+ const parsed = parseLine(rawLines[i]);
95
+ if (parsed !== null) {
96
+ parsedLines.push({
97
+ type: parsed.type,
98
+ value: parsed.value,
99
+ lineNumber: i + 1
100
+ });
101
+ }
102
+ }
103
+ return parsedLines;
104
+ }
105
+ /**
106
+ * Join lines back into SDP text format with CRLF line endings
107
+ *
108
+ * Always outputs standard CRLF line endings per RFC 8866,
109
+ * even if input used LF or CR.
110
+ *
111
+ * @param lines - Array of line strings (without line endings)
112
+ * @returns SDP text with CRLF line endings
113
+ */
114
+ function joinLines(lines) {
115
+ return lines.join('\r\n') + '\r\n';
116
+ }
117
+ /**
118
+ * Format a line in SDP format: <type>=<value>
119
+ *
120
+ * @param type - Single character line type
121
+ * @param value - Line value
122
+ * @returns Formatted SDP line (without line ending)
123
+ */
124
+ function formatLine(type, value) {
125
+ if (type.length !== 1) {
126
+ throw new Error(`Invalid line type '${type}': must be single character`);
127
+ }
128
+ return `${type}=${value}`;
129
+ }
130
+ /**
131
+ * Validate that a line type is a valid SDP field
132
+ *
133
+ * Valid SDP field types per RFC 8866:
134
+ * v, o, s, i, u, e, p, c, b, t, r, z, k, a, m
135
+ *
136
+ * @param type - Line type character
137
+ * @returns true if valid SDP field type
138
+ */
139
+ function isValidLineType(type) {
140
+ const validTypes = ['v', 'o', 's', 'i', 'u', 'e', 'p', 'c', 'b', 't', 'r', 'z', 'k', 'a', 'm'];
141
+ return validTypes.includes(type);
142
+ }
143
+ /**
144
+ * Get display name for a line type
145
+ *
146
+ * @param type - Line type character
147
+ * @returns Human-readable field name
148
+ */
149
+ function getLineTypeName(type) {
150
+ var _a;
151
+ const names = {
152
+ 'v': 'version',
153
+ 'o': 'origin',
154
+ 's': 'session name',
155
+ 'i': 'information',
156
+ 'u': 'URI',
157
+ 'e': 'email',
158
+ 'p': 'phone',
159
+ 'c': 'connection',
160
+ 'b': 'bandwidth',
161
+ 't': 'timing',
162
+ 'r': 'repeat',
163
+ 'z': 'timezone',
164
+ 'k': 'key',
165
+ 'a': 'attribute',
166
+ 'm': 'media'
167
+ };
168
+ return (_a = names[type]) !== null && _a !== void 0 ? _a : 'unknown';
169
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Time conversion utilities for SDP (RFC 8866)
3
+ *
4
+ * SDP uses typed time values with unit suffixes for repeat and timezone fields:
5
+ * - d: days
6
+ * - h: hours
7
+ * - m: minutes
8
+ * - (no suffix): seconds
9
+ */
10
+ import { TypedTime } from '../types/primitives';
11
+ /**
12
+ * Parse a typed time string into a TypedTime object
13
+ *
14
+ * Formats:
15
+ * - "7d" = 7 days
16
+ * - "3h" = 3 hours
17
+ * - "120m" = 120 minutes
18
+ * - "3600" = 3600 seconds (no suffix)
19
+ * - "30s" = 30 seconds (explicit suffix)
20
+ * - "-1h" = -1 hour (for timezone offsets)
21
+ *
22
+ * @param input - Time string to parse
23
+ * @returns TypedTime object
24
+ * @throws ParseError if input is invalid
25
+ */
26
+ export declare function parseTypedTime(input: string): TypedTime;
27
+ /**
28
+ * Serialize a TypedTime object to a string
29
+ *
30
+ * Outputs compact format per RFC 8866:
31
+ * - days: "7d"
32
+ * - hours: "3h"
33
+ * - minutes: "120m"
34
+ * - seconds: "3600" (no suffix for seconds)
35
+ *
36
+ * @param time - TypedTime to serialize
37
+ * @returns Formatted time string
38
+ */
39
+ export declare function serializeTypedTime(time: TypedTime): string;
40
+ /**
41
+ * Convert TypedTime to seconds
42
+ *
43
+ * Useful for comparisons and calculations
44
+ *
45
+ * @param time - TypedTime to convert
46
+ * @returns Number of seconds
47
+ */
48
+ export declare function typedTimeToSeconds(time: TypedTime): number;
49
+ /**
50
+ * Convert seconds to TypedTime with appropriate unit
51
+ *
52
+ * Chooses the largest unit that divides evenly:
53
+ * - 86400 seconds -> 1 day
54
+ * - 3600 seconds -> 1 hour
55
+ * - 120 seconds -> 2 minutes
56
+ * - 45 seconds -> 45 seconds
57
+ *
58
+ * @param seconds - Number of seconds
59
+ * @returns TypedTime with appropriate unit
60
+ */
61
+ export declare function secondsToTypedTime(seconds: number): TypedTime;
62
+ /**
63
+ * Add two TypedTime values
64
+ *
65
+ * Result uses the smaller unit to avoid precision loss
66
+ *
67
+ * @param a - First time value
68
+ * @param b - Second time value
69
+ * @returns Sum of the two times
70
+ */
71
+ export declare function addTypedTimes(a: TypedTime, b: TypedTime): TypedTime;
72
+ /**
73
+ * Compare two TypedTime values
74
+ *
75
+ * @param a - First time value
76
+ * @param b - Second time value
77
+ * @returns Negative if a < b, 0 if equal, positive if a > b
78
+ */
79
+ export declare function compareTypedTimes(a: TypedTime, b: TypedTime): number;
80
+ /**
81
+ * Check if two TypedTime values are equal
82
+ *
83
+ * @param a - First time value
84
+ * @param b - Second time value
85
+ * @returns true if equal (same duration in seconds)
86
+ */
87
+ export declare function typedTimesEqual(a: TypedTime, b: TypedTime): boolean;
88
+ /**
89
+ * Normalize a TypedTime to use the most compact unit
90
+ *
91
+ * Examples:
92
+ * - {value: 120, unit: 'minutes'} -> {value: 2, unit: 'hours'}
93
+ * - {value: 3600, unit: 'seconds'} -> {value: 1, unit: 'hours'}
94
+ *
95
+ * @param time - TypedTime to normalize
96
+ * @returns Normalized TypedTime
97
+ */
98
+ export declare function normalizeTypedTime(time: TypedTime): TypedTime;
99
+ //# sourceMappingURL=time-converter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time-converter.d.ts","sourceRoot":"","sources":["../../../src/utils/time-converter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAA6B,MAAM,qBAAqB,CAAC;AAG3E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAqCvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAiB1D;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAc1D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAmB7D;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAMnE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAEnE;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,CAG7D"}
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ /**
3
+ * Time conversion utilities for SDP (RFC 8866)
4
+ *
5
+ * SDP uses typed time values with unit suffixes for repeat and timezone fields:
6
+ * - d: days
7
+ * - h: hours
8
+ * - m: minutes
9
+ * - (no suffix): seconds
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.parseTypedTime = parseTypedTime;
13
+ exports.serializeTypedTime = serializeTypedTime;
14
+ exports.typedTimeToSeconds = typedTimeToSeconds;
15
+ exports.secondsToTypedTime = secondsToTypedTime;
16
+ exports.addTypedTimes = addTypedTimes;
17
+ exports.compareTypedTimes = compareTypedTimes;
18
+ exports.typedTimesEqual = typedTimesEqual;
19
+ exports.normalizeTypedTime = normalizeTypedTime;
20
+ const primitives_1 = require("../types/primitives");
21
+ const errors_1 = require("../types/errors");
22
+ /**
23
+ * Parse a typed time string into a TypedTime object
24
+ *
25
+ * Formats:
26
+ * - "7d" = 7 days
27
+ * - "3h" = 3 hours
28
+ * - "120m" = 120 minutes
29
+ * - "3600" = 3600 seconds (no suffix)
30
+ * - "30s" = 30 seconds (explicit suffix)
31
+ * - "-1h" = -1 hour (for timezone offsets)
32
+ *
33
+ * @param input - Time string to parse
34
+ * @returns TypedTime object
35
+ * @throws ParseError if input is invalid
36
+ */
37
+ function parseTypedTime(input) {
38
+ if (input.length === 0) {
39
+ throw new errors_1.ParseError('Empty time value', 0, 0);
40
+ }
41
+ // Match pattern: optional minus sign, digits, optional unit suffix
42
+ const match = input.match(/^(-?\d+)([dhms]?)$/);
43
+ if (!match) {
44
+ throw new errors_1.ParseError(`Invalid time format: '${input}'`, 0, 0);
45
+ }
46
+ const value = parseInt(match[1], 10);
47
+ const suffix = match[2] || 's'; // Default to seconds if no suffix
48
+ if (isNaN(value)) {
49
+ throw new errors_1.ParseError(`Invalid time value: '${value}'`, 0, 0);
50
+ }
51
+ // Map suffix to unit
52
+ const unit = (() => {
53
+ switch (suffix) {
54
+ case 'd':
55
+ return 'days';
56
+ case 'h':
57
+ return 'hours';
58
+ case 'm':
59
+ return 'minutes';
60
+ case 's':
61
+ case '':
62
+ return 'seconds';
63
+ default:
64
+ throw new errors_1.ParseError(`Invalid time unit: '${suffix}'`, 0, 0);
65
+ }
66
+ })();
67
+ return (0, primitives_1.createTypedTime)(value, unit);
68
+ }
69
+ /**
70
+ * Serialize a TypedTime object to a string
71
+ *
72
+ * Outputs compact format per RFC 8866:
73
+ * - days: "7d"
74
+ * - hours: "3h"
75
+ * - minutes: "120m"
76
+ * - seconds: "3600" (no suffix for seconds)
77
+ *
78
+ * @param time - TypedTime to serialize
79
+ * @returns Formatted time string
80
+ */
81
+ function serializeTypedTime(time) {
82
+ const suffix = (() => {
83
+ switch (time.unit) {
84
+ case 'days':
85
+ return 'd';
86
+ case 'hours':
87
+ return 'h';
88
+ case 'minutes':
89
+ return 'm';
90
+ case 'seconds':
91
+ return ''; // No suffix for seconds
92
+ default:
93
+ throw new Error(`Invalid time unit: ${time.unit}`);
94
+ }
95
+ })();
96
+ return `${time.value}${suffix}`;
97
+ }
98
+ /**
99
+ * Convert TypedTime to seconds
100
+ *
101
+ * Useful for comparisons and calculations
102
+ *
103
+ * @param time - TypedTime to convert
104
+ * @returns Number of seconds
105
+ */
106
+ function typedTimeToSeconds(time) {
107
+ const multipliers = {
108
+ 'seconds': 1,
109
+ 'minutes': 60,
110
+ 'hours': 3600,
111
+ 'days': 86400
112
+ };
113
+ const multiplier = multipliers[time.unit];
114
+ if (multiplier === undefined) {
115
+ throw new Error(`Invalid time unit: ${time.unit}`);
116
+ }
117
+ return time.value * multiplier;
118
+ }
119
+ /**
120
+ * Convert seconds to TypedTime with appropriate unit
121
+ *
122
+ * Chooses the largest unit that divides evenly:
123
+ * - 86400 seconds -> 1 day
124
+ * - 3600 seconds -> 1 hour
125
+ * - 120 seconds -> 2 minutes
126
+ * - 45 seconds -> 45 seconds
127
+ *
128
+ * @param seconds - Number of seconds
129
+ * @returns TypedTime with appropriate unit
130
+ */
131
+ function secondsToTypedTime(seconds) {
132
+ if (seconds < 0) {
133
+ throw new Error('Time cannot be negative');
134
+ }
135
+ // Try each unit from largest to smallest
136
+ if (seconds % 86400 === 0) {
137
+ return (0, primitives_1.createTypedTime)(seconds / 86400, 'days');
138
+ }
139
+ if (seconds % 3600 === 0) {
140
+ return (0, primitives_1.createTypedTime)(seconds / 3600, 'hours');
141
+ }
142
+ if (seconds % 60 === 0) {
143
+ return (0, primitives_1.createTypedTime)(seconds / 60, 'minutes');
144
+ }
145
+ return (0, primitives_1.createTypedTime)(seconds, 'seconds');
146
+ }
147
+ /**
148
+ * Add two TypedTime values
149
+ *
150
+ * Result uses the smaller unit to avoid precision loss
151
+ *
152
+ * @param a - First time value
153
+ * @param b - Second time value
154
+ * @returns Sum of the two times
155
+ */
156
+ function addTypedTimes(a, b) {
157
+ const aSeconds = typedTimeToSeconds(a);
158
+ const bSeconds = typedTimeToSeconds(b);
159
+ const totalSeconds = aSeconds + bSeconds;
160
+ return secondsToTypedTime(totalSeconds);
161
+ }
162
+ /**
163
+ * Compare two TypedTime values
164
+ *
165
+ * @param a - First time value
166
+ * @param b - Second time value
167
+ * @returns Negative if a < b, 0 if equal, positive if a > b
168
+ */
169
+ function compareTypedTimes(a, b) {
170
+ return typedTimeToSeconds(a) - typedTimeToSeconds(b);
171
+ }
172
+ /**
173
+ * Check if two TypedTime values are equal
174
+ *
175
+ * @param a - First time value
176
+ * @param b - Second time value
177
+ * @returns true if equal (same duration in seconds)
178
+ */
179
+ function typedTimesEqual(a, b) {
180
+ return typedTimeToSeconds(a) === typedTimeToSeconds(b);
181
+ }
182
+ /**
183
+ * Normalize a TypedTime to use the most compact unit
184
+ *
185
+ * Examples:
186
+ * - {value: 120, unit: 'minutes'} -> {value: 2, unit: 'hours'}
187
+ * - {value: 3600, unit: 'seconds'} -> {value: 1, unit: 'hours'}
188
+ *
189
+ * @param time - TypedTime to normalize
190
+ * @returns Normalized TypedTime
191
+ */
192
+ function normalizeTypedTime(time) {
193
+ const seconds = typedTimeToSeconds(time);
194
+ return secondsToTypedTime(seconds);
195
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Media validators for SDP (RFC 8866)
3
+ *
4
+ * Validates media descriptions and media-level constraints per RFC 8866.
5
+ */
6
+ import { MediaDescription } from '../types/media';
7
+ import { ValidationResult } from './session-validator';
8
+ /**
9
+ * Validate a media description
10
+ *
11
+ * Checks RFC 8866 Section 5.14 (m=) and media-level field requirements.
12
+ *
13
+ * @param media - Media description to validate
14
+ * @param index - Index of media description (for error messages)
15
+ * @param hasSessionConnection - Whether session-level connection exists
16
+ * @returns ValidationResult with any errors found
17
+ */
18
+ export declare function validateMediaDescription(media: MediaDescription, index: number, hasSessionConnection: boolean): ValidationResult;
19
+ /**
20
+ * Validate all media descriptions in a session
21
+ *
22
+ * @param mediaDescriptions - Array of media descriptions
23
+ * @param hasSessionConnection - Whether session-level connection exists
24
+ * @returns ValidationResult with any errors found
25
+ */
26
+ export declare function validateAllMediaDescriptions(mediaDescriptions: readonly MediaDescription[], hasSessionConnection: boolean): ValidationResult;
27
+ //# sourceMappingURL=media-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media-validator.d.ts","sourceRoot":"","sources":["../../../src/validator/media-validator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAA8B,MAAM,qBAAqB,CAAC;AAOnF;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,gBAAgB,EACvB,KAAK,EAAE,MAAM,EACb,oBAAoB,EAAE,OAAO,GAC5B,gBAAgB,CAyBlB;AAuVD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,iBAAiB,EAAE,SAAS,gBAAgB,EAAE,EAC9C,oBAAoB,EAAE,OAAO,GAC5B,gBAAgB,CASlB"}