@peers-app/peers-ui 0.27.3 → 0.27.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.
Files changed (311) hide show
  1. package/dist/screens/network-viewer/group-details-modal.d.ts +4 -0
  2. package/dist/screens/network-viewer/group-details-modal.js +6 -46
  3. package/dist/screens/network-viewer/network-viewer-ipc.d.ts +3 -2
  4. package/dist/screens/network-viewer/network-viewer-ipc.js +6 -0
  5. package/dist/screens/network-viewer/sync-recovery.js +103 -1
  6. package/dist/screens/variables/variable-details.js +2 -1
  7. package/dist/tabs-layout/network-status-indicator.js +26 -12
  8. package/dist/tabs-layout/use-network-status.d.ts +6 -1
  9. package/dist/tabs-layout/use-network-status.js +27 -4
  10. package/package.json +9 -3
  11. package/.claude/settings.local.json +0 -34
  12. package/.github/README.md +0 -52
  13. package/.github/workflows/delete-all-artifacts.yml +0 -49
  14. package/.github/workflows/publish.yml +0 -51
  15. package/babel.config.js +0 -7
  16. package/biome.json +0 -198
  17. package/dist/app-updates/app-updates-consumer.test.d.ts +0 -1
  18. package/dist/app-updates/app-updates-consumer.test.js +0 -56
  19. package/dist/app-updates/app-updates-settings.test.d.ts +0 -1
  20. package/dist/app-updates/app-updates-settings.test.js +0 -93
  21. package/dist/app-updates/remote-app-update-panel.test.d.ts +0 -1
  22. package/dist/app-updates/remote-app-update-panel.test.js +0 -165
  23. package/dist/components/access-level-field.test.d.ts +0 -1
  24. package/dist/components/access-level-field.test.js +0 -28
  25. package/dist/components/message-logs/tool-access-approval-card.test.d.ts +0 -1
  26. package/dist/components/message-logs/tool-access-approval-card.test.js +0 -102
  27. package/dist/components/responsive-section-nav.test.d.ts +0 -1
  28. package/dist/components/responsive-section-nav.test.js +0 -45
  29. package/dist/globals-hash.test.d.ts +0 -1
  30. package/dist/globals-hash.test.js +0 -16
  31. package/dist/hooks/use-observable-state.test.d.ts +0 -1
  32. package/dist/hooks/use-observable-state.test.js +0 -64
  33. package/dist/hooks/use-observable.test.d.ts +0 -1
  34. package/dist/hooks/use-observable.test.js +0 -191
  35. package/dist/hooks/use-rows.test.d.ts +0 -1
  36. package/dist/hooks/use-rows.test.js +0 -175
  37. package/dist/hooks/use-tool.test.d.ts +0 -1
  38. package/dist/hooks/use-tool.test.js +0 -190
  39. package/dist/host-shell/host-shell-consumer.test.d.ts +0 -1
  40. package/dist/host-shell/host-shell-consumer.test.js +0 -28
  41. package/dist/root-layout/root-layout-host.test.d.ts +0 -1
  42. package/dist/root-layout/root-layout-host.test.js +0 -86
  43. package/dist/screens/account/account-screen.test.d.ts +0 -1
  44. package/dist/screens/account/account-screen.test.js +0 -51
  45. package/dist/screens/assistants/assistant-config.test.d.ts +0 -1
  46. package/dist/screens/assistants/assistant-config.test.js +0 -57
  47. package/dist/screens/contacts/contact-list.test.d.ts +0 -1
  48. package/dist/screens/contacts/contact-list.test.js +0 -48
  49. package/dist/screens/device-pairing/device-pairing.test.d.ts +0 -1
  50. package/dist/screens/device-pairing/device-pairing.test.js +0 -119
  51. package/dist/screens/devices/devices-list.test.d.ts +0 -1
  52. package/dist/screens/devices/devices-list.test.js +0 -53
  53. package/dist/screens/groups/group-list.test.d.ts +0 -1
  54. package/dist/screens/groups/group-list.test.js +0 -38
  55. package/dist/screens/identity/identity-routes.test.d.ts +0 -1
  56. package/dist/screens/identity/identity-routes.test.js +0 -51
  57. package/dist/screens/identity/identity-screen.test.d.ts +0 -1
  58. package/dist/screens/identity/identity-screen.test.js +0 -103
  59. package/dist/screens/invites/accept-invite.test.d.ts +0 -1
  60. package/dist/screens/invites/accept-invite.test.js +0 -103
  61. package/dist/screens/invites/activity-view.test.d.ts +0 -1
  62. package/dist/screens/invites/activity-view.test.js +0 -108
  63. package/dist/screens/invites/invite-classify.test.d.ts +0 -1
  64. package/dist/screens/invites/invite-classify.test.js +0 -115
  65. package/dist/screens/network-viewer/network-viewer-ipc.test.d.ts +0 -1
  66. package/dist/screens/network-viewer/network-viewer-ipc.test.js +0 -61
  67. package/dist/screens/network-viewer/network-viewer.section.test.d.ts +0 -1
  68. package/dist/screens/network-viewer/network-viewer.section.test.js +0 -63
  69. package/dist/screens/network-viewer/sync-recovery.test.d.ts +0 -1
  70. package/dist/screens/network-viewer/sync-recovery.test.js +0 -104
  71. package/dist/screens/packages/package-helpers.test.d.ts +0 -1
  72. package/dist/screens/packages/package-helpers.test.js +0 -53
  73. package/dist/screens/packages/package-runtime-status.test.d.ts +0 -1
  74. package/dist/screens/packages/package-runtime-status.test.js +0 -50
  75. package/dist/screens/packages/packages-ipc.test.d.ts +0 -1
  76. package/dist/screens/packages/packages-ipc.test.js +0 -43
  77. package/dist/screens/settings/settings-page.test.d.ts +0 -1
  78. package/dist/screens/settings/settings-page.test.js +0 -19
  79. package/dist/screens/tools/tool-access-ipc.test.d.ts +0 -1
  80. package/dist/screens/tools/tool-access-ipc.test.js +0 -40
  81. package/dist/screens/tools/tool-catalog-ipc.test.d.ts +0 -1
  82. package/dist/screens/tools/tool-catalog-ipc.test.js +0 -52
  83. package/dist/tabs-layout/network-status-indicator.test.d.ts +0 -1
  84. package/dist/tabs-layout/network-status-indicator.test.js +0 -665
  85. package/dist/tabs-layout/tabs-state.test.d.ts +0 -1
  86. package/dist/tabs-layout/tabs-state.test.js +0 -110
  87. package/dist/tabs-layout/use-network-status.test.d.ts +0 -1
  88. package/dist/tabs-layout/use-network-status.test.js +0 -45
  89. package/dist/ui-router/ui-loader.test.d.ts +0 -1
  90. package/dist/ui-router/ui-loader.test.js +0 -91
  91. package/jest.config.js +0 -25
  92. package/release-guard.js +0 -10
  93. package/src/app-updates/app-update-controls.tsx +0 -73
  94. package/src/app-updates/app-updates-consumer.test.ts +0 -83
  95. package/src/app-updates/app-updates-consumer.ts +0 -121
  96. package/src/app-updates/app-updates-settings.test.tsx +0 -109
  97. package/src/app-updates/app-updates-settings.tsx +0 -136
  98. package/src/app-updates/remote-app-update-panel.test.tsx +0 -205
  99. package/src/app-updates/remote-app-update-panel.tsx +0 -210
  100. package/src/app-updates/use-app-update-status.ts +0 -16
  101. package/src/command-palette/command-palette-ui.tsx +0 -564
  102. package/src/command-palette/command-palette.ts +0 -242
  103. package/src/components/access-level-field.test.tsx +0 -32
  104. package/src/components/access-level-field.tsx +0 -68
  105. package/src/components/checkbox.tsx +0 -25
  106. package/src/components/group-switcher.tsx +0 -526
  107. package/src/components/input-date.tsx +0 -29
  108. package/src/components/input-number.tsx +0 -83
  109. package/src/components/input.tsx +0 -25
  110. package/src/components/inverse-lazy-list.tsx +0 -107
  111. package/src/components/io-schema-values.tsx +0 -103
  112. package/src/components/io-schema.tsx +0 -259
  113. package/src/components/lazy-list.tsx +0 -115
  114. package/src/components/list-screen.tsx +0 -126
  115. package/src/components/loading-indicator.tsx +0 -7
  116. package/src/components/markdown-editor/autolink-plugin.tsx +0 -29
  117. package/src/components/markdown-editor/editor-inline.tsx +0 -9
  118. package/src/components/markdown-editor/editor.tsx +0 -158
  119. package/src/components/markdown-editor/markdown-plugin.tsx +0 -202
  120. package/src/components/markdown-editor/mention-node.ts +0 -204
  121. package/src/components/markdown-editor/mentions-plugin.tsx +0 -354
  122. package/src/components/markdown-editor/move-line-plugin.tsx +0 -186
  123. package/src/components/markdown-editor/select-line-boundary-plugin.tsx +0 -95
  124. package/src/components/markdown-editor/theme.ts +0 -46
  125. package/src/components/markdown-editor/toolbar.tsx +0 -269
  126. package/src/components/markdown-with-mentions.tsx +0 -198
  127. package/src/components/message-logs/message-logs.tsx +0 -523
  128. package/src/components/message-logs/tool-access-approval-card.test.tsx +0 -127
  129. package/src/components/message-logs/tool-access-approval-card.tsx +0 -178
  130. package/src/components/messages/avatar.tsx +0 -171
  131. package/src/components/messages/channel-message-list.tsx +0 -189
  132. package/src/components/messages/channel-view.tsx +0 -92
  133. package/src/components/messages/message-compose.tsx +0 -192
  134. package/src/components/messages/message-display.tsx +0 -231
  135. package/src/components/messages/thread-message-list.tsx +0 -135
  136. package/src/components/qr-scanner.tsx +0 -180
  137. package/src/components/responsive-section-nav.test.tsx +0 -88
  138. package/src/components/responsive-section-nav.tsx +0 -92
  139. package/src/components/router.tsx +0 -175
  140. package/src/components/save-button.tsx +0 -134
  141. package/src/components/sortable-list.tsx +0 -130
  142. package/src/components/tabs.tsx +0 -76
  143. package/src/components/tooltip.tsx +0 -43
  144. package/src/components/trust-level-badge.tsx +0 -44
  145. package/src/components/trust-level-dropdown.tsx +0 -136
  146. package/src/components/typeahead.tsx +0 -357
  147. package/src/globals-hash.test.ts +0 -19
  148. package/src/globals.tsx +0 -226
  149. package/src/hooks/index.ts +0 -8
  150. package/src/hooks/use-host-contract.ts +0 -75
  151. package/src/hooks/use-observable-state.test.tsx +0 -101
  152. package/src/hooks/use-observable-state.ts +0 -29
  153. package/src/hooks/use-observable.test.tsx +0 -258
  154. package/src/hooks/use-observable.ts +0 -67
  155. package/src/hooks/use-on-screen.ts +0 -24
  156. package/src/hooks/use-promise.ts +0 -34
  157. package/src/hooks/use-rows.test.tsx +0 -196
  158. package/src/hooks/use-rows.ts +0 -120
  159. package/src/hooks/use-subscription.ts +0 -24
  160. package/src/hooks/use-tool.test.tsx +0 -225
  161. package/src/hooks/use-tool.ts +0 -116
  162. package/src/host-shell/host-shell-consumer.test.ts +0 -32
  163. package/src/host-shell/host-shell-consumer.ts +0 -53
  164. package/src/index.tsx +0 -42
  165. package/src/mention-configs.ts +0 -185
  166. package/src/operator-console/operator-console-state.ts +0 -119
  167. package/src/operator-console/operator-console.tsx +0 -233
  168. package/src/peers-services-registration.ts +0 -6
  169. package/src/root-layout/global-overlays.ts +0 -50
  170. package/src/root-layout/layout-picker.tsx +0 -47
  171. package/src/root-layout/layouts/full-screen-layout.tsx +0 -144
  172. package/src/root-layout/layouts/tabs-with-console-layout.tsx +0 -260
  173. package/src/root-layout/root-layout-host.test.tsx +0 -108
  174. package/src/root-layout/root-layout-host.tsx +0 -147
  175. package/src/root-layout/root-layout-registry.ts +0 -51
  176. package/src/root-layout/root-layout-state.ts +0 -55
  177. package/src/root-layout/root-layout.ts +0 -32
  178. package/src/screens/account/account-screen.test.tsx +0 -65
  179. package/src/screens/account/account-screen.tsx +0 -942
  180. package/src/screens/assistants/assistant-config.test.tsx +0 -54
  181. package/src/screens/assistants/assistant-config.tsx +0 -121
  182. package/src/screens/assistants/assistant-details.tsx +0 -89
  183. package/src/screens/assistants/assistant-info.tsx +0 -66
  184. package/src/screens/assistants/assistant-list.tsx +0 -145
  185. package/src/screens/assistants/assistant-tools.tsx +0 -82
  186. package/src/screens/console-logs/console-logs-list.tsx +0 -374
  187. package/src/screens/console-logs/log-display.tsx +0 -137
  188. package/src/screens/console-logs/log-filters.tsx +0 -64
  189. package/src/screens/console-logs/mobile-log-card.tsx +0 -161
  190. package/src/screens/console-logs/resizable-table-header.tsx +0 -110
  191. package/src/screens/contacts/contact-details.tsx +0 -123
  192. package/src/screens/contacts/contact-list.test.tsx +0 -59
  193. package/src/screens/contacts/contact-list.tsx +0 -286
  194. package/src/screens/contacts/index.ts +0 -2
  195. package/src/screens/data-explorer/data-explorer.tsx +0 -633
  196. package/src/screens/data-explorer/index.ts +0 -6
  197. package/src/screens/data-explorer/query-executor.tsx +0 -520
  198. package/src/screens/device-pairing/device-pairing.test.tsx +0 -143
  199. package/src/screens/device-pairing/device-pairing.tsx +0 -461
  200. package/src/screens/device-pairing/identity-ipc.ts +0 -25
  201. package/src/screens/device-pairing/index.ts +0 -2
  202. package/src/screens/device-pairing/use-device-pairing-state.ts +0 -15
  203. package/src/screens/devices/devices-list.test.tsx +0 -68
  204. package/src/screens/devices/devices-list.tsx +0 -365
  205. package/src/screens/devices/index.ts +0 -1
  206. package/src/screens/groups/group-details.tsx +0 -160
  207. package/src/screens/groups/group-invite-panel.tsx +0 -311
  208. package/src/screens/groups/group-list.test.tsx +0 -44
  209. package/src/screens/groups/group-list.tsx +0 -317
  210. package/src/screens/groups/group-members.tsx +0 -343
  211. package/src/screens/groups/index.ts +0 -3
  212. package/src/screens/identity/identity-routes.test.ts +0 -70
  213. package/src/screens/identity/identity-routes.ts +0 -301
  214. package/src/screens/identity/identity-screen.test.tsx +0 -138
  215. package/src/screens/identity/identity-screen.tsx +0 -282
  216. package/src/screens/identity/index.ts +0 -2
  217. package/src/screens/identity/invite-contact-panel.tsx +0 -45
  218. package/src/screens/identity/profile-invite.tsx +0 -93
  219. package/src/screens/invites/accept-invite.test.tsx +0 -115
  220. package/src/screens/invites/accept-invite.tsx +0 -318
  221. package/src/screens/invites/activity-view.test.tsx +0 -127
  222. package/src/screens/invites/activity-view.tsx +0 -162
  223. package/src/screens/invites/index.ts +0 -6
  224. package/src/screens/invites/invite-capture.ts +0 -104
  225. package/src/screens/invites/invite-classify.test.ts +0 -129
  226. package/src/screens/invites/invite-share.tsx +0 -104
  227. package/src/screens/invites/invites-ipc.ts +0 -25
  228. package/src/screens/invites/pending-invites-list.tsx +0 -256
  229. package/src/screens/network-viewer/connection-troubleshooter.tsx +0 -395
  230. package/src/screens/network-viewer/cpu-usage-graph.tsx +0 -294
  231. package/src/screens/network-viewer/device-details-modal.tsx +0 -339
  232. package/src/screens/network-viewer/group-details-modal.tsx +0 -421
  233. package/src/screens/network-viewer/index.ts +0 -8
  234. package/src/screens/network-viewer/network-viewer-ipc.test.ts +0 -72
  235. package/src/screens/network-viewer/network-viewer-ipc.ts +0 -39
  236. package/src/screens/network-viewer/network-viewer-section.ts +0 -12
  237. package/src/screens/network-viewer/network-viewer.section.test.tsx +0 -68
  238. package/src/screens/network-viewer/network-viewer.tsx +0 -708
  239. package/src/screens/network-viewer/remote-logs-panel.tsx +0 -190
  240. package/src/screens/network-viewer/sync-recovery.test.tsx +0 -114
  241. package/src/screens/network-viewer/sync-recovery.tsx +0 -461
  242. package/src/screens/network-viewer/usage-graph.tsx +0 -455
  243. package/src/screens/packages/local-folder-grants-panel.tsx +0 -290
  244. package/src/screens/packages/local-folders-ipc.ts +0 -28
  245. package/src/screens/packages/package-details.tsx +0 -166
  246. package/src/screens/packages/package-helpers.test.ts +0 -57
  247. package/src/screens/packages/package-helpers.ts +0 -137
  248. package/src/screens/packages/package-info.tsx +0 -354
  249. package/src/screens/packages/package-list.tsx +0 -519
  250. package/src/screens/packages/package-network-panel.tsx +0 -82
  251. package/src/screens/packages/package-new-local.tsx +0 -100
  252. package/src/screens/packages/package-runtime-status.test.tsx +0 -58
  253. package/src/screens/packages/package-runtime-status.tsx +0 -68
  254. package/src/screens/packages/package-versions.tsx +0 -298
  255. package/src/screens/packages/packages-ipc.test.ts +0 -47
  256. package/src/screens/packages/packages-ipc.ts +0 -125
  257. package/src/screens/peer-types/peer-type-details.tsx +0 -172
  258. package/src/screens/peer-types/peer-type-list.tsx +0 -64
  259. package/src/screens/search/global-search.tsx +0 -406
  260. package/src/screens/settings/color-mode-dropdown.tsx +0 -82
  261. package/src/screens/settings/settings-page.test.tsx +0 -24
  262. package/src/screens/settings/settings-page.tsx +0 -426
  263. package/src/screens/setup-user.tsx +0 -355
  264. package/src/screens/tools/tool-access-ipc.test.ts +0 -55
  265. package/src/screens/tools/tool-access-ipc.ts +0 -27
  266. package/src/screens/tools/tool-catalog-ipc.test.ts +0 -52
  267. package/src/screens/tools/tool-catalog-ipc.ts +0 -51
  268. package/src/screens/tools/tool-details.tsx +0 -52
  269. package/src/screens/tools/tool-info.tsx +0 -45
  270. package/src/screens/tools/tool-list.tsx +0 -106
  271. package/src/screens/tools/tool-schema.tsx +0 -44
  272. package/src/screens/tools/tool-test-details.tsx +0 -89
  273. package/src/screens/tools/tool-test-list.tsx +0 -73
  274. package/src/screens/variables/variable-details.tsx +0 -289
  275. package/src/screens/variables/variable-list.tsx +0 -110
  276. package/src/screens/welcome-modal.tsx +0 -294
  277. package/src/screens/workflows/workflow-details.tsx +0 -115
  278. package/src/screens/workflows/workflow-info.tsx +0 -22
  279. package/src/screens/workflows/workflow-instructions.tsx +0 -134
  280. package/src/screens/workflows/workflow-list.tsx +0 -117
  281. package/src/setupTests.ts +0 -38
  282. package/src/system-apps/assistants.app.ts +0 -7
  283. package/src/system-apps/console-logs.app.ts +0 -7
  284. package/src/system-apps/data-explorer.app.ts +0 -8
  285. package/src/system-apps/identity.app.ts +0 -9
  286. package/src/system-apps/index.ts +0 -77
  287. package/src/system-apps/mobile-settings.app.ts +0 -7
  288. package/src/system-apps/network-viewer.app.ts +0 -8
  289. package/src/system-apps/packages.app.ts +0 -7
  290. package/src/system-apps/search.app.ts +0 -8
  291. package/src/system-apps/settings.app.ts +0 -7
  292. package/src/system-apps/threads.app.ts +0 -7
  293. package/src/system-apps/tools.app.ts +0 -7
  294. package/src/system-apps/types.app.ts +0 -7
  295. package/src/system-apps/variables.app.ts +0 -7
  296. package/src/system-apps/workflows.app.ts +0 -7
  297. package/src/tabs-layout/network-status-indicator.test.tsx +0 -799
  298. package/src/tabs-layout/network-status-indicator.tsx +0 -756
  299. package/src/tabs-layout/tabs-layout.tsx +0 -857
  300. package/src/tabs-layout/tabs-state.test.ts +0 -152
  301. package/src/tabs-layout/tabs-state.ts +0 -587
  302. package/src/tabs-layout/use-network-status.test.tsx +0 -58
  303. package/src/tabs-layout/use-network-status.ts +0 -68
  304. package/src/ui-defaults/index.ts +0 -2
  305. package/src/ui-defaults/list-screen.tsx +0 -94
  306. package/src/ui-defaults/markdown-field.tsx +0 -87
  307. package/src/ui-router/routes-loader.ts +0 -193
  308. package/src/ui-router/ui-loader.test.tsx +0 -108
  309. package/src/ui-router/ui-loader.tsx +0 -606
  310. package/src/utils.ts +0 -95
  311. package/tsconfig.json +0 -18
@@ -1,606 +0,0 @@
1
- import {
2
- debounceByArgs,
3
- getUserContext,
4
- type IPackage,
5
- type IPeersPackageUIs,
6
- type IPeersUI,
7
- type IPeersUIRoute,
8
- newid,
9
- Packages,
10
- PackageVersions,
11
- packagePrefsVar,
12
- rpcServerCalls,
13
- toJSON,
14
- type UIContext,
15
- zodAnyObject,
16
- } from "@peers-app/peers-sdk";
17
- import { orderBy } from "lodash";
18
- import React, { Component, useEffect } from "react";
19
- import { LoadingIndicator } from "../components/loading-indicator";
20
- import { mainContentPath, packageReloaded } from "../globals";
21
- import { useObservable } from "../hooks";
22
- import "../ui-defaults";
23
- import { allPackages } from "./routes-loader";
24
-
25
- const peersUIs: { [key: string]: IPeersUI } = {};
26
-
27
- interface ErrorBoundaryState {
28
- hasError: boolean;
29
- error: Error | null;
30
- errorInfo: React.ErrorInfo | null;
31
- }
32
-
33
- interface ErrorBoundaryProps {
34
- peersUIId?: string;
35
- packageName?: string;
36
- componentName?: string;
37
- children: React.ReactNode;
38
- }
39
-
40
- class UIErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
41
- constructor(props: ErrorBoundaryProps) {
42
- super(props);
43
- this.state = { hasError: false, error: null, errorInfo: null };
44
- }
45
-
46
- static getDerivedStateFromError(error: Error): ErrorBoundaryState {
47
- return { hasError: true, error, errorInfo: null };
48
- }
49
-
50
- componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
51
- console.error("UIErrorBoundary caught an error:", error, errorInfo);
52
- this.setState({
53
- error,
54
- errorInfo,
55
- });
56
- }
57
-
58
- render() {
59
- if (this.state.hasError) {
60
- const { peersUIId, packageName, componentName } = this.props;
61
- const { error, errorInfo } = this.state;
62
-
63
- return (
64
- <div
65
- style={{
66
- padding: "20px",
67
- border: "2px solid #ff6b6b",
68
- borderRadius: "8px",
69
- backgroundColor: "#fff5f5",
70
- color: "#721c24",
71
- fontFamily: "monospace",
72
- margin: "10px 0",
73
- }}
74
- >
75
- <h3 style={{ color: "#c53030", marginTop: 0 }}>UI Component Error</h3>
76
- <div style={{ marginBottom: "15px" }}>
77
- {peersUIId && (
78
- <div>
79
- <strong>Peers UI ID:</strong> {peersUIId}
80
- </div>
81
- )}
82
- {packageName && (
83
- <div>
84
- <strong>Package:</strong> {packageName}
85
- </div>
86
- )}
87
- {componentName && (
88
- <div>
89
- <strong>Component:</strong> {componentName}
90
- </div>
91
- )}
92
- </div>
93
-
94
- <details style={{ marginBottom: "15px" }}>
95
- <summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
96
- Error Details
97
- </summary>
98
- <div
99
- style={{
100
- backgroundColor: "#fed7d7",
101
- padding: "10px",
102
- borderRadius: "4px",
103
- whiteSpace: "pre-wrap",
104
- overflow: "auto",
105
- maxHeight: "200px",
106
- }}
107
- >
108
- <strong>Error:</strong> {error?.message || "Unknown error"}
109
- {error?.stack && (
110
- <>
111
- <br />
112
- <br />
113
- <strong>Stack Trace:</strong>
114
- <br />
115
- {error.stack}
116
- </>
117
- )}
118
- </div>
119
- </details>
120
-
121
- {errorInfo && (
122
- <details>
123
- <summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
124
- Component Stack
125
- </summary>
126
- <div
127
- style={{
128
- backgroundColor: "#fed7d7",
129
- padding: "10px",
130
- borderRadius: "4px",
131
- whiteSpace: "pre-wrap",
132
- overflow: "auto",
133
- maxHeight: "200px",
134
- }}
135
- >
136
- {errorInfo.componentStack}
137
- </div>
138
- </details>
139
- )}
140
-
141
- <button
142
- type="button"
143
- onClick={() => this.setState({ hasError: false, error: null, errorInfo: null })}
144
- style={{
145
- marginTop: "15px",
146
- padding: "8px 16px",
147
- backgroundColor: "#c53030",
148
- color: "white",
149
- border: "none",
150
- borderRadius: "4px",
151
- cursor: "pointer",
152
- }}
153
- >
154
- Try Again
155
- </button>
156
- </div>
157
- );
158
- }
159
-
160
- return this.props.children;
161
- }
162
- }
163
-
164
- interface IProps extends UIContext {
165
- props: Record<string, unknown>;
166
- }
167
-
168
- /**
169
- * Pick a registered route for the current screen context and render its component.
170
- *
171
- * @param props - Screen context, including the route props to validate.
172
- */
173
- export const UIRouter = (props: IProps) => {
174
- let matchingRoute: IPeersUIRoute | undefined;
175
- const allRoutes = _window.getPeersUIRoutes() as IPeersUIRoute[];
176
- const filteredRoutes = allRoutes.filter((r) => {
177
- if (
178
- props.uiEditMode &&
179
- props.uiEditMode !== "*" &&
180
- r.uiEditMode !== "*" &&
181
- r.uiEditMode !== props.uiEditMode
182
- )
183
- return false;
184
- if (
185
- props.uiCategory &&
186
- props.uiCategory !== "*" &&
187
- r.uiCategory !== "*" &&
188
- r.uiCategory !== props.uiCategory
189
- )
190
- return false;
191
- if (
192
- props.uiSubcategory &&
193
- props.uiSubcategory !== "*" &&
194
- r.uiSubcategory !== "*" &&
195
- r.uiSubcategory !== props.uiSubcategory
196
- )
197
- return false;
198
- return true;
199
- });
200
-
201
- const context: UIContext & { path: string } = {
202
- ...props,
203
- path: props.path || mainContentPath(),
204
- };
205
- for (const route of filteredRoutes) {
206
- // if (route.path && !context.path.startsWith(route.path)) continue;
207
-
208
- // <todo> test this
209
- if (route.path) {
210
- // since `isMatch` can already be used to match the path, this might be overkill
211
- // but if you just need a simple regex match this makes it nice instead of having to declare a whole function
212
- const match = route.path.match(/^\/(.+)\/([gimsuy]{0,6})$/);
213
- if (match) {
214
- const [, pattern, flags] = match;
215
- try {
216
- const regex = new RegExp(pattern, flags);
217
- if (!regex.test(context.path)) continue;
218
- } catch {
219
- // Invalid regex → treat as plain prefix
220
- if (!context.path.startsWith(route.path)) continue;
221
- }
222
- } else {
223
- // TODO treating path as a prefix is confusing.
224
- // Now that we have regex matching, we should treat it as exact match if it's not a regex
225
- if (!context.path.startsWith(route.path)) continue;
226
- }
227
- }
228
- // </todo>
229
-
230
- if (!route.propsSchema || route.propsSchema.safeParse(props.props).success) {
231
- if (!route.isMatch || route.isMatch(props.props, context)) {
232
- matchingRoute = route;
233
- break;
234
- }
235
- }
236
- }
237
-
238
- if (!matchingRoute) {
239
- return undefined;
240
- }
241
-
242
- return <UILoader peersUIId={matchingRoute.peersUIId} props={props.props} />;
243
- };
244
-
245
- const UILoader = (args: { peersUIId: string; props?: Record<string, unknown> }) => {
246
- if (!args.props) {
247
- args.props = {};
248
- }
249
- const { props, peersUIId } = args;
250
- const [lastReloadTime] = useObservable(packageReloaded);
251
- props.__lastPackageReload = lastReloadTime;
252
- // Keep the same loader ancestor after the bundle enters the cache. Replacing it
253
- // on a path change would unmount the screen before its navigation guard can run.
254
- return <UIAsyncLoader key={peersUIId} peersUIId={peersUIId} props={props} />;
255
- };
256
-
257
- const uiLoadingPromises: Record<string, Promise<void>> = {};
258
-
259
- async function resolveUiBundleFileId(pkg: IPackage): Promise<string | undefined> {
260
- let pvId = pkg.activePackageVersionId;
261
- try {
262
- const pvar = packagePrefsVar(pkg.packageId);
263
- await pvar.loadingPromise;
264
- pvId = pvar()?.activePackageVersionId ?? pvId;
265
- } catch {
266
- /* use group default */
267
- }
268
- if (!pvId) return undefined;
269
- try {
270
- const pv = await PackageVersions().get(pvId);
271
- return pv?.uiBundleFileId;
272
- } catch {
273
- return undefined;
274
- }
275
- }
276
-
277
- function loadUIBundle(pkg: IPackage, forceRefresh?: boolean) {
278
- let importPromise: Promise<void> = uiLoadingPromises[pkg.packageId];
279
- if (!importPromise || forceRefresh) {
280
- const sTime = Date.now();
281
- console.log(`loading ui bundle for ${pkg.name}`);
282
- importPromise = (async () => {
283
- const uiBundleFileId = await resolveUiBundleFileId(pkg);
284
- if (!uiBundleFileId) {
285
- return;
286
- }
287
-
288
- const bundleCode = await rpcServerCalls.getFileContents(uiBundleFileId);
289
- if (bundleCode) {
290
- const exportUIs = (peerUIs: IPeersPackageUIs) => {
291
- peerUIs?.uis?.forEach((ui) => {
292
- peersUIs[ui.peersUIId] = ui;
293
- });
294
- };
295
- const bundleFunction = new Function("exportUIs", bundleCode);
296
- await bundleFunction(exportUIs);
297
- }
298
- console.log(
299
- `finished loading ui bundle for ${pkg.name}: ${(Date.now() - sTime).toFixed(0)}ms, ${bundleCode ? (bundleCode.length / 1000).toFixed(0) : "0"} KB`,
300
- );
301
- })().catch((err: unknown) => {
302
- console.error(`Error while loading ui module for ${pkg.name}`, err);
303
- throw err;
304
- });
305
- uiLoadingPromises[pkg.packageId] = importPromise;
306
- }
307
- return importPromise;
308
- }
309
-
310
- const UIAsyncLoader = (props: { peersUIId: string; props: Record<string, unknown> }) => {
311
- const { peersUIId } = props;
312
- const peersUI = peersUIs[peersUIId];
313
- const [loaded, setLoaded] = React.useState(false);
314
- const [loadError, setLoadError] = React.useState<Error | null>(null);
315
-
316
- const allRoutes = _window.getPeersUIRoutes() as IPeersUIRoute[];
317
- const uiPackageId = allRoutes.find((r) => r.peersUIId === peersUIId)?.packageId;
318
-
319
- useObservable(allPackages);
320
- const pkg = allPackages().find((p) => p.packageId === uiPackageId);
321
-
322
- useEffect(() => {
323
- if (!pkg || peersUIs[peersUIId]?.content) return;
324
- const pkgRef = pkg;
325
- setLoadError(null);
326
- loadUIBundle(pkgRef)
327
- .then(() => setLoaded(true))
328
- .catch((error) => {
329
- console.error(`Failed to load UI bundle for package ${pkgRef.name}:`, error);
330
- setLoadError(error);
331
- });
332
- }, [peersUIId, pkg?.packageId, pkg?.name, pkg]);
333
-
334
- if (!peersUI?.content && !pkg) {
335
- return <div>Could not find package that owns peersUIId {peersUIId}</div>;
336
- }
337
-
338
- if (!peersUI?.content && loadError) {
339
- return (
340
- <div
341
- style={{
342
- padding: "20px",
343
- border: "2px solid #ff6b6b",
344
- borderRadius: "8px",
345
- backgroundColor: "#fff5f5",
346
- color: "#721c24",
347
- fontFamily: "monospace",
348
- margin: "10px 0",
349
- }}
350
- >
351
- <h3 style={{ color: "#c53030", marginTop: 0 }}>Bundle Loading Error</h3>
352
- <div style={{ marginBottom: "15px" }}>
353
- <div>
354
- <strong>Peers UI ID:</strong> {peersUIId}
355
- </div>
356
- <div>
357
- <strong>Package:</strong> {pkg?.name}
358
- </div>
359
- <div>
360
- <strong>Package ID:</strong> {pkg?.packageId}
361
- </div>
362
- </div>
363
-
364
- <details style={{ marginBottom: "15px" }}>
365
- <summary style={{ cursor: "pointer", fontWeight: "bold", marginBottom: "10px" }}>
366
- Error Details
367
- </summary>
368
- <div
369
- style={{
370
- backgroundColor: "#fed7d7",
371
- padding: "10px",
372
- borderRadius: "4px",
373
- whiteSpace: "pre-wrap",
374
- overflow: "auto",
375
- maxHeight: "200px",
376
- }}
377
- >
378
- <strong>Error:</strong> {loadError.message || "Unknown error"}
379
- {loadError.stack && (
380
- <>
381
- <br />
382
- <br />
383
- <strong>Stack Trace:</strong>
384
- <br />
385
- {loadError.stack}
386
- </>
387
- )}
388
- </div>
389
- </details>
390
-
391
- <button
392
- type="button"
393
- onClick={() => {
394
- setLoadError(null);
395
- setLoaded(false);
396
- if (pkg) {
397
- loadUIBundle(pkg, true)
398
- .then(() => setLoaded(true))
399
- .catch(setLoadError);
400
- }
401
- }}
402
- style={{
403
- marginTop: "15px",
404
- padding: "8px 16px",
405
- backgroundColor: "#c53030",
406
- color: "white",
407
- border: "none",
408
- borderRadius: "4px",
409
- cursor: "pointer",
410
- }}
411
- >
412
- Retry Loading
413
- </button>
414
- </div>
415
- );
416
- }
417
-
418
- if (!peersUI?.content && !loaded) {
419
- return <LoadingIndicator />;
420
- }
421
-
422
- if (peersUI?.content) {
423
- const _props = props.props;
424
- try {
425
- peersUI.propsSchema.parse(_props);
426
- const Component = peersUI.content as React.ComponentType<Record<string, unknown>>;
427
- return (
428
- <UIErrorBoundary
429
- peersUIId={peersUIId}
430
- packageName={pkg?.name}
431
- componentName={peersUI.content?.name}
432
- >
433
- <Component {..._props} />
434
- </UIErrorBoundary>
435
- );
436
- } catch (parseError) {
437
- return (
438
- <div
439
- style={{
440
- padding: "20px",
441
- border: "2px solid #ff6b6b",
442
- borderRadius: "8px",
443
- backgroundColor: "#fff5f5",
444
- color: "#721c24",
445
- fontFamily: "monospace",
446
- margin: "10px 0",
447
- }}
448
- >
449
- <h3 style={{ color: "#c53030", marginTop: 0 }}>Props Validation Error</h3>
450
- <div style={{ marginBottom: "15px" }}>
451
- <div>
452
- <strong>Peers UI ID:</strong> {peersUIId}
453
- </div>
454
- <div>
455
- <strong>Package:</strong> {pkg?.name}
456
- </div>
457
- <div>
458
- <strong>Component:</strong> {peersUI.content?.name}
459
- </div>
460
- </div>
461
-
462
- <div
463
- style={{
464
- backgroundColor: "#fed7d7",
465
- padding: "10px",
466
- borderRadius: "4px",
467
- whiteSpace: "pre-wrap",
468
- overflow: "auto",
469
- maxHeight: "200px",
470
- marginBottom: "15px",
471
- }}
472
- >
473
- <strong>Error:</strong> Props did not match schema
474
- <br />
475
- <strong>Validation Error:</strong> {JSON.stringify(parseError, null, 2)}
476
- <br />
477
- <br />
478
- <strong>Props:</strong> {JSON.stringify(toJSON(_props), null, 2)}
479
- </div>
480
- </div>
481
- );
482
- }
483
- } else {
484
- return <div>Component not found</div>;
485
- }
486
- };
487
-
488
- type PeersRuntimeWindow = Window & {
489
- registerPeersUIRoute: (route: IPeersUIRoute) => void;
490
- getPeersUIRoutes: () => IPeersUIRoute[];
491
- UIRouter: typeof UIRouter;
492
- UILoader: typeof UILoader;
493
- };
494
-
495
- let _window: PeersRuntimeWindow;
496
-
497
- if (typeof window !== "undefined") {
498
- _window = window as unknown as PeersRuntimeWindow;
499
- if (!_window.registerPeersUIRoute) {
500
- let uiRoutes: IPeersUIRoute[] = [];
501
- Object.defineProperty(window, "registerPeersUIRoute", {
502
- value: (route: IPeersUIRoute) => {
503
- uiRoutes = uiRoutes.filter((r) => !(r.peersUIId === route.peersUIId));
504
- uiRoutes.push(route);
505
- uiRoutes = orderBy(uiRoutes, (r) => r.priority ?? 0, "desc");
506
- },
507
- writable: false,
508
- configurable: false,
509
- });
510
- Object.defineProperty(window, "getPeersUIRoutes", {
511
- value: () => {
512
- return [...uiRoutes];
513
- },
514
- writable: false,
515
- configurable: false,
516
- });
517
- Object.defineProperty(window, "UIRouter", {
518
- value: UIRouter,
519
- writable: false,
520
- configurable: false,
521
- });
522
- Object.defineProperty(window, "UILoader", {
523
- value: UILoader,
524
- writable: false,
525
- configurable: false,
526
- });
527
- }
528
- }
529
-
530
- /** Package id used when peers-ui registers its own built-in screens. */
531
- export const peersSystemPackageId = "000peers0system000package";
532
-
533
- /**
534
- * This is meant to make it easy to register components that are internal to peers
535
- */
536
- export async function registerInternalPeersUI(props: {
537
- component: IPeersUI["content"];
538
- /** Zod schemas may use a different zod instance than peers-sdk (duplicate resolution); keep loose. */
539
- propsSchema?: any;
540
- routes?: Omit<IPeersUIRoute, "peersUIId" | "packageId">[];
541
- peersUIId?: string;
542
- }) {
543
- const routeWin = window as Window & { registerPeersUIRoute?: (route: IPeersUIRoute) => void };
544
- while (!routeWin.registerPeersUIRoute) {
545
- console.log("Waiting for registerPeersUIRoute to be defined on the window object");
546
- await new Promise((resolve) => setTimeout(resolve, 20));
547
- }
548
- const peersUIId = props.peersUIId || newid();
549
-
550
- const peersUI: IPeersUI = {
551
- peersUIId,
552
- content: props.component,
553
- propsSchema: props.propsSchema || zodAnyObject,
554
- };
555
- peersUIs[peersUIId] = peersUI;
556
-
557
- if (props.routes?.length) {
558
- props.routes.forEach((route) => {
559
- _window.registerPeersUIRoute({
560
- packageId: peersSystemPackageId,
561
- peersUIId,
562
- propsSchema: props.propsSchema,
563
- ...route,
564
- });
565
- });
566
- }
567
- }
568
-
569
- const reloadPackage = debounceByArgs(async (packageId: string) => {
570
- const pkg = await Packages().get(packageId);
571
- if (pkg) {
572
- await loadUIBundle(pkg, true);
573
- console.log(`reloaded UI bundle for ${pkg.name}`);
574
- packageReloaded(Date.now());
575
- }
576
- }, 200);
577
-
578
- const uiPrefsSubscribed = new Set<string>();
579
-
580
- function subscribeToPrefs(packageId: string) {
581
- if (uiPrefsSubscribed.has(packageId)) return;
582
- uiPrefsSubscribed.add(packageId);
583
- const pvar = packagePrefsVar(packageId);
584
- let lastPvId = pvar()?.activePackageVersionId;
585
- pvar.subscribe((prefs) => {
586
- const newPvId = prefs?.activePackageVersionId;
587
- if (newPvId && newPvId !== lastPvId) {
588
- lastPvId = newPvId;
589
- reloadPackage(packageId);
590
- }
591
- });
592
- }
593
-
594
- getUserContext().then((_userContext) => {
595
- for (const packageId of Object.keys(uiLoadingPromises)) {
596
- subscribeToPrefs(packageId);
597
- }
598
-
599
- Packages().dataChanged.subscribe(async (evt) => {
600
- const pkg = evt.dataObject;
601
- const loadingPromise = uiLoadingPromises[pkg.packageId];
602
- if (!loadingPromise) return;
603
- subscribeToPrefs(pkg.packageId);
604
- reloadPackage(pkg.packageId);
605
- });
606
- });
package/src/utils.ts DELETED
@@ -1,95 +0,0 @@
1
- import DOMPurify from "dompurify";
2
- import _ from "lodash";
3
-
4
- /** Plain text content of an HTML string (parsed with `DOMParser`, so browser-only). */
5
- export function htmlToText(html: string): string {
6
- const doc = new DOMParser().parseFromString(html, "text/html");
7
- return doc.body.textContent || "";
8
- }
9
-
10
- /** Replaces `<@type:name:id>` / `<$type:name:id>` mentions with the readable name, underscores as spaces. */
11
- export function stripMentions(text: string): string {
12
- // Replace <type:name:id> with just the readable name part
13
- // Convert underscores to spaces for better readability
14
- return text.replace(/<[@$]([^:]+):([^:]+):([^>]+)>/g, (_match, _type, name, _id) => {
15
- return name.replace(/_/g, " ");
16
- });
17
- }
18
-
19
- /** Sanitizes HTML with DOMPurify, collapses repeated blank paragraphs, and drops a trailing one. */
20
- export function trimAndSanitizeHtml(value: string) {
21
- let sanitizedValue: string = DOMPurify.sanitize(value);
22
- // removes empty paragraphs
23
- // return sanitizedValue.replace(/\<p\>\<br\>\<\/p\>/ig, '').trim()
24
-
25
- const singleBlankLine = "<p><br></p>";
26
- const doubleBlankLine = singleBlankLine + singleBlankLine;
27
-
28
- // collapse lots of blank lines into one
29
- while (sanitizedValue.includes(doubleBlankLine)) {
30
- sanitizedValue = sanitizedValue.replaceAll(doubleBlankLine, singleBlankLine);
31
- }
32
-
33
- // remove trailing blank line
34
- if (sanitizedValue.endsWith(singleBlankLine)) {
35
- sanitizedValue = sanitizedValue.substr(0, sanitizedValue.length - singleBlankLine.length);
36
- }
37
- return sanitizedValue;
38
- }
39
-
40
- // must be done this way so TypeScript doesn't rewrite async keyword
41
- // export const AsyncFunction = eval('Object.getPrototypeOf(async function () { }).constructor');
42
- /** The `AsyncFunction` constructor, for compiling async code from a string. */
43
- export const AsyncFunction = Object.getPrototypeOf(async () => {}).constructor;
44
-
45
- /**
46
- * Compiles and runs `jsCode` as the body of a strict async function. `utils`, `Promise`,
47
- * `console` and each key of `externalReferences` are in scope; `process` and `global` are hidden.
48
- * Runs arbitrary code: never pass it untrusted input.
49
- */
50
- export function jsAsync(jsCode: string, externalReferences: any = {}) {
51
- jsCode = String(jsCode).trim();
52
- const hideGlobals = [
53
- "process",
54
- "global", //,'setTimeout','setInterval','setImmediate','clearImmediate','clearInterval','clearTimeout'
55
- ];
56
- const utils = module.exports;
57
- const refNames = ["utils", "utils_1", "Promise", "console"];
58
- const refValues = [utils, utils, Promise, console];
59
- _.keys(externalReferences).forEach((key) => {
60
- refNames.push(key);
61
- refValues.push(externalReferences[key]);
62
- });
63
- const compiledJs = AsyncFunction.apply(null, [
64
- ...refNames,
65
- ...hideGlobals,
66
- `"use strict";\n${jsCode}`,
67
- ]);
68
- return compiledJs.apply(null, refValues);
69
- }
70
-
71
- // export type IObjectMatch<T> = {
72
- // [key in keyof T]?: RegExp | string | number | boolean
73
- // }
74
-
75
- // export function objectMatch<T>(value: T, match: IObjectMatch<T>): boolean {
76
- // for (const [k, _m] of Object.entries(match)) {
77
- // const m = _m as any;
78
- // if (m === undefined) continue; // NOTE we are not trying to match undefined values
79
- // // NOTE null will match null or undefined
80
- // if (m === null && (value[k] === null || value[k] === undefined)) {
81
- // return true
82
- // }
83
- // if (_.isRegExp(m)) {
84
- // if (!String(value[k]).match(m)) {
85
- // return false;
86
- // }
87
- // } else if (m != value[k]) {
88
- // return false;
89
- // }
90
- // }
91
- // return true;
92
- // }
93
-
94
- // @ts-expect-error
95
- if (typeof window !== "undefined") window.utils = module.exports;