# MediaWiki SDK

[![npm downloads](https://img.shields.io/npm/dm/mediawiki-sdk.svg)](https://www.npmjs.com/package/mediawiki-sdk)
[![npm version](https://img.shields.io/npm/v/mediawiki-sdk.svg)](https://www.npmjs.com/package/mediawiki-sdk)
[![TypeScript](https://img.shields.io/badge/TypeScript-Built_with-blue.svg)](https://www.typescriptlang.org/)
[![Bundle size](https://badgen.net/bundlephobia/minzip/mediawiki-sdk)](https://bundlephobia.com/result?p=mediawiki-sdk)
[![License: ISC](https://img.shields.io/badge/License-ISC-yellow.svg)](https://opensource.org/licenses/ISC)
[![ESM in browser](https://img.shields.io/badge/browser-support-green.svg)](https://www.jsdelivr.com/package/npm/mediawiki-sdk)
[![Wiki](https://img.shields.io/badge/docs-wiki-blue)](https://github.com/DimaYastrebov/mediawiki-sdk/wiki)
[![codecov](https://codecov.io/gh/DimaYastrebov/mediawiki-sdk/branch/main/graph/badge.svg)](https://codecov.io/gh/DimaYastrebov/mediawiki-sdk)

**MediaWiki SDK** is a Node.js SDK, written in TypeScript, for interacting with the MediaWiki API. It provides methods to interface with MediaWiki-based platforms (such as Wikipedia, Wikidata, Fandom) and supports both JavaScript and TypeScript projects.

## Features

*   **Detailed Page Information**: Fetch comprehensive data for pages, including content (`extracts`), categories, revisions, links, and associated metadata.
*   **User Authentication**: Supports logging into MediaWiki sites, including handling for bot passwords.
*   **Flexible Querying**: Execute `action=query` requests using `prop`, `list`, and `meta` parameters for specific data retrieval needs.
*   **Search Functionality**: Offers methods for full-text search (`list=search`) and OpenSearch (autocomplete-style) queries.
*   **Wikitext Parsing**: Convert wikitext to HTML or retrieve structured data from page content via the `action=parse` API.
*   **Site Metadata Retrieval**: Access general information and configuration of a MediaWiki site.
*   **Strongly Typed with TypeScript**: Full static typing provides a robust development experience with autocompletion and compile-time error checking. Response objects are strictly typed.
*   **Promise-based Asynchronous API**: Designed with `async/await` in mind for clean and modern asynchronous code.

## Installation

Ensure you have Node.js version 16 or higher installed.

Install using npm:
```bash
npm install mediawiki-sdk
```

Or using yarn:
```bash
yarn add mediawiki-sdk
```

## Quick Start

**JavaScript (CommonJS):**
```javascript
const { MediaWiki } = require("mediawiki-sdk");

const mw = new MediaWiki({
  baseURL: "https://en.wikipedia.org/w/api.php" // Or your target MediaWiki API
});

(async () => {
  try {
    // Get rich data for pages
    const pageData = await mw.client.page(["JavaScript", "Python (programming language)"]);
    for (const id in pageData.query.pages) {
      const p = pageData.query.pages[id];
      if (!p.missing) {
        console.log(`Page: ${p.title} (ID: ${p.pageid}), Length: ${p.length}`);
      }
    }

    // Perform a full-text search
    const searchResults = await mw.client.search("Artificial Intelligence", null, 3); // Search term, default namespaces, limit 3
    searchResults.query.search.forEach(r => {
      console.log(`Search hit: ${r.title} (Snippet: ${r.snippet.replace(/<[^>]+>/g, '').substring(0,50)}...)`);
    });

    // Get random pages using a custom query
    const randomPages = await mw.client.query({
      list: ["random"],
      rnnamespace: "0", // Main namespace
      rnlimit: 2
    });
    randomPages.query.random.forEach(p => {
      console.log(`Random page: ${p.title} (ID: ${p.id})`);
    });

    // Get site metadata
    const siteInfo = await mw.client.siteInfo();
    console.log(`Wiki Name: ${siteInfo.query.general.sitename}, Main Page: ${siteInfo.query.general.mainpage}`);

    // OpenSearch for suggestions
    const suggestions = await mw.client.opensearch({ search: "typescript", limit: 5, namespace: [0] });
    console.log(`Suggestions for "${suggestions.query}":`, suggestions.results); // results is suggestions[1] in raw opensearch

    // Parse rendered HTML of a page
    const parsedPage = await mw.client.parse({ page: "Node.js" });
    console.log(`Parsed Title: ${parsedPage.title()}`);
    // console.log("HTML (first 100 chars):", parsedPage.text().substring(0, 100) + "...");

    // Parse raw wikitext
    const parsedFromText = await mw.client.parse({ text: "''Hello'' from '''SDK'''!", title: "Sandbox" }); // title provides context
    console.log("Rendered HTML from text:", parsedFromText.text());

    // Get a page summary (extract)
    const summary = await mw.client.summary({ title: "JavaScript" });
    console.log(`Summary for JavaScript (first 100 chars): ${summary.text().substring(0, 100)}...`);

    // Get current user info (anonymous by default)
    const userInfoAnon = await mw.client.userInfo();
    console.log(`Current user (anon): ${userInfoAnon.getUserName()}, ID: ${userInfoAnon.getUserId()}, IsAnonymous: ${userInfoAnon.isAnonymous()}`);

    // Example: Login and get authenticated user info
    // Replace with your bot credentials or handle errors if not provided
    /*
    try {
      await mw.login("YourBotUsername@YourBotName", "your_bot_password_here");
      console.log("Login successful!");
      const userInfoAuth = await mw.client.userInfo();
      console.log(`Logged in as: ${userInfoAuth.getUserName()}, ID: ${userInfoAuth.getUserId()}`);
    } catch (loginError) {
      console.warn("Login failed or skipped (ensure credentials are set for login example):", loginError.message);
    }
    */

  const editResponse = await mw.client.editPage({
    title: "Sandbox",
    text: "New content for Sandbox page",
    summary: "Updated by bot",
    bot: false
  });

  console.log("Edit result:", editResponse.getResult());
  } catch (error) {
    console.error("An error occurred:", error.message);
  }
})();
```

---

## API Reference

### `new MediaWiki(options: MediaWikiOptions)`

Creates a new instance of the `MediaWiki` client.

**Parameters (`MediaWikiOptions`):**

*   `baseURL` (string, **required**): The base URL of the MediaWiki API (e.g., `https://en.wikipedia.org/w/api.php` or `https://my.wiki.org/w`). The SDK will append `/api.php` if not present.
*   `servedby?` (boolean, optional): If `true`, includes `servedby=true` in requests to get server information in the response.
*   `curtimestamp?` (boolean, optional): If `true`, includes `curtimestamp=true` to get the current timestamp in the response.
*   `responselanginfo?` (boolean, optional): If `true`, includes `responselanginfo=true` to get response language information.
*   `requestid?` (string, optional): A custom request ID to be included in API requests for tracking.
*   `formatversion?` (`1 | 2`, optional): API format version. Defaults to `2`. The SDK is optimized for `formatversion=2`.
*   `ascii?` (boolean, optional): If `true`, includes `ascii=true` to replace non-ASCII characters with escape sequences.
*   `utf8?` (boolean, optional): If `true`, includes `utf8=true` to ensure UTF-8 encoding.

*Note: The `format` parameter is internally managed and set to `json`.*

---

### `mw.login(username: string, password: string): Promise<MediaWikiUser>`

Logs in to the MediaWiki site using the provided credentials. It's recommended to use [BotPasswords](https://www.mediawiki.org/wiki/Manual:Bot_passwords).

**Parameters:**

*   `username` (string, **required**): The MediaWiki username (e.g., `MyBot@MyBotName` for bot passwords).
*   `password` (string, **required**): The password or bot password.

**Returns:** `Promise<MediaWikiUser>` - An object containing `userId` and `userName` of the logged-in user.

---

### Client Methods (`mw.client`)

The `mw.client` object provides methods for making various API requests.

#### `mw.client.query(options: MediaWikiPageOptions): Promise<MediaWikiQueryResponse>`

Executes a generic `action=query` request. This is the core method for fetching data and allows for complex combinations of `prop`, `list`, and `meta` parameters.

**Parameters (`MediaWikiPageOptions`):**
An object specifying the query parameters. Key properties include:
*   `prop?: MediaWikiPageOptionsProp[]`: Properties to retrieve for pages (e.g., `["extracts", "categories"]`).
*   `list?: MediaWikiPageOptionsList[]`: Lists to retrieve (e.g., `["search", "random"]`).
*   `meta?: MediaWikiPageOptionsMeta[]`: Meta information to retrieve (e.g., `["siteinfo", "userinfo"]`).
*   `titles?: string[]`: Page titles to query. The SDK joins array elements with `|`.
*   `pageids?: string[]`: Page IDs to query. The SDK joins array elements with `|`.
*   `uiprop?: string`: Properties to retrieve for `meta=userinfo` (e.g., `"*"` for all).
*   Other parameters specific to MediaWiki API modules (e.g., `srsearch`, `rnlimit`, `exintro`) are passed directly as keys in the `options` object.

**Returns:** `Promise<MediaWikiQueryResponse>` - A general, strictly-typed response object for `query` actions. The structure of `response.query` will vary based on the request.

---

#### `mw.client.page(titles: string[]): Promise<MediaWikiQueryPageResponse>`

A convenience method to retrieve detailed information for one or more pages.
Wraps `client.query` with default `prop: ["info", "extracts", "categories", "revisions"]` and `indexpageids: true`.

**Parameters:**
*   `titles` (string[], **required**): An array of page titles.

**Returns:** `Promise<MediaWikiQueryPageResponse>` - Typed response containing `query.pages` with page details.

---

#### `mw.client.search(srsearch: string, srnamespace?: string[] | null, srlimit?: number | null): Promise<MediaWikiQuerySearchResponse>`

Performs a full-text search using `list=search`.

**Parameters:**
*   `srsearch` (string, **required**): The search term.
*   `srnamespace?` (string[], optional): Array of namespace IDs (as strings or numbers) to search within. Defaults to all if `null` or empty.
*   `srlimit?` (number, optional): Maximum number of results. Defaults to `10`.

**Returns:** `Promise<MediaWikiQuerySearchResponse>` - Typed response with `query.searchinfo` and `query.search` results.

---

#### `mw.client.opensearch(options: MediaWikiQueryOpenSearchOptions): Promise<MediaWikiQueryOpenSearchResponse>`

Performs an OpenSearch (autocomplete-style) query using `action=opensearch`.

**Parameters (`MediaWikiQueryOpenSearchOptions`):**
*   `search` (string, **required**): The search term.
*   `namespace?` (number[], optional): Array of namespace IDs to search in.
*   `limit?` (number, optional): Maximum number of suggestions.

**Returns:** `Promise<MediaWikiQueryOpenSearchResponse>` - Typed OpenSearch response array: `[query, results, descriptions, urls]`.

---

#### `mw.client.parse(options: MediaWikiQueryParseOptions): Promise<MediaWikiQueryParseResponseClass>`

Parses wikitext or page content into HTML and other structured data using `action=parse`.

**Parameters (`MediaWikiQueryParseOptions`):**
*   One of the following is **required**:
    *   `text?: string`: Raw wikitext to parse. Use `title` to provide context if needed.
    *   `page?: string`: Title of an existing page to parse.
    *   `pageid?: number`: ID of an existing page to parse.
*   `title?` (string, optional): Title for context when parsing `text`.
*   `redirects?` (boolean, optional): Whether to resolve redirects for `page` or `pageid`.
*   Other `action=parse` parameters like `prop`, `wrapoutputclass`, etc.

**Returns:** `Promise<MediaWikiQueryParseResponseClass>` - An instance of `MediaWikiQueryParseResponseClass` wrapping the parsed data, with helper methods like `.text()`, `.title()`.

---

#### `mw.client.summary(options: MediaWikiQuerySummaryOptions): Promise<MediaWikiQuerySummaryResponseClass>`

Retrieves a plain text summary (extract) for a page.
Wraps `client.query` with `prop: ["extracts"]`, `exintro: true`, and `explaintext: true`.

**Parameters (`MediaWikiQuerySummaryOptions`):**
*   `title` (string, **required**): The title of the page.

**Returns:** `Promise<MediaWikiQuerySummaryResponseClass>` - An instance of `MediaWikiQuerySummaryResponseClass` with a `.text()` method for the extract.

---

#### `mw.client.categories(options: MediaWikiQueryCategoriesOptions): Promise<MediaWikiQueryCategoriesResponse>`

Retrieves categories for a specified page.
Wraps `client.query` with `prop: ["categories"]`.

**Parameters (`MediaWikiQueryCategoriesOptions`):**
*   `title` (string, **required**): The title of the page.

**Returns:** `Promise<MediaWikiQueryCategoriesResponse>` - Typed response containing page categories.

---

#### `mw.client.revisions(options: MediaWikiQueryRevisionsOptions): Promise<MediaWikiQueryRevisionsResponse>`

Retrieves revision history for a specified page.
Wraps `client.query` with `prop: ["revisions"]`.

**Parameters (`MediaWikiQueryRevisionsOptions`):**
*   `title` (string, **required**): The title of the page.
*   `rvlimit?` (number, optional): The maximum number of revisions to return.

**Returns:** `Promise<MediaWikiQueryRevisionsResponse>` - Typed response containing page revisions.

---

#### `mw.client.siteInfo(): Promise<MediaWikiQuerySiteInfoResponse>`

Retrieves general site information and configuration using `meta=siteinfo`.

**Returns:** `Promise<MediaWikiQuerySiteInfoResponse>` - Typed response containing site metadata under `query.general`.

---

#### `mw.client.userInfo(): Promise<MediaWikiQueryUserInfoResponseClass>`

Retrieves information about the current user (either authenticated or anonymous).
Uses `meta=userinfo` and requests all properties via `uiprop: "*"`.

**Returns:** `Promise<MediaWikiQueryUserInfoResponseClass>` - An instance of `MediaWikiQueryUserInfoResponseClass` with helper methods like `.getUserName()`, `.getUserId()`, `.isAnonymous()`, `.getUserOptions()`.

## Type Safety

This SDK is written in TypeScript and exports comprehensive type definitions. This allows for:
*   Autocompletion in modern IDEs.
*   Compile-time checks for correct parameter usage and response handling.
*   Clearer understanding of the data structures returned by the API.

Response objects are often wrapped in classes (e.g., `MediaWikiQueryUserInfoResponseClass`, `MediaWikiQueryParseResponseClass`) that provide convenient accessor methods in addition to the raw API data.

---

For detailed information on MediaWiki API parameters and modules, refer to the [official MediaWiki API documentation](https://www.mediawiki.org/wiki/API:Main_page).