@peers-app/peers-ui 0.25.17 → 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.
- package/dist/screens/packages/package-info.js +2 -1
- package/dist/screens/packages/package-network-panel.d.ts +9 -0
- package/dist/screens/packages/package-network-panel.js +48 -0
- package/dist/ui-router/ui-loader.d.ts +6 -0
- package/dist/ui-router/ui-loader.js +11 -2
- package/package.json +3 -3
- package/src/screens/packages/package-info.tsx +2 -0
- package/src/screens/packages/package-network-panel.tsx +82 -0
- package/src/ui-router/ui-loader.tsx +12 -3
|
@@ -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
|
-
|
|
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, {
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
/**
|