@posthog/wizard 2.11.0 → 2.13.0
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/README.md +48 -7
- package/dist/{McpScreen-DvUncZBi.js → AuditChecksViewer-B0J7zcY2.js} +434 -22
- package/dist/AuditChecksViewer-B0J7zcY2.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-Br1hDRiB.js → add-mcp-server-to-clients-CUNR00bB.js} +5 -5
- package/dist/{add-mcp-server-to-clients-Br1hDRiB.js.map → add-mcp-server-to-clients-CUNR00bB.js.map} +1 -1
- package/dist/{readiness-gQvQNCeL.js → agent-interface-CV0-vtxj.js} +328 -462
- package/dist/agent-interface-CV0-vtxj.js.map +1 -0
- package/dist/{agent-runner-fWYFO4H0.js → agent-runner-LvVQH31D.js} +21 -31
- package/dist/{agent-runner-fWYFO4H0.js.map → agent-runner-LvVQH31D.js.map} +1 -1
- package/dist/analytics-BH7bEHQR.js +2 -0
- package/dist/analytics-VM7laaFx.js +123 -0
- package/dist/analytics-VM7laaFx.js.map +1 -0
- package/dist/bin.js +529 -42
- package/dist/bin.js.map +1 -1
- package/dist/{debug-D-0xueVl.js → debug-BdcTB7EF.js} +1 -1
- package/dist/debug-Cqi6nVfX.js +686 -0
- package/dist/debug-Cqi6nVfX.js.map +1 -0
- package/dist/{defaults-CPH6eWhN.js → defaults-GbLPuHxj.js} +1 -1
- package/dist/{defaults-CPH6eWhN.js.map → defaults-GbLPuHxj.js.map} +1 -1
- package/dist/{detection-B7GNzve-.js → detection-CSjmal-X.js} +3 -3
- package/dist/{detection-B7GNzve-.js.map → detection-CSjmal-X.js.map} +1 -1
- package/dist/{env-api-key-DU8uIEvo.js → env-api-key-D5G2PrXW.js} +1 -1
- package/dist/{env-api-key-DU8uIEvo.js.map → env-api-key-D5G2PrXW.js.map} +1 -1
- package/dist/{file-DhSBlq-x.js → file-8iNrXHkG.js} +2 -2
- package/dist/{file-DhSBlq-x.js.map → file-8iNrXHkG.js.map} +1 -1
- package/dist/{file-utils-Dy9JncCo.js → file-utils-DnTSiTJw.js} +1 -1
- package/dist/{file-utils-Dy9JncCo.js.map → file-utils-DnTSiTJw.js.map} +1 -1
- package/dist/{package-manager-D3Lo6nXf.js → package-manager-CD8RQW-e.js} +2 -2
- package/dist/{package-manager-D3Lo6nXf.js.map → package-manager-CD8RQW-e.js.map} +1 -1
- package/dist/paths-DJS47p5x.js +26 -0
- package/dist/paths-DJS47p5x.js.map +1 -0
- package/dist/{posthog-integration-D4SRhJIQ.js → posthog-integration-BL21S3T6.js} +41 -13
- package/dist/posthog-integration-BL21S3T6.js.map +1 -0
- package/dist/{posthog-ByrpqEjN.js → posthog-vm0k9PKS.js} +1 -1
- package/dist/{posthog-ByrpqEjN.js.map → posthog-vm0k9PKS.js.map} +1 -1
- package/dist/provisioning-BdQ1ONIg.js +2 -0
- package/dist/provisioning-g9aoVIEd.js +166 -0
- package/dist/provisioning-g9aoVIEd.js.map +1 -0
- package/dist/{registry-DaPKstG3.js → registry-BaMEaAKd.js} +4 -5
- package/dist/{registry-DaPKstG3.js.map → registry-BaMEaAKd.js.map} +1 -1
- package/dist/{router-SgzmfLGi.js → router-COhhuIW3.js} +4 -3
- package/dist/router-COhhuIW3.js.map +1 -0
- package/dist/{setup-utils-y4s-3uKT.js → setup-utils-CNV7FSlY.js} +11 -150
- package/dist/setup-utils-CNV7FSlY.js.map +1 -0
- package/dist/setup-utils-CU4FIqjB.js +2 -0
- package/dist/{start-playground-g1TxpCZ5.js → start-playground-C9GWnVdM.js} +102 -7
- package/dist/start-playground-C9GWnVdM.js.map +1 -0
- package/dist/start-tui-B_zwutLe.js +4195 -0
- package/dist/start-tui-B_zwutLe.js.map +1 -0
- package/dist/{steps-D1zKDqAo.js → steps-Dawz7k3T.js} +8 -8
- package/dist/steps-Dawz7k3T.js.map +1 -0
- package/dist/{task-stream-DX_jKDQu.js → task-stream-CX7Uf6EM.js} +4 -4
- package/dist/{task-stream-DX_jKDQu.js.map → task-stream-CX7Uf6EM.js.map} +1 -1
- package/dist/{telemetry-CyUUSAYy.js → telemetry-D6bjWA-A.js} +2 -2
- package/dist/{telemetry-CyUUSAYy.js.map → telemetry-D6bjWA-A.js.map} +1 -1
- package/dist/{wizard-abort-Buodno3f.js → wizard-abort-CJkNkSjT.js} +6 -4
- package/dist/{wizard-abort-Buodno3f.js.map → wizard-abort-CJkNkSjT.js.map} +1 -1
- package/dist/{wizard-abort-DZmO_sIZ.js → wizard-abort-Dl0BkqhT.js} +1 -1
- package/dist/wizard-session-BQC9vy9Z.js +2 -0
- package/dist/{wizard-session-D5bggSsu.js → wizard-session-BcNJTl2I.js} +1 -1
- package/dist/{wizard-session-D5bggSsu.js.map → wizard-session-BcNJTl2I.js.map} +1 -1
- package/dist/{wizard-ui-BExOjdjA.js → wizard-ui-YdGFRyu_.js} +1 -1
- package/dist/wizard-ui-YdGFRyu_.js.map +1 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/McpScreen-DvUncZBi.js.map +0 -1
- package/dist/agent-skill-DJOzDaQV.js +0 -59
- package/dist/agent-skill-DJOzDaQV.js.map +0 -1
- package/dist/analytics-CfAUlt6-.js +0 -2
- package/dist/analytics-D3rY3TaN.js +0 -210
- package/dist/analytics-D3rY3TaN.js.map +0 -1
- package/dist/debug-gWEjmYVV.js +0 -203
- package/dist/debug-gWEjmYVV.js.map +0 -1
- package/dist/paths-BL-x2rFy.js +0 -16
- package/dist/paths-BL-x2rFy.js.map +0 -1
- package/dist/posthog-integration-D4SRhJIQ.js.map +0 -1
- package/dist/readiness-gQvQNCeL.js.map +0 -1
- package/dist/router-SgzmfLGi.js.map +0 -1
- package/dist/setup-utils-_ONxN-TT.js +0 -2
- package/dist/setup-utils-y4s-3uKT.js.map +0 -1
- package/dist/start-playground-g1TxpCZ5.js.map +0 -1
- package/dist/start-tui-CQef69NR.js +0 -2167
- package/dist/start-tui-CQef69NR.js.map +0 -1
- package/dist/steps-D1zKDqAo.js.map +0 -1
- package/dist/wizard-session-COhklXAF.js +0 -2
- package/dist/wizard-ui-BExOjdjA.js.map +0 -1
|
@@ -0,0 +1,686 @@
|
|
|
1
|
+
import "./wizard-ui-YdGFRyu_.js";
|
|
2
|
+
import { n as WIZARD_LOG_FILE } from "./paths-DJS47p5x.js";
|
|
3
|
+
import { appendFileSync } from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
//#region src/utils/logging.ts
|
|
6
|
+
function prepareMessage(msg) {
|
|
7
|
+
if (typeof msg === "string") return msg;
|
|
8
|
+
if (msg instanceof Error) return `${msg.stack || ""}`;
|
|
9
|
+
return JSON.stringify(msg, null, " ");
|
|
10
|
+
}
|
|
11
|
+
function l(msg) {
|
|
12
|
+
console.log(msg);
|
|
13
|
+
}
|
|
14
|
+
function red(msg) {
|
|
15
|
+
return l(prepareMessage(msg));
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/lib/version.ts
|
|
19
|
+
const VERSION = "2.13.0";
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/env.ts
|
|
22
|
+
/**
|
|
23
|
+
* Central environment variable access for the PostHog wizard.
|
|
24
|
+
*
|
|
25
|
+
* ── Build-time constants ────────────────────────────────────────────
|
|
26
|
+
* Inlined by tsdown's `env` option at compile time. After build, the
|
|
27
|
+
* runtime value of these env vars has zero effect on the wizard.
|
|
28
|
+
*
|
|
29
|
+
* ── Runtime variables ───────────────────────────────────────────────
|
|
30
|
+
* Read through `runtimeEnv()` with a typed allowlist. This makes every
|
|
31
|
+
* runtime dependency on the environment explicit and grep-able.
|
|
32
|
+
*
|
|
33
|
+
* ── Direct process.env access ───────────────────────────────────────
|
|
34
|
+
* Reserved for subprocess environment configuration (writes) and
|
|
35
|
+
* vendored code. Production source outside those cases should use
|
|
36
|
+
* this module instead.
|
|
37
|
+
*/
|
|
38
|
+
const NODE_ENV = "production";
|
|
39
|
+
/** Read a runtime environment variable. Only allowlisted keys compile. */
|
|
40
|
+
function runtimeEnv(key) {
|
|
41
|
+
return process.env[key];
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/lib/constants.ts
|
|
45
|
+
/**
|
|
46
|
+
* Shared constants for the PostHog wizard.
|
|
47
|
+
*/
|
|
48
|
+
/**
|
|
49
|
+
* Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.
|
|
50
|
+
*/
|
|
51
|
+
let Integration = /* @__PURE__ */ function(Integration) {
|
|
52
|
+
Integration["nextjs"] = "nextjs";
|
|
53
|
+
Integration["nuxt"] = "nuxt";
|
|
54
|
+
Integration["vue"] = "vue";
|
|
55
|
+
Integration["reactRouter"] = "react-router";
|
|
56
|
+
Integration["tanstackStart"] = "tanstack-start";
|
|
57
|
+
Integration["tanstackRouter"] = "tanstack-router";
|
|
58
|
+
Integration["reactNative"] = "react-native";
|
|
59
|
+
Integration["angular"] = "angular";
|
|
60
|
+
Integration["astro"] = "astro";
|
|
61
|
+
Integration["django"] = "django";
|
|
62
|
+
Integration["flask"] = "flask";
|
|
63
|
+
Integration["fastapi"] = "fastapi";
|
|
64
|
+
Integration["laravel"] = "laravel";
|
|
65
|
+
Integration["sveltekit"] = "sveltekit";
|
|
66
|
+
Integration["swift"] = "swift";
|
|
67
|
+
Integration["android"] = "android";
|
|
68
|
+
Integration["rails"] = "rails";
|
|
69
|
+
Integration["python"] = "python";
|
|
70
|
+
Integration["ruby"] = "ruby";
|
|
71
|
+
Integration["javascriptNode"] = "javascript_node";
|
|
72
|
+
Integration["javascript_web"] = "javascript_web";
|
|
73
|
+
return Integration;
|
|
74
|
+
}({});
|
|
75
|
+
const DEFAULT_HOST_URL = "https://us.i.posthog.com";
|
|
76
|
+
const ISSUES_URL = "https://github.com/posthog/wizard/issues";
|
|
77
|
+
const CONTEXT_MILL_URL = "https://github.com/PostHog/context-mill";
|
|
78
|
+
const POSTHOG_DOCS_URL = "https://posthog.com/docs";
|
|
79
|
+
/** Remote base URL for fetching the skill menu + downloading skills. */
|
|
80
|
+
const REMOTE_SKILLS_BASE_URL = "https://github.com/PostHog/context-mill/releases/latest/download";
|
|
81
|
+
/** Local base URL when `--local-mcp` is set (served by context-mill dev server). */
|
|
82
|
+
const LOCAL_SKILLS_BASE_URL = "http://localhost:8765";
|
|
83
|
+
/**
|
|
84
|
+
* Pick the skills base URL based on the session's localMcp flag.
|
|
85
|
+
* Single source of truth — do not inline this ternary anywhere.
|
|
86
|
+
*/
|
|
87
|
+
function getSkillsBaseUrl(localMcp) {
|
|
88
|
+
return localMcp ? LOCAL_SKILLS_BASE_URL : REMOTE_SKILLS_BASE_URL;
|
|
89
|
+
}
|
|
90
|
+
const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = "sTMFPsFhdP1Ssg";
|
|
91
|
+
const ANALYTICS_HOST_URL = "https://internal-j.posthog.com";
|
|
92
|
+
const ANALYTICS_TEAM_TAG = "docs-and-wizard";
|
|
93
|
+
const POSTHOG_OAUTH_URL = "https://oauth.posthog.com";
|
|
94
|
+
const OAUTH_PORTS = [
|
|
95
|
+
8239,
|
|
96
|
+
8238,
|
|
97
|
+
8240,
|
|
98
|
+
8237,
|
|
99
|
+
8236,
|
|
100
|
+
8235
|
|
101
|
+
];
|
|
102
|
+
const POSTHOG_US_CLIENT_ID = "c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM";
|
|
103
|
+
const POSTHOG_DEV_CLIENT_ID = "DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ";
|
|
104
|
+
const POSTHOG_PROXY_CLIENT_ID = POSTHOG_US_CLIENT_ID;
|
|
105
|
+
const DUMMY_PROJECT_API_KEY = "_YOUR_POSTHOG_PROJECT_TOKEN_";
|
|
106
|
+
/**
|
|
107
|
+
* Scopes the wizard requests during the agentic provisioning signup flow.
|
|
108
|
+
*
|
|
109
|
+
* Each entry is justified by what the wizard's agent step does after signup:
|
|
110
|
+
* - user:read identify the user for analytics + agent context
|
|
111
|
+
* - project:read look up the freshly-provisioned project
|
|
112
|
+
* - llm_gateway:read authenticate to gateway.{us,eu}.posthog.com/wizard
|
|
113
|
+
* (the agent's LLM calls — without this scope, every
|
|
114
|
+
* agent message returns 401)
|
|
115
|
+
* - query:read run HogQL queries when the agent needs data
|
|
116
|
+
* - dashboard:write create the onboarding dashboard during setup
|
|
117
|
+
* - insight:write create the onboarding insights during setup
|
|
118
|
+
*
|
|
119
|
+
* Must be a subset of `ALLOWED_PROVISIONING_SCOPES` in
|
|
120
|
+
* `ee/api/agentic_provisioning/views.py` on the backend.
|
|
121
|
+
*/
|
|
122
|
+
const WIZARD_PROVISIONING_SCOPES = [
|
|
123
|
+
"user:read",
|
|
124
|
+
"project:read",
|
|
125
|
+
"llm_gateway:read",
|
|
126
|
+
"dashboard:write",
|
|
127
|
+
"insight:write",
|
|
128
|
+
"query:read"
|
|
129
|
+
];
|
|
130
|
+
/**
|
|
131
|
+
* Scopes the wizard requests during the OAuth login flow. Superset of
|
|
132
|
+
* `WIZARD_PROVISIONING_SCOPES` with two scopes that only apply to the login
|
|
133
|
+
* path and are not in the provisioning allowlist:
|
|
134
|
+
* - introspection lets the wizard introspect its own token
|
|
135
|
+
* - health_issue:read used by `wizard doctor`
|
|
136
|
+
*/
|
|
137
|
+
const WIZARD_OAUTH_SCOPES = [
|
|
138
|
+
...WIZARD_PROVISIONING_SCOPES,
|
|
139
|
+
"introspection",
|
|
140
|
+
"health_issue:read"
|
|
141
|
+
];
|
|
142
|
+
const WIZARD_INTERACTION_EVENT_NAME = "wizard interaction";
|
|
143
|
+
const WIZARD_REMARK_EVENT_NAME = "wizard remark";
|
|
144
|
+
/** Feature flag key whose value selects a variant from WIZARD_VARIANTS. */
|
|
145
|
+
const WIZARD_VARIANT_FLAG_KEY = "wizard-variant";
|
|
146
|
+
/** Feature flag key that gates the intro-screen "Tools" menu. */
|
|
147
|
+
const WIZARD_TOOLS_MENU_FLAG_KEY = "wizard-tools-menu";
|
|
148
|
+
/** Variant key -> metadata for wizard run (VARIANT flag selects which entry to use). */
|
|
149
|
+
const WIZARD_VARIANTS = {
|
|
150
|
+
base: { VARIANT: "base" },
|
|
151
|
+
subagents: { VARIANT: "subagents" }
|
|
152
|
+
};
|
|
153
|
+
/** User-Agent for wizard HTTP requests and MCP server identification. */
|
|
154
|
+
const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`;
|
|
155
|
+
/** Header prefix for PostHog properties (e.g. X-POSTHOG-PROPERTY-VARIANT). */
|
|
156
|
+
const POSTHOG_PROPERTY_HEADER_PREFIX = "X-POSTHOG-PROPERTY-";
|
|
157
|
+
/** Header prefix for PostHog feature flags. */
|
|
158
|
+
const POSTHOG_FLAG_HEADER_PREFIX = "X-POSTHOG-FLAG-";
|
|
159
|
+
/** Timeout for framework / project detection probes (ms). */
|
|
160
|
+
const DETECTION_TIMEOUT_MS = 1e4;
|
|
161
|
+
/** Timeout for the OAuth authorization flow (ms). */
|
|
162
|
+
const OAUTH_TIMEOUT_MS = 36e4;
|
|
163
|
+
//#endregion
|
|
164
|
+
//#region src/lib/health-checks/statuspage.ts
|
|
165
|
+
function mapIndicator(v) {
|
|
166
|
+
switch (v) {
|
|
167
|
+
case "none": return "healthy";
|
|
168
|
+
case "minor": return "degraded";
|
|
169
|
+
case "major":
|
|
170
|
+
case "critical": return "down";
|
|
171
|
+
default: return "degraded";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function mapComponentRaw(v) {
|
|
175
|
+
switch (v) {
|
|
176
|
+
case "operational": return "healthy";
|
|
177
|
+
case "degraded_performance":
|
|
178
|
+
case "under_maintenance": return "degraded";
|
|
179
|
+
case "partial_outage":
|
|
180
|
+
case "major_outage": return "down";
|
|
181
|
+
default: return "degraded";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function errResult$1(error) {
|
|
185
|
+
return {
|
|
186
|
+
status: "degraded",
|
|
187
|
+
error
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
async function fetchStatuspageIndicator(url, timeoutMs = 5e3) {
|
|
191
|
+
try {
|
|
192
|
+
const controller = new AbortController();
|
|
193
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
194
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
195
|
+
clearTimeout(tid);
|
|
196
|
+
if (!res.ok) return errResult$1(`HTTP ${res.status}`);
|
|
197
|
+
const indicator = (await res.json()).status?.indicator ?? null;
|
|
198
|
+
return {
|
|
199
|
+
status: mapIndicator(indicator),
|
|
200
|
+
rawIndicator: indicator ?? void 0
|
|
201
|
+
};
|
|
202
|
+
} catch (e) {
|
|
203
|
+
if (e instanceof Error && e.name === "AbortError") return errResult$1("Request timed out");
|
|
204
|
+
return errResult$1(e instanceof Error ? e.message : "Unknown error");
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function fetchStatuspageSummary(url, timeoutMs = 5e3) {
|
|
208
|
+
try {
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
211
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
212
|
+
clearTimeout(tid);
|
|
213
|
+
if (!res.ok) return errResult$1(`HTTP ${res.status}`);
|
|
214
|
+
const data = await res.json();
|
|
215
|
+
const indicator = data.status?.indicator ?? null;
|
|
216
|
+
const overall = mapIndicator(indicator);
|
|
217
|
+
const affected = (data.components ?? []).map((c) => ({
|
|
218
|
+
name: c.name,
|
|
219
|
+
status: mapComponentRaw(c.status),
|
|
220
|
+
rawStatus: c.status
|
|
221
|
+
})).filter((c) => c.status !== "healthy");
|
|
222
|
+
return {
|
|
223
|
+
status: affected.length > 0 ? "degraded" : overall,
|
|
224
|
+
rawIndicator: indicator ?? void 0,
|
|
225
|
+
degradedOrDownComponents: affected.length > 0 ? affected : void 0
|
|
226
|
+
};
|
|
227
|
+
} catch (e) {
|
|
228
|
+
if (e instanceof Error && e.name === "AbortError") return errResult$1("Request timed out");
|
|
229
|
+
return errResult$1(e instanceof Error ? e.message : "Unknown error");
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const checkAnthropicHealth = () => fetchStatuspageIndicator("https://status.claude.com/api/v2/status.json");
|
|
233
|
+
const checkGithubHealth = () => fetchStatuspageIndicator("https://www.githubstatus.com/api/v2/status.json");
|
|
234
|
+
const checkNpmOverallHealth = () => fetchStatuspageIndicator("https://status.npmjs.org/api/v2/status.json");
|
|
235
|
+
const checkNpmComponentHealth = () => fetchStatuspageSummary("https://status.npmjs.org/api/v2/summary.json");
|
|
236
|
+
const checkCloudflareOverallHealth = () => fetchStatuspageIndicator("https://www.cloudflarestatus.com/api/v2/status.json");
|
|
237
|
+
const checkCloudflareComponentHealth = () => fetchStatuspageSummary("https://www.cloudflarestatus.com/api/v2/summary.json");
|
|
238
|
+
//#endregion
|
|
239
|
+
//#region src/lib/health-checks/incidentio.ts
|
|
240
|
+
function mapIncidentImpact(impact) {
|
|
241
|
+
switch (impact) {
|
|
242
|
+
case "full_outage": return "down";
|
|
243
|
+
case "partial_outage":
|
|
244
|
+
case "degraded_performance": return "degraded";
|
|
245
|
+
default: return "degraded";
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function mapComponentStatus(status) {
|
|
249
|
+
switch (status) {
|
|
250
|
+
case "operational": return "healthy";
|
|
251
|
+
case "full_outage": return "down";
|
|
252
|
+
case "partial_outage":
|
|
253
|
+
case "degraded_performance": return "degraded";
|
|
254
|
+
default: return "degraded";
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function errResult(error) {
|
|
258
|
+
return {
|
|
259
|
+
status: "degraded",
|
|
260
|
+
error
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const POSTHOG_STATUS_URL = "https://www.posthogstatus.com/api/v1/summary";
|
|
264
|
+
async function fetchPosthogStatus(timeoutMs = 5e3) {
|
|
265
|
+
try {
|
|
266
|
+
const controller = new AbortController();
|
|
267
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
268
|
+
const res = await fetch(POSTHOG_STATUS_URL, { signal: controller.signal });
|
|
269
|
+
clearTimeout(tid);
|
|
270
|
+
if (!res.ok) {
|
|
271
|
+
const err = errResult(`HTTP ${res.status}`);
|
|
272
|
+
return {
|
|
273
|
+
overall: err,
|
|
274
|
+
components: err
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
const incidents = (await res.json()).ongoing_incidents ?? [];
|
|
278
|
+
if (incidents.length === 0) return {
|
|
279
|
+
overall: { status: "healthy" },
|
|
280
|
+
components: { status: "healthy" }
|
|
281
|
+
};
|
|
282
|
+
let worstOverall = "degraded";
|
|
283
|
+
const affected = [];
|
|
284
|
+
for (const incident of incidents) {
|
|
285
|
+
if (mapIncidentImpact(incident.current_worst_impact) === "down") worstOverall = "down";
|
|
286
|
+
for (const comp of incident.affected_components ?? []) {
|
|
287
|
+
const compStatus = mapComponentStatus(comp.current_status);
|
|
288
|
+
if (compStatus !== "healthy") affected.push({
|
|
289
|
+
name: comp.group_name ? `${comp.group_name} — ${comp.name}` : comp.name,
|
|
290
|
+
status: compStatus,
|
|
291
|
+
rawStatus: comp.current_status
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return {
|
|
296
|
+
overall: { status: worstOverall },
|
|
297
|
+
components: {
|
|
298
|
+
status: affected.length > 0 ? "degraded" : worstOverall,
|
|
299
|
+
degradedOrDownComponents: affected.length > 0 ? affected : void 0
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
} catch (e) {
|
|
303
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
304
|
+
const err = errResult("Request timed out");
|
|
305
|
+
return {
|
|
306
|
+
overall: err,
|
|
307
|
+
components: err
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const err = errResult(e instanceof Error ? e.message : "Unknown error");
|
|
311
|
+
return {
|
|
312
|
+
overall: err,
|
|
313
|
+
components: err
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
let _cache = null;
|
|
318
|
+
function getPosthogHealth() {
|
|
319
|
+
if (!_cache) _cache = fetchPosthogStatus();
|
|
320
|
+
return _cache;
|
|
321
|
+
}
|
|
322
|
+
const checkPosthogOverallHealth = async () => (await getPosthogHealth()).overall;
|
|
323
|
+
const checkPosthogComponentHealth = async () => (await getPosthogHealth()).components;
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/lib/health-checks/endpoints.ts
|
|
326
|
+
function downResult(error) {
|
|
327
|
+
return {
|
|
328
|
+
status: "down",
|
|
329
|
+
error
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
async function fetchEndpointHealth(url, timeoutMs = 5e3, expectedStatus = 200) {
|
|
333
|
+
try {
|
|
334
|
+
const controller = new AbortController();
|
|
335
|
+
const tid = setTimeout(() => controller.abort(), timeoutMs);
|
|
336
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
337
|
+
clearTimeout(tid);
|
|
338
|
+
if (res.status === expectedStatus) return {
|
|
339
|
+
status: "healthy",
|
|
340
|
+
rawIndicator: `HTTP ${res.status}`
|
|
341
|
+
};
|
|
342
|
+
return downResult(`HTTP ${res.status}`);
|
|
343
|
+
} catch (e) {
|
|
344
|
+
if (e instanceof Error && e.name === "AbortError") return downResult("Request timed out");
|
|
345
|
+
return downResult(e instanceof Error ? e.message : "Unknown error");
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const checkLlmGatewayHealth = () => fetchEndpointHealth("https://gateway.us.posthog.com/_liveness");
|
|
349
|
+
const checkMcpHealth = () => fetchEndpointHealth("https://mcp.posthog.com/");
|
|
350
|
+
const checkGithubReleasesHealth = () => fetchEndpointHealth(`${REMOTE_SKILLS_BASE_URL}/skill-menu.json`);
|
|
351
|
+
//#endregion
|
|
352
|
+
//#region src/lib/health-checks/readiness.ts
|
|
353
|
+
const SERVICE_LABELS = {
|
|
354
|
+
anthropic: "Anthropic",
|
|
355
|
+
posthogOverall: "PostHog",
|
|
356
|
+
posthogComponents: "PostHog (components)",
|
|
357
|
+
github: "GitHub",
|
|
358
|
+
npmOverall: "npm",
|
|
359
|
+
npmComponents: "npm (components)",
|
|
360
|
+
cloudflareOverall: "Cloudflare",
|
|
361
|
+
cloudflareComponents: "Cloudflare (components)",
|
|
362
|
+
llmGateway: "LLM Gateway",
|
|
363
|
+
mcp: "MCP",
|
|
364
|
+
githubReleases: "GitHub Releases"
|
|
365
|
+
};
|
|
366
|
+
/**
|
|
367
|
+
* See README section "Health checks" for the full rationale.
|
|
368
|
+
* Adjust these arrays to change what blocks a wizard run.
|
|
369
|
+
*/
|
|
370
|
+
const DEFAULT_WIZARD_READINESS_CONFIG = {
|
|
371
|
+
downBlocksRun: [
|
|
372
|
+
"anthropic",
|
|
373
|
+
"npmOverall",
|
|
374
|
+
"llmGateway",
|
|
375
|
+
"mcp",
|
|
376
|
+
"githubReleases"
|
|
377
|
+
],
|
|
378
|
+
degradedBlocksRun: ["anthropic"]
|
|
379
|
+
};
|
|
380
|
+
/**
|
|
381
|
+
* Reduced readiness config for --signup provisioning flows.
|
|
382
|
+
*
|
|
383
|
+
* Provisioning only needs PostHog and the LLM Gateway - it doesn't
|
|
384
|
+
* use Anthropic directly, npm, GitHub Releases, or MCP.
|
|
385
|
+
*/
|
|
386
|
+
const SIGNUP_WIZARD_READINESS_CONFIG = { downBlocksRun: ["posthogOverall", "llmGateway"] };
|
|
387
|
+
async function checkAllExternalServices() {
|
|
388
|
+
const [anthropic, posthogOverall, posthogComponents, github, npmOverall, npmComponents, cloudflareOverall, cloudflareComponents, llmGateway, mcp, githubReleases] = await Promise.all([
|
|
389
|
+
checkAnthropicHealth(),
|
|
390
|
+
checkPosthogOverallHealth(),
|
|
391
|
+
checkPosthogComponentHealth(),
|
|
392
|
+
checkGithubHealth(),
|
|
393
|
+
checkNpmOverallHealth(),
|
|
394
|
+
checkNpmComponentHealth(),
|
|
395
|
+
checkCloudflareOverallHealth(),
|
|
396
|
+
checkCloudflareComponentHealth(),
|
|
397
|
+
checkLlmGatewayHealth(),
|
|
398
|
+
checkMcpHealth(),
|
|
399
|
+
checkGithubReleasesHealth()
|
|
400
|
+
]);
|
|
401
|
+
return {
|
|
402
|
+
anthropic,
|
|
403
|
+
posthogOverall,
|
|
404
|
+
posthogComponents,
|
|
405
|
+
github,
|
|
406
|
+
npmOverall,
|
|
407
|
+
npmComponents,
|
|
408
|
+
cloudflareOverall,
|
|
409
|
+
cloudflareComponents,
|
|
410
|
+
llmGateway,
|
|
411
|
+
mcp,
|
|
412
|
+
githubReleases
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function describeResult(label, h) {
|
|
416
|
+
const parts = [`${label}: ${h.status}`];
|
|
417
|
+
if (h.rawIndicator) parts.push(`indicator=${h.rawIndicator}`);
|
|
418
|
+
if (h.error) parts.push(h.error);
|
|
419
|
+
return parts.join(" — ");
|
|
420
|
+
}
|
|
421
|
+
const MAX_COMPONENT_NAMES = 8;
|
|
422
|
+
function describeComponents(label, h) {
|
|
423
|
+
const affected = h.degradedOrDownComponents;
|
|
424
|
+
if (!affected || affected.length === 0) return `${label} components: all operational`;
|
|
425
|
+
const shown = affected.slice(0, MAX_COMPONENT_NAMES).map((c) => `${c.name} (${c.status})`);
|
|
426
|
+
const suffix = affected.length > MAX_COMPONENT_NAMES ? `, +${affected.length - MAX_COMPONENT_NAMES} more` : "";
|
|
427
|
+
return `${label} components impacted: ${shown.join(", ")}${suffix}`;
|
|
428
|
+
}
|
|
429
|
+
const READINESS_TIMEOUT_MS = 1e4;
|
|
430
|
+
async function evaluateWizardReadiness(config = DEFAULT_WIZARD_READINESS_CONFIG) {
|
|
431
|
+
try {
|
|
432
|
+
const health = await Promise.race([checkAllExternalServices(), new Promise((resolve) => setTimeout(() => resolve(allUnknown("Health check timed out")), READINESS_TIMEOUT_MS))]);
|
|
433
|
+
const reasons = [];
|
|
434
|
+
for (const key of Object.keys(health)) {
|
|
435
|
+
const result = health[key];
|
|
436
|
+
const label = SERVICE_LABELS[key];
|
|
437
|
+
reasons.push(describeResult(label, result));
|
|
438
|
+
if ("degradedOrDownComponents" in result) reasons.push(describeComponents(label, result));
|
|
439
|
+
}
|
|
440
|
+
const blockingKeys = getBlockingServiceKeys(health, config);
|
|
441
|
+
if (blockingKeys.length > 0) {
|
|
442
|
+
logToFile(`[health-checks] blocked by: ${blockingKeys.join(", ")}`);
|
|
443
|
+
return {
|
|
444
|
+
decision: "no",
|
|
445
|
+
health,
|
|
446
|
+
reasons
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
if (Object.values(health).some((h) => h.status !== "healthy")) return {
|
|
450
|
+
decision: "yes_with_warnings",
|
|
451
|
+
health,
|
|
452
|
+
reasons
|
|
453
|
+
};
|
|
454
|
+
return {
|
|
455
|
+
decision: "yes",
|
|
456
|
+
health,
|
|
457
|
+
reasons
|
|
458
|
+
};
|
|
459
|
+
} catch (err) {
|
|
460
|
+
logToFile(`[health-checks] error: ${err instanceof Error ? err.message : err}`);
|
|
461
|
+
return {
|
|
462
|
+
decision: "yes",
|
|
463
|
+
health: allUnknown("Unexpected error"),
|
|
464
|
+
reasons: ["Health check failed unexpectedly — proceeding anyway"]
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/** Keys that are component-level detail, not top-level services. */
|
|
469
|
+
const COMPONENT_KEYS = [
|
|
470
|
+
"posthogComponents",
|
|
471
|
+
"npmComponents",
|
|
472
|
+
"cloudflareComponents"
|
|
473
|
+
];
|
|
474
|
+
/**
|
|
475
|
+
* Get the keys of services that would block a wizard run per the given config.
|
|
476
|
+
*/
|
|
477
|
+
function getBlockingServiceKeys(health, config = DEFAULT_WIZARD_READINESS_CONFIG) {
|
|
478
|
+
return Object.keys(health).filter((key) => {
|
|
479
|
+
if (COMPONENT_KEYS.includes(key)) return false;
|
|
480
|
+
const result = health[key];
|
|
481
|
+
if (config.downBlocksRun.includes(key) && result.status === "down") return true;
|
|
482
|
+
if ((config.degradedBlocksRun ?? []).includes(key) && result.status !== "healthy") return true;
|
|
483
|
+
return false;
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
/** Build an AllServicesHealth where every service is Degraded with the given error. */
|
|
487
|
+
function allUnknown(error) {
|
|
488
|
+
const base = {
|
|
489
|
+
status: "degraded",
|
|
490
|
+
error
|
|
491
|
+
};
|
|
492
|
+
return {
|
|
493
|
+
anthropic: base,
|
|
494
|
+
posthogOverall: base,
|
|
495
|
+
posthogComponents: { ...base },
|
|
496
|
+
github: base,
|
|
497
|
+
npmOverall: base,
|
|
498
|
+
npmComponents: { ...base },
|
|
499
|
+
cloudflareOverall: base,
|
|
500
|
+
cloudflareComponents: { ...base },
|
|
501
|
+
llmGateway: base,
|
|
502
|
+
mcp: base,
|
|
503
|
+
githubReleases: base
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
//#endregion
|
|
507
|
+
//#region src/ui/logging-ui.ts
|
|
508
|
+
var LoggingUI = class {
|
|
509
|
+
intro(message) {
|
|
510
|
+
console.log(`┌ ${message}`);
|
|
511
|
+
}
|
|
512
|
+
outro(message) {
|
|
513
|
+
console.log(`└ ${message}`);
|
|
514
|
+
}
|
|
515
|
+
outroError(data) {
|
|
516
|
+
console.log(`✖ ${data.message ?? "Wizard aborted"}`);
|
|
517
|
+
if (data.body) console.log(`│ ${data.body}`);
|
|
518
|
+
if (data.docsUrl) console.log(`│ Docs: ${data.docsUrl}`);
|
|
519
|
+
}
|
|
520
|
+
waitForOutroDismissed() {
|
|
521
|
+
return Promise.resolve();
|
|
522
|
+
}
|
|
523
|
+
cancel(message) {
|
|
524
|
+
console.log(`■ ${message}`);
|
|
525
|
+
}
|
|
526
|
+
log = {
|
|
527
|
+
info(message) {
|
|
528
|
+
console.log(`│ ${message}`);
|
|
529
|
+
},
|
|
530
|
+
warn(message) {
|
|
531
|
+
console.log(`▲ ${message}`);
|
|
532
|
+
},
|
|
533
|
+
error(message) {
|
|
534
|
+
console.log(`✖ ${message}`);
|
|
535
|
+
},
|
|
536
|
+
success(message) {
|
|
537
|
+
console.log(`✔ ${message}`);
|
|
538
|
+
},
|
|
539
|
+
step(message) {
|
|
540
|
+
console.log(`◇ ${message}`);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
note(message) {
|
|
544
|
+
console.log(`│ ${message}`);
|
|
545
|
+
}
|
|
546
|
+
spinner() {
|
|
547
|
+
return {
|
|
548
|
+
start(message) {
|
|
549
|
+
if (message) console.log(`◌ ${message}`);
|
|
550
|
+
},
|
|
551
|
+
stop(message) {
|
|
552
|
+
if (message) console.log(`● ${message}`);
|
|
553
|
+
},
|
|
554
|
+
message(msg) {
|
|
555
|
+
if (msg) console.log(`◌ ${msg}`);
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
pushStatus(message) {
|
|
560
|
+
console.log(`◇ ${message}`);
|
|
561
|
+
}
|
|
562
|
+
setDetectedFramework(label) {
|
|
563
|
+
console.log(`✔ Framework: ${label}`);
|
|
564
|
+
}
|
|
565
|
+
onEnterScreen(_screen, _fn) {}
|
|
566
|
+
setLoginUrl(url) {
|
|
567
|
+
if (url) {
|
|
568
|
+
console.log(`│ If the browser didn't open automatically, use this link:`);
|
|
569
|
+
console.log(`│ ${url}`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
showBlockingOutage(result) {
|
|
573
|
+
console.log(`▲ Service health issues detected — blocking outage.`);
|
|
574
|
+
const blockingKeys = getBlockingServiceKeys(result.health);
|
|
575
|
+
if (blockingKeys.length > 0) {
|
|
576
|
+
console.log(`│`);
|
|
577
|
+
console.log(`│ Blocking services:`);
|
|
578
|
+
for (const key of blockingKeys) {
|
|
579
|
+
const status = result.health[key].status;
|
|
580
|
+
const error = result.health[key].error;
|
|
581
|
+
const label = SERVICE_LABELS[key];
|
|
582
|
+
const detail = error ? ` — ${error}` : "";
|
|
583
|
+
console.log(`│ ✖ ${label}: ${status}${detail}`);
|
|
584
|
+
}
|
|
585
|
+
console.log(`│`);
|
|
586
|
+
}
|
|
587
|
+
for (const reason of result.reasons) console.log(`│ ${reason}`);
|
|
588
|
+
console.log(`│ The wizard cannot start while these services are down.`);
|
|
589
|
+
return Promise.resolve();
|
|
590
|
+
}
|
|
591
|
+
setReadinessWarnings(result) {
|
|
592
|
+
console.log(`▲ Service health warnings detected.`);
|
|
593
|
+
for (const reason of result.reasons) console.log(`│ ${reason}`);
|
|
594
|
+
}
|
|
595
|
+
showPortConflict(_processInfo) {
|
|
596
|
+
return Promise.resolve();
|
|
597
|
+
}
|
|
598
|
+
showSettingsOverride(_conflicts, _backupAndFix) {
|
|
599
|
+
return Promise.resolve();
|
|
600
|
+
}
|
|
601
|
+
showAuthError() {
|
|
602
|
+
console.log(`✖ Authentication failed (401)`);
|
|
603
|
+
console.log(`│ Claude Code auth is conflicting with the wizard. Please try again after logging out:`);
|
|
604
|
+
console.log(`│ claude auth logout`);
|
|
605
|
+
}
|
|
606
|
+
startRun() {}
|
|
607
|
+
setCredentials(_credentials) {}
|
|
608
|
+
syncTodos(todos) {
|
|
609
|
+
const completed = todos.filter((t) => t.status === "completed").length;
|
|
610
|
+
const inProgress = todos.find((t) => t.status === "in_progress");
|
|
611
|
+
if (inProgress) console.log(`◌ [${completed}/${todos.length}] ${inProgress.activeForm || inProgress.content}`);
|
|
612
|
+
}
|
|
613
|
+
setEventPlan(_events) {}
|
|
614
|
+
setFrameworkContext(_key, _value) {}
|
|
615
|
+
};
|
|
616
|
+
//#endregion
|
|
617
|
+
//#region src/ui/index.ts
|
|
618
|
+
let currentUI = new LoggingUI();
|
|
619
|
+
function getUI() {
|
|
620
|
+
return currentUI;
|
|
621
|
+
}
|
|
622
|
+
function setUI(ui) {
|
|
623
|
+
currentUI = ui;
|
|
624
|
+
}
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region src/utils/debug.ts
|
|
627
|
+
let debugEnabled = false;
|
|
628
|
+
let logFilePath = WIZARD_LOG_FILE;
|
|
629
|
+
let logEnabled = true;
|
|
630
|
+
function getLogFilePath() {
|
|
631
|
+
return logFilePath;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Configure the log file path and enable/disable state.
|
|
635
|
+
* Call before initLogFile() to override defaults.
|
|
636
|
+
*/
|
|
637
|
+
function configureLogFile(opts) {
|
|
638
|
+
if (opts.path !== void 0) logFilePath = opts.path;
|
|
639
|
+
if (opts.enabled !== void 0) logEnabled = opts.enabled;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Configure log path from environment variables.
|
|
643
|
+
*
|
|
644
|
+
* Uses POSTHOG_WIZARD_LOG_DIR when set, joined with posthog-wizard.log.
|
|
645
|
+
*/
|
|
646
|
+
function configureLogFileFromEnvironment() {
|
|
647
|
+
const envLogDir = runtimeEnv("POSTHOG_WIZARD_LOG_DIR");
|
|
648
|
+
if (envLogDir) configureLogFile({ path: path.join(envLogDir, "posthog-wizard.log") });
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Initialize the log file with a run header.
|
|
652
|
+
* Call this at the start of each wizard run.
|
|
653
|
+
* Fails silently to avoid crashing the wizard.
|
|
654
|
+
*/
|
|
655
|
+
function initLogFile() {
|
|
656
|
+
if (!logEnabled) return;
|
|
657
|
+
try {
|
|
658
|
+
const header = `\n${"=".repeat(60)}\nPostHog Wizard Run: ${(/* @__PURE__ */ new Date()).toISOString()}\n${"=".repeat(60)}\n`;
|
|
659
|
+
appendFileSync(logFilePath, header);
|
|
660
|
+
} catch {}
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Log a message to the log file.
|
|
664
|
+
* Always writes regardless of debug flag (when logging is enabled).
|
|
665
|
+
* Fails silently to avoid masking errors in catch blocks.
|
|
666
|
+
*/
|
|
667
|
+
function logToFile(...args) {
|
|
668
|
+
if (!logEnabled) return;
|
|
669
|
+
try {
|
|
670
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
671
|
+
const msg = args.map((a) => prepareMessage(a)).join(" ");
|
|
672
|
+
appendFileSync(logFilePath, `[${timestamp}] ${msg}\n`);
|
|
673
|
+
} catch {}
|
|
674
|
+
}
|
|
675
|
+
function debug(...args) {
|
|
676
|
+
if (!debugEnabled) return;
|
|
677
|
+
const msg = args.map((a) => prepareMessage(a)).join(" ");
|
|
678
|
+
getUI().log.info(msg);
|
|
679
|
+
}
|
|
680
|
+
function enableDebugLogs() {
|
|
681
|
+
debugEnabled = true;
|
|
682
|
+
}
|
|
683
|
+
//#endregion
|
|
684
|
+
export { POSTHOG_PROPERTY_HEADER_PREFIX as A, WIZARD_VARIANTS as B, Integration as C, POSTHOG_DOCS_URL as D, POSTHOG_DEV_CLIENT_ID as E, WIZARD_OAUTH_SCOPES as F, VERSION as G, getSkillsBaseUrl as H, WIZARD_PROVISIONING_SCOPES as I, red as K, WIZARD_REMARK_EVENT_NAME as L, POSTHOG_US_CLIENT_ID as M, REMOTE_SKILLS_BASE_URL as N, POSTHOG_FLAG_HEADER_PREFIX as O, WIZARD_INTERACTION_EVENT_NAME as P, WIZARD_TOOLS_MENU_FLAG_KEY as R, ISSUES_URL as S, OAUTH_TIMEOUT_MS as T, NODE_ENV as U, WIZARD_VARIANT_FLAG_KEY as V, runtimeEnv as W, ANALYTICS_TEAM_TAG as _, getLogFilePath as a, DETECTION_TIMEOUT_MS as b, getUI as c, SERVICE_LABELS as d, SIGNUP_WIZARD_READINESS_CONFIG as f, ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY as g, ANALYTICS_HOST_URL as h, enableDebugLogs as i, POSTHOG_PROXY_CLIENT_ID as j, POSTHOG_OAUTH_URL as k, setUI as l, getBlockingServiceKeys as m, configureLogFileFromEnvironment as n, initLogFile as o, evaluateWizardReadiness as p, debug as r, logToFile as s, configureLogFile as t, LoggingUI as u, CONTEXT_MILL_URL as v, OAUTH_PORTS as w, DUMMY_PROJECT_API_KEY as x, DEFAULT_HOST_URL as y, WIZARD_USER_AGENT as z };
|
|
685
|
+
|
|
686
|
+
//# sourceMappingURL=debug-Cqi6nVfX.js.map
|