@moq/publish 0.1.1 → 0.2.1

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/broadcast.d.ts CHANGED
@@ -9,7 +9,7 @@ import * as Video from "./video";
9
9
  export type BroadcastProps = {
10
10
  connection?: Moq.Connection.Established | Signal<Moq.Connection.Established | undefined>;
11
11
  enabled?: boolean | Signal<boolean>;
12
- path?: Moq.Path.Valid | Signal<Moq.Path.Valid | undefined>;
12
+ name?: Moq.Path.Valid | Signal<Moq.Path.Valid | undefined>;
13
13
  audio?: Audio.EncoderProps;
14
14
  video?: Video.Props;
15
15
  location?: Location.Props;
@@ -22,7 +22,7 @@ export declare class Broadcast {
22
22
  static readonly CATALOG_TRACK = "catalog.json";
23
23
  connection: Signal<Moq.Connection.Established | undefined>;
24
24
  enabled: Signal<boolean>;
25
- path: Signal<Moq.Path.Valid | undefined>;
25
+ name: Signal<Moq.Path.Valid | undefined>;
26
26
  audio: Audio.Encoder;
27
27
  video: Video.Root;
28
28
  location: Location.Root;
package/element.d.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  import * as Moq from "@moq/lite";
2
2
  import { Broadcast } from "./broadcast";
3
3
  import * as Source from "./source";
4
- declare const OBSERVED: readonly ["url", "name", "path", "muted", "invisible", "source"];
4
+ declare const OBSERVED: readonly ["url", "name", "muted", "invisible", "source"];
5
5
  type Observed = (typeof OBSERVED)[number];
6
6
  type SourceType = "camera" | "screen" | "file";
7
7
  export default class MoqPublish extends HTMLElement {
8
8
  #private;
9
- static observedAttributes: readonly ["url", "name", "path", "muted", "invisible", "source"];
10
- url: Moq.Signals.Signal<URL | undefined>;
11
- path: Moq.Signals.Signal<Moq.Path.Valid | undefined>;
12
- source: Moq.Signals.Signal<File | SourceType | undefined>;
13
- muted: Moq.Signals.Signal<boolean>;
14
- invisible: Moq.Signals.Signal<boolean>;
9
+ static observedAttributes: readonly ["url", "name", "muted", "invisible", "source"];
10
+ state: {
11
+ source: Moq.Signals.Signal<File | SourceType | undefined>;
12
+ muted: Moq.Signals.Signal<boolean>;
13
+ invisible: Moq.Signals.Signal<boolean>;
14
+ };
15
15
  connection: Moq.Connection.Reload;
16
16
  broadcast: Broadcast;
17
17
  video: Moq.Signals.Signal<Source.Camera | Source.Screen | undefined>;
@@ -22,6 +22,16 @@ export default class MoqPublish extends HTMLElement {
22
22
  connectedCallback(): void;
23
23
  disconnectedCallback(): void;
24
24
  attributeChangedCallback(name: Observed, oldValue: string | null, newValue: string | null): void;
25
+ get url(): URL | undefined;
26
+ set url(value: string | URL | undefined);
27
+ get name(): Moq.Path.Valid | undefined;
28
+ set name(value: string | Moq.Path.Valid | undefined);
29
+ get source(): SourceType | File | undefined;
30
+ set source(value: SourceType | File | undefined);
31
+ get muted(): boolean;
32
+ set muted(value: boolean);
33
+ get invisible(): boolean;
34
+ set invisible(value: boolean);
25
35
  }
26
36
  declare global {
27
37
  interface HTMLElementTagNameMap {
package/element.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AAGnC,QAAA,MAAM,QAAQ,kEAAmE,CAAC;AAClF,KAAK,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1C,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAO/C,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;;IAClD,MAAM,CAAC,kBAAkB,mEAAY;IAErC,GAAG,sCAA0C;IAC7C,IAAI,iDAAqD;IACzD,MAAM,oDAAwD;IAG9D,KAAK,8BAAqB;IAC1B,SAAS,8BAAqB;IAE9B,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;IAClC,SAAS,EAAE,SAAS,CAAC;IAIrB,KAAK,gEAAoE;IACzE,KAAK,oEAAwE;IAC7E,IAAI,8CAAkD;IAUtD,OAAO,qBAAgB;;IAyEvB,iBAAiB;IAIjB,oBAAoB;IAIpB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;CAkGzF;AAID,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
1
+ {"version":3,"file":"element.d.ts","sourceRoot":"","sources":["../src/element.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,GAAG,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,UAAU,CAAC;AAEnC,QAAA,MAAM,QAAQ,0DAA2D,CAAC;AAC1E,KAAK,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1C,KAAK,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAO/C,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;;IAClD,MAAM,CAAC,kBAAkB,2DAAY;IAIrC,KAAK;;;;MAIH;IAEF,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;IAClC,SAAS,EAAE,SAAS,CAAC;IAIrB,KAAK,gEAAoE;IACzE,KAAK,oEAAwE;IAC7E,IAAI,8CAAkD;IAUtD,OAAO,qBAAgB;;IAuEvB,iBAAiB;IAIjB,oBAAoB;IAIpB,wBAAwB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAmGzF,IAAI,GAAG,IAAI,GAAG,GAAG,SAAS,CAEzB;IAED,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,EAEtC;IAED,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAErC;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,EAElD;IAED,IAAI,MAAM,IAAI,UAAU,GAAG,IAAI,GAAG,SAAS,CAE1C;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,EAE9C;IAED,IAAI,KAAK,IAAI,OAAO,CAEnB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,OAAO,EAEvB;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,EAE3B;CACD;AAID,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,aAAa,EAAE,UAAU,CAAC;KAC1B;CACD"}
package/element.js CHANGED
@@ -1,141 +1,170 @@
1
- import * as l from "@moq/lite";
2
- import { Signal as n, Effect as d } from "@moq/signals";
3
- import { B as u, C as h, M as b, S as v, F as g } from "./screen-Dz_GBTAe.js";
4
- const p = ["url", "name", "path", "muted", "invisible", "source"], w = new FinalizationRegistry((c) => c.close());
5
- class m extends HTMLElement {
6
- static observedAttributes = p;
7
- url = new n(void 0);
8
- path = new n(void 0);
9
- source = new n(void 0);
10
- // Controls whether audio/video is enabled.
11
- muted = new n(!1);
12
- invisible = new n(!1);
1
+ import * as c from "@moq/lite";
2
+ import { Signal as o, Effect as u } from "@moq/signals";
3
+ import { B as d, C as h, M as b, S as v, F as g } from "./screen-BORpmf_D.js";
4
+ const m = ["url", "name", "muted", "invisible", "source"], p = new FinalizationRegistry((l) => l.close());
5
+ class w extends HTMLElement {
6
+ static observedAttributes = m;
7
+ // Reactive state for element properties that are also HTML attributes.
8
+ // Access these Signals directly for reactive subscriptions (e.g. effect.get(el.state.source)).
9
+ state = {
10
+ source: new o(void 0),
11
+ muted: new o(!1),
12
+ invisible: new o(!1)
13
+ };
13
14
  connection;
14
15
  broadcast;
15
- #o = new n(void 0);
16
- video = new n(void 0);
17
- audio = new n(void 0);
18
- file = new n(void 0);
16
+ #n = new o(void 0);
17
+ video = new o(void 0);
18
+ audio = new o(void 0);
19
+ file = new o(void 0);
19
20
  // The inverse of the `muted` and `invisible` signals.
20
- #s;
21
21
  #e;
22
- #i;
22
+ #s;
23
+ #t;
23
24
  // Set when the element is connected to the DOM.
24
- #t = new n(!1);
25
- signals = new d();
25
+ #i = new o(!1);
26
+ signals = new u();
26
27
  constructor() {
27
- super(), w.register(this, this.signals), this.connection = new l.Connection.Reload({
28
- url: this.url,
29
- enabled: this.#t
30
- }), this.signals.cleanup(() => this.connection.close()), this.#s = new n(!1), this.#e = new n(!1), this.#i = new n(!1), this.signals.run((s) => {
31
- const e = s.get(this.muted), t = s.get(this.invisible);
32
- this.#s.set(!t), this.#e.set(!e), this.#i.set(!e || !t);
33
- }), this.broadcast = new u({
28
+ super(), p.register(this, this.signals), this.connection = new c.Connection.Reload({
29
+ enabled: this.#i
30
+ }), this.signals.cleanup(() => this.connection.close()), this.#e = new o(!1), this.#s = new o(!1), this.#t = new o(!1), this.signals.run((s) => {
31
+ const t = s.get(this.state.muted), i = s.get(this.state.invisible);
32
+ this.#e.set(!i), this.#s.set(!t), this.#t.set(!t || !i);
33
+ }), this.broadcast = new d({
34
34
  connection: this.connection.established,
35
- enabled: this.#t,
36
- path: this.path,
35
+ enabled: this.#i,
37
36
  audio: {
38
- enabled: this.#e
37
+ enabled: this.#s
39
38
  },
40
39
  video: {
41
40
  hd: {
42
- enabled: this.#s
41
+ enabled: this.#e
43
42
  }
44
43
  }
45
44
  }), this.signals.cleanup(() => this.broadcast.close());
46
- const i = () => {
47
- this.#o.set(this.querySelector("video"));
48
- }, o = new MutationObserver(i);
49
- o.observe(this, { childList: !0, subtree: !0 }), this.signals.cleanup(() => o.disconnect()), i(), this.signals.run((s) => {
50
- const e = s.get(this.#o);
51
- if (!e) return;
52
- const t = s.get(this.broadcast.video.source);
53
- if (!t) {
54
- e.style.display = "none";
45
+ const e = () => {
46
+ this.#n.set(this.querySelector("video"));
47
+ }, n = new MutationObserver(e);
48
+ n.observe(this, { childList: !0, subtree: !0 }), this.signals.cleanup(() => n.disconnect()), e(), this.signals.run((s) => {
49
+ const t = s.get(this.#n);
50
+ if (!t) return;
51
+ const i = s.get(this.broadcast.video.source);
52
+ if (!i) {
53
+ t.style.display = "none";
55
54
  return;
56
55
  }
57
- e.srcObject = new MediaStream([t]), e.style.display = "block", s.cleanup(() => {
58
- e.srcObject = null;
56
+ t.srcObject = new MediaStream([i]), t.style.display = "block", s.cleanup(() => {
57
+ t.srcObject = null;
59
58
  });
60
- }), this.signals.run(this.#n.bind(this));
59
+ }), this.signals.run(this.#o.bind(this));
61
60
  }
62
61
  connectedCallback() {
63
- this.#t.set(!0);
62
+ this.#i.set(!0);
64
63
  }
65
64
  disconnectedCallback() {
66
- this.#t.set(!1);
65
+ this.#i.set(!1);
67
66
  }
68
- attributeChangedCallback(i, o, s) {
69
- if (o !== s)
70
- if (i === "url")
71
- this.url.set(s ? new URL(s) : void 0);
72
- else if (i === "name" || i === "path")
73
- this.path.set(s ? l.Path.from(s) : void 0);
74
- else if (i === "source")
67
+ attributeChangedCallback(e, n, s) {
68
+ if (n !== s)
69
+ if (e === "url")
70
+ this.connection.url.set(s ? new URL(s) : void 0);
71
+ else if (e === "name")
72
+ this.broadcast.name.set(s ? c.Path.from(s) : void 0);
73
+ else if (e === "source")
75
74
  if (s === "camera" || s === "screen" || s === "file" || s === null)
76
- this.source.set(s);
75
+ this.state.source.set(s);
77
76
  else
78
77
  throw new Error(`Invalid source: ${s}`);
79
- else if (i === "muted")
80
- this.muted.set(s !== null);
81
- else if (i === "invisible")
82
- this.invisible.set(s !== null);
78
+ else if (e === "muted")
79
+ this.state.muted.set(s !== null);
80
+ else if (e === "invisible")
81
+ this.state.invisible.set(s !== null);
83
82
  else {
84
- const e = i;
85
- throw new Error(`Invalid attribute: ${e}`);
83
+ const t = e;
84
+ throw new Error(`Invalid attribute: ${t}`);
86
85
  }
87
86
  }
88
- #n(i) {
89
- const o = i.get(this.source);
90
- if (!o) return;
91
- if (o === "camera") {
92
- const e = new h({ enabled: this.#s });
87
+ #o(e) {
88
+ const n = e.get(this.state.source);
89
+ if (!n) return;
90
+ if (n === "camera") {
91
+ const t = new h({ enabled: this.#e });
93
92
  this.signals.run((r) => {
94
- const a = r.get(e.source);
93
+ const a = r.get(t.source);
95
94
  this.broadcast.video.source.set(a);
96
95
  });
97
- const t = new b({ enabled: this.#e });
96
+ const i = new b({ enabled: this.#s });
98
97
  this.signals.run((r) => {
99
- const a = r.get(t.source);
98
+ const a = r.get(i.source);
100
99
  this.broadcast.audio.source.set(a);
101
- }), i.set(this.video, e), i.set(this.audio, t), i.cleanup(() => {
102
- e.close(), t.close();
100
+ }), e.set(this.video, t), e.set(this.audio, i), e.cleanup(() => {
101
+ t.close(), i.close();
103
102
  });
104
103
  return;
105
104
  }
106
- if (o === "screen") {
107
- const e = new v({
108
- enabled: this.#i
105
+ if (n === "screen") {
106
+ const t = new v({
107
+ enabled: this.#t
109
108
  });
110
- this.signals.run((t) => {
111
- const r = t.get(e.source);
112
- r && (t.set(this.broadcast.video.source, r.video), t.set(this.broadcast.audio.source, r.audio));
113
- }), i.set(this.video, e), i.set(this.audio, e), i.cleanup(() => {
114
- e.close();
109
+ this.signals.run((i) => {
110
+ const r = i.get(t.source);
111
+ r && (i.set(this.broadcast.video.source, r.video), i.set(this.broadcast.audio.source, r.audio));
112
+ }), e.set(this.video, t), e.set(this.audio, t), e.cleanup(() => {
113
+ t.close();
115
114
  });
116
115
  return;
117
116
  }
118
- if (o === "file" || o instanceof File) {
119
- const e = new g({
117
+ if (n === "file" || n instanceof File) {
118
+ const t = new g({
120
119
  // If a File is provided, use it directly.
121
120
  // TODO: Show a file picker otherwise.
122
- file: o instanceof File ? o : void 0,
123
- enabled: this.#i
121
+ file: n instanceof File ? n : void 0,
122
+ enabled: this.#t
124
123
  });
125
- this.signals.run((t) => {
126
- const r = t.get(e.source);
124
+ this.signals.run((i) => {
125
+ const r = i.get(t.source);
127
126
  this.broadcast.video.source.set(r.video), this.broadcast.audio.source.set(r.audio);
128
- }), i.cleanup(() => {
129
- e.close();
127
+ }), e.cleanup(() => {
128
+ t.close();
130
129
  });
131
130
  return;
132
131
  }
133
- const s = o;
132
+ const s = n;
134
133
  throw new Error(`Invalid source: ${s}`);
135
134
  }
135
+ get url() {
136
+ return this.connection.url.peek();
137
+ }
138
+ set url(e) {
139
+ this.connection.url.set(e ? new URL(e) : void 0);
140
+ }
141
+ get name() {
142
+ return this.broadcast.name.peek();
143
+ }
144
+ set name(e) {
145
+ this.broadcast.name.set(e ? c.Path.from(e) : void 0);
146
+ }
147
+ get source() {
148
+ return this.state.source.peek();
149
+ }
150
+ set source(e) {
151
+ this.state.source.set(e);
152
+ }
153
+ get muted() {
154
+ return this.state.muted.peek();
155
+ }
156
+ set muted(e) {
157
+ this.state.muted.set(e);
158
+ }
159
+ get invisible() {
160
+ return this.state.invisible.peek();
161
+ }
162
+ set invisible(e) {
163
+ this.state.invisible.set(e);
164
+ }
136
165
  }
137
- customElements.define("moq-publish", m);
166
+ customElements.define("moq-publish", w);
138
167
  export {
139
- m as default
168
+ w as default
140
169
  };
141
170
  //# sourceMappingURL=element.js.map
package/element.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"element.js","sources":["../src/element.ts"],"sourcesContent":["import * as Moq from \"@moq/lite\";\nimport { Effect, Signal } from \"@moq/signals\";\nimport { Broadcast } from \"./broadcast\";\nimport * as Source from \"./source\";\n\n// TODO remove name; replaced with path\nconst OBSERVED = [\"url\", \"name\", \"path\", \"muted\", \"invisible\", \"source\"] as const;\ntype Observed = (typeof OBSERVED)[number];\n\ntype SourceType = \"camera\" | \"screen\" | \"file\";\n\n// Close everything when this element is garbage collected.\n// This is primarily to avoid a console.warn that we didn't close() before GC.\n// There's no destructor for web components so this is the best we can do.\nconst cleanup = new FinalizationRegistry<Effect>((signals) => signals.close());\n\nexport default class MoqPublish extends HTMLElement {\n\tstatic observedAttributes = OBSERVED;\n\n\turl = new Signal<URL | undefined>(undefined);\n\tpath = new Signal<Moq.Path.Valid | undefined>(undefined);\n\tsource = new Signal<SourceType | File | undefined>(undefined);\n\n\t// Controls whether audio/video is enabled.\n\tmuted = new Signal(false);\n\tinvisible = new Signal(false);\n\n\tconnection: Moq.Connection.Reload;\n\tbroadcast: Broadcast;\n\n\t#preview = new Signal<HTMLVideoElement | undefined>(undefined);\n\n\tvideo = new Signal<Source.Camera | Source.Screen | undefined>(undefined);\n\taudio = new Signal<Source.Microphone | Source.Screen | undefined>(undefined);\n\tfile = new Signal<Source.File | undefined>(undefined);\n\n\t// The inverse of the `muted` and `invisible` signals.\n\t#videoEnabled: Signal<boolean>;\n\t#audioEnabled: Signal<boolean>;\n\t#eitherEnabled: Signal<boolean>;\n\n\t// Set when the element is connected to the DOM.\n\t#enabled = new Signal(false);\n\n\tsignals = new Effect();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tcleanup.register(this, this.signals);\n\n\t\tthis.connection = new Moq.Connection.Reload({\n\t\t\turl: this.url,\n\t\t\tenabled: this.#enabled,\n\t\t});\n\t\tthis.signals.cleanup(() => this.connection.close());\n\n\t\t// The inverse of the `muted` and `invisible` signals.\n\t\t// TODO make this.signals.computed to simplify the code.\n\t\tthis.#videoEnabled = new Signal(false);\n\t\tthis.#audioEnabled = new Signal(false);\n\t\tthis.#eitherEnabled = new Signal(false);\n\n\t\tthis.signals.run((effect) => {\n\t\t\tconst muted = effect.get(this.muted);\n\t\t\tconst invisible = effect.get(this.invisible);\n\t\t\tthis.#videoEnabled.set(!invisible);\n\t\t\tthis.#audioEnabled.set(!muted);\n\t\t\tthis.#eitherEnabled.set(!muted || !invisible);\n\t\t});\n\n\t\tthis.broadcast = new Broadcast({\n\t\t\tconnection: this.connection.established,\n\t\t\tenabled: this.#enabled,\n\t\t\tpath: this.path,\n\n\t\t\taudio: {\n\t\t\t\tenabled: this.#audioEnabled,\n\t\t\t},\n\t\t\tvideo: {\n\t\t\t\thd: {\n\t\t\t\t\tenabled: this.#videoEnabled,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t\tthis.signals.cleanup(() => this.broadcast.close());\n\n\t\t// Watch to see if the preview element is added or removed.\n\t\tconst setPreview = () => {\n\t\t\tthis.#preview.set(this.querySelector(\"video\") as HTMLVideoElement | undefined);\n\t\t};\n\t\tconst observer = new MutationObserver(setPreview);\n\t\tobserver.observe(this, { childList: true, subtree: true });\n\t\tthis.signals.cleanup(() => observer.disconnect());\n\t\tsetPreview();\n\n\t\tthis.signals.run((effect) => {\n\t\t\tconst preview = effect.get(this.#preview);\n\t\t\tif (!preview) return;\n\n\t\t\tconst source = effect.get(this.broadcast.video.source);\n\t\t\tif (!source) {\n\t\t\t\tpreview.style.display = \"none\";\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpreview.srcObject = new MediaStream([source]);\n\t\t\tpreview.style.display = \"block\";\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tpreview.srcObject = null;\n\t\t\t});\n\t\t});\n\n\t\tthis.signals.run(this.#runSource.bind(this));\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#enabled.set(true);\n\t}\n\n\tdisconnectedCallback() {\n\t\tthis.#enabled.set(false);\n\t}\n\n\tattributeChangedCallback(name: Observed, oldValue: string | null, newValue: string | null) {\n\t\tif (oldValue === newValue) return;\n\n\t\tif (name === \"url\") {\n\t\t\tthis.url.set(newValue ? new URL(newValue) : undefined);\n\t\t} else if (name === \"name\" || name === \"path\") {\n\t\t\tthis.path.set(newValue ? Moq.Path.from(newValue) : undefined);\n\t\t} else if (name === \"source\") {\n\t\t\tif (newValue === \"camera\" || newValue === \"screen\" || newValue === \"file\" || newValue === null) {\n\t\t\t\tthis.source.set(newValue as SourceType | undefined);\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Invalid source: ${newValue}`);\n\t\t\t}\n\t\t} else if (name === \"muted\") {\n\t\t\tthis.muted.set(newValue !== null);\n\t\t} else if (name === \"invisible\") {\n\t\t\tthis.invisible.set(newValue !== null);\n\t\t} else {\n\t\t\tconst exhaustive: never = name;\n\t\t\tthrow new Error(`Invalid attribute: ${exhaustive}`);\n\t\t}\n\t}\n\n\t#runSource(effect: Effect) {\n\t\tconst source = effect.get(this.source);\n\t\tif (!source) return;\n\n\t\tif (source === \"camera\") {\n\t\t\tconst video = new Source.Camera({ enabled: this.#videoEnabled });\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(video.source);\n\t\t\t\tthis.broadcast.video.source.set(source);\n\t\t\t});\n\n\t\t\tconst audio = new Source.Microphone({ enabled: this.#audioEnabled });\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(audio.source);\n\t\t\t\tthis.broadcast.audio.source.set(source);\n\t\t\t});\n\n\t\t\teffect.set(this.video, video);\n\t\t\teffect.set(this.audio, audio);\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tvideo.close();\n\t\t\t\taudio.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (source === \"screen\") {\n\t\t\tconst screen = new Source.Screen({\n\t\t\t\tenabled: this.#eitherEnabled,\n\t\t\t});\n\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(screen.source);\n\t\t\t\tif (!source) return;\n\n\t\t\t\teffect.set(this.broadcast.video.source, source.video);\n\t\t\t\teffect.set(this.broadcast.audio.source, source.audio);\n\t\t\t});\n\n\t\t\teffect.set(this.video, screen);\n\t\t\teffect.set(this.audio, screen);\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tscreen.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (source === \"file\" || source instanceof File) {\n\t\t\tconst fileSource = new Source.File({\n\t\t\t\t// If a File is provided, use it directly.\n\t\t\t\t// TODO: Show a file picker otherwise.\n\t\t\t\tfile: source instanceof File ? source : undefined,\n\t\t\t\tenabled: this.#eitherEnabled,\n\t\t\t});\n\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(fileSource.source);\n\t\t\t\tthis.broadcast.video.source.set(source.video);\n\t\t\t\tthis.broadcast.audio.source.set(source.audio);\n\t\t\t});\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tfileSource.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst exhaustive: never = source;\n\t\tthrow new Error(`Invalid source: ${exhaustive}`);\n\t}\n}\n\ncustomElements.define(\"moq-publish\", MoqPublish);\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t\"moq-publish\": MoqPublish;\n\t}\n}\n"],"names":["OBSERVED","cleanup","signals","MoqPublish","Signal","#preview","#videoEnabled","#audioEnabled","#eitherEnabled","#enabled","Effect","Moq","effect","muted","invisible","Broadcast","setPreview","observer","preview","source","#runSource","name","oldValue","newValue","exhaustive","video","Source.Camera","audio","Source.Microphone","screen","Source.Screen","fileSource","Source.File"],"mappings":"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"}
1
+ {"version":3,"file":"element.js","sources":["../src/element.ts"],"sourcesContent":["import * as Moq from \"@moq/lite\";\nimport { Effect, Signal } from \"@moq/signals\";\nimport { Broadcast } from \"./broadcast\";\nimport * as Source from \"./source\";\n\nconst OBSERVED = [\"url\", \"name\", \"muted\", \"invisible\", \"source\"] as const;\ntype Observed = (typeof OBSERVED)[number];\n\ntype SourceType = \"camera\" | \"screen\" | \"file\";\n\n// Close everything when this element is garbage collected.\n// This is primarily to avoid a console.warn that we didn't close() before GC.\n// There's no destructor for web components so this is the best we can do.\nconst cleanup = new FinalizationRegistry<Effect>((signals) => signals.close());\n\nexport default class MoqPublish extends HTMLElement {\n\tstatic observedAttributes = OBSERVED;\n\n\t// Reactive state for element properties that are also HTML attributes.\n\t// Access these Signals directly for reactive subscriptions (e.g. effect.get(el.state.source)).\n\tstate = {\n\t\tsource: new Signal<SourceType | File | undefined>(undefined),\n\t\tmuted: new Signal(false),\n\t\tinvisible: new Signal(false),\n\t};\n\n\tconnection: Moq.Connection.Reload;\n\tbroadcast: Broadcast;\n\n\t#preview = new Signal<HTMLVideoElement | undefined>(undefined);\n\n\tvideo = new Signal<Source.Camera | Source.Screen | undefined>(undefined);\n\taudio = new Signal<Source.Microphone | Source.Screen | undefined>(undefined);\n\tfile = new Signal<Source.File | undefined>(undefined);\n\n\t// The inverse of the `muted` and `invisible` signals.\n\t#videoEnabled: Signal<boolean>;\n\t#audioEnabled: Signal<boolean>;\n\t#eitherEnabled: Signal<boolean>;\n\n\t// Set when the element is connected to the DOM.\n\t#enabled = new Signal(false);\n\n\tsignals = new Effect();\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tcleanup.register(this, this.signals);\n\n\t\tthis.connection = new Moq.Connection.Reload({\n\t\t\tenabled: this.#enabled,\n\t\t});\n\t\tthis.signals.cleanup(() => this.connection.close());\n\n\t\t// The inverse of the `muted` and `invisible` signals.\n\t\t// TODO make this.signals.computed to simplify the code.\n\t\tthis.#videoEnabled = new Signal(false);\n\t\tthis.#audioEnabled = new Signal(false);\n\t\tthis.#eitherEnabled = new Signal(false);\n\n\t\tthis.signals.run((effect) => {\n\t\t\tconst muted = effect.get(this.state.muted);\n\t\t\tconst invisible = effect.get(this.state.invisible);\n\t\t\tthis.#videoEnabled.set(!invisible);\n\t\t\tthis.#audioEnabled.set(!muted);\n\t\t\tthis.#eitherEnabled.set(!muted || !invisible);\n\t\t});\n\n\t\tthis.broadcast = new Broadcast({\n\t\t\tconnection: this.connection.established,\n\t\t\tenabled: this.#enabled,\n\n\t\t\taudio: {\n\t\t\t\tenabled: this.#audioEnabled,\n\t\t\t},\n\t\t\tvideo: {\n\t\t\t\thd: {\n\t\t\t\t\tenabled: this.#videoEnabled,\n\t\t\t\t},\n\t\t\t},\n\t\t});\n\t\tthis.signals.cleanup(() => this.broadcast.close());\n\n\t\t// Watch to see if the preview element is added or removed.\n\t\tconst setPreview = () => {\n\t\t\tthis.#preview.set(this.querySelector(\"video\") as HTMLVideoElement | undefined);\n\t\t};\n\t\tconst observer = new MutationObserver(setPreview);\n\t\tobserver.observe(this, { childList: true, subtree: true });\n\t\tthis.signals.cleanup(() => observer.disconnect());\n\t\tsetPreview();\n\n\t\tthis.signals.run((effect) => {\n\t\t\tconst preview = effect.get(this.#preview);\n\t\t\tif (!preview) return;\n\n\t\t\tconst source = effect.get(this.broadcast.video.source);\n\t\t\tif (!source) {\n\t\t\t\tpreview.style.display = \"none\";\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tpreview.srcObject = new MediaStream([source]);\n\t\t\tpreview.style.display = \"block\";\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tpreview.srcObject = null;\n\t\t\t});\n\t\t});\n\n\t\tthis.signals.run(this.#runSource.bind(this));\n\t}\n\n\tconnectedCallback() {\n\t\tthis.#enabled.set(true);\n\t}\n\n\tdisconnectedCallback() {\n\t\tthis.#enabled.set(false);\n\t}\n\n\tattributeChangedCallback(name: Observed, oldValue: string | null, newValue: string | null) {\n\t\tif (oldValue === newValue) return;\n\n\t\tif (name === \"url\") {\n\t\t\tthis.connection.url.set(newValue ? new URL(newValue) : undefined);\n\t\t} else if (name === \"name\") {\n\t\t\tthis.broadcast.name.set(newValue ? Moq.Path.from(newValue) : undefined);\n\t\t} else if (name === \"source\") {\n\t\t\tif (newValue === \"camera\" || newValue === \"screen\" || newValue === \"file\" || newValue === null) {\n\t\t\t\tthis.state.source.set(newValue as SourceType | undefined);\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Invalid source: ${newValue}`);\n\t\t\t}\n\t\t} else if (name === \"muted\") {\n\t\t\tthis.state.muted.set(newValue !== null);\n\t\t} else if (name === \"invisible\") {\n\t\t\tthis.state.invisible.set(newValue !== null);\n\t\t} else {\n\t\t\tconst exhaustive: never = name;\n\t\t\tthrow new Error(`Invalid attribute: ${exhaustive}`);\n\t\t}\n\t}\n\n\t#runSource(effect: Effect) {\n\t\tconst source = effect.get(this.state.source);\n\t\tif (!source) return;\n\n\t\tif (source === \"camera\") {\n\t\t\tconst video = new Source.Camera({ enabled: this.#videoEnabled });\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(video.source);\n\t\t\t\tthis.broadcast.video.source.set(source);\n\t\t\t});\n\n\t\t\tconst audio = new Source.Microphone({ enabled: this.#audioEnabled });\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(audio.source);\n\t\t\t\tthis.broadcast.audio.source.set(source);\n\t\t\t});\n\n\t\t\teffect.set(this.video, video);\n\t\t\teffect.set(this.audio, audio);\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tvideo.close();\n\t\t\t\taudio.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (source === \"screen\") {\n\t\t\tconst screen = new Source.Screen({\n\t\t\t\tenabled: this.#eitherEnabled,\n\t\t\t});\n\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(screen.source);\n\t\t\t\tif (!source) return;\n\n\t\t\t\teffect.set(this.broadcast.video.source, source.video);\n\t\t\t\teffect.set(this.broadcast.audio.source, source.audio);\n\t\t\t});\n\n\t\t\teffect.set(this.video, screen);\n\t\t\teffect.set(this.audio, screen);\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tscreen.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (source === \"file\" || source instanceof File) {\n\t\t\tconst fileSource = new Source.File({\n\t\t\t\t// If a File is provided, use it directly.\n\t\t\t\t// TODO: Show a file picker otherwise.\n\t\t\t\tfile: source instanceof File ? source : undefined,\n\t\t\t\tenabled: this.#eitherEnabled,\n\t\t\t});\n\n\t\t\tthis.signals.run((effect) => {\n\t\t\t\tconst source = effect.get(fileSource.source);\n\t\t\t\tthis.broadcast.video.source.set(source.video);\n\t\t\t\tthis.broadcast.audio.source.set(source.audio);\n\t\t\t});\n\n\t\t\teffect.cleanup(() => {\n\t\t\t\tfileSource.close();\n\t\t\t});\n\n\t\t\treturn;\n\t\t}\n\n\t\tconst exhaustive: never = source;\n\t\tthrow new Error(`Invalid source: ${exhaustive}`);\n\t}\n\n\tget url(): URL | undefined {\n\t\treturn this.connection.url.peek();\n\t}\n\n\tset url(value: string | URL | undefined) {\n\t\tthis.connection.url.set(value ? new URL(value) : undefined);\n\t}\n\n\tget name(): Moq.Path.Valid | undefined {\n\t\treturn this.broadcast.name.peek();\n\t}\n\n\tset name(value: string | Moq.Path.Valid | undefined) {\n\t\tthis.broadcast.name.set(value ? Moq.Path.from(value) : undefined);\n\t}\n\n\tget source(): SourceType | File | undefined {\n\t\treturn this.state.source.peek();\n\t}\n\n\tset source(value: SourceType | File | undefined) {\n\t\tthis.state.source.set(value);\n\t}\n\n\tget muted(): boolean {\n\t\treturn this.state.muted.peek();\n\t}\n\n\tset muted(value: boolean) {\n\t\tthis.state.muted.set(value);\n\t}\n\n\tget invisible(): boolean {\n\t\treturn this.state.invisible.peek();\n\t}\n\n\tset invisible(value: boolean) {\n\t\tthis.state.invisible.set(value);\n\t}\n}\n\ncustomElements.define(\"moq-publish\", MoqPublish);\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t\"moq-publish\": MoqPublish;\n\t}\n}\n"],"names":["OBSERVED","cleanup","signals","MoqPublish","Signal","#preview","#videoEnabled","#audioEnabled","#eitherEnabled","#enabled","Effect","Moq","effect","muted","invisible","Broadcast","setPreview","observer","preview","source","#runSource","name","oldValue","newValue","exhaustive","video","Source.Camera","audio","Source.Microphone","screen","Source.Screen","fileSource","Source.File","value"],"mappings":"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"}
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { E as e, C as o, D as a, F as r, M as t, S as s } from "./screen-Dz_GBTAe.js";
2
- import { B as u, i as p, a as _, P as b, u as S, b as f } from "./screen-Dz_GBTAe.js";
1
+ import { E as e, C as o, D as a, F as r, M as t, S as s } from "./screen-BORpmf_D.js";
2
+ import { B as u, i as p, a as _, P as b, u as S, b as f } from "./screen-BORpmf_D.js";
3
3
  const n = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
4
4
  __proto__: null,
5
5
  Encoder: e
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@moq/publish",
3
3
  "type": "module",
4
- "version": "0.1.1",
5
- "description": "Publish media to Media over QUIC streams",
4
+ "version": "0.2.1",
5
+ "description": "Publish Media over QUIC broadcasts",
6
6
  "license": "(MIT OR Apache-2.0)",
7
7
  "repository": "github:moq-dev/moq",
8
8
  "exports": {
@@ -34,7 +34,7 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@moq/hang": "^0.2.0",
37
- "@moq/lite": "^0.1.3",
37
+ "@moq/lite": "^0.1.4",
38
38
  "@moq/signals": "^0.1.3",
39
39
  "@moq/ui-core": "^0.1.0"
40
40
  }
@@ -3469,7 +3469,7 @@ var Effect = class _Effect {
3469
3469
  this.#scheduled = false;
3470
3470
  if (this.#fn) {
3471
3471
  this.#fn(this);
3472
- if (DEV && this.#unwatch.length === 0) {
3472
+ if (DEV && this.#dispose !== void 0 && this.#unwatch.length === 0 && this.#dispose.length === 0 && this.#async.length === 0) {
3473
3473
  console.warn("Effect did not subscribe to any signals; it will never rerun.", this.#stack);
3474
3474
  }
3475
3475
  }
@@ -3629,10 +3629,6 @@ var Effect = class _Effect {
3629
3629
  target.addEventListener(type, listener, options);
3630
3630
  this.cleanup(() => target.removeEventListener(type, listener, options));
3631
3631
  }
3632
- // Reschedule the effect to run again.
3633
- reload() {
3634
- this.#schedule();
3635
- }
3636
3632
  // Register a cleanup function.
3637
3633
  cleanup(fn) {
3638
3634
  if (this.#dispose === void 0) {
@@ -4047,6 +4043,11 @@ function setInt32(dst, v) {
4047
4043
  return new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
4048
4044
  }
4049
4045
 
4046
+ // ../lite/src/util/error.ts
4047
+ function unreachable(value) {
4048
+ throw new Error(\`unreachable: \${value}\`);
4049
+ }
4050
+
4050
4051
  // ../../node_modules/.bun/async-mutex@0.5.0/node_modules/async-mutex/index.mjs
4051
4052
  var E_TIMEOUT = new Error("timeout while waiting for mutex to become available");
4052
4053
  var E_ALREADY_LOCKED = new Error("mutex already locked");
@@ -4590,8 +4591,7 @@ var Publish = class _Publish {
4590
4591
  await w.bool(this.forward);
4591
4592
  await w.u53(0);
4592
4593
  } else {
4593
- const _ = version;
4594
- throw new Error(\`unsupported version: \${_}\`);
4594
+ unreachable(version);
4595
4595
  }
4596
4596
  }
4597
4597
  async encode(w, version) {
@@ -4637,8 +4637,7 @@ var Publish = class _Publish {
4637
4637
  forward
4638
4638
  });
4639
4639
  } else {
4640
- const _ = version;
4641
- throw new Error(\`unsupported version: \${_}\`);
4640
+ unreachable(version);
4642
4641
  }
4643
4642
  }
4644
4643
  };
@@ -5010,8 +5009,7 @@ var ClientSetup = class _ClientSetup {
5010
5009
  }
5011
5010
  await this.parameters.encode(w, version);
5012
5011
  } else {
5013
- const _ = version;
5014
- throw new Error(\`unsupported version: \${_}\`);
5012
+ unreachable(version);
5015
5013
  }
5016
5014
  }
5017
5015
  async encode(w, version) {
@@ -5034,8 +5032,7 @@ var ClientSetup = class _ClientSetup {
5034
5032
  const parameters = await Parameters.decode(r, version);
5035
5033
  return new _ClientSetup({ versions: supportedVersions, parameters });
5036
5034
  } else {
5037
- const _ = version;
5038
- throw new Error(\`unsupported version: \${_}\`);
5035
+ unreachable(version);
5039
5036
  }
5040
5037
  }
5041
5038
  static async decode(r, version) {
@@ -5057,8 +5054,7 @@ var ServerSetup = class _ServerSetup {
5057
5054
  await w.u53(this.version);
5058
5055
  await this.parameters.encode(w, version);
5059
5056
  } else {
5060
- const _ = version;
5061
- throw new Error(\`unsupported version: \${_}\`);
5057
+ unreachable(version);
5062
5058
  }
5063
5059
  }
5064
5060
  async encode(w, version) {
@@ -5073,8 +5069,7 @@ var ServerSetup = class _ServerSetup {
5073
5069
  const parameters = await Parameters.decode(r, version);
5074
5070
  return new _ServerSetup({ version: selectedVersion, parameters });
5075
5071
  } else {
5076
- const _ = version;
5077
- throw new Error(\`unsupported version: \${_}\`);
5072
+ unreachable(version);
5078
5073
  }
5079
5074
  }
5080
5075
  static async decode(r, version) {
@@ -5119,8 +5114,7 @@ var Subscribe = class _Subscribe {
5119
5114
  await w.u53(2);
5120
5115
  await w.u53(0);
5121
5116
  } else {
5122
- const _ = version;
5123
- throw new Error(\`unsupported version: \${_}\`);
5117
+ unreachable(version);
5124
5118
  }
5125
5119
  }
5126
5120
  async encode(w, version) {
@@ -5172,8 +5166,7 @@ var Subscribe = class _Subscribe {
5172
5166
  await Parameters.decode(r, version);
5173
5167
  return new _Subscribe({ requestId, trackNamespace, trackName, subscriberPriority });
5174
5168
  } else {
5175
- const _ = version;
5176
- throw new Error(\`unsupported version: \${_}\`);
5169
+ unreachable(version);
5177
5170
  }
5178
5171
  }
5179
5172
  };
@@ -5198,8 +5191,7 @@ var SubscribeOk = class _SubscribeOk {
5198
5191
  await w.bool(false);
5199
5192
  await w.u53(0);
5200
5193
  } else {
5201
- const _ = version;
5202
- throw new Error(\`unsupported version: \${_}\`);
5194
+ unreachable(version);
5203
5195
  }
5204
5196
  }
5205
5197
  async encode(w, version) {
@@ -5226,8 +5218,7 @@ var SubscribeOk = class _SubscribeOk {
5226
5218
  }
5227
5219
  await Parameters.decode(r, version);
5228
5220
  } else {
5229
- const _ = version;
5230
- throw new Error(\`unsupported version: \${_}\`);
5221
+ unreachable(version);
5231
5222
  }
5232
5223
  return new _SubscribeOk({ requestId, trackAlias });
5233
5224
  }
@@ -6035,7 +6026,7 @@ class Pe {
6035
6026
  m *= 1.1;
6036
6027
  else
6037
6028
  throw new Error(`unknown codec: ${h}`);
6038
- m = Math.min(m, c.maxBitrate || m);
6029
+ m = Math.round(Math.min(m, c.maxBitrate || m));
6039
6030
  const E = {
6040
6031
  codec: h,
6041
6032
  width: i.width,
@@ -6246,7 +6237,7 @@ class Xn {
6246
6237
  static CATALOG_TRACK = "catalog.json";
6247
6238
  connection;
6248
6239
  enabled;
6249
- path;
6240
+ name;
6250
6241
  audio;
6251
6242
  video;
6252
6243
  location;
@@ -6255,12 +6246,12 @@ class Xn {
6255
6246
  user;
6256
6247
  signals = new P();
6257
6248
  constructor(n) {
6258
- this.connection = f.from(n?.connection), this.enabled = f.from(n?.enabled ?? !1), this.path = f.from(n?.path), this.audio = new dn(n?.audio), this.video = new B(n?.video), this.location = new Wn(n?.location), this.chat = new Gn(n?.chat), this.preview = new pe(n?.preview), this.user = new Kn(n?.user), this.signals.run(this.#e.bind(this));
6249
+ this.connection = f.from(n?.connection), this.enabled = f.from(n?.enabled ?? !1), this.name = f.from(n?.name), this.audio = new dn(n?.audio), this.video = new B(n?.video), this.location = new Wn(n?.location), this.chat = new Gn(n?.chat), this.preview = new pe(n?.preview), this.user = new Kn(n?.user), this.signals.run(this.#e.bind(this));
6259
6250
  }
6260
6251
  #e(n) {
6261
6252
  const t = n.getAll([this.enabled, this.connection]);
6262
6253
  if (!t) return;
6263
- const [r, s] = t, i = n.get(this.path);
6254
+ const [r, s] = t, i = n.get(this.name);
6264
6255
  if (i === void 0) return;
6265
6256
  const o = new ln.Broadcast();
6266
6257
  n.cleanup(() => o.close()), s.publish(i, o), n.spawn(this.#n.bind(this, o, n));
@@ -6345,7 +6336,8 @@ class Hn {
6345
6336
  signals = new P();
6346
6337
  constructor(n, t) {
6347
6338
  this.kind = n, this.preferred = f.from(t?.preferred), this.signals.run((r) => {
6348
- r.spawn(this.#r.bind(this, r)), r.event(navigator.mediaDevices, "devicechange", () => r.reload());
6339
+ r.spawn(this.#r.bind(this, r)), r.event(navigator.mediaDevices, "devicechange", () => this.permission.mutate(() => {
6340
+ }));
6349
6341
  }), this.signals.run(this.#s.bind(this));
6350
6342
  }
6351
6343
  async #r(n) {
@@ -6583,4 +6575,4 @@ export {
6583
6575
  aa as i,
6584
6576
  da as u
6585
6577
  };
6586
- //# sourceMappingURL=screen-Dz_GBTAe.js.map
6578
+ //# sourceMappingURL=screen-BORpmf_D.js.map