@umbra-privacy/ceremony 0.1.2 → 0.1.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 (2) hide show
  1. package/dist/index.js +68 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -33,7 +33,7 @@ import { createWriteStream } from "fs";
33
33
  import { readFile, unlink } from "fs/promises";
34
34
  import { pipeline } from "stream/promises";
35
35
  import { Readable } from "stream";
36
- var DEFAULT_API_URL = "http://ceremony.api.umbraprivacy.com";
36
+ var DEFAULT_API_URL = "https://ceremony.api.umbraprivacy.com";
37
37
  var BASE = (process.env["CEREMONY_API_URL"] ?? DEFAULT_API_URL).replace(/\/$/, "");
38
38
  async function request(path, options = {}) {
39
39
  const res = await fetch(`${BASE}${path}`, {
@@ -690,11 +690,15 @@ function Attestation({ contribution }) {
690
690
 
691
691
  // src/components/App.tsx
692
692
  import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
693
- function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anonymous" }) {
693
+ var NAME_MAX_LEN = 100;
694
+ var NAME_VALID_RE = /^[\p{L}\p{N} _.\-]*$/u;
695
+ function App({ ceremonyId: initialCeremonyId, displayName: initialDisplayName }) {
694
696
  const { exit } = useApp();
695
697
  const [activeCeremonyId, setActiveCeremonyId] = useState4(initialCeremonyId);
698
+ const [displayName2, setDisplayName] = useState4(initialDisplayName ?? "anonymous");
699
+ const [nameSet, setNameSet] = useState4(initialDisplayName !== void 0);
696
700
  const [screen, setScreen] = useState4(
697
- initialCeremonyId ? { name: "loading" } : { name: "ceremony-picker", ceremonies: [], loading: true }
701
+ initialDisplayName === void 0 ? { name: "name-input", value: "" } : initialCeremonyId ? { name: "loading" } : { name: "ceremony-picker", ceremonies: [], loading: true }
698
702
  );
699
703
  const [ceremony, setCeremony] = useState4(null);
700
704
  const [session, setSession] = useState4(null);
@@ -702,12 +706,13 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
702
706
  const [selectedIdx, setSelectedIdx] = useState4(0);
703
707
  const [tab, setTab] = useState4(0);
704
708
  useEffect4(() => {
709
+ if (!nameSet) return;
705
710
  if (!initialCeremonyId) {
706
711
  loadCeremonies();
707
712
  } else {
708
713
  boot(initialCeremonyId);
709
714
  }
710
- }, []);
715
+ }, [nameSet]);
711
716
  async function loadCeremonies() {
712
717
  try {
713
718
  const { ceremonies } = await api.listCeremonies();
@@ -739,6 +744,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
739
744
  setScreen({ name: "error", message: "No tracks found in this ceremony.", recoverable: false });
740
745
  return;
741
746
  }
747
+ setSelectedIdx(0);
742
748
  setScreen({ name: "tracks", tracks });
743
749
  } catch (e) {
744
750
  if (e.code === "INVALID_SESSION" || e.status === 401) {
@@ -751,6 +757,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
751
757
  setScreen({ name: "error", message: "No tracks found in this ceremony.", recoverable: false });
752
758
  return;
753
759
  }
760
+ setSelectedIdx(0);
754
761
  setScreen({ name: "tracks", tracks });
755
762
  } catch (e2) {
756
763
  setScreen({ name: "error", message: e2.message ?? "Failed to load tracks.", recoverable: false });
@@ -760,6 +767,22 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
760
767
  setScreen({ name: "error", message: e.message ?? "Failed to load tracks.", recoverable: false });
761
768
  }
762
769
  }
770
+ function commitName(raw) {
771
+ const trimmed = raw.trim();
772
+ if (trimmed.length === 0) return;
773
+ setDisplayName(trimmed);
774
+ setNameSet(true);
775
+ setScreen(
776
+ initialCeremonyId ? { name: "loading" } : { name: "ceremony-picker", ceremonies: [], loading: true }
777
+ );
778
+ }
779
+ function randomAnonName() {
780
+ const hex = Array.from(
781
+ { length: 6 },
782
+ () => Math.floor(Math.random() * 16).toString(16)
783
+ ).join("");
784
+ return `anon-${hex}`;
785
+ }
763
786
  async function joinTrack(track) {
764
787
  if (!session) return;
765
788
  setScreen({ name: "joining" });
@@ -795,6 +818,29 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
795
818
  }, [screen.name]);
796
819
  useInput2((input, key) => {
797
820
  const q = input.toLowerCase();
821
+ if (screen.name === "name-input") {
822
+ if (key.escape) {
823
+ exit();
824
+ return;
825
+ }
826
+ if (key.tab) {
827
+ commitName(randomAnonName());
828
+ return;
829
+ }
830
+ if (key.return) {
831
+ commitName(screen.value);
832
+ return;
833
+ }
834
+ if (key.backspace || key.delete) {
835
+ setScreen({ name: "name-input", value: screen.value.slice(0, -1) });
836
+ return;
837
+ }
838
+ if (input && input.length === 1 && NAME_VALID_RE.test(input)) {
839
+ if (screen.value.length >= NAME_MAX_LEN) return;
840
+ setScreen({ name: "name-input", value: screen.value + input });
841
+ }
842
+ return;
843
+ }
798
844
  if (q === "q" && screen.name !== "entropy") {
799
845
  if (screen.name === "queue" && session) {
800
846
  clearQueueCleanup();
@@ -866,6 +912,23 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
866
912
  goHome();
867
913
  }
868
914
  });
915
+ if (screen.name === "name-input") {
916
+ const { value } = screen;
917
+ const canSubmit = value.trim().length > 0;
918
+ return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
919
+ /* @__PURE__ */ jsx6(Header, { ceremony: null }),
920
+ /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, gap: 1, children: [
921
+ /* @__PURE__ */ jsx6(Text6, { bold: true, children: "Who are you contributing as?" }),
922
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: "Your display name appears next to your contributions in the public transcript. Pick anything \u2014 your real name, a handle, or hit Tab for a random anonymous name." }),
923
+ /* @__PURE__ */ jsxs6(Box6, { children: [
924
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", children: " > " }),
925
+ /* @__PURE__ */ jsx6(Text6, { children: value }),
926
+ /* @__PURE__ */ jsx6(Text6, { color: "cyan", inverse: true, children: " " })
927
+ ] }),
928
+ /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: canSubmit ? "Enter to continue \xB7 Tab for random \xB7 \u232B backspace \xB7 Esc to quit" : "Type a name, or Tab for a random anonymous name \xB7 Esc to quit" })
929
+ ] })
930
+ ] });
931
+ }
869
932
  if (screen.name === "ceremony-picker") {
870
933
  const { ceremonies, loading } = screen;
871
934
  return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
@@ -1125,7 +1188,7 @@ function App({ ceremonyId: initialCeremonyId, displayName: displayName2 = "anony
1125
1188
  // src/index.tsx
1126
1189
  import { jsx as jsx7 } from "react/jsx-runtime";
1127
1190
  var ceremonyId = process.env["CEREMONY_ID"] ?? "";
1128
- var displayName = process.env["CONTRIBUTOR_NAME"] ?? "anonymous";
1191
+ var displayName = process.env["CONTRIBUTOR_NAME"];
1129
1192
  process.stdout.write("\x1B[?1049h\x1B[H");
1130
1193
  function restoreScreen() {
1131
1194
  process.stdout.write("\x1B[?1049l");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umbra-privacy/ceremony",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Terminal UI for the Umbra Phase 2 trusted setup ceremony",
5
5
  "type": "module",
6
6
  "bin": {