@tollbooth-dpyc/web 1.4.1 → 1.4.2
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.
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
* Renders ONLY when this browser holds the session nsec for the signed-in
|
|
5
5
|
* npub. NIP-07 and courier-proof sign-ins see nothing: no disabled control,
|
|
6
6
|
* no placeholder, no mention. Painting the key takes two deliberate taps —
|
|
7
|
-
* "Claim your session key", then the Reveal
|
|
7
|
+
* "Claim your session key", then the Reveal (eye) button — so an account page opened
|
|
8
8
|
* in front of other people does not show it.
|
|
9
9
|
*
|
|
10
10
|
* Destinations: copy, download .env, password-manager prompt, and an
|
|
11
11
|
* encrypted DM to another npub the patron names. The nsec never reaches a
|
|
12
12
|
* log, error text, analytics call, or MCP tool argument.
|
|
13
13
|
*/
|
|
14
|
-
export
|
|
14
|
+
export interface SessionKeyClaimClassNames {
|
|
15
|
+
/** Each round icon action (Reveal, Copy, .env, password manager, DM) when not active. Default: the package's outlined chip. */
|
|
16
|
+
action?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface SessionKeyClaimProps {
|
|
15
19
|
npub: string;
|
|
16
|
-
|
|
20
|
+
classNames?: SessionKeyClaimClassNames;
|
|
21
|
+
}
|
|
22
|
+
export default function SessionKeyClaim({ npub, classNames }: SessionKeyClaimProps): import("react").JSX.Element | null;
|
|
@@ -5,7 +5,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
* Renders ONLY when this browser holds the session nsec for the signed-in
|
|
6
6
|
* npub. NIP-07 and courier-proof sign-ins see nothing: no disabled control,
|
|
7
7
|
* no placeholder, no mention. Painting the key takes two deliberate taps —
|
|
8
|
-
* "Claim your session key", then the Reveal
|
|
8
|
+
* "Claim your session key", then the Reveal (eye) button — so an account page opened
|
|
9
9
|
* in front of other people does not show it.
|
|
10
10
|
*
|
|
11
11
|
* Destinations: copy, download .env, password-manager prompt, and an
|
|
@@ -13,13 +13,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
* log, error text, analytics call, or MCP tool argument.
|
|
14
14
|
*/
|
|
15
15
|
import { useRef, useState } from "react";
|
|
16
|
+
import { Check, Copy, Download, Eye, EyeOff, KeyRound, Send } from "lucide-react";
|
|
16
17
|
import { tollboothConfig } from "../config.js";
|
|
17
18
|
import { passwordManagerOutcomeLabel, sessionKeyClaimVisible, sessionKeyEnvContents, sessionKeyEnvFilename, } from "../sessionKeyClaim.js";
|
|
18
19
|
import { sendSessionKeyDm } from "../sessionKeyDm.js";
|
|
19
20
|
import { getSessionNsec, getSessionNsecBytes, hasSessionNsec, sessionNsecNpub, } from "../sessionNsec.js";
|
|
20
21
|
import { shareOrDownload } from "../shareFile.js";
|
|
21
22
|
import { card, input, muted } from "./ui.js";
|
|
22
|
-
export default function SessionKeyClaim({ npub }) {
|
|
23
|
+
export default function SessionKeyClaim({ npub, classNames = {} }) {
|
|
23
24
|
const visible = sessionKeyClaimVisible({
|
|
24
25
|
hasSessionNsec: hasSessionNsec(),
|
|
25
26
|
sessionNsecNpub: sessionNsecNpub(),
|
|
@@ -28,9 +29,9 @@ export default function SessionKeyClaim({ npub }) {
|
|
|
28
29
|
// Hard requirement: silence when the browser does not hold the key.
|
|
29
30
|
if (!visible)
|
|
30
31
|
return null;
|
|
31
|
-
return _jsx(SessionKeyClaimInner, {});
|
|
32
|
+
return _jsx(SessionKeyClaimInner, { actionClass: classNames.action });
|
|
32
33
|
}
|
|
33
|
-
function SessionKeyClaimInner() {
|
|
34
|
+
function SessionKeyClaimInner({ actionClass }) {
|
|
34
35
|
const { slug, appName } = tollboothConfig();
|
|
35
36
|
const envFilename = sessionKeyEnvFilename(slug);
|
|
36
37
|
const [revealed, setRevealed] = useState(false);
|
|
@@ -162,17 +163,19 @@ function SessionKeyClaimInner() {
|
|
|
162
163
|
setDmOpen(false);
|
|
163
164
|
setFlash(null);
|
|
164
165
|
setRecipient("");
|
|
165
|
-
}, className: `text-[12px] ${muted} hover:text-[var(--tb-ink)]`, children: "Hide" })] }), _jsxs("p", { className: `mb-3 text-[12.5px] leading-relaxed ${muted}`, children: ["Anyone who holds this key is you. It leaves this page only when you choose a destination below \u2014 never logged, never sent to ", appName, "."] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(DestButton, { onClick: () => setShowKey((v) => !v), active: showKey, children: showKey ? "
|
|
166
|
+
}, className: `text-[12px] ${muted} hover:text-[var(--tb-ink)]`, children: "Hide" })] }), _jsxs("p", { className: `mb-3 text-[12.5px] leading-relaxed ${muted}`, children: ["Anyone who holds this key is you. It leaves this page only when you choose a destination below \u2014 never logged, never sent to ", appName, "."] }), _jsxs("div", { className: "flex flex-wrap gap-2", children: [_jsx(DestButton, { label: showKey ? "Conceal the key" : "Reveal the key", onClick: () => setShowKey((v) => !v), active: showKey, className: actionClass, children: showKey ? _jsx(EyeOff, { size: 20, "aria-hidden": "true" }) : _jsx(Eye, { size: 20, "aria-hidden": "true" }) }), _jsx(DestButton, { label: copied ? "Copied" : "Copy the key", onClick: () => void copyKey(), disabled: busy, className: actionClass, children: copied ? _jsx(Check, { size: 20, "aria-hidden": "true" }) : _jsx(Copy, { size: 20, "aria-hidden": "true" }) }), _jsx(DestButton, { label: "Download a .env file", onClick: () => void downloadEnv(), disabled: busy, className: actionClass, children: _jsx(Download, { size: 20, "aria-hidden": "true" }) }), _jsx(DestButton, { label: "Save to your password manager", onClick: () => void passwordManagerSave(), disabled: busy, className: actionClass, children: _jsx(KeyRound, { size: 20, "aria-hidden": "true" }) }), _jsx(DestButton, { label: "Send by encrypted DM", onClick: () => {
|
|
166
167
|
setDmOpen((v) => !v);
|
|
167
168
|
setFlash(null);
|
|
168
|
-
}, disabled: busy, active: dmOpen, children:
|
|
169
|
+
}, disabled: busy, active: dmOpen, className: actionClass, children: _jsx(Send, { size: 20, "aria-hidden": "true" }) })] }), showKey && (_jsx("div", { className: "mt-3 break-all rounded-lg border border-[var(--tb-line)] bg-[var(--tb-surface-2)] px-3 py-2 font-mono text-[12px] text-[var(--tb-ink)]", children: getSessionNsec() })), dmOpen && (_jsxs("div", { className: "mt-3 space-y-2 rounded-lg border border-[var(--tb-line)] bg-[var(--tb-surface-2)] p-3", children: [_jsx("p", { className: `text-[12px] leading-relaxed ${muted}`, children: "Encrypts the key to an npub you own and publishes the sealed message to public relays. Only that npub can open it." }), _jsxs("div", { className: "flex flex-wrap items-end gap-2", children: [_jsxs("label", { className: `block min-w-[16rem] flex-1 text-[12px] ${muted}`, children: ["Recipient npub", _jsx("input", { value: recipient, onChange: (e) => setRecipient(e.target.value), spellCheck: false, autoCapitalize: "off", autoCorrect: "off", placeholder: "npub1\u2026", className: `mt-1 h-11 ${input}` })] }), _jsx("button", { type: "button", onClick: () => void sendDm(), disabled: busy || recipient.trim().length < 60, className: "min-h-11 shrink-0 rounded-full border border-[var(--tb-accent)] bg-[var(--tb-accent)] px-4 text-[13px] font-semibold text-[var(--tb-on-accent)] disabled:opacity-40", children: busy ? "Sending…" : "Send encrypted DM" })] })] })), _jsxs("form", { ref: formRef, className: "absolute h-px w-px overflow-hidden opacity-0", "aria-hidden": "true", autoComplete: "on", onSubmit: (e) => {
|
|
169
170
|
e.preventDefault();
|
|
170
171
|
}, children: [_jsx("input", { ref: userRef, name: "username", autoComplete: "username", defaultValue: "", readOnly: true, tabIndex: -1 }), _jsx("input", { ref: passRef, name: "password", type: "password", autoComplete: "new-password", defaultValue: "", readOnly: true, tabIndex: -1 })] }), flash && (_jsx("p", { className: `mt-3 text-[12.5px] leading-relaxed ${flash.tone === "ok" ? "text-[var(--tb-ink)]" : "text-[var(--tb-err-ink)]"}`, role: "status", children: flash.text }))] }));
|
|
171
172
|
}
|
|
172
|
-
|
|
173
|
-
|
|
173
|
+
/** An icon-only round action. `label` is its aria-label and tooltip. */
|
|
174
|
+
function DestButton({ label, onClick, disabled, active, className, children, }) {
|
|
175
|
+
const idle = className ?? `border-[var(--tb-line)] ${muted} active:bg-[var(--tb-surface-2)]`;
|
|
176
|
+
return (_jsx("button", { type: "button", onClick: onClick, disabled: disabled, "aria-label": label, title: label, className: `inline-flex h-11 w-11 shrink-0 items-center justify-center rounded-full border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--tb-accent)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--tb-surface)] disabled:opacity-40 ${active
|
|
174
177
|
? "border-[var(--tb-accent)] bg-[var(--tb-accent)] text-[var(--tb-on-accent)]"
|
|
175
|
-
:
|
|
178
|
+
: idle}`, children: children }));
|
|
176
179
|
}
|
|
177
180
|
/**
|
|
178
181
|
* Offer the key to a browser password manager. Never claims an OS keychain.
|
package/dist/react/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export { default as NpubGate } from "./NpubGate.tsx";
|
|
|
9
9
|
export { default as NostrProfilePanel } from "./NostrProfilePanel.tsx";
|
|
10
10
|
export { PageControls, SortHeader, TableShell, type PageControlsProps, type PageControlsClassNames, type SortHeaderProps, type SortHeaderClassNames, type TableShellClassNames, } from "./PagedTable.tsx";
|
|
11
11
|
export { default as QuoteScroller, type QuoteScrollerProps, type QuoteScrollerClassNames } from "./QuoteScroller.tsx";
|
|
12
|
-
export { default as SessionKeyClaim } from "./SessionKeyClaim.tsx";
|
|
12
|
+
export { default as SessionKeyClaim, type SessionKeyClaimProps, type SessionKeyClaimClassNames, } from "./SessionKeyClaim.tsx";
|
|
13
13
|
export { default as TableFilter, type DateFieldOption, type FilterQuestion, type TableFilterProps, type TableFilterClassNames, type TableFilterDates, type TableFilterQuestions, type TableFilterSearch, } from "./TableFilter.tsx";
|
|
14
14
|
export { default as ThemeToggle, type ThemeToggleProps, type ThemeToggleClassNames } from "./ThemeToggle.tsx";
|
|
15
15
|
export { default as TimezonePicker, type TimezoneOption, type TimezonePickerClassNames, type TimezonePickerProps, } from "./TimezonePicker.tsx";
|
package/dist/react/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { default as NpubGate } from "./NpubGate.js";
|
|
|
9
9
|
export { default as NostrProfilePanel } from "./NostrProfilePanel.js";
|
|
10
10
|
export { PageControls, SortHeader, TableShell, } from "./PagedTable.js";
|
|
11
11
|
export { default as QuoteScroller } from "./QuoteScroller.js";
|
|
12
|
-
export { default as SessionKeyClaim } from "./SessionKeyClaim.js";
|
|
12
|
+
export { default as SessionKeyClaim, } from "./SessionKeyClaim.js";
|
|
13
13
|
export { default as TableFilter, } from "./TableFilter.js";
|
|
14
14
|
export { default as ThemeToggle } from "./ThemeToggle.js";
|
|
15
15
|
export { default as TimezonePicker, } from "./TimezonePicker.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tollbooth-dpyc/web",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "Shared browser SDK for Tollbooth DPYC operator front ends: npub sign-in, proofs, MCP client, profile and wallet",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Lonnie VanZandt",
|