> ## Documentation Index
> Fetch the complete documentation index at: https://yumebox.gal.tf/llms.txt
> Use this file to discover all available pages before exploring further.

# JavaScript API

Extension: `.js`. You must define `main(profile)` and return a configuration object. To append to a list, use `rules+`, not the YAML modifier `rules-end`.

## `main(profile)`

<ParamField body="profile" type="object" required>
  The current configuration object, which can be read and modified directly.
</ParamField>

<ParamField body="return" type="object" required>
  Return a configuration object or a Promise that resolves to one.

  If the function returns `undefined`, an array, or a scalar, or if it throws an error, the current script fails and the configuration from before the script ran is preserved.
</ParamField>

```js main-sync.js icon="braces" lines theme={null}
function main(profile) {
  profile["log-level"] = "info";
  return profile;
}
```

```js main-async.js icon="braces" lines theme={null}
async function main(profile) {
  const response = await fetch("http://127.0.0.1:8080/patch.yaml");
  if (!response.ok) return profile;
  return deepMerge(profile, await response.yaml(), true);
}
```

## `deepMerge(target, patch, isOverride)`

<ParamField body="target" type="object" required>
  The target object. It is modified in place and returned.
</ParamField>

<ParamField body="patch" type="object" required>
  The content to merge.
</ParamField>

<ParamField body="isOverride" type="boolean" default="true">
  When `true`, enables the `+key` / `key+` / `key!` modifiers.
</ParamField>

### Patch keys

<ParamField body="key" type="any">
  Objects merge recursively; arrays replace; scalars overwrite.
</ParamField>

<ParamField body="+key" type="array">
  Insert at the beginning of the list (`isOverride = true`).
</ParamField>

<ParamField body="key+" type="array">
  Append to the end of the list (`isOverride = true`).
</ParamField>

<ParamField body="key!" type="object">
  Replace the entire field.
</ParamField>

<ParamField body="angle-wrapped key" type="any">
  Literal field name.
</ParamField>

```js deep-merge.js icon="braces" lines theme={null}
function main(profile) {
  return deepMerge(
    profile,
    {
      "+rules": ["DOMAIN-SUFFIX,router.local,DIRECT"],
      "rules+": ["DOMAIN-SUFFIX,example.com,DIRECT"],
      "dns!": {
        enable: true,
        nameserver: ["1.1.1.1"],
      },
    },
    true
  );
}
```

## Built-in APIs

### `yaml`

<ParamField body="yaml.parse(text)" type="(text: string) => any">
  YAML text -> value.
</ParamField>

<ParamField body="yaml.stringify(value)" type="(value: any) => string">
  Value -> YAML text.
</ParamField>

### `fetch(input, init?)`

Only `http://` is supported.

<ParamField body="input" type="string | object" required>
  A URL, or an object containing `url`.
</ParamField>

<ParamField body="init.method" type="string" default="GET">
  HTTP method.
</ParamField>

<ParamField body="init.headers" type="object">
  Request headers.
</ParamField>

<ParamField body="init.body" type="string | object">
  Request body; non-string values are passed through `JSON.stringify`.
</ParamField>

<ResponseField name="ok" type="boolean">
  Whether the status is 2xx.
</ResponseField>

<ResponseField name="status" type="number">
  Status code.
</ResponseField>

<ResponseField name="statusText" type="string">
  Status text.
</ResponseField>

<ResponseField name="url" type="string">
  Request URL.
</ResponseField>

<ResponseField name="headers" type="object">
  Provides `get` / `has` / `toJSON`.
</ResponseField>

<ResponseField name="text()" type="Promise<string>">
  Response body as text.
</ResponseField>

<ResponseField name="json()" type="Promise<any>">
  Parsed JSON.
</ResponseField>

<ResponseField name="yaml()" type="Promise<any>">
  Parsed YAML.
</ResponseField>

```js fetch-rules.js icon="braces" lines theme={null}
async function main(profile) {
  const response = await fetch("http://127.0.0.1:8080/rules.yaml");
  if (!response.ok) return profile;
  return deepMerge(profile, await response.yaml(), true);
}
```

### `console`

Writes to a `.log` file in the script's directory with the same base name as the main file. The log is reset before each execution.

<ParamField body="console.log / info / warn / error / debug" type="function">
  Write a log entry at the corresponding level. Log content is redacted for Age-encrypted configurations.
</ParamField>

### Base64

<ParamField body="b64e(value)" type="(value: string) => string">
  UTF-8 -> Base64.
</ParamField>

<ParamField body="b64d(value)" type="(value: string) => string">
  Base64 -> UTF-8.
</ParamField>

<ParamField body="Buffer.from(value, encoding?)" type="function">
  Compatibility API for UTF-8 encoding or Base64 decoding.
</ParamField>

## Example

```js filter-proxies.js icon="braces" lines theme={null}
function main(profile) {
  const proxies = Array.isArray(profile.proxies) ? profile.proxies : [];
  profile.proxies = proxies.filter((item) => {
    const name = String((item && item.name) || "");
    return !name.includes("expired");
  });
  return profile;
}
```
