@genex-ai/embed-sdk 0.6.0 → 0.6.1

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.
@@ -12,6 +12,7 @@ var parentOrigin = null;
12
12
  var initialized = false;
13
13
  var redeeming = false;
14
14
  var requestingGuest = false;
15
+ var identityEpoch = 0;
15
16
  var handshakeTimeoutMs = 1e4;
16
17
  var refreshDelayMs = 10 * 6e4;
17
18
  var refreshRetryMs = 6e4;
@@ -419,6 +420,7 @@ async function fetchDashboardOrigins() {
419
420
  async function redeemTicket(ticket) {
420
421
  if (!config || localTestMode || redeeming || state !== "pending" && state !== "guest") return;
421
422
  const upgradingFromGuest = state === "guest";
423
+ const epoch = ++identityEpoch;
422
424
  redeeming = true;
423
425
  try {
424
426
  const res = await doFetch(`${config.apiUrl}/api/embed/session`, {
@@ -426,12 +428,14 @@ async function redeemTicket(ticket) {
426
428
  headers: { "Content-Type": "application/json" },
427
429
  body: JSON.stringify({ ticket })
428
430
  });
431
+ if (epoch !== identityEpoch) return;
429
432
  if (!res.ok) {
430
433
  emit("error", { error: new Error(`ticket redemption failed (${res.status})`) });
431
434
  if (!upgradingFromGuest) await handleRedeemFailure();
432
435
  return;
433
436
  }
434
437
  const body = await res.json();
438
+ if (epoch !== identityEpoch) return;
435
439
  embedToken = body.embedToken;
436
440
  user = body.user;
437
441
  colyseusUrls = body.colyseus?.urls;
@@ -449,6 +453,7 @@ async function redeemTicket(ticket) {
449
453
  for (const waiter of playerWaiters.splice(0)) waiter.resolve({ user, guest: false });
450
454
  emit("authenticated", ctx);
451
455
  } catch (error) {
456
+ if (epoch !== identityEpoch) return;
452
457
  emit("error", { error });
453
458
  if (!upgradingFromGuest) await handleRedeemFailure();
454
459
  } finally {
@@ -458,6 +463,7 @@ async function redeemTicket(ticket) {
458
463
  async function requestGuestSession() {
459
464
  if (!config || localTestMode || requestingGuest || redeeming) return;
460
465
  if (state !== "pending" && state !== "guest") return;
466
+ const epoch = ++identityEpoch;
461
467
  requestingGuest = true;
462
468
  try {
463
469
  const res = await doFetch(`${config.apiUrl}/api/embed/guest-session`, {
@@ -465,17 +471,20 @@ async function requestGuestSession() {
465
471
  headers: { "Content-Type": "application/json" },
466
472
  body: JSON.stringify({ slug: config.slug })
467
473
  });
474
+ if (epoch !== identityEpoch) return;
468
475
  if (!res.ok) {
469
476
  emit("error", { error: new Error(`guest session failed (${res.status})`) });
470
477
  enterBlocked();
471
478
  return;
472
479
  }
473
480
  const body = await res.json();
481
+ if (epoch !== identityEpoch) return;
474
482
  embedToken = body.embedToken;
475
483
  user = body.user;
476
484
  colyseusUrls = body.colyseus?.urls;
477
485
  enterGuest();
478
486
  } catch (error) {
487
+ if (epoch !== identityEpoch) return;
479
488
  emit("error", { error });
480
489
  enterBlocked();
481
490
  } finally {
@@ -553,18 +562,22 @@ function scheduleRefresh() {
553
562
  }
554
563
  async function refreshToken() {
555
564
  if (!config || state !== "authenticated" && state !== "guest" || !embedToken) return;
565
+ const epoch = identityEpoch;
566
+ const tokenAtStart = embedToken;
556
567
  let status;
557
568
  try {
558
569
  const res = await doFetch(`${config.apiUrl}/api/embed/session/refresh`, {
559
570
  method: "POST",
560
- headers: { Authorization: `Bearer ${embedToken}` },
571
+ headers: { Authorization: `Bearer ${tokenAtStart}` },
561
572
  // Best-effort completion if the tab starts unloading mid-refresh; zero
562
573
  // security consequence either way (worst case the token just expires).
563
574
  keepalive: true
564
575
  });
565
576
  status = res.status;
577
+ if (epoch !== identityEpoch || embedToken !== tokenAtStart) return;
566
578
  if (res.ok) {
567
579
  const body = await res.json();
580
+ if (epoch !== identityEpoch || embedToken !== tokenAtStart) return;
568
581
  embedToken = body.embedToken;
569
582
  scheduleRefresh();
570
583
  return;
@@ -572,6 +585,7 @@ async function refreshToken() {
572
585
  } catch {
573
586
  status = void 0;
574
587
  }
588
+ if (epoch !== identityEpoch || embedToken !== tokenAtStart) return;
575
589
  if (status === 401) {
576
590
  if (state === "guest") {
577
591
  void requestGuestSession();
@@ -588,6 +602,7 @@ async function refreshToken() {
588
602
  }
589
603
  function enterBlocked() {
590
604
  if (state === "blocked") return;
605
+ identityEpoch++;
591
606
  state = "blocked";
592
607
  user = null;
593
608
  embedToken = void 0;
@@ -731,6 +746,7 @@ function __resetForTests(overrides) {
731
746
  initialized = false;
732
747
  redeeming = false;
733
748
  requestingGuest = false;
749
+ identityEpoch++;
734
750
  listeners.clear();
735
751
  authWaiters = [];
736
752
  playerWaiters = [];
package/dist/index.d.ts CHANGED
@@ -116,7 +116,7 @@ declare function getUser(): EmbedUser | null;
116
116
  */
117
117
  declare function getEmbedToken(): string | undefined;
118
118
  /**
119
- * The credential for multiplayer: pass as `connect({ ..., auth: getColyseusAuth() })`
119
+ * The credential for multiplayer: pass as `connect({ ..., auth: () => getColyseusAuth() })`
120
120
  * AFTER `await waitForPlayer()` — the relay rejects tokenless joins, but
121
121
  * accepts guest tokens. Read it fresh at every connect() call (tokens rotate
122
122
  * ~every 10 minutes). NEVER log this value.
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  submitScore,
18
18
  waitForAuth,
19
19
  waitForPlayer
20
- } from "./chunk-5VYRFOFN.js";
20
+ } from "./chunk-UOC55SJL.js";
21
21
  export {
22
22
  __resetForTests,
23
23
  _stashTicketFromUrl,
package/dist/sentry.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  _stashTicketFromUrl,
3
3
  getUser,
4
4
  on
5
- } from "./chunk-5VYRFOFN.js";
5
+ } from "./chunk-UOC55SJL.js";
6
6
 
7
7
  // src/sentry.ts
8
8
  import * as Sentry from "@sentry/browser";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/embed-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Player identity + durable game state for genex games — 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",