@diffenderfer-games/hub 2.0.0-next.3 → 2.0.0-next.5

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 (40) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/auto.d.ts +2 -2
  3. package/dist/auto.js +2 -2
  4. package/dist/doctor/cli.mjs +1 -1
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +2 -2
  7. package/dist/rooms.js +1 -1
  8. package/dist/shared/client-version.gen.js +1 -1
  9. package/dist/shared/daily.d.ts +13 -4
  10. package/dist/shared/daily.d.ts.map +1 -1
  11. package/dist/shared/daily.js +15 -6
  12. package/dist/shared/daily.js.map +1 -1
  13. package/dist/shared/index.d.ts +237 -6
  14. package/dist/shared/index.d.ts.map +1 -1
  15. package/dist/shared/rooms.d.ts.map +1 -1
  16. package/dist/shared/rooms.js +12 -1
  17. package/dist/shared/rooms.js.map +1 -1
  18. package/dist/shared/src.js +696 -31
  19. package/dist/shared/src.js.map +1 -1
  20. package/package.json +2 -2
  21. package/src/core/connection.ts +6 -0
  22. package/src/core/errors.ts +8 -1
  23. package/src/core/hub-progress.ts +44 -8
  24. package/src/core/hub.ts +55 -4
  25. package/src/core/offline/cloud-saves.ts +62 -0
  26. package/src/core/offline/hub-kinds/index.ts +11 -3
  27. package/src/core/offline/hub-kinds/progress-kinds.ts +21 -4
  28. package/src/core/offline/hub-kinds/resume-kind.ts +108 -0
  29. package/src/core/offline/local-store.ts +46 -1
  30. package/src/core/page.ts +10 -0
  31. package/src/core/rest/routes.gen.ts +4 -0
  32. package/src/core/resume/hub-resume.ts +252 -0
  33. package/src/core/resume/local-resume.ts +130 -0
  34. package/src/core/resume/resume-list.ts +65 -0
  35. package/src/core/resume/resume-request.ts +52 -0
  36. package/src/core/resume/resume-types.ts +64 -0
  37. package/src/core/version/client-version.gen.ts +1 -1
  38. package/src/daily/daily-system.ts +14 -5
  39. package/src/index.ts +4 -1
  40. package/src/realtime/rooms-forwarder.ts +14 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # @diffenderfer-games/hub
2
2
 
3
+ ## 2.0.0-next.5
4
+
5
+ ### Patch Changes
6
+
7
+ - 7585522: Saves offline no longer risk the cloud copy. Offline, `getSave(slot)` rejects with a `HubError` whose `code` is `save_unknown` (new export `SAVE_UNKNOWN_CODE`; `isOffline` is `true`) when the device has never seen the hub's copy of that slot, instead of answering `save: null`; it still answers from the device's copy after a snapshot (`prefetchAll`), an online read, a landed write, or for a slot the device wrote and has queued. A `putSave` replayed from the offline queue now sends `base`, the slot's `updatedAt` on the hub as the device last saw it, and the hub refuses it with 409 `save_conflict` when another device saved since (dropped and reported in the `hub:sync` conflicts); writes sent at once while online are unchanged. The client also remembers the signed-in user from `login`, `signup`, `claim` and `ensureGuest` replies, and forgets it on `logout`. Contract: `writeSave` takes an optional `base` and may answer 409; new error code `save_conflict`. Older clients (no `base`) behave as before. See docs/hub.md "Saves offline".
8
+ - Updated dependencies [7585522]
9
+ - @diffenderfer-games/hub-contract@2.0.0-next.5
10
+
11
+ ## 2.0.0-next.4
12
+
13
+ ### Minor Changes
14
+
15
+ - 9f993ab: Resume saved games. New `hub.resume` (`save`, `flush`, `clear`, `load`, `get`, `requested`, `blockedBy`, `list`, `discard`): one auto-saved run per player per game that the home page's new Resume card lists, so players pick long single-player runs up again on any device. Saves are kept on the device at once, debounced (3 s), sent when the page hides, and replay offline through the new `hub.resume` outbox kind; they are ignored during races, daily challenges and hub rooms. `hub.resume.requested` is a synchronous `true` when the page was opened from the card (`?hub_resume=1`, taken out of the URL). Games opt in with `game.resumable: true` in the manifest. Contract: `resumeEndpoints` (`getResumeSlot`, `saveResumeSlot`, `clearResumeSlot`, `listMyResumeSlots`), `ResumeSlot`, `ResumeSummary`, `ResumeProgress`, `ResumeWrite`, `RESUME_MAX_STATE_BYTES` (512 KB), `RESUME_TEXT_MAX`, `RESUME_RETENTION_MS` (60 days), `RESUME_REQUEST_PARAM`; `saveResumeSlot` and `clearResumeSlot` join `OFFLINE_REPLAY_ENDPOINTS`. See docs/hub.md "Resume saved games". Daily: `hub.daily.complete()` now ends the daily run at the call (`hub.daily.active` is `null` at once, even if the hub refuses the completion); games must call `hub.daily.cancel()` when the player leaves a daily unfinished, or `hub.resume.save` stays off (it warns once).
16
+
17
+ ### Patch Changes
18
+
19
+ - Updated dependencies [9f993ab]
20
+ - @diffenderfer-games/hub-contract@2.0.0-next.4
21
+
3
22
  ## 2.0.0-next.3
4
23
 
5
24
  ### Patch Changes
package/dist/auto.d.ts CHANGED
@@ -8,7 +8,7 @@ import { a as RaceHistoryQuery, c as RaceRuntimeApi, i as RaceEvents, l as RaceS
8
8
  import { f as raceForwarder } from "./shared/race.js";
9
9
  import { n as roomsForwarder } from "./shared/rooms.js";
10
10
  import { $ as HubNotifyApi, A as RacerState, B as SuggestionStatus, C as RaceRecord, D as RaceStats, E as RaceState, F as ReportReason, G as REALTIME_READY_EVENT, H as isRealtimeApi, I as RoomInfo, J as RealtimeHubLink, K as REALTIME_SINGLETON_API, L as SocialConfig, M as Relation, N as ReportInput, O as Racer, P as ReportKind, Q as socialForwarder, R as SocialMe, S as RaceParams, T as RaceStatValue, U as REALTIME_FAILED_EVENT, V as findRealtimeApi, W as REALTIME_FEATURE_VERSION, X as notifyForwarder, Y as linkRealtimeToHub, Z as presenceForwarder, _ as PlayerLite, a as ErrorBody, at as SocialCounts, b as PresenceKind, c as JoinInfo, d as Message, et as HubPresenceApi, f as MessagesPage, g as PlayerCard, h as Party, i as Counts, it as PlayerRef, j as RecentPlayer, k as RacerResult, l as Launch, m as NotifyPrefs, n as ChatMode, nt as OpenInviteOptions, o as FriendEntry, ot as SocialEvents, p as NotifyChange, q as RealtimeApi, r as Conversation, rt as PlayOnlineMethods, s as Invite, t as Audience, tt as HubSocialApi, u as LaunchTicket, v as Presence, w as RaceResult, x as RaceOutcome, y as PresenceInput, z as Suggestion } from "./shared/social.js";
11
- import { $ as LeaderboardResult, A as OUTBOX_MAX_ENTRIES, B as Board, C as OfflineApi, D as OfflineListener, E as OfflineEventName, F as ProfilePatch, G as GameRecords, H as GameAnalytics, I as QueueOp, J as HubStatus, K as GlobalAnalytics, L as QueueOpInput, M as OfflineKindDefinition, N as ReplayContext, O as OfflineOp, P as CLIENT_VERSION_HEADER, Q as LeaderboardEntry, R as QueuedScoreOptions, S as SyncResult, T as OfflineEventDetails, U as GameInfo, V as BoardWithTop, W as GameLeaderboards, X as InventorySnapshot, Y as Inventory, Z as Json, _ as TradeNoteOptions, a as HubErrorDetails, at as SaveMeta, b as StatResult, c as Hub, ct as Stats, d as ClientSupport, dt as User, et as MeResponse, f as HubMenuControl, ft as EndpointFields, g as TradeListOptions, h as TradeId, ht as GamePayload, i as HubErrorCode, it as Save, j as OfflineHandler, k as OUTBOX_MAX_CHARS, l as createHub, lt as SubmitScoreOptions, m as TradeBundle, mt as EndpointReply, n as ContentRejectedError, nt as Profile, o as OfflineError, ot as SnapshotResponse, p as GrantBundle, pt as EndpointName, q as HubOptions, r as HubError, rt as ProfileSummary, s as UNSUPPORTED_BY_HUB, st as SortDir, t as HUB_CLIENT_VERSION, tt as Metrics, u as hub, ut as SubmitScoreResult, v as AuthResponse, w as OUTBOX_FULL_CODE, x as SyncConflict, y as ProfileUpdate, z as BufferedEvent } from "./shared/index.js";
11
+ import { $ as GameInfo, A as StatResult, B as OUTBOX_MAX_ENTRIES, C as GrantBundle, Ct as EndpointName, D as TradeNoteOptions, E as TradeListOptions, F as OfflineEventDetails, G as ProfilePatch, H as OfflineKindDefinition, I as OfflineEventName, J as QueuedScoreOptions, K as QueueOp, L as OfflineListener, M as SyncResult, N as OfflineApi, O as AuthResponse, P as OUTBOX_FULL_CODE, Q as GameAnalytics, R as OfflineOp, S as HubMenuControl, St as EndpointFields, T as TradeId, Tt as GamePayload, U as ReplayContext, V as OfflineHandler, W as CLIENT_VERSION_HEADER, X as Board, Y as BufferedEvent, Z as BoardWithTop, _ as ResumeEntry, _t as SortDir, a as HubErrorDetails, at as Inventory, b as ResumeRun, bt as SubmitScoreResult, c as UNSUPPORTED_BY_HUB, ct as LeaderboardEntry, d as hub, dt as Metrics, et as GameLeaderboards, f as ClientSupport, ft as Profile, g as ResumeBlocker, gt as SnapshotResponse, h as RESUME_MAX_STATE_BYTES, ht as SaveMeta, i as HubErrorCode, it as HubStatus, j as SyncConflict, k as ProfileUpdate, l as Hub, lt as LeaderboardResult, m as RESUME_DEBOUNCE_MS, mt as Save, n as ContentRejectedError, nt as GlobalAnalytics, o as OfflineError, ot as InventorySnapshot, p as HubResume, pt as ProfileSummary, q as QueueOpInput, r as HubError, rt as HubOptions, s as SAVE_UNKNOWN_CODE, st as Json, t as HUB_CLIENT_VERSION, tt as GameRecords, u as createHub, ut as MeResponse, v as ResumeLoadOptions, vt as Stats, w as TradeBundle, wt as EndpointReply, x as ResumeSaveInput, xt as User, y as ResumeProgress, yt as SubmitScoreOptions, z as OUTBOX_MAX_CHARS } from "./shared/index.js";
12
12
  //#region src/auto.d.ts
13
13
  /** What `window.HubSDK` holds. */
14
14
  export interface HubSdkGlobal {
@@ -32,5 +32,5 @@ declare global {
32
32
  }
33
33
  }
34
34
  //#endregion
35
- export { type Anchor, type Audience, type AuthResponse, type AutoPauseOptions, type AxisDef, type AxisSide, type Board, type BoardWithTop, type BufferedEvent, type BusyOptions, CLIENT_VERSION_HEADER, type ChatMode, type ClientSupport, ContentRejectedError, type Conversation, type Counts, DAILY_SINGLETON_API, DAILY_START_EVENT, type DailyAll, type DailyChallenge, type DailyCompleteResponse, type DailyCompletion, type DailyCompletionMeta, type DailyCompletions, type DailyDefinition, type DailyEventDetail, type DailyGameStatus, type DailyHost, type DailyStartResponse, type DailyStatus, DailySystem, type DraggedSpot, type EdgeOffsets, type EndpointFields, type EndpointName, type EndpointReply, type ErrorBody, FOCUS_RING_SHADOW, type FriendEntry, type GameAnalytics, type GameInfo, type GameLeaderboards, type GamePayload, type GameRecords, type GamepadMapping, type GlobalAnalytics, type GrantBundle, type GroupDef, HUB_CLIENT_VERSION, Hub, HubError, type HubErrorCode, type HubErrorDetails, type HubMenuControl, type HubMpApi, type HubNotifyApi, type HubOptions, type HubPresenceApi, type HubRaceApi, type HubRoom, type HubRoomsApi, type HubSocialApi, type HubStatus, INPUT_SINGLETON_API, type InputConfig, type InputDef, type InputEvents, type InputHost, type InputModality, type InputOptions, type InputOverrides, type InputReading, type InputSource, InputSystem, type InputSystemOptions, type Insets, type Inventory, type InventorySnapshot, type Invite, type InviteCreated, type InviteLink, type InviteLinkMethods, type InviteOptions, type InviteResult, type JoinInfo, type JoinInfoEvent, type JoinOptions, type Json, type Launch, type LaunchTicket, type LayoutBox, type LayoutItem, type LayoutOptions, type LeaderboardEntry, type LeaderboardResult, MODALITY_ATTRIBUTE, type MeResponse, type MenuBridge, type Message, type MessagesPage, type Metrics, type MouseMapping, type NavBlurEvent, type NavElement, type NavElementKind, type NavFocusEvent, type NavTarget, type NavigableDef, type Notice, type NotifyChange, type NotifyPrefs, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, type OfflineEventDetails, type OfflineEventName, type OfflineHandler, type OfflineKindDefinition, type OfflineListener, type OfflineOp, type OpenInviteOptions, Overlay, type OverlayEdge, type OverlayEvent, type OverlayListener, type OverlayReason, type PageInputControl, type Party, type PlayOnlineMethods, type PlayerCard, type PlayerLite, type PlayerRef, type Presence, type PresenceInput, type PresenceKind, type Profile, type ProfilePatch, type ProfileSummary, type ProfileUpdate, type QueueOp, type QueueOpInput, type QueuedScoreOptions, type REALTIME_FAILED_EVENT, type REALTIME_FEATURE_VERSION, type REALTIME_READY_EVENT, type REALTIME_SINGLETON_API, type RaceCreateOptions, type RaceDefinition, type RaceEvents, type RaceHistory, type RaceHistoryQuery, type RaceHistoryViewOptions, type RaceHudPlace, type RaceOutcome, type RaceParams, type RaceRecord, type RaceRecordPlayer, type RaceResult, type RaceResultPlayer, type RaceRuntimeApi, type RaceStart, type RaceStatValue, type RaceState, type RaceStats, type RaceStatusEvent, type Racer, type RacerResult, type RacerState, type RealtimeApi, type RealtimeErrorShape, type RealtimeHubLink, type RecentPlayer, type Rect, type Relation, type ReplayContext, type ReportInput, type ReportKind, type ReportReason, type RoomChatLine, type RoomCreateOptions, type RoomEvents, type RoomInfo, type RoomListOptions, type RoomMessage, type RoomReclaimMethods, type RoomSeat, type RoomSeatChange, type RoomSelf, type RoomSendOptions, type RoomState, type RoomStateChange, type RoomStateOptions, type Save, type SaveMeta, type SchemaOutput, type ServerEvents, type Snapshot, type SnapshotResponse, type SocialConfig, type SocialCounts, type SocialEvents, type SocialMe, type SortDir, type StatResult, type Stats, type SubmitScoreOptions, type SubmitScoreResult, type Suggestion, type SuggestionStatus, type SyncConflict, type SyncResult, type TouchMapping, type TradeBundle, type TradeId, type TradeListOptions, type TradeNoteOptions, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, type UiStack, type UiStackHandoff, type User, type Vector, type VirtualControlType, type VirtualDef, type VirtualInputs, type VirtualOverride, boxesTouch, controlSize, createHub, type findRealtimeApi, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, type isRealtimeApi, isUiStack, layoutControls, type linkRealtimeToHub, type multiplayerForwarder as mp, type notifyForwarder as notify, parseInputOverrides, type presenceForwarder as presence, type raceForwarder as race, type roomsForwarder as rooms, type socialForwarder as social, trackInputModality };
35
+ export { type Anchor, type Audience, type AuthResponse, type AutoPauseOptions, type AxisDef, type AxisSide, type Board, type BoardWithTop, type BufferedEvent, type BusyOptions, CLIENT_VERSION_HEADER, type ChatMode, type ClientSupport, ContentRejectedError, type Conversation, type Counts, DAILY_SINGLETON_API, DAILY_START_EVENT, type DailyAll, type DailyChallenge, type DailyCompleteResponse, type DailyCompletion, type DailyCompletionMeta, type DailyCompletions, type DailyDefinition, type DailyEventDetail, type DailyGameStatus, type DailyHost, type DailyStartResponse, type DailyStatus, DailySystem, type DraggedSpot, type EdgeOffsets, type EndpointFields, type EndpointName, type EndpointReply, type ErrorBody, FOCUS_RING_SHADOW, type FriendEntry, type GameAnalytics, type GameInfo, type GameLeaderboards, type GamePayload, type GameRecords, type GamepadMapping, type GlobalAnalytics, type GrantBundle, type GroupDef, HUB_CLIENT_VERSION, Hub, HubError, type HubErrorCode, type HubErrorDetails, type HubMenuControl, type HubMpApi, type HubNotifyApi, type HubOptions, type HubPresenceApi, type HubRaceApi, HubResume, type HubRoom, type HubRoomsApi, type HubSocialApi, type HubStatus, INPUT_SINGLETON_API, type InputConfig, type InputDef, type InputEvents, type InputHost, type InputModality, type InputOptions, type InputOverrides, type InputReading, type InputSource, InputSystem, type InputSystemOptions, type Insets, type Inventory, type InventorySnapshot, type Invite, type InviteCreated, type InviteLink, type InviteLinkMethods, type InviteOptions, type InviteResult, type JoinInfo, type JoinInfoEvent, type JoinOptions, type Json, type Launch, type LaunchTicket, type LayoutBox, type LayoutItem, type LayoutOptions, type LeaderboardEntry, type LeaderboardResult, MODALITY_ATTRIBUTE, type MeResponse, type MenuBridge, type Message, type MessagesPage, type Metrics, type MouseMapping, type NavBlurEvent, type NavElement, type NavElementKind, type NavFocusEvent, type NavTarget, type NavigableDef, type Notice, type NotifyChange, type NotifyPrefs, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, type OfflineEventDetails, type OfflineEventName, type OfflineHandler, type OfflineKindDefinition, type OfflineListener, type OfflineOp, type OpenInviteOptions, Overlay, type OverlayEdge, type OverlayEvent, type OverlayListener, type OverlayReason, type PageInputControl, type Party, type PlayOnlineMethods, type PlayerCard, type PlayerLite, type PlayerRef, type Presence, type PresenceInput, type PresenceKind, type Profile, type ProfilePatch, type ProfileSummary, type ProfileUpdate, type QueueOp, type QueueOpInput, type QueuedScoreOptions, type REALTIME_FAILED_EVENT, type REALTIME_FEATURE_VERSION, type REALTIME_READY_EVENT, type REALTIME_SINGLETON_API, RESUME_DEBOUNCE_MS, RESUME_MAX_STATE_BYTES, type RaceCreateOptions, type RaceDefinition, type RaceEvents, type RaceHistory, type RaceHistoryQuery, type RaceHistoryViewOptions, type RaceHudPlace, type RaceOutcome, type RaceParams, type RaceRecord, type RaceRecordPlayer, type RaceResult, type RaceResultPlayer, type RaceRuntimeApi, type RaceStart, type RaceStatValue, type RaceState, type RaceStats, type RaceStatusEvent, type Racer, type RacerResult, type RacerState, type RealtimeApi, type RealtimeErrorShape, type RealtimeHubLink, type RecentPlayer, type Rect, type Relation, type ReplayContext, type ReportInput, type ReportKind, type ReportReason, type ResumeBlocker, type ResumeEntry, type ResumeLoadOptions, type ResumeProgress, type ResumeRun, type ResumeSaveInput, type RoomChatLine, type RoomCreateOptions, type RoomEvents, type RoomInfo, type RoomListOptions, type RoomMessage, type RoomReclaimMethods, type RoomSeat, type RoomSeatChange, type RoomSelf, type RoomSendOptions, type RoomState, type RoomStateChange, type RoomStateOptions, SAVE_UNKNOWN_CODE, type Save, type SaveMeta, type SchemaOutput, type ServerEvents, type Snapshot, type SnapshotResponse, type SocialConfig, type SocialCounts, type SocialEvents, type SocialMe, type SortDir, type StatResult, type Stats, type SubmitScoreOptions, type SubmitScoreResult, type Suggestion, type SuggestionStatus, type SyncConflict, type SyncResult, type TouchMapping, type TradeBundle, type TradeId, type TradeListOptions, type TradeNoteOptions, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, type UiStack, type UiStackHandoff, type User, type Vector, type VirtualControlType, type VirtualDef, type VirtualInputs, type VirtualOverride, boxesTouch, controlSize, createHub, type findRealtimeApi, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, type isRealtimeApi, isUiStack, layoutControls, type linkRealtimeToHub, type multiplayerForwarder as mp, type notifyForwarder as notify, parseInputOverrides, type presenceForwarder as presence, type raceForwarder as race, type roomsForwarder as rooms, type socialForwarder as social, trackInputModality };
36
36
  //# sourceMappingURL=auto.d.ts.map
package/dist/auto.js CHANGED
@@ -2,7 +2,7 @@ import { a as DailySystem, i as DAILY_START_EVENT, n as getDaily, r as isDailySy
2
2
  import { t as HUB_CLIENT_VERSION } from "./shared/client-version.gen.js";
3
3
  import { a as isPageInputControl, c as layoutControls, d as MODALITY_ATTRIBUTE, f as trackInputModality, i as parseInputOverrides, l as boxesTouch, n as getInput, o as InputSystem, p as FOCUS_RING_SHADOW, r as isInputSystem, s as Overlay, t as INPUT_SINGLETON_API, u as controlSize } from "./shared/input.js";
4
4
  import { n as isUiStack, r as UI_STACK_VERSION, t as getUiStack } from "./shared/page-stack.js";
5
- import { a as OUTBOX_FULL_CODE, c as OfflineApi, d as OfflineError, f as UNSUPPORTED_BY_HUB, i as CLIENT_VERSION_HEADER, l as ContentRejectedError, n as createHub, o as OUTBOX_MAX_CHARS, r as hub, s as OUTBOX_MAX_ENTRIES, t as Hub, u as HubError } from "./shared/src.js";
5
+ import { a as RESUME_DEBOUNCE_MS, c as OUTBOX_FULL_CODE, d as OfflineApi, f as ContentRejectedError, g as UNSUPPORTED_BY_HUB, h as SAVE_UNKNOWN_CODE, i as HubResume, l as OUTBOX_MAX_CHARS, m as OfflineError, n as createHub, o as RESUME_MAX_STATE_BYTES, p as HubError, r as hub, s as CLIENT_VERSION_HEADER, t as Hub, u as OUTBOX_MAX_ENTRIES } from "./shared/src.js";
6
6
  //#region src/auto.ts
7
7
  /**
8
8
  * `@diffenderfer-games/hub/auto`: everything the main entry exports, plus a
@@ -22,6 +22,6 @@ if (typeof window !== "undefined") window.HubSDK = {
22
22
  ContentRejectedError
23
23
  };
24
24
  //#endregion
25
- export { CLIENT_VERSION_HEADER, ContentRejectedError, DAILY_SINGLETON_API, DAILY_START_EVENT, DailySystem, FOCUS_RING_SHADOW, HUB_CLIENT_VERSION, Hub, HubError, INPUT_SINGLETON_API, InputSystem, MODALITY_ATTRIBUTE, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, Overlay, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, boxesTouch, controlSize, createHub, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, isUiStack, layoutControls, parseInputOverrides, trackInputModality };
25
+ export { CLIENT_VERSION_HEADER, ContentRejectedError, DAILY_SINGLETON_API, DAILY_START_EVENT, DailySystem, FOCUS_RING_SHADOW, HUB_CLIENT_VERSION, Hub, HubError, HubResume, INPUT_SINGLETON_API, InputSystem, MODALITY_ATTRIBUTE, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, Overlay, RESUME_DEBOUNCE_MS, RESUME_MAX_STATE_BYTES, SAVE_UNKNOWN_CODE, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, boxesTouch, controlSize, createHub, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, isUiStack, layoutControls, parseInputOverrides, trackInputModality };
26
26
 
27
27
  //# sourceMappingURL=auto.js.map
@@ -5,7 +5,7 @@ import { parseArgs } from "node:util";
5
5
  import { GAME_LABELS, GamePackageJson, HubVersion, splitGameLabels } from "@diffenderfer-games/hub-contract";
6
6
  //#region src/core/version/client-version.gen.ts
7
7
  /** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
8
- const HUB_CLIENT_VERSION = "2.0.0-next.3";
8
+ const HUB_CLIENT_VERSION = "2.0.0-next.5";
9
9
  //#endregion
10
10
  //#region src/core/version/semver.ts
11
11
  const VERSION_PATTERN = /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
package/dist/index.d.ts CHANGED
@@ -8,5 +8,5 @@ import { a as RaceHistoryQuery, c as RaceRuntimeApi, i as RaceEvents, l as RaceS
8
8
  import { f as raceForwarder } from "./shared/race.js";
9
9
  import { n as roomsForwarder } from "./shared/rooms.js";
10
10
  import { $ as HubNotifyApi, A as RacerState, B as SuggestionStatus, C as RaceRecord, D as RaceStats, E as RaceState, F as ReportReason, G as REALTIME_READY_EVENT, H as isRealtimeApi, I as RoomInfo, J as RealtimeHubLink, K as REALTIME_SINGLETON_API, L as SocialConfig, M as Relation, N as ReportInput, O as Racer, P as ReportKind, Q as socialForwarder, R as SocialMe, S as RaceParams, T as RaceStatValue, U as REALTIME_FAILED_EVENT, V as findRealtimeApi, W as REALTIME_FEATURE_VERSION, X as notifyForwarder, Y as linkRealtimeToHub, Z as presenceForwarder, _ as PlayerLite, a as ErrorBody, at as SocialCounts, b as PresenceKind, c as JoinInfo, d as Message, et as HubPresenceApi, f as MessagesPage, g as PlayerCard, h as Party, i as Counts, it as PlayerRef, j as RecentPlayer, k as RacerResult, l as Launch, m as NotifyPrefs, n as ChatMode, nt as OpenInviteOptions, o as FriendEntry, ot as SocialEvents, p as NotifyChange, q as RealtimeApi, r as Conversation, rt as PlayOnlineMethods, s as Invite, t as Audience, tt as HubSocialApi, u as LaunchTicket, v as Presence, w as RaceResult, x as RaceOutcome, y as PresenceInput, z as Suggestion } from "./shared/social.js";
11
- import { $ as LeaderboardResult, A as OUTBOX_MAX_ENTRIES, B as Board, C as OfflineApi, D as OfflineListener, E as OfflineEventName, F as ProfilePatch, G as GameRecords, H as GameAnalytics, I as QueueOp, J as HubStatus, K as GlobalAnalytics, L as QueueOpInput, M as OfflineKindDefinition, N as ReplayContext, O as OfflineOp, P as CLIENT_VERSION_HEADER, Q as LeaderboardEntry, R as QueuedScoreOptions, S as SyncResult, T as OfflineEventDetails, U as GameInfo, V as BoardWithTop, W as GameLeaderboards, X as InventorySnapshot, Y as Inventory, Z as Json, _ as TradeNoteOptions, a as HubErrorDetails, at as SaveMeta, b as StatResult, c as Hub, ct as Stats, d as ClientSupport, dt as User, et as MeResponse, f as HubMenuControl, ft as EndpointFields, g as TradeListOptions, h as TradeId, ht as GamePayload, i as HubErrorCode, it as Save, j as OfflineHandler, k as OUTBOX_MAX_CHARS, l as createHub, lt as SubmitScoreOptions, m as TradeBundle, mt as EndpointReply, n as ContentRejectedError, nt as Profile, o as OfflineError, ot as SnapshotResponse, p as GrantBundle, pt as EndpointName, q as HubOptions, r as HubError, rt as ProfileSummary, s as UNSUPPORTED_BY_HUB, st as SortDir, t as HUB_CLIENT_VERSION, tt as Metrics, u as hub, ut as SubmitScoreResult, v as AuthResponse, w as OUTBOX_FULL_CODE, x as SyncConflict, y as ProfileUpdate, z as BufferedEvent } from "./shared/index.js";
12
- export { type Anchor, type Audience, type AuthResponse, type AutoPauseOptions, type AxisDef, type AxisSide, type Board, type BoardWithTop, type BufferedEvent, type BusyOptions, CLIENT_VERSION_HEADER, type ChatMode, type ClientSupport, ContentRejectedError, type Conversation, type Counts, DAILY_SINGLETON_API, DAILY_START_EVENT, type DailyAll, type DailyChallenge, type DailyCompleteResponse, type DailyCompletion, type DailyCompletionMeta, type DailyCompletions, type DailyDefinition, type DailyEventDetail, type DailyGameStatus, type DailyHost, type DailyStartResponse, type DailyStatus, DailySystem, type DraggedSpot, type EdgeOffsets, type EndpointFields, type EndpointName, type EndpointReply, type ErrorBody, FOCUS_RING_SHADOW, type FriendEntry, type GameAnalytics, type GameInfo, type GameLeaderboards, type GamePayload, type GameRecords, type GamepadMapping, type GlobalAnalytics, type GrantBundle, type GroupDef, HUB_CLIENT_VERSION, Hub, HubError, type HubErrorCode, type HubErrorDetails, type HubMenuControl, type HubMpApi, type HubNotifyApi, type HubOptions, type HubPresenceApi, type HubRaceApi, type HubRoom, type HubRoomsApi, type HubSocialApi, type HubStatus, INPUT_SINGLETON_API, type InputConfig, type InputDef, type InputEvents, type InputHost, type InputModality, type InputOptions, type InputOverrides, type InputReading, type InputSource, InputSystem, type InputSystemOptions, type Insets, type Inventory, type InventorySnapshot, type Invite, type InviteCreated, type InviteLink, type InviteLinkMethods, type InviteOptions, type InviteResult, type JoinInfo, type JoinInfoEvent, type JoinOptions, type Json, type Launch, type LaunchTicket, type LayoutBox, type LayoutItem, type LayoutOptions, type LeaderboardEntry, type LeaderboardResult, MODALITY_ATTRIBUTE, type MeResponse, type MenuBridge, type Message, type MessagesPage, type Metrics, type MouseMapping, type NavBlurEvent, type NavElement, type NavElementKind, type NavFocusEvent, type NavTarget, type NavigableDef, type Notice, type NotifyChange, type NotifyPrefs, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, type OfflineEventDetails, type OfflineEventName, type OfflineHandler, type OfflineKindDefinition, type OfflineListener, type OfflineOp, type OpenInviteOptions, Overlay, type OverlayEdge, type OverlayEvent, type OverlayListener, type OverlayReason, type PageInputControl, type Party, type PlayOnlineMethods, type PlayerCard, type PlayerLite, type PlayerRef, type Presence, type PresenceInput, type PresenceKind, type Profile, type ProfilePatch, type ProfileSummary, type ProfileUpdate, type QueueOp, type QueueOpInput, type QueuedScoreOptions, type REALTIME_FAILED_EVENT, type REALTIME_FEATURE_VERSION, type REALTIME_READY_EVENT, type REALTIME_SINGLETON_API, type RaceCreateOptions, type RaceDefinition, type RaceEvents, type RaceHistory, type RaceHistoryQuery, type RaceHistoryViewOptions, type RaceHudPlace, type RaceOutcome, type RaceParams, type RaceRecord, type RaceRecordPlayer, type RaceResult, type RaceResultPlayer, type RaceRuntimeApi, type RaceStart, type RaceStatValue, type RaceState, type RaceStats, type RaceStatusEvent, type Racer, type RacerResult, type RacerState, type RealtimeApi, type RealtimeErrorShape, type RealtimeHubLink, type RecentPlayer, type Rect, type Relation, type ReplayContext, type ReportInput, type ReportKind, type ReportReason, type RoomChatLine, type RoomCreateOptions, type RoomEvents, type RoomInfo, type RoomListOptions, type RoomMessage, type RoomReclaimMethods, type RoomSeat, type RoomSeatChange, type RoomSelf, type RoomSendOptions, type RoomState, type RoomStateChange, type RoomStateOptions, type Save, type SaveMeta, type SchemaOutput, type ServerEvents, type Snapshot, type SnapshotResponse, type SocialConfig, type SocialCounts, type SocialEvents, type SocialMe, type SortDir, type StatResult, type Stats, type SubmitScoreOptions, type SubmitScoreResult, type Suggestion, type SuggestionStatus, type SyncConflict, type SyncResult, type TouchMapping, type TradeBundle, type TradeId, type TradeListOptions, type TradeNoteOptions, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, type UiStack, type UiStackHandoff, type User, type Vector, type VirtualControlType, type VirtualDef, type VirtualInputs, type VirtualOverride, boxesTouch, controlSize, createHub, type findRealtimeApi, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, type isRealtimeApi, isUiStack, layoutControls, type linkRealtimeToHub, type multiplayerForwarder as mp, type notifyForwarder as notify, parseInputOverrides, type presenceForwarder as presence, type raceForwarder as race, type roomsForwarder as rooms, type socialForwarder as social, trackInputModality };
11
+ import { $ as GameInfo, A as StatResult, B as OUTBOX_MAX_ENTRIES, C as GrantBundle, Ct as EndpointName, D as TradeNoteOptions, E as TradeListOptions, F as OfflineEventDetails, G as ProfilePatch, H as OfflineKindDefinition, I as OfflineEventName, J as QueuedScoreOptions, K as QueueOp, L as OfflineListener, M as SyncResult, N as OfflineApi, O as AuthResponse, P as OUTBOX_FULL_CODE, Q as GameAnalytics, R as OfflineOp, S as HubMenuControl, St as EndpointFields, T as TradeId, Tt as GamePayload, U as ReplayContext, V as OfflineHandler, W as CLIENT_VERSION_HEADER, X as Board, Y as BufferedEvent, Z as BoardWithTop, _ as ResumeEntry, _t as SortDir, a as HubErrorDetails, at as Inventory, b as ResumeRun, bt as SubmitScoreResult, c as UNSUPPORTED_BY_HUB, ct as LeaderboardEntry, d as hub, dt as Metrics, et as GameLeaderboards, f as ClientSupport, ft as Profile, g as ResumeBlocker, gt as SnapshotResponse, h as RESUME_MAX_STATE_BYTES, ht as SaveMeta, i as HubErrorCode, it as HubStatus, j as SyncConflict, k as ProfileUpdate, l as Hub, lt as LeaderboardResult, m as RESUME_DEBOUNCE_MS, mt as Save, n as ContentRejectedError, nt as GlobalAnalytics, o as OfflineError, ot as InventorySnapshot, p as HubResume, pt as ProfileSummary, q as QueueOpInput, r as HubError, rt as HubOptions, s as SAVE_UNKNOWN_CODE, st as Json, t as HUB_CLIENT_VERSION, tt as GameRecords, u as createHub, ut as MeResponse, v as ResumeLoadOptions, vt as Stats, w as TradeBundle, wt as EndpointReply, x as ResumeSaveInput, xt as User, y as ResumeProgress, yt as SubmitScoreOptions, z as OUTBOX_MAX_CHARS } from "./shared/index.js";
12
+ export { type Anchor, type Audience, type AuthResponse, type AutoPauseOptions, type AxisDef, type AxisSide, type Board, type BoardWithTop, type BufferedEvent, type BusyOptions, CLIENT_VERSION_HEADER, type ChatMode, type ClientSupport, ContentRejectedError, type Conversation, type Counts, DAILY_SINGLETON_API, DAILY_START_EVENT, type DailyAll, type DailyChallenge, type DailyCompleteResponse, type DailyCompletion, type DailyCompletionMeta, type DailyCompletions, type DailyDefinition, type DailyEventDetail, type DailyGameStatus, type DailyHost, type DailyStartResponse, type DailyStatus, DailySystem, type DraggedSpot, type EdgeOffsets, type EndpointFields, type EndpointName, type EndpointReply, type ErrorBody, FOCUS_RING_SHADOW, type FriendEntry, type GameAnalytics, type GameInfo, type GameLeaderboards, type GamePayload, type GameRecords, type GamepadMapping, type GlobalAnalytics, type GrantBundle, type GroupDef, HUB_CLIENT_VERSION, Hub, HubError, type HubErrorCode, type HubErrorDetails, type HubMenuControl, type HubMpApi, type HubNotifyApi, type HubOptions, type HubPresenceApi, type HubRaceApi, HubResume, type HubRoom, type HubRoomsApi, type HubSocialApi, type HubStatus, INPUT_SINGLETON_API, type InputConfig, type InputDef, type InputEvents, type InputHost, type InputModality, type InputOptions, type InputOverrides, type InputReading, type InputSource, InputSystem, type InputSystemOptions, type Insets, type Inventory, type InventorySnapshot, type Invite, type InviteCreated, type InviteLink, type InviteLinkMethods, type InviteOptions, type InviteResult, type JoinInfo, type JoinInfoEvent, type JoinOptions, type Json, type Launch, type LaunchTicket, type LayoutBox, type LayoutItem, type LayoutOptions, type LeaderboardEntry, type LeaderboardResult, MODALITY_ATTRIBUTE, type MeResponse, type MenuBridge, type Message, type MessagesPage, type Metrics, type MouseMapping, type NavBlurEvent, type NavElement, type NavElementKind, type NavFocusEvent, type NavTarget, type NavigableDef, type Notice, type NotifyChange, type NotifyPrefs, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, type OfflineEventDetails, type OfflineEventName, type OfflineHandler, type OfflineKindDefinition, type OfflineListener, type OfflineOp, type OpenInviteOptions, Overlay, type OverlayEdge, type OverlayEvent, type OverlayListener, type OverlayReason, type PageInputControl, type Party, type PlayOnlineMethods, type PlayerCard, type PlayerLite, type PlayerRef, type Presence, type PresenceInput, type PresenceKind, type Profile, type ProfilePatch, type ProfileSummary, type ProfileUpdate, type QueueOp, type QueueOpInput, type QueuedScoreOptions, type REALTIME_FAILED_EVENT, type REALTIME_FEATURE_VERSION, type REALTIME_READY_EVENT, type REALTIME_SINGLETON_API, RESUME_DEBOUNCE_MS, RESUME_MAX_STATE_BYTES, type RaceCreateOptions, type RaceDefinition, type RaceEvents, type RaceHistory, type RaceHistoryQuery, type RaceHistoryViewOptions, type RaceHudPlace, type RaceOutcome, type RaceParams, type RaceRecord, type RaceRecordPlayer, type RaceResult, type RaceResultPlayer, type RaceRuntimeApi, type RaceStart, type RaceStatValue, type RaceState, type RaceStats, type RaceStatusEvent, type Racer, type RacerResult, type RacerState, type RealtimeApi, type RealtimeErrorShape, type RealtimeHubLink, type RecentPlayer, type Rect, type Relation, type ReplayContext, type ReportInput, type ReportKind, type ReportReason, type ResumeBlocker, type ResumeEntry, type ResumeLoadOptions, type ResumeProgress, type ResumeRun, type ResumeSaveInput, type RoomChatLine, type RoomCreateOptions, type RoomEvents, type RoomInfo, type RoomListOptions, type RoomMessage, type RoomReclaimMethods, type RoomSeat, type RoomSeatChange, type RoomSelf, type RoomSendOptions, type RoomState, type RoomStateChange, type RoomStateOptions, SAVE_UNKNOWN_CODE, type Save, type SaveMeta, type SchemaOutput, type ServerEvents, type Snapshot, type SnapshotResponse, type SocialConfig, type SocialCounts, type SocialEvents, type SocialMe, type SortDir, type StatResult, type Stats, type SubmitScoreOptions, type SubmitScoreResult, type Suggestion, type SuggestionStatus, type SyncConflict, type SyncResult, type TouchMapping, type TradeBundle, type TradeId, type TradeListOptions, type TradeNoteOptions, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, type UiStack, type UiStackHandoff, type User, type Vector, type VirtualControlType, type VirtualDef, type VirtualInputs, type VirtualOverride, boxesTouch, controlSize, createHub, type findRealtimeApi, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, type isRealtimeApi, isUiStack, layoutControls, type linkRealtimeToHub, type multiplayerForwarder as mp, type notifyForwarder as notify, parseInputOverrides, type presenceForwarder as presence, type raceForwarder as race, type roomsForwarder as rooms, type socialForwarder as social, trackInputModality };
package/dist/index.js CHANGED
@@ -2,5 +2,5 @@ import { a as DailySystem, i as DAILY_START_EVENT, n as getDaily, r as isDailySy
2
2
  import { t as HUB_CLIENT_VERSION } from "./shared/client-version.gen.js";
3
3
  import { a as isPageInputControl, c as layoutControls, d as MODALITY_ATTRIBUTE, f as trackInputModality, i as parseInputOverrides, l as boxesTouch, n as getInput, o as InputSystem, p as FOCUS_RING_SHADOW, r as isInputSystem, s as Overlay, t as INPUT_SINGLETON_API, u as controlSize } from "./shared/input.js";
4
4
  import { n as isUiStack, r as UI_STACK_VERSION, t as getUiStack } from "./shared/page-stack.js";
5
- import { a as OUTBOX_FULL_CODE, c as OfflineApi, d as OfflineError, f as UNSUPPORTED_BY_HUB, i as CLIENT_VERSION_HEADER, l as ContentRejectedError, n as createHub, o as OUTBOX_MAX_CHARS, r as hub, s as OUTBOX_MAX_ENTRIES, t as Hub, u as HubError } from "./shared/src.js";
6
- export { CLIENT_VERSION_HEADER, ContentRejectedError, DAILY_SINGLETON_API, DAILY_START_EVENT, DailySystem, FOCUS_RING_SHADOW, HUB_CLIENT_VERSION, Hub, HubError, INPUT_SINGLETON_API, InputSystem, MODALITY_ATTRIBUTE, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, Overlay, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, boxesTouch, controlSize, createHub, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, isUiStack, layoutControls, parseInputOverrides, trackInputModality };
5
+ import { a as RESUME_DEBOUNCE_MS, c as OUTBOX_FULL_CODE, d as OfflineApi, f as ContentRejectedError, g as UNSUPPORTED_BY_HUB, h as SAVE_UNKNOWN_CODE, i as HubResume, l as OUTBOX_MAX_CHARS, m as OfflineError, n as createHub, o as RESUME_MAX_STATE_BYTES, p as HubError, r as hub, s as CLIENT_VERSION_HEADER, t as Hub, u as OUTBOX_MAX_ENTRIES } from "./shared/src.js";
6
+ export { CLIENT_VERSION_HEADER, ContentRejectedError, DAILY_SINGLETON_API, DAILY_START_EVENT, DailySystem, FOCUS_RING_SHADOW, HUB_CLIENT_VERSION, Hub, HubError, HubResume, INPUT_SINGLETON_API, InputSystem, MODALITY_ATTRIBUTE, OUTBOX_FULL_CODE, OUTBOX_MAX_CHARS, OUTBOX_MAX_ENTRIES, OfflineApi, OfflineError, Overlay, RESUME_DEBOUNCE_MS, RESUME_MAX_STATE_BYTES, SAVE_UNKNOWN_CODE, UI_STACK_VERSION, UNSUPPORTED_BY_HUB, boxesTouch, controlSize, createHub, getDaily, getInput, getUiStack, hub, isDailySystem, isInputSystem, isPageInputControl, isUiStack, layoutControls, parseInputOverrides, trackInputModality };
package/dist/rooms.js CHANGED
@@ -1 +1 @@
1
- export { t as rooms } from "./shared/rooms.js";
1
+ export { n as rooms } from "./shared/rooms.js";
@@ -1,6 +1,6 @@
1
1
  //#region src/core/version/client-version.gen.ts
2
2
  /** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
3
- const HUB_CLIENT_VERSION = "2.0.0-next.3";
3
+ const HUB_CLIENT_VERSION = "2.0.0-next.5";
4
4
  //#endregion
5
5
  export { HUB_CLIENT_VERSION as t };
6
6
 
@@ -71,8 +71,12 @@ declare const DAILY_START_EVENT = "hub:daily-start";
71
71
  /** Daily challenges (`hub.daily`). */
72
72
  declare class DailySystem {
73
73
  /**
74
- * The challenge in progress (set when a day starts, cleared on complete).
75
- * A game's win handler checks it: `if (hub.daily.active) hub.daily.complete(…)`.
74
+ * The challenge in progress: set when a day starts; cleared the moment the
75
+ * game calls `complete` (whatever the hub answers, and before it answers)
76
+ * or `cancel`. A game's win handler checks it:
77
+ * `if (hub.daily.active) hub.daily.complete(…)`. While it is set the page
78
+ * is in a daily run, so `hub.resume.save` saves nothing: a game whose
79
+ * player leaves a daily unfinished must call `cancel()`.
76
80
  */
77
81
  active: DailyChallenge | null;
78
82
  private readonly host;
@@ -100,12 +104,17 @@ declare class DailySystem {
100
104
  * Resolves with the new completion count and rank, or `null` when no
101
105
  * challenge is active, the hub refused, or the hub can't be reached: then
102
106
  * the completion is queued (`hub:daily-queued`) and replays when it is
103
- * back (`hub:daily-complete` follows).
107
+ * back (`hub:daily-complete` follows). The daily run ends at the call,
108
+ * so `active` is `null` at once, even if the hub then refuses it.
104
109
  */
105
110
  complete(meta?: DailyCompletionMeta): Promise<DailyCompleteResponse | null>;
106
111
  /** Ask the page's other daily systems to start `day` (this one ignores its own event). */
107
112
  private relayStart;
108
- /** Abandon the active challenge without recording it (e.g. the player quit). */
113
+ /**
114
+ * Abandon the active challenge without recording it: the player quit, or
115
+ * left the daily for normal play (another level, a new game). Until then
116
+ * the page counts as in a daily run and `hub.resume.save` saves nothing.
117
+ */
109
118
  cancel(): void;
110
119
  /** This game's window and the player's completions. */
111
120
  status(): Promise<DailyStatus>;
@@ -1 +1 @@
1
- {"version":3,"file":"daily.d.ts","names":[],"sources":["../../src/daily/types.ts","../../src/daily/daily-system.ts","../../src/daily/page-daily.ts"],"mappings":";;;;KAQK,cAAc,0BAA0B,kBAAkB,qBAAqB,gBAAgB;;KAGxF,cAAc;;KAGd,WAAW;;KAGX,kBAAkB;;KAGlB,qBAAqB;;KAGrB,wBAAwB;;UAGnB;;EAEf;;EAEA;;EAEA;;EAEA;;;UAIe;;EAEf,OAAO,WAAW;;;KAIR,sBAAsB,eAAe;;UAGhC;;WAEN;;EAET,UAAU,QAAQ;;EAElB,OAAO,QAAQ;;EAEf,MAAM,cAAc,QAAQ;;EAE5B,SAAS,aAAa,eAAe,MAAM,sBAAsB,QAAQ;;EAEzE,KAAK,cAAc,QAAQ;;;KAIjB;EACN;EAAa;EAAc;;EAC3B;EAAa;EAAe;EAAqB,MAAM;;EACvD;EAAa;EAAc,MAAM;;EACjC;EAAa;;;;;cCnDN;;cA0BA;;;;;EAKX,QAAQ;mBACS;UACT;UACA;UACA;EAEI,YAAA,MAAM;;MAiBd;;;;;;EASJ,OAAO,YAAY;;;;;;;EAeb,aAAa,cAAc;;;;;;;;EAyB3B,SAAS,OAAM,sBAA2B,QAAQ;;UAsBhD;;EAaR;;EAKA,UAAU,QAAQ;;EAKlB,OAAO,QAAQ;;;;;cCzJJ;;iBAIG,cAAc,qBAAqB,aAAa;;;;;;iBAWhD,SAAS,MAAM,YAAY"}
1
+ {"version":3,"file":"daily.d.ts","names":[],"sources":["../../src/daily/types.ts","../../src/daily/daily-system.ts","../../src/daily/page-daily.ts"],"mappings":";;;;KAQK,cAAc,0BAA0B,kBAAkB,qBAAqB,gBAAgB;;KAGxF,cAAc;;KAGd,WAAW;;KAGX,kBAAkB;;KAGlB,qBAAqB;;KAGrB,wBAAwB;;UAGnB;;EAEf;;EAEA;;EAEA;;EAEA;;;UAIe;;EAEf,OAAO,WAAW;;;KAIR,sBAAsB,eAAe;;UAGhC;;WAEN;;EAET,UAAU,QAAQ;;EAElB,OAAO,QAAQ;;EAEf,MAAM,cAAc,QAAQ;;EAE5B,SAAS,aAAa,eAAe,MAAM,sBAAsB,QAAQ;;EAEzE,KAAK,cAAc,QAAQ;;;KAIjB;EACN;EAAa;EAAc;;EAC3B;EAAa;EAAe;EAAqB,MAAM;;EACvD;EAAa;EAAc,MAAM;;EACjC;EAAa;;;;;cCnDN;;cA0BA;;;;;;;;;EASX,QAAQ;mBACS;UACT;UACA;UACA;EAEI,YAAA,MAAM;;MAiBd;;;;;;EASJ,OAAO,YAAY;;;;;;;EAeb,aAAa,cAAc;;;;;;;;;EA0B3B,SAAS,OAAM,sBAA2B,QAAQ;;UAsBhD;;;;;;EAiBR;;EAKA,UAAU,QAAQ;;EAKlB,OAAO,QAAQ;;;;;cClKJ;;iBAIG,cAAc,qBAAqB,aAAa;;;;;;iBAWhD,SAAS,MAAM,YAAY"}
@@ -34,8 +34,12 @@ var DailySystem = class {
34
34
  _defineProperty(
35
35
  this,
36
36
  /**
37
- * The challenge in progress (set when a day starts, cleared on complete).
38
- * A game's win handler checks it: `if (hub.daily.active) hub.daily.complete(…)`.
37
+ * The challenge in progress: set when a day starts; cleared the moment the
38
+ * game calls `complete` (whatever the hub answers, and before it answers)
39
+ * or `cancel`. A game's win handler checks it:
40
+ * `if (hub.daily.active) hub.daily.complete(…)`. While it is set the page
41
+ * is in a daily run, so `hub.resume.save` saves nothing: a game whose
42
+ * player leaves a daily unfinished must call `cancel()`.
39
43
  */
40
44
  "active",
41
45
  null
@@ -106,14 +110,15 @@ var DailySystem = class {
106
110
  * Resolves with the new completion count and rank, or `null` when no
107
111
  * challenge is active, the hub refused, or the hub can't be reached: then
108
112
  * the completion is queued (`hub:daily-queued`) and replays when it is
109
- * back (`hub:daily-complete` follows).
113
+ * back (`hub:daily-complete` follows). The daily run ends at the call,
114
+ * so `active` is `null` at once, even if the hub then refuses it.
110
115
  */
111
116
  async complete(meta = {}) {
112
117
  const challenge = this.active;
113
118
  if (challenge === null) return null;
119
+ this.active = null;
114
120
  try {
115
121
  const completed = await this.host.complete(challenge.day, challenge.token, meta);
116
- this.active = null;
117
122
  if (completed === null) {
118
123
  this.host.emit("hub:daily-queued", {
119
124
  day: challenge.day,
@@ -147,7 +152,11 @@ var DailySystem = class {
147
152
  this.isRelaying = false;
148
153
  }
149
154
  }
150
- /** Abandon the active challenge without recording it (e.g. the player quit). */
155
+ /**
156
+ * Abandon the active challenge without recording it: the player quit, or
157
+ * left the daily for normal play (another level, a new game). Until then
158
+ * the page counts as in a daily run and `hub.resume.save` saves nothing.
159
+ */
151
160
  cancel() {
152
161
  this.active = null;
153
162
  }
@@ -188,7 +197,7 @@ let claimedDaily = null;
188
197
  function getDaily(host) {
189
198
  claimedDaily ?? (claimedDaily = claimSingleton({
190
199
  name: "daily",
191
- version: "2.0.0-next.3",
200
+ version: "2.0.0-next.5",
192
201
  api: 1,
193
202
  create: () => new DailySystem(host),
194
203
  isInstance: isDailySystem
@@ -1 +1 @@
1
- {"version":3,"file":"daily.js","names":[],"sources":["../../src/daily/daily-system.ts","../../src/daily/page-daily.ts"],"mappings":";;;;;;;;;;;;;AAaA,MAAM,cAAc;;AAGpB,MAAa,oBAAoB;;AAIjC,SAAS,SAAS,WAAmC;CACnD,OAAO,OAAO,cAAc,YAAY,YAAY,KAAK,SAAS,IAAI,YAAY;AACpF;;AAGA,SAAS,kBAAiC;CAGxC,MAAM,WAAW,OAAO,WAAW,cAAc,OAAO,SAAS,UAAU,QAAQ,gBAAgB,CAAC;CACpG,IAAI,aAAa,QAAQ,OAAO,aAAa,aAC3C,OAAO;CAET,OAAO,SAAS,IAAI,IAAI,SAAS,IAAI,CAAC,CAAC,aAAa,IAAI,OAAO,CAAC;AAClE;;AAIA,SAAS,UAAU,OAAwB;CACzC,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;;AAGA,IAAa,cAAb,MAAyB;CAWvB,YAAY,MAAiB;;;;;;;GAN7B;GAAgC;;EACf,gBAAA,MAAA,QAAA,KAAA,CAAA;EACT,gBAAA,MAAA,QAAuC,IAAA;EACvC,gBAAA,MAAA,cAA4B,IAAA;EAC5B,gBAAA,MAAA,cAAa,KAAA;EAGnB,KAAK,OAAO;EACZ,IAAI,OAAO,WAAW,aAEpB,OAAO,iBAAiB,oBAAoB,UAAU;GACpD,IAAI,KAAK,YACP;GAEF,MAAM,MAAM,iBAAiB,cAAc,UAAU,MAAM,QAAQ,KAAK,IAAI,KAAA;GAC5E,IAAI,OAAO,QAAQ,UACjB,KAAU,aAAa,GAAG;EAE9B,CAAC;CAEL;;CAGA,IAAI,YAAqB;EACvB,OAAO,KAAK,SAAS;CACvB;;;;;;CAOA,OAAO,YAAmC;EACxC,KAAK,OAAO,WAAW;EACvB,MAAM,MAAM,gBAAgB,KAAK,KAAK;EACtC,KAAK,aAAa;EAClB,IAAI,QAAQ,MACV,KAAU,aAAa,GAAG;CAE9B;;;;;;;CAQA,MAAM,aAAa,KAA4B;EAC7C,MAAM,OAAO,KAAK;EAClB,IAAI,SAAS,MAAM;GACjB,KAAK,aAAa;GAClB,KAAK,WAAW,GAAG;GACnB;EACF;EACA,IAAI;GACF,MAAM,UAAU,MAAM,KAAK,KAAK,MAAM,GAAG;GACzC,MAAM,YAA4B;IAAE,KAAK,QAAQ;IAAK,MAAM,QAAQ;IAAM,OAAO,QAAQ;IAAO,kBAAkB,QAAQ;GAAiB;GAC3I,KAAK,SAAS;GACd,KAAK,KAAK,KAAK,qBAAqB;IAAE,KAAK,QAAQ;IAAK,MAAM,QAAQ;IAAM,kBAAkB,QAAQ;GAAiB,CAAC;GACxH,KAAK,EAAE,GAAG,UAAU,CAAC;EACvB,SAAS,OAAO;GACd,KAAK,KAAK,KAAK,mBAAmB;IAAE;IAAK,OAAO,UAAU,KAAK;GAAE,CAAC;EACpE;CACF;;;;;;;;CASA,MAAM,SAAS,OAA4B,CAAC,GAA0C;EACpF,MAAM,YAAY,KAAK;EACvB,IAAI,cAAc,MAChB,OAAO;EAET,IAAI;GACF,MAAM,YAAY,MAAM,KAAK,KAAK,SAAS,UAAU,KAAK,UAAU,OAAO,IAAI;GAC/E,KAAK,SAAS;GACd,IAAI,cAAc,MAAM;IAEtB,KAAK,KAAK,KAAK,oBAAoB;KAAE,KAAK,UAAU;KAAK,QAAQ;KAAM;IAAK,CAAC;IAC7E,OAAO;GACT;GACA,KAAK,KAAK,KAAK,sBAAsB;IAAE,KAAK,UAAU;IAAK,OAAO,UAAU;IAAO,MAAM,UAAU;IAAM;GAAK,CAAC;GAC/G,OAAO;EACT,SAAS,OAAO;GACd,KAAK,KAAK,KAAK,mBAAmB;IAAE,KAAK,UAAU;IAAK,OAAO,UAAU,KAAK;GAAE,CAAC;GACjF,OAAO;EACT;CACF;;CAGA,WAAmB,KAAmB;EACpC,IAAI,OAAO,WAAW,aACpB;EAEF,KAAK,aAAa;EAClB,IAAI;GACF,OAAO,cAAc,IAAI,YAAY,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;EAC9E,UAAU;GACR,KAAK,aAAa;EACpB;CACF;;CAGA,SAAe;EACb,KAAK,SAAS;CAChB;;CAGA,SAA+B;EAC7B,OAAO,KAAK,KAAK,OAAO;CAC1B;;CAGA,MAAyB;EACvB,OAAO,KAAK,KAAK,IAAI;CACvB;AACF;;;;;;;;AC5JA,MAAa,sBAAsB;;AAInC,SAAgB,cAAc,WAA8C;CAC1E,OAAO,WAAW,WAAW;EAAC;EAAU;EAAgB;EAAY;EAAU;EAAU;CAAK,CAAC;AAChG;AAEA,IAAI,eAAmC;;;;;;AAOvC,SAAgB,SAAS,MAA8B;CACrD,iBAAA,eAAiB,eAAe;EAC9B,MAAM;EACN,SAAA;EACA,KAAA;EACA,cAAc,IAAI,YAAY,IAAI;EAClC,YAAY;CACd,CAAC;CACD,OAAO;AACT"}
1
+ {"version":3,"file":"daily.js","names":[],"sources":["../../src/daily/daily-system.ts","../../src/daily/page-daily.ts"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { o as multiplayerForwarder } from "./mp.js";
4
4
  import { f as raceForwarder } from "./race.js";
5
5
  import { n as roomsForwarder } from "./rooms.js";
6
6
  import { Q as socialForwarder, X as notifyForwarder, Z as presenceForwarder } from "./social.js";
7
- import { Board, Board as Board$1, ErrorCode, GameInfo, GameLeaderboards, GameRecords, HubVersion, Inventory, Inventory as Inventory$1, Json, Json as Json$1, LeaderboardEntry, Metrics, Metrics as Metrics$1, PublicEndpoints, RejectReason, SessionUser, SortDir, SortDir as SortDir$1, Stats, Stats as Stats$1 } from "@diffenderfer-games/hub-contract";
7
+ import { Board, Board as Board$1, ErrorCode, GameInfo, GameLeaderboards, GameRecords, HubVersion, Inventory, Inventory as Inventory$1, Json, Json as Json$1, LeaderboardEntry, Metrics, Metrics as Metrics$1, PublicEndpoints, RejectReason, ResumeSlot, ResumeSummary, SessionUser, SortDir, SortDir as SortDir$1, Stats, Stats as Stats$1 } from "@diffenderfer-games/hub-contract";
8
8
  import { CallReturn, ClientData } from "@ayepi/core/client";
9
9
  //#region src/core/storage/key-value.d.ts
10
10
  /**
@@ -256,6 +256,16 @@ declare class LocalStore {
256
256
  putSave(slot: string, saveData: Json, label: string | null): number;
257
257
  /** Forget a save. */
258
258
  deleteSave(slot: string): void;
259
+ /**
260
+ * The hub's `updatedAt` for `slot` as the current user last saw it (`null`:
261
+ * the slot was empty), or `undefined` when this device doesn't know.
262
+ */
263
+ cloudSave(slot: string): number | null | undefined;
264
+ /** Note the hub's copy of `slot` (just read or written) for the current user: its `updatedAt`, or `null` when empty. */
265
+ rememberCloudSave(slot: string, updatedAt: number | null): void;
266
+ /** Cache a slot as read from the hub (forgetting it when the hub has none), and note the hub's copy. */
267
+ cacheCloudSave(slot: string, save: Save | null): void;
268
+ private readCloudSaves;
259
269
  /** This game's cached stats. */
260
270
  getStats(): Stats;
261
271
  /** Apply one stat update and return the stat's new value. */
@@ -278,7 +288,12 @@ declare class LocalStore {
278
288
  setEvents(events: readonly BufferedEvent[]): void;
279
289
  /** Buffer one event (capped; heartbeats are dropped first). */
280
290
  bufferEvent(type: string): void;
281
- /** Fan a `/me/snapshot` reply out across every game's cache keys. */
291
+ /**
292
+ * Fan a `/me/snapshot` reply out across every game's cache keys. It lists
293
+ * every save slot of every game the player has played, so each game's
294
+ * slots on the hub become known (and this game's are all empty when it
295
+ * isn't listed).
296
+ */
282
297
  hydrate(snapshot: SnapshotResponse): void;
283
298
  }
284
299
  //#endregion
@@ -544,6 +559,47 @@ declare class OfflineApi {
544
559
  on<Name extends OfflineEventName>(name: Name, listener: OfflineListener<Name>): () => void;
545
560
  }
546
561
  //#endregion
562
+ //#region src/core/resume/local-resume.d.ts
563
+ /** A run as this device saved it. */
564
+ interface LocalRun {
565
+ readonly status: 'saved';
566
+ readonly userId: number | null;
567
+ /** When the game saved it, epoch ms. */
568
+ readonly at: number;
569
+ readonly label: string;
570
+ readonly fraction: number | null;
571
+ readonly title: string | null;
572
+ readonly version: number;
573
+ /** The game's title, for the Resume card before the hub knows the run. */
574
+ readonly gameTitle: string;
575
+ readonly state: Json;
576
+ readonly isSynced: boolean;
577
+ }
578
+ /** A run this device cleared (kept until the hub has the clear). */
579
+ interface LocalClear {
580
+ readonly status: 'cleared';
581
+ readonly userId: number | null;
582
+ readonly at: number;
583
+ readonly isSynced: boolean;
584
+ }
585
+ /** A device copy of one game's slot. */
586
+ type LocalResume = LocalRun | LocalClear;
587
+ /** The device copies of every game's slot. */
588
+ declare class LocalResumeStore {
589
+ private readonly store;
590
+ constructor(store: KeyValueStore);
591
+ /** `slug`'s copy, or `null`. */
592
+ read(slug: string): LocalResume | null;
593
+ /** Store `slug`'s copy; answers whether it stuck (a full storage refuses a large state). */
594
+ write(slug: string, record: LocalResume): boolean;
595
+ /** Forget `slug`'s copy. */
596
+ remove(slug: string): void;
597
+ /** The hub now has `slug`'s save or clear made at `at`: mark it synced (a clear is simply forgotten). */
598
+ markSynced(slug: string, at: number): void;
599
+ /** Every game's copy, by slug. */
600
+ all(): Map<string, LocalResume>;
601
+ }
602
+ //#endregion
547
603
  //#region src/core/connection.d.ts
548
604
  /** A queued op the hub refused during a sync (or that kept failing): dropped, with the reason. */
549
605
  interface SyncConflict {
@@ -576,6 +632,8 @@ declare class HubConnection {
576
632
  protected readonly store: LocalStore;
577
633
  /** This game's queued operations. */
578
634
  protected readonly outbox: Outbox;
635
+ /** The device copies of every game's resume slot (`hub.resume`). */
636
+ protected readonly resumeStore: LocalResumeStore;
579
637
  private readonly offlineMode;
580
638
  private isReachable;
581
639
  private runningSync;
@@ -697,6 +755,8 @@ declare class HubProgress extends HubConnection {
697
755
  ok: true;
698
756
  }>;
699
757
  private signInLocally;
758
+ /** Remember who the hub signed in, so the cache's notes about the hub's copies are read for the right player. */
759
+ private signedIn;
700
760
  /** This game's profile for the current user, or `profile: null`. `TData` is the game's own data type. */
701
761
  getProfile<TData = Json>(): Promise<{
702
762
  profile: Profile<TData> | null;
@@ -709,10 +769,18 @@ declare class HubProgress extends HubConnection {
709
769
  listSaves(): Promise<{
710
770
  saves: SaveMeta[];
711
771
  }>;
712
- /** One slot's contents, or `save: null` when the slot is empty. `TData` is the game's own save type. */
772
+ /**
773
+ * One slot's contents, or `save: null` when the slot is empty. `TData` is
774
+ * the game's own save type. Offline it answers from the device's copy, but
775
+ * only when the device knows the hub's copy of the slot; otherwise (a fresh
776
+ * device or cleared browser) it rejects with a {@link HubError} whose
777
+ * `code` is `save_unknown` (`isOffline` is `true`), never a false "empty".
778
+ */
713
779
  getSave<TData = Json>(slot: string): Promise<{
714
780
  save: Save<TData> | null;
715
781
  }>;
782
+ /** The device's copy of `slot`, when it can be trusted offline (see {@link getSave}). */
783
+ private offlineSave;
716
784
  /** Create or overwrite a save slot. `saveData` is any JSON up to 64 KB. */
717
785
  putSave<TData extends GamePayload = Json>(slot: string, saveData: TData, label?: string): Promise<{
718
786
  ok: true;
@@ -851,6 +919,154 @@ interface HubMenuControl {
851
919
  readonly visible: boolean;
852
920
  }
853
921
  //#endregion
922
+ //#region src/core/offline/hub-kinds/resume-kind.d.ts
923
+ /** Send the run saved at `savedAt`; `state` only when the device copy couldn't hold it. */
924
+ type ResumeSavePayload = {
925
+ readonly action: 'save';
926
+ readonly savedAt: number;
927
+ readonly label: string;
928
+ readonly fraction: number | null;
929
+ readonly title: string | null;
930
+ readonly version: number;
931
+ readonly state?: Json;
932
+ };
933
+ /** Clear the run, unless one was saved after `before`. */
934
+ type ResumeClearPayload = {
935
+ readonly action: 'clear';
936
+ readonly before: number;
937
+ };
938
+ /** One resume op. */
939
+ type ResumePayload = ResumeSavePayload | ResumeClearPayload;
940
+ //#endregion
941
+ //#region src/core/resume/resume-types.d.ts
942
+ /** How far along a run is. */
943
+ interface ResumeProgress {
944
+ /** A short line the game writes, such as "Level 12" or "Round 3 of 5" (up to 60 characters). */
945
+ readonly label: string;
946
+ /** 0 to 1, drawn as a progress bar; leave it out when the game can't say. */
947
+ readonly fraction?: number | null;
948
+ }
949
+ /** A run to save. `TState` is the game's own JSON-safe state type. */
950
+ interface ResumeSaveInput<TState extends GamePayload> {
951
+ /** Everything the game needs to pick the run up again (up to 512 KB as JSON). */
952
+ readonly state: TState;
953
+ readonly progress: ResumeProgress;
954
+ /** An optional name for the run ("Klondike, draw 3"), shown under the game's name. */
955
+ readonly title?: string | null;
956
+ /** The game's state version (default 0). Bump it when `state` changes shape; see `load({ version })`. */
957
+ readonly version?: number;
958
+ }
959
+ /** A saved run, read back. */
960
+ interface ResumeRun<TState> {
961
+ readonly state: TState;
962
+ readonly progress: {
963
+ readonly label: string;
964
+ readonly fraction: number | null;
965
+ };
966
+ readonly title: string | null;
967
+ readonly version: number;
968
+ /** When the game saved it, epoch ms. */
969
+ readonly savedAt: number;
970
+ }
971
+ /** Options for reading the run back. */
972
+ interface ResumeLoadOptions {
973
+ /**
974
+ * The state version this code reads. A run saved with an older version is
975
+ * dropped (cleared) and reads as `null`; a newer one (from a newer copy of
976
+ * the game in another tab) reads as `null` but is kept.
977
+ */
978
+ readonly version?: number;
979
+ }
980
+ /** One saved run in the player's list (the home page's Resume card). */
981
+ interface ResumeEntry {
982
+ /** The game's slug. */
983
+ readonly slug: string;
984
+ readonly gameTitle: string;
985
+ /** The game's URL path, like `/solitaire`. */
986
+ readonly path: string;
987
+ /** The game has a tile image (`/_tiles/<slug>`). */
988
+ readonly hasImage: boolean;
989
+ readonly progress: {
990
+ readonly label: string;
991
+ readonly fraction: number | null;
992
+ };
993
+ readonly title: string | null;
994
+ /** When it was saved, epoch ms. */
995
+ readonly savedAt: number;
996
+ /** Saved on this device and not yet sent to the hub (offline, or the tab closed first). */
997
+ readonly isLocalOnly: boolean;
998
+ }
999
+ /** Why a save was ignored: the page is in a race, a daily challenge or an online room. */
1000
+ type ResumeBlocker = 'race' | 'daily' | 'room';
1001
+ //#endregion
1002
+ //#region src/core/resume/hub-resume.d.ts
1003
+ /** How long saves must be quiet before the latest is sent, ms. */
1004
+ declare const RESUME_DEBOUNCE_MS = 3000;
1005
+ /** Largest state, bytes of JSON (the contract's `RESUME_MAX_STATE_BYTES`). */
1006
+ declare const RESUME_MAX_STATE_BYTES: number;
1007
+ /** What `hub.resume` needs from its client. */
1008
+ interface ResumeHost {
1009
+ /** This game's slug; `null` on the home page. */
1010
+ readonly slug: string | null;
1011
+ readonly local: LocalResumeStore;
1012
+ /** The signed-in player's id as the device knows it, or `null`. */
1013
+ currentUserId(): number | null;
1014
+ /** The game's display title. */
1015
+ gameTitle(): string;
1016
+ /** Why saving is off right now, or `null`. */
1017
+ blocker(): ResumeBlocker | null;
1018
+ /** Perform a resume op: at once when online with nothing waiting, else queued. */
1019
+ send(payload: ResumePayload): Promise<void>;
1020
+ /** This game's run on the hub, or `undefined` when the hub can't be reached. */
1021
+ fetchSlot(): Promise<ResumeSlot | null | undefined>;
1022
+ /** The player's runs on the hub, or `undefined` when it can't be reached. */
1023
+ fetchList(): Promise<ResumeSummary[] | undefined>;
1024
+ /** Clear another game's run on the hub (the home page's discard); throws offline. */
1025
+ clearOther(slug: string): Promise<void>;
1026
+ }
1027
+ /** `hub.resume`. */
1028
+ declare class HubResume {
1029
+ private readonly host;
1030
+ private timer;
1031
+ private waiting;
1032
+ private isListening;
1033
+ private readonly warnedBlockers;
1034
+ constructor(host: ResumeHost);
1035
+ /**
1036
+ * `true` when the page was opened from the Resume card (`?hub_resume=1`,
1037
+ * taken out of the address bar). Synchronous, so a game can restore before
1038
+ * it routes or draws its title screen.
1039
+ */
1040
+ get requested(): boolean;
1041
+ /** Why a save would be ignored right now (`race`, `daily`, `room`), or `null`. */
1042
+ get blockedBy(): ResumeBlocker | null;
1043
+ /**
1044
+ * Save the run (the latest save wins). Stored on the device at once; sent
1045
+ * after {@link RESUME_DEBOUNCE_MS} of quiet, or when the page is hidden.
1046
+ * Returns `false` (and saves nothing) in a race, a daily challenge or an
1047
+ * online room. Throws a `HubError` 413 over 512 KB, 400 without a label.
1048
+ */
1049
+ save<TState extends GamePayload>(run: ResumeSaveInput<TState>): boolean;
1050
+ /** Send a waiting save now (the page does this itself when hidden or closed). */
1051
+ flush(): Promise<void>;
1052
+ /** Clear the run: call it when the run ends (won, lost or quit). Works offline. */
1053
+ clear(): Promise<void>;
1054
+ /** The saved run with its progress and time, or `null`. The newer of the device's copy and the hub's wins. */
1055
+ get<TState = GamePayload>(options?: ResumeLoadOptions): Promise<ResumeRun<TState> | null>;
1056
+ /** The saved state, or `null` (see {@link get} for the version rule). */
1057
+ load<TState = GamePayload>(options?: ResumeLoadOptions): Promise<TState | null>;
1058
+ /** The player's saved runs in every resumable game, newest first (the home page's Resume card). */
1059
+ list(): Promise<ResumeEntry[]>;
1060
+ /** Discard another game's run from the home page (online only: throws a `HubError` offline). */
1061
+ discard(slug: string): Promise<void>;
1062
+ /** Say once per blocker why saves are ignored, so a game that forgot `hub.daily.cancel()` finds out. */
1063
+ private warnBlocked;
1064
+ private requireSlug;
1065
+ private schedule;
1066
+ /** Send a waiting save as soon as the page is hidden or closed. */
1067
+ private listenToPage;
1068
+ }
1069
+ //#endregion
854
1070
  //#region src/core/version/hub-version.d.ts
855
1071
  /** How a hub regards a client version. */
856
1072
  type ClientSupport =
@@ -868,6 +1084,7 @@ type ClientSupport =
868
1084
  declare class Hub extends HubEconomy {
869
1085
  /** This client's package version (sent as `x-hub-client`). */
870
1086
  readonly clientVersion: string;
1087
+ private resumeApi;
871
1088
  /**
872
1089
  * The hub's version and the client versions it supports (`GET /_api/version`),
873
1090
  * read once per page. `null` for a hub from before versioning.
@@ -903,6 +1120,14 @@ declare class Hub extends HubEconomy {
903
1120
  get notify(): typeof notifyForwarder;
904
1121
  /** Races: a single-player game becomes multiplayer by racing. */
905
1122
  get race(): typeof raceForwarder;
1123
+ /**
1124
+ * Resume a saved game: `hub.resume.save({ state, progress })` during a long
1125
+ * single-player run, `clear()` when it ends, `load()` and `requested` to
1126
+ * pick it up again (docs: "Resume saved games"). Needs `game.resumable: true`.
1127
+ */
1128
+ get resume(): HubResume;
1129
+ /** What `hub.resume` needs from this client. */
1130
+ private resumeHost;
906
1131
  /** What the daily system needs from this client: its REST calls and window events. */
907
1132
  private dailyHost;
908
1133
  }
@@ -919,12 +1144,18 @@ declare function createHub(options?: HubOptions): Hub;
919
1144
  declare const UNSUPPORTED_BY_HUB = "unsupported_by_hub";
920
1145
  /** The code the social runtime gives a call it could not send (no connection). */
921
1146
  declare const OFFLINE_CODE = "offline";
1147
+ /**
1148
+ * The code `getSave` rejects with when the hub can't be reached and this
1149
+ * device has no copy of the slot it can trust (a fresh device or cleared
1150
+ * browser): the slot may well hold a save, so it is not reported empty.
1151
+ */
1152
+ declare const SAVE_UNKNOWN_CODE = "save_unknown";
922
1153
  /**
923
1154
  * A machine-readable error code: one of the contract's public codes
924
1155
  * (`content_rejected`, `rate_limited`, `suspended`, `claim_required`, ...),
925
1156
  * {@link UNSUPPORTED_BY_HUB}, or a code a newer hub added.
926
1157
  */
927
- type HubErrorCode = ErrorCode | typeof UNSUPPORTED_BY_HUB | typeof OFFLINE_CODE | (string & Record<never, never>);
1158
+ type HubErrorCode = ErrorCode | typeof UNSUPPORTED_BY_HUB | typeof OFFLINE_CODE | typeof SAVE_UNKNOWN_CODE | (string & Record<never, never>);
928
1159
  /** The machine-readable extras the hub attaches to an error body. */
929
1160
  interface HubErrorDetails {
930
1161
  /** A stable error code, for code to branch on. */
@@ -979,7 +1210,7 @@ declare class ContentRejectedError extends HubError {
979
1210
  //#endregion
980
1211
  //#region src/core/version/client-version.gen.d.ts
981
1212
  /** This client's package version, sent as `x-hub-client` on REST calls and `client` in `hello`. */
982
- declare const HUB_CLIENT_VERSION = "2.0.0-next.3";
1213
+ declare const HUB_CLIENT_VERSION = "2.0.0-next.5";
983
1214
  //#endregion
984
- export { LeaderboardResult as $, OUTBOX_MAX_ENTRIES as A, Board$1 as B, OfflineApi as C, OfflineListener as D, OfflineEventName as E, ProfilePatch as F, GameRecords as G, GameAnalytics as H, QueueOp as I, HubStatus as J, GlobalAnalytics as K, QueueOpInput as L, OfflineKindDefinition as M, ReplayContext as N, OfflineOp as O, CLIENT_VERSION_HEADER as P, LeaderboardEntry as Q, QueuedScoreOptions as R, SyncResult as S, OfflineEventDetails as T, GameInfo$1 as U, BoardWithTop as V, GameLeaderboards as W, InventorySnapshot as X, Inventory$1 as Y, Json$1 as Z, TradeNoteOptions as _, HubErrorDetails as a, SaveMeta as at, StatResult as b, Hub as c, Stats$1 as ct, ClientSupport as d, User as dt, MeResponse as et, HubMenuControl as f, EndpointFields as ft, TradeListOptions as g, TradeId as h, GamePayload as ht, HubErrorCode as i, Save as it, OfflineHandler as j, OUTBOX_MAX_CHARS as k, createHub as l, SubmitScoreOptions as lt, TradeBundle as m, EndpointReply as mt, ContentRejectedError as n, Profile as nt, OfflineError as o, SnapshotResponse as ot, GrantBundle as p, EndpointName as pt, HubOptions as q, HubError as r, ProfileSummary as rt, UNSUPPORTED_BY_HUB as s, SortDir$1 as st, HUB_CLIENT_VERSION as t, Metrics$1 as tt, hub as u, SubmitScoreResult as ut, AuthResponse as v, OUTBOX_FULL_CODE as w, SyncConflict as x, ProfileUpdate as y, BufferedEvent as z };
1215
+ export { GameInfo$1 as $, StatResult as A, OUTBOX_MAX_ENTRIES as B, GrantBundle as C, EndpointName as Ct, TradeNoteOptions as D, TradeListOptions as E, OfflineEventDetails as F, ProfilePatch as G, OfflineKindDefinition as H, OfflineEventName as I, QueuedScoreOptions as J, QueueOp as K, OfflineListener as L, SyncResult as M, OfflineApi as N, AuthResponse as O, OUTBOX_FULL_CODE as P, GameAnalytics as Q, OfflineOp as R, HubMenuControl as S, EndpointFields as St, TradeId as T, GamePayload as Tt, ReplayContext as U, OfflineHandler as V, CLIENT_VERSION_HEADER as W, Board$1 as X, BufferedEvent as Y, BoardWithTop as Z, ResumeEntry as _, SortDir$1 as _t, HubErrorDetails as a, Inventory$1 as at, ResumeRun as b, SubmitScoreResult as bt, UNSUPPORTED_BY_HUB as c, LeaderboardEntry as ct, hub as d, Metrics$1 as dt, GameLeaderboards as et, ClientSupport as f, Profile as ft, ResumeBlocker as g, SnapshotResponse as gt, RESUME_MAX_STATE_BYTES as h, SaveMeta as ht, HubErrorCode as i, HubStatus as it, SyncConflict as j, ProfileUpdate as k, Hub as l, LeaderboardResult as lt, RESUME_DEBOUNCE_MS as m, Save as mt, ContentRejectedError as n, GlobalAnalytics as nt, OfflineError as o, InventorySnapshot as ot, HubResume as p, ProfileSummary as pt, QueueOpInput as q, HubError as r, HubOptions as rt, SAVE_UNKNOWN_CODE as s, Json$1 as st, HUB_CLIENT_VERSION as t, GameRecords as tt, createHub as u, MeResponse as ut, ResumeLoadOptions as v, Stats$1 as vt, TradeBundle as w, EndpointReply as wt, ResumeSaveInput as x, User as xt, ResumeProgress as y, SubmitScoreOptions as yt, OUTBOX_MAX_CHARS as z };
985
1216
  //# sourceMappingURL=index.d.ts.map