From d756687e5755fe37a5e0946777bec878464f4863 Mon Sep 17 00:00:00 2001 From: thegreatalxx <198081098+thegreatalxx@users.noreply.github.com> Date: Mon, 4 May 2026 17:23:20 -0400 Subject: [PATCH 1/2] feat(cli): implement trigger command for mock events --- src/cli.ts | 2 + src/commands/trigger.ts | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/commands/trigger.ts diff --git a/src/cli.ts b/src/cli.ts index 2776c23..7129ab2 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -5,6 +5,7 @@ import { listen } from "./commands/listen"; import { login } from "./commands/login"; import { logout } from "./commands/logout"; import { migrate } from "./commands/migrate"; +import { trigger } from "./commands/trigger"; import { update } from "./commands/update"; import * as Migration from "./services/migration/migrate"; import * as OAuth from "./services/oauth"; @@ -18,6 +19,7 @@ const mainCommand = Command.make("polar").pipe( logout, migrate, listen, + trigger, update ]) ); diff --git a/src/commands/trigger.ts b/src/commands/trigger.ts new file mode 100644 index 0000000..c4028df --- /dev/null +++ b/src/commands/trigger.ts @@ -0,0 +1,89 @@ +import { Args, Command } from "@effect/cli"; +import { Effect } from "effect"; +import { environmentPrompt } from "../prompts/environment"; + +const eventType = Args.text({ name: "event" }); +const url = Args.text({ name: "url" }); + +const MOCK_PAYLOADS: Record = { + "subscription.created": { + type: "subscription.created", + data: { + id: "sub_123456", + status: "active", + customer_id: "cus_abcdef", + product_id: "prod_pro_plan", + current_period_end: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), + } + }, + "order.created": { + type: "order.created", + data: { + id: "ord_789012", + amount: 2000, + currency: "usd", + customer_id: "cus_abcdef", + product_id: "prod_digital_ebook", + } + }, + "benefit.granted": { + type: "benefit.granted", + data: { + id: "ben_345678", + customer_id: "cus_abcdef", + benefit_type: "github_repository", + properties: { + repository_owner: "polarsource", + repository_name: "polar", + } + } + } +}; + +export const trigger = Command.make("trigger", { event: eventType, url }, ({ event, url }) => + Effect.gen(function* () { + const environment = yield* environmentPrompt; + + const payload = MOCK_PAYLOADS[event]; + if (!payload) { + console.error(`\x1b[31mError:\x1b[0m Unknown event type '${event}'.`); + console.log("\x1b[2mAvailable events:\x1b[0m"); + Object.keys(MOCK_PAYLOADS).forEach(e => console.log(` - ${e}`)); + return; + } + + const timestamp = Math.floor(Date.now() / 1000).toString(); + const webhookId = `wh_mock_${Math.random().toString(36).substring(7)}`; + + const headers = { + "user-agent": "polar.sh webhooks", + "content-type": "application/json", + "webhook-id": webhookId, + "webhook-timestamp": timestamp, + "webhook-signature": "mock_signature_for_local_testing", + }; + + const fullPayload = { + ...payload, + timestamp: new Date().toISOString(), + }; + + console.log(`\x1b[36mTriggering\x1b[0m '${event}' to ${url}...`); + + try { + const response = yield* Effect.promise(() => fetch(url, { + method: "POST", + headers, + body: JSON.stringify(fullPayload), + })); + + if (response.ok) { + console.log(`\x1b[32mSuccess!\x1b[0m Webhook received with status ${response.status}`); + } else { + console.error(`\x1b[31mFailed:\x1b[0m Receiver returned ${response.status} ${response.statusText}`); + } + } catch (error) { + console.error(`\x1b[31mError:\x1b[0m Could not reach ${url}. Is your server running?`); + } + }) +); From c7ef93bfa5f9135089f34baf4be378955654483c Mon Sep 17 00:00:00 2001 From: thegreatalxx <198081098+thegreatalxx@users.noreply.github.com> Date: Mon, 4 May 2026 17:24:33 -0400 Subject: [PATCH 2/2] feat(cli): add whoami command and enhance trigger payloads --- src/cli.ts | 2 ++ src/commands/whoami.ts | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/commands/whoami.ts diff --git a/src/cli.ts b/src/cli.ts index 7129ab2..27df930 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -6,6 +6,7 @@ import { login } from "./commands/login"; import { logout } from "./commands/logout"; import { migrate } from "./commands/migrate"; import { trigger } from "./commands/trigger"; +import { whoami } from "./commands/whoami"; import { update } from "./commands/update"; import * as Migration from "./services/migration/migrate"; import * as OAuth from "./services/oauth"; @@ -20,6 +21,7 @@ const mainCommand = Command.make("polar").pipe( migrate, listen, trigger, + whoami, update ]) ); diff --git a/src/commands/whoami.ts b/src/commands/whoami.ts new file mode 100644 index 0000000..23227c4 --- /dev/null +++ b/src/commands/whoami.ts @@ -0,0 +1,38 @@ +import { Command } from "@effect/cli"; +import { Effect } from "effect"; +import { environmentPrompt } from "../prompts/environment"; +import * as Polar from "../services/polar"; + +export const whoami = Command.make("whoami", {}, () => + Effect.gen(function* () { + const environment = yield* environmentPrompt; + const polar = yield* Polar.Polar; + + try { + const user = yield* polar.use((client) => client.users.getAuthenticated(), environment); + const organizations = yield* polar.use((client) => client.organizations.list({ limit: 100 }), environment); + + const bold = "\x1b[1m"; + const cyan = "\x1b[36m"; + const reset = "\x1b[0m"; + const dim = "\x1b[2m"; + + console.log(""); + console.log(` ${bold}Logged in as:${reset} ${cyan}${user.email}${reset}`); + console.log(` ${bold}Environment:${reset} ${environment}`); + console.log(""); + + if (organizations.result.items.length > 0) { + console.log(` ${bold}Organizations:${reset}`); + organizations.result.items.forEach(org => { + console.log(` ${dim}•${reset} ${org.name} ${dim}(${org.slug})${reset}`); + }); + } else { + console.log(` ${dim}No organizations found.${reset}`); + } + console.log(""); + } catch (error) { + console.error("\x1b[31mError:\x1b[0m Not logged in or session expired. Run 'polar login' to authenticate."); + } + }) +);