@looplay/sdk 0.8.7 → 0.8.9

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/README.md CHANGED
@@ -35,7 +35,6 @@ import { LooplayIframeAuth } from '@looplay/sdk';
35
35
 
36
36
  export const looplayAuth = new LooplayIframeAuth({
37
37
  appId: 'YOUR_APP_ID', // from your creator dashboard — required
38
- apiUrl: 'https://api.looplay.gg',
39
38
  });
40
39
  ```
41
40
 
@@ -64,10 +63,11 @@ backward compatibility, but you should set one regardless).
64
63
  import { LooplayIframeAuth } from '@looplay/sdk';
65
64
 
66
65
  // 1. Initialize the SDK
66
+ // apiUrl and parentOrigin are automatically configured:
67
+ // - parentOrigin defaults to import.meta.env.VITE_PARENT_ORIGIN (or document.referrer)
68
+ // - apiUrl defaults to import.meta.env.VITE_API_URL (or 'https://api.looplay.gg')
67
69
  export const looplayAuth = new LooplayIframeAuth({
68
70
  appId: 'YOUR_APP_ID', // from your creator dashboard
69
- apiUrl: 'https://api.looplay.gg', // required for standalone builds; optional inside the iframe
70
- parentOrigin: import.meta.env.VITE_PARENT_ORIGIN, // restrict the accepted postMessage origin
71
71
 
72
72
  // Optional: Auto-request rewarded ads after match activity
73
73
  autoRequestAds: {
@@ -309,7 +309,6 @@ directly, no bundler needed:
309
309
  <script>
310
310
  const looplayAuth = new LooplaySDK.LooplayIframeAuth({
311
311
  appId: 'YOUR_APP_ID',
312
- apiUrl: 'https://api.looplay.gg',
313
312
  });
314
313
  looplayAuth.init();
315
314
  looplayAuth.initLifecycleTracking();
@@ -334,11 +333,13 @@ that's a separate opt-in browser bundle, only needed if you want
334
333
  </script>
335
334
  ```
336
335
 
337
- **Security note**: the origin check relies on `parentOrigin` (explicit option)
338
- or `document.referrer`. Referrer can be stripped by `Referrer-Policy`, browser
339
- privacy settings, or extensions when that happens the check is skipped and
340
- `LooplayIframeAuth` logs a `console.warn`. Always pass `parentOrigin` explicitly
341
- in production embeds instead of relying on the referrer fallback.
336
+ **Security note**: the origin check relies on `parentOrigin` (explicit option
337
+ or `import.meta.env.VITE_PARENT_ORIGIN`), falling back to `document.referrer`.
338
+ Referrer can be stripped by `Referrer-Policy`, browser privacy settings, or
339
+ extensions when that happens and no `parentOrigin` or `VITE_PARENT_ORIGIN` is configured,
340
+ the check is skipped and `LooplayIframeAuth` logs a `console.warn`. Configure
341
+ `VITE_PARENT_ORIGIN` in your environment or pass `parentOrigin` explicitly
342
+ in production embeds instead of relying solely on the referrer fallback.
342
343
 
343
344
  **Lifecycle**: call `dispose()` when tearing down (route change, HMR, test
344
345
  cleanup) to remove the `message` listener and clear subscribers:
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
3
4
  // src/errors.ts
4
5
  var LooplaySDKError = class extends Error {
5
6
  constructor(message) {
@@ -684,6 +685,43 @@ var ApiClient = class {
684
685
  }
685
686
  };
686
687
 
688
+ // src/constants.ts
689
+ var DEFAULT_API_URL = "https://miniapp-api.looplay.gg";
690
+ function resolveEnvParentOrigin() {
691
+ try {
692
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('looplay-sdk.cjs.js', document.baseURI).href)) }) !== "undefined" && undefined?.VITE_PARENT_ORIGIN) {
693
+ const val = undefined.VITE_PARENT_ORIGIN;
694
+ if (typeof val === "string" && val.trim().length > 0) return val.trim();
695
+ }
696
+ } catch {
697
+ }
698
+ try {
699
+ if (typeof process !== "undefined" && process.env?.VITE_PARENT_ORIGIN) {
700
+ const val = process.env.VITE_PARENT_ORIGIN;
701
+ if (typeof val === "string" && val.trim().length > 0) return val.trim();
702
+ }
703
+ } catch {
704
+ }
705
+ return void 0;
706
+ }
707
+ function resolveEnvApiUrl() {
708
+ try {
709
+ if (typeof ({ url: (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('looplay-sdk.cjs.js', document.baseURI).href)) }) !== "undefined" && undefined) {
710
+ const val = undefined.VITE_API_URL ?? undefined.VITE_LOOPLAY_API_URL;
711
+ if (typeof val === "string" && val.trim().length > 0) return val.trim();
712
+ }
713
+ } catch {
714
+ }
715
+ try {
716
+ if (typeof process !== "undefined" && process.env) {
717
+ const val = process.env.VITE_API_URL ?? process.env.VITE_LOOPLAY_API_URL;
718
+ if (typeof val === "string" && val.trim().length > 0) return val.trim();
719
+ }
720
+ } catch {
721
+ }
722
+ return void 0;
723
+ }
724
+
687
725
  // src/looplay-sdk.ts
688
726
  var LooplaySDK = class {
689
727
  auth;
@@ -691,7 +729,12 @@ var LooplaySDK = class {
691
729
  gameId;
692
730
  initialized = false;
693
731
  constructor(options = {}) {
694
- const { auth, baseUrl, fetch, defaultHeaders } = options;
732
+ const {
733
+ auth,
734
+ baseUrl = resolveEnvApiUrl() ?? DEFAULT_API_URL,
735
+ fetch,
736
+ defaultHeaders
737
+ } = options;
695
738
  if (auth) {
696
739
  this.auth = new LooplayAuth(auth);
697
740
  }
@@ -776,9 +819,23 @@ var LooplaySDK = class {
776
819
  if (!this.api) throw new MissingBaseUrlError();
777
820
  await this.api.listGameAssets(params.gameId);
778
821
  }
822
+ /**
823
+ * Best-effort self-report — must never block init(). A missing/misconfigured
824
+ * whitelist (a separate setup step from SDK integration) makes the backend
825
+ * reject this call; if that rejection propagated, the whole init() would
826
+ * reject too and every other SDK method would throw NotInitializedError,
827
+ * breaking a game over what's really just an unfinished onboarding step.
828
+ */
779
829
  async detectIntegration(params) {
780
830
  if (!this.api) return;
781
- await this.api.detectIntegration(params.gameId);
831
+ try {
832
+ await this.api.detectIntegration(params.gameId);
833
+ } catch (error) {
834
+ console.warn(
835
+ "[LooplaySDK] detectIntegration failed (SDK will still initialize) \u2014 check that this game has a whitelisted origin/domain configured:",
836
+ error
837
+ );
838
+ }
782
839
  }
783
840
  };
784
841
 
@@ -950,7 +1007,7 @@ var LooplayIframeAuth = class {
950
1007
  return this.state.jwt;
951
1008
  }
952
1009
  getApiUrl() {
953
- return this.state.apiUrl ?? this.options.apiUrl ?? null;
1010
+ return this.state.apiUrl ?? this.options.apiUrl ?? resolveEnvApiUrl() ?? DEFAULT_API_URL;
954
1011
  }
955
1012
  /** Resolves to the configured `appId`, falling back to whatever the parent pushed as `gameId`. */
956
1013
  getGameId() {
@@ -1152,12 +1209,13 @@ var LooplayIframeAuth = class {
1152
1209
  }
1153
1210
  /**
1154
1211
  * Idempotent; auto-emits GAME_STARTED exactly once per distinct auth
1155
- * session (bearer or anonymous), and self-reports SDK integration the
1156
- * same way the standalone `LooplaySDK.init()` does without this, games
1157
- * embedded via iframe never trigger the active detect call, only the
1158
- * passive heartbeat that tracking calls leave behind (which doesn't fire
1159
- * at all while the game is still IN_REVIEW/not LIVE, since tracking is
1160
- * blocked until then).
1212
+ * session (bearer or anonymous). SDK integration self-reporting for the
1213
+ * iframe path lives in `detectIntegrationOnce()` (fired from `setState()`
1214
+ * on every auth/config change, not gated behind lifecycle tracking being
1215
+ * enabled at all) without it, games embedded via iframe would never
1216
+ * trigger the active detect call, only the passive heartbeat that
1217
+ * tracking calls leave behind (which doesn't fire while the game is still
1218
+ * IN_REVIEW/not LIVE, since tracking is blocked until then).
1161
1219
  */
1162
1220
  initLifecycleTracking() {
1163
1221
  if (this.lifecycleTrackingInitialized || typeof window === "undefined")
@@ -1168,11 +1226,6 @@ var LooplayIframeAuth = class {
1168
1226
  const key = this.getTrackingKey();
1169
1227
  if (!key || this.lastGameStartedKey === key) return;
1170
1228
  this.lastGameStartedKey = key;
1171
- const gameId = this.getGameId();
1172
- if (gameId) {
1173
- this.debug("auto detectIntegration dispatch", { gameId });
1174
- void this.getClient().detectIntegration(gameId).catch(() => void 0);
1175
- }
1176
1229
  this.debug("auto GAME_STARTED dispatch");
1177
1230
  void this.emitGameEvent("GAME_STARTED");
1178
1231
  });
@@ -1330,6 +1383,8 @@ ${gameId}`;
1330
1383
  }
1331
1384
  resolveParentOrigin() {
1332
1385
  if (this.options.parentOrigin) return this.options.parentOrigin;
1386
+ const envOrigin = resolveEnvParentOrigin();
1387
+ if (envOrigin) return envOrigin;
1333
1388
  if (typeof document === "undefined" || !document.referrer) return null;
1334
1389
  try {
1335
1390
  return new URL(document.referrer).origin;
@@ -1373,6 +1428,7 @@ ${gameId}`;
1373
1428
 
1374
1429
  exports.ApiClient = ApiClient;
1375
1430
  exports.BrowserLocalStorageAuthStorage = BrowserLocalStorageAuthStorage;
1431
+ exports.DEFAULT_API_URL = DEFAULT_API_URL;
1376
1432
  exports.HttpClient = HttpClient;
1377
1433
  exports.HttpError = HttpError;
1378
1434
  exports.LOOPLAY_SDK_VERSION = LOOPLAY_SDK_VERSION;
@@ -1387,5 +1443,7 @@ exports.NotAuthenticatedError = NotAuthenticatedError;
1387
1443
  exports.NotInitializedError = NotInitializedError;
1388
1444
  exports.ServiceClient = ServiceClient;
1389
1445
  exports.TelegramAuthProvider = TelegramAuthProvider;
1446
+ exports.resolveEnvApiUrl = resolveEnvApiUrl;
1447
+ exports.resolveEnvParentOrigin = resolveEnvParentOrigin;
1390
1448
  //# sourceMappingURL=looplay-sdk.cjs.js.map
1391
1449
  //# sourceMappingURL=looplay-sdk.cjs.js.map