Add Electron test harness with example plugin
This commit is contained in:
225
test/electron/index.html
Normal file
225
test/electron/index.html
Normal file
@@ -0,0 +1,225 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>@paarrot/plugin-manager — Electron Test</title>
|
||||
<style>
|
||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', system-ui, sans-serif;
|
||||
font-size: 13px;
|
||||
background: #1a1a2e;
|
||||
color: #e0e0e0;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
header {
|
||||
padding: 10px 16px;
|
||||
background: #16213e;
|
||||
border-bottom: 1px solid #0f3460;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
header h1 { font-size: 14px; font-weight: 600; color: #e94560; }
|
||||
|
||||
#status-badge {
|
||||
font-size: 11px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
background: #333;
|
||||
color: #888;
|
||||
}
|
||||
#status-badge.loaded { background: #1a4a2e; color: #4caf50; }
|
||||
|
||||
main {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: 1px;
|
||||
background: #0f3460;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel {
|
||||
background: #1a1a2e;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
padding: 8px 12px;
|
||||
background: #16213e;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: #7986cb;
|
||||
border-bottom: 1px solid #0f3460;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.panel-body {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
/* Inputs / buttons */
|
||||
input[type="text"], select {
|
||||
background: #0f3460;
|
||||
border: 1px solid #233a6e;
|
||||
color: #e0e0e0;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 13px;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
}
|
||||
input[type="text"]:focus, select:focus { border-color: #7986cb; }
|
||||
|
||||
button {
|
||||
padding: 6px 14px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
background: #0f3460;
|
||||
color: #e0e0e0;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
button:hover { background: #1a4a8e; }
|
||||
button.primary { background: #e94560; color: #fff; }
|
||||
button.primary:hover { background: #c73652; }
|
||||
|
||||
.row { display: flex; gap: 8px; align-items: center; }
|
||||
.row input { flex: 1; }
|
||||
|
||||
/* Command list */
|
||||
#cmd-list { list-style: none; display: flex; flex-direction: column; gap: 4px; }
|
||||
#cmd-list li { font-size: 12px; color: #aaa; }
|
||||
#cmd-list code { color: #e94560; font-size: 12px; }
|
||||
|
||||
/* Message result */
|
||||
#msg-result {
|
||||
background: #0f3460;
|
||||
border: 1px solid #233a6e;
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
white-space: pre-wrap;
|
||||
min-height: 52px;
|
||||
color: #b0bec5;
|
||||
}
|
||||
|
||||
/* Settings */
|
||||
.setting-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 6px 0;
|
||||
border-bottom: 1px solid #12244a;
|
||||
}
|
||||
.setting-row label { flex: 1; color: #b0bec5; font-size: 12px; }
|
||||
.setting-row input[type="checkbox"] { width: auto; }
|
||||
.setting-row input[type="text"], .setting-row select { width: 140px; flex: none; }
|
||||
|
||||
/* Log */
|
||||
#log {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
.log-entry { padding: 2px 0; }
|
||||
.log-log { color: #90a4ae; }
|
||||
.log-info { color: #7986cb; }
|
||||
.log-success { color: #4caf50; }
|
||||
.log-error { color: #e94560; }
|
||||
.log-warn { color: #ffb300; }
|
||||
|
||||
/* Theme section */
|
||||
.theme-row { display: flex; gap: 8px; flex-wrap: wrap; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>@paarrot/plugin-manager</h1>
|
||||
<span id="status-badge">Loading…</span>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!-- Top-left: Commands -->
|
||||
<div class="panel">
|
||||
<div class="panel-header">Commands</div>
|
||||
<div class="panel-body">
|
||||
<div>
|
||||
<div style="font-size:11px;color:#7986cb;margin-bottom:6px;">Registered commands:</div>
|
||||
<ul id="cmd-list"><li style="color:#555">Loading…</li></ul>
|
||||
</div>
|
||||
<div class="row">
|
||||
<input type="text" id="cmd-input" placeholder="/hello World" />
|
||||
<button class="primary" id="cmd-run">Run</button>
|
||||
</div>
|
||||
<div id="cmd-result" style="font-family:monospace;font-size:12px;color:#4caf50;min-height:20px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Top-right: Message Interceptor -->
|
||||
<div class="panel">
|
||||
<div class="panel-header">Message Interceptor</div>
|
||||
<div class="panel-body">
|
||||
<div style="font-size:11px;color:#7986cb;">
|
||||
Type a message. The plugin will expand abbreviations like <code style="color:#e94560">brb</code>, <code style="color:#e94560">omw</code>, <code style="color:#e94560">afk</code>.
|
||||
</div>
|
||||
<textarea id="msg-input" rows="3"
|
||||
style="background:#0f3460;border:1px solid #233a6e;color:#e0e0e0;padding:8px;border-radius:4px;font-size:13px;resize:none;width:100%;outline:none;"
|
||||
placeholder="Type something… try 'brb' or 'omw'"></textarea>
|
||||
<button class="primary" id="msg-send">Process Message</button>
|
||||
<pre id="msg-result"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom-left: Settings + Theme -->
|
||||
<div class="panel">
|
||||
<div class="panel-header">Settings & Theme</div>
|
||||
<div class="panel-body">
|
||||
<div style="font-size:11px;color:#7986cb;margin-bottom:4px;">Plugin settings (persisted to localStorage):</div>
|
||||
<div id="settings-container"></div>
|
||||
<div style="margin-top:8px;font-size:11px;color:#7986cb;">Plugin Themes:</div>
|
||||
<div class="theme-row">
|
||||
<button id="theme-apply">Apply Ocean Blue</button>
|
||||
<button id="theme-reset">Reset Theme</button>
|
||||
</div>
|
||||
<div style="margin-top:8px;font-size:11px;color:#7986cb;">Events:</div>
|
||||
<button id="event-fire">Fire test-event</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom-right: Log -->
|
||||
<div class="panel">
|
||||
<div class="panel-header">Log</div>
|
||||
<div class="panel-body" style="padding:8px;">
|
||||
<div id="log"></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script src="renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
27
test/electron/main.js
Normal file
27
test/electron/main.js
Normal file
@@ -0,0 +1,27 @@
|
||||
const { app, BrowserWindow } = require('electron');
|
||||
const path = require('path');
|
||||
|
||||
/**
|
||||
* Creates the main application window.
|
||||
* nodeIntegration is enabled so the renderer can use require() / dynamic import()
|
||||
* directly against the local node_modules — appropriate for a local test harness.
|
||||
*/
|
||||
function createWindow() {
|
||||
const win = new BrowserWindow({
|
||||
width: 1200,
|
||||
height: 800,
|
||||
backgroundColor: '#1a1a2e',
|
||||
webPreferences: {
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
});
|
||||
|
||||
win.loadFile(path.join(__dirname, 'index.html'));
|
||||
}
|
||||
|
||||
app.whenReady().then(createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') app.quit();
|
||||
});
|
||||
886
test/electron/package-lock.json
generated
Normal file
886
test/electron/package-lock.json
generated
Normal file
@@ -0,0 +1,886 @@
|
||||
{
|
||||
"name": "plugin-manager-electron-test",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "plugin-manager-electron-test",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@paarrot/plugin-manager": "file:../.."
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^35.0.0"
|
||||
}
|
||||
},
|
||||
"../..": {
|
||||
"name": "@paarrot/plugin-manager",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"rimraf": "^5.0.0",
|
||||
"typescript": "^5.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@electron/get": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.3.tgz",
|
||||
"integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"env-paths": "^2.2.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"got": "^11.8.5",
|
||||
"progress": "^2.0.3",
|
||||
"semver": "^6.2.0",
|
||||
"sumchecker": "^3.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"global-agent": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@paarrot/plugin-manager": {
|
||||
"resolved": "../..",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@sindresorhus/is": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz",
|
||||
"integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/is?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/@szmarczak/http-timer": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
|
||||
"integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"defer-to-connect": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cacheable-request": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz",
|
||||
"integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-cache-semantics": "*",
|
||||
"@types/keyv": "^3.1.4",
|
||||
"@types/node": "*",
|
||||
"@types/responselike": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
"integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/keyv": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz",
|
||||
"integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.19.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz",
|
||||
"integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/responselike": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz",
|
||||
"integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/boolean": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
|
||||
"integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
|
||||
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-lookup": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz",
|
||||
"integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cacheable-request": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz",
|
||||
"integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"clone-response": "^1.0.2",
|
||||
"get-stream": "^5.1.0",
|
||||
"http-cache-semantics": "^4.0.0",
|
||||
"keyv": "^4.0.0",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"normalize-url": "^6.0.1",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/clone-response": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
|
||||
"integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
|
||||
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mimic-response": "^3.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/decompress-response/node_modules/mimic-response": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
|
||||
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/defer-to-connect": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz",
|
||||
"integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
|
||||
"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/define-properties": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
|
||||
"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-data-property": "^1.0.1",
|
||||
"has-property-descriptors": "^1.0.0",
|
||||
"object-keys": "^1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-node": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
|
||||
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "35.7.5",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-35.7.5.tgz",
|
||||
"integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@electron/get": "^2.0.0",
|
||||
"@types/node": "^22.7.7",
|
||||
"extract-zip": "^2.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"electron": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.20.55"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/env-paths": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
|
||||
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-error": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
|
||||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/escape-string-regexp": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/extract-zip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"extract-zip": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@types/yauzl": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fs-extra": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
|
||||
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6 <7 || >=8"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
|
||||
"integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"es6-error": "^4.1.1",
|
||||
"matcher": "^3.0.0",
|
||||
"roarr": "^2.15.3",
|
||||
"semver": "^7.3.2",
|
||||
"serialize-error": "^7.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/global-agent/node_modules/semver": {
|
||||
"version": "7.7.4",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
|
||||
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/globalthis": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
|
||||
"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"define-properties": "^1.2.1",
|
||||
"gopd": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/got": {
|
||||
"version": "11.8.6",
|
||||
"resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz",
|
||||
"integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sindresorhus/is": "^4.0.0",
|
||||
"@szmarczak/http-timer": "^4.0.5",
|
||||
"@types/cacheable-request": "^6.0.1",
|
||||
"@types/responselike": "^1.0.0",
|
||||
"cacheable-lookup": "^5.0.3",
|
||||
"cacheable-request": "^7.0.2",
|
||||
"decompress-response": "^6.0.0",
|
||||
"http2-wrapper": "^1.0.0-beta.5.2",
|
||||
"lowercase-keys": "^2.0.0",
|
||||
"p-cancelable": "^2.0.0",
|
||||
"responselike": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/got?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/has-property-descriptors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
|
||||
"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"es-define-property": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/http-cache-semantics": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/http2-wrapper": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz",
|
||||
"integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quick-lru": "^5.1.1",
|
||||
"resolve-alpn": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
|
||||
"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/json-stringify-safe": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
|
||||
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/jsonfile": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
|
||||
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
}
|
||||
},
|
||||
"node_modules/keyv": {
|
||||
"version": "4.5.4",
|
||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||
"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json-buffer": "3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lowercase-keys": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||
"integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/matcher": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||
"integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"escape-string-regexp": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-response": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
|
||||
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/normalize-url": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
|
||||
"integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/p-cancelable": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz",
|
||||
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/quick-lru": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-alpn": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz",
|
||||
"integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/responselike": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz",
|
||||
"integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lowercase-keys": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/roarr": {
|
||||
"version": "2.15.4",
|
||||
"resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
|
||||
"integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"boolean": "^3.0.1",
|
||||
"detect-node": "^2.0.4",
|
||||
"globalthis": "^1.0.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"semver-compare": "^1.0.0",
|
||||
"sprintf-js": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "6.3.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
||||
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
}
|
||||
},
|
||||
"node_modules/semver-compare": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
|
||||
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/serialize-error": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
|
||||
"integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"type-fest": "^0.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/sprintf-js": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sumchecker": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||
"integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/type-fest": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
|
||||
"integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
|
||||
"dev": true,
|
||||
"license": "(MIT OR CC0-1.0)",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
test/electron/package.json
Normal file
15
test/electron/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "plugin-manager-electron-test",
|
||||
"version": "1.0.0",
|
||||
"description": "Electron test harness for @paarrot/plugin-manager",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@paarrot/plugin-manager": "file:../.."
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^35.0.0"
|
||||
}
|
||||
}
|
||||
237
test/electron/plugins/example-plugin/index.js
Normal file
237
test/electron/plugins/example-plugin/index.js
Normal file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Example plugin — demonstrates every PluginContext API surface.
|
||||
* Loaded as CommonJS by the test harness (eval'd via new Function).
|
||||
*/
|
||||
module.exports = {
|
||||
name: 'Example Plugin',
|
||||
version: '1.0.0',
|
||||
|
||||
/** @param {import('@paarrot/plugin-manager').PluginContext} ctx */
|
||||
onLoad(ctx) {
|
||||
// -------------------------------------------------------------------------
|
||||
// Settings — persisted to storage automatically
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.settings.define({
|
||||
greeting: {
|
||||
type: 'string',
|
||||
label: 'Greeting word',
|
||||
default: 'Hello',
|
||||
},
|
||||
autoExpand: {
|
||||
type: 'boolean',
|
||||
label: 'Auto-expand abbreviations (brb, omw, afk)',
|
||||
default: true,
|
||||
},
|
||||
logLevel: {
|
||||
type: 'select',
|
||||
label: 'Log verbosity',
|
||||
default: 'normal',
|
||||
options: [
|
||||
{ value: 'quiet', label: 'Quiet' },
|
||||
{ value: 'normal', label: 'Normal' },
|
||||
{ value: 'verbose', label: 'Verbose' },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Commands
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.commands.register({
|
||||
name: 'hello',
|
||||
description: 'Greet someone',
|
||||
args: [{ name: 'name', type: 'string', required: false, description: 'Who to greet' }],
|
||||
run(args) {
|
||||
const greeting = ctx.settings.get('greeting') ?? 'Hello';
|
||||
return `${greeting}, ${args.name || 'World'}!`;
|
||||
},
|
||||
});
|
||||
|
||||
ctx.commands.register({
|
||||
name: 'echo',
|
||||
description: 'Echo text back',
|
||||
args: [{ name: 'text', type: 'string', description: 'Text to echo' }],
|
||||
run: (args) => args.text || '(nothing)',
|
||||
});
|
||||
|
||||
ctx.commands.register({
|
||||
name: 'roll',
|
||||
description: 'Roll a dice — /roll <sides>',
|
||||
args: [{ name: 'sides', type: 'number', description: 'Number of sides (default 6)' }],
|
||||
run(args) {
|
||||
const sides = parseInt(args.sides, 10) || 6;
|
||||
const result = Math.floor(Math.random() * sides) + 1;
|
||||
return `Rolled a d${sides}: ${result}`;
|
||||
},
|
||||
});
|
||||
|
||||
ctx.commands.register({
|
||||
name: 'setting',
|
||||
description: 'Read a plugin setting — /setting <key>',
|
||||
args: [{ name: 'key', type: 'string' }],
|
||||
run(args) {
|
||||
const val = ctx.settings.get(args.key);
|
||||
return val !== undefined ? `${args.key} = ${JSON.stringify(val)}` : `Setting "${args.key}" not found`;
|
||||
},
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Message interceptors
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.messages.onBeforeSend((msg) => {
|
||||
if (!ctx.settings.get('autoExpand')) return;
|
||||
msg.content = msg.content
|
||||
.replace(/\bbrb\b/gi, 'be right back')
|
||||
.replace(/\bomw\b/gi, 'on my way')
|
||||
.replace(/\bafk\b/gi, 'away from keyboard');
|
||||
|
||||
if (ctx.settings.get('logLevel') === 'verbose') {
|
||||
ctx.log('beforeSend interceptor ran');
|
||||
}
|
||||
});
|
||||
|
||||
ctx.messages.onReceive((msg) => {
|
||||
if (ctx.settings.get('logLevel') !== 'quiet') {
|
||||
ctx.log(`Received message in ${msg.roomId}: "${msg.content.slice(0, 40)}"`);
|
||||
}
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Theme — Ocean Blue dark palette
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.themes.register({
|
||||
id: 'ocean',
|
||||
name: 'Ocean Blue',
|
||||
kind: 'dark',
|
||||
colors: {
|
||||
background: {
|
||||
container: '#0d1b2a',
|
||||
containerHover: '#1b2d42',
|
||||
containerActive: '#243856',
|
||||
containerLine: '#1e3a5f',
|
||||
onContainer: '#c9d6e3',
|
||||
},
|
||||
surface: {
|
||||
container: '#112233',
|
||||
containerHover: '#1a3344',
|
||||
containerActive: '#224455',
|
||||
containerLine: '#1e3a5f',
|
||||
onContainer: '#d0dde8',
|
||||
},
|
||||
surfaceVariant: {
|
||||
container: '#162840',
|
||||
containerHover: '#1f3555',
|
||||
containerActive: '#28426a',
|
||||
containerLine: '#2a4a70',
|
||||
onContainer: '#b8cfe0',
|
||||
},
|
||||
primary: {
|
||||
main: '#0077b6',
|
||||
mainHover: '#0096c7',
|
||||
mainActive: '#00b4d8',
|
||||
mainLine: '#0077b6',
|
||||
onMain: '#ffffff',
|
||||
container: '#023e8a',
|
||||
containerHover: '#0d47a1',
|
||||
containerActive: '#1565c0',
|
||||
containerLine: '#0d47a1',
|
||||
onContainer: '#90e0ef',
|
||||
},
|
||||
secondary: {
|
||||
main: '#48cae4',
|
||||
mainHover: '#00b4d8',
|
||||
mainActive: '#0096c7',
|
||||
mainLine: '#48cae4',
|
||||
onMain: '#000000',
|
||||
container: '#0d6986',
|
||||
containerHover: '#0e7fa0',
|
||||
containerActive: '#0f95bb',
|
||||
containerLine: '#0d6986',
|
||||
onContainer: '#caf0f8',
|
||||
},
|
||||
success: {
|
||||
main: '#00b894',
|
||||
mainHover: '#00cca3',
|
||||
mainActive: '#00dfb2',
|
||||
mainLine: '#00b894',
|
||||
onMain: '#000000',
|
||||
container: '#007a65',
|
||||
containerHover: '#009478',
|
||||
containerActive: '#00ae8b',
|
||||
containerLine: '#007a65',
|
||||
onContainer: '#b2f0e8',
|
||||
},
|
||||
warning: {
|
||||
main: '#f39c12',
|
||||
mainHover: '#f5a623',
|
||||
mainActive: '#f7b733',
|
||||
mainLine: '#f39c12',
|
||||
onMain: '#000000',
|
||||
container: '#a66c00',
|
||||
containerHover: '#bf7c00',
|
||||
containerActive: '#d98c00',
|
||||
containerLine: '#a66c00',
|
||||
onContainer: '#fde9b2',
|
||||
},
|
||||
critical: {
|
||||
main: '#e74c3c',
|
||||
mainHover: '#ec5f50',
|
||||
mainActive: '#f17264',
|
||||
mainLine: '#e74c3c',
|
||||
onMain: '#ffffff',
|
||||
container: '#9c1e12',
|
||||
containerHover: '#b52316',
|
||||
containerActive: '#ce281a',
|
||||
containerLine: '#9c1e12',
|
||||
onContainer: '#fcd4d0',
|
||||
},
|
||||
other: {
|
||||
focusRing: '#0096c7',
|
||||
shadow: 'rgba(0,0,0,0.5)',
|
||||
overlay: 'rgba(0,0,0,0.6)',
|
||||
},
|
||||
},
|
||||
extraCss: `
|
||||
body.plugin-example-plugin-ocean {
|
||||
background: #0d1b2a;
|
||||
color: #c9d6e3;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Events — listen on the injected event client
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.events.on('test-event', (data) => {
|
||||
ctx.log(`test-event received: ${JSON.stringify(data)}`);
|
||||
});
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Timers — heartbeat every 30 s
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.timers.setInterval(() => {
|
||||
if (ctx.settings.get('logLevel') === 'verbose') {
|
||||
ctx.log('Heartbeat tick');
|
||||
}
|
||||
}, 30_000);
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Notify on load
|
||||
// -------------------------------------------------------------------------
|
||||
ctx.notify({
|
||||
title: 'Example Plugin',
|
||||
body: 'Loaded successfully! Try a /command below.',
|
||||
type: 'success',
|
||||
});
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// Timers, event handlers, and themes are cleaned up automatically by the registry.
|
||||
},
|
||||
|
||||
/** Public API — accessible by other plugins via ctx.require('example-plugin') */
|
||||
exports: {
|
||||
version: '1.0.0',
|
||||
greet: (name) => `Hi from Example Plugin, ${name}!`,
|
||||
},
|
||||
};
|
||||
237
test/electron/renderer.js
Normal file
237
test/electron/renderer.js
Normal file
@@ -0,0 +1,237 @@
|
||||
/**
|
||||
* Renderer process entry point for the plugin-manager Electron test harness.
|
||||
*
|
||||
* Uses a dynamic import() to load the ESM @paarrot/plugin-manager dist,
|
||||
* then loads the example plugin from disk and demonstrates every API surface.
|
||||
*/
|
||||
(async () => {
|
||||
const { pathToFileURL } = require('url');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
// Resolve the plugin-manager dist entry using a file:// URL so Electron can
|
||||
// import an ESM module located inside node_modules.
|
||||
const pmEntry = path.join(
|
||||
__dirname, 'node_modules', '@paarrot', 'plugin-manager', 'dist', 'index.js'
|
||||
);
|
||||
const { PluginRegistry, createPluginContext } = await import(pathToFileURL(pmEntry).href);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Logging helper — writes to the on-screen log panel
|
||||
// ---------------------------------------------------------------------------
|
||||
const logEl = document.getElementById('log');
|
||||
|
||||
/** @param {'log'|'info'|'success'|'error'|'warn'} type */
|
||||
function addLog(message, type = 'log') {
|
||||
const entry = document.createElement('div');
|
||||
entry.className = `log-entry log-${type}`;
|
||||
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
|
||||
logEl.appendChild(entry);
|
||||
logEl.scrollTop = logEl.scrollHeight;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registry
|
||||
// ---------------------------------------------------------------------------
|
||||
const registry = new PluginRegistry({
|
||||
storage: localStorage,
|
||||
onThemeRegistered: (themeId, _className, css) => {
|
||||
const el = document.createElement('style');
|
||||
el.id = `plugin-theme-${themeId}`;
|
||||
el.textContent = css;
|
||||
document.head.appendChild(el);
|
||||
addLog(`Theme registered: ${themeId}`, 'info');
|
||||
},
|
||||
onThemeUnregistered: (themeId) => {
|
||||
document.getElementById(`plugin-theme-${themeId}`)?.remove();
|
||||
addLog(`Theme unregistered: ${themeId}`, 'info');
|
||||
},
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Load the example plugin from disk (CJS eval — same pattern as cinny)
|
||||
// ---------------------------------------------------------------------------
|
||||
const pluginPath = path.join(__dirname, 'plugins', 'example-plugin', 'index.js');
|
||||
const pluginCode = fs.readFileSync(pluginPath, 'utf-8');
|
||||
const pluginExports = {};
|
||||
const mod = { exports: pluginExports };
|
||||
// eslint-disable-next-line no-new-func
|
||||
new Function('module', 'exports', pluginCode)(mod, pluginExports);
|
||||
const plugin = mod.exports;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Simple in-process event emitter (stands in for a real client like Matrix)
|
||||
// ---------------------------------------------------------------------------
|
||||
const eventEmitter = {
|
||||
_handlers: {},
|
||||
on(event, handler) {
|
||||
(this._handlers[event] ??= []).push(handler);
|
||||
},
|
||||
off(event, handler) {
|
||||
this._handlers[event] = (this._handlers[event] ?? []).filter(h => h !== handler);
|
||||
},
|
||||
emit(event, data) {
|
||||
(this._handlers[event] ?? []).forEach(h => h(data));
|
||||
},
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Plugin context
|
||||
// ---------------------------------------------------------------------------
|
||||
const context = createPluginContext(
|
||||
{
|
||||
pluginId: 'example-plugin',
|
||||
eventClient: eventEmitter,
|
||||
onNotify: (opts) =>
|
||||
addLog(`[${opts.type?.toUpperCase() ?? 'NOTIFY'}] ${opts.title}: ${opts.body}`, 'info'),
|
||||
},
|
||||
registry
|
||||
);
|
||||
|
||||
// Intercept context logging so it appears in the UI panel
|
||||
context.log = (...args) => {
|
||||
console.log('[Plugin example-plugin]', ...args);
|
||||
registry.addLog('example-plugin', 'log', args);
|
||||
addLog(args.map(String).join(' '), 'log');
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Register + load
|
||||
// ---------------------------------------------------------------------------
|
||||
registry.registerPlugin('example-plugin', plugin, context);
|
||||
await plugin.onLoad(context);
|
||||
|
||||
document.getElementById('status-badge').textContent = 'example-plugin loaded';
|
||||
document.getElementById('status-badge').classList.add('loaded');
|
||||
addLog('example-plugin loaded successfully', 'success');
|
||||
|
||||
// Populate registered command list
|
||||
const cmdListEl = document.getElementById('cmd-list');
|
||||
cmdListEl.innerHTML = registry
|
||||
.getCommands()
|
||||
.map(c => `<li><code>/${c.name}</code> — ${c.command.description ?? ''}</li>`)
|
||||
.join('');
|
||||
|
||||
// Render settings form
|
||||
renderSettings();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UI — Commands
|
||||
// ---------------------------------------------------------------------------
|
||||
const cmdInput = document.getElementById('cmd-input');
|
||||
const cmdResult = document.getElementById('cmd-result');
|
||||
|
||||
document.getElementById('cmd-run').addEventListener('click', async () => {
|
||||
const raw = cmdInput.value.trim();
|
||||
if (!raw.startsWith('/')) {
|
||||
addLog('Commands must start with /', 'error');
|
||||
return;
|
||||
}
|
||||
const [name, ...rest] = raw.slice(1).split(' ');
|
||||
try {
|
||||
const result = await registry.executeCommand(name, rest.join(' '));
|
||||
cmdResult.textContent = result ?? '(no output)';
|
||||
addLog(`/${name}: ${result ?? '(no output)'}`, 'success');
|
||||
} catch (err) {
|
||||
cmdResult.textContent = err.message;
|
||||
addLog(err.message, 'error');
|
||||
}
|
||||
cmdInput.value = '';
|
||||
});
|
||||
|
||||
cmdInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') document.getElementById('cmd-run').click();
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UI — Message Interceptor
|
||||
// ---------------------------------------------------------------------------
|
||||
document.getElementById('msg-send').addEventListener('click', async () => {
|
||||
const content = document.getElementById('msg-input').value;
|
||||
const msg = { content, roomId: 'test-room', eventType: 'm.room.message' };
|
||||
const processed = await registry.processBeforeSend(msg);
|
||||
document.getElementById('msg-result').textContent =
|
||||
`Original: "${content}"\nProcessed: "${processed.content}"`;
|
||||
addLog(`Intercepted: "${content}" → "${processed.content}"`, 'log');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UI — Theme
|
||||
// ---------------------------------------------------------------------------
|
||||
document.getElementById('theme-apply').addEventListener('click', () => {
|
||||
const themes = registry.getPluginThemes();
|
||||
if (!themes.length) { addLog('No plugin themes registered', 'error'); return; }
|
||||
const theme = themes[0];
|
||||
document.body.className = theme.className;
|
||||
addLog(`Applied theme: ${theme.name}`, 'success');
|
||||
});
|
||||
|
||||
document.getElementById('theme-reset').addEventListener('click', () => {
|
||||
document.body.className = '';
|
||||
addLog('Theme reset', 'log');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UI — Custom Events
|
||||
// ---------------------------------------------------------------------------
|
||||
document.getElementById('event-fire').addEventListener('click', () => {
|
||||
const payload = { from: 'UI button', timestamp: Date.now() };
|
||||
eventEmitter.emit('test-event', payload);
|
||||
addLog(`Fired test-event with payload: ${JSON.stringify(payload)}`, 'log');
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Settings renderer
|
||||
// ---------------------------------------------------------------------------
|
||||
function renderSettings() {
|
||||
const schema = registry.getPluginSettingsSchema('example-plugin');
|
||||
if (!schema) return;
|
||||
const container = document.getElementById('settings-container');
|
||||
container.innerHTML = '';
|
||||
|
||||
for (const [key, def] of Object.entries(schema)) {
|
||||
const value = registry.getPluginSetting('example-plugin', key);
|
||||
const row = document.createElement('div');
|
||||
row.className = 'setting-row';
|
||||
|
||||
const label = document.createElement('label');
|
||||
label.textContent = def.label ?? key;
|
||||
row.appendChild(label);
|
||||
|
||||
let input;
|
||||
if (def.type === 'boolean') {
|
||||
input = document.createElement('input');
|
||||
input.type = 'checkbox';
|
||||
input.checked = !!value;
|
||||
input.addEventListener('change', () => {
|
||||
registry.setPluginSetting('example-plugin', key, input.checked);
|
||||
addLog(`Setting "${key}" = ${input.checked}`, 'log');
|
||||
});
|
||||
} else if (def.type === 'select') {
|
||||
input = document.createElement('select');
|
||||
(def.options ?? []).forEach((opt) => {
|
||||
const o = document.createElement('option');
|
||||
o.value = opt.value;
|
||||
o.textContent = opt.label;
|
||||
if (opt.value === value) o.selected = true;
|
||||
input.appendChild(o);
|
||||
});
|
||||
input.addEventListener('change', () => {
|
||||
registry.setPluginSetting('example-plugin', key, input.value);
|
||||
addLog(`Setting "${key}" = ${input.value}`, 'log');
|
||||
});
|
||||
} else {
|
||||
input = document.createElement('input');
|
||||
input.type = 'text';
|
||||
input.value = value ?? '';
|
||||
input.addEventListener('change', () => {
|
||||
registry.setPluginSetting('example-plugin', key, input.value);
|
||||
addLog(`Setting "${key}" = "${input.value}"`, 'log');
|
||||
});
|
||||
}
|
||||
|
||||
row.appendChild(input);
|
||||
container.appendChild(row);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user