@diffenderfer-games/hub 2.0.0-next.6 → 2.0.0-next.8

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +58 -27
  2. package/dist/auto.d.ts +2 -2
  3. package/dist/auto.js +2 -2
  4. package/dist/avatar-pixi.js +1 -1
  5. package/dist/avatar-svg.js +1 -1
  6. package/dist/avatar.d.ts +2 -2
  7. package/dist/avatar.js +3 -3
  8. package/dist/doctor/cli.mjs +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +2 -2
  11. package/dist/shared/art.js +145 -3
  12. package/dist/shared/art.js.map +1 -1
  13. package/dist/shared/avatar.d.ts +3 -3
  14. package/dist/shared/client-version.gen.js +1 -1
  15. package/dist/shared/daily.js +1 -1
  16. package/dist/shared/describe.d.ts.map +1 -1
  17. package/dist/shared/describe.js +9 -1
  18. package/dist/shared/describe.js.map +1 -1
  19. package/dist/shared/index.d.ts +88 -11
  20. package/dist/shared/index.d.ts.map +1 -1
  21. package/dist/shared/live-canvas.js +1 -1
  22. package/dist/shared/overlays.js +1 -1
  23. package/dist/shared/pose-key.js +1 -1
  24. package/dist/shared/src.js +172 -28
  25. package/dist/shared/src.js.map +1 -1
  26. package/dist/shared/svg-markup.js +112 -27
  27. package/dist/shared/svg-markup.js.map +1 -1
  28. package/dist/shared/svg.js +1 -1
  29. package/dist/turns-rules.d.ts +2 -0
  30. package/dist/turns-rules.js +1 -0
  31. package/dist/turns.d.ts +23 -1
  32. package/dist/turns.d.ts.map +1 -1
  33. package/dist/turns.js +79 -13
  34. package/dist/turns.js.map +1 -1
  35. package/package.json +7 -2
  36. package/src/avatar/adapters/pixi-crowd.ts +302 -302
  37. package/src/avatar/adapters/pixi-types.ts +84 -84
  38. package/src/avatar/adapters/three.ts +126 -126
  39. package/src/avatar/art/glasses.ts +61 -3
  40. package/src/avatar/art/shape.ts +22 -3
  41. package/src/avatar/describe.ts +4 -1
  42. package/src/avatar/geom.ts +5 -0
  43. package/src/avatar/render/compose.ts +67 -22
  44. package/src/avatar/render/eyewear.ts +75 -13
  45. package/src/avatar-three.ts +18 -18
  46. package/src/avatar.ts +2 -2
  47. package/src/core/avatar/hub-avatar.ts +308 -308
  48. package/src/core/hub-progress.ts +269 -269
  49. package/src/core/page-account.ts +121 -121
  50. package/src/core/turns/hub-turns.ts +25 -4
  51. package/src/core/turns/turn-game.ts +143 -21
  52. package/src/core/turns/your-turn-buzz.ts +69 -0
  53. package/src/core/version/client-version.gen.ts +1 -1
  54. package/src/index.ts +68 -67
  55. package/src/overlay/overlay.ts +3 -3
  56. package/src/turns-kit/check-rules.ts +116 -17
  57. package/src/turns-rules.ts +12 -0
  58. package/src/turns.ts +4 -3
@@ -5097,6 +5097,50 @@ function isSavedEntry(candidate) {
5097
5097
  return typeof readField(candidate, "path") === "string" && typeof readField(candidate, "progress") === "object";
5098
5098
  }
5099
5099
  //#endregion
5100
+ //#region src/core/turns/your-turn-buzz.ts
5101
+ /** The pattern: two short pulses, ms. */
5102
+ const YOUR_TURN_BUZZ = [
5103
+ 60,
5104
+ 40,
5105
+ 60
5106
+ ];
5107
+ /** Where this device keeps the player's choice (`off` turns it off). */
5108
+ const YOUR_TURN_BUZZ_KEY = "dg:your-turn-buzz";
5109
+ /** Whether going from `previous` to `next` makes this player newly due (the moment to buzz). */
5110
+ function isNewlyDue(previous, next) {
5111
+ const wasDue = previous.phase === "playing" && previous.isMyTurn;
5112
+ return next.phase === "playing" && next.isMyTurn && !wasDue && !next.isMuted;
5113
+ }
5114
+ /** The player's own switch on this device (on unless they turned it off). */
5115
+ function readYourTurnBuzz() {
5116
+ try {
5117
+ return localStorage.getItem(YOUR_TURN_BUZZ_KEY) !== "off";
5118
+ } catch {
5119
+ return true;
5120
+ }
5121
+ }
5122
+ /** Save the player's switch on this device. */
5123
+ function saveYourTurnBuzz(isOn) {
5124
+ try {
5125
+ localStorage.setItem(YOUR_TURN_BUZZ_KEY, isOn ? "on" : "off");
5126
+ } catch {}
5127
+ }
5128
+ /** Whether the page asks for less motion (the hub's setting, else the system's). */
5129
+ function prefersLessMotion() {
5130
+ if (typeof document !== "undefined" && document.documentElement.dataset.hubMotion === "reduce") return true;
5131
+ return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
5132
+ }
5133
+ /** Buzz now, when this page is visible and nothing says not to; fails silently. Answers whether it buzzed. */
5134
+ function buzzYourTurn() {
5135
+ if (typeof document === "undefined" || document.visibilityState !== "visible" || !readYourTurnBuzz() || prefersLessMotion()) return false;
5136
+ if (typeof navigator === "undefined" || typeof navigator.vibrate !== "function") return false;
5137
+ try {
5138
+ return navigator.vibrate([...YOUR_TURN_BUZZ]);
5139
+ } catch {
5140
+ return false;
5141
+ }
5142
+ }
5143
+ //#endregion
5100
5144
  //#region src/core/turns/turn-game.ts
5101
5145
  /** The window event the social runtime fires for each `ev:turn`. */
5102
5146
  const TURN_EVENT = "hub:turn";
@@ -5106,9 +5150,13 @@ const TURN_RESYNC_EVENT = "hub:turn-resync";
5106
5150
  const TURN_CHAT_EVENT = "hub:turn-chat";
5107
5151
  /** How often a page without the live runtime looks for moves, ms. */
5108
5152
  const TURN_POLL_MS = 2e4;
5153
+ /** How long a visible page waiting on another player's move may hear nothing before it fetches the game again, ms. */
5154
+ const TURN_QUIET_MS = 15e3;
5155
+ /** How often the page checks whether it should fetch, ms. */
5156
+ const TURN_CHECK_MS = 5e3;
5109
5157
  /** One online game. `View`, `Move` and `Ev` (its events) are the game's own JSON types from its rules. */
5110
5158
  var TurnGame = class TurnGame {
5111
- constructor(host, initial) {
5159
+ constructor(host, initial, options = {}) {
5112
5160
  _defineProperty(this, "id", void 0);
5113
5161
  _defineProperty(this, "state", void 0);
5114
5162
  _defineProperty(this, "host", void 0);
@@ -5122,7 +5170,11 @@ var TurnGame = class TurnGame {
5122
5170
  _defineProperty(this, "isClosed", false);
5123
5171
  _defineProperty(this, "catchingUp", null);
5124
5172
  _defineProperty(this, "ownSeq", null);
5173
+ _defineProperty(this, "heardAt", Date.now());
5174
+ _defineProperty(this, "options", void 0);
5175
+ _defineProperty(this, "isBuzzOn", true);
5125
5176
  this.host = host;
5177
+ this.options = options;
5126
5178
  this.id = initial.id;
5127
5179
  this.state = initial;
5128
5180
  host.opened(this);
@@ -5156,20 +5208,44 @@ var TurnGame = class TurnGame {
5156
5208
  get link() {
5157
5209
  return this.state.link === null ? null : new URL(this.state.link, location.origin).href;
5158
5210
  }
5211
+ /** Whether this player may move now without it being their turn (the rules' `mayAct`: a jump-in, calling or catching "UNO"): offer that action. */
5212
+ get mayActNow() {
5213
+ const { mySeat } = this.state;
5214
+ return mySeat !== null && this.state.summary.phase === "playing" && (this.state.summary.mayAct ?? []).includes(mySeat);
5215
+ }
5216
+ /** The tournament match this game is, or `null` (show it if you like: "Saturday Cup: your match"). */
5217
+ get tournament() {
5218
+ return this.state.tournament ?? null;
5219
+ }
5220
+ /**
5221
+ * The "your turn" buzz for this game: a short vibration when this player
5222
+ * becomes due on a live update while the page is visible (never for the
5223
+ * next step of their own turn, a move out of turn, a game just opened or a
5224
+ * catch-up; never when the player turned it off or asks for less motion;
5225
+ * silently nothing where the device can't vibrate). On by default.
5226
+ */
5227
+ setYourTurnBuzz(isOn) {
5228
+ this.isBuzzOn = isOn;
5229
+ }
5159
5230
  /** Creator: start the game (empty seats go to the computer when the game allows). */
5160
5231
  async start() {
5161
5232
  this.update(await this.host.start(this.id));
5162
5233
  }
5163
5234
  /**
5164
- * Make a move. Rejects with a `HubError`: 403 `not_your_turn`, 409
5165
- * `stale` (the game moved on: the view is refreshed first), 422 `illegal`
5166
- * with the rules' own code in `rule`.
5235
+ * Make a move: when it is your turn (`summary.isMyTurn`), or out of turn
5236
+ * when the rules allow it (`mayActNow`). Rejects with a `HubError`: 403
5237
+ * `not_your_turn`, 409 `stale` (the game moved on, or another player's
5238
+ * move got there first: the view is refreshed first), 422 `illegal` with
5239
+ * the rules' own code in `rule`, 500 `rules_error` or 503 `rules_busy`
5240
+ * (the move was not made; the game is fetched again). The answer's `view` is the newest this
5241
+ * page has: moves that arrived live while the answer was on its way (the
5242
+ * computer's, another player's) are never rolled back.
5167
5243
  */
5168
5244
  async move(move) {
5169
5245
  this.ownSeq = this.state.summary.seq + 1;
5170
5246
  try {
5171
5247
  const answer = await this.host.move(this.id, this.state.summary.seq, toPayload(move));
5172
- this.update(answer.game);
5248
+ if (answer.game.summary.seq >= this.state.summary.seq) this.update(answer.game);
5173
5249
  return {
5174
5250
  seq: answer.game.summary.seq,
5175
5251
  view: this.view,
@@ -5177,6 +5253,7 @@ var TurnGame = class TurnGame {
5177
5253
  };
5178
5254
  } catch (failure) {
5179
5255
  if (failure instanceof HubError && failure.code === "stale") await this.refresh();
5256
+ else if (failure instanceof HubError && (failure.code === "rules_error" || failure.code === "rules_busy")) await this.catchUp();
5180
5257
  throw failure;
5181
5258
  } finally {
5182
5259
  this.ownSeq = null;
@@ -5205,7 +5282,7 @@ var TurnGame = class TurnGame {
5205
5282
  }
5206
5283
  /** A finished game: a new one with the same friends (they get an invite). */
5207
5284
  async rematch() {
5208
- return new TurnGame(this.host, await this.host.rematch(this.id));
5285
+ return new TurnGame(this.host, await this.host.rematch(this.id), this.options);
5209
5286
  }
5210
5287
  /** Creator, before the start: add an invite link (`link: true`, then read `link`) or list the open seats for anyone (`public`). */
5211
5288
  async share(share) {
@@ -5215,7 +5292,33 @@ var TurnGame = class TurnGame {
5215
5292
  async invite(userIds) {
5216
5293
  this.update(await this.host.invite(this.id, userIds));
5217
5294
  }
5218
- /** The turn's deadline passed (or its player is suspended): let the computer play it. */
5295
+ /**
5296
+ * Whether "Let the computer play for <name>" may work now: another
5297
+ * player is due, the hub's hand-over wait (`summary.handOverAt`) has
5298
+ * passed and a due player isn't connected (`TurnSeat.connected` false
5299
+ * or unknown), or the turn's `deadline` passed. `false` in a
5300
+ * tournament match, and from a hub too old to say. Re-check it on each
5301
+ * `turn` event (a player coming or going fires one) and when
5302
+ * `handOverAt` comes.
5303
+ */
5304
+ canLetComputerPlay(now = Date.now()) {
5305
+ const { summary, mySeat } = this.state;
5306
+ if (summary.phase !== "playing" || mySeat === null || this.state.tournament !== void 0) return false;
5307
+ const due = summary.seats.filter((seat) => summary.toAct.includes(seat.seat) && seat.seat !== mySeat && seat.status === "joined");
5308
+ if (due.length === 0) return false;
5309
+ if (summary.deadline !== null && summary.deadline <= now) return true;
5310
+ const { handOverAt } = summary;
5311
+ return handOverAt !== void 0 && handOverAt !== null && handOverAt <= now && due.some((seat) => seat.connected !== true);
5312
+ }
5313
+ /**
5314
+ * Let the computer play for whoever is due: a turn whose deadline passed
5315
+ * (or whose player is suspended) is played once; otherwise, when that
5316
+ * player has been due a while (2 minutes) and isn't connected at all, the
5317
+ * computer plays their seat for the rest of the game (it shows as `bot`,
5318
+ * named with who chose it) until they open the game again. Rejects with
5319
+ * 409 `deadline_not_passed` when neither (it never says whether they are
5320
+ * online), and 409 `not_supported` in a tournament match.
5321
+ */
5219
5322
  async letComputerPlay() {
5220
5323
  this.update(await this.host.autoPlay(this.id));
5221
5324
  }
@@ -5223,20 +5326,28 @@ var TurnGame = class TurnGame {
5223
5326
  say(send) {
5224
5327
  return this.host.chat(this.id, send);
5225
5328
  }
5226
- /** Fetch the game again, and replay moves missed since the last one this page saw. */
5329
+ /**
5330
+ * Fetch the game again, and replay moves missed since the last one this
5331
+ * page saw. An answer older than what the page has by then (live moves
5332
+ * arrived while it was on its way) is dropped, never rolled back to, and
5333
+ * a move that arrived live is never replayed twice.
5334
+ */
5227
5335
  async refresh() {
5228
- const before = this.state.summary.seq;
5229
5336
  const fresh = await this.host.get(this.id);
5230
- if (fresh.summary.seq > before) {
5231
- const missed = await this.host.history(this.id, before);
5337
+ const seen = this.state.summary.seq;
5338
+ if (fresh.summary.seq <= seen) {
5232
5339
  this.update(fresh);
5233
- for (const move of missed) this.emit("move", {
5234
- seq: move.seq,
5235
- seat: move.seat,
5236
- view: this.view,
5237
- events: move.events.map((event) => toGameData(event))
5238
- });
5239
- } else this.update(fresh);
5340
+ return;
5341
+ }
5342
+ const missed = await this.host.history(this.id, seen);
5343
+ const since = this.state.summary.seq;
5344
+ this.update(fresh);
5345
+ for (const move of missed) if (move.seq > since && move.seq <= fresh.summary.seq) this.emit("move", {
5346
+ seq: move.seq,
5347
+ seat: move.seat,
5348
+ view: this.view,
5349
+ events: move.events.map((event) => toGameData(event))
5350
+ });
5240
5351
  }
5241
5352
  /** Hear moves, turn changes, the end and chat; returns a function that stops listening. */
5242
5353
  on(eventName, listener) {
@@ -5253,11 +5364,13 @@ var TurnGame = class TurnGame {
5253
5364
  for (const stop of this.stopListening) stop();
5254
5365
  this.host.closed(this);
5255
5366
  }
5256
- /** Take a fresh answer from the hub; fire `turn` and `ended` when they changed. */
5367
+ /** Take a fresh answer from the hub (one older than what the page has is dropped: no rollback); fire `turn` and `ended` when they changed. */
5257
5368
  update(next) {
5369
+ this.heardAt = Date.now();
5258
5370
  const previous = this.state;
5371
+ if (next.summary.seq < previous.summary.seq) return;
5259
5372
  this.state = next;
5260
- if (previous.summary.seq !== next.summary.seq || previous.summary.phase !== next.summary.phase || !sameSeats(previous.summary, next.summary) || previous.chatMode !== next.chatMode || previous.link !== next.link) this.emit("turn", next.summary);
5373
+ if (previous.summary.seq !== next.summary.seq || previous.summary.phase !== next.summary.phase || !sameSeats(previous.summary, next.summary) || previous.summary.handOverAt !== next.summary.handOverAt || previous.chatMode !== next.chatMode || previous.link !== next.link) this.emit("turn", next.summary);
5261
5374
  if (previous.summary.phase !== "ended" && next.summary.phase === "ended") this.emit("ended", {
5262
5375
  outcome: next.outcome,
5263
5376
  view: this.view
@@ -5267,8 +5380,14 @@ var TurnGame = class TurnGame {
5267
5380
  const set = this.listeners[eventName];
5268
5381
  for (const listener of set) listener(payload);
5269
5382
  }
5383
+ /** Whether it is another player's move now (the page is waiting on someone). */
5384
+ isWaitingOnOthers() {
5385
+ const { summary } = this.state;
5386
+ return summary.phase === "playing" && !summary.isMyTurn;
5387
+ }
5270
5388
  /** A live `hub:turn` for this game: a move (or a missed run of them), or another change. */
5271
5389
  onLive(detail) {
5390
+ this.heardAt = Date.now();
5272
5391
  const seq = readField(detail, "seq");
5273
5392
  const view = readField(detail, "view");
5274
5393
  const summary = readField(detail, "summary");
@@ -5277,17 +5396,20 @@ var TurnGame = class TurnGame {
5277
5396
  this.catchUp();
5278
5397
  return;
5279
5398
  }
5399
+ if (seq < this.state.summary.seq) return;
5280
5400
  const seat = readField(detail, "seat");
5281
5401
  const events = readField(detail, "events");
5282
5402
  const outcome = readField(detail, "outcome");
5283
5403
  const isMove = typeof seat === "number" && seq === this.state.summary.seq + 1 && seq !== this.ownSeq;
5284
5404
  if (summary.phase !== this.state.summary.phase || !sameSeating(this.state.summary, summary)) this.catchUp();
5405
+ const before = this.state.summary;
5285
5406
  this.update({
5286
5407
  ...this.state,
5287
5408
  summary,
5288
5409
  view: toPayloadJson(view),
5289
5410
  outcome: isOutcome(outcome) ? outcome : this.state.outcome
5290
5411
  });
5412
+ if (this.isBuzzOn && (this.options.isBuzzOn?.() ?? true) && isNewlyDue(before, this.state.summary)) buzzYourTurn();
5291
5413
  if (isMove) this.emit("move", {
5292
5414
  seq,
5293
5415
  seat,
@@ -5332,8 +5454,13 @@ var TurnGame = class TurnGame {
5332
5454
  window.addEventListener(TURN_RESYNC_EVENT, onResync);
5333
5455
  document.addEventListener("visibilitychange", onVisible);
5334
5456
  const poll = setInterval(() => {
5335
- if (!this.host.isLive() && document.visibilityState === "visible") this.catchUp();
5336
- }, TURN_POLL_MS);
5457
+ if (document.visibilityState !== "visible" || this.catchingUp !== null) return;
5458
+ const quietMs = Date.now() - this.heardAt;
5459
+ if (this.host.isLive() ? this.isWaitingOnOthers() && quietMs >= 15e3 : quietMs >= 2e4) {
5460
+ this.heardAt = Date.now();
5461
+ this.catchUp();
5462
+ }
5463
+ }, TURN_CHECK_MS);
5337
5464
  this.stopListening.push(() => {
5338
5465
  window.removeEventListener(TURN_EVENT, onTurn);
5339
5466
  }, () => {
@@ -5358,9 +5485,9 @@ function eachSeat(a, b, same) {
5358
5485
  function sameSeating(a, b) {
5359
5486
  return eachSeat(a, b, (seat, other) => seat.status === other.status && seat.userId === other.userId);
5360
5487
  }
5361
- /** The same seating, and the same looks (a player's new avatar is a change: `turn` fires). */
5488
+ /** The same seating, looks and who is connected (a player's new avatar, or a player coming or going, is a change: `turn` fires). */
5362
5489
  function sameSeats(a, b) {
5363
- return sameSeating(a, b) && eachSeat(a, b, (seat, other) => seat.look === other.look);
5490
+ return sameSeating(a, b) && eachSeat(a, b, (seat, other) => seat.look === other.look && seat.connected === other.connected);
5364
5491
  }
5365
5492
  /** A game's move as the JSON the hub takes. */
5366
5493
  function toPayload(move) {
@@ -5414,8 +5541,25 @@ function isGameId(idOrKey) {
5414
5541
  var HubTurns = class {
5415
5542
  constructor(host) {
5416
5543
  _defineProperty(this, "host", void 0);
5544
+ _defineProperty(this, "isBuzzOn", true);
5545
+ _defineProperty(this, "gameOptions", { isBuzzOn: () => this.isBuzzOn });
5417
5546
  this.host = host;
5418
5547
  }
5548
+ /**
5549
+ * This page's "your turn" buzz (a short vibration when the player becomes
5550
+ * due in an open game, see `TurnGame.setYourTurnBuzz`): pass `false` if
5551
+ * your game gives its own signal. On by default.
5552
+ */
5553
+ setYourTurnBuzz(isOn) {
5554
+ this.isBuzzOn = isOn;
5555
+ }
5556
+ /** The player's own "Buzz when it's my turn" switch on this device (the menu's Settings show it too). */
5557
+ get playerYourTurnBuzz() {
5558
+ return readYourTurnBuzz();
5559
+ }
5560
+ set playerYourTurnBuzz(isOn) {
5561
+ saveYourTurnBuzz(isOn);
5562
+ }
5419
5563
  /** The invite link key this page was opened with (`?hub_turn_link=`), taken out of the address bar; `null` when none. Synchronous. */
5420
5564
  get link() {
5421
5565
  return linkOnPage();
@@ -5434,16 +5578,16 @@ var HubTurns = class {
5434
5578
  ...options.deadline === void 0 ? {} : { deadline: options.deadline },
5435
5579
  ...options.autoStart === void 0 ? {} : { autoStart: options.autoStart }
5436
5580
  };
5437
- return new TurnGame(this.host, await this.host.create(body));
5581
+ return new TurnGame(this.host, await this.host.create(body), this.gameOptions);
5438
5582
  }
5439
5583
  /** Take a seat: by the game's id (an invite, an open seat) or by an invite link's key. */
5440
5584
  async join(idOrLinkKey) {
5441
5585
  const joined = isGameId(idOrLinkKey) ? await this.host.join(idOrLinkKey) : await this.host.joinByLink(idOrLinkKey);
5442
- return new TurnGame(this.host, joined);
5586
+ return new TurnGame(this.host, joined, this.gameOptions);
5443
5587
  }
5444
5588
  /** Open a game the player sits in (from `hub.saved.opened`, the Continue list, an invite). */
5445
5589
  async open(id) {
5446
- return new TurnGame(this.host, await this.host.get(id));
5590
+ return new TurnGame(this.host, await this.host.get(id), this.gameOptions);
5447
5591
  }
5448
5592
  /** This game's online games the player sits in (the same rows as `hub.saved.list({ kinds: ['turns'] })`). */
5449
5593
  list() {
@@ -5900,6 +6044,6 @@ function createHub(options = {}) {
5900
6044
  return new Hub(options);
5901
6045
  }
5902
6046
  //#endregion
5903
- export { UNSUPPORTED_BY_HUB as A, OUTBOX_MAX_CHARS as C, HubError as D, ContentRejectedError as E, OfflineError as O, OUTBOX_FULL_CODE as S, OfflineApi as T, savedGameUrl as _, TURN_LINK_PARAM as a, RESUME_MAX_STATE_BYTES as b, TURN_POLL_MS as c, HubSaved as d, SAVED_CHANGE_QUIET_MS as f, SAVED_OPEN_PARAM as g, SAVED_OPEN_EVENT as h, HubTurns as i, HubAvatar as j, SAVE_UNKNOWN_CODE as k, TURN_RESYNC_EVENT as l, SAVED_KIND_PARAM as m, createHub as n, TURN_CHAT_EVENT as o, SAVED_CHANGE_EVENT as p, hub as r, TURN_EVENT as s, Hub as t, TurnGame as u, HubResume as v, OUTBOX_MAX_ENTRIES as w, CLIENT_VERSION_HEADER as x, RESUME_DEBOUNCE_MS as y };
6047
+ export { OUTBOX_MAX_ENTRIES as A, savedGameUrl as C, CLIENT_VERSION_HEADER as D, RESUME_MAX_STATE_BYTES as E, SAVE_UNKNOWN_CODE as F, UNSUPPORTED_BY_HUB as I, HubAvatar as L, ContentRejectedError as M, HubError as N, OUTBOX_FULL_CODE as O, OfflineError as P, SAVED_OPEN_PARAM as S, RESUME_DEBOUNCE_MS as T, HubSaved as _, TURN_LINK_PARAM as a, SAVED_KIND_PARAM as b, TURN_POLL_MS as c, TurnGame as d, YOUR_TURN_BUZZ as f, saveYourTurnBuzz as g, readYourTurnBuzz as h, HubTurns as i, OfflineApi as j, OUTBOX_MAX_CHARS as k, TURN_QUIET_MS as l, isNewlyDue as m, createHub as n, TURN_CHAT_EVENT as o, YOUR_TURN_BUZZ_KEY as p, hub as r, TURN_EVENT as s, Hub as t, TURN_RESYNC_EVENT as u, SAVED_CHANGE_QUIET_MS as v, HubResume as w, SAVED_OPEN_EVENT as x, SAVED_CHANGE_EVENT as y };
5904
6048
 
5905
6049
  //# sourceMappingURL=src.js.map