@minia2a/elizaos-plugin-minia2a 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,18 +1,19 @@
1
1
  # @minia2a/elizaos-plugin-minia2a
2
2
 
3
- **ElizaOS plugin for [minia2a.uk](https://minia2a.uk)** — discover and call 299+ x402 pay-per-call APIs directly from your AI agent.
3
+ **The marketplace plugin for ElizaOS agents** — discover, try, and pay for 299+ x402 APIs across crypto, web, AI, and data. USDC on Base.
4
4
 
5
- ## What This Plugin Does
5
+ > Unlike single-vendor x402 plugins that bundle a fixed set of endpoints, this plugin connects your agent to the **entire minia2a.uk marketplace** — 299+ services from dozens of providers, with live discovery, free trials, and transparent pricing.
6
6
 
7
- Your ElizaOS agent gets 3 new abilities:
7
+ ## Why This Plugin
8
8
 
9
- | Action | What it does |
10
- |--------|-------------|
11
- | `SEARCH_APIS` | Search 299+ APIs by keyword or category |
12
- | `CALL_API` | Call any endpoint with auto-trial (15 free calls per API) |
13
- | `LIST_POPULAR_APIS` | Browse trending/most-used services |
14
-
15
- Plus a provider that injects live marketplace stats into the agent's context.
9
+ | Feature | Fixed-Endpoint Plugins | This Plugin |
10
+ |---------|----------------------|-------------|
11
+ | Services | 8–75 endpoints | **299+ across categories** |
12
+ | Discovery | Pre-bundled at build time | **Live marketplace search** |
13
+ | Free trials | Sometimes | **15 free calls per endpoint** |
14
+ | New services | Wait for plugin update | **Available instantly** |
15
+ | Provider diversity | Single vendor | **Dozens of providers** |
16
+ | Payment | USDC on chain | **USDC on Base (~3¢ gas)** |
16
17
 
17
18
  ## Install
18
19
 
@@ -20,7 +21,7 @@ Plus a provider that injects live marketplace stats into the agent's context.
20
21
  npm install @minia2a/elizaos-plugin-minia2a
21
22
  ```
22
23
 
23
- ## Configure
24
+ ## Quick Start
24
25
 
25
26
  Add to your agent's `character.json`:
26
27
 
@@ -37,38 +38,49 @@ Add to your agent's `character.json`:
37
38
  }
38
39
  ```
39
40
 
40
- ## Usage
41
-
42
- Once configured, your agent can:
41
+ ## Actions
43
42
 
44
- **Search for APIs:**
45
- > "Search for APIs that can scrape websites"
43
+ | Action | What it does | Example prompt |
44
+ |--------|-------------|----------------|
45
+ | `SEARCH_APIS` | Search 299+ APIs by keyword or category | "Find APIs that can scrape websites" |
46
+ | `CALL_API` | Call any endpoint with auto-trial | "Get the current gas price on Base" |
47
+ | `LIST_POPULAR_APIS` | Browse trending services | "What are the most used APIs?" |
46
48
 
47
- **Browse the marketplace:**
48
- > "What APIs are available?"
49
+ ## Provider
49
50
 
50
- **Call an endpoint:**
51
- > "Call the /x402/gas endpoint" or "Try the gas price API"
51
+ The `MINIA2A_MARKETPLACE` provider injects live marketplace context into every agent interaction — service counts, popular endpoints, trial availability, and pricing.
52
52
 
53
53
  ## x402 Payment Flow
54
54
 
55
- This plugin handles the full x402 flow:
56
-
57
- 1. Agent requests an endpoint → gets **HTTP 402 Payment Required** with price + wallet address
55
+ 1. Agent requests endpoint gets `HTTP 402 Payment Required` with price + wallet
58
56
  2. Agent auto-signs USDC on Base (if `paymentPrivateKey` configured)
59
- 3. Agent retries with payment proof → receives result
57
+ 3. Agent retries with `Authorization: x402 <signed-tx>` → receives result
58
+ 4. Receipt returned in `X-Receipt` header for audit trail
59
+
60
+ **Without a payment key:** the agent uses free trials — 15 calls per endpoint, zero setup, no wallet.
61
+
62
+ ## Categories
63
+
64
+ - 🤖 **AI/LLM** — text generation, classification, translation, summarization
65
+ - 🔗 **Web** — scraping, search, email verification, DNS, HTTP analysis
66
+ - 💰 **Crypto** — gas prices, wallet intel, token security, DEX data, Polymarket
67
+ - 🔐 **Security** — CAPTCHA solving, domain intel, SSL checks, OSINT
68
+ - 📊 **Data** — enrichment, validation, formatting, CSV/JSON conversion
69
+ - 🛠️ **Dev Tools** — code review, regex, UUID, hashing, JWT decode
60
70
 
61
- Without a payment key configured, the agent uses **free trials** (15 calls per endpoint).
71
+ ## Pricing
62
72
 
63
- ## Real Data
73
+ - **Free trial:** 15 calls per endpoint (`?trial=1`)
74
+ - **Paid calls:** Priced per endpoint (typically $0.001–$0.10)
75
+ - **Platform fee:** 5% (transparent, no hidden costs)
76
+ - **Credits:** 1 USDC = 200 credits, no subscription, no minimum
77
+ - **Settlement:** USDC on Base (~3¢ gas, ~2s confirmation)
64
78
 
65
- minia2a.uk currently has **299 services** with **8,144+ trials** from **318 developers** across categories including:
79
+ ## Related
66
80
 
67
- - 🤖 AI/LLM (text generation, classification, translation)
68
- - 🔗 Web (scraping, search, email verification)
69
- - 💰 Crypto (gas, prices, wallet intel, token security)
70
- - 🔐 Security (CAPTCHA solving, domain intel, audits)
71
- - 📊 Data (enrichment, validation, formatting)
81
+ - [minia2a.uk](https://minia2a.uk) The marketplace
82
+ - [@minia2a/sdk](https://www.npmjs.com/package/@minia2a/sdk) CLI for x402 developers
83
+ - [x402.org](https://x402.org) The payment protocol
72
84
 
73
85
  ## License
74
86
 
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.callApiAction = void 0;
4
+ const spending_1 = require("../spending");
4
5
  const DEFAULT_BASE_URL = "https://minia2a.uk";
5
6
  exports.callApiAction = {
6
7
  name: "CALL_API",
@@ -35,6 +36,11 @@ exports.callApiAction = {
35
36
  const config = runtime.getSetting("MINIA2A_CONFIG") || {};
36
37
  const baseUrl = config.baseUrl || DEFAULT_BASE_URL;
37
38
  const autoTrial = config.autoTrial !== false; // default true
39
+ const maxSpend = config.maxSpendPerSession || 0;
40
+ // Initialize session spending tracker if budget is configured
41
+ if (maxSpend > 0) {
42
+ (0, spending_1.initSpendingTracker)(runtime.agentId, maxSpend);
43
+ }
38
44
  try {
39
45
  const text = message.content?.text || "";
40
46
  // Extract endpoint name from message
@@ -105,6 +111,17 @@ exports.callApiAction = {
105
111
  paymentDetails: paymentHeader,
106
112
  };
107
113
  }
114
+ // Budget check before payment
115
+ if (maxSpend > 0) {
116
+ const budgetCheck = (0, spending_1.canAfford)(runtime.agentId, 1); // approximate 1¢ minimum check
117
+ if (!budgetCheck.allowed) {
118
+ return {
119
+ text: `🛑 ${budgetCheck.reason}\n\nUse free trials (15 per endpoint) or increase maxSpendPerSession in config.`,
120
+ success: false,
121
+ budgetExceeded: true,
122
+ };
123
+ }
124
+ }
108
125
  // If we have a payment key, handle the payment flow
109
126
  if (callback) {
110
127
  callback({ text: `💳 Payment required — auto-signing USDC on Base...` });
@@ -112,6 +129,7 @@ exports.callApiAction = {
112
129
  // Extract payment address and amount from 402 headers
113
130
  // The actual USDC signing would use ethers.js or viem
114
131
  // For now, return payment instructions
132
+ // TODO: Implement full x402 payment flow (sign USDC tx → retry with X-PAYMENT header)
115
133
  return {
116
134
  text: `💳 **Payment Required**\n\nEndpoint: ${endpoint}\nPayment details: ${paymentHeader}\n\n💡 Tip: Use free trials first — each endpoint has 15 free calls. Set \`autoTrial: true\` in config.`,
117
135
  success: false,
@@ -0,0 +1,2 @@
1
+ import { Action } from "@elizaos/core";
2
+ export declare const viewSpendingAction: Action;
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.viewSpendingAction = void 0;
4
+ const spending_1 = require("../spending");
5
+ exports.viewSpendingAction = {
6
+ name: "VIEW_SPENDING",
7
+ similes: [
8
+ "CHECK_SPENDING",
9
+ "VIEW_BUDGET",
10
+ "SPENDING_STATUS",
11
+ "CHECK_BUDGET",
12
+ "HOW_MUCH_SPENT",
13
+ "MINIA2A_SPENDING",
14
+ ],
15
+ description: "View current session spending on minia2a API calls. Shows total spent, remaining budget, and call count.",
16
+ validate: async (_runtime, message, _state) => {
17
+ const text = message.content?.text?.toLowerCase() || "";
18
+ const triggers = [
19
+ "view spending",
20
+ "check spending",
21
+ "how much spent",
22
+ "budget status",
23
+ "view budget",
24
+ "check budget",
25
+ "spending status",
26
+ "remaining budget",
27
+ ];
28
+ return triggers.some((t) => text.includes(t));
29
+ },
30
+ handler: async (runtime, _message, _state, _options, _callback) => {
31
+ const summary = (0, spending_1.getSpendSummary)(runtime.agentId);
32
+ return {
33
+ text: summary,
34
+ success: true,
35
+ };
36
+ },
37
+ examples: [
38
+ [
39
+ {
40
+ user: "{{user1}}",
41
+ content: { text: "How much have I spent on API calls this session?" },
42
+ },
43
+ {
44
+ user: "{{user2}}",
45
+ content: {
46
+ text: "💰 Session Spending: $0.15 across 3 paid calls. Budget: $5.00 (3% used). Remaining: $4.85.",
47
+ action: "VIEW_SPENDING",
48
+ },
49
+ },
50
+ ],
51
+ ],
52
+ };
package/dist/index.d.ts CHANGED
@@ -3,7 +3,9 @@ export { Minia2aPluginConfig } from "./types";
3
3
  export { searchApisAction } from "./actions/searchApis";
4
4
  export { callApiAction } from "./actions/callApi";
5
5
  export { listPopularAction } from "./actions/listPopular";
6
+ export { viewSpendingAction } from "./actions/viewSpending";
6
7
  export { marketplaceStatsProvider } from "./providers/marketplaceStats";
8
+ export { initSpendingTracker, getSpending, getSpendSummary, canAfford, recordSpend, resetSpending } from "./spending";
7
9
  /**
8
10
  * minia2a.uk plugin for ElizaOS
9
11
  *
@@ -11,12 +13,15 @@ export { marketplaceStatsProvider } from "./providers/marketplaceStats";
11
13
  * - Search 299+ x402 pay-per-call APIs (SEARCH_APIS)
12
14
  * - Call any endpoint with auto-trial support (CALL_API)
13
15
  * - Browse trending/popular services (LIST_POPULAR_APIS)
16
+ * - Track and control API spending per session (VIEW_SPENDING)
14
17
  * - Get marketplace stats injected into agent context (MINIA2A_MARKETPLACE provider)
15
18
  *
16
19
  * Configuration via character.json settings.MINIA2A_CONFIG:
17
20
  * - baseUrl: minia2a marketplace URL (default: https://minia2a.uk)
18
21
  * - autoTrial: use free trials automatically (default: true)
19
22
  * - maxPricePerCall: max USD per paid call (default: 0, trials only)
23
+ * - maxSpendPerSession: total USD cents budget cap per session (0 = unlimited)
24
+ * - paymentPrivateKey: wallet key for x402 USDC payments on Base
20
25
  *
21
26
  * @example
22
27
  * ```json
@@ -26,7 +31,8 @@ export { marketplaceStatsProvider } from "./providers/marketplaceStats";
26
31
  * "settings": {
27
32
  * "MINIA2A_CONFIG": {
28
33
  * "autoTrial": true,
29
- * "maxPricePerCall": 0.10
34
+ * "maxPricePerCall": 0.10,
35
+ * "maxSpendPerSession": 500
30
36
  * }
31
37
  * }
32
38
  * }
package/dist/index.js CHANGED
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.minia2aPlugin = exports.marketplaceStatsProvider = exports.listPopularAction = exports.callApiAction = exports.searchApisAction = void 0;
3
+ exports.minia2aPlugin = exports.resetSpending = exports.recordSpend = exports.canAfford = exports.getSpendSummary = exports.getSpending = exports.initSpendingTracker = exports.marketplaceStatsProvider = exports.viewSpendingAction = exports.listPopularAction = exports.callApiAction = exports.searchApisAction = void 0;
4
4
  const searchApis_1 = require("./actions/searchApis");
5
5
  const callApi_1 = require("./actions/callApi");
6
6
  const listPopular_1 = require("./actions/listPopular");
7
+ const viewSpending_1 = require("./actions/viewSpending");
7
8
  const marketplaceStats_1 = require("./providers/marketplaceStats");
8
9
  var searchApis_2 = require("./actions/searchApis");
9
10
  Object.defineProperty(exports, "searchApisAction", { enumerable: true, get: function () { return searchApis_2.searchApisAction; } });
@@ -11,8 +12,17 @@ var callApi_2 = require("./actions/callApi");
11
12
  Object.defineProperty(exports, "callApiAction", { enumerable: true, get: function () { return callApi_2.callApiAction; } });
12
13
  var listPopular_2 = require("./actions/listPopular");
13
14
  Object.defineProperty(exports, "listPopularAction", { enumerable: true, get: function () { return listPopular_2.listPopularAction; } });
15
+ var viewSpending_2 = require("./actions/viewSpending");
16
+ Object.defineProperty(exports, "viewSpendingAction", { enumerable: true, get: function () { return viewSpending_2.viewSpendingAction; } });
14
17
  var marketplaceStats_2 = require("./providers/marketplaceStats");
15
18
  Object.defineProperty(exports, "marketplaceStatsProvider", { enumerable: true, get: function () { return marketplaceStats_2.marketplaceStatsProvider; } });
19
+ var spending_1 = require("./spending");
20
+ Object.defineProperty(exports, "initSpendingTracker", { enumerable: true, get: function () { return spending_1.initSpendingTracker; } });
21
+ Object.defineProperty(exports, "getSpending", { enumerable: true, get: function () { return spending_1.getSpending; } });
22
+ Object.defineProperty(exports, "getSpendSummary", { enumerable: true, get: function () { return spending_1.getSpendSummary; } });
23
+ Object.defineProperty(exports, "canAfford", { enumerable: true, get: function () { return spending_1.canAfford; } });
24
+ Object.defineProperty(exports, "recordSpend", { enumerable: true, get: function () { return spending_1.recordSpend; } });
25
+ Object.defineProperty(exports, "resetSpending", { enumerable: true, get: function () { return spending_1.resetSpending; } });
16
26
  /**
17
27
  * minia2a.uk plugin for ElizaOS
18
28
  *
@@ -20,12 +30,15 @@ Object.defineProperty(exports, "marketplaceStatsProvider", { enumerable: true, g
20
30
  * - Search 299+ x402 pay-per-call APIs (SEARCH_APIS)
21
31
  * - Call any endpoint with auto-trial support (CALL_API)
22
32
  * - Browse trending/popular services (LIST_POPULAR_APIS)
33
+ * - Track and control API spending per session (VIEW_SPENDING)
23
34
  * - Get marketplace stats injected into agent context (MINIA2A_MARKETPLACE provider)
24
35
  *
25
36
  * Configuration via character.json settings.MINIA2A_CONFIG:
26
37
  * - baseUrl: minia2a marketplace URL (default: https://minia2a.uk)
27
38
  * - autoTrial: use free trials automatically (default: true)
28
39
  * - maxPricePerCall: max USD per paid call (default: 0, trials only)
40
+ * - maxSpendPerSession: total USD cents budget cap per session (0 = unlimited)
41
+ * - paymentPrivateKey: wallet key for x402 USDC payments on Base
29
42
  *
30
43
  * @example
31
44
  * ```json
@@ -35,7 +48,8 @@ Object.defineProperty(exports, "marketplaceStatsProvider", { enumerable: true, g
35
48
  * "settings": {
36
49
  * "MINIA2A_CONFIG": {
37
50
  * "autoTrial": true,
38
- * "maxPricePerCall": 0.10
51
+ * "maxPricePerCall": 0.10,
52
+ * "maxSpendPerSession": 500
39
53
  * }
40
54
  * }
41
55
  * }
@@ -44,13 +58,14 @@ Object.defineProperty(exports, "marketplaceStatsProvider", { enumerable: true, g
44
58
  exports.minia2aPlugin = {
45
59
  name: "@minia2a/elizaos-plugin-minia2a",
46
60
  npmName: "@minia2a/elizaos-plugin-minia2a",
47
- description: "Discover and call 299+ x402 pay-per-call APIs from minia2a.uk. Search, free trials, and USDC payments on Base.",
61
+ description: "Discover and call 299+ x402 pay-per-call APIs from minia2a.uk. Search, free trials, budget controls, and USDC payments on Base.",
48
62
  config: {
49
63
  baseUrl: "https://minia2a.uk",
50
64
  autoTrial: true,
51
65
  maxPricePerCall: 0,
66
+ maxSpendPerSession: 0,
52
67
  },
53
- actions: [searchApis_1.searchApisAction, callApi_1.callApiAction, listPopular_1.listPopularAction],
68
+ actions: [searchApis_1.searchApisAction, callApi_1.callApiAction, listPopular_1.listPopularAction, viewSpending_1.viewSpendingAction],
54
69
  providers: [marketplaceStats_1.marketplaceStatsProvider],
55
70
  };
56
71
  exports.default = exports.minia2aPlugin;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Session-level spending tracker for budget controls.
3
+ *
4
+ * Tracks cumulative spend within a single agent session.
5
+ * When maxSpendPerSession is configured, paid calls are blocked
6
+ * once the budget is exhausted. Free trials are always allowed.
7
+ */
8
+ interface SessionSpend {
9
+ totalCents: number;
10
+ callCount: number;
11
+ maxBudgetCents: number;
12
+ startTime: number;
13
+ }
14
+ export declare function initSpendingTracker(runtimeId: string, maxSpendPerSession: number): void;
15
+ export declare function getSpending(runtimeId: string): SessionSpend | undefined;
16
+ export declare function canAfford(runtimeId: string, priceCents: number): {
17
+ allowed: boolean;
18
+ reason?: string;
19
+ };
20
+ export declare function recordSpend(runtimeId: string, priceCents: number): void;
21
+ export declare function getSpendSummary(runtimeId: string): string;
22
+ export declare function resetSpending(runtimeId: string): void;
23
+ export {};
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Session-level spending tracker for budget controls.
4
+ *
5
+ * Tracks cumulative spend within a single agent session.
6
+ * When maxSpendPerSession is configured, paid calls are blocked
7
+ * once the budget is exhausted. Free trials are always allowed.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.initSpendingTracker = initSpendingTracker;
11
+ exports.getSpending = getSpending;
12
+ exports.canAfford = canAfford;
13
+ exports.recordSpend = recordSpend;
14
+ exports.getSpendSummary = getSpendSummary;
15
+ exports.resetSpending = resetSpending;
16
+ const sessions = new Map();
17
+ function getSessionId(runtimeId) {
18
+ return `minia2a-spend-${runtimeId}`;
19
+ }
20
+ function initSpendingTracker(runtimeId, maxSpendPerSession) {
21
+ const sessionId = getSessionId(runtimeId);
22
+ if (!sessions.has(sessionId)) {
23
+ sessions.set(sessionId, {
24
+ totalCents: 0,
25
+ callCount: 0,
26
+ maxBudgetCents: maxSpendPerSession,
27
+ startTime: Date.now(),
28
+ });
29
+ }
30
+ }
31
+ function getSpending(runtimeId) {
32
+ return sessions.get(getSessionId(runtimeId));
33
+ }
34
+ function canAfford(runtimeId, priceCents) {
35
+ const session = sessions.get(getSessionId(runtimeId));
36
+ if (!session)
37
+ return { allowed: true }; // No tracker = no limit
38
+ if (session.maxBudgetCents === 0)
39
+ return { allowed: true }; // Unlimited
40
+ const projected = session.totalCents + priceCents;
41
+ if (projected > session.maxBudgetCents) {
42
+ return {
43
+ allowed: false,
44
+ reason: `Budget exceeded: $${(session.totalCents / 100).toFixed(2)} spent + $${(priceCents / 100).toFixed(2)} would exceed $${(session.maxBudgetCents / 100).toFixed(2)} session limit`,
45
+ };
46
+ }
47
+ return { allowed: true };
48
+ }
49
+ function recordSpend(runtimeId, priceCents) {
50
+ const session = sessions.get(getSessionId(runtimeId));
51
+ if (session) {
52
+ session.totalCents += priceCents;
53
+ session.callCount++;
54
+ }
55
+ }
56
+ function getSpendSummary(runtimeId) {
57
+ const session = sessions.get(getSessionId(runtimeId));
58
+ if (!session)
59
+ return "No spending tracker active.";
60
+ const elapsed = Math.round((Date.now() - session.startTime) / 1000);
61
+ const budgetStatus = session.maxBudgetCents === 0
62
+ ? "unlimited"
63
+ : `$${(session.maxBudgetCents / 100).toFixed(2)} (${((session.totalCents / session.maxBudgetCents) * 100).toFixed(0)}% used)`;
64
+ return [
65
+ `💰 **Session Spending** (${elapsed}s elapsed)`,
66
+ ` Total spent: $${(session.totalCents / 100).toFixed(2)} across ${session.callCount} paid call(s)`,
67
+ ` Budget: ${budgetStatus}`,
68
+ session.maxBudgetCents > 0
69
+ ? ` Remaining: $${((session.maxBudgetCents - session.totalCents) / 100).toFixed(2)}`
70
+ : "",
71
+ ]
72
+ .filter(Boolean)
73
+ .join("\n");
74
+ }
75
+ function resetSpending(runtimeId) {
76
+ sessions.delete(getSessionId(runtimeId));
77
+ }
package/dist/types.d.ts CHANGED
@@ -37,4 +37,6 @@ export interface Minia2aPluginConfig {
37
37
  maxPricePerCall?: number;
38
38
  /** Wallet private key for signing x402 payments on Base */
39
39
  paymentPrivateKey?: string;
40
+ /** Maximum total spend in USD cents allowed per agent session (0 = unlimited) */
41
+ maxSpendPerSession?: number;
40
42
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@minia2a/elizaos-plugin-minia2a",
3
- "version": "0.1.1",
4
- "description": "ElizaOS plugin for minia2a.uk — discover and call 299+ x402 pay-per-call APIs from your agent",
3
+ "version": "0.2.0",
4
+ "description": "ElizaOS plugin for the minia2a.uk marketplace — 299+ x402 pay-per-call APIs across crypto, web, AI, and data. 15 free trials per endpoint. USDC on Base.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
@@ -18,10 +18,19 @@
18
18
  "x402",
19
19
  "minia2a",
20
20
  "agent-payments",
21
+ "pay-per-call",
21
22
  "usdc",
23
+ "base",
22
24
  "m2m",
23
25
  "ai-agent",
24
- "marketplace"
26
+ "marketplace",
27
+ "micropayments",
28
+ "web-scraping",
29
+ "crypto-data",
30
+ "captcha-solving",
31
+ "ai-inference",
32
+ "api-discovery",
33
+ "agent-economy"
25
34
  ],
26
35
  "author": "minia2a.uk",
27
36
  "license": "MIT",