# gem-bridge-sdk

SDK for integrating mini-applications with the Gem Space platform. Works in TypeScript and JavaScript projects.

## Install

```bash
npm install @gemspace/gem-bridge-sdk
```

## API overview

The SDK exposes **7 bridge requests** for mini-app development:

| Method                    | Required     | Request                     | Response                     | Description                                           |
| ------------------------- | ------------ | --------------------------- | ---------------------------- | ----------------------------------------------------- |
| `bridge.app.init()`       | Optional     | `IAppInitRequestBody`       | `IAppInitResponseBody`       | Returns app and platform configuration from Gem Space |
| `bridge.profile.get()`    | Optional     | `IProfileGetRequestBody`    | `IProfileGetResponseBody`    | Returns the current user profile                      |
| `bridge.app.ready()`      | **Required** | `IAppReadyRequestBody`      | `IAppReadyResponseBody`      | Notifies Gem Space that the mini-app is ready for use |
| `bridge.app.close()`      | Optional     | `IAppCloseRequestBody`      | `IAppCloseResponseBody`      | Requests closing the mini-app                         |
| `bridge.storage.get()`    | Optional     | `IStorageGetRequestBody`    | `IStorageGetResponseBody`    | Reads a value from host storage                       |
| `bridge.storage.set()`    | Optional     | `IStorageSetRequestBody`    | `IStorageSetResponseBody`    | Writes a value to host storage                        |
| `bridge.storage.remove()` | Optional     | `IStorageRemoveRequestBody` | `IStorageRemoveResponseBody` | Removes a value from host storage                     |

## Usage

### npm / bundler

```ts
import { bridge } from '@gemspace/gem-bridge-sdk';

// Optional — platform and app configuration
const initData = await bridge.app.init();
// { appId, version, platform, clientVersion, manifestVersion, theme, viewMode, viewport }

// Optional — current user profile
const profile = await bridge.profile.get();
// { user: { id, displayName, username, languageCode, avatarUrl } }

// Required — tell Gem Space the mini-app is ready
await bridge.app.ready();
// { result: true }

// Optional — request closing the mini-app
await bridge.app.close();
// { result: true }
```

### Request & response types

```ts
// bridge.app.init()
interface IAppInitRequestBody {}
interface IAppInitResponseBody {
  appId: string;
  version: string;
  platform: 'android' | 'web' | 'ios';
  clientVersion: string;
  manifestVersion: number;
  theme: 'dark' | 'light' | 'system';
  viewMode: 'fullscreen' | 'compact' | 'popup';
  viewport: {
    width: number;
    height: number;
    safeAreaTop?: number;
    safeAreaBottom?: number;
  };
}

// bridge.profile.get()
interface IProfileGetRequestBody {}
interface IProfileGetResponseBody {
  user: {
    id: string;
    displayName: string;
    username: string;
    languageCode: string;
    avatarUrl: string;
  };
}

// bridge.app.ready()
interface IAppReadyRequestBody {}
interface IAppReadyResponseBody {
  result: boolean;
}

// bridge.app.close()
interface IAppCloseRequestBody {}
interface IAppCloseResponseBody {
  result: boolean;
}

// bridge.storage.get()
interface IStorageGetRequestBody {
  key: string;
}
interface IStorageGetResponseBody {
  key: string;
  value: string | null;
}

// bridge.storage.set()
interface IStorageSetRequestBody {
  key: string;
  value: string;
}
interface IStorageSetResponseBody {
  result: boolean;
}

// bridge.storage.remove()
interface IStorageRemoveRequestBody {
  key: string;
}
interface IStorageRemoveResponseBody {
  result: boolean;
}
```

### Storage

```ts
await bridge.storage.set({ key: 'lastOpened', value: '2026-06-10T00:00:00.000Z' });
// { result: true }

const { key, value } = await bridge.storage.get({ key: 'lastOpened' });
// { key: 'lastOpened', value: '2026-06-10T00:00:00.000Z' }

await bridge.storage.remove({ key: 'lastOpened' });
// { result: true }
```

### CDN script tag

```html
<script src="https://cdn.jsdelivr.net/npm/@gemspace/gem-bridge-sdk/index.global.js"></script>
<script>
  (async () => {
    const initData = await GemSpaceBridge.bridge.app.init();
    console.log(initData);
  })();
</script>
```

Also available via [unpkg](https://unpkg.com/@gemspace/gem-bridge-sdk/index.global.js).

## Errors

Bridge requests reject with an error object when the host cannot handle a message. Each error has `code`, `name`, and `description` fields (IBridgeError).

| Code  | Name                   | Description                                       |
| ----- | ---------------------- | ------------------------------------------------- |
| `404` | `HandlerNotFound`      | No handler registered for message                 |
| `500` | `HandlerError`         | Handler threw an exception                        |
| `400` | `HandlerBadData`       | Invalid message format or missing required fields |
| `701` | `StorageQuotaExceeded` | Mini-app storage quota exceeded                   |

```ts
try {
  await bridge.storage.set({ key: 'data', value: largePayload });
} catch (error) {
  // { code: 701, name: 'StorageQuotaExceeded', description: 'Mini-app storage quota exceeded' }
  console.error(error);
}
```

## Requirements

- Mini-app runs inside a host iframe and has to implement the Gem Space bridge protocol.
- Maximum allowed storage size is 5 MB; otherwise `StorageQuotaExceeded` (`701`) is returned.
- Do not store sensitive data (access tokens, passwords, API keys, PII) via bridge storage. Use it only for non-sensitive app state (e.g. `lastOpened` date, UI preferences, etc). Storage persists on the device until the user logs out.
