@stealthscale/sdk-host 0.1.0

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.
@@ -0,0 +1,1426 @@
1
+ import { a as HostContent, c as sampledFrom, i as HostNotFound, n as HostRoot, o as createHost, r as HostProvider, s as internalsOf, t as createHostRoutes } from "../create-routes-CkgZV-dU.js";
2
+ import { standaloneSources } from "../standalone.js";
3
+ import { DataError } from "@stealthscale/provider-data";
4
+ import { hostContract } from "@stealthscale/sdk-core";
5
+ import { Into, Slot, useResolvedProduct, useSlot } from "@stealthscale/sdk-plugin";
6
+ import { localStore } from "@stealthscale/settings";
7
+ import { c } from "react/compiler-runtime";
8
+ import { RouterProvider, createAppRootRoute, createRouter, routeHref, routeMap, routerOptions, useRouteContext, useRouter, useRouterState } from "@stealthscale/provider-router";
9
+ import { jsx, jsxs } from "react/jsx-runtime";
10
+ import { Fragment as Fragment$1, createContext, use, useState, useSyncExternalStore } from "react";
11
+ import { useTranslation } from "@stealthscale/provider-i18n";
12
+ import { Stack } from "@stealthscale/component-layout";
13
+ import { AppShell, FloatingPanel } from "@stealthscale/component-screen";
14
+ import { Field, Fieldset, NativeSelect, SegmentGroup, Switch } from "@stealthscale/component-forms";
15
+ import { createRoot } from "react-dom/client";
16
+ import { Shell, useThemeChoice } from "@stealthscale/provider-shell";
17
+ import { useColorMode } from "@stealthscale/provider-color-mode";
18
+ import { useLocale } from "@stealthscale/provider-locale";
19
+ //#region src/standalone/context.ts
20
+ /**
21
+ * Provides the development panel with the standalone page's sources, its operation modes, its
22
+ * declared flags, the router's map and the page's glyphs.
23
+ */
24
+ /**
25
+ * Provides the standalone page's state to the panel. The value is undefined outside the page.
26
+ */
27
+ const StandaloneContext = createContext(void 0);
28
+ /**
29
+ * Returns the standalone page's state.
30
+ *
31
+ * @throws {@link Error} Outside the standalone page.
32
+ */
33
+ function useStandalone() {
34
+ const state = use(StandaloneContext);
35
+ if (state === void 0) throw new Error("The development panel renders inside the standalone page alone.");
36
+ return state;
37
+ }
38
+ //#endregion
39
+ //#region src/standalone/data.ts
40
+ /**
41
+ * Serves a standalone product's operations as the development panel sets each one: from its
42
+ * sample, from its sample after a delay, or with a refusal of one kind.
43
+ */
44
+ /**
45
+ * Lists every mode, in the order the panel offers them.
46
+ */
47
+ const MODES$1 = [
48
+ "sample",
49
+ "delayed",
50
+ "conflict",
51
+ "forbidden",
52
+ "invalid",
53
+ "network",
54
+ "not-found",
55
+ "server",
56
+ "unauthenticated"
57
+ ];
58
+ /**
59
+ * The milliseconds a delayed operation waits before it serves its sample.
60
+ */
61
+ const DELAY = 2e3;
62
+ /**
63
+ * Returns the operation modes of one page, every operation at its sample until the panel sets
64
+ * another mode.
65
+ */
66
+ function operationModes() {
67
+ let modes = {};
68
+ const listeners = /* @__PURE__ */ new Set();
69
+ return {
70
+ get: () => modes,
71
+ set: (id, mode) => {
72
+ modes = {
73
+ ...modes,
74
+ [id]: mode
75
+ };
76
+ for (const listener of listeners) listener();
77
+ },
78
+ subscribe: (listener) => {
79
+ listeners.add(listener);
80
+ return () => {
81
+ listeners.delete(listener);
82
+ };
83
+ }
84
+ };
85
+ }
86
+ /**
87
+ * Returns a transport that serves each declared operation in the mode the panel set for it when it
88
+ * runs.
89
+ *
90
+ * @remarks
91
+ * A delayed operation serves its sample after `DELAY`. A refused one rejects with a `DataError`
92
+ * of the mode's kind, so the page renders the error state the kind leads to. A subscription
93
+ * streams nothing, as the sampled transport's does.
94
+ * @param product - The declared queries and mutations, whose samples the transport serves.
95
+ * @param modes - The mode of each operation.
96
+ */
97
+ function standaloneTransport(product, modes) {
98
+ const sampled = sampledFrom(product);
99
+ return {
100
+ run: async (operation, variables, options) => {
101
+ const mode = modes.get()[operation.id] ?? "sample";
102
+ if (mode === "delayed") await new Promise((resolve) => {
103
+ setTimeout(resolve, DELAY);
104
+ });
105
+ else if (mode !== "sample") throw new DataError({
106
+ kind: mode,
107
+ message: `The development panel refuses ${operation.id} as ${mode}.`,
108
+ operation: operation.id
109
+ });
110
+ return sampled.run(operation, variables, options);
111
+ },
112
+ subscribe: (operation, variables, next, signal) => sampled.subscribe(operation, variables, next, signal)
113
+ };
114
+ }
115
+ //#endregion
116
+ //#region src/standalone/hosted.ts
117
+ /**
118
+ * Creates the host of the standalone page.
119
+ *
120
+ * @remarks
121
+ * The page keeps a person's switches, settings and placements in local storage by default, so
122
+ * they outlast a reload as they do in a product. The session, the decisions, the flag overrides
123
+ * and the operations' modes start afresh on every load.
124
+ * @param product - The standalone product, from `virtual:product`.
125
+ * @param glyphs - The glyphs the settings sections' forms render.
126
+ * @param store - The store of a person's switches, settings and placements.
127
+ */
128
+ function standaloneHosted(product, glyphs, store = localStore()) {
129
+ const sources = standaloneSources(product);
130
+ const modes = operationModes();
131
+ return {
132
+ host: createHost({
133
+ access: sources.access,
134
+ data: { transport: standaloneTransport(product, modes) },
135
+ flags: sources.flags,
136
+ glyphs,
137
+ product,
138
+ session: sources.session,
139
+ store
140
+ }),
141
+ modes,
142
+ sources
143
+ };
144
+ }
145
+ //#endregion
146
+ //#region src/standalone/group.tsx
147
+ /**
148
+ * Renders a small fieldset with its legend and its controls stacked under it.
149
+ *
150
+ * @param props - The legend and the controls.
151
+ * @returns The fieldset.
152
+ */
153
+ function Group(t0) {
154
+ const $ = c(7);
155
+ const { children, title } = t0;
156
+ let t1;
157
+ if ($[0] !== title) {
158
+ t1 = /* @__PURE__ */ jsx(Fieldset.Legend, { children: title });
159
+ $[0] = title;
160
+ $[1] = t1;
161
+ } else t1 = $[1];
162
+ let t2;
163
+ if ($[2] !== children) {
164
+ t2 = /* @__PURE__ */ jsx(Stack, {
165
+ gap: "sm",
166
+ children
167
+ });
168
+ $[2] = children;
169
+ $[3] = t2;
170
+ } else t2 = $[3];
171
+ let t3;
172
+ if ($[4] !== t1 || $[5] !== t2) {
173
+ t3 = /* @__PURE__ */ jsxs(Fieldset.Root, {
174
+ size: "sm",
175
+ children: [t1, t2]
176
+ });
177
+ $[4] = t1;
178
+ $[5] = t2;
179
+ $[6] = t3;
180
+ } else t3 = $[6];
181
+ return t3;
182
+ }
183
+ //#endregion
184
+ //#region src/standalone/access-controls.tsx
185
+ /**
186
+ * Renders the development panel's control of the decisions on single resources: every check
187
+ * allowed, every check denied, or every check pending.
188
+ */
189
+ /**
190
+ * Lists the decisions in the order the panel offers them, each with the key of its words and the
191
+ * call that applies it.
192
+ */
193
+ const DECISIONS = [
194
+ {
195
+ apply: (access) => {
196
+ access.allow();
197
+ },
198
+ key: "standalone.panel.access.allow",
199
+ value: "allow"
200
+ },
201
+ {
202
+ apply: (access) => {
203
+ access.deny();
204
+ },
205
+ key: "standalone.panel.access.deny",
206
+ value: "deny"
207
+ },
208
+ {
209
+ apply: (access) => {
210
+ access.pending();
211
+ },
212
+ key: "standalone.panel.access.pending",
213
+ value: "pending"
214
+ }
215
+ ];
216
+ /**
217
+ * Renders a segment group of the three decisions, which applies the one a person picks to every
218
+ * check from then on.
219
+ *
220
+ * @remarks
221
+ * The access source tells the host's access store, which drops the decisions it knew and asks
222
+ * again, so every `useAccess` on the page follows.
223
+ * @returns The group.
224
+ */
225
+ function AccessControls() {
226
+ const $ = c(16);
227
+ const { access } = useStandalone();
228
+ const { t } = useTranslation("host");
229
+ const [decision, setDecision] = useState("allow");
230
+ let t0;
231
+ if ($[0] !== t) {
232
+ t0 = t("standalone.panel.access.title");
233
+ $[0] = t;
234
+ $[1] = t0;
235
+ } else t0 = $[1];
236
+ let t1;
237
+ if ($[2] !== t) {
238
+ t1 = t("standalone.panel.access.title");
239
+ $[2] = t;
240
+ $[3] = t1;
241
+ } else t1 = $[3];
242
+ let t2;
243
+ if ($[4] !== access) {
244
+ t2 = (t3) => {
245
+ const { value } = t3;
246
+ const picked = DECISIONS.find((one) => one.value === value);
247
+ picked.apply(access);
248
+ setDecision(picked.value);
249
+ };
250
+ $[4] = access;
251
+ $[5] = t2;
252
+ } else t2 = $[5];
253
+ let t3;
254
+ if ($[6] !== t) {
255
+ t3 = DECISIONS.map((t4) => {
256
+ const { key, value: value_0 } = t4;
257
+ return /* @__PURE__ */ jsx(SegmentGroup.Item, {
258
+ value: value_0,
259
+ children: /* @__PURE__ */ jsx(SegmentGroup.ItemText, { children: t(key) })
260
+ }, value_0);
261
+ });
262
+ $[6] = t;
263
+ $[7] = t3;
264
+ } else t3 = $[7];
265
+ let t4;
266
+ if ($[8] !== decision || $[9] !== t1 || $[10] !== t2 || $[11] !== t3) {
267
+ t4 = /* @__PURE__ */ jsx(SegmentGroup.Root, {
268
+ "aria-label": t1,
269
+ onValueChange: t2,
270
+ size: "sm",
271
+ value: decision,
272
+ children: t3
273
+ });
274
+ $[8] = decision;
275
+ $[9] = t1;
276
+ $[10] = t2;
277
+ $[11] = t3;
278
+ $[12] = t4;
279
+ } else t4 = $[12];
280
+ let t5;
281
+ if ($[13] !== t0 || $[14] !== t4) {
282
+ t5 = /* @__PURE__ */ jsx(Group, {
283
+ title: t0,
284
+ children: t4
285
+ });
286
+ $[13] = t0;
287
+ $[14] = t4;
288
+ $[15] = t5;
289
+ } else t5 = $[15];
290
+ return t5;
291
+ }
292
+ //#endregion
293
+ //#region src/standalone/picker.tsx
294
+ /**
295
+ * Renders a small native select in a field its label names.
296
+ *
297
+ * @remarks
298
+ * The panel picks with a native select, because a listbox opened inside a floating panel stacks
299
+ * under the panel. The select states its size itself: the stylesheet compiler emits the rules of
300
+ * the sizes it reads in the source, and a size the select takes from the field at run time has
301
+ * none.
302
+ * @param props - The choices, the value, the words, the glyph and the callback a pick calls.
303
+ * @returns The field.
304
+ */
305
+ function Picker(t0) {
306
+ const $ = c(18);
307
+ const { choices, indicator, label, onValueChange, value } = t0;
308
+ let t1;
309
+ if ($[0] !== label) {
310
+ t1 = /* @__PURE__ */ jsx(Field.Label, { children: label });
311
+ $[0] = label;
312
+ $[1] = t1;
313
+ } else t1 = $[1];
314
+ let t2;
315
+ if ($[2] !== onValueChange) {
316
+ t2 = (event) => {
317
+ onValueChange(event.currentTarget.value);
318
+ };
319
+ $[2] = onValueChange;
320
+ $[3] = t2;
321
+ } else t2 = $[3];
322
+ let t3;
323
+ if ($[4] !== choices) {
324
+ t3 = choices.map(_temp$7);
325
+ $[4] = choices;
326
+ $[5] = t3;
327
+ } else t3 = $[5];
328
+ let t4;
329
+ if ($[6] !== t2 || $[7] !== t3 || $[8] !== value) {
330
+ t4 = /* @__PURE__ */ jsx(NativeSelect.Field, {
331
+ onChange: t2,
332
+ value,
333
+ children: t3
334
+ });
335
+ $[6] = t2;
336
+ $[7] = t3;
337
+ $[8] = value;
338
+ $[9] = t4;
339
+ } else t4 = $[9];
340
+ let t5;
341
+ if ($[10] !== indicator) {
342
+ t5 = indicator === void 0 ? null : /* @__PURE__ */ jsx(NativeSelect.Indicator, { children: indicator });
343
+ $[10] = indicator;
344
+ $[11] = t5;
345
+ } else t5 = $[11];
346
+ let t6;
347
+ if ($[12] !== t4 || $[13] !== t5) {
348
+ t6 = /* @__PURE__ */ jsxs(NativeSelect.Root, {
349
+ size: "sm",
350
+ children: [t4, t5]
351
+ });
352
+ $[12] = t4;
353
+ $[13] = t5;
354
+ $[14] = t6;
355
+ } else t6 = $[14];
356
+ let t7;
357
+ if ($[15] !== t1 || $[16] !== t6) {
358
+ t7 = /* @__PURE__ */ jsxs(Field.Root, {
359
+ size: "sm",
360
+ children: [t1, t6]
361
+ });
362
+ $[15] = t1;
363
+ $[16] = t6;
364
+ $[17] = t7;
365
+ } else t7 = $[17];
366
+ return t7;
367
+ }
368
+ function _temp$7(choice) {
369
+ return /* @__PURE__ */ jsx("option", {
370
+ value: choice.value,
371
+ children: choice.label
372
+ }, choice.value);
373
+ }
374
+ //#endregion
375
+ //#region src/standalone/data-controls.tsx
376
+ /**
377
+ * Renders the development panel's operation controls: a picker per declared query and mutation of
378
+ * how the page's transport serves it.
379
+ */
380
+ /**
381
+ * Maps each mode to the key of its words.
382
+ */
383
+ const WORDS = {
384
+ conflict: "standalone.panel.data.modes.conflict",
385
+ delayed: "standalone.panel.data.modes.delayed",
386
+ forbidden: "standalone.panel.data.modes.forbidden",
387
+ invalid: "standalone.panel.data.modes.invalid",
388
+ network: "standalone.panel.data.modes.network",
389
+ "not-found": "standalone.panel.data.modes.not-found",
390
+ sample: "standalone.panel.data.modes.sample",
391
+ server: "standalone.panel.data.modes.server",
392
+ unauthenticated: "standalone.panel.data.modes.unauthenticated"
393
+ };
394
+ /**
395
+ * Renders one picker per declared query and mutation, named by its qualified id, which sets how the
396
+ * page's transport serves its operation.
397
+ *
398
+ * @remarks
399
+ * A query's pick resets every query of the page's data client and invalidates the router, so a
400
+ * page on screen loads again from nothing in the new mode: a refusal shows the page's error, a
401
+ * delay its pending state, and a page that failed renders again. An invalidation of the queries
402
+ * alone would keep the cached data through a refetch that fails or waits. A mutation runs in its
403
+ * mode the next time a person sends it, and its pick loads nothing again.
404
+ * @returns The group.
405
+ */
406
+ function DataControls() {
407
+ const $ = c(22);
408
+ const { glyphs, modes } = useStandalone();
409
+ let t0;
410
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
411
+ t0 = { strict: false };
412
+ $[0] = t0;
413
+ } else t0 = $[0];
414
+ const { host } = useRouteContext(t0);
415
+ const router = useRouter();
416
+ const { t } = useTranslation("host");
417
+ const { mutations, queries } = useResolvedProduct();
418
+ const current = useSyncExternalStore(modes.subscribe, modes.get, modes.get);
419
+ let t1;
420
+ if ($[1] !== t) {
421
+ t1 = MODES$1.map((mode) => ({
422
+ label: t(WORDS[mode]),
423
+ value: mode
424
+ }));
425
+ $[1] = t;
426
+ $[2] = t1;
427
+ } else t1 = $[2];
428
+ const choices = t1;
429
+ let t2;
430
+ if ($[3] !== queries) {
431
+ t2 = new Set(queries.map(_temp$6));
432
+ $[3] = queries;
433
+ $[4] = t2;
434
+ } else t2 = $[4];
435
+ const loaded = t2;
436
+ let t3;
437
+ if ($[5] !== t) {
438
+ t3 = t("standalone.panel.data.title");
439
+ $[5] = t;
440
+ $[6] = t3;
441
+ } else t3 = $[6];
442
+ let t4;
443
+ if ($[7] !== mutations || $[8] !== queries) {
444
+ t4 = [...queries, ...mutations];
445
+ $[7] = mutations;
446
+ $[8] = queries;
447
+ $[9] = t4;
448
+ } else t4 = $[9];
449
+ let t5;
450
+ if ($[10] !== choices || $[11] !== current || $[12] !== glyphs || $[13] !== host || $[14] !== loaded || $[15] !== modes || $[16] !== router || $[17] !== t4) {
451
+ t5 = t4.map((t6) => {
452
+ const { id, operation: operation_0 } = t6;
453
+ return /* @__PURE__ */ jsx(Picker, {
454
+ choices,
455
+ indicator: glyphs.select?.indicator,
456
+ label: id,
457
+ onValueChange: (value) => {
458
+ modes.set(operation_0.id, value);
459
+ if (!loaded.has(operation_0.id)) return;
460
+ host.data.resetQueries();
461
+ router.invalidate();
462
+ },
463
+ value: current[operation_0.id] ?? "sample"
464
+ }, id);
465
+ });
466
+ $[10] = choices;
467
+ $[11] = current;
468
+ $[12] = glyphs;
469
+ $[13] = host;
470
+ $[14] = loaded;
471
+ $[15] = modes;
472
+ $[16] = router;
473
+ $[17] = t4;
474
+ $[18] = t5;
475
+ } else t5 = $[18];
476
+ let t6;
477
+ if ($[19] !== t3 || $[20] !== t5) {
478
+ t6 = /* @__PURE__ */ jsx(Group, {
479
+ title: t3,
480
+ children: t5
481
+ });
482
+ $[19] = t3;
483
+ $[20] = t5;
484
+ $[21] = t6;
485
+ } else t6 = $[21];
486
+ return t6;
487
+ }
488
+ function _temp$6(t0) {
489
+ const { operation } = t0;
490
+ return operation.id;
491
+ }
492
+ //#endregion
493
+ //#region src/standalone/toggle.tsx
494
+ /**
495
+ * Renders a small switch that spreads across the panel, its words at the start and its control at
496
+ * the end.
497
+ *
498
+ * @param props - The state, the words and the callback a press calls.
499
+ * @returns The switch.
500
+ */
501
+ function Toggle(t0) {
502
+ const $ = c(9);
503
+ const { checked, label, onCheckedChange } = t0;
504
+ let t1;
505
+ if ($[0] !== onCheckedChange) {
506
+ t1 = (details) => {
507
+ onCheckedChange(details.checked);
508
+ };
509
+ $[0] = onCheckedChange;
510
+ $[1] = t1;
511
+ } else t1 = $[1];
512
+ let t2;
513
+ if ($[2] !== label) {
514
+ t2 = /* @__PURE__ */ jsx(Switch.Label, { children: label });
515
+ $[2] = label;
516
+ $[3] = t2;
517
+ } else t2 = $[3];
518
+ let t3;
519
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
520
+ t3 = /* @__PURE__ */ jsx(Switch.Control, { children: /* @__PURE__ */ jsx(Switch.Thumb, {}) });
521
+ $[4] = t3;
522
+ } else t3 = $[4];
523
+ let t4;
524
+ if ($[5] !== checked || $[6] !== t1 || $[7] !== t2) {
525
+ t4 = /* @__PURE__ */ jsxs(Switch.Root, {
526
+ checked,
527
+ onCheckedChange: t1,
528
+ size: "sm",
529
+ spread: true,
530
+ children: [t2, t3]
531
+ });
532
+ $[5] = checked;
533
+ $[6] = t1;
534
+ $[7] = t2;
535
+ $[8] = t4;
536
+ } else t4 = $[8];
537
+ return t4;
538
+ }
539
+ //#endregion
540
+ //#region src/standalone/flag-controls.tsx
541
+ /**
542
+ * Renders the development panel's flag controls: a switch per boolean flag, and a picker per
543
+ * experiment.
544
+ */
545
+ /**
546
+ * Renders one control per flag the installed plugins declare, named by its qualified id, which
547
+ * overrides the flag in this tab.
548
+ *
549
+ * @remarks
550
+ * An override replaces the value every condition, menu and `useFeatureFlag` on the page reads, as
551
+ * the flag store's overrides do in a product outside production.
552
+ * @returns The group.
553
+ */
554
+ function FlagControls() {
555
+ const $ = c(13);
556
+ const { flags: declared, glyphs } = useStandalone();
557
+ let t0;
558
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
559
+ t0 = { strict: false };
560
+ $[0] = t0;
561
+ } else t0 = $[0];
562
+ const { host } = useRouteContext(t0);
563
+ const { flags } = host.stores;
564
+ const { t } = useTranslation("host");
565
+ useSyncExternalStore(flags.subscribe, flags.get, flags.get);
566
+ let t1;
567
+ if ($[1] !== t) {
568
+ t1 = t("standalone.panel.flags.title");
569
+ $[1] = t;
570
+ $[2] = t1;
571
+ } else t1 = $[2];
572
+ let t2;
573
+ if ($[3] !== declared || $[4] !== flags || $[5] !== glyphs) {
574
+ let t3;
575
+ if ($[7] !== flags || $[8] !== glyphs) {
576
+ t3 = (t4) => {
577
+ const { id, variants } = t4;
578
+ return variants === void 0 ? /* @__PURE__ */ jsx(Toggle, {
579
+ checked: flags.read(id) === true,
580
+ label: id,
581
+ onCheckedChange: (on) => {
582
+ flags.override(id, on);
583
+ }
584
+ }, id) : /* @__PURE__ */ jsx(Picker, {
585
+ choices: variants.map(_temp$5),
586
+ indicator: glyphs.select?.indicator,
587
+ label: id,
588
+ onValueChange: (variant_0) => {
589
+ flags.override(id, variant_0);
590
+ },
591
+ value: String(flags.read(id))
592
+ }, id);
593
+ };
594
+ $[7] = flags;
595
+ $[8] = glyphs;
596
+ $[9] = t3;
597
+ } else t3 = $[9];
598
+ t2 = declared.map(t3);
599
+ $[3] = declared;
600
+ $[4] = flags;
601
+ $[5] = glyphs;
602
+ $[6] = t2;
603
+ } else t2 = $[6];
604
+ let t3;
605
+ if ($[10] !== t1 || $[11] !== t2) {
606
+ t3 = /* @__PURE__ */ jsx(Group, {
607
+ title: t1,
608
+ children: t2
609
+ });
610
+ $[10] = t1;
611
+ $[11] = t2;
612
+ $[12] = t3;
613
+ } else t3 = $[12];
614
+ return t3;
615
+ }
616
+ function _temp$5(variant) {
617
+ return {
618
+ label: variant,
619
+ value: variant
620
+ };
621
+ }
622
+ //#endregion
623
+ //#region src/standalone/page-controls.tsx
624
+ /**
625
+ * Renders a picker of the routes in the router's map that a sample or an empty path fills, each
626
+ * named by its qualified id, which opens the route a person picks.
627
+ *
628
+ * @remarks
629
+ * The picker shows the address the page is at, and lists it first where no route's sample leads
630
+ * there, such as a page a link opened with other parameters.
631
+ * @returns The field.
632
+ */
633
+ function PageControls() {
634
+ const $ = c(19);
635
+ const { glyphs, routes } = useStandalone();
636
+ const router = useRouter();
637
+ let t0;
638
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
639
+ t0 = { select: _temp$4 };
640
+ $[0] = t0;
641
+ } else t0 = $[0];
642
+ const pathname = useRouterState(t0);
643
+ const { t } = useTranslation("host");
644
+ const t1 = useResolvedProduct();
645
+ let t2;
646
+ if ($[1] !== pathname || $[2] !== routes || $[3] !== t1.routes) {
647
+ let t3;
648
+ if ($[5] !== routes) {
649
+ t3 = (t4) => {
650
+ const { id, path, sample } = t4;
651
+ return routes.has(id) && (sample !== void 0 || !path.includes("$"));
652
+ };
653
+ $[5] = routes;
654
+ $[6] = t3;
655
+ } else t3 = $[6];
656
+ const declared = t1.routes.filter(t3);
657
+ let t4;
658
+ if ($[7] !== routes) {
659
+ t4 = (t5) => {
660
+ const { id: id_0, sample: sample_0 } = t5;
661
+ return {
662
+ label: id_0,
663
+ value: routeHref(routes, { id: id_0 }, sample_0)
664
+ };
665
+ };
666
+ $[7] = routes;
667
+ $[8] = t4;
668
+ } else t4 = $[8];
669
+ const choices = declared.map(t4);
670
+ t2 = choices.some((t5) => {
671
+ const { value } = t5;
672
+ return value === pathname;
673
+ }) ? choices : [{
674
+ label: pathname,
675
+ value: pathname
676
+ }, ...choices];
677
+ $[1] = pathname;
678
+ $[2] = routes;
679
+ $[3] = t1.routes;
680
+ $[4] = t2;
681
+ } else t2 = $[4];
682
+ const listed = t2;
683
+ const t3 = glyphs.select?.indicator;
684
+ let t4;
685
+ if ($[9] !== t) {
686
+ t4 = t("standalone.panel.page.route");
687
+ $[9] = t;
688
+ $[10] = t4;
689
+ } else t4 = $[10];
690
+ let t5;
691
+ if ($[11] !== router) {
692
+ t5 = (to) => {
693
+ router.navigate({ to });
694
+ };
695
+ $[11] = router;
696
+ $[12] = t5;
697
+ } else t5 = $[12];
698
+ let t6;
699
+ if ($[13] !== listed || $[14] !== pathname || $[15] !== t3 || $[16] !== t4 || $[17] !== t5) {
700
+ t6 = /* @__PURE__ */ jsx(Picker, {
701
+ choices: listed,
702
+ indicator: t3,
703
+ label: t4,
704
+ onValueChange: t5,
705
+ value: pathname
706
+ });
707
+ $[13] = listed;
708
+ $[14] = pathname;
709
+ $[15] = t3;
710
+ $[16] = t4;
711
+ $[17] = t5;
712
+ $[18] = t6;
713
+ } else t6 = $[18];
714
+ return t6;
715
+ }
716
+ function _temp$4(state) {
717
+ return state.location.pathname;
718
+ }
719
+ //#endregion
720
+ //#region src/standalone/plugin-controls.tsx
721
+ /**
722
+ * Renders the development panel's plugin controls: the plugin's switch, and its kill switch.
723
+ */
724
+ /**
725
+ * Renders the switch of the plugin the standalone product runs, and the switch of its kill switch.
726
+ *
727
+ * @remarks
728
+ * The standalone product's id is the plugin's. The first switch writes the person's switch, as
729
+ * the Plugins page does. The second overrides the kill switch in this tab, so the plugin's pages
730
+ * turn not found and its contributions leave the page.
731
+ * @returns The group.
732
+ */
733
+ function PluginControls() {
734
+ const $ = c(9);
735
+ let t0;
736
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
737
+ t0 = { strict: false };
738
+ $[0] = t0;
739
+ } else t0 = $[0];
740
+ const { host } = useRouteContext(t0);
741
+ const { switches } = internalsOf(host);
742
+ const { flags } = host.stores;
743
+ const { t } = useTranslation("host");
744
+ const { plugins, productId } = useResolvedProduct();
745
+ const switched = useSyncExternalStore(switches.subscribe, switches.get, switches.get);
746
+ useSyncExternalStore(flags.subscribe, flags.get, flags.get);
747
+ const T0 = Group;
748
+ let t1;
749
+ if ($[1] !== t) {
750
+ t1 = t("standalone.panel.plugin.title");
751
+ $[1] = t;
752
+ $[2] = t1;
753
+ } else t1 = $[2];
754
+ let t2;
755
+ if ($[3] !== productId) {
756
+ t2 = (t3) => {
757
+ const { id } = t3;
758
+ return id === productId;
759
+ };
760
+ $[3] = productId;
761
+ $[4] = t2;
762
+ } else t2 = $[4];
763
+ const t4 = plugins.filter(t2).map((t3) => {
764
+ const { id: id_0, killSwitch } = t3;
765
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Toggle, {
766
+ checked: switched[id_0] !== false,
767
+ label: t("standalone.panel.plugin.switch"),
768
+ onCheckedChange: (on) => {
769
+ switches.set(id_0, on);
770
+ }
771
+ }), /* @__PURE__ */ jsx(Toggle, {
772
+ checked: flags.read(killSwitch) !== false,
773
+ label: t("standalone.panel.plugin.kill"),
774
+ onCheckedChange: (on_0) => {
775
+ flags.override(killSwitch, on_0);
776
+ }
777
+ })] }, id_0);
778
+ });
779
+ let t5;
780
+ if ($[5] !== T0 || $[6] !== t1 || $[7] !== t4) {
781
+ t5 = /* @__PURE__ */ jsx(T0, {
782
+ title: t1,
783
+ children: t4
784
+ });
785
+ $[5] = T0;
786
+ $[6] = t1;
787
+ $[7] = t4;
788
+ $[8] = t5;
789
+ } else t5 = $[8];
790
+ return t5;
791
+ }
792
+ //#endregion
793
+ //#region src/standalone/session-controls.tsx
794
+ /**
795
+ * Renders the development panel's session controls: whether somebody is signed in, and each
796
+ * permission and entitlement the session has.
797
+ */
798
+ /**
799
+ * Returns the session with one id added to one of its lists, or taken out of it.
800
+ */
801
+ function grantedIn(session, list, id, on) {
802
+ const others = session[list].filter((one) => one !== id);
803
+ return {
804
+ ...session,
805
+ [list]: on ? [...others, id] : others
806
+ };
807
+ }
808
+ /**
809
+ * Renders a switch for signing in, then one per declared permission and entitlement, each named by
810
+ * its qualified id.
811
+ *
812
+ * @remarks
813
+ * Each switch replaces the session, so every condition, menu and decision on the page follows at
814
+ * once.
815
+ * @returns The group.
816
+ */
817
+ function SessionControls() {
818
+ const $ = c(20);
819
+ const { session } = useStandalone();
820
+ const { t } = useTranslation("host");
821
+ const { entitlements, permissions } = useResolvedProduct();
822
+ const current = useSyncExternalStore(session.subscribe, session.read, session.read);
823
+ let t0;
824
+ if ($[0] !== t) {
825
+ t0 = t("standalone.panel.session.title");
826
+ $[0] = t;
827
+ $[1] = t0;
828
+ } else t0 = $[1];
829
+ const t1 = current.authenticated;
830
+ let t2;
831
+ if ($[2] !== t) {
832
+ t2 = t("standalone.panel.session.signedIn");
833
+ $[2] = t;
834
+ $[3] = t2;
835
+ } else t2 = $[3];
836
+ let t3;
837
+ if ($[4] !== current || $[5] !== session) {
838
+ t3 = (authenticated) => {
839
+ session.set({
840
+ ...current,
841
+ authenticated
842
+ });
843
+ };
844
+ $[4] = current;
845
+ $[5] = session;
846
+ $[6] = t3;
847
+ } else t3 = $[6];
848
+ let t4;
849
+ if ($[7] !== current.authenticated || $[8] !== t2 || $[9] !== t3) {
850
+ t4 = /* @__PURE__ */ jsx(Toggle, {
851
+ checked: t1,
852
+ label: t2,
853
+ onCheckedChange: t3
854
+ });
855
+ $[7] = current.authenticated;
856
+ $[8] = t2;
857
+ $[9] = t3;
858
+ $[10] = t4;
859
+ } else t4 = $[10];
860
+ let t5;
861
+ if ($[11] !== current || $[12] !== entitlements || $[13] !== permissions || $[14] !== session) {
862
+ t5 = [...permissions.map(_temp$3), ...entitlements.map(_temp2$1)].map((t6) => {
863
+ const [list, id_1] = t6;
864
+ return /* @__PURE__ */ jsx(Toggle, {
865
+ checked: current[list].includes(id_1),
866
+ label: id_1,
867
+ onCheckedChange: (on) => {
868
+ session.set(grantedIn(current, list, id_1, on));
869
+ }
870
+ }, id_1);
871
+ });
872
+ $[11] = current;
873
+ $[12] = entitlements;
874
+ $[13] = permissions;
875
+ $[14] = session;
876
+ $[15] = t5;
877
+ } else t5 = $[15];
878
+ let t6;
879
+ if ($[16] !== t0 || $[17] !== t4 || $[18] !== t5) {
880
+ t6 = /* @__PURE__ */ jsxs(Group, {
881
+ title: t0,
882
+ children: [t4, t5]
883
+ });
884
+ $[16] = t0;
885
+ $[17] = t4;
886
+ $[18] = t5;
887
+ $[19] = t6;
888
+ } else t6 = $[19];
889
+ return t6;
890
+ }
891
+ function _temp2$1(t0) {
892
+ const { id: id_0 } = t0;
893
+ return ["entitlements", id_0];
894
+ }
895
+ function _temp$3(t0) {
896
+ const { id } = t0;
897
+ return ["permissions", id];
898
+ }
899
+ //#endregion
900
+ //#region src/standalone/shell-controls.tsx
901
+ /**
902
+ * Lists the color mode choices in the order the panel offers them, each with the key of its words.
903
+ */
904
+ const MODES = [
905
+ {
906
+ key: "standalone.panel.shell.light",
907
+ value: "light"
908
+ },
909
+ {
910
+ key: "standalone.panel.shell.dark",
911
+ value: "dark"
912
+ },
913
+ {
914
+ key: "standalone.panel.shell.system",
915
+ value: "system"
916
+ }
917
+ ];
918
+ /**
919
+ * Renders a picker of the page's locales and one of its themes, each where the page offers more
920
+ * than one, and a segment group of the color modes.
921
+ *
922
+ * @remarks
923
+ * Each control calls the shell's own setter, so the choice is remembered as a product's would be.
924
+ * A locale and a theme are named by their codes, as the page's configuration states them.
925
+ * @returns The group.
926
+ */
927
+ function ShellControls() {
928
+ const $ = c(30);
929
+ const { glyphs } = useStandalone();
930
+ const { t } = useTranslation("host");
931
+ const { locale, locales, setLocale } = useLocale();
932
+ const { setTheme, theme, themes } = useThemeChoice();
933
+ const { choice, setColorMode } = useColorMode();
934
+ let t0;
935
+ if ($[0] !== t) {
936
+ t0 = t("standalone.panel.shell.title");
937
+ $[0] = t;
938
+ $[1] = t0;
939
+ } else t0 = $[1];
940
+ let t1;
941
+ if ($[2] !== glyphs || $[3] !== locale || $[4] !== locales || $[5] !== setLocale || $[6] !== t) {
942
+ t1 = locales.length > 1 ? /* @__PURE__ */ jsx(Picker, {
943
+ choices: locales.map(_temp$2),
944
+ indicator: glyphs.select?.indicator,
945
+ label: t("standalone.panel.shell.language"),
946
+ onValueChange: setLocale,
947
+ value: locale
948
+ }) : null;
949
+ $[2] = glyphs;
950
+ $[3] = locale;
951
+ $[4] = locales;
952
+ $[5] = setLocale;
953
+ $[6] = t;
954
+ $[7] = t1;
955
+ } else t1 = $[7];
956
+ let t2;
957
+ if ($[8] !== glyphs || $[9] !== setTheme || $[10] !== t || $[11] !== theme || $[12] !== themes) {
958
+ t2 = themes.length > 1 ? /* @__PURE__ */ jsx(Picker, {
959
+ choices: themes.map(_temp2),
960
+ indicator: glyphs.select?.indicator,
961
+ label: t("standalone.panel.shell.theme"),
962
+ onValueChange: setTheme,
963
+ value: theme
964
+ }) : null;
965
+ $[8] = glyphs;
966
+ $[9] = setTheme;
967
+ $[10] = t;
968
+ $[11] = theme;
969
+ $[12] = themes;
970
+ $[13] = t2;
971
+ } else t2 = $[13];
972
+ let t3;
973
+ if ($[14] !== t) {
974
+ t3 = t("standalone.panel.shell.colorMode");
975
+ $[14] = t;
976
+ $[15] = t3;
977
+ } else t3 = $[15];
978
+ let t4;
979
+ if ($[16] !== setColorMode) {
980
+ t4 = (t5) => {
981
+ const { value } = t5;
982
+ setColorMode(value);
983
+ };
984
+ $[16] = setColorMode;
985
+ $[17] = t4;
986
+ } else t4 = $[17];
987
+ let t5;
988
+ if ($[18] !== t) {
989
+ t5 = MODES.map((t6) => {
990
+ const { key, value: value_0 } = t6;
991
+ return /* @__PURE__ */ jsx(SegmentGroup.Item, {
992
+ value: value_0,
993
+ children: /* @__PURE__ */ jsx(SegmentGroup.ItemText, { children: t(key) })
994
+ }, value_0);
995
+ });
996
+ $[18] = t;
997
+ $[19] = t5;
998
+ } else t5 = $[19];
999
+ let t6;
1000
+ if ($[20] !== choice || $[21] !== t3 || $[22] !== t4 || $[23] !== t5) {
1001
+ t6 = /* @__PURE__ */ jsx(SegmentGroup.Root, {
1002
+ "aria-label": t3,
1003
+ onValueChange: t4,
1004
+ size: "sm",
1005
+ value: choice,
1006
+ children: t5
1007
+ });
1008
+ $[20] = choice;
1009
+ $[21] = t3;
1010
+ $[22] = t4;
1011
+ $[23] = t5;
1012
+ $[24] = t6;
1013
+ } else t6 = $[24];
1014
+ let t7;
1015
+ if ($[25] !== t0 || $[26] !== t1 || $[27] !== t2 || $[28] !== t6) {
1016
+ t7 = /* @__PURE__ */ jsxs(Group, {
1017
+ title: t0,
1018
+ children: [
1019
+ t1,
1020
+ t2,
1021
+ t6
1022
+ ]
1023
+ });
1024
+ $[25] = t0;
1025
+ $[26] = t1;
1026
+ $[27] = t2;
1027
+ $[28] = t6;
1028
+ $[29] = t7;
1029
+ } else t7 = $[29];
1030
+ return t7;
1031
+ }
1032
+ function _temp2(one_0) {
1033
+ return {
1034
+ label: one_0,
1035
+ value: one_0
1036
+ };
1037
+ }
1038
+ function _temp$2(one) {
1039
+ return {
1040
+ label: one,
1041
+ value: one
1042
+ };
1043
+ }
1044
+ //#endregion
1045
+ //#region src/standalone/controls.tsx
1046
+ /**
1047
+ * Renders the page picker, then the session, the decisions, the flags, the plugin's switches, the
1048
+ * operations and the display.
1049
+ *
1050
+ * @returns The stack of groups.
1051
+ */
1052
+ function PanelControls() {
1053
+ const $ = c(1);
1054
+ let t0;
1055
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
1056
+ t0 = /* @__PURE__ */ jsxs(Stack, {
1057
+ gap: "lg",
1058
+ children: [
1059
+ /* @__PURE__ */ jsx(PageControls, {}),
1060
+ /* @__PURE__ */ jsx(SessionControls, {}),
1061
+ /* @__PURE__ */ jsx(AccessControls, {}),
1062
+ /* @__PURE__ */ jsx(FlagControls, {}),
1063
+ /* @__PURE__ */ jsx(PluginControls, {}),
1064
+ /* @__PURE__ */ jsx(DataControls, {}),
1065
+ /* @__PURE__ */ jsx(ShellControls, {})
1066
+ ]
1067
+ });
1068
+ $[0] = t0;
1069
+ } else t0 = $[0];
1070
+ return t0;
1071
+ }
1072
+ //#endregion
1073
+ //#region src/standalone/panel.tsx
1074
+ /**
1075
+ * Renders the development panel: a floating window over the standalone page, open from the start,
1076
+ * with every control of the page.
1077
+ */
1078
+ /**
1079
+ * The panel's width, in CSS pixels.
1080
+ */
1081
+ const WIDTH = 352;
1082
+ /**
1083
+ * The panel's height where the window has room for it, in CSS pixels.
1084
+ */
1085
+ const HEIGHT = 560;
1086
+ /**
1087
+ * The room between the panel and the window's edges, in CSS pixels.
1088
+ */
1089
+ const GAP = 16;
1090
+ /**
1091
+ * Returns the panel's place at the window's bottom-end corner, no taller than the window allows.
1092
+ */
1093
+ function placementOf(width, height) {
1094
+ const tall = Math.min(HEIGHT, height - 32);
1095
+ return {
1096
+ position: {
1097
+ x: Math.max(GAP, width - WIDTH - GAP),
1098
+ y: Math.max(GAP, height - tall - GAP)
1099
+ },
1100
+ size: {
1101
+ height: tall,
1102
+ width: WIDTH
1103
+ }
1104
+ };
1105
+ }
1106
+ /**
1107
+ * Renders the panel, which a person drags, resizes and minimizes, and never closes.
1108
+ *
1109
+ * @remarks
1110
+ * The panel opens at the window's bottom-end corner and is open for the page's life, so it needs
1111
+ * no trigger on the page. It is not modal: the page under it takes the pointer and the keys. Its
1112
+ * stage triggers render where the page's glyphs give theirs.
1113
+ * @returns The panel's root.
1114
+ */
1115
+ function StandalonePanel() {
1116
+ const $ = c(22);
1117
+ const { glyphs } = useStandalone();
1118
+ const { t } = useTranslation("host");
1119
+ const [t0] = useState(_temp$1);
1120
+ const { position, size } = t0;
1121
+ let t1;
1122
+ if ($[0] !== t) {
1123
+ t1 = t("standalone.panel.title");
1124
+ $[0] = t;
1125
+ $[1] = t1;
1126
+ } else t1 = $[1];
1127
+ let t2;
1128
+ if ($[2] !== t1) {
1129
+ t2 = /* @__PURE__ */ jsx(FloatingPanel.DragTrigger, { children: /* @__PURE__ */ jsx(FloatingPanel.Title, { children: t1 }) });
1130
+ $[2] = t1;
1131
+ $[3] = t2;
1132
+ } else t2 = $[3];
1133
+ let t3;
1134
+ if ($[4] !== glyphs.minimize) {
1135
+ t3 = glyphs.minimize === void 0 ? null : /* @__PURE__ */ jsx(FloatingPanel.StageTrigger, {
1136
+ stage: "minimized",
1137
+ children: glyphs.minimize
1138
+ });
1139
+ $[4] = glyphs.minimize;
1140
+ $[5] = t3;
1141
+ } else t3 = $[5];
1142
+ let t4;
1143
+ if ($[6] !== glyphs.restore) {
1144
+ t4 = glyphs.restore === void 0 ? null : /* @__PURE__ */ jsx(FloatingPanel.StageTrigger, {
1145
+ stage: "default",
1146
+ children: glyphs.restore
1147
+ });
1148
+ $[6] = glyphs.restore;
1149
+ $[7] = t4;
1150
+ } else t4 = $[7];
1151
+ let t5;
1152
+ if ($[8] !== t3 || $[9] !== t4) {
1153
+ t5 = /* @__PURE__ */ jsxs(FloatingPanel.Control, { children: [t3, t4] });
1154
+ $[8] = t3;
1155
+ $[9] = t4;
1156
+ $[10] = t5;
1157
+ } else t5 = $[10];
1158
+ let t6;
1159
+ if ($[11] !== t2 || $[12] !== t5) {
1160
+ t6 = /* @__PURE__ */ jsxs(FloatingPanel.Header, { children: [t2, t5] });
1161
+ $[11] = t2;
1162
+ $[12] = t5;
1163
+ $[13] = t6;
1164
+ } else t6 = $[13];
1165
+ let t7;
1166
+ let t8;
1167
+ if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
1168
+ t7 = /* @__PURE__ */ jsx(FloatingPanel.Body, { children: /* @__PURE__ */ jsx(PanelControls, {}) });
1169
+ t8 = /* @__PURE__ */ jsx(FloatingPanel.ResizeTriggers, {});
1170
+ $[14] = t7;
1171
+ $[15] = t8;
1172
+ } else {
1173
+ t7 = $[14];
1174
+ t8 = $[15];
1175
+ }
1176
+ let t9;
1177
+ if ($[16] !== t6) {
1178
+ t9 = /* @__PURE__ */ jsx(FloatingPanel.Positioner, { children: /* @__PURE__ */ jsxs(FloatingPanel.Content, { children: [
1179
+ t6,
1180
+ t7,
1181
+ t8
1182
+ ] }) });
1183
+ $[16] = t6;
1184
+ $[17] = t9;
1185
+ } else t9 = $[17];
1186
+ let t10;
1187
+ if ($[18] !== position || $[19] !== size || $[20] !== t9) {
1188
+ t10 = /* @__PURE__ */ jsx(FloatingPanel.Root, {
1189
+ defaultPosition: position,
1190
+ defaultSize: size,
1191
+ open: true,
1192
+ children: t9
1193
+ });
1194
+ $[18] = position;
1195
+ $[19] = size;
1196
+ $[20] = t9;
1197
+ $[21] = t10;
1198
+ } else t10 = $[21];
1199
+ return t10;
1200
+ }
1201
+ function _temp$1() {
1202
+ return placementOf(window.innerWidth, window.innerHeight);
1203
+ }
1204
+ //#endregion
1205
+ //#region src/standalone/frame.tsx
1206
+ /**
1207
+ * Renders the shell with a bar, a column and a band for each region a contribution fills, the page
1208
+ * in the main region, and the panel through `Into`.
1209
+ *
1210
+ * @remarks
1211
+ * A region nobody fills renders no part of the shell, so an empty aside takes no column, as a
1212
+ * product's frame leaves it out.
1213
+ * @returns The host's root around the shell.
1214
+ */
1215
+ function StandaloneFrame() {
1216
+ const $ = c(22);
1217
+ const { slots } = hostContract;
1218
+ const header = [
1219
+ useSlot(slots.brand),
1220
+ useSlot(slots.header),
1221
+ useSlot(slots.userMenu)
1222
+ ].some(_temp);
1223
+ const navigation = useSlot(slots.navigation).filled;
1224
+ const aside = useSlot(slots.aside).filled;
1225
+ const footer = useSlot(slots.footer).filled;
1226
+ const status = useSlot(slots.status).filled;
1227
+ let t0;
1228
+ if ($[0] !== header) {
1229
+ t0 = header ? /* @__PURE__ */ jsxs(AppShell.Header, { children: [
1230
+ /* @__PURE__ */ jsx(Slot, { slot: slots.brand }),
1231
+ /* @__PURE__ */ jsx(Slot, { slot: slots.header }),
1232
+ /* @__PURE__ */ jsx(Slot, { slot: slots.userMenu })
1233
+ ] }) : null;
1234
+ $[0] = header;
1235
+ $[1] = t0;
1236
+ } else t0 = $[1];
1237
+ let t1;
1238
+ if ($[2] !== navigation) {
1239
+ t1 = navigation ? /* @__PURE__ */ jsx(AppShell.Navbar, { children: /* @__PURE__ */ jsx(Slot, { slot: slots.navigation }) }) : null;
1240
+ $[2] = navigation;
1241
+ $[3] = t1;
1242
+ } else t1 = $[3];
1243
+ let t2;
1244
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
1245
+ t2 = /* @__PURE__ */ jsx(AppShell.Main, { children: /* @__PURE__ */ jsx(HostContent, {}) });
1246
+ $[4] = t2;
1247
+ } else t2 = $[4];
1248
+ let t3;
1249
+ if ($[5] !== aside) {
1250
+ t3 = aside ? /* @__PURE__ */ jsx(AppShell.Aside, { children: /* @__PURE__ */ jsx(Slot, { slot: slots.aside }) }) : null;
1251
+ $[5] = aside;
1252
+ $[6] = t3;
1253
+ } else t3 = $[6];
1254
+ let t4;
1255
+ if ($[7] !== t1 || $[8] !== t3) {
1256
+ t4 = /* @__PURE__ */ jsxs(AppShell.Body, { children: [
1257
+ t1,
1258
+ t2,
1259
+ t3
1260
+ ] });
1261
+ $[7] = t1;
1262
+ $[8] = t3;
1263
+ $[9] = t4;
1264
+ } else t4 = $[9];
1265
+ let t5;
1266
+ if ($[10] !== footer) {
1267
+ t5 = footer ? /* @__PURE__ */ jsx(AppShell.Footer, { children: /* @__PURE__ */ jsx(Slot, { slot: slots.footer }) }) : null;
1268
+ $[10] = footer;
1269
+ $[11] = t5;
1270
+ } else t5 = $[11];
1271
+ let t6;
1272
+ if ($[12] !== status) {
1273
+ t6 = status ? /* @__PURE__ */ jsx(AppShell.Status, { children: /* @__PURE__ */ jsx(Slot, { slot: slots.status }) }) : null;
1274
+ $[12] = status;
1275
+ $[13] = t6;
1276
+ } else t6 = $[13];
1277
+ let t7;
1278
+ if ($[14] !== t0 || $[15] !== t4 || $[16] !== t5 || $[17] !== t6) {
1279
+ t7 = /* @__PURE__ */ jsxs(AppShell.Root, { children: [
1280
+ t0,
1281
+ t4,
1282
+ t5,
1283
+ t6
1284
+ ] });
1285
+ $[14] = t0;
1286
+ $[15] = t4;
1287
+ $[16] = t5;
1288
+ $[17] = t6;
1289
+ $[18] = t7;
1290
+ } else t7 = $[18];
1291
+ let t8;
1292
+ if ($[19] === Symbol.for("react.memo_cache_sentinel")) {
1293
+ t8 = /* @__PURE__ */ jsx(Into, {
1294
+ slot: slots.overlay,
1295
+ children: /* @__PURE__ */ jsx(StandalonePanel, {})
1296
+ });
1297
+ $[19] = t8;
1298
+ } else t8 = $[19];
1299
+ let t9;
1300
+ if ($[20] !== t7) {
1301
+ t9 = /* @__PURE__ */ jsxs(HostRoot, { children: [t7, t8] });
1302
+ $[20] = t7;
1303
+ $[21] = t9;
1304
+ } else t9 = $[21];
1305
+ return t9;
1306
+ }
1307
+ function _temp(t0) {
1308
+ const { filled } = t0;
1309
+ return filled;
1310
+ }
1311
+ //#endregion
1312
+ //#region src/standalone/start.ts
1313
+ /**
1314
+ * Reads what the standalone page starts from: the address it opens at, and the flags the panel
1315
+ * offers.
1316
+ */
1317
+ /**
1318
+ * Returns the address the standalone page opens at: the plugin's first menu entry, else its first
1319
+ * route that a sample or an empty path fills. Undefined where the plugin has neither.
1320
+ *
1321
+ * @param product - The standalone product, whose id is the plugin's.
1322
+ * @param routes - The router's map.
1323
+ */
1324
+ function startOf(product, routes) {
1325
+ const filled = product.routes.filter(({ plugin }) => plugin === product.productId).filter(({ path, sample }) => sample !== void 0 || !path.includes("$"));
1326
+ const [start] = [...filled.filter(({ navigation }) => navigation !== void 0), ...filled];
1327
+ return start === void 0 ? void 0 : routeHref(routes, { id: start.id }, start.sample);
1328
+ }
1329
+ /**
1330
+ * Returns every flag the installed plugins' contracts declare, in install order, with the variants
1331
+ * of each experiment.
1332
+ */
1333
+ function flagsOf(product) {
1334
+ return Object.values(product.manifests).flatMap(({ contract }) => Object.values(contract.featureFlags).map(({ id, variants }) => ({
1335
+ id,
1336
+ variants: variants?.map(String)
1337
+ })));
1338
+ }
1339
+ //#endregion
1340
+ //#region src/standalone/router.ts
1341
+ /**
1342
+ * Builds the standalone page's router: the host's routes under a root that renders the standalone
1343
+ * frame, opened at the plugin's start.
1344
+ */
1345
+ /**
1346
+ * Returns the standalone page's router over the browser's address.
1347
+ *
1348
+ * @remarks
1349
+ * A page opened at `/` replaces its address with the plugin's start, so the back button does not
1350
+ * return to an empty page. The start is read once the router has given every route its path.
1351
+ * @param host - The host the router's context contains.
1352
+ * @param product - The standalone product, whose routes the host compiles.
1353
+ */
1354
+ function standaloneRouter(host, product) {
1355
+ const root = createAppRootRoute()({
1356
+ component: StandaloneFrame,
1357
+ notFoundComponent: HostNotFound
1358
+ });
1359
+ const tree = root.addChildren([...createHostRoutes(product)(root)]);
1360
+ const routes = routeMap(tree);
1361
+ const router = createRouter({
1362
+ ...routerOptions({
1363
+ data: host.data,
1364
+ host,
1365
+ routes
1366
+ }),
1367
+ routeTree: tree
1368
+ });
1369
+ const start = startOf(product, routes);
1370
+ if (start !== void 0 && router.history.location.pathname === "/") router.history.replace(start);
1371
+ return {
1372
+ router,
1373
+ routes
1374
+ };
1375
+ }
1376
+ //#endregion
1377
+ //#region src/standalone/app.tsx
1378
+ /**
1379
+ * Starts the standalone page of a plugin: the plugin under a real host, the plugins beside it from
1380
+ * their contracts alone, and the development panel over the page.
1381
+ *
1382
+ * @remarks
1383
+ * The standalone layer of `vite-config-product` serves a page whose entry calls
1384
+ * `renderStandalone` with `virtual:product` and `virtual:i18n`. The module renders React, so it
1385
+ * is an entry of its own, apart from `./standalone`, which the build evaluates in Node.
1386
+ */
1387
+ /**
1388
+ * Renders the standalone page once the host is ready.
1389
+ *
1390
+ * @param options - The product, the catalogues, the glyphs, the locales, the themes and the
1391
+ * element.
1392
+ * @returns The React root the page renders in, which `unmount` takes down.
1393
+ * @throws {@link Error} Where no element is given and the document has none with the id `root`.
1394
+ */
1395
+ async function renderStandalone({ catalogues, element = document.querySelector("#root"), glyphs = {}, locales, product, themes }) {
1396
+ if (element === null) throw new Error("The standalone page renders into the element with the id root, and the document has none.");
1397
+ const { host, modes, sources } = standaloneHosted(product, glyphs);
1398
+ const { router, routes } = standaloneRouter(host, product);
1399
+ const state = {
1400
+ access: sources.access,
1401
+ flags: flagsOf(product),
1402
+ glyphs,
1403
+ modes,
1404
+ routes,
1405
+ session: sources.session
1406
+ };
1407
+ await host.ready();
1408
+ const root = createRoot(element);
1409
+ root.render(/* @__PURE__ */ jsx(StandaloneContext, {
1410
+ value: state,
1411
+ children: /* @__PURE__ */ jsx(Shell, {
1412
+ app: product.productId,
1413
+ catalogues,
1414
+ locales,
1415
+ themes,
1416
+ children: /* @__PURE__ */ jsx(HostProvider, {
1417
+ host,
1418
+ router,
1419
+ children: /* @__PURE__ */ jsx(RouterProvider, { router })
1420
+ })
1421
+ })
1422
+ }));
1423
+ return root;
1424
+ }
1425
+ //#endregion
1426
+ export { renderStandalone };