npm package: @l2launcher/launcher-api
Description: l2launcher integration
Latest version: 0.0.15

# L2Launcher API

This library is needed only for test development, as in production this library will be automatically available in the `window.L2LAUNCHER` field.

# For production

In production, the library initialization will occur automatically before your code. The `new L2Launcher()` instance will be created immediately after library initialization and will be available through `window.L2LAUNCHER`.

```javascript
// Library is already initialized and available
const launcher = window.L2LAUNCHER;

// Use API methods directly
const status = await launcher.api.getInstallationStatus();
```

## HTML

### Requirements

1. The main HTML file must be named `index.html` and placed at the root of your project
2. All links on the page must start with a dot (relative paths), e.g., `./assets/script.js`, `./assets/style.css`, `./assets/images/logo.png`. This applies to scripts, styles, images, videos, and other assets
3. The `index.html` must avoid a `<base>` tag that. The `<base>` tag will be automatically added in production by l2launcher.com
4. All other external links/fetch/xhr requests will be blocked by [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)

   > Technically, you can use multiple HTML files (`index.html` and `./assets/*.html`), but only `index.html` will be initialized with this library and have a properly set `<base>` tag. So [SPA](https://en.wikipedia.org/wiki/Single-page_application) is preferred here.

### Example index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>My Custom Launcher</title>
    <base href="/">
    <script src="./assets/my-app.js"></script>
    <link rel="stylesheet" href="./assets/my-app.css"/>
</head>
<body>
    <img src="./assets/images/some-image.png" alt="test-img">
    <script>
        // Use API methods
        const status = await window.L2LAUNCHER.api.getInstallationStatus();
    </script>
</body>
</html>
```

# For development
## Installation

```bash
npm install @l2launcher/launcher-api
```

### Dev HTML

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <title>My Custom Launcher</title>
    <base href="/">
    
    <!-- This script should be deleted for production -->
    <script src="./node_modules/@l2launcher/launcher-api/dist/l2launcher-lib.iife.js"></script>
    <!-- This script should be deleted for production -->
    <script>
        /**
         * L2LauncherInit is available in l2launcher-lib.iife.js
         * You can also pass config as second parameter: L2LauncherInit.init(parameters, config)
         */
        const launcherParameters = { SOME_IMAGE: './assets/images/some.png' };
        window.L2LAUNCHER = L2LauncherInit.init(launcherParameters);
    </script>
    
    <link rel="stylesheet" href="./assets/my-app.css"/>
    <script src="./assets/my-app.js"></script>
</head>
<body>
<img src="./assets/images/some-image.png" alt="test-img">
<script>
    // Use API methods
    const status = await window.L2LAUNCHER.api.getInstallationStatus();
    // Or use parameter
    const pathToImage = window.L2LAUNCHER.parameters.SOME_IMAGE;
</script>
</body>
</html>
```

## API Reference

### L2Launcher Class

Main class that provides access to all launcher functionality.

#### Constructor

```typescript
new L2Launcher(parameters?: LauncherParameters, config?: LauncherConfig)
```

**Parameters:**
- `parameters` (optional): Parameters object (key-value pairs as strings). Default: `{}`
- `config` (optional): Configuration object
  - `timeout?: number` - Request timeout in milliseconds (default: 5000)

**Example:**
```typescript
const launcher = new L2Launcher();
// or
const launcher = new L2Launcher({ SOME_KEY: 'value' });
// or
const launcher = new L2Launcher({ SOME_KEY: 'value' }, { timeout: 10000 });
```

#### Properties

- `VERSION: string` - Library version (read from package.json)
- `config: LauncherConfig` - Configuration object
- `api: Api` - API instance for making requests
- `parameters: LauncherParameters` - Parameters object (Record<string, string>)

### API Methods

All API methods are accessible through `launcher.api`. All methods return `Promise<ApiResponse<T>>` where `ApiResponse` is a union type:

```typescript
// Success response
{
    success: true;
    data: T;
    statusCode: number;
}
// Error response
| {
    success: false;
    error: string;
    statusCode: number;
}
```

#### Client Endpoints

All client endpoints are relative to the `<base>` tag URL, which already includes the `clientId`. These endpoints use POST method.

##### `getInstallationStatus()`

Get the current installation status of the client.

**Endpoint:** `POST installation-status`

**Returns:** `Promise<ApiResponse<InstallationStatusResponse>>`

**Response Type:**
```typescript
{
    status: InstallationStatus;  // 'notInstalled' | 'preparing' | 'installing' | 'installed' | 'error'
    progress?: number;            // Progress percentage (0-100)
    message?: string;             // Status message
}
```

**Example:**
```typescript
const response = await launcher.api.getInstallationStatus();
if (response.success) {
    const status = response.data;
    console.log('Status:', status.status);
    console.log('Progress:', status.progress);
    console.log('Message:', status.message);
}
```

##### `getClientInfo()`

Get detailed information about the client.

**Endpoint:** `POST info`

**Returns:** `Promise<ApiResponse<ClientInfo>>`

**Response Type:**
```typescript
{
    client: ClientDetails;      // Client details (clientId, name)
    project: ProjectInfo;        // Project information (projectId, name)
    icon?: string;              // Optional icon URL
    publicName: string;         // Public name of the client
}
```

**Example:**
```typescript
const response = await launcher.api.getClientInfo();
if (response.success) {
    const info = response.data;
    console.log('Client ID:', info.client.clientId);
    console.log('Client name:', info.client.name);
    console.log('Project ID:', info.project.projectId);
    console.log('Project name:', info.project.name);
    console.log('Public name:', info.publicName);
    if (info.icon) {
        console.log('Icon URL:', info.icon);
    }
}
```

##### `installClient()`

Start or check the installation process of the client.

**Endpoint:** `POST install`

**Returns:** `Promise<ApiResponse<InstallationStatusResponse>>`

**Example:**
```typescript
const response = await launcher.api.installClient();
if (response.success) {
    const status = response.data;
    if (status.status === 'preparing' || status.status === 'installing') {
        console.log('Installation started');
        console.log('Progress:', status.progress);
        console.log('Message:', status.message);
        // Poll for progress updates
        pollInstallationStatus();
    } else if (status.status === 'installed') {
        console.log('Client already installed');
    }
}
```

##### `updateClient()`

Update the installed client to the latest version.

**Endpoint:** `POST update`

**Returns:** `Promise<ApiResponse<InstallationStatusResponse>>`

**Example:**
```typescript
const response = await launcher.api.updateClient();
if (response.success) {
    const status = response.data;
    if (status.status === 'preparing' || status.status === 'installing') {
        console.log('Update started');
        console.log('Progress:', status.progress);
        console.log('Message:', status.message);
    } else if (status.status === 'installed') {
        console.log('Client is up to date');
    }
}
```

##### `launchClient(args?)`

Launch the game client with optional command-line arguments.

**Endpoint:** `POST launch`

**Parameters:**
- `args?: string[]` - Optional array of command-line arguments

**Returns:** `Promise<ApiResponse<LaunchResponse>>`

**Response Type:**
```typescript
{
    launched: true;
}
```

**Example:**
```typescript
// Launch without arguments
const response = await launcher.api.launchClient();
if (response.success && response.data?.launched === true) {
    console.log('Client launched successfully');
}

// Launch with arguments
// Args will be sent to your *.exe
const responseWithArgs = await launcher.api.launchClient(['-windowed', '-nosound']);
if (responseWithArgs.success && responseWithArgs.data?.launched === true) {
    console.log('Client launched in windowed mode');
}
```

##### `createShortcut()`

Create a desktop shortcut for the client.

**Endpoint:** `POST shortcut`

**Returns:** `Promise<ApiResponse<ShortcutResponse>>`

**Response Type:**
```typescript
{
    created: true;
}
```

**Example:**
```typescript
const response = await launcher.api.createShortcut();
if (response.success && response.data?.created === true) {
    console.log('Shortcut created successfully');
}
```

##### `deleteClient()`

Delete the installed client from the system.

**Endpoint:** `POST delete`

**Returns:** `Promise<ApiResponse<DeleteResponse>>`

**Response Type:**
```typescript
{
    deleted: true;
}
```

**Example:**
```typescript
const response = await launcher.api.deleteClient();
if (response.success && response.data?.deleted === true) {
    console.log('Client deleted successfully');
}
```

#### Public Endpoints

Public endpoints use absolute paths and do not depend on the `<base>` tag. These endpoints use GET method.

##### `ping()`

Check if the server is available.

**Returns:** `Promise<ApiResponse<PingResponse>>`

**Response Type:**
```typescript
'pong'
```

**Example:**
```typescript
const response = await launcher.api.ping();
if (response.success) {
    console.log('Server responded:', response.data); // 'pong'
}
```

##### `isAllowed()`

Check if the current origin is allowed to make requests to protected endpoints.

**Returns:** `Promise<ApiResponse<IsAllowedResponse>>`

**Response Type:**
```typescript
{
    allowed: true;
    origin: string;
} | {
    allowed: false;
    origin: string;
    reason: string;
}
```

**Example:**
```typescript
const response = await launcher.api.isAllowed();
if (response.success) {
    if (response.data.allowed) {
        console.log('Origin is allowed:', response.data.origin);
    } else {
        console.log('Origin not allowed:', response.data.reason);
    }
}
```

## Types

All types and classes are exported from the library:

```typescript
// Import types
import type {
    LauncherConfig,
    LauncherParameters,
    ApiResponse,
    InstallationStatus,
    InstallationStatusResponse,
    LaunchRequest,
    LaunchResponse,
    ShortcutResponse,
    DeleteResponse,
    ClientInfo,
    ClientDetails,
    ProjectInfo,
    PingResponse,
    IsAllowedResponse
} from '@l2launcher/launcher-api';

// Import classes (for ES modules)
import { L2Launcher, Api } from '@l2launcher/launcher-api';
const launcher1 = new L2Launcher({SOME_KEY: 'value'}, {apiConfig: {timeout: 5000}});


// Or use factory function
import { L2LauncherInit } from '@l2launcher/launcher-api';

const launcher2 = L2LauncherInit.init({SOME_KEY: 'value'}, {apiConfig: {timeout: 5000}});
```

## License

MIT