@genex-ai/embed-sdk 0.15.0 → 0.17.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/dist/{chunk-DWDBRKRS.js → chunk-DNLXNEPL.js} +63 -9
- package/dist/index.d.ts +20 -2
- package/dist/index.js +1 -1
- package/dist/sentry.js +1 -1
- package/package.json +1 -1
|
@@ -341,7 +341,7 @@ var RETRY_FLAG = "genex:embed:retry";
|
|
|
341
341
|
var POPOVER_DISMISSED_FLAG = "genex:guest:popover-dismissed";
|
|
342
342
|
var LOCAL_AUTH_FLAG = "genex:embed:local-auth";
|
|
343
343
|
var PLAYER_ID_KEY = "genex:player";
|
|
344
|
-
var SDK_VERSION = "0.
|
|
344
|
+
var SDK_VERSION = "0.17.0";
|
|
345
345
|
var config = null;
|
|
346
346
|
var state = "pending";
|
|
347
347
|
var user = null;
|
|
@@ -366,6 +366,8 @@ var nativeReauthTimeoutMs = 3e4;
|
|
|
366
366
|
var heartbeatIntervalMs = 3e4;
|
|
367
367
|
var handshakeTimer;
|
|
368
368
|
var refreshTimer;
|
|
369
|
+
var unattendedWaiterTimer;
|
|
370
|
+
var earlyWaiterWarned = false;
|
|
369
371
|
var messageHandler;
|
|
370
372
|
var listeners = /* @__PURE__ */ new Map();
|
|
371
373
|
var authWaiters = [];
|
|
@@ -382,8 +384,16 @@ function win() {
|
|
|
382
384
|
function doc() {
|
|
383
385
|
return globalThis.document;
|
|
384
386
|
}
|
|
385
|
-
function doFetch(input, init) {
|
|
386
|
-
|
|
387
|
+
function doFetch(input, init, timeoutMs) {
|
|
388
|
+
let signal;
|
|
389
|
+
if (timeoutMs !== void 0) {
|
|
390
|
+
try {
|
|
391
|
+
const ctor = globalThis.AbortSignal;
|
|
392
|
+
if (ctor && typeof ctor.timeout === "function") signal = ctor.timeout(timeoutMs);
|
|
393
|
+
} catch {
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return globalThis.fetch(input, signal ? { ...init, signal } : init);
|
|
387
397
|
}
|
|
388
398
|
function readRetryFlag() {
|
|
389
399
|
try {
|
|
@@ -449,6 +459,10 @@ function initEmbed(cfg2) {
|
|
|
449
459
|
if (!w) return;
|
|
450
460
|
if (initialized) return;
|
|
451
461
|
initialized = true;
|
|
462
|
+
if (unattendedWaiterTimer !== void 0) {
|
|
463
|
+
clearTimeout(unattendedWaiterTimer);
|
|
464
|
+
unattendedWaiterTimer = void 0;
|
|
465
|
+
}
|
|
452
466
|
config = {
|
|
453
467
|
slug: cfg2.slug,
|
|
454
468
|
apiUrl: cfg2.apiUrl.replace(/\/$/, ""),
|
|
@@ -506,6 +520,7 @@ function getColyseusUrls() {
|
|
|
506
520
|
function waitForAuth() {
|
|
507
521
|
if (state === "authenticated" && user) return Promise.resolve({ user });
|
|
508
522
|
if (state === "blocked") return Promise.reject(new Error("genex embed auth: blocked"));
|
|
523
|
+
noteWaiterBeforeInit("waitForAuth");
|
|
509
524
|
return new Promise((resolve, reject) => {
|
|
510
525
|
authWaiters.push({ resolve, reject });
|
|
511
526
|
});
|
|
@@ -515,10 +530,29 @@ function waitForPlayer() {
|
|
|
515
530
|
return Promise.resolve({ user, guest: state === "guest" });
|
|
516
531
|
}
|
|
517
532
|
if (state === "blocked") return Promise.reject(new Error("genex embed auth: blocked"));
|
|
533
|
+
noteWaiterBeforeInit("waitForPlayer");
|
|
518
534
|
return new Promise((resolve, reject) => {
|
|
519
535
|
playerWaiters.push({ resolve, reject });
|
|
520
536
|
});
|
|
521
537
|
}
|
|
538
|
+
function noteWaiterBeforeInit(fn) {
|
|
539
|
+
if (initialized) return;
|
|
540
|
+
if (!earlyWaiterWarned) {
|
|
541
|
+
earlyWaiterWarned = true;
|
|
542
|
+
try {
|
|
543
|
+
console.error(
|
|
544
|
+
`[genex] ${fn}() called before initEmbed() \u2014 identity can never resolve and the game will sit black. Call initEmbed({ slug, apiUrl, dashboardOrigins }) first (genex-threejs-embed-auth), and draw a frame before you await identity.`
|
|
545
|
+
);
|
|
546
|
+
} catch {
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (unattendedWaiterTimer === void 0) {
|
|
550
|
+
unattendedWaiterTimer = setTimeout(() => {
|
|
551
|
+
unattendedWaiterTimer = void 0;
|
|
552
|
+
if (!initialized) enterBlocked("no-identity");
|
|
553
|
+
}, handshakeTimeoutMs);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
522
556
|
function on(event, cb) {
|
|
523
557
|
let set = listeners.get(event);
|
|
524
558
|
if (!set) {
|
|
@@ -841,16 +875,25 @@ function postToParent(message, targetOrigin) {
|
|
|
841
875
|
async function startStandaloneFlow(w) {
|
|
842
876
|
const frag = readFragment(w);
|
|
843
877
|
if (frag.ticket) {
|
|
878
|
+
armStandaloneWatchdog();
|
|
844
879
|
await redeemTicket(frag.ticket);
|
|
845
880
|
return;
|
|
846
881
|
}
|
|
847
882
|
if (frag.guest) {
|
|
883
|
+
armStandaloneWatchdog();
|
|
848
884
|
await requestGuestSession();
|
|
849
885
|
return;
|
|
850
886
|
}
|
|
851
887
|
showOverlay("redirecting");
|
|
852
888
|
await redirectToAuthorize(w, { guestOk: true });
|
|
853
889
|
}
|
|
890
|
+
function armStandaloneWatchdog() {
|
|
891
|
+
if (handshakeTimer !== void 0) clearTimeout(handshakeTimer);
|
|
892
|
+
handshakeTimer = setTimeout(() => {
|
|
893
|
+
handshakeTimer = void 0;
|
|
894
|
+
if (state === "pending") enterBlocked("no-identity");
|
|
895
|
+
}, handshakeTimeoutMs);
|
|
896
|
+
}
|
|
854
897
|
var stashedTicketHash = null;
|
|
855
898
|
function _stashTicketFromUrl() {
|
|
856
899
|
const w = win();
|
|
@@ -929,11 +972,15 @@ async function redeemTicket(ticket) {
|
|
|
929
972
|
const epoch = ++identityEpoch;
|
|
930
973
|
redeeming = true;
|
|
931
974
|
try {
|
|
932
|
-
const res = await doFetch(
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
975
|
+
const res = await doFetch(
|
|
976
|
+
`${config.apiUrl}/api/embed/session`,
|
|
977
|
+
{
|
|
978
|
+
method: "POST",
|
|
979
|
+
headers: { "Content-Type": "application/json" },
|
|
980
|
+
body: JSON.stringify({ ticket })
|
|
981
|
+
},
|
|
982
|
+
handshakeTimeoutMs
|
|
983
|
+
);
|
|
937
984
|
if (epoch !== identityEpoch) return;
|
|
938
985
|
if (!res.ok) {
|
|
939
986
|
emit("error", { error: new Error(`ticket redemption failed (${res.status})`) });
|
|
@@ -946,6 +993,8 @@ async function redeemTicket(ticket) {
|
|
|
946
993
|
user = body.user;
|
|
947
994
|
colyseusUrls = body.colyseus?.urls;
|
|
948
995
|
state = "authenticated";
|
|
996
|
+
if (handshakeTimer !== void 0) clearTimeout(handshakeTimer);
|
|
997
|
+
handshakeTimer = void 0;
|
|
949
998
|
clearRetryFlag();
|
|
950
999
|
removeOverlay();
|
|
951
1000
|
removeGuestPopover();
|
|
@@ -984,7 +1033,7 @@ async function requestGuestSession() {
|
|
|
984
1033
|
// guest id and the token is unchanged — this just lets the play event
|
|
985
1034
|
// key on something that survives the tab.
|
|
986
1035
|
body: JSON.stringify({ slug: config.slug, playerId: playerId() })
|
|
987
|
-
});
|
|
1036
|
+
}, handshakeTimeoutMs);
|
|
988
1037
|
if (epoch !== identityEpoch) return;
|
|
989
1038
|
if (!res.ok) {
|
|
990
1039
|
emit("error", { error: new Error(`guest session failed (${res.status})`) });
|
|
@@ -1076,6 +1125,8 @@ function enterLocalTestMode(w) {
|
|
|
1076
1125
|
}
|
|
1077
1126
|
async function handleRedeemFailure() {
|
|
1078
1127
|
const w = win();
|
|
1128
|
+
if (handshakeTimer !== void 0) clearTimeout(handshakeTimer);
|
|
1129
|
+
handshakeTimer = void 0;
|
|
1079
1130
|
if (inNativeMode()) {
|
|
1080
1131
|
clearNativeReauth();
|
|
1081
1132
|
postNativeError("ticket-rejected");
|
|
@@ -1469,8 +1520,11 @@ function __resetForTests(overrides) {
|
|
|
1469
1520
|
messageHandler = void 0;
|
|
1470
1521
|
if (handshakeTimer !== void 0) clearTimeout(handshakeTimer);
|
|
1471
1522
|
if (refreshTimer !== void 0) clearTimeout(refreshTimer);
|
|
1523
|
+
if (unattendedWaiterTimer !== void 0) clearTimeout(unattendedWaiterTimer);
|
|
1472
1524
|
handshakeTimer = void 0;
|
|
1473
1525
|
refreshTimer = void 0;
|
|
1526
|
+
unattendedWaiterTimer = void 0;
|
|
1527
|
+
earlyWaiterWarned = false;
|
|
1474
1528
|
stopNativeTimers();
|
|
1475
1529
|
if (w) delete w[NATIVE_RECEIVER];
|
|
1476
1530
|
nativeEntry = null;
|
package/dist/index.d.ts
CHANGED
|
@@ -20,7 +20,20 @@ interface Entitlement {
|
|
|
20
20
|
id: string;
|
|
21
21
|
skuId: string;
|
|
22
22
|
name: string;
|
|
23
|
+
/**
|
|
24
|
+
* How the player got it: `purchase` | `gift` | `test` | `free`.
|
|
25
|
+
*
|
|
26
|
+
* Almost never what you want — branch on {@link Entitlement.skuType}.
|
|
27
|
+
*/
|
|
23
28
|
type: string;
|
|
29
|
+
/**
|
|
30
|
+
* What the item IS: `consumable` | `durable`. **This is the one to branch on.**
|
|
31
|
+
*
|
|
32
|
+
* A consumable is spent on use, so consume it and apply the effect once. A
|
|
33
|
+
* durable is owned forever — never consume it; its presence in this list IS
|
|
34
|
+
* the ownership.
|
|
35
|
+
*/
|
|
36
|
+
skuType: string;
|
|
24
37
|
quantity: number;
|
|
25
38
|
consumed: boolean;
|
|
26
39
|
createdAt: string;
|
|
@@ -245,7 +258,9 @@ declare function getColyseusUrls(): string[];
|
|
|
245
258
|
* session ends up blocked. THE gate for /state saves and any account-bound
|
|
246
259
|
* feature. In a guest session this stays PENDING (it is not rejected —
|
|
247
260
|
* a live upgrade resolves it), so never gate scene boot or connect() on it:
|
|
248
|
-
* use waitForPlayer() for those.
|
|
261
|
+
* use waitForPlayer() for those. Call initEmbed() FIRST: parked before it,
|
|
262
|
+
* this logs one console line and, unattended, ends `blocked` after the
|
|
263
|
+
* handshake budget instead of hanging.
|
|
249
264
|
*/
|
|
250
265
|
declare function waitForAuth(): Promise<{
|
|
251
266
|
user: EmbedUser;
|
|
@@ -253,7 +268,10 @@ declare function waitForAuth(): Promise<{
|
|
|
253
268
|
/**
|
|
254
269
|
* Resolves with the current player — guest OR signed-in — as soon as either
|
|
255
270
|
* identity exists; rejects only if the session ends up blocked. THE gate for
|
|
256
|
-
* multiplayer connect() and player-name UI.
|
|
271
|
+
* multiplayer connect() and player-name UI. Call initEmbed() FIRST — and draw
|
|
272
|
+
* a frame before awaiting this: parked before init, it logs one console line
|
|
273
|
+
* and, unattended, ends `blocked` after the handshake budget instead of
|
|
274
|
+
* leaving the page black.
|
|
257
275
|
*/
|
|
258
276
|
declare function waitForPlayer(): Promise<{
|
|
259
277
|
user: EmbedUser;
|
package/dist/index.js
CHANGED
package/dist/sentry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/embed-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Player identity + durable game state for genex games \u2014 signed-in or guest play, per-player save slots, shared world state, and soft-trust leaderboards.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|