@looplay/types
v0.1.1
Published
Shared types for Looplay SDK and services
Readme
@looplay/types
Shared TypeScript types for the Looplay SDK and backend services.
This package provides shared types/interfaces used by both the Looplay SDK (client) and the Looplay platform API (server), ensuring end-to-end type safety across integrations.
- 📦 Package name:
@looplay/types - 🏷️ Version:
0.1.0 - 🟦 Runtime: Zero dependencies (dev-only TypeScript)
- 📜 License: UNLICENSED (private)
Installation
Published as a dual export package (ESM + CJS) with bundled .d.ts declaration files.
# npm
npm install @looplay/types
# pnpm
pnpm add @looplay/types
# yarn
yarn add @looplay/typesThe package is private (
UNLICENSED). Make sure you have access to the appropriate registry.
Integration Flow
To integrate Looplay into your game or service, follow these steps to ensure type-safe API communication.
1. Import the Types
Import the necessary types into your service or client code:
// ESM
import type {
GameEventKey,
TrackMatchEndRequest,
EmitGameEventRequest,
EmitGameEventResponse,
} from '@looplay/types';
// CJS
const types = require('@looplay/types');2. Track Match Completions
When a player finishes a game session (win, lose, or abandon), construct the payload using TrackMatchEndRequest and send it to the platform.
const endMatchPayload: TrackMatchEndRequest = {
matchId: 'unique-match-id-1234', // Ensure this is unique per match to avoid duplicates
matchDurationSeconds: 120,
isCompleted: true,
isWin: true,
};
// Example using fetch
await fetch('https://api.looplay.io/games/your-game-id/end', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(endMatchPayload),
});3. Emit Custom Game Events
For actions like claiming rewards or completing specific quests, use EmitGameEventRequest and expect an EmitGameEventResponse.
const eventPayload: EmitGameEventRequest = {
actionCode: 'CLAIM_REWARD', // Can be a GameEventKey or a custom string
value: 50,
refId: 'quest-123',
payload: { bonus: true, tier: 'gold' },
};
const res = await fetch('https://api.looplay.io/games/your-game-id/emit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(eventPayload),
});
const data: EmitGameEventResponse = await res.json();
if (data.success) {
console.log(`Event recorded: ${data.eventId}. Points earned: ${data.pointsEarned}`);
}Exported Types Reference
| Name | Kind | Description |
| --- | --- | --- |
| GameEventKey | type | Platform-defined game event codes. Any string is also allowed for game-specific quests. |
| TrackMatchEndRequest | interface | Body for POST /games/:id/end — track match/round completion. |
| EmitGameEventRequest | interface | Body for POST /games/:id/emit — emit a custom action event. |
| EmitGameEventResponse | interface | Response for POST /games/:id/emit. |
GameEventKey
export type GameEventKey =
| 'PLAY_MATCH'
| 'WIN_MATCH'
| 'LOSE_MATCH'
| 'COMPLETE_LEVEL'
| 'CLAIM_REWARD'
| 'CUSTOM_ACTION';- Enumerates the standard event codes defined by the platform.
- Any custom
stringcan be used for game/quest-specific events.
TrackMatchEndRequest
Body for POST /games/:id/end to report a match/round completion.
export interface TrackMatchEndRequest {
/** Idempotency anchor — same matchId = same event, safe to dedup. */
matchId: string;
matchDurationSeconds: number;
isCompleted?: boolean;
isWin?: boolean;
}| Field | Type | Required | Description |
| --- | --- | --- | --- |
| matchId | string | ✅ | Unique match identifier — used to deduplicate submissions. |
| matchDurationSeconds | number | ✅ | Match duration in seconds. |
| isCompleted | boolean | ❌ | Whether the match completed (vs. abandoned/cancelled). |
| isWin | boolean | ❌ | Whether the player won the match. |
EmitGameEventRequest
Body for POST /games/:id/emit to emit a custom game event.
export interface EmitGameEventRequest {
actionCode: GameEventKey | string;
value?: number;
refId?: string;
payload?: Record<string, unknown>;
}| Field | Type | Required | Description |
| --- | --- | --- | --- |
| actionCode | GameEventKey \| string | ✅ | Action code (standard key or custom string). |
| value | number | ❌ | Numeric value associated with the event (e.g. points, count). |
| refId | string | ❌ | External reference (e.g. quest id, item id). |
| payload | Record<string, unknown> | ❌ | Arbitrary additional data. |
EmitGameEventResponse
export interface EmitGameEventResponse {
success?: boolean;
eventId?: string;
pointsEarned?: number;
[key: string]: unknown;
}| Field | Type | Description |
| --- | --- | --- |
| success | boolean | Whether the event was successfully recorded. |
| eventId | string | Server-side ID of the emitted event. |
| pointsEarned | number | Points awarded by the event (if applicable). |
| [key: string]: unknown | — | Allows the server to return additional custom fields. |
Development
Requirements
- Node.js ≥ 18 (ES2022)
- TypeScript ^5.6.3
Scripts
# Build into dist/ (with .d.ts, .d.ts.map, .js)
npm run build
# Type-check only, no emit
npm run typecheckNotable TypeScript Settings
| Option | Value | Note |
| --- | --- | --- |
| target / lib | ES2022 | Modern runtime, top-level await, native Error cause. |
| module / moduleResolution | ES2022 / Bundler | Designed for modern bundlers (Vite, esbuild, Webpack 5). |
| declaration | true | Emits .d.ts files for consumers. |
| strict | true | All strict checks enabled. |
| outDir | dist | Output directory (gitignored). |
The
dist/andnode_modules/directories are gitignored. Only sources undersrc/are committed.
Project Structure
looplay-types/
├── src/
│ └── index.ts # All types are exported from here
├── dist/ # Build output (gitignored)
├── package.json
├── tsconfig.json
└── README.mdContributing
- Add or modify types in
src/index.ts. - Run
npm run typecheckto ensure no type errors. - Run
npm run buildto regeneratedist/. - Open a PR with a clear description of the change.
Any breaking type change must bump the major version and notify the SDK and services teams.
License
UNLICENSED — internal use only within the Looplay system.
