hostinger-api-mcp 3.28.1 → 3.28.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@ Generated at release time from the diff between the previous and current
4
4
  build. Tool changes are listed individually; everything else is summarised
5
5
  by area.
6
6
 
7
+ ## v3.28.2 — 2026-11-04
8
+
9
+ ### Also in this release
10
+
11
+ - Bundled agent skills: `skills/headless/VERSION`, `skills/headless/steps/08-deploy/SKILL.md`
12
+ - Other files: `src/core/skills.js`, `src/core/skills.ts`
13
+
7
14
  ## v3.28.1 — 2026-11-04
8
15
 
9
16
  ### Also in this release
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.28.1",
3
+ "version": "3.28.2",
4
4
  "description": "Hostinger API — manage domains, DNS, hosting, VPS, billing and more from Gemini CLI.",
5
5
  "mcpServers": {
6
6
  "hostinger": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hostinger-api-mcp",
3
- "version": "3.28.1",
3
+ "version": "3.28.2",
4
4
  "mcpName": "io.github.hostinger/hostinger-api-mcp",
5
5
  "description": "MCP server for Hostinger API",
6
6
  "repository": {
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/hostinger/api-mcp-server",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.28.1",
9
+ "version": "3.28.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@hostinger/mcp",
14
- "version": "3.28.1",
14
+ "version": "3.28.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -1,3 +1,3 @@
1
- version=3.28.1
2
- commit=4609383f23a0
1
+ version=3.28.2
2
+ commit=96c74d42d44e
3
3
  built=2026-11-04
@@ -115,9 +115,10 @@ echo "$DEPLOY_DIR/app.zip" # the absolute path to pass as `path` in Step 3
115
115
  ```
116
116
 
117
117
  ```powershell
118
- # Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a folder on the system drive
118
+ # Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a plain folder in your
119
+ # profile, which only you can write to (never a folder under C:\, which every local account can write into)
119
120
  cd $HOME\.hostinger\<domain>\src
120
- $DeployDir = Join-Path $env:SystemDrive "hostinger-deploy\<domain>"; New-Item -ItemType Directory -Force $DeployDir | Out-Null
121
+ $DeployDir = Join-Path $HOME "hostinger-deploy\<domain>"; New-Item -ItemType Directory -Force $DeployDir | Out-Null
121
122
  tar -a -cf "$DeployDir\app.zip" --exclude=node_modules --exclude=.next --exclude=dist --exclude=out --exclude=.git --exclude=.htaccess .
122
123
  "$DeployDir\app.zip" # the absolute path to pass as `path` in Step 3
123
124
  ```
@@ -239,10 +239,10 @@ export default [
239
239
  },
240
240
  {
241
241
  "uri": "skill://hostinger-headless/steps/08-deploy/SKILL.md",
242
- "digest": "sha256:a2c06b1e0c953d3830c99f164dd39883881451dfbeb5b5a32a665d70b4f2ab5d",
243
- "size": 15740,
242
+ "digest": "sha256:0d3533b1a3ce8ae77dc95f9ebb59d55f31acbc41d2abbdc99ad03c482d950170",
243
+ "size": 15831,
244
244
  "mimeType": "text/markdown",
245
- "text": "---\nname: headless-step-deploy\ndescription: \"Step 8 (deploy) of the Hostinger Headless flow. Archives the frontend source, then deploys through the connector's one-shot hosting_deploy (type nodejs — it uploads the source, runs npm install and the build on the server) with the chosen framework's build settings (appType + output dir) passed explicitly, polls to completion with hosting_get-deployment, verifies the live site and that the backend survived, then writes deploy.json.\"\n---\n\n# headless-step-deploy\n\nShip the frontend to the live domain through the Hostinger connector. You hand the connector a zip of\nthe project **source** and it uploads it, runs `npm install` + the build script on the server, and\nserves the result. **Out:** `deploy.json`.\n\nThis is an **instance-barrier** step: run it only after `provision.status == \"completed\"` and validate\n(if run) has passed. All operations go through the connector (`execute`).\n\n> **Connected to the hosted server (`mcp.hostinger.com`)?** Its `hosting_deploy` deploys Git\n> repositories only and cannot read a local `path`. Run this step through the local\n> `hostinger-api-mcp` server instead (see the connect step:\n> `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp`).\n\n> **With a shell and the Hostinger CLI installed**, the same deploy is one command, with the build\n> settings passed exactly as the table below says. Run it from the project, since it links the current directory:\n> `cd ~/.hostinger/<domain>/src && hostinger up --domain <domain> --type nodejs --app-type <appType> --output-directory <dir> --build-script build --node-version 22 --package-manager npm --yes --format json`.\n> It uploads, builds, waits and returns `data.buildUuid` and `data.buildState`; add `--no-wait` to\n> return at once and wait with `node <skill>/wait.mjs build <domain> <uuid>`. Then continue at\n> \"Verify\" below. Recent CLI versions see that the site is headless (`data.headless: true`) and\n> deploy only its Node.js frontend, leaving `/cms` alone; still pass the settings above.\n\n**In:** the project in `~/.hostinger/<domain>/src/`, `site.json` (`username`, `urls`), `state.json`\n(`frontend.framework`, `frontend.rendering`).\n\n> ## ⚠️ The one rule that makes this work: pass build settings explicitly\n> If you let `hosting_deploy` **auto-detect** build settings, for a headless site that detection returns\n> **null** (`appType:null`, `outputDirectory:null`, Node 20) — the build \"completes\" but the **root\n> serves 403** (no `appType`/output → the vhost serves a directory with no entry). This is reproducible.\n> **Always pass `appType`, `outputDirectory`, `nodeVersion`, `buildScript`, `packageManager` and\n> `rootDirectory` on the `hosting_deploy` call** with the framework's values; the deploy then resolves\n> them and serves correctly, and `/cms` is preserved.\n\n## Build configurations\n\nMap `frontend.framework` (from `state.json`) to its `appType` + build output directory, and pass those\non the `hosting_deploy` call. `appType` is the framework's value, e.g. `next`, `nuxt`, `astro`,\n`svelte-kit`, `nest`, `express`, `fastify`, `react`, `create-react-app`, `gatsby`, `vite`, `vue`,\n`angular`, `parcel`, `svelte`, `other`.\n\nCommon cases (all `nodeVersion: 22`, `buildScript: \"build\"`, `packageManager: \"npm\"`, `rootDirectory: \".\"`):\n\n| Framework / mode | Local config | `appType` | `outputDirectory` |\n|---|---|---|---|\n| **Next.js — SSR** *(default)* | `output: 'standalone'` | `next` | `.next` |\n| **Nuxt — SSR** | default | `nuxt` | `.output` |\n| **SvelteKit — SSR** | node adapter | `svelte-kit` | `build` |\n| **Astro — static** | `output: 'static'` | `astro` | `dist` |\n| **Vite / React / Vue — static (SPA)** | — | `vite` (or `react`/`vue`) | `dist` |\n| **Express / NestJS / Fastify — server** | — | `express`/`nest`/`fastify` | build output dir |\n\nSSR/server frameworks run a persistent Node process (root sends `x-powered-by` / `cache-control: no-store`);\nstatic frameworks serve their output dir as files. If unsure of a framework's output dir, check the\nframework's own build output, but **always pass `appType`/`outputDirectory` on the deploy call with the\nframework's correct values** — don't rely on auto-detection (it returns null → 403).\n\n> ## ⚠️ Next.js 16+: build with webpack, not Turbopack (recurring deploy failure)\n> Next.js 16 makes **Turbopack** the default bundler for `next build`. Turbopack's native (Rust)\n> compiler needs a newer **glibc** than the Hostinger build server ships, so the server build aborts\n> with a \"glibc too old\" error — and Turbopack **does not fall back** to webpack on its own, so the\n> deploy fails every time. **Fix: build with webpack.** On **Next.js 16+** the project's `build` script\n> in `package.json` must be `next build --webpack` (not plain `next build`); `buildScript` on the deploy\n> call stays `\"build\"` — that's what runs it. The `--webpack` flag exists only on Next.js 16+; on\n> **Next.js 15.x** leave the build script as plain `next build` (it already defaults to webpack).\n> **Confirm this in `package.json` before deploying** (the frontend step scaffolds it this way — see\n> `../06-frontend`). Alternative, only if you must avoid the `--webpack` flag: pin Next.js to `15.x`\n> (keeping plain `next build`), whose `next build` still defaults to webpack. Next.js only — other\n> frameworks are unaffected.\n\n## Step 1 — Pre-flight\n\n1. **Instance live (the deploy gate).** `provision.status == \"completed\"`, re-verified with\n `hosting_websites_list-setups { \"domain\": \"<domain>\" }`: deploy overwrites the site root, so it never\n trusts `state.json` alone.\n2. **Build output exists locally** (the framework's output dir — e.g. `.next/`, `dist/`, `.output/`) and\n the project builds clean (frontend/validate already did this). If not, go back.\n - **Next.js 16+:** `package.json`'s `build` script is `next build --webpack`, not plain `next build` —\n the server's glibc can't run Turbopack's native compiler (see the box above). On Next.js 15.x leave it\n as plain `next build`. Fix it here if it isn't.\n3. **Env vars (only if used).** Build-time vars (e.g. `NEXT_PUBLIC_*`) must be set **before** the build\n with `hosting_nodejs_replace-environment-variables` (full replace). Never put secrets in the repo or\n the archive. **Webapp with a database:** that full replace wipes the `DB_*`/`DATABASE_URL` that\n `hosting_databases_setup-website` injected (the generated password reads back masked), so set all app\n vars in the same replace and, if you can't, first reset the password with\n `hosting_databases_change-password` and resend every `DB_*`/`DATABASE_URL` — see\n `../03-provision/webapp/SKILL.md` Step 3.\n\n## Step 2 — Archive the source\n\nZip the project **source** with `package.json` at the archive root. **Include** the app/source,\n`public/`, the framework config (`next.config.mjs` / `astro.config.mjs`), `tsconfig.json`,\n`package.json`, `package-lock.json`, `.nvmrc`. **Exclude** `node_modules/`, the build output\n(`.next/`, `dist/`, `out/`), `.git/`, and any `.htaccess` — the server installs and builds from source.\n\n> ## ⚠️ Write the archive outside `~/.hostinger/` (the deploy refuses it there)\n> `hosting_deploy` refuses any `path` under a hidden folder at the top of the home directory\n> (`~/.hostinger`, `~/.config`, …) with *\"it is, or contains, a home, system or credentials location\"*:\n> a deploy publishes what it reads, so the connector protects dotfolders that can hold tokens. That\n> covers both `~/.hostinger/<domain>/app.zip` **and** the `~/.hostinger/<domain>/src/` directory\n> itself, so neither can be passed as `path`. Keep the source in the workspace as usual, but write the\n> archive to a fresh temp directory and pass that. Don't copy the archive somewhere else after a\n> refusal, and don't move `src/` out of the workspace.\n\n```bash\n# macOS/Linux — the OS temp dir is outside the home directory\ncd ~/.hostinger/<domain>/src\nDEPLOY_DIR=$(mktemp -d)\nzip -r -X \"$DEPLOY_DIR/app.zip\" . -x 'node_modules/*' '.next/*' 'dist/*' 'out/*' '.git/*' '**/.htaccess'\necho \"$DEPLOY_DIR/app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\n```powershell\n# Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a folder on the system drive\ncd $HOME\\.hostinger\\<domain>\\src\n$DeployDir = Join-Path $env:SystemDrive \"hostinger-deploy\\<domain>\"; New-Item -ItemType Directory -Force $DeployDir | Out-Null\ntar -a -cf \"$DeployDir\\app.zip\" --exclude=node_modules --exclude=.next --exclude=dist --exclude=out --exclude=.git --exclude=.htaccess .\n\"$DeployDir\\app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\nDelete the temp directory once the build in Step 4 is `completed`.\n\n## Step 3 — Deploy (one shot: settings + upload + build)\n\nPass the framework's build settings **inline** on the deploy call — there is no separate settings step.\n`path` is the absolute path of the archive from Step 2, in its temp directory. Never pass a path under\n`~/.hostinger/`, the `src/` directory included: the deploy refuses it (see Step 2).\n\n```json\n{ \"operation\": \"hosting_deploy\",\n \"params\": {\n \"domain\": \"<domain>\",\n \"path\": \"<absolute path printed in Step 2, e.g. /var/folders/…/tmp.XXXX/app.zip>\",\n \"type\": \"nodejs\",\n \"appType\": \"<framework appType, e.g. next>\",\n \"outputDirectory\": \"<framework output dir, e.g. .next>\",\n \"nodeVersion\": 22,\n \"buildScript\": \"build\",\n \"packageManager\": \"npm\",\n \"rootDirectory\": \".\" } }\n```\n\n`hosting_deploy` uploads the source and triggers `npm install` + the build **end-to-end** — do not call\nany upload or build operation yourself. It returns a build `buildUuid` at once. This **overwrites the\nwebsite root** (expected) and keeps `/cms` intact. `type` is always `\"nodejs\"` for a headless site —\n**never `\"static\"`** (see the gate below). Passing `appType`/`outputDirectory` explicitly is what\nkeeps the root from serving 403 (see the rule above).\n\n## Step 4 — Wait for the build and the live root\n\nWait for it in one command (see *Waiting on Hostinger* in the top-level `SKILL.md`):\n\n```bash\nnode <skill>/wait.mjs build <domain> <buildUuid>\n```\n\nIt waits for `hosting_get-deployment` to report the build `completed`, then for `https://<domain>/` to\nserve 200. What its result means here:\n\n- `ok: true`: the build is done and the root serves 200. Go on to Step 5.\n- `ok: false` with `build.state: failed`: read `log_tail` (the end of the build log) and `analysis`, fix\n locally, re-archive and redeploy (pass `fromLine` to `hosting_get-deployment` to read only new log\n output).\n- `ok: false` with `build settings missing`: the settings didn't take (the root would 403 for good). Fix\n the deploy call and redeploy.\n- `ok: false` with `timed_out`: `last_status` says whether the build was still running or the root\n wasn't serving 200 yet (see Step 5's note on a 403). For an SSR app that built but hangs,\n `hosting_nodejs_restart-application { username, domain }` recovers the server without a rebuild.\n\n## Step 5 — Verify the live site (all must pass)\n\n| Check | How | Expect |\n|---|---|---|\n| Root serves | `GET https://<domain>/` | **200** (not 403 / 404) |\n| SSR is live *(server frameworks)* | response headers | `x-powered-by` present, `cache-control: no-store` |\n| Static serves *(static frameworks)* | `GET https://<domain>/` | 200 HTML with real home content |\n| Key routes | a couple of planned routes + one deep route | 200, real content |\n| **Backend survived** *(WordPress / WooCommerce)* | `GET https://<domain>/cms/wp-json/wp/v2/posts?per_page=1` | 200 |\n\n> **Only WordPress (including WordPress + WooCommerce) has a `/cms` on the domain**, so the *Backend\n> survived* check is WordPress-only.\n> - **WordPress + WooCommerce:** also confirm the store survived the deploy —\n> `GET https://<domain>/cms/wp-json/wc/store/v1/products?per_page=1` → 200. There is nothing external to\n> link (no sales-channel step — that's Ecommerce only). **Checkout** stays owner-completed: when\n> `site.json → woocommerce.payment_enabled` is `false`, don't test `/checkout`; a catalog that serves 200\n> is a passing, complete deploy.\n> - **Ecommerce:** the backend is the **Hostinger Ecommerce store**, read over the external Storefront API\n> (`api-ecommerce.hostinger.com`) — nothing a deploy touches lives on this domain. There is no `/cms`;\n> confirm the storefront still fetches products as a frontend check if you like. **Only check that\n> checkout can be reached when `site.json → ecommerce.payment_enabled` is `true`** — on a free account\n> (`payment_enabled: false`) there is no checkout, so **skip that check entirely**; a catalog that serves\n> 200 is a passing, complete deploy. Never fail or hold the deploy because checkout is unavailable.\n> - **Webapp:** no content backend at all — the whole root is the app. Skip the check; `/cms` won't resolve.\n\nThe root check is already done when `wait.mjs build` returned `ok: true`; check the rest in one shell\ncommand (`curl` each URL). A `completed` build whose root 403s almost always means the build settings\nweren't passed to `hosting_deploy` (null settings) — pass them and redeploy. Caching can briefly serve a\nstale root; re-check after ~30 s.\n\n## Step 6 — Record `deploy.json`\n\n```json\n{\n \"build_uuid\": \"…\",\n \"stack\": \"nextjs\",\n \"rendering\": \"ssr\",\n \"app_type\": \"next\",\n \"output_directory\": \".next\",\n \"node_version\": 22,\n \"method\": \"hosting_deploy (type: nodejs, settings passed inline)\",\n \"deployed_at\": \"…\",\n \"verified_at\": \"…\",\n \"urls\": { \"live\": \"https://<domain>\", \"cms\": \"https://<domain>/cms\" },\n \"checks\": { \"root\": 200, \"ssr_headers\": true, \"backend_preserved\": true }\n}\n```\n\nNo secrets in `deploy.json`. The `urls.cms` field and the `backend_preserved` check above are\n**WordPress-only** — adjust the record to the backend:\n\n- **WordPress:** keep `urls.cms` and `checks.backend_preserved` as shown.\n- **WordPress + WooCommerce:** keep `urls.cms` + `checks.backend_preserved` (it *is* WordPress), and add\n `urls.store_api` from `site.json`; no external link step.\n- **Ecommerce:** omit `urls.cms`/`backend_preserved`; record the store URLs instead (`urls.storefront_api`,\n `urls.store_admin` from `site.json`) and link the custom sales channel to the live domain —\n `ecommerce_sales-channels_update { store_id, sales_channel_id, url }` (see the ecommerce provision step).\n- **Webapp:** omit `urls.cms` and `backend_preserved` entirely — `urls` is just `{ \"live\": \"https://<domain>\" }`.\n\nUpdate `state.json` (`stage` → `done`), then continue to Step 9 (done).\n\n---\n\n## Gate — a headless deploy is always `type: \"nodejs\"`, never `type: \"static\"`\n\n**Hard rule, check it before every deploy:** a headless site is deployed **only** with\n`type: \"nodejs\"` plus the explicit `appType`/`outputDirectory`/`nodeVersion`/`buildScript`/\n`packageManager`/`rootDirectory` from the table. **Never pass `type: \"static\"` on a headless site** — it\nserves the build as plain files over the document root and **overwrites `/cms`**, destroying the\nWordPress backend (this is the \"accidentally cleared cms\" failure). A static-built SPA (Vite/React/Vue)\nstill deploys as `type: \"nodejs\"` with its `appType` — the framework's static output is served correctly\nthat way, and `/cms` is preserved. If a flow ever tells you to deploy a headless site as `type:\n\"static\"`, you are on a stale/legacy skill copy — stop and re-pull the latest skills.\n\n`hosting_deploy` on the local server is the only path: give its `path` a local **archive** (`zip`, `tar`,\n`tar.gz`, `tgz`, `7z`) written outside `~/.hostinger/` as in Step 2. There is no separate upload or\nbuild step to fall back to.\n"
245
+ "text": "---\nname: headless-step-deploy\ndescription: \"Step 8 (deploy) of the Hostinger Headless flow. Archives the frontend source, then deploys through the connector's one-shot hosting_deploy (type nodejs — it uploads the source, runs npm install and the build on the server) with the chosen framework's build settings (appType + output dir) passed explicitly, polls to completion with hosting_get-deployment, verifies the live site and that the backend survived, then writes deploy.json.\"\n---\n\n# headless-step-deploy\n\nShip the frontend to the live domain through the Hostinger connector. You hand the connector a zip of\nthe project **source** and it uploads it, runs `npm install` + the build script on the server, and\nserves the result. **Out:** `deploy.json`.\n\nThis is an **instance-barrier** step: run it only after `provision.status == \"completed\"` and validate\n(if run) has passed. All operations go through the connector (`execute`).\n\n> **Connected to the hosted server (`mcp.hostinger.com`)?** Its `hosting_deploy` deploys Git\n> repositories only and cannot read a local `path`. Run this step through the local\n> `hostinger-api-mcp` server instead (see the connect step:\n> `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp`).\n\n> **With a shell and the Hostinger CLI installed**, the same deploy is one command, with the build\n> settings passed exactly as the table below says. Run it from the project, since it links the current directory:\n> `cd ~/.hostinger/<domain>/src && hostinger up --domain <domain> --type nodejs --app-type <appType> --output-directory <dir> --build-script build --node-version 22 --package-manager npm --yes --format json`.\n> It uploads, builds, waits and returns `data.buildUuid` and `data.buildState`; add `--no-wait` to\n> return at once and wait with `node <skill>/wait.mjs build <domain> <uuid>`. Then continue at\n> \"Verify\" below. Recent CLI versions see that the site is headless (`data.headless: true`) and\n> deploy only its Node.js frontend, leaving `/cms` alone; still pass the settings above.\n\n**In:** the project in `~/.hostinger/<domain>/src/`, `site.json` (`username`, `urls`), `state.json`\n(`frontend.framework`, `frontend.rendering`).\n\n> ## ⚠️ The one rule that makes this work: pass build settings explicitly\n> If you let `hosting_deploy` **auto-detect** build settings, for a headless site that detection returns\n> **null** (`appType:null`, `outputDirectory:null`, Node 20) — the build \"completes\" but the **root\n> serves 403** (no `appType`/output → the vhost serves a directory with no entry). This is reproducible.\n> **Always pass `appType`, `outputDirectory`, `nodeVersion`, `buildScript`, `packageManager` and\n> `rootDirectory` on the `hosting_deploy` call** with the framework's values; the deploy then resolves\n> them and serves correctly, and `/cms` is preserved.\n\n## Build configurations\n\nMap `frontend.framework` (from `state.json`) to its `appType` + build output directory, and pass those\non the `hosting_deploy` call. `appType` is the framework's value, e.g. `next`, `nuxt`, `astro`,\n`svelte-kit`, `nest`, `express`, `fastify`, `react`, `create-react-app`, `gatsby`, `vite`, `vue`,\n`angular`, `parcel`, `svelte`, `other`.\n\nCommon cases (all `nodeVersion: 22`, `buildScript: \"build\"`, `packageManager: \"npm\"`, `rootDirectory: \".\"`):\n\n| Framework / mode | Local config | `appType` | `outputDirectory` |\n|---|---|---|---|\n| **Next.js — SSR** *(default)* | `output: 'standalone'` | `next` | `.next` |\n| **Nuxt — SSR** | default | `nuxt` | `.output` |\n| **SvelteKit — SSR** | node adapter | `svelte-kit` | `build` |\n| **Astro — static** | `output: 'static'` | `astro` | `dist` |\n| **Vite / React / Vue — static (SPA)** | — | `vite` (or `react`/`vue`) | `dist` |\n| **Express / NestJS / Fastify — server** | — | `express`/`nest`/`fastify` | build output dir |\n\nSSR/server frameworks run a persistent Node process (root sends `x-powered-by` / `cache-control: no-store`);\nstatic frameworks serve their output dir as files. If unsure of a framework's output dir, check the\nframework's own build output, but **always pass `appType`/`outputDirectory` on the deploy call with the\nframework's correct values** — don't rely on auto-detection (it returns null → 403).\n\n> ## ⚠️ Next.js 16+: build with webpack, not Turbopack (recurring deploy failure)\n> Next.js 16 makes **Turbopack** the default bundler for `next build`. Turbopack's native (Rust)\n> compiler needs a newer **glibc** than the Hostinger build server ships, so the server build aborts\n> with a \"glibc too old\" error — and Turbopack **does not fall back** to webpack on its own, so the\n> deploy fails every time. **Fix: build with webpack.** On **Next.js 16+** the project's `build` script\n> in `package.json` must be `next build --webpack` (not plain `next build`); `buildScript` on the deploy\n> call stays `\"build\"` — that's what runs it. The `--webpack` flag exists only on Next.js 16+; on\n> **Next.js 15.x** leave the build script as plain `next build` (it already defaults to webpack).\n> **Confirm this in `package.json` before deploying** (the frontend step scaffolds it this way — see\n> `../06-frontend`). Alternative, only if you must avoid the `--webpack` flag: pin Next.js to `15.x`\n> (keeping plain `next build`), whose `next build` still defaults to webpack. Next.js only — other\n> frameworks are unaffected.\n\n## Step 1 — Pre-flight\n\n1. **Instance live (the deploy gate).** `provision.status == \"completed\"`, re-verified with\n `hosting_websites_list-setups { \"domain\": \"<domain>\" }`: deploy overwrites the site root, so it never\n trusts `state.json` alone.\n2. **Build output exists locally** (the framework's output dir — e.g. `.next/`, `dist/`, `.output/`) and\n the project builds clean (frontend/validate already did this). If not, go back.\n - **Next.js 16+:** `package.json`'s `build` script is `next build --webpack`, not plain `next build` —\n the server's glibc can't run Turbopack's native compiler (see the box above). On Next.js 15.x leave it\n as plain `next build`. Fix it here if it isn't.\n3. **Env vars (only if used).** Build-time vars (e.g. `NEXT_PUBLIC_*`) must be set **before** the build\n with `hosting_nodejs_replace-environment-variables` (full replace). Never put secrets in the repo or\n the archive. **Webapp with a database:** that full replace wipes the `DB_*`/`DATABASE_URL` that\n `hosting_databases_setup-website` injected (the generated password reads back masked), so set all app\n vars in the same replace and, if you can't, first reset the password with\n `hosting_databases_change-password` and resend every `DB_*`/`DATABASE_URL` — see\n `../03-provision/webapp/SKILL.md` Step 3.\n\n## Step 2 — Archive the source\n\nZip the project **source** with `package.json` at the archive root. **Include** the app/source,\n`public/`, the framework config (`next.config.mjs` / `astro.config.mjs`), `tsconfig.json`,\n`package.json`, `package-lock.json`, `.nvmrc`. **Exclude** `node_modules/`, the build output\n(`.next/`, `dist/`, `out/`), `.git/`, and any `.htaccess` — the server installs and builds from source.\n\n> ## ⚠️ Write the archive outside `~/.hostinger/` (the deploy refuses it there)\n> `hosting_deploy` refuses any `path` under a hidden folder at the top of the home directory\n> (`~/.hostinger`, `~/.config`, …) with *\"it is, or contains, a home, system or credentials location\"*:\n> a deploy publishes what it reads, so the connector protects dotfolders that can hold tokens. That\n> covers both `~/.hostinger/<domain>/app.zip` **and** the `~/.hostinger/<domain>/src/` directory\n> itself, so neither can be passed as `path`. Keep the source in the workspace as usual, but write the\n> archive to a fresh temp directory and pass that. Don't copy the archive somewhere else after a\n> refusal, and don't move `src/` out of the workspace.\n\n```bash\n# macOS/Linux — the OS temp dir is outside the home directory\ncd ~/.hostinger/<domain>/src\nDEPLOY_DIR=$(mktemp -d)\nzip -r -X \"$DEPLOY_DIR/app.zip\" . -x 'node_modules/*' '.next/*' 'dist/*' 'out/*' '.git/*' '**/.htaccess'\necho \"$DEPLOY_DIR/app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\n```powershell\n# Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a plain folder in your\n# profile, which only you can write to (never a folder under C:\\, which every local account can write into)\ncd $HOME\\.hostinger\\<domain>\\src\n$DeployDir = Join-Path $HOME \"hostinger-deploy\\<domain>\"; New-Item -ItemType Directory -Force $DeployDir | Out-Null\ntar -a -cf \"$DeployDir\\app.zip\" --exclude=node_modules --exclude=.next --exclude=dist --exclude=out --exclude=.git --exclude=.htaccess .\n\"$DeployDir\\app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\nDelete the temp directory once the build in Step 4 is `completed`.\n\n## Step 3 — Deploy (one shot: settings + upload + build)\n\nPass the framework's build settings **inline** on the deploy call — there is no separate settings step.\n`path` is the absolute path of the archive from Step 2, in its temp directory. Never pass a path under\n`~/.hostinger/`, the `src/` directory included: the deploy refuses it (see Step 2).\n\n```json\n{ \"operation\": \"hosting_deploy\",\n \"params\": {\n \"domain\": \"<domain>\",\n \"path\": \"<absolute path printed in Step 2, e.g. /var/folders/…/tmp.XXXX/app.zip>\",\n \"type\": \"nodejs\",\n \"appType\": \"<framework appType, e.g. next>\",\n \"outputDirectory\": \"<framework output dir, e.g. .next>\",\n \"nodeVersion\": 22,\n \"buildScript\": \"build\",\n \"packageManager\": \"npm\",\n \"rootDirectory\": \".\" } }\n```\n\n`hosting_deploy` uploads the source and triggers `npm install` + the build **end-to-end** — do not call\nany upload or build operation yourself. It returns a build `buildUuid` at once. This **overwrites the\nwebsite root** (expected) and keeps `/cms` intact. `type` is always `\"nodejs\"` for a headless site —\n**never `\"static\"`** (see the gate below). Passing `appType`/`outputDirectory` explicitly is what\nkeeps the root from serving 403 (see the rule above).\n\n## Step 4 — Wait for the build and the live root\n\nWait for it in one command (see *Waiting on Hostinger* in the top-level `SKILL.md`):\n\n```bash\nnode <skill>/wait.mjs build <domain> <buildUuid>\n```\n\nIt waits for `hosting_get-deployment` to report the build `completed`, then for `https://<domain>/` to\nserve 200. What its result means here:\n\n- `ok: true`: the build is done and the root serves 200. Go on to Step 5.\n- `ok: false` with `build.state: failed`: read `log_tail` (the end of the build log) and `analysis`, fix\n locally, re-archive and redeploy (pass `fromLine` to `hosting_get-deployment` to read only new log\n output).\n- `ok: false` with `build settings missing`: the settings didn't take (the root would 403 for good). Fix\n the deploy call and redeploy.\n- `ok: false` with `timed_out`: `last_status` says whether the build was still running or the root\n wasn't serving 200 yet (see Step 5's note on a 403). For an SSR app that built but hangs,\n `hosting_nodejs_restart-application { username, domain }` recovers the server without a rebuild.\n\n## Step 5 — Verify the live site (all must pass)\n\n| Check | How | Expect |\n|---|---|---|\n| Root serves | `GET https://<domain>/` | **200** (not 403 / 404) |\n| SSR is live *(server frameworks)* | response headers | `x-powered-by` present, `cache-control: no-store` |\n| Static serves *(static frameworks)* | `GET https://<domain>/` | 200 HTML with real home content |\n| Key routes | a couple of planned routes + one deep route | 200, real content |\n| **Backend survived** *(WordPress / WooCommerce)* | `GET https://<domain>/cms/wp-json/wp/v2/posts?per_page=1` | 200 |\n\n> **Only WordPress (including WordPress + WooCommerce) has a `/cms` on the domain**, so the *Backend\n> survived* check is WordPress-only.\n> - **WordPress + WooCommerce:** also confirm the store survived the deploy —\n> `GET https://<domain>/cms/wp-json/wc/store/v1/products?per_page=1` → 200. There is nothing external to\n> link (no sales-channel step — that's Ecommerce only). **Checkout** stays owner-completed: when\n> `site.json → woocommerce.payment_enabled` is `false`, don't test `/checkout`; a catalog that serves 200\n> is a passing, complete deploy.\n> - **Ecommerce:** the backend is the **Hostinger Ecommerce store**, read over the external Storefront API\n> (`api-ecommerce.hostinger.com`) — nothing a deploy touches lives on this domain. There is no `/cms`;\n> confirm the storefront still fetches products as a frontend check if you like. **Only check that\n> checkout can be reached when `site.json → ecommerce.payment_enabled` is `true`** — on a free account\n> (`payment_enabled: false`) there is no checkout, so **skip that check entirely**; a catalog that serves\n> 200 is a passing, complete deploy. Never fail or hold the deploy because checkout is unavailable.\n> - **Webapp:** no content backend at all — the whole root is the app. Skip the check; `/cms` won't resolve.\n\nThe root check is already done when `wait.mjs build` returned `ok: true`; check the rest in one shell\ncommand (`curl` each URL). A `completed` build whose root 403s almost always means the build settings\nweren't passed to `hosting_deploy` (null settings) — pass them and redeploy. Caching can briefly serve a\nstale root; re-check after ~30 s.\n\n## Step 6 — Record `deploy.json`\n\n```json\n{\n \"build_uuid\": \"…\",\n \"stack\": \"nextjs\",\n \"rendering\": \"ssr\",\n \"app_type\": \"next\",\n \"output_directory\": \".next\",\n \"node_version\": 22,\n \"method\": \"hosting_deploy (type: nodejs, settings passed inline)\",\n \"deployed_at\": \"…\",\n \"verified_at\": \"…\",\n \"urls\": { \"live\": \"https://<domain>\", \"cms\": \"https://<domain>/cms\" },\n \"checks\": { \"root\": 200, \"ssr_headers\": true, \"backend_preserved\": true }\n}\n```\n\nNo secrets in `deploy.json`. The `urls.cms` field and the `backend_preserved` check above are\n**WordPress-only** — adjust the record to the backend:\n\n- **WordPress:** keep `urls.cms` and `checks.backend_preserved` as shown.\n- **WordPress + WooCommerce:** keep `urls.cms` + `checks.backend_preserved` (it *is* WordPress), and add\n `urls.store_api` from `site.json`; no external link step.\n- **Ecommerce:** omit `urls.cms`/`backend_preserved`; record the store URLs instead (`urls.storefront_api`,\n `urls.store_admin` from `site.json`) and link the custom sales channel to the live domain —\n `ecommerce_sales-channels_update { store_id, sales_channel_id, url }` (see the ecommerce provision step).\n- **Webapp:** omit `urls.cms` and `backend_preserved` entirely — `urls` is just `{ \"live\": \"https://<domain>\" }`.\n\nUpdate `state.json` (`stage` → `done`), then continue to Step 9 (done).\n\n---\n\n## Gate — a headless deploy is always `type: \"nodejs\"`, never `type: \"static\"`\n\n**Hard rule, check it before every deploy:** a headless site is deployed **only** with\n`type: \"nodejs\"` plus the explicit `appType`/`outputDirectory`/`nodeVersion`/`buildScript`/\n`packageManager`/`rootDirectory` from the table. **Never pass `type: \"static\"` on a headless site** — it\nserves the build as plain files over the document root and **overwrites `/cms`**, destroying the\nWordPress backend (this is the \"accidentally cleared cms\" failure). A static-built SPA (Vite/React/Vue)\nstill deploys as `type: \"nodejs\"` with its `appType` — the framework's static output is served correctly\nthat way, and `/cms` is preserved. If a flow ever tells you to deploy a headless site as `type:\n\"static\"`, you are on a stale/legacy skill copy — stop and re-pull the latest skills.\n\n`hosting_deploy` on the local server is the only path: give its `path` a local **archive** (`zip`, `tar`,\n`tar.gz`, `tgz`, `7z`) written outside `~/.hostinger/` as in Step 2. There is no separate upload or\nbuild step to fall back to.\n"
246
246
  },
247
247
  {
248
248
  "uri": "skill://hostinger-headless/steps/09-done/SKILL.md",
@@ -253,10 +253,10 @@ const skills: Skill[] = [
253
253
  },
254
254
  {
255
255
  "uri": "skill://hostinger-headless/steps/08-deploy/SKILL.md",
256
- "digest": "sha256:a2c06b1e0c953d3830c99f164dd39883881451dfbeb5b5a32a665d70b4f2ab5d",
257
- "size": 15740,
256
+ "digest": "sha256:0d3533b1a3ce8ae77dc95f9ebb59d55f31acbc41d2abbdc99ad03c482d950170",
257
+ "size": 15831,
258
258
  "mimeType": "text/markdown",
259
- "text": "---\nname: headless-step-deploy\ndescription: \"Step 8 (deploy) of the Hostinger Headless flow. Archives the frontend source, then deploys through the connector's one-shot hosting_deploy (type nodejs — it uploads the source, runs npm install and the build on the server) with the chosen framework's build settings (appType + output dir) passed explicitly, polls to completion with hosting_get-deployment, verifies the live site and that the backend survived, then writes deploy.json.\"\n---\n\n# headless-step-deploy\n\nShip the frontend to the live domain through the Hostinger connector. You hand the connector a zip of\nthe project **source** and it uploads it, runs `npm install` + the build script on the server, and\nserves the result. **Out:** `deploy.json`.\n\nThis is an **instance-barrier** step: run it only after `provision.status == \"completed\"` and validate\n(if run) has passed. All operations go through the connector (`execute`).\n\n> **Connected to the hosted server (`mcp.hostinger.com`)?** Its `hosting_deploy` deploys Git\n> repositories only and cannot read a local `path`. Run this step through the local\n> `hostinger-api-mcp` server instead (see the connect step:\n> `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp`).\n\n> **With a shell and the Hostinger CLI installed**, the same deploy is one command, with the build\n> settings passed exactly as the table below says. Run it from the project, since it links the current directory:\n> `cd ~/.hostinger/<domain>/src && hostinger up --domain <domain> --type nodejs --app-type <appType> --output-directory <dir> --build-script build --node-version 22 --package-manager npm --yes --format json`.\n> It uploads, builds, waits and returns `data.buildUuid` and `data.buildState`; add `--no-wait` to\n> return at once and wait with `node <skill>/wait.mjs build <domain> <uuid>`. Then continue at\n> \"Verify\" below. Recent CLI versions see that the site is headless (`data.headless: true`) and\n> deploy only its Node.js frontend, leaving `/cms` alone; still pass the settings above.\n\n**In:** the project in `~/.hostinger/<domain>/src/`, `site.json` (`username`, `urls`), `state.json`\n(`frontend.framework`, `frontend.rendering`).\n\n> ## ⚠️ The one rule that makes this work: pass build settings explicitly\n> If you let `hosting_deploy` **auto-detect** build settings, for a headless site that detection returns\n> **null** (`appType:null`, `outputDirectory:null`, Node 20) — the build \"completes\" but the **root\n> serves 403** (no `appType`/output → the vhost serves a directory with no entry). This is reproducible.\n> **Always pass `appType`, `outputDirectory`, `nodeVersion`, `buildScript`, `packageManager` and\n> `rootDirectory` on the `hosting_deploy` call** with the framework's values; the deploy then resolves\n> them and serves correctly, and `/cms` is preserved.\n\n## Build configurations\n\nMap `frontend.framework` (from `state.json`) to its `appType` + build output directory, and pass those\non the `hosting_deploy` call. `appType` is the framework's value, e.g. `next`, `nuxt`, `astro`,\n`svelte-kit`, `nest`, `express`, `fastify`, `react`, `create-react-app`, `gatsby`, `vite`, `vue`,\n`angular`, `parcel`, `svelte`, `other`.\n\nCommon cases (all `nodeVersion: 22`, `buildScript: \"build\"`, `packageManager: \"npm\"`, `rootDirectory: \".\"`):\n\n| Framework / mode | Local config | `appType` | `outputDirectory` |\n|---|---|---|---|\n| **Next.js — SSR** *(default)* | `output: 'standalone'` | `next` | `.next` |\n| **Nuxt — SSR** | default | `nuxt` | `.output` |\n| **SvelteKit — SSR** | node adapter | `svelte-kit` | `build` |\n| **Astro — static** | `output: 'static'` | `astro` | `dist` |\n| **Vite / React / Vue — static (SPA)** | — | `vite` (or `react`/`vue`) | `dist` |\n| **Express / NestJS / Fastify — server** | — | `express`/`nest`/`fastify` | build output dir |\n\nSSR/server frameworks run a persistent Node process (root sends `x-powered-by` / `cache-control: no-store`);\nstatic frameworks serve their output dir as files. If unsure of a framework's output dir, check the\nframework's own build output, but **always pass `appType`/`outputDirectory` on the deploy call with the\nframework's correct values** — don't rely on auto-detection (it returns null → 403).\n\n> ## ⚠️ Next.js 16+: build with webpack, not Turbopack (recurring deploy failure)\n> Next.js 16 makes **Turbopack** the default bundler for `next build`. Turbopack's native (Rust)\n> compiler needs a newer **glibc** than the Hostinger build server ships, so the server build aborts\n> with a \"glibc too old\" error — and Turbopack **does not fall back** to webpack on its own, so the\n> deploy fails every time. **Fix: build with webpack.** On **Next.js 16+** the project's `build` script\n> in `package.json` must be `next build --webpack` (not plain `next build`); `buildScript` on the deploy\n> call stays `\"build\"` — that's what runs it. The `--webpack` flag exists only on Next.js 16+; on\n> **Next.js 15.x** leave the build script as plain `next build` (it already defaults to webpack).\n> **Confirm this in `package.json` before deploying** (the frontend step scaffolds it this way — see\n> `../06-frontend`). Alternative, only if you must avoid the `--webpack` flag: pin Next.js to `15.x`\n> (keeping plain `next build`), whose `next build` still defaults to webpack. Next.js only — other\n> frameworks are unaffected.\n\n## Step 1 — Pre-flight\n\n1. **Instance live (the deploy gate).** `provision.status == \"completed\"`, re-verified with\n `hosting_websites_list-setups { \"domain\": \"<domain>\" }`: deploy overwrites the site root, so it never\n trusts `state.json` alone.\n2. **Build output exists locally** (the framework's output dir — e.g. `.next/`, `dist/`, `.output/`) and\n the project builds clean (frontend/validate already did this). If not, go back.\n - **Next.js 16+:** `package.json`'s `build` script is `next build --webpack`, not plain `next build` —\n the server's glibc can't run Turbopack's native compiler (see the box above). On Next.js 15.x leave it\n as plain `next build`. Fix it here if it isn't.\n3. **Env vars (only if used).** Build-time vars (e.g. `NEXT_PUBLIC_*`) must be set **before** the build\n with `hosting_nodejs_replace-environment-variables` (full replace). Never put secrets in the repo or\n the archive. **Webapp with a database:** that full replace wipes the `DB_*`/`DATABASE_URL` that\n `hosting_databases_setup-website` injected (the generated password reads back masked), so set all app\n vars in the same replace and, if you can't, first reset the password with\n `hosting_databases_change-password` and resend every `DB_*`/`DATABASE_URL` — see\n `../03-provision/webapp/SKILL.md` Step 3.\n\n## Step 2 — Archive the source\n\nZip the project **source** with `package.json` at the archive root. **Include** the app/source,\n`public/`, the framework config (`next.config.mjs` / `astro.config.mjs`), `tsconfig.json`,\n`package.json`, `package-lock.json`, `.nvmrc`. **Exclude** `node_modules/`, the build output\n(`.next/`, `dist/`, `out/`), `.git/`, and any `.htaccess` — the server installs and builds from source.\n\n> ## ⚠️ Write the archive outside `~/.hostinger/` (the deploy refuses it there)\n> `hosting_deploy` refuses any `path` under a hidden folder at the top of the home directory\n> (`~/.hostinger`, `~/.config`, …) with *\"it is, or contains, a home, system or credentials location\"*:\n> a deploy publishes what it reads, so the connector protects dotfolders that can hold tokens. That\n> covers both `~/.hostinger/<domain>/app.zip` **and** the `~/.hostinger/<domain>/src/` directory\n> itself, so neither can be passed as `path`. Keep the source in the workspace as usual, but write the\n> archive to a fresh temp directory and pass that. Don't copy the archive somewhere else after a\n> refusal, and don't move `src/` out of the workspace.\n\n```bash\n# macOS/Linux — the OS temp dir is outside the home directory\ncd ~/.hostinger/<domain>/src\nDEPLOY_DIR=$(mktemp -d)\nzip -r -X \"$DEPLOY_DIR/app.zip\" . -x 'node_modules/*' '.next/*' 'dist/*' 'out/*' '.git/*' '**/.htaccess'\necho \"$DEPLOY_DIR/app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\n```powershell\n# Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a folder on the system drive\ncd $HOME\\.hostinger\\<domain>\\src\n$DeployDir = Join-Path $env:SystemDrive \"hostinger-deploy\\<domain>\"; New-Item -ItemType Directory -Force $DeployDir | Out-Null\ntar -a -cf \"$DeployDir\\app.zip\" --exclude=node_modules --exclude=.next --exclude=dist --exclude=out --exclude=.git --exclude=.htaccess .\n\"$DeployDir\\app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\nDelete the temp directory once the build in Step 4 is `completed`.\n\n## Step 3 — Deploy (one shot: settings + upload + build)\n\nPass the framework's build settings **inline** on the deploy call — there is no separate settings step.\n`path` is the absolute path of the archive from Step 2, in its temp directory. Never pass a path under\n`~/.hostinger/`, the `src/` directory included: the deploy refuses it (see Step 2).\n\n```json\n{ \"operation\": \"hosting_deploy\",\n \"params\": {\n \"domain\": \"<domain>\",\n \"path\": \"<absolute path printed in Step 2, e.g. /var/folders/…/tmp.XXXX/app.zip>\",\n \"type\": \"nodejs\",\n \"appType\": \"<framework appType, e.g. next>\",\n \"outputDirectory\": \"<framework output dir, e.g. .next>\",\n \"nodeVersion\": 22,\n \"buildScript\": \"build\",\n \"packageManager\": \"npm\",\n \"rootDirectory\": \".\" } }\n```\n\n`hosting_deploy` uploads the source and triggers `npm install` + the build **end-to-end** — do not call\nany upload or build operation yourself. It returns a build `buildUuid` at once. This **overwrites the\nwebsite root** (expected) and keeps `/cms` intact. `type` is always `\"nodejs\"` for a headless site —\n**never `\"static\"`** (see the gate below). Passing `appType`/`outputDirectory` explicitly is what\nkeeps the root from serving 403 (see the rule above).\n\n## Step 4 — Wait for the build and the live root\n\nWait for it in one command (see *Waiting on Hostinger* in the top-level `SKILL.md`):\n\n```bash\nnode <skill>/wait.mjs build <domain> <buildUuid>\n```\n\nIt waits for `hosting_get-deployment` to report the build `completed`, then for `https://<domain>/` to\nserve 200. What its result means here:\n\n- `ok: true`: the build is done and the root serves 200. Go on to Step 5.\n- `ok: false` with `build.state: failed`: read `log_tail` (the end of the build log) and `analysis`, fix\n locally, re-archive and redeploy (pass `fromLine` to `hosting_get-deployment` to read only new log\n output).\n- `ok: false` with `build settings missing`: the settings didn't take (the root would 403 for good). Fix\n the deploy call and redeploy.\n- `ok: false` with `timed_out`: `last_status` says whether the build was still running or the root\n wasn't serving 200 yet (see Step 5's note on a 403). For an SSR app that built but hangs,\n `hosting_nodejs_restart-application { username, domain }` recovers the server without a rebuild.\n\n## Step 5 — Verify the live site (all must pass)\n\n| Check | How | Expect |\n|---|---|---|\n| Root serves | `GET https://<domain>/` | **200** (not 403 / 404) |\n| SSR is live *(server frameworks)* | response headers | `x-powered-by` present, `cache-control: no-store` |\n| Static serves *(static frameworks)* | `GET https://<domain>/` | 200 HTML with real home content |\n| Key routes | a couple of planned routes + one deep route | 200, real content |\n| **Backend survived** *(WordPress / WooCommerce)* | `GET https://<domain>/cms/wp-json/wp/v2/posts?per_page=1` | 200 |\n\n> **Only WordPress (including WordPress + WooCommerce) has a `/cms` on the domain**, so the *Backend\n> survived* check is WordPress-only.\n> - **WordPress + WooCommerce:** also confirm the store survived the deploy —\n> `GET https://<domain>/cms/wp-json/wc/store/v1/products?per_page=1` → 200. There is nothing external to\n> link (no sales-channel step — that's Ecommerce only). **Checkout** stays owner-completed: when\n> `site.json → woocommerce.payment_enabled` is `false`, don't test `/checkout`; a catalog that serves 200\n> is a passing, complete deploy.\n> - **Ecommerce:** the backend is the **Hostinger Ecommerce store**, read over the external Storefront API\n> (`api-ecommerce.hostinger.com`) — nothing a deploy touches lives on this domain. There is no `/cms`;\n> confirm the storefront still fetches products as a frontend check if you like. **Only check that\n> checkout can be reached when `site.json → ecommerce.payment_enabled` is `true`** — on a free account\n> (`payment_enabled: false`) there is no checkout, so **skip that check entirely**; a catalog that serves\n> 200 is a passing, complete deploy. Never fail or hold the deploy because checkout is unavailable.\n> - **Webapp:** no content backend at all — the whole root is the app. Skip the check; `/cms` won't resolve.\n\nThe root check is already done when `wait.mjs build` returned `ok: true`; check the rest in one shell\ncommand (`curl` each URL). A `completed` build whose root 403s almost always means the build settings\nweren't passed to `hosting_deploy` (null settings) — pass them and redeploy. Caching can briefly serve a\nstale root; re-check after ~30 s.\n\n## Step 6 — Record `deploy.json`\n\n```json\n{\n \"build_uuid\": \"…\",\n \"stack\": \"nextjs\",\n \"rendering\": \"ssr\",\n \"app_type\": \"next\",\n \"output_directory\": \".next\",\n \"node_version\": 22,\n \"method\": \"hosting_deploy (type: nodejs, settings passed inline)\",\n \"deployed_at\": \"…\",\n \"verified_at\": \"…\",\n \"urls\": { \"live\": \"https://<domain>\", \"cms\": \"https://<domain>/cms\" },\n \"checks\": { \"root\": 200, \"ssr_headers\": true, \"backend_preserved\": true }\n}\n```\n\nNo secrets in `deploy.json`. The `urls.cms` field and the `backend_preserved` check above are\n**WordPress-only** — adjust the record to the backend:\n\n- **WordPress:** keep `urls.cms` and `checks.backend_preserved` as shown.\n- **WordPress + WooCommerce:** keep `urls.cms` + `checks.backend_preserved` (it *is* WordPress), and add\n `urls.store_api` from `site.json`; no external link step.\n- **Ecommerce:** omit `urls.cms`/`backend_preserved`; record the store URLs instead (`urls.storefront_api`,\n `urls.store_admin` from `site.json`) and link the custom sales channel to the live domain —\n `ecommerce_sales-channels_update { store_id, sales_channel_id, url }` (see the ecommerce provision step).\n- **Webapp:** omit `urls.cms` and `backend_preserved` entirely — `urls` is just `{ \"live\": \"https://<domain>\" }`.\n\nUpdate `state.json` (`stage` → `done`), then continue to Step 9 (done).\n\n---\n\n## Gate — a headless deploy is always `type: \"nodejs\"`, never `type: \"static\"`\n\n**Hard rule, check it before every deploy:** a headless site is deployed **only** with\n`type: \"nodejs\"` plus the explicit `appType`/`outputDirectory`/`nodeVersion`/`buildScript`/\n`packageManager`/`rootDirectory` from the table. **Never pass `type: \"static\"` on a headless site** — it\nserves the build as plain files over the document root and **overwrites `/cms`**, destroying the\nWordPress backend (this is the \"accidentally cleared cms\" failure). A static-built SPA (Vite/React/Vue)\nstill deploys as `type: \"nodejs\"` with its `appType` — the framework's static output is served correctly\nthat way, and `/cms` is preserved. If a flow ever tells you to deploy a headless site as `type:\n\"static\"`, you are on a stale/legacy skill copy — stop and re-pull the latest skills.\n\n`hosting_deploy` on the local server is the only path: give its `path` a local **archive** (`zip`, `tar`,\n`tar.gz`, `tgz`, `7z`) written outside `~/.hostinger/` as in Step 2. There is no separate upload or\nbuild step to fall back to.\n"
259
+ "text": "---\nname: headless-step-deploy\ndescription: \"Step 8 (deploy) of the Hostinger Headless flow. Archives the frontend source, then deploys through the connector's one-shot hosting_deploy (type nodejs — it uploads the source, runs npm install and the build on the server) with the chosen framework's build settings (appType + output dir) passed explicitly, polls to completion with hosting_get-deployment, verifies the live site and that the backend survived, then writes deploy.json.\"\n---\n\n# headless-step-deploy\n\nShip the frontend to the live domain through the Hostinger connector. You hand the connector a zip of\nthe project **source** and it uploads it, runs `npm install` + the build script on the server, and\nserves the result. **Out:** `deploy.json`.\n\nThis is an **instance-barrier** step: run it only after `provision.status == \"completed\"` and validate\n(if run) has passed. All operations go through the connector (`execute`).\n\n> **Connected to the hosted server (`mcp.hostinger.com`)?** Its `hosting_deploy` deploys Git\n> repositories only and cannot read a local `path`. Run this step through the local\n> `hostinger-api-mcp` server instead (see the connect step:\n> `npx --yes --package=@hostinger/mcp@latest hostinger-api-mcp`).\n\n> **With a shell and the Hostinger CLI installed**, the same deploy is one command, with the build\n> settings passed exactly as the table below says. Run it from the project, since it links the current directory:\n> `cd ~/.hostinger/<domain>/src && hostinger up --domain <domain> --type nodejs --app-type <appType> --output-directory <dir> --build-script build --node-version 22 --package-manager npm --yes --format json`.\n> It uploads, builds, waits and returns `data.buildUuid` and `data.buildState`; add `--no-wait` to\n> return at once and wait with `node <skill>/wait.mjs build <domain> <uuid>`. Then continue at\n> \"Verify\" below. Recent CLI versions see that the site is headless (`data.headless: true`) and\n> deploy only its Node.js frontend, leaving `/cms` alone; still pass the settings above.\n\n**In:** the project in `~/.hostinger/<domain>/src/`, `site.json` (`username`, `urls`), `state.json`\n(`frontend.framework`, `frontend.rendering`).\n\n> ## ⚠️ The one rule that makes this work: pass build settings explicitly\n> If you let `hosting_deploy` **auto-detect** build settings, for a headless site that detection returns\n> **null** (`appType:null`, `outputDirectory:null`, Node 20) — the build \"completes\" but the **root\n> serves 403** (no `appType`/output → the vhost serves a directory with no entry). This is reproducible.\n> **Always pass `appType`, `outputDirectory`, `nodeVersion`, `buildScript`, `packageManager` and\n> `rootDirectory` on the `hosting_deploy` call** with the framework's values; the deploy then resolves\n> them and serves correctly, and `/cms` is preserved.\n\n## Build configurations\n\nMap `frontend.framework` (from `state.json`) to its `appType` + build output directory, and pass those\non the `hosting_deploy` call. `appType` is the framework's value, e.g. `next`, `nuxt`, `astro`,\n`svelte-kit`, `nest`, `express`, `fastify`, `react`, `create-react-app`, `gatsby`, `vite`, `vue`,\n`angular`, `parcel`, `svelte`, `other`.\n\nCommon cases (all `nodeVersion: 22`, `buildScript: \"build\"`, `packageManager: \"npm\"`, `rootDirectory: \".\"`):\n\n| Framework / mode | Local config | `appType` | `outputDirectory` |\n|---|---|---|---|\n| **Next.js — SSR** *(default)* | `output: 'standalone'` | `next` | `.next` |\n| **Nuxt — SSR** | default | `nuxt` | `.output` |\n| **SvelteKit — SSR** | node adapter | `svelte-kit` | `build` |\n| **Astro — static** | `output: 'static'` | `astro` | `dist` |\n| **Vite / React / Vue — static (SPA)** | — | `vite` (or `react`/`vue`) | `dist` |\n| **Express / NestJS / Fastify — server** | — | `express`/`nest`/`fastify` | build output dir |\n\nSSR/server frameworks run a persistent Node process (root sends `x-powered-by` / `cache-control: no-store`);\nstatic frameworks serve their output dir as files. If unsure of a framework's output dir, check the\nframework's own build output, but **always pass `appType`/`outputDirectory` on the deploy call with the\nframework's correct values** — don't rely on auto-detection (it returns null → 403).\n\n> ## ⚠️ Next.js 16+: build with webpack, not Turbopack (recurring deploy failure)\n> Next.js 16 makes **Turbopack** the default bundler for `next build`. Turbopack's native (Rust)\n> compiler needs a newer **glibc** than the Hostinger build server ships, so the server build aborts\n> with a \"glibc too old\" error — and Turbopack **does not fall back** to webpack on its own, so the\n> deploy fails every time. **Fix: build with webpack.** On **Next.js 16+** the project's `build` script\n> in `package.json` must be `next build --webpack` (not plain `next build`); `buildScript` on the deploy\n> call stays `\"build\"` — that's what runs it. The `--webpack` flag exists only on Next.js 16+; on\n> **Next.js 15.x** leave the build script as plain `next build` (it already defaults to webpack).\n> **Confirm this in `package.json` before deploying** (the frontend step scaffolds it this way — see\n> `../06-frontend`). Alternative, only if you must avoid the `--webpack` flag: pin Next.js to `15.x`\n> (keeping plain `next build`), whose `next build` still defaults to webpack. Next.js only — other\n> frameworks are unaffected.\n\n## Step 1 — Pre-flight\n\n1. **Instance live (the deploy gate).** `provision.status == \"completed\"`, re-verified with\n `hosting_websites_list-setups { \"domain\": \"<domain>\" }`: deploy overwrites the site root, so it never\n trusts `state.json` alone.\n2. **Build output exists locally** (the framework's output dir — e.g. `.next/`, `dist/`, `.output/`) and\n the project builds clean (frontend/validate already did this). If not, go back.\n - **Next.js 16+:** `package.json`'s `build` script is `next build --webpack`, not plain `next build` —\n the server's glibc can't run Turbopack's native compiler (see the box above). On Next.js 15.x leave it\n as plain `next build`. Fix it here if it isn't.\n3. **Env vars (only if used).** Build-time vars (e.g. `NEXT_PUBLIC_*`) must be set **before** the build\n with `hosting_nodejs_replace-environment-variables` (full replace). Never put secrets in the repo or\n the archive. **Webapp with a database:** that full replace wipes the `DB_*`/`DATABASE_URL` that\n `hosting_databases_setup-website` injected (the generated password reads back masked), so set all app\n vars in the same replace and, if you can't, first reset the password with\n `hosting_databases_change-password` and resend every `DB_*`/`DATABASE_URL` — see\n `../03-provision/webapp/SKILL.md` Step 3.\n\n## Step 2 — Archive the source\n\nZip the project **source** with `package.json` at the archive root. **Include** the app/source,\n`public/`, the framework config (`next.config.mjs` / `astro.config.mjs`), `tsconfig.json`,\n`package.json`, `package-lock.json`, `.nvmrc`. **Exclude** `node_modules/`, the build output\n(`.next/`, `dist/`, `out/`), `.git/`, and any `.htaccess` — the server installs and builds from source.\n\n> ## ⚠️ Write the archive outside `~/.hostinger/` (the deploy refuses it there)\n> `hosting_deploy` refuses any `path` under a hidden folder at the top of the home directory\n> (`~/.hostinger`, `~/.config`, …) with *\"it is, or contains, a home, system or credentials location\"*:\n> a deploy publishes what it reads, so the connector protects dotfolders that can hold tokens. That\n> covers both `~/.hostinger/<domain>/app.zip` **and** the `~/.hostinger/<domain>/src/` directory\n> itself, so neither can be passed as `path`. Keep the source in the workspace as usual, but write the\n> archive to a fresh temp directory and pass that. Don't copy the archive somewhere else after a\n> refusal, and don't move `src/` out of the workspace.\n\n```bash\n# macOS/Linux — the OS temp dir is outside the home directory\ncd ~/.hostinger/<domain>/src\nDEPLOY_DIR=$(mktemp -d)\nzip -r -X \"$DEPLOY_DIR/app.zip\" . -x 'node_modules/*' '.next/*' 'dist/*' 'out/*' '.git/*' '**/.htaccess'\necho \"$DEPLOY_DIR/app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\n```powershell\n# Windows PowerShell — %TEMP% sits under AppData, which the deploy also refuses; use a plain folder in your\n# profile, which only you can write to (never a folder under C:\\, which every local account can write into)\ncd $HOME\\.hostinger\\<domain>\\src\n$DeployDir = Join-Path $HOME \"hostinger-deploy\\<domain>\"; New-Item -ItemType Directory -Force $DeployDir | Out-Null\ntar -a -cf \"$DeployDir\\app.zip\" --exclude=node_modules --exclude=.next --exclude=dist --exclude=out --exclude=.git --exclude=.htaccess .\n\"$DeployDir\\app.zip\" # the absolute path to pass as `path` in Step 3\n```\n\nDelete the temp directory once the build in Step 4 is `completed`.\n\n## Step 3 — Deploy (one shot: settings + upload + build)\n\nPass the framework's build settings **inline** on the deploy call — there is no separate settings step.\n`path` is the absolute path of the archive from Step 2, in its temp directory. Never pass a path under\n`~/.hostinger/`, the `src/` directory included: the deploy refuses it (see Step 2).\n\n```json\n{ \"operation\": \"hosting_deploy\",\n \"params\": {\n \"domain\": \"<domain>\",\n \"path\": \"<absolute path printed in Step 2, e.g. /var/folders/…/tmp.XXXX/app.zip>\",\n \"type\": \"nodejs\",\n \"appType\": \"<framework appType, e.g. next>\",\n \"outputDirectory\": \"<framework output dir, e.g. .next>\",\n \"nodeVersion\": 22,\n \"buildScript\": \"build\",\n \"packageManager\": \"npm\",\n \"rootDirectory\": \".\" } }\n```\n\n`hosting_deploy` uploads the source and triggers `npm install` + the build **end-to-end** — do not call\nany upload or build operation yourself. It returns a build `buildUuid` at once. This **overwrites the\nwebsite root** (expected) and keeps `/cms` intact. `type` is always `\"nodejs\"` for a headless site —\n**never `\"static\"`** (see the gate below). Passing `appType`/`outputDirectory` explicitly is what\nkeeps the root from serving 403 (see the rule above).\n\n## Step 4 — Wait for the build and the live root\n\nWait for it in one command (see *Waiting on Hostinger* in the top-level `SKILL.md`):\n\n```bash\nnode <skill>/wait.mjs build <domain> <buildUuid>\n```\n\nIt waits for `hosting_get-deployment` to report the build `completed`, then for `https://<domain>/` to\nserve 200. What its result means here:\n\n- `ok: true`: the build is done and the root serves 200. Go on to Step 5.\n- `ok: false` with `build.state: failed`: read `log_tail` (the end of the build log) and `analysis`, fix\n locally, re-archive and redeploy (pass `fromLine` to `hosting_get-deployment` to read only new log\n output).\n- `ok: false` with `build settings missing`: the settings didn't take (the root would 403 for good). Fix\n the deploy call and redeploy.\n- `ok: false` with `timed_out`: `last_status` says whether the build was still running or the root\n wasn't serving 200 yet (see Step 5's note on a 403). For an SSR app that built but hangs,\n `hosting_nodejs_restart-application { username, domain }` recovers the server without a rebuild.\n\n## Step 5 — Verify the live site (all must pass)\n\n| Check | How | Expect |\n|---|---|---|\n| Root serves | `GET https://<domain>/` | **200** (not 403 / 404) |\n| SSR is live *(server frameworks)* | response headers | `x-powered-by` present, `cache-control: no-store` |\n| Static serves *(static frameworks)* | `GET https://<domain>/` | 200 HTML with real home content |\n| Key routes | a couple of planned routes + one deep route | 200, real content |\n| **Backend survived** *(WordPress / WooCommerce)* | `GET https://<domain>/cms/wp-json/wp/v2/posts?per_page=1` | 200 |\n\n> **Only WordPress (including WordPress + WooCommerce) has a `/cms` on the domain**, so the *Backend\n> survived* check is WordPress-only.\n> - **WordPress + WooCommerce:** also confirm the store survived the deploy —\n> `GET https://<domain>/cms/wp-json/wc/store/v1/products?per_page=1` → 200. There is nothing external to\n> link (no sales-channel step — that's Ecommerce only). **Checkout** stays owner-completed: when\n> `site.json → woocommerce.payment_enabled` is `false`, don't test `/checkout`; a catalog that serves 200\n> is a passing, complete deploy.\n> - **Ecommerce:** the backend is the **Hostinger Ecommerce store**, read over the external Storefront API\n> (`api-ecommerce.hostinger.com`) — nothing a deploy touches lives on this domain. There is no `/cms`;\n> confirm the storefront still fetches products as a frontend check if you like. **Only check that\n> checkout can be reached when `site.json → ecommerce.payment_enabled` is `true`** — on a free account\n> (`payment_enabled: false`) there is no checkout, so **skip that check entirely**; a catalog that serves\n> 200 is a passing, complete deploy. Never fail or hold the deploy because checkout is unavailable.\n> - **Webapp:** no content backend at all — the whole root is the app. Skip the check; `/cms` won't resolve.\n\nThe root check is already done when `wait.mjs build` returned `ok: true`; check the rest in one shell\ncommand (`curl` each URL). A `completed` build whose root 403s almost always means the build settings\nweren't passed to `hosting_deploy` (null settings) — pass them and redeploy. Caching can briefly serve a\nstale root; re-check after ~30 s.\n\n## Step 6 — Record `deploy.json`\n\n```json\n{\n \"build_uuid\": \"…\",\n \"stack\": \"nextjs\",\n \"rendering\": \"ssr\",\n \"app_type\": \"next\",\n \"output_directory\": \".next\",\n \"node_version\": 22,\n \"method\": \"hosting_deploy (type: nodejs, settings passed inline)\",\n \"deployed_at\": \"…\",\n \"verified_at\": \"…\",\n \"urls\": { \"live\": \"https://<domain>\", \"cms\": \"https://<domain>/cms\" },\n \"checks\": { \"root\": 200, \"ssr_headers\": true, \"backend_preserved\": true }\n}\n```\n\nNo secrets in `deploy.json`. The `urls.cms` field and the `backend_preserved` check above are\n**WordPress-only** — adjust the record to the backend:\n\n- **WordPress:** keep `urls.cms` and `checks.backend_preserved` as shown.\n- **WordPress + WooCommerce:** keep `urls.cms` + `checks.backend_preserved` (it *is* WordPress), and add\n `urls.store_api` from `site.json`; no external link step.\n- **Ecommerce:** omit `urls.cms`/`backend_preserved`; record the store URLs instead (`urls.storefront_api`,\n `urls.store_admin` from `site.json`) and link the custom sales channel to the live domain —\n `ecommerce_sales-channels_update { store_id, sales_channel_id, url }` (see the ecommerce provision step).\n- **Webapp:** omit `urls.cms` and `backend_preserved` entirely — `urls` is just `{ \"live\": \"https://<domain>\" }`.\n\nUpdate `state.json` (`stage` → `done`), then continue to Step 9 (done).\n\n---\n\n## Gate — a headless deploy is always `type: \"nodejs\"`, never `type: \"static\"`\n\n**Hard rule, check it before every deploy:** a headless site is deployed **only** with\n`type: \"nodejs\"` plus the explicit `appType`/`outputDirectory`/`nodeVersion`/`buildScript`/\n`packageManager`/`rootDirectory` from the table. **Never pass `type: \"static\"` on a headless site** — it\nserves the build as plain files over the document root and **overwrites `/cms`**, destroying the\nWordPress backend (this is the \"accidentally cleared cms\" failure). A static-built SPA (Vite/React/Vue)\nstill deploys as `type: \"nodejs\"` with its `appType` — the framework's static output is served correctly\nthat way, and `/cms` is preserved. If a flow ever tells you to deploy a headless site as `type:\n\"static\"`, you are on a stale/legacy skill copy — stop and re-pull the latest skills.\n\n`hosting_deploy` on the local server is the only path: give its `path` a local **archive** (`zip`, `tar`,\n`tar.gz`, `tgz`, `7z`) written outside `~/.hostinger/` as in Step 2. There is no separate upload or\nbuild step to fall back to.\n"
260
260
  },
261
261
  {
262
262
  "uri": "skill://hostinger-headless/steps/09-done/SKILL.md",
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/agency-hosting.js';
5
5
  import instructions from '../core/instructions.agency-hosting.js';
6
6
 
7
- startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.28.1', tools, instructions });
7
+ startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.28.2', tools, instructions });
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/agency-hosting.js';
5
5
  import instructions from '../core/instructions.agency-hosting.js';
6
6
 
7
- startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.28.1', tools, instructions });
7
+ startServer({ name: 'hostinger-agency-hosting-mcp', version: '3.28.2', tools, instructions });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/agent-readiness.js';
5
5
 
6
- startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/agent-readiness.js';
5
5
 
6
- startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-agent-readiness-mcp', version: '3.28.2', tools });
@@ -5,4 +5,4 @@ import tools from '../core/tools/all.js';
5
5
  import instructions from '../core/instructions.js';
6
6
  import skills from '../core/skills.js';
7
7
 
8
- startServer({ name: 'hostinger-api-mcp', version: '3.28.1', tools, instructions, skills });
8
+ startServer({ name: 'hostinger-api-mcp', version: '3.28.2', tools, instructions, skills });
@@ -5,4 +5,4 @@ import tools from '../core/tools/all.js';
5
5
  import instructions from '../core/instructions.js';
6
6
  import skills from '../core/skills.js';
7
7
 
8
- startServer({ name: 'hostinger-api-mcp', version: '3.28.1', tools, instructions, skills });
8
+ startServer({ name: 'hostinger-api-mcp', version: '3.28.2', tools, instructions, skills });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/billing.js';
5
5
 
6
- startServer({ name: 'hostinger-billing-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-billing-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/billing.js';
5
5
 
6
- startServer({ name: 'hostinger-billing-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-billing-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/dns.js';
5
5
 
6
- startServer({ name: 'hostinger-dns-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-dns-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/dns.js';
5
5
 
6
- startServer({ name: 'hostinger-dns-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-dns-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/domains.js';
5
5
 
6
- startServer({ name: 'hostinger-domains-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-domains-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/domains.js';
5
5
 
6
- startServer({ name: 'hostinger-domains-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-domains-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/ecommerce.js';
5
5
 
6
- startServer({ name: 'hostinger-ecommerce-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-ecommerce-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/ecommerce.js';
5
5
 
6
- startServer({ name: 'hostinger-ecommerce-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-ecommerce-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/gpu.js';
5
5
 
6
- startServer({ name: 'hostinger-gpu-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-gpu-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/gpu.js';
5
5
 
6
- startServer({ name: 'hostinger-gpu-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-gpu-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/horizons.js';
5
5
 
6
- startServer({ name: 'hostinger-horizons-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-horizons-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/horizons.js';
5
5
 
6
- startServer({ name: 'hostinger-horizons-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-horizons-mcp', version: '3.28.2', tools });
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/hosting.js';
5
5
  import instructions from '../core/instructions.js';
6
6
 
7
- startServer({ name: 'hostinger-hosting-mcp', version: '3.28.1', tools, instructions });
7
+ startServer({ name: 'hostinger-hosting-mcp', version: '3.28.2', tools, instructions });
@@ -4,4 +4,4 @@ import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/hosting.js';
5
5
  import instructions from '../core/instructions.js';
6
6
 
7
- startServer({ name: 'hostinger-hosting-mcp', version: '3.28.1', tools, instructions });
7
+ startServer({ name: 'hostinger-hosting-mcp', version: '3.28.2', tools, instructions });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/mail.js';
5
5
 
6
- startServer({ name: 'hostinger-mail-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-mail-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/mail.js';
5
5
 
6
- startServer({ name: 'hostinger-mail-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-mail-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/reach.js';
5
5
 
6
- startServer({ name: 'hostinger-reach-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-reach-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/reach.js';
5
5
 
6
- startServer({ name: 'hostinger-reach-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-reach-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/vps.js';
5
5
 
6
- startServer({ name: 'hostinger-vps-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-vps-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/vps.js';
5
5
 
6
- startServer({ name: 'hostinger-vps-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-vps-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/wordpress.js';
5
5
 
6
- startServer({ name: 'hostinger-wordpress-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-wordpress-mcp', version: '3.28.2', tools });
@@ -3,4 +3,4 @@
3
3
  import { startServer } from '../core/runtime.js';
4
4
  import tools from '../core/tools/wordpress.js';
5
5
 
6
- startServer({ name: 'hostinger-wordpress-mcp', version: '3.28.1', tools });
6
+ startServer({ name: 'hostinger-wordpress-mcp', version: '3.28.2', tools });