nixamp 0.10.0 → 0.10.1

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.
@@ -149,6 +149,8 @@ export declare class Directory {
149
149
  */
150
150
  private readonly onLive;
151
151
  private readonly items;
152
+ /** Every code a channel has had on each listing, so a returning channel keeps its own. */
153
+ private readonly channelHistory;
152
154
  /** Streams that stopped, so the phone line can say when. */
153
155
  private readonly ended;
154
156
  private sequence;
package/dist/directory.js CHANGED
@@ -104,6 +104,8 @@ export class Directory {
104
104
  randomCode;
105
105
  onLive;
106
106
  items = new Map();
107
+ /** Every code a channel has had on each listing, so a returning channel keeps its own. */
108
+ channelHistory = new Map();
107
109
  /** Streams that stopped, so the phone line can say when. */
108
110
  ended = new Map();
109
111
  sequence = 0;
@@ -179,13 +181,19 @@ export class Directory {
179
181
  // listing always meant, and no channels is the honest empty list.
180
182
  playing: announcement.playing ?? true,
181
183
  channels: announcement.channels ?? [],
182
- channelCodes: this.codesFor(announcement.channels ?? [], existing?.channelCodes ?? (previously && "channelCodes" in previously ? previously.channelCodes : undefined), id),
184
+ channelCodes: this.codesFor(announcement.channels ?? [],
185
+ // What each channel has been called before, on this listing: a
186
+ // channel that was gone for a heartbeat -- a server restarting puts
187
+ // its channels back a moment after it announces -- comes back to the
188
+ // code people were given, not a new one.
189
+ { ...(this.channelHistory.get(id) ?? {}), ...(existing?.channelCodes ?? {}) }, id),
183
190
  updatedAt: this.now(),
184
191
  // A stream that never stopped keeps its original start. One that did
185
192
  // starts again now, because that is what a caller is being told about.
186
193
  startedAt: existing?.startedAt ?? this.now(),
187
194
  };
188
195
  this.items.set(id, listing);
196
+ this.channelHistory.set(id, { ...(this.channelHistory.get(id) ?? {}), ...listing.channelCodes });
189
197
  // The transition, not the heartbeat: existing means it was already live.
190
198
  if (existing === undefined)
191
199
  this.onLive(listing);
@@ -196,6 +204,7 @@ export class Directory {
196
204
  if (item !== undefined)
197
205
  this.remember(item);
198
206
  this.items.delete(id);
207
+ this.channelHistory.delete(id);
199
208
  }
200
209
  list() {
201
210
  this.sweep();
@@ -250,7 +259,11 @@ export class Directory {
250
259
  for (const item of this.items.values()) {
251
260
  if (item.code === code)
252
261
  return true;
253
- if (item.id !== own && Object.values(item.channelCodes).includes(code))
262
+ }
263
+ // Every code a channel has ever had on a listing that is still up is
264
+ // that channel's to come back to, on every listing but the one asking.
265
+ for (const [id, codes] of this.channelHistory) {
266
+ if (id !== own && Object.values(codes).includes(code))
254
267
  return true;
255
268
  }
256
269
  return [...this.ended.values()].some((i) => i.code === code);
@@ -331,6 +344,7 @@ export class Directory {
331
344
  if (item.updatedAt < cutoff) {
332
345
  this.remember(item);
333
346
  this.items.delete(id);
347
+ this.channelHistory.delete(id);
334
348
  }
335
349
  }
336
350
  const forget = this.now() - ENDED_TTL_MS;
package/dist/server.js CHANGED
@@ -2256,6 +2256,9 @@ export function createHandler(engine, options) {
2256
2256
  return;
2257
2257
  }
2258
2258
  options.channels.ephemeral(channelId);
2259
+ // Told to the directory now, so the room code arrives with the
2260
+ // channel rather than at the next heartbeat, ninety seconds on.
2261
+ void options.live?.announce?.();
2259
2262
  }
2260
2263
  json(response, 200, { kind: "live", channel: channelId, name: entry.title });
2261
2264
  return;
@@ -2354,6 +2357,9 @@ export function createHandler(engine, options) {
2354
2357
  return;
2355
2358
  }
2356
2359
  options.channels.ephemeral(channelId);
2360
+ // Told to the directory now, so the room code arrives with the
2361
+ // channel rather than at the next heartbeat, ninety seconds on.
2362
+ void options.live?.announce?.();
2357
2363
  }
2358
2364
  json(response, 200, shownLink(channelId, resolved));
2359
2365
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nixamp",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
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/directory.ts CHANGED
@@ -210,6 +210,8 @@ export function parseAnnouncement(input: unknown): Announcement | null {
210
210
  */
211
211
  export class Directory {
212
212
  private readonly items = new Map<string, Listing>();
213
+ /** Every code a channel has had on each listing, so a returning channel keeps its own. */
214
+ private readonly channelHistory = new Map<string, Record<string, string>>();
213
215
  /** Streams that stopped, so the phone line can say when. */
214
216
  private readonly ended = new Map<string, Ended>();
215
217
  private sequence = 0;
@@ -291,7 +293,11 @@ export class Directory {
291
293
  channels: announcement.channels ?? [],
292
294
  channelCodes: this.codesFor(
293
295
  announcement.channels ?? [],
294
- existing?.channelCodes ?? (previously && "channelCodes" in previously ? previously.channelCodes : undefined),
296
+ // What each channel has been called before, on this listing: a
297
+ // channel that was gone for a heartbeat -- a server restarting puts
298
+ // its channels back a moment after it announces -- comes back to the
299
+ // code people were given, not a new one.
300
+ { ...(this.channelHistory.get(id) ?? {}), ...(existing?.channelCodes ?? {}) },
295
301
  id,
296
302
  ),
297
303
  updatedAt: this.now(),
@@ -300,6 +306,7 @@ export class Directory {
300
306
  startedAt: existing?.startedAt ?? this.now(),
301
307
  };
302
308
  this.items.set(id, listing);
309
+ this.channelHistory.set(id, { ...(this.channelHistory.get(id) ?? {}), ...listing.channelCodes });
303
310
  // The transition, not the heartbeat: existing means it was already live.
304
311
  if (existing === undefined) this.onLive(listing);
305
312
  return listing;
@@ -309,6 +316,7 @@ export class Directory {
309
316
  const item = this.items.get(id);
310
317
  if (item !== undefined) this.remember(item);
311
318
  this.items.delete(id);
319
+ this.channelHistory.delete(id);
312
320
  }
313
321
 
314
322
  list(): Listing[] {
@@ -362,7 +370,11 @@ export class Directory {
362
370
  if (Object.values(besides).includes(code)) return true;
363
371
  for (const item of this.items.values()) {
364
372
  if (item.code === code) return true;
365
- if (item.id !== own && Object.values(item.channelCodes).includes(code)) return true;
373
+ }
374
+ // Every code a channel has ever had on a listing that is still up is
375
+ // that channel's to come back to, on every listing but the one asking.
376
+ for (const [id, codes] of this.channelHistory) {
377
+ if (id !== own && Object.values(codes).includes(code)) return true;
366
378
  }
367
379
  return [...this.ended.values()].some((i) => i.code === code);
368
380
  }
@@ -445,6 +457,7 @@ export class Directory {
445
457
  if (item.updatedAt < cutoff) {
446
458
  this.remember(item);
447
459
  this.items.delete(id);
460
+ this.channelHistory.delete(id);
448
461
  }
449
462
  }
450
463
  const forget = this.now() - ENDED_TTL_MS;
package/src/server.ts CHANGED
@@ -2721,6 +2721,9 @@ export function createHandler(engine: Engine, options: HandlerOptions) {
2721
2721
  return;
2722
2722
  }
2723
2723
  options.channels.ephemeral(channelId);
2724
+ // Told to the directory now, so the room code arrives with the
2725
+ // channel rather than at the next heartbeat, ninety seconds on.
2726
+ void options.live?.announce?.();
2724
2727
  }
2725
2728
  json(response, 200, { kind: "live", channel: channelId, name: entry.title });
2726
2729
  return;
@@ -2826,6 +2829,9 @@ export function createHandler(engine: Engine, options: HandlerOptions) {
2826
2829
  return;
2827
2830
  }
2828
2831
  options.channels.ephemeral(channelId);
2832
+ // Told to the directory now, so the room code arrives with the
2833
+ // channel rather than at the next heartbeat, ninety seconds on.
2834
+ void options.live?.announce?.();
2829
2835
  }
2830
2836
  json(response, 200, shownLink(channelId, resolved));
2831
2837
  return;
package/web/dist/sw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* nixamp service worker — generated, do not edit */
2
- const CACHE = "nixamp-1789043647290";
2
+ const CACHE = "nixamp-1789044172172";
3
3
  const PRECACHE = [
4
4
  "/",
5
5
  "/apple-touch-icon.png",