klv-ts 0.1.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/LICENSE +1 -0
- package/README.md +30 -0
- package/dist/index.cjs +103 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +37 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# klv-ts
|
|
2
|
+
|
|
3
|
+
A modern TypeScript parser for SMPTE 336M KLV packets.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Generic SMPTE 336M parser
|
|
8
|
+
- Browser support
|
|
9
|
+
- Node.js support
|
|
10
|
+
- Zero dependencies
|
|
11
|
+
- Tree-shakeable
|
|
12
|
+
- TypeScript first
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install klv-ts
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { KlvParser } from "klv-ts";
|
|
24
|
+
|
|
25
|
+
const parser = new KlvParser();
|
|
26
|
+
|
|
27
|
+
const packet = parser.parse(bytes);
|
|
28
|
+
|
|
29
|
+
console.log(packet.length);
|
|
30
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/parser/ByteReader.ts
|
|
4
|
+
var ByteReader = class {
|
|
5
|
+
data;
|
|
6
|
+
offset = 0;
|
|
7
|
+
constructor(data) {
|
|
8
|
+
this.data = data;
|
|
9
|
+
}
|
|
10
|
+
get position() {
|
|
11
|
+
return this.offset;
|
|
12
|
+
}
|
|
13
|
+
get remaining() {
|
|
14
|
+
return this.data.length - this.offset;
|
|
15
|
+
}
|
|
16
|
+
hasRemaining(length = 1) {
|
|
17
|
+
return this.remaining >= length;
|
|
18
|
+
}
|
|
19
|
+
readByte() {
|
|
20
|
+
if (!this.hasRemaining()) {
|
|
21
|
+
throw new Error("Unexpected end of buffer.");
|
|
22
|
+
}
|
|
23
|
+
return this.data[this.offset++];
|
|
24
|
+
}
|
|
25
|
+
readBytes(length) {
|
|
26
|
+
if (!this.hasRemaining(length)) {
|
|
27
|
+
throw new Error("Unexpected end of buffer.");
|
|
28
|
+
}
|
|
29
|
+
const bytes = this.data.slice(this.offset, this.offset + length);
|
|
30
|
+
this.offset += length;
|
|
31
|
+
return bytes;
|
|
32
|
+
}
|
|
33
|
+
skip(length) {
|
|
34
|
+
if (!this.hasRemaining(length)) {
|
|
35
|
+
throw new Error("Unexpected end of buffer.");
|
|
36
|
+
}
|
|
37
|
+
this.offset += length;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/parser/BerReader.ts
|
|
42
|
+
var BerReader = class {
|
|
43
|
+
static readLength(reader) {
|
|
44
|
+
const first = reader.readByte();
|
|
45
|
+
if ((first & 128) === 0) {
|
|
46
|
+
return first;
|
|
47
|
+
}
|
|
48
|
+
const octets = first & 127;
|
|
49
|
+
if (octets === 0) {
|
|
50
|
+
throw new Error("Indefinite BER lengths are not supported.");
|
|
51
|
+
}
|
|
52
|
+
let length = 0;
|
|
53
|
+
for (let i = 0; i < octets; i++) {
|
|
54
|
+
length = length << 8 | reader.readByte();
|
|
55
|
+
}
|
|
56
|
+
return length;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// src/parser/UniversalKey.ts
|
|
61
|
+
var UniversalKey = class _UniversalKey {
|
|
62
|
+
constructor(bytes) {
|
|
63
|
+
this.bytes = bytes;
|
|
64
|
+
if (bytes.length !== _UniversalKey.LENGTH) {
|
|
65
|
+
throw new Error("Universal Key must contain 16 bytes.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
bytes;
|
|
69
|
+
static LENGTH = 16;
|
|
70
|
+
isSmpte() {
|
|
71
|
+
return this.bytes[0] === 6 && this.bytes[1] === 14 && this.bytes[2] === 43 && this.bytes[3] === 52;
|
|
72
|
+
}
|
|
73
|
+
equals(other) {
|
|
74
|
+
return this.bytes.every((v, i) => v === other.bytes[i]);
|
|
75
|
+
}
|
|
76
|
+
toHex(separator = "") {
|
|
77
|
+
return Array.from(this.bytes).map((b) => b.toString(16).padStart(2, "0")).join(separator);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/parser/KlvParser.ts
|
|
82
|
+
var KlvParser = class {
|
|
83
|
+
parse(data) {
|
|
84
|
+
const reader = new ByteReader(data);
|
|
85
|
+
const keyBytes = reader.readBytes(UniversalKey.LENGTH);
|
|
86
|
+
const key = new UniversalKey(keyBytes);
|
|
87
|
+
const length = BerReader.readLength(reader);
|
|
88
|
+
const value = reader.readBytes(length);
|
|
89
|
+
return {
|
|
90
|
+
key,
|
|
91
|
+
length,
|
|
92
|
+
value,
|
|
93
|
+
raw: data
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
exports.BerReader = BerReader;
|
|
99
|
+
exports.ByteReader = ByteReader;
|
|
100
|
+
exports.KlvParser = KlvParser;
|
|
101
|
+
exports.UniversalKey = UniversalKey;
|
|
102
|
+
//# sourceMappingURL=index.cjs.map
|
|
103
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parser/ByteReader.ts","../src/parser/BerReader.ts","../src/parser/UniversalKey.ts","../src/parser/KlvParser.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["export class ByteReader {\r\n\r\n private readonly data: Uint8Array;\r\n private offset = 0;\r\n\r\n constructor(data: Uint8Array) {\r\n this.data = data;\r\n }\r\n\r\n get position(): number {\r\n return this.offset;\r\n }\r\n\r\n get remaining(): number {\r\n return this.data.length - this.offset;\r\n }\r\n\r\n hasRemaining(length = 1): boolean {\r\n return this.remaining >= length;\r\n }\r\n\r\n readByte(): number {\r\n if (!this.hasRemaining()) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n return this.data[this.offset++];\r\n }\r\n\r\n readBytes(length: number): Uint8Array {\r\n if (!this.hasRemaining(length)) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n const bytes = this.data.slice(this.offset, this.offset + length);\r\n this.offset += length;\r\n\r\n return bytes;\r\n }\r\n\r\n skip(length: number): void {\r\n if (!this.hasRemaining(length)) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n this.offset += length;\r\n }\r\n}","import { ByteReader } from \"./ByteReader\";\r\n\r\nexport class BerReader {\r\n\r\n static readLength(reader: ByteReader): number {\r\n\r\n const first = reader.readByte();\r\n\r\n // Short form\r\n if ((first & 0x80) === 0) {\r\n return first;\r\n }\r\n\r\n const octets = first & 0x7F;\r\n\r\n if (octets === 0) {\r\n throw new Error(\"Indefinite BER lengths are not supported.\");\r\n }\r\n\r\n let length = 0;\r\n\r\n for (let i = 0; i < octets; i++) {\r\n length = (length << 8) | reader.readByte();\r\n }\r\n\r\n return length;\r\n }\r\n\r\n}","export class UniversalKey {\r\n\r\n static readonly LENGTH = 16;\r\n\r\n constructor(\r\n public readonly bytes: Uint8Array\r\n ) {\r\n\r\n if (bytes.length !== UniversalKey.LENGTH) {\r\n throw new Error(\"Universal Key must contain 16 bytes.\");\r\n }\r\n\r\n }\r\n\r\n isSmpte(): boolean {\r\n\r\n return (\r\n this.bytes[0] === 0x06 &&\r\n this.bytes[1] === 0x0E &&\r\n this.bytes[2] === 0x2B &&\r\n this.bytes[3] === 0x34\r\n );\r\n\r\n }\r\n\r\n equals(other: UniversalKey): boolean {\r\n\r\n return this.bytes.every((v, i) => v === other.bytes[i]);\r\n\r\n }\r\n\r\n toHex(separator = \"\"): string {\r\n\r\n return Array.from(this.bytes)\r\n .map(b => b.toString(16).padStart(2, \"0\"))\r\n .join(separator);\r\n\r\n }\r\n\r\n}","import { KlvPacket } from \"../packet/KlvPacket\";\r\nimport { BerReader } from \"./BerReader\";\r\nimport { ByteReader } from \"./ByteReader\";\r\nimport { UniversalKey } from \"./UniversalKey\";\r\n\r\nexport class KlvParser {\r\n\r\n parse(data: Uint8Array): KlvPacket {\r\n\r\n const reader = new ByteReader(data);\r\n\r\n const keyBytes = reader.readBytes(UniversalKey.LENGTH);\r\n\r\n const key = new UniversalKey(keyBytes);\r\n\r\n const length = BerReader.readLength(reader);\r\n\r\n const value = reader.readBytes(length);\r\n\r\n return {\r\n\r\n key,\r\n\r\n length,\r\n\r\n value,\r\n\r\n raw: data\r\n\r\n };\r\n\r\n }\r\n\r\n}"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
declare class UniversalKey {
|
|
2
|
+
readonly bytes: Uint8Array;
|
|
3
|
+
static readonly LENGTH = 16;
|
|
4
|
+
constructor(bytes: Uint8Array);
|
|
5
|
+
isSmpte(): boolean;
|
|
6
|
+
equals(other: UniversalKey): boolean;
|
|
7
|
+
toHex(separator?: string): string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface KlvPacket {
|
|
11
|
+
key: UniversalKey;
|
|
12
|
+
length: number;
|
|
13
|
+
value: Uint8Array;
|
|
14
|
+
raw: Uint8Array;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare class ByteReader {
|
|
18
|
+
private readonly data;
|
|
19
|
+
private offset;
|
|
20
|
+
constructor(data: Uint8Array);
|
|
21
|
+
get position(): number;
|
|
22
|
+
get remaining(): number;
|
|
23
|
+
hasRemaining(length?: number): boolean;
|
|
24
|
+
readByte(): number;
|
|
25
|
+
readBytes(length: number): Uint8Array;
|
|
26
|
+
skip(length: number): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class BerReader {
|
|
30
|
+
static readLength(reader: ByteReader): number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class KlvParser {
|
|
34
|
+
parse(data: Uint8Array): KlvPacket;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { BerReader, ByteReader, type KlvPacket, KlvParser, UniversalKey };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
declare class UniversalKey {
|
|
2
|
+
readonly bytes: Uint8Array;
|
|
3
|
+
static readonly LENGTH = 16;
|
|
4
|
+
constructor(bytes: Uint8Array);
|
|
5
|
+
isSmpte(): boolean;
|
|
6
|
+
equals(other: UniversalKey): boolean;
|
|
7
|
+
toHex(separator?: string): string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface KlvPacket {
|
|
11
|
+
key: UniversalKey;
|
|
12
|
+
length: number;
|
|
13
|
+
value: Uint8Array;
|
|
14
|
+
raw: Uint8Array;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
declare class ByteReader {
|
|
18
|
+
private readonly data;
|
|
19
|
+
private offset;
|
|
20
|
+
constructor(data: Uint8Array);
|
|
21
|
+
get position(): number;
|
|
22
|
+
get remaining(): number;
|
|
23
|
+
hasRemaining(length?: number): boolean;
|
|
24
|
+
readByte(): number;
|
|
25
|
+
readBytes(length: number): Uint8Array;
|
|
26
|
+
skip(length: number): void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare class BerReader {
|
|
30
|
+
static readLength(reader: ByteReader): number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare class KlvParser {
|
|
34
|
+
parse(data: Uint8Array): KlvPacket;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { BerReader, ByteReader, type KlvPacket, KlvParser, UniversalKey };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/parser/ByteReader.ts
|
|
2
|
+
var ByteReader = class {
|
|
3
|
+
data;
|
|
4
|
+
offset = 0;
|
|
5
|
+
constructor(data) {
|
|
6
|
+
this.data = data;
|
|
7
|
+
}
|
|
8
|
+
get position() {
|
|
9
|
+
return this.offset;
|
|
10
|
+
}
|
|
11
|
+
get remaining() {
|
|
12
|
+
return this.data.length - this.offset;
|
|
13
|
+
}
|
|
14
|
+
hasRemaining(length = 1) {
|
|
15
|
+
return this.remaining >= length;
|
|
16
|
+
}
|
|
17
|
+
readByte() {
|
|
18
|
+
if (!this.hasRemaining()) {
|
|
19
|
+
throw new Error("Unexpected end of buffer.");
|
|
20
|
+
}
|
|
21
|
+
return this.data[this.offset++];
|
|
22
|
+
}
|
|
23
|
+
readBytes(length) {
|
|
24
|
+
if (!this.hasRemaining(length)) {
|
|
25
|
+
throw new Error("Unexpected end of buffer.");
|
|
26
|
+
}
|
|
27
|
+
const bytes = this.data.slice(this.offset, this.offset + length);
|
|
28
|
+
this.offset += length;
|
|
29
|
+
return bytes;
|
|
30
|
+
}
|
|
31
|
+
skip(length) {
|
|
32
|
+
if (!this.hasRemaining(length)) {
|
|
33
|
+
throw new Error("Unexpected end of buffer.");
|
|
34
|
+
}
|
|
35
|
+
this.offset += length;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/parser/BerReader.ts
|
|
40
|
+
var BerReader = class {
|
|
41
|
+
static readLength(reader) {
|
|
42
|
+
const first = reader.readByte();
|
|
43
|
+
if ((first & 128) === 0) {
|
|
44
|
+
return first;
|
|
45
|
+
}
|
|
46
|
+
const octets = first & 127;
|
|
47
|
+
if (octets === 0) {
|
|
48
|
+
throw new Error("Indefinite BER lengths are not supported.");
|
|
49
|
+
}
|
|
50
|
+
let length = 0;
|
|
51
|
+
for (let i = 0; i < octets; i++) {
|
|
52
|
+
length = length << 8 | reader.readByte();
|
|
53
|
+
}
|
|
54
|
+
return length;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/parser/UniversalKey.ts
|
|
59
|
+
var UniversalKey = class _UniversalKey {
|
|
60
|
+
constructor(bytes) {
|
|
61
|
+
this.bytes = bytes;
|
|
62
|
+
if (bytes.length !== _UniversalKey.LENGTH) {
|
|
63
|
+
throw new Error("Universal Key must contain 16 bytes.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
bytes;
|
|
67
|
+
static LENGTH = 16;
|
|
68
|
+
isSmpte() {
|
|
69
|
+
return this.bytes[0] === 6 && this.bytes[1] === 14 && this.bytes[2] === 43 && this.bytes[3] === 52;
|
|
70
|
+
}
|
|
71
|
+
equals(other) {
|
|
72
|
+
return this.bytes.every((v, i) => v === other.bytes[i]);
|
|
73
|
+
}
|
|
74
|
+
toHex(separator = "") {
|
|
75
|
+
return Array.from(this.bytes).map((b) => b.toString(16).padStart(2, "0")).join(separator);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// src/parser/KlvParser.ts
|
|
80
|
+
var KlvParser = class {
|
|
81
|
+
parse(data) {
|
|
82
|
+
const reader = new ByteReader(data);
|
|
83
|
+
const keyBytes = reader.readBytes(UniversalKey.LENGTH);
|
|
84
|
+
const key = new UniversalKey(keyBytes);
|
|
85
|
+
const length = BerReader.readLength(reader);
|
|
86
|
+
const value = reader.readBytes(length);
|
|
87
|
+
return {
|
|
88
|
+
key,
|
|
89
|
+
length,
|
|
90
|
+
value,
|
|
91
|
+
raw: data
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export { BerReader, ByteReader, KlvParser, UniversalKey };
|
|
97
|
+
//# sourceMappingURL=index.js.map
|
|
98
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/parser/ByteReader.ts","../src/parser/BerReader.ts","../src/parser/UniversalKey.ts","../src/parser/KlvParser.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export class ByteReader {\r\n\r\n private readonly data: Uint8Array;\r\n private offset = 0;\r\n\r\n constructor(data: Uint8Array) {\r\n this.data = data;\r\n }\r\n\r\n get position(): number {\r\n return this.offset;\r\n }\r\n\r\n get remaining(): number {\r\n return this.data.length - this.offset;\r\n }\r\n\r\n hasRemaining(length = 1): boolean {\r\n return this.remaining >= length;\r\n }\r\n\r\n readByte(): number {\r\n if (!this.hasRemaining()) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n return this.data[this.offset++];\r\n }\r\n\r\n readBytes(length: number): Uint8Array {\r\n if (!this.hasRemaining(length)) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n const bytes = this.data.slice(this.offset, this.offset + length);\r\n this.offset += length;\r\n\r\n return bytes;\r\n }\r\n\r\n skip(length: number): void {\r\n if (!this.hasRemaining(length)) {\r\n throw new Error(\"Unexpected end of buffer.\");\r\n }\r\n\r\n this.offset += length;\r\n }\r\n}","import { ByteReader } from \"./ByteReader\";\r\n\r\nexport class BerReader {\r\n\r\n static readLength(reader: ByteReader): number {\r\n\r\n const first = reader.readByte();\r\n\r\n // Short form\r\n if ((first & 0x80) === 0) {\r\n return first;\r\n }\r\n\r\n const octets = first & 0x7F;\r\n\r\n if (octets === 0) {\r\n throw new Error(\"Indefinite BER lengths are not supported.\");\r\n }\r\n\r\n let length = 0;\r\n\r\n for (let i = 0; i < octets; i++) {\r\n length = (length << 8) | reader.readByte();\r\n }\r\n\r\n return length;\r\n }\r\n\r\n}","export class UniversalKey {\r\n\r\n static readonly LENGTH = 16;\r\n\r\n constructor(\r\n public readonly bytes: Uint8Array\r\n ) {\r\n\r\n if (bytes.length !== UniversalKey.LENGTH) {\r\n throw new Error(\"Universal Key must contain 16 bytes.\");\r\n }\r\n\r\n }\r\n\r\n isSmpte(): boolean {\r\n\r\n return (\r\n this.bytes[0] === 0x06 &&\r\n this.bytes[1] === 0x0E &&\r\n this.bytes[2] === 0x2B &&\r\n this.bytes[3] === 0x34\r\n );\r\n\r\n }\r\n\r\n equals(other: UniversalKey): boolean {\r\n\r\n return this.bytes.every((v, i) => v === other.bytes[i]);\r\n\r\n }\r\n\r\n toHex(separator = \"\"): string {\r\n\r\n return Array.from(this.bytes)\r\n .map(b => b.toString(16).padStart(2, \"0\"))\r\n .join(separator);\r\n\r\n }\r\n\r\n}","import { KlvPacket } from \"../packet/KlvPacket\";\r\nimport { BerReader } from \"./BerReader\";\r\nimport { ByteReader } from \"./ByteReader\";\r\nimport { UniversalKey } from \"./UniversalKey\";\r\n\r\nexport class KlvParser {\r\n\r\n parse(data: Uint8Array): KlvPacket {\r\n\r\n const reader = new ByteReader(data);\r\n\r\n const keyBytes = reader.readBytes(UniversalKey.LENGTH);\r\n\r\n const key = new UniversalKey(keyBytes);\r\n\r\n const length = BerReader.readLength(reader);\r\n\r\n const value = reader.readBytes(length);\r\n\r\n return {\r\n\r\n key,\r\n\r\n length,\r\n\r\n value,\r\n\r\n raw: data\r\n\r\n };\r\n\r\n }\r\n\r\n}"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "klv-ts",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Generic SMPTE 336M KLV parser for JavaScript and TypeScript",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"dev": "tsup --watch",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"lint": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "pnpm build && pnpm test"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"klv",
|
|
29
|
+
"misb",
|
|
30
|
+
"mpegts",
|
|
31
|
+
"smpte",
|
|
32
|
+
"metadata",
|
|
33
|
+
"video",
|
|
34
|
+
"uas"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/JuankAnacona/klv-ts.git"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {
|
|
41
|
+
"tsup": "^8.5.1",
|
|
42
|
+
"vitest": "^4.1.10"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"typescript": "5.9.2"
|
|
46
|
+
}
|
|
47
|
+
}
|