wiki-plugin-allyabase 0.0.7 → 0.0.9
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/client/allyabase.js +122 -0
- package/package.json +1 -1
- package/server/server.js +146 -50
package/client/allyabase.js
CHANGED
|
@@ -139,6 +139,128 @@ function emit($item, item) {
|
|
|
139
139
|
console.log('[allyabase] Fork detected from:', forkInfo);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
// Add configuration section
|
|
143
|
+
const configContainer = document.createElement('div');
|
|
144
|
+
configContainer.style.padding = '10px';
|
|
145
|
+
configContainer.style.marginBottom = '15px';
|
|
146
|
+
configContainer.style.backgroundColor = '#f0f8ff';
|
|
147
|
+
configContainer.style.borderRadius = '5px';
|
|
148
|
+
configContainer.style.border = '1px solid #cce5ff';
|
|
149
|
+
|
|
150
|
+
const configTitle = document.createElement('div');
|
|
151
|
+
configTitle.style.fontWeight = 'bold';
|
|
152
|
+
configTitle.style.marginBottom = '10px';
|
|
153
|
+
configTitle.textContent = '⚙️ Configuration';
|
|
154
|
+
configContainer.appendChild(configTitle);
|
|
155
|
+
|
|
156
|
+
// Location Emoji Input
|
|
157
|
+
const locationLabel = document.createElement('div');
|
|
158
|
+
locationLabel.style.fontSize = '12px';
|
|
159
|
+
locationLabel.style.marginBottom = '4px';
|
|
160
|
+
locationLabel.textContent = 'Location Emoji (3 emoji):';
|
|
161
|
+
configContainer.appendChild(locationLabel);
|
|
162
|
+
|
|
163
|
+
const locationInput = document.createElement('input');
|
|
164
|
+
locationInput.type = 'text';
|
|
165
|
+
locationInput.id = 'location-emoji-input';
|
|
166
|
+
locationInput.style.width = '200px';
|
|
167
|
+
locationInput.style.padding = '5px';
|
|
168
|
+
locationInput.style.fontSize = '16px';
|
|
169
|
+
locationInput.style.marginBottom = '10px';
|
|
170
|
+
locationInput.placeholder = 'e.g., 🔥💎🌟';
|
|
171
|
+
configContainer.appendChild(locationInput);
|
|
172
|
+
|
|
173
|
+
// Federation Emoji Input
|
|
174
|
+
const federationLabel = document.createElement('div');
|
|
175
|
+
federationLabel.style.fontSize = '12px';
|
|
176
|
+
federationLabel.style.marginBottom = '4px';
|
|
177
|
+
federationLabel.textContent = 'Federation Emoji (1 emoji):';
|
|
178
|
+
configContainer.appendChild(federationLabel);
|
|
179
|
+
|
|
180
|
+
const federationInput = document.createElement('input');
|
|
181
|
+
federationInput.type = 'text';
|
|
182
|
+
federationInput.id = 'federation-emoji-input';
|
|
183
|
+
federationInput.style.width = '200px';
|
|
184
|
+
federationInput.style.padding = '5px';
|
|
185
|
+
federationInput.style.fontSize = '16px';
|
|
186
|
+
federationInput.style.marginBottom = '10px';
|
|
187
|
+
federationInput.placeholder = 'e.g., 💚';
|
|
188
|
+
federationInput.value = '💚';
|
|
189
|
+
configContainer.appendChild(federationInput);
|
|
190
|
+
|
|
191
|
+
// Save button
|
|
192
|
+
const saveConfigBtn = document.createElement('button');
|
|
193
|
+
saveConfigBtn.textContent = 'Save Configuration';
|
|
194
|
+
saveConfigBtn.style.padding = '8px 15px';
|
|
195
|
+
saveConfigBtn.style.fontSize = '12px';
|
|
196
|
+
saveConfigBtn.style.cursor = 'pointer';
|
|
197
|
+
saveConfigBtn.style.marginTop = '5px';
|
|
198
|
+
saveConfigBtn.style.backgroundColor = '#4CAF50';
|
|
199
|
+
saveConfigBtn.style.color = 'white';
|
|
200
|
+
saveConfigBtn.style.border = 'none';
|
|
201
|
+
saveConfigBtn.style.borderRadius = '4px';
|
|
202
|
+
configContainer.appendChild(saveConfigBtn);
|
|
203
|
+
|
|
204
|
+
// Config status message
|
|
205
|
+
const configStatus = document.createElement('div');
|
|
206
|
+
configStatus.id = 'config-status';
|
|
207
|
+
configStatus.style.fontSize = '11px';
|
|
208
|
+
configStatus.style.marginTop = '8px';
|
|
209
|
+
configStatus.style.minHeight = '16px';
|
|
210
|
+
configContainer.appendChild(configStatus);
|
|
211
|
+
|
|
212
|
+
container.appendChild(configContainer);
|
|
213
|
+
|
|
214
|
+
// Load current configuration
|
|
215
|
+
async function loadConfig() {
|
|
216
|
+
try {
|
|
217
|
+
const response = await get('/plugin/allyabase/config');
|
|
218
|
+
const data = await response.json();
|
|
219
|
+
if (data.success && data.config) {
|
|
220
|
+
locationInput.value = data.config.locationEmoji || '';
|
|
221
|
+
federationInput.value = data.config.federationEmoji || '💚';
|
|
222
|
+
}
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.error('[allyabase] Error loading config:', err);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Save configuration
|
|
229
|
+
saveConfigBtn.addEventListener('click', async () => {
|
|
230
|
+
try {
|
|
231
|
+
configStatus.textContent = 'Saving...';
|
|
232
|
+
configStatus.style.color = '#666';
|
|
233
|
+
|
|
234
|
+
const response = await post('/plugin/allyabase/config', {
|
|
235
|
+
locationEmoji: locationInput.value.trim(),
|
|
236
|
+
federationEmoji: federationInput.value.trim() || '💚'
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
const result = await response.json();
|
|
240
|
+
|
|
241
|
+
if (result.success) {
|
|
242
|
+
configStatus.textContent = '✓ Configuration saved successfully!';
|
|
243
|
+
configStatus.style.color = 'green';
|
|
244
|
+
// Reload base emoji display
|
|
245
|
+
loadBaseEmoji();
|
|
246
|
+
} else {
|
|
247
|
+
configStatus.textContent = `✗ Error: ${result.error}`;
|
|
248
|
+
configStatus.style.color = 'red';
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
configStatus.textContent = '';
|
|
253
|
+
}, 3000);
|
|
254
|
+
} catch (err) {
|
|
255
|
+
console.error('[allyabase] Error saving config:', err);
|
|
256
|
+
configStatus.textContent = `✗ Error: ${err.message}`;
|
|
257
|
+
configStatus.style.color = 'red';
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Load config on initialization
|
|
262
|
+
loadConfig();
|
|
263
|
+
|
|
142
264
|
// Add base emoji identifier section
|
|
143
265
|
const baseEmojiContainer = document.createElement('div');
|
|
144
266
|
baseEmojiContainer.style.padding = '10px';
|
package/package.json
CHANGED
package/server/server.js
CHANGED
|
@@ -29,6 +29,9 @@ const SERVICE_PORTS = {
|
|
|
29
29
|
// PID file for tracking PM2 process
|
|
30
30
|
const PM2_PID_FILE = path.join(__dirname, 'allyabase-pm2.pid');
|
|
31
31
|
|
|
32
|
+
// Plugin configuration file (stores locationEmoji, federationEmoji, etc.)
|
|
33
|
+
const CONFIG_FILE = path.join(__dirname, 'plugin-config.json');
|
|
34
|
+
|
|
32
35
|
let baseStatus = {
|
|
33
36
|
running: false,
|
|
34
37
|
services: {},
|
|
@@ -37,7 +40,38 @@ let baseStatus = {
|
|
|
37
40
|
|
|
38
41
|
let allyabaseProcess = null;
|
|
39
42
|
|
|
40
|
-
//
|
|
43
|
+
// Load plugin configuration (locationEmoji, federationEmoji, etc.)
|
|
44
|
+
function loadPluginConfig() {
|
|
45
|
+
try {
|
|
46
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
47
|
+
return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
|
|
48
|
+
}
|
|
49
|
+
// Return defaults if no config file exists
|
|
50
|
+
return {
|
|
51
|
+
locationEmoji: null,
|
|
52
|
+
federationEmoji: '💚'
|
|
53
|
+
};
|
|
54
|
+
} catch (err) {
|
|
55
|
+
console.error('[wiki-plugin-allyabase] Error loading plugin config:', err);
|
|
56
|
+
return {
|
|
57
|
+
locationEmoji: null,
|
|
58
|
+
federationEmoji: '💚'
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Save plugin configuration
|
|
64
|
+
function savePluginConfig(config) {
|
|
65
|
+
try {
|
|
66
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf8');
|
|
67
|
+
return true;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error('[wiki-plugin-allyabase] Error saving plugin config:', err);
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Function to load wiki's sessionless keys from owner.json (authentication only)
|
|
41
75
|
function loadWikiKeypair() {
|
|
42
76
|
try {
|
|
43
77
|
const ownerPath = path.join(process.env.HOME || '/root', '.wiki/status/owner.json');
|
|
@@ -46,9 +80,7 @@ function loadWikiKeypair() {
|
|
|
46
80
|
if (ownerData.sessionlessKeys) {
|
|
47
81
|
return {
|
|
48
82
|
pubKey: ownerData.sessionlessKeys.pubKey,
|
|
49
|
-
privateKey: ownerData.sessionlessKeys.privateKey
|
|
50
|
-
locationEmoji: ownerData.locationEmoji,
|
|
51
|
-
federationEmoji: ownerData.federationEmoji
|
|
83
|
+
privateKey: ownerData.sessionlessKeys.privateKey
|
|
52
84
|
};
|
|
53
85
|
}
|
|
54
86
|
}
|
|
@@ -121,17 +153,17 @@ function killProcessByPort(port) {
|
|
|
121
153
|
});
|
|
122
154
|
}
|
|
123
155
|
|
|
124
|
-
// Function to stop PM2
|
|
156
|
+
// Function to stop PM2-managed allyabase services (not the daemon itself,
|
|
157
|
+
// since wiki may also be running under PM2)
|
|
125
158
|
async function stopPM2() {
|
|
126
|
-
console.log('[wiki-plugin-allyabase] Stopping
|
|
159
|
+
console.log('[wiki-plugin-allyabase] Stopping allyabase services...');
|
|
127
160
|
|
|
128
161
|
return new Promise((resolve) => {
|
|
129
|
-
|
|
130
|
-
exec('pm2 kill', (err, stdout, stderr) => {
|
|
162
|
+
exec('pm2 stop all', (err, stdout, stderr) => {
|
|
131
163
|
if (err) {
|
|
132
|
-
console.log(`[wiki-plugin-allyabase]
|
|
164
|
+
console.log(`[wiki-plugin-allyabase] pm2 stop all failed (might not be running): ${err.message}`);
|
|
133
165
|
} else {
|
|
134
|
-
console.log(`[wiki-plugin-allyabase]
|
|
166
|
+
console.log(`[wiki-plugin-allyabase] Allyabase services stopped`);
|
|
135
167
|
}
|
|
136
168
|
|
|
137
169
|
// Clean up PID file
|
|
@@ -521,8 +553,8 @@ async function startServer(params) {
|
|
|
521
553
|
if (targetWikiUrls && targetWikiUrls.length > 0) {
|
|
522
554
|
// This is a cross-wiki request - try all registered URLs
|
|
523
555
|
const currentWikiUrl = `http://localhost:${req.socket.localPort}`;
|
|
524
|
-
const
|
|
525
|
-
const thisWikiLocationEmoji =
|
|
556
|
+
const config = loadPluginConfig();
|
|
557
|
+
const thisWikiLocationEmoji = config.locationEmoji;
|
|
526
558
|
|
|
527
559
|
console.log('[BDO EMOJI] Cross-wiki request detected');
|
|
528
560
|
console.log('[BDO EMOJI] Target wikis (${targetWikiUrls.length}): ${targetWikiUrls.join(', ')}');
|
|
@@ -751,58 +783,122 @@ async function startServer(params) {
|
|
|
751
783
|
res.send(baseStatus);
|
|
752
784
|
});
|
|
753
785
|
|
|
754
|
-
// Endpoint to get wiki's base emoji identifier
|
|
786
|
+
// Endpoint to get wiki's base emoji identifier (from plugin config)
|
|
755
787
|
app.get('/plugin/allyabase/base-emoji', function(req, res) {
|
|
756
788
|
try {
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
const ownerData = JSON.parse(fs.readFileSync(ownerPath, 'utf8'));
|
|
760
|
-
|
|
761
|
-
const response = {
|
|
762
|
-
federationEmoji: ownerData.federationEmoji || '💚',
|
|
763
|
-
locationEmoji: ownerData.locationEmoji || null,
|
|
764
|
-
baseEmoji: (ownerData.federationEmoji || '💚') + (ownerData.locationEmoji || ''),
|
|
765
|
-
warnings: []
|
|
766
|
-
};
|
|
789
|
+
const config = loadPluginConfig();
|
|
790
|
+
const keypair = loadWikiKeypair();
|
|
767
791
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
792
|
+
const response = {
|
|
793
|
+
federationEmoji: config.federationEmoji || '💚',
|
|
794
|
+
locationEmoji: config.locationEmoji || null,
|
|
795
|
+
baseEmoji: (config.federationEmoji || '💚') + (config.locationEmoji || ''),
|
|
796
|
+
warnings: []
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
// Validation warnings
|
|
800
|
+
if (!config.locationEmoji) {
|
|
801
|
+
response.warnings.push({
|
|
802
|
+
severity: 'error',
|
|
803
|
+
message: 'Location emoji not configured',
|
|
804
|
+
fix: 'Set your 3-emoji location identifier in the plugin settings'
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
if (!keypair || !keypair.pubKey) {
|
|
809
|
+
response.warnings.push({
|
|
810
|
+
severity: 'error',
|
|
811
|
+
message: 'Missing sessionless keys in owner.json',
|
|
812
|
+
fix: 'BDO operations will fail without sessionless keys in ~/.wiki/status/owner.json'
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
res.send(response);
|
|
817
|
+
} catch (err) {
|
|
818
|
+
console.error('Error reading base emoji config:', err);
|
|
819
|
+
res.status(500).send({
|
|
820
|
+
error: 'Failed to load base emoji',
|
|
821
|
+
message: err.message
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
// Endpoint to get plugin configuration
|
|
827
|
+
app.get('/plugin/allyabase/config', function(req, res) {
|
|
828
|
+
try {
|
|
829
|
+
const config = loadPluginConfig();
|
|
830
|
+
res.send({
|
|
831
|
+
success: true,
|
|
832
|
+
config: config
|
|
833
|
+
});
|
|
834
|
+
} catch (err) {
|
|
835
|
+
console.error('Error loading plugin config:', err);
|
|
836
|
+
res.status(500).send({
|
|
837
|
+
success: false,
|
|
838
|
+
error: 'Failed to load configuration',
|
|
839
|
+
message: err.message
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
// Endpoint to save plugin configuration (requires owner auth)
|
|
845
|
+
app.post('/plugin/allyabase/config', owner, function(req, res) {
|
|
846
|
+
try {
|
|
847
|
+
const { locationEmoji, federationEmoji } = req.body;
|
|
848
|
+
|
|
849
|
+
// Validate locationEmoji (should be exactly 3 emoji)
|
|
850
|
+
if (locationEmoji) {
|
|
851
|
+
const emojiRegex = /[\u{1F1E6}-\u{1F1FF}]{2}|(?:[\u{1F3F4}\u{1F3F3}][\u{FE0F}]?(?:\u{200D}[\u{2620}\u{2695}\u{2696}\u{2708}\u{1F308}][\u{FE0F}]?)?)|(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\u{200D}(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F))*/gu;
|
|
852
|
+
const emojis = locationEmoji.match(emojiRegex) || [];
|
|
853
|
+
|
|
854
|
+
if (emojis.length !== 3) {
|
|
855
|
+
return res.status(400).send({
|
|
856
|
+
success: false,
|
|
857
|
+
error: 'Location emoji must be exactly 3 emoji characters',
|
|
858
|
+
got: emojis.length
|
|
780
859
|
});
|
|
781
860
|
}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Validate federationEmoji (should be exactly 1 emoji)
|
|
864
|
+
if (federationEmoji) {
|
|
865
|
+
const emojiRegex = /[\u{1F1E6}-\u{1F1FF}]{2}|(?:[\u{1F3F4}\u{1F3F3}][\u{FE0F}]?(?:\u{200D}[\u{2620}\u{2695}\u{2696}\u{2708}\u{1F308}][\u{FE0F}]?)?)|(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)(?:\u{200D}(?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F))*/gu;
|
|
866
|
+
const emojis = federationEmoji.match(emojiRegex) || [];
|
|
782
867
|
|
|
783
|
-
if (
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
868
|
+
if (emojis.length !== 1) {
|
|
869
|
+
return res.status(400).send({
|
|
870
|
+
success: false,
|
|
871
|
+
error: 'Federation emoji must be exactly 1 emoji character',
|
|
872
|
+
got: emojis.length
|
|
788
873
|
});
|
|
789
874
|
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const config = loadPluginConfig();
|
|
878
|
+
|
|
879
|
+
// Update config with provided values
|
|
880
|
+
if (locationEmoji !== undefined) config.locationEmoji = locationEmoji;
|
|
881
|
+
if (federationEmoji !== undefined) config.federationEmoji = federationEmoji;
|
|
790
882
|
|
|
791
|
-
|
|
883
|
+
const saved = savePluginConfig(config);
|
|
884
|
+
|
|
885
|
+
if (saved) {
|
|
886
|
+
res.send({
|
|
887
|
+
success: true,
|
|
888
|
+
config: config,
|
|
889
|
+
message: 'Configuration saved successfully'
|
|
890
|
+
});
|
|
792
891
|
} else {
|
|
793
|
-
res.status(
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
severity: 'error',
|
|
797
|
-
message: 'owner.json file not found',
|
|
798
|
-
fix: 'Create ~/.wiki/status/owner.json with locationEmoji and sessionlessKeys'
|
|
799
|
-
}]
|
|
892
|
+
res.status(500).send({
|
|
893
|
+
success: false,
|
|
894
|
+
error: 'Failed to save configuration'
|
|
800
895
|
});
|
|
801
896
|
}
|
|
802
897
|
} catch (err) {
|
|
803
|
-
console.error('Error
|
|
898
|
+
console.error('Error saving plugin config:', err);
|
|
804
899
|
res.status(500).send({
|
|
805
|
-
|
|
900
|
+
success: false,
|
|
901
|
+
error: 'Failed to save configuration',
|
|
806
902
|
message: err.message
|
|
807
903
|
});
|
|
808
904
|
}
|