@peers-app/peers-ui 0.25.16 → 0.25.18

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.
@@ -7,6 +7,7 @@ const input_1 = require("../../components/input");
7
7
  const markdown_with_mentions_1 = require("../../components/markdown-with-mentions");
8
8
  const tooltip_1 = require("../../components/tooltip");
9
9
  const hooks_1 = require("../../hooks");
10
+ const package_network_panel_1 = require("./package-network-panel");
10
11
  /** Info tab for the package details screen. */
11
12
  const PackageInfo = (props) => {
12
13
  const { pkg } = props;
@@ -116,6 +117,6 @@ const PackageInfo = (props) => {
116
117
  await (0, peers_sdk_1.updatePackagePrefs)(pkg.packageId, {
117
118
  followTags: val === "stable" ? "stable" : val,
118
119
  });
119
- }, children: [(0, jsx_runtime_1.jsx)("option", { value: "stable", children: "Stable" }), (0, jsx_runtime_1.jsx)("option", { value: "stable,beta", children: "Stable + Beta" })] })] })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-2", children: [(0, jsx_runtime_1.jsx)("hr", {}), (0, jsx_runtime_1.jsxs)("small", { children: ["Description:", (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { markdownContent: `This should be edited in the package's README.md. It will automatically update when you restart Peers or reload the package.` })] }), (0, jsx_runtime_1.jsx)(markdown_with_mentions_1.MarkdownWithMentions, { content: pkg.description || "" })] })] }));
120
+ }, children: [(0, jsx_runtime_1.jsx)("option", { value: "stable", children: "Stable" }), (0, jsx_runtime_1.jsx)("option", { value: "stable,beta", children: "Stable + Beta" })] })] })] }))] }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-2", children: [(0, jsx_runtime_1.jsx)("hr", {}), (0, jsx_runtime_1.jsxs)("small", { children: ["Description:", (0, jsx_runtime_1.jsx)(tooltip_1.Tooltip, { markdownContent: `This should be edited in the package's README.md. It will automatically update when you restart Peers or reload the package.` })] }), (0, jsx_runtime_1.jsx)(markdown_with_mentions_1.MarkdownWithMentions, { content: pkg.description || "" })] }), (0, jsx_runtime_1.jsx)(package_network_panel_1.PackageNetworkPanel, { packageId: pkg.packageId })] }));
120
121
  };
121
122
  exports.PackageInfo = PackageInfo;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Shows the host allowlist and credential refs declared by an isolated package.
3
+ *
4
+ * Secret values stay on the host. A host that does not provide System HTTP, such
5
+ * as the PWA, renders nothing.
6
+ */
7
+ export declare const PackageNetworkPanel: (props: {
8
+ packageId: string;
9
+ }) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PackageNetworkPanel = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const peers_sdk_1 = require("@peers-app/peers-sdk");
6
+ const react_1 = require("react");
7
+ /**
8
+ * Shows the host allowlist and credential refs declared by an isolated package.
9
+ *
10
+ * Secret values stay on the host. A host that does not provide System HTTP, such
11
+ * as the PWA, renders nothing.
12
+ */
13
+ const PackageNetworkPanel = (props) => {
14
+ const [policy, setPolicy] = (0, react_1.useState)();
15
+ (0, react_1.useEffect)(() => {
16
+ let cancelled = false;
17
+ let dispose = () => { };
18
+ (async () => {
19
+ try {
20
+ const userContext = await (0, peers_sdk_1.getUserContext)();
21
+ const dataContextId = userContext.currentlyActiveGroupId() || userContext.userId;
22
+ const transport = (0, peers_sdk_1.getHostContractTransport)() ?? (await (0, peers_sdk_1.waitForHostContractTransport)({ timeoutMs: 3_000 }));
23
+ const consumer = (0, peers_sdk_1.createContractConsumer)((0, peers_sdk_1.getHttpContractDefinition)(), transport, {
24
+ dataContextId,
25
+ });
26
+ dispose = () => consumer.dispose();
27
+ const next = await consumer.tools.describePolicy({ packageId: props.packageId });
28
+ if (!cancelled) {
29
+ setPolicy(next);
30
+ }
31
+ }
32
+ catch {
33
+ if (!cancelled) {
34
+ setPolicy(undefined);
35
+ }
36
+ }
37
+ })();
38
+ return () => {
39
+ cancelled = true;
40
+ dispose();
41
+ };
42
+ }, [props.packageId]);
43
+ if (!policy || (policy.allowedHosts.length === 0 && policy.credentials.length === 0)) {
44
+ return policy ? ((0, jsx_runtime_1.jsx)("div", { className: "mt-3", children: (0, jsx_runtime_1.jsx)("small", { className: "text-muted", children: "This package does not declare outbound network access." }) })) : null;
45
+ }
46
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "mt-3", children: [(0, jsx_runtime_1.jsx)("small", { children: "Network access" }), (0, jsx_runtime_1.jsx)("ul", { className: "mb-2", children: policy.allowedHosts.map((host) => ((0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("code", { children: host }) }, host))) }), policy.credentials.length > 0 && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("small", { children: "Credentials injected by the host" }), (0, jsx_runtime_1.jsx)("ul", { className: "mb-0", children: policy.credentials.map((credential) => ((0, jsx_runtime_1.jsxs)("li", { children: [(0, jsx_runtime_1.jsx)("code", { children: credential.ref }), " sets ", (0, jsx_runtime_1.jsx)("code", { children: credential.header }), " from", " ", (0, jsx_runtime_1.jsx)("code", { children: credential.secretVar }), " (", credential.scope, ")"] }, credential.ref))) })] }))] }));
47
+ };
48
+ exports.PackageNetworkPanel = PackageNetworkPanel;
@@ -3,7 +3,13 @@ import "../ui-defaults";
3
3
  interface IProps extends UIContext {
4
4
  props: Record<string, unknown>;
5
5
  }
6
+ /**
7
+ * Pick a registered route for the current screen context and render its component.
8
+ *
9
+ * @param props - Screen context, including the route props to validate.
10
+ */
6
11
  export declare const UIRouter: (props: IProps) => import("react/jsx-runtime").JSX.Element | undefined;
12
+ /** Package id used when peers-ui registers its own built-in screens. */
7
13
  export declare const peersSystemPackageId = "000peers0system000package";
8
14
  /**
9
15
  * This is meant to make it easy to register components that are internal to peers
@@ -99,6 +99,11 @@ class UIErrorBoundary extends react_1.Component {
99
99
  return this.props.children;
100
100
  }
101
101
  }
102
+ /**
103
+ * Pick a registered route for the current screen context and render its component.
104
+ *
105
+ * @param props - Screen context, including the route props to validate.
106
+ */
102
107
  const UIRouter = (props) => {
103
108
  let matchingRoute;
104
109
  const allRoutes = _window.getPeersUIRoutes();
@@ -166,9 +171,12 @@ const UIRouter = (props) => {
166
171
  };
167
172
  exports.UIRouter = UIRouter;
168
173
  const UILoader = (args) => {
174
+ if (!args.props) {
175
+ args.props = {};
176
+ }
169
177
  const { props, peersUIId } = args;
170
178
  const [lastReloadTime] = (0, hooks_1.useObservable)(globals_1.packageReloaded);
171
- args.props.__lastPackageReload = lastReloadTime;
179
+ props.__lastPackageReload = lastReloadTime;
172
180
  // check if peersUIId maps to an in-memory react component
173
181
  const peersUI = peersUIs[peersUIId];
174
182
  if (peersUI?.content) {
@@ -184,7 +192,7 @@ const UILoader = (args) => {
184
192
  const Component = peersUI.content;
185
193
  return ((0, jsx_runtime_1.jsx)(UIErrorBoundary, { peersUIId: peersUIId, componentName: peersUI.content?.name, children: (0, jsx_runtime_1.jsx)(Component, { ...args.props }) }));
186
194
  }
187
- return (0, jsx_runtime_1.jsx)(UIAsyncLoader, { ...args });
195
+ return (0, jsx_runtime_1.jsx)(UIAsyncLoader, { peersUIId: peersUIId, props: props });
188
196
  };
189
197
  const uiLoadingPromises = {};
190
198
  // Check if we're running in a React Native WebView (has injectUIBundle available)
@@ -388,6 +396,7 @@ if (typeof window !== "undefined") {
388
396
  });
389
397
  }
390
398
  }
399
+ /** Package id used when peers-ui registers its own built-in screens. */
391
400
  exports.peersSystemPackageId = "000peers0system000package";
392
401
  /**
393
402
  * This is meant to make it easy to register components that are internal to peers
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peers-app/peers-ui",
3
- "version": "0.25.16",
3
+ "version": "0.25.18",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/peers-app/peers-ui.git"
@@ -30,7 +30,7 @@
30
30
  "lint:fix": "biome check --write ."
31
31
  },
32
32
  "peerDependencies": {
33
- "@peers-app/peers-sdk": "^0.25.16",
33
+ "@peers-app/peers-sdk": "^0.25.18",
34
34
  "bootstrap": "^5.3.3",
35
35
  "react": "^18.0.0",
36
36
  "react-dom": "^18.0.0"
@@ -41,7 +41,7 @@
41
41
  "@babel/preset-react": "^7.24.1",
42
42
  "@babel/preset-typescript": "^7.27.1",
43
43
  "@biomejs/biome": "2.3.11",
44
- "@peers-app/peers-sdk": "0.25.16",
44
+ "@peers-app/peers-sdk": "0.25.18",
45
45
  "@testing-library/dom": "^10.4.0",
46
46
  "@testing-library/jest-dom": "^6.6.3",
47
47
  "@testing-library/react": "^16.3.0",
@@ -17,6 +17,7 @@ import { Input } from "../../components/input";
17
17
  import { MarkdownWithMentions } from "../../components/markdown-with-mentions";
18
18
  import { Tooltip } from "../../components/tooltip";
19
19
  import { useObservable, usePromise } from "../../hooks";
20
+ import { PackageNetworkPanel } from "./package-network-panel";
20
21
 
21
22
  /** Info tab for the package details screen. */
22
23
  export const PackageInfo = (props: { pkg: IDoc<IPackage> }) => {
@@ -347,6 +348,7 @@ export const PackageInfo = (props: { pkg: IDoc<IPackage> }) => {
347
348
  </small>
348
349
  <MarkdownWithMentions content={pkg.description || ""} />
349
350
  </div>
351
+ <PackageNetworkPanel packageId={pkg.packageId} />
350
352
  </div>
351
353
  );
352
354
  };
@@ -0,0 +1,82 @@
1
+ import {
2
+ createContractConsumer,
3
+ getHostContractTransport,
4
+ getHttpContractDefinition,
5
+ getUserContext,
6
+ type IHttpPolicyInfo,
7
+ waitForHostContractTransport,
8
+ } from "@peers-app/peers-sdk";
9
+ import { useEffect, useState } from "react";
10
+
11
+ /**
12
+ * Shows the host allowlist and credential refs declared by an isolated package.
13
+ *
14
+ * Secret values stay on the host. A host that does not provide System HTTP, such
15
+ * as the PWA, renders nothing.
16
+ */
17
+ export const PackageNetworkPanel = (props: { packageId: string }) => {
18
+ const [policy, setPolicy] = useState<IHttpPolicyInfo | undefined>();
19
+
20
+ useEffect(() => {
21
+ let cancelled = false;
22
+ let dispose = () => {};
23
+ (async () => {
24
+ try {
25
+ const userContext = await getUserContext();
26
+ const dataContextId = userContext.currentlyActiveGroupId() || userContext.userId;
27
+ const transport =
28
+ getHostContractTransport() ?? (await waitForHostContractTransport({ timeoutMs: 3_000 }));
29
+ const consumer = createContractConsumer(getHttpContractDefinition(), transport, {
30
+ dataContextId,
31
+ });
32
+ dispose = () => consumer.dispose();
33
+ const next = await consumer.tools.describePolicy({ packageId: props.packageId });
34
+ if (!cancelled) {
35
+ setPolicy(next);
36
+ }
37
+ } catch {
38
+ if (!cancelled) {
39
+ setPolicy(undefined);
40
+ }
41
+ }
42
+ })();
43
+ return () => {
44
+ cancelled = true;
45
+ dispose();
46
+ };
47
+ }, [props.packageId]);
48
+
49
+ if (!policy || (policy.allowedHosts.length === 0 && policy.credentials.length === 0)) {
50
+ return policy ? (
51
+ <div className="mt-3">
52
+ <small className="text-muted">This package does not declare outbound network access.</small>
53
+ </div>
54
+ ) : null;
55
+ }
56
+
57
+ return (
58
+ <div className="mt-3">
59
+ <small>Network access</small>
60
+ <ul className="mb-2">
61
+ {policy.allowedHosts.map((host) => (
62
+ <li key={host}>
63
+ <code>{host}</code>
64
+ </li>
65
+ ))}
66
+ </ul>
67
+ {policy.credentials.length > 0 && (
68
+ <>
69
+ <small>Credentials injected by the host</small>
70
+ <ul className="mb-0">
71
+ {policy.credentials.map((credential) => (
72
+ <li key={credential.ref}>
73
+ <code>{credential.ref}</code> sets <code>{credential.header}</code> from{" "}
74
+ <code>{credential.secretVar}</code> ({credential.scope})
75
+ </li>
76
+ ))}
77
+ </ul>
78
+ </>
79
+ )}
80
+ </div>
81
+ );
82
+ };
@@ -165,6 +165,11 @@ interface IProps extends UIContext {
165
165
  props: Record<string, unknown>;
166
166
  }
167
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
+ */
168
173
  export const UIRouter = (props: IProps) => {
169
174
  let matchingRoute: IPeersUIRoute | undefined;
170
175
  const allRoutes = _window.getPeersUIRoutes() as IPeersUIRoute[];
@@ -237,10 +242,13 @@ export const UIRouter = (props: IProps) => {
237
242
  return UILoader({ peersUIId: matchingRoute.peersUIId, props: props.props });
238
243
  };
239
244
 
240
- const UILoader = (args: { peersUIId: string; props: Record<string, unknown> }) => {
245
+ const UILoader = (args: { peersUIId: string; props?: Record<string, unknown> }) => {
246
+ if (!args.props) {
247
+ args.props = {};
248
+ }
241
249
  const { props, peersUIId } = args;
242
250
  const [lastReloadTime] = useObservable(packageReloaded);
243
- args.props.__lastPackageReload = lastReloadTime;
251
+ props.__lastPackageReload = lastReloadTime;
244
252
  // check if peersUIId maps to an in-memory react component
245
253
  const peersUI = peersUIs[peersUIId];
246
254
  if (peersUI?.content) {
@@ -274,7 +282,7 @@ const UILoader = (args: { peersUIId: string; props: Record<string, unknown> }) =
274
282
  );
275
283
  }
276
284
 
277
- return <UIAsyncLoader {...args} />;
285
+ return <UIAsyncLoader peersUIId={peersUIId} props={props} />;
278
286
  };
279
287
 
280
288
  const uiLoadingPromises: Record<string, Promise<void>> = {};
@@ -589,6 +597,7 @@ if (typeof window !== "undefined") {
589
597
  }
590
598
  }
591
599
 
600
+ /** Package id used when peers-ui registers its own built-in screens. */
592
601
  export const peersSystemPackageId = "000peers0system000package";
593
602
 
594
603
  /**