@sonnechasser/ntrp 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.
@@ -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,77 @@ 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
+ var TRIAL_ACTIVE_NUDGE_FROM_DAY = 8;
14815
+ function evaluateTrial(activatedAt, now2 = /* @__PURE__ */ new Date()) {
14816
+ const daysSince = Math.floor((now2.getTime() - activatedAt.getTime()) / 864e5);
14817
+ if (daysSince >= TRIAL_GRACE_END_DAYS) {
14818
+ return {
14819
+ phase: "expired",
14820
+ daysSinceActivation: daysSince,
14821
+ daysUntilLockout: 0,
14822
+ trialDaysRemaining: 0,
14823
+ shouldNudge: false
14824
+ };
14825
+ }
14826
+ if (daysSince >= TRIAL_FULL_DAYS) {
14827
+ return {
14828
+ phase: "grace",
14829
+ daysSinceActivation: daysSince,
14830
+ daysUntilLockout: TRIAL_GRACE_END_DAYS - daysSince,
14831
+ trialDaysRemaining: 0,
14832
+ shouldNudge: true
14833
+ };
14834
+ }
14835
+ const trialDaysRemaining = TRIAL_FULL_DAYS - daysSince;
14836
+ return {
14837
+ phase: "active",
14838
+ daysSinceActivation: daysSince,
14839
+ daysUntilLockout: TRIAL_GRACE_END_DAYS - daysSince,
14840
+ trialDaysRemaining,
14841
+ shouldNudge: daysSince >= TRIAL_ACTIVE_NUDGE_FROM_DAY
14842
+ };
14843
+ }
14844
+ function formatTrialActiveMessage(daysSince) {
14845
+ const daysLeft = TRIAL_FULL_DAYS - daysSince;
14846
+ if (daysLeft <= 0) return "trial license";
14847
+ const dayWord = daysLeft === 1 ? "day" : "days";
14848
+ return `trial license (${daysLeft} ${dayWord} remaining)`;
14849
+ }
14850
+
14851
+ // src/license/upgrade-whimsy.ts
14852
+ var CUTOFF_NUDGES = [
14853
+ "Okay \u2014 that's the line. /upgrade and you're back.",
14854
+ "We're paused until you say yes. /upgrade.",
14855
+ "Didn't want it to end like this. /upgrade if you want in again.",
14856
+ "Time's up. /upgrade \u2014 takes a minute.",
14857
+ "I'll be here. You just need to /upgrade first.",
14858
+ "That's all I can do on the free side. /upgrade.",
14859
+ "Door's closed for now. /upgrade opens it."
14860
+ ];
14861
+ function pick(items) {
14862
+ return items[Math.floor(Math.random() * items.length)] ?? items[0];
14863
+ }
14864
+ function randomCutoffNudge() {
14865
+ return pick(CUTOFF_NUDGES);
14866
+ }
14867
+
14868
+ // src/license/normalize.ts
14869
+ var NTRP_PREFIX = /^NTRP-/i;
14870
+ var UUID_KEY = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14871
+ function detectLicenseFormat(key) {
14872
+ if (NTRP_PREFIX.test(key)) return "ntrp";
14873
+ if (UUID_KEY.test(key)) return "lemonsqueezy";
14874
+ return "unknown";
14875
+ }
14876
+
14877
+ // src/license/lemonsqueezy.ts
14878
+ import { hostname } from "os";
14879
+
14880
+ // src/license/verify.ts
14804
14881
  var SIGNING_SECRET = "ntrp-gtm-health-2026";
14805
14882
  function validateLicenseKey(key) {
14806
14883
  const invalid = (msg) => ({
@@ -14827,16 +14904,75 @@ function validateLicenseKey(key) {
14827
14904
  const edition = editionCode === "01" ? "pro" : editionCode === "02" ? "team" : "trial";
14828
14905
  const expiryTs = parseInt(expiryHex, 16);
14829
14906
  const expiresAt = expiryTs > 0 ? new Date(expiryTs * 1e3) : null;
14830
- if (expiresAt && expiresAt < /* @__PURE__ */ new Date()) {
14907
+ if (expiresAt && expiresAt < /* @__PURE__ */ new Date() && edition !== "trial") {
14831
14908
  return invalid(`License expired on ${expiresAt.toISOString().slice(0, 10)}`);
14832
14909
  }
14833
14910
  return {
14834
14911
  valid: true,
14835
14912
  edition,
14836
14913
  expiresAt,
14837
- message: `${edition} license${expiresAt ? ` (expires ${expiresAt.toISOString().slice(0, 10)})` : " (perpetual)"}`
14914
+ message: edition === "trial" ? "trial license" : `${edition} license${expiresAt ? ` (expires ${expiresAt.toISOString().slice(0, 10)})` : " (perpetual)"}`
14915
+ };
14916
+ }
14917
+ function trialActivatedAt() {
14918
+ const stored = getConfigValue("license-activated-at");
14919
+ if (stored) {
14920
+ const parsed = new Date(stored);
14921
+ if (!Number.isNaN(parsed.getTime())) return parsed;
14922
+ }
14923
+ const now2 = /* @__PURE__ */ new Date();
14924
+ setConfigValue("license-activated-at", now2.toISOString());
14925
+ return now2;
14926
+ }
14927
+ function applyTrialPolicy(result) {
14928
+ if (result.edition !== "trial") return result;
14929
+ const trial = evaluateTrial(trialActivatedAt());
14930
+ if (trial.phase === "expired") {
14931
+ return {
14932
+ valid: false,
14933
+ edition: "trial",
14934
+ expiresAt: result.expiresAt,
14935
+ message: randomCutoffNudge(),
14936
+ trialPhase: "expired",
14937
+ shouldNudgeUpgrade: false,
14938
+ daysUntilLockout: 0,
14939
+ trialDaysRemaining: 0
14940
+ };
14941
+ }
14942
+ const message = trial.phase === "grace" ? `trial license (grace \u2014 ${trial.daysUntilLockout} day${trial.daysUntilLockout === 1 ? "" : "s"} until lockout)` : formatTrialActiveMessage(trial.daysSinceActivation);
14943
+ return {
14944
+ ...result,
14945
+ message,
14946
+ trialPhase: trial.phase,
14947
+ shouldNudgeUpgrade: trial.shouldNudge,
14948
+ daysUntilLockout: trial.daysUntilLockout,
14949
+ trialDaysRemaining: trial.trialDaysRemaining
14838
14950
  };
14839
14951
  }
14952
+ function storedLicenseProvider(key) {
14953
+ const configured = getConfigValue("license-provider");
14954
+ if (configured === "ntrp" || configured === "lemonsqueezy") return configured;
14955
+ return detectLicenseFormat(key) === "lemonsqueezy" ? "lemonsqueezy" : "ntrp";
14956
+ }
14957
+ function checkLemonSqueezyLicense(key) {
14958
+ const instanceId = getConfigValue("license-instance-id");
14959
+ if (!instanceId) {
14960
+ return {
14961
+ valid: false,
14962
+ edition: "trial",
14963
+ expiresAt: null,
14964
+ message: "License not activated on this machine. Run: ntrp activate <key>"
14965
+ };
14966
+ }
14967
+ const edition = getConfigValue("license-edition") ?? "pro";
14968
+ const base = {
14969
+ valid: true,
14970
+ edition,
14971
+ expiresAt: null,
14972
+ message: `${edition} license`
14973
+ };
14974
+ return applyTrialPolicy(base);
14975
+ }
14840
14976
  function checkLicense() {
14841
14977
  const key = getConfigValue("license-key");
14842
14978
  if (!key) {
@@ -14847,7 +14983,14 @@ function checkLicense() {
14847
14983
  message: "No license key found. Run: ntrp activate <key>"
14848
14984
  };
14849
14985
  }
14850
- return validateLicenseKey(key);
14986
+ if (storedLicenseProvider(key) === "lemonsqueezy") {
14987
+ return checkLemonSqueezyLicense(key);
14988
+ }
14989
+ const result = validateLicenseKey(key);
14990
+ if (!result.valid || result.edition !== "trial") {
14991
+ return result;
14992
+ }
14993
+ return applyTrialPolicy(result);
14851
14994
  }
14852
14995
 
14853
14996
  // src/services/setup.ts
@@ -14887,7 +15030,9 @@ function setupCheck() {
14887
15030
  },
14888
15031
  license: {
14889
15032
  valid: license.valid,
14890
- message: license.message
15033
+ message: license.message,
15034
+ trial_phase: license.trialPhase ?? null,
15035
+ days_until_lockout: license.daysUntilLockout ?? null
14891
15036
  }
14892
15037
  };
14893
15038
  }