@wippy-fe/types-global-proxy 0.0.26 → 0.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.d.ts +183 -8
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- import { PanelTree, ModalSize, PanelTarget } from '@wippy-fe/layout';
1
+ import { PanelTree, ModalSize, SizeValue, PanelTarget } from '@wippy-fe/layout';
2
2
  import { AxiosDefaults, AxiosInstance } from 'axios';
3
3
  import { ConfirmationOptions } from 'primevue/confirmationoptions';
4
4
  import { ToastMessageOptions } from 'primevue/toast';
5
5
  import * as nanoevents from 'nanoevents';
6
+ import { GLOBAL_CONFIG_VAR, GLOBAL_API_PROVIDER, GLOBAL_PROXY_CONFIG_VAR, GLOBAL_WEB_COMPONENT_CACHE } from '@wippy-fe/shared';
6
7
  import * as tailwindcss_types_config from 'tailwindcss/types/config';
7
8
 
8
9
  /**
@@ -15,7 +16,7 @@ import * as tailwindcss_types_config from 'tailwindcss/types/config';
15
16
  * - `page` → renders a Wippy page (WPage double-buffer for `main: true`, single-instance otherwise)
16
17
  * - `artifact` → renders a Wippy artifact (WPage with type='artifact')
17
18
  * - `component` → renders a registered web component via `tagName`
18
- * - `builtin` → renders host chrome (@HOST/nav-sidebar / @HOST/chat-wrapper / @HOST/artifact-viewer / @HOST/session-selector)
19
+ * - `builtin` → renders host chrome (nav-sidebar / chat-wrapper / artifact-viewer / session-selector)
19
20
  *
20
21
  * The host resolver converts this into `@wippy-fe/layout`'s `PanelDef` at
21
22
  * construction time and passes it into a `LayoutManager`.
@@ -25,6 +26,14 @@ interface HostPanelBase {
25
26
  title?: string;
26
27
  icon?: string;
27
28
  props?: Record<string, unknown>;
29
+ /**
30
+ * Drawer open state for panels whose active layout slot has
31
+ * `display: 'drawer-*'`. Surfaced in the snapshot wire so subscribed
32
+ * iframes can react to open/close. Mutated via
33
+ * `host.layout.openDrawer / closeDrawer / toggleDrawer` (or any
34
+ * `updatePanel` patch).
35
+ */
36
+ drawerOpen?: boolean;
28
37
  }
29
38
  interface HostPagePanelDef extends HostPanelBase {
30
39
  kind: 'page';
@@ -39,6 +48,12 @@ interface HostComponentPanelDef extends HostPanelBase {
39
48
  kind: 'component';
40
49
  tagName: string;
41
50
  }
51
+ /**
52
+ * Built-in panel ids shipped by gen-2-chat. The `@HOST/` prefix marks
53
+ * them as framework-owned so consumers can later plug in their own
54
+ * `kind: 'builtin'` ids without colliding (and so the declaration
55
+ * shows ownership at a glance).
56
+ */
42
57
  type HostBuiltinId = '@HOST/nav-sidebar' | '@HOST/chat-wrapper' | '@HOST/artifact-viewer' | '@HOST/session-selector';
43
58
  interface HostBuiltinPanelDef extends HostPanelBase {
44
59
  kind: 'builtin';
@@ -100,14 +115,37 @@ type HostFloatingDef = HostOverlayContent & HostOverlayBase & {
100
115
  /**
101
116
  * Modal def — centered overlay. Size is either a single `ModalSize`
102
117
  * or a breakpoint-keyed map (desktop centered / mobile fullscreen).
118
+ *
119
+ * `useNativeDialog` defaults to `true` — the modal renders via
120
+ * `<dialog showModal()>` (top-layer stacking, focus trap, inert
121
+ * propagation). Set `false` to opt back into the legacy div-overlay
122
+ * implementation while consumers migrate; the legacy path is
123
+ * `@deprecated` and will be removed in the next major.
103
124
  */
104
125
  type HostModalDef = HostOverlayContent & HostOverlayBase & {
105
126
  size?: ModalSize | Record<string, ModalSize>;
127
+ useNativeDialog?: boolean;
128
+ };
129
+ /**
130
+ * Coordinator def — headless coordinator app. Same content kinds as
131
+ * panels/floating/modals (page → iframe, artifact → iframe, component
132
+ * → web component, builtin → Vue), but mounted in a hidden host div
133
+ * with no slot / position / size. Use case: a custom app that wires
134
+ * cross-cutting glue — subscribes to WS topics, listens on the layout
135
+ * bus, dispatches `host.layout.updatePanel` / `expandPanel` /
136
+ * `navigate`. Display panels stay focused on rendering.
137
+ */
138
+ type HostCoordinatorDef = HostOverlayContent & {
139
+ props?: Record<string, unknown>;
106
140
  };
107
141
  /**
108
142
  * The root layout declaration stored in `AppConfig.hostConfig.layout`.
109
143
  * Shape mirrors `@wippy-fe/layout`'s `LayoutDeclaration` but replaces
110
144
  * `panels` with a tagged-union `HostPanelDef` map.
145
+ *
146
+ * **Status: Draft 1 (preview).** Shipped but not yet validated against
147
+ * a production consumer. Field names and validation rules may still
148
+ * change between minor releases. See `managed-layout.md`.
111
149
  */
112
150
  interface HostLayoutDeclaration {
113
151
  layouts: Record<string, PanelTree> & {
@@ -117,8 +155,27 @@ interface HostLayoutDeclaration {
117
155
  panels: Record<string, HostPanelDef>;
118
156
  floating?: Record<string, HostFloatingDef>;
119
157
  modals?: Record<string, HostModalDef>;
158
+ /**
159
+ * Headless coordinator apps. Mounted in a hidden host div, get the
160
+ * full proxy API, never appear in any layout slot. Validated with the
161
+ * same kind/builtin-id checks as panels.
162
+ */
163
+ coordinators?: Record<string, HostCoordinatorDef>;
120
164
  dragEnabled?: boolean;
121
165
  }
166
+ /**
167
+ * The envelope every subscriber receives. `sourcePanelId` is the
168
+ * publisher's panelId (null when published from outside any registered
169
+ * panel — e.g. a grand-child relay whose panel boundary fell off the
170
+ * map, or system events). `targetPanelId` is non-null only for
171
+ * `send(target, ...)` calls; `broadcast()` leaves it null.
172
+ */
173
+ interface BroadcastEnvelope {
174
+ channel: string;
175
+ payload: unknown;
176
+ sourcePanelId: string | null;
177
+ targetPanelId: string | null;
178
+ }
122
179
 
123
180
  declare namespace PageApi {
124
181
  interface Page {
@@ -399,6 +456,19 @@ interface HostConfig {
399
456
  * Ignored by `iframe.html` / `chat-iframe.html` shells.
400
457
  */
401
458
  layout?: HostLayoutDeclaration;
459
+ /**
460
+ * Lazy WebSocket connection: defer the WS handshake until the first
461
+ * `useSubscription()` registers, and disconnect when the last
462
+ * subscriber unmounts. Saves a connection (and the matching server
463
+ * resource) for shells that don't actually consume push events at
464
+ * boot — chat-only iframes and panels that page through artifacts
465
+ * via REST.
466
+ *
467
+ * Apps that call `wsClient.sendMessage(...)` directly without
468
+ * subscribing first should NOT enable this — sendMessage will throw
469
+ * "WebSocket is not connected". Default is `false` (eager connect).
470
+ */
471
+ lazyWS?: boolean;
402
472
  }
403
473
  interface AppContext {
404
474
  resourceId: string;
@@ -920,6 +990,15 @@ interface LayoutSnapshot {
920
990
  activeBreakpoint?: string;
921
991
  dragEnabled?: boolean;
922
992
  }
993
+ /**
994
+ * Child-iframe handle on the host's managed-layout shell.
995
+ *
996
+ * **Status: Draft 1 (preview).** Shipped but not yet driven by a
997
+ * production consumer. Field names, defaults, and validation rules may
998
+ * still change between minor releases. Pin to an exact CDN version
999
+ * until this label is removed. See `managed-layout.md` for guidance,
1000
+ * worked examples, and the three-tier "where state lives" rule.
1001
+ */
923
1002
  interface LayoutApi {
924
1003
  /**
925
1004
  * Current layout snapshot — sync property getter, never waits. Returns
@@ -929,20 +1008,92 @@ interface LayoutApi {
929
1008
  * or subscribe reactively via `@wippy-fe/vue-host`'s `useWippyLayout`.
930
1009
  */
931
1010
  readonly snapshot: LayoutSnapshot | null;
932
- /** Resize a panel in the active breakpoint layout. */
933
- resizePanel: (panelId: string, size: string) => void;
1011
+ /**
1012
+ * Resize a panel in the active breakpoint layout. `size` follows the
1013
+ * GoldenLayout-style grammar — `'auto' | 'Nfr' | 'Npx' | 'N%'`.
1014
+ * Anything else is rejected at the host's `validateLayout` boundary
1015
+ * (silent no-op for unknown panelId; `LayoutValidationError` for bad
1016
+ * size).
1017
+ */
1018
+ resizePanel: (panelId: string, size: SizeValue) => void;
934
1019
  /** Collapse a panel (no-op if not `collapsible`). */
935
1020
  collapsePanel: (panelId: string) => void;
936
1021
  /** Expand a collapsed panel. */
937
1022
  expandPanel: (panelId: string) => void;
1023
+ /**
1024
+ * Open a panel's drawer overlay. Only meaningful when the panel's
1025
+ * active layout slot has `display: 'drawer-*'`. For inline slots,
1026
+ * this sets `panel.drawerOpen` but has no visible effect (the engine
1027
+ * ignores it on inline slots). The same panel can switch between
1028
+ * inline and drawer display across breakpoints — iframe state is
1029
+ * preserved across the transition.
1030
+ */
1031
+ openDrawer: (panelId: string) => void;
1032
+ /** Close a panel's drawer overlay. */
1033
+ closeDrawer: (panelId: string) => void;
1034
+ /** Flip a panel's drawer open state. */
1035
+ toggleDrawer: (panelId: string) => void;
938
1036
  /** Move a panel to a new position in the active layout. */
939
1037
  movePanel: (panelId: string, target: PanelTarget) => void;
940
1038
  /** Remove a panel from all breakpoint layouts + panels map. */
941
1039
  removePanel: (panelId: string) => void;
1040
+ /**
1041
+ * Patch an existing panel's def at runtime — swap content kind / id /
1042
+ * tagName, replace `route` / `title` / `icon`, or shallow-merge `props`.
1043
+ * Unknown panelId is a silent no-op. Same merge semantics as the
1044
+ * host-side `updatePanelLiveState`: `props` shallow-merges, other
1045
+ * top-level fields replace wholesale.
1046
+ */
1047
+ updatePanel: (panelId: string, def: Partial<HostPanelDef>) => void;
1048
+ /**
1049
+ * Open a modal at runtime. The author's tagged-union content shape
1050
+ * (`kind: 'page' | 'artifact' | 'component' | 'builtin'`) is mirrored
1051
+ * into the host declaration so the modal's component / props can be
1052
+ * resolved from the host side. Re-opening an already-open id is a
1053
+ * silent no-op (matches host-side `manager.openModal`'s thrown
1054
+ * `LayoutValidationError`, but downgraded for cross-boundary callers).
1055
+ *
1056
+ * Defaults to `<dialog showModal()>` rendering for top-layer stacking,
1057
+ * focus trap, and inert propagation. Pass `def.useNativeDialog: false`
1058
+ * to opt back into the legacy div-overlay path during migration.
1059
+ */
1060
+ openModal: (id: string, def: HostModalDef) => void;
942
1061
  /** Close a currently-open modal by id. */
943
1062
  closeModal: (modalId: string) => void;
1063
+ /** Add a floating panel at runtime. Existing id is overwritten. */
1064
+ addFloating: (id: string, def: HostFloatingDef) => void;
944
1065
  /** Remove a floating panel by id. */
945
1066
  removeFloating: (floatingId: string) => void;
1067
+ /**
1068
+ * Publish on the in-tab layout bus to every OTHER subscribed iframe
1069
+ * panel and to host-mounted subscribers (components, services). The
1070
+ * sender's own window is excluded from the iframe fan-out (the host
1071
+ * receiver skips `w === source`); host-mounted handlers attached to
1072
+ * the same panel still fire via the in-process LocalBus mirror.
1073
+ * Subscribe via `host.layout.on(channel, handler)`.
1074
+ */
1075
+ broadcast: (channel: string, payload: unknown) => void;
1076
+ /**
1077
+ * Send to a specific panel only (1:1). Unknown target panelIds are
1078
+ * silent no-ops on the iframe fan-out (matches `updatePanel`).
1079
+ * `target = self` IS delivered: the receiver routes by `panelId →
1080
+ * windows` without a source-equality check, so addressing your own
1081
+ * panel loops the message back through `host.layout.on(...)`. Use
1082
+ * this for the documented loop-through-coordinator pattern. Passing
1083
+ * a non-string `target` throws — use `broadcast()` for 1:N.
1084
+ */
1085
+ send: (target: string, channel: string, payload: unknown) => void;
1086
+ /**
1087
+ * Subscribe to a layout-bus channel. Returns an `off()` function. The
1088
+ * handler receives the full envelope including `sourcePanelId` (who
1089
+ * published, `null` if from host system) and `targetPanelId` (who was
1090
+ * addressed, `null` for 1:N broadcasts).
1091
+ *
1092
+ * Layout-bus channels are deliberately separate from WS topics — they
1093
+ * never cross to other browser tabs and are scoped to the host page's
1094
+ * lifetime.
1095
+ */
1096
+ on: (channel: string, handler: (env: BroadcastEnvelope) => void) => () => void;
946
1097
  }
947
1098
 
948
1099
  type KnownTopics = '@history' | '@visibility' | '@message' | '@state-error' | '@layout-change' | '@layout-breakpoint';
@@ -1148,10 +1299,6 @@ interface ProxyApiInstance {
1148
1299
  loadWebComponent: (componentId: string, tagName?: string) => Promise<void>;
1149
1300
  }
1150
1301
 
1151
- declare const GLOBAL_CONFIG_VAR: "__WIPPY_APP_CONFIG__";
1152
- declare const GLOBAL_PROXY_CONFIG_VAR: "__WIPPY_PROXY_CONFIG__";
1153
- declare const GLOBAL_API_PROVIDER: "__WIPPY_APP_API__";
1154
- declare const GLOBAL_WEB_COMPONENT_CACHE: "__WIPPY_WEB_COMPONENT_CACHE__";
1155
1302
  declare global {
1156
1303
  interface Window {
1157
1304
  [GLOBAL_CONFIG_VAR]: AppConfig | ChildAppConfig;
@@ -1220,3 +1367,31 @@ declare global {
1220
1367
  [GLOBAL_PROXY_CONFIG_VAR]?: ProxyConfig;
1221
1368
  }
1222
1369
  }
1370
+
1371
+ // Augment axios's request config so consumers can opt out of the proxy
1372
+ // api's default auth handling on a per-request basis. The proxy's createApi
1373
+ // reads `skipDefaultAuth` in both the request and response interceptors;
1374
+ // see `gen-2-chat:src/proxy/shared/api.ts` for the runtime semantics.
1375
+ declare module 'axios' {
1376
+ interface AxiosRequestConfig {
1377
+ /**
1378
+ * Skip the proxy api's default auth handling for THIS request.
1379
+ *
1380
+ * When `true`:
1381
+ * - the request interceptor will NOT attach `Authorization: Bearer <token>`
1382
+ * - the response interceptor will NOT call `host.handleError('auth-expired')` on 401
1383
+ *
1384
+ * Use for:
1385
+ * - calls to a backend that uses a different auth domain
1386
+ * - calls that legitimately probe an unauthenticated endpoint
1387
+ * - calls where a 401 is meaningful but should not log the user out
1388
+ *
1389
+ * Cross-origin requests (URL with a different origin from the api's
1390
+ * `baseURL`) auto-skip the Wippy default regardless of this flag.
1391
+ */
1392
+ skipDefaultAuth?: boolean;
1393
+ }
1394
+ interface InternalAxiosRequestConfig {
1395
+ skipDefaultAuth?: boolean;
1396
+ }
1397
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wippy-fe/types-global-proxy",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Global type declarations for Wippy iframe proxy (window.getWippyApi, $W, etc.)",
5
5
  "license": "UNLICENSED",
6
6
  "types": "index.d.ts"