@norskvideo/norsk-studio-alpha 1.27.0-2025-07-09-0fcad3ea

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 (160) hide show
  1. package/README.md +10 -0
  2. package/client/info.js +43461 -0
  3. package/client/processor.audioLevel/styles.css +165 -0
  4. package/client/shared/style.css +1627 -0
  5. package/client/shared/tailwind.css +31 -0
  6. package/client/style.css +1074 -0
  7. package/lib/index.d.ts +3 -0
  8. package/lib/index.js +14 -0
  9. package/lib/index.js.map +1 -0
  10. package/lib/info.d.ts +3 -0
  11. package/lib/info.js +44 -0
  12. package/lib/info.js.map +1 -0
  13. package/lib/input.decklink/info.d.ts +3 -0
  14. package/lib/input.decklink/info.js +51 -0
  15. package/lib/input.decklink/info.js.map +1 -0
  16. package/lib/input.decklink/runtime.d.ts +12 -0
  17. package/lib/input.decklink/runtime.js +22 -0
  18. package/lib/input.decklink/runtime.js.map +1 -0
  19. package/lib/input.decklink/types.d.ts +23 -0
  20. package/lib/input.decklink/types.js +3 -0
  21. package/lib/input.decklink/types.js.map +1 -0
  22. package/lib/input.decklink/types.yaml +32 -0
  23. package/lib/input.mp4file/info.d.ts +3 -0
  24. package/lib/input.mp4file/info.js +34 -0
  25. package/lib/input.mp4file/info.js.map +1 -0
  26. package/lib/input.mp4file/runtime.d.ts +14 -0
  27. package/lib/input.mp4file/runtime.js +33 -0
  28. package/lib/input.mp4file/runtime.js.map +1 -0
  29. package/lib/input.mp4file/types.d.ts +23 -0
  30. package/lib/input.mp4file/types.js +3 -0
  31. package/lib/input.mp4file/types.js.map +1 -0
  32. package/lib/input.mp4file/types.yaml +30 -0
  33. package/lib/input.ndi/info.d.ts +3 -0
  34. package/lib/input.ndi/info.js +52 -0
  35. package/lib/input.ndi/info.js.map +1 -0
  36. package/lib/input.ndi/runtime.d.ts +24 -0
  37. package/lib/input.ndi/runtime.js +60 -0
  38. package/lib/input.ndi/runtime.js.map +1 -0
  39. package/lib/input.ndi/source-selection.d.ts +10 -0
  40. package/lib/input.ndi/source-selection.js +84 -0
  41. package/lib/input.ndi/source-selection.js.map +1 -0
  42. package/lib/input.ndi/types.d.ts +52 -0
  43. package/lib/input.ndi/types.js +3 -0
  44. package/lib/input.ndi/types.js.map +1 -0
  45. package/lib/input.ndi/types.yaml +37 -0
  46. package/lib/output.ndi/info.d.ts +8 -0
  47. package/lib/output.ndi/info.js +61 -0
  48. package/lib/output.ndi/info.js.map +1 -0
  49. package/lib/output.ndi/inline-view.d.ts +6 -0
  50. package/lib/output.ndi/inline-view.js +12 -0
  51. package/lib/output.ndi/inline-view.js.map +1 -0
  52. package/lib/output.ndi/runtime.d.ts +14 -0
  53. package/lib/output.ndi/runtime.js +35 -0
  54. package/lib/output.ndi/runtime.js.map +1 -0
  55. package/lib/output.ndi/types.d.ts +35 -0
  56. package/lib/output.ndi/types.js +3 -0
  57. package/lib/output.ndi/types.js.map +1 -0
  58. package/lib/output.ndi/types.yaml +72 -0
  59. package/lib/output.recorder/info.d.ts +10 -0
  60. package/lib/output.recorder/info.js +79 -0
  61. package/lib/output.recorder/info.js.map +1 -0
  62. package/lib/output.recorder/runtime.d.ts +66 -0
  63. package/lib/output.recorder/runtime.js +301 -0
  64. package/lib/output.recorder/runtime.js.map +1 -0
  65. package/lib/output.recorder/types.d.ts +225 -0
  66. package/lib/output.recorder/types.js +3 -0
  67. package/lib/output.recorder/types.js.map +1 -0
  68. package/lib/output.recorder/types.yaml +211 -0
  69. package/lib/processor.actionReplay/info.d.ts +25 -0
  70. package/lib/processor.actionReplay/info.js +77 -0
  71. package/lib/processor.actionReplay/info.js.map +1 -0
  72. package/lib/processor.actionReplay/runtime.d.ts +38 -0
  73. package/lib/processor.actionReplay/runtime.js +225 -0
  74. package/lib/processor.actionReplay/runtime.js.map +1 -0
  75. package/lib/processor.actionReplay/summary.d.ts +4 -0
  76. package/lib/processor.actionReplay/summary.js +76 -0
  77. package/lib/processor.actionReplay/summary.js.map +1 -0
  78. package/lib/processor.actionReplay/types.d.ts +38 -0
  79. package/lib/processor.actionReplay/types.js +3 -0
  80. package/lib/processor.actionReplay/types.js.map +1 -0
  81. package/lib/processor.actionReplay/types.yaml +74 -0
  82. package/lib/processor.audioLevel/info.d.ts +27 -0
  83. package/lib/processor.audioLevel/info.js +61 -0
  84. package/lib/processor.audioLevel/info.js.map +1 -0
  85. package/lib/processor.audioLevel/inline-view.d.ts +4 -0
  86. package/lib/processor.audioLevel/inline-view.js +26 -0
  87. package/lib/processor.audioLevel/inline-view.js.map +1 -0
  88. package/lib/processor.audioLevel/runtime.d.ts +26 -0
  89. package/lib/processor.audioLevel/runtime.js +86 -0
  90. package/lib/processor.audioLevel/runtime.js.map +1 -0
  91. package/lib/processor.audioLevel/summary-view.d.ts +7 -0
  92. package/lib/processor.audioLevel/summary-view.js +37 -0
  93. package/lib/processor.audioLevel/summary-view.js.map +1 -0
  94. package/lib/processor.audioLevel/types.d.ts +42 -0
  95. package/lib/processor.audioLevel/types.js +3 -0
  96. package/lib/processor.audioLevel/types.js.map +1 -0
  97. package/lib/processor.audioLevel/types.yaml +83 -0
  98. package/lib/processor.gemini-poc/info.d.ts +8 -0
  99. package/lib/processor.gemini-poc/info.js +59 -0
  100. package/lib/processor.gemini-poc/info.js.map +1 -0
  101. package/lib/processor.gemini-poc/runtime.d.ts +38 -0
  102. package/lib/processor.gemini-poc/runtime.js +132 -0
  103. package/lib/processor.gemini-poc/runtime.js.map +1 -0
  104. package/lib/processor.gemini-poc/types.d.ts +23 -0
  105. package/lib/processor.gemini-poc/types.js +3 -0
  106. package/lib/processor.gemini-poc/types.js.map +1 -0
  107. package/lib/processor.gemini-poc/types.yaml +43 -0
  108. package/lib/processor.mixMinus/info.d.ts +7 -0
  109. package/lib/processor.mixMinus/info.js +40 -0
  110. package/lib/processor.mixMinus/info.js.map +1 -0
  111. package/lib/processor.mixMinus/runtime.d.ts +23 -0
  112. package/lib/processor.mixMinus/runtime.js +85 -0
  113. package/lib/processor.mixMinus/runtime.js.map +1 -0
  114. package/lib/processor.mixMinus/types.d.ts +18 -0
  115. package/lib/processor.mixMinus/types.js +3 -0
  116. package/lib/processor.mixMinus/types.js.map +1 -0
  117. package/lib/processor.mixMinus/types.yaml +19 -0
  118. package/lib/processor.monetise/info.d.ts +3 -0
  119. package/lib/processor.monetise/info.js +72 -0
  120. package/lib/processor.monetise/info.js.map +1 -0
  121. package/lib/processor.monetise/runtime.d.ts +62 -0
  122. package/lib/processor.monetise/runtime.js +217 -0
  123. package/lib/processor.monetise/runtime.js.map +1 -0
  124. package/lib/processor.monetise/summary.d.ts +7 -0
  125. package/lib/processor.monetise/summary.js +40 -0
  126. package/lib/processor.monetise/summary.js.map +1 -0
  127. package/lib/processor.monetise/types.d.ts +16 -0
  128. package/lib/processor.monetise/types.js +3 -0
  129. package/lib/processor.monetise/types.js.map +1 -0
  130. package/lib/processor.monetise/types.yaml +9 -0
  131. package/lib/processor.whisper-transcribe/info.d.ts +9 -0
  132. package/lib/processor.whisper-transcribe/info.js +46 -0
  133. package/lib/processor.whisper-transcribe/info.js.map +1 -0
  134. package/lib/processor.whisper-transcribe/runtime.d.ts +22 -0
  135. package/lib/processor.whisper-transcribe/runtime.js +70 -0
  136. package/lib/processor.whisper-transcribe/runtime.js.map +1 -0
  137. package/lib/processor.whisper-transcribe/types.d.ts +21 -0
  138. package/lib/processor.whisper-transcribe/types.js +3 -0
  139. package/lib/processor.whisper-transcribe/types.js.map +1 -0
  140. package/lib/processor.whisper-transcribe/types.yaml +28 -0
  141. package/lib/shared/schemas.d.ts +8 -0
  142. package/lib/shared/schemas.js +44 -0
  143. package/lib/shared/schemas.js.map +1 -0
  144. package/lib/test/output.recorder.d.ts +1 -0
  145. package/lib/test/output.recorder.js +186 -0
  146. package/lib/test/output.recorder.js.map +1 -0
  147. package/lib/util.timestamps/info.d.ts +14 -0
  148. package/lib/util.timestamps/info.js +64 -0
  149. package/lib/util.timestamps/info.js.map +1 -0
  150. package/lib/util.timestamps/inline-view.d.ts +6 -0
  151. package/lib/util.timestamps/inline-view.js +95 -0
  152. package/lib/util.timestamps/inline-view.js.map +1 -0
  153. package/lib/util.timestamps/runtime.d.ts +13 -0
  154. package/lib/util.timestamps/runtime.js +51 -0
  155. package/lib/util.timestamps/runtime.js.map +1 -0
  156. package/lib/util.timestamps/types.d.ts +36 -0
  157. package/lib/util.timestamps/types.js +3 -0
  158. package/lib/util.timestamps/types.js.map +1 -0
  159. package/lib/util.timestamps/types.yaml +74 -0
  160. package/package.json +57 -0
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.waitForAssert = waitForAssert;
30
+ const norsk_sdk_1 = require("@norskvideo/norsk-sdk");
31
+ const __1 = require("../");
32
+ const builder_1 = require("@norskvideo/norsk-studio/lib/test/_util/builder");
33
+ const document = __importStar(require("@norskvideo/norsk-studio/lib/runtime/document"));
34
+ const yaml_1 = __importDefault(require("yaml"));
35
+ const execution_1 = __importStar(require("@norskvideo/norsk-studio/lib/runtime/execution"));
36
+ const express_1 = __importDefault(require("express"));
37
+ const client_types_1 = require("@norskvideo/norsk-studio/lib/extension/client-types");
38
+ const sources_1 = require("@norskvideo/norsk-studio/lib/test/_util/sources");
39
+ const info_1 = __importDefault(require("../output.recorder/info"));
40
+ const node_fetch_1 = __importDefault(require("node-fetch"));
41
+ const chai_1 = require("chai");
42
+ const promises_1 = __importDefault(require("fs/promises"));
43
+ const util_1 = require("@norskvideo/norsk-studio/lib/shared/util");
44
+ async function defaultRuntime() {
45
+ const runtime = (0, builder_1.emptyRuntime)();
46
+ await (0, __1.registerAll)(runtime);
47
+ return runtime;
48
+ }
49
+ describe("Output Recorder", () => {
50
+ async function testDocument() {
51
+ const runtime = await defaultRuntime();
52
+ await promises_1.default.rm('/tmp/recorder', { recursive: true, force: true });
53
+ const yaml = new builder_1.YamlBuilder()
54
+ .addNode(new builder_1.YamlNodeBuilder('recorder', (0, info_1.default)(client_types_1.RegistrationConsts), {
55
+ store_path: '/tmp/recorder',
56
+ cuts_path: '/tmp/recorder',
57
+ expiry_hours: 1
58
+ }).reify())
59
+ .reify();
60
+ const compiled = document.load(__filename, runtime, yaml_1.default.stringify(yaml));
61
+ return compiled;
62
+ }
63
+ let norsk = undefined;
64
+ let app;
65
+ let server;
66
+ let port;
67
+ let result;
68
+ let recorder;
69
+ function latest() {
70
+ return result.runtimeState.latest['recorder'];
71
+ }
72
+ after(async () => {
73
+ clearInterval(recorder?.timer);
74
+ await norsk?.close();
75
+ server?.close();
76
+ });
77
+ before(async () => {
78
+ const compiled = await testDocument();
79
+ norsk = await norsk_sdk_1.Norsk.connect({ onShutdown: () => { } });
80
+ const source = await (0, sources_1.videoAndAudio)(norsk, 'source');
81
+ app = (0, express_1.default)();
82
+ app.use(express_1.default.json());
83
+ server = app.listen(0);
84
+ port = server.address().port;
85
+ result = await (0, execution_1.default)(norsk, compiled, app);
86
+ recorder = result.components["recorder"];
87
+ const sink = new execution_1.ComponentSubscriptions(norsk, recorder);
88
+ sink.setSources([new execution_1.StudioNodeSubscriptionSource(source, (0, sources_1.testSourceDescription)(), {
89
+ type: "take-all-streams", filter: client_types_1.Av.map((media) => ({ media }))
90
+ })]);
91
+ return new Promise((r) => {
92
+ setTimeout(r, 10000.0);
93
+ });
94
+ });
95
+ describe("timeline", () => {
96
+ it("has a single entry with some data", async () => {
97
+ const request = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/timeline`);
98
+ const body = await request.json();
99
+ (0, chai_1.expect)(body.timeline.length).equal(1);
100
+ });
101
+ });
102
+ describe("creating a cut", () => {
103
+ let cutUrl;
104
+ before(async () => {
105
+ const { timeline } = (await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/timeline`).then(async (r) => r.json()));
106
+ const request = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/cut`, {
107
+ method: 'POST',
108
+ headers: { 'content-type': 'application/json', 'accept': 'application/json' },
109
+ body: JSON.stringify({
110
+ start: timeline[0].start,
111
+ duration_s: 5.0
112
+ })
113
+ });
114
+ (0, chai_1.expect)(request.status).equal(201);
115
+ const { url } = (await request.json());
116
+ cutUrl = url;
117
+ });
118
+ it("returns the URL to the cut", async () => {
119
+ (0, chai_1.expect)(cutUrl).not.empty;
120
+ });
121
+ it("the url contains the current status", async () => {
122
+ const status = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${cutUrl}`).then(async (r) => r.json());
123
+ (0, chai_1.expect)(status.status).not.empty;
124
+ });
125
+ it("adds a cut to the collection", async () => {
126
+ (0, chai_1.expect)(latest().cuts.length).equal(1);
127
+ });
128
+ it("updates percentage complete", async () => {
129
+ await waitForAssert(async () => latest().cuts[0].percent == 100.0, async () => {
130
+ const status = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${cutUrl}`).then(async (r) => r.json());
131
+ (0, chai_1.expect)(latest().cuts[0].percent).equal(100.0);
132
+ (0, chai_1.expect)(status.status).equal('CutReady');
133
+ });
134
+ });
135
+ it("provides the file over the API", async () => {
136
+ await (0, util_1.waitForCondition)(() => latest().cuts[0].percent == 100.0);
137
+ const status = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${cutUrl}`).then(async (r) => r.json());
138
+ if (status.status !== 'CutReady')
139
+ throw "Cut not ready";
140
+ const request = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${status.url}`);
141
+ (0, chai_1.expect)(request.status).equal(200);
142
+ const buffer = await request.text();
143
+ (0, chai_1.expect)(buffer.length).greaterThan(0);
144
+ });
145
+ it("Prunes the file and makes it unavailable", async () => {
146
+ await (0, util_1.waitForCondition)(() => latest().cuts[0].percent == 100.0);
147
+ recorder.cfg.expiry_hours = 0.0;
148
+ await recorder.pruneCutStore();
149
+ const status = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${cutUrl}`).then(async (r) => r.json());
150
+ if (status.status !== 'CutReady')
151
+ throw new Error("Cut not ready");
152
+ const request = await (0, node_fetch_1.default)(`http://localhost:${port}/recorder/${status.url}`);
153
+ const _buffer = await request.text();
154
+ (0, chai_1.expect)(request.status).equal(404);
155
+ });
156
+ });
157
+ describe("invalid requests", () => {
158
+ });
159
+ });
160
+ async function waitForAssert(condition, assert, timeout, interval) {
161
+ return new Promise((resolve, reject) => {
162
+ const doAssert = () => {
163
+ try {
164
+ void assert().then(resolve);
165
+ }
166
+ catch (e) {
167
+ reject(e);
168
+ }
169
+ };
170
+ const failure = setTimeout(() => {
171
+ clearTimeout(failure);
172
+ clearInterval(check);
173
+ doAssert();
174
+ }, timeout);
175
+ const check = setInterval(() => {
176
+ void condition().then((result) => {
177
+ if (result) {
178
+ clearTimeout(failure);
179
+ clearInterval(check);
180
+ doAssert();
181
+ }
182
+ });
183
+ }, interval);
184
+ });
185
+ }
186
+ //# sourceMappingURL=output.recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"output.recorder.js","sourceRoot":"","sources":["../../src/test/output.recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type Registration from "@norskvideo/norsk-studio/lib/extension/registration";
2
+ export default function (R: Registration): import("@norskvideo/norsk-studio/lib/extension/client-types").NodeInfo<{
3
+ id: string;
4
+ displayName: string;
5
+ }, {
6
+ timestamps: import("./types").components["schemas"]["TimestampCollection"][];
7
+ }, Record<string, never>, {
8
+ type: "new-timestamp";
9
+ key: string;
10
+ value: number;
11
+ wallMs: number;
12
+ }>;
13
+ export declare const hardwareNames: readonly ["quadra", "nvidia"];
14
+ export type HardwareName = typeof hardwareNames[number];
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.hardwareNames = void 0;
7
+ exports.default = default_1;
8
+ const inline_view_1 = __importDefault(require("./inline-view"));
9
+ function default_1(R) {
10
+ const { defineComponent, All } = R;
11
+ return defineComponent({
12
+ identifier: 'util.timestamps',
13
+ category: 'output',
14
+ name: "Jitter",
15
+ description: "A jitter utility which processes and tracks timestamps.",
16
+ subscription: {
17
+ accepts: {
18
+ type: "dynamic-streams",
19
+ mode: 'any',
20
+ streams: () => All.map((media) => ({ media }))
21
+ },
22
+ produces: undefined
23
+ },
24
+ display: (_desc) => { return {}; },
25
+ runtime: {
26
+ initialState: () => ({
27
+ timestamps: [],
28
+ }),
29
+ handleEvent(ev, state) {
30
+ const evType = ev.type;
31
+ switch (evType) {
32
+ case "new-timestamp": {
33
+ const target = state.timestamps.find((e) => e.key === ev.key) ??
34
+ (() => {
35
+ const start = { key: ev.key, startTimeMs: new Date().valueOf(), startTimestamp: ev.value, timestamps: [] };
36
+ state.timestamps.push(start);
37
+ return start;
38
+ })();
39
+ target.timestamps.push({ ts: ev.value, wall: ev.wallMs });
40
+ while (target.timestamps.length > 200) {
41
+ target.timestamps.splice(0, 1);
42
+ }
43
+ break;
44
+ }
45
+ default:
46
+ assertUnreachable(evType);
47
+ }
48
+ return { ...state };
49
+ },
50
+ inline: inline_view_1.default
51
+ },
52
+ configForm: {
53
+ form: {}
54
+ }
55
+ });
56
+ }
57
+ function assertUnreachable(_) {
58
+ throw new Error("Didn't expect to get here");
59
+ }
60
+ exports.hardwareNames = [
61
+ 'quadra',
62
+ 'nvidia'
63
+ ];
64
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../src/util.timestamps/info.ts"],"names":[],"mappings":";;;;;;AAIA,4BAoDC;AAtDD,gEAAuC;AAEvC,mBAAwB,CAAe;IACrC,MAAM,EACJ,eAAe,EACf,GAAG,EACJ,GAAG,CAAC,CAAC;IAEN,OAAO,eAAe,CAA8F;QAClH,UAAU,EAAE,iBAAiB;QAC7B,QAAQ,EAAE,QAAQ;QAClB,IAAI,EAAE,QAAQ;QACd,WAAW,EAAE,yDAAyD;QACtE,YAAY,EAAE;YACZ,OAAO,EAAE;gBACP,IAAI,EAAE,iBAAiB;gBACvB,IAAI,EAAE,KAAK;gBACX,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;aAC/C;YACD,QAAQ,EAAE,SAAS;SACpB;QACD,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,CAAC;QAClC,OAAO,EAAE;YACP,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;gBACnB,UAAU,EAAE,EAAE;aACf,CAAC;YACF,WAAW,CAAC,EAAE,EAAE,KAAK;gBACnB,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;gBACvB,QAAQ,MAAM,EAAE,CAAC;oBACf,KAAK,eAAe,CAAC,CAAC,CAAC;wBACrB,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,CAAC;4BAC3D,CAAC,GAAG,EAAE;gCACJ,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,EAAE,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;gCAC3G,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gCAC7B,OAAO,KAAK,CAAC;4BACf,CAAC,CAAC,EAAE,CAAA;wBACN,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;wBAE1D,OAAO,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;4BACtC,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;wBACjC,CAAC;wBACD,MAAM;oBACR,CAAC;oBACD;wBACE,iBAAiB,CAAC,MAAM,CAAC,CAAA;gBAC7B,CAAC;gBACD,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;YACtB,CAAC;YACD,MAAM,EAAE,qBAAU;SACnB;QACD,UAAU,EAAE;YACV,IAAI,EAAE,EAAE;SACT;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,iBAAiB,CAAC,CAAQ;IACjC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;AAC/C,CAAC;AAEY,QAAA,aAAa,GAAG;IAC3B,QAAQ;IACR,QAAQ;CACA,CAAA"}
@@ -0,0 +1,6 @@
1
+ import type { TimestampOutputState, TimestampOutputSettings } from "./runtime";
2
+ declare function InlineView({ state, config: _2 }: {
3
+ state: TimestampOutputState;
4
+ config: TimestampOutputSettings;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ export default InlineView;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jsx_runtime_1 = require("react/jsx-runtime");
7
+ const react_1 = require("react");
8
+ const auto_1 = __importDefault(require("chart.js/auto"));
9
+ function InlineView({ state, config: _2 }) {
10
+ const chartContainer = (0, react_1.useRef)(null);
11
+ const [chartControl, setChartControl] = (0, react_1.useState)(undefined);
12
+ (0, react_1.useEffect)(() => {
13
+ if (!chartContainer.current)
14
+ return;
15
+ if (state.timestamps.length < 2)
16
+ return;
17
+ auto_1.default.defaults.color = "#FFF";
18
+ const chart = new auto_1.default(chartContainer.current, {
19
+ type: 'line',
20
+ options: {
21
+ plugins: {
22
+ legend: {
23
+ display: false
24
+ },
25
+ },
26
+ animation: false,
27
+ color: '#FFF',
28
+ scales: {
29
+ x: {
30
+ min: 0,
31
+ max: 200,
32
+ grid: {
33
+ display: false,
34
+ }
35
+ },
36
+ y: {
37
+ min: 0,
38
+ max: 5000,
39
+ grid: {
40
+ display: false,
41
+ }
42
+ }
43
+ }
44
+ },
45
+ data: {
46
+ labels: new Array(200).fill(0).map((_, i) => i).map((_) => ""),
47
+ datasets: state.timestamps.map((t) => {
48
+ const mapped = (t.timestamps.map((f) => {
49
+ const elapsedWall = (f.wall - t.startTimeMs);
50
+ const elapsedTime = (f.ts - t.startTimestamp) * 1000.0;
51
+ return Math.abs(elapsedTime - elapsedWall);
52
+ }));
53
+ return {
54
+ label: t.key,
55
+ fill: false,
56
+ borderColor: 'rgba(255, 0, 0, 255)',
57
+ borderWidth: 1,
58
+ pointStyle: 'dash',
59
+ data: mapped
60
+ };
61
+ })
62
+ }
63
+ });
64
+ setChartControl(chart);
65
+ setInterval(() => {
66
+ chart.update();
67
+ }, 100);
68
+ }, [chartContainer]);
69
+ (0, react_1.useEffect)(() => {
70
+ if (!chartControl)
71
+ return;
72
+ chartControl.data = {
73
+ labels: new Array(200).fill(0).map((_, i) => i).map((_) => ""),
74
+ datasets: state.timestamps.map((t) => {
75
+ const mapped = (t.timestamps.map((f) => {
76
+ const elapsedWall = (f.wall - t.startTimeMs);
77
+ const elapsedTime = (f.ts - t.startTimestamp) * 1000.0;
78
+ return Math.abs(elapsedTime - elapsedWall);
79
+ }));
80
+ return {
81
+ label: t.key,
82
+ fill: false,
83
+ borderColor: 'rgba(255, 0, 0, 255)',
84
+ borderWidth: 1,
85
+ pointStyle: 'dash',
86
+ data: mapped
87
+ };
88
+ })
89
+ };
90
+ }, [state]);
91
+ { }
92
+ return (0, jsx_runtime_1.jsx)("div", { className: "util-timestamp", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-gray-50 dark:bg-gray-700 rounded", style: { width: "360px", height: '200px', padding: '10px' }, children: (0, jsx_runtime_1.jsx)("canvas", { className: "bg-gray-50 dark:bg-gray-700 rounded", ref: chartContainer }) }) });
93
+ }
94
+ exports.default = InlineView;
95
+ //# sourceMappingURL=inline-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inline-view.js","sourceRoot":"","sources":["../../src/util.timestamps/inline-view.tsx"],"names":[],"mappings":";;;;;;AAAA,iCAAoD;AAGpD,yDAAkC;AAElC,SAAS,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAoE;IACzG,MAAM,cAAc,GAAG,IAAA,cAAM,EAAoB,IAAI,CAAC,CAAC;IAEvD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,IAAA,gBAAQ,EAAoB,SAAS,CAAC,CAAC;IAE/E,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,CAAC,cAAc,CAAC,OAAO;YAAE,OAAO;QACpC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO;QAIxC,cAAK,CAAC,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC;QAG9B,MAAM,KAAK,GAAG,IAAI,cAAK,CAAC,cAAc,CAAC,OAAO,EAAE;YAC9C,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE;gBACP,OAAO,EAAE;oBACP,MAAM,EAAE;wBACN,OAAO,EAAE,KAAK;qBACf;iBACF;gBAED,SAAS,EAAE,KAAK;gBAEhB,KAAK,EAAE,MAAM;gBAGb,MAAM,EAAE;oBACN,CAAC,EAAE;wBACD,GAAG,EAAE,CAAC;wBACN,GAAG,EAAE,GAAG;wBACR,IAAI,EAAE;4BACJ,OAAO,EAAE,KAAK;yBACf;qBACF;oBACD,CAAC,EAAE;wBACD,GAAG,EAAE,CAAC;wBACN,GAAG,EAAE,IAAI;wBACT,IAAI,EAAE;4BACJ,OAAO,EAAE,KAAK;yBACf;qBACF;iBACF;aACF;YACD,IAAI,EAAE;gBACJ,MAAM,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;gBAC9D,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACnC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;wBACrC,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAA;wBAC5C,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC;wBACvD,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC;oBAC7C,CAAC,CAAC,CAAC,CAAA;oBACH,OAAO;wBACL,KAAK,EAAE,CAAC,CAAC,GAAG;wBACZ,IAAI,EAAE,KAAK;wBACX,WAAW,EAAE,sBAAsB;wBACnC,WAAW,EAAE,CAAC;wBACd,UAAU,EAAE,MAAM;wBAElB,IAAI,EAAE,MAAM;qBACb,CAAA;gBACH,CAAC,CAAC;aACH;SACF,CAAC,CAAA;QACF,eAAe,CAAC,KAAK,CAAC,CAAC;QAEvB,WAAW,CAAC,GAAG,EAAE;YACf,KAAK,CAAC,MAAM,EAAE,CAAA;QAChB,CAAC,EAAE,GAAG,CAAC,CAAA;IACT,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAA;IAGpB,IAAA,iBAAS,EAAC,GAAG,EAAE;QACb,IAAI,CAAC,YAAY;YAAE,OAAO;QAC1B,YAAY,CAAC,IAAI,GAAG;YAClB,MAAM,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC9D,QAAQ,EAAE,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACnC,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACrC,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAA;oBAC5C,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,cAAc,CAAC,GAAG,MAAM,CAAC;oBACvD,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,CAAC;gBAC7C,CAAC,CAAC,CAAC,CAAA;gBACH,OAAO;oBACL,KAAK,EAAE,CAAC,CAAC,GAAG;oBACZ,IAAI,EAAE,KAAK;oBACX,WAAW,EAAE,sBAAsB;oBACnC,WAAW,EAAE,CAAC;oBACd,UAAU,EAAE,MAAM;oBAElB,IAAI,EAAE,MAAM;iBACb,CAAA;YACH,CAAC,CAAC;SACH,CAAA;IACH,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAA;IAGX,CAAC,CAAkF,CAAC;IACpF,OAAO,gCAAK,SAAS,EAAC,gBAAgB,YACpC,gCAAK,SAAS,EAAC,qCAAqC,EAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAC9G,mCAAQ,SAAS,EAAC,qCAAqC,EAAC,GAAG,EAAE,cAAc,GAElE,GACL,GACF,CAAA;AACR,CAAC;AAED,kBAAe,UAAU,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { Norsk } from '@norskvideo/norsk-sdk';
2
+ import { OnCreated, ServerComponentDefinition, ServerComponentSchemas, StudioRuntime } from '@norskvideo/norsk-studio/lib/extension/runtime-types';
3
+ import { SimpleSinkWrapper } from '@norskvideo/norsk-studio/lib/extension/base-nodes';
4
+ import { components } from './types';
5
+ export type TimestampOutputSettings = components['schemas']['TimestampOutputSettings'];
6
+ export type TimestampCollection = components['schemas']['TimestampCollection'];
7
+ export type TimestampOutputState = components['schemas']['TimestampOutputState'];
8
+ export type TimestampOutputEvent = components['schemas']['TimestampOutputEvent'];
9
+ export type TimestampOutputCommand = components['schemas']['TimestampOutputCommand'];
10
+ export default class TimestampOutputDefinition implements ServerComponentDefinition<TimestampOutputSettings, SimpleSinkWrapper, TimestampOutputState, TimestampOutputCommand, TimestampOutputEvent> {
11
+ schemas(): Promise<ServerComponentSchemas>;
12
+ create(norsk: Norsk, cfg: TimestampOutputSettings, cb: OnCreated<SimpleSinkWrapper>, runtime: StudioRuntime<TimestampOutputState, TimestampOutputCommand, TimestampOutputEvent>): Promise<void>;
13
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const base_nodes_1 = require("@norskvideo/norsk-studio/lib/extension/base-nodes");
7
+ const path_1 = __importDefault(require("path"));
8
+ const schemas_1 = require("../shared/schemas");
9
+ class TimestampOutputDefinition {
10
+ async schemas() {
11
+ return (0, schemas_1.schemaFromTypes)(path_1.default.join(__dirname, 'types.yaml'), {
12
+ config: 'TimestampOutputSettings',
13
+ state: 'TimestampOutputState'
14
+ });
15
+ }
16
+ async create(norsk, cfg, cb, runtime) {
17
+ const node = new TimestampOutput(norsk, runtime, cfg);
18
+ await node.initialised;
19
+ cb(node);
20
+ }
21
+ }
22
+ exports.default = TimestampOutputDefinition;
23
+ class TimestampOutput extends base_nodes_1.CustomSinkNode {
24
+ initialised;
25
+ norsk;
26
+ updates;
27
+ cfg;
28
+ node;
29
+ constructor(norsk, { updates }, cfg) {
30
+ super(cfg.id);
31
+ this.cfg = cfg;
32
+ this.norsk = norsk;
33
+ this.updates = updates;
34
+ this.initialised = this.initialise();
35
+ }
36
+ async initialise() {
37
+ const node = await this.norsk.inspect.streamTimestampReport({
38
+ onTimestamp: this.onTimestamp.bind(this)
39
+ });
40
+ this.setup({ sink: node });
41
+ }
42
+ onTimestamp(key, timestamp) {
43
+ this.updates.raiseEvent({
44
+ type: 'new-timestamp',
45
+ key: `${key.programNumber}-${key.sourceName}-${key.streamId}-${key.renditionName}`,
46
+ value: Number((timestamp.n * 100n) / timestamp.d) / 100,
47
+ wallMs: new Date().valueOf()
48
+ });
49
+ }
50
+ }
51
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/util.timestamps/runtime.ts"],"names":[],"mappings":";;;;;AAGA,kFAAsG;AACtG,gDAAwB;AAGxB,+CAAoD;AAWpD,MAAqB,yBAAyB;IAC5C,KAAK,CAAC,OAAO;QACX,OAAO,IAAA,yBAAe,EAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC,EAAE;YACzD,MAAM,EAAE,yBAAyB;YACjC,KAAK,EAAE,sBAAsB;SAC9B,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,KAAY,EAAE,GAA4B,EAAE,EAAgC,EAAE,OAA0F;QACnL,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QACtD,MAAM,IAAI,CAAC,WAAW,CAAC;QACvB,EAAE,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;CACF;AAZD,4CAYC;AAED,MAAM,eAAgB,SAAQ,2BAAc;IAC1C,WAAW,CAAgB;IAC3B,KAAK,CAAQ;IACb,OAAO,CAAqF;IAE5F,GAAG,CAA0B;IAC7B,IAAI,CAAyB;IAE7B,YAAY,KAAY,EAAE,EAAE,OAAO,EAAqF,EAAE,GAA4B;QACpJ,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,qBAAqB,CAAC;YAC1D,WAAW,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;SACzC,CAAC,CAAA;QACF,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED,WAAW,CAAC,GAAc,EAAE,SAAmB;QAC7C,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;YACtB,IAAI,EAAE,eAAe;YACrB,GAAG,EAAE,GAAG,GAAG,CAAC,aAAa,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,aAAa,EAAE;YAClF,KAAK,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG;YACvD,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE;SAC7B,CAAC,CAAA;IACJ,CAAC;CACF"}
@@ -0,0 +1,36 @@
1
+ export type paths = Record<string, never>;
2
+ export type webhooks = Record<string, never>;
3
+ export interface components {
4
+ schemas: {
5
+ TimestampOutputSettings: {
6
+ id: string;
7
+ displayName: string;
8
+ };
9
+ TimestampCollection: {
10
+ key: string;
11
+ timestamps: {
12
+ ts: number;
13
+ wall: number;
14
+ }[];
15
+ startTimestamp: number;
16
+ startTimeMs: number;
17
+ };
18
+ TimestampOutputState: {
19
+ timestamps: components["schemas"]["TimestampCollection"][];
20
+ };
21
+ TimestampOutputEvent: {
22
+ type: "new-timestamp";
23
+ key: string;
24
+ value: number;
25
+ wallMs: number;
26
+ };
27
+ TimestampOutputCommand: Record<string, never>;
28
+ };
29
+ responses: never;
30
+ parameters: never;
31
+ requestBodies: never;
32
+ headers: never;
33
+ pathItems: never;
34
+ }
35
+ export type $defs = Record<string, never>;
36
+ export type operations = Record<string, never>;
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/util.timestamps/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,74 @@
1
+ openapi: 3.0.0
2
+ info:
3
+ title: Timestamp Output
4
+ version: 1.0.0
5
+
6
+ components:
7
+ schemas:
8
+ TimestampOutputSettings:
9
+ type: object
10
+ properties:
11
+ id:
12
+ type: string
13
+ displayName:
14
+ type: string
15
+ required:
16
+ - id
17
+ - displayName
18
+
19
+ TimestampCollection:
20
+ type: object
21
+ properties:
22
+ key:
23
+ type: string
24
+ timestamps:
25
+ type: array
26
+ items:
27
+ type: object
28
+ properties:
29
+ ts:
30
+ type: number
31
+ wall:
32
+ type: number
33
+ required:
34
+ - ts
35
+ - wall
36
+ startTimestamp:
37
+ type: number
38
+ startTimeMs:
39
+ type: number
40
+ required:
41
+ - key
42
+ - timestamps
43
+ - startTimestamp
44
+ - startTimeMs
45
+
46
+ TimestampOutputState:
47
+ type: object
48
+ properties:
49
+ timestamps:
50
+ type: array
51
+ items:
52
+ $ref: '#/components/schemas/TimestampCollection'
53
+ required:
54
+ - timestamps
55
+
56
+ TimestampOutputEvent:
57
+ type: object
58
+ properties:
59
+ type:
60
+ const: 'new-timestamp'
61
+ key:
62
+ type: string
63
+ value:
64
+ type: number
65
+ wallMs:
66
+ type: number
67
+ required:
68
+ - type
69
+ - key
70
+ - value
71
+ - wallMs
72
+
73
+ TimestampOutputCommand:
74
+ type: object
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@norskvideo/norsk-studio-alpha",
3
+ "version": "1.27.0-2025-07-09-0fcad3ea",
4
+ "description": "",
5
+ "scripts": {
6
+ "clean": "rm -rf lib client build && make clean",
7
+ "types": "make -j 8",
8
+ "build": "npm run build-impl || true",
9
+ "build-impl": "npm run types && npx studio-wrap-infos src/ && npx npm-run-all build:* && rm -rf build",
10
+ "build:server": "npx tsc",
11
+ "build:client": "npx tsc -p tsconfig-client.json && npx studio-bundle build/info.js client/info.js",
12
+ "build:copy-css": "rsync --mkpath -v -r --include '*/' --include '*.css' --exclude '*' src/ client/",
13
+ "build:types": "rsync --mkpath -v -r --include '*/' --include '*.yaml' --exclude '*' src/ lib/",
14
+ "build:tailwind": "npx tailwindcss -i src/shared/tailwind.css -o client/style.css",
15
+ "build:eslint": "npx eslint src",
16
+ "test": "LOG_LEVEL=error mocha --no-parallel --jobs=0 --timeout 120000 --recursive lib/test"
17
+ },
18
+ "files": [
19
+ "client/*",
20
+ "lib/*",
21
+ "shared/*"
22
+ ],
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "@apidevtools/json-schema-ref-parser": "^12.0.1",
26
+ "@norskvideo/norsk-sdk": "^1.0.402-2025-07-09-3593ca7e",
27
+ "@norskvideo/norsk-studio": "1.27.0-2025-07-09-0fcad3ea",
28
+ "@norskvideo/norsk-studio-built-ins": "1.27.0-2025-07-09-0fcad3ea",
29
+ "json-refs": "^3.0.15",
30
+ "JSX": "^1.1.0",
31
+ "node-fetch": "^2.7.0",
32
+ "openapi-types": "^12.1.3",
33
+ "react": "^18.3.0",
34
+ "react-dom": "^18.3.1",
35
+ "react-select": "^5.7.0"
36
+ },
37
+ "main": "lib/index.js",
38
+ "devDependencies": {
39
+ "@types/chai": "^4.3.11",
40
+ "@types/mocha": "^10.0.6",
41
+ "@types/node-fetch": "^2.6.9",
42
+ "@types/react": "^18.2.33",
43
+ "@types/react-dom": "^18.2.14",
44
+ "@typescript-eslint/eslint-plugin": "^6.19.0",
45
+ "@typescript-eslint/parser": "^6.9.1",
46
+ "chai": "^4.3.10",
47
+ "esbuild": "^0.20.2",
48
+ "esbuild-plugin-external-global": "^1.0.1",
49
+ "eslint": "^8.53.0",
50
+ "hls-parser": "^0.10.8",
51
+ "mocha": "^10.4.0",
52
+ "npm-run-all": "^4.1.5",
53
+ "puppeteer": "^21.5.2",
54
+ "tailwindcss": "^3.4.1",
55
+ "typescript": "^5.4.5"
56
+ }
57
+ }