@sonnechasser/ntrp 0.1.2 → 0.1.3

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.
@@ -6525,7 +6525,7 @@ function secretPromptLine(question) {
6525
6525
  return ` ${paint("accent", "\u25B8")} ${bold(question)} ${chalk3.dim("(hidden \u2014 paste once, Enter)")} `;
6526
6526
  }
6527
6527
  function stripTerminalArtifacts(input) {
6528
- return input.replace(/\x1b\[[0-9;]*[a-zA-Z~]/g, "").replace(/\x1b\][^\x07]*(\x07|\x1b\\)/g, "");
6528
+ return input.replace(/\x1b\[[0-9;]*[a-zA-Z~]/g, "").replace(/\x1b\][^\x07]*(\x07|\x1b\\)/g, "").replace(/\x1b\[200~/g, "").replace(/\x1b\[201~/g, "");
6529
6529
  }
6530
6530
  function renderQuestion(question, defaultValue) {
6531
6531
  const base = ` ${marker()}${bold(question)}`;
@@ -6583,8 +6583,8 @@ function createPromptSession(existing, ctx) {
6583
6583
  for (; ; ) {
6584
6584
  const raw = (await rl2.question(renderQuestion(`Your pick [1-${choices.length}]`, defaultLabel))).trim();
6585
6585
  assertNotGlobalReplCommand(raw);
6586
- const pick = raw || defaultLabel || "";
6587
- const n = Number(pick);
6586
+ const pick2 = raw || defaultLabel || "";
6587
+ const n = Number(pick2);
6588
6588
  if (Number.isInteger(n) && n >= 1 && n <= choices.length) {
6589
6589
  return choices[n - 1].value;
6590
6590
  }
@@ -6712,12 +6712,18 @@ function createPromptSession(existing, ctx) {
6712
6712
  console.log(" " + chalk3.dim("Try again \u2014 paste the key once, then Enter."));
6713
6713
  }
6714
6714
  }
6715
+ async function askPressEnter(message) {
6716
+ await rl2.question(
6717
+ ` ${paint("accent", "\u25B8")} ${bold(message)} ${chalk3.dim("(Enter)")} `
6718
+ );
6719
+ }
6715
6720
  return {
6716
6721
  ask,
6717
6722
  askRequired,
6718
6723
  confirm,
6719
6724
  choose,
6720
6725
  askMulti,
6726
+ askPressEnter,
6721
6727
  askSecret,
6722
6728
  close: () => {
6723
6729
  if (ctx && existing) {
@@ -14801,6 +14807,72 @@ import { join as join14 } from "path";
14801
14807
  // src/license/verify.ts
14802
14808
  init_store();
14803
14809
  import { createHmac } from "crypto";
14810
+
14811
+ // src/license/trial-policy.ts
14812
+ var TRIAL_FULL_DAYS = 11;
14813
+ var TRIAL_GRACE_END_DAYS = 30;
14814
+ function evaluateTrial(activatedAt, now2 = /* @__PURE__ */ new Date()) {
14815
+ const daysSince = Math.floor((now2.getTime() - activatedAt.getTime()) / 864e5);
14816
+ if (daysSince >= TRIAL_GRACE_END_DAYS) {
14817
+ return {
14818
+ phase: "expired",
14819
+ daysSinceActivation: daysSince,
14820
+ daysUntilLockout: 0,
14821
+ shouldNudge: false
14822
+ };
14823
+ }
14824
+ if (daysSince >= TRIAL_FULL_DAYS) {
14825
+ return {
14826
+ phase: "grace",
14827
+ daysSinceActivation: daysSince,
14828
+ daysUntilLockout: TRIAL_GRACE_END_DAYS - daysSince,
14829
+ shouldNudge: true
14830
+ };
14831
+ }
14832
+ return {
14833
+ phase: "active",
14834
+ daysSinceActivation: daysSince,
14835
+ daysUntilLockout: TRIAL_GRACE_END_DAYS - daysSince,
14836
+ shouldNudge: false
14837
+ };
14838
+ }
14839
+ function formatTrialActiveMessage(daysSince) {
14840
+ const daysLeft = TRIAL_FULL_DAYS - daysSince;
14841
+ if (daysLeft <= 0) return "trial license";
14842
+ const dayWord = daysLeft === 1 ? "day" : "days";
14843
+ return `trial license (${daysLeft} ${dayWord} remaining)`;
14844
+ }
14845
+
14846
+ // src/license/upgrade-whimsy.ts
14847
+ var CUTOFF_NUDGES = [
14848
+ "Okay \u2014 that's the line. /upgrade and you're back.",
14849
+ "We're paused until you say yes. /upgrade.",
14850
+ "Didn't want it to end like this. /upgrade if you want in again.",
14851
+ "Time's up. /upgrade \u2014 takes a minute.",
14852
+ "I'll be here. You just need to /upgrade first.",
14853
+ "That's all I can do on the free side. /upgrade.",
14854
+ "Door's closed for now. /upgrade opens it."
14855
+ ];
14856
+ function pick(items) {
14857
+ return items[Math.floor(Math.random() * items.length)] ?? items[0];
14858
+ }
14859
+ function randomCutoffNudge() {
14860
+ return pick(CUTOFF_NUDGES);
14861
+ }
14862
+
14863
+ // src/license/normalize.ts
14864
+ var NTRP_PREFIX = /^NTRP-/i;
14865
+ var UUID_KEY = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14866
+ function detectLicenseFormat(key) {
14867
+ if (NTRP_PREFIX.test(key)) return "ntrp";
14868
+ if (UUID_KEY.test(key)) return "lemonsqueezy";
14869
+ return "unknown";
14870
+ }
14871
+
14872
+ // src/license/lemonsqueezy.ts
14873
+ import { hostname } from "os";
14874
+
14875
+ // src/license/verify.ts
14804
14876
  var SIGNING_SECRET = "ntrp-gtm-health-2026";
14805
14877
  function validateLicenseKey(key) {
14806
14878
  const invalid = (msg) => ({
@@ -14827,16 +14899,73 @@ function validateLicenseKey(key) {
14827
14899
  const edition = editionCode === "01" ? "pro" : editionCode === "02" ? "team" : "trial";
14828
14900
  const expiryTs = parseInt(expiryHex, 16);
14829
14901
  const expiresAt = expiryTs > 0 ? new Date(expiryTs * 1e3) : null;
14830
- if (expiresAt && expiresAt < /* @__PURE__ */ new Date()) {
14902
+ if (expiresAt && expiresAt < /* @__PURE__ */ new Date() && edition !== "trial") {
14831
14903
  return invalid(`License expired on ${expiresAt.toISOString().slice(0, 10)}`);
14832
14904
  }
14833
14905
  return {
14834
14906
  valid: true,
14835
14907
  edition,
14836
14908
  expiresAt,
14837
- message: `${edition} license${expiresAt ? ` (expires ${expiresAt.toISOString().slice(0, 10)})` : " (perpetual)"}`
14909
+ message: edition === "trial" ? "trial license" : `${edition} license${expiresAt ? ` (expires ${expiresAt.toISOString().slice(0, 10)})` : " (perpetual)"}`
14910
+ };
14911
+ }
14912
+ function trialActivatedAt() {
14913
+ const stored = getConfigValue("license-activated-at");
14914
+ if (stored) {
14915
+ const parsed = new Date(stored);
14916
+ if (!Number.isNaN(parsed.getTime())) return parsed;
14917
+ }
14918
+ const now2 = /* @__PURE__ */ new Date();
14919
+ setConfigValue("license-activated-at", now2.toISOString());
14920
+ return now2;
14921
+ }
14922
+ function applyTrialPolicy(result) {
14923
+ if (result.edition !== "trial") return result;
14924
+ const trial = evaluateTrial(trialActivatedAt());
14925
+ if (trial.phase === "expired") {
14926
+ return {
14927
+ valid: false,
14928
+ edition: "trial",
14929
+ expiresAt: result.expiresAt,
14930
+ message: randomCutoffNudge(),
14931
+ trialPhase: "expired",
14932
+ shouldNudgeUpgrade: false,
14933
+ daysUntilLockout: 0
14934
+ };
14935
+ }
14936
+ const message = trial.phase === "grace" ? `trial license (grace \u2014 ${trial.daysUntilLockout} day${trial.daysUntilLockout === 1 ? "" : "s"} until lockout)` : formatTrialActiveMessage(trial.daysSinceActivation);
14937
+ return {
14938
+ ...result,
14939
+ message,
14940
+ trialPhase: trial.phase,
14941
+ shouldNudgeUpgrade: trial.shouldNudge,
14942
+ daysUntilLockout: trial.daysUntilLockout
14838
14943
  };
14839
14944
  }
14945
+ function storedLicenseProvider(key) {
14946
+ const configured = getConfigValue("license-provider");
14947
+ if (configured === "ntrp" || configured === "lemonsqueezy") return configured;
14948
+ return detectLicenseFormat(key) === "lemonsqueezy" ? "lemonsqueezy" : "ntrp";
14949
+ }
14950
+ function checkLemonSqueezyLicense(key) {
14951
+ const instanceId = getConfigValue("license-instance-id");
14952
+ if (!instanceId) {
14953
+ return {
14954
+ valid: false,
14955
+ edition: "trial",
14956
+ expiresAt: null,
14957
+ message: "License not activated on this machine. Run: ntrp activate <key>"
14958
+ };
14959
+ }
14960
+ const edition = getConfigValue("license-edition") ?? "pro";
14961
+ const base = {
14962
+ valid: true,
14963
+ edition,
14964
+ expiresAt: null,
14965
+ message: `${edition} license`
14966
+ };
14967
+ return applyTrialPolicy(base);
14968
+ }
14840
14969
  function checkLicense() {
14841
14970
  const key = getConfigValue("license-key");
14842
14971
  if (!key) {
@@ -14847,7 +14976,14 @@ function checkLicense() {
14847
14976
  message: "No license key found. Run: ntrp activate <key>"
14848
14977
  };
14849
14978
  }
14850
- return validateLicenseKey(key);
14979
+ if (storedLicenseProvider(key) === "lemonsqueezy") {
14980
+ return checkLemonSqueezyLicense(key);
14981
+ }
14982
+ const result = validateLicenseKey(key);
14983
+ if (!result.valid || result.edition !== "trial") {
14984
+ return result;
14985
+ }
14986
+ return applyTrialPolicy(result);
14851
14987
  }
14852
14988
 
14853
14989
  // src/services/setup.ts
@@ -14887,7 +15023,9 @@ function setupCheck() {
14887
15023
  },
14888
15024
  license: {
14889
15025
  valid: license.valid,
14890
- message: license.message
15026
+ message: license.message,
15027
+ trial_phase: license.trialPhase ?? null,
15028
+ days_until_lockout: license.daysUntilLockout ?? null
14891
15029
  }
14892
15030
  };
14893
15031
  }