@genex-ai/embed-sdk 0.4.1 → 0.6.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.
@@ -5,8 +5,9 @@ var POPOVER_DISMISSED_FLAG = "genex:guest:popover-dismissed";
5
5
  var config = null;
6
6
  var state = "pending";
7
7
  var user = null;
8
+ var localTestMode = false;
8
9
  var embedToken;
9
- var colyseusUrl;
10
+ var colyseusUrls;
10
11
  var parentOrigin = null;
11
12
  var initialized = false;
12
13
  var redeeming = false;
@@ -77,6 +78,10 @@ function initEmbed(cfg) {
77
78
  dashboardOrigins: [...cfg.dashboardOrigins]
78
79
  };
79
80
  state = "pending";
81
+ if (wantsLocalTest(w)) {
82
+ enterLocalTestMode(w);
83
+ return;
84
+ }
80
85
  showOverlay("connecting");
81
86
  if (isEmbedded()) {
82
87
  startEmbeddedHandshake(w);
@@ -105,6 +110,9 @@ function getEmbedToken() {
105
110
  function getColyseusAuth() {
106
111
  return embedToken ? { embedToken } : void 0;
107
112
  }
113
+ function getColyseusUrls() {
114
+ return colyseusUrls ?? [];
115
+ }
108
116
  function waitForAuth() {
109
117
  if (state === "authenticated" && user) return Promise.resolve({ user });
110
118
  if (state === "blocked") return Promise.reject(new Error("genex embed auth: blocked"));
@@ -234,6 +242,7 @@ async function submitScore(score, opts) {
234
242
  }
235
243
  async function getLeaderboard(opts) {
236
244
  if (!config) throw new Error("genex embed: call initEmbed() first");
245
+ if (localTestMode) return { items: [], me: null };
237
246
  if (state === "pending") {
238
247
  try {
239
248
  await waitForPlayer();
@@ -383,7 +392,7 @@ function readFragment(w) {
383
392
  return { ticket, guest };
384
393
  }
385
394
  async function redirectToAuthorize(w, opts) {
386
- if (!config) return;
395
+ if (!config || localTestMode) return;
387
396
  const origin = opts?.guestOk ? config.dashboardOrigins[0] ?? (await fetchDashboardOrigins())[0] : (await fetchDashboardOrigins())[0] ?? config.dashboardOrigins[0];
388
397
  if (!origin) {
389
398
  enterBlocked();
@@ -408,7 +417,7 @@ async function fetchDashboardOrigins() {
408
417
  return config.dashboardOrigins;
409
418
  }
410
419
  async function redeemTicket(ticket) {
411
- if (!config || redeeming || state !== "pending" && state !== "guest") return;
420
+ if (!config || localTestMode || redeeming || state !== "pending" && state !== "guest") return;
412
421
  const upgradingFromGuest = state === "guest";
413
422
  redeeming = true;
414
423
  try {
@@ -425,8 +434,7 @@ async function redeemTicket(ticket) {
425
434
  const body = await res.json();
426
435
  embedToken = body.embedToken;
427
436
  user = body.user;
428
- colyseusUrl = body.colyseus?.url;
429
- void colyseusUrl;
437
+ colyseusUrls = body.colyseus?.urls;
430
438
  state = "authenticated";
431
439
  clearRetryFlag();
432
440
  removeOverlay();
@@ -448,7 +456,7 @@ async function redeemTicket(ticket) {
448
456
  }
449
457
  }
450
458
  async function requestGuestSession() {
451
- if (!config || requestingGuest || redeeming) return;
459
+ if (!config || localTestMode || requestingGuest || redeeming) return;
452
460
  if (state !== "pending" && state !== "guest") return;
453
461
  requestingGuest = true;
454
462
  try {
@@ -465,7 +473,7 @@ async function requestGuestSession() {
465
473
  const body = await res.json();
466
474
  embedToken = body.embedToken;
467
475
  user = body.user;
468
- colyseusUrl = body.colyseus?.url;
476
+ colyseusUrls = body.colyseus?.urls;
469
477
  enterGuest();
470
478
  } catch (error) {
471
479
  emit("error", { error });
@@ -494,6 +502,39 @@ function enterGuest() {
494
502
  emit("guest", ctx);
495
503
  }
496
504
  }
505
+ function isLoopbackLocation(w) {
506
+ try {
507
+ const u = new URL(w.location.origin);
508
+ return u.protocol === "http:" && (u.hostname === "localhost" || u.hostname === "127.0.0.1" || u.hostname === "[::1]");
509
+ } catch {
510
+ return false;
511
+ }
512
+ }
513
+ function wantsLocalTest(w) {
514
+ if (isEmbedded()) return false;
515
+ if (!isLoopbackLocation(w)) return false;
516
+ try {
517
+ return new URLSearchParams(w.location.search).get("genex_local_test") === "1";
518
+ } catch {
519
+ return false;
520
+ }
521
+ }
522
+ function enterLocalTestMode(w) {
523
+ localTestMode = true;
524
+ readFragment(w);
525
+ const localUser = { id: "local:test", name: "Local Tester" };
526
+ user = localUser;
527
+ state = "guest";
528
+ removeOverlay();
529
+ try {
530
+ console.info(
531
+ "[genex] local test mode \u2014 local visuals and controls only. Auth, saves, leaderboards, and multiplayer are NOT validated here; no Genex credential exists."
532
+ );
533
+ } catch {
534
+ }
535
+ for (const waiter of playerWaiters.splice(0)) waiter.resolve({ user: localUser, guest: true });
536
+ emit("guest", { user: localUser });
537
+ }
497
538
  async function handleRedeemFailure() {
498
539
  const w = win();
499
540
  if (w && !isEmbedded() && !readRetryFlag()) {
@@ -683,8 +724,9 @@ function __resetForTests(overrides) {
683
724
  config = null;
684
725
  state = "pending";
685
726
  user = null;
727
+ localTestMode = false;
686
728
  embedToken = void 0;
687
- colyseusUrl = void 0;
729
+ colyseusUrls = void 0;
688
730
  parentOrigin = null;
689
731
  initialized = false;
690
732
  redeeming = false;
@@ -708,6 +750,7 @@ export {
708
750
  getUser,
709
751
  getEmbedToken,
710
752
  getColyseusAuth,
753
+ getColyseusUrls,
711
754
  waitForAuth,
712
755
  waitForPlayer,
713
756
  on,
package/dist/index.d.ts CHANGED
@@ -98,6 +98,9 @@ declare function getAuthState(): AuthState;
98
98
  /**
99
99
  * The current player — non-null once 'authenticated' OR 'guest'. Guests have
100
100
  * an `id` prefixed `guest:` and a server-assigned name like "Guest-1234".
101
+ * Local test mode is the one guest-state exception: `id` is `local:test`
102
+ * (a prefix that can never collide with `guest:` or account ids) and the
103
+ * name is "Local Tester".
101
104
  */
102
105
  declare function getUser(): EmbedUser | null;
103
106
  /**
@@ -121,6 +124,9 @@ declare function getEmbedToken(): string | undefined;
121
124
  declare function getColyseusAuth(): {
122
125
  embedToken: string;
123
126
  } | undefined;
127
+ /** The relay URLs for this session (server-owned; a regional list when configured). Pass to
128
+ * connect()/matchmake() as `urls` so the SDK joins the lowest-latency one; single-url fallback. */
129
+ declare function getColyseusUrls(): string[];
124
130
  /**
125
131
  * Resolves with the signed-in ACCOUNT once authenticated; rejects if the
126
132
  * session ends up blocked. THE gate for /state saves and any account-bound
@@ -217,4 +223,4 @@ declare function __resetForTests(overrides?: {
217
223
  refreshRetryMs?: number;
218
224
  }): void;
219
225
 
220
- export { type AuthState, type EmbedConfig, type EmbedEvent, type EmbedUser, type Leaderboard, type LeaderboardEntry, type PlayerStateResult, type SaveStateResult, type SubmitScoreResult, type WorldStateResult, __resetForTests, _stashTicketFromUrl, getAuthState, getColyseusAuth, getEmbedToken, getLeaderboard, getUser, initEmbed, isEmbedded, loadPlayerState, loadWorldState, on, savePlayerState, saveWorldState, submitScore, waitForAuth, waitForPlayer };
226
+ export { type AuthState, type EmbedConfig, type EmbedEvent, type EmbedUser, type Leaderboard, type LeaderboardEntry, type PlayerStateResult, type SaveStateResult, type SubmitScoreResult, type WorldStateResult, __resetForTests, _stashTicketFromUrl, getAuthState, getColyseusAuth, getColyseusUrls, getEmbedToken, getLeaderboard, getUser, initEmbed, isEmbedded, loadPlayerState, loadWorldState, on, savePlayerState, saveWorldState, submitScore, waitForAuth, waitForPlayer };
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  _stashTicketFromUrl,
4
4
  getAuthState,
5
5
  getColyseusAuth,
6
+ getColyseusUrls,
6
7
  getEmbedToken,
7
8
  getLeaderboard,
8
9
  getUser,
@@ -16,12 +17,13 @@ import {
16
17
  submitScore,
17
18
  waitForAuth,
18
19
  waitForPlayer
19
- } from "./chunk-LWEYUUBS.js";
20
+ } from "./chunk-5VYRFOFN.js";
20
21
  export {
21
22
  __resetForTests,
22
23
  _stashTicketFromUrl,
23
24
  getAuthState,
24
25
  getColyseusAuth,
26
+ getColyseusUrls,
25
27
  getEmbedToken,
26
28
  getLeaderboard,
27
29
  getUser,
package/dist/sentry.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  _stashTicketFromUrl,
3
3
  getUser,
4
4
  on
5
- } from "./chunk-LWEYUUBS.js";
5
+ } from "./chunk-5VYRFOFN.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.4.1",
3
+ "version": "0.6.0",
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",