# init

sdk.init() picks the host, opens the handshake on filudi.com and resolves with the player, the locale, the features and the policy.

`init(options): Promise<InitResult>`. Call it once, before anything else. A second call returns the same
promise. It never rejects: a portal script that fails to load falls back to `mock`, and `result.host` says
so.

<CodePanel title="Initialise">
  <Fragment slot="javascript">
    ```js
    import { sdk } from '@filudi/game-sdk';

    const result = await sdk.init({ gameId: 'gloop', version: '1.4.0' });
    console.log(result.host);              // 'filudi' | 'crazygames' | 'poki' | 'playgama' | 'mock'
    console.log(result.player.nickname);   // 'Guest-Fox'
    if (result.features.leaderboard) showBoardButton();
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    import { sdk, type InitResult } from '@filudi/game-sdk';

    const result: InitResult = await sdk.init({ gameId: 'gloop', version: '1.4.0' });
    const host: InitResult['host'] = result.host;   // 'filudi' | 'crazygames' | 'poki' | 'playgama' | 'mock'
    if (result.features.leaderboard) showBoardButton();
    ```

  </Fragment>
</CodePanel>

## Options

<CodePanel title="InitOptions">
  <Fragment slot="javascript">
    ```js
    await sdk.init({
      gameId: 'gloop',            // slug, same as in the console
      version: '1.4.0',           // bundle version, sent with events
      debug: false,               // console logging, same as ?filudi_debug=1
      crazygames: { leaderboardKey: import.meta.env.VITE_CG_LEADERBOARD_KEY ?? '' },
    });
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    interface InitOptions {
      gameId: string;                       // slug, same as in the console
      host?: HostName;                      // skip detection
      version?: string;                     // bundle version, sent with events
      locale?: string;                      // overrides the host's locale
      mock?: Partial<MockConfig>;           // only read by the mock adapter
      timeoutMs?: number;                   // portal SDK script load, default 4000
      handshakeTimeoutMs?: number;          // wait for filudi:init, default 1500
      debug?: boolean;                      // console logging, same as ?filudi_debug=1
      events?: 'default' | 'always';        // 'always' sends track() batches from portals too
      eventsUrl?: string;                   // where portal batches go (POST .../v1/sdk/events), with 'always'
      crazygames?: { leaderboardKey?: string };
      poki?: Record<string, never>;
    }
    ```

  </Fragment>
</CodePanel>

`gameId` is the slug of the game in the console. On filudi.com the frame is opened for one game; when the
handshake names another slug than the one you passed, the SDK logs an error and uses the slug of the frame,
because the API would refuse the other one. `version` is the version string you upload; events carry it, so
pass the release version from your build.

The SDK ignores options for a host the game does not run on.

## Result

<CodePanel title="InitResult">
  <Fragment slot="javascript">
    ```js
    const { host, player, locale, features, policy } = await sdk.init({ gameId: 'gloop' });
    // features.saves: 'remote' on filudi.com and portals with storage, 'local' elsewhere
    // features.leaderboard, features.rewarded, features.interstitial, features.account: booleans
    // policy.personalizedAds: false on kids sites or without consent
    // policy.ageBand: 'all' | 'kids' | 'teen' | 'adult'
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    interface InitResult {
      host: HostName;
      player: Player;                       // { id, nickname, guest, host }
      locale: string;
      features: {
        saves: 'remote' | 'local';
        leaderboard: boolean;
        rewarded: boolean;
        interstitial: boolean;
        account: boolean;
      };
      policy: {
        personalizedAds: boolean;           // false on kids sites or without consent
        ageBand: 'all' | 'kids' | 'teen' | 'adult';
      };
    }
    ```

  </Fragment>
</CodePanel>

## Host detection

In this order: `options.host`; `?filudi_host=<name>` on the page URL; a portal global or hostname
(`CrazyGames.SDK` or `*.crazygames.com`; `PokiSDK` or `*.poki.com` or `*.poki-gdn.com`; Playgama's bridge);
the filudi handshake when the SDK runs inside an iframe (skipped on portal domains and at top level);
`localhost`, `127.0.0.1` or any unknown host gives `mock`.

On `mock`, two behaviours share the name. With `options.mock` or `?filudi_host=mock`, the ESM build loads
the configurable mock. Without them, and always in the IIFE, the SDK runs standalone: ads unavailable,
saves in `localStorage`, no leaderboard.

## The mock

<CodePanel title="MockConfig">
  <Fragment slot="javascript">
    ```js
    await sdk.init({
      gameId: 'gloop',
      mock: { host: 'filudi', ads: 'no-fill', latencyMs: 300, player: { nickname: 'Guest-Fox' } },
    });
    ```

  </Fragment>
  <Fragment slot="typescript">
    ```ts
    interface MockConfig {
      host: HostName;                       // whose rules the mock follows (ad interval, features)
      latencyMs: number;                    // added to every async call
      ads: 'fill' | 'no-fill' | 'adblock' | 'error';
      player: Partial<Player>;
      saveConflict: SaveRead<unknown> | null; // returned as the server copy on the next write
      leaderboard: LeaderboardEntry[];      // seed entries
      locale: string;
      eventsUrl: string | null;             // where track() batches go; null drops them
    }
    ```

  </Fragment>
</CodePanel>

## Before init resolves

Async and void methods called while `init()` is pending wait for it. `sdk.player.get()`,
`sdk.ads.available()`, `sdk.i18n.locale()` and `sdk.device()` throw until it resolves. Every `on()` works at
any time and returns an unsubscribe function. Calling anything before `init()` was called at all throws.

## Unavailable cases

`init()` has none: it resolves on every host. When a portal script fails, takes longer than `timeoutMs` or
reports a disabled environment, the result says `host: 'mock'` and every other module answers as on the
mock.
