Skip to content

TypeScript Support

Use TypeScript definitions for better IDE support when developing plugins.

Setup

Copy the type definitions to your plugin folder:

my-plugin/
├── plugin.js
├── gemshell.d.ts    # Type definitions
└── ...

Type Definitions

Create gemshell.d.ts:

typescript
/**
 * Settings injected at runtime
 */
declare const GEMSHELL_SETTINGS: Record<string, any>;

/**
 * Plugin setting definition
 */
interface PluginSetting {
  id: string;
  type: 'checkbox' | 'text' | 'textarea' | 'number' | 'slider' | 'range' | 'select' | 'color';
  label: string;
  default?: any;
  description?: string;
  placeholder?: string;
  min?: number;
  max?: number;
  step?: number;
  rows?: number;
  options?: string[];
}

/**
 * Build context passed to hooks
 */
interface BuildContext {
  gamePath: string;
  outputPath: string;
  config: {
    title: string;
    appName: string;
    version: string;
    width: number;
    height: number;
  };
  platform: 'darwin' | 'win32' | 'linux';
  arch: 'arm64' | 'x64' | 'ia32';
  error?: string;
  percent?: number;
  message?: string;
}

/**
 * Plugin manifest
 */
interface Plugin {
  name: string;
  version: string;
  author?: string;
  description?: string;
  gemshell?: string;
  inject?: string[];
  settings?: PluginSetting[];
  
  onPreBuild?(context: BuildContext, settings: Record<string, any>): Promise<void>;
  onModifyAssets?(context: BuildContext, settings: Record<string, any>): Promise<void>;
  onBeforePackage?(context: BuildContext, settings: Record<string, any>): Promise<void>;
  onPostBuild?(context: BuildContext, settings: Record<string, any>): Promise<void>;
  onBuildError?(context: BuildContext, settings: Record<string, any>): Promise<void>;
  onBuildProgress?(context: BuildContext, settings: Record<string, any>): void;
}

/**
 * GemShell Plugin API (available in hooks)
 */
declare const gemshell: {
  log(message: string, ...args: any[]): void;
  warn(message: string, ...args: any[]): void;
  error(message: string, ...args: any[]): void;
  
  storage: {
    get<T>(key: string, defaultValue?: T): T;
    set(key: string, value: any): void;
    delete(key: string): void;
    clear(): void;
    has(key: string): boolean;
    keys(): string[];
  };
  
  fs: {
    read(path: string): string;
    readJson<T>(path: string): T;
    readBinary(path: string): Buffer;
    write(path: string, content: string): void;
    writeJson(path: string, data: any): void;
    writeBinary(path: string, buffer: Buffer): void;
    exists(path: string): boolean;
    stat(path: string): { size: number; mtime: number; isDirectory: boolean };
    mkdir(path: string): void;
    copy(src: string, dest: string): void;
    remove(path: string): void;
    list(path: string): string[];
  };
  
  http: {
    get(url: string, options?: RequestOptions): Promise<HttpResponse>;
    post(url: string, body?: any, options?: RequestOptions): Promise<HttpResponse>;
    put(url: string, body?: any, options?: RequestOptions): Promise<HttpResponse>;
    delete(url: string, options?: RequestOptions): Promise<HttpResponse>;
    request(options: FullRequestOptions): Promise<HttpResponse>;
  };
  
  glob(pattern: string): string[];
  
  transform: {
    replaceInFile(path: string, search: string, replace: string): void;
    appendToFile(path: string, content: string): void;
    prependToFile(path: string, content: string): void;
    injectIntoHtml(content: string, position: 'head' | 'body-start' | 'body-end'): void;
  };
  
  build: {
    getInfo(): BuildInfo;
    getGameConfig(): GameConfig;
    incrementBuildNumber(): number;
    getPaths(): BuildPaths;
  };
  
  native: {
    isAvailable(): boolean;
    getVersion(): string;
    encrypt(key: string, text: string): string | null;
    decrypt(key: string, ciphertext: string): string | null;
    encryptBytes(key: string, buffer: Buffer): Buffer | null;
    decryptBytes(key: string, buffer: Buffer): Buffer | null;
  };
};

interface RequestOptions {
  headers?: Record<string, string>;
  timeout?: number;
  auth?: { username: string; password: string };
}

interface FullRequestOptions extends RequestOptions {
  method: string;
  url: string;
  body?: any;
}

interface HttpResponse {
  status: number;
  statusText: string;
  headers: Record<string, string>;
  data: any;
}

interface BuildInfo {
  platform: string;
  arch: string;
  gemshellVersion: string;
  buildNumber: number;
  timestamp: string;
  isProduction: boolean;
  isDevelopment: boolean;
}

interface GameConfig {
  title: string;
  appName: string;
  version: string;
  width: number;
  height: number;
}

interface BuildPaths {
  source: string;
  output: string;
  temp: string;
  assets: string;
}

Usage in plugin.js

With the type definitions, your IDE will provide:

  • Autocomplete for gemshell.* APIs
  • Type checking for settings
  • Documentation on hover
javascript
// @ts-check
/// <reference path="./gemshell.d.ts" />

/** @type {Plugin} */
module.exports = {
  name: 'My Plugin',
  version: '1.0.0',
  
  settings: [
    { id: 'enabled', type: 'checkbox', label: 'Enable', default: true }
  ],
  
  async onPreBuild(context, settings) {
    // IDE now knows context.config.title is a string
    gemshell.log(`Building ${context.config.title}`);
    
    // IDE autocompletes gemshell.storage.get()
    const count = gemshell.storage.get('buildCount', 0);
  }
};

Usage in script.js

javascript
// @ts-check
/// <reference path="./gemshell.d.ts" />

// IDE knows GEMSHELL_SETTINGS exists
const { enabled, position } = GEMSHELL_SETTINGS;

JSDoc Alternative

If you prefer not to use a separate .d.ts file:

javascript
/**
 * @typedef {Object} Settings
 * @property {boolean} enabled
 * @property {string} position
 */

/** @type {Settings} */
const settings = GEMSHELL_SETTINGS;