koin.js 1.0.4 → 1.0.6

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/index.mjs CHANGED
@@ -5640,10 +5640,45 @@ function getCore2(system) {
5640
5640
  return getCore(system);
5641
5641
  }
5642
5642
 
5643
+ // src/lib/rom-cache.ts
5644
+ var CACHE_NAME = "koin-rom-cache-v1";
5645
+ async function getCachedRom(romId) {
5646
+ if (typeof caches === "undefined") return null;
5647
+ try {
5648
+ const cache = await caches.open(CACHE_NAME);
5649
+ const response = await cache.match(romId);
5650
+ if (response) {
5651
+ console.log(`[Cache] Hit for ROM ${romId}`);
5652
+ return await response.blob();
5653
+ }
5654
+ } catch (e) {
5655
+ console.warn("[Cache] Read failed:", e);
5656
+ }
5657
+ return null;
5658
+ }
5659
+ async function fetchAndCacheRom(romId, url) {
5660
+ const response = await fetch(url);
5661
+ if (!response.ok) {
5662
+ throw new Error(`Failed to fetch ROM: ${response.statusText}`);
5663
+ }
5664
+ const blob = await response.blob();
5665
+ if (typeof caches !== "undefined") {
5666
+ try {
5667
+ const cache = await caches.open(CACHE_NAME);
5668
+ await cache.put(romId, new Response(blob));
5669
+ console.log(`[Cache] Cached ROM ${romId}`);
5670
+ } catch (e) {
5671
+ console.warn("[Cache] Write failed:", e);
5672
+ }
5673
+ }
5674
+ return blob;
5675
+ }
5676
+
5643
5677
  // src/hooks/emulator/useEmulatorCore.ts
5644
5678
  function useEmulatorCore({
5645
5679
  system,
5646
5680
  romUrl,
5681
+ romId,
5647
5682
  core: coreOverride,
5648
5683
  biosUrl,
5649
5684
  initialState,
@@ -5725,7 +5760,25 @@ function useEmulatorCore({
5725
5760
  setError(null);
5726
5761
  const core = coreOverride || getCore2(system);
5727
5762
  let romOption = romUrl;
5728
- if (romFileName) {
5763
+ if (romId) {
5764
+ try {
5765
+ let blob = await getCachedRom(romId);
5766
+ if (!blob) {
5767
+ console.log(`[Nostalgist] Fetching and caching ROM ${romId}`);
5768
+ blob = await fetchAndCacheRom(romId, romUrl);
5769
+ } else {
5770
+ console.log(`[Nostalgist] Loaded ROM ${romId} from cache`);
5771
+ }
5772
+ if (blob) {
5773
+ romOption = {
5774
+ fileName: romFileName || "rom.bin",
5775
+ fileContent: blob
5776
+ };
5777
+ }
5778
+ } catch (err) {
5779
+ console.error("[Nostalgist] Cache/Fetch error, falling back to direct URL:", err);
5780
+ }
5781
+ } else if (romFileName) {
5729
5782
  romOption = { fileName: romFileName, fileContent: romUrl };
5730
5783
  }
5731
5784
  const inputConfig = buildRetroArchConfig({
@@ -6392,7 +6445,8 @@ var useNostalgist = ({
6392
6445
  onError,
6393
6446
  initialVolume = 100,
6394
6447
  romFileName,
6395
- shader
6448
+ shader,
6449
+ romId
6396
6450
  }) => {
6397
6451
  const isHeavySystem = useMemo(() => {
6398
6452
  return PERFORMANCE_TIER_2_SYSTEMS.has(system.toUpperCase());
@@ -6420,6 +6474,7 @@ var useNostalgist = ({
6420
6474
  } = useEmulatorCore({
6421
6475
  system,
6422
6476
  romUrl,
6477
+ romId,
6423
6478
  core,
6424
6479
  biosUrl,
6425
6480
  initialState,
@@ -6613,6 +6668,7 @@ function useControls(system, onNotify) {
6613
6668
  function useGameSession(props) {
6614
6669
  const {
6615
6670
  romUrl,
6671
+ romId,
6616
6672
  romFileName,
6617
6673
  system,
6618
6674
  core,
@@ -6661,6 +6717,7 @@ function useGameSession(props) {
6661
6717
  const nostalgist = useNostalgist({
6662
6718
  system,
6663
6719
  romUrl,
6720
+ romId,
6664
6721
  romFileName,
6665
6722
  core,
6666
6723
  biosUrl,
@@ -7434,8 +7491,39 @@ function usePlayerPersistence(onSettingsChange) {
7434
7491
  updateSettings
7435
7492
  };
7436
7493
  }
7494
+
7495
+ // src/lib/telemetry.ts
7496
+ var sendTelemetry = (eventName, params = {}) => {
7497
+ if (typeof window === "undefined") return;
7498
+ try {
7499
+ fetch("https://koin.theretrosaga.com/api/telemetry", {
7500
+ method: "POST",
7501
+ headers: {
7502
+ "Content-Type": "application/json"
7503
+ },
7504
+ body: JSON.stringify({
7505
+ event_name: eventName,
7506
+ params: {
7507
+ ...params,
7508
+ url: window.location.href,
7509
+ referrer: document.referrer,
7510
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
7511
+ }
7512
+ })
7513
+ }).catch(() => {
7514
+ });
7515
+ } catch (e) {
7516
+ }
7517
+ };
7437
7518
  var GamePlayer = memo(function GamePlayer2(props) {
7438
7519
  const { settings, updateSettings, isLoaded: settingsLoaded } = usePlayerPersistence();
7520
+ useEffect(() => {
7521
+ sendTelemetry("game_start", {
7522
+ system: props.system,
7523
+ core: props.core,
7524
+ game: props.title || "unknown"
7525
+ });
7526
+ }, [props.system, props.core, props.title]);
7439
7527
  const [biosModalOpen, setBiosModalOpen] = useState(false);
7440
7528
  const [showShortcutsModal, setShowShortcutsModal] = useState(false);
7441
7529
  const effectiveShader = props.shader !== void 0 ? props.shader : settings.shader;
@@ -7533,6 +7621,13 @@ var GamePlayer = memo(function GamePlayer2(props) {
7533
7621
  status,
7534
7622
  isPerformanceMode
7535
7623
  } = nostalgist;
7624
+ useEffect(() => {
7625
+ if (status === "running") {
7626
+ console.log("[Koin Debug] Status:", status);
7627
+ console.log("[Koin Debug] isPerformanceMode:", isPerformanceMode);
7628
+ console.log("[Koin Debug] crossOriginIsolated:", typeof window !== "undefined" ? window.crossOriginIsolated : "N/A");
7629
+ }
7630
+ }, [status, isPerformanceMode]);
7536
7631
  useEffect(() => {
7537
7632
  if (settingsLoaded) {
7538
7633
  setVolume(settings.volume);
@@ -7726,6 +7821,18 @@ var GamePlayer = memo(function GamePlayer2(props) {
7726
7821
  ]
7727
7822
  }
7728
7823
  ),
7824
+ !isPerformanceMode && (status === "running" || status === "paused") && /* @__PURE__ */ jsx(
7825
+ "div",
7826
+ {
7827
+ className: "bg-red-900/80 backdrop-blur-md px-2 py-1 rounded border border-red-500/50 flex items-center gap-1.5",
7828
+ title: "Standard Mode (Single Threaded)",
7829
+ children: /* @__PURE__ */ jsxs("span", { className: "text-[10px] uppercase font-bold tracking-wider text-red-200", children: [
7830
+ "Standard (",
7831
+ typeof window !== "undefined" && window.crossOriginIsolated ? "Isolated" : "Not Isolated",
7832
+ ")"
7833
+ ] })
7834
+ }
7835
+ ),
7729
7836
  settings.showInputDisplay && (status === "running" || status === "paused") && /* @__PURE__ */ jsx(
7730
7837
  InputDisplay_default,
7731
7838
  {