@geastack/core 0.1.33 → 0.1.35
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/app_frame_perf.cpp +12 -0
- package/audio-worklet.d.ts +49 -0
- package/gea_app_entry.cpp +36 -3
- package/gea_sources.mjs +2 -2
- package/include/app.h +6 -0
- package/include/audio.h +11 -0
- package/include/audio_stream.h +73 -0
- package/include/canvas.h +1 -0
- package/include/pixel.h +40 -6
- package/index.d.ts +228 -8
- package/package.json +5 -2
- package/runtime/audio-worklet.ts +51 -0
- package/runtime-surface.ts +7 -0
- package/scripts/build-gea-vite-geatsc.mjs +51 -3
- package/scripts/gea-bundle-type-hints.mjs +9 -1
- package/scripts/gea-embedded-compat-staging.mjs +2 -0
- package/scripts/gea-static-asset.mjs +15 -0
- package/scripts/gea-vite-module-graph-plugin.mjs +1 -14
- package/scripts/gea-worker-modules.mjs +192 -0
- package/scripts/generate-gea-embedded-assets.mjs +2 -1
- package/typed-arrays.d.ts +13 -0
- package/workers.d.ts +66 -0
package/index.d.ts
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/// <reference path="./css.d.ts" />
|
|
2
2
|
|
|
3
|
+
export type * from './workers'
|
|
4
|
+
export type * from './audio-worklet'
|
|
5
|
+
/** Gea-only hardware output cancellation; call from an AudioWorklet message handler. */
|
|
6
|
+
export declare function flushAudioWorkletOutput(): void
|
|
7
|
+
export type * from './typed-arrays'
|
|
8
|
+
import type { AudioContextOptions, AudioWorklet, MediaStreamAudioSourceNode } from './audio-worklet'
|
|
9
|
+
|
|
3
10
|
// Opt-in native 64-bit integer. Structurally a `number` (assign/read without
|
|
4
11
|
// casts), but where a binding, parameter, field, or return is annotated `int`,
|
|
5
12
|
// geatsc lowers it to a C++ `long long` and emits exact integer arithmetic
|
|
@@ -70,6 +77,7 @@ export interface GeaIntrinsicElements {
|
|
|
70
77
|
h5: NativeViewProps
|
|
71
78
|
h6: NativeViewProps
|
|
72
79
|
audio: AudioProps
|
|
80
|
+
video: VideoProps
|
|
73
81
|
button: NativeButtonProps
|
|
74
82
|
img: ImageProps
|
|
75
83
|
input: NativeInputElementProps
|
|
@@ -117,9 +125,13 @@ declare global {
|
|
|
117
125
|
// (`double setTimeout(TimerCallback, double)`), so both the id and the delay
|
|
118
126
|
// are `number`, and the callback takes no arguments (unlike the browser's,
|
|
119
127
|
// which forwards extra `setTimeout` arguments to it).
|
|
128
|
+
/** @gea-host-no-property-writes */
|
|
120
129
|
function setTimeout(callback: () => void, delayMs: number): number
|
|
130
|
+
/** @gea-host-no-property-writes */
|
|
121
131
|
function clearTimeout(id: number): void
|
|
132
|
+
/** @gea-host-no-property-writes */
|
|
122
133
|
function setInterval(callback: () => void, delayMs: number): number
|
|
134
|
+
/** @gea-host-no-property-writes */
|
|
123
135
|
function clearInterval(id: number): void
|
|
124
136
|
|
|
125
137
|
/**
|
|
@@ -364,6 +376,7 @@ export interface Document {
|
|
|
364
376
|
querySelector(selector: string): Element | null
|
|
365
377
|
querySelectorAll(selector: string): readonly Element[]
|
|
366
378
|
createElement(tag: 'audio'): HTMLAudioElement
|
|
379
|
+
createElement(tag: 'video'): HTMLVideoElement
|
|
367
380
|
createElement(tag: 'virtual-list'): VirtualListElement
|
|
368
381
|
createElement(tag: string): Element
|
|
369
382
|
createTextNode(text: string): Node
|
|
@@ -596,13 +609,28 @@ export interface AudioProps extends DataAttributes {
|
|
|
596
609
|
autoplay?: boolean | string | number
|
|
597
610
|
controls?: boolean | string | number
|
|
598
611
|
loop?: boolean | string | number
|
|
599
|
-
ref?: HTMLAudioElement | null
|
|
612
|
+
ref?: HTMLAudioElement | (typeof globalThis extends { HTMLAudioElement: { prototype: infer E } } ? E : never) | null
|
|
613
|
+
autoPlay?: boolean
|
|
600
614
|
children?: any
|
|
601
615
|
}
|
|
602
616
|
|
|
617
|
+
export interface VideoProps extends DataAttributes {
|
|
618
|
+
id?: string
|
|
619
|
+
class?: ClassValue
|
|
620
|
+
style?: Style
|
|
621
|
+
autoplay?: boolean
|
|
622
|
+
muted?: boolean
|
|
623
|
+
playsinline?: boolean
|
|
624
|
+
autoPlay?: boolean
|
|
625
|
+
playsInline?: boolean
|
|
626
|
+
ref?: HTMLVideoElement | (typeof globalThis extends { HTMLVideoElement: { prototype: infer E } } ? E : never) | null
|
|
627
|
+
}
|
|
628
|
+
|
|
603
629
|
export type ImageSource = string | ArrayBuffer | Uint8Array | GeaEmbeddedImage
|
|
604
630
|
|
|
605
631
|
export interface ImageProps extends DataAttributes {
|
|
632
|
+
alt?: string
|
|
633
|
+
key?: string | number
|
|
606
634
|
id?: string
|
|
607
635
|
class?: ClassValue
|
|
608
636
|
// Optional: a static template can leave this unset and apply the source
|
|
@@ -1300,15 +1328,26 @@ export interface OscillatorNode {
|
|
|
1300
1328
|
}
|
|
1301
1329
|
|
|
1302
1330
|
export interface AudioContext {
|
|
1331
|
+
/** Conservative maximum software buffering delay, in seconds. */
|
|
1332
|
+
readonly baseLatency: number
|
|
1333
|
+
/** Device buffering estimate in seconds; zero when unavailable. */
|
|
1334
|
+
readonly outputLatency: number
|
|
1335
|
+
readonly sampleRate: number
|
|
1336
|
+
readonly state: 'running' | 'suspended' | 'closed'
|
|
1337
|
+
readonly audioWorklet: AudioWorklet
|
|
1303
1338
|
readonly currentTime: number
|
|
1304
1339
|
readonly destination: AudioDestinationNode
|
|
1305
1340
|
createOscillator(): OscillatorNode
|
|
1306
1341
|
createBufferSource(): AudioBufferSourceNode
|
|
1307
1342
|
decodeAudioData(audioData: ArrayBuffer | Uint8Array | GeaAudioBlob): Promise<AudioBuffer>
|
|
1343
|
+
createMediaStreamSource(stream: MediaStream): MediaStreamAudioSourceNode
|
|
1344
|
+
resume(): Promise<void>
|
|
1345
|
+
suspend(): Promise<void>
|
|
1346
|
+
close(): Promise<void>
|
|
1308
1347
|
}
|
|
1309
1348
|
|
|
1310
1349
|
export interface AudioContextConstructor {
|
|
1311
|
-
new (): AudioContext
|
|
1350
|
+
new (options?: AudioContextOptions): AudioContext
|
|
1312
1351
|
}
|
|
1313
1352
|
|
|
1314
1353
|
export declare const audioContext: AudioContext
|
|
@@ -1531,6 +1570,7 @@ export interface ButtonProps {
|
|
|
1531
1570
|
}
|
|
1532
1571
|
|
|
1533
1572
|
export interface NativeButtonProps extends NativeEventAttributes {
|
|
1573
|
+
disabled?: boolean
|
|
1534
1574
|
key?: string | number
|
|
1535
1575
|
class?: ClassValue
|
|
1536
1576
|
style?: Style
|
|
@@ -1653,9 +1693,13 @@ export interface FetchResponse {
|
|
|
1653
1693
|
bytes(): Uint8Array
|
|
1654
1694
|
}
|
|
1655
1695
|
|
|
1696
|
+
/** @gea-host-no-property-writes */
|
|
1656
1697
|
export declare function fetchAsync(url: string, init?: FetchRequestInit): number
|
|
1698
|
+
/** @gea-host-no-property-writes */
|
|
1657
1699
|
export declare function fetchReady(id: number): boolean
|
|
1700
|
+
/** @gea-host-no-property-writes */
|
|
1658
1701
|
export declare function fetchResult(id: number): FetchResponse
|
|
1702
|
+
/** @gea-host-no-property-writes */
|
|
1659
1703
|
export declare function fetchRelease(id: number): void
|
|
1660
1704
|
|
|
1661
1705
|
/**
|
|
@@ -1692,6 +1736,7 @@ export declare function fetchUploadTotal(id: number): number
|
|
|
1692
1736
|
|
|
1693
1737
|
declare global {
|
|
1694
1738
|
function fetch(url: string, init?: FetchRequestInit): FetchResponse
|
|
1739
|
+
/** @gea-host-no-property-writes */
|
|
1695
1740
|
function fetchAsync(url: string, init?: FetchRequestInit): number
|
|
1696
1741
|
function fetchUploadFileAsync(
|
|
1697
1742
|
url: string,
|
|
@@ -1705,8 +1750,11 @@ declare global {
|
|
|
1705
1750
|
function fetchUploadProgress(id: number): number
|
|
1706
1751
|
function fetchUploadSent(id: number): number
|
|
1707
1752
|
function fetchUploadTotal(id: number): number
|
|
1753
|
+
/** @gea-host-no-property-writes */
|
|
1708
1754
|
function fetchReady(id: number): boolean
|
|
1755
|
+
/** @gea-host-no-property-writes */
|
|
1709
1756
|
function fetchResult(id: number): FetchResponse
|
|
1757
|
+
/** @gea-host-no-property-writes */
|
|
1710
1758
|
function fetchRelease(id: number): void
|
|
1711
1759
|
function atob(data: string): string
|
|
1712
1760
|
function btoa(data: string | ArrayBuffer | Uint8Array): string
|
|
@@ -1727,18 +1775,20 @@ export interface WebSocketErrorEvent {
|
|
|
1727
1775
|
}
|
|
1728
1776
|
|
|
1729
1777
|
export interface WebSocketInstance {
|
|
1778
|
+
readonly bufferedAmount: number
|
|
1730
1779
|
readonly url: string
|
|
1731
1780
|
readonly readyState: number
|
|
1732
1781
|
onopen: (() => void) | null
|
|
1733
1782
|
onmessage: ((event: WebSocketMessageEvent) => void) | null
|
|
1734
1783
|
onclose: ((event: WebSocketCloseEvent) => void) | null
|
|
1735
1784
|
onerror: ((event: WebSocketErrorEvent) => void) | null
|
|
1785
|
+
/** @gea-host-no-property-writes */
|
|
1736
1786
|
send(data: string): void
|
|
1737
1787
|
close(code?: number, reason?: string): void
|
|
1738
1788
|
}
|
|
1739
1789
|
|
|
1740
1790
|
export interface WebSocketConstructor {
|
|
1741
|
-
new (url: string): WebSocketInstance
|
|
1791
|
+
new (url: string, protocols?: string | string[]): WebSocketInstance
|
|
1742
1792
|
readonly CONNECTING: 0
|
|
1743
1793
|
readonly OPEN: 1
|
|
1744
1794
|
readonly CLOSING: 2
|
|
@@ -1805,7 +1855,7 @@ export declare const http: HttpModule
|
|
|
1805
1855
|
|
|
1806
1856
|
export interface MediaStreamTrack {
|
|
1807
1857
|
readonly id: string
|
|
1808
|
-
readonly kind:
|
|
1858
|
+
readonly kind: string
|
|
1809
1859
|
enabled: boolean
|
|
1810
1860
|
readonly readyState: 'live' | 'ended'
|
|
1811
1861
|
stop(): void
|
|
@@ -1813,12 +1863,19 @@ export interface MediaStreamTrack {
|
|
|
1813
1863
|
|
|
1814
1864
|
export interface MediaStream {
|
|
1815
1865
|
readonly id: string
|
|
1866
|
+
readonly active: boolean
|
|
1816
1867
|
getAudioTracks(): MediaStreamTrack[]
|
|
1868
|
+
getVideoTracks(): MediaStreamTrack[]
|
|
1817
1869
|
getTracks(): MediaStreamTrack[]
|
|
1870
|
+
getTrackById(id: string): MediaStreamTrack | null
|
|
1871
|
+
addTrack(track: MediaStreamTrack): void
|
|
1872
|
+
removeTrack(track: MediaStreamTrack): void
|
|
1818
1873
|
}
|
|
1819
1874
|
|
|
1820
1875
|
export interface MediaStreamConstructor {
|
|
1821
1876
|
new (): MediaStream
|
|
1877
|
+
new (stream: MediaStream): MediaStream
|
|
1878
|
+
new (tracks: MediaStreamTrack[]): MediaStream
|
|
1822
1879
|
}
|
|
1823
1880
|
|
|
1824
1881
|
export interface MediaStreamConstraints {
|
|
@@ -1863,10 +1920,34 @@ export interface MediaRecorderConstructor {
|
|
|
1863
1920
|
|
|
1864
1921
|
export interface HTMLAudioElement extends Element {
|
|
1865
1922
|
src: string
|
|
1923
|
+
srcObject: MediaStream | null
|
|
1924
|
+
autoplay: boolean
|
|
1925
|
+
readonly paused: boolean
|
|
1866
1926
|
currentTime: number
|
|
1867
1927
|
volume: number
|
|
1868
1928
|
loop: boolean
|
|
1869
|
-
play(): void
|
|
1929
|
+
play(): Promise<void>
|
|
1930
|
+
pause(): void
|
|
1931
|
+
/** Freeze the current PCM queue endpoint; later RTP silence is excluded. */
|
|
1932
|
+
beginDrain(): void
|
|
1933
|
+
/** Discard queued speech while keeping the live output clock running. */
|
|
1934
|
+
clearBufferedAudio(): void
|
|
1935
|
+
/** Queued PCM has reached the output driver. Hardware DMA drains on capture handoff. */
|
|
1936
|
+
readonly drained: boolean
|
|
1937
|
+
/** RMS of PCM being pulled for playback, normalized to 0–1. */
|
|
1938
|
+
readonly audioLevel: number
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
export interface HTMLVideoElement extends Element {
|
|
1942
|
+
/** Native HTTP multipart JPEG streaming; decoded on native network/video workers. */
|
|
1943
|
+
src: string
|
|
1944
|
+
srcObject: MediaStream | null
|
|
1945
|
+
autoplay: boolean
|
|
1946
|
+
readonly paused: boolean
|
|
1947
|
+
readonly videoWidth: number
|
|
1948
|
+
readonly videoHeight: number
|
|
1949
|
+
onplaying: (() => void) | null
|
|
1950
|
+
play(): Promise<void>
|
|
1870
1951
|
pause(): void
|
|
1871
1952
|
}
|
|
1872
1953
|
|
|
@@ -1875,6 +1956,13 @@ export interface AudioConstructor {
|
|
|
1875
1956
|
}
|
|
1876
1957
|
|
|
1877
1958
|
declare global {
|
|
1959
|
+
interface HTMLAudioElement {
|
|
1960
|
+
beginDrain(): void
|
|
1961
|
+
clearBufferedAudio(): void
|
|
1962
|
+
readonly drained: boolean
|
|
1963
|
+
/** RMS of PCM being pulled for playback, normalized to 0–1. */
|
|
1964
|
+
readonly audioLevel: number
|
|
1965
|
+
}
|
|
1878
1966
|
interface Blob {
|
|
1879
1967
|
readonly path: string
|
|
1880
1968
|
}
|
|
@@ -1907,10 +1995,54 @@ export interface RTCSessionDescriptionInit {
|
|
|
1907
1995
|
sdp?: string
|
|
1908
1996
|
}
|
|
1909
1997
|
|
|
1998
|
+
export interface RTCSessionDescription {
|
|
1999
|
+
readonly type: RTCSessionDescriptionInit['type']
|
|
2000
|
+
readonly sdp: string
|
|
2001
|
+
toJSON(): RTCSessionDescriptionInit
|
|
2002
|
+
}
|
|
2003
|
+
export interface RTCSessionDescriptionConstructor {
|
|
2004
|
+
new (init: RTCSessionDescriptionInit): RTCSessionDescription
|
|
2005
|
+
}
|
|
2006
|
+
declare global {
|
|
2007
|
+
const RTCSessionDescription: RTCSessionDescriptionConstructor
|
|
2008
|
+
}
|
|
2009
|
+
|
|
1910
2010
|
export interface RTCIceCandidateInit {
|
|
1911
|
-
candidate
|
|
2011
|
+
candidate?: string
|
|
1912
2012
|
sdpMid?: string | null
|
|
1913
2013
|
sdpMLineIndex?: number | null
|
|
2014
|
+
usernameFragment?: string | null
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
export interface RTCLocalIceCandidateInit extends RTCIceCandidateInit {
|
|
2018
|
+
relayProtocol?: 'udp' | 'tcp' | 'tls' | null
|
|
2019
|
+
url?: string | null
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
export interface RTCIceCandidate {
|
|
2023
|
+
readonly candidate: string
|
|
2024
|
+
readonly sdpMid: string | null
|
|
2025
|
+
readonly sdpMLineIndex: number | null
|
|
2026
|
+
readonly foundation: string | null
|
|
2027
|
+
readonly component: 'rtp' | 'rtcp' | null
|
|
2028
|
+
readonly priority: number | null
|
|
2029
|
+
readonly address: string | null
|
|
2030
|
+
readonly protocol: 'udp' | 'tcp' | null
|
|
2031
|
+
readonly port: number | null
|
|
2032
|
+
readonly type: 'host' | 'srflx' | 'prflx' | 'relay' | null
|
|
2033
|
+
readonly tcpType: 'active' | 'passive' | 'so' | null
|
|
2034
|
+
readonly relatedAddress: string | null
|
|
2035
|
+
readonly relatedPort: number | null
|
|
2036
|
+
readonly usernameFragment: string | null
|
|
2037
|
+
readonly relayProtocol: 'udp' | 'tcp' | 'tls' | null
|
|
2038
|
+
readonly url: string | null
|
|
2039
|
+
toJSON(): RTCIceCandidateInit
|
|
2040
|
+
}
|
|
2041
|
+
export interface RTCIceCandidateConstructor {
|
|
2042
|
+
new (init?: RTCLocalIceCandidateInit): RTCIceCandidate
|
|
2043
|
+
}
|
|
2044
|
+
declare global {
|
|
2045
|
+
const RTCIceCandidate: RTCIceCandidateConstructor
|
|
1914
2046
|
}
|
|
1915
2047
|
|
|
1916
2048
|
export interface RTCIceServer {
|
|
@@ -1921,15 +2053,61 @@ export interface RTCIceServer {
|
|
|
1921
2053
|
|
|
1922
2054
|
export interface RTCConfiguration {
|
|
1923
2055
|
iceServers?: RTCIceServer[]
|
|
2056
|
+
iceTransportPolicy?: 'all' | 'relay'
|
|
1924
2057
|
}
|
|
1925
2058
|
|
|
1926
2059
|
export interface RTCPeerConnectionIceEvent {
|
|
1927
|
-
readonly candidate:
|
|
2060
|
+
readonly candidate: RTCIceCandidate | null
|
|
1928
2061
|
}
|
|
1929
2062
|
|
|
1930
2063
|
export interface RTCTrackEvent {
|
|
1931
2064
|
readonly track: MediaStreamTrack
|
|
1932
2065
|
readonly streams: readonly MediaStream[]
|
|
2066
|
+
readonly receiver: RTCRtpReceiver
|
|
2067
|
+
readonly transceiver: RTCRtpTransceiver
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
export interface RTCDataChannelInit {
|
|
2071
|
+
ordered?: boolean
|
|
2072
|
+
maxPacketLifeTime?: number
|
|
2073
|
+
maxRetransmits?: number
|
|
2074
|
+
protocol?: string
|
|
2075
|
+
negotiated?: boolean
|
|
2076
|
+
id?: number
|
|
2077
|
+
}
|
|
2078
|
+
export interface RTCDataChannelMessageEvent { readonly data: string | ArrayBuffer }
|
|
2079
|
+
export interface RTCDataChannel {
|
|
2080
|
+
readonly label: string
|
|
2081
|
+
readonly protocol: string
|
|
2082
|
+
readonly ordered: boolean
|
|
2083
|
+
readonly id: number | null
|
|
2084
|
+
readonly maxPacketLifeTime: number | null
|
|
2085
|
+
readonly maxRetransmits: number | null
|
|
2086
|
+
readonly readyState: 'connecting' | 'open' | 'closing' | 'closed'
|
|
2087
|
+
binaryType: 'arraybuffer'
|
|
2088
|
+
readonly bufferedAmount: number
|
|
2089
|
+
bufferedAmountLowThreshold: number
|
|
2090
|
+
onopen: (() => void) | null
|
|
2091
|
+
onclose: (() => void) | null
|
|
2092
|
+
onmessage: ((event: RTCDataChannelMessageEvent) => void) | null
|
|
2093
|
+
onbufferedamountlow: (() => void) | null
|
|
2094
|
+
send(data: string | ArrayBuffer | Uint8Array): void
|
|
2095
|
+
close(): void
|
|
2096
|
+
}
|
|
2097
|
+
export interface RTCRtpSender {
|
|
2098
|
+
readonly track: MediaStreamTrack | null
|
|
2099
|
+
replaceTrack(track: MediaStreamTrack | null): Promise<void>
|
|
2100
|
+
}
|
|
2101
|
+
export interface RTCRtpReceiver { readonly track: MediaStreamTrack | null }
|
|
2102
|
+
export interface RTCRtpTransceiverInit { direction?: 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive' }
|
|
2103
|
+
export interface RTCRtpTransceiver {
|
|
2104
|
+
readonly sender: RTCRtpSender
|
|
2105
|
+
readonly receiver: RTCRtpReceiver
|
|
2106
|
+
readonly mid: string | null
|
|
2107
|
+
direction: 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive'
|
|
2108
|
+
readonly currentDirection: 'sendrecv' | 'sendonly' | 'recvonly' | 'inactive' | null
|
|
2109
|
+
readonly stopped: boolean
|
|
2110
|
+
stop(): void
|
|
1933
2111
|
}
|
|
1934
2112
|
|
|
1935
2113
|
export interface RTCPeerConnectionInstance {
|
|
@@ -1941,7 +2119,19 @@ export interface RTCPeerConnectionInstance {
|
|
|
1941
2119
|
onconnectionstatechange: (() => void) | null
|
|
1942
2120
|
oniceconnectionstatechange: (() => void) | null
|
|
1943
2121
|
|
|
1944
|
-
|
|
2122
|
+
readonly signalingState: 'stable' | 'have-local-offer' | 'have-remote-offer' | 'closed'
|
|
2123
|
+
readonly localDescription: RTCSessionDescription | null
|
|
2124
|
+
readonly remoteDescription: RTCSessionDescription | null
|
|
2125
|
+
onsignalingstatechange: (() => void) | null
|
|
2126
|
+
onnegotiationneeded: (() => void) | null
|
|
2127
|
+
ondatachannel: ((event: { channel: RTCDataChannel }) => void) | null
|
|
2128
|
+
addTrack(track: MediaStreamTrack, stream?: MediaStream): RTCRtpSender
|
|
2129
|
+
removeTrack(sender: RTCRtpSender): void
|
|
2130
|
+
addTransceiver(trackOrKind: MediaStreamTrack | 'audio', init?: RTCRtpTransceiverInit): RTCRtpTransceiver
|
|
2131
|
+
getTransceivers(): RTCRtpTransceiver[]
|
|
2132
|
+
getSenders(): RTCRtpSender[]
|
|
2133
|
+
getReceivers(): RTCRtpReceiver[]
|
|
2134
|
+
createDataChannel(label: string, init?: RTCDataChannelInit): RTCDataChannel
|
|
1945
2135
|
createOffer(): Promise<RTCSessionDescriptionInit>
|
|
1946
2136
|
createAnswer(): Promise<RTCSessionDescriptionInit>
|
|
1947
2137
|
setLocalDescription(desc: RTCSessionDescriptionInit): Promise<void>
|
|
@@ -1958,3 +2148,33 @@ declare global {
|
|
|
1958
2148
|
const RTCPeerConnection: RTCPeerConnectionConstructor
|
|
1959
2149
|
function Image(props: ImageProps): GeaJsxElement
|
|
1960
2150
|
}
|
|
2151
|
+
|
|
2152
|
+
|
|
2153
|
+
/** Streaming mono signed PCM16, little endian, carried as base64 text. */
|
|
2154
|
+
export interface PcmAudioStream {
|
|
2155
|
+
setInput(stream: MediaStream): void
|
|
2156
|
+
/** Capture and upload on the native socket worker, independently of UI callbacks. */
|
|
2157
|
+
pipeTo(socket: WebSocketInstance, prefix: string, suffix: string): void
|
|
2158
|
+
/** Decode matching PCM packets on the native receive worker; control messages still reach JS. */
|
|
2159
|
+
receiveFrom(socket: WebSocketInstance, prefix: string, suffix: string): void
|
|
2160
|
+
/** Read the next 40ms capture block, or an empty string if not ready. */
|
|
2161
|
+
readBase64(): string
|
|
2162
|
+
writeBase64(data: string): void
|
|
2163
|
+
resetPlayback(interrupted?: boolean): void
|
|
2164
|
+
close(): void
|
|
2165
|
+
readonly queuedMs: number
|
|
2166
|
+
/** Conservative audible duration, excluding mixer and device DMA latency. */
|
|
2167
|
+
readonly playedMs: number
|
|
2168
|
+
readonly drained: boolean
|
|
2169
|
+
readonly audioLevel: number
|
|
2170
|
+
readonly capturePendingMs: number
|
|
2171
|
+
readonly captureDroppedSamples: number
|
|
2172
|
+
readonly capturePackets: number
|
|
2173
|
+
}
|
|
2174
|
+
export interface PcmAudioStreamConstructor {
|
|
2175
|
+
new (sampleRate: number): PcmAudioStream
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
declare global {
|
|
2179
|
+
const PcmAudioStream: PcmAudioStreamConstructor
|
|
2180
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geastack/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.35",
|
|
4
4
|
"description": "GeaStack app API, reactivity headers, runtime sources, and type declarations.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
"files": [
|
|
35
35
|
"app_frame_perf.cpp",
|
|
36
36
|
"css.d.ts",
|
|
37
|
+
"workers.d.ts",
|
|
38
|
+
"audio-worklet.d.ts",
|
|
39
|
+
"typed-arrays.d.ts",
|
|
37
40
|
"events.cpp",
|
|
38
41
|
"gea_sources.sh",
|
|
39
42
|
"gea_sources.mjs",
|
|
@@ -63,7 +66,7 @@
|
|
|
63
66
|
"@geajs/core": "1.5.1",
|
|
64
67
|
"@geajs/vite-plugin": "1.5.0",
|
|
65
68
|
"@geastack/compiler": "^1.0.20",
|
|
66
|
-
"@geastack/geatsc-plugin-gea": "^0.1.
|
|
69
|
+
"@geastack/geatsc-plugin-gea": "^0.1.15",
|
|
67
70
|
"opentype.js": "^2.0.0",
|
|
68
71
|
"vite": "^8.0.0"
|
|
69
72
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { MessagePort } from '../workers.js'
|
|
2
|
+
|
|
3
|
+
/** Native implementations of the AudioWorkletGlobalScope's two class APIs.
|
|
4
|
+
* The module loader supplies these lexical bindings to compiled worklet modules;
|
|
5
|
+
* applications use the browser globals, without imports or platform branches.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare function __geaAudioWorkletProcessorPort(): MessagePort
|
|
9
|
+
declare function __geaFlushAudioWorkletOutput(): void
|
|
10
|
+
|
|
11
|
+
/** Gea hardware cancellation extension; capture remains active. */
|
|
12
|
+
export function flushAudioWorkletOutput(): void {
|
|
13
|
+
__geaFlushAudioWorkletOutput()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
declare function __geaRegisterAudioWorkletProcessor(
|
|
17
|
+
name: string,
|
|
18
|
+
create: () => AudioWorkletProcessor,
|
|
19
|
+
process: (
|
|
20
|
+
processor: AudioWorkletProcessor,
|
|
21
|
+
inputs: Float32Array[][],
|
|
22
|
+
outputs: Float32Array[][]
|
|
23
|
+
) => boolean
|
|
24
|
+
): void
|
|
25
|
+
|
|
26
|
+
export abstract class AudioWorkletProcessor {
|
|
27
|
+
readonly port: MessagePort
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
this.port = __geaAudioWorkletProcessorPort()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
abstract process(
|
|
34
|
+
inputs: Float32Array[][],
|
|
35
|
+
outputs: Float32Array[][],
|
|
36
|
+
parameters: Record<string, Float32Array>
|
|
37
|
+
): boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The native module builder validates the concrete registration constructor.
|
|
41
|
+
// AudioParam descriptors are explicitly unsupported, before code generation.
|
|
42
|
+
export function registerProcessor(
|
|
43
|
+
name: string,
|
|
44
|
+
constructor: new () => AudioWorkletProcessor
|
|
45
|
+
): void {
|
|
46
|
+
__geaRegisterAudioWorkletProcessor(
|
|
47
|
+
name,
|
|
48
|
+
() => new constructor(),
|
|
49
|
+
(processor, inputs, outputs) => processor.process(inputs, outputs, {})
|
|
50
|
+
)
|
|
51
|
+
}
|
package/runtime-surface.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export * from './runtime/compiler'
|
|
2
|
+
export type * from './workers'
|
|
3
|
+
export type * from './audio-worklet'
|
|
4
|
+
export { flushAudioWorkletOutput } from './runtime/audio-worklet'
|
|
2
5
|
export * from './runtime/host'
|
|
3
6
|
export * from './runtime/ble'
|
|
4
7
|
export * from './runtime/images'
|
|
@@ -109,6 +112,10 @@ export type {
|
|
|
109
112
|
GeolocationPosition,
|
|
110
113
|
GeolocationPositionError,
|
|
111
114
|
HTMLAudioElement,
|
|
115
|
+
PcmAudioStream,
|
|
116
|
+
PcmAudioStreamConstructor,
|
|
117
|
+
HTMLVideoElement,
|
|
118
|
+
VideoProps,
|
|
112
119
|
HttpModule,
|
|
113
120
|
HttpRequestHandler,
|
|
114
121
|
HttpServer,
|
|
@@ -8,6 +8,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
|
8
8
|
import { inlineJsonImports, transformGeaEmbeddedCompatSource } from './gea-embedded-compat-transform.mjs'
|
|
9
9
|
import { normalizeEmbeddedJsxOptions, shouldIgnoreCompatStagingDirectory } from './gea-embedded-compat-staging.mjs'
|
|
10
10
|
import { dotEnvDefines, inlineProcessEnv } from './dotenv-defines.mjs'
|
|
11
|
+
import { collectWorkerModuleSources, writeWorkerRegistry, validateWorkletRegistrations } from './gea-worker-modules.mjs'
|
|
11
12
|
import { resolveCompilerRuntimeEntry } from './gea-native-style-plugin.mjs'
|
|
12
13
|
import {
|
|
13
14
|
MODULE_HINT_SCOPE,
|
|
@@ -20,6 +21,8 @@ import {
|
|
|
20
21
|
restoreModuleGraphElAnnotations,
|
|
21
22
|
} from './gea-bundle-type-hints.mjs'
|
|
22
23
|
|
|
24
|
+
const nativeModules = new Map()
|
|
25
|
+
let nativeModuleSources = new Map()
|
|
23
26
|
const args = process.argv.slice(2)
|
|
24
27
|
const requireFromLib = createRequire(new URL('../package.json', import.meta.url))
|
|
25
28
|
const coreRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
@@ -246,7 +249,11 @@ function copyCompatSourceTree(srcDir, dstDir, envDefines = {}) {
|
|
|
246
249
|
// (the fully native store/record lowering path). Then bake in .env vars
|
|
247
250
|
// (process.env.<KEY> -> literal) so the module-graph snapshots geatsc
|
|
248
251
|
// compiles carry the value — Vite's `define` only rewrites the bundle.
|
|
249
|
-
|
|
252
|
+
const native = nativeModuleSources.get(src) ?? { code, modules: [] }
|
|
253
|
+
for (const module of native.modules) {
|
|
254
|
+
nativeModules.set(`${module.kind}:${module.url}`, { ...module, stagedEntry: path.resolve(path.dirname(dst), path.relative(path.dirname(src), module.entry)) })
|
|
255
|
+
}
|
|
256
|
+
fs.writeFileSync(dst, inlineProcessEnv(transformGeaEmbeddedCompatSource(inlineJsonImports(native.code, src), src), envDefines))
|
|
250
257
|
} else {
|
|
251
258
|
fs.copyFileSync(src, dst)
|
|
252
259
|
if (path.extname(entry.name) === '.css') copyCssUrlAssets(src, dst)
|
|
@@ -304,7 +311,7 @@ function linkCompatNodeModules(appDir, stagedAppDir, compatSrcDir) {
|
|
|
304
311
|
// staging its containing directory wholesale (which also brings the css/asset
|
|
305
312
|
// files discoverLocalImport skips).
|
|
306
313
|
function escapedCompatImportDirs(appDir, entry) {
|
|
307
|
-
const escaped = collectReachableSourceFiles(appDir, entry).filter((file) => path.relative(appDir, file).startsWith('..'))
|
|
314
|
+
const escaped = [...new Set([...collectReachableSourceFiles(appDir, entry), ...nativeModuleSources.keys()])].filter((file) => path.relative(appDir, file).startsWith('..'))
|
|
308
315
|
const dirs = [...new Set(escaped.map((file) => path.dirname(file)))].sort()
|
|
309
316
|
return dirs.filter((dir, index) => !dirs.slice(0, index).some((outer) => outer !== dir && !path.relative(outer, dir).startsWith('..')))
|
|
310
317
|
}
|
|
@@ -4393,6 +4400,8 @@ let stagedEntryFile = null
|
|
|
4393
4400
|
let fontSourceDir = appDir
|
|
4394
4401
|
|
|
4395
4402
|
if (geaEmbeddedCompat) {
|
|
4403
|
+
nativeModuleSources = collectWorkerModuleSources(path.resolve(appDir, entry),
|
|
4404
|
+
(file) => collectReachableSourceFiles(path.dirname(file), path.basename(file)))
|
|
4396
4405
|
const compatSrcDir = path.join(outDir, 'gea-embedded-compat-src')
|
|
4397
4406
|
fs.rmSync(compatSrcDir, { recursive: true, force: true })
|
|
4398
4407
|
// Relative imports may escape the app dir (examples/shared components).
|
|
@@ -4587,7 +4596,46 @@ if (hasFlag('--gea-ir-backend') || hasFlag('--gea-replace-renderers')) {
|
|
|
4587
4596
|
// measurement scripts are always run with this
|
|
4588
4597
|
// limit; the build has to state the same one, not depend on the caller's
|
|
4589
4598
|
// NODE_OPTIONS.
|
|
4590
|
-
|
|
4599
|
+
// Native interface call graphs can exceed V8's default ~1 MiB stack during
|
|
4600
|
+
// closure analysis; keep the compiler stack below the host's 8 MiB limit.
|
|
4601
|
+
run('node', ['--stack_size=8192', '--max-old-space-size=32768', ...geatscArgs])
|
|
4602
|
+
|
|
4603
|
+
if (nativeModules.size) {
|
|
4604
|
+
const nativeSources = []
|
|
4605
|
+
for (const module of nativeModules.values()) {
|
|
4606
|
+
if (!fs.existsSync(module.stagedEntry)) fail(`missing ${module.kind} module: ${module.entry}`)
|
|
4607
|
+
if (module.kind === 'worklet') {
|
|
4608
|
+
const implementation = path.join(coreRoot, 'runtime/audio-worklet.ts')
|
|
4609
|
+
const bindings = `import { AudioWorkletProcessor, registerProcessor } from ${JSON.stringify(implementation)}\n`
|
|
4610
|
+
const source = fs.readFileSync(module.stagedEntry, 'utf8')
|
|
4611
|
+
fs.writeFileSync(module.stagedEntry, bindings + source)
|
|
4612
|
+
const compilerRequire = createRequire(pathToFileURL(geatscBin))
|
|
4613
|
+
validateWorkletRegistrations(compilerRequire('typescript'), module.stagedEntry, implementation)
|
|
4614
|
+
}
|
|
4615
|
+
const moduleOut = path.join(outDir, `${module.kind}-${module.id}`)
|
|
4616
|
+
const moduleArgs = [
|
|
4617
|
+
geatscBin, 'compile', module.stagedEntry, '--out-dir', moduleOut,
|
|
4618
|
+
'--target', 'cpp', '--plugin', geaPluginSpecifier,
|
|
4619
|
+
'--entry-symbol', module.symbol, '--isolate-symbols', '--realm-storage',
|
|
4620
|
+
'--plugin-option', `gea.microtasks-namespace=gea::framework::app::generated::gea_${module.kind}_${module.id}`,
|
|
4621
|
+
]
|
|
4622
|
+
if (cppBoard) moduleArgs.push('--cpp-board', cppBoard)
|
|
4623
|
+
if (cxxStandard) moduleArgs.push('--cxx-standard', cxxStandard)
|
|
4624
|
+
run('node', ['--stack_size=8192', '--max-old-space-size=32768', ...moduleArgs])
|
|
4625
|
+
const list = fs.readFileSync(path.join(moduleOut, 'geatsc-sources.txt'), 'utf8').split(/\r?\n/).filter(Boolean)
|
|
4626
|
+
nativeSources.push(...list.filter((source) => path.basename(source) !== 'gea_runtime_builtins.cpp'))
|
|
4627
|
+
}
|
|
4628
|
+
const listPath = path.join(outDir, 'geatsc-sources.txt')
|
|
4629
|
+
const sources = fs.readFileSync(listPath, 'utf8').split(/\r?\n/).filter(Boolean)
|
|
4630
|
+
const registry = path.join(outDir, 'gea_worker_modules.cpp')
|
|
4631
|
+
writeWorkerRegistry([...nativeModules.values()], registry)
|
|
4632
|
+
// The app entry and its native registrations must be in one archive member:
|
|
4633
|
+
// constructor-only members are not extracted by ordinary static linking.
|
|
4634
|
+
const nativeEntry = path.join(outDir, 'gea_native_entry.cpp')
|
|
4635
|
+
fs.writeFileSync(nativeEntry, `#include ${JSON.stringify(sources[0])}\n#include ${JSON.stringify(registry)}\n`)
|
|
4636
|
+
fs.writeFileSync(listPath, [nativeEntry, ...sources.slice(1), ...nativeSources].join('\n') + '\n')
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4591
4639
|
|
|
4592
4640
|
process.stdout.write(`gea-vite-bundle=${bundlePath}\n`)
|
|
4593
4641
|
if (moduleGraphOutDir) process.stdout.write(`module-graph=${path.join(moduleGraphOutDir, 'gea-module-graph.json')}\n`)
|
|
@@ -156,8 +156,16 @@ export function discoverLocalImport(source, srcId, localImports) {
|
|
|
156
156
|
if (source.endsWith('.css')) return
|
|
157
157
|
const base = resolveLocalImportBase(source, srcId)
|
|
158
158
|
if (!base) return
|
|
159
|
+
// TypeScript's ESM imports name the emitted .js/.mjs/.cjs file while the
|
|
160
|
+
// source tree contains .ts/.mts/.cts. Follow those edges before staging.
|
|
161
|
+
const extension = path.extname(base)
|
|
162
|
+
const sourceExtensions = extension === '.js' ? ['.ts', '.tsx', '.d.ts']
|
|
163
|
+
: extension === '.mjs' ? ['.mts', '.d.mts']
|
|
164
|
+
: extension === '.cjs' ? ['.cts', '.d.cts'] : []
|
|
165
|
+
const stem = base.slice(0, base.length - extension.length)
|
|
159
166
|
for (const candidate of [
|
|
160
167
|
base,
|
|
168
|
+
...sourceExtensions.map((extension) => stem + extension),
|
|
161
169
|
base + '.tsx',
|
|
162
170
|
base + '.ts',
|
|
163
171
|
base + '.jsx',
|
|
@@ -177,7 +185,7 @@ export function discoverLocalImport(source, srcId, localImports) {
|
|
|
177
185
|
// non-ASCII byte (`wOFF` header → "Unexpected character" at column 4).
|
|
178
186
|
// Assets aren't parseable modules; skip them (the added-extension
|
|
179
187
|
// candidates below are always JS/TS, so a genuine module still resolves).
|
|
180
|
-
if (!/\.(?:
|
|
188
|
+
if (!/\.(?:[cm]?[jt]s|jsx|tsx)$/i.test(candidate)) break
|
|
181
189
|
localImports.push(candidate)
|
|
182
190
|
break
|
|
183
191
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { createHash } from 'node:crypto'
|
|
4
|
+
|
|
5
|
+
// One identity for Vite's native module graph and the firmware lookup table.
|
|
6
|
+
export function describeStaticAsset(source) {
|
|
7
|
+
const contents = fs.readFileSync(source)
|
|
8
|
+
const sha256 = createHash('sha256').update(contents).digest('hex')
|
|
9
|
+
return {
|
|
10
|
+
source,
|
|
11
|
+
bytes: contents.length,
|
|
12
|
+
sha256,
|
|
13
|
+
url: `gea-asset://sha256/${sha256}/${encodeURIComponent(path.basename(source))}`,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { describeStaticAsset } from './gea-static-asset.mjs'
|
|
1
2
|
import crypto from 'node:crypto'
|
|
2
3
|
import fs from 'node:fs'
|
|
3
4
|
import path from 'node:path'
|
|
@@ -424,20 +425,6 @@ function entryReachableModuleIds(pluginContext, rawIdsByNormalizedId, allIds) {
|
|
|
424
425
|
return allIds.filter((id) => reachable.has(id))
|
|
425
426
|
}
|
|
426
427
|
|
|
427
|
-
function describeStaticAsset(source) {
|
|
428
|
-
const contents = fs.readFileSync(source)
|
|
429
|
-
const sha256 = crypto.createHash('sha256').update(contents).digest('hex')
|
|
430
|
-
// The hash makes the logical URL collision-safe and stable for unchanged
|
|
431
|
-
// bytes. The basename remains available to native bundle adapters, while the
|
|
432
|
-
// manifest is the authoritative URL -> source mapping.
|
|
433
|
-
const basename = encodeURIComponent(path.basename(source))
|
|
434
|
-
return {
|
|
435
|
-
source,
|
|
436
|
-
bytes: contents.length,
|
|
437
|
-
sha256,
|
|
438
|
-
url: `gea-asset://sha256/${sha256}/${basename}`,
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
428
|
|
|
442
429
|
async function captureResolvedImports(pluginContext, state, id, code) {
|
|
443
430
|
const normalized = normalizeModuleId(id)
|