@makershq/react 0.0.0-stage → 0.3.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.
Files changed (66) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -2
  3. package/THIRD_PARTY_NOTICES.md +77 -0
  4. package/dist/api.d.ts +82 -0
  5. package/dist/api.js +183 -0
  6. package/dist/cache.d.ts +22 -0
  7. package/dist/cache.js +86 -0
  8. package/dist/components/icons/external-link/index.d.ts +52 -0
  9. package/dist/components/icons/external-link/index.js +60 -0
  10. package/dist/components/icons/index.d.ts +31 -0
  11. package/dist/components/icons/index.js +56 -0
  12. package/dist/components/icons/reduced-motion.d.ts +4 -0
  13. package/dist/components/icons/reduced-motion.js +24 -0
  14. package/dist/components/icons/x/index.d.ts +98 -0
  15. package/dist/components/icons/x/index.js +87 -0
  16. package/dist/components/release-markdown/index.d.ts +22 -0
  17. package/dist/components/release-markdown/index.js +101 -0
  18. package/dist/components/release-notes/index.d.ts +51 -0
  19. package/dist/components/release-notes/index.js +89 -0
  20. package/dist/connectors/use-release-note-list-connector.d.ts +24 -0
  21. package/dist/connectors/use-release-note-list-connector.js +219 -0
  22. package/dist/index.d.ts +20 -0
  23. package/dist/index.js +13 -0
  24. package/dist/styles.css +2 -0
  25. package/dist/styles.d.ts +8 -0
  26. package/dist/tauri/components/native-child/index.d.ts +19 -0
  27. package/dist/tauri/components/native-child/index.js +146 -0
  28. package/dist/tauri/components/native-child/theme.d.ts +12 -0
  29. package/dist/tauri/components/native-child/theme.js +45 -0
  30. package/dist/tauri/components/release-notes-host/index.d.ts +36 -0
  31. package/dist/tauri/components/release-notes-host/index.js +81 -0
  32. package/dist/tauri/components/release-notes-settings/index.d.ts +10 -0
  33. package/dist/tauri/components/release-notes-settings/index.js +23 -0
  34. package/dist/tauri/components/update-window/index.d.ts +20 -0
  35. package/dist/tauri/components/update-window/index.js +68 -0
  36. package/dist/tauri/context.d.ts +20 -0
  37. package/dist/tauri/context.js +22 -0
  38. package/dist/tauri/contracts.d.ts +84 -0
  39. package/dist/tauri/contracts.js +7 -0
  40. package/dist/tauri/hooks/use-release-notes.d.ts +92 -0
  41. package/dist/tauri/hooks/use-release-notes.js +101 -0
  42. package/dist/tauri/host-controller.d.ts +134 -0
  43. package/dist/tauri/host-controller.js +951 -0
  44. package/dist/tauri/index.d.ts +10 -0
  45. package/dist/tauri/index.js +9 -0
  46. package/dist/tauri/peer-protocol.d.ts +36 -0
  47. package/dist/tauri/peer-protocol.js +43 -0
  48. package/dist/tauri/preferences.d.ts +18 -0
  49. package/dist/tauri/preferences.js +39 -0
  50. package/dist/tauri/protocol.d.ts +71 -0
  51. package/dist/tauri/protocol.js +106 -0
  52. package/dist/tauri/remote-settings-client.d.ts +72 -0
  53. package/dist/tauri/remote-settings-client.js +265 -0
  54. package/dist/website/components/update-toast/index.d.ts +14 -0
  55. package/dist/website/components/update-toast/index.js +22 -0
  56. package/dist/website/components/website-updates/index.d.ts +24 -0
  57. package/dist/website/components/website-updates/index.js +35 -0
  58. package/dist/website/components/whats-new-panel/index.d.ts +23 -0
  59. package/dist/website/components/whats-new-panel/index.js +38 -0
  60. package/dist/website/preferences.d.ts +32 -0
  61. package/dist/website/preferences.js +85 -0
  62. package/dist/website/use-website-updates-connector.d.ts +34 -0
  63. package/dist/website/use-website-updates-connector.js +318 -0
  64. package/dist/website/version.d.ts +27 -0
  65. package/dist/website/version.js +73 -0
  66. package/package.json +71 -3
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
3
+ *
4
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
5
+ *
6
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
7
+ */
8
+ import { useReleaseNotes } from '../../hooks/use-release-notes.js';
9
+ /** Renders the approved Updates settings content using its enclosing native host.
10
+ * @returns Current version, manual update check, preference and changelog actions.
11
+ */
12
+ export function ReleaseNotesSettings() {
13
+ const { state, open, checkForUpdates, setShowAfterUpdate } = useReleaseNotes();
14
+ return (_jsxs("section", { className: "flrn-native flrn-settings", "data-theme": state.theme, children: [_jsx("h1", { children: "Updates" }), _jsxs("div", { className: "flrn-setting-row", children: [_jsxs("div", { children: [_jsx("p", { children: "Current version" }), _jsx("p", { className: "flrn-muted", children: "The version installed on this device." })] }), _jsx("span", { children: state.currentVersion || 'Loading…' })] }), _jsxs("div", { className: "flrn-setting-row", children: [_jsxs("div", { children: [_jsx("p", { children: "Check for updates" }), _jsx("p", { className: "flrn-muted", children: "Checks the update server for a newer version." })] }), _jsx("button", { disabled: state.status === 'checking' ||
15
+ state.status === 'progress' ||
16
+ !state.ready, onClick: () => {
17
+ void checkForUpdates().catch(() => undefined);
18
+ }, children: state.status === 'checking' ? 'Checking…' : 'Check now' })] }), _jsxs("div", { className: "flrn-setting-row", children: [_jsxs("label", { htmlFor: "flrn-after-update", children: [_jsx("span", { children: "Show changelog after each update" }), _jsxs("span", { className: "flrn-muted", children: ["See what changed after ", state.name || 'this app', " updates."] })] }), _jsx("input", { disabled: !state.ready, id: "flrn-after-update", type: "checkbox", role: "switch", checked: state.preferences.showAfterUpdate, onChange: (event) => {
19
+ void setShowAfterUpdate(event.target.checked).catch(() => undefined);
20
+ } })] }), _jsxs("div", { className: "flrn-setting-row", children: [_jsxs("div", { children: [_jsx("p", { children: "Release notes" }), _jsx("p", { className: "flrn-muted", children: "Explore the latest changes and previous releases." })] }), _jsx("button", { className: "flrn-secondary", disabled: !state.ready, onClick: () => {
21
+ void open().catch(() => undefined);
22
+ }, children: "What\u2019s new" })] }), state.error && _jsx("p", { role: "alert", children: state.error })] }));
23
+ }
@@ -0,0 +1,20 @@
1
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
2
+ *
3
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
4
+ *
5
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
6
+ */
7
+ import type { NativeState } from '../../contracts.js';
8
+ import type { ChildAction } from '../../protocol.js';
9
+ /** Presents a consumer updater candidate and its installation progress.
10
+ * @param props - Authenticated host snapshot and bounded actions.
11
+ * @param props.state - Current host presentation state.
12
+ * @param props.act - Sends one supported action to the host.
13
+ * @param props.close - Closes this child without cancelling installation.
14
+ * @returns Native update window content.
15
+ */
16
+ export declare function UpdateWindow({ state, act, close, }: {
17
+ state: NativeState;
18
+ act: (action: ChildAction) => void;
19
+ close: () => void;
20
+ }): import("react").JSX.Element;
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
3
+ *
4
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
5
+ *
6
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
7
+ */
8
+ import { openUrl } from '@tauri-apps/plugin-opener';
9
+ import { ReleaseNotesReader } from '../../../components/release-notes/index.js';
10
+ import { safeHttpUrl } from '../../../api.js';
11
+ async function openExternal(url) {
12
+ const safe = safeHttpUrl(url);
13
+ if (safe)
14
+ await openUrl(safe);
15
+ }
16
+ /** Presents a consumer updater candidate and its installation progress.
17
+ * @param props - Authenticated host snapshot and bounded actions.
18
+ * @param props.state - Current host presentation state.
19
+ * @param props.act - Sends one supported action to the host.
20
+ * @param props.close - Closes this child without cancelling installation.
21
+ * @returns Native update window content.
22
+ */
23
+ export function UpdateWindow({ state, act, close, }) {
24
+ const progress = state.status === 'progress' ? state.progress : null;
25
+ const candidate = state.status === 'available' || state.status === 'progress'
26
+ ? state.candidate
27
+ : null;
28
+ const checking = state.status === 'checking';
29
+ const checkError = state.status === 'error';
30
+ const current = state.status === 'current';
31
+ const downloading = progress?.phase === 'downloading' ? progress : null;
32
+ const percent = downloading?.totalBytes
33
+ ? Math.min(100, Math.round((downloading.downloadedBytes / downloading.totalBytes) * 100))
34
+ : undefined;
35
+ const title = checkError
36
+ ? 'Couldn’t check for updates'
37
+ : checking
38
+ ? 'Checking for updates…'
39
+ : current
40
+ ? 'You’re up to date'
41
+ : progress
42
+ ? progress.phase === 'downloading'
43
+ ? 'Downloading your update'
44
+ : progress.phase === 'installing'
45
+ ? 'Installing your update'
46
+ : 'Restarting…'
47
+ : `A new version of ${state.name} is available`;
48
+ return (_jsxs(_Fragment, { children: [_jsxs("header", { className: "flrn-update-intro", children: [_jsx("img", { src: state.icon, alt: "" }), _jsxs("div", { children: [_jsx("h1", { children: title }), _jsx("p", { children: checkError
49
+ ? 'Check your connection and try again.'
50
+ : checking
51
+ ? 'Checking the update server for a newer version.'
52
+ : current
53
+ ? `${state.name} ${state.currentVersion} is the latest version.`
54
+ : candidate
55
+ ? progress
56
+ ? `${progress.phase === 'downloading' ? 'Downloading' : progress.phase === 'installing' ? 'Installing' : 'Restarting'} ${state.name} ${candidate.version}.`
57
+ : `${state.name} ${candidate.version} is available. You’re using ${state.currentVersion}. Would you like to download it now?`
58
+ : 'Checking for updates…' }), candidate && (_jsxs("p", { children: [state.name, " will restart automatically after installation."] })), state.error && _jsx("p", { role: "alert", children: state.error })] })] }), _jsx("div", { className: "flrn-child-scroll flrn-update-notes-panel", children: current ? (_jsx("p", { className: "flrn-current", children: "You have the latest improvements." })) : (candidate && (_jsxs(_Fragment, { children: [_jsx(ReleaseNotesReader, { projectId: state.projectId, version: candidate.version, theme: state.theme, openExternal: openExternal }), candidate.notes && (_jsxs("details", { className: "flrn-updater-notes", children: [_jsx("summary", { children: "Notes from the app updater" }), _jsx("p", { children: candidate.notes })] }))] }))) }), _jsx("footer", { children: progress ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flrn-progress", role: "status", children: [_jsx("p", { children: progress.phase === 'downloading'
59
+ ? `Downloading update…${percent === undefined ? '' : ` ${percent}%`}`
60
+ : progress.phase === 'installing'
61
+ ? 'Installing update…'
62
+ : 'Restarting…' }), downloading && (_jsxs(_Fragment, { children: [_jsx("progress", { max: 100, value: percent, "aria-label": "Download progress" }), _jsxs("p", { className: "flrn-muted", children: [formatBytes(downloading.downloadedBytes), downloading.totalBytes
63
+ ? ` of ${formatBytes(downloading.totalBytes)}`
64
+ : ''] })] }))] }), downloading && state.canCancel && (_jsx("button", { className: "flrn-secondary", onClick: () => act({ type: 'cancel' }), children: "Cancel" }))] })) : current ? (_jsxs(_Fragment, { children: [_jsx("button", { className: "flrn-secondary", onClick: () => act({ type: 'open-reader' }), children: "Read release notes" }), _jsx("button", { onClick: close, children: "Done" })] })) : candidate ? (_jsxs(_Fragment, { children: [_jsx("button", { className: "flrn-secondary", onClick: () => act({ type: 'skip', version: candidate.version }), children: "Skip this version" }), _jsx("button", { onClick: () => act({ type: 'install', version: candidate.version }), children: "Install update" })] })) : (_jsx("button", { disabled: checking, onClick: () => act({ type: 'check' }), children: checking ? 'Checking…' : 'Try again' })) })] }));
65
+ }
66
+ function formatBytes(bytes) {
67
+ return `${(bytes / 1_000_000).toLocaleString(undefined, { maximumFractionDigits: 1 })} MB`;
68
+ }
@@ -0,0 +1,20 @@
1
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
2
+ *
3
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
4
+ *
5
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
6
+ */
7
+ import { type Context } from 'react';
8
+ import type { NativeHost } from './host-controller.js';
9
+ /** Internal presentation actions shared by local and connected settings views. */
10
+ export type NativePresentationHost = Pick<NativeHost, 'subscribe' | 'getSnapshot' | 'open' | 'check' | 'setShowAfterUpdate' | 'notifyUpdateAvailable' | 'presentationAction'>;
11
+ /** Shares the private native lifecycle owner with host-window presentation.
12
+ * @param props - React context provider properties.
13
+ * @returns Context provider content.
14
+ */
15
+ export declare const HostContext: Context<NativePresentationHost | null>;
16
+ /** Reads the enclosing native host.
17
+ * @returns Host lifecycle owner.
18
+ * @throws Error outside a host window provider.
19
+ */
20
+ export declare function useHost(): NativePresentationHost;
@@ -0,0 +1,22 @@
1
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
2
+ *
3
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
4
+ *
5
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
6
+ */
7
+ import { createContext, useContext } from 'react';
8
+ /** Shares the private native lifecycle owner with host-window presentation.
9
+ * @param props - React context provider properties.
10
+ * @returns Context provider content.
11
+ */
12
+ export const HostContext = createContext(null);
13
+ /** Reads the enclosing native host.
14
+ * @returns Host lifecycle owner.
15
+ * @throws Error outside a host window provider.
16
+ */
17
+ export function useHost() {
18
+ const host = useContext(HostContext);
19
+ if (!host)
20
+ throw new Error('Use native release notes inside ReleaseNotesHost in its host window.');
21
+ return host;
22
+ }
@@ -0,0 +1,84 @@
1
+ /** Defines the consumer-owned updater contract for native release-note presentation.
2
+ *
3
+ * Keeps native resources, installation policy and restart control in the consuming app.
4
+ *
5
+ * Extend presentation states without transferring updater ownership into the SDK.
6
+ */
7
+ /** A version offered by the consuming application's updater. */
8
+ export interface AvailableUpdate {
9
+ version: string;
10
+ /** Exact updater candidate version. */
11
+ notes?: string;
12
+ }
13
+ /** Installation progress reported by the consuming application. */
14
+ export type InstallProgress = {
15
+ phase: 'downloading';
16
+ downloadedBytes: number;
17
+ totalBytes?: number;
18
+ } | {
19
+ phase: 'installing' | 'restarting';
20
+ };
21
+ /** Consumer-owned update operations; the SDK never obtains native update handles. */
22
+ export interface AppUpdater {
23
+ /** Checks eligibility using the app's own updater policy.
24
+ * @returns A candidate or null when already current.
25
+ */
26
+ check(): Promise<AvailableUpdate | null>;
27
+ /** Flushes app state, installs the exact candidate and restarts automatically.
28
+ * @param version - Candidate selected by the user; reject stale candidates.
29
+ * @param reportProgress - Reports serializable presentation progress.
30
+ * @returns Completion or a rejected installation error.
31
+ */
32
+ install(version: string, reportProgress: (progress: InstallProgress) => void): Promise<void>;
33
+ /** Cancels a supported active download.
34
+ * @returns Completion after the consumer has cancelled its operation.
35
+ */
36
+ cancel?(): Promise<void>;
37
+ }
38
+ /** Only the three approved preferences persist in the app's local data directory. */
39
+ export interface ReleaseNotesPreferences {
40
+ showAfterUpdate: boolean;
41
+ /** Whether an installed upgrade opens its exact release notes. */
42
+ acknowledgedVersion: string | null;
43
+ /** Highest installed version whose presentation has been acknowledged. */
44
+ skippedVersion: string | null;
45
+ }
46
+ /** Public synchronized state; update operations remain owned by the app. */
47
+ export interface ReleaseNotesState {
48
+ ready: boolean;
49
+ /** True after app metadata, preferences and host listeners are ready. */
50
+ presentation: 'native' | 'headless';
51
+ /** Presentation policy fixed for this host lifecycle. */
52
+ projectId: string;
53
+ /** Public release-note project identifier. */
54
+ name: string;
55
+ /** Application name read from Tauri. */
56
+ currentVersion: string;
57
+ /** Installed application version. */
58
+ icon: string;
59
+ /** Consumer-owned application icon URL. */
60
+ theme: 'system' | 'light' | 'dark';
61
+ /** Consumer-selected presentation theme. */
62
+ preferences: ReleaseNotesPreferences;
63
+ /** Shared persistent release-note preferences. */
64
+ status: 'idle' | 'checking' | 'available' | 'current' | 'progress' | 'error';
65
+ /** Current consumer update operation state. */
66
+ candidate: AvailableUpdate | null;
67
+ /** Exact app-owned candidate, when one is available. */
68
+ progress: InstallProgress | null;
69
+ /** Current app-reported installation progress. */
70
+ canCancel: boolean;
71
+ /** Whether the active download currently accepts cancellation. */
72
+ error: string | null;
73
+ }
74
+ /** Private serializable identity for one reader or update presentation. */
75
+ export interface NativePresentationRequest {
76
+ generation: number;
77
+ originWindowLabel: string;
78
+ }
79
+ /** Private synchronized snapshot used by authenticated native adapters. */
80
+ export interface NativeState extends ReleaseNotesState {
81
+ readerVersion: string | null;
82
+ readerRequest: NativePresentationRequest | null;
83
+ updateRequest: NativePresentationRequest | null;
84
+ }
@@ -0,0 +1,7 @@
1
+ /** Defines the consumer-owned updater contract for native release-note presentation.
2
+ *
3
+ * Keeps native resources, installation policy and restart control in the consuming app.
4
+ *
5
+ * Extend presentation states without transferring updater ownership into the SDK.
6
+ */
7
+ export {};
@@ -0,0 +1,92 @@
1
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
2
+ *
3
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
4
+ *
5
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
6
+ */
7
+ import type { Release } from '../../api.js';
8
+ import type { AvailableUpdate, ReleaseNotesState } from '../contracts.js';
9
+ /** App-owned reader placement with acknowledgment bound to its active request. */
10
+ export interface ReaderPresentation {
11
+ version?: string;
12
+ /** Exact installed version, or undefined for history. */
13
+ originWindowLabel: string;
14
+ /** Window which requested the reader. */
15
+ /** Hides this request without acknowledging unread content.
16
+ * @returns Completion after the active request is dismissed.
17
+ */
18
+ dismiss(): Promise<void>;
19
+ /** Confirms freshly rendered exact-version content; failures appear in shared state.
20
+ * @param release - The rendered release document.
21
+ * @param release.id - Stable public release identifier.
22
+ * @param release.version - Optional exact application version.
23
+ * @param release.title - Human-readable title.
24
+ * @param release.excerpt - Optional plain-text preview.
25
+ * @param release.previewImageSource - Optional preview image source.
26
+ * @param release.markdown - Complete release document.
27
+ * @param release.date - Publication calendar date.
28
+ * @param release.url - Public article URL.
29
+ * @param state - Rendered content provenance.
30
+ * @param state.cached - Whether this is an offline copy, which never acknowledges.
31
+ */
32
+ onReleaseRendered(release: Release, state: {
33
+ cached: boolean;
34
+ }): void;
35
+ }
36
+ /** App-owned update placement with commands bound to its active request. */
37
+ export interface UpdatePresentation {
38
+ originWindowLabel: string;
39
+ /** Window which requested the update presentation. */
40
+ /** Hides presentation without cancelling installation.
41
+ * @returns Completion after the active request is dismissed.
42
+ */
43
+ dismiss(): Promise<void>;
44
+ /** Accepts installation; progress and failures arrive in shared state.
45
+ * @returns Command acceptance, without waiting for installation or restart.
46
+ */
47
+ install(): Promise<void>;
48
+ /** Persists this exact candidate as skipped and dismisses its presentation.
49
+ * @returns Completion after preference persistence and dismissal.
50
+ */
51
+ skip(): Promise<void>;
52
+ /** Accepts supported cancellation; completion and failures arrive in shared state.
53
+ * @returns Command acceptance, without waiting for consumer cancellation.
54
+ */
55
+ cancel(): Promise<void>;
56
+ }
57
+ /** Native release-note actions for menu items and an existing background update checker. */
58
+ export interface ReleaseNotesActions {
59
+ /** Opens or focuses the changelog.
60
+ * @returns Completion after the native window is ready.
61
+ */
62
+ open(): Promise<void>;
63
+ /** Runs the app-owned manual check, including previously skipped candidates.
64
+ * @returns Completion after the host presents its result; rejects unavailable native connections.
65
+ */
66
+ checkForUpdates(): Promise<void>;
67
+ /** Presents an app-owned candidate unless the user skipped this exact version.
68
+ * @param candidate - Version and optional plain-text notes from the app updater.
69
+ * @param candidate.version - Exact candidate version.
70
+ * @param candidate.notes - Optional plain-text updater notes.
71
+ * @returns Presentation completion; rejects invalid candidates or missing capabilities.
72
+ */
73
+ notifyUpdateAvailable(candidate: AvailableUpdate): Promise<void>;
74
+ }
75
+ /** Shared native state and optional app-owned presentations, with existing actions preserved. */
76
+ export interface ReleaseNotesResult extends ReleaseNotesActions {
77
+ state: ReleaseNotesState;
78
+ /** Synchronized public state; updater resources stay in the main window. */
79
+ reader: ReaderPresentation | null;
80
+ /** Active headless reader request; the app owns placement and focus. */
81
+ update: UpdatePresentation | null;
82
+ /** Active headless update request, independent of the reader. */
83
+ /** Persists the shared after-update reader preference.
84
+ * @param value - Whether installed upgrades should open their exact release notes.
85
+ * @returns Completion after preference persistence and synchronization.
86
+ */
87
+ setShowAfterUpdate(value: boolean): Promise<void>;
88
+ }
89
+ /** Gets host actions without exposing updater handles or SDK-managed scheduling.
90
+ * @returns Actions bound to the one native host.
91
+ */
92
+ export declare function useReleaseNotes(): ReleaseNotesResult;
@@ -0,0 +1,101 @@
1
+ /** Presents release notes and consumer-owned updates in native Tauri windows.
2
+ *
3
+ * Mounts SDK child views before app children and keeps all updater callbacks in the host.
4
+ *
5
+ * Import this optional entry point only in Tauri apps with the documented capabilities.
6
+ */
7
+ import { useCallback, useMemo, useSyncExternalStore } from 'react';
8
+ import { useHost } from '../context.js';
9
+ /** Gets host actions without exposing updater handles or SDK-managed scheduling.
10
+ * @returns Actions bound to the one native host.
11
+ */
12
+ export function useReleaseNotes() {
13
+ const host = useHost();
14
+ const snapshot = useSyncExternalStore(host.subscribe, host.getSnapshot);
15
+ const checkForUpdates = useCallback(() => host.check(), [host]);
16
+ const state = useMemo(() => ({
17
+ ready: snapshot.ready,
18
+ presentation: snapshot.presentation,
19
+ projectId: snapshot.projectId,
20
+ name: snapshot.name,
21
+ currentVersion: snapshot.currentVersion,
22
+ icon: snapshot.icon,
23
+ theme: snapshot.theme,
24
+ preferences: snapshot.preferences,
25
+ status: snapshot.status,
26
+ candidate: snapshot.candidate,
27
+ progress: snapshot.progress,
28
+ canCancel: snapshot.status === 'progress' &&
29
+ snapshot.progress?.phase === 'downloading' &&
30
+ snapshot.canCancel,
31
+ error: snapshot.error,
32
+ }), [snapshot]);
33
+ const reader = useMemo(() => {
34
+ const request = snapshot.readerRequest;
35
+ if (snapshot.presentation !== 'headless' || !request)
36
+ return null;
37
+ return {
38
+ version: snapshot.readerVersion ?? undefined,
39
+ originWindowLabel: request.originWindowLabel,
40
+ dismiss: () => host.presentationAction('reader', request.generation, {
41
+ type: 'dismiss',
42
+ }),
43
+ onReleaseRendered: (release, info) => {
44
+ if (release.version)
45
+ void host
46
+ .presentationAction('reader', request.generation, {
47
+ type: 'rendered',
48
+ version: release.version,
49
+ cached: info.cached,
50
+ })
51
+ .catch(() => undefined);
52
+ },
53
+ };
54
+ }, [
55
+ host,
56
+ snapshot.presentation,
57
+ snapshot.readerRequest,
58
+ snapshot.readerVersion,
59
+ ]);
60
+ const update = useMemo(() => {
61
+ const request = snapshot.updateRequest;
62
+ const version = snapshot.candidate?.version;
63
+ if (snapshot.presentation !== 'headless' || !request)
64
+ return null;
65
+ return {
66
+ originWindowLabel: request.originWindowLabel,
67
+ dismiss: () => host.presentationAction('update', request.generation, {
68
+ type: 'dismiss',
69
+ }),
70
+ install: () => version
71
+ ? host.presentationAction('update', request.generation, {
72
+ type: 'install',
73
+ version,
74
+ })
75
+ : Promise.resolve(),
76
+ skip: () => version
77
+ ? host.presentationAction('update', request.generation, {
78
+ type: 'skip',
79
+ version,
80
+ })
81
+ : Promise.resolve(),
82
+ cancel: () => host.presentationAction('update', request.generation, {
83
+ type: 'cancel',
84
+ }),
85
+ };
86
+ }, [
87
+ host,
88
+ snapshot.presentation,
89
+ snapshot.updateRequest,
90
+ snapshot.candidate?.version,
91
+ ]);
92
+ return {
93
+ state,
94
+ reader,
95
+ update,
96
+ open: host.open,
97
+ checkForUpdates,
98
+ setShowAfterUpdate: host.setShowAfterUpdate,
99
+ notifyUpdateAvailable: host.notifyUpdateAvailable,
100
+ };
101
+ }
@@ -0,0 +1,134 @@
1
+ /** Coordinates native child windows while the main app retains its updater resources.
2
+ *
3
+ * Owns preferences, narrowly authenticated events and exact installed-version presentation.
4
+ *
5
+ * Keep callback execution in this host; child windows receive serializable state only.
6
+ */
7
+ import type { AppUpdater, AvailableUpdate, NativeState } from './contracts.js';
8
+ import { type ChildKind, type PresentationAction } from './protocol.js';
9
+ /** Host-only state owner for one project and native main window. */
10
+ export declare class NativeHostController {
11
+ private projectId;
12
+ private updater;
13
+ private hostWindowLabel;
14
+ private presentation;
15
+ private state;
16
+ private snapshotRevision;
17
+ private presentationGeneration;
18
+ private latestUpdateGeneration;
19
+ private automaticAttempt;
20
+ private listeners;
21
+ private children;
22
+ private peers;
23
+ private openings;
24
+ private store;
25
+ private disposers;
26
+ private disposed;
27
+ private automaticVersion;
28
+ private automaticPending;
29
+ private persistence;
30
+ private operation;
31
+ private installation;
32
+ private ready;
33
+ private initializationError;
34
+ private releaseLease;
35
+ private disposal;
36
+ private hostWindow;
37
+ private nativeThemeUpdates;
38
+ private nativeThemeRequest;
39
+ /** Initializes the single host and its app-local preference store.
40
+ * @param projectId - Public release-note project.
41
+ * @param icon - Consumer-owned app icon URL.
42
+ * @param updater - Consumer-owned updater callbacks.
43
+ * @param theme - App's selected theme.
44
+ * @param hostWindowLabel - Label of the sole callback-owning native window.
45
+ * @param presentation - Fixed presentation policy for this lifecycle.
46
+ */
47
+ constructor(projectId: string, icon: string, updater: AppUpdater, theme: NativeState['theme'], hostWindowLabel: string, presentation?: NativeState['presentation']);
48
+ /** Subscribes to host state.
49
+ * @param listener - React external-store listener.
50
+ * @returns Unsubscribe callback.
51
+ */
52
+ subscribe: (listener: () => void) => (() => void);
53
+ /** Returns the stable current state snapshot.
54
+ * @returns Serializable native presentation state.
55
+ */
56
+ getSnapshot: () => NativeState;
57
+ private initialize;
58
+ private patch;
59
+ private fail;
60
+ private sendState;
61
+ private sendPeerState;
62
+ private connectPeer;
63
+ private dispatchPeer;
64
+ private savePreferences;
65
+ private ensureReady;
66
+ /** Updates consumer callbacks and appearance without recreating native resources.
67
+ * @param updater - Latest app-owned callbacks.
68
+ * @param icon - Current app icon URL.
69
+ * @param theme - Current app theme.
70
+ */
71
+ configure(updater: AppUpdater, icon: string, theme: NativeState['theme']): void;
72
+ /** Synchronizes consumer theme changes to existing child windows.
73
+ * @param theme - System, light or dark consumer preference.
74
+ */
75
+ setTheme(theme: NativeState['theme']): void;
76
+ private synchronizeNativeTheme;
77
+ /** Opens or focuses the single changelog window.
78
+ * @returns Completion after the native window is ready.
79
+ */
80
+ open: () => Promise<void>;
81
+ private openFrom;
82
+ /** Offers a background updater candidate while respecting the skipped version.
83
+ * @param candidate - Version supplied by the consumer's existing background checker.
84
+ * @param candidate.version - Exact candidate version.
85
+ * @param candidate.notes - Optional plain-text updater notes.
86
+ * @returns Completion after a matching update window is open, or a quiet skip.
87
+ */
88
+ notifyUpdateAvailable: (candidate: AvailableUpdate) => Promise<void>;
89
+ private validateCandidate;
90
+ /** Runs an explicit user check, bypassing skipped-version suppression.
91
+ * @param originLabel - Existing settings window to receive focus after closing the update.
92
+ * @returns Completion after the updater result is shown.
93
+ */
94
+ check: (originLabel?: string) => Promise<void>;
95
+ /** Saves the shared after-update preference.
96
+ * @param value - Whether future upgrades should open a changelog.
97
+ * @returns Completion after persistence and child synchronization.
98
+ */
99
+ setShowAfterUpdate: (value: boolean) => Promise<void>;
100
+ private retryAutomatic;
101
+ private requestPresentation;
102
+ private settleUpdatePresentation;
103
+ private dismissPresentation;
104
+ /** Accepts one action bound to the active headless presentation.
105
+ * @param kind - Reader or update presentation.
106
+ * @param generation - Private presentation identity captured by the hook.
107
+ * @param action - Bounded presentation command.
108
+ * @param action.type - Fixed command discriminator.
109
+ * @param action.version - Exact displayed candidate or rendered release version.
110
+ * @param action.cached - Whether rendered content came from offline storage.
111
+ * @returns Command acceptance; installation and cancellation progress through shared state.
112
+ */
113
+ presentationAction: (kind: ChildKind, generation: number, action: PresentationAction) => Promise<void>;
114
+ private openWindow;
115
+ private createOrFocus;
116
+ private dispatch;
117
+ /** Releases listeners, local resources and native child windows on host unmount.
118
+ * @returns Completion after pending preference/appearance writes and child cleanup.
119
+ */
120
+ dispose(): Promise<void>;
121
+ private cleanup;
122
+ }
123
+ /** Creates the private native lifecycle owner for a single host window.
124
+ * @param projectId - Public release-note project.
125
+ * @param icon - Consumer icon URL.
126
+ * @param updater - Consumer updater callbacks.
127
+ * @param theme - Consumer theme.
128
+ * @param hostWindowLabel - Callback-owning native window.
129
+ * @param presentation - Fixed native or headless presentation policy.
130
+ * @returns Internal lifecycle owner; never exported by the package entry point.
131
+ */
132
+ export declare function createNativeHostController(projectId: string, icon: string, updater: AppUpdater, theme: NativeState['theme'], hostWindowLabel: string, presentation?: NativeState['presentation']): NativeHostController;
133
+ /** Internal controller type used only by native presentation components. */
134
+ export type NativeHost = NativeHostController;