@peers-app/peers-ui 0.27.3 → 0.27.4

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 (309) hide show
  1. package/dist/screens/network-viewer/network-viewer-ipc.d.ts +3 -1
  2. package/dist/screens/network-viewer/network-viewer-ipc.js +6 -0
  3. package/dist/screens/network-viewer/sync-recovery.js +103 -1
  4. package/dist/screens/variables/variable-details.js +2 -1
  5. package/dist/tabs-layout/network-status-indicator.js +26 -12
  6. package/dist/tabs-layout/use-network-status.d.ts +6 -1
  7. package/dist/tabs-layout/use-network-status.js +27 -4
  8. package/package.json +9 -3
  9. package/.claude/settings.local.json +0 -34
  10. package/.github/README.md +0 -52
  11. package/.github/workflows/delete-all-artifacts.yml +0 -49
  12. package/.github/workflows/publish.yml +0 -51
  13. package/babel.config.js +0 -7
  14. package/biome.json +0 -198
  15. package/dist/app-updates/app-updates-consumer.test.d.ts +0 -1
  16. package/dist/app-updates/app-updates-consumer.test.js +0 -56
  17. package/dist/app-updates/app-updates-settings.test.d.ts +0 -1
  18. package/dist/app-updates/app-updates-settings.test.js +0 -93
  19. package/dist/app-updates/remote-app-update-panel.test.d.ts +0 -1
  20. package/dist/app-updates/remote-app-update-panel.test.js +0 -165
  21. package/dist/components/access-level-field.test.d.ts +0 -1
  22. package/dist/components/access-level-field.test.js +0 -28
  23. package/dist/components/message-logs/tool-access-approval-card.test.d.ts +0 -1
  24. package/dist/components/message-logs/tool-access-approval-card.test.js +0 -102
  25. package/dist/components/responsive-section-nav.test.d.ts +0 -1
  26. package/dist/components/responsive-section-nav.test.js +0 -45
  27. package/dist/globals-hash.test.d.ts +0 -1
  28. package/dist/globals-hash.test.js +0 -16
  29. package/dist/hooks/use-observable-state.test.d.ts +0 -1
  30. package/dist/hooks/use-observable-state.test.js +0 -64
  31. package/dist/hooks/use-observable.test.d.ts +0 -1
  32. package/dist/hooks/use-observable.test.js +0 -191
  33. package/dist/hooks/use-rows.test.d.ts +0 -1
  34. package/dist/hooks/use-rows.test.js +0 -175
  35. package/dist/hooks/use-tool.test.d.ts +0 -1
  36. package/dist/hooks/use-tool.test.js +0 -190
  37. package/dist/host-shell/host-shell-consumer.test.d.ts +0 -1
  38. package/dist/host-shell/host-shell-consumer.test.js +0 -28
  39. package/dist/root-layout/root-layout-host.test.d.ts +0 -1
  40. package/dist/root-layout/root-layout-host.test.js +0 -86
  41. package/dist/screens/account/account-screen.test.d.ts +0 -1
  42. package/dist/screens/account/account-screen.test.js +0 -51
  43. package/dist/screens/assistants/assistant-config.test.d.ts +0 -1
  44. package/dist/screens/assistants/assistant-config.test.js +0 -57
  45. package/dist/screens/contacts/contact-list.test.d.ts +0 -1
  46. package/dist/screens/contacts/contact-list.test.js +0 -48
  47. package/dist/screens/device-pairing/device-pairing.test.d.ts +0 -1
  48. package/dist/screens/device-pairing/device-pairing.test.js +0 -119
  49. package/dist/screens/devices/devices-list.test.d.ts +0 -1
  50. package/dist/screens/devices/devices-list.test.js +0 -53
  51. package/dist/screens/groups/group-list.test.d.ts +0 -1
  52. package/dist/screens/groups/group-list.test.js +0 -38
  53. package/dist/screens/identity/identity-routes.test.d.ts +0 -1
  54. package/dist/screens/identity/identity-routes.test.js +0 -51
  55. package/dist/screens/identity/identity-screen.test.d.ts +0 -1
  56. package/dist/screens/identity/identity-screen.test.js +0 -103
  57. package/dist/screens/invites/accept-invite.test.d.ts +0 -1
  58. package/dist/screens/invites/accept-invite.test.js +0 -103
  59. package/dist/screens/invites/activity-view.test.d.ts +0 -1
  60. package/dist/screens/invites/activity-view.test.js +0 -108
  61. package/dist/screens/invites/invite-classify.test.d.ts +0 -1
  62. package/dist/screens/invites/invite-classify.test.js +0 -115
  63. package/dist/screens/network-viewer/network-viewer-ipc.test.d.ts +0 -1
  64. package/dist/screens/network-viewer/network-viewer-ipc.test.js +0 -61
  65. package/dist/screens/network-viewer/network-viewer.section.test.d.ts +0 -1
  66. package/dist/screens/network-viewer/network-viewer.section.test.js +0 -63
  67. package/dist/screens/network-viewer/sync-recovery.test.d.ts +0 -1
  68. package/dist/screens/network-viewer/sync-recovery.test.js +0 -104
  69. package/dist/screens/packages/package-helpers.test.d.ts +0 -1
  70. package/dist/screens/packages/package-helpers.test.js +0 -53
  71. package/dist/screens/packages/package-runtime-status.test.d.ts +0 -1
  72. package/dist/screens/packages/package-runtime-status.test.js +0 -50
  73. package/dist/screens/packages/packages-ipc.test.d.ts +0 -1
  74. package/dist/screens/packages/packages-ipc.test.js +0 -43
  75. package/dist/screens/settings/settings-page.test.d.ts +0 -1
  76. package/dist/screens/settings/settings-page.test.js +0 -19
  77. package/dist/screens/tools/tool-access-ipc.test.d.ts +0 -1
  78. package/dist/screens/tools/tool-access-ipc.test.js +0 -40
  79. package/dist/screens/tools/tool-catalog-ipc.test.d.ts +0 -1
  80. package/dist/screens/tools/tool-catalog-ipc.test.js +0 -52
  81. package/dist/tabs-layout/network-status-indicator.test.d.ts +0 -1
  82. package/dist/tabs-layout/network-status-indicator.test.js +0 -665
  83. package/dist/tabs-layout/tabs-state.test.d.ts +0 -1
  84. package/dist/tabs-layout/tabs-state.test.js +0 -110
  85. package/dist/tabs-layout/use-network-status.test.d.ts +0 -1
  86. package/dist/tabs-layout/use-network-status.test.js +0 -45
  87. package/dist/ui-router/ui-loader.test.d.ts +0 -1
  88. package/dist/ui-router/ui-loader.test.js +0 -91
  89. package/jest.config.js +0 -25
  90. package/release-guard.js +0 -10
  91. package/src/app-updates/app-update-controls.tsx +0 -73
  92. package/src/app-updates/app-updates-consumer.test.ts +0 -83
  93. package/src/app-updates/app-updates-consumer.ts +0 -121
  94. package/src/app-updates/app-updates-settings.test.tsx +0 -109
  95. package/src/app-updates/app-updates-settings.tsx +0 -136
  96. package/src/app-updates/remote-app-update-panel.test.tsx +0 -205
  97. package/src/app-updates/remote-app-update-panel.tsx +0 -210
  98. package/src/app-updates/use-app-update-status.ts +0 -16
  99. package/src/command-palette/command-palette-ui.tsx +0 -564
  100. package/src/command-palette/command-palette.ts +0 -242
  101. package/src/components/access-level-field.test.tsx +0 -32
  102. package/src/components/access-level-field.tsx +0 -68
  103. package/src/components/checkbox.tsx +0 -25
  104. package/src/components/group-switcher.tsx +0 -526
  105. package/src/components/input-date.tsx +0 -29
  106. package/src/components/input-number.tsx +0 -83
  107. package/src/components/input.tsx +0 -25
  108. package/src/components/inverse-lazy-list.tsx +0 -107
  109. package/src/components/io-schema-values.tsx +0 -103
  110. package/src/components/io-schema.tsx +0 -259
  111. package/src/components/lazy-list.tsx +0 -115
  112. package/src/components/list-screen.tsx +0 -126
  113. package/src/components/loading-indicator.tsx +0 -7
  114. package/src/components/markdown-editor/autolink-plugin.tsx +0 -29
  115. package/src/components/markdown-editor/editor-inline.tsx +0 -9
  116. package/src/components/markdown-editor/editor.tsx +0 -158
  117. package/src/components/markdown-editor/markdown-plugin.tsx +0 -202
  118. package/src/components/markdown-editor/mention-node.ts +0 -204
  119. package/src/components/markdown-editor/mentions-plugin.tsx +0 -354
  120. package/src/components/markdown-editor/move-line-plugin.tsx +0 -186
  121. package/src/components/markdown-editor/select-line-boundary-plugin.tsx +0 -95
  122. package/src/components/markdown-editor/theme.ts +0 -46
  123. package/src/components/markdown-editor/toolbar.tsx +0 -269
  124. package/src/components/markdown-with-mentions.tsx +0 -198
  125. package/src/components/message-logs/message-logs.tsx +0 -523
  126. package/src/components/message-logs/tool-access-approval-card.test.tsx +0 -127
  127. package/src/components/message-logs/tool-access-approval-card.tsx +0 -178
  128. package/src/components/messages/avatar.tsx +0 -171
  129. package/src/components/messages/channel-message-list.tsx +0 -189
  130. package/src/components/messages/channel-view.tsx +0 -92
  131. package/src/components/messages/message-compose.tsx +0 -192
  132. package/src/components/messages/message-display.tsx +0 -231
  133. package/src/components/messages/thread-message-list.tsx +0 -135
  134. package/src/components/qr-scanner.tsx +0 -180
  135. package/src/components/responsive-section-nav.test.tsx +0 -88
  136. package/src/components/responsive-section-nav.tsx +0 -92
  137. package/src/components/router.tsx +0 -175
  138. package/src/components/save-button.tsx +0 -134
  139. package/src/components/sortable-list.tsx +0 -130
  140. package/src/components/tabs.tsx +0 -76
  141. package/src/components/tooltip.tsx +0 -43
  142. package/src/components/trust-level-badge.tsx +0 -44
  143. package/src/components/trust-level-dropdown.tsx +0 -136
  144. package/src/components/typeahead.tsx +0 -357
  145. package/src/globals-hash.test.ts +0 -19
  146. package/src/globals.tsx +0 -226
  147. package/src/hooks/index.ts +0 -8
  148. package/src/hooks/use-host-contract.ts +0 -75
  149. package/src/hooks/use-observable-state.test.tsx +0 -101
  150. package/src/hooks/use-observable-state.ts +0 -29
  151. package/src/hooks/use-observable.test.tsx +0 -258
  152. package/src/hooks/use-observable.ts +0 -67
  153. package/src/hooks/use-on-screen.ts +0 -24
  154. package/src/hooks/use-promise.ts +0 -34
  155. package/src/hooks/use-rows.test.tsx +0 -196
  156. package/src/hooks/use-rows.ts +0 -120
  157. package/src/hooks/use-subscription.ts +0 -24
  158. package/src/hooks/use-tool.test.tsx +0 -225
  159. package/src/hooks/use-tool.ts +0 -116
  160. package/src/host-shell/host-shell-consumer.test.ts +0 -32
  161. package/src/host-shell/host-shell-consumer.ts +0 -53
  162. package/src/index.tsx +0 -42
  163. package/src/mention-configs.ts +0 -185
  164. package/src/operator-console/operator-console-state.ts +0 -119
  165. package/src/operator-console/operator-console.tsx +0 -233
  166. package/src/peers-services-registration.ts +0 -6
  167. package/src/root-layout/global-overlays.ts +0 -50
  168. package/src/root-layout/layout-picker.tsx +0 -47
  169. package/src/root-layout/layouts/full-screen-layout.tsx +0 -144
  170. package/src/root-layout/layouts/tabs-with-console-layout.tsx +0 -260
  171. package/src/root-layout/root-layout-host.test.tsx +0 -108
  172. package/src/root-layout/root-layout-host.tsx +0 -147
  173. package/src/root-layout/root-layout-registry.ts +0 -51
  174. package/src/root-layout/root-layout-state.ts +0 -55
  175. package/src/root-layout/root-layout.ts +0 -32
  176. package/src/screens/account/account-screen.test.tsx +0 -65
  177. package/src/screens/account/account-screen.tsx +0 -942
  178. package/src/screens/assistants/assistant-config.test.tsx +0 -54
  179. package/src/screens/assistants/assistant-config.tsx +0 -121
  180. package/src/screens/assistants/assistant-details.tsx +0 -89
  181. package/src/screens/assistants/assistant-info.tsx +0 -66
  182. package/src/screens/assistants/assistant-list.tsx +0 -145
  183. package/src/screens/assistants/assistant-tools.tsx +0 -82
  184. package/src/screens/console-logs/console-logs-list.tsx +0 -374
  185. package/src/screens/console-logs/log-display.tsx +0 -137
  186. package/src/screens/console-logs/log-filters.tsx +0 -64
  187. package/src/screens/console-logs/mobile-log-card.tsx +0 -161
  188. package/src/screens/console-logs/resizable-table-header.tsx +0 -110
  189. package/src/screens/contacts/contact-details.tsx +0 -123
  190. package/src/screens/contacts/contact-list.test.tsx +0 -59
  191. package/src/screens/contacts/contact-list.tsx +0 -286
  192. package/src/screens/contacts/index.ts +0 -2
  193. package/src/screens/data-explorer/data-explorer.tsx +0 -633
  194. package/src/screens/data-explorer/index.ts +0 -6
  195. package/src/screens/data-explorer/query-executor.tsx +0 -520
  196. package/src/screens/device-pairing/device-pairing.test.tsx +0 -143
  197. package/src/screens/device-pairing/device-pairing.tsx +0 -461
  198. package/src/screens/device-pairing/identity-ipc.ts +0 -25
  199. package/src/screens/device-pairing/index.ts +0 -2
  200. package/src/screens/device-pairing/use-device-pairing-state.ts +0 -15
  201. package/src/screens/devices/devices-list.test.tsx +0 -68
  202. package/src/screens/devices/devices-list.tsx +0 -365
  203. package/src/screens/devices/index.ts +0 -1
  204. package/src/screens/groups/group-details.tsx +0 -160
  205. package/src/screens/groups/group-invite-panel.tsx +0 -311
  206. package/src/screens/groups/group-list.test.tsx +0 -44
  207. package/src/screens/groups/group-list.tsx +0 -317
  208. package/src/screens/groups/group-members.tsx +0 -343
  209. package/src/screens/groups/index.ts +0 -3
  210. package/src/screens/identity/identity-routes.test.ts +0 -70
  211. package/src/screens/identity/identity-routes.ts +0 -301
  212. package/src/screens/identity/identity-screen.test.tsx +0 -138
  213. package/src/screens/identity/identity-screen.tsx +0 -282
  214. package/src/screens/identity/index.ts +0 -2
  215. package/src/screens/identity/invite-contact-panel.tsx +0 -45
  216. package/src/screens/identity/profile-invite.tsx +0 -93
  217. package/src/screens/invites/accept-invite.test.tsx +0 -115
  218. package/src/screens/invites/accept-invite.tsx +0 -318
  219. package/src/screens/invites/activity-view.test.tsx +0 -127
  220. package/src/screens/invites/activity-view.tsx +0 -162
  221. package/src/screens/invites/index.ts +0 -6
  222. package/src/screens/invites/invite-capture.ts +0 -104
  223. package/src/screens/invites/invite-classify.test.ts +0 -129
  224. package/src/screens/invites/invite-share.tsx +0 -104
  225. package/src/screens/invites/invites-ipc.ts +0 -25
  226. package/src/screens/invites/pending-invites-list.tsx +0 -256
  227. package/src/screens/network-viewer/connection-troubleshooter.tsx +0 -395
  228. package/src/screens/network-viewer/cpu-usage-graph.tsx +0 -294
  229. package/src/screens/network-viewer/device-details-modal.tsx +0 -339
  230. package/src/screens/network-viewer/group-details-modal.tsx +0 -421
  231. package/src/screens/network-viewer/index.ts +0 -8
  232. package/src/screens/network-viewer/network-viewer-ipc.test.ts +0 -72
  233. package/src/screens/network-viewer/network-viewer-ipc.ts +0 -39
  234. package/src/screens/network-viewer/network-viewer-section.ts +0 -12
  235. package/src/screens/network-viewer/network-viewer.section.test.tsx +0 -68
  236. package/src/screens/network-viewer/network-viewer.tsx +0 -708
  237. package/src/screens/network-viewer/remote-logs-panel.tsx +0 -190
  238. package/src/screens/network-viewer/sync-recovery.test.tsx +0 -114
  239. package/src/screens/network-viewer/sync-recovery.tsx +0 -461
  240. package/src/screens/network-viewer/usage-graph.tsx +0 -455
  241. package/src/screens/packages/local-folder-grants-panel.tsx +0 -290
  242. package/src/screens/packages/local-folders-ipc.ts +0 -28
  243. package/src/screens/packages/package-details.tsx +0 -166
  244. package/src/screens/packages/package-helpers.test.ts +0 -57
  245. package/src/screens/packages/package-helpers.ts +0 -137
  246. package/src/screens/packages/package-info.tsx +0 -354
  247. package/src/screens/packages/package-list.tsx +0 -519
  248. package/src/screens/packages/package-network-panel.tsx +0 -82
  249. package/src/screens/packages/package-new-local.tsx +0 -100
  250. package/src/screens/packages/package-runtime-status.test.tsx +0 -58
  251. package/src/screens/packages/package-runtime-status.tsx +0 -68
  252. package/src/screens/packages/package-versions.tsx +0 -298
  253. package/src/screens/packages/packages-ipc.test.ts +0 -47
  254. package/src/screens/packages/packages-ipc.ts +0 -125
  255. package/src/screens/peer-types/peer-type-details.tsx +0 -172
  256. package/src/screens/peer-types/peer-type-list.tsx +0 -64
  257. package/src/screens/search/global-search.tsx +0 -406
  258. package/src/screens/settings/color-mode-dropdown.tsx +0 -82
  259. package/src/screens/settings/settings-page.test.tsx +0 -24
  260. package/src/screens/settings/settings-page.tsx +0 -426
  261. package/src/screens/setup-user.tsx +0 -355
  262. package/src/screens/tools/tool-access-ipc.test.ts +0 -55
  263. package/src/screens/tools/tool-access-ipc.ts +0 -27
  264. package/src/screens/tools/tool-catalog-ipc.test.ts +0 -52
  265. package/src/screens/tools/tool-catalog-ipc.ts +0 -51
  266. package/src/screens/tools/tool-details.tsx +0 -52
  267. package/src/screens/tools/tool-info.tsx +0 -45
  268. package/src/screens/tools/tool-list.tsx +0 -106
  269. package/src/screens/tools/tool-schema.tsx +0 -44
  270. package/src/screens/tools/tool-test-details.tsx +0 -89
  271. package/src/screens/tools/tool-test-list.tsx +0 -73
  272. package/src/screens/variables/variable-details.tsx +0 -289
  273. package/src/screens/variables/variable-list.tsx +0 -110
  274. package/src/screens/welcome-modal.tsx +0 -294
  275. package/src/screens/workflows/workflow-details.tsx +0 -115
  276. package/src/screens/workflows/workflow-info.tsx +0 -22
  277. package/src/screens/workflows/workflow-instructions.tsx +0 -134
  278. package/src/screens/workflows/workflow-list.tsx +0 -117
  279. package/src/setupTests.ts +0 -38
  280. package/src/system-apps/assistants.app.ts +0 -7
  281. package/src/system-apps/console-logs.app.ts +0 -7
  282. package/src/system-apps/data-explorer.app.ts +0 -8
  283. package/src/system-apps/identity.app.ts +0 -9
  284. package/src/system-apps/index.ts +0 -77
  285. package/src/system-apps/mobile-settings.app.ts +0 -7
  286. package/src/system-apps/network-viewer.app.ts +0 -8
  287. package/src/system-apps/packages.app.ts +0 -7
  288. package/src/system-apps/search.app.ts +0 -8
  289. package/src/system-apps/settings.app.ts +0 -7
  290. package/src/system-apps/threads.app.ts +0 -7
  291. package/src/system-apps/tools.app.ts +0 -7
  292. package/src/system-apps/types.app.ts +0 -7
  293. package/src/system-apps/variables.app.ts +0 -7
  294. package/src/system-apps/workflows.app.ts +0 -7
  295. package/src/tabs-layout/network-status-indicator.test.tsx +0 -799
  296. package/src/tabs-layout/network-status-indicator.tsx +0 -756
  297. package/src/tabs-layout/tabs-layout.tsx +0 -857
  298. package/src/tabs-layout/tabs-state.test.ts +0 -152
  299. package/src/tabs-layout/tabs-state.ts +0 -587
  300. package/src/tabs-layout/use-network-status.test.tsx +0 -58
  301. package/src/tabs-layout/use-network-status.ts +0 -68
  302. package/src/ui-defaults/index.ts +0 -2
  303. package/src/ui-defaults/list-screen.tsx +0 -94
  304. package/src/ui-defaults/markdown-field.tsx +0 -87
  305. package/src/ui-router/routes-loader.ts +0 -193
  306. package/src/ui-router/ui-loader.test.tsx +0 -108
  307. package/src/ui-router/ui-loader.tsx +0 -606
  308. package/src/utils.ts +0 -95
  309. 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;