@quanta-intellect/vessel-browser 0.1.101 → 0.1.104

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.
package/out/main/index.js CHANGED
@@ -4593,16 +4593,17 @@ const PREMIUM_TOOLS = /* @__PURE__ */ new Set([
4593
4593
  ]);
4594
4594
  function isPremium() {
4595
4595
  const { premium } = loadSettings();
4596
- if (premium.status === "active" || premium.status === "trialing") {
4596
+ if (premium.status !== "active" && premium.status !== "trialing") {
4597
+ return false;
4598
+ }
4599
+ if (!premium.validatedAt) {
4597
4600
  return true;
4598
4601
  }
4599
- if (premium.validatedAt && premium.status !== "free") {
4600
- const lastValidated = new Date(premium.validatedAt).getTime();
4601
- if (Date.now() - lastValidated < OFFLINE_GRACE_PERIOD_MS) {
4602
- return true;
4603
- }
4602
+ const lastValidated = new Date(premium.validatedAt).getTime();
4603
+ if (!Number.isFinite(lastValidated)) {
4604
+ return false;
4604
4605
  }
4605
- return false;
4606
+ return Date.now() - lastValidated < OFFLINE_GRACE_PERIOD_MS;
4606
4607
  }
4607
4608
  function getPremiumState() {
4608
4609
  return { ...loadSettings().premium };
@@ -4647,9 +4648,31 @@ async function getCheckoutUrl(email) {
4647
4648
  }
4648
4649
  }
4649
4650
  async function getPortalUrl() {
4650
- return errorResult(
4651
- "Billing portal access is temporarily disabled until authenticated customer access is implemented."
4652
- );
4651
+ const current = loadSettings().premium;
4652
+ const identifier = current.verificationToken;
4653
+ if (!identifier) {
4654
+ return errorResult(
4655
+ "Verify your Premium subscription before opening billing management."
4656
+ );
4657
+ }
4658
+ try {
4659
+ const res = await fetch(`${VERIFICATION_API}/portal`, {
4660
+ method: "POST",
4661
+ headers: { "Content-Type": "application/json" },
4662
+ body: JSON.stringify({ identifier })
4663
+ });
4664
+ if (!res.ok) {
4665
+ const detail = await readApiErrorDetail(res);
4666
+ return errorResult(detail || `HTTP ${res.status}`);
4667
+ }
4668
+ const { url } = await res.json();
4669
+ if (typeof url !== "string" || !url.trim()) {
4670
+ return errorResult("Billing portal did not return a valid URL.");
4671
+ }
4672
+ return okResult({ url });
4673
+ } catch (err) {
4674
+ return errorResult(getErrorMessage(err, "Failed to open billing portal"));
4675
+ }
4653
4676
  }
4654
4677
  async function verifySubscription$1(identifier) {
4655
4678
  const current = loadSettings().premium;
@@ -4801,7 +4824,14 @@ const TELEMETRY_PROPERTY_ALLOWLIST = {
4801
4824
  bookmark_action: /* @__PURE__ */ new Set(["action"]),
4802
4825
  vault_action: /* @__PURE__ */ new Set(["action"]),
4803
4826
  extraction_failed: /* @__PURE__ */ new Set(["reason"]),
4804
- premium_funnel: /* @__PURE__ */ new Set(["step", "status", "reason"])
4827
+ premium_funnel: /* @__PURE__ */ new Set([
4828
+ "step",
4829
+ "status",
4830
+ "reason",
4831
+ "source",
4832
+ "previous_status",
4833
+ "new_status"
4834
+ ])
4805
4835
  };
4806
4836
  function getDeviceIdPath() {
4807
4837
  return path.join(electron.app.getPath("userData"), ".vessel-device-id");
@@ -27266,6 +27296,14 @@ const PREMIUM_TRACKABLE_STEPS = [
27266
27296
  ];
27267
27297
  const premiumApiOrigin = process.env.VESSEL_PREMIUM_API ? new URL(process.env.VESSEL_PREMIUM_API).origin : "https://vesselpremium.quantaintellect.com";
27268
27298
  function registerPremiumHandlers(tabManager, sendToRendererViews) {
27299
+ const trackPremiumStatusChange = (previousStatus, nextStatus, source) => {
27300
+ if (previousStatus === nextStatus) return;
27301
+ trackPremiumFunnel("premium_status_changed", {
27302
+ previous_status: previousStatus,
27303
+ new_status: nextStatus,
27304
+ source
27305
+ });
27306
+ };
27269
27307
  const watchPremiumCheckoutTab = (tabId) => {
27270
27308
  const tab = tabManager.getTab(tabId);
27271
27309
  const wc = tab?.view.webContents;
@@ -27303,13 +27341,26 @@ function registerPremiumHandlers(tabManager, sendToRendererViews) {
27303
27341
  return;
27304
27342
  }
27305
27343
  trackPremiumFunnel("auto_activation_attempted");
27344
+ trackPremiumFunnel("premium_verify_started", {
27345
+ source: "checkout_auto"
27346
+ });
27347
+ const previousStatus = getPremiumState().status;
27306
27348
  const state2 = await verifySubscription(sessionId);
27307
27349
  if (isPremiumActiveState(state2)) {
27308
27350
  sendToRendererViews(Channels.PREMIUM_UPDATE, state2);
27351
+ trackPremiumFunnel("premium_verify_succeeded", {
27352
+ status: state2.status,
27353
+ source: "checkout_auto"
27354
+ });
27355
+ trackPremiumStatusChange(previousStatus, state2.status, "checkout_auto");
27309
27356
  trackPremiumFunnel("auto_activation_succeeded", {
27310
27357
  status: state2.status
27311
27358
  });
27312
27359
  } else {
27360
+ trackPremiumFunnel("premium_verify_failed", {
27361
+ status: state2.status,
27362
+ source: "checkout_auto"
27363
+ });
27313
27364
  trackPremiumFunnel("auto_activation_failed", {
27314
27365
  status: state2.status
27315
27366
  });
@@ -27342,9 +27393,19 @@ function registerPremiumHandlers(tabManager, sendToRendererViews) {
27342
27393
  return errorResult("Invalid email format");
27343
27394
  }
27344
27395
  trackPremiumFunnel("activation_attempted");
27396
+ trackPremiumFunnel("activation_code_requested", {
27397
+ source: "settings"
27398
+ });
27345
27399
  const result = await requestActivationCode(email);
27346
27400
  if (!result.ok) {
27401
+ trackPremiumFunnel("activation_code_failed", {
27402
+ source: "settings"
27403
+ });
27347
27404
  trackPremiumFunnel("activation_failed");
27405
+ } else {
27406
+ trackPremiumFunnel("activation_code_sent", {
27407
+ source: "settings"
27408
+ });
27348
27409
  }
27349
27410
  return result;
27350
27411
  });
@@ -27361,13 +27422,30 @@ function registerPremiumHandlers(tabManager, sendToRendererViews) {
27361
27422
  });
27362
27423
  }
27363
27424
  trackPremiumFunnel("activation_attempted");
27425
+ trackPremiumFunnel("premium_verify_started", {
27426
+ source: "settings_code"
27427
+ });
27428
+ const previousStatus = getPremiumState().status;
27364
27429
  const result = await verifyActivationCode(email, code, challengeToken);
27365
27430
  if (result.ok) {
27431
+ trackPremiumFunnel("premium_verify_succeeded", {
27432
+ status: result.state.status,
27433
+ source: "settings_code"
27434
+ });
27366
27435
  trackPremiumFunnel("activation_succeeded", {
27367
27436
  status: result.state.status
27368
27437
  });
27438
+ trackPremiumStatusChange(
27439
+ previousStatus,
27440
+ result.state.status,
27441
+ "settings_code"
27442
+ );
27369
27443
  sendToRendererViews(Channels.PREMIUM_UPDATE, result.state);
27370
27444
  } else {
27445
+ trackPremiumFunnel("premium_verify_failed", {
27446
+ status: result.state.status,
27447
+ source: "settings_code"
27448
+ });
27371
27449
  trackPremiumFunnel("activation_failed", { status: result.state.status });
27372
27450
  }
27373
27451
  return result;
@@ -27380,6 +27458,8 @@ function registerPremiumHandlers(tabManager, sendToRendererViews) {
27380
27458
  if (result.ok && result.url) {
27381
27459
  const tabId = tabManager.createTab(result.url);
27382
27460
  watchPremiumCheckoutTab(tabId);
27461
+ } else {
27462
+ trackPremiumFunnel("checkout_open_failed");
27383
27463
  }
27384
27464
  return result;
27385
27465
  });
@@ -11515,7 +11515,7 @@ const SettingsPrivacy = (props) => {
11515
11515
  })();
11516
11516
  };
11517
11517
  delegateEvents(["input", "click"]);
11518
- var _tmpl$$4 = /* @__PURE__ */ template(`<div class=premium-section><div class=premium-active-badge>Premium Active</div><p class=premium-detail></p><div class=premium-actions-row><button class="premium-btn premium-btn-manage">Manage Subscription</button><button class="premium-btn premium-btn-reset">Sign Out`), _tmpl$2$4 = /* @__PURE__ */ template(`<div class=vault-entries>`), _tmpl$3$3 = /* @__PURE__ */ template(`<div class=settings-category-panel><div class=settings-field><label class=settings-label>Vessel Premium</label></div><div class=settings-field><label class=settings-label>Saved Sessions</label><p class=settings-hint style=margin-bottom:10px>Save the current browser state (tabs, cookies, storage) as a named session. Restore it later from this panel.</p><div class=premium-activate-row style=margin-bottom:8px><input class="settings-input premium-email-input"placeholder="Session name"><button class="premium-btn premium-btn-activate">Save Current`), _tmpl$4$3 = /* @__PURE__ */ template(`<div class=premium-activate-row><input class="settings-input premium-email-input"inputmode=numeric maxlength=6 placeholder="Enter 6-digit code"><button class="premium-btn premium-btn-activate">`), _tmpl$5$2 = /* @__PURE__ */ template(`<button class="premium-btn premium-btn-reset">Clear Saved Email`), _tmpl$6$2 = /* @__PURE__ */ template(`<div class=premium-section><p class=premium-description>Unlock screenshot/vision analysis, session management, Obsidian integration, workflow tracking, DevTools tools, table extraction, Agent Credential Vault, and unlimited tool iterations.</p><div class=premium-activate-row><input class="settings-input premium-email-input"type=email placeholder="Enter your subscription email"><button class="premium-btn premium-btn-activate"></button></div><button class="premium-btn premium-btn-upgrade">Subscribe to Premium — $5.99/mo after 7-day free trial`), _tmpl$7$2 = /* @__PURE__ */ template(`<p class=settings-status>`), _tmpl$8$1 = /* @__PURE__ */ template(`<div class=vault-entry><div class=vault-entry-info><span class=vault-entry-label></span><span class=vault-entry-detail> &middot; <!> cookies &middot; <!> domains</span></div><div style=display:flex;gap:6px;align-items:center><button class="premium-btn premium-btn-activate"title="Restore this session (replaces current tabs and cookies)"style="padding:2px 10px;font-size:12px">Load</button><button class=vault-entry-remove title="Delete session">&times;`);
11518
+ var _tmpl$$4 = /* @__PURE__ */ template(`<div class=premium-section><div class=premium-active-badge>Premium Active</div><p class=premium-detail></p><div class=premium-actions-row><button class="premium-btn premium-btn-manage">Manage Subscription</button><button class="premium-btn premium-btn-reset">Sign Out`), _tmpl$2$4 = /* @__PURE__ */ template(`<div class=vault-entries>`), _tmpl$3$3 = /* @__PURE__ */ template(`<div class=settings-category-panel><div class=settings-field><label class=settings-label>Vessel Premium</label></div><div class=settings-field><label class=settings-label>Saved Sessions</label><p class=settings-hint style=margin-bottom:10px>Save the current browser state (tabs, cookies, storage) as a named session. Restore it later from this panel.</p><div class=premium-activate-row style=margin-bottom:8px><input class="settings-input premium-email-input"placeholder="Session name"><button class="premium-btn premium-btn-activate">Save Current`), _tmpl$4$3 = /* @__PURE__ */ template(`<div class=premium-activate-row><input class="settings-input premium-email-input"inputmode=numeric maxlength=6 placeholder="Enter 6-digit code"><button class="premium-btn premium-btn-activate">`), _tmpl$5$2 = /* @__PURE__ */ template(`<button class="premium-btn premium-btn-reset">Clear Saved Email`), _tmpl$6$2 = /* @__PURE__ */ template(`<div class=premium-section><p class=premium-description>Unlock screenshot/vision analysis, session management, Obsidian integration, workflow tracking, DevTools tools, table extraction, Agent Credential Vault, and unlimited tool iterations.</p><div class=premium-activate-row><input class="settings-input premium-email-input"type=email placeholder="Enter your subscription email"><button class="premium-btn premium-btn-activate"></button></div><button class="premium-btn premium-btn-upgrade">`), _tmpl$7$2 = /* @__PURE__ */ template(`<p class=settings-status>`), _tmpl$8$1 = /* @__PURE__ */ template(`<div class=vault-entry><div class=vault-entry-info><span class=vault-entry-label></span><span class=vault-entry-detail> &middot; <!> cookies &middot; <!> domains</span></div><div style=display:flex;gap:6px;align-items:center><button class="premium-btn premium-btn-activate"title="Restore this session (replaces current tabs and cookies)"style="padding:2px 10px;font-size:12px">Load</button><button class=vault-entry-remove title="Delete session">&times;`);
11519
11519
  const SettingsAccount = (props) => {
11520
11520
  const p = props.premium;
11521
11521
  const s = props.sessions;
@@ -11620,6 +11620,7 @@ const SettingsAccount = (props) => {
11620
11620
  _el$24.$$click = () => {
11621
11621
  p.startCheckout();
11622
11622
  };
11623
+ insert(_el$24, () => p.loading() ? "Opening Checkout..." : "Subscribe to Premium — $5.99/mo after 7-day free trial");
11623
11624
  insert(_el$16, createComponent(Show, {
11624
11625
  get when() {
11625
11626
  return p.message();
@@ -11628,9 +11629,9 @@ const SettingsAccount = (props) => {
11628
11629
  var _el$26 = _tmpl$7$2();
11629
11630
  insert(_el$26, () => msg().text);
11630
11631
  createRenderEffect((_p$) => {
11631
- var _v$ = !!(msg().kind === "success"), _v$2 = !!(msg().kind === "error");
11632
- _v$ !== _p$.e && _el$26.classList.toggle("success", _p$.e = _v$);
11633
- _v$2 !== _p$.t && _el$26.classList.toggle("error", _p$.t = _v$2);
11632
+ var _v$3 = !!(msg().kind === "success"), _v$4 = !!(msg().kind === "error");
11633
+ _v$3 !== _p$.e && _el$26.classList.toggle("success", _p$.e = _v$3);
11634
+ _v$4 !== _p$.t && _el$26.classList.toggle("error", _p$.t = _v$4);
11634
11635
  return _p$;
11635
11636
  }, {
11636
11637
  e: void 0,
@@ -11655,7 +11656,15 @@ const SettingsAccount = (props) => {
11655
11656
  return _el$25;
11656
11657
  }
11657
11658
  }), null);
11658
- createRenderEffect(() => _el$20.disabled = p.loading() || !p.email().trim());
11659
+ createRenderEffect((_p$) => {
11660
+ var _v$ = p.loading() || !p.email().trim(), _v$2 = p.loading();
11661
+ _v$ !== _p$.e && (_el$20.disabled = _p$.e = _v$);
11662
+ _v$2 !== _p$.t && (_el$24.disabled = _p$.t = _v$2);
11663
+ return _p$;
11664
+ }, {
11665
+ e: void 0,
11666
+ t: void 0
11667
+ });
11659
11668
  createRenderEffect(() => _el$19.value = p.email());
11660
11669
  return _el$16;
11661
11670
  })();
@@ -11706,9 +11715,9 @@ const SettingsAccount = (props) => {
11706
11715
  var _el$27 = _tmpl$7$2();
11707
11716
  insert(_el$27, () => msg().text);
11708
11717
  createRenderEffect((_p$) => {
11709
- var _v$3 = !!(msg().kind === "success"), _v$4 = !!(msg().kind === "error");
11710
- _v$3 !== _p$.e && _el$27.classList.toggle("success", _p$.e = _v$3);
11711
- _v$4 !== _p$.t && _el$27.classList.toggle("error", _p$.t = _v$4);
11718
+ var _v$5 = !!(msg().kind === "success"), _v$6 = !!(msg().kind === "error");
11719
+ _v$5 !== _p$.e && _el$27.classList.toggle("success", _p$.e = _v$5);
11720
+ _v$6 !== _p$.t && _el$27.classList.toggle("error", _p$.t = _v$6);
11712
11721
  return _p$;
11713
11722
  }, {
11714
11723
  e: void 0,
@@ -12807,8 +12816,30 @@ const Settings = () => {
12807
12816
  const trackPremiumContext = (step) => window.vessel.premium.trackContext(step).catch((err) => {
12808
12817
  logger.warn("Failed to track premium context:", err);
12809
12818
  });
12810
- const startPremiumCheckout = () => {
12811
- void window.vessel.premium.checkout(premiumEmail().trim() || void 0);
12819
+ const startPremiumCheckout = async () => {
12820
+ setPremiumLoading(true);
12821
+ setPremiumMessage(null);
12822
+ try {
12823
+ const result = await window.vessel.premium.checkout(premiumEmail().trim() || void 0);
12824
+ if (result.ok) {
12825
+ setPremiumMessage({
12826
+ kind: "success",
12827
+ text: "Checkout opened. This screen will update when Premium activates."
12828
+ });
12829
+ } else {
12830
+ setPremiumMessage({
12831
+ kind: "error",
12832
+ text: result.error || "Could not open checkout."
12833
+ });
12834
+ }
12835
+ } catch (err) {
12836
+ setPremiumMessage({
12837
+ kind: "error",
12838
+ text: err instanceof Error ? err.message : "Could not open checkout."
12839
+ });
12840
+ } finally {
12841
+ setPremiumLoading(false);
12842
+ }
12812
12843
  };
12813
12844
  const resetPremiumActivationFlow = () => {
12814
12845
  setPremiumCode("");
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <meta http-equiv="Content-Security-Policy" content="default-src 'self'; base-uri 'none'; object-src 'none'; frame-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; font-src 'self' data:; form-action 'self';" />
7
7
  <title>Vessel</title>
8
- <script type="module" crossorigin src="./assets/index-CfezqyLr.js"></script>
8
+ <script type="module" crossorigin src="./assets/index-D3ABnKy4.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="./assets/index-BF_JrL2V.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quanta-intellect/vessel-browser",
3
3
  "mcpName": "io.github.unmodeled-tyler/vessel-browser",
4
- "version": "0.1.101",
4
+ "version": "0.1.104",
5
5
  "description": "AI-native web browser runtime for autonomous agents with human supervision",
6
6
  "main": "./out/main/index.js",
7
7
  "bin": {