@opentui/core 0.4.3 → 0.4.5

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