telescope-ai 0.1.2 → 0.2.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 CHANGED
@@ -31,6 +31,11 @@ const client = new TelescopeClient({
31
31
  const data = await client.insights.instrument.generate({
32
32
  instrument_reference_id1: "AAPL_US",
33
33
  });
34
+
35
+ const latestNews = await client.news.latest.generate({
36
+ instrument_reference_id1s: ["AAPL_US"],
37
+ instrument_group_ids: ["your-group-id"],
38
+ });
34
39
  ```
35
40
 
36
41
  ### Streaming Example
@@ -117,6 +122,7 @@ const client = new TelescopeClient({
117
122
  - `TelescopeClient.VERSION` - Static property containing the SDK version
118
123
  - `client.insights` - Namespaced access to Insights API
119
124
  - `client.atlas` - Namespaced access to Atlas API
125
+ - `client.news` - Namespaced access to News API
120
126
 
121
127
  #### Methods
122
128
 
@@ -147,25 +153,34 @@ const session = client.insights.instrument.streamFromResponse(response);
147
153
  const data = await client.insights.portfolio.generateFromResponse(response);
148
154
  ```
149
155
 
150
- ### Atlas API
156
+ > **Note:** Ripple and Guardrails clients are coming in a future release once their backends support the V2 SSE format.
157
+
158
+ ### News API
151
159
 
152
- Access via `client.atlas`:
160
+ Access via `client.news`.
153
161
 
154
162
  ```typescript
155
- // Streaming
156
- const session = client.atlas.streamAdvice({
157
- advisor_environment_id: "...",
158
- client_details: "...",
159
- // ... other required fields
163
+ // Non-streaming: latest stories for instruments
164
+ const latest = await client.news.latest.generate({
165
+ instrument_reference_id1s: ["AAPL_US", "NVDA_US"],
166
+ instrument_group_ids: ["group-uuid"],
167
+ limit: 20,
168
+ locale: "en-US",
160
169
  });
161
170
 
162
- // Non-streaming
163
- const advice = await client.atlas.getAdvice("advice-id");
164
- const recent = await client.atlas.getLatestAdvice(30);
165
- await client.atlas.archiveAdvice(["id1", "id2"], true);
166
- ```
171
+ // Streaming: trending topics
172
+ const session = client.news.trendingTopics.stream({
173
+ topics: ["Region: Global"],
174
+ limit: 10,
175
+ locale: "en-US",
176
+ });
167
177
 
168
- > **Note:** Ripple and Guardrails clients are coming in a future release once their backends support the V2 SSE format.
178
+ // Non-streaming: trending topics
179
+ const topics = await client.news.trendingTopics.generate({
180
+ topics: ["Asset Class: Crypto"],
181
+ limit: 10,
182
+ });
183
+ ```
169
184
 
170
185
  ### StreamSession
171
186
 
@@ -257,7 +272,6 @@ import type {
257
272
  StreamStatus,
258
273
  StreamPhase,
259
274
  InstrumentInsightsResponse,
260
- AtlasAdviceResponse,
261
275
  } from "telescope-ai";
262
276
  ```
263
277
 
@@ -194,7 +194,7 @@ function pathToKey(path) {
194
194
  * Returns null for unknown event types (per spec: clients MUST ignore unknown events).
195
195
  */
196
196
  function parseEvent(eventName, rawData) {
197
- switch (eventName) {
197
+ switch (eventName.toLowerCase()) {
198
198
  case "patch": {
199
199
  const data = rawData;
200
200
  return {
@@ -217,7 +217,7 @@ function parseEvent(eventName, rawData) {
217
217
  data: {
218
218
  code: data.code,
219
219
  message: data.message,
220
- http_status: data.http_status,
220
+ http_status: data.http_status ?? data.status_code ?? 0,
221
221
  path: data.path,
222
222
  additional_data: data.additional_data
223
223
  }
@@ -388,6 +388,7 @@ var ResponseBuilder = class {
388
388
  * - Path completion tracking
389
389
  * - Promise-based completion
390
390
  */
391
+ init_errors();
391
392
  /**
392
393
  * StreamSession manages a single streaming request.
393
394
  *
@@ -515,6 +516,14 @@ var StreamSession = class {
515
516
  }
516
517
  handleError(errorData) {
517
518
  this.notifyObservers((obs) => obs.onError?.(errorData));
519
+ const sseError = new SSEError(errorData);
520
+ this.setStatus({
521
+ phase: "error",
522
+ startedAt: this._status.startedAt,
523
+ completedAt: Date.now(),
524
+ error: sseError
525
+ });
526
+ this.completionReject(sseError);
518
527
  }
519
528
  handleHeartbeat() {
520
529
  this.notifyObservers((obs) => obs.onHeartbeat?.());
@@ -544,56 +553,29 @@ var StreamSession = class {
544
553
  };
545
554
 
546
555
  //#endregion
547
- //#region src/insights/client.ts
548
- var client_exports$1 = /* @__PURE__ */ __exportAll({ InsightsClient: () => InsightsClient });
549
- var InstrumentInsightsClient, PortfolioInsightsClient, InsightsClient;
550
- var init_client$1 = __esmMin((() => {
556
+ //#region src/insights/instrument/client.ts
557
+ var InstrumentInsightsClient;
558
+ var init_client$7 = __esmMin((() => {
551
559
  init_errors();
552
560
  InstrumentInsightsClient = class {
553
561
  constructor(client) {
554
562
  this.client = client;
555
563
  }
556
- /**
557
- * Stream insights for a single instrument via SSE.
558
- *
559
- * @example
560
- * ```ts
561
- * const session = client.insights.instrument.stream({ instrument_id: "abc123" });
562
- * session.subscribe({ onPatch: (data) => console.log(data.groups) });
563
- * const result = await session.complete();
564
- * ```
565
- */
566
564
  stream(request, options) {
567
565
  return this.client.stream("/v2/insights/instrument", {
568
566
  ...request,
569
567
  stream: true
570
568
  }, options);
571
569
  }
572
- /**
573
- * Get insights for an instrument (non-streaming).
574
- *
575
- * @example
576
- * ```ts
577
- * const data = await client.insights.instrument.generate({ instrument_id: "abc123" });
578
- * ```
579
- */
580
570
  async generate(request) {
581
571
  return this.client.post("/v2/insights/instrument", {
582
572
  ...request,
583
573
  stream: false
584
574
  });
585
575
  }
586
- /**
587
- * Create a StreamSession from a pre-existing SSE response.
588
- * Use this when you have a response from a proxy or custom fetch.
589
- */
590
576
  streamFromResponse(source) {
591
577
  return this.client.streamFromResponse(source);
592
578
  }
593
- /**
594
- * Parse a pre-existing JSON response (non-streaming).
595
- * Use this when you have a response from a proxy or custom fetch.
596
- */
597
579
  async generateFromResponse(response) {
598
580
  if (!response.ok) {
599
581
  const body = await response.text().catch(() => "");
@@ -602,37 +584,32 @@ var init_client$1 = __esmMin((() => {
602
584
  return response.json();
603
585
  }
604
586
  };
587
+ }));
588
+
589
+ //#endregion
590
+ //#region src/insights/portfolio/client.ts
591
+ var PortfolioInsightsClient;
592
+ var init_client$6 = __esmMin((() => {
593
+ init_errors();
605
594
  PortfolioInsightsClient = class {
606
595
  constructor(client) {
607
596
  this.client = client;
608
597
  }
609
- /**
610
- * Stream insights for a portfolio via SSE.
611
- */
612
598
  stream(request, options) {
613
599
  return this.client.stream("/v2/insights/portfolio", {
614
600
  ...request,
615
601
  stream: true
616
602
  }, options);
617
603
  }
618
- /**
619
- * Get insights for a portfolio (non-streaming).
620
- */
621
604
  async generate(request) {
622
605
  return this.client.post("/v2/insights/portfolio", {
623
606
  ...request,
624
607
  stream: false
625
608
  });
626
609
  }
627
- /**
628
- * Create a StreamSession from a pre-existing SSE response.
629
- */
630
610
  streamFromResponse(source) {
631
611
  return this.client.streamFromResponse(source);
632
612
  }
633
- /**
634
- * Parse a pre-existing JSON response (non-streaming).
635
- */
636
613
  async generateFromResponse(response) {
637
614
  if (!response.ok) {
638
615
  const body = await response.text().catch(() => "");
@@ -641,23 +618,153 @@ var init_client$1 = __esmMin((() => {
641
618
  return response.json();
642
619
  }
643
620
  };
621
+ }));
622
+
623
+ //#endregion
624
+ //#region src/insights/watchlist/client.ts
625
+ var WatchlistInsightsClient;
626
+ var init_client$5 = __esmMin((() => {
627
+ init_errors();
628
+ WatchlistInsightsClient = class {
629
+ constructor(client) {
630
+ this.client = client;
631
+ }
632
+ stream(request, options) {
633
+ return this.client.stream("/v2/insights/watchlist", {
634
+ ...request,
635
+ stream: true
636
+ }, options);
637
+ }
638
+ async generate(request) {
639
+ return this.client.post("/v2/insights/watchlist", {
640
+ ...request,
641
+ stream: false
642
+ });
643
+ }
644
+ streamFromResponse(source) {
645
+ return this.client.streamFromResponse(source);
646
+ }
647
+ async generateFromResponse(response) {
648
+ if (!response.ok) {
649
+ const body = await response.text().catch(() => "");
650
+ throw new ApiError(`Response not OK: ${response.status}`, response.status, body || void 0);
651
+ }
652
+ return response.json();
653
+ }
654
+ };
655
+ }));
656
+
657
+ //#endregion
658
+ //#region src/insights/market/client.ts
659
+ var MarketInsightsClient;
660
+ var init_client$4 = __esmMin((() => {
661
+ init_errors();
662
+ MarketInsightsClient = class {
663
+ constructor(client) {
664
+ this.client = client;
665
+ }
666
+ stream(request, options) {
667
+ return this.client.stream("/v2/insights/market", {
668
+ ...request,
669
+ stream: true
670
+ }, options);
671
+ }
672
+ async generate(request) {
673
+ return this.client.post("/v2/insights/market", {
674
+ ...request,
675
+ stream: false
676
+ });
677
+ }
678
+ streamFromResponse(source) {
679
+ return this.client.streamFromResponse(source);
680
+ }
681
+ async generateFromResponse(response) {
682
+ if (!response.ok) {
683
+ const body = await response.text().catch(() => "");
684
+ throw new ApiError(`Response not OK: ${response.status}`, response.status, body || void 0);
685
+ }
686
+ return response.json();
687
+ }
688
+ };
689
+ }));
690
+
691
+ //#endregion
692
+ //#region src/insights/trending/client.ts
693
+ var TrendingInsightsClient;
694
+ var init_client$3 = __esmMin((() => {
695
+ init_errors();
696
+ TrendingInsightsClient = class {
697
+ constructor(client) {
698
+ this.client = client;
699
+ }
700
+ stream(request, options) {
701
+ return this.client.stream("/v2/insights/trending", {
702
+ ...request,
703
+ stream: true
704
+ }, options);
705
+ }
706
+ async generate(request) {
707
+ return this.client.post("/v2/insights/trending", {
708
+ ...request,
709
+ stream: false
710
+ });
711
+ }
712
+ streamFromResponse(source) {
713
+ return this.client.streamFromResponse(source);
714
+ }
715
+ async generateFromResponse(response) {
716
+ if (!response.ok) {
717
+ const body = await response.text().catch(() => "");
718
+ throw new ApiError(`Response not OK: ${response.status}`, response.status, body || void 0);
719
+ }
720
+ return response.json();
721
+ }
722
+ };
723
+ }));
724
+
725
+ //#endregion
726
+ //#region src/insights/client.ts
727
+ var client_exports$2 = /* @__PURE__ */ __exportAll({
728
+ InsightsClient: () => InsightsClient,
729
+ InstrumentInsightsClient: () => InstrumentInsightsClient,
730
+ MarketInsightsClient: () => MarketInsightsClient,
731
+ PortfolioInsightsClient: () => PortfolioInsightsClient,
732
+ TrendingInsightsClient: () => TrendingInsightsClient,
733
+ WatchlistInsightsClient: () => WatchlistInsightsClient
734
+ });
735
+ var InsightsClient;
736
+ var init_client$2 = __esmMin((() => {
737
+ init_client$7();
738
+ init_client$6();
739
+ init_client$5();
740
+ init_client$4();
741
+ init_client$3();
742
+ init_client$7();
743
+ init_client$6();
744
+ init_client$5();
745
+ init_client$4();
746
+ init_client$3();
644
747
  InsightsClient = class {
645
- /** Instrument insights operations */
646
748
  instrument;
647
- /** Portfolio insights operations */
648
749
  portfolio;
750
+ watchlist;
751
+ market;
752
+ trending;
649
753
  constructor(client) {
650
754
  this.instrument = new InstrumentInsightsClient(client);
651
755
  this.portfolio = new PortfolioInsightsClient(client);
756
+ this.watchlist = new WatchlistInsightsClient(client);
757
+ this.market = new MarketInsightsClient(client);
758
+ this.trending = new TrendingInsightsClient(client);
652
759
  }
653
760
  };
654
761
  }));
655
762
 
656
763
  //#endregion
657
764
  //#region src/atlas/client.ts
658
- var client_exports = /* @__PURE__ */ __exportAll({ AtlasClient: () => AtlasClient });
765
+ var client_exports$1 = /* @__PURE__ */ __exportAll({ AtlasClient: () => AtlasClient });
659
766
  var AtlasClient;
660
- var init_client = __esmMin((() => {
767
+ var init_client$1 = __esmMin((() => {
661
768
  AtlasClient = class {
662
769
  constructor(client) {
663
770
  this.client = client;
@@ -699,6 +806,86 @@ var init_client = __esmMin((() => {
699
806
  archived
700
807
  });
701
808
  }
809
+ /**
810
+ * List available advisor environments.
811
+ */
812
+ async getAdvisorEnvironments(options) {
813
+ const params = new URLSearchParams();
814
+ if (options?.region) params.set("region", options.region);
815
+ if (options?.currency) params.set("currency", options.currency);
816
+ const qs = params.toString();
817
+ const path = `/v2/atlas/advisor-environments${qs ? `?${qs}` : ""}`;
818
+ return (await this.client.get(path)).environments;
819
+ }
820
+ };
821
+ }));
822
+
823
+ //#endregion
824
+ //#region src/news/client.ts
825
+ var client_exports = /* @__PURE__ */ __exportAll({ NewsClient: () => NewsClient });
826
+ var NewsLatestClient, NewsTrendingTopicsClient, NewsClient;
827
+ var init_client = __esmMin((() => {
828
+ init_errors();
829
+ NewsLatestClient = class {
830
+ constructor(client) {
831
+ this.client = client;
832
+ }
833
+ /**
834
+ * Get latest stories for a set of instruments (non-streaming).
835
+ */
836
+ async generate(request) {
837
+ return this.client.post("/v2/news/latest", {
838
+ ...request,
839
+ stream: false
840
+ });
841
+ }
842
+ };
843
+ NewsTrendingTopicsClient = class {
844
+ constructor(client) {
845
+ this.client = client;
846
+ }
847
+ /**
848
+ * Stream ranked trending topics via SSE.
849
+ */
850
+ stream(request, options) {
851
+ return this.client.stream("/v2/news/trending/topics", {
852
+ ...request,
853
+ stream: true
854
+ }, options);
855
+ }
856
+ /**
857
+ * Get ranked trending topics (non-streaming).
858
+ */
859
+ async generate(request) {
860
+ return this.client.post("/v2/news/trending/topics", {
861
+ ...request,
862
+ stream: false
863
+ });
864
+ }
865
+ /**
866
+ * Create a StreamSession from a pre-existing SSE response.
867
+ */
868
+ streamFromResponse(source) {
869
+ return this.client.streamFromResponse(source);
870
+ }
871
+ /**
872
+ * Parse a pre-existing JSON response (non-streaming).
873
+ */
874
+ async generateFromResponse(response) {
875
+ if (!response.ok) {
876
+ const body = await response.text().catch(() => "");
877
+ throw new ApiError(`Response not OK: ${response.status}`, response.status, body || void 0);
878
+ }
879
+ return response.json();
880
+ }
881
+ };
882
+ NewsClient = class {
883
+ latest;
884
+ trendingTopics;
885
+ constructor(client) {
886
+ this.latest = new NewsLatestClient(client);
887
+ this.trendingTopics = new NewsTrendingTopicsClient(client);
888
+ }
702
889
  };
703
890
  }));
704
891
 
@@ -706,7 +893,7 @@ var init_client = __esmMin((() => {
706
893
  //#region src/core/client.ts
707
894
  init_errors();
708
895
  /** SDK version - matches package.json */
709
- const VERSION = "0.1.0";
896
+ const VERSION = "0.2.0";
710
897
  const DEFAULT_TELESCOPE_API_ORIGIN = "https://api.telescope.co";
711
898
  const DEFAULT_CONNECT_TIMEOUT = 3e4;
712
899
  const DEFAULT_JSON_HEADERS = { "Content-Type": "application/json" };
@@ -744,6 +931,7 @@ var TelescopeClient = class {
744
931
  debugEnabled;
745
932
  _insights;
746
933
  _atlas;
934
+ _news;
747
935
  constructor(options = {}) {
748
936
  if (options.apiKey && options.clientToken) throw new Error("Cannot provide both apiKey and clientToken. Use one or the other.");
749
937
  const authToken = options.clientToken ?? options.apiKey ?? getEnvVar("TELESCOPE_API_KEY");
@@ -772,7 +960,7 @@ var TelescopeClient = class {
772
960
  get insights() {
773
961
  let client = this._insights;
774
962
  if (!client) {
775
- const { InsightsClient } = (init_client$1(), __toCommonJS(client_exports$1));
963
+ const { InsightsClient } = (init_client$2(), __toCommonJS(client_exports$2));
776
964
  client = new InsightsClient(this);
777
965
  this._insights = client;
778
966
  }
@@ -790,13 +978,31 @@ var TelescopeClient = class {
790
978
  get atlas() {
791
979
  let client = this._atlas;
792
980
  if (!client) {
793
- const { AtlasClient } = (init_client(), __toCommonJS(client_exports));
981
+ const { AtlasClient } = (init_client$1(), __toCommonJS(client_exports$1));
794
982
  client = new AtlasClient(this);
795
983
  this._atlas = client;
796
984
  }
797
985
  return client;
798
986
  }
799
987
  /**
988
+ * Namespaced access to News API.
989
+ *
990
+ * @example
991
+ * ```ts
992
+ * const latest = await client.news.latest.generate({ ... });
993
+ * const session = client.news.trendingTopics.stream({ topic: "global" });
994
+ * ```
995
+ */
996
+ get news() {
997
+ let client = this._news;
998
+ if (!client) {
999
+ const { NewsClient } = (init_client(), __toCommonJS(client_exports));
1000
+ client = new NewsClient(this);
1001
+ this._news = client;
1002
+ }
1003
+ return client;
1004
+ }
1005
+ /**
800
1006
  * Log debug messages when debug mode is enabled.
801
1007
  */
802
1008
  debug(message, data) {
@@ -817,7 +1023,7 @@ var TelescopeClient = class {
817
1023
  abortController.abort(/* @__PURE__ */ new Error(`Request timed out after ${this.connectTimeout}ms`));
818
1024
  }, this.connectTimeout);
819
1025
  try {
820
- const response = await fetch(`${this.baseUrl}/v2/client-tokens`, {
1026
+ const response = await fetch(buildApiUrl(this.baseUrl, "/v2/client-tokens"), {
821
1027
  method: "POST",
822
1028
  headers: {
823
1029
  ...DEFAULT_JSON_HEADERS,
@@ -856,7 +1062,7 @@ var TelescopeClient = class {
856
1062
  hasBody: options.body != null
857
1063
  });
858
1064
  try {
859
- const url = `${this.baseUrl}${path}`;
1065
+ const url = buildApiUrl(this.baseUrl, path);
860
1066
  const headers = new Headers(options.headers || {});
861
1067
  if (!headers.has("Content-Type") && options.body != null) headers.set("Content-Type", "application/json");
862
1068
  headers.set("Authorization", `Bearer ${this.apiKey}`);
@@ -1010,13 +1216,14 @@ var TelescopeClient = class {
1010
1216
  if (session.status.phase === "pending") abortController.abort(/* @__PURE__ */ new Error(`Stream connection timed out after ${connectionTimeout}ms`));
1011
1217
  }, connectionTimeout);
1012
1218
  try {
1013
- await fetchEventSource(`${this.baseUrl}${path}`, {
1219
+ await fetchEventSource(buildApiUrl(this.baseUrl, path), {
1014
1220
  method: "POST",
1015
1221
  body: JSON.stringify(body ?? {}),
1016
1222
  headers: {
1017
1223
  ...DEFAULT_JSON_HEADERS,
1018
1224
  Accept: "text/event-stream",
1019
- Authorization: `Bearer ${this.apiKey}`
1225
+ Authorization: `Bearer ${this.apiKey}`,
1226
+ ...options.headers
1020
1227
  },
1021
1228
  signal: abortController.signal,
1022
1229
  openWhenHidden: true,
@@ -1095,6 +1302,10 @@ function combineSignals(...signals) {
1095
1302
  }
1096
1303
  return controller.signal;
1097
1304
  }
1305
+ function buildApiUrl(baseUrl, path) {
1306
+ const normalizedBase = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
1307
+ return new URL(path, normalizedBase).toString();
1308
+ }
1098
1309
  /**
1099
1310
  * Safely get an environment variable in Node.js/Bun runtimes.
1100
1311
  * Returns undefined in browser environments.
@@ -1108,5 +1319,5 @@ function isBrowser() {
1108
1319
  }
1109
1320
 
1110
1321
  //#endregion
1111
- export { TokenError as _, InsightsClient as a, isArrayIndex as c, processSSEStream as d, ApiError as f, TelescopeClientError as g, StreamingError as h, init_client as i, parseEvent as l, SSEError as m, VERSION as n, init_client$1 as o, NetworkError as p, AtlasClient as r, StreamSession as s, TelescopeClient as t, pathToKey as u, init_errors as v };
1112
- //# sourceMappingURL=client-QPIC24Zs.mjs.map
1322
+ export { StreamingError as _, AtlasClient as a, init_errors as b, init_client$2 as c, parseEvent as d, pathToKey as f, SSEError as g, NetworkError as h, init_client as i, StreamSession as l, ApiError as m, VERSION as n, init_client$1 as o, processSSEStream as p, NewsClient as r, InsightsClient as s, TelescopeClient as t, isArrayIndex as u, TelescopeClientError as v, TokenError as y };
1323
+ //# sourceMappingURL=client-CLPQRhxT.mjs.map