wiki-plugin-lucille 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client/lucille.js CHANGED
@@ -22,52 +22,16 @@ window.plugins.lucille = (function() {
22
22
  const price = item.price || 0;
23
23
  const playerBase = item.playerBase || '/plugin/lucille';
24
24
 
25
- // Check owner status and render config section if owner
25
+ // Check owner status and render setup dashboard if owner
26
26
  fetch('/plugin/lucille/setup/status', { credentials: 'include' })
27
27
  .then(r => r.json())
28
28
  .then(data => {
29
29
  if (!data.isOwner) return;
30
- const configDiv = document.createElement('div');
31
- configDiv.style.cssText = 'border:1px solid rgba(167,139,250,0.3);border-radius:8px;padding:12px;margin-top:8px;background:rgba(167,139,250,0.06);font-family:system-ui;';
32
- const stripeStatus = data.stripeOnboarded
33
- ? '<span style="color:#0e0;font-size:0.75rem;">✅ Stripe payouts enabled</span>'
34
- : data.serverAddieReady
35
- ? '<a href="/plugin/lucille/setup/stripe" target="_blank" style="color:#fb0;font-size:0.75rem;">⚠️ Complete Stripe setup →</a>'
36
- : '';
37
- configDiv.innerHTML = `
38
- <div style="font-size:0.8rem;color:#a78bfa;margin-bottom:8px;font-weight:600;">Allyabase connection (owner only)</div>
39
- <div style="display:flex;gap:6px;align-items:center;">
40
- <input id="luc-url-input" value="${escapeHtml(data.allyabaseUrl || '')}" placeholder="https://dev.allyabase.com"
41
- style="flex:1;background:#0d001a;border:1px solid rgba(167,139,250,0.3);border-radius:4px;padding:6px 8px;color:#e0d0ff;font-size:0.8rem;">
42
- <button id="luc-url-btn"
43
- style="background:#7c3aed;border:none;border-radius:4px;padding:6px 12px;color:white;cursor:pointer;font-size:0.8rem;white-space:nowrap;">
44
- Save
45
- </button>
46
- </div>
47
- <div id="luc-url-status" style="margin-top:6px;font-size:0.75rem;"></div>
48
- ${stripeStatus ? '<div style="margin-top:6px;">' + stripeStatus + '</div>' : ''}`;
49
- $item.append(configDiv);
50
- configDiv.querySelector('#luc-url-btn').addEventListener('click', function() {
51
- const input = configDiv.querySelector('#luc-url-input');
52
- const btn = configDiv.querySelector('#luc-url-btn');
53
- const status = configDiv.querySelector('#luc-url-status');
54
- const base = (input.value || '').trim().replace(/\/$/, '');
55
- if (!base) { status.textContent = 'Enter an allyabase URL first'; return; }
56
- btn.disabled = true; btn.textContent = 'Saving…';
57
- fetch('/plugin/lucille/setup', {
58
- method: 'POST',
59
- credentials: 'include',
60
- headers: { 'Content-Type': 'application/json' },
61
- body: JSON.stringify({ allyabaseUrl: base })
62
- })
63
- .then(r => r.json())
64
- .then(d => {
65
- if (d.error) { status.innerHTML = '<span style="color:#f55;">' + escapeHtml(d.error) + '</span>'; return; }
66
- status.innerHTML = '<span style="color:#0e0;">Saved</span>';
67
- })
68
- .catch(e => { status.innerHTML = '<span style="color:#f55;">' + escapeHtml(e.message) + '</span>'; })
69
- .finally(() => { btn.disabled = false; btn.textContent = 'Save'; });
70
- });
30
+ const panel = document.createElement('div');
31
+ panel.style.cssText = 'font-family:system-ui;margin-top:8px;';
32
+ panel.innerHTML = lucilleOwnerHTML(data);
33
+ $item.append(panel);
34
+ attachLucilleOwnerListeners(panel, data);
71
35
  })
72
36
  .catch(() => {});
73
37
 
@@ -160,6 +124,156 @@ window.plugins.lucille = (function() {
160
124
  });
161
125
  }
162
126
 
127
+ // ── Owner dashboard ───────────────────────────────────────────────────────
128
+
129
+ function dot(ok, warn) {
130
+ const c = ok ? '#0e0' : warn ? '#fb0' : '#f55';
131
+ return `<span style="color:${c};font-size:14px;line-height:1;">●</span>`;
132
+ }
133
+
134
+ function lucilleOwnerHTML(d) {
135
+ const spacesOk = d.hasSpacesKey && d.spacesBucket;
136
+ const spacesLabel = spacesOk
137
+ ? `${escapeHtml(d.spacesRegion)} / <strong>${escapeHtml(d.spacesBucket)}</strong>${d.hasCdnEndpoint ? ' + CDN' : ''}`
138
+ : 'Not configured';
139
+ const trackerOk = !!d.trackerHost;
140
+ const trackerLabel = trackerOk
141
+ ? `ws://${escapeHtml(d.trackerHost)}:${d.trackerPort}`
142
+ : 'No public hostname set';
143
+
144
+ const allyOk = !!d.allyabaseUrl;
145
+ const stripeOk = d.stripeOnboarded;
146
+ const addiePending = d.serverAddieReady && !stripeOk;
147
+
148
+ const serviceColor = d.running ? '#0e0' : d.configured ? '#fb0' : '#f55';
149
+ const serviceLabel = d.running ? 'Running' : d.configured ? 'Stopped — restart wiki' : 'Not configured';
150
+
151
+ return `
152
+ <div style="border:2px solid #7c3aed;border-radius:10px;padding:14px;background:#0d001a;color:#e0d0ff;">
153
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
154
+ <span style="font-size:1rem;">🎬</span>
155
+ <strong style="color:#a78bfa;font-size:0.95rem;">Lucille</strong>
156
+ <span style="margin-left:auto;font-size:0.7rem;color:#5a3080;background:rgba(124,58,237,.15);border:1px solid rgba(124,58,237,.3);border-radius:4px;padding:2px 6px;">owner</span>
157
+ </div>
158
+
159
+ <!-- Service status -->
160
+ <div style="background:rgba(167,139,250,0.06);border:1px solid rgba(167,139,250,0.15);border-radius:6px;padding:8px 12px;margin-bottom:12px;font-size:0.82rem;">
161
+ <span style="color:#7060a0;">Service: </span>
162
+ <span style="color:${serviceColor};font-weight:600;">${dot(d.running, d.configured)} ${serviceLabel}</span>
163
+ </div>
164
+
165
+ <!-- Config checklist -->
166
+ <div style="font-size:0.8rem;margin-bottom:12px;">
167
+
168
+ <!-- DO Spaces row -->
169
+ <div style="display:flex;align-items:baseline;gap:8px;padding:6px 0;border-bottom:1px solid rgba(90,48,128,0.25);">
170
+ <span style="flex:0 0 14px;">${dot(spacesOk)}</span>
171
+ <span style="color:#a080d0;flex:0 0 110px;">DO Spaces</span>
172
+ <span style="color:${spacesOk ? '#c89aff' : '#7060a0'};">${spacesLabel}</span>
173
+ <a href="/plugin/lucille/setup" target="_blank"
174
+ style="margin-left:auto;color:#7c3aed;font-size:0.72rem;white-space:nowrap;text-decoration:none;">
175
+ ${spacesOk ? 'Edit ↗' : 'Configure ↗'}
176
+ </a>
177
+ </div>
178
+
179
+ <!-- Tracker row -->
180
+ <div style="display:flex;align-items:baseline;gap:8px;padding:6px 0;border-bottom:1px solid rgba(90,48,128,0.25);">
181
+ <span style="flex:0 0 14px;">${dot(trackerOk, true)}</span>
182
+ <span style="color:#a080d0;flex:0 0 110px;">Tracker</span>
183
+ <span style="color:${trackerOk ? '#c89aff' : '#7060a0'};">${trackerLabel}</span>
184
+ <a href="/plugin/lucille/setup" target="_blank"
185
+ style="margin-left:auto;color:#7c3aed;font-size:0.72rem;white-space:nowrap;text-decoration:none;">
186
+ ${trackerOk ? 'Edit ↗' : 'Configure ↗'}
187
+ </a>
188
+ </div>
189
+
190
+ <!-- Allyabase row -->
191
+ <div style="padding:6px 0;border-bottom:1px solid rgba(90,48,128,0.25);">
192
+ <div style="display:flex;align-items:center;gap:8px;margin-bottom:${allyOk ? 0 : 6}px;">
193
+ <span style="flex:0 0 14px;">${dot(allyOk)}</span>
194
+ <span style="color:#a080d0;flex:0 0 110px;">Allyabase</span>
195
+ ${allyOk
196
+ ? `<span style="color:#c89aff;font-size:0.78rem;">${escapeHtml(d.allyabaseUrl)}</span>`
197
+ : '<span style="color:#7060a0;">Not set</span>'
198
+ }
199
+ </div>
200
+ ${!allyOk ? `
201
+ <div style="display:flex;gap:6px;margin-top:4px;padding-left:22px;">
202
+ <input id="luc-url-input" value="" placeholder="https://dev.allyabase.com"
203
+ style="flex:1;background:#1a0033;border:1px solid #5a3080;border-radius:4px;padding:5px 8px;color:#e0d0ff;font-size:0.78rem;">
204
+ <button id="luc-url-btn"
205
+ style="background:#7c3aed;border:none;border-radius:4px;padding:5px 10px;color:white;cursor:pointer;font-size:0.78rem;white-space:nowrap;">
206
+ Save
207
+ </button>
208
+ </div>
209
+ <div id="luc-url-status" style="margin-top:4px;font-size:0.72rem;padding-left:22px;min-height:1em;"></div>` : `
210
+ <div style="display:flex;gap:6px;margin-top:4px;padding-left:22px;">
211
+ <input id="luc-url-input" value="${escapeHtml(d.allyabaseUrl)}" placeholder="https://dev.allyabase.com"
212
+ style="flex:1;background:#1a0033;border:1px solid #5a3080;border-radius:4px;padding:5px 8px;color:#e0d0ff;font-size:0.78rem;">
213
+ <button id="luc-url-btn"
214
+ style="background:#5a3080;border:none;border-radius:4px;padding:5px 10px;color:#c89aff;cursor:pointer;font-size:0.78rem;white-space:nowrap;">
215
+ Update
216
+ </button>
217
+ </div>
218
+ <div id="luc-url-status" style="margin-top:4px;font-size:0.72rem;padding-left:22px;min-height:1em;"></div>`}
219
+ </div>
220
+
221
+ <!-- Stripe row -->
222
+ <div style="display:flex;align-items:center;gap:8px;padding:6px 0;">
223
+ <span style="flex:0 0 14px;">${dot(stripeOk, addiePending)}</span>
224
+ <span style="color:#a080d0;flex:0 0 110px;">Stripe</span>
225
+ ${stripeOk
226
+ ? '<span style="color:#0e0;font-size:0.78rem;">Payouts enabled — tier upgrades will pay you</span>'
227
+ : addiePending
228
+ ? `<a href="/plugin/lucille/setup/stripe" target="_blank"
229
+ style="color:#fbbf24;font-size:0.78rem;text-decoration:none;">
230
+ ⚠️ Complete Stripe onboarding →
231
+ </a>`
232
+ : '<span style="color:#7060a0;font-size:0.78rem;">Save Allyabase URL first</span>'
233
+ }
234
+ </div>
235
+
236
+ </div>
237
+
238
+ <!-- Full setup link -->
239
+ <a href="/plugin/lucille/setup" target="_blank"
240
+ style="display:block;text-align:center;padding:7px;background:rgba(124,58,237,.2);border:1px solid rgba(124,58,237,.4);border-radius:6px;color:#c89aff;font-size:0.8rem;font-weight:600;text-decoration:none;">
241
+ Open full setup page ↗
242
+ </a>
243
+ <div style="margin-top:8px;font-size:0.72rem;color:#5a3080;text-align:center;">
244
+ DO Spaces credentials, tiers, federation peers, and tracker config are all on the setup page.
245
+ </div>
246
+ </div>`;
247
+ }
248
+
249
+ function attachLucilleOwnerListeners(panel, data) {
250
+ const urlBtn = panel.querySelector('#luc-url-btn');
251
+ if (!urlBtn) return;
252
+ urlBtn.addEventListener('click', function() {
253
+ const input = panel.querySelector('#luc-url-input');
254
+ const status = panel.querySelector('#luc-url-status');
255
+ const base = (input.value || '').trim().replace(/\/$/, '');
256
+ if (!base) { status.textContent = 'Enter a URL first.'; return; }
257
+ urlBtn.disabled = true; urlBtn.textContent = 'Saving…';
258
+ fetch('/plugin/lucille/setup', {
259
+ method: 'POST', credentials: 'include',
260
+ headers: { 'Content-Type': 'application/json' },
261
+ body: JSON.stringify({ allyabaseUrl: base })
262
+ })
263
+ .then(r => r.json())
264
+ .then(d => {
265
+ if (d.error) { status.innerHTML = '<span style="color:#f55;">' + escapeHtml(d.error) + '</span>'; return; }
266
+ status.innerHTML = '<span style="color:#0e0;">✅ Saved</span>';
267
+ // Re-fetch and re-render
268
+ fetch('/plugin/lucille/setup/status', { credentials: 'include' })
269
+ .then(r => r.json())
270
+ .then(fresh => { if (fresh.isOwner) { panel.innerHTML = lucilleOwnerHTML(fresh); attachLucilleOwnerListeners(panel, fresh); } });
271
+ })
272
+ .catch(e => { status.innerHTML = '<span style="color:#f55;">' + escapeHtml(e.message) + '</span>'; })
273
+ .finally(() => { urlBtn.disabled = false; urlBtn.textContent = data.allyabaseUrl ? 'Update' : 'Save'; });
274
+ });
275
+ }
276
+
163
277
  // ── Helpers ───────────────────────────────────────────────────────────────
164
278
  function escapeHtml(str) {
165
279
  return String(str).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-lucille",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Federated Wiki plugin — P2P video hosting via Lucille (WebTorrent + DO Spaces)",
5
5
  "keywords": ["wiki", "plugin", "video", "webtorrent", "planet-nine"],
6
6
  "author": "Planet Nine",
package/server/server.js CHANGED
@@ -775,9 +775,18 @@ async function startServer(params) {
775
775
  tiers: cfg.tiers,
776
776
  federationPeers: cfg.federationPeers,
777
777
  isOwner,
778
- allyabaseUrl: isOwner ? allyabaseUrl : undefined,
779
- serverAddieReady: isOwner ? !!(cfg.serverAddie && cfg.serverAddie.uuid) : undefined,
780
- stripeOnboarded: isOwner ? !!cfg.stripeOnboarded : undefined
778
+ // Owner-only fields
779
+ ...(isOwner && {
780
+ allyabaseUrl,
781
+ serverAddieReady: !!(cfg.serverAddie && cfg.serverAddie.uuid),
782
+ stripeOnboarded: !!cfg.stripeOnboarded,
783
+ hasSpacesKey: !!cfg.spacesKey,
784
+ spacesBucket: cfg.spacesBucket || '',
785
+ spacesRegion: cfg.spacesRegion || 'nyc3',
786
+ trackerHost: cfg.trackerHost || '',
787
+ trackerPort: cfg.trackerPort || 8000,
788
+ hasCdnEndpoint: !!cfg.spacesCdnEndpoint
789
+ })
781
790
  });
782
791
  });
783
792