@squadbase/vantage 0.6.2-dev1.9d91dda → 0.6.2-dev1.ac99e02
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.
- package/dist/add-4GHF2TX2.js +6 -0
- package/dist/add-4GHF2TX2.js.map +1 -0
- package/dist/{build-TVKFIVFQ.js → build-MFWRPYKW.js} +7 -7
- package/dist/{build-TVKFIVFQ.js.map → build-MFWRPYKW.js.map} +1 -1
- package/dist/{check-3KHZXZMQ.js → check-ZBIH422T.js} +5 -5
- package/dist/{check-3KHZXZMQ.js.map → check-ZBIH422T.js.map} +1 -1
- package/dist/{chunk-P7W4LR3Z.js → chunk-7DZGJQ3P.js} +3 -3
- package/dist/{chunk-P7W4LR3Z.js.map → chunk-7DZGJQ3P.js.map} +1 -1
- package/dist/{chunk-U2M6HGKQ.js → chunk-AABMKHEU.js} +4 -4
- package/dist/{chunk-U2M6HGKQ.js.map → chunk-AABMKHEU.js.map} +1 -1
- package/dist/{chunk-NKFBFDRZ.js → chunk-AG6RZ2RR.js} +981 -14
- package/dist/chunk-AG6RZ2RR.js.map +1 -0
- package/dist/{chunk-QI3XQKHS.js → chunk-GNXCX4WE.js} +10 -3
- package/dist/chunk-GNXCX4WE.js.map +1 -0
- package/dist/chunk-IBGOCWJB.js +1716 -0
- package/dist/chunk-IBGOCWJB.js.map +1 -0
- package/dist/{chunk-RPZAALCX.js → chunk-OB6UBJXF.js} +153 -153
- package/dist/{chunk-RPZAALCX.js.map → chunk-OB6UBJXF.js.map} +1 -1
- package/dist/{chunk-LMUACBMA.js → chunk-QEWCYW3I.js} +43 -8
- package/dist/chunk-QEWCYW3I.js.map +1 -0
- package/dist/{chunk-ZVANIULZ.js → chunk-RNTDBX6S.js} +4 -4
- package/dist/{chunk-ZVANIULZ.js.map → chunk-RNTDBX6S.js.map} +1 -1
- package/dist/{chunk-PVTHHV7X.js → chunk-V3LF7BE7.js} +27 -5
- package/dist/chunk-V3LF7BE7.js.map +1 -0
- package/dist/{chunk-DTDVSFRY.js → chunk-XQUSGIDG.js} +17 -3
- package/dist/chunk-XQUSGIDG.js.map +1 -0
- package/dist/cli.js +12 -11
- package/dist/cli.js.map +1 -1
- package/dist/client/index.d.ts +32 -3
- package/dist/client/index.js +205 -12
- package/dist/client/index.js.map +1 -1
- package/dist/components/index.d.ts +216 -1
- package/dist/components/index.js +2 -2
- package/dist/{dev-GDKATCC7.js → dev-DCTOHQ6W.js} +8 -8
- package/dist/dev-DCTOHQ6W.js.map +1 -0
- package/dist/{docs-EJJ3BECT.js → docs-JVP4RPKT.js} +3 -3
- package/dist/{docs-EJJ3BECT.js.map → docs-JVP4RPKT.js.map} +1 -1
- package/dist/{doctor-WQXPXP6K.js → doctor-5E2VEZPK.js} +5 -5
- package/dist/{doctor-WQXPXP6K.js.map → doctor-5E2VEZPK.js.map} +1 -1
- package/dist/{preview-OGMCNQUO.js → preview-T6CLSQVX.js} +3 -3
- package/dist/{preview-OGMCNQUO.js.map → preview-T6CLSQVX.js.map} +1 -1
- package/dist/query/index.d.ts +0 -11
- package/dist/query/index.js +2 -2
- package/dist/{routes-MWBWWOJ2.js → routes-3SGAFDMC.js} +4 -4
- package/dist/{routes-MWBWWOJ2.js.map → routes-3SGAFDMC.js.map} +1 -1
- package/dist/{search-6Y422SV6.js → search-5LC4XPB5.js} +3 -3
- package/dist/{search-6Y422SV6.js.map → search-5LC4XPB5.js.map} +1 -1
- package/dist/table/index.js +7 -6
- package/dist/table/index.js.map +1 -1
- package/dist/ui/index.d.ts +140 -10
- package/dist/ui/index.js +1405 -63
- package/dist/ui/index.js.map +1 -1
- package/dist/{upgrade-HCANX4GQ.js → upgrade-DBBE6GIR.js} +6 -6
- package/dist/{upgrade-HCANX4GQ.js.map → upgrade-DBBE6GIR.js.map} +1 -1
- package/dist/vite/index.d.ts +10 -0
- package/dist/vite/index.js +3 -3
- package/docs/index.json +291 -61
- package/docs/ja/changelog.md +26 -0
- package/docs/ja/components.md +33 -89
- package/docs/ja/page-types/csv.md +83 -0
- package/docs/ja/page-types/doc.md +83 -0
- package/docs/ja/page-types/excel.md +82 -0
- package/docs/ja/page-types/slide.md +132 -0
- package/docs/ja/page-types.md +47 -0
- package/docs/ja/parts/area-chart.md +61 -0
- package/docs/ja/parts/bar-chart.md +69 -0
- package/docs/ja/parts/bar-list.md +35 -0
- package/docs/ja/parts/category-bar.md +36 -0
- package/docs/ja/parts/donut-chart.md +47 -0
- package/docs/ja/parts/echart.md +3 -0
- package/docs/ja/parts/line-chart.md +58 -0
- package/docs/ja/parts/progress-circle.md +34 -0
- package/docs/ja/parts/sparkline.md +1 -1
- package/docs/ja/parts/tracker.md +32 -0
- package/docs/ja/routing.md +8 -86
- package/docs/ja/ui/alert-dialog.md +41 -0
- package/docs/ja/ui/avatar.md +31 -0
- package/docs/ja/ui/combobox.md +74 -0
- package/docs/ja/ui/drawer.md +41 -0
- package/docs/ja/ui/field.md +42 -0
- package/docs/ja/ui/hover-card.md +21 -0
- package/docs/ja/ui/kbd.md +16 -0
- package/docs/ja/ui/pagination.md +36 -0
- package/docs/ja/ui/radio-group.md +21 -0
- package/docs/ja/ui/toast.md +46 -0
- package/docs/ja/ui-and-theming.md +14 -7
- package/package.json +21 -13
- package/registry/ui/accordion.tsx +74 -0
- package/registry/ui/alert-dialog.tsx +189 -0
- package/registry/ui/alert.tsx +78 -0
- package/registry/ui/app-shell.tsx +281 -0
- package/registry/ui/area-chart.tsx +1015 -0
- package/registry/ui/avatar.tsx +110 -0
- package/registry/ui/badge.tsx +54 -0
- package/registry/ui/bar-chart.tsx +1013 -0
- package/registry/ui/bar-list.tsx +302 -0
- package/registry/ui/breadcrumb.tsx +126 -0
- package/registry/ui/button.tsx +60 -0
- package/registry/ui/calendar.tsx +221 -0
- package/registry/ui/card.tsx +105 -0
- package/registry/ui/category-bar.tsx +281 -0
- package/registry/ui/checkbox.tsx +28 -0
- package/registry/ui/collapsible.tsx +21 -0
- package/registry/ui/combobox.tsx +310 -0
- package/registry/ui/command.tsx +196 -0
- package/registry/ui/dashboard-card.tsx +174 -0
- package/registry/ui/data-table.tsx +16 -91
- package/registry/ui/date-range-picker.tsx +209 -0
- package/registry/ui/dialog.tsx +159 -0
- package/registry/ui/donut-chart.tsx +1004 -0
- package/registry/ui/drawer.tsx +229 -0
- package/registry/ui/dropdown-menu.tsx +272 -0
- package/registry/ui/echart.tsx +486 -0
- package/registry/ui/field.tsx +240 -0
- package/registry/ui/filter-bar.tsx +365 -0
- package/registry/ui/funnel-steps.tsx +274 -0
- package/registry/ui/hover-card.tsx +52 -0
- package/registry/ui/input-group.tsx +158 -0
- package/registry/ui/input.tsx +22 -0
- package/registry/ui/kbd.tsx +28 -0
- package/registry/ui/label.tsx +20 -0
- package/registry/ui/line-chart.tsx +1007 -0
- package/registry/ui/metric-value.tsx +54 -0
- package/registry/ui/multi-select.tsx +226 -0
- package/registry/ui/page-shell.tsx +227 -0
- package/registry/ui/pagination.tsx +138 -0
- package/registry/ui/placeholder.tsx +30 -0
- package/registry/ui/popover.tsx +90 -0
- package/registry/ui/progress-circle.tsx +272 -0
- package/registry/ui/progress.tsx +83 -0
- package/registry/ui/radio-group.tsx +39 -0
- package/registry/ui/scroll-area.tsx +55 -0
- package/registry/ui/searchable-select.tsx +209 -0
- package/registry/ui/section-header.tsx +41 -0
- package/registry/ui/segmented-control.tsx +71 -0
- package/registry/ui/select.tsx +253 -0
- package/registry/ui/separator.tsx +25 -0
- package/registry/ui/sheet.tsx +137 -0
- package/registry/ui/sidebar.tsx +723 -0
- package/registry/ui/skeleton.tsx +15 -0
- package/registry/ui/slider.tsx +54 -0
- package/registry/ui/sparkline.tsx +155 -0
- package/registry/ui/spinner.tsx +12 -0
- package/registry/ui/states.tsx +61 -0
- package/registry/ui/status-badge.tsx +79 -0
- package/registry/ui/switch.tsx +32 -0
- package/registry/ui/table.tsx +116 -0
- package/registry/ui/tabs.tsx +82 -0
- package/registry/ui/textarea.tsx +20 -0
- package/registry/ui/toast.tsx +250 -0
- package/registry/ui/toggle-group.tsx +89 -0
- package/registry/ui/toggle.tsx +45 -0
- package/registry/ui/tooltip.tsx +66 -0
- package/registry/ui/tracker.tsx +236 -0
- package/registry/ui/trend-indicator.tsx +62 -0
- package/skills/vantage-add-feature/SKILL.md +9 -7
- package/skills/vantage-pitfalls/SKILL.md +5 -1
- package/templates/AGENTS.md +10 -1
- package/templates/agents/csv.md +2 -1
- package/templates/agents/doc.md +4 -3
- package/templates/agents/page.md +22 -8
- package/templates/agents/xlsx.md +2 -1
- package/dist/add-DY4AXANK.js +0 -6
- package/dist/add-DY4AXANK.js.map +0 -1
- package/dist/chunk-DTDVSFRY.js.map +0 -1
- package/dist/chunk-LMUACBMA.js.map +0 -1
- package/dist/chunk-NKFBFDRZ.js.map +0 -1
- package/dist/chunk-PVTHHV7X.js.map +0 -1
- package/dist/chunk-QI3XQKHS.js.map +0 -1
- package/dist/chunk-VA776YE5.js +0 -316
- package/dist/chunk-VA776YE5.js.map +0 -1
- package/dist/dev-GDKATCC7.js.map +0 -1
package/dist/client/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { setRoutes } from '../chunk-6S4BAIGV.js';
|
|
2
|
-
import { createQueryClient } from '../chunk-
|
|
3
|
-
import { StrictMode, Component } from 'react';
|
|
2
|
+
import { createQueryClient, setDraftActive, isDraftSettling, SETTLING_MS } from '../chunk-XQUSGIDG.js';
|
|
3
|
+
import { StrictMode, Component, createRef, useSyncExternalStore } from 'react';
|
|
4
4
|
import { createRoot } from 'react-dom/client';
|
|
5
5
|
import { RouterProvider, createRootRoute, createRoute, createRouter, Outlet, lazyRouteComponent } from '@tanstack/react-router';
|
|
6
6
|
import { QueryClientProvider } from '@tanstack/react-query';
|
|
@@ -51,10 +51,17 @@ function lazyComponent(load) {
|
|
|
51
51
|
function lazyErrorComponent(load) {
|
|
52
52
|
return lazyRouteComponent(load);
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function draftGuarded(Inner) {
|
|
55
|
+
return function DraftGuardedError(props) {
|
|
56
|
+
if (isDraftSettling()) throw props.error;
|
|
57
|
+
return /* @__PURE__ */ jsx(Inner, { ...props });
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function buildRouter(manifest, options = {}) {
|
|
61
|
+
const guard = options.draft ? draftGuarded : (c) => c;
|
|
55
62
|
const rootRoute = createRootRoute({
|
|
56
63
|
component: manifest.rootLayout ? lazyComponent(manifest.rootLayout) : RootPassthrough,
|
|
57
|
-
errorComponent: manifest.error ? lazyErrorComponent(manifest.error) : DefaultError,
|
|
64
|
+
errorComponent: guard(manifest.error ? lazyErrorComponent(manifest.error) : DefaultError),
|
|
58
65
|
notFoundComponent: manifest.notFound ? lazyComponent(manifest.notFound) : DefaultNotFound
|
|
59
66
|
});
|
|
60
67
|
const layoutById = /* @__PURE__ */ new Map();
|
|
@@ -96,10 +103,14 @@ function buildRouter(manifest) {
|
|
|
96
103
|
const router = createRouter({
|
|
97
104
|
routeTree: rootRoute,
|
|
98
105
|
defaultPendingComponent: DefaultPending,
|
|
99
|
-
defaultErrorComponent: DefaultError,
|
|
106
|
+
defaultErrorComponent: guard(DefaultError),
|
|
100
107
|
defaultNotFoundComponent: DefaultNotFound,
|
|
101
108
|
defaultPreload: "intent",
|
|
102
|
-
scrollRestoration: true
|
|
109
|
+
scrollRestoration: true,
|
|
110
|
+
// The router's own outermost boundary would catch the error a guarded error
|
|
111
|
+
// component rethrows and draw its stock error page; let it reach the draft
|
|
112
|
+
// boundary around the router instead.
|
|
113
|
+
...options.draft ? { disableGlobalCatchBoundary: true } : {}
|
|
103
114
|
});
|
|
104
115
|
return { router, meta };
|
|
105
116
|
}
|
|
@@ -113,6 +124,104 @@ function layoutDepth(layout, manifest) {
|
|
|
113
124
|
}
|
|
114
125
|
return depth;
|
|
115
126
|
}
|
|
127
|
+
var resetListeners = /* @__PURE__ */ new Set();
|
|
128
|
+
var draftFiles = [];
|
|
129
|
+
var DRAFT_END_RESET_MS = SETTLING_MS + 100;
|
|
130
|
+
function resetDraftBoundaries() {
|
|
131
|
+
for (const reset of resetListeners) reset();
|
|
132
|
+
}
|
|
133
|
+
function connectDraft(hot, handlers) {
|
|
134
|
+
hot.on("vantage:draft-state", (data) => {
|
|
135
|
+
const active = data?.active === true;
|
|
136
|
+
if (active && Array.isArray(data?.files)) draftFiles = data.files.filter((f) => typeof f === "string");
|
|
137
|
+
setDraftActive(active);
|
|
138
|
+
if (!active) setTimeout(resetDraftBoundaries, DRAFT_END_RESET_MS);
|
|
139
|
+
});
|
|
140
|
+
hot.on("vantage:draft-page", (data) => {
|
|
141
|
+
if (typeof data?.route === "string" && data.route !== "") handlers.onPage(data.route);
|
|
142
|
+
});
|
|
143
|
+
hot.on("vantage:draft-page-closed", (data) => {
|
|
144
|
+
if (typeof data?.route === "string" && data.route !== "") handlers.onPageClosed?.(data.route);
|
|
145
|
+
});
|
|
146
|
+
hot.on("vite:afterUpdate", () => resetDraftBoundaries());
|
|
147
|
+
hot.send("vantage:draft-sync");
|
|
148
|
+
}
|
|
149
|
+
function draftFileInStack(stack, files) {
|
|
150
|
+
if (!stack) return void 0;
|
|
151
|
+
let best;
|
|
152
|
+
for (const file of files) {
|
|
153
|
+
const needle = `/${file}`;
|
|
154
|
+
for (let at = stack.indexOf(needle); at !== -1; at = stack.indexOf(needle, at + 1)) {
|
|
155
|
+
if (/[\w./-]/.test(stack.charAt(at + needle.length))) continue;
|
|
156
|
+
if (best === void 0 || at < best.at) best = { file, at };
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return best?.file;
|
|
161
|
+
}
|
|
162
|
+
function reportDraftRenderError(hot, error, componentStack) {
|
|
163
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
164
|
+
const stack = [error instanceof Error ? error.stack : void 0, componentStack].filter(Boolean).join("\n");
|
|
165
|
+
const file = draftFileInStack(stack, draftFiles);
|
|
166
|
+
hot.send("vantage:draft-render-error", file === void 0 ? { message } : { file, message });
|
|
167
|
+
}
|
|
168
|
+
function announceDraftPage(route, parent = window.parent) {
|
|
169
|
+
if (parent === window) return;
|
|
170
|
+
parent.postMessage({ source: "vantage", type: "vantage:draft-page-opened", path: route }, "*");
|
|
171
|
+
}
|
|
172
|
+
function announceDraftPageClosed(route, parent = window.parent) {
|
|
173
|
+
if (parent === window) return;
|
|
174
|
+
parent.postMessage({ source: "vantage", type: "vantage:draft-page-closed", path: route }, "*");
|
|
175
|
+
}
|
|
176
|
+
function freeze(host) {
|
|
177
|
+
const copy = host.cloneNode(true);
|
|
178
|
+
const from = host.querySelectorAll("canvas");
|
|
179
|
+
const to = copy.querySelectorAll("canvas");
|
|
180
|
+
from.forEach((canvas, i) => {
|
|
181
|
+
try {
|
|
182
|
+
to[i]?.getContext("2d")?.drawImage(canvas, 0, 0);
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return copy;
|
|
187
|
+
}
|
|
188
|
+
var DraftFreezeBoundary = class extends Component {
|
|
189
|
+
state = { hasError: false, error: null, draft: false, generation: 0 };
|
|
190
|
+
host = createRef();
|
|
191
|
+
frozen = createRef();
|
|
192
|
+
static getDerivedStateFromError(error) {
|
|
193
|
+
return { hasError: true, error, draft: isDraftSettling() };
|
|
194
|
+
}
|
|
195
|
+
componentDidMount() {
|
|
196
|
+
resetListeners.add(this.reset);
|
|
197
|
+
}
|
|
198
|
+
componentWillUnmount() {
|
|
199
|
+
resetListeners.delete(this.reset);
|
|
200
|
+
}
|
|
201
|
+
// Runs before the commit touches the DOM, so the screen is still the last good one.
|
|
202
|
+
getSnapshotBeforeUpdate(_props, prev) {
|
|
203
|
+
if (!prev.hasError && this.state.hasError && this.host.current) return freeze(this.host.current);
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
componentDidUpdate(_props, _prev, snapshot) {
|
|
207
|
+
if (snapshot && this.frozen.current) this.frozen.current.replaceChildren(...Array.from(snapshot.childNodes));
|
|
208
|
+
}
|
|
209
|
+
componentDidCatch(error, info) {
|
|
210
|
+
if (isDraftSettling()) this.props.onError?.(error, info?.componentStack ?? void 0);
|
|
211
|
+
}
|
|
212
|
+
reset = () => {
|
|
213
|
+
if (this.state.hasError) {
|
|
214
|
+
this.setState((s) => ({ hasError: false, error: null, draft: false, generation: s.generation + 1 }));
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
render() {
|
|
218
|
+
if (this.state.hasError) {
|
|
219
|
+
if (!this.state.draft) throw this.state.error;
|
|
220
|
+
return /* @__PURE__ */ jsx("div", { ref: this.frozen, "data-vantage-draft-frozen": true, style: { display: "contents" } });
|
|
221
|
+
}
|
|
222
|
+
return /* @__PURE__ */ jsx("div", { ref: this.host, style: { display: "contents" }, children: this.props.children }, this.state.generation);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
116
225
|
|
|
117
226
|
// src/client/self-heal.ts
|
|
118
227
|
var RELOAD_COOLDOWN_MS = 1e4;
|
|
@@ -147,32 +256,116 @@ function registerChunkErrorSelfHeal() {
|
|
|
147
256
|
}
|
|
148
257
|
});
|
|
149
258
|
}
|
|
150
|
-
function
|
|
259
|
+
function createRouterHolder(initial) {
|
|
260
|
+
let current = initial;
|
|
261
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
262
|
+
return {
|
|
263
|
+
get: () => current,
|
|
264
|
+
set(next) {
|
|
265
|
+
current = next;
|
|
266
|
+
for (const l of listeners) l();
|
|
267
|
+
},
|
|
268
|
+
subscribe(l) {
|
|
269
|
+
listeners.add(l);
|
|
270
|
+
return () => {
|
|
271
|
+
listeners.delete(l);
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function SwappableRouter({ holder }) {
|
|
277
|
+
const router = useSyncExternalStore(holder.subscribe, holder.get);
|
|
278
|
+
return /* @__PURE__ */ jsx(RouterProvider, { router });
|
|
279
|
+
}
|
|
280
|
+
function bootstrap(manifest, options = {}) {
|
|
281
|
+
const { hot } = options;
|
|
151
282
|
registerChunkErrorSelfHeal();
|
|
152
283
|
setRoutes(manifest);
|
|
153
|
-
const
|
|
284
|
+
const holder = createRouterHolder(buildRouter(manifest, { draft: Boolean(hot) }).router);
|
|
154
285
|
const queryClient = createQueryClient();
|
|
155
286
|
const defaultTitle = document.title;
|
|
156
287
|
const updateTitle = () => {
|
|
157
288
|
try {
|
|
158
|
-
const matches =
|
|
289
|
+
const matches = holder.get().state?.matches ?? [];
|
|
159
290
|
const leaf = matches[matches.length - 1];
|
|
160
291
|
const title = leaf?.staticData?.title;
|
|
161
292
|
document.title = typeof title === "string" && title.length > 0 ? title : defaultTitle;
|
|
162
293
|
} catch {
|
|
163
294
|
}
|
|
164
295
|
};
|
|
165
|
-
|
|
296
|
+
let unsubscribeTitle = holder.get().subscribe?.("onResolved", updateTitle);
|
|
166
297
|
const el = document.getElementById("root");
|
|
167
298
|
if (!el) {
|
|
168
299
|
throw new Error('[vantage] Root element "#root" was not found in the document.');
|
|
169
300
|
}
|
|
301
|
+
if (!hot) {
|
|
302
|
+
createRoot(el).render(
|
|
303
|
+
/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(AppErrorBoundary, { children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(RouterProvider, { router: holder.get() }) }) }) })
|
|
304
|
+
);
|
|
305
|
+
updateTitle();
|
|
306
|
+
return { update: () => location.reload() };
|
|
307
|
+
}
|
|
308
|
+
let currentManifest = manifest;
|
|
309
|
+
let pendingRoute = null;
|
|
310
|
+
let openedRoute = null;
|
|
311
|
+
const hasRoute = (route) => currentManifest.pages.some((p) => p.routePath === route);
|
|
312
|
+
const navigable = (route) => !/[:*]/.test(route);
|
|
313
|
+
const open = async (route) => {
|
|
314
|
+
openedRoute = route;
|
|
315
|
+
try {
|
|
316
|
+
await holder.get().navigate({ to: route });
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
announceDraftPage(route);
|
|
320
|
+
};
|
|
321
|
+
connectDraft(hot, {
|
|
322
|
+
onPage(route) {
|
|
323
|
+
if (!navigable(route)) return;
|
|
324
|
+
if (hasRoute(route)) void open(route);
|
|
325
|
+
else pendingRoute = route;
|
|
326
|
+
},
|
|
327
|
+
onPageClosed(route) {
|
|
328
|
+
if (!navigable(route)) return;
|
|
329
|
+
if (pendingRoute === route) pendingRoute = null;
|
|
330
|
+
announceDraftPageClosed(route);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
170
333
|
createRoot(el).render(
|
|
171
|
-
/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(AppErrorBoundary, { children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(
|
|
334
|
+
/* @__PURE__ */ jsx(StrictMode, { children: /* @__PURE__ */ jsx(AppErrorBoundary, { children: /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(DraftFreezeBoundary, { onError: (error, componentStack) => reportDraftRenderError(hot, error, componentStack), children: /* @__PURE__ */ jsx(SwappableRouter, { holder }) }) }) }) })
|
|
172
335
|
);
|
|
173
336
|
updateTitle();
|
|
337
|
+
return {
|
|
338
|
+
update(next) {
|
|
339
|
+
currentManifest = next;
|
|
340
|
+
setRoutes(next);
|
|
341
|
+
unsubscribeTitle?.();
|
|
342
|
+
holder.set(buildRouter(next, { draft: true }).router);
|
|
343
|
+
void holder.get().load?.();
|
|
344
|
+
unsubscribeTitle = holder.get().subscribe?.("onResolved", updateTitle);
|
|
345
|
+
if (pendingRoute !== null && hasRoute(pendingRoute)) {
|
|
346
|
+
const route = pendingRoute;
|
|
347
|
+
pendingRoute = null;
|
|
348
|
+
void open(route);
|
|
349
|
+
} else if (openedRoute !== null && !hasRoute(openedRoute)) {
|
|
350
|
+
if (location.pathname === openedRoute) void holder.get().navigate({ to: "/" }).catch(() => {
|
|
351
|
+
});
|
|
352
|
+
openedRoute = null;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
function DraftSkeleton() {
|
|
358
|
+
return /* @__PURE__ */ jsx(
|
|
359
|
+
"div",
|
|
360
|
+
{
|
|
361
|
+
"data-vantage-skeleton": true,
|
|
362
|
+
"aria-hidden": "true",
|
|
363
|
+
className: "animate-pulse rounded-md bg-muted",
|
|
364
|
+
style: { minHeight: "4rem", width: "100%" }
|
|
365
|
+
}
|
|
366
|
+
);
|
|
174
367
|
}
|
|
175
368
|
|
|
176
|
-
export { bootstrap };
|
|
369
|
+
export { DraftSkeleton, bootstrap };
|
|
177
370
|
//# sourceMappingURL=index.js.map
|
|
178
371
|
//# sourceMappingURL=index.js.map
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/states.tsx","../../src/client/error-boundary.tsx","../../src/client/build-router.tsx","../../src/client/self-heal.ts","../../src/client/bootstrap.tsx"],"names":["jsx"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReactNode } from \"react\"\n\n/** Minimal internal states used as router-level defaults. */\n\nexport function DefaultPending(): ReactNode {\n return (\n <div className=\"flex min-h-[40vh] items-center justify-center\" role=\"status\" aria-live=\"polite\">\n <div className=\"flex items-center gap-3 text-sm text-[var(--muted-foreground,#71717a)]\">\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Loading…\n </div>\n </div>\n )\n}\n\nexport function DefaultError({ error }: { error: unknown }): ReactNode {\n const message = error instanceof Error ? error.message : String(error)\n return (\n <div className=\"mx-auto max-w-2xl p-6\" role=\"alert\">\n <div className=\"rounded-lg border border-[var(--border,#e4e4e7)] bg-[var(--card,#fff)] p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--foreground,#09090b)]\">Something went wrong</h2>\n <p className=\"mt-2 text-sm text-[var(--muted-foreground,#71717a)]\">{message}</p>\n </div>\n </div>\n )\n}\n\nexport function DefaultNotFound(): ReactNode {\n return (\n <div className=\"mx-auto max-w-2xl p-6 text-center\">\n <p className=\"text-5xl font-bold text-[var(--muted-foreground,#a1a1aa)]\">404</p>\n <h2 className=\"mt-3 text-lg font-semibold text-[var(--foreground,#09090b)]\">Page not found</h2>\n <p className=\"mt-1 text-sm text-[var(--muted-foreground,#71717a)]\">\n The page you are looking for does not exist.\n </p>\n </div>\n )\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\"\nimport { DefaultError } from \"./states\"\n\ninterface Props {\n children: ReactNode\n fallback?: (error: unknown) => ReactNode\n}\n\ninterface State {\n error: unknown\n}\n\n/**\n * Top-level error boundary that wraps the entire application (outside the\n * router). Route-level errors are handled by the router's errorComponent; this\n * catches catastrophic render failures in the provider tree.\n */\nexport class AppErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(error: unknown): State {\n return { error }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo): void {\n // Forwarded to the terminal in dev via the console bridge.\n console.error(\"[vantage] Unhandled application error:\", error, info.componentStack)\n }\n\n render(): ReactNode {\n if (this.state.error != null) {\n return this.props.fallback\n ? this.props.fallback(this.state.error)\n : <DefaultError error={this.state.error} />\n }\n return this.props.children\n }\n}\n","import {\n createRootRoute,\n createRoute,\n createRouter,\n lazyRouteComponent,\n Outlet,\n} from \"@tanstack/react-router\"\nimport type { ClientManifest, Loader } from \"./manifest\"\nimport { DefaultError, DefaultNotFound, DefaultPending } from \"./states\"\n\n// The programmatic route tree fights TanStack's file-route generics, which are\n// designed for codegen. Internal assembly is intentionally untyped; the public\n// surface (pages, definePage) stays fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyRoute = any\n\nfunction RootPassthrough() {\n return <Outlet />\n}\n\nfunction lazyComponent(load: Loader): AnyRoute {\n return lazyRouteComponent(load as () => Promise<{ default: any }>)\n}\n\nfunction lazyErrorComponent(load: Loader): AnyRoute {\n return lazyRouteComponent(load as () => Promise<{ default: any }>)\n}\n\nexport interface BuiltRouter {\n router: AnyRoute\n /** routeId -> page meta, for the title manager. */\n meta: Map<string, { title?: string; description?: string; routePath: string }>\n}\n\n/** Assemble a TanStack Router instance from the generated manifest. */\nexport function buildRouter(manifest: ClientManifest): BuiltRouter {\n const rootRoute = createRootRoute({\n component: manifest.rootLayout ? lazyComponent(manifest.rootLayout) : RootPassthrough,\n errorComponent: manifest.error ? lazyErrorComponent(manifest.error) : DefaultError,\n notFoundComponent: manifest.notFound ? lazyComponent(manifest.notFound) : DefaultNotFound,\n })\n\n const layoutById = new Map<string, AnyRoute>()\n const childrenByParent = new Map<string, AnyRoute[]>()\n const meta = new Map<string, { title?: string; description?: string; routePath: string }>()\n\n const pushChild = (parentKey: string, route: AnyRoute) => {\n const list = childrenByParent.get(parentKey) ?? []\n list.push(route)\n childrenByParent.set(parentKey, list)\n }\n\n // 1. Create layout routes (parents referenced lazily via getParentRoute).\n for (const layout of manifest.layouts) {\n const parentKey = layout.parentId ?? \"__root__\"\n const route: AnyRoute = createRoute({\n getParentRoute: () =>\n layout.parentId ? layoutById.get(layout.parentId)! : rootRoute,\n path: layout.path,\n component: lazyComponent(layout.load),\n } as AnyRoute)\n layoutById.set(layout.id, route)\n pushChild(parentKey, route)\n }\n\n // 2. Create page routes.\n for (const page of manifest.pages) {\n const parentKey = page.parentLayoutId ?? \"__root__\"\n const route: AnyRoute = createRoute({\n getParentRoute: () =>\n page.parentLayoutId ? layoutById.get(page.parentLayoutId)! : rootRoute,\n path: page.path,\n component: lazyComponent(page.load),\n staticData: { title: page.title, description: page.description, routePath: page.routePath },\n } as AnyRoute)\n pushChild(parentKey, route)\n // route.id is finalized after createRouter; index by routePath-derived key\n // is unreliable, so the title manager reads staticData off matches instead.\n }\n\n // 3. Attach children — deepest layouts first so nested trees are built before\n // their parent references them.\n const layoutsDeepFirst = [...manifest.layouts].sort(\n (a, b) => layoutDepth(b, manifest) - layoutDepth(a, manifest),\n )\n for (const layout of layoutsDeepFirst) {\n const route = layoutById.get(layout.id)!\n route.addChildren(childrenByParent.get(layout.id) ?? [])\n }\n rootRoute.addChildren(childrenByParent.get(\"__root__\") ?? [])\n\n const router = createRouter({\n routeTree: rootRoute,\n defaultPendingComponent: DefaultPending,\n defaultErrorComponent: DefaultError,\n defaultNotFoundComponent: DefaultNotFound,\n defaultPreload: \"intent\",\n scrollRestoration: true,\n } as AnyRoute)\n\n return { router, meta }\n}\n\nfunction layoutDepth(layout: { id: string; parentId: string | null }, manifest: ClientManifest): number {\n let depth = 0\n let current: string | null = layout.parentId\n const byId = new Map(manifest.layouts.map((l) => [l.id, l]))\n while (current) {\n depth++\n current = byId.get(current)?.parentId ?? null\n }\n return depth\n}\n","/**\n * Stale-chunk self-healing.\n *\n * A published app is served build-by-build: its HTML references content-hashed\n * JS chunks that belong to one build. When the app is re-published, an\n * already-open tab can end up requesting a chunk hash that the newly-served\n * build no longer has (the routing pin that keeps a session on one build is\n * short-lived by design), which fails the dynamic import. Vite emits\n * `vite:preloadError` for exactly that case.\n *\n * We reload once to pick up the new build. A short sessionStorage cooldown keeps\n * a genuinely-unreachable chunk (offline, or a build that was garbage-collected)\n * from turning into an infinite reload loop — after the first failed reload the\n * error is allowed to surface to the error boundary instead.\n */\nconst RELOAD_COOLDOWN_MS = 10_000\nconst RELOAD_STAMP_KEY = \"__vantage_chunk_reload_at\"\n\n// Messages browsers use when a dynamic import / module preload fails to load.\nconst DYNAMIC_IMPORT_FAILURE = /Failed to fetch dynamically imported module|error loading dynamically imported module|Importing a module script failed/i\n\nfunction reloadOnceForStaleChunk(): void {\n let last = 0\n try {\n last = Number(window.sessionStorage.getItem(RELOAD_STAMP_KEY) ?? \"0\")\n } catch {\n // sessionStorage can throw in private/embedded contexts — treat as \"no prior reload\".\n }\n if (Number.isFinite(last) && Date.now() - last < RELOAD_COOLDOWN_MS) {\n // Already reloaded very recently; the chunk is still unreachable, so stop\n // reloading and let the error surface rather than looping.\n return\n }\n try {\n window.sessionStorage.setItem(RELOAD_STAMP_KEY, String(Date.now()))\n } catch {\n // best-effort — a failed write just means we can't dedupe, not a reason to skip healing.\n }\n window.location.reload()\n}\n\n/**\n * Register global listeners that reload the page when a chunk from a\n * now-replaced build fails to load. Safe to call once at bootstrap; a no-op\n * outside the browser.\n */\nexport function registerChunkErrorSelfHeal(): void {\n if (typeof window === \"undefined\") return\n\n // Vite's canonical signal for a failed dynamic-import preload. Calling\n // preventDefault() stops Vite from re-throwing; we reload instead.\n window.addEventListener(\"vite:preloadError\", (event) => {\n event.preventDefault()\n reloadOnceForStaleChunk()\n })\n\n // Belt-and-suspenders: a dynamic import that fails without a modulepreload\n // surfaces as an unhandled rejection. Only act on the specific stale-module\n // messages so unrelated rejections are left alone.\n window.addEventListener(\"unhandledrejection\", (event) => {\n const reason = event.reason\n const message = reason instanceof Error ? reason.message : String(reason ?? \"\")\n if (DYNAMIC_IMPORT_FAILURE.test(message)) {\n reloadOnceForStaleChunk()\n }\n })\n}\n","import { StrictMode } from \"react\"\nimport { createRoot } from \"react-dom/client\"\nimport { RouterProvider } from \"@tanstack/react-router\"\nimport { QueryClientProvider } from \"@tanstack/react-query\"\nimport { createQueryClient } from \"../query/client\"\nimport { setRoutes } from \"../router/registry\"\nimport { AppErrorBoundary } from \"./error-boundary\"\nimport { buildRouter } from \"./build-router\"\nimport { registerChunkErrorSelfHeal } from \"./self-heal\"\nimport type { ClientManifest } from \"./manifest\"\n\n/**\n * Client entrypoint. The generated `.vantage/client-entry.tsx` calls this with\n * the route manifest. Owns React root creation and the provider tree:\n *\n * <AppErrorBoundary>\n * <QueryClientProvider>\n * <RouterProvider />\n */\nexport function bootstrap(manifest: ClientManifest): void {\n // Recover from stale chunks after a re-publish: reload once when a dynamic\n // import fails because the served build changed under an open tab.\n registerChunkErrorSelfHeal()\n\n // Publish the route list before the first render so `useRoutes()` is\n // populated for the very first page, not one paint late.\n setRoutes(manifest)\n\n const { router } = buildRouter(manifest)\n const queryClient = createQueryClient()\n\n // The document's initial title is the fallback for pages without a definePage\n // title, so navigating away from a titled page doesn't leave a stale title.\n const defaultTitle = document.title\n\n const updateTitle = () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const matches: any[] = router.state?.matches ?? []\n const leaf = matches[matches.length - 1]\n const title = leaf?.staticData?.title\n document.title = typeof title === \"string\" && title.length > 0 ? title : defaultTitle\n } catch {\n /* title updates are best-effort */\n }\n }\n router.subscribe?.(\"onResolved\", updateTitle)\n\n const el = document.getElementById(\"root\")\n if (!el) {\n throw new Error('[vantage] Root element \"#root\" was not found in the document.')\n }\n\n createRoot(el).render(\n <StrictMode>\n <AppErrorBoundary>\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={router} />\n </QueryClientProvider>\n </AppErrorBoundary>\n </StrictMode>,\n )\n\n updateTitle()\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/states.tsx","../../src/client/error-boundary.tsx","../../src/client/build-router.tsx","../../src/client/draft.tsx","../../src/client/self-heal.ts","../../src/client/bootstrap.tsx","../../src/client/draft-skeleton.tsx"],"names":["jsx","Component"],"mappings":"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","file":"index.js","sourcesContent":["import type { ReactNode } from \"react\"\n\n/** Minimal internal states used as router-level defaults. */\n\nexport function DefaultPending(): ReactNode {\n return (\n <div className=\"flex min-h-[40vh] items-center justify-center\" role=\"status\" aria-live=\"polite\">\n <div className=\"flex items-center gap-3 text-sm text-[var(--muted-foreground,#71717a)]\">\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n Loading…\n </div>\n </div>\n )\n}\n\nexport function DefaultError({ error }: { error: unknown }): ReactNode {\n const message = error instanceof Error ? error.message : String(error)\n return (\n <div className=\"mx-auto max-w-2xl p-6\" role=\"alert\">\n <div className=\"rounded-lg border border-[var(--border,#e4e4e7)] bg-[var(--card,#fff)] p-6\">\n <h2 className=\"text-lg font-semibold text-[var(--foreground,#09090b)]\">Something went wrong</h2>\n <p className=\"mt-2 text-sm text-[var(--muted-foreground,#71717a)]\">{message}</p>\n </div>\n </div>\n )\n}\n\nexport function DefaultNotFound(): ReactNode {\n return (\n <div className=\"mx-auto max-w-2xl p-6 text-center\">\n <p className=\"text-5xl font-bold text-[var(--muted-foreground,#a1a1aa)]\">404</p>\n <h2 className=\"mt-3 text-lg font-semibold text-[var(--foreground,#09090b)]\">Page not found</h2>\n <p className=\"mt-1 text-sm text-[var(--muted-foreground,#71717a)]\">\n The page you are looking for does not exist.\n </p>\n </div>\n )\n}\n","import { Component, type ErrorInfo, type ReactNode } from \"react\"\nimport { DefaultError } from \"./states\"\n\ninterface Props {\n children: ReactNode\n fallback?: (error: unknown) => ReactNode\n}\n\ninterface State {\n error: unknown\n}\n\n/**\n * Top-level error boundary that wraps the entire application (outside the\n * router). Route-level errors are handled by the router's errorComponent; this\n * catches catastrophic render failures in the provider tree.\n */\nexport class AppErrorBoundary extends Component<Props, State> {\n state: State = { error: null }\n\n static getDerivedStateFromError(error: unknown): State {\n return { error }\n }\n\n componentDidCatch(error: unknown, info: ErrorInfo): void {\n // Forwarded to the terminal in dev via the console bridge.\n console.error(\"[vantage] Unhandled application error:\", error, info.componentStack)\n }\n\n render(): ReactNode {\n if (this.state.error != null) {\n return this.props.fallback\n ? this.props.fallback(this.state.error)\n : <DefaultError error={this.state.error} />\n }\n return this.props.children\n }\n}\n","import {\n createRootRoute,\n createRoute,\n createRouter,\n lazyRouteComponent,\n Outlet,\n} from \"@tanstack/react-router\"\nimport { isDraftSettling } from \"./draft-state\"\nimport type { ClientManifest, Loader } from \"./manifest\"\nimport { DefaultError, DefaultNotFound, DefaultPending } from \"./states\"\n\n// The programmatic route tree fights TanStack's file-route generics, which are\n// designed for codegen. Internal assembly is intentionally untyped; the public\n// surface (pages, definePage) stays fully typed.\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyRoute = any\n\nfunction RootPassthrough() {\n return <Outlet />\n}\n\nfunction lazyComponent(load: Loader): AnyRoute {\n return lazyRouteComponent(load as () => Promise<{ default: any }>)\n}\n\nfunction lazyErrorComponent(load: Loader): AnyRoute {\n return lazyRouteComponent(load as () => Promise<{ default: any }>)\n}\n\n/**\n * While a draft is showing, a failing route must not draw the error page: the\n * error goes up to the draft boundary, which keeps the previous screen. With no\n * draft active this renders the wrapped component untouched.\n */\nfunction draftGuarded(Inner: AnyRoute): AnyRoute {\n return function DraftGuardedError(props: { error: unknown }) {\n if (isDraftSettling()) throw props.error\n return <Inner {...props} />\n }\n}\n\nexport interface BuildRouterOptions {\n /** Route the draft preview's failures to the draft boundary (see `draftGuarded`). */\n draft?: boolean\n}\n\nexport interface BuiltRouter {\n router: AnyRoute\n /** routeId -> page meta, for the title manager. */\n meta: Map<string, { title?: string; description?: string; routePath: string }>\n}\n\n/** Assemble a TanStack Router instance from the generated manifest. */\nexport function buildRouter(manifest: ClientManifest, options: BuildRouterOptions = {}): BuiltRouter {\n const guard = options.draft ? draftGuarded : (c: AnyRoute) => c\n const rootRoute = createRootRoute({\n component: manifest.rootLayout ? lazyComponent(manifest.rootLayout) : RootPassthrough,\n errorComponent: guard(manifest.error ? lazyErrorComponent(manifest.error) : DefaultError),\n notFoundComponent: manifest.notFound ? lazyComponent(manifest.notFound) : DefaultNotFound,\n })\n\n const layoutById = new Map<string, AnyRoute>()\n const childrenByParent = new Map<string, AnyRoute[]>()\n const meta = new Map<string, { title?: string; description?: string; routePath: string }>()\n\n const pushChild = (parentKey: string, route: AnyRoute) => {\n const list = childrenByParent.get(parentKey) ?? []\n list.push(route)\n childrenByParent.set(parentKey, list)\n }\n\n // 1. Create layout routes (parents referenced lazily via getParentRoute).\n for (const layout of manifest.layouts) {\n const parentKey = layout.parentId ?? \"__root__\"\n const route: AnyRoute = createRoute({\n getParentRoute: () =>\n layout.parentId ? layoutById.get(layout.parentId)! : rootRoute,\n path: layout.path,\n component: lazyComponent(layout.load),\n } as AnyRoute)\n layoutById.set(layout.id, route)\n pushChild(parentKey, route)\n }\n\n // 2. Create page routes.\n for (const page of manifest.pages) {\n const parentKey = page.parentLayoutId ?? \"__root__\"\n const route: AnyRoute = createRoute({\n getParentRoute: () =>\n page.parentLayoutId ? layoutById.get(page.parentLayoutId)! : rootRoute,\n path: page.path,\n component: lazyComponent(page.load),\n staticData: { title: page.title, description: page.description, routePath: page.routePath },\n } as AnyRoute)\n pushChild(parentKey, route)\n // route.id is finalized after createRouter; index by routePath-derived key\n // is unreliable, so the title manager reads staticData off matches instead.\n }\n\n // 3. Attach children — deepest layouts first so nested trees are built before\n // their parent references them.\n const layoutsDeepFirst = [...manifest.layouts].sort(\n (a, b) => layoutDepth(b, manifest) - layoutDepth(a, manifest),\n )\n for (const layout of layoutsDeepFirst) {\n const route = layoutById.get(layout.id)!\n route.addChildren(childrenByParent.get(layout.id) ?? [])\n }\n rootRoute.addChildren(childrenByParent.get(\"__root__\") ?? [])\n\n const router = createRouter({\n routeTree: rootRoute,\n defaultPendingComponent: DefaultPending,\n defaultErrorComponent: guard(DefaultError),\n defaultNotFoundComponent: DefaultNotFound,\n defaultPreload: \"intent\",\n scrollRestoration: true,\n // The router's own outermost boundary would catch the error a guarded error\n // component rethrows and draw its stock error page; let it reach the draft\n // boundary around the router instead.\n ...(options.draft ? { disableGlobalCatchBoundary: true } : {}),\n } as AnyRoute)\n\n return { router, meta }\n}\n\nfunction layoutDepth(layout: { id: string; parentId: string | null }, manifest: ClientManifest): number {\n let depth = 0\n let current: string | null = layout.parentId\n const byId = new Map(manifest.layouts.map((l) => [l.id, l]))\n while (current) {\n depth++\n current = byId.get(current)?.parentId ?? null\n }\n return depth\n}\n","import { Component, createRef, type ReactNode } from \"react\"\nimport { isDraftActive, isDraftSettling, SETTLING_MS, setDraftActive } from \"./draft-state\"\n\n/** The slice of Vite's HMR context the draft layer uses. */\nexport interface DraftHot {\n on(event: string, cb: (data: any) => void): void // eslint-disable-line @typescript-eslint/no-explicit-any\n send(event: string, data?: unknown): void\n}\n\nconst resetListeners = new Set<() => void>()\n\n/** The files the server last said it holds a draft of (project-relative), to tell which one a failure came from. */\nlet draftFiles: string[] = []\n\n/**\n * How long a screen held after a draft failed waits for the version the server\n * falls back to. The update normally follows within a frame or two; if none\n * comes (nothing on disk to go back to) the children are drawn again after this.\n * Not before `isDraftSettling` is over: a final version that really throws would\n * be taken for the draft's failure once more and held with nobody left to reset it.\n */\nexport const DRAFT_END_RESET_MS = SETTLING_MS + 100\n\n/** Ask every draft boundary to draw its children again. */\nexport function resetDraftBoundaries(): void {\n for (const reset of resetListeners) reset()\n}\n\n/**\n * Wire the server's draft events to the client:\n * vantage:draft-state → `window.__VANTAGE_DRAFT__`, and back to live content a moment after it ends\n * vantage:draft-page → `onPage` (the router lives in bootstrap)\n * vantage:draft-page-closed → `onPageClosed` (a new page that was never written)\n * vite:afterUpdate → a newer version arrived, so try drawing again\n */\nexport function connectDraft(\n hot: DraftHot,\n handlers: { onPage(route: string): void; onPageClosed?(route: string): void },\n): void {\n hot.on(\"vantage:draft-state\", (data: { active?: boolean; files?: unknown } | undefined) => {\n const active = data?.active === true\n // Kept when the draft ends: a failure reported a moment later still names its file.\n if (active && Array.isArray(data?.files)) draftFiles = data.files.filter((f): f is string => typeof f === \"string\")\n setDraftActive(active)\n // Not at once: the server announces the end before it sends the version it\n // fell back to, and drawing the failing one again here would show the error page.\n if (!active) setTimeout(resetDraftBoundaries, DRAFT_END_RESET_MS)\n })\n hot.on(\"vantage:draft-page\", (data: { route?: string } | undefined) => {\n if (typeof data?.route === \"string\" && data.route !== \"\") handlers.onPage(data.route)\n })\n hot.on(\"vantage:draft-page-closed\", (data: { route?: string } | undefined) => {\n if (typeof data?.route === \"string\" && data.route !== \"\") handlers.onPageClosed?.(data.route)\n })\n hot.on(\"vite:afterUpdate\", () => resetDraftBoundaries())\n // The server only announces a change, so a page that loads while a draft is showing has to ask.\n hot.send(\"vantage:draft-sync\")\n}\n\n/**\n * The draft file a failure came from: the one named first in the stack (the\n * module that threw, then the components that rendered it). Browser stacks name\n * modules by their dev-server URL, so a project-relative path is looked for as a\n * `/path` followed by nothing that could extend it.\n */\nexport function draftFileInStack(stack: string | undefined, files: readonly string[]): string | undefined {\n if (!stack) return undefined\n let best: { file: string; at: number } | undefined\n for (const file of files) {\n const needle = `/${file}`\n for (let at = stack.indexOf(needle); at !== -1; at = stack.indexOf(needle, at + 1)) {\n if (/[\\w./-]/.test(stack.charAt(at + needle.length))) continue\n if (best === undefined || at < best.at) best = { file, at }\n break\n }\n }\n return best?.file\n}\n\n/**\n * Tell the server the draft threw while rendering, so it can fall back to the\n * version before. `file` is the draft the failure came from when the stack names\n * one; without it the server steps back the draft it applied last.\n */\nexport function reportDraftRenderError(hot: DraftHot, error: unknown, componentStack?: string): void {\n const message = error instanceof Error ? error.message : String(error)\n const stack = [error instanceof Error ? error.stack : undefined, componentStack].filter(Boolean).join(\"\\n\")\n const file = draftFileInStack(stack, draftFiles)\n hot.send(\"vantage:draft-render-error\", file === undefined ? { message } : { file, message })\n}\n\n/**\n * Tell the surrounding editor a draft page is on screen. A no-op outside an\n * iframe: there is nobody to tell.\n */\nexport function announceDraftPage(route: string, parent: Window = window.parent): void {\n if (parent === window) return\n parent.postMessage({ source: \"vantage\", type: \"vantage:draft-page-opened\", path: route }, \"*\")\n}\n\n/** Tell the surrounding editor a draft page it was told about is gone. */\nexport function announceDraftPageClosed(route: string, parent: Window = window.parent): void {\n if (parent === window) return\n parent.postMessage({ source: \"vantage\", type: \"vantage:draft-page-closed\", path: route }, \"*\")\n}\n\n/** A copy of what is on screen, canvases included (cloning a canvas leaves it blank). */\nfunction freeze(host: HTMLElement): Node {\n const copy = host.cloneNode(true) as HTMLElement\n const from = host.querySelectorAll(\"canvas\")\n const to = copy.querySelectorAll(\"canvas\")\n from.forEach((canvas, i) => {\n try {\n to[i]?.getContext(\"2d\")?.drawImage(canvas, 0, 0)\n } catch {\n /* a canvas that cannot be read stays blank */\n }\n })\n return copy\n}\n\ninterface Props {\n children: ReactNode\n onError?: (error: unknown, componentStack?: string) => void\n}\n\ninterface State {\n hasError: boolean\n error: unknown\n /** The failure happened while a draft was showing (the draft may end before the screen is redrawn). */\n draft: boolean\n generation: number\n}\n\n/**\n * Keeps the previous screen up when a draft throws while rendering.\n *\n * Wraps the router. While a draft is showing, the error components rethrow\n * (see `build-router`) instead of drawing the error page, and that lands here:\n * the DOM as it was just before the failure is copied and kept, the server is\n * told (`onError`), and it falls back to the version before. The next HMR\n * update — or the draft ending — draws the children again. Without an active\n * draft nothing is caught: the error goes on to `AppErrorBoundary` as before.\n */\nexport class DraftFreezeBoundary extends Component<Props, State> {\n state: State = { hasError: false, error: null, draft: false, generation: 0 }\n private host = createRef<HTMLDivElement>()\n private frozen = createRef<HTMLDivElement>()\n\n static getDerivedStateFromError(error: unknown): Partial<State> {\n return { hasError: true, error, draft: isDraftSettling() }\n }\n\n componentDidMount(): void {\n resetListeners.add(this.reset)\n }\n\n componentWillUnmount(): void {\n resetListeners.delete(this.reset)\n }\n\n // Runs before the commit touches the DOM, so the screen is still the last good one.\n getSnapshotBeforeUpdate(_props: Props, prev: State): Node | null {\n if (!prev.hasError && this.state.hasError && this.host.current) return freeze(this.host.current)\n return null\n }\n\n componentDidUpdate(_props: Props, _prev: State, snapshot: Node | null): void {\n if (snapshot && this.frozen.current) this.frozen.current.replaceChildren(...Array.from(snapshot.childNodes))\n }\n\n componentDidCatch(error: unknown, info?: { componentStack?: string | null }): void {\n if (isDraftSettling()) this.props.onError?.(error, info?.componentStack ?? undefined)\n }\n\n private reset = (): void => {\n if (this.state.hasError) {\n this.setState((s) => ({ hasError: false, error: null, draft: false, generation: s.generation + 1 }))\n }\n }\n\n render(): ReactNode {\n if (this.state.hasError) {\n // Not a draft's failure: leave it to the boundary above.\n if (!this.state.draft) throw this.state.error\n return <div ref={this.frozen} data-vantage-draft-frozen style={{ display: \"contents\" }} />\n }\n return (\n <div key={this.state.generation} ref={this.host} style={{ display: \"contents\" }}>\n {this.props.children}\n </div>\n )\n }\n}\n","/**\n * Stale-chunk self-healing.\n *\n * A published app is served build-by-build: its HTML references content-hashed\n * JS chunks that belong to one build. When the app is re-published, an\n * already-open tab can end up requesting a chunk hash that the newly-served\n * build no longer has (the routing pin that keeps a session on one build is\n * short-lived by design), which fails the dynamic import. Vite emits\n * `vite:preloadError` for exactly that case.\n *\n * We reload once to pick up the new build. A short sessionStorage cooldown keeps\n * a genuinely-unreachable chunk (offline, or a build that was garbage-collected)\n * from turning into an infinite reload loop — after the first failed reload the\n * error is allowed to surface to the error boundary instead.\n */\nconst RELOAD_COOLDOWN_MS = 10_000\nconst RELOAD_STAMP_KEY = \"__vantage_chunk_reload_at\"\n\n// Messages browsers use when a dynamic import / module preload fails to load.\nconst DYNAMIC_IMPORT_FAILURE = /Failed to fetch dynamically imported module|error loading dynamically imported module|Importing a module script failed/i\n\nfunction reloadOnceForStaleChunk(): void {\n let last = 0\n try {\n last = Number(window.sessionStorage.getItem(RELOAD_STAMP_KEY) ?? \"0\")\n } catch {\n // sessionStorage can throw in private/embedded contexts — treat as \"no prior reload\".\n }\n if (Number.isFinite(last) && Date.now() - last < RELOAD_COOLDOWN_MS) {\n // Already reloaded very recently; the chunk is still unreachable, so stop\n // reloading and let the error surface rather than looping.\n return\n }\n try {\n window.sessionStorage.setItem(RELOAD_STAMP_KEY, String(Date.now()))\n } catch {\n // best-effort — a failed write just means we can't dedupe, not a reason to skip healing.\n }\n window.location.reload()\n}\n\n/**\n * Register global listeners that reload the page when a chunk from a\n * now-replaced build fails to load. Safe to call once at bootstrap; a no-op\n * outside the browser.\n */\nexport function registerChunkErrorSelfHeal(): void {\n if (typeof window === \"undefined\") return\n\n // Vite's canonical signal for a failed dynamic-import preload. Calling\n // preventDefault() stops Vite from re-throwing; we reload instead.\n window.addEventListener(\"vite:preloadError\", (event) => {\n event.preventDefault()\n reloadOnceForStaleChunk()\n })\n\n // Belt-and-suspenders: a dynamic import that fails without a modulepreload\n // surfaces as an unhandled rejection. Only act on the specific stale-module\n // messages so unrelated rejections are left alone.\n window.addEventListener(\"unhandledrejection\", (event) => {\n const reason = event.reason\n const message = reason instanceof Error ? reason.message : String(reason ?? \"\")\n if (DYNAMIC_IMPORT_FAILURE.test(message)) {\n reloadOnceForStaleChunk()\n }\n })\n}\n","import { StrictMode, useSyncExternalStore } from \"react\"\nimport { createRoot } from \"react-dom/client\"\nimport { RouterProvider } from \"@tanstack/react-router\"\nimport { QueryClientProvider } from \"@tanstack/react-query\"\nimport { createQueryClient } from \"../query/client\"\nimport { setRoutes } from \"../router/registry\"\nimport { AppErrorBoundary } from \"./error-boundary\"\nimport { buildRouter } from \"./build-router\"\nimport {\n announceDraftPage,\n announceDraftPageClosed,\n connectDraft,\n DraftFreezeBoundary,\n reportDraftRenderError,\n type DraftHot,\n} from \"./draft\"\nimport { registerChunkErrorSelfHeal } from \"./self-heal\"\nimport type { ClientManifest } from \"./manifest\"\n\nexport interface BootstrapOptions {\n /**\n * The HMR context of the generated entry, passed only when the draft preview\n * is on. Its presence is what switches the draft behaviour on; without it the\n * client is exactly what it was.\n */\n hot?: DraftHot\n}\n\nexport interface BootstrapHandle {\n /** The route tree changed (a page appeared or went away): draw from the new manifest. */\n update(manifest: ClientManifest): void\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyRouter = any\n\n/** The current router, swappable without remounting the providers above it. */\nfunction createRouterHolder(initial: AnyRouter) {\n let current = initial\n const listeners = new Set<() => void>()\n return {\n get: (): AnyRouter => current,\n set(next: AnyRouter) {\n current = next\n for (const l of listeners) l()\n },\n subscribe(l: () => void) {\n listeners.add(l)\n return () => {\n listeners.delete(l)\n }\n },\n }\n}\n\ntype RouterHolder = ReturnType<typeof createRouterHolder>\n\nfunction SwappableRouter({ holder }: { holder: RouterHolder }) {\n const router = useSyncExternalStore(holder.subscribe, holder.get)\n return <RouterProvider router={router} />\n}\n\n/**\n * Client entrypoint. The generated `.vantage/client-entry.tsx` calls this with\n * the route manifest. Owns React root creation and the provider tree:\n *\n * <AppErrorBoundary>\n * <QueryClientProvider>\n * <RouterProvider />\n *\n * With the draft preview on (`options.hot`) the router sits in a swappable\n * holder inside a `DraftFreezeBoundary`, so a new route tree can replace it and\n * a failing draft can keep the previous screen.\n */\nexport function bootstrap(manifest: ClientManifest, options: BootstrapOptions = {}): BootstrapHandle {\n const { hot } = options\n // Recover from stale chunks after a re-publish: reload once when a dynamic\n // import fails because the served build changed under an open tab.\n registerChunkErrorSelfHeal()\n\n // Publish the route list before the first render so `useRoutes()` is\n // populated for the very first page, not one paint late.\n setRoutes(manifest)\n\n const holder = createRouterHolder(buildRouter(manifest, { draft: Boolean(hot) }).router)\n const queryClient = createQueryClient()\n\n // The document's initial title is the fallback for pages without a definePage\n // title, so navigating away from a titled page doesn't leave a stale title.\n const defaultTitle = document.title\n\n const updateTitle = () => {\n try {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const matches: any[] = holder.get().state?.matches ?? []\n const leaf = matches[matches.length - 1]\n const title = leaf?.staticData?.title\n document.title = typeof title === \"string\" && title.length > 0 ? title : defaultTitle\n } catch {\n /* title updates are best-effort */\n }\n }\n let unsubscribeTitle: (() => void) | undefined = holder.get().subscribe?.(\"onResolved\", updateTitle)\n\n const el = document.getElementById(\"root\")\n if (!el) {\n throw new Error('[vantage] Root element \"#root\" was not found in the document.')\n }\n\n if (!hot) {\n createRoot(el).render(\n <StrictMode>\n <AppErrorBoundary>\n <QueryClientProvider client={queryClient}>\n <RouterProvider router={holder.get()} />\n </QueryClientProvider>\n </AppErrorBoundary>\n </StrictMode>,\n )\n updateTitle()\n // Only the draft preview swaps route trees; anyone else gets a plain reload.\n return { update: () => location.reload() }\n }\n\n let currentManifest = manifest\n /** A draft page announced before the route tree that holds it arrived. */\n let pendingRoute: string | null = null\n /** The draft page last opened, so its removal can move the screen off it. */\n let openedRoute: string | null = null\n\n const hasRoute = (route: string) => currentManifest.pages.some((p) => p.routePath === route)\n // A route with parameters has no single URL to move to.\n const navigable = (route: string) => !/[:*]/.test(route)\n\n const open = async (route: string): Promise<void> => {\n openedRoute = route\n try {\n await holder.get().navigate({ to: route })\n } catch {\n /* the screen stays where it was */\n }\n announceDraftPage(route)\n }\n\n connectDraft(hot, {\n onPage(route) {\n // Nothing to open for a route with parameters (the server does not announce one either).\n if (!navigable(route)) return\n if (hasRoute(route)) void open(route)\n else pendingRoute = route\n },\n onPageClosed(route) {\n if (!navigable(route)) return\n if (pendingRoute === route) pendingRoute = null\n announceDraftPageClosed(route)\n },\n })\n\n createRoot(el).render(\n <StrictMode>\n <AppErrorBoundary>\n <QueryClientProvider client={queryClient}>\n <DraftFreezeBoundary onError={(error, componentStack) => reportDraftRenderError(hot, error, componentStack)}>\n <SwappableRouter holder={holder} />\n </DraftFreezeBoundary>\n </QueryClientProvider>\n </AppErrorBoundary>\n </StrictMode>,\n )\n updateTitle()\n\n return {\n update(next) {\n currentManifest = next\n setRoutes(next)\n unsubscribeTitle?.()\n holder.set(buildRouter(next, { draft: true }).router)\n // A router that replaces a running one is not started by the provider: without\n // this the page it opens on stays blank until something navigates.\n void holder.get().load?.()\n unsubscribeTitle = holder.get().subscribe?.(\"onResolved\", updateTitle)\n\n if (pendingRoute !== null && hasRoute(pendingRoute)) {\n const route = pendingRoute\n pendingRoute = null\n void open(route)\n } else if (openedRoute !== null && !hasRoute(openedRoute)) {\n // The draft page was dropped: don't leave the screen on a dead route.\n if (location.pathname === openedRoute) void holder.get().navigate({ to: \"/\" }).catch(() => {})\n openedRoute = null\n }\n },\n }\n}\n","import type { ReactNode } from \"react\"\n\n/**\n * A frame with nothing in it, drawn where a part has not been written yet. Same\n * look as the placeholder the draft layer declares for a missing component, so\n * the two read as one thing on screen.\n */\nexport function DraftSkeleton(): ReactNode {\n return (\n <div\n data-vantage-skeleton\n aria-hidden=\"true\"\n className=\"animate-pulse rounded-md bg-muted\"\n style={{ minHeight: \"4rem\", width: \"100%\" }}\n />\n )\n}\n"]}
|