perplexity-user-mcp 0.8.36

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 (125) hide show
  1. package/README.md +192 -0
  2. package/dist/attachments.d.ts +20 -0
  3. package/dist/attachments.mjs +43 -0
  4. package/dist/checks/browser.d.ts +100 -0
  5. package/dist/checks/browser.mjs +89 -0
  6. package/dist/checks/config.d.ts +91 -0
  7. package/dist/checks/config.mjs +88 -0
  8. package/dist/checks/ide.d.ts +89 -0
  9. package/dist/checks/ide.mjs +80 -0
  10. package/dist/checks/mcp.d.ts +61 -0
  11. package/dist/checks/mcp.mjs +56 -0
  12. package/dist/checks/native-deps.d.ts +131 -0
  13. package/dist/checks/native-deps.mjs +115 -0
  14. package/dist/checks/network.d.ts +71 -0
  15. package/dist/checks/network.mjs +70 -0
  16. package/dist/checks/probe.d.ts +93 -0
  17. package/dist/checks/probe.mjs +82 -0
  18. package/dist/checks/profiles.d.ts +99 -0
  19. package/dist/checks/profiles.mjs +90 -0
  20. package/dist/checks/runtime.d.ts +89 -0
  21. package/dist/checks/runtime.mjs +90 -0
  22. package/dist/checks/vault.d.ts +101 -0
  23. package/dist/checks/vault.mjs +90 -0
  24. package/dist/chunk-3B276PGG.mjs +115 -0
  25. package/dist/chunk-4UEJOM6W.mjs +9 -0
  26. package/dist/chunk-6EP2BLTV.mjs +205 -0
  27. package/dist/chunk-6YMQVLFX.mjs +146 -0
  28. package/dist/chunk-7JL36EBH.mjs +118 -0
  29. package/dist/chunk-DPGMKSSA.mjs +57 -0
  30. package/dist/chunk-H4BUAPPO.mjs +1950 -0
  31. package/dist/chunk-HMKLWVXB.mjs +109 -0
  32. package/dist/chunk-HTUAQRKH.mjs +125 -0
  33. package/dist/chunk-HU5B4FXS.mjs +139 -0
  34. package/dist/chunk-KCXM2M4B.mjs +1006 -0
  35. package/dist/chunk-LKJMLGFP.mjs +237 -0
  36. package/dist/chunk-LZPLNZ5U.mjs +67 -0
  37. package/dist/chunk-MTDFKNXX.mjs +19 -0
  38. package/dist/chunk-OF4DMAPJ.mjs +511 -0
  39. package/dist/chunk-PE23RMXY.mjs +43 -0
  40. package/dist/chunk-Q2VY4R5F.mjs +175 -0
  41. package/dist/chunk-S5VD7WTU.mjs +2540 -0
  42. package/dist/chunk-SVPRB62V.mjs +106 -0
  43. package/dist/chunk-TQLCLE4L.mjs +345 -0
  44. package/dist/chunk-U3DGFLXZ.mjs +43 -0
  45. package/dist/chunk-X45O6YD3.mjs +688 -0
  46. package/dist/chunk-XKSWCEGI.mjs +168 -0
  47. package/dist/chunk-Z7DAACGZ.mjs +534 -0
  48. package/dist/chunk-ZQFUZPLO.mjs +257 -0
  49. package/dist/cli.d.ts +952 -0
  50. package/dist/cli.mjs +827 -0
  51. package/dist/client.d.ts +355 -0
  52. package/dist/client.mjs +27 -0
  53. package/dist/cloud-sync.d-Cqt6y18U.d.ts +42 -0
  54. package/dist/cloud-sync.d.ts +42 -0
  55. package/dist/cloud-sync.mjs +17 -0
  56. package/dist/config.d.ts +186 -0
  57. package/dist/config.mjs +54 -0
  58. package/dist/daemon/attach.d.ts +36 -0
  59. package/dist/daemon/attach.mjs +25 -0
  60. package/dist/daemon/audit.d.ts +23 -0
  61. package/dist/daemon/audit.mjs +12 -0
  62. package/dist/daemon/client-http.d.ts +42 -0
  63. package/dist/daemon/client-http.mjs +29 -0
  64. package/dist/daemon/index.d.ts +14 -0
  65. package/dist/daemon/index.mjs +110 -0
  66. package/dist/daemon/install-tunnel.d.ts +46 -0
  67. package/dist/daemon/install-tunnel.mjs +14 -0
  68. package/dist/daemon/launcher.d.ts +163 -0
  69. package/dist/daemon/launcher.mjs +50 -0
  70. package/dist/daemon/lockfile.d.ts +29 -0
  71. package/dist/daemon/lockfile.mjs +18 -0
  72. package/dist/daemon/server.d.ts +159 -0
  73. package/dist/daemon/server.mjs +20 -0
  74. package/dist/daemon/token.d.ts +17 -0
  75. package/dist/daemon/token.mjs +17 -0
  76. package/dist/daemon/tunnel-providers/index.d.ts +330 -0
  77. package/dist/daemon/tunnel-providers/index.mjs +57 -0
  78. package/dist/daemon/tunnel.d.ts +23 -0
  79. package/dist/daemon/tunnel.mjs +9 -0
  80. package/dist/doctor-report.d.ts +24 -0
  81. package/dist/doctor-report.mjs +14 -0
  82. package/dist/doctor.d-CXmUqOXX.d.ts +43 -0
  83. package/dist/doctor.d.ts +44 -0
  84. package/dist/doctor.mjs +16 -0
  85. package/dist/export.d.ts +19 -0
  86. package/dist/export.mjs +15 -0
  87. package/dist/health-check.d.ts +108 -0
  88. package/dist/health-check.mjs +92 -0
  89. package/dist/history-store.d-BzjBF2m3.d.ts +65 -0
  90. package/dist/history-store.d.ts +65 -0
  91. package/dist/history-store.mjs +48 -0
  92. package/dist/impit-login-runner.d.ts +469 -0
  93. package/dist/impit-login-runner.mjs +685 -0
  94. package/dist/index.d.ts +159 -0
  95. package/dist/index.mjs +236 -0
  96. package/dist/login-runner.d.ts +333 -0
  97. package/dist/login-runner.mjs +320 -0
  98. package/dist/logout.d.ts +28 -0
  99. package/dist/logout.mjs +45 -0
  100. package/dist/manual-login-runner.d.ts +150 -0
  101. package/dist/manual-login-runner.mjs +146 -0
  102. package/dist/native-deps-BNThFHxa.d.ts +175 -0
  103. package/dist/native-deps-YNKXITRY.mjs +139 -0
  104. package/dist/profiles.d-DqS1oZWr.d.ts +41 -0
  105. package/dist/profiles.d.ts +41 -0
  106. package/dist/profiles.mjs +33 -0
  107. package/dist/redact.d.ts +159 -0
  108. package/dist/redact.mjs +11 -0
  109. package/dist/refresh.d.ts +118 -0
  110. package/dist/refresh.mjs +21 -0
  111. package/dist/reinit-watcher.d.ts +15 -0
  112. package/dist/reinit-watcher.mjs +8 -0
  113. package/dist/session-metadata-B9aV_n5g.d.ts +148 -0
  114. package/dist/tty-prompt.d.ts +44 -0
  115. package/dist/tty-prompt.mjs +39 -0
  116. package/dist/vault.d-BtRSLZiM.d.ts +8 -0
  117. package/dist/vault.d.ts +37 -0
  118. package/dist/vault.mjs +21 -0
  119. package/dist/viewer-detect.d-HWGnyFAA.d.ts +4 -0
  120. package/dist/viewer-detect.d.ts +4 -0
  121. package/dist/viewer-detect.mjs +37 -0
  122. package/dist/viewers.d-BGCK6sw6.d.ts +10 -0
  123. package/dist/viewers.d.ts +18 -0
  124. package/dist/viewers.mjs +122 -0
  125. package/package.json +152 -0
@@ -0,0 +1,41 @@
1
+ interface ProfileMeta {
2
+ name: string;
3
+ displayName: string;
4
+ createdAt: string;
5
+ loginMode?: string;
6
+ tier?: string;
7
+ lastLogin?: string;
8
+ }
9
+
10
+ interface ProfilePaths {
11
+ dir: string;
12
+ meta: string;
13
+ vault: string;
14
+ vaultPlain: string;
15
+ browserData: string;
16
+ modelsCache: string;
17
+ history: string;
18
+ attachments: string;
19
+ researches: string;
20
+ reinit: string;
21
+ }
22
+
23
+ declare function getConfigDir(): string;
24
+ declare function getProfilesDir(): string;
25
+ declare function getProfilePaths(name: string): ProfilePaths;
26
+ declare function validateName(name: string): string | null;
27
+ declare function createProfile(name: string, opts?: { displayName?: string; loginMode?: string }): ProfileMeta;
28
+ declare function listProfiles(): ProfileMeta[];
29
+ declare function getProfile(name: string): ProfileMeta | null;
30
+ declare function deleteProfile(name: string): void;
31
+ declare function getActiveName(): string | null;
32
+ declare function getActive(): ProfileMeta | null;
33
+ declare function setActive(name: string): void;
34
+ declare function suggestNextDefaultName(): string;
35
+ declare function renameProfile(oldName: string, newName: string): void;
36
+ declare function recordLoginSuccess(
37
+ name: string,
38
+ opts: { tier: string; loginMode: string; lastLogin: string }
39
+ ): ProfileMeta;
40
+
41
+ export { type ProfileMeta, type ProfilePaths, createProfile, deleteProfile, getActive, getActiveName, getConfigDir, getProfile, getProfilePaths, getProfilesDir, listProfiles, recordLoginSuccess, renameProfile, setActive, suggestNextDefaultName, validateName };
@@ -0,0 +1,33 @@
1
+ import {
2
+ createProfile,
3
+ deleteProfile,
4
+ getActive,
5
+ getActiveName,
6
+ getConfigDir,
7
+ getProfile,
8
+ getProfilePaths,
9
+ getProfilesDir,
10
+ listProfiles,
11
+ recordLoginSuccess,
12
+ renameProfile,
13
+ setActive,
14
+ suggestNextDefaultName,
15
+ validateName
16
+ } from "./chunk-XKSWCEGI.mjs";
17
+ import "./chunk-4UEJOM6W.mjs";
18
+ export {
19
+ createProfile,
20
+ deleteProfile,
21
+ getActive,
22
+ getActiveName,
23
+ getConfigDir,
24
+ getProfile,
25
+ getProfilePaths,
26
+ getProfilesDir,
27
+ listProfiles,
28
+ recordLoginSuccess,
29
+ renameProfile,
30
+ setActive,
31
+ suggestNextDefaultName,
32
+ validateName
33
+ };
@@ -0,0 +1,159 @@
1
+ // Security-critical: scrubs sensitive patterns from strings before logging
2
+ // or before sending to external destinations (GitHub issue reports, debug
3
+ // exports). Pattern list ordered from most-specific to least-specific to
4
+ // avoid accidental re-matching by a more general rule.
5
+
6
+ // Scope: this module is called on OUR OWN trusted log/debug data (logger
7
+ // output, doctor reports, cookies). It is NOT a user-input sanitizer.
8
+ // Deliberate trade-offs in the current pattern set:
9
+ // - Emails are matched post-URL-decode only (raw %40 encoded forms pass through)
10
+ // - Unix home paths assume no whitespace in usernames
11
+ // - Windows home paths only cover C:\Users\... (UNC paths pass through)
12
+ // - Long-token redaction (≥20 base64/hex chars) may over-redact legitimate
13
+ // long URLs or JSON values — accepted trade-off for safety over debuggability
14
+ // If any of these assumptions changes (e.g., we start redacting user-supplied
15
+ // payloads), the pattern set must be revisited.
16
+
17
+ /**
18
+ * Canonical secret-shape regex list. Distinct from the legacy PATTERNS array
19
+ * below because every match emits a kind-tagged `<redacted:<kind>>` placeholder
20
+ * so the redactor's output is unambiguous for audit / test / grep-gate
21
+ * purposes. Applied BEFORE the legacy PATTERNS inside redactString so specific
22
+ * shapes win over the generic long-token catchall.
23
+ */
24
+ const SECRET_PATTERNS = Object.freeze([
25
+ // OAuth / local prefixes come FIRST so a value like `"bearer":"pplx_at_…"`
26
+ // gets the specific oauth-access tag instead of the generic daemon-bearer
27
+ // one from the bearer-json catchall below.
28
+ { name: "oauth-access", kind: "oauth-access", re: /pplx_at_[A-Za-z0-9_\-]{10,}/g },
29
+ { name: "oauth-refresh", kind: "oauth-refresh", re: /pplx_rt_[A-Za-z0-9_\-]{10,}/g },
30
+ { name: "oauth-code", kind: "oauth-code", re: /pplx_ac_[A-Za-z0-9_\-]{10,}/g },
31
+ { name: "local-bearer", kind: "local-bearer", re: /pplx_local_[a-z0-9-]+_[A-Za-z0-9_\-]{10,}/g },
32
+ { name: "daemon-bearer-json", kind: "daemon-bearer", re: /"bearerToken"\s*:\s*"[A-Za-z0-9_\-]{30,}"/g },
33
+ // Matches the `"bearer":"..."` shape used by daemon:bearer:reveal:response
34
+ // so reveal-payload logs stay leak-free. Value is only required to be
35
+ // 20+ safe-identifier chars — covers both raw daemon bearers and future
36
+ // short-lived tokens.
37
+ { name: "bearer-json", kind: "daemon-bearer", re: /"bearer"\s*:\s*"[A-Za-z0-9_\-]{20,}"/g },
38
+ { name: "authorization-header", kind: "bearer-header", re: /[Aa]uthorization\s*:\s*Bearer\s+[A-Za-z0-9_\-\.]{20,}/g },
39
+ { name: "ngrok-authtoken", kind: "ngrok-authtoken", re: /"authtoken"\s*:\s*"\d+[A-Za-z0-9]{20,}"/g },
40
+ { name: "jwt", kind: "jwt", re: /eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+/g },
41
+ { name: "cf-clearance", kind: "cf-clearance", re: /cf_clearance=[^;\s]+/g },
42
+ { name: "perplexity-session", kind: "perplexity-session", re: /__Secure-next-auth\.session-token=[^;\s]+/g },
43
+ ]);
44
+
45
+ /**
46
+ * String-only secret redactor. Applies SECRET_PATTERNS and returns a string
47
+ * with kind-tagged placeholders. Does NOT apply the legacy PATTERNS
48
+ * (emails / userIds / paths / IPs / generic long-token); call `redact()` for
49
+ * the full composite behavior.
50
+ * @param {string} input
51
+ * @returns {string}
52
+ */
53
+ function redactSecrets(input) {
54
+ if (typeof input !== "string") return input;
55
+ let out = input;
56
+ for (const { re, kind } of SECRET_PATTERNS) {
57
+ out = out.replace(re, (match) => {
58
+ if (match.startsWith('"bearerToken"')) return `"bearerToken":"<redacted:${kind}>"`;
59
+ if (match.startsWith('"bearer"')) return `"bearer":"<redacted:${kind}>"`;
60
+ if (/^[Aa]uthorization\s*:/i.test(match)) return match.replace(/Bearer\s+[A-Za-z0-9_\-\.]{20,}/, `Bearer <redacted:${kind}>`);
61
+ if (match.startsWith('"authtoken"')) return `"authtoken":"<redacted:${kind}>"`;
62
+ if (match.startsWith("cf_clearance=")) return `cf_clearance=<redacted:${kind}>`;
63
+ if (match.startsWith("__Secure-next-auth.session-token=")) return `__Secure-next-auth.session-token=<redacted:${kind}>`;
64
+ return `<redacted:${kind}>`;
65
+ });
66
+ }
67
+ return out;
68
+ }
69
+
70
+ const PATTERNS = [
71
+ // Emails: RFC 5322 subset. Must come before generic token rules because
72
+ // emails contain characters that other rules would catch.
73
+ {
74
+ re: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
75
+ replace: "<email>",
76
+ },
77
+ // Perplexity user IDs: user_ followed by hex/alphanum (>=8 chars).
78
+ {
79
+ re: /\buser_[A-Fa-f0-9]{8,}\b/g,
80
+ replace: "<userId>",
81
+ },
82
+ // Home directory paths. Must replace before the "long opaque token" rule
83
+ // because long path segments would otherwise trip it.
84
+ {
85
+ re: /(\/Users\/|\/home\/)[^/\s]+/g,
86
+ replace: "<home>",
87
+ },
88
+ {
89
+ re: /([A-Z]:)\\Users\\[^\\]+/g,
90
+ replace: "<home>",
91
+ },
92
+ // IPv4
93
+ {
94
+ re: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
95
+ replace: "<ip>",
96
+ },
97
+ // IPv6. Three alternations cover: (1) full 8-group addresses, (2) :: compressed
98
+ // forms with at least one prefix group (e.g. 2001:db8::1, fe80::1), (3) leading-::
99
+ // forms like ::1 and ::. A function filter then requires hex letters (a-f/A-F) OR
100
+ // a double-colon so that pure-digit colon-separated strings like "23:59:59"
101
+ // (HH:MM:SS wall-clock) and ISO timestamps are left untouched.
102
+ {
103
+ re: /\b(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\b|\b(?:[0-9a-fA-F]{1,4}:){1,7}:(?:[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4}){0,6})?\b|(?<!\w)::(?:[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4}){0,6})?(?!\w)/g,
104
+ replace: (match) => {
105
+ const hasHex = /[a-fA-F]/.test(match);
106
+ const hasDoubleColon = /::/.test(match);
107
+ return (hasHex || hasDoubleColon) ? "<ip>" : match;
108
+ },
109
+ },
110
+ // Long opaque tokens (base64 / hex, >=20 chars). Applied last so more
111
+ // specific rules win first. Captures key=value and replaces only the value.
112
+ {
113
+ re: /=([A-Za-z0-9+/=]{20,})/g,
114
+ replace: "=<redacted>",
115
+ },
116
+ ];
117
+
118
+ /**
119
+ * Redact sensitive patterns from a string or object graph.
120
+ * For objects: every string-valued leaf is redacted recursively.
121
+ * Arrays are handled recursively too. Primitive non-strings are returned unchanged.
122
+ * @template T
123
+ * @param {T} value
124
+ * @param {WeakSet<object>} [_seen]
125
+ * @returns {T}
126
+ */
127
+ function redact(value, _seen) {
128
+ if (value == null) return value;
129
+ if (typeof value === "string") return redactString(value);
130
+ if (typeof value !== "object") return value;
131
+
132
+ // Cycle detection for objects/arrays. We use a WeakSet threaded through the
133
+ // recursion so siblings don't falsely collide with each other.
134
+ const seen = _seen ?? new WeakSet();
135
+ if (seen.has(value)) return "<circular>";
136
+ seen.add(value);
137
+
138
+ if (Array.isArray(value)) return value.map((v) => redact(v, seen));
139
+
140
+ const out = {};
141
+ for (const [k, v] of Object.entries(value)) out[k] = redact(v, seen);
142
+ return out;
143
+ }
144
+
145
+ function redactString(s) {
146
+ // SECRET_PATTERNS first: specific bearer / OAuth / JWT / ngrok / cookie
147
+ // shapes get tagged "<redacted:<kind>>" placeholders. Then the legacy
148
+ // PATTERNS handle everything else (emails / userIds / home paths / IPs /
149
+ // generic long-token catchall). Running secrets first prevents the generic
150
+ // `=(20+chars)` catchall from eating a bearer with a plain `<redacted>`
151
+ // label when we'd rather have `<redacted:oauth-access>`.
152
+ let out = redactSecrets(s);
153
+ for (const { re, replace } of PATTERNS) {
154
+ out = out.replace(re, replace);
155
+ }
156
+ return out;
157
+ }
158
+
159
+ export { SECRET_PATTERNS, redact, redactSecrets };
@@ -0,0 +1,11 @@
1
+ import {
2
+ SECRET_PATTERNS,
3
+ redact,
4
+ redactSecrets
5
+ } from "./chunk-HMKLWVXB.mjs";
6
+ import "./chunk-4UEJOM6W.mjs";
7
+ export {
8
+ SECRET_PATTERNS,
9
+ redact,
10
+ redactSecrets
11
+ };
@@ -0,0 +1,118 @@
1
+ import { PlaywrightCookie } from './config.js';
2
+ import 'patchright';
3
+
4
+ /**
5
+ * Live refresh of account info (models/config, ASI access, rate limits, experiments).
6
+ *
7
+ * Architecture — three pluggable tiers, tried in order:
8
+ *
9
+ * 1. got-scraping — pure JS HTTP client (Apify's got fork). Reorders TLS
10
+ * extensions + HTTP/2 SETTINGS + header ordering to look Chrome-ish.
11
+ * ~200ms round trip. Always available (shipped as a regular dep).
12
+ *
13
+ * 2. impit (optional) — Rust-backed JA3/JA4 impersonation via rustls-patched +
14
+ * reqwest. Closer to real Chrome than got-scraping. Only attempted if the
15
+ * user has installed it into ~/.perplexity-mcp/native-deps/ (Settings
16
+ * → Speed Boost). ~300-500ms.
17
+ *
18
+ * 3. browser — headless Patchright. Guaranteed to work because Chromium
19
+ * speaks the same TLS as whatever solved Turnstile at login time. ~3-5s.
20
+ *
21
+ * Each tier returns the same TierResult shape so the orchestrator can just
22
+ * walk them in order. A CF challenge (HTML response instead of JSON) counts
23
+ * as "try the next tier". Anything else (network error, 5xx, unparseable)
24
+ * also cascades.
25
+ */
26
+
27
+ type RefreshTier = "got-scraping" | "impit" | "browser";
28
+ interface RefreshResult {
29
+ ok: boolean;
30
+ source: "live" | "no-cookies" | "cf-challenge" | "failed";
31
+ tier: RefreshTier | null;
32
+ modelCount: number;
33
+ accountTier: "Max" | "Pro" | "Enterprise" | "Free" | "Unknown";
34
+ error?: string;
35
+ cachePath: string;
36
+ elapsedMs: number;
37
+ tierAttempts?: Array<{
38
+ tier: RefreshTier;
39
+ ok: boolean;
40
+ elapsedMs: number;
41
+ error?: string;
42
+ }>;
43
+ }
44
+ interface RefreshOptions {
45
+ log?: (line: string) => void;
46
+ timeoutMs?: number;
47
+ /** Force a particular tier for testing. Omit for normal cascade. */
48
+ forceTier?: RefreshTier;
49
+ }
50
+ /**
51
+ * Minimal shape of the `impit` module that we actually call.
52
+ * Full types aren't declared in our tsconfig because impit is NOT a build-time
53
+ * dependency — it's installed at runtime by the user via "Install Speed Boost".
54
+ */
55
+ interface ImpitModule {
56
+ Impit: new (opts: {
57
+ browser: string;
58
+ ignoreTlsErrors?: boolean;
59
+ proxyUrl?: string;
60
+ }) => {
61
+ fetch(url: string, init?: {
62
+ method?: string;
63
+ body?: string | Uint8Array;
64
+ headers?: Record<string, string>;
65
+ signal?: AbortSignal;
66
+ redirect?: "follow" | "manual" | "error";
67
+ }): Promise<{
68
+ status: number;
69
+ headers: Headers | Record<string, string>;
70
+ text(): Promise<string>;
71
+ json(): Promise<unknown>;
72
+ }>;
73
+ };
74
+ }
75
+ /**
76
+ * Dynamically import impit from the user's native-deps directory.
77
+ * Returns null if impit isn't installed there.
78
+ *
79
+ * Note on createRequire: when this code is bundled into the extension host
80
+ * (CJS via tsup), `import.meta.url` is undefined, which makes
81
+ * `createRequire(import.meta.url)` throw — the previous implementation
82
+ * silently caught that and reported "impit not installed" even when the
83
+ * package was on disk. Rooting `createRequire` at the impit module's own
84
+ * absolute path works in both CJS- and ESM-bundled output (Node accepts a
85
+ * file path string per the docs) and resolves impit's peer native binding
86
+ * from native-deps/node_modules correctly.
87
+ */
88
+ declare function loadImpit(): Promise<ImpitModule | null>;
89
+ declare function isImpitAvailable(): boolean;
90
+ /**
91
+ * Browser-free authenticated fetch via impit. Used as a fast path for REST
92
+ * endpoints that only need cookies + a Chrome-ish TLS fingerprint
93
+ * (e.g. /rest/thread/list_ask_threads). Callers should fall back to the
94
+ * browser path on any non-success outcome.
95
+ *
96
+ * Returns null when impit isn't installed/loadable or the request threw at
97
+ * the network level. Returns `{ challenged: true }` when the response body
98
+ * looks like a Cloudflare interstitial.
99
+ */
100
+ declare function impitFetchJson(url: string, init: {
101
+ method?: string;
102
+ body?: unknown;
103
+ headers?: Record<string, string>;
104
+ } | undefined, cookies: PlaywrightCookie[], timeoutMs?: number): Promise<{
105
+ status: number;
106
+ data: unknown;
107
+ challenged?: boolean;
108
+ } | null>;
109
+ declare function refreshAccountInfo(opts?: RefreshOptions): Promise<RefreshResult>;
110
+ declare function getModelsCacheInfo(): {
111
+ path: string;
112
+ exists: boolean;
113
+ mtime: Date | null;
114
+ ageHours: number | null;
115
+ };
116
+ declare function getImpitRuntimeDir(): string;
117
+
118
+ export { type ImpitModule, type RefreshOptions, type RefreshResult, type RefreshTier, getImpitRuntimeDir, getModelsCacheInfo, impitFetchJson, isImpitAvailable, loadImpit, refreshAccountInfo };
@@ -0,0 +1,21 @@
1
+ import {
2
+ getImpitRuntimeDir,
3
+ getModelsCacheInfo,
4
+ impitFetchJson,
5
+ isImpitAvailable,
6
+ loadImpit,
7
+ refreshAccountInfo
8
+ } from "./chunk-Z7DAACGZ.mjs";
9
+ import "./chunk-LKJMLGFP.mjs";
10
+ import "./chunk-TQLCLE4L.mjs";
11
+ import "./chunk-MTDFKNXX.mjs";
12
+ import "./chunk-XKSWCEGI.mjs";
13
+ import "./chunk-4UEJOM6W.mjs";
14
+ export {
15
+ getImpitRuntimeDir,
16
+ getModelsCacheInfo,
17
+ impitFetchJson,
18
+ isImpitAvailable,
19
+ loadImpit,
20
+ refreshAccountInfo
21
+ };
@@ -0,0 +1,15 @@
1
+ interface ReinitWatcher {
2
+ dispose(): void;
3
+ }
4
+
5
+ interface WatchReinitOptions {
6
+ debounceMs?: number;
7
+ }
8
+
9
+ declare function watchReinit(
10
+ profileName: string,
11
+ callback: () => void | Promise<void>,
12
+ opts?: WatchReinitOptions
13
+ ): ReinitWatcher;
14
+
15
+ export { type ReinitWatcher, type WatchReinitOptions, watchReinit };
@@ -0,0 +1,8 @@
1
+ import {
2
+ watchReinit
3
+ } from "./chunk-U3DGFLXZ.mjs";
4
+ import "./chunk-XKSWCEGI.mjs";
5
+ import "./chunk-4UEJOM6W.mjs";
6
+ export {
7
+ watchReinit
8
+ };
@@ -0,0 +1,148 @@
1
+ const API_VERSION_QUERY = "version=2.18&source=default";
2
+
3
+ function buildRuntimeEndpoints(origin) {
4
+ const base = origin.replace(/\/+$/, "");
5
+ return {
6
+ session: `${base}/api/auth/session?${API_VERSION_QUERY}`,
7
+ csrf: `${base}/api/auth/csrf?${API_VERSION_QUERY}`,
8
+ signInEmail: `${base}/api/auth/signin/email?${API_VERSION_QUERY}`,
9
+ otpRedirectLink: `${base}/api/auth/otp-redirect-link`,
10
+ ssoDetails: `${base}/rest/enterprise/organization/login/details?${API_VERSION_QUERY}`,
11
+ models: `${base}/rest/models/config?config_schema=v1&${API_VERSION_QUERY}`,
12
+ asi: `${base}/rest/billing/asi-access-decision?${API_VERSION_QUERY}`,
13
+ rateLimits: `${base}/rest/rate-limit/status?${API_VERSION_QUERY}`,
14
+ experiments: `${base}/rest/experiments/attributes?${API_VERSION_QUERY}`,
15
+ userInfo: `${base}/rest/user/info?${API_VERSION_QUERY}`,
16
+ };
17
+ }
18
+
19
+ async function pageRequest(page, url, init = {}) {
20
+ return page.evaluate(async ({ url: target, init: requestInit }) => {
21
+ try {
22
+ const response = await fetch(target, {
23
+ credentials: "include",
24
+ ...requestInit,
25
+ });
26
+ const contentType = response.headers.get("content-type") ?? "";
27
+ let json = null;
28
+ let text = null;
29
+ try {
30
+ if (contentType.includes("json")) json = await response.json();
31
+ else text = (await response.text()).slice(0, 500);
32
+ } catch {}
33
+ return {
34
+ ok: response.ok,
35
+ status: response.status,
36
+ redirected: response.redirected,
37
+ url: response.url,
38
+ contentType,
39
+ json,
40
+ text,
41
+ };
42
+ } catch (error) {
43
+ return {
44
+ ok: false,
45
+ status: 0,
46
+ redirected: false,
47
+ url: target,
48
+ contentType: "",
49
+ json: null,
50
+ text: null,
51
+ error: error?.message ?? String(error),
52
+ };
53
+ }
54
+ }, { url, init });
55
+ }
56
+
57
+ async function pollSession(page, sessionUrl, { timeoutMs = 10_000, intervalMs = 500 } = {}) {
58
+ const started = Date.now();
59
+ while (Date.now() - started < timeoutMs) {
60
+ const sessionResp = await pageRequest(page, sessionUrl);
61
+ if (sessionResp.ok && sessionResp.json?.user?.id) {
62
+ return sessionResp.json;
63
+ }
64
+ await page.waitForTimeout(intervalMs);
65
+ }
66
+ return null;
67
+ }
68
+
69
+ function deriveAccountFlags({ experiments, userInfo, asi }) {
70
+ const isEnterprise = userInfo?.is_enterprise === true || experiments?.server_is_enterprise === true;
71
+ const isMax = experiments?.server_is_max === true;
72
+ const canUseComputer = asi?.can_use_computer ?? false;
73
+ const isPro =
74
+ experiments?.server_is_pro === true ||
75
+ (canUseComputer && !isMax && !isEnterprise);
76
+
77
+ return { isPro, isMax, isEnterprise, canUseComputer };
78
+ }
79
+
80
+ function deriveTier(payload) {
81
+ const { isPro, isMax, isEnterprise } = deriveAccountFlags(payload);
82
+ if (isMax) return "Max";
83
+ if (isEnterprise) return "Enterprise";
84
+ if (isPro) return "Pro";
85
+ return "Authenticated";
86
+ }
87
+
88
+ async function collectSessionMetadata(page, origin, opts = {}) {
89
+ const endpoints = buildRuntimeEndpoints(origin);
90
+ const sessionData =
91
+ opts.sessionData ??
92
+ await pollSession(page, endpoints.session, { timeoutMs: opts.sessionTimeoutMs ?? 10_000 });
93
+
94
+ if (!sessionData?.user?.id) {
95
+ return {
96
+ sessionData: null,
97
+ models: null,
98
+ asi: null,
99
+ rateLimits: null,
100
+ experiments: null,
101
+ userInfo: null,
102
+ tier: "Authenticated",
103
+ cache: {
104
+ modelsConfig: null,
105
+ rateLimits: null,
106
+ isPro: false,
107
+ isMax: false,
108
+ isEnterprise: false,
109
+ canUseComputer: false,
110
+ },
111
+ };
112
+ }
113
+
114
+ const [modelsResp, asiResp, rateResp, expResp, userInfoResp] = await Promise.all([
115
+ pageRequest(page, endpoints.models),
116
+ pageRequest(page, endpoints.asi),
117
+ pageRequest(page, endpoints.rateLimits),
118
+ pageRequest(page, endpoints.experiments),
119
+ pageRequest(page, endpoints.userInfo),
120
+ ]);
121
+
122
+ const payload = {
123
+ experiments: expResp.ok ? expResp.json : null,
124
+ userInfo: userInfoResp.ok ? userInfoResp.json : null,
125
+ asi: asiResp.ok ? asiResp.json : null,
126
+ };
127
+ const flags = deriveAccountFlags(payload);
128
+
129
+ return {
130
+ sessionData,
131
+ models: modelsResp.ok ? modelsResp.json : null,
132
+ asi: asiResp.ok ? asiResp.json : null,
133
+ rateLimits: rateResp.ok ? rateResp.json : null,
134
+ experiments: expResp.ok ? expResp.json : null,
135
+ userInfo: userInfoResp.ok ? userInfoResp.json : null,
136
+ tier: deriveTier(payload),
137
+ cache: {
138
+ modelsConfig: modelsResp.ok ? modelsResp.json : null,
139
+ rateLimits: rateResp.ok ? rateResp.json : null,
140
+ isPro: flags.isPro,
141
+ isMax: flags.isMax,
142
+ isEnterprise: flags.isEnterprise,
143
+ canUseComputer: flags.canUseComputer,
144
+ },
145
+ };
146
+ }
147
+
148
+ export { buildRuntimeEndpoints as b, collectSessionMetadata as c, pageRequest as p };
@@ -0,0 +1,44 @@
1
+ import { createInterface } from 'node:readline';
2
+
3
+ function promptSecret({ stdin = process.stdin, stderr = process.stderr, prompt = "> " } = {}) {
4
+ return new Promise((resolve) => {
5
+ stderr.write(prompt);
6
+ const rl = createInterface({ input: stdin, output: stderr, terminal: false });
7
+ rl.once("line", (line) => {
8
+ rl.close();
9
+ resolve(String(line).trim());
10
+ });
11
+ });
12
+ }
13
+
14
+ /**
15
+ * Minimal y/N confirmation prompt for destructive-ish CLI subcommands.
16
+ *
17
+ * - Prompt goes to stderr. Answer comes from stdin. Matches the existing
18
+ * `promptSecret` shape so tests can inject fakes.
19
+ * - Accepts `y`, `Y`, `yes`, `YES`, `Yes` as confirmation. Everything else —
20
+ * including empty input, EOF (Ctrl-D), and stdin close — is treated as a
21
+ * decline. Returns `true` on confirm, `false` on decline.
22
+ * - Does NOT exit the process; the caller decides whether to exit 130.
23
+ */
24
+ function promptYesNo({ stdin = process.stdin, stderr = process.stderr, prompt = "Continue? [y/N] " } = {}) {
25
+ return new Promise((resolve) => {
26
+ stderr.write(prompt);
27
+ const rl = createInterface({ input: stdin, output: stderr, terminal: false });
28
+ let settled = false;
29
+ const finish = (value) => {
30
+ if (settled) return;
31
+ settled = true;
32
+ try { rl.close(); } catch { /* ignore */ }
33
+ resolve(value);
34
+ };
35
+ rl.once("line", (line) => {
36
+ const answer = String(line).trim().toLowerCase();
37
+ finish(answer === "y" || answer === "yes");
38
+ });
39
+ // EOF / stream close before a line arrives → decline.
40
+ rl.once("close", () => finish(false));
41
+ });
42
+ }
43
+
44
+ export { promptSecret, promptYesNo };
@@ -0,0 +1,39 @@
1
+ import "./chunk-4UEJOM6W.mjs";
2
+
3
+ // src/tty-prompt.js
4
+ import { createInterface } from "readline";
5
+ function promptSecret({ stdin = process.stdin, stderr = process.stderr, prompt = "> " } = {}) {
6
+ return new Promise((resolve) => {
7
+ stderr.write(prompt);
8
+ const rl = createInterface({ input: stdin, output: stderr, terminal: false });
9
+ rl.once("line", (line) => {
10
+ rl.close();
11
+ resolve(String(line).trim());
12
+ });
13
+ });
14
+ }
15
+ function promptYesNo({ stdin = process.stdin, stderr = process.stderr, prompt = "Continue? [y/N] " } = {}) {
16
+ return new Promise((resolve) => {
17
+ stderr.write(prompt);
18
+ const rl = createInterface({ input: stdin, output: stderr, terminal: false });
19
+ let settled = false;
20
+ const finish = (value) => {
21
+ if (settled) return;
22
+ settled = true;
23
+ try {
24
+ rl.close();
25
+ } catch {
26
+ }
27
+ resolve(value);
28
+ };
29
+ rl.once("line", (line) => {
30
+ const answer = String(line).trim().toLowerCase();
31
+ finish(answer === "y" || answer === "yes");
32
+ });
33
+ rl.once("close", () => finish(false));
34
+ });
35
+ }
36
+ export {
37
+ promptSecret,
38
+ promptYesNo
39
+ };
@@ -0,0 +1,8 @@
1
+ declare class Vault {
2
+ get(profile: string, key: string): Promise<string | null>;
3
+ set(profile: string, key: string, value: string): Promise<void>;
4
+ delete(profile: string, key: string): Promise<void>;
5
+ deleteAll(profile: string): Promise<void>;
6
+ }
7
+
8
+ export { Vault };