antigravity-seo-kit 1.0.0
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/LICENSE +88 -0
- package/README.md +136 -0
- package/bin/cli.js +117 -0
- package/lib/api.js +207 -0
- package/lib/downloader.js +187 -0
- package/lib/fingerprint.js +68 -0
- package/lib/installer.js +446 -0
- package/lib/utils.js +254 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
COMMERCIAL SOFTWARE LICENSE AGREEMENT
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nguyendev. All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are the
|
|
6
|
+
proprietary property of nguyendev.
|
|
7
|
+
|
|
8
|
+
BY INSTALLING, COPYING, OR OTHERWISE USING THE SOFTWARE, YOU AGREE TO BE
|
|
9
|
+
BOUND BY THE TERMS OF THIS LICENSE AGREEMENT.
|
|
10
|
+
|
|
11
|
+
1. GRANT OF LICENSE
|
|
12
|
+
|
|
13
|
+
Subject to the terms of this agreement and a valid license key activation,
|
|
14
|
+
the Licensee is granted a non-exclusive, non-transferable, revocable license
|
|
15
|
+
to:
|
|
16
|
+
|
|
17
|
+
(a) USE the Software on up to three (3) devices per license key;
|
|
18
|
+
(b) MODIFY the Software for personal or internal business use;
|
|
19
|
+
(c) USE the Software with Google Antigravity or compatible AI agent
|
|
20
|
+
platforms for SEO analysis purposes.
|
|
21
|
+
|
|
22
|
+
2. RESTRICTIONS
|
|
23
|
+
|
|
24
|
+
The Licensee may NOT:
|
|
25
|
+
|
|
26
|
+
(a) Redistribute, sublicense, sell, rent, lease, or share the Software
|
|
27
|
+
or any derivative works to third parties;
|
|
28
|
+
(b) Share, publish, or expose license keys to unauthorized users;
|
|
29
|
+
(c) Remove, alter, or circumvent license verification mechanisms;
|
|
30
|
+
(d) Use the Software after license expiration or revocation;
|
|
31
|
+
(e) Reverse engineer, decompile, or disassemble the license verification
|
|
32
|
+
system;
|
|
33
|
+
(f) Create competing products based on the Software;
|
|
34
|
+
(g) Transfer this license to another individual or entity without prior
|
|
35
|
+
written consent.
|
|
36
|
+
|
|
37
|
+
3. DEVICE MANAGEMENT
|
|
38
|
+
|
|
39
|
+
(a) Each license key permits activation on up to three (3) devices
|
|
40
|
+
simultaneously;
|
|
41
|
+
(b) Devices can be managed (added/removed) through the CLI tool or
|
|
42
|
+
license management portal;
|
|
43
|
+
(c) Exceeding the device limit requires either removing existing devices
|
|
44
|
+
or purchasing additional license keys.
|
|
45
|
+
|
|
46
|
+
4. INTELLECTUAL PROPERTY
|
|
47
|
+
|
|
48
|
+
The Software is protected by copyright laws and international treaties.
|
|
49
|
+
The Licensee acknowledges that nguyendev retains all rights, title, and
|
|
50
|
+
interest in and to the Software, including all intellectual property rights.
|
|
51
|
+
|
|
52
|
+
5. UPDATES AND SUPPORT
|
|
53
|
+
|
|
54
|
+
(a) License holders are entitled to Software updates for the duration
|
|
55
|
+
of their license term;
|
|
56
|
+
(b) Support is provided through designated channels as specified at
|
|
57
|
+
time of purchase;
|
|
58
|
+
(c) nguyendev reserves the right to modify, discontinue, or redesign
|
|
59
|
+
the Software at any time.
|
|
60
|
+
|
|
61
|
+
6. TERMINATION
|
|
62
|
+
|
|
63
|
+
(a) This license is effective until terminated;
|
|
64
|
+
(b) It will terminate automatically if the Licensee fails to comply with
|
|
65
|
+
any term of this agreement;
|
|
66
|
+
(c) It will terminate upon license key expiration (if applicable);
|
|
67
|
+
(d) Upon termination, the Licensee must cease using and destroy all
|
|
68
|
+
copies of the Software.
|
|
69
|
+
|
|
70
|
+
7. DISCLAIMER OF WARRANTIES
|
|
71
|
+
|
|
72
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
73
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
74
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
75
|
+
|
|
76
|
+
8. LIMITATION OF LIABILITY
|
|
77
|
+
|
|
78
|
+
IN NO EVENT SHALL NGUYENDEV BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
|
|
79
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
|
|
80
|
+
CONNECTION WITH THE USE OF THE SOFTWARE.
|
|
81
|
+
|
|
82
|
+
9. GOVERNING LAW
|
|
83
|
+
|
|
84
|
+
This agreement shall be governed by and construed in accordance with
|
|
85
|
+
applicable laws.
|
|
86
|
+
|
|
87
|
+
For license inquiries and support,
|
|
88
|
+
visit: https://antigravityseokit.solann.io/
|
package/README.md
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# SEO Kit for Google Antigravity
|
|
2
|
+
|
|
3
|
+
> **Professional SEO Analysis Toolkit** — 35 specialized skills organized into a 5-phase SEO lifecycle for comprehensive audits, E-E-A-T analysis, schema markup, GEO optimization, keyword research, audience analysis, AI prompt research, and more. Built for [Google Antigravity](https://deepmind.google/technologies/antigravity/) AI agent platform.
|
|
4
|
+
|
|
5
|
+
## ⚡ Quick Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx antigravity-seo-kit install --key=SK-XXXX-XXXX-XXXX
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> Purchase a license key at: [https://antigravityseokit.solann.io/](https://antigravityseokit.solann.io/)
|
|
12
|
+
|
|
13
|
+
## Features
|
|
14
|
+
|
|
15
|
+
- **35 specialized SEO skills** organized into a 5-phase lifecycle
|
|
16
|
+
- **Master Orchestrator** (`/seo-run`) — auto-detects project phase, suggests next step
|
|
17
|
+
- **Technical SEO Audit** with 9 categories (crawlability, indexability, Core Web Vitals, etc.)
|
|
18
|
+
- **E-E-A-T Content Quality** analysis with Sept 2025 QRG update
|
|
19
|
+
- **Schema Markup** detection, validation, and JSON-LD generation
|
|
20
|
+
- **AI Search Optimization (GEO)** for AI Overviews, ChatGPT, Perplexity
|
|
21
|
+
- **Agentic SEO** audit — Action schema, A2A readiness, API discoverability
|
|
22
|
+
- **Content Strategy** — gap analysis, topical authority, entity SEO, 30/60/90 roadmap
|
|
23
|
+
- **Keyword Research** — seed expansion, volume/difficulty, intent classification, clustering
|
|
24
|
+
- **Audience Analysis** — persona definition, journey mapping, community language mining
|
|
25
|
+
- **AI Prompt Research** — conversational query patterns, multi-turn intent chains
|
|
26
|
+
- **Backlink Analysis** — profile, toxic links, competitor link gap
|
|
27
|
+
- **Local SEO** with GBP, NAP consistency, citations, reviews, Maps intelligence
|
|
28
|
+
- **Programmatic SEO** for pages at scale with quality gates
|
|
29
|
+
- **Google Search Console & Analytics** integration
|
|
30
|
+
- **Auto-Fix Generator** — ready-to-use meta tags, schema, robots.txt, redirects
|
|
31
|
+
- **SEO Experiment Tracking** — A/B tests with baseline/measurement cycle
|
|
32
|
+
- **Extension System** for DataForSEO, Ahrefs, Semrush, and AI image generation
|
|
33
|
+
|
|
34
|
+
## SEO Lifecycle
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
📋 ONBOARD → 🔎 RESEARCH → 🔍 AUDIT → 🧠 STRATEGY → ⚡ EXECUTE → 📈 MONITOR → (re-audit)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Just remember one command:** `/seo-run <domain>` — it guides you through everything.
|
|
41
|
+
|
|
42
|
+
## Commands
|
|
43
|
+
|
|
44
|
+
### CLI Commands
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Install SEO Kit
|
|
48
|
+
npx antigravity-seo-kit install --key=SK-XXXX-XXXX-XXXX
|
|
49
|
+
|
|
50
|
+
# Update to latest version
|
|
51
|
+
npx antigravity-seo-kit update
|
|
52
|
+
|
|
53
|
+
# Check installation status
|
|
54
|
+
npx antigravity-seo-kit status
|
|
55
|
+
|
|
56
|
+
# List activated devices
|
|
57
|
+
npx antigravity-seo-kit devices
|
|
58
|
+
|
|
59
|
+
# Remove a device
|
|
60
|
+
npx antigravity-seo-kit devices remove <deviceId>
|
|
61
|
+
|
|
62
|
+
# Uninstall
|
|
63
|
+
npx antigravity-seo-kit uninstall --confirm
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### SEO Workflows (inside Antigravity)
|
|
67
|
+
|
|
68
|
+
| Workflow | Phase | Skills | Purpose |
|
|
69
|
+
|----------|-------|--------|---------|
|
|
70
|
+
| `/seo-run` | Master | Delegates | Auto-detect phase, suggest next step |
|
|
71
|
+
| `/seo-onboard` | 1 | 4 | Project setup, API check, brand identity, personas |
|
|
72
|
+
| `/seo-research` | Research | 5 | Keyword research, audience, prompt patterns |
|
|
73
|
+
| `/seo-audit` | 2 | 9 | Full website diagnostic, Health Score |
|
|
74
|
+
| `/seo-strategy` | 3 | 10 | Content gaps, entity, authority, roadmap |
|
|
75
|
+
| `/seo-execute` | 4 | 6 | Code fixes, schema, redirects, content |
|
|
76
|
+
| `/seo-monitor` | 5 | 6 | Experiments, AI citability, traffic |
|
|
77
|
+
| `/seo-local-suite` | Special | 2 | Local SEO + Maps intelligence |
|
|
78
|
+
| `/seo-page` | Utility | 4 | Deep single-page analysis |
|
|
79
|
+
|
|
80
|
+
> **Direct Skill Access**: You can always call any of the 35 skills directly by name (e.g., "Run seo-entity for example.com") without going through the lifecycle.
|
|
81
|
+
|
|
82
|
+
## System Requirements
|
|
83
|
+
|
|
84
|
+
- **Node.js** ≥ 18 (for CLI installer)
|
|
85
|
+
- **Python** ≥ 3.11 (for analysis scripts)
|
|
86
|
+
- **Google Antigravity** or compatible AI agent platform
|
|
87
|
+
|
|
88
|
+
## Setup After Installation
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# 1. Install Python dependencies
|
|
92
|
+
pip install -r requirements.txt
|
|
93
|
+
|
|
94
|
+
# 2. (Optional) Install Google API dependencies
|
|
95
|
+
pip install -r requirements-google.txt
|
|
96
|
+
|
|
97
|
+
# 3. (Optional) Install Playwright for visual analysis
|
|
98
|
+
pip install playwright && playwright install chromium
|
|
99
|
+
|
|
100
|
+
# 4. Open your workspace in Google Antigravity
|
|
101
|
+
# 5. Start with: /seo-run yourdomain.com
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Extensions
|
|
105
|
+
|
|
106
|
+
| Extension | What it Adds |
|
|
107
|
+
|-----------|-------------|
|
|
108
|
+
| **DataForSEO** | 22 commands: live SERP, keywords, backlinks, on-page analysis, AI visibility |
|
|
109
|
+
| **Banana Image Gen** | 6 commands: OG image, hero, product, infographic, custom, batch via Gemini AI |
|
|
110
|
+
| **Ahrefs MCP** | DR/UR, backlink quality, content gap, referring domains |
|
|
111
|
+
| **Semrush MCP** | Keyword gap, toxic links, backlink audit, domain analytics |
|
|
112
|
+
|
|
113
|
+
## License Management
|
|
114
|
+
|
|
115
|
+
Each license key supports up to **3 devices** simultaneously. Manage your devices:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# View activated devices
|
|
119
|
+
npx antigravity-seo-kit devices
|
|
120
|
+
|
|
121
|
+
# Remove a device to free up a slot
|
|
122
|
+
npx antigravity-seo-kit devices remove <deviceId>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## License
|
|
126
|
+
|
|
127
|
+
This software is distributed under a **Commercial License**. See [LICENSE](LICENSE) for full terms.
|
|
128
|
+
|
|
129
|
+
- ✅ Use on up to 3-20 devices per license
|
|
130
|
+
- ✅ Modify for personal/business use
|
|
131
|
+
- ❌ Redistribution prohibited
|
|
132
|
+
- ❌ Sublicensing prohibited
|
|
133
|
+
|
|
134
|
+
## Support
|
|
135
|
+
|
|
136
|
+
For license inquiries and support, visit: [https://antigravityseokit.solann.io/](https://antigravityseokit.solann.io/)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const { showBanner, showHelp, isValidKeyFormat, error, info, colorize } = require('../lib/utils');
|
|
6
|
+
const installer = require('../lib/installer');
|
|
7
|
+
|
|
8
|
+
// ─── Parse Arguments ────────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const command = args[0];
|
|
12
|
+
const subCommand = args[1];
|
|
13
|
+
|
|
14
|
+
function getArg(name) {
|
|
15
|
+
const arg = args.find(a => a.startsWith(`--${name}=`));
|
|
16
|
+
return arg ? arg.split('=').slice(1).join('=') : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getFlag(name) {
|
|
20
|
+
return args.includes(`--${name}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
async function main() {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
switch (command) {
|
|
30
|
+
case 'install': {
|
|
31
|
+
showBanner();
|
|
32
|
+
const key = getArg('key');
|
|
33
|
+
if (!key) {
|
|
34
|
+
error('License key required.');
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(` Usage: ${colorize('cyan', 'npx antigravity-seo-kit install --key=SK-XXXX-XXXX-XXXX')}`);
|
|
37
|
+
console.log('');
|
|
38
|
+
console.log(` Purchase: ${colorize('cyan', 'https://antigravity-seokit.solann.io/')}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
if (!isValidKeyFormat(key)) {
|
|
42
|
+
error('Invalid key format. Expected: SK-XXXX-XXXX-XXXX');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
await installer.install(key, cwd);
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
case 'update': {
|
|
50
|
+
showBanner();
|
|
51
|
+
await installer.update(cwd);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
case 'uninstall': {
|
|
56
|
+
showBanner();
|
|
57
|
+
if (!getFlag('confirm')) {
|
|
58
|
+
console.log(`${colorize('yellow', '⚠️')} This will remove all SEO Kit files from this workspace.`);
|
|
59
|
+
console.log(` Add ${colorize('cyan', '--confirm')} to proceed.`);
|
|
60
|
+
console.log('');
|
|
61
|
+
console.log(` ${colorize('gray', 'npx antigravity-seo-kit uninstall --confirm')}`);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
await installer.uninstall(cwd);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
case 'status': {
|
|
69
|
+
showBanner();
|
|
70
|
+
await installer.status(cwd);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
case 'devices': {
|
|
75
|
+
showBanner();
|
|
76
|
+
if (subCommand === 'remove') {
|
|
77
|
+
const deviceId = args[2];
|
|
78
|
+
await installer.deviceRemove(cwd, deviceId);
|
|
79
|
+
} else {
|
|
80
|
+
await installer.devices(cwd);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
case 'help':
|
|
86
|
+
case '--help':
|
|
87
|
+
case '-h': {
|
|
88
|
+
showHelp();
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
case '--version':
|
|
93
|
+
case '-v': {
|
|
94
|
+
const pkg = require('../package.json');
|
|
95
|
+
console.log(pkg.version);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
default: {
|
|
100
|
+
showHelp();
|
|
101
|
+
if (command) {
|
|
102
|
+
error(`Unknown command: "${command}"`);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
} catch (err) {
|
|
108
|
+
console.log('');
|
|
109
|
+
error(`Unexpected error: ${err.message}`);
|
|
110
|
+
if (process.env.DEBUG) {
|
|
111
|
+
console.error(err.stack);
|
|
112
|
+
}
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
main();
|
package/lib/api.js
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const http = require('http');
|
|
5
|
+
const { PACKAGE_VERSION } = require('./utils');
|
|
6
|
+
|
|
7
|
+
// ─── Configuration ──────────────────────────────────────────────────────────
|
|
8
|
+
|
|
9
|
+
// TODO: Replace with your actual license server URL
|
|
10
|
+
const DEFAULT_API_URL = process.env.SEO_KIT_API_URL || 'https://app.solann.io/api/seo-kit/';
|
|
11
|
+
|
|
12
|
+
function getApiUrl() {
|
|
13
|
+
// Ensure trailing slash so new URL('licenses/verify', base) resolves correctly
|
|
14
|
+
const url = DEFAULT_API_URL.replace(/\/+$/, '');
|
|
15
|
+
return url + '/';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function getUserAgent() {
|
|
19
|
+
return `antigravity-seo-kit/${PACKAGE_VERSION} node/${process.version} ${process.platform}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ─── HTTP Client ────────────────────────────────────────────────────────────
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Make an HTTP(S) request. Returns parsed JSON response.
|
|
26
|
+
* Uses only Node.js built-in modules (no dependencies).
|
|
27
|
+
*/
|
|
28
|
+
function request(method, urlPath, { body = null, licenseKey = null, timeout = 15000 } = {}) {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
const baseUrl = getApiUrl();
|
|
31
|
+
const fullUrl = new URL(urlPath, baseUrl);
|
|
32
|
+
|
|
33
|
+
const isHttps = fullUrl.protocol === 'https:';
|
|
34
|
+
const transport = isHttps ? https : http;
|
|
35
|
+
|
|
36
|
+
const headers = {
|
|
37
|
+
'User-Agent': getUserAgent(),
|
|
38
|
+
'Accept': 'application/json',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (licenseKey) {
|
|
42
|
+
headers['X-License-Key'] = licenseKey;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (body) {
|
|
46
|
+
headers['Content-Type'] = 'application/json';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const options = {
|
|
50
|
+
hostname: fullUrl.hostname,
|
|
51
|
+
port: fullUrl.port || (isHttps ? 443 : 80),
|
|
52
|
+
path: fullUrl.pathname + fullUrl.search,
|
|
53
|
+
method: method.toUpperCase(),
|
|
54
|
+
headers,
|
|
55
|
+
timeout,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const req = transport.request(options, (res) => {
|
|
59
|
+
let data = '';
|
|
60
|
+
res.on('data', (chunk) => { data += chunk; });
|
|
61
|
+
res.on('end', () => {
|
|
62
|
+
try {
|
|
63
|
+
const parsed = data ? JSON.parse(data) : {};
|
|
64
|
+
if (res.statusCode >= 200 && res.statusCode < 300) {
|
|
65
|
+
resolve({ status: res.statusCode, data: parsed });
|
|
66
|
+
} else {
|
|
67
|
+
reject(new ApiError(
|
|
68
|
+
parsed.error?.message || parsed.message || `HTTP ${res.statusCode}`,
|
|
69
|
+
res.statusCode,
|
|
70
|
+
parsed
|
|
71
|
+
));
|
|
72
|
+
}
|
|
73
|
+
} catch (e) {
|
|
74
|
+
reject(new ApiError(`Invalid JSON response: ${data.substring(0, 200)}`, res.statusCode));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
req.on('error', (err) => {
|
|
80
|
+
if (err.code === 'ECONNREFUSED') {
|
|
81
|
+
reject(new ApiError('Cannot connect to license server. Please check your internet connection.', 0));
|
|
82
|
+
} else if (err.code === 'ENOTFOUND') {
|
|
83
|
+
reject(new ApiError('License server not found. DNS resolution failed.', 0));
|
|
84
|
+
} else {
|
|
85
|
+
reject(new ApiError(`Network error: ${err.message}`, 0));
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
req.on('timeout', () => {
|
|
90
|
+
req.destroy();
|
|
91
|
+
reject(new ApiError('Request timed out. Please try again.', 0));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
if (body) {
|
|
95
|
+
req.write(JSON.stringify(body));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
req.end();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ─── API Error ──────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
class ApiError extends Error {
|
|
105
|
+
constructor(message, statusCode, responseData = null) {
|
|
106
|
+
super(message);
|
|
107
|
+
this.name = 'ApiError';
|
|
108
|
+
this.statusCode = statusCode;
|
|
109
|
+
this.responseData = responseData;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
get isNetworkError() { return this.statusCode === 0; }
|
|
113
|
+
get isNotFound() { return this.statusCode === 404; }
|
|
114
|
+
get isForbidden() { return this.statusCode === 403; }
|
|
115
|
+
get isUnauthorized() { return this.statusCode === 401; }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ─── License API Methods ────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Verify a license key and activate the current device.
|
|
122
|
+
*
|
|
123
|
+
* POST /licenses/verify
|
|
124
|
+
* Body: { licenseKey, deviceId, deviceName }
|
|
125
|
+
*
|
|
126
|
+
* Response: {
|
|
127
|
+
* valid: true,
|
|
128
|
+
* license: { plan, expiresAt, ... },
|
|
129
|
+
* devicesUsed: 2,
|
|
130
|
+
* maxDevices: 3,
|
|
131
|
+
* devices: [{ deviceId, deviceName, activatedAt }]
|
|
132
|
+
* }
|
|
133
|
+
*/
|
|
134
|
+
async function verifyLicense(licenseKey, deviceId, deviceName) {
|
|
135
|
+
const { data } = await request('POST', 'licenses/verify', {
|
|
136
|
+
body: { licenseKey, deviceId, deviceName },
|
|
137
|
+
});
|
|
138
|
+
return data;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get license status and info.
|
|
143
|
+
*
|
|
144
|
+
* GET /licenses/status
|
|
145
|
+
*/
|
|
146
|
+
async function getLicenseStatus(licenseKey) {
|
|
147
|
+
const { data } = await request('GET', 'licenses/status', { licenseKey });
|
|
148
|
+
return data;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* List all activated devices for a license.
|
|
153
|
+
*
|
|
154
|
+
* GET /licenses/devices
|
|
155
|
+
*/
|
|
156
|
+
async function listDevices(licenseKey) {
|
|
157
|
+
const { data } = await request('GET', 'licenses/devices', { licenseKey });
|
|
158
|
+
return data;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Remove a device from the license.
|
|
163
|
+
*
|
|
164
|
+
* DELETE /licenses/devices/:deviceId
|
|
165
|
+
*/
|
|
166
|
+
async function removeDevice(licenseKey, deviceId) {
|
|
167
|
+
const { data } = await request('DELETE', `licenses/devices/${deviceId}`, { licenseKey });
|
|
168
|
+
return data;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Check for the latest release version.
|
|
173
|
+
*
|
|
174
|
+
* GET /releases/latest
|
|
175
|
+
*/
|
|
176
|
+
async function getLatestRelease() {
|
|
177
|
+
const { data } = await request('GET', 'releases/latest');
|
|
178
|
+
return data;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the download URL for SEO Kit assets.
|
|
183
|
+
* The seokit-web server serves a .tar.gz archive after verifying the license key.
|
|
184
|
+
*
|
|
185
|
+
* Default: https://antigravityseokit.solann.io/api/seo-kit/releases/download
|
|
186
|
+
* Override: SEO_KIT_ASSETS_URL environment variable
|
|
187
|
+
*
|
|
188
|
+
* GET /releases/download?version=x.y.z
|
|
189
|
+
* Header: X-License-Key
|
|
190
|
+
*/
|
|
191
|
+
function getAssetsDownloadUrl(version) {
|
|
192
|
+
const base = process.env.SEO_KIT_ASSETS_URL || 'https://antigravityseokit.solann.io/api/seo-kit/';
|
|
193
|
+
return `${base}releases/download?version=${encodeURIComponent(version)}`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ─── Exports ────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
module.exports = {
|
|
199
|
+
verifyLicense,
|
|
200
|
+
getLicenseStatus,
|
|
201
|
+
listDevices,
|
|
202
|
+
removeDevice,
|
|
203
|
+
getLatestRelease,
|
|
204
|
+
getAssetsDownloadUrl,
|
|
205
|
+
ApiError,
|
|
206
|
+
getApiUrl,
|
|
207
|
+
};
|