nixamp 0.7.25 → 0.7.26

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/dist/admin.d.ts CHANGED
@@ -39,6 +39,14 @@ export interface AdminOptions {
39
39
  label: string;
40
40
  url: string;
41
41
  }[];
42
+ /**
43
+ * The key that only watches, when this server has one.
44
+ *
45
+ * The links built from it are the ones to hand other people. Absent when
46
+ * pointed at a server by hand, since a listening key is not something you
47
+ * can work out from a control one.
48
+ */
49
+ listenKey?: string | null;
42
50
  /** What it is serving, so the admin view says so without being asked. */
43
51
  source: string;
44
52
  }
@@ -76,6 +84,8 @@ export interface View {
76
84
  url: string;
77
85
  }[];
78
86
  key: string | null;
87
+ /** The key that only watches, for the links you hand to other people. */
88
+ listenKey?: string | null;
79
89
  source: string;
80
90
  }
81
91
  export declare function draw(ui: Container, theme: Theme, view: View): void;
package/dist/admin.js CHANGED
@@ -39,6 +39,7 @@ export function resolveTarget(argv) {
39
39
  return {
40
40
  url: url_,
41
41
  key: key ?? state.key,
42
+ ...(state.listenKey ? { listenKey: state.listenKey } : {}),
42
43
  // A state file written before 0.5.3 has no list; loopback stands in.
43
44
  links: state.urls ?? [{ label: "here", url: daemonUrl(state) }],
44
45
  source: state.source,
@@ -176,7 +177,7 @@ export async function admin(argv) {
176
177
  app.on("exit", () => clearInterval(timer));
177
178
  app.render(({ ui, theme }) => draw(ui, theme, {
178
179
  url: target.url, report, snapshot, error, typing, restreaming, replacing,
179
- links: target.links, key: target.key, source: target.source,
180
+ links: target.links, key: target.key, listenKey: target.listenKey, source: target.source,
180
181
  }));
181
182
  await app.start();
182
183
  clearInterval(timer);
@@ -229,13 +230,31 @@ export function draw(ui, theme, view) {
229
230
  // reach it. The key is on them: without it every address is a 401.
230
231
  if (view.links.length > 0) {
231
232
  const width = Math.max(...view.links.map((link) => link.label.length));
232
- ui.panel({ title: "Share links", size: view.links.length + (view.source ? 3 : 2) }, (p) => {
233
+ // Both kinds, labelled, because they are not interchangeable and the
234
+ // operator had only ever been shown the one that drives. Handing that to
235
+ // somebody who wanted to watch hands them the controls with it, and
236
+ // there was nothing else to hand them.
237
+ // Counted rather than guessed: a heading of its own, the links, the second
238
+ // heading and its links when there is a viewing key, the source, and the
239
+ // two borders. A panel one line short silently drops the last row.
240
+ const rows = 1 + view.links.length
241
+ + (view.listenKey ? 1 + view.links.length : 0)
242
+ + (view.source ? 1 : 0);
243
+ ui.panel({ title: "Your links, and the ones to share", size: rows + 2 }, (p) => {
244
+ p.label("Yours -- these administer this server:");
233
245
  for (const link of view.links) {
234
- const full = shareLink(link.url, view.key);
235
- p.text(`${link.label.padEnd(width)} ${full}`, {
246
+ p.text(`${link.label.padEnd(width)} ${shareLink(link.url, view.key)}`, {
236
247
  fg: link.label === "on the internet" ? theme.accent : theme.foreground,
237
248
  });
238
249
  }
250
+ if (view.listenKey) {
251
+ p.label("To share -- these watch and listen, and change nothing:");
252
+ for (const link of view.links) {
253
+ p.text(`${link.label.padEnd(width)} ${shareLink(link.url, view.listenKey, false)}`, {
254
+ fg: link.label === "on the internet" ? theme.accent : theme.foreground,
255
+ });
256
+ }
257
+ }
239
258
  if (view.source)
240
259
  p.label(view.source);
241
260
  });
package/dist/daemon.d.ts CHANGED
@@ -4,6 +4,13 @@ export interface DaemonState {
4
4
  port: number;
5
5
  /** The share key, so `nixamp admin` can talk to it without being told. */
6
6
  key: string | null;
7
+ /**
8
+ * The key that only views, for handing to somebody who should watch.
9
+ *
10
+ * Absent on a state file written by an older nixamp, and absent on a server
11
+ * running with no key at all.
12
+ */
13
+ listenKey?: string | null;
7
14
  source: string;
8
15
  startedAt: number;
9
16
  /** Where its output went, for when it died and you want to know why. */
package/dist/daemon.js CHANGED
@@ -121,8 +121,11 @@ function spell(ms) {
121
121
  * typed the command.
122
122
  */
123
123
  export function daemonLines(state, uptimeMs) {
124
- // The daemon's own key is the one that administers, so it is an /a/ link.
124
+ // Two links per address: the one that drives this server and the one that
125
+ // only watches it. Printing just the first left the operator with nothing to
126
+ // hand anybody -- and handing over the wrong one hands over the controls.
125
127
  const link = (url) => shareLink(url, state.key ?? null);
128
+ const viewLink = (url) => shareLink(url, state.listenKey ?? null, false);
126
129
  // A state file written by an older nixamp has no list, so host and port
127
130
  // still stand in rather than printing nothing at all.
128
131
  const addresses = state.urls ?? [{ label: "here", url: daemonUrl(state) }];
@@ -131,6 +134,15 @@ export function daemonLines(state, uptimeMs) {
131
134
  for (const { label, url } of addresses)
132
135
  lines.push(` ${label.padEnd(width)} ${link(url)}`);
133
136
  lines.push(` ${"source".padEnd(width)} ${state.source}`);
137
+ // The viewing links, said separately and said as what they are. Somebody who
138
+ // should be able to watch your library should not be handed the link that
139
+ // re-streams it, and the operator had nothing else to give them.
140
+ if (state.listenKey) {
141
+ lines.push("", " To share -- these watch and listen, and change nothing:");
142
+ for (const { label, url } of addresses) {
143
+ lines.push(` ${label.padEnd(width)} ${viewLink(url)}`);
144
+ }
145
+ }
134
146
  if (uptimeMs !== undefined)
135
147
  lines.push(` ${"up".padEnd(width)} ${spell(uptimeMs)}`);
136
148
  if (state.guessedPublic) {
@@ -227,6 +239,7 @@ async function waitForAnnounce(log, timeoutMs) {
227
239
  host: String(parsed["host"]),
228
240
  port: Number(parsed["port"]),
229
241
  key: parsed["key"] ?? null,
242
+ ...(typeof parsed["listenKey"] === "string" ? { listenKey: parsed["listenKey"] } : {}),
230
243
  source: String(parsed["source"]),
231
244
  ...(Array.isArray(urls) ? { urls: urls } : {}),
232
245
  ...(typeof parsed["firewall"] === "string" ? { firewall: parsed["firewall"] } : {}),
package/dist/server.js CHANGED
@@ -2962,6 +2962,10 @@ export async function serve(argv, version = "0.1.0") {
2962
2962
  host: options.host,
2963
2963
  port,
2964
2964
  key,
2965
+ // The other half of the pair. Without it `nixamp admin` can only draw
2966
+ // the links that administer, so the operator has nothing to hand
2967
+ // somebody who should be able to watch and not to drive.
2968
+ listenKey,
2965
2969
  source: root,
2966
2970
  urls: addresses,
2967
2971
  firewall,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nixamp",
3
- "version": "0.7.25",
3
+ "version": "0.7.26",
4
4
  "description": "It really whips the terminal's ass. A Winamp-shaped audio player for your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/admin.ts CHANGED
@@ -38,6 +38,14 @@ export interface AdminOptions {
38
38
  * anybody. These are the ones worth reading off the screen.
39
39
  */
40
40
  links: { label: string; url: string }[];
41
+ /**
42
+ * The key that only watches, when this server has one.
43
+ *
44
+ * The links built from it are the ones to hand other people. Absent when
45
+ * pointed at a server by hand, since a listening key is not something you
46
+ * can work out from a control one.
47
+ */
48
+ listenKey?: string | null;
41
49
  /** What it is serving, so the admin view says so without being asked. */
42
50
  source: string;
43
51
  }
@@ -76,6 +84,7 @@ export function resolveTarget(argv: string[]): AdminOptions {
76
84
  return {
77
85
  url: url_,
78
86
  key: key ?? state.key,
87
+ ...(state.listenKey ? { listenKey: state.listenKey } : {}),
79
88
  // A state file written before 0.5.3 has no list; loopback stands in.
80
89
  links: state.urls ?? [{ label: "here", url: daemonUrl(state) }],
81
90
  source: state.source,
@@ -198,7 +207,7 @@ export async function admin(argv: string[]): Promise<void> {
198
207
  app.on("exit", () => clearInterval(timer));
199
208
  app.render(({ ui, theme }) => draw(ui, theme, {
200
209
  url: target.url, report, snapshot, error, typing, restreaming, replacing,
201
- links: target.links, key: target.key, source: target.source,
210
+ links: target.links, key: target.key, listenKey: target.listenKey, source: target.source,
202
211
  }));
203
212
 
204
213
  await app.start();
@@ -242,6 +251,8 @@ export interface View {
242
251
  /** Labelled addresses, and the key that makes them work. */
243
252
  links: { label: string; url: string }[];
244
253
  key: string | null;
254
+ /** The key that only watches, for the links you hand to other people. */
255
+ listenKey?: string | null;
245
256
  source: string;
246
257
  }
247
258
 
@@ -276,13 +287,32 @@ export function draw(ui: Container, theme: Theme, view: View): void {
276
287
  // reach it. The key is on them: without it every address is a 401.
277
288
  if (view.links.length > 0) {
278
289
  const width = Math.max(...view.links.map((link) => link.label.length));
279
- ui.panel({ title: "Share links", size: view.links.length + (view.source ? 3 : 2) }, (p) => {
290
+ // Both kinds, labelled, because they are not interchangeable and the
291
+ // operator had only ever been shown the one that drives. Handing that to
292
+ // somebody who wanted to watch hands them the controls with it, and
293
+ // there was nothing else to hand them.
294
+ // Counted rather than guessed: a heading of its own, the links, the second
295
+ // heading and its links when there is a viewing key, the source, and the
296
+ // two borders. A panel one line short silently drops the last row.
297
+ const rows =
298
+ 1 + view.links.length
299
+ + (view.listenKey ? 1 + view.links.length : 0)
300
+ + (view.source ? 1 : 0);
301
+ ui.panel({ title: "Your links, and the ones to share", size: rows + 2 }, (p) => {
302
+ p.label("Yours -- these administer this server:");
280
303
  for (const link of view.links) {
281
- const full = shareLink(link.url, view.key);
282
- p.text(`${link.label.padEnd(width)} ${full}`, {
304
+ p.text(`${link.label.padEnd(width)} ${shareLink(link.url, view.key)}`, {
283
305
  fg: link.label === "on the internet" ? theme.accent : theme.foreground,
284
306
  });
285
307
  }
308
+ if (view.listenKey) {
309
+ p.label("To share -- these watch and listen, and change nothing:");
310
+ for (const link of view.links) {
311
+ p.text(`${link.label.padEnd(width)} ${shareLink(link.url, view.listenKey, false)}`, {
312
+ fg: link.label === "on the internet" ? theme.accent : theme.foreground,
313
+ });
314
+ }
315
+ }
286
316
  if (view.source) p.label(view.source);
287
317
  });
288
318
  }
package/src/daemon.ts CHANGED
@@ -18,6 +18,13 @@ export interface DaemonState {
18
18
  port: number;
19
19
  /** The share key, so `nixamp admin` can talk to it without being told. */
20
20
  key: string | null;
21
+ /**
22
+ * The key that only views, for handing to somebody who should watch.
23
+ *
24
+ * Absent on a state file written by an older nixamp, and absent on a server
25
+ * running with no key at all.
26
+ */
27
+ listenKey?: string | null;
21
28
  source: string;
22
29
  startedAt: number;
23
30
  /** Where its output went, for when it died and you want to know why. */
@@ -164,8 +171,11 @@ function spell(ms: number): string {
164
171
  * typed the command.
165
172
  */
166
173
  export function daemonLines(state: DaemonState, uptimeMs?: number): string[] {
167
- // The daemon's own key is the one that administers, so it is an /a/ link.
174
+ // Two links per address: the one that drives this server and the one that
175
+ // only watches it. Printing just the first left the operator with nothing to
176
+ // hand anybody -- and handing over the wrong one hands over the controls.
168
177
  const link = (url: string): string => shareLink(url, state.key ?? null);
178
+ const viewLink = (url: string): string => shareLink(url, state.listenKey ?? null, false);
169
179
  // A state file written by an older nixamp has no list, so host and port
170
180
  // still stand in rather than printing nothing at all.
171
181
  const addresses = state.urls ?? [{ label: "here", url: daemonUrl(state) }];
@@ -174,6 +184,16 @@ export function daemonLines(state: DaemonState, uptimeMs?: number): string[] {
174
184
  const lines = [`nixamp daemon running (pid ${state.pid})`];
175
185
  for (const { label, url } of addresses) lines.push(` ${label.padEnd(width)} ${link(url)}`);
176
186
  lines.push(` ${"source".padEnd(width)} ${state.source}`);
187
+
188
+ // The viewing links, said separately and said as what they are. Somebody who
189
+ // should be able to watch your library should not be handed the link that
190
+ // re-streams it, and the operator had nothing else to give them.
191
+ if (state.listenKey) {
192
+ lines.push("", " To share -- these watch and listen, and change nothing:");
193
+ for (const { label, url } of addresses) {
194
+ lines.push(` ${label.padEnd(width)} ${viewLink(url)}`);
195
+ }
196
+ }
177
197
  if (uptimeMs !== undefined) lines.push(` ${"up".padEnd(width)} ${spell(uptimeMs)}`);
178
198
 
179
199
  if (state.guessedPublic) {
@@ -300,6 +320,7 @@ async function waitForAnnounce(
300
320
  host: String(parsed["host"]),
301
321
  port: Number(parsed["port"]),
302
322
  key: (parsed["key"] as string | null) ?? null,
323
+ ...(typeof parsed["listenKey"] === "string" ? { listenKey: parsed["listenKey"] } : {}),
303
324
  source: String(parsed["source"]),
304
325
  ...(Array.isArray(urls) ? { urls: urls as { label: string; url: string }[] } : {}),
305
326
  ...(typeof parsed["firewall"] === "string" ? { firewall: parsed["firewall"] } : {}),
package/src/server.ts CHANGED
@@ -3447,6 +3447,10 @@ export async function serve(argv: string[], version = "0.1.0"): Promise<void> {
3447
3447
  host: options.host,
3448
3448
  port,
3449
3449
  key,
3450
+ // The other half of the pair. Without it `nixamp admin` can only draw
3451
+ // the links that administer, so the operator has nothing to hand
3452
+ // somebody who should be able to watch and not to drive.
3453
+ listenKey,
3450
3454
  source: root,
3451
3455
  urls: addresses,
3452
3456
  firewall,
package/web/dist/sw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* nixamp service worker — generated, do not edit */
2
- const CACHE = "nixamp-1788968794036";
2
+ const CACHE = "nixamp-1788970585276";
3
3
  const PRECACHE = [
4
4
  "/",
5
5
  "/apple-touch-icon.png",