gesso-framework 0.6.3 → 0.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # gesso-framework
2
2
 
3
+ ## 0.6.5
4
+
5
+ ### Patch Changes
6
+
7
+ - e93e0ee: A `Link` can now name an in-app destination with `to`, and a Cmd-click opens it somewhere new, the way a browser treats an anchor. `to` takes one of the application's own urls (`/epic/BUD-12?story=BUD-13`) or a `RouteTarget` from `to(route, params)`. A plain click, Enter or Space runs `onPress` and then navigates the router in place. A click with Command or Control held (either one, on any platform), a middle click, or Cmd-Enter / Ctrl-Enter runs `onPress` and then asks the shell to open the app at that url somewhere new, leaving the current screen where it is. An `href` link is unchanged: it opens through `openUrl` however it is clicked. When a link has both, `to` wins. `Breadcrumb` items take the same `to`.
8
+
9
+ The request is the new `ShellService.openRoute(url)`, and what "somewhere new" means is the shell's decision. `createApp` and `GessoApp` take an `onOpenRoute(url)` for a host with its own idea of a new tab, such as an app inside Jira opening one through Forge's `router.open`. Without one, a browser shell opens a tab at the app's own address for that url: the path on the same origin in `path` mode, the same page with the fragment set in `hash` mode. In `memory` mode there is no address, so the link is followed in place. A handed-in `ShellHistory` can answer the new optional `href(url)` to give the address itself; without it, such a link is also followed in place.
10
+
11
+ In `gesso-electrobun`, the view bridge has `openRoute(url)` to pass as `onOpenRoute`, and `createDesktopApp` answers it by opening a new window of the application at that route: `openWindow({ route })`, and an `onOpenRoute(url, window)` option to do something else. A window learns its route from the page it loads: `open` reads `window.route`, `withWindowRoute` puts it in the view url's fragment, and `windowRoute()` reads it back as the window's starting url. An `open` that ignores it keeps working. The Electrobun template does all three.
12
+
13
+ - gesso-core@0.6.5
14
+
15
+ ## 0.6.4
16
+
17
+ ### Patch Changes
18
+
19
+ - 2f6a858: The `history` option now also takes a ready-made `ShellHistory`, for an app embedded in a page whose address bar belongs to its host. An app in an iframe inside another product, such as an Atlassian Forge Custom UI app in Jira, can reach the host's address only through a history object the host hands out. Adapt that object to `ShellHistory` and pass it to `createApp`, `createSyncApp(...).useHistory` or `GessoApp` in place of `{ mode }`, and the router reads its starting url from it, pushes and replaces through it, and follows the changes it reports. A history passed in stays the caller's: disposing the app stops listening to it but does not dispose it, so it survives a remount. Options work exactly as before.
20
+ - gesso-core@0.6.4
21
+
3
22
  ## 0.6.3
4
23
 
5
24
  ### Patch Changes
@@ -1664,6 +1664,9 @@ type ShellRequest = {
1664
1664
  } | {
1665
1665
  type: 'openUrl';
1666
1666
  url: string;
1667
+ } | {
1668
+ type: 'openRoute';
1669
+ url: string;
1667
1670
  } | {
1668
1671
  type: 'redirect';
1669
1672
  url: string;
@@ -1949,6 +1952,30 @@ declare class ShellService {
1949
1952
  settleClipboard(id: number, copied: boolean): void;
1950
1953
  /** Opens a URL in the user's browser, in a new tab or window. */
1951
1954
  openUrl(url: string): void;
1955
+ /**
1956
+ * Opens this application at one of its own urls, somewhere new: what
1957
+ * a Cmd-click or a Ctrl-click on an in-app link asks for.
1958
+ *
1959
+ * Not `openUrl`, because the two urls are different kinds of thing.
1960
+ * `openUrl` takes an address that already means something to the
1961
+ * browser. This takes the router's url, `/epic/BUD-12?story=BUD-13`,
1962
+ * which means something only to this application, and only the
1963
+ * shell knows what address shows the application at it: a path on
1964
+ * the page's origin, a fragment on the page's own address, a tab in
1965
+ * the product the app is embedded in, or a new native window. The
1966
+ * render thread cannot know which, so it names the route and the
1967
+ * shell decides.
1968
+ *
1969
+ * What each shell does, in order: the host's `onOpenRoute` if it gave
1970
+ * one; otherwise a new tab at the address the history gives for the
1971
+ * url (`ShellHistory.href`); otherwise, where there is no address,
1972
+ * which is `memory` mode, the shell follows the url in place, exactly
1973
+ * as `RouterService.navigate` would, rather than doing nothing.
1974
+ *
1975
+ * The current screen does not navigate. Nothing comes back, as with
1976
+ * `openUrl`. With no shell installed the request is dropped.
1977
+ */
1978
+ openRoute(url: string): void;
1952
1979
  /**
1953
1980
  * Replaces the page with `url`, leaving the application.
1954
1981
  *
@@ -4895,6 +4922,16 @@ type RuntimeToShellMessage = {
4895
4922
  type: 'openUrl';
4896
4923
  url: string;
4897
4924
  } |
4925
+ /**
4926
+ * Open the app at one of its own urls somewhere new
4927
+ * (ShellService.openRoute). `url` is the router's, not an address:
4928
+ * the shell turns it into one, through its `onOpenRoute` or its
4929
+ * history, or follows it in place when it has neither.
4930
+ */
4931
+ {
4932
+ type: 'openRoute';
4933
+ url: string;
4934
+ } |
4898
4935
  /**
4899
4936
  * Replace the page with a url, leaving the app (ShellService.redirect).
4900
4937
  * `url` is as the component gave it, relative or not; the shell
@@ -5326,6 +5363,18 @@ interface ShellHistoryOptions {
5326
5363
  /** `memory` mode only: where the app starts. Defaults to `/`. */
5327
5364
  readonly initialUrl?: string;
5328
5365
  }
5366
+ /**
5367
+ * A url kept somewhere, which the shell reads, writes and listens to.
5368
+ *
5369
+ * `createShellHistory` makes one from `ShellHistoryOptions`, and that
5370
+ * covers every window the app owns the address of. An app embedded in
5371
+ * a page whose address belongs to something else does not own it: an
5372
+ * Atlassian Forge Custom UI app runs in an iframe inside Jira, and the
5373
+ * only way to Jira's address bar is the history object Forge's bridge
5374
+ * hands out. Such a host implements this interface over whatever it
5375
+ * has, and passes the object as the app's `history` option in place of
5376
+ * options, so the router and the host's address bar stay one url.
5377
+ */
5329
5378
  interface ShellHistory {
5330
5379
  /** The url the window is at now. */
5331
5380
  readonly url: string;
@@ -5333,9 +5382,31 @@ interface ShellHistory {
5333
5382
  replace(url: string): void;
5334
5383
  back(): void;
5335
5384
  forward(): void;
5336
- /** Reports urls the person produced: back, forward, or a typed address. */
5385
+ /**
5386
+ * Reports urls the person produced: back, forward, or a typed address.
5387
+ *
5388
+ * There is one listener, and a second call replaces the first. An
5389
+ * app that was handed its history and is being taken down relies on
5390
+ * that to stop listening, since disposing a history it did not make
5391
+ * is not its decision.
5392
+ */
5337
5393
  onChange(listener: (url: string) => void): void;
5338
5394
  dispose(): void;
5395
+ /**
5396
+ * The address a new tab would open to show the app at `url`, or null
5397
+ * when this history has none to give.
5398
+ *
5399
+ * Asked when a link is followed somewhere new (`ShellService.openRoute`,
5400
+ * a Cmd-click or a Ctrl-click). The browser modes answer with the
5401
+ * document address that holds `url`, which is what `push` would have
5402
+ * written; `memory` answers null, because a url kept in memory names
5403
+ * no page anything else could load. Optional, because a history an
5404
+ * embedder wrote may have no such answer either, and leaving it out
5405
+ * says exactly that: the shell then follows the link in place. A
5406
+ * host that can open its own kind of tab (Jira's, through Forge's
5407
+ * `router.open`) says so with the shell's `onOpenRoute` instead.
5408
+ */
5409
+ href?(url: string): string | null;
5339
5410
  }
5340
5411
  /**
5341
5412
  * Just the parts of a window this module uses.
@@ -5455,6 +5526,25 @@ interface WorkerAppOptions {
5455
5526
  * reach. `gesso-electrobun`'s bridge is what goes here.
5456
5527
  */
5457
5528
  onOpenUrl?: (url: string) => void;
5529
+ /**
5530
+ * Opens the app at one of its own urls somewhere new
5531
+ * (`ShellService.openRoute`, a Cmd-click or a Ctrl-click on an in-app
5532
+ * `Link`), in place of a new browser tab.
5533
+ *
5534
+ * `url` is the router's, `/epic/BUD-12?story=BUD-13`, not an address.
5535
+ * Without this the shell opens a new tab at the address its history
5536
+ * gives for it (`ShellHistory.href`): the origin and the path in
5537
+ * `path` mode, the page with that fragment in `hash` mode. With no
5538
+ * address to give, in `memory` mode or with a history that has no
5539
+ * `href`, it follows the url in place.
5540
+ *
5541
+ * A host whose idea of a new tab is not the browser's goes here: an
5542
+ * app embedded in another product opens one of that product's tabs
5543
+ * (an Atlassian Forge app, Forge's `router.open`), and a desktop
5544
+ * window asks for another window (`gesso-electrobun`'s bridge,
5545
+ * `openRoute`).
5546
+ */
5547
+ onOpenRoute?: (url: string) => void;
5458
5548
  /**
5459
5549
  * Replaces the page with a url the application asked for
5460
5550
  * (`ShellService.redirect`), in place of `window.location.assign`.
@@ -5570,8 +5660,18 @@ interface WorkerAppOptions {
5570
5660
  * routes, resolves nothing, and could not — a route names a
5571
5661
  * component class, which never leaves the worker. It reports the url
5572
5662
  * the window is at and performs the pushes the worker asks for.
5663
+ *
5664
+ * Or a `ShellHistory` made elsewhere, for a page whose address the
5665
+ * app does not own. An app embedded in another product — an
5666
+ * Atlassian Forge Custom UI app is an iframe inside Jira — reaches
5667
+ * the address bar only through the history object its host hands
5668
+ * out, so it adapts that object to `ShellHistory` and passes it here,
5669
+ * and the router and the host's address stay one url. A history
5670
+ * passed this way is used as it is and survives the app: unmount
5671
+ * stops listening to it but does not dispose it, by the rule
5672
+ * `appLogicWorker` follows, and a remount picks the same one up.
5573
5673
  */
5574
- history?: ShellHistoryOptions;
5674
+ history?: ShellHistoryOptions | ShellHistory;
5575
5675
  }
5576
5676
  declare class WorkerApp {
5577
5677
  private readonly options;
@@ -5604,6 +5704,8 @@ declare class WorkerApp {
5604
5704
  */
5605
5705
  private scrollability;
5606
5706
  private history;
5707
+ /** True only when the history was made here from options; see `resolveShellHistory`. */
5708
+ private ownsHistory;
5607
5709
  /** True once the render worker has answered `ready` at least once. */
5608
5710
  private ready;
5609
5711
  /** The running `requestAnimationFrame` handle, when ticks are wanted. */
@@ -6026,8 +6128,11 @@ declare class GessoAppBuilder {
6026
6128
  /**
6027
6129
  * How the app's url is kept: `path` (pushState, the default in a
6028
6130
  * browser), `hash`, or `memory`. See `shellHistory`.
6131
+ *
6132
+ * Or a `ShellHistory` made elsewhere, for an app embedded in a page
6133
+ * whose address belongs to its host; see `GessoAppOptions.history`.
6029
6134
  */
6030
- useHistory(history: ShellHistoryOptions): this;
6135
+ useHistory(history: ShellHistoryOptions | ShellHistory): this;
6031
6136
  /**
6032
6137
  * Pins the rendering backend. Without this the app is on `auto`:
6033
6138
  * WebGPU where the browser has it, Canvas2D elsewhere.
@@ -6152,8 +6257,20 @@ interface GessoAppOptions {
6152
6257
  /**
6153
6258
  * How the app's url is kept: `path` (pushState, the default in a
6154
6259
  * browser), `hash`, or `memory`. See `shellHistory`.
6260
+ *
6261
+ * Or a `ShellHistory` made elsewhere, for a page whose address the
6262
+ * app does not own: an iframe inside another product, where the
6263
+ * host's own history object is the only way to its address bar. It
6264
+ * is used as it is, and left undisposed when the app is disposed,
6265
+ * because it belongs to whoever passed it.
6266
+ */
6267
+ history?: ShellHistoryOptions | ShellHistory;
6268
+ /**
6269
+ * Opens the app at one of its own urls somewhere new
6270
+ * (`ShellService.openRoute`), in place of a new browser tab. The
6271
+ * same option, and the same fallbacks, as `WorkerAppOptions.onOpenRoute`.
6155
6272
  */
6156
- history?: ShellHistoryOptions;
6273
+ onOpenRoute?: (url: string) => void;
6157
6274
  canvas?: CanvasHost;
6158
6275
  /** The rendering backend; see RendererChoice. Defaults to `auto`. */
6159
6276
  renderer?: RendererChoice;
@@ -6223,6 +6340,7 @@ declare class GessoApp {
6223
6340
  private readonly accessibilityEnabled;
6224
6341
  private readonly adapter;
6225
6342
  private readonly historyOptions;
6343
+ private readonly onOpenRoute;
6226
6344
  private running;
6227
6345
  private resizeObserver;
6228
6346
  private proxy;
@@ -6230,6 +6348,8 @@ declare class GessoApp {
6230
6348
  private audio;
6231
6349
  private mirror;
6232
6350
  private history;
6351
+ /** True only when the history was made here from options; see `resolveShellHistory`. */
6352
+ private ownsHistory;
6233
6353
  private detachVisibility;
6234
6354
  private detachFileDrop;
6235
6355
  /** Pickers and remembered handles, made on the first file request. */
@@ -8319,4 +8439,4 @@ declare class RenderWorkerApp {
8319
8439
  }
8320
8440
  //#endregion
8321
8441
  export { StorageAdapter as $, UiOwnerReport as $n, Resource as $r, FontFaceDeclaration as $t, Presence as A, AudioState as An, Channel as Ar, ActionCause as At, PersistedOptions as B, ShellFileType as Bn, bind as Br, UiTreeSnapshot as Bt, FocusService as C, formatUrl as Cn, pickKeys as Cr, AppLogicEndpoint as Ct, FindService as D, AudioRequest as Dn, findUnplainPath as Dr, ShellHistoryMode as Dt, TextService as E, AudioMetadata as En, createChannelRegistry as Er, ShellHistory as Et, AudioSinkOptions as F, UiDuration as Fn, ControlledOptions as Fr, DevtoolsEvent as Ft, IndexedDbStorage as G, ShellStorageResult as Gn, EachKey as Gr, FrameMetrics as Gt, persisted as H, ShellRequest as Hn, ShowProps as Hr, RuntimeErrorSource as Ht, AudioSinkOutput as I, UiEasingChoice as In, ControlledValue as Ir, DevtoolsRequest as It, OpfsFileHandle as J, observeColorScheme as Jn, debounced as Jr, GessoRuntimeOptions as Jt, IndexedDbStorageOptions as K, ColorScheme as Kn, EachProps as Kr, FramePhaseTimings as Kt, MediaSessionLike as L, ShellFile as Ln, controlled as Lr, FrameEntry as Lt, RouterOutlet as M, AnimateOptions as Mn, Inject as Mr, ChannelErrorEntry as Mt, AudioElementLike as N, AnimationService as Nn, Input as Nr, CommandEntry as Nt, observeMediaQuery as O, AudioSample as On, requirePlainData as Or, ShellHistoryOptions as Ot, AudioSink as P, SpringOptions as Pn, Output as Pr, ConsoleEntry as Pt, MemoryStorage as Q, UiNodeReport as Qn, mutate as Qr, UiFramePhase as Qt, audioClock as R, ShellFileRequest as Rn, ThemeTokenCell as Rr, PatchEntry as Rt, writeClipboard as S, buildPath as Sn, pick as Sr, createApp as St, EditingService as T, AudioAction as Tn, ChannelRegistryHandle as Tr, WorkerAppOptions as Tt, ShellStorage as U, ShellService as Un, show as Ur, RuntimeToShellMessage as Ut, PersistedState as V, ShellRecentFile as Vn, Show as Vr, treeText as Vt, ShellStorageOptions as W, ShellStorageOp as Wn, Each as Wr, ShellToRuntimeMessage as Wt, OpfsStorageOptions as X, NodePathTarget as Xn, MutateOptions as Xr, RuntimeInput as Xt, OpfsStorage as Y, BoundStream as Yn, throttled as Yr, RendererChoice as Yt, OpfsWritable as Z, UiEnvironmentReport as Zn, Mutation as Zr, UI_FRAME_PHASES as Zt, EditingMirrorTarget as _, derive as _i, RouteOptions as _n, createComponent as _r, GessoAppOptions as _t, UiRole as a, select as ai, MediaOptions as an, formatAge as ar, storageReadValue as at, EditingProxy as b, to as bn, isComponentElement as br, WebMcpChoice as bt, UiSemanticsPatch as c, FanOut as ci, RouteMatch as cn, formatStream as cr, UndoableOptions as ct, markNow as d, ComputedCell as di, RouterService as dn, ComponentHost as dr, UndoStackOptions as dt, ResourceOptions as ei, FontFaceLike as en, UiPropOrigin as er, StorageOutcome as et, measureSpan as f, ComputedOptions as fi, RouteState as fn, OverlayLayer as fr, UndoTransaction as ft, renderRoot as g, Equality as gi, RouteGuard as gn, OverlayService as gr, GessoApp as gt, RenderWorkerApp as h, DeriveOptions as hi, RouteDefinition as hn, OverlayRect as hr, shellStorageDenied as ht, UI_SEMANTIC_STATES as i, SelectOptions as ii, FontService as in, describeStream as ir, storageReadFailure as it, PresenceProps as j, AudioStatus as jn, Define as jr, ActionEntry as jt, observeReducedMotion as k, AudioService as kn, ChannelRegistry as kr, createShellHistory as kt, UiSemanticsRecord$1 as l, FanOutOptions as li, RouterHistorySink as ln, printPropValue as lr, undoable as lt, setPerformanceMarks$1 as m, computed as mi, RouteContext as mn, OverlayPlacement as mr, performShellStorage as mt, MARK_PREFIX as n, ResourceStatus as ni, FontFamilyStatus as nn, UiSemanticsReport as nr, classifyStorageError as nt, UiSemanticState as o, FanCell as oi, MediaService as on, formatNodePath as or, UndoShortcutOptions as ot, performanceMarksEnabled as p, ReadSource as pi, OutletProps as pn, OverlayEntry as pr, ShellLocalStore as pt, OpfsDirectory as q, ColorSchemePreference as qn, each as qr, GessoRuntime as qt, UI_ROLES as r, resource as ri, FontHost as rn, UiStreamReport as rr, storageErrorMessage as rt, UiSemanticsMap$1 as s, FanKey as si, RouteAnswer as sn, formatNodeReport as sr, registerUndoShortcuts as st, EditingState$1 as t, ResourceState as ti, FontFamilyDeclaration as tn, UiPropReport as tr, StorageRead as tt, markInstant as u, fanOut as ui, RouterRoutes as un, ComponentHostResolver as ur, UndoStack as ut, SemanticsMirror as v, ServiceRegistry as vi, RouteTarget as vn, ComponentElement as vr, createSyncApp as vt, ScrollService as w, parseUrl as wn, ChannelRegistration as wr, WorkerApp as wt, EditingProxySink as x, RouteParams as xn, structurallyEqual as xr, CreateAppOptions as xt, SemanticsMirrorSink as y, route as yn, FrameworkChild as yr, GessoAppBuilder as yt, FrameService as z, ShellFileResult as zn, themeTokenCell as zr, UiTreeNode as zt };
8322
- //# sourceMappingURL=index-DWQA6g_M.d.ts.map
8442
+ //# sourceMappingURL=index-B8PU7Cf0.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _ as channel, a as isChannelHostMessage, c as applyPatch, d as ChannelSpec, f as ChannelToken, g as ViewOf, h as CommandsOf, i as isChannelClientMessage, l as applyPatches, m as CommandMap, n as ChannelHostMessage, o as Patch, p as Command, r as ChannelPort, s as PatchPath, t as ChannelClientMessage, u as diffProjection, v as defineChannel, y as viewKeys } from "./ChannelProtocol-ByNoHujM.js";
2
2
  import { A as portHandle, C as MessageEndpoint, D as isHubMessage, E as WorkerHandle, F as JsonSchema, I as channelSchema, L as describeChannel, M as workerHandle, N as ChannelSchema, O as isPortErrorMessage, P as CommandSchema, S as APPLICATION_WORKER, T as PortHost, _ as serve, b as ProvidedChannel, g as ServedChannel, j as servePorts, k as isPortHandshake, v as serveChannels, w as PortHandshake, x as provide, y as ChannelSource } from "./ui-U39HjNFA.js";
3
3
  import { C as internalState, S as InternalState, _ as ReadableCell, a as ComponentType, b as isOutputTarget, c as isClassComponent, d as bounds, f as EmitArgs, g as OutputTarget, h as OutputCell, i as ComponentProps, l as ChannelReplica, m as InputCell, o as FunctionComponent, p as EmitValue, r as ComponentContext, s as Inputs, t as ClassComponent, u as BoundsCell, v as input, w as Component, x as output, y as into } from "./FunctionComponent-fYMdePtH.js";
4
- import { $ as StorageAdapter, $n as UiOwnerReport, $r as Resource, $t as FontFaceDeclaration, A as Presence, An as AudioState, Ar as Channel, At as ActionCause, B as PersistedOptions, Bn as ShellFileType, Br as bind, Bt as UiTreeSnapshot, C as FocusService, Cn as formatUrl, Cr as pickKeys, Ct as AppLogicEndpoint, D as FindService, Dn as AudioRequest, Dr as findUnplainPath, Dt as ShellHistoryMode, E as TextService, En as AudioMetadata, Er as createChannelRegistry, Et as ShellHistory, F as AudioSinkOptions, Fn as UiDuration, Fr as ControlledOptions, Ft as DevtoolsEvent, G as IndexedDbStorage, Gn as ShellStorageResult, Gr as EachKey, Gt as FrameMetrics, H as persisted, Hn as ShellRequest, Hr as ShowProps, Ht as RuntimeErrorSource, I as AudioSinkOutput, In as UiEasingChoice, Ir as ControlledValue, It as DevtoolsRequest, J as OpfsFileHandle, Jn as observeColorScheme, Jr as debounced, Jt as GessoRuntimeOptions, K as IndexedDbStorageOptions, Kn as ColorScheme, Kr as EachProps, Kt as FramePhaseTimings, L as MediaSessionLike, Ln as ShellFile, Lr as controlled, Lt as FrameEntry, M as RouterOutlet, Mn as AnimateOptions, Mr as Inject, Mt as ChannelErrorEntry, N as AudioElementLike, Nn as AnimationService, Nr as Input, Nt as CommandEntry, O as observeMediaQuery, On as AudioSample, Or as requirePlainData, Ot as ShellHistoryOptions, P as AudioSink, Pn as SpringOptions, Pr as Output, Pt as ConsoleEntry, Q as MemoryStorage, Qn as UiNodeReport, Qr as mutate, Qt as UiFramePhase, R as audioClock, Rn as ShellFileRequest, Rr as ThemeTokenCell, Rt as PatchEntry, S as writeClipboard, Sn as buildPath, Sr as pick, St as createApp, T as EditingService, Tn as AudioAction, Tr as ChannelRegistryHandle, Tt as WorkerAppOptions, U as ShellStorage, Un as ShellService, Ur as show, Ut as RuntimeToShellMessage, V as PersistedState, Vn as ShellRecentFile, Vr as Show, Vt as treeText, W as ShellStorageOptions, Wn as ShellStorageOp, Wr as Each, Wt as ShellToRuntimeMessage, X as OpfsStorageOptions, Xn as NodePathTarget, Xr as MutateOptions, Xt as RuntimeInput, Y as OpfsStorage, Yn as BoundStream, Yr as throttled, Yt as RendererChoice, Z as OpfsWritable, Zn as UiEnvironmentReport, Zr as Mutation, Zt as UI_FRAME_PHASES, _ as EditingMirrorTarget, _i as derive, _n as RouteOptions, _r as createComponent, _t as GessoAppOptions, a as UiRole, ai as select, an as MediaOptions, ar as formatAge, at as storageReadValue, b as EditingProxy, bn as to, br as isComponentElement, bt as WebMcpChoice, c as UiSemanticsPatch, ci as FanOut, cn as RouteMatch, cr as formatStream, ct as UndoableOptions, d as markNow, di as ComputedCell, dn as RouterService, dr as ComponentHost, dt as UndoStackOptions, ei as ResourceOptions, en as FontFaceLike, er as UiPropOrigin, et as StorageOutcome, f as measureSpan, fi as ComputedOptions, fn as RouteState, fr as OverlayLayer, ft as UndoTransaction, g as renderRoot, gi as Equality, gn as RouteGuard, gr as OverlayService, gt as GessoApp, h as RenderWorkerApp, hi as DeriveOptions, hn as RouteDefinition, hr as OverlayRect, ht as shellStorageDenied, i as UI_SEMANTIC_STATES, ii as SelectOptions, in as FontService, ir as describeStream, it as storageReadFailure, j as PresenceProps, jn as AudioStatus, jr as Define, jt as ActionEntry, k as observeReducedMotion, kn as AudioService, kr as ChannelRegistry, kt as createShellHistory, l as UiSemanticsRecord, li as FanOutOptions, ln as RouterHistorySink, lr as printPropValue, lt as undoable, m as setPerformanceMarks, mi as computed, mn as RouteContext, mr as OverlayPlacement, mt as performShellStorage, n as MARK_PREFIX, ni as ResourceStatus, nn as FontFamilyStatus, nr as UiSemanticsReport, nt as classifyStorageError, o as UiSemanticState, oi as FanCell, on as MediaService, or as formatNodePath, ot as UndoShortcutOptions, p as performanceMarksEnabled, pi as ReadSource, pn as OutletProps, pr as OverlayEntry, pt as ShellLocalStore, q as OpfsDirectory, qn as ColorSchemePreference, qr as each, qt as GessoRuntime, r as UI_ROLES, ri as resource, rn as FontHost, rr as UiStreamReport, rt as storageErrorMessage, s as UiSemanticsMap, si as FanKey, sn as RouteAnswer, sr as formatNodeReport, st as registerUndoShortcuts, t as EditingState, ti as ResourceState, tn as FontFamilyDeclaration, tr as UiPropReport, tt as StorageRead, u as markInstant, ui as fanOut, un as RouterRoutes, ur as ComponentHostResolver, ut as UndoStack, v as SemanticsMirror, vi as ServiceRegistry, vn as RouteTarget, vr as ComponentElement, vt as createSyncApp, w as ScrollService, wn as parseUrl, wr as ChannelRegistration, wt as WorkerApp, x as EditingProxySink, xn as RouteParams, xr as structurallyEqual, xt as CreateAppOptions, y as SemanticsMirrorSink, yn as route, yr as FrameworkChild, yt as GessoAppBuilder, z as FrameService, zn as ShellFileResult, zr as themeTokenCell, zt as UiTreeNode } from "./index-DWQA6g_M.js";
4
+ import { $ as StorageAdapter, $n as UiOwnerReport, $r as Resource, $t as FontFaceDeclaration, A as Presence, An as AudioState, Ar as Channel, At as ActionCause, B as PersistedOptions, Bn as ShellFileType, Br as bind, Bt as UiTreeSnapshot, C as FocusService, Cn as formatUrl, Cr as pickKeys, Ct as AppLogicEndpoint, D as FindService, Dn as AudioRequest, Dr as findUnplainPath, Dt as ShellHistoryMode, E as TextService, En as AudioMetadata, Er as createChannelRegistry, Et as ShellHistory, F as AudioSinkOptions, Fn as UiDuration, Fr as ControlledOptions, Ft as DevtoolsEvent, G as IndexedDbStorage, Gn as ShellStorageResult, Gr as EachKey, Gt as FrameMetrics, H as persisted, Hn as ShellRequest, Hr as ShowProps, Ht as RuntimeErrorSource, I as AudioSinkOutput, In as UiEasingChoice, Ir as ControlledValue, It as DevtoolsRequest, J as OpfsFileHandle, Jn as observeColorScheme, Jr as debounced, Jt as GessoRuntimeOptions, K as IndexedDbStorageOptions, Kn as ColorScheme, Kr as EachProps, Kt as FramePhaseTimings, L as MediaSessionLike, Ln as ShellFile, Lr as controlled, Lt as FrameEntry, M as RouterOutlet, Mn as AnimateOptions, Mr as Inject, Mt as ChannelErrorEntry, N as AudioElementLike, Nn as AnimationService, Nr as Input, Nt as CommandEntry, O as observeMediaQuery, On as AudioSample, Or as requirePlainData, Ot as ShellHistoryOptions, P as AudioSink, Pn as SpringOptions, Pr as Output, Pt as ConsoleEntry, Q as MemoryStorage, Qn as UiNodeReport, Qr as mutate, Qt as UiFramePhase, R as audioClock, Rn as ShellFileRequest, Rr as ThemeTokenCell, Rt as PatchEntry, S as writeClipboard, Sn as buildPath, Sr as pick, St as createApp, T as EditingService, Tn as AudioAction, Tr as ChannelRegistryHandle, Tt as WorkerAppOptions, U as ShellStorage, Un as ShellService, Ur as show, Ut as RuntimeToShellMessage, V as PersistedState, Vn as ShellRecentFile, Vr as Show, Vt as treeText, W as ShellStorageOptions, Wn as ShellStorageOp, Wr as Each, Wt as ShellToRuntimeMessage, X as OpfsStorageOptions, Xn as NodePathTarget, Xr as MutateOptions, Xt as RuntimeInput, Y as OpfsStorage, Yn as BoundStream, Yr as throttled, Yt as RendererChoice, Z as OpfsWritable, Zn as UiEnvironmentReport, Zr as Mutation, Zt as UI_FRAME_PHASES, _ as EditingMirrorTarget, _i as derive, _n as RouteOptions, _r as createComponent, _t as GessoAppOptions, a as UiRole, ai as select, an as MediaOptions, ar as formatAge, at as storageReadValue, b as EditingProxy, bn as to, br as isComponentElement, bt as WebMcpChoice, c as UiSemanticsPatch, ci as FanOut, cn as RouteMatch, cr as formatStream, ct as UndoableOptions, d as markNow, di as ComputedCell, dn as RouterService, dr as ComponentHost, dt as UndoStackOptions, ei as ResourceOptions, en as FontFaceLike, er as UiPropOrigin, et as StorageOutcome, f as measureSpan, fi as ComputedOptions, fn as RouteState, fr as OverlayLayer, ft as UndoTransaction, g as renderRoot, gi as Equality, gn as RouteGuard, gr as OverlayService, gt as GessoApp, h as RenderWorkerApp, hi as DeriveOptions, hn as RouteDefinition, hr as OverlayRect, ht as shellStorageDenied, i as UI_SEMANTIC_STATES, ii as SelectOptions, in as FontService, ir as describeStream, it as storageReadFailure, j as PresenceProps, jn as AudioStatus, jr as Define, jt as ActionEntry, k as observeReducedMotion, kn as AudioService, kr as ChannelRegistry, kt as createShellHistory, l as UiSemanticsRecord, li as FanOutOptions, ln as RouterHistorySink, lr as printPropValue, lt as undoable, m as setPerformanceMarks, mi as computed, mn as RouteContext, mr as OverlayPlacement, mt as performShellStorage, n as MARK_PREFIX, ni as ResourceStatus, nn as FontFamilyStatus, nr as UiSemanticsReport, nt as classifyStorageError, o as UiSemanticState, oi as FanCell, on as MediaService, or as formatNodePath, ot as UndoShortcutOptions, p as performanceMarksEnabled, pi as ReadSource, pn as OutletProps, pr as OverlayEntry, pt as ShellLocalStore, q as OpfsDirectory, qn as ColorSchemePreference, qr as each, qt as GessoRuntime, r as UI_ROLES, ri as resource, rn as FontHost, rr as UiStreamReport, rt as storageErrorMessage, s as UiSemanticsMap, si as FanKey, sn as RouteAnswer, sr as formatNodeReport, st as registerUndoShortcuts, t as EditingState, ti as ResourceState, tn as FontFamilyDeclaration, tr as UiPropReport, tt as StorageRead, u as markInstant, ui as fanOut, un as RouterRoutes, ur as ComponentHostResolver, ut as UndoStack, v as SemanticsMirror, vi as ServiceRegistry, vn as RouteTarget, vr as ComponentElement, vt as createSyncApp, w as ScrollService, wn as parseUrl, wr as ChannelRegistration, wt as WorkerApp, x as EditingProxySink, xn as RouteParams, xr as structurallyEqual, xt as CreateAppOptions, y as SemanticsMirrorSink, yn as route, yr as FrameworkChild, yt as GessoAppBuilder, z as FrameService, zn as ShellFileResult, zr as themeTokenCell, zt as UiTreeNode } from "./index-B8PU7Cf0.js";
5
5
  export { APPLICATION_WORKER, type ActionCause, type ActionEntry, type AnimateOptions, AnimationService, type AppLogicEndpoint, type AudioAction, type AudioElementLike, type AudioMetadata, type AudioRequest, type AudioSample, AudioService, AudioSink, type AudioSinkOptions, type AudioSinkOutput, type AudioState, type AudioStatus, type BoundStream, BoundsCell, Channel, type ChannelClientMessage, type ChannelErrorEntry, type ChannelHostMessage, type ChannelPort, type ChannelRegistration, ChannelRegistry, type ChannelRegistryHandle, ChannelReplica, type ChannelSchema, type ChannelSource, type ChannelSpec, type ChannelToken, type ClassComponent, type ColorScheme, type ColorSchemePreference, type Command, type CommandEntry, type CommandMap, type CommandSchema, type CommandsOf, Component, type ComponentContext, type ComponentElement, ComponentHost, ComponentHostResolver, type ComponentProps, type ComponentType, ComputedCell, type ComputedOptions, type ConsoleEntry, type ControlledOptions, type ControlledValue, type CreateAppOptions, Define, type DeriveOptions, type DevtoolsEvent, type DevtoolsRequest, Each, type EachKey, type EachProps, type EditingMirrorTarget, EditingProxy, type EditingProxySink, EditingService, type EditingState, type EmitArgs, type EmitValue, type Equality, FanCell, type FanKey, FanOut, type FanOutOptions, FindService, FocusService, type FontFaceDeclaration, type FontFaceLike, type FontFamilyDeclaration, type FontFamilyStatus, type FontHost, FontService, type FrameEntry, type FrameMetrics, type FramePhaseTimings, FrameService, type FrameworkChild, type FunctionComponent, GessoApp, GessoAppBuilder, type GessoAppOptions, GessoRuntime, type GessoRuntimeOptions, IndexedDbStorage, type IndexedDbStorageOptions, Inject, Input, InputCell, type Inputs, InternalState, type JsonSchema, MARK_PREFIX, type MediaOptions, MediaService, type MediaSessionLike, MemoryStorage, type MessageEndpoint, type MutateOptions, type Mutation, type NodePathTarget, type OpfsDirectory, type OpfsFileHandle, OpfsStorage, type OpfsStorageOptions, type OpfsWritable, type OutletProps, Output, type OutputCell, type OutputTarget, type OverlayEntry, OverlayLayer, type OverlayPlacement, type OverlayRect, OverlayService, type Patch, type PatchEntry, type PatchPath, type PersistedOptions, PersistedState, type PortHandshake, type PortHost, Presence, type PresenceProps, ProvidedChannel, type ReadSource, type ReadableCell, RenderWorkerApp, type RendererChoice, Resource, type ResourceOptions, type ResourceState, type ResourceStatus, type RouteAnswer, type RouteContext, type RouteDefinition, type RouteGuard, type RouteMatch, type RouteOptions, type RouteParams, RouteState, type RouteTarget, type RouterHistorySink, RouterOutlet, type RouterRoutes, RouterService, type RuntimeErrorSource, type RuntimeInput, type RuntimeToShellMessage, ScrollService, type SelectOptions, SemanticsMirror, type SemanticsMirrorSink, type ServedChannel, ServiceRegistry, type ShellFile, type ShellFileRequest, type ShellFileResult, type ShellFileType, type ShellHistory, type ShellHistoryMode, type ShellHistoryOptions, type ShellLocalStore, type ShellRecentFile, type ShellRequest, ShellService, ShellStorage, type ShellStorageOp, type ShellStorageOptions, type ShellStorageResult, type ShellToRuntimeMessage, Show, type ShowProps, type SpringOptions, type StorageAdapter, type StorageOutcome, type StorageRead, TextService, ThemeTokenCell, UI_FRAME_PHASES, UI_ROLES, UI_SEMANTIC_STATES, type UiDuration, type UiEasingChoice, type UiEnvironmentReport, type UiFramePhase, type UiNodeReport, type UiOwnerReport, type UiPropOrigin, type UiPropReport, type UiRole, type UiSemanticState, type UiSemanticsMap, type UiSemanticsPatch, type UiSemanticsRecord, type UiSemanticsReport, type UiStreamReport, type UiTreeNode, type UiTreeSnapshot, type UndoShortcutOptions, UndoStack, type UndoStackOptions, type UndoTransaction, type UndoableOptions, type ViewOf, type WebMcpChoice, WorkerApp, type WorkerAppOptions, type WorkerHandle, applyPatch, applyPatches, audioClock, bind, bounds, buildPath, channel, channelSchema, classifyStorageError, computed, controlled, createApp, createChannelRegistry, createComponent, createShellHistory, createSyncApp, debounced, defineChannel, derive, describeChannel, describeStream, diffProjection, each, fanOut, findUnplainPath, formatAge, formatNodePath, formatNodeReport, formatStream, formatUrl, input, internalState, into, isChannelClientMessage, isChannelHostMessage, isClassComponent, isComponentElement, isHubMessage, isOutputTarget, isPortErrorMessage, isPortHandshake, markInstant, markNow, measureSpan, mutate, observeColorScheme, observeMediaQuery, observeReducedMotion, output, parseUrl, performShellStorage, performanceMarksEnabled, persisted, pick, pickKeys, portHandle, printPropValue, provide, registerUndoShortcuts, renderRoot, requirePlainData, resource, route, select, serve, serveChannels, servePorts, setPerformanceMarks, shellStorageDenied, show, storageErrorMessage, storageReadFailure, storageReadValue, structurallyEqual, themeTokenCell, throttled, to, treeText, undoable, viewKeys, workerHandle, writeClipboard };
package/dist/index.js CHANGED
@@ -1949,6 +1949,35 @@ var ShellService = class {
1949
1949
  });
1950
1950
  }
1951
1951
  /**
1952
+ * Opens this application at one of its own urls, somewhere new: what
1953
+ * a Cmd-click or a Ctrl-click on an in-app link asks for.
1954
+ *
1955
+ * Not `openUrl`, because the two urls are different kinds of thing.
1956
+ * `openUrl` takes an address that already means something to the
1957
+ * browser. This takes the router's url, `/epic/BUD-12?story=BUD-13`,
1958
+ * which means something only to this application, and only the
1959
+ * shell knows what address shows the application at it: a path on
1960
+ * the page's origin, a fragment on the page's own address, a tab in
1961
+ * the product the app is embedded in, or a new native window. The
1962
+ * render thread cannot know which, so it names the route and the
1963
+ * shell decides.
1964
+ *
1965
+ * What each shell does, in order: the host's `onOpenRoute` if it gave
1966
+ * one; otherwise a new tab at the address the history gives for the
1967
+ * url (`ShellHistory.href`); otherwise, where there is no address,
1968
+ * which is `memory` mode, the shell follows the url in place, exactly
1969
+ * as `RouterService.navigate` would, rather than doing nothing.
1970
+ *
1971
+ * The current screen does not navigate. Nothing comes back, as with
1972
+ * `openUrl`. With no shell installed the request is dropped.
1973
+ */
1974
+ openRoute(url) {
1975
+ this.handler?.({
1976
+ type: "openRoute",
1977
+ url
1978
+ });
1979
+ }
1980
+ /**
1952
1981
  * Replaces the page with `url`, leaving the application.
1953
1982
  *
1954
1983
  * Not the router's `navigate`, which moves between screens *inside*
@@ -3761,6 +3790,80 @@ function createShellHistory(options = {}, host = typeof window === "undefined" ?
3761
3790
  if (mode === "memory" || host === void 0) return new MemoryHistory(options.initialUrl ?? "/");
3762
3791
  return new BrowserHistory(host, mode, options.base ?? "");
3763
3792
  }
3793
+ /**
3794
+ * The history an app runs against, and whether the app may dispose it.
3795
+ *
3796
+ * Options are turned into a history here, and that history is the
3797
+ * app's to dispose with everything else it made. A history passed in
3798
+ * ready-made is used as it is and left alone at the end, by the rule
3799
+ * `appLogicWorker` already follows: what the app made, it disposes;
3800
+ * what it was handed, it leaves to whoever handed it. That is also
3801
+ * what keeps a host's history alive across a remount, which disposes
3802
+ * the app and builds it again around the same object.
3803
+ */
3804
+ function resolveShellHistory(source) {
3805
+ if (isShellHistory(source)) return {
3806
+ history: source,
3807
+ owned: false
3808
+ };
3809
+ return {
3810
+ history: createShellHistory(source),
3811
+ owned: true
3812
+ };
3813
+ }
3814
+ /**
3815
+ * Tells a ready-made history from options by its methods.
3816
+ *
3817
+ * Options are plain data and never carry a function, so the presence of
3818
+ * `push` and `onChange` as functions is unambiguous. It is checked by
3819
+ * behaviour rather than by `instanceof` because the histories worth
3820
+ * passing are adapters an embedder wrote, not classes from here.
3821
+ */
3822
+ function isShellHistory(value) {
3823
+ return value !== void 0 && typeof value.push === "function" && typeof value.onChange === "function";
3824
+ }
3825
+ /**
3826
+ * Opens the app at `url` somewhere new, as the shell's answer to
3827
+ * `ShellService.openRoute`.
3828
+ *
3829
+ * In this order, and the order is the decision. A host's own handler
3830
+ * wins, because an app embedded in another product or in a desktop
3831
+ * window knows what a new tab means there and a browser default would
3832
+ * be wrong in both. Without one, the history is asked for the address
3833
+ * that holds `url`, and that address is opened. Without an address,
3834
+ * which is `memory` mode and any handed-in history with no `href`, the
3835
+ * link is followed in place: a Cmd-click that did nothing at all would
3836
+ * read as a broken link, and arriving at the destination in the window
3837
+ * already open is what a browser does with a modifier it cannot honour.
3838
+ *
3839
+ * Shared by `WorkerApp` and `GessoApp`, which differ only in how a url
3840
+ * reaches the router, so it is passed in.
3841
+ */
3842
+ function openRouteWith(handler, url, history, open, followInPlace) {
3843
+ if (handler !== void 0) {
3844
+ handler(url);
3845
+ return;
3846
+ }
3847
+ const address = history?.href?.(url) ?? null;
3848
+ if (address !== null) {
3849
+ open(address);
3850
+ return;
3851
+ }
3852
+ followInPlace(url);
3853
+ }
3854
+ /**
3855
+ * Stops an app hearing about a history it is done with.
3856
+ *
3857
+ * A history the app made is disposed, which drops its listeners and
3858
+ * its window events with it. One it was handed is not the app's to
3859
+ * dispose, so the listener is replaced with one that does nothing:
3860
+ * the host's history goes on working, and a back button pressed after
3861
+ * the app is gone no longer reaches it.
3862
+ */
3863
+ function releaseShellHistory(history, owned) {
3864
+ if (owned) history.dispose();
3865
+ else history.onChange(() => {});
3866
+ }
3764
3867
  var MemoryHistory = class {
3765
3868
  entries;
3766
3869
  index = 0;
@@ -3791,6 +3894,10 @@ var MemoryHistory = class {
3791
3894
  dispose() {
3792
3895
  this.listener = null;
3793
3896
  }
3897
+ /** No address: a url kept here names no page another tab could load. */
3898
+ href() {
3899
+ return null;
3900
+ }
3794
3901
  step(delta) {
3795
3902
  const next = this.index + delta;
3796
3903
  if (next < 0 || next >= this.entries.length) return;
@@ -3858,6 +3965,17 @@ var BrowserHistory = class {
3858
3965
  this.host.removeEventListener("popstate", this.onPopState);
3859
3966
  this.host.removeEventListener("hashchange", this.onHashChange);
3860
3967
  }
3968
+ /**
3969
+ * The address `push` would write for `url`, for a new tab to open.
3970
+ *
3971
+ * Relative, as `pushState` takes it, and resolved against the page by
3972
+ * whatever opens it: `/epic/2` in `path` mode, and the page's own
3973
+ * path and query with the fragment set in `hash` mode, so the new tab
3974
+ * loads the same document and starts on the same screen.
3975
+ */
3976
+ href(url) {
3977
+ return this.toHref(url);
3978
+ }
3861
3979
  report() {
3862
3980
  const url = this.url;
3863
3981
  if (url === this.written) return;
@@ -4078,6 +4196,8 @@ var WorkerApp = class {
4078
4196
  right: false
4079
4197
  };
4080
4198
  history = null;
4199
+ /** True only when the history was made here from options; see `resolveShellHistory`. */
4200
+ ownsHistory = false;
4081
4201
  /** True once the render worker has answered `ready` at least once. */
4082
4202
  ready = false;
4083
4203
  /** The running `requestAnimationFrame` handle, when ticks are wanted. */
@@ -4439,8 +4559,9 @@ var WorkerApp = class {
4439
4559
  this.proxy = null;
4440
4560
  this.mirror?.dispose();
4441
4561
  this.mirror = null;
4442
- this.history?.dispose();
4562
+ if (this.history !== null) releaseShellHistory(this.history, this.ownsHistory);
4443
4563
  this.history = null;
4564
+ this.ownsHistory = false;
4444
4565
  this.detachInput?.();
4445
4566
  this.detachInput = null;
4446
4567
  this.audio?.dispose();
@@ -4548,6 +4669,16 @@ var WorkerApp = class {
4548
4669
  openUrlWith(this.options.onOpenUrl, message.url);
4549
4670
  return;
4550
4671
  }
4672
+ if (message.type === "openRoute") {
4673
+ openRouteWith(this.options.onOpenRoute, message.url, this.history, (address) => window.open(address, "_blank", "noopener"), (url) => {
4674
+ this.history?.push(url);
4675
+ this.post({
4676
+ type: "url",
4677
+ url
4678
+ });
4679
+ });
4680
+ return;
4681
+ }
4551
4682
  if (message.type === "redirect") {
4552
4683
  redirectWith(this.options.onRedirect, message.url, window.location);
4553
4684
  return;
@@ -4595,8 +4726,9 @@ var WorkerApp = class {
4595
4726
  * the screen that url names, not on its root.
4596
4727
  */
4597
4728
  attachHistory() {
4598
- const history = createShellHistory(this.options.history);
4729
+ const { history, owned } = resolveShellHistory(this.options.history);
4599
4730
  this.history = history;
4731
+ this.ownsHistory = owned;
4600
4732
  history.onChange((url) => this.post({
4601
4733
  type: "url",
4602
4734
  url
@@ -9701,6 +9833,7 @@ var GessoApp = class {
9701
9833
  accessibilityEnabled;
9702
9834
  adapter;
9703
9835
  historyOptions;
9836
+ onOpenRoute;
9704
9837
  running = false;
9705
9838
  resizeObserver = null;
9706
9839
  proxy = null;
@@ -9708,6 +9841,8 @@ var GessoApp = class {
9708
9841
  audio = null;
9709
9842
  mirror = null;
9710
9843
  history = null;
9844
+ /** True only when the history was made here from options; see `resolveShellHistory`. */
9845
+ ownsHistory = false;
9711
9846
  detachVisibility = null;
9712
9847
  detachFileDrop = null;
9713
9848
  /** Pickers and remembered handles, made on the first file request. */
@@ -9728,6 +9863,7 @@ var GessoApp = class {
9728
9863
  this.inputEnabled = options.input ?? true;
9729
9864
  this.accessibilityEnabled = options.accessibility ?? true;
9730
9865
  this.historyOptions = options.history;
9866
+ this.onOpenRoute = options.onOpenRoute;
9731
9867
  this.colorSchemePreference = options.colorScheme ?? "auto";
9732
9868
  this.runtime = new GessoRuntime({
9733
9869
  root: options.root,
@@ -9931,8 +10067,9 @@ var GessoApp = class {
9931
10067
  this.detachColorScheme = null;
9932
10068
  this.detachViewportInsets?.();
9933
10069
  this.detachViewportInsets = null;
9934
- this.history?.dispose();
10070
+ if (this.history !== null) releaseShellHistory(this.history, this.ownsHistory);
9935
10071
  this.history = null;
10072
+ this.ownsHistory = false;
9936
10073
  this.adapter.detach();
9937
10074
  this.resizeObserver?.disconnect();
9938
10075
  this.resizeObserver = null;
@@ -10014,8 +10151,9 @@ var GessoApp = class {
10014
10151
  * be a difference between the two hosts that nothing declared.
10015
10152
  */
10016
10153
  attachHistory() {
10017
- const history = createShellHistory(this.historyOptions);
10154
+ const { history, owned } = resolveShellHistory(this.historyOptions);
10018
10155
  this.history = history;
10156
+ this.ownsHistory = owned;
10019
10157
  this.runtime.onShellRequest((request) => this.handleShellRequest(request, history));
10020
10158
  history.onChange((url) => this.runtime.setUrl(url));
10021
10159
  this.runtime.setUrl(history.url);
@@ -10041,6 +10179,14 @@ var GessoApp = class {
10041
10179
  else history.forward();
10042
10180
  return;
10043
10181
  }
10182
+ if (request.type === "openRoute") {
10183
+ const view = isCanvasElement(this.canvas) ? this.canvas.ownerDocument.defaultView : null;
10184
+ openRouteWith(this.onOpenRoute, request.url, view === null ? null : history, (address) => view?.open(address, "_blank", "noopener"), (url) => {
10185
+ history.push(url);
10186
+ this.runtime.setUrl(url);
10187
+ });
10188
+ return;
10189
+ }
10044
10190
  if (!isCanvasElement(this.canvas)) {
10045
10191
  if (request.type === "popup") this.runtime.settlePopup(request.id, false);
10046
10192
  else if (request.type === "storage") this.runtime.settleStorage(request.id, shellStorageDenied());
@@ -10204,6 +10350,9 @@ var GessoAppBuilder = class {
10204
10350
  /**
10205
10351
  * How the app's url is kept: `path` (pushState, the default in a
10206
10352
  * browser), `hash`, or `memory`. See `shellHistory`.
10353
+ *
10354
+ * Or a `ShellHistory` made elsewhere, for an app embedded in a page
10355
+ * whose address belongs to its host; see `GessoAppOptions.history`.
10207
10356
  */
10208
10357
  useHistory(history) {
10209
10358
  this.historyOptions = history;
@@ -11393,6 +11542,10 @@ var RenderWorkerApp = class {
11393
11542
  type: "openUrl",
11394
11543
  url: request.url
11395
11544
  });
11545
+ else if (request.type === "openRoute") this.host.postMessage({
11546
+ type: "openRoute",
11547
+ url: request.url
11548
+ });
11396
11549
  else if (request.type === "redirect") this.host.postMessage({
11397
11550
  type: "redirect",
11398
11551
  url: request.url