propline-cli 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 PropLine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # propline-cli
2
+
3
+ Terminal interface for the [PropLine](https://prop-line.com) player props betting odds API. Wraps the [`propline`](https://www.npmjs.com/package/propline) Node SDK with pretty-printed tables and a `--json` opt-out.
4
+
5
+ ```bash
6
+ npx propline-cli live
7
+ # or, for repeated use:
8
+ npm install -g propline-cli
9
+ propline live
10
+ ```
11
+
12
+ ## Auth
13
+
14
+ Set your API key once:
15
+
16
+ ```bash
17
+ export PROPLINE_API_KEY=your_key_here
18
+ ```
19
+
20
+ Or pass `--api-key` per-invocation. Get a free key at <https://prop-line.com>.
21
+
22
+ ## Quick examples
23
+
24
+ ```bash
25
+ # Every game in progress, across every sport
26
+ propline live
27
+
28
+ # Today's MLB slate
29
+ propline events baseball_mlb
30
+
31
+ # Cross-book odds for one event
32
+ propline odds baseball_mlb 12345 --markets h2h,spreads,totals,player_points
33
+
34
+ # Scores from the last 3 days
35
+ propline scores basketball_nba
36
+
37
+ # Cross-book +EV plays (Pro tier)
38
+ propline ev baseball_mlb 12345 --plus
39
+
40
+ # Player prop history (Pro tier)
41
+ propline player-history baseball_mlb "Aaron Judge" --market batter_home_runs
42
+
43
+ # Bulk CSV export of resolved props (Pro tier)
44
+ propline export-resolved-props --sport baseball_mlb --since 2026-04-01T00:00:00Z --out mlb-resolved.csv
45
+
46
+ # Manage webhook subscriptions (Streaming tier)
47
+ propline webhooks list
48
+ propline webhooks create --url https://example.com/hook --events line_movement,resolution --sport baseball_mlb
49
+ propline webhooks deliveries 42
50
+ ```
51
+
52
+ ## Commands
53
+
54
+ | Command | Description |
55
+ | --- | --- |
56
+ | `propline sports` | List available sports |
57
+ | `propline events <sport>` | List upcoming events for a sport |
58
+ | `propline odds <sport> [event_id]` | Bulk odds (no event_id) or per-event (with) |
59
+ | `propline scores <sport>` | Recent scores + status |
60
+ | `propline live` | Every in-progress game across the major sports |
61
+ | `propline ev <sport> <event_id>` | Cross-book +EV vs no-vig fair line (Pro) |
62
+ | `propline player-history <sport> <player>` | Recent prop history for a player on a market |
63
+ | `propline export-resolved-props --sport <key>` | Bulk CSV export of resolved props (Pro) |
64
+ | `propline webhooks list / create / delete / test / deliveries` | Webhook management (Streaming) |
65
+
66
+ Run `propline <cmd> --help` for the full flag set on any command.
67
+
68
+ ## Global flags
69
+
70
+ - `--api-key <key>` — overrides `PROPLINE_API_KEY`
71
+ - `--base-url <url>` — point at a self-hosted / staging deployment (default `https://api.prop-line.com/v1`)
72
+ - `--timeout <seconds>` — request timeout (default 15)
73
+ - `--json` — emit raw JSON instead of a table; pipe-friendly with `jq`
74
+
75
+ ## License
76
+
77
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,589 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/index.ts
4
+ import { Command, Option } from "commander";
5
+
6
+ // src/client.ts
7
+ import { PropLine, PropLineError } from "propline";
8
+ function buildClient(flags) {
9
+ const apiKey = flags.apiKey ?? process.env.PROPLINE_API_KEY;
10
+ if (!apiKey) {
11
+ process.stderr.write(
12
+ "error: API key required.\n\n Set PROPLINE_API_KEY in your environment, or pass --api-key.\n Get one free at https://prop-line.com\n"
13
+ );
14
+ process.exit(2);
15
+ }
16
+ return new PropLine(apiKey, {
17
+ baseUrl: flags.baseUrl,
18
+ timeoutMs: flags.timeout ? flags.timeout * 1e3 : void 0
19
+ });
20
+ }
21
+ async function runCommand(fn) {
22
+ try {
23
+ await fn();
24
+ } catch (err) {
25
+ if (err instanceof PropLineError) {
26
+ process.stderr.write(`error: ${err.message}
27
+ `);
28
+ } else if (err instanceof Error) {
29
+ process.stderr.write(`error: ${err.message}
30
+ `);
31
+ } else {
32
+ process.stderr.write(`error: ${String(err)}
33
+ `);
34
+ }
35
+ process.exit(1);
36
+ }
37
+ }
38
+
39
+ // src/format.ts
40
+ function printJson(data) {
41
+ process.stdout.write(JSON.stringify(data, null, 2) + "\n");
42
+ }
43
+ function printTable(rows, columns) {
44
+ if (rows.length === 0) {
45
+ process.stdout.write("(no rows)\n");
46
+ return;
47
+ }
48
+ const cells = rows.map(
49
+ (r) => columns.map((c) => {
50
+ const v = c.value(r);
51
+ return v === void 0 || v === null ? "" : String(v);
52
+ })
53
+ );
54
+ const headers = columns.map((c) => c.label);
55
+ const widths = headers.map(
56
+ (h, i) => Math.min(60, Math.max(h.length, ...cells.map((row) => (row[i] ?? "").length)))
57
+ );
58
+ function pad(s, w, numeric) {
59
+ const truncated = s.length > w ? s.slice(0, w - 1) + "\u2026" : s;
60
+ if (numeric) return truncated.padStart(w);
61
+ return truncated.padEnd(w);
62
+ }
63
+ process.stdout.write(
64
+ headers.map((h, i) => pad(h, widths[i] ?? 0, columns[i]?.numeric ?? false)).join(" ") + "\n"
65
+ );
66
+ process.stdout.write(widths.map((w) => "\u2500".repeat(w)).join(" ") + "\n");
67
+ for (const row of cells) {
68
+ process.stdout.write(
69
+ row.map((c, i) => pad(c, widths[i] ?? 0, columns[i]?.numeric ?? false)).join(" ") + "\n"
70
+ );
71
+ }
72
+ }
73
+ function formatPrice(price) {
74
+ if (price === null || price === void 0) return "\u2013";
75
+ if (price === 0) return "EVEN";
76
+ return price > 0 ? `+${price}` : String(price);
77
+ }
78
+ function formatPoint(point) {
79
+ if (point === null || point === void 0) return "";
80
+ if (Number.isInteger(point)) return String(point);
81
+ return point.toFixed(1);
82
+ }
83
+ function formatTime(iso) {
84
+ if (!iso) return "";
85
+ const d = new Date(iso);
86
+ if (Number.isNaN(d.getTime())) return iso;
87
+ return d.toISOString().replace(/\.\d{3}Z$/, "Z");
88
+ }
89
+ function truncate(s, n) {
90
+ if (s.length <= n) return s;
91
+ return s.slice(0, n - 1) + "\u2026";
92
+ }
93
+
94
+ // src/commands.ts
95
+ function cmdSports(flags) {
96
+ return runCommand(async () => {
97
+ const client = buildClient(flags);
98
+ const sports = await client.getSports();
99
+ if (flags.json) return printJson(sports);
100
+ const cols = [
101
+ { label: "KEY", value: (r) => r.key },
102
+ { label: "TITLE", value: (r) => r.title },
103
+ { label: "ACTIVE", value: (r) => r.active ? "yes" : "no" }
104
+ ];
105
+ printTable(sports, cols);
106
+ });
107
+ }
108
+ function cmdEvents(sport, flags) {
109
+ return runCommand(async () => {
110
+ const client = buildClient(flags);
111
+ const events = await client.getEvents(sport);
112
+ if (flags.json) return printJson(events);
113
+ const cols = [
114
+ { label: "ID", value: (r) => String(r.id) },
115
+ { label: "AWAY", value: (r) => r.away_team },
116
+ { label: "HOME", value: (r) => r.home_team },
117
+ { label: "COMMENCES", value: (r) => formatTime(r.commence_time) }
118
+ ];
119
+ printTable(events, cols);
120
+ });
121
+ }
122
+ function cmdOdds(sport, eventId, flags) {
123
+ return runCommand(async () => {
124
+ const client = buildClient(flags);
125
+ const markets = parseMarketsFlag(flags.markets);
126
+ if (eventId) {
127
+ const resp2 = await client.getOdds(sport, { eventId, markets });
128
+ if (flags.json) return printJson(resp2);
129
+ printOddsResponse(resp2);
130
+ return;
131
+ }
132
+ const resp = await client.getOdds(sport, { markets });
133
+ if (flags.json) return printJson(resp);
134
+ const rows = resp.map((ev) => {
135
+ const books = ev.bookmakers ?? [];
136
+ const markets2 = books.reduce((sum, b) => sum + (b.markets?.length ?? 0), 0);
137
+ return {
138
+ id: String(ev.id),
139
+ teams: `${ev.away_team} @ ${ev.home_team}`,
140
+ commence: formatTime(ev.commence_time),
141
+ books: books.length,
142
+ markets: markets2
143
+ };
144
+ });
145
+ const cols = [
146
+ { label: "ID", value: (r) => r.id },
147
+ { label: "MATCHUP", value: (r) => r.teams },
148
+ { label: "COMMENCES", value: (r) => r.commence },
149
+ { label: "BOOKS", value: (r) => String(r.books), numeric: true },
150
+ { label: "MARKETS", value: (r) => String(r.markets), numeric: true }
151
+ ];
152
+ printTable(rows, cols);
153
+ });
154
+ }
155
+ function printOddsResponse(resp) {
156
+ const rows = [];
157
+ for (const book of resp.bookmakers ?? []) {
158
+ for (const market of book.markets ?? []) {
159
+ for (const o of market.outcomes ?? []) {
160
+ rows.push({
161
+ book: book.title,
162
+ market: market.key,
163
+ player: o.description ?? "",
164
+ side: o.name,
165
+ point: formatPoint(o.point ?? null),
166
+ price: formatPrice(o.price)
167
+ });
168
+ }
169
+ }
170
+ }
171
+ if (rows.length === 0) {
172
+ process.stdout.write(
173
+ `(no markets returned \u2014 try --markets h2h,spreads,totals or the desired prop key)
174
+ `
175
+ );
176
+ return;
177
+ }
178
+ const header = `${resp.away_team} @ ${resp.home_team} (event ${resp.id})
179
+ `;
180
+ process.stdout.write(header);
181
+ const cols = [
182
+ { label: "BOOK", value: (r) => r.book },
183
+ { label: "MARKET", value: (r) => r.market },
184
+ { label: "PLAYER", value: (r) => truncate(r.player, 28) },
185
+ { label: "SIDE", value: (r) => r.side },
186
+ { label: "LINE", value: (r) => r.point, numeric: true },
187
+ { label: "PRICE", value: (r) => r.price, numeric: true }
188
+ ];
189
+ printTable(rows, cols);
190
+ }
191
+ function cmdScores(sport, flags) {
192
+ return runCommand(async () => {
193
+ const client = buildClient(flags);
194
+ const scores = await client.getScores(sport, { daysFrom: flags.daysFrom });
195
+ if (flags.json) return printJson(scores);
196
+ const cols = [
197
+ { label: "ID", value: (r) => String(r.id) },
198
+ { label: "STATUS", value: (r) => String(r.status) },
199
+ { label: "AWAY", value: (r) => r.away_team },
200
+ {
201
+ label: "AS",
202
+ value: (r) => r.away_score === null ? "" : String(r.away_score),
203
+ numeric: true
204
+ },
205
+ { label: "HOME", value: (r) => r.home_team },
206
+ {
207
+ label: "HS",
208
+ value: (r) => r.home_score === null ? "" : String(r.home_score),
209
+ numeric: true
210
+ },
211
+ { label: "COMMENCED", value: (r) => formatTime(r.commence_time) }
212
+ ];
213
+ printTable(scores, cols);
214
+ });
215
+ }
216
+ var LIVE_SPORTS = [
217
+ "baseball_mlb",
218
+ "basketball_nba",
219
+ "hockey_nhl",
220
+ "basketball_ncaab",
221
+ "football_nfl",
222
+ "football_ncaaf",
223
+ "soccer_epl",
224
+ "soccer_la_liga",
225
+ "soccer_serie_a",
226
+ "soccer_bundesliga",
227
+ "soccer_ligue_1",
228
+ "soccer_mls",
229
+ "tennis",
230
+ "golf",
231
+ "mma_ufc"
232
+ ];
233
+ function cmdLive(flags) {
234
+ return runCommand(async () => {
235
+ const client = buildClient(flags);
236
+ const settled = await Promise.allSettled(
237
+ LIVE_SPORTS.map(async (sportKey) => {
238
+ const scores = await client.getScores(sportKey, { daysFrom: 1 });
239
+ return scores.filter((sc) => sc.status === "in_progress").map((sc) => ({
240
+ sport: sportKey,
241
+ id: String(sc.id),
242
+ teams: `${sc.away_team} @ ${sc.home_team}`,
243
+ score: sc.home_score !== null && sc.away_score !== null ? `${sc.away_score}-${sc.home_score}` : "",
244
+ period: typeof sc.period === "string" ? sc.period : ""
245
+ }));
246
+ })
247
+ );
248
+ const rows = [];
249
+ for (const r of settled) {
250
+ if (r.status !== "fulfilled") continue;
251
+ rows.push(...r.value);
252
+ }
253
+ if (flags.json) return printJson(rows);
254
+ if (rows.length === 0) {
255
+ process.stdout.write("(no games in progress right now)\n");
256
+ return;
257
+ }
258
+ const cols = [
259
+ { label: "SPORT", value: (r) => r.sport },
260
+ { label: "ID", value: (r) => r.id },
261
+ { label: "MATCHUP", value: (r) => r.teams },
262
+ { label: "SCORE", value: (r) => r.score },
263
+ { label: "PERIOD", value: (r) => r.period }
264
+ ];
265
+ printTable(rows, cols);
266
+ });
267
+ }
268
+ function cmdEv(sport, eventId, flags) {
269
+ return runCommand(async () => {
270
+ const client = buildClient(flags);
271
+ const resp = await client.getEventEv(sport, eventId, {
272
+ markets: parseMarketsFlag(flags.markets)
273
+ });
274
+ if (flags.json) return printJson(resp);
275
+ const rows = [];
276
+ for (const line of resp.lines) {
277
+ for (const o of line.outcomes) {
278
+ rows.push({
279
+ market: line.market_key,
280
+ player: line.description,
281
+ point: formatPoint(line.point),
282
+ side: o.name,
283
+ book: o.book_title,
284
+ price: formatPrice(o.price),
285
+ ev: `${o.ev_pct >= 0 ? "+" : ""}${o.ev_pct.toFixed(2)}%`,
286
+ plus: o.is_plus_ev
287
+ });
288
+ }
289
+ }
290
+ const filtered = flags.plus ? rows.filter((r) => r.plus) : rows;
291
+ filtered.sort((a, b) => parseFloat(b.ev) - parseFloat(a.ev));
292
+ process.stdout.write(
293
+ `${resp.away_team} @ ${resp.home_team} \xB7 fair anchor: ${resp.fair_source_default}
294
+ `
295
+ );
296
+ const cols = [
297
+ { label: "MARKET", value: (r) => r.market },
298
+ { label: "PLAYER", value: (r) => truncate(r.player, 24) },
299
+ { label: "LINE", value: (r) => r.point, numeric: true },
300
+ { label: "SIDE", value: (r) => r.side },
301
+ { label: "BOOK", value: (r) => r.book },
302
+ { label: "PRICE", value: (r) => r.price, numeric: true },
303
+ { label: "EV%", value: (r) => r.ev, numeric: true }
304
+ ];
305
+ printTable(filtered, cols);
306
+ });
307
+ }
308
+ function cmdPlayerHistory(sport, player, flags) {
309
+ return runCommand(async () => {
310
+ const client = buildClient(flags);
311
+ const resp = await client.getPlayerHistory(sport, player, {
312
+ market: flags.market,
313
+ bookmaker: flags.bookmaker,
314
+ limit: flags.limit
315
+ });
316
+ if (flags.json) return printJson(resp);
317
+ process.stdout.write(
318
+ `${resp.player_name} \xB7 ${resp.market} (${resp.entries.length} entries)
319
+ `
320
+ );
321
+ const cols = [
322
+ { label: "DATE", value: (r) => formatTime(r.commence_time).slice(0, 10) },
323
+ { label: "MATCHUP", value: (r) => `${r.away_team} @ ${r.home_team}` },
324
+ { label: "BOOK", value: (r) => r.bookmaker_title },
325
+ {
326
+ label: "LINE",
327
+ value: (r) => formatPoint(r.line),
328
+ numeric: true
329
+ },
330
+ { label: "OVER", value: (r) => formatPrice(r.over_price), numeric: true },
331
+ {
332
+ label: "UNDER",
333
+ value: (r) => formatPrice(r.under_price),
334
+ numeric: true
335
+ },
336
+ {
337
+ label: "ACTUAL",
338
+ value: (r) => r.actual_value === null ? "" : String(r.actual_value),
339
+ numeric: true
340
+ },
341
+ {
342
+ label: "RESULT",
343
+ value: (r) => {
344
+ if (r.over_result === "won") return "OVER \u2713";
345
+ if (r.under_result === "won") return "UNDER \u2713";
346
+ if (r.over_result === "push" || r.under_result === "push") return "PUSH";
347
+ if (r.over_result === "void" || r.under_result === "void") return "VOID";
348
+ return "";
349
+ }
350
+ }
351
+ ];
352
+ printTable(resp.entries, cols);
353
+ });
354
+ }
355
+ function cmdExportResolvedProps(flags) {
356
+ return runCommand(async () => {
357
+ const client = buildClient(flags);
358
+ if (flags.out) {
359
+ const path = await client.exportResolvedProps({
360
+ sport: flags.sport,
361
+ market: flags.market,
362
+ bookmaker: flags.bookmaker,
363
+ since: flags.since,
364
+ until: flags.until,
365
+ outPath: flags.out
366
+ });
367
+ process.stdout.write(`exported \u2192 ${path}
368
+ `);
369
+ return;
370
+ }
371
+ const buf = await client.exportResolvedProps({
372
+ sport: flags.sport,
373
+ market: flags.market,
374
+ bookmaker: flags.bookmaker,
375
+ since: flags.since,
376
+ until: flags.until
377
+ });
378
+ process.stdout.write(buf);
379
+ });
380
+ }
381
+ function cmdWebhooksList(flags) {
382
+ return runCommand(async () => {
383
+ const client = buildClient(flags);
384
+ const hooks = await client.listWebhooks();
385
+ if (flags.json) return printJson(hooks);
386
+ const cols = [
387
+ { label: "ID", value: (r) => String(r.id), numeric: true },
388
+ { label: "URL", value: (r) => truncate(r.url, 50) },
389
+ { label: "EVENTS", value: (r) => (r.events ?? []).join(",") },
390
+ { label: "ACTIVE", value: (r) => r.active ? "yes" : "no" },
391
+ { label: "SPORT", value: (r) => r.filter_sport_key ?? "" },
392
+ { label: "MARKET", value: (r) => r.filter_market_key ?? "" },
393
+ { label: "CREATED", value: (r) => formatTime(r.created_at) }
394
+ ];
395
+ printTable(hooks, cols);
396
+ });
397
+ }
398
+ function cmdWebhooksCreate(flags) {
399
+ return runCommand(async () => {
400
+ const client = buildClient(flags);
401
+ const events = flags.events ? flags.events.split(",").map((s) => s.trim()) : void 0;
402
+ const hook = await client.createWebhook({
403
+ url: flags.url,
404
+ events,
405
+ filterSportKey: flags.sport,
406
+ filterMarketKey: flags.market,
407
+ filterPlayerName: flags.player,
408
+ filterEventId: flags.eventId,
409
+ minPriceChangePct: flags.minPriceChangePct
410
+ });
411
+ if (flags.json) return printJson(hook);
412
+ process.stdout.write(
413
+ `webhook ${hook.id} created.
414
+ url: ${hook.url}
415
+ events: ${(hook.events ?? []).join(",") || "(all)"}
416
+ secret: ${hook.secret}
417
+
418
+ STORE THE SECRET NOW \u2014 it's only revealed once. Use it to verify
419
+ the X-PropLine-Signature header on every delivery.
420
+ `
421
+ );
422
+ });
423
+ }
424
+ function cmdWebhooksDelete(id, flags) {
425
+ return runCommand(async () => {
426
+ const client = buildClient(flags);
427
+ const numeric = Number(id);
428
+ if (!Number.isFinite(numeric)) {
429
+ throw new Error(`webhook id must be numeric: ${id}`);
430
+ }
431
+ await client.deleteWebhook(numeric);
432
+ if (flags.json) return printJson({ ok: true, id: numeric });
433
+ process.stdout.write(`webhook ${numeric} deleted.
434
+ `);
435
+ });
436
+ }
437
+ function cmdWebhooksTest(id, flags) {
438
+ return runCommand(async () => {
439
+ const client = buildClient(flags);
440
+ const numeric = Number(id);
441
+ if (!Number.isFinite(numeric)) {
442
+ throw new Error(`webhook id must be numeric: ${id}`);
443
+ }
444
+ const result = await client.testWebhook(numeric);
445
+ if (flags.json) return printJson(result);
446
+ process.stdout.write(`test payload queued for webhook ${numeric}.
447
+ `);
448
+ });
449
+ }
450
+ function cmdWebhooksDeliveries(id, flags) {
451
+ return runCommand(async () => {
452
+ const client = buildClient(flags);
453
+ const numeric = Number(id);
454
+ if (!Number.isFinite(numeric)) {
455
+ throw new Error(`webhook id must be numeric: ${id}`);
456
+ }
457
+ const deliveries = await client.listWebhookDeliveries(numeric, {
458
+ limit: flags.limit
459
+ });
460
+ if (flags.json) return printJson(deliveries);
461
+ const cols = [
462
+ { label: "ID", value: (r) => String(r.id), numeric: true },
463
+ { label: "STATUS", value: (r) => String(r.status) },
464
+ {
465
+ label: "RESP",
466
+ value: (r) => r.response_code === null ? "" : String(r.response_code),
467
+ numeric: true
468
+ },
469
+ { label: "ATTEMPTS", value: (r) => String(r.attempts), numeric: true },
470
+ { label: "DELIVERED", value: (r) => formatTime(r.delivered_at) }
471
+ ];
472
+ printTable(deliveries, cols);
473
+ });
474
+ }
475
+ function parseMarketsFlag(value) {
476
+ if (!value) return void 0;
477
+ return value.split(",").map((s) => s.trim()).filter(Boolean);
478
+ }
479
+
480
+ // src/index.ts
481
+ var VERSION = "0.1.0";
482
+ var program = new Command();
483
+ program.name("propline").description(
484
+ "PropLine CLI \u2014 query live odds, scores, +EV plays, prop resolution, and webhooks from the terminal."
485
+ ).version(VERSION).addOption(
486
+ new Option("--api-key <key>", "PropLine API key").env("PROPLINE_API_KEY")
487
+ ).addOption(
488
+ new Option(
489
+ "--base-url <url>",
490
+ "API base URL (default https://api.prop-line.com/v1)"
491
+ )
492
+ ).addOption(
493
+ new Option(
494
+ "--timeout <seconds>",
495
+ "Request timeout in seconds (default 15)"
496
+ ).argParser((v) => parseInt(v, 10))
497
+ ).addOption(new Option("--json", "Emit raw JSON instead of a table")).showHelpAfterError();
498
+ function gather(cmd) {
499
+ const own = cmd.opts();
500
+ const parent = cmd.parent?.opts() ?? {};
501
+ return { ...parent, ...own };
502
+ }
503
+ program.command("sports").description("List available sports").action(function() {
504
+ return cmdSports(gather(this));
505
+ });
506
+ program.command("events").argument("<sport>", "sport key (e.g. baseball_mlb)").description("List upcoming events for a sport").action(function(sport) {
507
+ return cmdEvents(sport, gather(this));
508
+ });
509
+ program.command("odds").argument("<sport>", "sport key (e.g. baseball_mlb)").argument("[event_id]", "specific event id (omit for bulk odds)").option(
510
+ "-m, --markets <list>",
511
+ "comma-separated market keys (e.g. h2h,spreads,totals or player_points)"
512
+ ).description("Get current odds across all books").action(function(sport, eventId) {
513
+ return cmdOdds(sport, eventId, gather(this));
514
+ });
515
+ program.command("scores").argument("<sport>", "sport key").option(
516
+ "-d, --days-from <n>",
517
+ "days back to include (default 3)",
518
+ (v) => parseInt(v, 10)
519
+ ).description("Get game scores and status").action(function(sport) {
520
+ return cmdScores(sport, gather(this));
521
+ });
522
+ program.command("live").description(
523
+ "Show every in-progress game across the major sports (score + period)"
524
+ ).action(function() {
525
+ return cmdLive(gather(this));
526
+ });
527
+ program.command("ev").argument("<sport>", "sport key").argument("<event_id>", "event id").option("-m, --markets <list>", "comma-separated market keys").option(
528
+ "--plus",
529
+ "show only +EV outcomes (filter rows where ev_pct > 0)",
530
+ false
531
+ ).description("Cross-book +EV against a sharp no-vig fair line (Pro tier)").action(function(sport, eventId) {
532
+ return cmdEv(sport, eventId, gather(this));
533
+ });
534
+ program.command("player-history").argument("<sport>", "sport key").argument("<player>", 'player name (quote if it contains spaces \u2014 e.g. "Aaron Judge")').requiredOption(
535
+ "-m, --market <key>",
536
+ "market key (required \u2014 e.g. pitcher_strikeouts)"
537
+ ).option("-b, --bookmaker <key>", "filter to a single book (e.g. draftkings)").option(
538
+ "-l, --limit <n>",
539
+ "max entries (1-100, default 20)",
540
+ (v) => parseInt(v, 10)
541
+ ).description("Recent prop history for a player on a market (Pro full, Free redacted)").action(function(sport, player) {
542
+ return cmdPlayerHistory(sport, player, gather(this));
543
+ });
544
+ program.command("export-resolved-props").requiredOption("--sport <key>", "sport key (required)").option("--market <key>", "filter by market key").option("--bookmaker <key>", "filter by bookmaker key").option("--since <iso>", "ISO datetime lower bound on resolved_at").option("--until <iso>", "ISO datetime upper bound on resolved_at").option(
545
+ "--out <path>",
546
+ "write CSV to this path (default: stream CSV to stdout)"
547
+ ).description("Bulk CSV export of resolved props (Pro tier)").action(function() {
548
+ return cmdExportResolvedProps(gather(this));
549
+ });
550
+ var webhooks = program.command("webhooks").description("Manage webhook subscriptions (Streaming tier)");
551
+ webhooks.command("list").description("List your webhook subscriptions").action(function() {
552
+ return cmdWebhooksList(gather(this));
553
+ });
554
+ webhooks.command("create").requiredOption("--url <url>", "HTTPS endpoint that will receive POSTs").option(
555
+ "--events <list>",
556
+ "comma-separated event types: line_movement,resolution (default: all)"
557
+ ).option("--sport <key>", "filter to a single sport").option("--market <key>", "filter to a single market key").option("--player <name>", "filter to a player name (case-insensitive substring)").option(
558
+ "--event-id <id>",
559
+ "filter to one event id (numeric)",
560
+ (v) => parseInt(v, 10)
561
+ ).option(
562
+ "--min-price-change-pct <n>",
563
+ "minimum % change in American odds to fire a line_movement",
564
+ (v) => parseFloat(v)
565
+ ).description("Register a webhook subscription (returns the signing secret ONCE)").action(function() {
566
+ return cmdWebhooksCreate(gather(this));
567
+ });
568
+ webhooks.command("delete").argument("<id>", "webhook id").description("Delete a webhook (cascades its delivery history)").action(function(id) {
569
+ return cmdWebhooksDelete(id, gather(this));
570
+ });
571
+ webhooks.command("test").argument("<id>", "webhook id").description("Queue a sample test payload to the webhook URL").action(function(id) {
572
+ return cmdWebhooksTest(id, gather(this));
573
+ });
574
+ webhooks.command("deliveries").argument("<id>", "webhook id").option(
575
+ "-l, --limit <n>",
576
+ "max deliveries (default 50)",
577
+ (v) => parseInt(v, 10)
578
+ ).description("Show recent delivery attempts for a webhook").action(function(id) {
579
+ return cmdWebhooksDeliveries(id, gather(this));
580
+ });
581
+ program.parseAsync().catch((err) => {
582
+ process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}
583
+ `);
584
+ process.exit(1);
585
+ });
586
+ export {
587
+ VERSION
588
+ };
589
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/format.ts","../src/commands.ts"],"sourcesContent":["// PropLine CLI — terminal interface to the PropLine player props API.\n// Wraps the `propline` Node SDK; no API surface of its own. Add new\n// commands by importing a handler from ./commands.ts and registering\n// it on the matching `program.command(...)` below.\n\nimport { Command, Option } from \"commander\";\nimport {\n cmdSports,\n cmdEvents,\n cmdOdds,\n cmdScores,\n cmdLive,\n cmdEv,\n cmdPlayerHistory,\n cmdExportResolvedProps,\n cmdWebhooksList,\n cmdWebhooksCreate,\n cmdWebhooksDelete,\n cmdWebhooksTest,\n cmdWebhooksDeliveries,\n} from \"./commands.js\";\n\nexport const VERSION = \"0.1.0\";\n\nconst program = new Command();\n\nprogram\n .name(\"propline\")\n .description(\n \"PropLine CLI — query live odds, scores, +EV plays, prop resolution, and webhooks from the terminal.\",\n )\n .version(VERSION)\n // Global flags. Each command resolves these via its own options object\n // (commander merges parent options into action callbacks for us via\n // .opts({ from: 'parent' }), but easier to just pull from this.parent\n // explicitly to stay strict-typed-friendly).\n .addOption(\n new Option(\"--api-key <key>\", \"PropLine API key\").env(\"PROPLINE_API_KEY\"),\n )\n .addOption(\n new Option(\n \"--base-url <url>\",\n \"API base URL (default https://api.prop-line.com/v1)\",\n ),\n )\n .addOption(\n new Option(\n \"--timeout <seconds>\",\n \"Request timeout in seconds (default 15)\",\n ).argParser((v) => parseInt(v, 10)),\n )\n .addOption(new Option(\"--json\", \"Emit raw JSON instead of a table\"))\n .showHelpAfterError();\n\n// Helper to merge global + command-local options into the flat shape\n// the handlers expect. Keeps each command call site terse.\nfunction gather(cmd: Command): Record<string, unknown> {\n const own = cmd.opts();\n const parent = cmd.parent?.opts() ?? {};\n return { ...parent, ...own };\n}\n\n/* ── sports ─────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"sports\")\n .description(\"List available sports\")\n .action(function (this: Command) {\n return cmdSports(gather(this));\n });\n\n/* ── events ─────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"events\")\n .argument(\"<sport>\", \"sport key (e.g. baseball_mlb)\")\n .description(\"List upcoming events for a sport\")\n .action(function (this: Command, sport: string) {\n return cmdEvents(sport, gather(this));\n });\n\n/* ── odds ───────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"odds\")\n .argument(\"<sport>\", \"sport key (e.g. baseball_mlb)\")\n .argument(\"[event_id]\", \"specific event id (omit for bulk odds)\")\n .option(\n \"-m, --markets <list>\",\n \"comma-separated market keys (e.g. h2h,spreads,totals or player_points)\",\n )\n .description(\"Get current odds across all books\")\n .action(function (this: Command, sport: string, eventId: string | undefined) {\n return cmdOdds(sport, eventId, gather(this));\n });\n\n/* ── scores ─────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"scores\")\n .argument(\"<sport>\", \"sport key\")\n .option(\n \"-d, --days-from <n>\",\n \"days back to include (default 3)\",\n (v) => parseInt(v, 10),\n )\n .description(\"Get game scores and status\")\n .action(function (this: Command, sport: string) {\n return cmdScores(sport, gather(this));\n });\n\n/* ── live ───────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"live\")\n .description(\n \"Show every in-progress game across the major sports (score + period)\",\n )\n .action(function (this: Command) {\n return cmdLive(gather(this));\n });\n\n/* ── ev ─────────────────────────────────────────────────────────────── */\n\nprogram\n .command(\"ev\")\n .argument(\"<sport>\", \"sport key\")\n .argument(\"<event_id>\", \"event id\")\n .option(\"-m, --markets <list>\", \"comma-separated market keys\")\n .option(\n \"--plus\",\n \"show only +EV outcomes (filter rows where ev_pct > 0)\",\n false,\n )\n .description(\"Cross-book +EV against a sharp no-vig fair line (Pro tier)\")\n .action(function (this: Command, sport: string, eventId: string) {\n return cmdEv(sport, eventId, gather(this));\n });\n\n/* ── player-history ─────────────────────────────────────────────────── */\n\nprogram\n .command(\"player-history\")\n .argument(\"<sport>\", \"sport key\")\n .argument(\"<player>\", 'player name (quote if it contains spaces — e.g. \"Aaron Judge\")')\n .requiredOption(\n \"-m, --market <key>\",\n \"market key (required — e.g. pitcher_strikeouts)\",\n )\n .option(\"-b, --bookmaker <key>\", \"filter to a single book (e.g. draftkings)\")\n .option(\"-l, --limit <n>\", \"max entries (1-100, default 20)\", (v) =>\n parseInt(v, 10),\n )\n .description(\"Recent prop history for a player on a market (Pro full, Free redacted)\")\n .action(function (this: Command, sport: string, player: string) {\n return cmdPlayerHistory(sport, player, gather(this) as never);\n });\n\n/* ── export-resolved-props ──────────────────────────────────────────── */\n\nprogram\n .command(\"export-resolved-props\")\n .requiredOption(\"--sport <key>\", \"sport key (required)\")\n .option(\"--market <key>\", \"filter by market key\")\n .option(\"--bookmaker <key>\", \"filter by bookmaker key\")\n .option(\"--since <iso>\", \"ISO datetime lower bound on resolved_at\")\n .option(\"--until <iso>\", \"ISO datetime upper bound on resolved_at\")\n .option(\n \"--out <path>\",\n \"write CSV to this path (default: stream CSV to stdout)\",\n )\n .description(\"Bulk CSV export of resolved props (Pro tier)\")\n .action(function (this: Command) {\n return cmdExportResolvedProps(gather(this) as never);\n });\n\n/* ── webhooks ───────────────────────────────────────────────────────── */\n\nconst webhooks = program.command(\"webhooks\").description(\"Manage webhook subscriptions (Streaming tier)\");\n\nwebhooks\n .command(\"list\")\n .description(\"List your webhook subscriptions\")\n .action(function (this: Command) {\n return cmdWebhooksList(gather(this));\n });\n\nwebhooks\n .command(\"create\")\n .requiredOption(\"--url <url>\", \"HTTPS endpoint that will receive POSTs\")\n .option(\n \"--events <list>\",\n \"comma-separated event types: line_movement,resolution (default: all)\",\n )\n .option(\"--sport <key>\", \"filter to a single sport\")\n .option(\"--market <key>\", \"filter to a single market key\")\n .option(\"--player <name>\", \"filter to a player name (case-insensitive substring)\")\n .option(\n \"--event-id <id>\",\n \"filter to one event id (numeric)\",\n (v) => parseInt(v, 10),\n )\n .option(\n \"--min-price-change-pct <n>\",\n \"minimum % change in American odds to fire a line_movement\",\n (v) => parseFloat(v),\n )\n .description(\"Register a webhook subscription (returns the signing secret ONCE)\")\n .action(function (this: Command) {\n return cmdWebhooksCreate(gather(this) as never);\n });\n\nwebhooks\n .command(\"delete\")\n .argument(\"<id>\", \"webhook id\")\n .description(\"Delete a webhook (cascades its delivery history)\")\n .action(function (this: Command, id: string) {\n return cmdWebhooksDelete(id, gather(this));\n });\n\nwebhooks\n .command(\"test\")\n .argument(\"<id>\", \"webhook id\")\n .description(\"Queue a sample test payload to the webhook URL\")\n .action(function (this: Command, id: string) {\n return cmdWebhooksTest(id, gather(this));\n });\n\nwebhooks\n .command(\"deliveries\")\n .argument(\"<id>\", \"webhook id\")\n .option(\"-l, --limit <n>\", \"max deliveries (default 50)\", (v) =>\n parseInt(v, 10),\n )\n .description(\"Show recent delivery attempts for a webhook\")\n .action(function (this: Command, id: string) {\n return cmdWebhooksDeliveries(id, gather(this) as never);\n });\n\nprogram.parseAsync().catch((err) => {\n process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\\n`);\n process.exit(1);\n});\n","// Thin wrapper around the propline SDK constructor. Resolves auth from\n// (in priority order): --api-key flag → PROPLINE_API_KEY env var → exit\n// with a friendly message. Also threads --base-url for self-hosted /\n// staging deployments and --timeout for slow networks.\n//\n// Pulled out of index.ts so every command resolves credentials the same\n// way — drift between commands is the most common source of \"works on\n// my machine\" CLI bugs.\n\nimport { PropLine, PropLineError } from \"propline\";\n\nexport interface ClientFlags {\n apiKey?: string;\n baseUrl?: string;\n timeout?: number;\n}\n\nexport function buildClient(flags: ClientFlags): PropLine {\n const apiKey = flags.apiKey ?? process.env.PROPLINE_API_KEY;\n if (!apiKey) {\n process.stderr.write(\n \"error: API key required.\\n\\n\" +\n \" Set PROPLINE_API_KEY in your environment, or pass --api-key.\\n\" +\n \" Get one free at https://prop-line.com\\n\",\n );\n process.exit(2);\n }\n return new PropLine(apiKey, {\n baseUrl: flags.baseUrl,\n timeoutMs: flags.timeout ? flags.timeout * 1000 : undefined,\n });\n}\n\n/** Wrap a command body with consistent error reporting. PropLine API\n * errors get a one-line summary; everything else surfaces the message\n * + exits non-zero so shell scripts can detect failure. */\nexport async function runCommand(fn: () => Promise<void>): Promise<void> {\n try {\n await fn();\n } catch (err) {\n if (err instanceof PropLineError) {\n process.stderr.write(`error: ${err.message}\\n`);\n } else if (err instanceof Error) {\n process.stderr.write(`error: ${err.message}\\n`);\n } else {\n process.stderr.write(`error: ${String(err)}\\n`);\n }\n process.exit(1);\n }\n}\n","// Pretty-printing helpers — zero deps. Default output is a fixed-width\n// table with right-aligned numeric columns; pass --json on any command\n// to bypass and emit raw response JSON instead. Tables are streamed to\n// stdout via console.log so a downstream `| head` short-circuits cleanly.\n\nexport interface Column<T> {\n label: string;\n /** Stringified cell value. */\n value: (row: T) => string;\n /** Right-align (numeric) vs default left-align. */\n numeric?: boolean;\n}\n\nexport function printJson(data: unknown): void {\n process.stdout.write(JSON.stringify(data, null, 2) + \"\\n\");\n}\n\nexport function printTable<T>(rows: T[], columns: Column<T>[]): void {\n if (rows.length === 0) {\n process.stdout.write(\"(no rows)\\n\");\n return;\n }\n const cells: string[][] = rows.map((r) =>\n columns.map((c) => {\n const v = c.value(r);\n return v === undefined || v === null ? \"\" : String(v);\n }),\n );\n const headers = columns.map((c) => c.label);\n\n // Width = max(header, max cell). Capped at 60 chars so a long player\n // name or URL doesn't blow the layout open; the table is for skim\n // reading, full data is one --json away.\n const widths = headers.map((h, i) =>\n Math.min(60, Math.max(h.length, ...cells.map((row) => (row[i] ?? \"\").length))),\n );\n\n function pad(s: string, w: number, numeric: boolean): string {\n const truncated = s.length > w ? s.slice(0, w - 1) + \"…\" : s;\n if (numeric) return truncated.padStart(w);\n return truncated.padEnd(w);\n }\n\n // Header\n process.stdout.write(\n headers\n .map((h, i) => pad(h, widths[i] ?? 0, columns[i]?.numeric ?? false))\n .join(\" \") + \"\\n\",\n );\n // Underline\n process.stdout.write(widths.map((w) => \"─\".repeat(w)).join(\" \") + \"\\n\");\n // Rows\n for (const row of cells) {\n process.stdout.write(\n row\n .map((c, i) => pad(c, widths[i] ?? 0, columns[i]?.numeric ?? false))\n .join(\" \") + \"\\n\",\n );\n }\n}\n\nexport function formatPrice(price: number | null | undefined): string {\n if (price === null || price === undefined) return \"–\";\n if (price === 0) return \"EVEN\";\n return price > 0 ? `+${price}` : String(price);\n}\n\nexport function formatPoint(point: number | null | undefined): string {\n if (point === null || point === undefined) return \"\";\n if (Number.isInteger(point)) return String(point);\n return point.toFixed(1);\n}\n\nexport function formatTime(iso: string | null | undefined): string {\n if (!iso) return \"\";\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return iso;\n return d.toISOString().replace(/\\.\\d{3}Z$/, \"Z\");\n}\n\n/** Truncate to N chars with ellipsis — used for long player/market names. */\nexport function truncate(s: string, n: number): string {\n if (s.length <= n) return s;\n return s.slice(0, n - 1) + \"…\";\n}\n","// Per-command handlers. Each one builds a PropLine client, calls the\n// SDK, and pretty-prints the result via format.ts (or dumps raw JSON\n// when --json is passed). Commands stay independent — no shared\n// per-call state — so future ones can be added without touching the\n// existing surface.\n\nimport type { PropLine } from \"propline\";\nimport { buildClient, runCommand, type ClientFlags } from \"./client.js\";\nimport {\n printJson,\n printTable,\n formatPrice,\n formatPoint,\n formatTime,\n truncate,\n type Column,\n} from \"./format.js\";\n\ninterface CommonFlags extends ClientFlags {\n json?: boolean;\n}\n\n/* ── sports ─────────────────────────────────────────────────────────── */\n\nexport function cmdSports(flags: CommonFlags): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const sports = await client.getSports();\n if (flags.json) return printJson(sports);\n const cols: Column<(typeof sports)[number]>[] = [\n { label: \"KEY\", value: (r) => r.key },\n { label: \"TITLE\", value: (r) => r.title },\n { label: \"ACTIVE\", value: (r) => (r.active ? \"yes\" : \"no\") },\n ];\n printTable(sports, cols);\n });\n}\n\n/* ── events ─────────────────────────────────────────────────────────── */\n\nexport function cmdEvents(sport: string, flags: CommonFlags): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const events = await client.getEvents(sport);\n if (flags.json) return printJson(events);\n const cols: Column<(typeof events)[number]>[] = [\n { label: \"ID\", value: (r) => String(r.id) },\n { label: \"AWAY\", value: (r) => r.away_team },\n { label: \"HOME\", value: (r) => r.home_team },\n { label: \"COMMENCES\", value: (r) => formatTime(r.commence_time) },\n ];\n printTable(events, cols);\n });\n}\n\n/* ── odds (bulk and single-event) ───────────────────────────────────── */\n\nexport function cmdOdds(\n sport: string,\n eventId: string | undefined,\n flags: CommonFlags & { markets?: string },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const markets = parseMarketsFlag(flags.markets);\n\n if (eventId) {\n const resp = await client.getOdds(sport, { eventId, markets });\n if (flags.json) return printJson(resp);\n printOddsResponse(resp);\n return;\n }\n\n const resp = await client.getOdds(sport, { markets });\n if (flags.json) return printJson(resp);\n // Bulk: one row per (event, book, market, outcome) gets dense fast.\n // Collapse to a per-event summary row showing how many books / markets\n // each event has, so the user sees the slate at a glance.\n type Row = {\n id: string;\n teams: string;\n commence: string;\n books: number;\n markets: number;\n };\n const rows: Row[] = resp.map((ev) => {\n const books = ev.bookmakers ?? [];\n const markets = books.reduce((sum, b) => sum + (b.markets?.length ?? 0), 0);\n return {\n id: String(ev.id),\n teams: `${ev.away_team} @ ${ev.home_team}`,\n commence: formatTime(ev.commence_time),\n books: books.length,\n markets,\n };\n });\n const cols: Column<Row>[] = [\n { label: \"ID\", value: (r) => r.id },\n { label: \"MATCHUP\", value: (r) => r.teams },\n { label: \"COMMENCES\", value: (r) => r.commence },\n { label: \"BOOKS\", value: (r) => String(r.books), numeric: true },\n { label: \"MARKETS\", value: (r) => String(r.markets), numeric: true },\n ];\n printTable(rows, cols);\n });\n}\n\ninterface OddsResponseLike {\n id: number | string;\n home_team: string;\n away_team: string;\n bookmakers?: Array<{\n key: string;\n title: string;\n markets?: Array<{\n key: string;\n outcomes?: Array<{\n name: string;\n description?: string | null;\n price: number;\n point?: number | null;\n }>;\n }>;\n }>;\n}\n\nfunction printOddsResponse(resp: OddsResponseLike): void {\n // Per-event detail view: one row per (book, market, outcome). Same\n // shape as `propline odds <sport> <event> --json` but flattened so the\n // table reads top-to-bottom by book → market → outcome.\n type Row = {\n book: string;\n market: string;\n player: string;\n side: string;\n point: string;\n price: string;\n };\n const rows: Row[] = [];\n for (const book of resp.bookmakers ?? []) {\n for (const market of book.markets ?? []) {\n for (const o of market.outcomes ?? []) {\n rows.push({\n book: book.title,\n market: market.key,\n player: o.description ?? \"\",\n side: o.name,\n point: formatPoint(o.point ?? null),\n price: formatPrice(o.price),\n });\n }\n }\n }\n if (rows.length === 0) {\n process.stdout.write(\n `(no markets returned — try --markets h2h,spreads,totals or the desired prop key)\\n`,\n );\n return;\n }\n const header = `${resp.away_team} @ ${resp.home_team} (event ${resp.id})\\n`;\n process.stdout.write(header);\n const cols: Column<Row>[] = [\n { label: \"BOOK\", value: (r) => r.book },\n { label: \"MARKET\", value: (r) => r.market },\n { label: \"PLAYER\", value: (r) => truncate(r.player, 28) },\n { label: \"SIDE\", value: (r) => r.side },\n { label: \"LINE\", value: (r) => r.point, numeric: true },\n { label: \"PRICE\", value: (r) => r.price, numeric: true },\n ];\n printTable(rows, cols);\n}\n\n/* ── scores ─────────────────────────────────────────────────────────── */\n\nexport function cmdScores(\n sport: string,\n flags: CommonFlags & { daysFrom?: number },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const scores = await client.getScores(sport, { daysFrom: flags.daysFrom });\n if (flags.json) return printJson(scores);\n const cols: Column<(typeof scores)[number]>[] = [\n { label: \"ID\", value: (r) => String(r.id) },\n { label: \"STATUS\", value: (r) => String(r.status) },\n { label: \"AWAY\", value: (r) => r.away_team },\n {\n label: \"AS\",\n value: (r) => (r.away_score === null ? \"\" : String(r.away_score)),\n numeric: true,\n },\n { label: \"HOME\", value: (r) => r.home_team },\n {\n label: \"HS\",\n value: (r) => (r.home_score === null ? \"\" : String(r.home_score)),\n numeric: true,\n },\n { label: \"COMMENCED\", value: (r) => formatTime(r.commence_time) },\n ];\n printTable(scores, cols);\n });\n}\n\n/* ── live (cross-sport in-progress games) ────────────────────────────── */\n\nconst LIVE_SPORTS = [\n \"baseball_mlb\",\n \"basketball_nba\",\n \"hockey_nhl\",\n \"basketball_ncaab\",\n \"football_nfl\",\n \"football_ncaaf\",\n \"soccer_epl\",\n \"soccer_la_liga\",\n \"soccer_serie_a\",\n \"soccer_bundesliga\",\n \"soccer_ligue_1\",\n \"soccer_mls\",\n \"tennis\",\n \"golf\",\n \"mma_ufc\",\n];\n\nexport function cmdLive(flags: CommonFlags): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n // Hit /scores per sport in parallel and keep only `in_progress` rows.\n // Tolerates per-sport failure so one 404 doesn't abort the whole\n // command — the CLI is meant for casual terminal use, not strict\n // pipelines.\n type LiveRow = {\n sport: string;\n id: string;\n teams: string;\n score: string;\n period: string;\n };\n const settled = await Promise.allSettled(\n LIVE_SPORTS.map(async (sportKey): Promise<LiveRow[]> => {\n const scores = await client.getScores(sportKey, { daysFrom: 1 });\n return scores\n .filter((sc) => sc.status === \"in_progress\")\n .map((sc) => ({\n sport: sportKey,\n id: String(sc.id),\n teams: `${sc.away_team} @ ${sc.home_team}`,\n score:\n sc.home_score !== null && sc.away_score !== null\n ? `${sc.away_score}-${sc.home_score}`\n : \"\",\n period: typeof sc.period === \"string\" ? sc.period : \"\",\n }));\n }),\n );\n const rows: LiveRow[] = [];\n for (const r of settled) {\n if (r.status !== \"fulfilled\") continue;\n rows.push(...r.value);\n }\n if (flags.json) return printJson(rows);\n if (rows.length === 0) {\n process.stdout.write(\"(no games in progress right now)\\n\");\n return;\n }\n const cols: Column<LiveRow>[] = [\n { label: \"SPORT\", value: (r) => r.sport },\n { label: \"ID\", value: (r) => r.id },\n { label: \"MATCHUP\", value: (r) => r.teams },\n { label: \"SCORE\", value: (r) => r.score },\n { label: \"PERIOD\", value: (r) => r.period },\n ];\n printTable(rows, cols);\n });\n}\n\n/* ── ev (cross-book +EV) ────────────────────────────────────────────── */\n\nexport function cmdEv(\n sport: string,\n eventId: string,\n flags: CommonFlags & { markets?: string; plus?: boolean },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const resp = await client.getEventEv(sport, eventId, {\n markets: parseMarketsFlag(flags.markets),\n });\n if (flags.json) return printJson(resp);\n type Row = {\n market: string;\n player: string;\n point: string;\n side: string;\n book: string;\n price: string;\n ev: string;\n plus: boolean;\n };\n const rows: Row[] = [];\n for (const line of resp.lines) {\n for (const o of line.outcomes) {\n rows.push({\n market: line.market_key,\n player: line.description,\n point: formatPoint(line.point),\n side: o.name,\n book: o.book_title,\n price: formatPrice(o.price),\n ev: `${o.ev_pct >= 0 ? \"+\" : \"\"}${o.ev_pct.toFixed(2)}%`,\n plus: o.is_plus_ev,\n });\n }\n }\n const filtered = flags.plus ? rows.filter((r) => r.plus) : rows;\n // Sort +EV first regardless of filter — the most-actionable rows\n // should land at the top of the terminal, not the bottom.\n filtered.sort((a, b) => parseFloat(b.ev) - parseFloat(a.ev));\n process.stdout.write(\n `${resp.away_team} @ ${resp.home_team} · fair anchor: ${resp.fair_source_default}\\n`,\n );\n const cols: Column<Row>[] = [\n { label: \"MARKET\", value: (r) => r.market },\n { label: \"PLAYER\", value: (r) => truncate(r.player, 24) },\n { label: \"LINE\", value: (r) => r.point, numeric: true },\n { label: \"SIDE\", value: (r) => r.side },\n { label: \"BOOK\", value: (r) => r.book },\n { label: \"PRICE\", value: (r) => r.price, numeric: true },\n { label: \"EV%\", value: (r) => r.ev, numeric: true },\n ];\n printTable(filtered, cols);\n });\n}\n\n/* ── player-history ─────────────────────────────────────────────────── */\n\nexport function cmdPlayerHistory(\n sport: string,\n player: string,\n flags: CommonFlags & {\n market: string;\n bookmaker?: string;\n limit?: number;\n },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const resp = await client.getPlayerHistory(sport, player, {\n market: flags.market,\n bookmaker: flags.bookmaker,\n limit: flags.limit,\n });\n if (flags.json) return printJson(resp);\n process.stdout.write(\n `${resp.player_name} · ${resp.market} (${resp.entries.length} entries)\\n`,\n );\n type Entry = (typeof resp.entries)[number];\n const cols: Column<Entry>[] = [\n { label: \"DATE\", value: (r) => formatTime(r.commence_time).slice(0, 10) },\n { label: \"MATCHUP\", value: (r) => `${r.away_team} @ ${r.home_team}` },\n { label: \"BOOK\", value: (r) => r.bookmaker_title },\n {\n label: \"LINE\",\n value: (r) => formatPoint(r.line),\n numeric: true,\n },\n { label: \"OVER\", value: (r) => formatPrice(r.over_price), numeric: true },\n {\n label: \"UNDER\",\n value: (r) => formatPrice(r.under_price),\n numeric: true,\n },\n {\n label: \"ACTUAL\",\n value: (r) => (r.actual_value === null ? \"\" : String(r.actual_value)),\n numeric: true,\n },\n {\n label: \"RESULT\",\n value: (r) => {\n if (r.over_result === \"won\") return \"OVER ✓\";\n if (r.under_result === \"won\") return \"UNDER ✓\";\n if (r.over_result === \"push\" || r.under_result === \"push\") return \"PUSH\";\n if (r.over_result === \"void\" || r.under_result === \"void\") return \"VOID\";\n return \"\";\n },\n },\n ];\n printTable(resp.entries, cols);\n });\n}\n\n/* ── export-resolved-props ──────────────────────────────────────────── */\n\nexport function cmdExportResolvedProps(\n flags: CommonFlags & {\n sport: string;\n market?: string;\n bookmaker?: string;\n since?: string;\n until?: string;\n out?: string;\n },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n if (flags.out) {\n const path = await client.exportResolvedProps({\n sport: flags.sport,\n market: flags.market,\n bookmaker: flags.bookmaker,\n since: flags.since,\n until: flags.until,\n outPath: flags.out,\n });\n process.stdout.write(`exported → ${path}\\n`);\n return;\n }\n // No --out: stream raw CSV bytes straight to stdout so a user can\n // pipe `propline export-resolved-props --sport mlb | head` to\n // sample. --json is meaningless here since the API only emits CSV;\n // we ignore it for this command.\n const buf = await client.exportResolvedProps({\n sport: flags.sport,\n market: flags.market,\n bookmaker: flags.bookmaker,\n since: flags.since,\n until: flags.until,\n });\n process.stdout.write(buf);\n });\n}\n\n/* ── webhooks ───────────────────────────────────────────────────────── */\n\nexport function cmdWebhooksList(flags: CommonFlags): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const hooks = await client.listWebhooks();\n if (flags.json) return printJson(hooks);\n type H = (typeof hooks)[number];\n const cols: Column<H>[] = [\n { label: \"ID\", value: (r) => String(r.id), numeric: true },\n { label: \"URL\", value: (r) => truncate(r.url, 50) },\n { label: \"EVENTS\", value: (r) => (r.events ?? []).join(\",\") },\n { label: \"ACTIVE\", value: (r) => (r.active ? \"yes\" : \"no\") },\n { label: \"SPORT\", value: (r) => r.filter_sport_key ?? \"\" },\n { label: \"MARKET\", value: (r) => r.filter_market_key ?? \"\" },\n { label: \"CREATED\", value: (r) => formatTime(r.created_at) },\n ];\n printTable(hooks, cols);\n });\n}\n\nexport function cmdWebhooksCreate(\n flags: CommonFlags & {\n url: string;\n events?: string;\n sport?: string;\n market?: string;\n player?: string;\n eventId?: number;\n minPriceChangePct?: number;\n },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const events = flags.events\n ? (flags.events.split(\",\").map((s) => s.trim()) as Array<\n \"line_movement\" | \"resolution\"\n >)\n : undefined;\n const hook = await client.createWebhook({\n url: flags.url,\n events,\n filterSportKey: flags.sport,\n filterMarketKey: flags.market,\n filterPlayerName: flags.player,\n filterEventId: flags.eventId,\n minPriceChangePct: flags.minPriceChangePct,\n });\n if (flags.json) return printJson(hook);\n process.stdout.write(\n `webhook ${hook.id} created.\\n` +\n `url: ${hook.url}\\n` +\n `events: ${(hook.events ?? []).join(\",\") || \"(all)\"}\\n` +\n `secret: ${hook.secret}\\n\\n` +\n `STORE THE SECRET NOW — it's only revealed once. Use it to verify\\n` +\n `the X-PropLine-Signature header on every delivery.\\n`,\n );\n });\n}\n\nexport function cmdWebhooksDelete(\n id: string,\n flags: CommonFlags,\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const numeric = Number(id);\n if (!Number.isFinite(numeric)) {\n throw new Error(`webhook id must be numeric: ${id}`);\n }\n await client.deleteWebhook(numeric);\n if (flags.json) return printJson({ ok: true, id: numeric });\n process.stdout.write(`webhook ${numeric} deleted.\\n`);\n });\n}\n\nexport function cmdWebhooksTest(id: string, flags: CommonFlags): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const numeric = Number(id);\n if (!Number.isFinite(numeric)) {\n throw new Error(`webhook id must be numeric: ${id}`);\n }\n const result = await client.testWebhook(numeric);\n if (flags.json) return printJson(result);\n process.stdout.write(`test payload queued for webhook ${numeric}.\\n`);\n });\n}\n\nexport function cmdWebhooksDeliveries(\n id: string,\n flags: CommonFlags & { limit?: number },\n): Promise<void> {\n return runCommand(async () => {\n const client = buildClient(flags);\n const numeric = Number(id);\n if (!Number.isFinite(numeric)) {\n throw new Error(`webhook id must be numeric: ${id}`);\n }\n const deliveries = await client.listWebhookDeliveries(numeric, {\n limit: flags.limit,\n });\n if (flags.json) return printJson(deliveries);\n type D = (typeof deliveries)[number];\n const cols: Column<D>[] = [\n { label: \"ID\", value: (r) => String(r.id), numeric: true },\n { label: \"STATUS\", value: (r) => String(r.status) },\n {\n label: \"RESP\",\n value: (r) => (r.response_code === null ? \"\" : String(r.response_code)),\n numeric: true,\n },\n { label: \"ATTEMPTS\", value: (r) => String(r.attempts), numeric: true },\n { label: \"DELIVERED\", value: (r) => formatTime(r.delivered_at) },\n ];\n printTable(deliveries, cols);\n });\n}\n\n/* ── helpers ────────────────────────────────────────────────────────── */\n\nfunction parseMarketsFlag(value: string | undefined): string[] | undefined {\n if (!value) return undefined;\n return value\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\n/** Avoid an unused-import warning while still re-exporting the type\n * for downstream consumers who want to wire their own subcommands. */\nexport type { PropLine };\n"],"mappings":"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","names":["resp","markets"]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "propline-cli",
3
+ "version": "0.1.0",
4
+ "description": "Command-line interface for the PropLine player props betting odds API. Wraps the propline SDK with pretty-printed tables and JSON output.",
5
+ "keywords": [
6
+ "cli",
7
+ "sports",
8
+ "betting",
9
+ "odds",
10
+ "player-props",
11
+ "api",
12
+ "sportsbook",
13
+ "mlb",
14
+ "nba",
15
+ "nhl",
16
+ "nfl",
17
+ "soccer",
18
+ "ufc",
19
+ "bovada",
20
+ "draftkings",
21
+ "fanduel",
22
+ "pinnacle",
23
+ "prizepicks"
24
+ ],
25
+ "homepage": "https://prop-line.com",
26
+ "bugs": "https://github.com/proplineapi/propline-cli/issues",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+https://github.com/proplineapi/propline-cli.git"
30
+ },
31
+ "license": "MIT",
32
+ "author": "PropLine <support@prop-line.com>",
33
+ "type": "module",
34
+ "main": "./dist/index.js",
35
+ "bin": {
36
+ "propline": "./dist/index.js"
37
+ },
38
+ "files": [
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE"
42
+ ],
43
+ "engines": {
44
+ "node": ">=18"
45
+ },
46
+ "scripts": {
47
+ "build": "tsup",
48
+ "typecheck": "tsc --noEmit",
49
+ "start": "node dist/index.js",
50
+ "dev": "tsup --watch",
51
+ "prepublishOnly": "npm run build"
52
+ },
53
+ "dependencies": {
54
+ "commander": "^12.1.0",
55
+ "propline": "^0.4.0"
56
+ },
57
+ "devDependencies": {
58
+ "@types/node": "^20.19.39",
59
+ "tsup": "^8.3.0",
60
+ "typescript": "^5.6.0"
61
+ }
62
+ }