@opentui/core 0.4.3 → 0.4.4

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/index.js CHANGED
@@ -43,7 +43,7 @@ import {
43
43
  mergeKeyAliases,
44
44
  mergeKeyBindings,
45
45
  wrapWithDelegates
46
- } from "./index-xt9f071j.js";
46
+ } from "./index-7z5n7k9m.js";
47
47
  import {
48
48
  ASCIIFontSelectionHelper,
49
49
  ATTRIBUTE_BASE_BITS,
@@ -64,6 +64,13 @@ import {
64
64
  LogLevel,
65
65
  MacOSScrollAccel,
66
66
  MouseParser,
67
+ NativeAudioStreamCloseReason,
68
+ NativeAudioStreamCloseReason1 as NativeAudioStreamCloseReason2,
69
+ NativeAudioStreamFormat,
70
+ NativeAudioStreamFormat1 as NativeAudioStreamFormat2,
71
+ NativeAudioStreamState,
72
+ NativeAudioStreamState1 as NativeAudioStreamState2,
73
+ NativeAudioStreamStateNames,
67
74
  NativeMeasureTargetKind,
68
75
  OptimizedBuffer,
69
76
  PasteEvent,
@@ -185,7 +192,7 @@ import {
185
192
  visualizeRenderableTree,
186
193
  white,
187
194
  yellow
188
- } from "./index-d5xqskty.js";
195
+ } from "./index-za1krqsf.js";
189
196
  // src/post/effects.ts
190
197
  function toU8(value) {
191
198
  return Math.round(Math.max(0, Math.min(1, Number.isFinite(value) ? value : 0)) * 255);
@@ -2526,40 +2533,1295 @@ class SlotRenderable extends Renderable {
2526
2533
  // src/audio.ts
2527
2534
  import { EventEmitter } from "events";
2528
2535
  import { readFile } from "node:fs/promises";
2536
+
2537
+ // src/audio-stream/icy/metadata.ts
2538
+ function parseIcyMetadata(bytes, decoder) {
2539
+ const decoded = decoder.decode(bytes);
2540
+ const nul = decoded.indexOf("\x00");
2541
+ const text = nul === -1 ? decoded : decoded.slice(0, nul);
2542
+ if (text.length === 0)
2543
+ return null;
2544
+ const fields = Object.create(null);
2545
+ let found = false;
2546
+ let offset = 0;
2547
+ while (offset < text.length) {
2548
+ const separator = text.indexOf("='", offset);
2549
+ if (separator === -1)
2550
+ break;
2551
+ const key = text.slice(offset, separator);
2552
+ if (key.length === 0 || /[';=]/.test(key))
2553
+ break;
2554
+ const end = text.indexOf("';", separator + 2);
2555
+ if (end === -1)
2556
+ break;
2557
+ Object.defineProperty(fields, key, {
2558
+ configurable: true,
2559
+ enumerable: true,
2560
+ writable: true,
2561
+ value: text.slice(separator + 2, end)
2562
+ });
2563
+ found = true;
2564
+ offset = end + 2;
2565
+ }
2566
+ return found ? Object.freeze(fields) : null;
2567
+ }
2568
+
2569
+ // src/audio-stream/icy/demuxer.ts
2570
+ var EMPTY_FIELDS = Object.freeze(Object.create(null));
2571
+ function copyHeaders(headers) {
2572
+ const copy = Object.create(null);
2573
+ for (const [name, value] of Object.entries(headers ?? {}))
2574
+ copy[name.toLowerCase()] = value;
2575
+ return Object.freeze(copy);
2576
+ }
2577
+ function fieldsEqual(left, right) {
2578
+ const keys = Object.keys(left);
2579
+ return keys.length === Object.keys(right).length && keys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && left[key] === right[key]);
2580
+ }
2581
+
2582
+ class IcyStreamDemuxer {
2583
+ initialMetadata;
2584
+ audioRemaining;
2585
+ metadata = null;
2586
+ metadataOffset = 0;
2587
+ fields = EMPTY_FIELDS;
2588
+ interval;
2589
+ decoder;
2590
+ headers;
2591
+ constructor(options) {
2592
+ if (!Number.isSafeInteger(options.metadataInterval) || options.metadataInterval < 0) {
2593
+ throw new TypeError("metadataInterval must be a non-negative safe integer");
2594
+ }
2595
+ this.interval = options.metadataInterval;
2596
+ try {
2597
+ this.decoder = new TextDecoder(options.metadataEncoding ?? "iso-8859-1");
2598
+ } catch {
2599
+ throw new TypeError(`Unsupported metadataEncoding: ${options.metadataEncoding}`);
2600
+ }
2601
+ this.headers = copyHeaders(options.headers);
2602
+ this.audioRemaining = this.interval;
2603
+ this.initialMetadata = Object.freeze({ format: "icy", headers: this.headers, fields: this.fields });
2604
+ }
2605
+ *push(chunk) {
2606
+ if (this.interval === 0) {
2607
+ if (chunk.byteLength > 0)
2608
+ yield { type: "audio", data: chunk };
2609
+ return;
2610
+ }
2611
+ let offset = 0;
2612
+ while (offset < chunk.byteLength) {
2613
+ if (this.audioRemaining > 0) {
2614
+ const length2 = Math.min(this.audioRemaining, chunk.byteLength - offset);
2615
+ yield { type: "audio", data: chunk.subarray(offset, offset + length2) };
2616
+ offset += length2;
2617
+ this.audioRemaining -= length2;
2618
+ continue;
2619
+ }
2620
+ if (this.metadata == null) {
2621
+ const metadataLength = (chunk[offset] ?? 0) * 16;
2622
+ offset += 1;
2623
+ if (metadataLength === 0) {
2624
+ this.audioRemaining = this.interval;
2625
+ continue;
2626
+ }
2627
+ this.metadata = new Uint8Array(metadataLength);
2628
+ this.metadataOffset = 0;
2629
+ }
2630
+ const metadata = this.metadata;
2631
+ const length = Math.min(metadata.byteLength - this.metadataOffset, chunk.byteLength - offset);
2632
+ metadata.set(chunk.subarray(offset, offset + length), this.metadataOffset);
2633
+ offset += length;
2634
+ this.metadataOffset += length;
2635
+ if (this.metadataOffset !== metadata.byteLength)
2636
+ continue;
2637
+ const fields = parseIcyMetadata(metadata, this.decoder);
2638
+ this.metadata = null;
2639
+ this.metadataOffset = 0;
2640
+ this.audioRemaining = this.interval;
2641
+ if (fields != null && !fieldsEqual(this.fields, fields)) {
2642
+ this.fields = fields;
2643
+ yield {
2644
+ type: "metadata",
2645
+ metadata: Object.freeze({ format: "icy", headers: this.headers, fields })
2646
+ };
2647
+ }
2648
+ }
2649
+ }
2650
+ *flush() {
2651
+ if (this.interval === 0)
2652
+ return;
2653
+ if (this.audioRemaining === 0 || this.metadata != null) {
2654
+ throw new Error("ICY stream ended inside a metadata block");
2655
+ }
2656
+ }
2657
+ }
2658
+ function createIcyStreamDemuxer(options) {
2659
+ return new IcyStreamDemuxer(options);
2660
+ }
2661
+
2662
+ // src/audio-stream/demuxer.ts
2663
+ function selectAudioStreamDemuxer(options) {
2664
+ const icyHeaders = Object.create(null);
2665
+ options.headers.forEach((value2, name) => {
2666
+ if (name.toLowerCase().startsWith("icy-"))
2667
+ icyHeaders[name.toLowerCase()] = value2;
2668
+ });
2669
+ const headers = Object.freeze(icyHeaders);
2670
+ const rawInterval = options.headers.get("icy-metaint");
2671
+ if (rawInterval == null) {
2672
+ return Object.keys(headers).length === 0 ? null : createIcyStreamDemuxer({ metadataInterval: 0, metadataEncoding: options.metadataEncoding, headers });
2673
+ }
2674
+ const value = rawInterval.trim();
2675
+ if (!/^\d+$/.test(value))
2676
+ throw new Error(`Invalid icy-metaint response header: ${rawInterval}`);
2677
+ const interval = Number(value);
2678
+ if (!Number.isSafeInteger(interval))
2679
+ throw new Error(`Invalid icy-metaint response header: ${rawInterval}`);
2680
+ return createIcyStreamDemuxer({ metadataInterval: interval, metadataEncoding: options.metadataEncoding, headers });
2681
+ }
2682
+
2683
+ // src/audio.ts
2684
+ class AudioInitializationError extends Error {
2685
+ action;
2686
+ status;
2687
+ constructor(action, message, status, cause) {
2688
+ super(message);
2689
+ this.name = "AudioInitializationError";
2690
+ this.action = action;
2691
+ this.status = status;
2692
+ if (cause !== undefined)
2693
+ this.cause = cause;
2694
+ }
2695
+ }
2529
2696
  function statusToError(action, status) {
2530
2697
  return new Error(`Audio ${action} failed: ${status}`);
2531
2698
  }
2532
2699
  function toBytes(data) {
2533
2700
  return data instanceof Uint8Array ? data : new Uint8Array(data);
2534
2701
  }
2702
+ var DEFAULT_AUDIO_SAMPLE_RATE = 48000;
2703
+ var DEFAULT_STREAM_PROBE_BYTES = 1024 * 1024;
2704
+ var STREAM_POLL_INTERVAL_MS = 5;
2705
+ var MAX_TIMER_DELAY_MS = 2147483647;
2706
+ var MAX_U32 = 4294967295;
2707
+ var INVALID_STREAM_CHUNK_MESSAGE = "Audio stream chunks must be Uint8Array instances";
2708
+
2709
+ class AudioStreamError extends Error {
2710
+ context;
2711
+ constructor(message, context, cause) {
2712
+ super(message);
2713
+ this.name = "AudioStreamError";
2714
+ this.context = context;
2715
+ if (cause !== undefined)
2716
+ this.cause = cause;
2717
+ }
2718
+ }
2719
+
2720
+ class ClassifiedAudioStreamError extends AudioStreamError {
2721
+ retryable;
2722
+ retryAfterMs;
2723
+ constructor(message, context, retryable, retryAfterMs, cause) {
2724
+ super(message, context, cause);
2725
+ this.retryable = retryable;
2726
+ this.retryAfterMs = retryAfterMs;
2727
+ }
2728
+ }
2729
+ function createAbortError() {
2730
+ return new DOMException("The operation was aborted", "AbortError");
2731
+ }
2732
+ var isU32 = (value) => Number.isInteger(value) && value >= 0 && value <= MAX_U32;
2733
+ function resolvePositiveU32(value, fallback, name) {
2734
+ const resolved = value ?? fallback;
2735
+ if (!Number.isFinite(resolved) || !Number.isInteger(resolved) || resolved <= 0) {
2736
+ throw new TypeError(`${name} must be a finite positive integer`);
2737
+ }
2738
+ if (resolved > MAX_U32)
2739
+ throw new RangeError(`${name} exceeds the supported limit`);
2740
+ return resolved;
2741
+ }
2742
+ function resolveReconnectOptions(options) {
2743
+ const maxRetries = options.maxRetries ?? Number.POSITIVE_INFINITY;
2744
+ const initialDelayMs = options.initialDelayMs ?? 1000;
2745
+ const maxDelayMs = options.maxDelayMs ?? 15000;
2746
+ const backoffFactor = options.backoffFactor ?? 2;
2747
+ const retryOnEnd = options.retryOnEnd ?? false;
2748
+ const retry = options.retry;
2749
+ if (maxRetries !== Number.POSITIVE_INFINITY && (!Number.isInteger(maxRetries) || maxRetries < 0)) {
2750
+ throw new TypeError("reconnect.maxRetries must be a non-negative integer or Infinity");
2751
+ }
2752
+ if (!Number.isFinite(initialDelayMs) || !Number.isInteger(initialDelayMs) || initialDelayMs < 0) {
2753
+ throw new TypeError("reconnect.initialDelayMs must be a finite non-negative integer");
2754
+ }
2755
+ if (!Number.isFinite(maxDelayMs) || !Number.isInteger(maxDelayMs) || maxDelayMs < 0) {
2756
+ throw new TypeError("reconnect.maxDelayMs must be a finite non-negative integer");
2757
+ }
2758
+ if (!Number.isFinite(backoffFactor) || backoffFactor < 1) {
2759
+ throw new TypeError("reconnect.backoffFactor must be a finite number greater than or equal to 1");
2760
+ }
2761
+ if (typeof retryOnEnd !== "boolean") {
2762
+ throw new TypeError("reconnect.retryOnEnd must be a boolean");
2763
+ }
2764
+ if (retry !== undefined && typeof retry !== "function") {
2765
+ throw new TypeError("reconnect.retry must be a function");
2766
+ }
2767
+ return {
2768
+ maxRetries,
2769
+ initialDelayMs,
2770
+ maxDelayMs,
2771
+ backoffFactor,
2772
+ retryOnEnd,
2773
+ retry: retry == null ? undefined : (error, context) => retry.call(options, error, context)
2774
+ };
2775
+ }
2776
+ function resolveAudioStreamOptions(options) {
2777
+ const format = resolveAudioStreamFormat(options.format);
2778
+ const capacityMs = resolvePositiveU32(options.buffer?.capacityMs, 2000, "buffer.capacityMs");
2779
+ const startupMs = resolvePositiveU32(options.buffer?.startupMs, 1000, "buffer.startupMs");
2780
+ const resumeMs = resolvePositiveU32(options.buffer?.resumeMs, 1000, "buffer.resumeMs");
2781
+ const maxProbeBytes = resolvePositiveU32(options.maxProbeBytes, DEFAULT_STREAM_PROBE_BYTES, "maxProbeBytes");
2782
+ if (startupMs > capacityMs)
2783
+ throw new RangeError("buffer.startupMs must not exceed buffer.capacityMs");
2784
+ if (resumeMs > capacityMs)
2785
+ throw new RangeError("buffer.resumeMs must not exceed buffer.capacityMs");
2786
+ return {
2787
+ format,
2788
+ capacityMs,
2789
+ startupMs,
2790
+ resumeMs,
2791
+ volume: options.volume ?? 1,
2792
+ pan: options.pan ?? 0,
2793
+ groupId: options.groupId ?? 0,
2794
+ maxProbeBytes,
2795
+ signal: options.signal,
2796
+ reconnect: options.reconnect === undefined ? undefined : resolveReconnectOptions(options.reconnect)
2797
+ };
2798
+ }
2799
+ function resolveAudioStreamConnector(connector) {
2800
+ const connect = connector?.connect;
2801
+ if (typeof connect !== "function")
2802
+ throw new TypeError("Audio stream connector must define connect()");
2803
+ return { connect: (context) => connect.call(connector, context) };
2804
+ }
2805
+ function runBoundedCleanup(cleanup, timeoutMs = 50) {
2806
+ let result;
2807
+ try {
2808
+ result = Promise.resolve(cleanup()).catch(() => {
2809
+ return;
2810
+ });
2811
+ } catch {
2812
+ return Promise.resolve();
2813
+ }
2814
+ return new Promise((resolve) => {
2815
+ const timer = setTimeout(resolve, timeoutMs);
2816
+ result.then(() => {
2817
+ clearTimeout(timer);
2818
+ resolve();
2819
+ });
2820
+ });
2821
+ }
2822
+ function waitForDelay(delayMs, signal) {
2823
+ if (signal.aborted)
2824
+ return Promise.reject(createAbortError());
2825
+ return new Promise((resolve, reject) => {
2826
+ let remainingMs = delayMs;
2827
+ let timer;
2828
+ const schedule = () => {
2829
+ const currentDelayMs = Math.min(remainingMs, MAX_TIMER_DELAY_MS);
2830
+ timer = setTimeout(() => {
2831
+ remainingMs -= currentDelayMs;
2832
+ if (remainingMs > 0)
2833
+ schedule();
2834
+ else {
2835
+ signal.removeEventListener("abort", onAbort);
2836
+ resolve();
2837
+ }
2838
+ }, currentDelayMs);
2839
+ };
2840
+ const onAbort = () => {
2841
+ clearTimeout(timer);
2842
+ reject(createAbortError());
2843
+ };
2844
+ signal.addEventListener("abort", onAbort, { once: true });
2845
+ schedule();
2846
+ });
2847
+ }
2848
+ function waitForPoll(signal) {
2849
+ return waitForDelay(STREAM_POLL_INTERVAL_MS, signal).then(() => true).catch(() => false);
2850
+ }
2851
+ function parseRetryAfter(value, maxDelayMs) {
2852
+ if (value == null)
2853
+ return;
2854
+ const seconds = Number(value.trim());
2855
+ if (Number.isFinite(seconds) && seconds >= 0)
2856
+ return Math.min(maxDelayMs, Math.ceil(seconds * 1000));
2857
+ const date = Date.parse(value);
2858
+ if (!Number.isFinite(date))
2859
+ return;
2860
+ return Math.min(maxDelayMs, Math.max(0, date - Date.now()));
2861
+ }
2862
+ function resolveAudioStreamFormat(value) {
2863
+ const format = value ?? "mp3";
2864
+ if (format !== "mp3" && format !== "flac")
2865
+ throw new TypeError(`Unsupported audio stream format: ${format}`);
2866
+ return format;
2867
+ }
2868
+ function toNativeAudioStreamFormat(format) {
2869
+ switch (format) {
2870
+ case "mp3":
2871
+ return NativeAudioStreamFormat.Mp3;
2872
+ case "flac":
2873
+ return NativeAudioStreamFormat.Flac;
2874
+ }
2875
+ }
2876
+ function resolveContentTypePolicy(value, receiver) {
2877
+ const policy = value ?? "validate";
2878
+ if (policy !== "validate" && policy !== "ignore" && typeof policy !== "function") {
2879
+ throw new TypeError("contentTypePolicy must be 'validate', 'ignore', or a function");
2880
+ }
2881
+ return typeof policy === "function" ? (context) => policy.call(receiver, context) : policy;
2882
+ }
2883
+ function isAllowedContentType(format, value) {
2884
+ const contentType = value.split(";", 1)[0]?.trim().toLowerCase();
2885
+ switch (format) {
2886
+ case "mp3":
2887
+ return ["audio/mpeg", "audio/mp3", "application/octet-stream", "application/mp3"].includes(contentType ?? "");
2888
+ case "flac":
2889
+ return ["audio/flac", "audio/x-flac", "application/octet-stream"].includes(contentType ?? "");
2890
+ }
2891
+ }
2892
+ function createAudioStreamUrlConnector(source, request, format, contentTypePolicy) {
2893
+ return {
2894
+ async connect({ signal, attempt }) {
2895
+ let response;
2896
+ try {
2897
+ const headers = new Headers(request?.headers);
2898
+ if (!headers.has("icy-metadata"))
2899
+ headers.set("Icy-MetaData", "1");
2900
+ response = await globalThis.fetch(source, { ...request, headers, signal });
2901
+ } catch (cause) {
2902
+ throw new ClassifiedAudioStreamError("Audio stream fetch failed", { action: "fetch", attempt }, true, undefined, cause);
2903
+ }
2904
+ if (!response.ok) {
2905
+ const retryAfterMs = parseRetryAfter(response.headers.get("retry-after"), Number.POSITIVE_INFINITY);
2906
+ await runBoundedCleanup(() => response.body?.cancel());
2907
+ const retryable = [408, 425, 429].includes(response.status) || response.status >= 500 && response.status <= 599;
2908
+ throw new ClassifiedAudioStreamError(`Audio stream request failed with HTTP ${response.status}`, { action: "response", status: response.status, attempt }, retryable, retryAfterMs);
2909
+ }
2910
+ const contentType = response.headers.get("content-type");
2911
+ let contentTypeAccepted = contentType == null || contentTypePolicy === "ignore";
2912
+ if (!contentTypeAccepted && contentTypePolicy === "validate") {
2913
+ contentTypeAccepted = isAllowedContentType(format, contentType);
2914
+ } else if (typeof contentTypePolicy === "function") {
2915
+ try {
2916
+ const result = contentTypePolicy(Object.freeze({
2917
+ format,
2918
+ contentType,
2919
+ status: response.status,
2920
+ url: response.url || String(source)
2921
+ }));
2922
+ if (typeof result !== "boolean")
2923
+ throw new TypeError("contentTypePolicy must return a boolean");
2924
+ contentTypeAccepted = result;
2925
+ } catch (cause) {
2926
+ await runBoundedCleanup(() => response.body?.cancel());
2927
+ throw new ClassifiedAudioStreamError(cause instanceof Error ? cause.message : "Audio stream content type policy failed", { action: "response", status: response.status, attempt }, false, undefined, cause);
2928
+ }
2929
+ }
2930
+ if (!contentTypeAccepted) {
2931
+ await runBoundedCleanup(() => response.body?.cancel());
2932
+ throw new ClassifiedAudioStreamError(`Unsupported audio stream Content-Type: ${contentType}`, { action: "response", status: response.status, attempt }, false);
2933
+ }
2934
+ if (response.body == null) {
2935
+ throw new ClassifiedAudioStreamError("Audio stream response has no body", { action: "response", status: response.status, attempt }, true);
2936
+ }
2937
+ return {
2938
+ body: response.body,
2939
+ info: { headers: response.headers, status: response.status }
2940
+ };
2941
+ }
2942
+ };
2943
+ }
2944
+ function resolveMetadataEncoding(value) {
2945
+ try {
2946
+ return new TextDecoder(value ?? "iso-8859-1").encoding;
2947
+ } catch {
2948
+ throw new TypeError(`Unsupported metadataEncoding: ${value}`);
2949
+ }
2950
+ }
2951
+ function resolveAudioStreamRequest(request) {
2952
+ if (request === undefined)
2953
+ return;
2954
+ const { body: _body, signal: _signal, ...safeRequest } = request;
2955
+ return safeRequest;
2956
+ }
2957
+ function isReadableStreamSource(source) {
2958
+ try {
2959
+ return typeof source?.getReader === "function";
2960
+ } catch {
2961
+ return false;
2962
+ }
2963
+ }
2964
+ function isAsyncIterableSource(source) {
2965
+ try {
2966
+ return typeof source?.[Symbol.asyncIterator] === "function";
2967
+ } catch {
2968
+ return false;
2969
+ }
2970
+ }
2971
+ function isUint8Array(value) {
2972
+ return ArrayBuffer.isView(value) && Object.prototype.toString.call(value) === "[object Uint8Array]";
2973
+ }
2974
+ var createAudioStream;
2975
+ var openAudioStream;
2976
+
2977
+ class AudioStream extends EventEmitter {
2978
+ closed;
2979
+ format;
2980
+ lib;
2981
+ engine;
2982
+ connector;
2983
+ demuxerFactory;
2984
+ readAction;
2985
+ options;
2986
+ removeFromOwner;
2987
+ lifecycleController = new AbortController;
2988
+ nativeStreamId = null;
2989
+ nativeStats = null;
2990
+ activeAttempt = null;
2991
+ pendingCleanup = null;
2992
+ reconnectAttempts = 0;
2993
+ consecutiveReconnectAttempts = 0;
2994
+ disposed = false;
2995
+ exposed = false;
2996
+ terminalError = null;
2997
+ metadata = null;
2998
+ pendingMetadataEvent = false;
2999
+ metadataEventScheduled = false;
3000
+ terminalEventScheduled = false;
3001
+ setupResolve;
3002
+ setupReject;
3003
+ closedResolve;
3004
+ setupPromise;
3005
+ overallAbortListener = () => this.dispose();
3006
+ static {
3007
+ createAudioStream = (init) => new AudioStream(init);
3008
+ openAudioStream = (stream) => stream.open();
3009
+ }
3010
+ constructor(init) {
3011
+ super();
3012
+ this.lib = init.lib;
3013
+ this.engine = init.engine;
3014
+ this.connector = init.connector;
3015
+ this.demuxerFactory = init.demuxer;
3016
+ this.readAction = init.readAction;
3017
+ this.options = resolveAudioStreamOptions(init.options);
3018
+ this.format = this.options.format;
3019
+ this.removeFromOwner = init.removeFromOwner;
3020
+ this.setupPromise = new Promise((resolve, reject) => (this.setupResolve = resolve, this.setupReject = reject));
3021
+ this.closed = new Promise((resolve) => this.closedResolve = resolve);
3022
+ this.options.signal?.addEventListener("abort", this.overallAbortListener, { once: true });
3023
+ }
3024
+ get state() {
3025
+ if (this.disposed)
3026
+ return "disposed";
3027
+ if (this.terminalError != null)
3028
+ return "errored";
3029
+ return this.nativeStats == null ? "initializing" : NativeAudioStreamStateNames[this.nativeStats.state] ?? "errored";
3030
+ }
3031
+ async open() {
3032
+ if (this.options.signal?.aborted)
3033
+ this.dispose();
3034
+ else
3035
+ this.runLifecycle();
3036
+ await this.setupPromise;
3037
+ if (this.lifecycleController.signal.aborted && this.state !== "ended")
3038
+ throw this.terminalError ?? createAbortError();
3039
+ this.exposed = true;
3040
+ if (this.pendingMetadataEvent && this.metadata != null)
3041
+ this.emitMetadata();
3042
+ this.pendingMetadataEvent = false;
3043
+ if (this.state === "ended")
3044
+ this.emitTerminal("ended");
3045
+ }
3046
+ getStats() {
3047
+ const stats = this.readNativeStats();
3048
+ if (!this.lifecycleController.signal.aborted && this.nativeStreamId != null) {
3049
+ const error = this.snapshotError(stats);
3050
+ const ended = stats?.state === NativeAudioStreamState.Ended && !this.options.reconnect?.retryOnEnd;
3051
+ if (error != null || ended) {
3052
+ queueMicrotask(() => {
3053
+ if (this.lifecycleController.signal.aborted)
3054
+ return;
3055
+ const reason = error == null || error.context.action === "decoder" ? NativeAudioStreamCloseReason.PreserveNativeTerminal : NativeAudioStreamCloseReason.TransportError;
3056
+ this.finish(reason, error ?? undefined);
3057
+ });
3058
+ }
3059
+ }
3060
+ return this.toPublicStats();
3061
+ }
3062
+ getMetadata() {
3063
+ return this.metadata;
3064
+ }
3065
+ setVolume(volume) {
3066
+ return this.control("setVolume", (streamId) => this.lib.audioSetStreamVolume(this.engine, streamId, volume));
3067
+ }
3068
+ setPan(pan) {
3069
+ return this.control("setPan", (streamId) => this.lib.audioSetStreamPan(this.engine, streamId, pan));
3070
+ }
3071
+ setGroup(groupId) {
3072
+ if (!isU32(groupId)) {
3073
+ const context = { action: "setGroup" };
3074
+ if (this.exposed) {
3075
+ this.emitAsync("error", new AudioStreamError("Invalid audio stream group", context), context);
3076
+ }
3077
+ return false;
3078
+ }
3079
+ return this.control("setGroup", (streamId) => this.lib.audioSetStreamGroup(this.engine, streamId, groupId));
3080
+ }
3081
+ control(action, call) {
3082
+ const streamId = this.nativeStreamId;
3083
+ if (this.disposed || this.lifecycleController.signal.aborted || streamId == null)
3084
+ return false;
3085
+ const status = call(streamId);
3086
+ if (status !== 0) {
3087
+ const context = { action, status };
3088
+ if (this.exposed) {
3089
+ this.emitAsync("error", new AudioStreamError(`Audio stream ${action} failed: ${status}`, context), context);
3090
+ }
3091
+ return false;
3092
+ }
3093
+ return true;
3094
+ }
3095
+ dispose() {
3096
+ if (this.disposed) {
3097
+ if (this.nativeStreamId != null && this.closeNativeStream(NativeAudioStreamCloseReason.Disposed) === 0)
3098
+ this.removeOwner();
3099
+ return;
3100
+ }
3101
+ this.disposed = true;
3102
+ const wasExposed = this.exposed;
3103
+ this.lifecycleController.abort();
3104
+ const cleanup = this.stopSource();
3105
+ this.setupReject(createAbortError());
3106
+ if (this.closeNativeStream(NativeAudioStreamCloseReason.Disposed) === 0)
3107
+ this.removeOwner();
3108
+ cleanup.finally(() => {
3109
+ if (wasExposed && !this.terminalEventScheduled)
3110
+ this.emitTerminal("disposed");
3111
+ else if (!this.terminalEventScheduled)
3112
+ this.closedResolve();
3113
+ });
3114
+ }
3115
+ async runLifecycle() {
3116
+ while (!this.lifecycleController.signal.aborted) {
3117
+ const attempt = {
3118
+ controller: new AbortController,
3119
+ body: null,
3120
+ closeConnection: null,
3121
+ reader: null,
3122
+ iterator: null,
3123
+ demuxer: null,
3124
+ demuxerFinished: false,
3125
+ sourceReleased: false,
3126
+ sourceAcquisitionAttempted: false,
3127
+ connectionClosed: false,
3128
+ demuxerAborted: false,
3129
+ resourceAcquisition: null,
3130
+ cleanupPromise: null
3131
+ };
3132
+ this.activeAttempt = attempt;
3133
+ let connection;
3134
+ try {
3135
+ let returnedConnection;
3136
+ const finishConnectionAcquisition = this.beginResourceAcquisition(attempt);
3137
+ try {
3138
+ returnedConnection = await this.connector.connect({
3139
+ signal: attempt.controller.signal,
3140
+ attempt: this.consecutiveReconnectAttempts
3141
+ });
3142
+ } finally {
3143
+ finishConnectionAcquisition();
3144
+ }
3145
+ connection = this.resolveConnection(returnedConnection, attempt);
3146
+ } catch (failure) {
3147
+ const active = this.isAttemptActive(attempt);
3148
+ await this.stopSource(attempt);
3149
+ if (!active)
3150
+ return;
3151
+ const context = {
3152
+ action: this.readAction,
3153
+ attempt: this.consecutiveReconnectAttempts
3154
+ };
3155
+ const error2 = failure instanceof AudioStreamError ? failure : new AudioStreamError(failure instanceof Error ? failure.message : "Audio stream connection failed", context, failure);
3156
+ if (await this.retry(error2, attempt, "connect"))
3157
+ continue;
3158
+ return;
3159
+ }
3160
+ if (!this.isAttemptActive(attempt)) {
3161
+ await this.stopSource(attempt);
3162
+ return;
3163
+ }
3164
+ if (!isReadableStreamSource(connection.body) && !isAsyncIterableSource(connection.body)) {
3165
+ await this.stopSource(attempt);
3166
+ const context = { action: "source" };
3167
+ await this.finish(NativeAudioStreamCloseReason.TransportError, new AudioStreamError("Audio stream connection body must be a ReadableStream or AsyncIterable", context));
3168
+ return;
3169
+ }
3170
+ if (!this.isAttemptActive(attempt)) {
3171
+ await this.stopSource(attempt);
3172
+ return;
3173
+ }
3174
+ let initialMetadata = null;
3175
+ let demuxerFailed = false;
3176
+ let demuxerFailure;
3177
+ const finishDemuxerAcquisition = this.beginResourceAcquisition(attempt);
3178
+ try {
3179
+ attempt.demuxer = this.demuxerFactory?.(connection.info) ?? null;
3180
+ initialMetadata = attempt.demuxer?.initialMetadata ?? null;
3181
+ } catch (cause) {
3182
+ demuxerFailed = true;
3183
+ demuxerFailure = cause;
3184
+ } finally {
3185
+ finishDemuxerAcquisition();
3186
+ }
3187
+ if (demuxerFailed) {
3188
+ await this.stopSource(attempt);
3189
+ const error2 = demuxerFailure instanceof AudioStreamError ? demuxerFailure : new AudioStreamError(demuxerFailure instanceof Error ? demuxerFailure.message : "Audio stream demuxer creation failed", { action: "demuxer" }, demuxerFailure);
3190
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error2);
3191
+ return;
3192
+ }
3193
+ if (!this.isAttemptActive(attempt)) {
3194
+ await this.stopSource(attempt);
3195
+ return;
3196
+ }
3197
+ this.publishMetadata(initialMetadata, attempt);
3198
+ try {
3199
+ this.createNativeStream();
3200
+ } catch (cause) {
3201
+ await this.stopSource(attempt);
3202
+ const error2 = cause instanceof AudioStreamError ? cause : new AudioStreamError("Audio stream create failed", { action: "create" }, cause);
3203
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error2);
3204
+ return;
3205
+ }
3206
+ try {
3207
+ if (!await this.consumeSource(connection, attempt))
3208
+ return;
3209
+ } catch (cause) {
3210
+ if (this.lifecycleController.signal.aborted)
3211
+ return;
3212
+ const error2 = cause instanceof AudioStreamError ? cause : cause instanceof TypeError && cause.message === INVALID_STREAM_CHUNK_MESSAGE ? cause : new AudioStreamError("Audio stream source failed", { action: "source" }, cause);
3213
+ if (error2 instanceof ClassifiedAudioStreamError) {
3214
+ if (await this.retry(error2, attempt, "read"))
3215
+ continue;
3216
+ return;
3217
+ }
3218
+ const context = error2 instanceof AudioStreamError ? error2.context : { action: "source" };
3219
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error2, context);
3220
+ return;
3221
+ }
3222
+ if (!this.options.reconnect?.retryOnEnd) {
3223
+ await this.finish(NativeAudioStreamCloseReason.PreserveNativeTerminal);
3224
+ return;
3225
+ }
3226
+ const error = new AudioStreamError("Audio stream source ended", { action: "source" });
3227
+ if (await this.retry(error, attempt, undefined, true))
3228
+ continue;
3229
+ return;
3230
+ }
3231
+ }
3232
+ createNativeStream() {
3233
+ if (this.nativeStreamId != null)
3234
+ return;
3235
+ const created = this.lib.audioCreateStream(this.engine, {
3236
+ capacityMs: this.options.capacityMs,
3237
+ startupMs: this.options.startupMs,
3238
+ resumeMs: this.options.resumeMs,
3239
+ maxProbeBytes: this.options.maxProbeBytes,
3240
+ volume: this.options.volume,
3241
+ pan: this.options.pan,
3242
+ groupId: this.options.groupId,
3243
+ format: toNativeAudioStreamFormat(this.options.format)
3244
+ });
3245
+ if (created.status !== 0 || created.streamId == null) {
3246
+ const context = { action: "create", status: created.status };
3247
+ throw new AudioStreamError(`Audio stream create failed: ${created.status}`, context);
3248
+ }
3249
+ this.nativeStreamId = created.streamId;
3250
+ }
3251
+ async consumeSource(connection, attempt) {
3252
+ const initial = await this.pollNativeSnapshot(attempt);
3253
+ if (initial == null || !this.isAttemptActive(attempt))
3254
+ return false;
3255
+ const decoderReady = this.awaitReady(attempt, initial.readyGeneration);
3256
+ try {
3257
+ await this.pumpSource(connection, attempt);
3258
+ } catch (cause) {
3259
+ this.observeReady(this.readNativeStats(), initial.readyGeneration);
3260
+ await this.stopSource(attempt);
3261
+ await decoderReady;
3262
+ if (!this.lifecycleController.signal.aborted)
3263
+ throw cause;
3264
+ return false;
3265
+ }
3266
+ if (this.lifecycleController.signal.aborted)
3267
+ return false;
3268
+ const status = this.lib.audioEndStream(this.engine, this.nativeStreamId);
3269
+ if (status !== 0) {
3270
+ const nativeError = this.snapshotError(this.readNativeStats());
3271
+ if (nativeError?.context.action === "decoder")
3272
+ throw nativeError;
3273
+ const context = { action: "end", status };
3274
+ throw new AudioStreamError(`Audio stream end failed: ${status}`, context);
3275
+ }
3276
+ if (!await decoderReady || this.lifecycleController.signal.aborted)
3277
+ return false;
3278
+ if (!await this.awaitEnded(attempt))
3279
+ return false;
3280
+ await this.stopSource(attempt);
3281
+ return !this.lifecycleController.signal.aborted;
3282
+ }
3283
+ async pumpSource(connection, attempt) {
3284
+ const source = connection.body;
3285
+ if (!this.isAttemptActive(attempt)) {
3286
+ await this.runBoundedAttemptCleanup(attempt);
3287
+ return;
3288
+ }
3289
+ const release = () => {
3290
+ if (attempt.sourceReleased)
3291
+ return;
3292
+ if (attempt.reader == null) {
3293
+ attempt.sourceReleased = true;
3294
+ return;
3295
+ }
3296
+ try {
3297
+ attempt.reader.releaseLock();
3298
+ attempt.sourceReleased = true;
3299
+ } catch {}
3300
+ };
3301
+ const next = () => attempt.reader == null ? attempt.iterator.next() : attempt.reader.read();
3302
+ attempt.sourceAcquisitionAttempted = true;
3303
+ const finishSourceAcquisition = this.beginResourceAcquisition(attempt);
3304
+ try {
3305
+ attempt.reader = isReadableStreamSource(source) ? source.getReader() : null;
3306
+ attempt.iterator = attempt.reader == null ? source[Symbol.asyncIterator]() : null;
3307
+ } catch (cause) {
3308
+ const context = { action: this.readAction };
3309
+ throw new ClassifiedAudioStreamError("Audio stream source failed", context, true, undefined, cause);
3310
+ } finally {
3311
+ finishSourceAcquisition();
3312
+ }
3313
+ if (!this.isAttemptActive(attempt)) {
3314
+ await this.runBoundedAttemptCleanup(attempt);
3315
+ return;
3316
+ }
3317
+ while (this.isAttemptActive(attempt)) {
3318
+ let result;
3319
+ try {
3320
+ result = await next();
3321
+ } catch (cause) {
3322
+ const context = { action: this.readAction };
3323
+ throw new ClassifiedAudioStreamError("Audio stream source failed", context, true, undefined, cause);
3324
+ }
3325
+ if (!this.isAttemptActive(attempt))
3326
+ return;
3327
+ if (result.done) {
3328
+ release();
3329
+ if (attempt.demuxer != null) {
3330
+ try {
3331
+ await this.processDemuxOutput(attempt.demuxer.flush(), attempt);
3332
+ } catch (cause) {
3333
+ if (cause instanceof AudioStreamError)
3334
+ throw cause;
3335
+ const context = { action: this.readAction };
3336
+ throw new ClassifiedAudioStreamError(cause instanceof Error ? cause.message : "Audio stream demuxer flush failed", context, true, undefined, cause);
3337
+ }
3338
+ }
3339
+ attempt.demuxerFinished = true;
3340
+ await this.runBoundedAttemptCleanup(attempt);
3341
+ return;
3342
+ }
3343
+ const chunk = result.value;
3344
+ if (!isUint8Array(chunk))
3345
+ throw new TypeError(INVALID_STREAM_CHUNK_MESSAGE);
3346
+ if (chunk.byteLength === 0) {
3347
+ await waitForDelay(0, attempt.controller.signal);
3348
+ continue;
3349
+ }
3350
+ if (attempt.demuxer == null) {
3351
+ await this.writeStreamChunk(chunk, attempt);
3352
+ continue;
3353
+ }
3354
+ try {
3355
+ await this.processDemuxOutput(attempt.demuxer.push(chunk), attempt);
3356
+ } catch (cause) {
3357
+ if (cause instanceof AudioStreamError)
3358
+ throw cause;
3359
+ throw new AudioStreamError(cause instanceof Error ? cause.message : "Audio stream demuxer failed", { action: "demuxer" }, cause);
3360
+ }
3361
+ }
3362
+ }
3363
+ async processDemuxOutput(outputs, attempt) {
3364
+ for (const output of outputs) {
3365
+ if (!this.isAttemptActive(attempt))
3366
+ return;
3367
+ if (output.type === "audio") {
3368
+ if (!isUint8Array(output.data)) {
3369
+ throw new AudioStreamError("Audio stream demuxer audio output must be a Uint8Array", {
3370
+ action: "demuxer"
3371
+ });
3372
+ }
3373
+ await this.writeStreamChunk(output.data, attempt);
3374
+ } else if (output.type === "metadata") {
3375
+ this.publishMetadata(output.metadata, attempt);
3376
+ } else {
3377
+ throw new AudioStreamError("Audio stream demuxer returned an invalid output", { action: "demuxer" });
3378
+ }
3379
+ }
3380
+ }
3381
+ async writeStreamChunk(chunk, attempt) {
3382
+ let offset = 0;
3383
+ while (offset < chunk.byteLength && this.isAttemptActive(attempt)) {
3384
+ const streamId = this.nativeStreamId;
3385
+ if (streamId == null)
3386
+ return;
3387
+ let accepted;
3388
+ try {
3389
+ accepted = this.lib.audioWriteStream(this.engine, streamId, chunk.subarray(offset));
3390
+ } catch (cause) {
3391
+ const context = { action: "write" };
3392
+ throw new AudioStreamError("Audio stream write failed", context, cause);
3393
+ }
3394
+ if (accepted < 0) {
3395
+ const context = { action: "write", status: accepted };
3396
+ throw new AudioStreamError(`Audio stream write failed: ${accepted}`, context);
3397
+ }
3398
+ if (accepted === 0) {
3399
+ if (await this.pollNativeSnapshot(attempt) == null)
3400
+ return;
3401
+ await waitForDelay(STREAM_POLL_INTERVAL_MS, attempt.controller.signal);
3402
+ continue;
3403
+ }
3404
+ offset += accepted;
3405
+ }
3406
+ }
3407
+ resolveConnection(connection, attempt) {
3408
+ const finishAcquisition = this.beginResourceAcquisition(attempt);
3409
+ try {
3410
+ const close = connection.close;
3411
+ if (close !== undefined && typeof close !== "function") {
3412
+ throw new TypeError("Audio stream connection close must be a function");
3413
+ }
3414
+ attempt.closeConnection = close == null ? null : () => close.call(connection);
3415
+ const info = connection.info;
3416
+ const body = connection.body;
3417
+ attempt.body = body;
3418
+ return { body, info };
3419
+ } finally {
3420
+ finishAcquisition();
3421
+ }
3422
+ }
3423
+ beginResourceAcquisition(attempt) {
3424
+ let resolve;
3425
+ const acquisition = new Promise((done) => {
3426
+ resolve = done;
3427
+ });
3428
+ attempt.resourceAcquisition = acquisition;
3429
+ return () => {
3430
+ if (attempt.resourceAcquisition === acquisition)
3431
+ attempt.resourceAcquisition = null;
3432
+ resolve();
3433
+ };
3434
+ }
3435
+ cleanupAttempt(attempt) {
3436
+ if (attempt.cleanupPromise != null)
3437
+ return attempt.cleanupPromise;
3438
+ let resolveCleanup;
3439
+ let rejectCleanup;
3440
+ const cleanup = new Promise((resolve, reject) => {
3441
+ resolveCleanup = resolve;
3442
+ rejectCleanup = reject;
3443
+ });
3444
+ attempt.cleanupPromise = cleanup;
3445
+ this.performAttemptCleanup(attempt).then(resolveCleanup, rejectCleanup);
3446
+ const clearCleanup = () => {
3447
+ if (attempt.cleanupPromise === cleanup)
3448
+ attempt.cleanupPromise = null;
3449
+ };
3450
+ cleanup.then(clearCleanup, clearCleanup);
3451
+ return cleanup;
3452
+ }
3453
+ async performAttemptCleanup(attempt) {
3454
+ if (attempt.resourceAcquisition != null)
3455
+ await attempt.resourceAcquisition;
3456
+ const pending = [];
3457
+ const reason = createAbortError();
3458
+ if (!attempt.demuxerFinished && !attempt.demuxerAborted && attempt.demuxer != null) {
3459
+ attempt.demuxerAborted = true;
3460
+ try {
3461
+ attempt.demuxer.abort?.(reason);
3462
+ } catch {}
3463
+ }
3464
+ if (!attempt.sourceReleased) {
3465
+ if (attempt.reader != null) {
3466
+ attempt.sourceReleased = true;
3467
+ try {
3468
+ const result = attempt.reader.cancel(reason);
3469
+ try {
3470
+ attempt.reader.releaseLock();
3471
+ } catch {}
3472
+ pending.push(result);
3473
+ } catch {}
3474
+ } else if (attempt.iterator != null) {
3475
+ attempt.sourceReleased = true;
3476
+ try {
3477
+ pending.push(Promise.resolve(attempt.iterator.return?.()));
3478
+ } catch {}
3479
+ } else if (attempt.body != null && !attempt.sourceAcquisitionAttempted) {
3480
+ attempt.sourceReleased = true;
3481
+ try {
3482
+ if (isReadableStreamSource(attempt.body)) {
3483
+ pending.push(attempt.body.cancel(reason));
3484
+ } else if (isAsyncIterableSource(attempt.body)) {
3485
+ attempt.iterator = attempt.body[Symbol.asyncIterator]();
3486
+ pending.push(Promise.resolve(attempt.iterator.return?.()));
3487
+ }
3488
+ } catch {}
3489
+ }
3490
+ }
3491
+ if (!attempt.connectionClosed && attempt.closeConnection != null) {
3492
+ attempt.connectionClosed = true;
3493
+ try {
3494
+ pending.push(Promise.resolve(attempt.closeConnection()));
3495
+ } catch {}
3496
+ }
3497
+ await Promise.allSettled(pending);
3498
+ }
3499
+ runBoundedAttemptCleanup(attempt) {
3500
+ if (this.pendingCleanup != null)
3501
+ return this.pendingCleanup;
3502
+ let resolveCleanup;
3503
+ let rejectCleanup;
3504
+ const pendingCleanup = new Promise((resolve, reject) => {
3505
+ resolveCleanup = resolve;
3506
+ rejectCleanup = reject;
3507
+ });
3508
+ this.pendingCleanup = pendingCleanup;
3509
+ const cleanup = runBoundedCleanup(() => this.cleanupAttempt(attempt));
3510
+ cleanup.then(resolveCleanup, rejectCleanup);
3511
+ const clearCleanup = () => {
3512
+ if (this.pendingCleanup === pendingCleanup)
3513
+ this.pendingCleanup = null;
3514
+ };
3515
+ pendingCleanup.then(clearCleanup, clearCleanup);
3516
+ return pendingCleanup;
3517
+ }
3518
+ async retry(error, attempt, phase, cleanEnd = false) {
3519
+ if (this.lifecycleController.signal.aborted)
3520
+ return false;
3521
+ const reconnect = this.options.reconnect;
3522
+ const retryable = phase == null || !(error instanceof ClassifiedAudioStreamError) || error.retryable;
3523
+ if (reconnect == null || this.consecutiveReconnectAttempts >= reconnect.maxRetries) {
3524
+ if (cleanEnd)
3525
+ await this.finish(NativeAudioStreamCloseReason.PreserveNativeTerminal);
3526
+ else
3527
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error);
3528
+ return false;
3529
+ }
3530
+ let retryDelayMs = error instanceof ClassifiedAudioStreamError ? error.retryAfterMs : undefined;
3531
+ if (phase != null && reconnect.retry != null) {
3532
+ let decision;
3533
+ try {
3534
+ decision = reconnect.retry(error, {
3535
+ attempt: this.consecutiveReconnectAttempts + 1,
3536
+ maxRetries: reconnect.maxRetries,
3537
+ phase
3538
+ });
3539
+ if (decision !== false && (decision == null || typeof decision !== "object")) {
3540
+ throw new TypeError("Audio stream retry policy must return false or a retry decision");
3541
+ }
3542
+ } catch (cause) {
3543
+ await this.finish(NativeAudioStreamCloseReason.TransportError, new AudioStreamError("Audio stream retry policy failed", { action: "source" }, cause));
3544
+ return false;
3545
+ }
3546
+ if (decision === false) {
3547
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error);
3548
+ return false;
3549
+ }
3550
+ if (this.lifecycleController.signal.aborted)
3551
+ return false;
3552
+ let policyDelayMs;
3553
+ try {
3554
+ policyDelayMs = decision.delayMs;
3555
+ } catch (cause) {
3556
+ await this.finish(NativeAudioStreamCloseReason.TransportError, new AudioStreamError("Audio stream retry policy failed", { action: "source" }, cause));
3557
+ return false;
3558
+ }
3559
+ if (policyDelayMs !== undefined && (!Number.isFinite(policyDelayMs) || !Number.isInteger(policyDelayMs) || policyDelayMs < 0)) {
3560
+ await this.finish(NativeAudioStreamCloseReason.TransportError, new AudioStreamError("Audio stream retry delay must be a finite non-negative integer", {
3561
+ action: "source"
3562
+ }));
3563
+ return false;
3564
+ }
3565
+ if (policyDelayMs !== undefined)
3566
+ retryDelayMs = Math.min(reconnect.maxDelayMs, policyDelayMs);
3567
+ } else if (!retryable) {
3568
+ await this.finish(NativeAudioStreamCloseReason.TransportError, error);
3569
+ return false;
3570
+ }
3571
+ if (retryDelayMs !== undefined)
3572
+ retryDelayMs = Math.min(reconnect.maxDelayMs, retryDelayMs);
3573
+ await this.cleanupAttempt(attempt);
3574
+ if (this.lifecycleController.signal.aborted)
3575
+ return false;
3576
+ if (this.nativeStreamId != null) {
3577
+ const nativeError = this.snapshotError(this.readNativeStats());
3578
+ if (nativeError != null) {
3579
+ const reason = nativeError.context.action === "decoder" ? NativeAudioStreamCloseReason.PreserveNativeTerminal : NativeAudioStreamCloseReason.TransportError;
3580
+ await this.finish(reason, nativeError);
3581
+ return false;
3582
+ }
3583
+ const restartStatus = this.lib.audioRestartStream(this.engine, this.nativeStreamId);
3584
+ if (restartStatus !== 0) {
3585
+ const restartContext = { action: "restart", status: restartStatus };
3586
+ await this.finish(NativeAudioStreamCloseReason.TransportError, new AudioStreamError("Audio stream restart failed during reconnect", restartContext));
3587
+ return false;
3588
+ }
3589
+ this.readNativeStats();
3590
+ }
3591
+ this.reconnectAttempts += 1;
3592
+ this.consecutiveReconnectAttempts += 1;
3593
+ const delayMs = retryDelayMs ?? Math.min(reconnect.maxDelayMs, reconnect.initialDelayMs * reconnect.backoffFactor ** (this.consecutiveReconnectAttempts - 1));
3594
+ if (this.exposed) {
3595
+ this.emitAsync("reconnecting", {
3596
+ attempt: this.consecutiveReconnectAttempts,
3597
+ delayMs,
3598
+ maxRetries: reconnect.maxRetries,
3599
+ error
3600
+ });
3601
+ }
3602
+ return waitForDelay(delayMs, this.lifecycleController.signal).then(() => true).catch(() => false);
3603
+ }
3604
+ async awaitReady(attempt, previousGeneration) {
3605
+ while (this.isAttemptActive(attempt)) {
3606
+ const stats = await this.pollNativeSnapshot(attempt);
3607
+ if (stats == null)
3608
+ return false;
3609
+ if (this.observeReady(stats, previousGeneration))
3610
+ return true;
3611
+ if (!await waitForPoll(attempt.controller.signal))
3612
+ return false;
3613
+ }
3614
+ return false;
3615
+ }
3616
+ observeReady(stats, previousGeneration) {
3617
+ if (stats == null || stats.readyGeneration === previousGeneration)
3618
+ return false;
3619
+ this.consecutiveReconnectAttempts = 0;
3620
+ this.setupResolve();
3621
+ return true;
3622
+ }
3623
+ async awaitEnded(attempt) {
3624
+ while (this.isAttemptActive(attempt)) {
3625
+ const stats = await this.pollNativeSnapshot(attempt);
3626
+ if (stats == null)
3627
+ return false;
3628
+ if (stats.state === NativeAudioStreamState.Ended)
3629
+ return true;
3630
+ if (!await waitForPoll(attempt.controller.signal))
3631
+ return false;
3632
+ }
3633
+ return false;
3634
+ }
3635
+ async pollNativeSnapshot(attempt) {
3636
+ if (!this.isAttemptActive(attempt))
3637
+ return null;
3638
+ const stats = this.readNativeStats();
3639
+ const error = this.snapshotError(stats);
3640
+ if (error != null) {
3641
+ const reason = error.context.action === "decoder" ? NativeAudioStreamCloseReason.PreserveNativeTerminal : NativeAudioStreamCloseReason.TransportError;
3642
+ await this.finish(reason, error);
3643
+ return null;
3644
+ }
3645
+ return stats;
3646
+ }
3647
+ snapshotError(stats) {
3648
+ if (stats == null)
3649
+ return new AudioStreamError("Audio stream stats failed", { action: "stats" });
3650
+ if (NativeAudioStreamStateNames[stats.state] == null) {
3651
+ return new AudioStreamError(`Unknown native audio stream state: ${stats.state}`, { action: "stats" });
3652
+ }
3653
+ if (stats.state !== NativeAudioStreamState.Failed && stats.state !== NativeAudioStreamState.Cancelled)
3654
+ return null;
3655
+ const context = { action: "decoder", errorCode: stats.errorCode };
3656
+ return new AudioStreamError(stats.state === NativeAudioStreamState.Failed ? `Audio stream decoder failed: ${stats.errorCode}` : "Audio stream was cancelled by the decoder", context);
3657
+ }
3658
+ async finish(reason, error, context) {
3659
+ if (this.lifecycleController.signal.aborted)
3660
+ return;
3661
+ if (error instanceof AudioStreamError)
3662
+ context = error.context;
3663
+ this.lifecycleController.abort();
3664
+ this.terminalError = error ?? null;
3665
+ const cleanup = this.stopSource();
3666
+ const closeStatus = this.closeNativeStream(reason);
3667
+ if (error == null && closeStatus !== 0) {
3668
+ context = { action: "destroy", status: closeStatus };
3669
+ error = new AudioStreamError("Audio stream destroy failed after end", context);
3670
+ this.terminalError = error;
3671
+ }
3672
+ await cleanup;
3673
+ if (error != null)
3674
+ this.setupReject(error);
3675
+ else
3676
+ this.setupResolve();
3677
+ if (closeStatus === 0)
3678
+ this.removeOwner();
3679
+ if (!this.disposed && this.exposed) {
3680
+ if (error != null)
3681
+ this.emitTerminal("error", error, context);
3682
+ else
3683
+ this.emitTerminal("ended");
3684
+ } else if (error != null && !this.disposed)
3685
+ this.closedResolve();
3686
+ }
3687
+ publishMetadata(metadata, attempt) {
3688
+ if (!this.isAttemptActive(attempt) || Object.is(this.metadata, metadata))
3689
+ return;
3690
+ this.metadata = metadata;
3691
+ if (!this.exposed) {
3692
+ this.pendingMetadataEvent = true;
3693
+ return;
3694
+ }
3695
+ this.emitMetadata();
3696
+ }
3697
+ emitMetadata() {
3698
+ if (this.metadataEventScheduled)
3699
+ return;
3700
+ this.metadataEventScheduled = true;
3701
+ setTimeout(() => {
3702
+ this.metadataEventScheduled = false;
3703
+ if (!this.disposed)
3704
+ EventEmitter.prototype.emit.call(this, "metadata", this.metadata);
3705
+ }, 0);
3706
+ }
3707
+ emitAsync(event, ...args) {
3708
+ setTimeout(() => EventEmitter.prototype.emit.call(this, event, ...args), 0);
3709
+ }
3710
+ emitTerminal(event, ...args) {
3711
+ if (this.terminalEventScheduled)
3712
+ return;
3713
+ this.terminalEventScheduled = true;
3714
+ setTimeout(() => {
3715
+ try {
3716
+ EventEmitter.prototype.emit.call(this, event, ...args);
3717
+ } finally {
3718
+ this.closedResolve();
3719
+ }
3720
+ }, 0);
3721
+ }
3722
+ isAttemptActive(attempt) {
3723
+ return !this.lifecycleController.signal.aborted && this.activeAttempt === attempt;
3724
+ }
3725
+ stopSource(attempt = this.activeAttempt) {
3726
+ if (attempt == null)
3727
+ return this.pendingCleanup ?? Promise.resolve();
3728
+ if (this.activeAttempt === attempt)
3729
+ this.activeAttempt = null;
3730
+ attempt.controller.abort();
3731
+ return this.runBoundedAttemptCleanup(attempt);
3732
+ }
3733
+ closeNativeStream(reason) {
3734
+ const streamId = this.nativeStreamId;
3735
+ if (streamId == null)
3736
+ return 0;
3737
+ const result = this.lib.audioCloseStream(this.engine, streamId, reason);
3738
+ if (result.status !== 0 || result.stats == null)
3739
+ return result.status === 0 ? -1 : result.status;
3740
+ this.nativeStats = result.stats;
3741
+ this.nativeStreamId = null;
3742
+ return 0;
3743
+ }
3744
+ readNativeStats() {
3745
+ if (this.nativeStreamId == null)
3746
+ return this.nativeStats;
3747
+ const stats = this.lib.audioGetStreamStats(this.engine, this.nativeStreamId);
3748
+ if (stats != null)
3749
+ this.nativeStats = stats;
3750
+ return stats;
3751
+ }
3752
+ toPublicStats() {
3753
+ const stats = this.nativeStats;
3754
+ const sampleRate = stats?.sampleRate ?? 0;
3755
+ const bufferedFrames = stats?.bufferedFrames ?? 0;
3756
+ return {
3757
+ state: this.state,
3758
+ sampleRate,
3759
+ channels: stats?.channels ?? 0,
3760
+ bufferedFrames,
3761
+ capacityFrames: stats?.capacityFrames ?? 0,
3762
+ bufferedDurationMs: sampleRate === 0 ? 0 : bufferedFrames * 1000 / sampleRate,
3763
+ bytesReceived: stats?.bytesReceived ?? 0n,
3764
+ framesDecoded: stats?.framesDecoded ?? 0n,
3765
+ framesPlayed: stats?.framesPlayed ?? 0n,
3766
+ underruns: stats?.underruns ?? 0,
3767
+ reconnectAttempts: this.reconnectAttempts
3768
+ };
3769
+ }
3770
+ removeOwner() {
3771
+ this.options.signal?.removeEventListener("abort", this.overallAbortListener);
3772
+ this.removeFromOwner();
3773
+ }
3774
+ }
2535
3775
 
2536
3776
  class Audio extends EventEmitter {
2537
3777
  static create(options = {}) {
2538
- return new Audio(resolveRenderLib(), options);
3778
+ let lib;
3779
+ try {
3780
+ lib = resolveRenderLib();
3781
+ } catch (cause) {
3782
+ throw new AudioInitializationError("resolveRenderLib", "Failed to resolve the native audio library", undefined, cause);
3783
+ }
3784
+ return new Audio(lib, options);
2539
3785
  }
3786
+ sampleRate;
2540
3787
  lib;
2541
3788
  defaultStartOptions;
2542
3789
  engine = null;
2543
3790
  groups = new Map;
3791
+ streams = new Set;
2544
3792
  playbackStarted = false;
2545
3793
  mixerStarted = false;
3794
+ disposing = false;
2546
3795
  constructor(lib, options) {
2547
3796
  super();
2548
3797
  this.lib = lib;
2549
3798
  this.defaultStartOptions = options.startOptions;
3799
+ const normalizedSampleRate = options.sampleRate == null || !Number.isFinite(options.sampleRate) ? 0 : Math.min(MAX_U32, Math.max(0, Math.trunc(options.sampleRate)));
3800
+ this.sampleRate = normalizedSampleRate || DEFAULT_AUDIO_SAMPLE_RATE;
2550
3801
  const createOptions = options.sampleRate == null && options.playbackChannels == null ? undefined : {
2551
- sampleRate: options.sampleRate == null ? undefined : Math.max(0, Math.trunc(options.sampleRate)),
3802
+ sampleRate: options.sampleRate == null ? undefined : normalizedSampleRate,
2552
3803
  playbackChannels: options.playbackChannels == null ? undefined : Math.max(0, Math.trunc(options.playbackChannels))
2553
3804
  };
2554
3805
  this.engine = this.lib.createAudioEngine(createOptions);
2555
3806
  if (!this.engine) {
2556
- this.emitError("createAudioEngine", undefined, "Audio createAudioEngine returned null");
2557
- return;
3807
+ throw new AudioInitializationError("createAudioEngine", "Audio createAudioEngine returned null");
2558
3808
  }
2559
3809
  if (options.autoStart ?? false) {
2560
- this.start(this.defaultStartOptions);
3810
+ const status = this.lib.audioStart(this.engine, this.defaultStartOptions);
3811
+ if (status !== 0) {
3812
+ this.throwAfterInitializationCleanup(new AudioInitializationError("start", `Audio auto-start failed: ${status}`, status));
3813
+ }
3814
+ this.playbackStarted = true;
3815
+ this.mixerStarted = true;
2561
3816
  }
2562
3817
  }
3818
+ throwAfterInitializationCleanup(error) {
3819
+ const engine2 = this.engine;
3820
+ this.engine = null;
3821
+ if (engine2)
3822
+ this.lib.destroyAudioEngine(engine2);
3823
+ throw error;
3824
+ }
2563
3825
  emitError(action, status, message, cause) {
2564
3826
  const error = message ? new Error(message) : statusToError(action, status ?? -1);
2565
3827
  if (cause)
@@ -2698,6 +3960,74 @@ class Audio extends EventEmitter {
2698
3960
  }
2699
3961
  return result.voiceId;
2700
3962
  }
3963
+ async playStream(source, options = {}) {
3964
+ const urlOptions = options;
3965
+ if (urlOptions.request !== undefined || urlOptions.reconnect !== undefined || urlOptions.metadataEncoding !== undefined || urlOptions.contentTypePolicy !== undefined) {
3966
+ return Promise.reject(new TypeError("request, reconnect, metadataEncoding, and contentTypePolicy options are only supported by playStreamUrl()"));
3967
+ }
3968
+ if (!isReadableStreamSource(source) && !isAsyncIterableSource(source)) {
3969
+ return Promise.reject(new TypeError("Audio stream source must be a ReadableStream or AsyncIterable"));
3970
+ }
3971
+ const { demuxer, ...streamOptions } = options;
3972
+ const connector = {
3973
+ async connect() {
3974
+ return { body: source, info: undefined };
3975
+ }
3976
+ };
3977
+ return this.openStream(connector, demuxer == null ? undefined : () => demuxer(), streamOptions, "source");
3978
+ }
3979
+ async playStreamUrl(source, options = {}) {
3980
+ if (options.demuxer !== undefined) {
3981
+ throw new TypeError("demuxer is only supported by playStream() and playStreamSource()");
3982
+ }
3983
+ if (typeof source !== "string" && Object.prototype.toString.call(source) !== "[object URL]") {
3984
+ return Promise.reject(new TypeError("Audio stream URL source must be a string or URL"));
3985
+ }
3986
+ const { request, metadataEncoding, reconnect, format, contentTypePolicy, ...streamOptions } = options;
3987
+ const resolvedFormat = resolveAudioStreamFormat(format);
3988
+ const resolvedContentTypePolicy = resolveContentTypePolicy(contentTypePolicy, options);
3989
+ const encoding = resolveMetadataEncoding(metadataEncoding);
3990
+ const connector = createAudioStreamUrlConnector(source, resolveAudioStreamRequest(request), resolvedFormat, resolvedContentTypePolicy);
3991
+ return this.openStream(connector, (info) => {
3992
+ try {
3993
+ return selectAudioStreamDemuxer({ headers: info.headers, metadataEncoding: encoding });
3994
+ } catch (cause) {
3995
+ throw new AudioStreamError(cause instanceof Error ? cause.message : "Invalid audio stream metadata response", { action: "response", status: info.status }, cause);
3996
+ }
3997
+ }, { ...streamOptions, reconnect, format: resolvedFormat }, "fetch");
3998
+ }
3999
+ async playStreamSource(connector, options = {}) {
4000
+ const urlOptions = options;
4001
+ if (urlOptions.request !== undefined || urlOptions.metadataEncoding !== undefined || urlOptions.contentTypePolicy !== undefined) {
4002
+ return Promise.reject(new TypeError("request, metadataEncoding, and contentTypePolicy are only supported by playStreamUrl()"));
4003
+ }
4004
+ const { demuxer, ...streamOptions } = options;
4005
+ return this.openStream(connector, demuxer, streamOptions, "source");
4006
+ }
4007
+ async openStream(connector, demuxer, options, readAction) {
4008
+ const engine2 = this.engine;
4009
+ if (!engine2)
4010
+ throw new Error("Audio engine unavailable during stream playback");
4011
+ const resolvedConnector = resolveAudioStreamConnector(connector);
4012
+ let stream;
4013
+ stream = createAudioStream({
4014
+ lib: this.lib,
4015
+ engine: engine2,
4016
+ connector: resolvedConnector,
4017
+ demuxer,
4018
+ options,
4019
+ readAction,
4020
+ removeFromOwner: () => this.streams.delete(stream)
4021
+ });
4022
+ this.streams.add(stream);
4023
+ try {
4024
+ await openAudioStream(stream);
4025
+ return stream;
4026
+ } catch (error) {
4027
+ stream.dispose();
4028
+ throw error;
4029
+ }
4030
+ }
2701
4031
  stopVoice(voice) {
2702
4032
  const engine2 = this.engine;
2703
4033
  if (!engine2) {
@@ -2865,15 +4195,22 @@ class Audio extends EventEmitter {
2865
4195
  return stats;
2866
4196
  }
2867
4197
  dispose() {
2868
- if (!this.engine)
4198
+ if (!this.engine || this.disposing)
2869
4199
  return;
2870
- if (this.mixerStarted) {
2871
- this.stop();
4200
+ this.disposing = true;
4201
+ try {
4202
+ for (const stream of [...this.streams])
4203
+ stream.dispose();
4204
+ if (this.mixerStarted) {
4205
+ this.stop();
4206
+ }
4207
+ this.groups.clear();
4208
+ this.lib.destroyAudioEngine(this.engine);
4209
+ this.engine = null;
4210
+ this.emit("disposed");
4211
+ } finally {
4212
+ this.disposing = false;
2872
4213
  }
2873
- this.groups.clear();
2874
- this.lib.destroyAudioEngine(this.engine);
2875
- this.engine = null;
2876
- this.emit("disposed");
2877
4214
  }
2878
4215
  }
2879
4216
  function setupAudio(options = {}) {
@@ -6771,6 +8108,83 @@ var Nt = d.parseInline;
6771
8108
  var Ft = b.parse;
6772
8109
  var jt = x.lex;
6773
8110
 
8111
+ // src/renderables/text-table-width.ts
8112
+ function comparePriority(leftGrowth, leftCapacity, rightGrowth, rightCapacity) {
8113
+ const left = leftGrowth * leftGrowth * rightCapacity;
8114
+ const right = rightGrowth * rightGrowth * leftCapacity;
8115
+ if (Number.isSafeInteger(left) && Number.isSafeInteger(right)) {
8116
+ return left < right ? -1 : left > right ? 1 : 0;
8117
+ }
8118
+ const exactLeft = BigInt(leftGrowth) * BigInt(leftGrowth) * BigInt(rightCapacity);
8119
+ const exactRight = BigInt(rightGrowth) * BigInt(rightGrowth) * BigInt(leftCapacity);
8120
+ return exactLeft < exactRight ? -1 : exactLeft > exactRight ? 1 : 0;
8121
+ }
8122
+ function allocateProportionalColumnWidths(widths, targetWidth, minWidth) {
8123
+ const baseWidths = widths.map((width) => Math.max(minWidth, Math.floor(width)));
8124
+ const totalBaseWidth = baseWidths.reduce((sum, width) => sum + width, 0);
8125
+ const capacity = baseWidths.map((width) => width - minWidth);
8126
+ const growth = new Array(baseWidths.length).fill(0);
8127
+ const available = Math.min(Math.max(0, targetWidth - minWidth * baseWidths.length), totalBaseWidth - minWidth * baseWidths.length);
8128
+ if (available === 0)
8129
+ return growth.map(() => minWidth);
8130
+ if (available === capacity.reduce((sum, width) => sum + width, 0))
8131
+ return baseWidths;
8132
+ const weights = capacity.map(Math.sqrt);
8133
+ const active = capacity.map((width, idx) => ({ idx, width, weight: weights[idx] })).filter((column) => column.width > 0).sort((a, b2) => a.weight - b2.weight);
8134
+ if (active.length === capacity.length && capacity.every((width) => width === capacity[0])) {
8135
+ const sharedGrowth = Math.floor(available / capacity.length);
8136
+ const remainder = available % capacity.length;
8137
+ return growth.map((_2, idx) => minWidth + sharedGrowth + (idx < remainder ? 1 : 0));
8138
+ }
8139
+ let remaining = available;
8140
+ let totalWeight = active.reduce((sum, column) => sum + column.weight, 0);
8141
+ for (const column of active) {
8142
+ if (remaining / totalWeight <= column.weight)
8143
+ break;
8144
+ growth[column.idx] = column.width;
8145
+ remaining -= column.width;
8146
+ totalWeight -= column.weight;
8147
+ }
8148
+ const level = remaining / totalWeight;
8149
+ for (const column of active) {
8150
+ if (growth[column.idx] === column.width)
8151
+ continue;
8152
+ growth[column.idx] = Math.min(column.width, Math.floor(level * column.weight));
8153
+ }
8154
+ let allocatedGrowth = growth.reduce((sum, width) => sum + width, 0);
8155
+ while (allocatedGrowth > available) {
8156
+ let worstIdx = -1;
8157
+ for (let idx = 0;idx < baseWidths.length; idx++) {
8158
+ if (growth[idx] === 0)
8159
+ continue;
8160
+ const comparison = worstIdx === -1 ? 1 : comparePriority(growth[idx], capacity[idx], growth[worstIdx], capacity[worstIdx]);
8161
+ if (comparison > 0 || comparison === 0 && idx > worstIdx) {
8162
+ worstIdx = idx;
8163
+ }
8164
+ }
8165
+ if (worstIdx === -1)
8166
+ break;
8167
+ growth[worstIdx] -= 1;
8168
+ allocatedGrowth -= 1;
8169
+ }
8170
+ while (allocatedGrowth < available) {
8171
+ let bestIdx = -1;
8172
+ for (let idx = 0;idx < baseWidths.length; idx++) {
8173
+ if (growth[idx] >= capacity[idx])
8174
+ continue;
8175
+ const comparison = bestIdx === -1 ? -1 : comparePriority(growth[idx] + 1, capacity[idx], growth[bestIdx] + 1, capacity[bestIdx]);
8176
+ if (comparison < 0) {
8177
+ bestIdx = idx;
8178
+ }
8179
+ }
8180
+ if (bestIdx === -1)
8181
+ break;
8182
+ growth[bestIdx] += 1;
8183
+ allocatedGrowth += 1;
8184
+ }
8185
+ return growth.map((width) => width + minWidth);
8186
+ }
8187
+
6774
8188
  // src/renderables/TextTable.ts
6775
8189
  var MEASURE_HEIGHT = 1e4;
6776
8190
 
@@ -7324,54 +8738,7 @@ class TextTableRenderable extends Renderable {
7324
8738
  }
7325
8739
  fitColumnWidthsProportional(widths, targetContentWidth) {
7326
8740
  const minWidth = 1 + this.getHorizontalCellPadding();
7327
- const hardMinWidths = new Array(widths.length).fill(minWidth);
7328
- const baseWidths = widths.map((width) => Math.max(1, Math.floor(width)));
7329
- const preferredMinWidths = baseWidths.map((width) => Math.min(width, minWidth + 1));
7330
- const preferredMinTotal = preferredMinWidths.reduce((sum, width) => sum + width, 0);
7331
- const floorWidths = preferredMinTotal <= targetContentWidth ? preferredMinWidths : hardMinWidths;
7332
- const floorTotal = floorWidths.reduce((sum, width) => sum + width, 0);
7333
- const clampedTarget = Math.max(floorTotal, targetContentWidth);
7334
- const totalBaseWidth = baseWidths.reduce((sum, width) => sum + width, 0);
7335
- if (totalBaseWidth <= clampedTarget) {
7336
- return baseWidths;
7337
- }
7338
- const shrinkable = baseWidths.map((width, idx) => width - floorWidths[idx]);
7339
- const totalShrinkable = shrinkable.reduce((sum, value) => sum + value, 0);
7340
- if (totalShrinkable <= 0) {
7341
- return [...floorWidths];
7342
- }
7343
- const targetShrink = totalBaseWidth - clampedTarget;
7344
- const integerShrink = new Array(baseWidths.length).fill(0);
7345
- const fractions = new Array(baseWidths.length).fill(0);
7346
- let usedShrink = 0;
7347
- for (let idx = 0;idx < baseWidths.length; idx++) {
7348
- if (shrinkable[idx] <= 0)
7349
- continue;
7350
- const exact = shrinkable[idx] / totalShrinkable * targetShrink;
7351
- const whole = Math.min(shrinkable[idx], Math.floor(exact));
7352
- integerShrink[idx] = whole;
7353
- fractions[idx] = exact - whole;
7354
- usedShrink += whole;
7355
- }
7356
- let remainingShrink = targetShrink - usedShrink;
7357
- while (remainingShrink > 0) {
7358
- let bestIdx = -1;
7359
- let bestFraction = -1;
7360
- for (let idx = 0;idx < baseWidths.length; idx++) {
7361
- if (shrinkable[idx] - integerShrink[idx] <= 0)
7362
- continue;
7363
- if (fractions[idx] > bestFraction) {
7364
- bestFraction = fractions[idx];
7365
- bestIdx = idx;
7366
- }
7367
- }
7368
- if (bestIdx === -1)
7369
- break;
7370
- integerShrink[bestIdx] += 1;
7371
- fractions[bestIdx] = 0;
7372
- remainingShrink -= 1;
7373
- }
7374
- return baseWidths.map((width, idx) => Math.max(floorWidths[idx], width - integerShrink[idx]));
8741
+ return allocateProportionalColumnWidths(widths, targetContentWidth, minWidth);
7375
8742
  }
7376
8743
  fitColumnWidthsBalanced(widths, targetContentWidth) {
7377
8744
  const minWidth = 1 + this.getHorizontalCellPadding();
@@ -11547,6 +12914,7 @@ export {
11547
12914
  createTerminalPalette,
11548
12915
  createSlotRegistry,
11549
12916
  createMarkdownCodeBlockRenderer,
12917
+ createIcyStreamDemuxer,
11550
12918
  createExtmarksController,
11551
12919
  createCoreSlotRegistry,
11552
12920
  createCliRenderer,
@@ -11645,6 +13013,9 @@ export {
11645
13013
  OptimizedBuffer,
11646
13014
  NativeSpanFeed,
11647
13015
  NativeMeasureTargetKind,
13016
+ NativeAudioStreamState2 as NativeAudioStreamState,
13017
+ NativeAudioStreamFormat2 as NativeAudioStreamFormat,
13018
+ NativeAudioStreamCloseReason2 as NativeAudioStreamCloseReason,
11648
13019
  MouseParser,
11649
13020
  MouseEvent,
11650
13021
  MouseButton,
@@ -11695,6 +13066,9 @@ export {
11695
13066
  BorderCharArrays,
11696
13067
  BloomEffect,
11697
13068
  BaseRenderable,
13069
+ AudioStreamError,
13070
+ AudioStream,
13071
+ AudioInitializationError,
11698
13072
  Audio,
11699
13073
  ArrowRenderable,
11700
13074
  ATTRIBUTE_BASE_MASK,
@@ -11705,5 +13079,5 @@ export {
11705
13079
  ACHROMATOPSIA_MATRIX
11706
13080
  };
11707
13081
 
11708
- //# debugId=9FCFC4351B1344F964756E2164756E21
13082
+ //# debugId=EF989EBD255C13EC64756E2164756E21
11709
13083
  //# sourceMappingURL=index.js.map