@bountyboard/arcade-sdk 1.1.0 → 1.2.0
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/AGENTS.md +10 -7
- package/CHANGELOG.md +38 -0
- package/README.md +332 -86
- package/dist/{chunk-OWOESH4X.js → chunk-KDBBR532.js} +51 -9
- package/dist/chunk-KDBBR532.js.map +1 -0
- package/dist/global-sdk.d.ts +53 -3
- package/dist/global.js +139 -38
- package/dist/index.cjs +50 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/multiplayer.cjs +139 -38
- package/dist/multiplayer.cjs.map +1 -1
- package/dist/multiplayer.d.cts +2 -2
- package/dist/multiplayer.d.ts +2 -2
- package/dist/multiplayer.js +88 -29
- package/dist/multiplayer.js.map +1 -1
- package/dist/{types-Cq8p7ZkC.d.cts → types-dtsNXYZW.d.cts} +53 -3
- package/dist/{types-Cq8p7ZkC.d.ts → types-dtsNXYZW.d.ts} +53 -3
- package/docs/external-authoritative-servers.md +265 -0
- package/docs/llms.txt +715 -0
- package/docs/relay-rooms.md +134 -0
- package/package.json +2 -1
- package/dist/chunk-OWOESH4X.js.map +0 -1
package/dist/multiplayer.cjs
CHANGED
|
@@ -37,6 +37,8 @@ var AD_PLACEMENT_SRC = "https://pagead2.googlesyndication.com/pagead/js/adsbygoo
|
|
|
37
37
|
var AD_PLACEMENT_SCRIPT_ID = "bb-arcade-h5-ads";
|
|
38
38
|
var DEFAULT_AD_LOAD_TIMEOUT_MS = 6e3;
|
|
39
39
|
var SAVE_TIMEOUT_MS = 15e3;
|
|
40
|
+
var LOCK_TIMEOUT_MS = 5e3;
|
|
41
|
+
var MAX_SAVE_BYTES = 1024 * 1024;
|
|
40
42
|
var INIT_CONFIG_GRACE_MS = 1500;
|
|
41
43
|
var DEFAULT_ALLOW = [
|
|
42
44
|
"bountyboard.gg",
|
|
@@ -61,6 +63,14 @@ function cleanText(value, fallback, max) {
|
|
|
61
63
|
if (typeof value !== "string") return fallback || "";
|
|
62
64
|
return value.replace(/[^\w:.-]+/g, "_").slice(0, max || 80) || fallback || "";
|
|
63
65
|
}
|
|
66
|
+
var cachedTextEncoder = null;
|
|
67
|
+
function utf8ByteLength(value) {
|
|
68
|
+
if (typeof TextEncoder !== "undefined") {
|
|
69
|
+
cachedTextEncoder = cachedTextEncoder || new TextEncoder();
|
|
70
|
+
return cachedTextEncoder.encode(value).length;
|
|
71
|
+
}
|
|
72
|
+
return new Blob([value]).size;
|
|
73
|
+
}
|
|
64
74
|
function toBoolean(value) {
|
|
65
75
|
return value === true || value === "true" || value === "1";
|
|
66
76
|
}
|
|
@@ -180,13 +190,14 @@ function createBBArcade() {
|
|
|
180
190
|
};
|
|
181
191
|
let hostConfigReceived = false;
|
|
182
192
|
let hostPlayer = null;
|
|
193
|
+
const playerChangeHandlers = [];
|
|
183
194
|
let blocked = false;
|
|
184
195
|
const pending = {};
|
|
185
196
|
let seq = 0;
|
|
186
197
|
function post(type, score, extra) {
|
|
187
198
|
if (blocked) return;
|
|
188
199
|
const message = { source: SDK_MESSAGE_SOURCE, v: VERSION, type };
|
|
189
|
-
if (typeof score === "number" && isFinite(score)) message.score = Math.
|
|
200
|
+
if (typeof score === "number" && isFinite(score)) message.score = Math.trunc(score);
|
|
190
201
|
if (extra && typeof extra === "object") {
|
|
191
202
|
const fields = extra;
|
|
192
203
|
for (const key in fields) {
|
|
@@ -207,7 +218,7 @@ function createBBArcade() {
|
|
|
207
218
|
return true;
|
|
208
219
|
}
|
|
209
220
|
}
|
|
210
|
-
function request(type, payload) {
|
|
221
|
+
function request(type, payload, timeoutMs = SAVE_TIMEOUT_MS) {
|
|
211
222
|
return new Promise(function(resolve, reject) {
|
|
212
223
|
if (blocked) return reject(sdkError("error"));
|
|
213
224
|
if (!isEmbedded()) return reject(sdkError("unsupported"));
|
|
@@ -217,7 +228,7 @@ function createBBArcade() {
|
|
|
217
228
|
delete pending[requestId];
|
|
218
229
|
reject(sdkError("error"));
|
|
219
230
|
}
|
|
220
|
-
},
|
|
231
|
+
}, timeoutMs);
|
|
221
232
|
pending[requestId] = { resolve, reject, timer };
|
|
222
233
|
try {
|
|
223
234
|
window.parent.postMessage(
|
|
@@ -309,7 +320,7 @@ function createBBArcade() {
|
|
|
309
320
|
if (!hostnameAllowed(origin, allow)) blockHost(options);
|
|
310
321
|
return;
|
|
311
322
|
}
|
|
312
|
-
request("host").then(
|
|
323
|
+
request("host", void 0, LOCK_TIMEOUT_MS).then(
|
|
313
324
|
function(res) {
|
|
314
325
|
const r = res;
|
|
315
326
|
if (!hostnameAllowed(r && r.origin, allow)) blockHost(options);
|
|
@@ -333,7 +344,7 @@ function createBBArcade() {
|
|
|
333
344
|
lockToHostBestEffort(opts, allow);
|
|
334
345
|
return;
|
|
335
346
|
}
|
|
336
|
-
request("host_attest").then(
|
|
347
|
+
request("host_attest", void 0, LOCK_TIMEOUT_MS).then(
|
|
337
348
|
function(res) {
|
|
338
349
|
const r = res;
|
|
339
350
|
if (!r || !r.attestation) {
|
|
@@ -395,7 +406,15 @@ function createBBArcade() {
|
|
|
395
406
|
if (msg.source !== HOST_MESSAGE_SOURCE || msg.type !== "config") return;
|
|
396
407
|
hostConfigReceived = true;
|
|
397
408
|
if (msg.player !== void 0) {
|
|
398
|
-
|
|
409
|
+
const nextPlayer = sanitizePlayer(msg.player);
|
|
410
|
+
const changed = nextPlayer === null ? hostPlayer !== null : hostPlayer === null || nextPlayer.name !== hostPlayer.name || nextPlayer.avatarUrl !== hostPlayer.avatarUrl;
|
|
411
|
+
hostPlayer = nextPlayer;
|
|
412
|
+
if (changed) {
|
|
413
|
+
const snapshot = nextPlayer ? { name: nextPlayer.name, avatarUrl: nextPlayer.avatarUrl } : null;
|
|
414
|
+
for (let i = 0; i < playerChangeHandlers.length; i++) {
|
|
415
|
+
safeCall(playerChangeHandlers[i], snapshot);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
399
418
|
}
|
|
400
419
|
const rewardedAds = msg.rewardedAds;
|
|
401
420
|
if (rewardedAds && typeof rewardedAds === "object") {
|
|
@@ -527,6 +546,7 @@ function createBBArcade() {
|
|
|
527
546
|
let resolved = false;
|
|
528
547
|
let status = "unavailable";
|
|
529
548
|
let rewardOffered = false;
|
|
549
|
+
let adShown = false;
|
|
530
550
|
const waitTimer = setTimeout(function() {
|
|
531
551
|
if (rewardOffered || resolved) return;
|
|
532
552
|
const timeout = Object.assign(
|
|
@@ -571,6 +591,7 @@ function createBBArcade() {
|
|
|
571
591
|
}
|
|
572
592
|
post("rewarded_ad", void 0, Object.assign({ event: "started" }, base));
|
|
573
593
|
try {
|
|
594
|
+
adShown = true;
|
|
574
595
|
showAdFn();
|
|
575
596
|
} catch (err) {
|
|
576
597
|
const showError = Object.assign(
|
|
@@ -620,7 +641,13 @@ function createBBArcade() {
|
|
|
620
641
|
},
|
|
621
642
|
adBreakDone: function(placementInfo) {
|
|
622
643
|
if (resolved) return;
|
|
623
|
-
const result = rewardOffered || status !== "unavailable" ? {
|
|
644
|
+
const result = rewardOffered || status !== "unavailable" ? {
|
|
645
|
+
// A reward was offered but the ad never reached the screen
|
|
646
|
+
// (the game retained show() and let the break lapse): the
|
|
647
|
+
// break is over without a view, so resolve 'dismissed',
|
|
648
|
+
// not the non-terminal-looking 'ready'.
|
|
649
|
+
status: status === "ready" && !adShown ? "dismissed" : status
|
|
650
|
+
} : { status: "unavailable", error: "no_rewarded_ad" };
|
|
624
651
|
if (placementInfo && typeof placementInfo === "object") {
|
|
625
652
|
result.breakStatus = cleanText(
|
|
626
653
|
placementInfo.breakStatus
|
|
@@ -823,12 +850,25 @@ function createBBArcade() {
|
|
|
823
850
|
prepareRewardedBreak: prepareRewardedAd,
|
|
824
851
|
rewardedBreak,
|
|
825
852
|
save: function(blob) {
|
|
826
|
-
|
|
853
|
+
const data = String(blob);
|
|
854
|
+
if (utf8ByteLength(data) > MAX_SAVE_BYTES) {
|
|
855
|
+
return Promise.reject(sdkError("too_large"));
|
|
856
|
+
}
|
|
857
|
+
return request("save", data);
|
|
827
858
|
},
|
|
828
859
|
load: function() {
|
|
829
860
|
return request("load");
|
|
830
861
|
},
|
|
831
862
|
getPlayer,
|
|
863
|
+
onPlayerChange: function(handler) {
|
|
864
|
+
if (typeof handler !== "function") return function() {
|
|
865
|
+
};
|
|
866
|
+
playerChangeHandlers.push(handler);
|
|
867
|
+
return function() {
|
|
868
|
+
const idx = playerChangeHandlers.indexOf(handler);
|
|
869
|
+
if (idx !== -1) playerChangeHandlers.splice(idx, 1);
|
|
870
|
+
};
|
|
871
|
+
},
|
|
832
872
|
getVariant: function(key, variants) {
|
|
833
873
|
const sorted = Array.isArray(variants) ? variants.slice().sort() : [];
|
|
834
874
|
const fallback = sorted.length > 0 ? sorted[0] : null;
|
|
@@ -895,6 +935,8 @@ function createInertBBArcade() {
|
|
|
895
935
|
save: () => Promise.reject(sdkError2("unsupported")),
|
|
896
936
|
load: () => Promise.reject(sdkError2("unsupported")),
|
|
897
937
|
getPlayer: () => Promise.resolve(null),
|
|
938
|
+
onPlayerChange: () => () => {
|
|
939
|
+
},
|
|
898
940
|
getVariant: (key, variants) => {
|
|
899
941
|
const sorted = Array.isArray(variants) ? variants.slice().sort() : [];
|
|
900
942
|
return Promise.resolve(sorted.length > 0 ? sorted[0] : null);
|
|
@@ -908,13 +950,17 @@ var BBArcade = typeof window === "undefined" ? createInertBBArcade() : createBBA
|
|
|
908
950
|
|
|
909
951
|
// src/multiplayer.ts
|
|
910
952
|
var WELCOME_TIMEOUT_MS = 1e4;
|
|
953
|
+
var MIN_WELCOME_TIMEOUT_MS = 1e3;
|
|
954
|
+
var MAX_WELCOME_TIMEOUT_MS = 6e4;
|
|
911
955
|
var MAX_RECONNECT_ATTEMPTS = 3;
|
|
912
956
|
var MAX_JOIN_DATA_BYTES = 1024;
|
|
957
|
+
var SEAT_FULL_CLOSE_CODE = 4005;
|
|
913
958
|
var CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
|
914
959
|
var CODE_LENGTH = 4;
|
|
915
|
-
function sdkError3(code) {
|
|
960
|
+
function sdkError3(code, detail) {
|
|
916
961
|
const err = new Error(code);
|
|
917
962
|
err.code = code;
|
|
963
|
+
if (detail) err.detail = detail;
|
|
918
964
|
return err;
|
|
919
965
|
}
|
|
920
966
|
function randomChars(length) {
|
|
@@ -931,23 +977,13 @@ function randomChars(length) {
|
|
|
931
977
|
function generateCode() {
|
|
932
978
|
return randomChars(CODE_LENGTH);
|
|
933
979
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
else if (code < 2048) bytes += 2;
|
|
940
|
-
else if (code >= 55296 && code <= 56319 && i + 1 < value.length) {
|
|
941
|
-
const next = value.charCodeAt(i + 1);
|
|
942
|
-
if (next >= 56320 && next <= 57343) {
|
|
943
|
-
bytes += 4;
|
|
944
|
-
i += 1;
|
|
945
|
-
} else {
|
|
946
|
-
bytes += 3;
|
|
947
|
-
}
|
|
948
|
-
} else bytes += 3;
|
|
980
|
+
var cachedTextEncoder2 = null;
|
|
981
|
+
function utf8ByteLength2(value) {
|
|
982
|
+
if (typeof TextEncoder !== "undefined") {
|
|
983
|
+
cachedTextEncoder2 = cachedTextEncoder2 || new TextEncoder();
|
|
984
|
+
return cachedTextEncoder2.encode(value).length;
|
|
949
985
|
}
|
|
950
|
-
return
|
|
986
|
+
return new Blob([value]).size;
|
|
951
987
|
}
|
|
952
988
|
function serializeJoinData(data) {
|
|
953
989
|
if (data === void 0) return null;
|
|
@@ -958,28 +994,34 @@ function serializeJoinData(data) {
|
|
|
958
994
|
} catch (e) {
|
|
959
995
|
throw sdkError3("rejected");
|
|
960
996
|
}
|
|
961
|
-
if (!serialized ||
|
|
997
|
+
if (!serialized || utf8ByteLength2(serialized) > MAX_JOIN_DATA_BYTES) {
|
|
962
998
|
throw sdkError3("rejected");
|
|
963
999
|
}
|
|
964
1000
|
return serialized;
|
|
965
1001
|
}
|
|
966
|
-
function requestTicket(
|
|
1002
|
+
function requestTicket(payload) {
|
|
967
1003
|
const request = BBArcade._request;
|
|
968
1004
|
if (typeof request !== "function") return Promise.reject(sdkError3("unsupported"));
|
|
969
|
-
return request("mp_ticket",
|
|
1005
|
+
return request("mp_ticket", payload).then((grant) => {
|
|
970
1006
|
const g = grant;
|
|
971
1007
|
if (!g || typeof g.ticket !== "string" || typeof g.roomUrl !== "string") {
|
|
972
1008
|
throw sdkError3("error");
|
|
973
1009
|
}
|
|
974
|
-
return {
|
|
1010
|
+
return {
|
|
1011
|
+
ticket: g.ticket,
|
|
1012
|
+
roomUrl: g.roomUrl,
|
|
1013
|
+
expiresAt: Number(g.expiresAt) || 0,
|
|
1014
|
+
roomId: typeof g.roomId === "string" && g.roomId ? g.roomId : null
|
|
1015
|
+
};
|
|
975
1016
|
});
|
|
976
1017
|
}
|
|
977
1018
|
var RoomConnection = class {
|
|
978
|
-
constructor(code, devGrant, joinData) {
|
|
1019
|
+
constructor(code, devGrant, joinData, welcomeTimeoutMs = WELCOME_TIMEOUT_MS) {
|
|
979
1020
|
this.playerId = "";
|
|
980
1021
|
this.players = [];
|
|
981
1022
|
this.state = null;
|
|
982
1023
|
this.connected = false;
|
|
1024
|
+
this.latencyMs = null;
|
|
983
1025
|
this.ws = null;
|
|
984
1026
|
// Keyed by event name; values are erased to (unknown) => void internally and
|
|
985
1027
|
// retyped at the on()/emit() boundary, which keeps the public API strictly
|
|
@@ -992,15 +1034,20 @@ var RoomConnection = class {
|
|
|
992
1034
|
// or the welcome timed out — permanent outcomes that must not reconnect.
|
|
993
1035
|
this.terminal = false;
|
|
994
1036
|
this.reconnectAttempts = 0;
|
|
1037
|
+
// The in-flight connect()'s settlement, so leave() can reject a join that
|
|
1038
|
+
// is still waiting on its welcome instead of stranding it on the timeout.
|
|
1039
|
+
this.pendingConnect = null;
|
|
995
1040
|
this.code = code;
|
|
996
1041
|
this.devGrant = devGrant;
|
|
997
1042
|
this.joinData = joinData;
|
|
1043
|
+
this.welcomeTimeoutMs = welcomeTimeoutMs;
|
|
998
1044
|
}
|
|
999
1045
|
/** Connect and resolve on the server's welcome (post-ticket-verification). */
|
|
1000
1046
|
connect(grant) {
|
|
1001
1047
|
return new Promise((resolve, reject) => {
|
|
1002
1048
|
let settled = false;
|
|
1003
1049
|
const url = grant.roomUrl + (grant.roomUrl.indexOf("?") === -1 ? "?" : "&") + "ticket=" + encodeURIComponent(grant.ticket) + (this.joinData === null ? "" : "&join=" + encodeURIComponent(this.joinData));
|
|
1050
|
+
const connectStartedAt = Date.now();
|
|
1004
1051
|
let ws;
|
|
1005
1052
|
try {
|
|
1006
1053
|
ws = new WebSocket(url);
|
|
@@ -1011,13 +1058,15 @@ var RoomConnection = class {
|
|
|
1011
1058
|
const welcomeTimer = setTimeout(() => {
|
|
1012
1059
|
if (settled) return;
|
|
1013
1060
|
settled = true;
|
|
1061
|
+
this.pendingConnect = null;
|
|
1014
1062
|
this.terminal = true;
|
|
1015
1063
|
try {
|
|
1016
1064
|
ws.close();
|
|
1017
1065
|
} catch (err) {
|
|
1018
1066
|
}
|
|
1019
1067
|
reject(sdkError3("error"));
|
|
1020
|
-
},
|
|
1068
|
+
}, this.welcomeTimeoutMs);
|
|
1069
|
+
this.pendingConnect = { reject, timer: welcomeTimer };
|
|
1021
1070
|
ws.onmessage = (event) => {
|
|
1022
1071
|
var _a, _b, _c, _d, _e;
|
|
1023
1072
|
let msg;
|
|
@@ -1028,14 +1077,23 @@ var RoomConnection = class {
|
|
|
1028
1077
|
}
|
|
1029
1078
|
if (!msg || typeof msg.t !== "string") return;
|
|
1030
1079
|
if (msg.t === "welcome") {
|
|
1080
|
+
if (this.intentionalClose) {
|
|
1081
|
+
try {
|
|
1082
|
+
ws.close();
|
|
1083
|
+
} catch (err) {
|
|
1084
|
+
}
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1031
1087
|
const reconnected = this.reconnectAttempts > 0;
|
|
1032
1088
|
this.playerId = String((_a = msg.playerId) != null ? _a : "");
|
|
1033
1089
|
this.players = Array.isArray(msg.players) ? msg.players : [];
|
|
1034
1090
|
this.state = (_b = msg.state) != null ? _b : null;
|
|
1035
1091
|
this.connected = true;
|
|
1036
1092
|
this.reconnectAttempts = 0;
|
|
1093
|
+
this.latencyMs = Math.max(0, Date.now() - connectStartedAt);
|
|
1037
1094
|
if (!settled) {
|
|
1038
1095
|
settled = true;
|
|
1096
|
+
this.pendingConnect = null;
|
|
1039
1097
|
clearTimeout(welcomeTimer);
|
|
1040
1098
|
resolve(this);
|
|
1041
1099
|
}
|
|
@@ -1077,21 +1135,24 @@ var RoomConnection = class {
|
|
|
1077
1135
|
if (!settled) {
|
|
1078
1136
|
settled = true;
|
|
1079
1137
|
this.terminal = true;
|
|
1138
|
+
this.pendingConnect = null;
|
|
1080
1139
|
clearTimeout(welcomeTimer);
|
|
1081
1140
|
try {
|
|
1082
1141
|
ws.close();
|
|
1083
1142
|
} catch (err) {
|
|
1084
1143
|
}
|
|
1085
|
-
reject(sdkError3(code === "unauthenticated" ? "unauthenticated" : "rejected"));
|
|
1144
|
+
reject(sdkError3(code === "unauthenticated" ? "unauthenticated" : "rejected", code));
|
|
1086
1145
|
return;
|
|
1087
1146
|
}
|
|
1088
1147
|
this.emit("error", { code });
|
|
1089
1148
|
}
|
|
1090
1149
|
};
|
|
1091
|
-
ws.onclose = () => {
|
|
1150
|
+
ws.onclose = (event) => {
|
|
1092
1151
|
this.connected = false;
|
|
1152
|
+
if (event && event.code === SEAT_FULL_CLOSE_CODE) this.terminal = true;
|
|
1093
1153
|
if (!settled) {
|
|
1094
1154
|
settled = true;
|
|
1155
|
+
this.pendingConnect = null;
|
|
1095
1156
|
clearTimeout(welcomeTimer);
|
|
1096
1157
|
reject(sdkError3("error"));
|
|
1097
1158
|
return;
|
|
@@ -1120,7 +1181,7 @@ var RoomConnection = class {
|
|
|
1120
1181
|
await new Promise((r) => setTimeout(r, 400 * this.reconnectAttempts));
|
|
1121
1182
|
if (this.intentionalClose || this.ended || this.terminal) return;
|
|
1122
1183
|
try {
|
|
1123
|
-
const grant = (_a = this.devGrant) != null ? _a : await requestTicket(this.code);
|
|
1184
|
+
const grant = (_a = this.devGrant) != null ? _a : await requestTicket({ roomId: this.code });
|
|
1124
1185
|
if (this.intentionalClose || this.ended || this.terminal) return;
|
|
1125
1186
|
await this.connect(grant);
|
|
1126
1187
|
if (this.intentionalClose) this.leave();
|
|
@@ -1155,6 +1216,12 @@ var RoomConnection = class {
|
|
|
1155
1216
|
var _a;
|
|
1156
1217
|
this.intentionalClose = true;
|
|
1157
1218
|
this.connected = false;
|
|
1219
|
+
if (this.pendingConnect) {
|
|
1220
|
+
const pending = this.pendingConnect;
|
|
1221
|
+
this.pendingConnect = null;
|
|
1222
|
+
clearTimeout(pending.timer);
|
|
1223
|
+
pending.reject(sdkError3("error"));
|
|
1224
|
+
}
|
|
1158
1225
|
try {
|
|
1159
1226
|
(_a = this.ws) == null ? void 0 : _a.close(1e3);
|
|
1160
1227
|
} catch (err) {
|
|
@@ -1174,23 +1241,57 @@ var RoomConnection = class {
|
|
|
1174
1241
|
}
|
|
1175
1242
|
}
|
|
1176
1243
|
};
|
|
1244
|
+
var MATCH_ATTEMPTS = 3;
|
|
1245
|
+
function normalizeWelcomeTimeoutMs(value) {
|
|
1246
|
+
if (typeof value !== "number" || !isFinite(value)) return WELCOME_TIMEOUT_MS;
|
|
1247
|
+
return Math.min(MAX_WELCOME_TIMEOUT_MS, Math.max(MIN_WELCOME_TIMEOUT_MS, Math.floor(value)));
|
|
1248
|
+
}
|
|
1249
|
+
async function matchJoin(joinData, timeoutMs) {
|
|
1250
|
+
let lastError = sdkError3("error");
|
|
1251
|
+
for (let attempt = 0; attempt < MATCH_ATTEMPTS; attempt++) {
|
|
1252
|
+
const grant = await requestTicket({ matchmake: true });
|
|
1253
|
+
if (!grant.roomId) throw sdkError3("error");
|
|
1254
|
+
try {
|
|
1255
|
+
return await new RoomConnection(grant.roomId, null, joinData, timeoutMs).connect(grant);
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
lastError = error;
|
|
1258
|
+
const detail = error == null ? void 0 : error.detail;
|
|
1259
|
+
if (detail !== "room_full" && detail !== "room_over") throw error;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
throw lastError;
|
|
1263
|
+
}
|
|
1177
1264
|
function joinRoom(options) {
|
|
1178
1265
|
const opts = options != null ? options : {};
|
|
1179
1266
|
if (typeof window === "undefined" || typeof WebSocket === "undefined") {
|
|
1180
1267
|
return Promise.reject(sdkError3("unsupported"));
|
|
1181
1268
|
}
|
|
1182
|
-
const code = opts.create || !opts.code ? generateCode() : opts.code.toUpperCase();
|
|
1183
1269
|
let joinData;
|
|
1184
1270
|
try {
|
|
1185
1271
|
joinData = serializeJoinData(opts.joinData);
|
|
1186
1272
|
} catch (err) {
|
|
1187
1273
|
return Promise.reject(err);
|
|
1188
1274
|
}
|
|
1275
|
+
const timeoutMs = normalizeWelcomeTimeoutMs(opts.timeoutMs);
|
|
1276
|
+
if (opts.match) {
|
|
1277
|
+
if (opts.code || opts.create || opts.roomUrl || opts.ticket) {
|
|
1278
|
+
return Promise.reject(sdkError3("rejected"));
|
|
1279
|
+
}
|
|
1280
|
+
return matchJoin(joinData, timeoutMs);
|
|
1281
|
+
}
|
|
1282
|
+
const code = opts.create || !opts.code ? generateCode() : opts.code.toUpperCase();
|
|
1189
1283
|
if (opts.roomUrl && opts.ticket) {
|
|
1190
|
-
const devGrant = {
|
|
1191
|
-
|
|
1284
|
+
const devGrant = {
|
|
1285
|
+
ticket: opts.ticket,
|
|
1286
|
+
roomUrl: opts.roomUrl,
|
|
1287
|
+
expiresAt: 0,
|
|
1288
|
+
roomId: code
|
|
1289
|
+
};
|
|
1290
|
+
return new RoomConnection(code, devGrant, joinData, timeoutMs).connect(devGrant);
|
|
1192
1291
|
}
|
|
1193
|
-
return requestTicket(
|
|
1292
|
+
return requestTicket({ roomId: code }).then(
|
|
1293
|
+
(grant) => new RoomConnection(code, null, joinData, timeoutMs).connect(grant)
|
|
1294
|
+
);
|
|
1194
1295
|
}
|
|
1195
1296
|
var multiplayer = { joinRoom };
|
|
1196
1297
|
// Annotate the CommonJS export names for ESM import in node:
|