@wippy-fe/types-global-proxy 0.0.22 → 0.0.25

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 +264 -17
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -1,9 +1,125 @@
1
+ import { PanelTree, ModalSize, PanelTarget } from '@wippy-fe/layout';
1
2
  import { AxiosDefaults, AxiosInstance } from 'axios';
2
3
  import { ConfirmationOptions } from 'primevue/confirmationoptions';
3
4
  import { ToastMessageOptions } from 'primevue/toast';
4
5
  import * as nanoevents from 'nanoevents';
5
6
  import * as tailwindcss_types_config from 'tailwindcss/types/config';
6
7
 
8
+ /**
9
+ * Host-side layout types (Wippy-flavored wrapper around `@wippy-fe/layout`).
10
+ *
11
+ * The pure package speaks in `PanelDef = { component: Component, props? }` —
12
+ * bring-your-own Vue component. The host layer replaces that with a
13
+ * tagged-union where `kind` picks a content resolver:
14
+ *
15
+ * - `page` → renders a Wippy page (WPage double-buffer for `main: true`, single-instance otherwise)
16
+ * - `artifact` → renders a Wippy artifact (WPage with type='artifact')
17
+ * - `component` → renders a registered web component via `tagName`
18
+ * - `builtin` → renders host chrome (nav-sidebar / chat-wrapper / artifact-viewer / session-selector)
19
+ *
20
+ * The host resolver converts this into `@wippy-fe/layout`'s `PanelDef` at
21
+ * construction time and passes it into a `LayoutManager`.
22
+ */
23
+
24
+ interface HostPanelBase {
25
+ title?: string;
26
+ icon?: string;
27
+ props?: Record<string, unknown>;
28
+ }
29
+ interface HostPagePanelDef extends HostPanelBase {
30
+ kind: 'page';
31
+ id: string;
32
+ route?: string;
33
+ }
34
+ interface HostArtifactPanelDef extends HostPanelBase {
35
+ kind: 'artifact';
36
+ id: string;
37
+ }
38
+ interface HostComponentPanelDef extends HostPanelBase {
39
+ kind: 'component';
40
+ tagName: string;
41
+ }
42
+ type HostBuiltinId = 'nav-sidebar' | 'chat-wrapper' | 'artifact-viewer' | 'session-selector';
43
+ interface HostBuiltinPanelDef extends HostPanelBase {
44
+ kind: 'builtin';
45
+ id: HostBuiltinId;
46
+ }
47
+ type HostPanelDef = HostPagePanelDef | HostArtifactPanelDef | HostComponentPanelDef | HostBuiltinPanelDef;
48
+ /**
49
+ * Overlay content shape — what kind of thing to render. Mirrors
50
+ * HostPanelDef's discriminant exactly so the same resolver dispatch
51
+ * works for both inline panels and overlays. This makes floating
52
+ * panels and modals declarable in pure JSON config (no Vue component
53
+ * references in the declaration).
54
+ */
55
+ type HostOverlayContent = {
56
+ kind: 'page';
57
+ id: string;
58
+ route?: string;
59
+ } | {
60
+ kind: 'artifact';
61
+ id: string;
62
+ } | {
63
+ kind: 'component';
64
+ tagName: string;
65
+ } | {
66
+ kind: 'builtin';
67
+ id: HostBuiltinId;
68
+ };
69
+ interface HostOverlayBase {
70
+ title?: string;
71
+ icon?: string;
72
+ props?: Record<string, unknown>;
73
+ dismissable?: boolean;
74
+ }
75
+ /**
76
+ * Floating window def — absolute-positioned, draggable, resizable.
77
+ * Composition: content kind + window chrome properties.
78
+ */
79
+ type HostFloatingDef = HostOverlayContent & HostOverlayBase & {
80
+ position: {
81
+ x: number;
82
+ y: number;
83
+ };
84
+ size: {
85
+ width: number;
86
+ height: number;
87
+ };
88
+ minSize?: {
89
+ width: number;
90
+ height: number;
91
+ };
92
+ maxSize?: {
93
+ width: number;
94
+ height: number;
95
+ };
96
+ minimizable?: boolean;
97
+ maximizable?: boolean;
98
+ zIndex?: number;
99
+ };
100
+ /**
101
+ * Modal def — centered overlay. Size is either a single `ModalSize`
102
+ * or a breakpoint-keyed map (desktop centered / mobile fullscreen).
103
+ */
104
+ type HostModalDef = HostOverlayContent & HostOverlayBase & {
105
+ size?: ModalSize | Record<string, ModalSize>;
106
+ };
107
+ /**
108
+ * The root layout declaration stored in `AppConfig.hostConfig.layout`.
109
+ * Shape mirrors `@wippy-fe/layout`'s `LayoutDeclaration` but replaces
110
+ * `panels` with a tagged-union `HostPanelDef` map.
111
+ */
112
+ interface HostLayoutDeclaration {
113
+ layouts: Record<string, PanelTree> & {
114
+ default: PanelTree;
115
+ };
116
+ breakpoints?: Record<string, number>;
117
+ panels: Record<string, HostPanelDef>;
118
+ floating?: Record<string, HostFloatingDef>;
119
+ modals?: Record<string, HostModalDef>;
120
+ dragEnabled?: boolean;
121
+ }
122
+
7
123
  declare namespace PageApi {
8
124
  interface Page {
9
125
  icon: string;
@@ -25,12 +141,23 @@ declare namespace PageApi {
25
141
  content_type?: 'text/html' | 'text/markdown' | 'application/json';
26
142
  /** Per-page config overrides — merged into AppConfig before CSS injection. Populated from registry entry config_overrides. */
27
143
  configOverrides?: AppConfigOverrides;
144
+ /**
145
+ * Optional Vue-Router-4 path that claims a top-level URL for this page.
146
+ * v1 canonical form: `/<literal>/:part(.*)*` (e.g. `/keeper/:part(.*)*`, `/:part(.*)*`).
147
+ * When set, the FE registers a dynamic route that renders this page at the claimed URL.
148
+ */
149
+ mountRoute?: string;
28
150
  }
29
151
  interface PagesResponse {
30
152
  count: number;
31
153
  pages: Page[];
32
154
  success: boolean;
33
155
  }
156
+ interface PagesRoutesResponse {
157
+ count: number;
158
+ routes: Record<string, string>;
159
+ success: boolean;
160
+ }
34
161
  interface PageContentResponse {
35
162
  content: string;
36
163
  success: boolean;
@@ -77,6 +204,7 @@ interface ApiRoutes {
77
204
  };
78
205
  pages: {
79
206
  list: string;
207
+ routes: string;
80
208
  get: string;
81
209
  content: string;
82
210
  baseUrl: string;
@@ -257,7 +385,6 @@ interface HostConfig {
257
385
  allowHtml: boolean;
258
386
  };
259
387
  };
260
- apiRoutes?: ApiRoutesOverride;
261
388
  stateCache?: {
262
389
  maxPages?: number;
263
390
  maxSizePerPage?: number;
@@ -267,6 +394,11 @@ interface HostConfig {
267
394
  type: 'non-persistent' | 'cookie';
268
395
  };
269
396
  history?: 'browser' | 'hash';
397
+ /**
398
+ * Declarative multi-panel layout for the `managed-layout.html` entry point.
399
+ * Ignored by `iframe.html` / `chat-iframe.html` shells.
400
+ */
401
+ layout?: HostLayoutDeclaration;
270
402
  }
271
403
  interface AppContext {
272
404
  resourceId: string;
@@ -274,8 +406,20 @@ interface AppContext {
274
406
  route?: string;
275
407
  parentResourceId?: string;
276
408
  nestingDepth?: number;
409
+ /** This iframe is the navigation owner of its parent level. */
410
+ isNavOwner?: boolean;
277
411
  layoutPanelId?: string;
278
412
  layoutId?: string;
413
+ /**
414
+ * Initial layout snapshot baked into the child payload by the
415
+ * managed-layout host. Child proxies seed `host.layout.snapshot` from
416
+ * this at boot — so `host.layout.snapshot` is NEVER null inside a
417
+ * managed-layout host, and consumers never have to wait for a
418
+ * round-trip. `undefined` outside a managed-layout host.
419
+ *
420
+ * Updates arrive asynchronously via the `@layout-change` proxy topic.
421
+ */
422
+ layout?: unknown;
279
423
  extensions?: Record<string, unknown>;
280
424
  }
281
425
  interface AppEnv {
@@ -289,6 +433,7 @@ interface AppConfig {
289
433
  env: AppEnv;
290
434
  axiosDefaults?: Partial<AxiosDefaults>;
291
435
  routePrefix?: string;
436
+ apiRoutes?: ApiRoutesOverride;
292
437
  theming: {
293
438
  global?: ThemingScope;
294
439
  host?: HostThemingScope;
@@ -297,17 +442,19 @@ interface AppConfig {
297
442
  hostConfig: HostConfig;
298
443
  context: AppContext;
299
444
  }
300
- interface ChildAppConfig {
301
- $schema: string;
302
- auth: AppAuthConfig;
303
- env: AppEnv;
304
- axiosDefaults?: Partial<AxiosDefaults>;
305
- routePrefix?: string;
306
- apiRoutes?: ApiRoutesOverride;
307
- customization: AppCustomization;
308
- context: AppContext;
309
- configOverrides?: AppConfigOverrides;
310
- }
445
+ type ChildAppConfig = Omit<AppConfig, 'hostConfig'> & {
446
+ /**
447
+ * This iframe's own pageId. Used by the link classifier to exclude
448
+ * self from mount route matching (prevents self-match on root mounts).
449
+ */
450
+ selfPageId?: string;
451
+ /**
452
+ * Map of mountRoute pattern → pageId for host-level routes claimed by view pages.
453
+ * Used by child iframes' link classifier to detect host-nav links and relay them
454
+ * via postMessage instead of triggering in-child navigation.
455
+ */
456
+ mountRoutes?: Record<string, string>;
457
+ };
311
458
  interface AppConfigOverrides {
312
459
  customization?: Partial<AppCustomization>;
313
460
  axiosDefaults?: Partial<AxiosDefaults>;
@@ -324,7 +471,7 @@ interface ProxyConfig {
324
471
  primevue: boolean;
325
472
  markdown: boolean;
326
473
  customCss: boolean;
327
- customVariabled: boolean;
474
+ customVariables: boolean;
328
475
  };
329
476
  tailwindConfig: boolean;
330
477
  resizeObserver: boolean;
@@ -754,11 +901,56 @@ interface OtherCommand {
754
901
  }
755
902
  type WsCommand = SessionOpenCommand | SessionCloseCommand | SessionMessageCommand | SessionCommandCommand | ExternalEventCommand;
756
903
 
757
- type KnownTopics = '@history' | '@visibility' | '@message' | '@state-error';
904
+ /**
905
+ * Read-only mirror of the current host `HostLayoutDeclaration`, minus
906
+ * Vue-component references (those can't cross the postMessage boundary).
907
+ * Child iframes use this to reason about the tree — e.g. which panels
908
+ * exist, what their current sizes/collapsed state / routes are — without
909
+ * being coupled to the host's component registry.
910
+ *
911
+ * `null` outside a managed-layout host (compat mode, `iframe.html`, or
912
+ * any standalone/headless entry point).
913
+ */
914
+ interface LayoutSnapshot {
915
+ layouts: Record<string, unknown>;
916
+ panels: Record<string, unknown>;
917
+ breakpoints?: Record<string, number>;
918
+ floating?: Record<string, unknown>;
919
+ modals?: Record<string, unknown>;
920
+ activeBreakpoint?: string;
921
+ dragEnabled?: boolean;
922
+ }
923
+ interface LayoutApi {
924
+ /**
925
+ * Current layout snapshot — sync property getter, never waits. Returns
926
+ * `null` when the child is NOT inside a managed-layout host. Updates
927
+ * arrive via the `@layout-change` proxy topic; read the property
928
+ * directly inside an `@layout-change` handler to see the fresh value,
929
+ * or subscribe reactively via `@wippy-fe/vue-host`'s `useWippyLayout`.
930
+ */
931
+ readonly snapshot: LayoutSnapshot | null;
932
+ /** Resize a panel in the active breakpoint layout. */
933
+ resizePanel: (panelId: string, size: string) => void;
934
+ /** Collapse a panel (no-op if not `collapsible`). */
935
+ collapsePanel: (panelId: string) => void;
936
+ /** Expand a collapsed panel. */
937
+ expandPanel: (panelId: string) => void;
938
+ /** Move a panel to a new position in the active layout. */
939
+ movePanel: (panelId: string, target: PanelTarget) => void;
940
+ /** Remove a panel from all breakpoint layouts + panels map. */
941
+ removePanel: (panelId: string) => void;
942
+ /** Close a currently-open modal by id. */
943
+ closeModal: (modalId: string) => void;
944
+ /** Remove a floating panel by id. */
945
+ removeFloating: (floatingId: string) => void;
946
+ }
947
+
948
+ type KnownTopics = '@history' | '@visibility' | '@message' | '@state-error' | '@layout-change' | '@layout-breakpoint';
758
949
  type Events = {
759
950
  /** Emitted when pages are updated */
760
951
  '@history': (data: {
761
952
  path: string;
953
+ navId?: number;
762
954
  }) => void;
763
955
  '@visibility': (visible: boolean) => void;
764
956
  '@message': (data: WsMessage) => void;
@@ -766,11 +958,46 @@ type Events = {
766
958
  error: string;
767
959
  key?: string;
768
960
  }) => void;
961
+ '@layout-change': (snapshot: LayoutSnapshot) => void;
962
+ '@layout-breakpoint': (data: {
963
+ name: string;
964
+ width: number;
965
+ }) => void;
769
966
  } & {
770
967
  [K in string as K extends KnownTopics ? never : K]: (data: WsMessage) => void;
771
968
  };
772
969
  declare function createEvents(): <T extends string>(topicPattern: T, callback: T extends KnownTopics ? Events[T] : Events["@message"]) => nanoevents.Unsubscribe;
773
970
 
971
+ /**
972
+ * Link classifier — decides whether an href targets:
973
+ * - `host-nav` host-level route claimed by a view page or system route
974
+ * - `child-nav` internal route belonging to the subapp's own router
975
+ * - `external` different origin / mailto / tel / ftp / file / javascript
976
+ * - `ignore` empty href, pure hash
977
+ *
978
+ * Pure function, framework-agnostic. Used by:
979
+ * - `prevent-clicks.ts` fallback handler for raw <a> clicks
980
+ * - `ProxyApiInstance.host.classifyLink(href)` exposed to vanilla subapp code
981
+ * - `@wippy-fe/router` RouterLink wrapper transparent host-nav relay
982
+ *
983
+ * Matching strategy for host-nav:
984
+ * 1. Compare the path's first literal segment against known system routes
985
+ * (`/chat`, `/c`, `/web`, `/page`, `/keeper`, `/login`, `/logout`)
986
+ * 2. Compare against mountRoute top literal segments from ChildAppConfig.mountRoutes
987
+ * 3. Root-mount fallback — if a view page claimed `/:part(.*)*`, it catches
988
+ * everything not otherwise matched
989
+ */
990
+ type LinkKind = 'ignore' | 'external' | 'host-nav' | 'child-nav';
991
+ interface LinkClassification {
992
+ kind: LinkKind;
993
+ /** The original href the caller passed in (echoed for convenience) */
994
+ href: string;
995
+ /** Path after origin + routePrefix stripping, when applicable */
996
+ normalizedPath?: string;
997
+ /** For host-nav matched to a mountRoute, the page id of the target */
998
+ targetPageId?: string;
999
+ }
1000
+
774
1001
  declare const LogLevel: {
775
1002
  readonly Emergency: 0;
776
1003
  readonly Alert: 1;
@@ -876,7 +1103,7 @@ interface ProxyApiInstance {
876
1103
  target: 'modal' | 'sidebar';
877
1104
  }) => void;
878
1105
  navigate: (url: string) => void;
879
- onRouteChanged: (internalRoute: string) => void;
1106
+ onRouteChanged: (internalRoute: string, navId?: number) => void;
880
1107
  handleError: (code: ('auth-expired' | 'other'), error: Record<string, unknown>) => void;
881
1108
  setContext: (context: Record<string, unknown>, sessionUUID?: string, source?: {
882
1109
  type: 'page' | 'artifact';
@@ -884,6 +1111,18 @@ interface ProxyApiInstance {
884
1111
  instanceUUID?: string;
885
1112
  }) => void;
886
1113
  formatUrl: (relativeUrl: string) => string;
1114
+ /**
1115
+ * Classify a link href as `host-nav` / `child-nav` / `external` / `ignore`.
1116
+ * Uses mountRoutes and routePrefix from the child's ChildAppConfig plus baked-in
1117
+ * system route segments. Pure function — safe to call anywhere.
1118
+ */
1119
+ classifyLink: (href: string | null | undefined) => LinkClassification;
1120
+ /**
1121
+ * Declarative multi-panel layout control (managed-layout entry point only).
1122
+ * Calls from child iframes not embedded inside a `managed-layout.html`
1123
+ * host will be dropped silently by the parent.
1124
+ */
1125
+ layout: LayoutApi;
887
1126
  logout: () => void;
888
1127
  };
889
1128
  api: AxiosInstance;
@@ -892,6 +1131,16 @@ interface ProxyApiInstance {
892
1131
  get: () => Promise<FormState>;
893
1132
  submit: (data: FormData | Record<string, unknown>) => Promise<FormResult>;
894
1133
  };
1134
+ /**
1135
+ * Subscribe to events. Returns an unsubscribe function that MUST be called
1136
+ * on component unmount to prevent subscription leaks.
1137
+ *
1138
+ * ```ts
1139
+ * const unsub = instance.on('session:*:message:*', (msg) => { ... })
1140
+ * // Later, on unmount:
1141
+ * unsub()
1142
+ * ```
1143
+ */
895
1144
  on: ReturnType<typeof createEvents>;
896
1145
  logger: LoggerApi;
897
1146
  state: StateApi;
@@ -901,7 +1150,6 @@ interface ProxyApiInstance {
901
1150
 
902
1151
  declare const GLOBAL_CONFIG_VAR: "__WIPPY_APP_CONFIG__";
903
1152
  declare const GLOBAL_PROXY_CONFIG_VAR: "__WIPPY_PROXY_CONFIG__";
904
- declare const GLOBAL_CONFIG_OVERRIDES_VAR: "__WIPPY_CONFIG_OVERRIDES__";
905
1153
  declare const GLOBAL_API_PROVIDER: "__WIPPY_APP_API__";
906
1154
  declare const GLOBAL_WEB_COMPONENT_CACHE: "__WIPPY_WEB_COMPONENT_CACHE__";
907
1155
  declare global {
@@ -909,7 +1157,6 @@ declare global {
909
1157
  [GLOBAL_CONFIG_VAR]: AppConfig | ChildAppConfig;
910
1158
  [GLOBAL_API_PROVIDER]: ProxyApiInstance;
911
1159
  [GLOBAL_PROXY_CONFIG_VAR]?: ProxyConfig;
912
- [GLOBAL_CONFIG_OVERRIDES_VAR]?: AppConfigOverrides;
913
1160
  [GLOBAL_WEB_COMPONENT_CACHE]: Record<string, {
914
1161
  usedAt: number;
915
1162
  data: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wippy-fe/types-global-proxy",
3
- "version": "0.0.22",
3
+ "version": "0.0.25",
4
4
  "description": "Global type declarations for Wippy iframe proxy (window.getWippyApi, $W, etc.)",
5
5
  "license": "UNLICENSED",
6
6
  "types": "index.d.ts"