@bloopjs/web 0.0.44 → 0.0.45

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/dist/mod.js CHANGED
@@ -2578,7 +2578,751 @@ var TIME_CTX_OFFSET2 = 0;
2578
2578
  var INPUT_CTX_OFFSET2 = TIME_CTX_OFFSET2 + 4;
2579
2579
  var EVENTS_OFFSET2 = INPUT_CTX_OFFSET2 + 4;
2580
2580
 
2581
+ // ../../node_modules/partysocket/dist/chunk-V6LO7DXK.mjs
2582
+ if (!globalThis.EventTarget || !globalThis.Event) {
2583
+ console.error(`
2584
+ PartySocket requires a global 'EventTarget' class to be available!
2585
+ You can polyfill this global by adding this to your code before any partysocket imports:
2586
+
2587
+ \`\`\`
2588
+ import 'partysocket/event-target-polyfill';
2589
+ \`\`\`
2590
+ Please file an issue at https://github.com/partykit/partykit if you're still having trouble.
2591
+ `);
2592
+ }
2593
+ var ErrorEvent = class extends Event {
2594
+ message;
2595
+ error;
2596
+ constructor(error, target) {
2597
+ super("error", target);
2598
+ this.message = error.message;
2599
+ this.error = error;
2600
+ }
2601
+ };
2602
+ var CloseEvent = class extends Event {
2603
+ code;
2604
+ reason;
2605
+ wasClean = true;
2606
+ constructor(code = 1000, reason = "", target) {
2607
+ super("close", target);
2608
+ this.code = code;
2609
+ this.reason = reason;
2610
+ }
2611
+ };
2612
+ var Events = {
2613
+ Event,
2614
+ ErrorEvent,
2615
+ CloseEvent
2616
+ };
2617
+ function assert2(condition, msg) {
2618
+ if (!condition) {
2619
+ throw new Error(msg);
2620
+ }
2621
+ }
2622
+ function cloneEventBrowser(e) {
2623
+ return new e.constructor(e.type, e);
2624
+ }
2625
+ function cloneEventNode(e) {
2626
+ if ("data" in e) {
2627
+ const evt2 = new MessageEvent(e.type, e);
2628
+ return evt2;
2629
+ }
2630
+ if ("code" in e || "reason" in e) {
2631
+ const evt2 = new CloseEvent(e.code || 1999, e.reason || "unknown reason", e);
2632
+ return evt2;
2633
+ }
2634
+ if ("error" in e) {
2635
+ const evt2 = new ErrorEvent(e.error, e);
2636
+ return evt2;
2637
+ }
2638
+ const evt = new Event(e.type, e);
2639
+ return evt;
2640
+ }
2641
+ var _a;
2642
+ var isNode = typeof process !== "undefined" && typeof ((_a = process.versions) == null ? undefined : _a.node) !== "undefined" && typeof document === "undefined";
2643
+ var cloneEvent = isNode ? cloneEventNode : cloneEventBrowser;
2644
+ var DEFAULT = {
2645
+ maxReconnectionDelay: 1e4,
2646
+ minReconnectionDelay: 1000 + Math.random() * 4000,
2647
+ minUptime: 5000,
2648
+ reconnectionDelayGrowFactor: 1.3,
2649
+ connectionTimeout: 4000,
2650
+ maxRetries: Number.POSITIVE_INFINITY,
2651
+ maxEnqueuedMessages: Number.POSITIVE_INFINITY,
2652
+ startClosed: false,
2653
+ debug: false
2654
+ };
2655
+ var didWarnAboutMissingWebSocket = false;
2656
+ var ReconnectingWebSocket = class _ReconnectingWebSocket extends EventTarget {
2657
+ _ws;
2658
+ _retryCount = -1;
2659
+ _uptimeTimeout;
2660
+ _connectTimeout;
2661
+ _shouldReconnect = true;
2662
+ _connectLock = false;
2663
+ _binaryType = "blob";
2664
+ _closeCalled = false;
2665
+ _messageQueue = [];
2666
+ _debugLogger = console.log.bind(console);
2667
+ _url;
2668
+ _protocols;
2669
+ _options;
2670
+ constructor(url, protocols, options = {}) {
2671
+ super();
2672
+ this._url = url;
2673
+ this._protocols = protocols;
2674
+ this._options = options;
2675
+ if (this._options.startClosed) {
2676
+ this._shouldReconnect = false;
2677
+ }
2678
+ if (this._options.debugLogger) {
2679
+ this._debugLogger = this._options.debugLogger;
2680
+ }
2681
+ this._connect();
2682
+ }
2683
+ static get CONNECTING() {
2684
+ return 0;
2685
+ }
2686
+ static get OPEN() {
2687
+ return 1;
2688
+ }
2689
+ static get CLOSING() {
2690
+ return 2;
2691
+ }
2692
+ static get CLOSED() {
2693
+ return 3;
2694
+ }
2695
+ get CONNECTING() {
2696
+ return _ReconnectingWebSocket.CONNECTING;
2697
+ }
2698
+ get OPEN() {
2699
+ return _ReconnectingWebSocket.OPEN;
2700
+ }
2701
+ get CLOSING() {
2702
+ return _ReconnectingWebSocket.CLOSING;
2703
+ }
2704
+ get CLOSED() {
2705
+ return _ReconnectingWebSocket.CLOSED;
2706
+ }
2707
+ get binaryType() {
2708
+ return this._ws ? this._ws.binaryType : this._binaryType;
2709
+ }
2710
+ set binaryType(value) {
2711
+ this._binaryType = value;
2712
+ if (this._ws) {
2713
+ this._ws.binaryType = value;
2714
+ }
2715
+ }
2716
+ get retryCount() {
2717
+ return Math.max(this._retryCount, 0);
2718
+ }
2719
+ get bufferedAmount() {
2720
+ const bytes = this._messageQueue.reduce((acc, message) => {
2721
+ if (typeof message === "string") {
2722
+ acc += message.length;
2723
+ } else if (message instanceof Blob) {
2724
+ acc += message.size;
2725
+ } else {
2726
+ acc += message.byteLength;
2727
+ }
2728
+ return acc;
2729
+ }, 0);
2730
+ return bytes + (this._ws ? this._ws.bufferedAmount : 0);
2731
+ }
2732
+ get extensions() {
2733
+ return this._ws ? this._ws.extensions : "";
2734
+ }
2735
+ get protocol() {
2736
+ return this._ws ? this._ws.protocol : "";
2737
+ }
2738
+ get readyState() {
2739
+ if (this._ws) {
2740
+ return this._ws.readyState;
2741
+ }
2742
+ return this._options.startClosed ? _ReconnectingWebSocket.CLOSED : _ReconnectingWebSocket.CONNECTING;
2743
+ }
2744
+ get url() {
2745
+ return this._ws ? this._ws.url : "";
2746
+ }
2747
+ get shouldReconnect() {
2748
+ return this._shouldReconnect;
2749
+ }
2750
+ onclose = null;
2751
+ onerror = null;
2752
+ onmessage = null;
2753
+ onopen = null;
2754
+ close(code = 1000, reason) {
2755
+ this._closeCalled = true;
2756
+ this._shouldReconnect = false;
2757
+ this._clearTimeouts();
2758
+ if (!this._ws) {
2759
+ this._debug("close enqueued: no ws instance");
2760
+ return;
2761
+ }
2762
+ if (this._ws.readyState === this.CLOSED) {
2763
+ this._debug("close: already closed");
2764
+ return;
2765
+ }
2766
+ this._ws.close(code, reason);
2767
+ }
2768
+ reconnect(code, reason) {
2769
+ this._shouldReconnect = true;
2770
+ this._closeCalled = false;
2771
+ this._retryCount = -1;
2772
+ if (!this._ws || this._ws.readyState === this.CLOSED) {
2773
+ this._connect();
2774
+ } else {
2775
+ this._disconnect(code, reason);
2776
+ this._connect();
2777
+ }
2778
+ }
2779
+ send(data) {
2780
+ if (this._ws && this._ws.readyState === this.OPEN) {
2781
+ this._debug("send", data);
2782
+ this._ws.send(data);
2783
+ } else {
2784
+ const { maxEnqueuedMessages = DEFAULT.maxEnqueuedMessages } = this._options;
2785
+ if (this._messageQueue.length < maxEnqueuedMessages) {
2786
+ this._debug("enqueue", data);
2787
+ this._messageQueue.push(data);
2788
+ }
2789
+ }
2790
+ }
2791
+ _debug(...args) {
2792
+ if (this._options.debug) {
2793
+ this._debugLogger("RWS>", ...args);
2794
+ }
2795
+ }
2796
+ _getNextDelay() {
2797
+ const {
2798
+ reconnectionDelayGrowFactor = DEFAULT.reconnectionDelayGrowFactor,
2799
+ minReconnectionDelay = DEFAULT.minReconnectionDelay,
2800
+ maxReconnectionDelay = DEFAULT.maxReconnectionDelay
2801
+ } = this._options;
2802
+ let delay = 0;
2803
+ if (this._retryCount > 0) {
2804
+ delay = minReconnectionDelay * reconnectionDelayGrowFactor ** (this._retryCount - 1);
2805
+ if (delay > maxReconnectionDelay) {
2806
+ delay = maxReconnectionDelay;
2807
+ }
2808
+ }
2809
+ this._debug("next delay", delay);
2810
+ return delay;
2811
+ }
2812
+ _wait() {
2813
+ return new Promise((resolve) => {
2814
+ setTimeout(resolve, this._getNextDelay());
2815
+ });
2816
+ }
2817
+ _getNextProtocols(protocolsProvider) {
2818
+ if (!protocolsProvider)
2819
+ return Promise.resolve(null);
2820
+ if (typeof protocolsProvider === "string" || Array.isArray(protocolsProvider)) {
2821
+ return Promise.resolve(protocolsProvider);
2822
+ }
2823
+ if (typeof protocolsProvider === "function") {
2824
+ const protocols = protocolsProvider();
2825
+ if (!protocols)
2826
+ return Promise.resolve(null);
2827
+ if (typeof protocols === "string" || Array.isArray(protocols)) {
2828
+ return Promise.resolve(protocols);
2829
+ }
2830
+ if (protocols.then) {
2831
+ return protocols;
2832
+ }
2833
+ }
2834
+ throw Error("Invalid protocols");
2835
+ }
2836
+ _getNextUrl(urlProvider) {
2837
+ if (typeof urlProvider === "string") {
2838
+ return Promise.resolve(urlProvider);
2839
+ }
2840
+ if (typeof urlProvider === "function") {
2841
+ const url = urlProvider();
2842
+ if (typeof url === "string") {
2843
+ return Promise.resolve(url);
2844
+ }
2845
+ if (url.then) {
2846
+ return url;
2847
+ }
2848
+ }
2849
+ throw Error("Invalid URL");
2850
+ }
2851
+ _connect() {
2852
+ if (this._connectLock || !this._shouldReconnect) {
2853
+ return;
2854
+ }
2855
+ this._connectLock = true;
2856
+ const {
2857
+ maxRetries = DEFAULT.maxRetries,
2858
+ connectionTimeout = DEFAULT.connectionTimeout
2859
+ } = this._options;
2860
+ if (this._retryCount >= maxRetries) {
2861
+ this._debug("max retries reached", this._retryCount, ">=", maxRetries);
2862
+ return;
2863
+ }
2864
+ this._retryCount++;
2865
+ this._debug("connect", this._retryCount);
2866
+ this._removeListeners();
2867
+ this._wait().then(() => Promise.all([
2868
+ this._getNextUrl(this._url),
2869
+ this._getNextProtocols(this._protocols || null)
2870
+ ])).then(([url, protocols]) => {
2871
+ if (this._closeCalled) {
2872
+ this._connectLock = false;
2873
+ return;
2874
+ }
2875
+ if (!this._options.WebSocket && typeof WebSocket === "undefined" && !didWarnAboutMissingWebSocket) {
2876
+ console.error(`‼️ No WebSocket implementation available. You should define options.WebSocket.
2877
+
2878
+ For example, if you're using node.js, run \`npm install ws\`, and then in your code:
2879
+
2880
+ import PartySocket from 'partysocket';
2881
+ import WS from 'ws';
2882
+
2883
+ const partysocket = new PartySocket({
2884
+ host: "127.0.0.1:1999",
2885
+ room: "test-room",
2886
+ WebSocket: WS
2887
+ });
2888
+
2889
+ `);
2890
+ didWarnAboutMissingWebSocket = true;
2891
+ }
2892
+ const WS = this._options.WebSocket || WebSocket;
2893
+ this._debug("connect", { url, protocols });
2894
+ this._ws = protocols ? new WS(url, protocols) : new WS(url);
2895
+ this._ws.binaryType = this._binaryType;
2896
+ this._connectLock = false;
2897
+ this._addListeners();
2898
+ this._connectTimeout = setTimeout(() => this._handleTimeout(), connectionTimeout);
2899
+ }).catch((err) => {
2900
+ this._connectLock = false;
2901
+ this._handleError(new Events.ErrorEvent(Error(err.message), this));
2902
+ });
2903
+ }
2904
+ _handleTimeout() {
2905
+ this._debug("timeout event");
2906
+ this._handleError(new Events.ErrorEvent(Error("TIMEOUT"), this));
2907
+ }
2908
+ _disconnect(code = 1000, reason) {
2909
+ this._clearTimeouts();
2910
+ if (!this._ws) {
2911
+ return;
2912
+ }
2913
+ this._removeListeners();
2914
+ try {
2915
+ if (this._ws.readyState === this.OPEN || this._ws.readyState === this.CONNECTING) {
2916
+ this._ws.close(code, reason);
2917
+ }
2918
+ this._handleClose(new Events.CloseEvent(code, reason, this));
2919
+ } catch (_error) {}
2920
+ }
2921
+ _acceptOpen() {
2922
+ this._debug("accept open");
2923
+ this._retryCount = 0;
2924
+ }
2925
+ _handleOpen = (event) => {
2926
+ this._debug("open event");
2927
+ const { minUptime = DEFAULT.minUptime } = this._options;
2928
+ clearTimeout(this._connectTimeout);
2929
+ this._uptimeTimeout = setTimeout(() => this._acceptOpen(), minUptime);
2930
+ assert2(this._ws, "WebSocket is not defined");
2931
+ this._ws.binaryType = this._binaryType;
2932
+ this._messageQueue.forEach((message) => {
2933
+ var _a2;
2934
+ (_a2 = this._ws) == null || _a2.send(message);
2935
+ });
2936
+ this._messageQueue = [];
2937
+ if (this.onopen) {
2938
+ this.onopen(event);
2939
+ }
2940
+ this.dispatchEvent(cloneEvent(event));
2941
+ };
2942
+ _handleMessage = (event) => {
2943
+ this._debug("message event");
2944
+ if (this.onmessage) {
2945
+ this.onmessage(event);
2946
+ }
2947
+ this.dispatchEvent(cloneEvent(event));
2948
+ };
2949
+ _handleError = (event) => {
2950
+ this._debug("error event", event.message);
2951
+ this._disconnect(undefined, event.message === "TIMEOUT" ? "timeout" : undefined);
2952
+ if (this.onerror) {
2953
+ this.onerror(event);
2954
+ }
2955
+ this._debug("exec error listeners");
2956
+ this.dispatchEvent(cloneEvent(event));
2957
+ this._connect();
2958
+ };
2959
+ _handleClose = (event) => {
2960
+ this._debug("close event");
2961
+ this._clearTimeouts();
2962
+ if (this._shouldReconnect) {
2963
+ this._connect();
2964
+ }
2965
+ if (this.onclose) {
2966
+ this.onclose(event);
2967
+ }
2968
+ this.dispatchEvent(cloneEvent(event));
2969
+ };
2970
+ _removeListeners() {
2971
+ if (!this._ws) {
2972
+ return;
2973
+ }
2974
+ this._debug("removeListeners");
2975
+ this._ws.removeEventListener("open", this._handleOpen);
2976
+ this._ws.removeEventListener("close", this._handleClose);
2977
+ this._ws.removeEventListener("message", this._handleMessage);
2978
+ this._ws.removeEventListener("error", this._handleError);
2979
+ }
2980
+ _addListeners() {
2981
+ if (!this._ws) {
2982
+ return;
2983
+ }
2984
+ this._debug("addListeners");
2985
+ this._ws.addEventListener("open", this._handleOpen);
2986
+ this._ws.addEventListener("close", this._handleClose);
2987
+ this._ws.addEventListener("message", this._handleMessage);
2988
+ this._ws.addEventListener("error", this._handleError);
2989
+ }
2990
+ _clearTimeouts() {
2991
+ clearTimeout(this._connectTimeout);
2992
+ clearTimeout(this._uptimeTimeout);
2993
+ }
2994
+ };
2995
+ /*!
2996
+ * Reconnecting WebSocket
2997
+ * by Pedro Ladaria <pedro.ladaria@gmail.com>
2998
+ * https://github.com/pladaria/reconnecting-websocket
2999
+ * License MIT
3000
+ */
3001
+
3002
+ // src/netcode/logs.ts
3003
+ var logger = {
3004
+ onLog: null,
3005
+ matchFrame: -1,
3006
+ frameNumber: -1,
3007
+ log(opts) {
3008
+ this.onLog?.({
3009
+ ...opts,
3010
+ frame_number: this.frameNumber,
3011
+ match_frame: this.matchFrame >= 0 ? this.matchFrame : null,
3012
+ timestamp: Date.now(),
3013
+ severity: "log"
3014
+ });
3015
+ },
3016
+ warn(opts) {
3017
+ this.onLog?.({
3018
+ ...opts,
3019
+ frame_number: this.frameNumber,
3020
+ match_frame: this.matchFrame >= 0 ? this.matchFrame : null,
3021
+ timestamp: Date.now(),
3022
+ severity: "warn"
3023
+ });
3024
+ },
3025
+ error(opts) {
3026
+ this.onLog?.({
3027
+ ...opts,
3028
+ frame_number: this.frameNumber,
3029
+ match_frame: this.matchFrame >= 0 ? this.matchFrame : null,
3030
+ timestamp: Date.now(),
3031
+ severity: "error"
3032
+ });
3033
+ }
3034
+ };
3035
+
3036
+ // src/netcode/transport.ts
3037
+ var iceServers = [
3038
+ { urls: "stun:stun.cloudflare.com:3478" }
3039
+ ];
3040
+ async function connect(ws, peerId, timeoutMs = 1e4) {
3041
+ const pc = new RTCPeerConnection({ iceServers });
3042
+ const reliable = pc.createDataChannel("reliable", {});
3043
+ const unreliable = pc.createDataChannel("unreliable", {
3044
+ ordered: false,
3045
+ maxRetransmits: 0
3046
+ });
3047
+ const offer = await pc.createOffer();
3048
+ await pc.setLocalDescription(offer);
3049
+ logger.log({ source: "webrtc", label: "set offer", json: offer });
3050
+ await gatherIce(pc, timeoutMs);
3051
+ logger.log({ source: "webrtc", label: "gathered ICE candidates" });
3052
+ logger.log({
3053
+ source: "ws",
3054
+ label: "sending local description",
3055
+ json: pc.localDescription,
3056
+ to: peerId
3057
+ });
3058
+ send(ws, {
3059
+ type: "offer",
3060
+ payload: btoa(JSON.stringify(pc.localDescription)),
3061
+ target: peerId
3062
+ });
3063
+ await waitForAnswer(ws, pc, timeoutMs);
3064
+ return {
3065
+ peerConnection: pc,
3066
+ reliable,
3067
+ unreliable,
3068
+ peerId
3069
+ };
3070
+ }
3071
+ async function logErrors(dc) {
3072
+ dc.onerror = (event) => {
3073
+ logger.error({
3074
+ source: "webrtc",
3075
+ label: `error on ${dc.label} channel`,
3076
+ json: event.error
3077
+ });
3078
+ };
3079
+ dc.onclosing = (_event) => {
3080
+ logger.log({
3081
+ source: "webrtc",
3082
+ label: `closing ${dc.label} channel`
3083
+ });
3084
+ };
3085
+ dc.onopen = (_event) => {
3086
+ logger.log({
3087
+ source: "webrtc",
3088
+ label: `opened ${dc.label} channel`
3089
+ });
3090
+ };
3091
+ dc.onclose = (_event) => {
3092
+ logger.log({
3093
+ source: "webrtc",
3094
+ label: `closed ${dc.label} channel`
3095
+ });
3096
+ };
3097
+ }
3098
+ async function logPeerConnection(pc, peerId) {
3099
+ pc.onconnectionstatechange = () => {
3100
+ logger.log({
3101
+ source: "webrtc",
3102
+ label: `[${peerId.substring(0, 6)}] connectionState = ${pc.connectionState}`
3103
+ });
3104
+ };
3105
+ pc.onsignalingstatechange = () => {
3106
+ logger.log({
3107
+ source: "webrtc",
3108
+ label: `[${peerId.substring(0, 6)}] signalingState = ${pc.signalingState}`
3109
+ });
3110
+ };
3111
+ }
3112
+ async function gatherIce(pc, timeoutMs) {
3113
+ return new Promise((yes, no) => {
3114
+ setTimeout(() => no(new Error("Timed out waiting for completion")), timeoutMs);
3115
+ pc.onicegatheringstatechange = () => {
3116
+ logger.log({
3117
+ source: "webrtc",
3118
+ label: `icegatheringstatechange: ${pc.iceGatheringState}`
3119
+ });
3120
+ if (pc.iceGatheringState === "complete") {
3121
+ yes(true);
3122
+ }
3123
+ };
3124
+ });
3125
+ }
3126
+ async function waitForAnswer(ws, pc, timeoutMs) {
3127
+ return new Promise((yes, no) => {
3128
+ const timeoutId = setTimeout(no, timeoutMs);
3129
+ const messageListener = async (event) => {
3130
+ const serverMsg = JSON.parse(event.data);
3131
+ if (serverMsg.type !== "message:json") {
3132
+ return;
3133
+ }
3134
+ const peerMsg = serverMsg.message;
3135
+ if (peerMsg.type !== "answer") {
3136
+ return;
3137
+ }
3138
+ const answerDesc = JSON.parse(atob(peerMsg.payload));
3139
+ logger.log({
3140
+ source: "webrtc",
3141
+ label: "received answer",
3142
+ json: answerDesc
3143
+ });
3144
+ await pc.setRemoteDescription(new RTCSessionDescription(answerDesc));
3145
+ logger.log({
3146
+ source: "webrtc",
3147
+ label: "set remote description with answer"
3148
+ });
3149
+ clearTimeout(timeoutId);
3150
+ yes();
3151
+ };
3152
+ ws.addEventListener("message", messageListener);
3153
+ });
3154
+ }
3155
+ function listenForOffers(ws, cb) {
3156
+ const messageListener = async (event) => {
3157
+ const envelope = JSON.parse(event.data);
3158
+ if (envelope.type !== "message:json") {
3159
+ return;
3160
+ }
3161
+ const msg = envelope.message;
3162
+ if (msg.type !== "offer") {
3163
+ return;
3164
+ }
3165
+ logger.log({ source: "webrtc", label: "received offer" });
3166
+ const offer = JSON.parse(atob(msg.payload));
3167
+ const pc = new RTCPeerConnection({ iceServers });
3168
+ await pc.setRemoteDescription(offer);
3169
+ logger.log({
3170
+ source: "webrtc",
3171
+ label: "set remote description",
3172
+ json: { offer, remoteDescription: pc.remoteDescription }
3173
+ });
3174
+ const answer = await pc.createAnswer();
3175
+ await pc.setLocalDescription(answer);
3176
+ logger.log({
3177
+ source: "webrtc",
3178
+ label: "set local description",
3179
+ json: pc.localDescription
3180
+ });
3181
+ await gatherIce(pc, 1e4);
3182
+ const channels = {
3183
+ reliable: null,
3184
+ unreliable: null
3185
+ };
3186
+ pc.ondatachannel = (event2) => {
3187
+ logger.log({
3188
+ source: "webrtc",
3189
+ label: `received datachannel ${event2.channel.label}`
3190
+ });
3191
+ switch (event2.channel.label) {
3192
+ case "reliable":
3193
+ channels.reliable = event2.channel;
3194
+ break;
3195
+ case "unreliable":
3196
+ channels.unreliable = event2.channel;
3197
+ break;
3198
+ }
3199
+ if (channels.reliable && channels.unreliable) {
3200
+ pc.ondatachannel = null;
3201
+ cb({
3202
+ peerConnection: pc,
3203
+ reliable: channels.reliable,
3204
+ unreliable: channels.unreliable,
3205
+ peerId: envelope.peerId
3206
+ });
3207
+ }
3208
+ };
3209
+ logger.log({
3210
+ source: "webrtc",
3211
+ label: "sending answer",
3212
+ json: pc.localDescription
3213
+ });
3214
+ send(ws, {
3215
+ type: "answer",
3216
+ payload: btoa(JSON.stringify(pc.localDescription)),
3217
+ target: envelope.peerId
3218
+ });
3219
+ };
3220
+ ws.addEventListener("message", messageListener);
3221
+ }
3222
+ function send(ws, msg) {
3223
+ ws.send(JSON.stringify(msg));
3224
+ logger.log({ source: "ws", direction: "outbound", json: msg });
3225
+ }
3226
+
3227
+ // src/netcode/broker.ts
3228
+ function joinRoom(brokerUrl, _roomId, cbs) {
3229
+ const broker = new ReconnectingWebSocket(brokerUrl);
3230
+ broker.addEventListener("open", () => {
3231
+ logger.log({
3232
+ source: "ws",
3233
+ label: "Connection opened"
3234
+ });
3235
+ });
3236
+ broker.addEventListener("close", (event) => {
3237
+ logger.warn({
3238
+ source: "ws",
3239
+ label: "Connection closed",
3240
+ json: event
3241
+ });
3242
+ });
3243
+ broker.addEventListener("error", (event) => {
3244
+ logger.error({
3245
+ source: "ws",
3246
+ label: "Connection error",
3247
+ json: event
3248
+ });
3249
+ });
3250
+ const pipes = new Map;
3251
+ let ourId = "";
3252
+ broker.addEventListener("message", async (event) => {
3253
+ try {
3254
+ const envelope = JSON.parse(event.data);
3255
+ logger.log({
3256
+ source: "ws",
3257
+ direction: "inbound",
3258
+ json: envelope
3259
+ });
3260
+ switch (envelope.type) {
3261
+ case "welcome":
3262
+ ourId = envelope.yourId;
3263
+ cbs.onPeerIdAssign(envelope.yourId);
3264
+ for (const peerId of envelope.peerIds) {
3265
+ if (peerId === ourId)
3266
+ continue;
3267
+ cbs.onPeerConnected(peerId);
3268
+ }
3269
+ break;
3270
+ case "message:json":
3271
+ break;
3272
+ case "peer:connect": {
3273
+ const pipe = await connect(broker, envelope.peerId);
3274
+ registerPipe(pipe, cbs);
3275
+ cbs.onPeerConnected(envelope.peerId);
3276
+ break;
3277
+ }
3278
+ case "peer:disconnect":
3279
+ cbs.onPeerDisconnected(envelope.peerId);
3280
+ break;
3281
+ default:
3282
+ logger.warn({
3283
+ source: "ws",
3284
+ label: `Unknown message type: ${envelope.type}`,
3285
+ json: envelope
3286
+ });
3287
+ }
3288
+ } catch (e) {
3289
+ logger.error({
3290
+ source: "ws",
3291
+ label: "Failed to parse json",
3292
+ json: {
3293
+ data: event.data,
3294
+ error: e
3295
+ }
3296
+ });
3297
+ }
3298
+ });
3299
+ listenForOffers(broker, (pipe) => {
3300
+ registerPipe(pipe, cbs);
3301
+ });
3302
+ function registerPipe(pipe, cbs2) {
3303
+ logErrors(pipe.reliable);
3304
+ logErrors(pipe.unreliable);
3305
+ logPeerConnection(pipe.peerConnection, ourId);
3306
+ cbs2.onDataChannelOpen(pipe.peerId, true, pipe.reliable);
3307
+ cbs2.onDataChannelOpen(pipe.peerId, false, pipe.unreliable);
3308
+ pipe.reliable.onmessage = (event) => {
3309
+ cbs2.onMessage(pipe.peerId, event.data, true);
3310
+ };
3311
+ pipe.reliable.onclose = () => {
3312
+ cbs2.onDataChannelClose(pipe.peerId, true);
3313
+ };
3314
+ pipe.unreliable.onmessage = (event) => {
3315
+ cbs2.onMessage(pipe.peerId, event.data, false);
3316
+ };
3317
+ pipe.unreliable.onclose = () => {
3318
+ cbs2.onDataChannelClose(pipe.peerId, false);
3319
+ };
3320
+ pipes.set(pipe.peerId, pipe);
3321
+ }
3322
+ }
3323
+
2581
3324
  // src/App.ts
3325
+ var DEFAULT_BROKER_URL = "wss://webrtc-divine-glade-8064.fly.dev/ws";
2582
3326
  async function start(opts) {
2583
3327
  if (!opts.sim) {
2584
3328
  const { sim } = await mount({
@@ -2588,20 +3332,24 @@ async function start(opts) {
2588
3332
  });
2589
3333
  opts.sim = sim;
2590
3334
  }
2591
- const app = new App(opts.sim, opts.game);
3335
+ const app = new App(opts.sim, opts.game, opts.brokerUrl ?? DEFAULT_BROKER_URL);
2592
3336
  return app;
2593
3337
  }
2594
3338
 
2595
3339
  class App {
2596
3340
  #sim;
2597
3341
  game;
3342
+ brokerUrl;
2598
3343
  #rafHandle = null;
2599
3344
  #unsubscribe = null;
2600
3345
  #now = performance.now();
2601
- constructor(sim, game) {
3346
+ constructor(sim, game, brokerUrl) {
2602
3347
  this.#sim = sim;
2603
3348
  this.game = game;
3349
+ this.brokerUrl = brokerUrl;
2604
3350
  this.game.hooks.beforeFrame = (frame) => {
3351
+ logger.frameNumber = this.#sim.time.frame;
3352
+ logger.matchFrame = this.#sim.wasm.get_match_frame();
2605
3353
  this.beforeFrame.notify(frame);
2606
3354
  };
2607
3355
  this.subscribe();
@@ -2612,6 +3360,9 @@ class App {
2612
3360
  set sim(sim) {
2613
3361
  this.#sim = sim;
2614
3362
  }
3363
+ joinRoom(roomId, callbacks) {
3364
+ joinRoom(this.brokerUrl, roomId, callbacks);
3365
+ }
2615
3366
  beforeFrame = createListener();
2616
3367
  afterFrame = createListener();
2617
3368
  subscribe() {
@@ -2748,10 +3499,18 @@ function createListener() {
2748
3499
  unsubscribeAll: () => listeners.clear()
2749
3500
  };
2750
3501
  }
3502
+ // src/netcode/protocol.ts
3503
+ var PacketType;
3504
+ ((PacketType2) => {
3505
+ PacketType2[PacketType2["None"] = 0] = "None";
3506
+ PacketType2[PacketType2["Inputs"] = 1] = "Inputs";
3507
+ })(PacketType ||= {});
2751
3508
  export {
2752
3509
  start,
3510
+ logger,
3511
+ PacketType,
2753
3512
  App
2754
3513
  };
2755
3514
 
2756
- //# debugId=59867E7246609DC264756E2164756E21
3515
+ //# debugId=2419B8104EB1627464756E2164756E21
2757
3516
  //# sourceMappingURL=mod.js.map