@oneaddress/setup 1.2.1 → 1.3.1

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 +85 -52
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -856,8 +856,31 @@ var _R = ["\u2588\u2588\u2588\u2588\u2588\u2588 ", "\u2588\u2588 \u2588\u2588"
856
856
  var _S = [" \u2588\u2588\u2588\u2588\u2588\u2588", "\u2588\u2588 ", "\u2588\u2588 ", " \u2588\u2588\u2588\u2588\u2588 ", " \u2588\u2588", " \u2588\u2588", "\u2588\u2588\u2588\u2588\u2588\u2588 "];
857
857
  var ONE_ROWS = Array.from({ length: 7 }, (_3, i) => [_O[i], _N[i], _E[i]].join(" "));
858
858
  var ADDR_ROWS = Array.from({ length: 7 }, (_3, i) => [_A[i], _D2[i], _D2[i], _R[i], _E[i], _S[i], _S[i]].join(" "));
859
- var WIZARD_VERSION = true ? "1.2.1" : "?";
859
+ var WIZARD_VERSION = true ? "1.3.1" : "?";
860
+ function printCompactHeader() {
861
+ const INNER = 42;
862
+ const TOP = fn("\u250C") + dm("\u2500".repeat(INNER)) + fn("\u2510");
863
+ const BOT = fn("\u2514") + dm("\u2500".repeat(INNER)) + fn("\u2518");
864
+ const S3 = dm("\u2502");
865
+ const blank = ` ${S3}${" ".repeat(INNER)}${S3}`;
866
+ const row = (content, visibleLen) => ` ${S3} ${content}${" ".repeat(Math.max(0, INNER - 2 - visibleLen))}${S3}`;
867
+ const ver = `v${WIZARD_VERSION} \xB7 partners.oneaddress.io`;
868
+ console.log("");
869
+ console.log(" " + TOP);
870
+ console.log(blank);
871
+ console.log(row(wb("One ") + ab("Address"), "One Address".length));
872
+ console.log(row(mi("Partner Setup Wizard"), "Partner Setup Wizard".length));
873
+ console.log(row(fn(ver), ver.length));
874
+ console.log(blank);
875
+ console.log(" " + BOT);
876
+ console.log("");
877
+ }
860
878
  function printHeader() {
879
+ const cols = typeof process !== "undefined" && process.stdout && process.stdout.columns ? process.stdout.columns : 80;
880
+ if (cols < 88) {
881
+ printCompactHeader();
882
+ return;
883
+ }
861
884
  const BAR_LEN = 85;
862
885
  const TOP_BAR = fn("\u250C") + dm("\u2500".repeat(BAR_LEN)) + fn("\u2510");
863
886
  const BOT_BAR = fn("\u2514") + dm("\u2500".repeat(BAR_LEN)) + fn("\u2518");
@@ -5201,7 +5224,7 @@ async function scaffold(platform, outputDir, partnerId, webhookSecret, webhookUr
5201
5224
 
5202
5225
  // src/register.ts
5203
5226
  var import_node_crypto = require("crypto");
5204
- var PKG_VERSION = true ? "1.2.1" : "dev";
5227
+ var PKG_VERSION = true ? "1.3.1" : "dev";
5205
5228
  var REGISTER_URL = "https://partners.oneaddress.io/api/partner/installs";
5206
5229
  function hmacSha256(secret, message) {
5207
5230
  return (0, import_node_crypto.createHmac)("sha256", secret).update(message).digest("hex");
@@ -5686,7 +5709,13 @@ async function startTunnel(port) {
5686
5709
  // src/register-url.ts
5687
5710
  var import_node_crypto4 = require("crypto");
5688
5711
  var PORTAL_API = "https://partners.oneaddress.io/api/partner/webhook-url";
5689
- async function getExistingWebhookUrl(partnerId, webhookSecret) {
5712
+ function describeReadFailure(status) {
5713
+ if (status === 401) return "the portal rejected the signature (HTTP 401), which means your Webhook signing secret does not match the one on your profile. Copy it again from partners.oneaddress.io \u2192 Webhook \u2192 Webhook signing secret.";
5714
+ if (status === 404) return "the portal has no active partner for this account (HTTP 404), which usually means it is not approved yet.";
5715
+ if (status === 400) return "the portal rejected the request (HTTP 400).";
5716
+ return `the portal returned HTTP ${status}.`;
5717
+ }
5718
+ async function getExistingWebhookUrl(partnerId, webhookSecret, onError) {
5690
5719
  try {
5691
5720
  const ts = String(Math.floor(Date.now() / 1e3));
5692
5721
  const sig = (0, import_node_crypto4.createHmac)("sha256", webhookSecret).update(`${ts}.`).digest("hex");
@@ -5699,14 +5728,18 @@ async function getExistingWebhookUrl(partnerId, webhookSecret) {
5699
5728
  },
5700
5729
  signal: AbortSignal.timeout(8e3)
5701
5730
  });
5702
- if (!res.ok) return void 0;
5731
+ if (!res.ok) {
5732
+ onError?.(describeReadFailure(res.status));
5733
+ return void 0;
5734
+ }
5703
5735
  const data = await res.json();
5704
5736
  return data.webhook_url ?? null;
5705
- } catch {
5737
+ } catch (err) {
5738
+ onError?.(`could not reach the portal (${err instanceof Error ? err.message : "network error"})`);
5706
5739
  return void 0;
5707
5740
  }
5708
5741
  }
5709
- async function getVerifiesAccountReference(partnerId, webhookSecret) {
5742
+ async function getVerifiesAccountReference(partnerId, webhookSecret, onError) {
5710
5743
  try {
5711
5744
  const ts = String(Math.floor(Date.now() / 1e3));
5712
5745
  const sig = (0, import_node_crypto4.createHmac)("sha256", webhookSecret).update(`${ts}.`).digest("hex");
@@ -5719,13 +5752,17 @@ async function getVerifiesAccountReference(partnerId, webhookSecret) {
5719
5752
  },
5720
5753
  signal: AbortSignal.timeout(8e3)
5721
5754
  });
5722
- if (!res.ok) return void 0;
5755
+ if (!res.ok) {
5756
+ onError?.(describeReadFailure(res.status));
5757
+ return void 0;
5758
+ }
5723
5759
  const data = await res.json();
5724
5760
  const v2 = data.verifies_account_reference;
5725
5761
  if (v2 === true || v2 === false) return v2;
5726
5762
  if (v2 === null) return null;
5727
5763
  return void 0;
5728
- } catch {
5764
+ } catch (err) {
5765
+ onError?.(`could not reach the portal (${err instanceof Error ? err.message : "network error"})`);
5729
5766
  return void 0;
5730
5767
  }
5731
5768
  }
@@ -5759,20 +5796,26 @@ async function registerWebhookUrl(partnerId, webhookSecret, webhookUrl) {
5759
5796
  }
5760
5797
  }
5761
5798
 
5762
- // src/admin-gate.ts
5799
+ // src/cli-gate.ts
5763
5800
  var MAX_ATTEMPTS = 3;
5764
5801
  var AUTH_URL = "https://partners.oneaddress.io/api/cli/auth";
5765
- async function checkCredentials(user, pass) {
5802
+ async function checkToken(token) {
5766
5803
  try {
5767
5804
  const res = await fetch(AUTH_URL, {
5768
5805
  method: "POST",
5769
5806
  headers: { "Content-Type": "application/json" },
5770
- body: JSON.stringify({ username: user.trim(), password: pass.trim() }),
5807
+ body: JSON.stringify({ token: token.trim() }),
5771
5808
  signal: AbortSignal.timeout(8e3)
5772
5809
  });
5773
- if (res.status === 200) return { ok: true };
5774
- if (res.status === 401) return { ok: false, reason: "Invalid credentials" };
5775
- if (res.status === 429) return { ok: false, reason: "Rate-limited \u2014 wait 60 s and retry", retryable: true };
5810
+ if (res.status === 200) {
5811
+ const data = await res.json().catch(() => ({}));
5812
+ if (data.ok && typeof data.partnerId === "string" && data.partnerId) {
5813
+ return { ok: true, partnerId: data.partnerId };
5814
+ }
5815
+ return { ok: false, reason: "Portal did not return a partner for this token, is it a CLI token from Profile \u2192 CLI Access?" };
5816
+ }
5817
+ if (res.status === 401) return { ok: false, reason: "Token not accepted" };
5818
+ if (res.status === 429) return { ok: false, reason: "Rate-limited, wait 60 s and retry", retryable: true };
5776
5819
  const body = await res.json().catch(() => ({}));
5777
5820
  return {
5778
5821
  ok: false,
@@ -5787,35 +5830,26 @@ async function checkCredentials(user, pass) {
5787
5830
  };
5788
5831
  }
5789
5832
  }
5790
- async function adminGate() {
5833
+ async function cliGate() {
5791
5834
  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
5792
- const user = await he({
5793
- message: attempt === 1 ? "OneAddress CLI Username" : `OneAddress CLI Username (attempt ${attempt}/${MAX_ATTEMPTS})`,
5794
- placeholder: "oneaddress",
5795
- validate: (v2) => v2.trim() ? void 0 : "Username is required"
5796
- });
5797
- if (pD(user)) {
5798
- xe("Cancelled.");
5799
- process.exit(0);
5800
- }
5801
- const pass = await ge({
5802
- message: "OneAddress CLI Password",
5803
- validate: (v2) => v2.trim() ? void 0 : "Password is required"
5835
+ const token = await ge({
5836
+ message: attempt === 1 ? "OneAddress CLI token (Profile \u2192 CLI Access in the portal)" : `OneAddress CLI token (attempt ${attempt}/${MAX_ATTEMPTS})`,
5837
+ validate: (v2) => v2.trim() ? void 0 : "CLI token is required"
5804
5838
  });
5805
- if (pD(pass)) {
5839
+ if (pD(token)) {
5806
5840
  xe("Cancelled.");
5807
5841
  process.exit(0);
5808
5842
  }
5809
- const result = await checkCredentials(user, pass);
5810
- if (result.ok) return;
5843
+ const result = await checkToken(token);
5844
+ if (result.ok) return { partnerId: result.partnerId };
5811
5845
  if (result.retryable) {
5812
- M2.warn(` ${result.reason} \u2014 retry the same credentials.`);
5846
+ M2.warn(` ${result.reason}, retry the same token.`);
5813
5847
  attempt--;
5814
5848
  continue;
5815
5849
  }
5816
5850
  if (attempt < MAX_ATTEMPTS) {
5817
5851
  const remaining = MAX_ATTEMPTS - attempt;
5818
- M2.error(` ${result.reason} \u2014 ${remaining} attempt${remaining === 1 ? "" : "s"} remaining.`);
5852
+ M2.error(` ${result.reason}, ${remaining} attempt${remaining === 1 ? "" : "s"} remaining.`);
5819
5853
  } else {
5820
5854
  M2.error(` ${result.reason}.`);
5821
5855
  }
@@ -5989,26 +6023,20 @@ function stripControlChars(line) {
5989
6023
  async function main() {
5990
6024
  printHeader();
5991
6025
  Ie("OneAddress Partner Setup");
5992
- await adminGate();
6026
+ const { partnerId: pid } = await cliGate();
6027
+ if (!UUID_RE.test(pid)) {
6028
+ xe("The portal returned an unexpected partner id. Please retry, or contact support.");
6029
+ process.exit(1);
6030
+ }
5993
6031
  M2.info("We will:");
5994
- M2.info(" 1. Collect your credentials from the Partner Portal");
6032
+ M2.info(" 1. Collect your remaining credentials from the Partner Portal");
5995
6033
  M2.info(" 2. Scaffold a working webhook server for your platform");
5996
6034
  M2.info(" 3. Get it live with a passing conformance check \u2014 in under 5 minutes");
5997
- M2.info("\nOpen partners.oneaddress.io \u2192 My Profile to find all three values below.\n");
5998
- const partnerId = await he({
5999
- message: "Your Partner ID (UUID format)",
6000
- placeholder: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
6001
- validate: (v2) => {
6002
- if (!v2.trim()) return "Partner ID is required";
6003
- if (!UUID_RE.test(v2.trim()))
6004
- return "Must be a valid UUID \u2014 find it at partners.oneaddress.io \u2192 My Profile";
6005
- }
6006
- });
6007
- assertNotCancelled(partnerId);
6035
+ M2.info("\nOpen partners.oneaddress.io \u2192 My Profile to find the two values below.\n");
6008
6036
  const webhookSecret = await ge({
6009
- message: "Your Webhook Secret (min 20 chars)",
6037
+ message: "Your Webhook signing secret (min 20 chars)",
6010
6038
  validate: (v2) => {
6011
- if (!v2.trim()) return "Webhook Secret is required";
6039
+ if (!v2.trim()) return "Webhook signing secret is required";
6012
6040
  if (v2.length < 20) return "That looks too short \u2014 paste the full secret from My Profile";
6013
6041
  }
6014
6042
  });
@@ -6024,7 +6052,6 @@ async function main() {
6024
6052
  }
6025
6053
  });
6026
6054
  assertNotCancelled(privateKeyRaw);
6027
- const pid = partnerId.trim();
6028
6055
  const secret = webhookSecret.trim();
6029
6056
  const normalised = normalisePrivateKey(privateKeyRaw.trim());
6030
6057
  if (normalised.error) {
@@ -6069,11 +6096,14 @@ async function main() {
6069
6096
  }
6070
6097
  }
6071
6098
  }
6072
- const accountRefDeclaration = await getVerifiesAccountReference(pid, secret);
6099
+ let accountRefReason = "";
6100
+ const accountRefDeclaration = await getVerifiesAccountReference(pid, secret, (r2) => {
6101
+ accountRefReason = r2;
6102
+ });
6073
6103
  const verifiesAccountReference = accountRefDeclaration === true;
6074
6104
  if (accountRefDeclaration === void 0) {
6075
6105
  M2.warn(
6076
- "Could not read your account-reference declaration from the portal.\nConformance check-14 has been left out of the generated `npm test`, so a\npassing run does NOT mean your receiver matches account references correctly.\nSet it at partners.oneaddress.io \u2192 My Profile, then re-run this wizard."
6106
+ "Could not read your account-reference declaration from the portal.\n" + (accountRefReason ? "Reason: " + accountRefReason + "\n" : "") + "Conformance check-14 has been left out of the generated `npm test`, so a\npassing run does NOT mean your receiver matches account references correctly.\nSet it at partners.oneaddress.io \u2192 My Profile, then re-run this wizard."
6077
6107
  );
6078
6108
  }
6079
6109
  const s1 = Y2();
@@ -6147,7 +6177,10 @@ async function main() {
6147
6177
  if (start.output) M2.warn(start.output.slice(0, 600));
6148
6178
  }
6149
6179
  let webhookUrl = "";
6150
- const existingUrlResult = await getExistingWebhookUrl(pid, secret);
6180
+ let existingUrlReason = "";
6181
+ const existingUrlResult = await getExistingWebhookUrl(pid, secret, (r2) => {
6182
+ existingUrlReason = r2;
6183
+ });
6151
6184
  if (typeof existingUrlResult === "string") {
6152
6185
  M2.warn(
6153
6186
  `A webhook URL is already registered for this partner:
@@ -6166,7 +6199,7 @@ Continuing will overwrite it.`
6166
6199
  }
6167
6200
  } else if (existingUrlResult === void 0) {
6168
6201
  M2.warn(
6169
- "Could not check whether a webhook URL is already registered (portal API unreachable). Any URL you register now will overwrite an existing one without warning."
6202
+ "Could not check whether a webhook URL is already registered" + (existingUrlReason ? ": " + existingUrlReason : " (portal API unreachable).") + "\nAny URL you register now will overwrite an existing one without warning."
6170
6203
  );
6171
6204
  const continueAnyway = await ye({
6172
6205
  message: "Continue anyway?",
package/package.json CHANGED
@@ -1,13 +1,14 @@
1
1
  {
2
2
  "name": "@oneaddress/setup",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "Interactive setup wizard for OneAddress partner webhook integrations",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "oneaddress-setup": "dist/index.js"
8
8
  },
9
9
  "files": [
10
- "LICENSE", "dist",
10
+ "LICENSE",
11
+ "dist",
11
12
  "README.md"
12
13
  ],
13
14
  "scripts": {