@eventpipe/cli 0.2.1 → 0.2.3

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 CHANGED
@@ -1,79 +1,179 @@
1
- # @eventpipe/cli
1
+ # Event Pipe CLI
2
2
 
3
- Build **Event Pipe** code-node bundles with [esbuild](https://esbuild.github.io/), publish with an **API key**, and use **login / create / listen** against the dashboard (Supabase session + relay WebSocket).
3
+ Official command-line tool for **[Event Pipe](https://eventpipe.app)** — bundle code nodes with [esbuild](https://esbuild.github.io/), **publish new pipeline versions**, create webhook endpoints, and stream events to your machine.
4
4
 
5
- ## Install
5
+ **Website:** [eventpipe.app](https://eventpipe.app) · **npm:** [`@eventpipe/cli`](https://www.npmjs.com/package/@eventpipe/cli)
6
+
7
+ ---
8
+
9
+ ## What you can do
10
+
11
+ | Area | What the CLI does |
12
+ |------|-------------------|
13
+ | **Publish** | Run **`eventpipe push`** after **`eventpipe login`** to upload a new pipeline version (same API as Pipe Studio). |
14
+ | **CI** | Set **`EVENTPIPE_API_KEY`** so **`push`** works without a browser. |
15
+ | **Webhooks** | **`create`** endpoints and **`listen`** to the relay (with optional **`--forward-to`** for local replay). |
16
+ | **Tooling** | **`eventpipe update`**, **`--version`**, and optional npm version hints on stderr. |
17
+
18
+ ---
19
+
20
+ ## Requirements
21
+
22
+ - **Node.js 20 or newer** ([nodejs.org](https://nodejs.org))
23
+ - An Event Pipe account ([sign up](https://eventpipe.app))
24
+ - For **`push`**: a **pipeline** already created in the app, and its **`pipelineId`** (UUID) in **`eventpipe.json`**
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ### Global (recommended)
6
31
 
7
32
  ```bash
8
- pnpm add -D @eventpipe/cli
9
- # or: npm i -D @eventpipe/cli
33
+ npm install -g @eventpipe/cli
10
34
  ```
11
35
 
12
- Global install (provides `eventpipe` and `eventpipe-cli`):
36
+ This provides **`eventpipe`** and **`eventpipe-cli`** on your `PATH`.
37
+
38
+ ### Per project
13
39
 
14
40
  ```bash
15
- npm install -g @eventpipe/cli
41
+ npm add -D @eventpipe/cli
16
42
  ```
17
43
 
18
- **macOS / Linux** from a clone of this repo, installs globally (requires Node 20+ and `npm` on `PATH`):
44
+ Run with **`npx eventpipe …`** or npm scripts.
45
+
46
+ ### Install scripts (from a clone of this repo)
47
+
48
+ **macOS / Linux:** `bash install/macos.sh`
49
+ **Windows (PowerShell):** `Set-ExecutionPolicy -Scope Process Bypass; .\install\windows.ps1`
50
+
51
+ ### Develop from source
19
52
 
20
53
  ```bash
21
- bash install/macos.sh
54
+ git clone <repo-url> && cd eventpipe-cli
55
+ pnpm install && pnpm run build
56
+ node dist/cli.js --help
22
57
  ```
23
58
 
24
- **Windows** — PowerShell:
59
+ ---
60
+
61
+ ## Publishing pipeline versions (`build` + `push`)
62
+
63
+ Publishing creates a **new immutable version** of your pipeline by calling **`POST /api/account/pipelines/{pipelineId}/versions`** with bundled code — the same endpoint the [web app](https://eventpipe.app) uses.
64
+
65
+ ### 1. Get `pipelineId`
66
+
67
+ In **Pipe Studio**, open your pipeline and copy its **UUID** from the URL or settings.
68
+
69
+ ### 2. Add `eventpipe.json` (minimal single code node)
25
70
 
26
- ```powershell
27
- Set-ExecutionPolicy -Scope Process Bypass; .\install\windows.ps1
71
+ The **`code`** node id in **`settings.pipe`** must match the code node you bundle (default file: **`src/handler.ts`**).
72
+
73
+ ```json
74
+ {
75
+ "pipelineId": "YOUR_PIPELINE_UUID",
76
+ "settings": {
77
+ "pipe": {
78
+ "schemaVersion": 3,
79
+ "nodes": [
80
+ { "id": "code", "type": "code", "config": {} }
81
+ ],
82
+ "edges": []
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ### 3. Handler entry (`src/handler.ts`)
89
+
90
+ ```typescript
91
+ type FlowEvent = {
92
+ method: string;
93
+ headers: Record<string, string>;
94
+ body: unknown;
95
+ };
96
+
97
+ type FlowContext = { env?: Record<string, string> };
98
+
99
+ export async function handler(event: FlowEvent, _context: FlowContext) {
100
+ return { ok: true, received: event.body };
101
+ }
28
102
  ```
29
103
 
30
- From a git checkout:
104
+ In production, secrets are read from **`context.env`** (set in the app **Event** tab), not from `process.env` inside the bundle.
105
+
106
+ ### 4. Sign in and push
31
107
 
32
108
  ```bash
33
- cd eventpipe-cli && pnpm install && pnpm run build
34
- # binaries: ./dist/cli.js
109
+ eventpipe login
110
+ eventpipe push
35
111
  ```
36
112
 
37
- ## Project layout
113
+ - **`login`** opens the browser and saves session under **`~/.eventpipe/credentials.json`**. Default app is **`https://eventpipe.app`** (override with **`EVENTPIPE_BASE_URL`** for self-hosted).
114
+ - **`push`** runs **`build`** then uploads bundles. If **`EVENTPIPE_API_KEY`** is set, it is used **instead of** session (typical for **CI**).
38
115
 
39
- | File | Purpose |
40
- |------|---------|
41
- | `eventpipe.json` | `pipelineId`, optional `nodeId` / `entry`, and `settings` (must include `pipe` v3) |
42
- | `src/handler.ts` | Default entry — `export async function handler(event, context)` |
116
+ ### CI example
43
117
 
44
- Runtime uses **`context.env`** for secrets (configure values in the app **Event** tab), not `process.env`.
118
+ ```bash
119
+ export EVENTPIPE_API_KEY=evp_xxxxxxxx
120
+ # optional for self-hosted: export EVENTPIPE_BASE_URL=https://your-app.example.com
121
+ eventpipe push --dir ./my-flow
122
+ ```
45
123
 
46
- ## Commands
124
+ ### Override pipeline id
47
125
 
48
- ### Auth & endpoints
126
+ ```bash
127
+ eventpipe push --pipeline <uuid>
128
+ # alias: --flow <uuid>
129
+ ```
130
+
131
+ ---
49
132
 
50
- - **`login`** Opens the browser to complete Supabase login; saves `~/.eventpipe/credentials.json`. Uses `https://eventpipe.app` unless `EVENTPIPE_BASE_URL` is set.
51
- - **`create [--name <slug>]`** — `POST /api/account/endpoints` (session auth). `--name` sets the URL slug (`/api/webhook/your-slug`) if it’s free; otherwise a random id is used. With no `--name`, the URL and display label are random.
52
- - **`listen <webhookId> [options]`** — Connects to the relay; prints one line per webhook. **`--verbose` / `-v`** prints the full event JSON (method, headers, query, body). **`--json`** prints one JSON object per line (stdout) for scripts. **`--forward-to http://127.0.0.1:PORT/path`** replays each request to your local server (forward status on stderr).
133
+ ## Other commands (summary)
53
134
 
54
- ### Bundles
135
+ | Command | Purpose |
136
+ |---------|---------|
137
+ | **`eventpipe login`** | Browser sign-in; stores session. |
138
+ | **`eventpipe create [--name <slug>]`** | New webhook endpoint (requires login). |
139
+ | **`eventpipe listen <id> [--json] [-v] [--forward-to <url>]`** | Stream webhooks from the relay. |
140
+ | **`eventpipe build [--dir <path>]`** | Esbuild → `.eventpipe/`; prints size and hash (max **200KB** per bundle). |
141
+ | **`eventpipe update`** | Runs **`npm install -g @eventpipe/cli@latest`**. |
142
+ | **`eventpipe -v` / `--version`** | Print CLI version. |
143
+ | **`eventpipe help`** | Built-in usage. |
55
144
 
56
- - **`build`** — Writes `.eventpipe/*.bundle.js` and prints size + sha256 (must be ≤ 200KB).
57
- - **`push`** — Runs `build`, then `POST /api/account/pipelines/:pipelineId/versions` with `codeBundles`.
145
+ ---
146
+
147
+ ## Project layout
58
148
 
59
- ### Environment
149
+ | File / folder | Role |
150
+ |---------------|------|
151
+ | **`eventpipe.json`** | **`pipelineId`**, **`settings.pipe`** (v3), optional **`nodeId`**, **`entry`**, or **`codeNodes`** for multi-file graphs. |
152
+ | **`src/handler.ts`** | Default entry when **`entry`** is omitted. |
153
+ | **`.eventpipe/`** | Generated bundles (from **`build`** / **`push`**). |
60
154
 
61
- | Variable | Used by | Description |
62
- |----------|---------|-------------|
63
- | `EVENTPIPE_BASE_URL` | login, push | Origin of the Next app (default `https://eventpipe.app`; no trailing slash) |
64
- | `EVENTPIPE_API_KEY` | push | Plaintext key from account API keys (`evp_...`) |
155
+ ---
65
156
 
66
- Optional: `--pipeline <uuid>` (or `--flow`) overrides `pipelineId` in `eventpipe.json` for `push`.
157
+ ## Update hints
67
158
 
68
- ### Server requirements for `listen`
159
+ After most commands, the CLI may check npm for a newer **`@eventpipe/cli`** and print a short message on **stderr** suggesting **`eventpipe update`**. Set **`EVENTPIPE_SKIP_UPDATE_CHECK=1`** to disable (e.g. in CI).
69
160
 
70
- The app needs a deployed **eventpipe-relay** (or compatible) service plus env vars documented in the app `.env.example`: `EVENTPIPE_RELAY_URL`, `EVENTPIPE_RELAY_WS_URL`, `EVENTPIPE_RELAY_INGEST_SECRET`, `EVENTPIPE_LISTEN_JWT_SECRET` (shared with the relay).
161
+ ---
71
162
 
72
163
  ## Example
73
164
 
74
- See `examples/stripe-webhook` (Stripe Balance via REST to stay under the bundle size cap).
165
+ See **`examples/stripe-webhook`** for a fuller project (multi-node **`codeNodes`** example).
166
+
167
+ ---
75
168
 
76
169
  ## Limits
77
170
 
78
- - One **code node** per project in this CLI version (multi-node flows: publish from the dashboard or extend the CLI).
79
- - Per-node bundle max **200KB** UTF-8 (same as the server).
171
+ - **Single-code-node** workflows are the simplest; multi-node graphs may need a **`codeNodes`** map or publishing from the [dashboard](https://eventpipe.app).
172
+ - **200KB** UTF-8 per code-node bundle (same as the server).
173
+
174
+ ---
175
+
176
+ ## Getting help
177
+
178
+ - **Product:** [eventpipe.app](https://eventpipe.app) — platform docs include **CLI** and **API reference**.
179
+ - **This repo:** `eventpipe help`
package/dist/cli.js CHANGED
@@ -8,6 +8,7 @@ import { publishVersion } from "./publish.js";
8
8
  import { applyPublishedStudioSources, codeNodeUsesLibrary } from "./studio-sources.js";
9
9
  import { cmdLogin } from "./cmd-login.js";
10
10
  import { cmdCreate } from "./cmd-create.js";
11
+ import { loadCredentials } from "./credentials.js";
11
12
  import { resolveEventpipeBaseUrl } from "./base-url.js";
12
13
  import { fetchLatestPublishedVersion, isPublishedVersionNewer, readInstalledCliVersion, } from "./cli-version.js";
13
14
  import { cmdUpdate } from "./cmd-update.js";
@@ -18,7 +19,7 @@ function usage() {
18
19
 
19
20
  Environment:
20
21
  EVENTPIPE_BASE_URL App origin (default: https://eventpipe.app); override for self-hosted
21
- EVENTPIPE_API_KEY Account API key (x-api-key) for push when not using session
22
+ EVENTPIPE_API_KEY Optional; for push in CI/automation (overrides session if set)
22
23
  EVENTPIPE_SKIP_UPDATE_CHECK Set to 1 to disable the npm version hint on stderr
23
24
 
24
25
  Commands:
@@ -28,7 +29,7 @@ Commands:
28
29
  Stream webhooks; --verbose prints full JSON event; --json one NDJSON line per event;
29
30
  --forward-to replays the request to your local server (status on stderr)
30
31
  build [--dir <path>] Bundle TS into .eventpipe/
31
- push [--dir <path>] build + POST /api/account/pipelines/:id/versions (needs EVENTPIPE_API_KEY)
32
+ push [--dir <path>] build + publish (session after login, or EVENTPIPE_API_KEY)
32
33
  update npm install -g @eventpipe/cli@latest
33
34
  help
34
35
 
@@ -102,11 +103,19 @@ async function cmdBuild(projectDir) {
102
103
  }
103
104
  }
104
105
  async function cmdPush(projectDir, pipelineOverride) {
105
- const base = resolveEventpipeBaseUrl();
106
106
  const key = process.env.EVENTPIPE_API_KEY?.trim();
107
- if (!key) {
108
- throw new Error("EVENTPIPE_API_KEY is required for push");
107
+ const cred = await loadCredentials();
108
+ let auth = null;
109
+ if (key) {
110
+ auth = { type: "apiKey", apiKey: key };
109
111
  }
112
+ else if (cred) {
113
+ auth = { type: "session", cred };
114
+ }
115
+ if (!auth) {
116
+ throw new Error("Run eventpipe login first, or set EVENTPIPE_API_KEY for push (e.g. in CI)");
117
+ }
118
+ const base = auth.type === "session" ? auth.cred.baseUrl : resolveEventpipeBaseUrl();
110
119
  const manifest = await loadManifest(projectDir);
111
120
  const pipelineId = pipelineOverride ?? manifest.pipelineId;
112
121
  const pipe = manifest.settings.pipe;
@@ -145,7 +154,7 @@ async function cmdPush(projectDir, pipelineOverride) {
145
154
  : null;
146
155
  const result = await publishVersion({
147
156
  baseUrl: base,
148
- apiKey: key,
157
+ auth,
149
158
  pipelineId,
150
159
  manifest: manifestForPublish,
151
160
  bundles,
package/dist/publish.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { EventpipeManifest } from "./config.js";
2
+ import type { StoredCredentials } from "./credentials.js";
2
3
  export type PublishResult = {
3
4
  success?: boolean;
4
5
  version?: number;
@@ -6,9 +7,16 @@ export type PublishResult = {
6
7
  bundleSizeBytes?: number;
7
8
  error?: string;
8
9
  };
10
+ export type PublishAuth = {
11
+ type: "apiKey";
12
+ apiKey: string;
13
+ } | {
14
+ type: "session";
15
+ cred: StoredCredentials;
16
+ };
9
17
  export declare function publishVersion(params: {
10
18
  baseUrl: string;
11
- apiKey: string;
19
+ auth: PublishAuth;
12
20
  pipelineId: string;
13
21
  manifest: EventpipeManifest;
14
22
  bundles: Array<{
package/dist/publish.js CHANGED
@@ -1,20 +1,34 @@
1
+ import { fetchWithSession } from "./auth-fetch.js";
1
2
  export async function publishVersion(params) {
2
- const res = await fetch(`${params.baseUrl}/api/account/pipelines/${params.pipelineId}/versions`, {
3
- method: "POST",
4
- headers: {
5
- "content-type": "application/json",
6
- "x-api-key": params.apiKey,
3
+ const url = `${params.baseUrl}/api/account/pipelines/${params.pipelineId}/versions`;
4
+ const body = JSON.stringify({
5
+ sourceCode: params.sourceCode ?? null,
6
+ buildMeta: {
7
+ bundler: "eventpipe-cli",
8
+ generatedAt: new Date().toISOString(),
7
9
  },
8
- body: JSON.stringify({
9
- sourceCode: params.sourceCode ?? null,
10
- buildMeta: {
11
- bundler: "eventpipe-cli",
12
- generatedAt: new Date().toISOString(),
13
- },
14
- settings: params.manifest.settings,
15
- codeBundles: params.bundles,
16
- }),
10
+ settings: params.manifest.settings,
11
+ codeBundles: params.bundles,
17
12
  });
13
+ let res;
14
+ if (params.auth.type === "apiKey") {
15
+ res = await fetch(url, {
16
+ method: "POST",
17
+ headers: {
18
+ "content-type": "application/json",
19
+ "x-api-key": params.auth.apiKey,
20
+ },
21
+ body,
22
+ });
23
+ }
24
+ else {
25
+ const out = await fetchWithSession(url, {
26
+ method: "POST",
27
+ headers: { "content-type": "application/json" },
28
+ body,
29
+ }, params.auth.cred);
30
+ res = out.response;
31
+ }
18
32
  const data = (await res.json());
19
33
  if (!res.ok) {
20
34
  return { error: data?.error ?? res.statusText };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@eventpipe/cli",
3
- "version": "0.2.1",
4
- "description": "Build and publish Event Pipe flow bundles (API key auth)",
3
+ "version": "0.2.3",
4
+ "description": "Build and publish Event Pipe flow bundles (session or API key)",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "eventpipe": "./dist/cli.js",