@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
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { t as WORKFLOW_REGISTRY } from "./bin.js";
|
|
3
|
-
import { n as AGENT_SKILL_STEPS } from "./agent-skill-DJOzDaQV.js";
|
|
2
|
+
import { a as AGENT_SKILL_STEPS, t as WORKFLOW_REGISTRY } from "./bin.js";
|
|
4
3
|
//#region src/lib/workflows/workflow-step.ts
|
|
5
4
|
/**
|
|
6
5
|
* Project a Workflow into the narrower FlowEntry shape the router consumes.
|
|
@@ -33,6 +32,8 @@ function workflowToFlowEntries(workflow) {
|
|
|
33
32
|
let Flow = /* @__PURE__ */ function(Flow) {
|
|
34
33
|
Flow["PostHogIntegration"] = "posthog-integration";
|
|
35
34
|
Flow["RevenueAnalyticsSetup"] = "revenue-analytics-setup";
|
|
35
|
+
Flow["Audit"] = "audit";
|
|
36
|
+
Flow["Audit3000"] = "audit-3000";
|
|
36
37
|
Flow["PosthogDoctor"] = "posthog-doctor";
|
|
37
38
|
Flow["AgentSkill"] = "agent-skill";
|
|
38
39
|
Flow["McpAdd"] = "mcp-add";
|
|
@@ -131,4 +132,4 @@ var WizardRouter = class {
|
|
|
131
132
|
//#endregion
|
|
132
133
|
export { WORKFLOW_STEPS as i, router_exports as n, Flow as r, WizardRouter as t };
|
|
133
134
|
|
|
134
|
-
//# sourceMappingURL=router-
|
|
135
|
+
//# sourceMappingURL=router-COhhuIW3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router-COhhuIW3.js","names":[],"sources":["../src/lib/workflows/workflow-step.ts","../src/ui/tui/flows.ts","../src/ui/tui/router.ts"],"sourcesContent":["import type { WizardSession, DiscoveredFeature } from '../wizard-session';\nimport type { WizardReadinessResult } from '../health-checks/readiness.js';\nimport type { WorkflowRun } from '../agent/agent-runner.js';\nimport type { Integration } from '../constants.js';\nimport type { FrameworkConfig } from '../framework-config.js';\n\n/**\n * A workflow step is the primary unit of the wizard's execution model.\n *\n * It can own:\n * - a screen in the TUI (optional — some steps are headless)\n * - agent work via a workflow reference (optional — some steps are UI-only)\n * - completion and visibility predicates\n *\n * The current PostHog integration flow is one ordered list of steps.\n * Future flows (e.g. revenue analytics) register a different step list.\n */\n/**\n * Context passed to onInit callbacks — fires during store construction,\n * before bin.ts has assigned the real session.\n */\nexport interface StoreInitContext {\n readonly session: WizardSession;\n readonly setReadinessResult: (result: WizardReadinessResult | null) => void;\n readonly setFrameworkContext: (key: string, value: unknown) => void;\n readonly emitChange: () => void;\n}\n\n/**\n * Context passed to onReady callbacks — fires after bin.ts has assigned\n * the real session, so reading `session.installDir` returns the target\n * project. Use for async pre-flow work like prerequisite detection.\n */\nexport interface WorkflowReadyContext {\n readonly session: WizardSession;\n readonly setFrameworkContext: (key: string, value: unknown) => void;\n\n // Detection-specific methods — used by core-integration's detect step\n readonly setFrameworkConfig: (\n integration: Integration,\n config: FrameworkConfig,\n ) => void;\n readonly setDetectedFramework: (label: string) => void;\n readonly setUnsupportedVersion: (info: {\n current: string;\n minimum: string;\n docsUrl: string;\n }) => void;\n readonly addDiscoveredFeature: (feature: DiscoveredFeature) => void;\n readonly setDetectionComplete: () => void;\n}\n\nexport interface WorkflowStep {\n /** Unique identifier for this step */\n id: string;\n\n /** Human-readable label for progress display */\n label: string;\n\n /**\n * TUI screen this step owns, if any.\n * Matches the Screen enum values (e.g. 'intro', 'run', 'outro').\n */\n screen?: string;\n\n /**\n * Whether this step should be visible in the current flow.\n * If omitted, the step is always visible.\n */\n show?: (session: WizardSession) => boolean;\n\n /**\n * Exit condition for the screen. Router advances when true.\n * Defaults to `gate` if unset.\n */\n isComplete?: (session: WizardSession) => boolean;\n\n /**\n * Define a gate if your screen needs to await user interactions.\n * bin.ts can `await store.getGate(stepId)` to pause until the\n * predicate becomes true.\n */\n gate?: (session: WizardSession) => boolean;\n\n /**\n * Called once during store construction, with the default session.\n * Use for session-independent fire-and-forget work that should start\n * as early as possible (e.g. health check kicked off while the user\n * is still reading the intro screen).\n */\n onInit?: (ctx: StoreInitContext) => void;\n\n /**\n * Called once after bin.ts has assigned the real session to the store,\n * before any gate is awaited. Awaited in sequence with other steps'\n * onReady callbacks. Use for session-dependent pre-flow work like\n * scanning the installDir for prerequisites. May be sync or async.\n */\n onReady?: (ctx: WorkflowReadyContext) => void | Promise<void>;\n}\n\n/**\n * An ordered list of workflow steps that defines a wizard flow.\n */\nexport type Workflow = WorkflowStep[];\n\n/**\n * Uniform configuration for a wizard workflow.\n *\n * Each workflow directory exports one of these. The system uses it\n * for CLI registration, flow/step wiring, and skill bootstrap.\n */\nexport interface WorkflowConfig {\n /** CLI command name (e.g. 'revenue'). Omit for the default flow. */\n command?: string;\n /** CLI description shown in --help */\n description: string;\n /** Unique flow key — matches the Flow enum value */\n flowKey: string;\n /** The ordered step list */\n steps: Workflow;\n /** Agent run config. Static object or async function for dynamic config. */\n run?: WorkflowRun | ((session: WizardSession) => Promise<WorkflowRun>);\n /** Prerequisites: other workflow flowKeys that must have run first */\n requires?: string[];\n /**\n * Path (relative to installDir) of the report file the workflow writes.\n * Mirrors `run.reportFile` but lifted to the top level so UI screens can\n * read it synchronously without resolving a deferred `run` function.\n */\n reportFile?: string;\n}\n\n/**\n * Project a Workflow into the narrower FlowEntry shape the router consumes.\n *\n * Two things happen here:\n * 1. Headless steps (no `screen`) are filtered out. The router walks\n * visible screens; gate-only steps like `detect` are store concerns.\n * 2. The step is narrowed to just { screen, show, isComplete } — the\n * router has no business touching gate, onInit, id, or label.\n *\n * This intentional separation keeps the router focused on one question:\n * \"Which screen should be rendered right now?\"\n */\nexport function workflowToFlowEntries(workflow: Workflow): Array<{\n screen: string;\n show?: (session: WizardSession) => boolean;\n isComplete?: (session: WizardSession) => boolean;\n}> {\n const entries = workflow\n .filter((step) => step.screen != null)\n .map((step) => ({\n screen: step.screen!,\n show: step.show,\n // `isComplete` defaults to `gate` — for most steps they're the same\n // predicate (e.g. intro: setupConfirmed unblocks bin.ts AND finishes\n // the screen). Only override when the two conditions diverge.\n isComplete: step.isComplete ?? step.gate,\n }));\n\n // Every workflow ends with the exit screen.\n entries.push({ screen: 'exit', show: undefined, isComplete: undefined });\n\n return entries;\n}\n","/**\n * Flow pipelines — declarative screen sequences for each wizard flow.\n *\n * Owns the Screen and Flow enums (re-exported by router.ts) to avoid\n * circular imports between router ↔ flows.\n *\n * Workflow-based flows are derived from WORKFLOW_REGISTRY via\n * workflowToFlowEntries(). MCP add/remove flows are standalone since\n * they don't go through the agent runner.\n */\n\nimport type { WizardSession } from '../../lib/wizard-session.js';\nimport {\n workflowToFlowEntries,\n type Workflow,\n} from '../../lib/workflows/workflow-step.js';\nimport { WORKFLOW_REGISTRY } from '../../lib/workflows/workflow-registry.js';\nimport { AGENT_SKILL_STEPS } from '../../lib/workflows/agent-skill/index.js';\n\n// ── Screen + Flow enums ──────────────────────────────────────────────\n\n/** Screens that participate in linear flows */\nexport enum Screen {\n Intro = 'intro',\n RevenueIntro = 'revenue-intro',\n AgentSkillIntro = 'agent-skill-intro',\n AuditIntro = 'audit-intro',\n AuditRun = 'audit-run',\n AuditOutro = 'audit-outro',\n Audit3000Intro = 'audit-3000-intro',\n Audit3000Run = 'audit-3000-run',\n Audit3000Outro = 'audit-3000-outro',\n HealthCheck = 'health-check',\n DoctorIntro = 'doctor-intro',\n DoctorReport = 'doctor-report',\n Setup = 'setup',\n Auth = 'auth',\n Run = 'run',\n Mcp = 'mcp',\n KeepSkills = 'keep-skills',\n Outro = 'outro',\n Exit = 'exit',\n McpAdd = 'mcp-add',\n McpRemove = 'mcp-remove',\n}\n\n/** Named flows the router can run */\nexport enum Flow {\n PostHogIntegration = 'posthog-integration',\n RevenueAnalyticsSetup = 'revenue-analytics-setup',\n Audit = 'audit',\n Audit3000 = 'audit-3000',\n PosthogDoctor = 'posthog-doctor',\n AgentSkill = 'agent-skill',\n McpAdd = 'mcp-add',\n McpRemove = 'mcp-remove',\n}\n\n// ── Flow definitions ─────────────────────────────────────────────────\n\nexport interface FlowEntry {\n /** Screen to show */\n screen: Screen;\n /** If provided, screen is skipped when this returns false. Omit = always show. */\n show?: (session: WizardSession) => boolean;\n /** If provided, screen is considered complete when this returns true. */\n isComplete?: (session: WizardSession) => boolean;\n}\n\n// ── Derived from WORKFLOW_REGISTRY ───────────────────────────────────\n\n/** Raw workflow step arrays — used by the store for gate/onInit definitions. */\nexport const WORKFLOW_STEPS: Partial<Record<Flow, Workflow>> = {\n ...(Object.fromEntries(\n WORKFLOW_REGISTRY.map((c) => [c.flowKey, c.steps]),\n ) as Partial<Record<Flow, Workflow>>),\n [Flow.AgentSkill]: AGENT_SKILL_STEPS,\n};\n\n/**\n * All flow pipelines.\n *\n * Workflow-based flows are derived from the registry.\n * MCP add/remove flows are standalone.\n */\nexport const FLOWS: Record<Flow, FlowEntry[]> = {\n // Derive workflow flows from registry\n ...(Object.fromEntries(\n WORKFLOW_REGISTRY.map((c) => [\n c.flowKey,\n workflowToFlowEntries(c.steps) as FlowEntry[],\n ]),\n ) as Record<Flow, FlowEntry[]>),\n\n // Generic agent skill flow\n [Flow.AgentSkill]: workflowToFlowEntries(AGENT_SKILL_STEPS) as FlowEntry[],\n\n // Standalone MCP flows\n [Flow.McpAdd]: [\n {\n screen: Screen.McpAdd,\n isComplete: (s) => s.mcpComplete,\n },\n { screen: Screen.Exit },\n ],\n\n [Flow.McpRemove]: [\n {\n screen: Screen.McpRemove,\n isComplete: (s) => s.mcpComplete,\n },\n { screen: Screen.Exit },\n ],\n};\n","/**\n * WizardRouter — declarative flow pipelines + overlay stack.\n *\n * Two layers:\n * Flow cursor — linear pipeline of screens, advanced with next()\n * Overlay stack — interrupts (outage, auth-expired, etc.) that push/pop\n *\n * The visible screen is: top of overlay stack if non-empty, otherwise the flow cursor.\n *\n * Adding a flow screen = append to a pipeline array.\n * Adding an overlay = call pushOverlay() from anywhere.\n * No switch statements, no hardcoded transitions in business logic.\n */\n\nimport type { WizardSession } from '../../lib/wizard-session.js';\nimport { FLOWS, Screen, Flow, type FlowEntry } from './flows.js';\n\n// Re-export so existing imports from './router.js' keep working\nexport { Screen, Flow };\nexport type { FlowEntry };\n\n// ── Screen name taxonomy ──────────────────────────────────────────────\n\n/** Screens that interrupt flows as overlays */\nexport enum Overlay {\n SettingsOverride = 'settings-override',\n ManagedSettings = 'managed-settings',\n PortConflict = 'port-conflict',\n AuthError = 'auth-error',\n}\n\n/** Union of all screen names */\nexport type ScreenName = Screen | Overlay;\n\n// ── Router ────────────────────────────────────────────────────────────\n\nexport class WizardRouter {\n private flow: FlowEntry[];\n private flowName: Flow;\n private overlays: Overlay[] = [];\n\n constructor(flowName: Flow = Flow.PostHogIntegration) {\n this.flowName = flowName;\n this.flow = FLOWS[flowName];\n }\n\n /**\n * Resolve which screen should be active based on session state.\n * Walks the flow pipeline, skipping hidden entries and completed entries,\n * returns the first incomplete screen.\n */\n resolve(session: WizardSession): ScreenName {\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n\n for (const entry of this.flow) {\n if (entry.show && !entry.show(session)) continue;\n if (entry.isComplete && entry.isComplete(session)) continue;\n return entry.screen;\n }\n\n // All entries complete — show the last screen (outro)\n return this.flow[this.flow.length - 1].screen;\n }\n\n /** The screen that should be rendered right now. */\n get activeScreen(): ScreenName {\n // Overlays take priority — resolve() handles this too,\n // but activeScreen is called before session is available in some paths\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n return this.flow[0].screen;\n }\n\n /** The name of the active flow. */\n get activeFlow(): Flow {\n return this.flowName;\n }\n\n /** Whether an overlay is currently active. */\n get hasOverlay(): boolean {\n return this.overlays.length > 0;\n }\n\n /**\n * Push an overlay that interrupts the current flow.\n * The flow resumes when the overlay is dismissed via popOverlay().\n */\n pushOverlay(overlay: Overlay): void {\n this.overlays.push(overlay);\n }\n\n /**\n * Dismiss the topmost overlay. The flow screen underneath resumes.\n */\n popOverlay(): void {\n this.overlays.pop();\n }\n\n /**\n * Direction hint for screen transitions.\n */\n private _lastDirection: 'push' | 'pop' | null = null;\n\n get lastNavDirection(): 'push' | 'pop' | null {\n return this._lastDirection;\n }\n\n /** @internal — called by store wrapper to track direction */\n _setDirection(dir: 'push' | 'pop' | null): void {\n this._lastDirection = dir;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiJA,SAAgB,sBAAsB,UAInC;CACD,MAAM,UAAU,SACb,QAAQ,SAAS,KAAK,UAAU,KAAK,CACrC,KAAK,UAAU;EACd,QAAQ,KAAK;EACb,MAAM,KAAK;EAIX,YAAY,KAAK,cAAc,KAAK;EACrC,EAAE;AAGL,SAAQ,KAAK;EAAE,QAAQ;EAAQ,MAAM,KAAA;EAAW,YAAY,KAAA;EAAW,CAAC;AAExE,QAAO;;;;;ACrHT,IAAY,OAAL,yBAAA,MAAA;AACL,MAAA,wBAAA;AACA,MAAA,2BAAA;AACA,MAAA,WAAA;AACA,MAAA,eAAA;AACA,MAAA,mBAAA;AACA,MAAA,gBAAA;AACA,MAAA,YAAA;AACA,MAAA,eAAA;;KACD;;AAgBD,MAAa,iBAAkD;CAC7D,GAAI,OAAO,YACT,kBAAkB,KAAK,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,CACnD;kBACkB;CACpB;;;;;;;AAQD,MAAa,QAAmC;CAE9C,GAAI,OAAO,YACT,kBAAkB,KAAK,MAAM,CAC3B,EAAE,SACF,sBAAsB,EAAE,MAAM,CAC/B,CAAC,CACH;kBAGkB,sBAAsB,kBAAkB;cAG5C,CACb;EACE,QAAA;EACA,aAAa,MAAM,EAAE;EACtB,EACD,EAAE,QAAA,QAAqB,CACxB;iBAEiB,CAChB;EACE,QAAA;EACA,aAAa,MAAM,EAAE;EACtB,EACD,EAAE,QAAA,QAAqB,CACxB;CACF;;;;;;;AC7ED,IAAa,eAAb,MAA0B;CACxB;CACA;CACA,WAA8B,EAAE;CAEhC,YAAY,WAAA,uBAA0C;AACpD,OAAK,WAAW;AAChB,OAAK,OAAO,MAAM;;;;;;;CAQpB,QAAQ,SAAoC;AAC1C,MAAI,KAAK,SAAS,SAAS,EACzB,QAAO,KAAK,SAAS,KAAK,SAAS,SAAS;AAG9C,OAAK,MAAM,SAAS,KAAK,MAAM;AAC7B,OAAI,MAAM,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAE;AACxC,OAAI,MAAM,cAAc,MAAM,WAAW,QAAQ,CAAE;AACnD,UAAO,MAAM;;AAIf,SAAO,KAAK,KAAK,KAAK,KAAK,SAAS,GAAG;;;CAIzC,IAAI,eAA2B;AAG7B,MAAI,KAAK,SAAS,SAAS,EACzB,QAAO,KAAK,SAAS,KAAK,SAAS,SAAS;AAE9C,SAAO,KAAK,KAAK,GAAG;;;CAItB,IAAI,aAAmB;AACrB,SAAO,KAAK;;;CAId,IAAI,aAAsB;AACxB,SAAO,KAAK,SAAS,SAAS;;;;;;CAOhC,YAAY,SAAwB;AAClC,OAAK,SAAS,KAAK,QAAQ;;;;;CAM7B,aAAmB;AACjB,OAAK,SAAS,KAAK;;;;;CAMrB,iBAAgD;CAEhD,IAAI,mBAA0C;AAC5C,SAAO,KAAK;;;CAId,cAAc,KAAkC;AAC9C,OAAK,iBAAiB"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { c as getUI, s as logToFile } from "./debug-
|
|
2
|
-
import {
|
|
3
|
-
import { t as traceStep } from "./telemetry-
|
|
4
|
-
import {
|
|
1
|
+
import { F as WIZARD_OAUTH_SCOPES, S as ISSUES_URL, T as OAUTH_TIMEOUT_MS, c as getUI, j as POSTHOG_PROXY_CLIENT_ID, k as POSTHOG_OAUTH_URL, s as logToFile, w as OAUTH_PORTS, x as DUMMY_PROJECT_API_KEY, y as DEFAULT_HOST_URL, z as WIZARD_USER_AGENT } from "./debug-Cqi6nVfX.js";
|
|
2
|
+
import { n as analytics } from "./analytics-VM7laaFx.js";
|
|
3
|
+
import { t as traceStep } from "./telemetry-D6bjWA-A.js";
|
|
4
|
+
import { t as provisionNewAccount } from "./provisioning-g9aoVIEd.js";
|
|
5
|
+
import { r as wizardAbort } from "./wizard-abort-CJkNkSjT.js";
|
|
5
6
|
import { major, minVersion } from "semver";
|
|
6
7
|
import * as childProcess from "node:child_process";
|
|
7
8
|
import { execSync } from "node:child_process";
|
|
@@ -241,10 +242,10 @@ function getLocalLoginUrl(port) {
|
|
|
241
242
|
function getLocalSignupUrl(port) {
|
|
242
243
|
return `${getLocalLoginUrl(port)}?signup=true`;
|
|
243
244
|
}
|
|
244
|
-
function generateCodeVerifier
|
|
245
|
+
function generateCodeVerifier() {
|
|
245
246
|
return crypto.randomBytes(32).toString("base64url");
|
|
246
247
|
}
|
|
247
|
-
function generateCodeChallenge
|
|
248
|
+
function generateCodeChallenge(verifier) {
|
|
248
249
|
return crypto.createHash("sha256").update(verifier).digest("base64url");
|
|
249
250
|
}
|
|
250
251
|
async function startCallbackServer(authUrl, signupUrl, port) {
|
|
@@ -381,8 +382,8 @@ async function exchangeCodeForToken(code, codeVerifier, callbackUrl) {
|
|
|
381
382
|
}
|
|
382
383
|
async function performOAuthFlow(config) {
|
|
383
384
|
const clientId = POSTHOG_PROXY_CLIENT_ID;
|
|
384
|
-
const codeVerifier = generateCodeVerifier
|
|
385
|
-
const codeChallenge = generateCodeChallenge
|
|
385
|
+
const codeVerifier = generateCodeVerifier();
|
|
386
|
+
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
386
387
|
let shouldRetry = false;
|
|
387
388
|
do {
|
|
388
389
|
shouldRetry = false;
|
|
@@ -441,137 +442,6 @@ async function performOAuthFlow(config) {
|
|
|
441
442
|
throw new Error("OAuth port retry loop exited unexpectedly");
|
|
442
443
|
}
|
|
443
444
|
//#endregion
|
|
444
|
-
//#region src/utils/provisioning.ts
|
|
445
|
-
/**
|
|
446
|
-
* Provisioning API client for creating new PostHog accounts.
|
|
447
|
-
*
|
|
448
|
-
* Uses the agentic provisioning API with PKCE auth:
|
|
449
|
-
* 1. POST /account_requests - create account, get auth code
|
|
450
|
-
* 2. POST /oauth/token - exchange code for tokens (with PKCE)
|
|
451
|
-
* 3. POST /resources - provision project, get API key
|
|
452
|
-
*/
|
|
453
|
-
const WIZARD_CLIENT_ID = POSTHOG_US_CLIENT_ID;
|
|
454
|
-
const API_VERSION = "0.1d";
|
|
455
|
-
const PROVISIONING_BASE_URL = "https://us.posthog.com";
|
|
456
|
-
function generateCodeVerifier() {
|
|
457
|
-
return crypto.randomBytes(32).toString("base64url");
|
|
458
|
-
}
|
|
459
|
-
function generateCodeChallenge(verifier) {
|
|
460
|
-
return crypto.createHash("sha256").update(verifier).digest("base64url");
|
|
461
|
-
}
|
|
462
|
-
const AccountRequestResponseSchema = z.object({
|
|
463
|
-
id: z.string(),
|
|
464
|
-
type: z.enum([
|
|
465
|
-
"oauth",
|
|
466
|
-
"requires_auth",
|
|
467
|
-
"error"
|
|
468
|
-
]),
|
|
469
|
-
oauth: z.object({ code: z.string() }).optional(),
|
|
470
|
-
error: z.object({
|
|
471
|
-
code: z.string(),
|
|
472
|
-
message: z.string()
|
|
473
|
-
}).optional()
|
|
474
|
-
});
|
|
475
|
-
const TokenResponseSchema = z.object({
|
|
476
|
-
token_type: z.string(),
|
|
477
|
-
access_token: z.string(),
|
|
478
|
-
refresh_token: z.string(),
|
|
479
|
-
expires_in: z.number(),
|
|
480
|
-
account: z.object({ id: z.string() }).optional()
|
|
481
|
-
});
|
|
482
|
-
const ResourceResponseSchema = z.object({
|
|
483
|
-
status: z.string(),
|
|
484
|
-
id: z.string(),
|
|
485
|
-
service_id: z.string(),
|
|
486
|
-
complete: z.object({ access_configuration: z.object({
|
|
487
|
-
api_key: z.string(),
|
|
488
|
-
host: z.string(),
|
|
489
|
-
personal_api_key: z.string().optional()
|
|
490
|
-
}) }).optional()
|
|
491
|
-
});
|
|
492
|
-
/**
|
|
493
|
-
* Create a new PostHog account and provision a project via the provisioning API.
|
|
494
|
-
*
|
|
495
|
-
* This is the "no browser" signup path: the wizard collects the email,
|
|
496
|
-
* calls the provisioning API to create the account, and gets back
|
|
497
|
-
* credentials without opening a browser.
|
|
498
|
-
*/
|
|
499
|
-
async function provisionNewAccount(email, name, region = "US", opts) {
|
|
500
|
-
const codeVerifier = generateCodeVerifier();
|
|
501
|
-
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
502
|
-
logToFile("[provisioning] starting account creation");
|
|
503
|
-
const accountRes = await axios.post(`${PROVISIONING_BASE_URL}/api/agentic/provisioning/account_requests`, {
|
|
504
|
-
id: crypto.randomUUID(),
|
|
505
|
-
email,
|
|
506
|
-
name,
|
|
507
|
-
client_id: WIZARD_CLIENT_ID,
|
|
508
|
-
code_challenge: codeChallenge,
|
|
509
|
-
code_challenge_method: "S256",
|
|
510
|
-
configuration: {
|
|
511
|
-
region,
|
|
512
|
-
...opts?.orgName ? { organization_name: opts.orgName } : {}
|
|
513
|
-
}
|
|
514
|
-
}, {
|
|
515
|
-
headers: {
|
|
516
|
-
"Content-Type": "application/json",
|
|
517
|
-
"API-Version": API_VERSION,
|
|
518
|
-
"User-Agent": WIZARD_USER_AGENT
|
|
519
|
-
},
|
|
520
|
-
timeout: 3e4
|
|
521
|
-
});
|
|
522
|
-
const accountData = AccountRequestResponseSchema.parse(accountRes.data);
|
|
523
|
-
if (accountData.type === "error") {
|
|
524
|
-
const msg = accountData.error?.message ?? "Account creation failed";
|
|
525
|
-
analytics.captureException(new Error(msg), {
|
|
526
|
-
step: "provisioning_account_request",
|
|
527
|
-
error_code: accountData.error?.code
|
|
528
|
-
});
|
|
529
|
-
throw new Error(msg);
|
|
530
|
-
}
|
|
531
|
-
if (accountData.type === "requires_auth") throw new Error("This email is already associated with a PostHog account. Please use the login flow instead.");
|
|
532
|
-
const code = accountData.oauth?.code;
|
|
533
|
-
if (!code) throw new Error("No authorization code received from account creation");
|
|
534
|
-
logToFile("[provisioning] account created, exchanging code for tokens");
|
|
535
|
-
const tokenRes = await axios.post(`${PROVISIONING_BASE_URL}/api/agentic/oauth/token`, new URLSearchParams({
|
|
536
|
-
grant_type: "authorization_code",
|
|
537
|
-
code,
|
|
538
|
-
code_verifier: codeVerifier
|
|
539
|
-
}).toString(), {
|
|
540
|
-
headers: {
|
|
541
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
542
|
-
"API-Version": API_VERSION,
|
|
543
|
-
"User-Agent": WIZARD_USER_AGENT
|
|
544
|
-
},
|
|
545
|
-
timeout: 3e4
|
|
546
|
-
});
|
|
547
|
-
const tokenData = TokenResponseSchema.parse(tokenRes.data);
|
|
548
|
-
logToFile("[provisioning] tokens received, provisioning resources");
|
|
549
|
-
const resourceRes = await axios.post(`${PROVISIONING_BASE_URL}/api/agentic/provisioning/resources`, {
|
|
550
|
-
service_id: "analytics",
|
|
551
|
-
...opts?.projectName ? { configuration: { project_name: opts.projectName } } : {}
|
|
552
|
-
}, {
|
|
553
|
-
headers: {
|
|
554
|
-
"Content-Type": "application/json",
|
|
555
|
-
Authorization: `Bearer ${tokenData.access_token}`,
|
|
556
|
-
"API-Version": API_VERSION,
|
|
557
|
-
"User-Agent": WIZARD_USER_AGENT
|
|
558
|
-
},
|
|
559
|
-
timeout: 3e4
|
|
560
|
-
});
|
|
561
|
-
const resourceData = ResourceResponseSchema.parse(resourceRes.data);
|
|
562
|
-
if (resourceData.status !== "complete" || !resourceData.complete) throw new Error("Resource provisioning did not complete");
|
|
563
|
-
logToFile("[provisioning] resources provisioned successfully");
|
|
564
|
-
return {
|
|
565
|
-
accessToken: tokenData.access_token,
|
|
566
|
-
refreshToken: tokenData.refresh_token,
|
|
567
|
-
projectApiKey: resourceData.complete.access_configuration.api_key,
|
|
568
|
-
host: resourceData.complete.access_configuration.host,
|
|
569
|
-
personalApiKey: resourceData.complete.access_configuration.personal_api_key,
|
|
570
|
-
projectId: resourceData.id,
|
|
571
|
-
accountId: tokenData.account?.id ?? ""
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
//#endregion
|
|
575
445
|
//#region src/lib/api.ts
|
|
576
446
|
const ApiUserSchema = z.object({
|
|
577
447
|
distinct_id: z.string(),
|
|
@@ -847,16 +717,7 @@ async function fetchProjectDataById(apiKey, projectId, cloudUrl) {
|
|
|
847
717
|
async function askForWizardLogin(options) {
|
|
848
718
|
if (options.signup) return askForProvisioningSignup(options.email, options.region);
|
|
849
719
|
const tokenResponse = await performOAuthFlow({
|
|
850
|
-
scopes: [
|
|
851
|
-
"user:read",
|
|
852
|
-
"project:read",
|
|
853
|
-
"introspection",
|
|
854
|
-
"llm_gateway:read",
|
|
855
|
-
"dashboard:write",
|
|
856
|
-
"insight:write",
|
|
857
|
-
"query:read",
|
|
858
|
-
"health_issue:read"
|
|
859
|
-
],
|
|
720
|
+
scopes: [...WIZARD_OAUTH_SCOPES],
|
|
860
721
|
signup: false
|
|
861
722
|
});
|
|
862
723
|
const projectId = tokenResponse.scoped_teams?.[0];
|
|
@@ -931,4 +792,4 @@ async function askForProvisioningSignup(email, region) {
|
|
|
931
792
|
//#endregion
|
|
932
793
|
export { isUsingTypeScript as a, createVersionBucket as c, getCloudUrlFromRegion as d, getLlmGatewayUrlFromHost as f, getPackageDotJson as i, ApiError as l, detectAllPackageManagers as m, detectOrgAndProject as n, tryGetPackageJson as o, getUiHostFromHost as p, getOrAskForProjectData as r, updatePackageDotJson as s, abort as t, handleApiError as u };
|
|
933
794
|
|
|
934
|
-
//# sourceMappingURL=setup-utils-
|
|
795
|
+
//# sourceMappingURL=setup-utils-CNV7FSlY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-utils-CNV7FSlY.js","names":["fs","path","fs"],"sources":["../src/utils/package-manager.ts","../src/utils/urls.ts","../src/utils/oauth.ts","../src/lib/api.ts","../src/utils/semver.ts","../src/utils/setup-utils.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/typedef */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { traceStep } from '../telemetry';\nimport { getPackageDotJson, updatePackageDotJson } from './setup-utils';\nimport { analytics } from './analytics';\nimport type { WizardOptions } from './types';\n\nexport interface PackageManager {\n name: string;\n label: string;\n installCommand: string;\n buildCommand: string;\n /* The command that the package manager uses to run a script from package.json */\n runScriptCommand: string;\n flags: string;\n forceInstallFlag: string;\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) => boolean;\n addOverride: (\n pkgName: string,\n pkgVersion: string,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ) => Promise<void>;\n}\n\nexport const BUN: PackageManager = {\n name: 'bun',\n label: 'Bun',\n installCommand: 'bun add',\n buildCommand: 'bun run build',\n runScriptCommand: 'bun run',\n flags: '',\n forceInstallFlag: '--force',\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) =>\n ['bun.lockb', 'bun.lock'].some((lockFile) =>\n fs.existsSync(path.join(installDir, lockFile)),\n ),\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const overrides = packageDotJson.overrides || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n overrides: {\n ...overrides,\n [pkgName]: pkgVersion,\n },\n },\n { installDir: installDir },\n );\n },\n};\nexport const YARN_V1: PackageManager = {\n name: 'yarn',\n label: 'Yarn V1',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '--ignore-workspace-root-check',\n forceInstallFlag: '--force',\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) => {\n try {\n return fs\n .readFileSync(path.join(installDir, 'yarn.lock'), 'utf-8')\n .slice(0, 500)\n .includes('yarn lockfile v1');\n } catch (e) {\n return false;\n }\n },\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const resolutions = packageDotJson.resolutions || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n resolutions: {\n ...resolutions,\n [pkgName]: pkgVersion,\n },\n },\n { installDir },\n );\n },\n};\n/** YARN V2/3/4 */\nexport const YARN_V2: PackageManager = {\n name: 'yarn',\n label: 'Yarn V2/3/4',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '',\n forceInstallFlag: '--force',\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) => {\n try {\n return fs\n .readFileSync(path.join(installDir, 'yarn.lock'), 'utf-8')\n .slice(0, 500)\n .includes('__metadata');\n } catch (e) {\n return false;\n }\n },\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const resolutions = packageDotJson.resolutions || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n resolutions: {\n ...resolutions,\n [pkgName]: pkgVersion,\n },\n },\n { installDir },\n );\n },\n};\nexport const PNPM: PackageManager = {\n name: 'pnpm',\n label: 'pnpm',\n installCommand: 'pnpm add',\n buildCommand: 'pnpm build',\n runScriptCommand: 'pnpm',\n flags: '--ignore-workspace-root-check',\n forceInstallFlag: '--force',\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) =>\n fs.existsSync(path.join(installDir, 'pnpm-lock.yaml')),\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const pnpm = packageDotJson.pnpm || {};\n const overrides = pnpm.overrides || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n pnpm: {\n ...pnpm,\n overrides: {\n ...overrides,\n [pkgName]: pkgVersion,\n },\n },\n },\n { installDir },\n );\n },\n};\nexport const NPM: PackageManager = {\n name: 'npm',\n label: 'npm',\n installCommand: 'npm add',\n buildCommand: 'npm run build',\n runScriptCommand: 'npm run',\n flags: '',\n forceInstallFlag: '--force',\n detect: ({ installDir }: Pick<WizardOptions, 'installDir'>) =>\n fs.existsSync(path.join(installDir, 'package-lock.json')),\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const overrides = packageDotJson.overrides || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n overrides: {\n ...overrides,\n [pkgName]: pkgVersion,\n },\n },\n { installDir },\n );\n },\n};\n\nexport const EXPO: PackageManager = {\n name: 'expo',\n label: 'Expo',\n installCommand: 'npx expo install',\n buildCommand: 'npx expo build',\n runScriptCommand: 'npx expo run',\n flags: '',\n forceInstallFlag: '--force',\n detect: () => false,\n addOverride: async (\n pkgName,\n pkgVersion,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n ): Promise<void> => {\n const packageDotJson = await getPackageDotJson({ installDir });\n const overrides = packageDotJson.overrides || {};\n\n await updatePackageDotJson(\n {\n ...packageDotJson,\n overrides: {\n ...overrides,\n [pkgName]: pkgVersion,\n },\n },\n { installDir },\n );\n },\n};\n\nexport const packageManagers = [BUN, YARN_V1, YARN_V2, PNPM, NPM, EXPO];\n\nexport function detectAllPackageManagers({\n installDir,\n}: Pick<WizardOptions, 'installDir'>): PackageManager[] {\n return traceStep('detect-package-manager', () => {\n const detectedManagers: PackageManager[] = [];\n for (const packageManager of packageManagers) {\n if (packageManager.detect({ installDir })) {\n detectedManagers.push(packageManager);\n }\n }\n\n if (detectedManagers.length === 0) {\n analytics.setTag('package-manager', 'not-detected');\n }\n return detectedManagers;\n });\n}\n","import axios from 'axios';\nimport { IS_DEV, WIZARD_USER_AGENT } from '../lib/constants';\nimport type { CloudRegion } from './types';\n\nexport const getAssetHostFromHost = (host: string) => {\n if (host.includes('us.i.posthog.com')) {\n return 'https://us-assets.i.posthog.com';\n }\n\n if (host.includes('eu.i.posthog.com')) {\n return 'https://eu-assets.i.posthog.com';\n }\n\n return host;\n};\n\nexport const getUiHostFromHost = (host: string) => {\n if (host.includes('us.i.posthog.com')) {\n return 'https://us.posthog.com';\n }\n\n if (host.includes('eu.i.posthog.com')) {\n return 'https://eu.posthog.com';\n }\n\n return host;\n};\n\nexport const getHostFromRegion = (region: CloudRegion) => {\n if (IS_DEV) {\n return 'http://localhost:8010';\n }\n\n if (region === 'eu') {\n return 'https://eu.i.posthog.com';\n }\n\n return 'https://us.i.posthog.com';\n};\n\nexport const getCloudUrlFromRegion = (region: CloudRegion) => {\n if (IS_DEV) {\n return 'http://localhost:8010';\n }\n\n if (region === 'eu') {\n return 'https://eu.posthog.com';\n }\n\n return 'https://us.posthog.com';\n};\n\nexport async function detectRegionFromToken(\n accessToken: string,\n): Promise<CloudRegion> {\n if (IS_DEV) {\n return 'us';\n }\n\n const headers = {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n };\n\n const [usResult, euResult] = await Promise.allSettled([\n axios.get('https://us.posthog.com/api/users/@me/', { headers }),\n axios.get('https://eu.posthog.com/api/users/@me/', { headers }),\n ]);\n\n if (usResult.status === 'fulfilled') return 'us';\n if (euResult.status === 'fulfilled') return 'eu';\n\n throw new Error(\n 'Could not determine cloud region from access token. Please check your PostHog account.',\n );\n}\n\nexport const getLlmGatewayUrlFromHost = (host: string) => {\n if (host.includes('localhost')) {\n return 'http://localhost:3308/wizard';\n }\n\n if (host.includes('eu.posthog.com') || host.includes('eu.i.posthog.com')) {\n return 'https://gateway.eu.posthog.com/wizard';\n }\n\n return 'https://gateway.us.posthog.com/wizard';\n};\n","import * as crypto from 'node:crypto';\nimport * as http from 'node:http';\nimport { execSync } from 'node:child_process';\nimport axios from 'axios';\nimport { logToFile } from './debug';\nimport opn from 'opn';\nimport { z } from 'zod';\nimport { getUI } from '../ui';\nimport {\n IS_DEV,\n ISSUES_URL,\n OAUTH_PORTS,\n OAUTH_TIMEOUT_MS,\n POSTHOG_DEV_CLIENT_ID,\n POSTHOG_OAUTH_URL,\n POSTHOG_PROXY_CLIENT_ID,\n WIZARD_USER_AGENT,\n} from '../lib/constants';\nimport { NODE_ENV } from '@env';\nimport { abort } from './setup-utils';\nimport { analytics } from './analytics';\n\nconst OAUTH_CALLBACK_STYLES = `\n <style>\n * {\n font-family: monospace;\n background-color: #1b0a00;\n color: #F7A502;\n font-weight: medium;\n font-size: 24px;\n margin: .25rem;\n }\n\n .blink {\n animation: blink-animation 1s steps(2, start) infinite;\n }\n\n @keyframes blink-animation {\n to {\n opacity: 0;\n }\n }\n </style>\n`;\n\nconst OAuthTokenResponseSchema = z.object({\n access_token: z.string(),\n expires_in: z.number(),\n token_type: z.string(),\n scope: z.string(),\n refresh_token: z.string(),\n scoped_teams: z.array(z.number()).optional(),\n scoped_organizations: z.array(z.string()).optional(),\n});\n\nexport type OAuthTokenResponse = z.infer<typeof OAuthTokenResponseSchema>;\n\ninterface OAuthConfig {\n scopes: string[];\n signup?: boolean;\n}\n\nfunction getLocalOAuthOrigin(port: number): string {\n return `http://localhost:${port}`;\n}\n\nfunction getCallbackUrl(port: number): string {\n return `${getLocalOAuthOrigin(port)}/callback`;\n}\n\nfunction getLocalLoginUrl(port: number): string {\n return `${getLocalOAuthOrigin(port)}/authorize`;\n}\n\nfunction getLocalSignupUrl(port: number): string {\n return `${getLocalLoginUrl(port)}?signup=true`;\n}\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\nasync function startCallbackServer(\n authUrl: string,\n signupUrl: string,\n port: number,\n): Promise<{\n port: number;\n server: http.Server;\n waitForCallback: () => Promise<string>;\n}> {\n return new Promise((resolve, reject) => {\n let callbackResolve: (code: string) => void;\n let callbackReject: (error: Error) => void;\n\n const waitForCallback = () =>\n new Promise<string>((res, rej) => {\n callbackResolve = res;\n callbackReject = rej;\n });\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end();\n return;\n }\n const url = new URL(req.url, getLocalOAuthOrigin(port));\n\n if (url.pathname === '/authorize') {\n const isSignup = url.searchParams.get('signup') === 'true';\n const redirectUrl = isSignup ? signupUrl : authUrl;\n res.writeHead(302, { Location: redirectUrl });\n res.end();\n return;\n }\n\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n const isAccessDenied = error === 'access_denied';\n res.writeHead(isAccessDenied ? 200 : 400, {\n 'Content-Type': 'text/html; charset=utf-8',\n });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Authorization ${\n isAccessDenied ? 'cancelled' : 'failed'\n }</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>${\n isAccessDenied\n ? 'Authorization cancelled.'\n : `Authorization failed.`\n }</p>\n <p>Return to your terminal. This window will close automatically.</p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackReject(new Error(`OAuth error: ${error}`));\n return;\n }\n\n if (code) {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard is ready</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>PostHog login complete!</p>\n <p>Return to your terminal: the wizard is hard at work on your project<span class=\"blink\">█</span></p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackResolve(code);\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Invalid request</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>Invalid request - no authorization code received.</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `);\n }\n });\n\n server.listen(port, () => {\n resolve({ port, server, waitForCallback });\n });\n\n server.on('error', reject);\n });\n}\n\nfunction getPortProcessInfo(port: number): {\n command: string;\n pid: string;\n port: number;\n user: string;\n} {\n try {\n const output = execSync(`lsof -i :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const lines = output.split('\\n');\n // First line is header, second is the process\n if (lines.length < 2)\n return { command: 'unknown', pid: 'unknown', port, user: 'unknown' };\n const fields = lines[1].split(/\\s+/);\n // lsof columns: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME\n const command = fields[0] ?? 'unknown';\n const pid = fields[1] ?? 'unknown';\n const user = fields[2] ?? 'unknown';\n return { command, pid, port, user };\n } catch {\n return { command: 'unknown', pid: 'unknown', port, user: 'unknown' };\n }\n}\n\nfunction isPortInUseError(error: unknown): boolean {\n return (\n error instanceof Error &&\n 'code' in error &&\n (error as NodeJS.ErrnoException).code === 'EADDRINUSE'\n );\n}\n\nasync function exchangeCodeForToken(\n code: string,\n codeVerifier: string,\n callbackUrl: string,\n): Promise<OAuthTokenResponse> {\n const clientId = IS_DEV ? POSTHOG_DEV_CLIENT_ID : POSTHOG_PROXY_CLIENT_ID;\n\n const response = await axios.post(\n `${POSTHOG_OAUTH_URL}/oauth/token`,\n {\n grant_type: 'authorization_code',\n code,\n redirect_uri: callbackUrl,\n client_id: clientId,\n code_verifier: codeVerifier,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': WIZARD_USER_AGENT,\n },\n },\n );\n\n return OAuthTokenResponseSchema.parse(response.data);\n}\n\nexport async function performOAuthFlow(\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const clientId = IS_DEV ? POSTHOG_DEV_CLIENT_ID : POSTHOG_PROXY_CLIENT_ID;\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n let shouldRetry = false;\n\n do {\n shouldRetry = false;\n let lastProcessInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null = null;\n\n for (const port of OAUTH_PORTS) {\n const callbackUrl = getCallbackUrl(port);\n const authUrl = new URL(`${POSTHOG_OAUTH_URL}/oauth/authorize`);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', callbackUrl);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('scope', config.scopes.join(' '));\n authUrl.searchParams.set('required_access_level', 'project');\n\n const signupUrl = new URL(\n `${POSTHOG_OAUTH_URL}/signup?next=${encodeURIComponent(\n authUrl.toString(),\n )}`,\n );\n const localSignupUrl = getLocalSignupUrl(port);\n const localLoginUrl = getLocalLoginUrl(port);\n const urlToOpen = config.signup ? localSignupUrl : localLoginUrl;\n\n logToFile(`[oauth] attempting callback server on port ${port}`);\n\n let server: http.Server;\n let waitForCallback: () => Promise<string>;\n try {\n ({ server, waitForCallback } = await startCallbackServer(\n authUrl.toString(),\n signupUrl.toString(),\n port,\n ));\n } catch (e) {\n if (!isPortInUseError(e)) throw e;\n lastProcessInfo = getPortProcessInfo(port);\n continue;\n }\n\n logToFile('[oauth] callback server ready, showing login URL');\n\n getUI().setLoginUrl(urlToOpen);\n\n if (NODE_ENV !== 'test') {\n opn(urlToOpen, { wait: false }).catch(() => {\n // opn throws in environments without a browser\n });\n }\n\n const loginSpinner = getUI().spinner();\n loginSpinner.start('Waiting for authorization...');\n\n try {\n const code = await Promise.race([\n waitForCallback(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error('Authorization timed out')),\n OAUTH_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const token = await exchangeCodeForToken(\n code,\n codeVerifier,\n callbackUrl,\n );\n\n server.close();\n getUI().setLoginUrl(null);\n loginSpinner.stop('Authorization complete!');\n\n return token;\n } catch (e) {\n loginSpinner.stop('Authorization failed.');\n server.close();\n\n const error = e instanceof Error ? e : new Error('Unknown error');\n\n if (error.message.includes('timeout')) {\n getUI().log.error('Authorization timed out. Please try again.');\n } else if (error.message.includes('access_denied')) {\n getUI().log.info(\n `Authorization was cancelled.\\n\\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\\n\\nYou can try again by re-running the wizard.`,\n );\n } else {\n getUI().log.error(\n `Authorization failed:\\n\\n${error.message}\\n\\nIf you think this is a bug in the PostHog wizard, please create an issue:\\n${ISSUES_URL}`,\n );\n }\n\n analytics.captureException(error, {\n step: 'oauth_flow',\n });\n\n await abort();\n throw error;\n }\n }\n\n if (!lastProcessInfo) {\n throw new Error('No OAuth callback ports configured');\n }\n\n await getUI().showPortConflict(lastProcessInfo);\n shouldRetry = true;\n } while (shouldRetry);\n\n throw new Error('OAuth port retry loop exited unexpectedly');\n}\n","import axios, { AxiosError } from 'axios';\nimport { z } from 'zod';\nimport { analytics } from '../utils/analytics';\nimport { WIZARD_USER_AGENT } from './constants';\n\nexport const ApiUserSchema = z.object({\n distinct_id: z.string(),\n organizations: z.array(\n z.object({\n id: z.string().uuid(),\n }),\n ),\n team: z.object({\n id: z.number(),\n organization: z.string().uuid(),\n }),\n organization: z.object({\n id: z.string().uuid(),\n }),\n});\n\nexport const ApiProjectSchema = z.object({\n id: z.number(),\n uuid: z.string().uuid(),\n organization: z.string().uuid(),\n api_token: z.string(),\n name: z.string(),\n});\n\nexport type ApiUser = z.infer<typeof ApiUserSchema>;\nexport type ApiProject = z.infer<typeof ApiProjectSchema>;\n\nexport class ApiError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly endpoint?: string,\n ) {\n super(message);\n this.name = 'ApiError';\n }\n}\n\nexport async function fetchUserData(\n accessToken: string,\n baseUrl: string,\n): Promise<ApiUser> {\n try {\n const response = await axios.get(`${baseUrl}/api/users/@me/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiUserSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch user data');\n analytics.captureException(apiError, {\n endpoint: '/api/users/@me/',\n baseUrl,\n });\n throw apiError;\n }\n}\n\nexport async function fetchProjectData(\n accessToken: string,\n projectId: number,\n baseUrl: string,\n): Promise<ApiProject> {\n try {\n const response = await axios.get(`${baseUrl}/api/projects/${projectId}/`, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n\n return ApiProjectSchema.parse(response.data);\n } catch (error) {\n const apiError = handleApiError(error, 'fetch project data');\n analytics.captureException(apiError, {\n endpoint: `/api/projects/${projectId}/`,\n baseUrl,\n projectId,\n });\n throw apiError;\n }\n}\n\nexport function handleApiError(error: unknown, operation: string): ApiError {\n if (axios.isAxiosError(error)) {\n const axiosError = error as AxiosError<{ detail?: string }>;\n const status = axiosError.response?.status;\n const detail = axiosError.response?.data?.detail;\n const endpoint = axiosError.config?.url;\n\n if (status === 401) {\n return new ApiError(\n `Authentication failed while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 403) {\n return new ApiError(\n `Access denied while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n if (status === 404) {\n return new ApiError(\n `Resource not found while trying to ${operation}`,\n status,\n endpoint,\n );\n }\n\n const message = detail || `Failed to ${operation}`;\n return new ApiError(message, status, endpoint);\n }\n\n if (error instanceof z.ZodError) {\n return new ApiError(`Invalid response format while trying to ${operation}`);\n }\n\n return new ApiError(\n `Unexpected error while trying to ${operation}: ${\n error instanceof Error ? error.message : 'Unknown error'\n }`,\n );\n}\n","import {\n major,\n minVersion,\n satisfies,\n subset,\n valid,\n validRange,\n} from 'semver';\n\n/**\n * Version strings from package.json that are not semver ranges.\n * URLs, git refs, dist-tags, local paths, workspace protocol, npm aliases, etc.\n * These should be rejected early — we can't determine a clear version from them.\n */\nfunction isNonSemverVersion(version: string): boolean {\n const v = version.trim();\n return (\n v === '' ||\n v.startsWith('http://') ||\n v.startsWith('https://') ||\n v.startsWith('git+') ||\n v.startsWith('git://') ||\n v.startsWith('file:') ||\n v.startsWith('npm:') ||\n v.startsWith('workspace:') ||\n v.startsWith('/') ||\n v.includes('/') // user/repo shorthand\n );\n}\n\nexport function fulfillsVersionRange({\n version,\n acceptableVersions,\n canBeLatest,\n}: {\n version: string;\n acceptableVersions: string;\n canBeLatest: boolean;\n}): boolean {\n if (version === 'latest') {\n return canBeLatest;\n }\n\n if (isNonSemverVersion(version)) {\n return false;\n }\n\n let cleanedUserVersion, isRange;\n\n if (valid(version)) {\n cleanedUserVersion = valid(version);\n isRange = false;\n } else if (validRange(version)) {\n cleanedUserVersion = validRange(version);\n isRange = true;\n }\n\n return (\n // If the given version is a bogus format, this will still be undefined and we'll automatically reject it\n !!cleanedUserVersion &&\n (isRange\n ? subset(cleanedUserVersion, acceptableVersions)\n : satisfies(cleanedUserVersion, acceptableVersions))\n );\n}\n\n/**\n * Creates a version bucket function for analytics.\n * Converts versions like \"1.2.3\" to \"1.x\" for grouping in analytics.\n *\n * @param minMajorVersion - Optional minimum major version threshold.\n * Versions below this will be bucketed as \"<{min}.0.0\"\n *\n * @example\n * const getVersionBucket = createVersionBucket(); // no minimum\n * getVersionBucket(\"1.2.3\") // \"1.x\"\n *\n * const getVersionBucket = createVersionBucket(11);\n * getVersionBucket(\"15.3.0\") // \"15.x\"\n * getVersionBucket(\"10.0.0\") // \"<11.0.0\"\n */\nexport function createVersionBucket(minMajorVersion?: number) {\n return (version: string | undefined): string => {\n if (!version) {\n return 'none';\n }\n\n if (isNonSemverVersion(version)) {\n return 'unknown';\n }\n\n try {\n const minVer = minVersion(version);\n if (!minVer) {\n return 'invalid';\n }\n const majorVersion = major(minVer);\n if (minMajorVersion !== undefined && majorVersion < minMajorVersion) {\n return `<${minMajorVersion}.0.0`;\n }\n return `${majorVersion}.x`;\n } catch {\n return 'unknown';\n }\n };\n}\n","import * as childProcess from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport { basename, isAbsolute, join, relative } from 'node:path';\n\nimport { traceStep } from '../telemetry';\nimport { debug } from './debug';\nimport type { PackageDotJson } from './package-json';\nimport {\n type PackageManager,\n detectAllPackageManagers,\n NPM as npm,\n} from './package-manager';\nimport type { CloudRegion, WizardOptions } from './types';\nimport { getPackageVersion } from './package-json';\nimport {\n DEFAULT_HOST_URL,\n DUMMY_PROJECT_API_KEY,\n ISSUES_URL,\n WIZARD_OAUTH_SCOPES,\n} from '../lib/constants';\nimport { analytics } from './analytics';\nimport { getUI } from '../ui';\nimport {\n getCloudUrlFromRegion,\n getHostFromRegion,\n detectRegionFromToken,\n} from './urls';\nimport { performOAuthFlow } from './oauth';\nimport { provisionNewAccount } from './provisioning';\nimport { fetchUserData, fetchProjectData } from '../lib/api';\nimport { fulfillsVersionRange } from './semver';\nimport { wizardAbort } from './wizard-abort';\n\ninterface ProjectData {\n projectApiKey: string;\n accessToken: string;\n host: string;\n distinctId: string;\n projectId: number;\n}\n\nexport interface CliSetupConfig {\n filename: string;\n name: string;\n gitignore: boolean;\n\n likelyAlreadyHasAuthToken(contents: string): boolean;\n tokenContent(authToken: string): string;\n\n likelyAlreadyHasOrgAndProject(contents: string): boolean;\n orgAndProjContent(org: string, project: string): string;\n\n likelyAlreadyHasUrl?(contents: string): boolean;\n urlContent?(url: string): string;\n}\n\nexport interface CliSetupConfigContent {\n authToken: string;\n org?: string;\n project?: string;\n url?: string;\n}\n\n/** @deprecated Use wizardAbort() directly for new code. */\nexport async function abort(message?: string, status?: number): Promise<never> {\n return wizardAbort({ message, exitCode: status });\n}\n\nexport function isInGitRepo() {\n try {\n childProcess.execSync('git rev-parse --is-inside-work-tree', {\n stdio: 'ignore',\n });\n return true;\n } catch {\n return false;\n }\n}\n\nconst FREEMAIL_DOMAINS = new Set([\n 'gmail.com',\n 'googlemail.com',\n 'hotmail.com',\n 'outlook.com',\n 'yahoo.com',\n 'icloud.com',\n 'me.com',\n 'mail.com',\n 'protonmail.com',\n 'proton.me',\n 'live.com',\n 'aol.com',\n 'yandex.com',\n 'zoho.com',\n 'gmx.com',\n 'fastmail.com',\n]);\n\nfunction parseGitRemote(): { org: string; repo: string } | null {\n try {\n const url = childProcess\n .execSync('git remote get-url origin', {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .toString()\n .trim();\n // git@github.com:acme-corp/my-app.git or https://github.com/acme-corp/my-app.git\n const match = url.match(/[/:]([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?$/);\n if (match) return { org: match[1], repo: match[2] };\n } catch {\n // not in a git repo or no remote\n }\n return null;\n}\n\nexport function detectOrgAndProject(email: string): {\n orgName: string | undefined;\n projectName: string | undefined;\n} {\n const remote = parseGitRemote();\n\n // Project name: git repo name > directory name\n const projectName = remote?.repo || basename(process.cwd()) || undefined;\n\n // Org name: git remote org > email domain (skip freemail)\n let orgName: string | undefined;\n if (remote?.org) {\n orgName = remote.org;\n } else {\n const domain = email.split('@')[1]?.toLowerCase();\n if (domain && !FREEMAIL_DOMAINS.has(domain)) {\n orgName = domain.split('.')[0];\n }\n }\n\n return { orgName, projectName };\n}\n\nexport function getUncommittedOrUntrackedFiles(): string[] {\n try {\n const gitStatus = childProcess\n .execSync('git status --porcelain=v1', {\n // we only care about stdout\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .toString();\n\n const files = gitStatus\n .split(os.EOL)\n .map((line) => line.trim())\n .filter(Boolean)\n .map((f) => `- ${f.split(/\\s+/)[1]}`);\n\n return files;\n } catch {\n return [];\n }\n}\n\nexport async function isReact19Installed({\n installDir,\n}: Pick<WizardOptions, 'installDir'>): Promise<boolean> {\n try {\n const packageJson = await tryGetPackageJson({ installDir });\n if (!packageJson) return false;\n const reactVersion = getPackageVersion('react', packageJson);\n\n if (!reactVersion) {\n return false;\n }\n\n return fulfillsVersionRange({\n version: reactVersion,\n acceptableVersions: '>=19.0.0',\n canBeLatest: true,\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Installs or updates a package with the user's package manager.\n *\n * IMPORTANT: This function modifies the `package.json`! Be sure to re-read\n * it if you make additional modifications to it after calling this function!\n */\nexport async function installPackage({\n packageName,\n alreadyInstalled,\n packageNameDisplayLabel,\n packageManager,\n forceInstall = false,\n integration,\n installDir,\n}: {\n packageName: string;\n alreadyInstalled: boolean;\n packageNameDisplayLabel?: string;\n packageManager?: PackageManager;\n forceInstall?: boolean;\n integration?: string;\n installDir: string;\n}): Promise<{ packageManager?: PackageManager }> {\n return traceStep('install-package', async () => {\n const sdkInstallSpinner = getUI().spinner();\n\n const pkgManager =\n packageManager || (await getPackageManager({ installDir }));\n\n const isReact19 = await isReact19Installed({ installDir });\n const legacyPeerDepsFlag =\n isReact19 && pkgManager.name === 'npm' ? '--legacy-peer-deps' : '';\n\n sdkInstallSpinner.start(\n `${alreadyInstalled ? 'Updating' : 'Installing'} ${\n packageNameDisplayLabel ?? packageName\n } with ${pkgManager.label}.`,\n );\n\n try {\n await new Promise<void>((resolve, reject) => {\n childProcess.exec(\n `${pkgManager.installCommand} ${packageName} ${pkgManager.flags} ${\n forceInstall ? pkgManager.forceInstallFlag : ''\n } ${legacyPeerDepsFlag}`.trim(),\n { cwd: installDir },\n (err, stdout, stderr) => {\n if (err) {\n fs.writeFileSync(\n join(\n process.cwd(),\n `posthog-wizard-installation-error-${Date.now()}.log`,\n ),\n JSON.stringify({\n stdout,\n stderr,\n }),\n { encoding: 'utf8' },\n );\n\n reject(err);\n } else {\n resolve();\n }\n },\n );\n });\n } catch (e) {\n sdkInstallSpinner.stop('Installation failed.');\n getUI().log.error(\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Encountered the following error during installation:\\n\\n${e}\\n\\nThe wizard has created a \\`posthog-wizard-installation-error-*.log\\` file. If you think this issue is caused by the PostHog wizard, create an issue on GitHub and include the log file's content:\\n${ISSUES_URL}`,\n );\n await abort();\n }\n\n sdkInstallSpinner.stop(\n `${alreadyInstalled ? 'Updated' : 'Installed'} ${\n packageNameDisplayLabel ?? packageName\n } with ${pkgManager.label}.`,\n );\n\n analytics.wizardCapture('package installed', {\n package_name: packageName,\n package_manager: pkgManager.name,\n integration,\n });\n\n return { packageManager: pkgManager };\n });\n}\n\n/**\n * Get package.json or abort the wizard if not found.\n * Only use where package.json is required (e.g., package install, overrides).\n * For detection/version-checks, use tryGetPackageJson() instead.\n */\nexport async function getPackageDotJson({\n installDir,\n}: Pick<WizardOptions, 'installDir'>): Promise<PackageDotJson> {\n const packageJsonFileContents = await fs.promises\n .readFile(join(installDir, 'package.json'), 'utf8')\n .catch(() => {\n getUI().log.error(\n 'Could not find package.json. Make sure to run the wizard in the root of your app!',\n );\n return abort();\n });\n\n let packageJson: PackageDotJson | undefined = undefined;\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n packageJson = JSON.parse(packageJsonFileContents);\n } catch {\n getUI().log.error(\n `Unable to parse your package.json. Make sure it has a valid format!`,\n );\n\n await abort();\n }\n\n return packageJson || {};\n}\n\n/**\n * Try to get package.json, returning null if it doesn't exist.\n * Use this for detection purposes where missing package.json is expected (e.g., Python projects).\n */\nexport async function tryGetPackageJson({\n installDir,\n}: Pick<WizardOptions, 'installDir'>): Promise<PackageDotJson | null> {\n try {\n const packageJsonFileContents = await fs.promises.readFile(\n join(installDir, 'package.json'),\n 'utf8',\n );\n return JSON.parse(packageJsonFileContents) as PackageDotJson;\n } catch {\n return null;\n }\n}\n\nexport async function updatePackageDotJson(\n packageDotJson: PackageDotJson,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n): Promise<void> {\n try {\n await fs.promises.writeFile(\n join(installDir, 'package.json'),\n JSON.stringify(packageDotJson, null, 2),\n {\n encoding: 'utf8',\n flag: 'w',\n },\n );\n } catch {\n getUI().log.error(`Unable to update your package.json.`);\n\n await abort();\n }\n}\n\n/**\n * Detect and return the package manager. Pure — no prompts.\n * Falls back to first detected or npm if ambiguous.\n */\n// eslint-disable-next-line @typescript-eslint/require-await\nexport async function getPackageManager(\n options: Pick<WizardOptions, 'installDir'> & { ci?: boolean },\n): Promise<PackageManager> {\n const detectedPackageManagers = detectAllPackageManagers({\n installDir: options.installDir,\n });\n\n if (detectedPackageManagers.length >= 1) {\n const selected = detectedPackageManagers[0];\n analytics.setTag('package-manager', selected.name);\n return selected;\n }\n\n // No package manager detected — default to npm\n analytics.setTag('package-manager', npm.name);\n return npm;\n}\n\nexport function isUsingTypeScript({\n installDir,\n}: Pick<WizardOptions, 'installDir'>) {\n try {\n return fs.existsSync(join(installDir, 'tsconfig.json'));\n } catch {\n return false;\n }\n}\n\n/**\n * Get project data for the wizard via OAuth or CI API key.\n */\nexport async function getOrAskForProjectData(\n _options: Pick<WizardOptions, 'signup' | 'ci' | 'apiKey' | 'projectId'> & {\n email?: string;\n region?: CloudRegion;\n },\n): Promise<{\n host: string;\n projectApiKey: string;\n accessToken: string;\n projectId: number;\n cloudRegion: CloudRegion;\n}> {\n // CI mode: bypass OAuth, use personal API key for LLM gateway\n if (_options.ci && _options.apiKey) {\n getUI().log.info('Using provided API key (CI mode - OAuth bypassed)');\n\n const cloudRegion = await detectRegionFromToken(_options.apiKey);\n const host = getHostFromRegion(cloudRegion);\n const cloudUrl = getCloudUrlFromRegion(cloudRegion);\n\n const projectData =\n _options.projectId != null\n ? await fetchProjectDataById(\n _options.apiKey,\n _options.projectId,\n cloudUrl,\n )\n : await fetchProjectDataWithApiKey(_options.apiKey, cloudUrl);\n\n return {\n host,\n projectApiKey: projectData.api_token,\n accessToken: _options.apiKey,\n projectId: projectData.id,\n cloudRegion,\n };\n }\n\n const { host, projectApiKey, accessToken, projectId, cloudRegion } =\n await traceStep('login', () =>\n askForWizardLogin({\n signup: _options.signup,\n email: _options.email,\n region: _options.region,\n }),\n );\n\n if (!projectApiKey) {\n const cloudUrl = getCloudUrlFromRegion(cloudRegion);\n getUI().log.error(`Didn't receive a project token. This shouldn't happen :(\n\nPlease let us know if you think this is a bug in the wizard:\n${ISSUES_URL}`);\n\n getUI().log\n .info(`In the meantime, we'll add a dummy project token (\"${DUMMY_PROJECT_API_KEY}\") for you to replace later.\nYou can find your project token here:\n${cloudUrl}/settings/project#variables`);\n }\n\n return {\n accessToken,\n host: host || DEFAULT_HOST_URL,\n projectApiKey: projectApiKey || DUMMY_PROJECT_API_KEY,\n projectId,\n cloudRegion,\n };\n}\n\nasync function fetchProjectDataWithApiKey(\n apiKey: string,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number }> {\n const userData = await fetchUserData(apiKey, cloudUrl);\n const projectId = userData.team?.id;\n\n if (!projectId) {\n throw new Error(\n 'Could not determine project ID from API key. Please ensure your API key has access to a project in this cloud region.',\n );\n }\n\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n };\n}\n\nasync function fetchProjectDataById(\n apiKey: string,\n projectId: number,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number }> {\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n };\n}\n\nasync function askForWizardLogin(options: {\n signup: boolean;\n email?: string;\n region?: CloudRegion;\n}): Promise<ProjectData & { cloudRegion: CloudRegion }> {\n if (options.signup) {\n return askForProvisioningSignup(options.email, options.region);\n }\n\n const tokenResponse = await performOAuthFlow({\n scopes: [...WIZARD_OAUTH_SCOPES],\n signup: false,\n });\n\n const projectId = tokenResponse.scoped_teams?.[0];\n\n if (projectId === undefined) {\n const error = new Error(\n 'No project access granted. Please authorize with project-level access.',\n );\n analytics.captureException(error, {\n step: 'wizard_login',\n has_scoped_teams: !!tokenResponse.scoped_teams,\n });\n getUI().log.error(error.message);\n await abort();\n }\n\n const cloudRegion = await detectRegionFromToken(tokenResponse.access_token);\n const cloudUrl = getCloudUrlFromRegion(cloudRegion);\n const host = getHostFromRegion(cloudRegion);\n\n const projectData = await fetchProjectData(\n tokenResponse.access_token,\n projectId!,\n cloudUrl,\n );\n const userData = await fetchUserData(tokenResponse.access_token, cloudUrl);\n\n const data = {\n accessToken: tokenResponse.access_token,\n projectApiKey: projectData.api_token,\n host,\n distinctId: userData.distinct_id,\n projectId: projectId!,\n cloudRegion,\n };\n\n getUI().log.success('Login complete.');\n analytics.setTag('opened-wizard-link', true);\n analytics.setDistinctId(data.distinctId);\n\n return data;\n}\n\nasync function askForProvisioningSignup(\n email?: string,\n region?: CloudRegion,\n): Promise<ProjectData & { cloudRegion: CloudRegion }> {\n if (!email || !email.includes('@')) {\n getUI().log.error(\n 'Email is required for signup. Use --email your@email.com with --signup.',\n );\n await abort();\n throw new Error('unreachable');\n }\n\n const spinner = getUI().spinner();\n spinner.start('Creating your PostHog account...');\n\n try {\n const provisionRegion = (region ?? 'us').toUpperCase() as 'US' | 'EU';\n const { orgName, projectName } = detectOrgAndProject(email);\n const result = await provisionNewAccount(email, '', provisionRegion, {\n orgName,\n projectName,\n });\n\n spinner.stop('Account created!');\n getUI().log.success('Welcome to PostHog!');\n\n const host = result.host;\n const cloudRegion: CloudRegion = host.includes('eu.') ? 'eu' : 'us';\n\n analytics.setTag('provisioning-signup', true);\n\n return {\n accessToken: result.accessToken,\n projectApiKey: result.projectApiKey,\n host,\n distinctId: email,\n projectId: parseInt(result.projectId, 10) || 0,\n cloudRegion,\n };\n } catch (error) {\n spinner.stop('Account creation failed.');\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n if (message.includes('already associated')) {\n getUI().log.info(\n 'This email already has a PostHog account. Switching to login flow...',\n );\n return askForWizardLogin({ signup: false });\n }\n\n getUI().log.error(`Failed to create account: ${message}`);\n analytics.captureException(\n error instanceof Error ? error : new Error(message),\n { step: 'provisioning_signup' },\n );\n await abort();\n throw error;\n }\n}\n\n/**\n * Creates a new config file with the given filepath and codeSnippet.\n */\nexport async function createNewConfigFile(\n filepath: string,\n codeSnippet: string,\n { installDir }: Pick<WizardOptions, 'installDir'>,\n moreInformation?: string,\n): Promise<boolean> {\n if (!isAbsolute(filepath)) {\n debug(`createNewConfigFile: filepath is not absolute: ${filepath}`);\n return false;\n }\n\n const prettyFilename = relative(installDir, filepath);\n\n try {\n await fs.promises.writeFile(filepath, codeSnippet);\n\n getUI().log.success(`Added new ${prettyFilename} file.`);\n\n if (moreInformation) {\n getUI().log.info(moreInformation);\n }\n\n return true;\n } catch (e) {\n debug(e);\n getUI().log.warn(\n `Could not create a new ${prettyFilename} file. Please create one manually and follow the instructions below.`,\n );\n }\n\n return false;\n}\n"],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { C as
|
|
1
|
+
import { m as getBlockingServiceKeys } from "./debug-Cqi6nVfX.js";
|
|
2
|
+
import "./wizard-ui-YdGFRyu_.js";
|
|
3
|
+
import { n as WIZARD_LOG_FILE } from "./paths-DJS47p5x.js";
|
|
4
|
+
import { C as CardLayout, E as WizardStore, S as SplitView, T as Icons, b as ProgressList, c as LearnCard, d as ScreenContainer, f as EventPlanViewer, g as GroupedPickerMenu, h as ConfirmationInput, l as HNViewer, m as ModalOverlay, n as McpScreen, o as ServiceHealthList, p as LogViewer, r as IssueTable, s as TipsCard, t as AuditChecksViewer, u as TabContainer, v as PickerMenu, w as Colors, x as LoadingBox } from "./AuditChecksViewer-B0J7zcY2.js";
|
|
5
5
|
import * as fs$1 from "fs";
|
|
6
6
|
import * as path$1 from "path";
|
|
7
7
|
import * as os from "os";
|
|
8
8
|
import { Box, Text, render, useInput } from "ink";
|
|
9
9
|
import { createElement, useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
10
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
//#region src/ui/tui/playground/demos/WelcomeDemo.tsx
|
|
12
12
|
/**
|
|
13
13
|
* WelcomeDemo — Splash screen. Press enter to push the tabbed view.
|
|
@@ -966,7 +966,7 @@ const Wrapper = ({ step, log, children }) => /* @__PURE__ */ jsxs(Box, {
|
|
|
966
966
|
}),
|
|
967
967
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
968
968
|
children,
|
|
969
|
-
log.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
969
|
+
log.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
970
970
|
/* @__PURE__ */ jsx(Box, { height: 1 }),
|
|
971
971
|
/* @__PURE__ */ jsx(Text, {
|
|
972
972
|
dimColor: true,
|
|
@@ -980,6 +980,96 @@ const Wrapper = ({ step, log, children }) => /* @__PURE__ */ jsxs(Box, {
|
|
|
980
980
|
]
|
|
981
981
|
});
|
|
982
982
|
//#endregion
|
|
983
|
+
//#region src/ui/tui/playground/demos/AuditChecksDemo.tsx
|
|
984
|
+
/**
|
|
985
|
+
* AuditChecksDemo — renders the AuditChecksViewer against a mock ledger so
|
|
986
|
+
* the scroll/expand/sort behavior can be verified in the playground without
|
|
987
|
+
* running the actual audit agent.
|
|
988
|
+
*/
|
|
989
|
+
const MOCK_CHECKS = [
|
|
990
|
+
{
|
|
991
|
+
id: "sdk-installed",
|
|
992
|
+
area: "Installation",
|
|
993
|
+
label: "PostHog SDK installed",
|
|
994
|
+
status: "pass",
|
|
995
|
+
file: "package.json",
|
|
996
|
+
details: "posthog-js@1.260.0 found in dependencies."
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
id: "sdk-up-to-date",
|
|
1000
|
+
area: "Installation",
|
|
1001
|
+
label: "SDK version up to date",
|
|
1002
|
+
status: "warning",
|
|
1003
|
+
details: "installed 1.260.0, latest 1.372.6 — more than one minor behind."
|
|
1004
|
+
},
|
|
1005
|
+
{
|
|
1006
|
+
id: "init-correct",
|
|
1007
|
+
area: "Installation",
|
|
1008
|
+
label: "Initialization is correct",
|
|
1009
|
+
status: "warning",
|
|
1010
|
+
file: "index.js:12",
|
|
1011
|
+
details: "Init runs at module load with no singleton guard; calling posthog.init() multiple times can cause duplicate events."
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
id: "identify-stable-distinct-id",
|
|
1015
|
+
area: "Identification",
|
|
1016
|
+
label: "Stable distinct_id (not session UUID)",
|
|
1017
|
+
status: "error",
|
|
1018
|
+
file: "index.js:18",
|
|
1019
|
+
details: "distinct_id is crypto.randomUUID() — a per-session ephemeral UUID that resets on every page load. Replace with an authenticated user id."
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
id: "identify-not-late",
|
|
1023
|
+
area: "Identification",
|
|
1024
|
+
label: "identify() called before captures / flag evals",
|
|
1025
|
+
status: "pass",
|
|
1026
|
+
file: "index.js:18",
|
|
1027
|
+
details: "posthog.identify() is called before any posthog.capture() calls in this module."
|
|
1028
|
+
},
|
|
1029
|
+
{
|
|
1030
|
+
id: "cross-runtime-distinct-id",
|
|
1031
|
+
area: "Identification",
|
|
1032
|
+
label: "Same distinct_id across client and server",
|
|
1033
|
+
status: "pass",
|
|
1034
|
+
details: "Single runtime — no cross-runtime check needed."
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
id: "identify-reset-on-logout",
|
|
1038
|
+
area: "Identification",
|
|
1039
|
+
label: "reset() called on logout / account switch",
|
|
1040
|
+
status: "error",
|
|
1041
|
+
file: "auth.ts:44",
|
|
1042
|
+
details: "signOut() clears app auth state but never calls posthog.reset(), so the next identify() on this device can merge into the prior user profile."
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
id: "capture-event-names-static",
|
|
1046
|
+
area: "Event Capture",
|
|
1047
|
+
label: "Event names are static and consistent",
|
|
1048
|
+
status: "pass",
|
|
1049
|
+
file: "index.js:21",
|
|
1050
|
+
details: "All posthog.capture() calls use static string literals ('pageview', 'cta_clicked'); no template literals or dynamic variables found."
|
|
1051
|
+
},
|
|
1052
|
+
{
|
|
1053
|
+
id: "capture-uses-proxy",
|
|
1054
|
+
area: "Event Capture",
|
|
1055
|
+
label: "Captures route through a reverse proxy",
|
|
1056
|
+
status: "warning",
|
|
1057
|
+
file: "index.js:13",
|
|
1058
|
+
details: "api_host is set to the default PostHog US ingest host (https://us.i.posthog.com) rather than a first-party reverse proxy — ad/tracking blockers can silently drop these events."
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
id: "capture-growth-events",
|
|
1062
|
+
area: "Event Capture",
|
|
1063
|
+
label: "Key activation events captured",
|
|
1064
|
+
status: "pending"
|
|
1065
|
+
}
|
|
1066
|
+
];
|
|
1067
|
+
const AuditChecksDemo = () => /* @__PURE__ */ jsx(Box, {
|
|
1068
|
+
flexDirection: "column",
|
|
1069
|
+
flexGrow: 1,
|
|
1070
|
+
children: /* @__PURE__ */ jsx(AuditChecksViewer, { checks: MOCK_CHECKS })
|
|
1071
|
+
});
|
|
1072
|
+
//#endregion
|
|
983
1073
|
//#region src/ui/tui/playground/PlaygroundApp.tsx
|
|
984
1074
|
/**
|
|
985
1075
|
* PlaygroundApp — Root component for the primitives playground.
|
|
@@ -1043,6 +1133,11 @@ const PlaygroundApp = ({ store }) => {
|
|
|
1043
1133
|
id: "hints",
|
|
1044
1134
|
label: "KeyHints",
|
|
1045
1135
|
component: /* @__PURE__ */ jsx(KeyboardHintsDemo, {})
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
id: "audit-checks",
|
|
1139
|
+
label: "Audit checks",
|
|
1140
|
+
component: /* @__PURE__ */ jsx(AuditChecksDemo, {})
|
|
1046
1141
|
}
|
|
1047
1142
|
],
|
|
1048
1143
|
statusMessage: "Primitives Playground — use arrow keys to switch tabs"
|
|
@@ -1079,4 +1174,4 @@ function startPlayground(version) {
|
|
|
1079
1174
|
//#endregion
|
|
1080
1175
|
export { startPlayground };
|
|
1081
1176
|
|
|
1082
|
-
//# sourceMappingURL=start-playground-
|
|
1177
|
+
//# sourceMappingURL=start-playground-C9GWnVdM.js.map
|