@trainheroic-unofficial/athlete-mcp 2.1.0 → 3.0.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.
Files changed (2) hide show
  1. package/dist/server.mjs +40 -5
  2. package/package.json +5 -5
package/dist/server.mjs CHANGED
@@ -545,6 +545,34 @@ function confirmGate(ctx, message, confirmArg) {
545
545
  */
546
546
  const SERVER_INSTRUCTIONS = "Speak to the user in plain, everyday language about their training. Describe what you are doing in the TrainHeroic app's own terms (for example, say you are creating a workout rather than naming a tool). Do not surface internal tool names (the snake_case identifiers such as athlete_session_create), raw parameter names, or numeric ids in your replies unless the user explicitly asks for them; they are implementation details. The tool descriptions cross-reference each other by name only so you can chain them correctly. Keep that wiring to yourself.";
547
547
  //#endregion
548
+ //#region ../js/src/http-error.ts
549
+ /**
550
+ * A final non-2xx response from TrainHeroic. The error deliberately carries only request
551
+ * metadata that is safe to send to telemetry: never the path, query string, request body,
552
+ * response body, credentials, or session token.
553
+ */
554
+ var TrainHeroicHttpError = class extends Error {
555
+ name = "TrainHeroicHttpError";
556
+ method;
557
+ status;
558
+ host;
559
+ constructor(method, url, status) {
560
+ const parsed = new URL(url);
561
+ const normalizedMethod = method.toUpperCase();
562
+ super(`TrainHeroic ${normalizedMethod} request failed with HTTP ${status}`);
563
+ this.method = normalizedMethod;
564
+ this.status = status;
565
+ this.host = parsed.host;
566
+ }
567
+ };
568
+ /** Call observability hooks without allowing them to change SDK behavior. */
569
+ function notifyHttpError(handler, method, url, status) {
570
+ if (!handler) return;
571
+ try {
572
+ Promise.resolve(handler(new TrainHeroicHttpError(method, url, status))).catch(() => {});
573
+ } catch {}
574
+ }
575
+ //#endregion
548
576
  //#region ../js/src/auth.ts
549
577
  const DEFAULT_AUTH_URL = "https://apis.trainheroic.com/auth";
550
578
  /**
@@ -566,8 +594,9 @@ function authUrl() {
566
594
  * the Phase 0 spike: no refresh_token, no api_token, no TTL). The 48-char session_id
567
595
  * is sent as the `session-token` header and works against both API hosts.
568
596
  */
569
- async function loginTrainHeroic(email, password) {
570
- const res = await fetch(authUrl(), {
597
+ async function loginTrainHeroic(email, password, options = {}) {
598
+ const url = authUrl();
599
+ const res = await fetch(url, {
571
600
  method: "POST",
572
601
  headers: {
573
602
  "content-type": "application/x-www-form-urlencoded",
@@ -578,7 +607,10 @@ async function loginTrainHeroic(email, password) {
578
607
  password
579
608
  }).toString()
580
609
  });
581
- if (!res.ok) return null;
610
+ if (!res.ok) {
611
+ notifyHttpError(options.onHttpError, "POST", url, res.status);
612
+ return null;
613
+ }
582
614
  const data = await res.json().catch(() => null);
583
615
  if (!data || typeof data.id !== "number" || !data.session_id) return null;
584
616
  return {
@@ -621,6 +653,7 @@ var TrainHeroicClient = class {
621
653
  #email;
622
654
  #password;
623
655
  #onSession;
656
+ #onHttpError;
624
657
  #sessionId;
625
658
  #loginInFlight = null;
626
659
  constructor(email, password, sessionId = null, options = {}) {
@@ -628,6 +661,7 @@ var TrainHeroicClient = class {
628
661
  this.#password = password;
629
662
  this.#sessionId = sessionId;
630
663
  this.#onSession = options.onSession;
664
+ this.#onHttpError = options.onHttpError;
631
665
  }
632
666
  get sessionId() {
633
667
  return this.#sessionId;
@@ -642,7 +676,7 @@ var TrainHeroicClient = class {
642
676
  }
643
677
  }
644
678
  async #login() {
645
- const session = await loginTrainHeroic(this.#email, this.#password);
679
+ const session = await loginTrainHeroic(this.#email, this.#password, this.#onHttpError ? { onHttpError: this.#onHttpError } : {});
646
680
  if (!session) throw new TrainHeroicAuthError("TrainHeroic login failed");
647
681
  this.#sessionId = session.sessionId;
648
682
  try {
@@ -659,6 +693,7 @@ var TrainHeroicClient = class {
659
693
  session = await this.#ensureSession();
660
694
  res = await this.#send(method, url, session, options.body);
661
695
  }
696
+ if (!res.ok) notifyHttpError(this.#onHttpError, method, url, res.status);
662
697
  const text = await res.text();
663
698
  let data = text;
664
699
  if (text.length > 0) try {
@@ -2115,7 +2150,7 @@ function registerAthleteTrainingTools(server, ctx) {
2115
2150
  }
2116
2151
  //#endregion
2117
2152
  //#region package.json
2118
- var version = "2.1.0";
2153
+ var version = "3.0.0";
2119
2154
  //#endregion
2120
2155
  //#region src/server.ts
2121
2156
  function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trainheroic-unofficial/athlete-mcp",
3
- "version": "2.1.0",
3
+ "version": "3.0.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,13 +21,13 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/server": "2.0.0",
23
23
  "zod": "^4.4.3",
24
- "@trainheroic-unofficial/core": "2.1.0",
25
- "@trainheroic-unofficial/js": "2.1.0"
24
+ "@trainheroic-unofficial/core": "3.0.0",
25
+ "@trainheroic-unofficial/js": "3.0.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/node": "^26.1.2",
28
+ "@types/node": "^26.2.0",
29
29
  "tsdown": "^0.22.14",
30
- "tsx": "^4.23.4",
30
+ "tsx": "^4.23.11",
31
31
  "typescript": "^7.0.2",
32
32
  "vitest": "^4.1.10"
33
33
  },