@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,219 @@
1
+ /**
2
+ * Coordinates anonymous release-note requests for the reader.
3
+ *
4
+ * Owns cancellation, pagination, isolated offline copies and retry state.
5
+ *
6
+ * Keep presentation and native window lifecycle callbacks in their components.
7
+ */
8
+ import { useCallback, useEffect, useRef, useState } from 'react';
9
+ import { fetchReleasePage, normalizeReleaseVersion, ReleaseUnavailableError, } from '../api.js';
10
+ import { readReleaseCache, writeReleaseCache } from '../cache.js';
11
+ /**
12
+ * Loads anonymous notes with isolated offline copies and bounded pagination.
13
+ * @param options - Project and optional exact version.
14
+ * @param options.projectId - Public project identifier.
15
+ * @param options.version - Optional exact version.
16
+ * @returns Reader state, continuation and retry operations.
17
+ */
18
+ export function useReleaseNoteListConnector({ projectId, version, }) {
19
+ let requestedVersion = version?.trim();
20
+ if (version !== undefined) {
21
+ try {
22
+ requestedVersion = normalizeReleaseVersion(version);
23
+ }
24
+ catch {
25
+ /* The request reports invalid versions through the error state. */
26
+ }
27
+ }
28
+ const identity = JSON.stringify([projectId, requestedVersion ?? null]);
29
+ const [attempt, setAttempt] = useState(0);
30
+ const [state, setState] = useState({
31
+ identity,
32
+ loading: true,
33
+ loadingMore: false,
34
+ cached: false,
35
+ error: false,
36
+ unavailable: false,
37
+ });
38
+ const activeIdentity = useRef(identity);
39
+ activeIdentity.current = identity;
40
+ const requestId = useRef(0);
41
+ const activeController = useRef(null);
42
+ const paging = useRef(false);
43
+ const current = state.identity === identity
44
+ ? state
45
+ : {
46
+ identity,
47
+ loading: true,
48
+ loadingMore: false,
49
+ cached: false,
50
+ error: false,
51
+ unavailable: false,
52
+ };
53
+ useEffect(() => {
54
+ const controller = new AbortController();
55
+ activeController.current = controller;
56
+ paging.current = false;
57
+ const id = ++requestId.current;
58
+ setState({
59
+ identity,
60
+ loading: true,
61
+ loadingMore: false,
62
+ cached: false,
63
+ error: false,
64
+ unavailable: false,
65
+ });
66
+ void fetchReleasePage(projectId, {
67
+ version: requestedVersion,
68
+ signal: controller.signal,
69
+ })
70
+ .then((page) => {
71
+ if (controller.signal.aborted || id !== requestId.current)
72
+ return;
73
+ writeReleaseCache(projectId, requestedVersion, page);
74
+ setState({
75
+ identity,
76
+ page,
77
+ loading: false,
78
+ loadingMore: false,
79
+ cached: false,
80
+ error: false,
81
+ unavailable: false,
82
+ });
83
+ })
84
+ .catch((error) => {
85
+ if (controller.signal.aborted || id !== requestId.current)
86
+ return;
87
+ const unavailable = error instanceof ReleaseUnavailableError;
88
+ if (unavailable)
89
+ writeReleaseCache(projectId, requestedVersion, null);
90
+ const saved = unavailable
91
+ ? undefined
92
+ : readReleaseCache(projectId, requestedVersion);
93
+ setState({
94
+ identity,
95
+ page: saved,
96
+ loading: false,
97
+ loadingMore: false,
98
+ cached: !!saved,
99
+ error: true,
100
+ unavailable,
101
+ });
102
+ });
103
+ return () => {
104
+ ++requestId.current;
105
+ paging.current = false;
106
+ controller.abort();
107
+ };
108
+ }, [projectId, requestedVersion, identity, attempt]);
109
+ async function loadMore() {
110
+ const cursor = current.page?.nextCursor;
111
+ if (!cursor || current.loadingMore || current.cached || paging.current)
112
+ return;
113
+ const controller = activeController.current;
114
+ if (!controller || controller.signal.aborted)
115
+ return;
116
+ paging.current = true;
117
+ const id = requestId.current;
118
+ setState((previous) => ({ ...previous, loadingMore: true, error: false }));
119
+ try {
120
+ const page = await fetchReleasePage(projectId, {
121
+ cursor,
122
+ signal: controller.signal,
123
+ });
124
+ if (id !== requestId.current || controller.signal.aborted)
125
+ return;
126
+ setState((previous) => {
127
+ if (previous.identity !== identity || !previous.page)
128
+ return previous;
129
+ const seen = new Set(previous.page.items.map((release) => release.id));
130
+ return {
131
+ ...previous,
132
+ page: {
133
+ items: [
134
+ ...previous.page.items,
135
+ ...page.items.filter((release) => !seen.has(release.id)),
136
+ ],
137
+ nextCursor: page.nextCursor === cursor ? null : page.nextCursor,
138
+ },
139
+ loadingMore: false,
140
+ };
141
+ });
142
+ }
143
+ catch (error) {
144
+ if (id !== requestId.current || controller.signal.aborted)
145
+ return;
146
+ if (error instanceof ReleaseUnavailableError) {
147
+ writeReleaseCache(projectId, requestedVersion, null);
148
+ setState({
149
+ identity,
150
+ loading: false,
151
+ loadingMore: false,
152
+ cached: false,
153
+ error: true,
154
+ unavailable: true,
155
+ });
156
+ }
157
+ else
158
+ setState((previous) => ({
159
+ ...previous,
160
+ loadingMore: false,
161
+ error: true,
162
+ }));
163
+ }
164
+ finally {
165
+ if (id === requestId.current)
166
+ paging.current = false;
167
+ }
168
+ }
169
+ function retry() {
170
+ if (current.page && !current.cached)
171
+ void loadMore();
172
+ else
173
+ setAttempt((value) => value + 1);
174
+ }
175
+ const loadMoreOperation = useRef(loadMore);
176
+ loadMoreOperation.current = loadMore;
177
+ const retryOperation = useRef(retry);
178
+ retryOperation.current = retry;
179
+ useEffect(() => {
180
+ if (current.loading ||
181
+ current.loadingMore ||
182
+ (!current.cached && !current.error))
183
+ return;
184
+ let requested = false;
185
+ function revalidate() {
186
+ if (requested)
187
+ return;
188
+ requested = true;
189
+ retryOperation.current();
190
+ }
191
+ window.addEventListener('online', revalidate);
192
+ return () => window.removeEventListener('online', revalidate);
193
+ }, [
194
+ identity,
195
+ current.cached,
196
+ current.error,
197
+ current.loading,
198
+ current.loadingMore,
199
+ ]);
200
+ const generation = requestId.current;
201
+ const loadMoreAction = useCallback(() => {
202
+ if (activeIdentity.current === identity && generation === requestId.current)
203
+ return loadMoreOperation.current();
204
+ }, [identity, generation]);
205
+ const retryAction = useCallback(() => {
206
+ if (activeIdentity.current === identity && generation === requestId.current)
207
+ retryOperation.current();
208
+ }, [identity, generation]);
209
+ return {
210
+ page: current.page,
211
+ loading: current.loading,
212
+ loadingMore: current.loadingMore,
213
+ cached: current.cached,
214
+ error: current.error,
215
+ unavailable: current.unavailable,
216
+ loadMore: loadMoreAction,
217
+ retry: retryAction,
218
+ };
219
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Exposes the browser-only Maker’s HQ React integration.
3
+ *
4
+ * Owns the small public component and HTTP data contracts without native imports.
5
+ *
6
+ * Add native capabilities only to the separate optional tauri entry point.
7
+ */
8
+ export { ReleaseNotes } from './components/release-notes/index.js';
9
+ export type { ReleaseNotesProps } from './components/release-notes/index.js';
10
+ export type { Release, ReleasePage } from './api.js';
11
+ export { WebsiteUpdates } from './website/components/website-updates/index.js';
12
+ export type { WebsiteUpdatesProps } from './website/components/website-updates/index.js';
13
+ export type { WebsiteBuild } from './website/version.js';
14
+ export { useReleaseNoteListConnector as useReleaseNotesReader } from './connectors/use-release-note-list-connector.js';
15
+ export type { ReleaseNotesReaderOptions } from './connectors/use-release-note-list-connector.js';
16
+ export { ReleaseMarkdown } from './components/release-markdown/index.js';
17
+ export type { ReleaseMarkdownProps } from './components/release-markdown/index.js';
18
+ export { releaseImageUrl } from './api.js';
19
+ export { useWebsiteUpdatesConnector as useWebsiteUpdates } from './website/use-website-updates-connector.js';
20
+ export type { WebsiteUpdatesOptions } from './website/use-website-updates-connector.js';
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Exposes the browser-only Maker’s HQ React integration.
3
+ *
4
+ * Owns the small public component and HTTP data contracts without native imports.
5
+ *
6
+ * Add native capabilities only to the separate optional tauri entry point.
7
+ */
8
+ export { ReleaseNotes } from './components/release-notes/index.js';
9
+ export { WebsiteUpdates } from './website/components/website-updates/index.js';
10
+ export { useReleaseNoteListConnector as useReleaseNotesReader } from './connectors/use-release-note-list-connector.js';
11
+ export { ReleaseMarkdown } from './components/release-markdown/index.js';
12
+ export { releaseImageUrl } from './api.js';
13
+ export { useWebsiteUpdatesConnector as useWebsiteUpdates } from './website/use-website-updates-connector.js';
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
+ .flrn-native{--text-sm:.875rem;--text-sm--line-height:1.25rem;--text-base:1rem;--text-base--line-height:1.5rem;--text-xl:1.25rem;--text-xl--line-height:1.75rem;--fl-background:var(--background,#fff);--fl-foreground:var(--foreground,#202020);--fl-muted:var(--muted-foreground,#686868);--fl-border:var(--border,#e4e4e4);--fl-primary:var(--primary,#252525);--fl-primary-fg:var(--primary-foreground,#fff);color:var(--fl-foreground);background:var(--fl-background);color-scheme:light;font-size:var(--text-base,1rem);line-height:var(--tw-leading,var(--text-base--line-height,calc(1.5 / 1)));line-height:var(--leading-normal,1.5);font-family:inherit}.flrn-native[data-theme=dark]{--fl-background:var(--background,#1c1c1e);--fl-foreground:var(--foreground,#f1f1f1);--fl-muted:var(--muted-foreground,#aaa);--fl-border:var(--border,#3b3b3d);--fl-primary:var(--primary,#f0f0f0);--fl-primary-fg:var(--primary-foreground,#202020);color-scheme:dark}@media (prefers-color-scheme:dark){.flrn-native[data-theme=system]{--fl-background:var(--background,#1c1c1e);--fl-foreground:var(--foreground,#f1f1f1);--fl-muted:var(--muted-foreground,#aaa);--fl-border:var(--border,#3b3b3d);--fl-primary:var(--primary,#f0f0f0);--fl-primary-fg:var(--primary-foreground,#202020);color-scheme:dark}}.flrn-native,.flrn-native *{box-sizing:border-box}.flrn-native h1{font-size:var(--text-xl,1.25rem);line-height:var(--tw-leading,var(--text-xl--line-height,calc(1.75 / 1.25)));line-height:var(--leading-snug,1.375);margin:0 0 16px;font-weight:600}.flrn-native p{margin:0}.flrn-native .flrn-muted{color:var(--fl-muted);font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)))}.flrn-native button{border:1px solid var(--fl-primary);font:inherit;font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));height:2.25rem;color:var(--fl-primary-fg);background:var(--fl-primary);cursor:pointer;border-radius:8px;flex-shrink:0;justify-content:center;align-items:center;gap:8px;padding:.5rem 1rem;font-weight:500;display:inline-flex}.flrn-native button:has(>svg){padding-inline:.75rem}.flrn-native button svg{flex-shrink:0;width:1rem;height:1rem}.flrn-native button.flrn-secondary{color:var(--fl-foreground);border-color:var(--fl-border);background:0 0}.flrn-native button:disabled{opacity:.5;cursor:default}.flrn-native :focus-visible{outline-offset:3px;outline:2px solid highlight}.flrn-native input{accent-color:var(--fl-primary);flex-shrink:0;width:16px;height:16px}.flrn-native.flrn-settings{max-width:760px;padding:24px}.flrn-native .flrn-setting-row{border-bottom:1px solid var(--fl-border);justify-content:space-between;align-items:center;gap:24px;padding:20px 0;display:flex}.flrn-native .flrn-setting-row label span{display:block}.flrn-native.flrn-child{flex-direction:column;width:100%;height:100vh;display:flex;overflow:hidden}.flrn-native .flrn-child-scroll{overscroll-behavior:contain;flex:1;min-height:0;overflow:auto}.flrn-native.flrn-child>footer{border-top:1px solid var(--fl-border);background:var(--fl-background);flex:none;justify-content:space-between;align-items:center;gap:16px;padding:16px 24px;display:flex}.flrn-native .flrn-preference{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));align-items:center;gap:8px;display:flex}.flrn-native .flrn-update-intro{border-bottom:1px solid var(--fl-border);align-items:flex-start;gap:20px;padding:28px 28px 20px;display:flex}.flrn-native .flrn-update-intro img{object-fit:contain;width:72px;height:72px}.flrn-native .flrn-update-intro h1{margin-bottom:8px}.flrn-native .flrn-update-intro p+p{margin-top:8px}.flrn-native .flrn-current{text-align:center;padding:48px 24px}.flrn-native .flrn-progress{width:100%}.flrn-native .flrn-progress progress{width:100%;accent-color:var(--fl-primary);margin:8px 0 0}.flrn-native .flrn-updater-notes{margin:20px 28px}.flrn-native .flrn-updater-notes p{white-space:pre-wrap;margin-top:12px}.flrn-native [role=alert]{padding:12px 24px}@media (max-width:440px){.flrn-native .flrn-update-intro{gap:12px;padding:20px}.flrn-native .flrn-update-intro img{width:48px;height:48px}.flrn-native.flrn-child>footer{flex-wrap:wrap;padding:16px}.flrn-native.flrn-settings{padding:20px}.flrn-native .flrn-setting-row{flex-wrap:wrap;gap:16px}}.flrn-native .flrn-update-notes-panel{border:1px solid var(--fl-border);border-radius:8px;margin:0 24px 20px}.flrn-native .flrn-update-intro{border-bottom:0}.flrn-native.flrn-child{height:auto;position:fixed;inset:0}.flrn-native input[role=switch]{appearance:none;border:1px solid var(--fl-border);background:var(--fl-border);cursor:pointer;border-radius:999px;width:36px;height:20px;margin:0;position:relative}.flrn-native input[role=switch]:before{content:"";background:var(--fl-background);border-radius:50%;width:14px;height:14px;position:absolute;top:2px;left:2px}.flrn-native input[role=switch]:checked{background:var(--fl-primary);border-color:var(--fl-primary)}.flrn-native input[role=switch]:checked:before{background:var(--fl-primary-fg);transform:translate(16px)}.fl-website-updates{--text-sm:.875rem;--text-sm--line-height:1.25rem;--text-lg:1.125rem;--text-lg--line-height:1.75rem;--flwu-background:var(--popover,var(--background,#fff));--flwu-foreground:var(--popover-foreground,var(--foreground,#171717));--flwu-muted:var(--muted-foreground,#737373);--flwu-border:var(--border,#e5e5e5);--flwu-accent:var(--accent,#f5f5f5);--flwu-primary:var(--primary,#171717);--flwu-primary-foreground:var(--primary-foreground,#fafafa);--flwu-ring:var(--ring,#737373);font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:var(--flwu-foreground);color-scheme:light;z-index:50;overflow-wrap:anywhere;width:380px;max-width:calc(100% - 32px);font-family:inherit;position:fixed;bottom:24px;right:24px}.fl-website-updates[data-theme=dark]{--flwu-background:var(--popover,var(--background,#262626));--flwu-foreground:var(--popover-foreground,var(--foreground,#fafafa));--flwu-muted:var(--muted-foreground,#a3a3a3);--flwu-border:var(--border,#404040);--flwu-accent:var(--accent,#404040);--flwu-primary:var(--primary,#e5e5e5);--flwu-primary-foreground:var(--primary-foreground,#171717);color-scheme:dark}@media (prefers-color-scheme:dark){.fl-website-updates[data-theme=system]{--flwu-background:var(--popover,var(--background,#262626));--flwu-foreground:var(--popover-foreground,var(--foreground,#fafafa));--flwu-muted:var(--muted-foreground,#a3a3a3);--flwu-border:var(--border,#404040);--flwu-accent:var(--accent,#404040);--flwu-primary:var(--primary,#e5e5e5);--flwu-primary-foreground:var(--primary-foreground,#171717);color-scheme:dark}}.fl-website-updates *{box-sizing:border-box}.fl-website-updates .flwu-toast,.fl-website-updates .flwu-panel{background:var(--flwu-background);border:1px solid var(--flwu-border);border-radius:16px;padding:16px;box-shadow:0 10px 15px -3px #0000001a,0 4px 6px -4px #0000001a}.fl-website-updates .flwu-toast-topline{align-items:flex-start;gap:10px;display:flex}.fl-website-updates .flwu-toast-topline>svg{flex-shrink:0;margin-top:3px}.fl-website-updates h2,.fl-website-updates h3,.fl-website-updates p{margin:0}.fl-website-updates h2{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));font-weight:500}.fl-website-updates p{color:var(--flwu-muted)}.fl-website-updates .flwu-toast p{margin-top:4px}.fl-website-updates button,.fl-website-updates a{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:inherit;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:8px;justify-content:center;align-items:center;gap:8px;min-height:32px;padding:6px 10px;font-family:inherit;font-weight:500;text-decoration:none;display:inline-flex}.fl-website-updates svg{flex-shrink:0}.fl-website-updates button:hover,.fl-website-updates a:hover{background:var(--flwu-accent)}.fl-website-updates button:focus-visible,.fl-website-updates a:focus-visible{outline:2px solid var(--flwu-ring);outline-offset:2px}.fl-website-updates button:disabled{opacity:.5;cursor:default}.fl-website-updates .flwu-primary{background:var(--flwu-primary);color:var(--flwu-primary-foreground)}.fl-website-updates .flwu-primary:hover{background:var(--flwu-primary);opacity:.9}.fl-website-updates .flwu-actions{justify-content:flex-end;gap:8px;margin-top:16px;display:flex}.fl-website-updates .flwu-panel{flex-direction:column;gap:16px;max-height:calc(100svh - 48px);display:flex;overflow-y:auto}.fl-website-updates .flwu-panel header{justify-content:space-between;align-items:center;gap:12px;display:flex}.fl-website-updates .flwu-panel header h2{align-items:center;gap:8px;display:flex}.fl-website-updates .flwu-close{width:32px;margin:-8px -6px -8px 0;padding:0}.fl-website-updates .flwu-content{flex-direction:column;gap:12px;display:flex}.fl-website-updates .flwu-content img{object-fit:contain;border-radius:0;width:100%;height:auto;display:block}.fl-website-updates .flwu-content h3{font-size:var(--text-lg,1.125rem);line-height:var(--tw-leading,var(--text-lg--line-height,calc(1.75 / 1.125)));line-height:var(--leading-snug,1.375);font-weight:500}.fl-website-updates .flwu-panel footer a{border-color:var(--flwu-border);width:100%;min-height:36px}.fl-website-updates .flwu-error{margin-top:12px}@media (max-width:620px){.fl-website-updates{bottom:16px;right:16px}.fl-website-updates .flwu-panel{max-height:calc(100svh - 32px)}}.fl-release-notes{--tw-leading:initial;--text-sm:.875rem;--text-sm--line-height:1.25rem;--text-base:1rem;--text-base--line-height:1.5rem;--text-lg:1.125rem;--text-lg--line-height:1.75rem;--text-xl:1.25rem;--text-xl--line-height:1.75rem;--text-2xl:1.5rem;--text-2xl--line-height:2rem;--text-3xl:1.875rem;--text-3xl--line-height:2.25rem;--fl-background:var(--background,#fff);--fl-foreground:var(--foreground,#1a1c1f);--fl-muted:var(--muted-foreground,#66686b);--fl-border:var(--border,#e4e4e5);--fl-accent:var(--accent,#f0f1f1);--fl-ring:var(--ring,#777);font-size:var(--text-base,1rem);line-height:var(--tw-leading,var(--text-base--line-height,calc(1.5 / 1)));line-height:var(--leading-relaxed,1.625);color:var(--fl-foreground);background:var(--fl-background);color-scheme:light;overflow-wrap:anywhere;min-width:0;padding:2rem;font-family:inherit}.fl-release-notes[data-theme=dark]{--fl-background:var(--background,#181818);--fl-foreground:var(--foreground,#fff);--fl-muted:var(--muted-foreground,#aaa);--fl-border:var(--border,#343434);--fl-accent:var(--accent,#333);color-scheme:dark}@media (prefers-color-scheme:dark){.fl-release-notes[data-theme=system]{--fl-background:var(--background,#181818);--fl-foreground:var(--foreground,#fff);--fl-muted:var(--muted-foreground,#aaa);--fl-border:var(--border,#343434);--fl-accent:var(--accent,#333);color-scheme:dark}}.fl-release-notes .fl-notes-release+.fl-notes-release{margin-top:3rem}.fl-release-notes .fl-notes-heading{flex-wrap:wrap;align-items:baseline;gap:1rem;margin-bottom:1rem;display:flex}.fl-release-notes .fl-notes-heading h2{font-size:var(--text-3xl,1.875rem);line-height:var(--tw-leading,var(--text-3xl--line-height,calc(2.25 / 1.875)));line-height:var(--leading-tight,1.25);letter-spacing:var(--tracking-tight,-.025em);margin:0;font-weight:600}.fl-release-notes .fl-notes-heading time{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:var(--fl-muted);margin-left:auto}.fl-release-notes .fl-notes-title{font-size:var(--text-lg,1.125rem);line-height:var(--tw-leading,var(--text-lg--line-height,calc(1.75 / 1.125)));margin:0 0 1rem;font-weight:600}.fl-release-notes .fl-notes-status{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:.75rem;min-height:12rem;display:flex}.fl-release-notes .fl-notes-status h2{font-size:var(--text-xl,1.25rem);line-height:var(--tw-leading,var(--text-xl--line-height,calc(1.75 / 1.25)));margin:0;font-weight:600}.fl-release-notes .fl-notes-status p{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:var(--fl-muted);margin:0}.fl-release-notes .fl-notes-notice{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:var(--fl-muted);margin:0 0 1.5rem}.fl-release-notes .fl-notes-footer{border-top:1px solid var(--fl-border);flex-wrap:wrap;align-items:center;gap:1rem;margin-top:2rem;padding-top:1rem;display:flex}.fl-release-notes .fl-notes-footer a{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:var(--fl-muted);margin-left:auto}.fl-release-notes .fl-notes-button{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));color:inherit;background:var(--fl-background);border:1px solid var(--fl-border);cursor:pointer;border-radius:.375rem;padding:.5rem .875rem;font-family:inherit}.fl-release-notes .fl-notes-button:hover{background:var(--fl-accent)}.fl-release-notes .fl-notes-button:disabled{opacity:.6;cursor:wait}.fl-release-notes .fl-notes-back{margin-bottom:1.5rem}.fl-release-notes :is(a,button,input):focus-visible{outline:2px solid var(--fl-ring);outline-offset:3px}.fl-release-notes .fl-notes-markdown{font-size:var(--text-base,1rem);line-height:var(--tw-leading,var(--text-base--line-height,calc(1.5 / 1)));line-height:var(--leading-relaxed,1.625)}.fl-release-notes .fl-notes-markdown :is(h1,h2){font-size:var(--text-2xl,1.5rem);line-height:var(--tw-leading,var(--text-2xl--line-height,calc(2 / 1.5)));margin:1.75rem 0 .75rem;font-weight:600}.fl-release-notes .fl-notes-markdown :is(h3,h4,h5,h6){font-size:var(--text-lg,1.125rem);line-height:var(--tw-leading,var(--text-lg--line-height,calc(1.75 / 1.125)));margin:1.5rem 0 .75rem;font-weight:600}.fl-release-notes .fl-notes-markdown p{margin:.75rem 0}.fl-release-notes .fl-notes-markdown :is(ul,ol){margin:1rem 0;padding-left:1.5rem}.fl-release-notes .fl-notes-markdown ul{list-style:outside}.fl-release-notes .fl-notes-markdown ol{list-style:decimal}.fl-release-notes .fl-notes-markdown li{margin:.5rem 0}.fl-release-notes .fl-notes-markdown a{color:inherit;text-underline-offset:3px;text-decoration:underline}.fl-release-notes .fl-notes-markdown img{object-fit:contain;border-radius:.375rem;max-width:100%;height:auto}.fl-release-notes .fl-notes-markdown pre{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));background:var(--fl-accent);border-radius:.375rem;padding:1rem;overflow:auto}.fl-release-notes .fl-notes-markdown code{font-size:var(--text-sm,.875rem);line-height:var(--tw-leading,var(--text-sm--line-height,calc(1.25 / .875)));font-family:ui-monospace,monospace}.fl-release-notes .fl-notes-markdown blockquote{border-left:3px solid var(--fl-border);color:var(--fl-muted);margin:1rem 0;padding-left:1rem}.fl-release-notes .fl-notes-markdown table{border-collapse:collapse;width:100%;display:block;overflow:auto}.fl-release-notes .fl-notes-markdown :is(td,th){border:1px solid var(--fl-border);text-align:left;padding:.5rem .75rem}.fl-release-notes .fl-notes-markdown hr{border:0;border-top:1px solid var(--fl-border);margin:1.5rem 0}@media (max-width:480px){.fl-release-notes{padding:1.25rem}.fl-release-notes .fl-notes-heading h2{font-size:var(--text-2xl,1.5rem);line-height:var(--tw-leading,var(--text-2xl--line-height,calc(2 / 1.5)))}.fl-release-notes .fl-notes-heading time{flex-basis:100%;margin-left:0}}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Declares the package's precompiled stylesheet imports.
3
+ *
4
+ * Owns CSS module recognition for declaration and native entry-point builds.
5
+ *
6
+ * Keep styles side-effect-only without consumer bundler-specific types.
7
+ */
8
+ export {}
@@ -0,0 +1,19 @@
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 ChildKind } from '../../protocol.js';
8
+ /** Renders one SDK-owned native child before consumer app boot.
9
+ * @param props - Validated child route.
10
+ * @param props.kind - Fixed reader or update role.
11
+ * @param props.host - Sole callback-owning window label.
12
+ * @param props.token - Random child capability token.
13
+ * @returns Native child presentation.
14
+ */
15
+ export declare function NativeChild({ kind, host, token, }: {
16
+ kind: ChildKind;
17
+ host: string;
18
+ token: string;
19
+ }): import("react").JSX.Element;
@@ -0,0 +1,146 @@
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 { useEffect, useState, useRef } from 'react';
9
+ import { emitTo } from '@tauri-apps/api/event';
10
+ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
11
+ import { openUrl } from '@tauri-apps/plugin-opener';
12
+ import { ReleaseNotesReader } from '../../../components/release-notes/index.js';
13
+ import { safeHttpUrl } from '../../../api.js';
14
+ import { ACTION_EVENT, hasPresentationState, CHILD_PREFIX, STATE_EVENT, } from '../../protocol.js';
15
+ import { UpdateWindow } from '../update-window/index.js';
16
+ import { synchronizeChildTheme } from './theme.js';
17
+ async function openExternal(url) {
18
+ const safe = safeHttpUrl(url);
19
+ if (safe)
20
+ await openUrl(safe);
21
+ }
22
+ /** Renders one SDK-owned native child before consumer app boot.
23
+ * @param props - Validated child route.
24
+ * @param props.kind - Fixed reader or update role.
25
+ * @param props.host - Sole callback-owning window label.
26
+ * @param props.token - Random child capability token.
27
+ * @returns Native child presentation.
28
+ */
29
+ export function NativeChild({ kind, host, token, }) {
30
+ const rootRef = useRef(null);
31
+ const ordering = useRef({ identity: '', revision: -1 });
32
+ const [revision, setRevision] = useState(-1);
33
+ const [state, setState] = useState(null);
34
+ const [error, setError] = useState(null);
35
+ const send = (action) => emitTo({ kind: 'WebviewWindow', label: host }, ACTION_EVENT, {
36
+ sender: CHILD_PREFIX + kind,
37
+ token,
38
+ action,
39
+ generation: (kind === 'reader'
40
+ ? state?.readerRequest
41
+ : state?.updateRequest)?.generation,
42
+ });
43
+ useEffect(() => {
44
+ const identity = JSON.stringify([kind, host, token]);
45
+ if (ordering.current.identity !== identity)
46
+ ordering.current = { identity, revision: -1 };
47
+ let disposed = false;
48
+ let unlisten;
49
+ const timeout = setTimeout(() => {
50
+ if (!disposed)
51
+ setError('Release notes could not connect to the app. Check native event capabilities.');
52
+ }, 15000);
53
+ void getCurrentWebviewWindow()
54
+ .listen(STATE_EVENT, ({ payload }) => {
55
+ if (disposed || !validStateEnvelope(payload, host, token))
56
+ return;
57
+ // A valid handshake resend establishes readiness even when its revision
58
+ // is already rendered (for example after a StrictMode effect replay).
59
+ clearTimeout(timeout);
60
+ setError(null);
61
+ if (payload.revision <= ordering.current.revision)
62
+ return;
63
+ ordering.current.revision = payload.revision;
64
+ setRevision(payload.revision);
65
+ setState(payload.state);
66
+ })
67
+ .then(async (cleanup) => {
68
+ if (disposed) {
69
+ cleanup();
70
+ return;
71
+ }
72
+ unlisten = cleanup;
73
+ await send({ type: 'ready' });
74
+ })
75
+ .catch(() => {
76
+ if (!disposed)
77
+ setError('Release notes could not connect to the app. Check native event capabilities.');
78
+ });
79
+ return () => {
80
+ disposed = true;
81
+ clearTimeout(timeout);
82
+ unlisten?.();
83
+ };
84
+ // The token and fixed route identify one child lifecycle.
85
+ }, [kind, host, token]);
86
+ useEffect(() => {
87
+ if (rootRef.current && state)
88
+ return synchronizeChildTheme(rootRef.current, state.theme);
89
+ }, [state?.theme, state?.icon, Boolean(state)]);
90
+ const act = (action) => {
91
+ void send(action).catch(() => setError('The app could not receive this action. Please try again.'));
92
+ };
93
+ if (!state)
94
+ return (_jsx("main", { ref: rootRef, className: "flrn-native flrn-child", children: _jsx("p", { role: error ? 'alert' : 'status', children: error || 'Loading…' }) }));
95
+ const close = () => {
96
+ void getCurrentWebviewWindow()
97
+ .close()
98
+ .catch(() => setError('The window could not be closed.'));
99
+ };
100
+ return (_jsxs("main", { ref: rootRef, className: "flrn-native flrn-child", "data-snapshot-revision": revision, "data-theme": state.theme, "data-app-icon": state.icon, onAuxClick: (event) => {
101
+ if (event.defaultPrevented || event.button !== 1)
102
+ return;
103
+ const anchor = event.target.closest?.('a');
104
+ if (!anchor)
105
+ return;
106
+ event.preventDefault();
107
+ void openExternal(anchor.href).catch(() => setError('The link could not be opened.'));
108
+ }, onClick: (event) => {
109
+ if (event.defaultPrevented)
110
+ return;
111
+ const anchor = event.target.closest?.('a');
112
+ if (!anchor)
113
+ return;
114
+ event.preventDefault();
115
+ void openExternal(anchor.href).catch(() => setError('The link could not be opened.'));
116
+ }, children: [kind === 'reader' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "flrn-child-scroll", children: _jsx(ReleaseNotesReader, { projectId: state.projectId, version: state.readerVersion ?? undefined, theme: state.theme, openExternal: openExternal, onReleaseRendered: (release, info) => {
117
+ if (!info.cached && release.version)
118
+ act({ type: 'rendered', version: release.version });
119
+ } }) }), _jsxs("footer", { children: [_jsxs("label", { className: "flrn-preference", children: [_jsx("input", { type: "checkbox", checked: state.preferences.showAfterUpdate, onChange: (event) => act({ type: 'preference', value: event.target.checked }) }), "Show changelog after each update"] }), _jsx("button", { onClick: close, children: "Close" })] })] })) : (_jsx(UpdateWindow, { state: state, act: act, close: close })), error && _jsx("p", { role: "alert", children: error })] }));
120
+ }
121
+ function validStateEnvelope(value, host, token) {
122
+ if (!value || typeof value !== 'object')
123
+ return false;
124
+ const message = value;
125
+ if (message.sender !== host ||
126
+ message.token !== token ||
127
+ typeof message.revision !== 'number' ||
128
+ !Number.isSafeInteger(message.revision) ||
129
+ message.revision < 0 ||
130
+ !message.state ||
131
+ typeof message.state !== 'object')
132
+ return false;
133
+ const state = message.state;
134
+ // Host data is authenticated, then checked before it reaches native views.
135
+ return (hasPresentationState(state) &&
136
+ typeof state.projectId === 'string' &&
137
+ typeof state.name === 'string' &&
138
+ typeof state.currentVersion === 'string' &&
139
+ typeof state.icon === 'string' &&
140
+ ['system', 'light', 'dark'].includes(String(state.theme)) &&
141
+ ['idle', 'checking', 'available', 'current', 'progress', 'error'].includes(String(state.status)) &&
142
+ Boolean(state.preferences &&
143
+ typeof state.preferences === 'object' &&
144
+ typeof state.preferences.showAfterUpdate ===
145
+ 'boolean'));
146
+ }
@@ -0,0 +1,12 @@
1
+ /** Synchronizes themes only inside the SDK-owned child document.
2
+ *
3
+ * Applies the consumer's root dark convention without mounting its app theme provider.
4
+ *
5
+ * Preserve host document ownership and restore child document styles during teardown.
6
+ */
7
+ /** Keeps consumer root tokens, native content and live system appearance in agreement.
8
+ * @param root - SDK child root whose resolved background fills the dedicated document.
9
+ * @param theme - Selected consumer theme.
10
+ * @returns Cleanup restoring the previous dedicated-document theme and listeners.
11
+ */
12
+ export declare function synchronizeChildTheme(root: HTMLElement, theme: 'system' | 'light' | 'dark'): () => void;
@@ -0,0 +1,45 @@
1
+ /** Synchronizes themes only inside the SDK-owned child document.
2
+ *
3
+ * Applies the consumer's root dark convention without mounting its app theme provider.
4
+ *
5
+ * Preserve host document ownership and restore child document styles during teardown.
6
+ */
7
+ /** Keeps consumer root tokens, native content and live system appearance in agreement.
8
+ * @param root - SDK child root whose resolved background fills the dedicated document.
9
+ * @param theme - Selected consumer theme.
10
+ * @returns Cleanup restoring the previous dedicated-document theme and listeners.
11
+ */
12
+ export function synchronizeChildTheme(root, theme) {
13
+ const documentRoot = root.ownerDocument.documentElement;
14
+ const body = root.ownerDocument.body;
15
+ const media = window.matchMedia('(prefers-color-scheme: dark)');
16
+ const previous = {
17
+ dark: documentRoot.classList.contains('dark'),
18
+ theme: documentRoot.getAttribute('data-theme'),
19
+ colorScheme: documentRoot.style.colorScheme,
20
+ background: documentRoot.style.backgroundColor,
21
+ bodyBackground: body.style.backgroundColor,
22
+ };
23
+ const apply = () => {
24
+ const resolved = theme === 'system' ? (media.matches ? 'dark' : 'light') : theme;
25
+ documentRoot.classList.toggle('dark', resolved === 'dark');
26
+ documentRoot.setAttribute('data-theme', resolved);
27
+ documentRoot.style.colorScheme = resolved;
28
+ const background = window.getComputedStyle(root).backgroundColor;
29
+ documentRoot.style.backgroundColor = background;
30
+ body.style.backgroundColor = background;
31
+ };
32
+ apply();
33
+ media.addEventListener('change', apply);
34
+ return () => {
35
+ media.removeEventListener('change', apply);
36
+ documentRoot.classList.toggle('dark', previous.dark);
37
+ if (previous.theme === null)
38
+ documentRoot.removeAttribute('data-theme');
39
+ else
40
+ documentRoot.setAttribute('data-theme', previous.theme);
41
+ documentRoot.style.colorScheme = previous.colorScheme;
42
+ documentRoot.style.backgroundColor = previous.background;
43
+ body.style.backgroundColor = previous.bodyBackground;
44
+ };
45
+ }
@@ -0,0 +1,36 @@
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 ReactNode } from 'react';
8
+ import type { AppUpdater } from '../../contracts.js';
9
+ /** Native host properties; app updates remain completely consumer-owned. */
10
+ export interface ReleaseNotesHostProps {
11
+ projectId: string;
12
+ /** Public Maker’s HQ project ID. */
13
+ icon: string;
14
+ /** Consumer app icon URL, resolved against the same entry point in child windows. */
15
+ updater: AppUpdater;
16
+ /** App-owned eligibility, installation, state flush and restart callbacks; main only. */
17
+ theme?: 'system' | 'light' | 'dark';
18
+ /** Consumer app theme; system follows the OS live. */
19
+ hostWindowLabel?: string;
20
+ /** Sole native updater owner; defaults to main. */
21
+ presentation?: 'native' | 'headless';
22
+ /** Fixed for this mount; remount the host to change presentation policy. */
23
+ children: ReactNode;
24
+ }
25
+ /** Mounts native SDK views before mounting the consuming application's children.
26
+ * @param props - Project, app branding and consumer-owned updater callbacks.
27
+ * @param props.projectId - Public release-note project.
28
+ * @param props.icon - Consumer-owned app icon URL.
29
+ * @param props.updater - Consumer-owned updater callbacks.
30
+ * @param props.theme - Consumer theme preference.
31
+ * @param props.hostWindowLabel - Sole callback-owning native window.
32
+ * @param props.presentation - Fixed native or headless presentation policy.
33
+ * @param props.children - Consumer app mounted in main and ordinary secondary windows, never SDK children.
34
+ * @returns The host application or a standalone native SDK child window.
35
+ */
36
+ export declare function ReleaseNotesHost({ projectId, icon, updater, theme, hostWindowLabel, presentation, children, }: ReleaseNotesHostProps): import("react").JSX.Element;
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx } 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 { useEffect, useState } from 'react';
9
+ import { isTauri } from '@tauri-apps/api/core';
10
+ import { getCurrentWebviewWindow } from '@tauri-apps/api/webviewWindow';
11
+ import { createNativeHostController, } from '../../host-controller.js';
12
+ import { HostContext } from '../../context.js';
13
+ import { childRoute } from '../../protocol.js';
14
+ import { RemoteSettingsClient } from '../../remote-settings-client.js';
15
+ import { NativeChild } from '../native-child/index.js';
16
+ const owners = new Set();
17
+ /** Mounts native SDK views before mounting the consuming application's children.
18
+ * @param props - Project, app branding and consumer-owned updater callbacks.
19
+ * @param props.projectId - Public release-note project.
20
+ * @param props.icon - Consumer-owned app icon URL.
21
+ * @param props.updater - Consumer-owned updater callbacks.
22
+ * @param props.theme - Consumer theme preference.
23
+ * @param props.hostWindowLabel - Sole callback-owning native window.
24
+ * @param props.presentation - Fixed native or headless presentation policy.
25
+ * @param props.children - Consumer app mounted in main and ordinary secondary windows, never SDK children.
26
+ * @returns The host application or a standalone native SDK child window.
27
+ */
28
+ export function ReleaseNotesHost({ projectId, icon, updater, theme = 'system', hostWindowLabel = 'main', presentation = 'native', children, }) {
29
+ const [mode] = useState(presentation);
30
+ if (presentation !== mode)
31
+ throw new Error('Remount ReleaseNotesHost to change presentation mode.');
32
+ const [route] = useState(() => {
33
+ if (!isTauri())
34
+ throw new Error('ReleaseNotesHost requires a Tauri 2 app. Use ReleaseNotes in a browser.');
35
+ return mode === 'headless'
36
+ ? null
37
+ : childRoute(window.location.href, getCurrentWebviewWindow().label);
38
+ });
39
+ if (route)
40
+ return (_jsx(NativeChild, { kind: route.kind, host: route.host, token: route.token }));
41
+ if (getCurrentWebviewWindow().label !== hostWindowLabel)
42
+ return (_jsx(RemoteHostProvider, { projectId: projectId, hostWindowLabel: hostWindowLabel, children: children }));
43
+ return (_jsx(HostProvider, { projectId: projectId, icon: icon, updater: updater, theme: theme, hostWindowLabel: hostWindowLabel, presentation: mode, children: children }));
44
+ }
45
+ function HostProvider({ projectId, icon, updater, theme = 'system', hostWindowLabel = 'main', presentation = 'native', children, }) {
46
+ const [controller, setController] = useState(null);
47
+ const [error, setError] = useState(null);
48
+ useEffect(() => {
49
+ if (owners.has(hostWindowLabel)) {
50
+ setError('Mount one ReleaseNotesHost per app host window.');
51
+ return;
52
+ }
53
+ owners.add(hostWindowLabel);
54
+ const owner = createNativeHostController(projectId, icon, updater, theme, hostWindowLabel, presentation);
55
+ setController(owner);
56
+ return () => {
57
+ owners.delete(hostWindowLabel);
58
+ void owner.dispose();
59
+ };
60
+ // Consumer rerenders update callbacks and appearance without reopening resources.
61
+ }, [projectId, hostWindowLabel]);
62
+ useEffect(() => {
63
+ controller?.configure(updater, icon, theme);
64
+ }, [controller, updater, icon, theme]);
65
+ if (error && presentation === 'headless')
66
+ throw new Error(error);
67
+ if (error)
68
+ return (_jsx("div", { className: "flrn-native", role: "alert", children: error }));
69
+ if (!controller)
70
+ return null;
71
+ return (_jsx(HostContext.Provider, { value: controller, children: children }));
72
+ }
73
+ function RemoteHostProvider({ projectId, hostWindowLabel, children, }) {
74
+ const [client, setClient] = useState(null);
75
+ useEffect(() => {
76
+ const client = new RemoteSettingsClient(projectId, hostWindowLabel);
77
+ setClient(client);
78
+ return () => client.dispose();
79
+ }, [projectId, hostWindowLabel]);
80
+ return client ? (_jsx(HostContext.Provider, { value: client, children: children })) : null;
81
+ }
@@ -0,0 +1,10 @@
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
+ /** Renders the approved Updates settings content using its enclosing native host.
8
+ * @returns Current version, manual update check, preference and changelog actions.
9
+ */
10
+ export declare function ReleaseNotesSettings(): import("react").JSX.Element;