@capxul/sandbox 1.0.0-alpha.1 → 1.0.0-alpha.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.
Files changed (2) hide show
  1. package/dist/main.mjs +71 -19
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -498,8 +498,8 @@ async function mintNextjsQuickstartKey(input, deps = {}) {
498
498
  //#endregion
499
499
  //#region src/runtime.ts
500
500
  const bundledPackageVersions = {
501
- sdk: "1.0.0-alpha.11",
502
- "sdk-react": "1.0.0-alpha.11"
501
+ sdk: "1.0.0-alpha.14",
502
+ "sdk-react": "1.0.0-alpha.14"
503
503
  };
504
504
  const packageRoot = fileURLToPath(new URL("..", import.meta.url));
505
505
  const FAUCET_DECIMALS = 6n;
@@ -570,10 +570,28 @@ function createConvexPathRunner({ deployment, env: sourceEnv = process.env, spaw
570
570
  };
571
571
  };
572
572
  }
573
- function normalizeEvmAddress(value) {
574
- const address = value.trim();
575
- if (!EVM_ADDRESS_PATTERN.test(address)) throw new Error("Address must be a 0x-prefixed 20-byte EVM address.");
576
- return address;
573
+ const ORG_HANDLE_SHAPE_PATTERN = /^[a-zA-Z0-9-]+$/;
574
+ /**
575
+ * Classify a faucet recipient prompt value: Capxul email, @org-handle, or
576
+ * as an explicit escape hatch — a raw EVM address. Canonical normalization
577
+ * (email lowercasing, handle validation) is left to the backend resolver.
578
+ */
579
+ function parseFaucetRecipient(value) {
580
+ const trimmed = value.trim();
581
+ if (EVM_ADDRESS_PATTERN.test(trimmed)) return {
582
+ kind: "address",
583
+ address: trimmed
584
+ };
585
+ if (trimmed.indexOf("@") > 0) return {
586
+ kind: "email",
587
+ email: trimmed
588
+ };
589
+ const orgHandle = trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
590
+ if (orgHandle.length > 0 && !orgHandle.toLowerCase().startsWith("0x") && ORG_HANDLE_SHAPE_PATTERN.test(orgHandle)) return {
591
+ kind: "orgHandle",
592
+ orgHandle
593
+ };
594
+ throw new Error("Recipient must be a Capxul email, @org-handle, or 0x address (escape hatch).");
577
595
  }
578
596
  function usdAmountToBaseUnits(value) {
579
597
  const amount = value.trim();
@@ -602,7 +620,20 @@ function canonicalConvexRunner(env = process.env) {
602
620
  //#endregion
603
621
  //#region src/commands/faucet-send.ts
604
622
  const DEFAULT_FAUCET_AMOUNT = "10";
605
- const FAUCET_FUNCTION = "dev/faucetMintTo:mintTo";
623
+ const FAUCET_ADDRESS_FUNCTION = "dev/faucetMintTo:mintTo";
624
+ const FAUCET_RECIPIENT_FUNCTION = "dev/faucetMintTo:mintToRecipient";
625
+ function recipientLabel(recipient) {
626
+ switch (recipient.kind) {
627
+ case "address": return recipient.address;
628
+ case "email": return recipient.email;
629
+ case "orgHandle": return `@${recipient.orgHandle}`;
630
+ }
631
+ }
632
+ function mintFailureMessage(recipient, output) {
633
+ const message = output.length > 0 ? output : "Faucet mint failed.";
634
+ if (recipient.kind === "orgHandle" && message.includes("INVALID_INPUT")) return [message, "Hint: personal payee handles are owner-scoped and cannot be funded by the faucet — use a Capxul email or an org handle."].join("\n");
635
+ return message;
636
+ }
606
637
  async function runFaucetSend() {
607
638
  intro("Capxul sandbox faucet send");
608
639
  note([
@@ -611,20 +642,21 @@ async function runFaucetSend() {
611
642
  "Asset: test USDX, 6 decimals",
612
643
  "This command calls the canonical backend dev faucet and cannot select live/mainnet."
613
644
  ].join("\n"), "Canonical sandbox");
614
- const addressPrompt = await text({
615
- message: "Recipient EVM address",
645
+ const recipientPrompt = await text({
646
+ message: "Recipient (Capxul email or @org-handle)",
616
647
  validate(value) {
617
648
  try {
618
- normalizeEvmAddress(value ?? "");
649
+ parseFaucetRecipient(value ?? "");
619
650
  } catch (error) {
620
651
  return errorMessage(error);
621
652
  }
622
653
  }
623
654
  });
624
- if (isCancel(addressPrompt)) {
655
+ if (isCancel(recipientPrompt)) {
625
656
  cancel("No faucet funds sent.");
626
657
  return 0;
627
658
  }
659
+ const recipient = parseFaucetRecipient(recipientPrompt);
628
660
  const amountPrompt = await text({
629
661
  message: "USDX amount",
630
662
  initialValue: DEFAULT_FAUCET_AMOUNT,
@@ -640,11 +672,21 @@ async function runFaucetSend() {
640
672
  cancel("No faucet funds sent.");
641
673
  return 0;
642
674
  }
643
- const holderAddress = normalizeEvmAddress(addressPrompt);
644
675
  const rawAmount = usdAmountToBaseUnits(amountPrompt);
645
676
  const displayAmount = amountPrompt.trim();
677
+ const identity = recipientLabel(recipient);
678
+ if (recipient.kind === "address") {
679
+ const escapeHatch = await confirm({
680
+ message: `Raw-address escape hatch — this skips Capxul identity resolution. Fund ${identity} directly?`,
681
+ initialValue: false
682
+ });
683
+ if (isCancel(escapeHatch) || escapeHatch === false) {
684
+ cancel("No faucet funds sent.");
685
+ return 0;
686
+ }
687
+ }
646
688
  const shouldSend = await confirm({
647
- message: `Mint ${displayAmount} test USDX to ${holderAddress}?`,
689
+ message: `Mint ${displayAmount} test USDX to ${identity}?`,
648
690
  initialValue: true
649
691
  });
650
692
  if (isCancel(shouldSend) || shouldSend === false) {
@@ -654,19 +696,29 @@ async function runFaucetSend() {
654
696
  const s = spinner();
655
697
  s.start("Minting testnet funds");
656
698
  try {
657
- const result = canonicalConvexRunner(loadOperatorEnv())("", [
699
+ const runConvex = canonicalConvexRunner(loadOperatorEnv());
700
+ const result = recipient.kind === "address" ? runConvex("", [
701
+ "run",
702
+ FAUCET_ADDRESS_FUNCTION,
703
+ JSON.stringify({
704
+ holderAddress: recipient.address,
705
+ rawAmount
706
+ })
707
+ ]) : runConvex("", [
658
708
  "run",
659
- FAUCET_FUNCTION,
709
+ FAUCET_RECIPIENT_FUNCTION,
660
710
  JSON.stringify({
661
- holderAddress,
711
+ recipient,
662
712
  rawAmount
663
713
  })
664
714
  ]);
665
- if (!result.ok) throw new Error(result.output || "Faucet mint failed.");
715
+ if (!result.ok) throw new Error(mintFailureMessage(recipient, result.output));
666
716
  const txHash = extractField(result.output, "txHash");
717
+ const safeAddress = recipient.kind === "address" ? recipient.address : extractField(result.output, "safeAddress");
667
718
  s.stop("Faucet funds sent");
668
719
  note([
669
- `Recipient: ${holderAddress}`,
720
+ `Recipient: ${identity}`,
721
+ `Safe address: ${safeAddress}`,
670
722
  `Amount: ${displayAmount} USDX`,
671
723
  `Raw amount: ${rawAmount}`,
672
724
  `Chain: Base Sepolia (84532)`,
@@ -784,7 +836,7 @@ const SANDBOX_COMMANDS = [{
784
836
  value: "faucet send",
785
837
  label: "Send testnet faucet funds",
786
838
  usage: "npx @capxul/sandbox faucet send",
787
- description: "Mint test USDX to an EVM address on Base Sepolia.",
839
+ description: "Mint test USDX to a Capxul identity (email or org handle) on Base Sepolia.",
788
840
  run: runFaucetSend
789
841
  }];
790
842
  const HELP_COMMANDS = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capxul/sandbox",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.2",
4
4
  "private": false,
5
5
  "description": "Capxul sandbox CLI for canonical quickstart keys and testnet faucet funds.",
6
6
  "keywords": [