npm package: @matrixcoder/axpo
Description: 💓 A Framework for Acode plugins
Author: Goutam Kumar
Latest version: 1.0.4

# Axpo ⚡

<div align="center">
  <img src="https://iili.io/qcAFUqQ.png" alt="Axpo" width="120" height="120" />
</div>

> A framework for building [Acode](https://acode.app) plugins with Some features.

## Installation

```bash
npm install axpo
```

**Quick start & create your first Axpo plugin**
```bash
npx axpo init
```

---

## Project Structure

After initialization, your project will have this structure:

```bash
my-first-plugin/
├── src/
│   └── main.ts / js         # Your plugin code
├── plugin.json              # Plugin manifest
├── axpo.config.ts / js      # Build configuration
├── tsconfig.json            # TypeScript config
├── package.json             # Dependencies
├── readme.md                # Documentation
├── icon.png                 # Plugin icon (max 50KB)
├── .gitignore               # Git ignore rules
└── build/                   # Build output (auto-generated)
```

### Important Files

| File | Purpose |
|------|---------|
| `src/main.ts/js` | Main plugin entry point |
| `plugin.json` | Plugin metadata and configuration |
| `axpo.config.ts/js` | Build and dev server settings |
| `icon.png` | Plugin icon (max 50KB) |

---

## Commands

### Inside a plugin project

```bash
npm run dev      # Start dev server with hot reload
npm run build    # Build + zip for production
npm run clean    # Clean build output
npm run publish  # Publish to Acode registry
```

### Axpo CLI

```bash
axpo init [name]     # Create a new plugin project
axpo dev             # Start development server
axpo build           # Build plugin (creates zip by default)
axpo build --no-zip  # Build only, skip zip
axpo zip             # Create zip from existing build
axpo publish         # Publish plugin to Acode registry
axpo logout          # Clear saved Acode credentials
axpo clean           # Remove build folder and zip files
```

**`axpo init` options**

| Flag | Description |
|------|-------------|
| `[name]` | Project folder name |
| `.` | Initialize in current directory |
| `-y, --yes` | Skip prompts, use defaults |

**`axpo build` options**

| Flag | Description |
|------|-------------|
| `--no-zip` | Skip zip creation |
| `-o, --output <file>` | Custom zip filename |
| `-w, --watch` | Watch mode (same as `axpo dev`) |

**`axpo publish` options**

| Flag | Description |
|------|-------------|
| `-z, --zip <file>` | Zip file to publish (default: `Plugin.zip`) |
| `-f, --force` | Skip confirmation prompt |

---

## Plugin Structure

```typescript
import { useContext, useSettings } from 'axpo/sdk';

export default function myPlugin() {
  return {
    async init() {
      const { baseUrl, page, pluginId, firstInit } = useContext();
      const settings = useSettings<MySettings>();

      page.setTitle('My Plugin');

      if (firstInit) {
        console.log('First run!');
      }
    },

    async destroy() {
      // cleanup
    },

    settings: [
      {
        key: 'theme',
        text: 'Color Theme',
        type: 'select',
        defaultValue: 'dark',
        options: [['light', 'Light'], ['dark', 'Dark']],
        onChange(value) { applyTheme(value); }
      },
      {
        key: 'fontSize',
        text: 'Font Size',
        type: 'number',
        defaultValue: 14,
        info: 'Size in pixels'
      },
      {
        key: 'enabled',
        text: 'Enable Plugin',
        type: 'checkbox',
        defaultValue: true
      }
    ]
  };
}
```

---

## Hooks

### `useContext()`
Must be called inside `init()` or `destroy()` only.

| Property | Type | Description |
|----------|------|-------------|
| `baseUrl` | `string` | Plugin base URL (with trailing slash) |
| `page` | `WCPage` | Page/UI manager |
| `pluginId` | `string` | Unique plugin ID |
| `firstInit` | `boolean` | First time running? |
| `cacheFile` | `File` | Cache file object |
| `cacheFileUrl` | `string` | Cache file URL |

### `useSettings<T>()`
Type-safe settings manager. Pass your settings interface as generic.

| Method | Description |
|--------|-------------|
| `get(key)` | Get a single setting value |
| `getAll()` | Get all settings as object |
| `set(key, value)` | Update a setting (triggers `onChange`) |

---

## Settings Types

| Type | Input | Value |
|------|-------|-------|
| `checkbox` | Toggle | `boolean` |
| `text` | Text field | `string` |
| `number` | Number field | `number` |
| `select` | Dropdown | `string` |

### SettingItem Properties

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `key` | `string` | Yes | Unique identifier for the setting |
| `text` | `string` | Yes | Display label |
| `type` | `SettingType` | Yes | Input type (checkbox/text/number/select) |
| `defaultValue` | `any` | Yes | Default value |
| `info` | `string` | No | Help text/description |
| `icon` | `string` | No | Icon name |
| `iconColor` | `string` | No | Icon color (hex/rgba) |
| `options` | `Array` | No | Options for select type: `[value, label]` or `value` |
| `placeholder` | `string` | No | Input placeholder |
| `required` | `boolean` | No | Whether field is required |
| `match` | `RegExp` | No | Validation regex pattern |
| `test` | `Function` | No | Custom validation function |
| `onChange` | `Function` | No | Change event handler |

**All setting options:**

```typescript
{
  key: string           // required — unique key
  text: string          // required — display label
  type: SettingType     // required — checkbox | text | number | select
  defaultValue: any     // required — default value
  info?: string         // help text
  icon?: string         // icon name
  iconColor?: string    // hex or rgba
  options?: Array<[string, string] | string>  // for select type
  placeholder?: string  // input placeholder
  required?: boolean    
  match?: RegExp        // validation pattern
  test?: (value) => boolean  // custom validation
  onChange?: (value) => void // on change handler
}
```

---


**Example with type safety:**

```typescript
import { useContext, useSettings } from 'axpo/sdk';
import type { Plugin, SettingItem } from 'axpo/sdk';

interface MySettings {
  theme: 'light' | 'dark';
  fontSize: number;
}

const myPlugin: Plugin = () => {
  return {
    async init() {
      const { page } = useContext();
      const settings = useSettings<MySettings>();

      page.setTitle('My Plugin');
      console.log(settings.get('theme'));
    },

    settings: [
      {
        key: 'theme',
        text: 'Theme',
        type: 'select',
        defaultValue: 'dark',
        options: [['light', 'Light'], ['dark', 'Dark']]
      }
    ] satisfies SettingItem[]
  };
};

export default myPlugin;
```

---

## Configuration (`axpo.config.ts`)

```typescript
import { defineConfig } from 'axpo';

export default defineConfig({
  buildOptions: {
    entryPoints: ['src/main.ts'],
    bundle: true,
    minify: false,
    target: 'es2020',
    alias: { '@': './src' }
  },
  files: ['readme.md', 'icon.png'],
  zipFilename: 'MyPlugin.zip',
  dev: { port: 3000 }
});
```

---

## `plugin.json`

```json
{
  "id": "com.example.plugin",
  "name": "Example Plugin",
  "main": "dist/main.js",
  "version": "1.0.0",
  "readme": "readme.md",
  "icon": "icon.png",
  "files": ["worker.js"],
  "minVersionCode": 292,
  "price": 0,
  "license": "MIT",
  "keywords": ["foo","bar"],
  "changelogs": "changelogs.md",
  "author": {
    "name": "Example Author",
    "email": "example@email.com",
    "url": "https://example.com",
    "github": "example"
  }
}
```

---

## Links

- **GitHub:** [github.com/MatrixCoder0101/axpo](https://github.com/MatrixCoder0101/axpo)
- **Acode Docs:** [docs.acode.app](https://docs.acode.app)

<center>Made with ❤️ by Goutam Kumar</center>