gloomberb 0.11.0 → 0.11.1
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 +29 -7
- package/README.zh-CN.md +6 -6
- package/package.json +10 -3
- package/src/api-client/auth.ts +14 -10
- package/src/api-client/data.ts +47 -0
- package/src/api-client/index.test.ts +77 -0
- package/src/api-client/index.ts +78 -4
- package/src/api-client/paths.ts +73 -0
- package/src/api-client/request.ts +15 -2
- package/src/api-client/socket-health.test.ts +1 -0
- package/src/api-client/socket.ts +2 -1
- package/src/api-client/types.ts +128 -0
- package/src/app/runtime/update.ts +8 -6
- package/src/app.tsx +12 -5
- package/src/architecture/import-boundaries.test.ts +5 -1
- package/src/capabilities/factories.ts +4 -0
- package/src/cli/index.ts +10 -4
- package/src/cli/registry.ts +1 -1
- package/src/components/chart/composite/composite-chart.tsx +4 -3
- package/src/components/chart/composite/format.test.ts +34 -0
- package/src/components/chart/composite/format.ts +33 -10
- package/src/components/chart/core/axis-format.ts +13 -3
- package/src/components/chart/core/index.test.ts +7 -0
- package/src/components/chart/core/renderer.ts +3 -4
- package/src/components/command-bar/surface/index.tsx +4 -1
- package/src/components/company-logo.test.ts +19 -0
- package/src/components/company-logo.tsx +60 -0
- package/src/components/feed-data-table/stack-view.tsx +7 -1
- package/src/components/index.ts +1 -0
- package/src/components/layout/detached-pane-shell.tsx +11 -5
- package/src/components/layout/header.tsx +5 -5
- package/src/components/layout/shell/index.tsx +3 -1
- package/src/components/onboarding/account-step/form-panel.tsx +4 -2
- package/src/components/onboarding/account-step/index.tsx +1 -1
- package/src/components/onboarding/account-step/signed-in-panel.tsx +1 -1
- package/src/components/onboarding/onboarding-wizard.test.tsx +44 -1
- package/src/components/onboarding/onboarding-wizard.tsx +13 -5
- package/src/components/onboarding/wizard-account.ts +4 -23
- package/src/components/table-view-shared.test.ts +11 -0
- package/src/components/table-view-shared.tsx +26 -0
- package/src/components/ui/data-table/index.tsx +19 -1
- package/src/components/ui/fields.tsx +5 -1
- package/src/i18n/es.ts +10 -1
- package/src/i18n/ja.ts +10 -1
- package/src/i18n/ko.ts +10 -1
- package/src/i18n/zh-cn.ts +10 -1
- package/src/i18n/zh-tw.ts +10 -1
- package/src/market-data/coordinator/index.test.ts +2 -2
- package/src/market-data/coordinator/index.ts +1 -1
- package/src/market-data/market/format.test.ts +7 -0
- package/src/market-data/market/freshness.ts +5 -2
- package/src/market-data/quotes/freshness.test.ts +16 -0
- package/src/news/aggregator.test.ts +92 -3
- package/src/news/aggregator.ts +98 -18
- package/src/news/hooks.test.tsx +2 -0
- package/src/news/hooks.ts +27 -1
- package/src/news/news-model.ts +5 -2
- package/src/news/types.ts +7 -0
- package/src/plugins/broker-sync/broker-sync.test.ts +29 -0
- package/src/plugins/broker-sync/normalize.ts +35 -5
- package/src/plugins/builtin/account-management/pane.tsx +5 -5
- package/src/plugins/builtin/alerts/alert-engine.test.ts +38 -1
- package/src/plugins/builtin/alerts/alert-engine.ts +30 -1
- package/src/plugins/builtin/alerts/index.test.tsx +49 -6
- package/src/plugins/builtin/alerts/index.tsx +7 -6
- package/src/plugins/builtin/alerts/pane.tsx +49 -1
- package/src/plugins/builtin/alerts/quotes.ts +11 -3
- package/src/plugins/builtin/alerts/types.ts +1 -0
- package/src/plugins/builtin/analytics/index.tsx +8 -1
- package/src/plugins/builtin/analytics/pane-model.ts +6 -4
- package/src/plugins/builtin/buildout/model/index.ts +1 -1
- package/src/plugins/builtin/buildout/pane/index.tsx +17 -18
- package/src/plugins/builtin/chart-composer/pane.tsx +22 -1
- package/src/plugins/builtin/chat/controller/channels.ts +7 -1
- package/src/plugins/builtin/chat/controller/index.ts +6 -8
- package/src/plugins/builtin/chat/controller/persistence.ts +0 -3
- package/src/plugins/builtin/chat/controller/realtime.ts +3 -3
- package/src/plugins/builtin/chat/controller/send.ts +1 -3
- package/src/plugins/builtin/chat/controller/session-runtime.ts +4 -9
- package/src/plugins/builtin/chat/controller/state.ts +1 -3
- package/src/plugins/builtin/chat/controller/storage.ts +0 -2
- package/src/plugins/builtin/chat/controller/view.ts +2 -2
- package/src/plugins/builtin/chat/controller.test.ts +78 -0
- package/src/plugins/builtin/chat/profile-popover.ts +1 -1
- package/src/plugins/builtin/cloud/auth-actions.tsx +14 -7
- package/src/plugins/builtin/cloud/auth-commands.ts +21 -47
- package/src/plugins/builtin/cloud/auth-dialog.tsx +296 -0
- package/src/{components/onboarding/account-step/model.test.ts → plugins/builtin/cloud/auth-model.test.ts} +1 -1
- package/src/{components/onboarding/account-step/model.ts → plugins/builtin/cloud/auth-model.ts} +34 -3
- package/src/plugins/builtin/cloud/browser.tsx +9 -0
- package/src/plugins/builtin/cloud/buildout-module.tsx +23 -0
- package/src/plugins/builtin/cloud/device-signin.ts +2 -8
- package/src/plugins/builtin/cloud/index.tsx +2 -0
- package/src/plugins/builtin/cloud/plugin.tsx +3 -23
- package/src/plugins/builtin/cloud/upgrade-command.ts +13 -6
- package/src/plugins/builtin/cloud-tweets/registration.ts +6 -1
- package/src/plugins/builtin/congress-trades/detail.tsx +43 -1
- package/src/plugins/builtin/congress-trades/model.test.ts +85 -0
- package/src/plugins/builtin/congress-trades/model.ts +69 -1
- package/src/plugins/builtin/congress-trades/pane.tsx +51 -2
- package/src/plugins/builtin/dividend-yield/client.ts +18 -0
- package/src/plugins/builtin/dividend-yield/pane.tsx +7 -6
- package/src/plugins/builtin/earnings/index.tsx +5 -3
- package/src/plugins/builtin/earnings/model.test.ts +19 -1
- package/src/plugins/builtin/earnings/model.ts +17 -15
- package/src/plugins/builtin/econ/index.test.tsx +6 -1
- package/src/plugins/builtin/holders/thirteenf-match.ts +1 -2
- package/src/plugins/builtin/insider/index.tsx +27 -11
- package/src/plugins/builtin/news/index.tsx +10 -6
- package/src/plugins/builtin/news/wire/breaking/notifications.test.ts +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.test.tsx +2 -0
- package/src/plugins/builtin/news/wire/breaking/pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/index.tsx +1 -1
- package/src/plugins/builtin/news/wire/industry-pane.tsx +7 -2
- package/src/plugins/builtin/news/wire/news/footer.ts +34 -1
- package/src/plugins/builtin/news/wire/news/preset-pane.tsx +4 -1
- package/src/plugins/builtin/news/wire/news/table.tsx +8 -2
- package/src/plugins/builtin/news/wire/rss/source.test.ts +12 -0
- package/src/plugins/builtin/news/wire/rss/source.ts +1 -1
- package/src/plugins/builtin/notes/files.ts +80 -0
- package/src/plugins/builtin/notes/index.tsx +3 -0
- package/src/plugins/builtin/notes/sync.test.ts +49 -0
- package/src/plugins/builtin/notes/sync.ts +98 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.test.ts +20 -0
- package/src/plugins/builtin/portfolio-list/account-metrics.ts +11 -6
- package/src/plugins/builtin/portfolio-list/pane/index.test.tsx +1 -0
- package/src/plugins/builtin/portfolio-list/pane/streaming.ts +6 -1
- package/src/plugins/builtin/portfolio-list/summary/index.tsx +14 -5
- package/src/plugins/builtin/research/corporate-actions-pane.tsx +5 -12
- package/src/plugins/builtin/research/equity-diagnostic-pane.test.tsx +303 -0
- package/src/plugins/builtin/research/equity-diagnostic-pane.tsx +485 -0
- package/src/plugins/builtin/research/index.test.ts +14 -0
- package/src/plugins/builtin/research/index.tsx +25 -0
- package/src/plugins/builtin/sec/index.tsx +24 -9
- package/src/plugins/builtin/sectors/index.tsx +14 -0
- package/src/plugins/builtin/shared/cloud-upgrade.ts +18 -11
- package/src/plugins/builtin/shared/public-share.ts +23 -0
- package/src/plugins/builtin/substack/api/cache.ts +7 -3
- package/src/plugins/builtin/substack/api/loaders.ts +36 -12
- package/src/plugins/builtin/substack/api/types.ts +2 -0
- package/src/plugins/builtin/substack/pane-state.ts +1 -1
- package/src/plugins/builtin/substack/pane.tsx +55 -12
- package/src/plugins/builtin/thirteenf/api.test.ts +1 -1
- package/src/plugins/builtin/thirteenf/api.ts +40 -18
- package/src/plugins/builtin/thirteenf/data.ts +15 -7
- package/src/plugins/builtin/thirteenf/pane.tsx +45 -10
- package/src/plugins/builtin/ticker-detail/overview-tab.tsx +12 -4
- package/src/plugins/builtin/ticker-detail/quote-monitor/card.tsx +8 -2
- package/src/plugins/builtin/ticker-detail/settings.ts +12 -0
- package/src/plugins/catalog-browser.test.ts +68 -0
- package/src/plugins/catalog-browser.ts +134 -0
- package/src/plugins/ibkr/flex/index.test.ts +19 -0
- package/src/plugins/ibkr/flex/index.ts +1 -1
- package/src/plugins/prediction-markets/controller/catalog.ts +77 -2
- package/src/plugins/prediction-markets/controller/data.ts +7 -1
- package/src/plugins/prediction-markets/controller/index.ts +4 -1
- package/src/plugins/prediction-markets/pane.tsx +8 -0
- package/src/plugins/prediction-markets/services/kalshi/adapter.ts +49 -9
- package/src/plugins/prediction-markets/services/polymarket/adapter.ts +31 -0
- package/src/renderers/browser/app-services.ts +61 -0
- package/src/renderers/browser/cloud-transport.test.ts +32 -0
- package/src/renderers/browser/cloud-transport.ts +29 -0
- package/src/renderers/browser/config-host.ts +62 -0
- package/src/renderers/browser/error-boundary.tsx +23 -0
- package/src/renderers/browser/main.tsx +61 -0
- package/src/renderers/browser/persistence.ts +74 -0
- package/src/renderers/browser/storage.test.ts +66 -0
- package/src/renderers/browser/storage.ts +50 -0
- package/src/renderers/browser/ticker-repository.ts +59 -0
- package/src/renderers/browser/ui-host.tsx +40 -0
- package/src/renderers/cloudflare/worker.test.ts +133 -0
- package/src/renderers/cloudflare/worker.ts +115 -0
- package/src/renderers/electrobun/view/app-services.ts +14 -3
- package/src/renderers/electrobun/view/build-assets.ts +12 -10
- package/src/renderers/electrobun/view/data-table/index.tsx +10 -1
- package/src/renderers/electrobun/view/desktop/controls.tsx +2 -0
- package/src/renderers/electrobun/view/dom-ui-host.tsx +143 -0
- package/src/renderers/electrobun/view/host/box.test.tsx +33 -0
- package/src/renderers/electrobun/view/host/box.tsx +11 -6
- package/src/renderers/electrobun/view/host/chart-surface.tsx +7 -1
- package/src/renderers/electrobun/view/host/input.tsx +11 -7
- package/src/renderers/electrobun/view/main.tsx +2 -0
- package/src/renderers/electrobun/view/ui-host.tsx +3 -137
- package/src/renderers/opentui/start.tsx +2 -0
- package/src/renderers/share/main.tsx +54 -0
- package/src/renderers/share/styles.css +19 -0
- package/src/renderers/share/view.test.tsx +22 -0
- package/src/renderers/share/view.tsx +79 -0
- package/src/shares/api.test.ts +56 -0
- package/src/shares/api.ts +103 -0
- package/src/shares/chart-snapshot.test.ts +34 -0
- package/src/shares/chart-snapshot.ts +28 -0
- package/src/shares/payload.ts +104 -0
- package/src/sources/gloomberb-cloud/index.test.ts +61 -1
- package/src/sources/gloomberb-cloud/index.ts +86 -14
- package/src/sources/gloomberb-cloud/normalizers.test.ts +34 -0
- package/src/sources/gloomberb-cloud/normalizers.ts +5 -5
- package/src/sources/provider-router/history.test.ts +2 -2
- package/src/sources/provider-router/news.test.ts +34 -0
- package/src/sources/provider-router/news.ts +15 -1
- package/src/sources/sec-edgar.test.ts +59 -0
- package/src/sources/sec-edgar.ts +63 -23
- package/src/sources/yahoo-finance/mappers.ts +3 -0
- package/src/sources/yahoo-finance/snapshots.ts +10 -2
- package/src/sources/yahoo-finance/symbols.test.ts +10 -0
- package/src/sources/yahoo-finance/symbols.ts +13 -8
- package/src/sources/yahoo-finance.test.ts +1 -1
- package/src/sources/yahoo-finance.ts +6 -2
- package/src/sync/baseline.ts +32 -0
- package/src/sync/controller.test.ts +67 -0
- package/src/sync/controller.ts +32 -1
- package/src/sync/core-contributors.test.ts +44 -0
- package/src/sync/core-contributors.ts +59 -10
- package/src/sync/react.ts +9 -2
- package/src/sync/types.ts +12 -0
- package/src/tickers/search/index.test.ts +27 -0
- package/src/tickers/search/upsert.ts +10 -0
- package/src/types/capability-route-source.ts +2 -1
- package/src/ui/host.tsx +4 -0
- package/src/utils/price-history.ts +11 -10
- package/src/utils/sec.test.ts +6 -0
- package/src/utils/sec.ts +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="https://
|
|
3
|
+
<img src="https://gloom.sh/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
|
|
4
4
|
|
|
5
5
|
# Gloomberb
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
Desktop app for macOS and Windows. Terminal UI for macOS, Linux, and Windows.
|
|
10
10
|
|
|
11
|
-
<a href="https://
|
|
11
|
+
<a href="https://gloom.sh/download/desktop"><strong>Download desktop</strong></a>
|
|
12
12
|
·
|
|
13
13
|
<a href="#install"><strong>Install the TUI</strong></a>
|
|
14
14
|
·
|
|
@@ -17,7 +17,7 @@ Desktop app for macOS and Windows. Terminal UI for macOS, Linux, and Windows.
|
|
|
17
17
|
<br />
|
|
18
18
|
<br />
|
|
19
19
|
|
|
20
|
-
<img src="https://
|
|
20
|
+
<img src="https://gloom.sh/landing-terminal.png" alt="Gloomberb terminal showing portfolio, watchlists, market data, and chart panels." width="720" />
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -29,8 +29,24 @@ Gloomberb has two ways in:
|
|
|
29
29
|
|---------|----------|-------------|
|
|
30
30
|
| Desktop app | A polished app window, pop-out panes, OS shortcuts, and built-in updates | Published for macOS and Windows. It also installs a `gloomberb` terminal command for the TUI. |
|
|
31
31
|
| Terminal UI | Fast keyboard workflows inside your terminal, SSH/dev boxes, Linux machines, and script-friendly setups | Runs with `gloomberb` on macOS, Linux, and Windows. |
|
|
32
|
+
| Browser app | The shared DOM interface without an install | Open [term.gloom.sh](https://term.gloom.sh). |
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
The desktop app and TUI share the full command language and plugin system. The browser app uses the same official DOM renderer and layout with a reviewed browser plugin catalog.
|
|
35
|
+
|
|
36
|
+
## Browser App
|
|
37
|
+
|
|
38
|
+
[term.gloom.sh](https://term.gloom.sh) works anonymously with configuration, tickers, layouts, session state, and plugin state stored in the browser. Anonymous sessions receive rate-limited, 15-minute-delayed Gloom Cloud market data and read-only chat. Login remains optional and enables sync and chat posting; Pro accounts receive realtime market data. Cloud REST and WebSocket traffic uses the same-origin `/api` path, which the Worker forwards only to `https://api.gloom.sh`; it is not an arbitrary network proxy.
|
|
39
|
+
|
|
40
|
+
The browser build intentionally omits brokers and native integrations, filesystem notes, local AI, external plugins, updater/debug tools, application menus, native window controls, pop-out native windows, and native context menus. Modules that still depend on desktop-only or CORS-blocked feeds are also absent for now: RSS/Substack, prediction markets and polls, market halts/heatmap/movers, dividend/ownership/SEC panes, earnings/IPO, and TV. Public shares open under `/s/:id` in a separate slim bundle. Share creation and owner deletion use the signed-in Gloom Cloud session through the same fixed API path; public reads require no account.
|
|
41
|
+
|
|
42
|
+
Local browser development:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bun run web:build
|
|
46
|
+
bunx wrangler dev
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Validate the public artifacts with `bun run web:audit` and `bun run cloudflare:dry-run`. `wrangler.jsonc` is intentionally generic and contains no account, route, domain, namespace, or secret. Production routing and the private Gloom Cloud API deployment are configured separately.
|
|
34
50
|
|
|
35
51
|
## Install
|
|
36
52
|
|
|
@@ -41,21 +57,21 @@ Install the desktop app and the `gloomberb` terminal command:
|
|
|
41
57
|
```bash
|
|
42
58
|
brew install --cask vincelwt/tap/gloomberb
|
|
43
59
|
# or
|
|
44
|
-
curl -fsSL
|
|
60
|
+
curl -fsSL gloom.sh/install | bash
|
|
45
61
|
```
|
|
46
62
|
|
|
47
63
|
Both install `Gloomberb.app` and a `gloomberb` command that runs the TUI through the app bundle, so the bundled runtime is stored once.
|
|
48
64
|
|
|
49
65
|
Prefer a direct download?
|
|
50
66
|
|
|
51
|
-
- [Download Gloomberb for Mac](https://
|
|
67
|
+
- [Download Gloomberb for Mac](https://gloom.sh/download/desktop)
|
|
52
68
|
|
|
53
69
|
### Linux
|
|
54
70
|
|
|
55
71
|
Install the standalone TUI binary:
|
|
56
72
|
|
|
57
73
|
```bash
|
|
58
|
-
curl -fsSL
|
|
74
|
+
curl -fsSL gloom.sh/install | bash
|
|
59
75
|
```
|
|
60
76
|
|
|
61
77
|
This installs `gloomberb` to `~/.local/bin` by default. A Linux desktop package is not published yet.
|
|
@@ -224,6 +240,7 @@ Use `HELP` inside Gloomberb for the live shortcut list. The common command-bar p
|
|
|
224
240
|
| `CMP <tickers>` | Normalized price comparison |
|
|
225
241
|
| `CORR <tickers>` | Ticker return correlations |
|
|
226
242
|
| `ANR <ticker>` | Analyst targets and ratings |
|
|
243
|
+
| `DIAG <ticker>` | Equity Diagnostic with cited flags and anomalies |
|
|
227
244
|
| `SEC <ticker>` | SEC filings and company disclosures |
|
|
228
245
|
| `OMON <ticker>` | Options monitor |
|
|
229
246
|
| `OVME` | Black-Scholes option calculator with Greeks and implied volatility |
|
|
@@ -307,6 +324,11 @@ The toolbar controls preset or exact date ranges, intervals from one minute thro
|
|
|
307
324
|
| `SB` | Toggle the status bar |
|
|
308
325
|
| `VF` | Toggle quote value flashing |
|
|
309
326
|
| `TH <theme>` | Change color theme |
|
|
327
|
+
| `FONT+` / `FONT-` | Increase or decrease desktop font size |
|
|
328
|
+
| `CONN` | Connection health |
|
|
329
|
+
| `POLL` | Prediction-market polls |
|
|
330
|
+
| `ART` | Loaded article lookup |
|
|
331
|
+
| `UPGRADE` | Account upgrade |
|
|
310
332
|
| `CR` | Cycle chart renderer |
|
|
311
333
|
| `LANG <locale>` | Change interface language (`auto`, `en`, `es`, `zh-CN`, `zh-TW`, `ja`, or `ko`) |
|
|
312
334
|
| `PL <plugin>` | Manage plugins |
|
package/README.zh-CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="https://
|
|
3
|
+
<img src="https://gloom.sh/gloomberb-logo-grayscale.svg" alt="Gloomberb logo" width="76" />
|
|
4
4
|
|
|
5
5
|
# Gloomberb
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
桌面应用支持 macOS 和 Windows。终端界面(TUI)支持 macOS、Linux 和 Windows。
|
|
10
10
|
|
|
11
|
-
<a href="https://
|
|
11
|
+
<a href="https://gloom.sh/download/desktop"><strong>下载桌面版</strong></a>
|
|
12
12
|
·
|
|
13
13
|
<a href="#安装">安装 TUI</a>
|
|
14
14
|
·
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<br />
|
|
18
18
|
<br />
|
|
19
19
|
|
|
20
|
-
<img src="https://
|
|
20
|
+
<img src="https://gloom.sh/landing-terminal.png" alt="Gloomberb 终端界面,显示投资组合、自选列表、市场数据和图表面板。" width="720" />
|
|
21
21
|
|
|
22
22
|
</div>
|
|
23
23
|
|
|
@@ -43,21 +43,21 @@ Gloomberb 有两种使用方式:
|
|
|
43
43
|
```bash
|
|
44
44
|
brew install --cask vincelwt/tap/gloomberb
|
|
45
45
|
# 或
|
|
46
|
-
curl -fsSL
|
|
46
|
+
curl -fsSL gloom.sh/install | bash
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
两种方式都会安装 `Gloomberb.app`,以及一个通过应用内置运行时执行 TUI 的 `gloomberb` 命令,运行时只会存储一份。
|
|
50
50
|
|
|
51
51
|
想直接下载?
|
|
52
52
|
|
|
53
|
-
- [下载 Gloomberb(Mac 版)](https://
|
|
53
|
+
- [下载 Gloomberb(Mac 版)](https://gloom.sh/download/desktop)
|
|
54
54
|
|
|
55
55
|
### Linux
|
|
56
56
|
|
|
57
57
|
安装独立的 TUI 可执行文件:
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
curl -fsSL
|
|
60
|
+
curl -fsSL gloom.sh/install | bash
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
默认会将 `gloomberb` 安装到 `~/.local/bin`。Linux 桌面安装包暂未发布。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gloomberb",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"packageManager": "bun@1.3.11",
|
|
5
5
|
"description": "Market research and portfolio tracker for the terminal",
|
|
6
6
|
"module": "src/index.tsx",
|
|
@@ -19,15 +19,21 @@
|
|
|
19
19
|
"build": "bun run scripts/build.ts",
|
|
20
20
|
"build:all": "bun run scripts/build.ts --all",
|
|
21
21
|
"desktop:view:build": "bun run scripts/build-electrobun-view.ts",
|
|
22
|
+
"web:build": "bun run scripts/build-web.ts",
|
|
23
|
+
"web:audit": "bun run web:build && bun run scripts/audit-web-bundle.ts",
|
|
24
|
+
"cloudflare:typecheck": "tsc --project tsconfig.cloudflare.json",
|
|
25
|
+
"cloudflare:dry-run": "bun run web:build && wrangler deploy --dry-run",
|
|
22
26
|
"desktop:dev": "bun run scripts/electrobun-dev.ts",
|
|
23
27
|
"desktop:build": "electrobun build",
|
|
24
28
|
"desktop:release": "electrobun build --env=stable",
|
|
25
29
|
"desktop:release:windows": "electrobun build --env=stable --targets=win-x64",
|
|
26
30
|
"i18n:audit": "bun run scripts/i18n-audit.ts",
|
|
27
|
-
"typecheck": "bun run typecheck:opentui && bun run typecheck:electrobun-bun && bun run typecheck:electrobun-view && bun run typecheck:scripts",
|
|
31
|
+
"typecheck": "bun run typecheck:opentui && bun run typecheck:electrobun-bun && bun run typecheck:electrobun-view && bun run typecheck:browser && bun run typecheck:cloudflare && bun run typecheck:scripts",
|
|
28
32
|
"typecheck:opentui": "tsc --project tsconfig.opentui.json",
|
|
29
33
|
"typecheck:electrobun-bun": "tsc --project tsconfig.electrobun-bun.json",
|
|
30
34
|
"typecheck:electrobun-view": "tsc --project tsconfig.electrobun-view.json",
|
|
35
|
+
"typecheck:browser": "tsc --project tsconfig.browser.json",
|
|
36
|
+
"typecheck:cloudflare": "tsc --project tsconfig.cloudflare.json",
|
|
31
37
|
"typecheck:scripts": "tsc --project tsconfig.scripts.json",
|
|
32
38
|
"test": "bun test",
|
|
33
39
|
"test:global-upgrade": "bun run scripts/smoke-global-upgrade.ts",
|
|
@@ -52,7 +58,8 @@
|
|
|
52
58
|
"electrobun": "^1.18.1",
|
|
53
59
|
"happy-dom": "^20.11.1",
|
|
54
60
|
"png-to-ico": "^2.1.8",
|
|
55
|
-
"rcedit": "^4.0.1"
|
|
61
|
+
"rcedit": "^4.0.1",
|
|
62
|
+
"wrangler": "^4.0.0"
|
|
56
63
|
},
|
|
57
64
|
"peerDependencies": {
|
|
58
65
|
"typescript": "^5.9.2"
|
package/src/api-client/auth.ts
CHANGED
|
@@ -18,6 +18,7 @@ type CloudApiRequest = <T>(path: string, options?: RequestInit) => Promise<T>;
|
|
|
18
18
|
interface CloudAuthApiOptions {
|
|
19
19
|
getCurrentUser(): AuthUser | null;
|
|
20
20
|
getSessionToken(): string | null;
|
|
21
|
+
hasSessionCredential(): boolean;
|
|
21
22
|
request: CloudApiRequest;
|
|
22
23
|
requireCapturedSession(message: string): void;
|
|
23
24
|
setCurrentUser(user: AuthUser | null): void;
|
|
@@ -29,7 +30,7 @@ export class CloudAuthApi {
|
|
|
29
30
|
constructor(private readonly options: CloudAuthApiOptions) {}
|
|
30
31
|
|
|
31
32
|
restoreCachedUser(user: PersistedAuthUser | null): void {
|
|
32
|
-
if (!this.options.
|
|
33
|
+
if (!this.options.hasSessionCredential() || !user?.id) {
|
|
33
34
|
this.options.setCurrentUser(null);
|
|
34
35
|
return;
|
|
35
36
|
}
|
|
@@ -56,15 +57,6 @@ export class CloudAuthApi {
|
|
|
56
57
|
});
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
async ensureVerifiedSession(): Promise<AuthUser | null> {
|
|
60
|
-
if (!this.options.getSessionToken()) return null;
|
|
61
|
-
if (!this.options.getCurrentUser()) {
|
|
62
|
-
await this.getSession();
|
|
63
|
-
}
|
|
64
|
-
const user = this.options.getCurrentUser();
|
|
65
|
-
return user?.emailVerified ? user : null;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
60
|
async signUp(email: string, username: string, name: string, password: string): Promise<AuthUser> {
|
|
69
61
|
const result = await this.options.request<{ user: AuthUser }>("/auth/sign-up/email", {
|
|
70
62
|
method: "POST",
|
|
@@ -134,6 +126,18 @@ export class CloudAuthApi {
|
|
|
134
126
|
}
|
|
135
127
|
}
|
|
136
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Emails a password reset link. The reset itself completes on the gloom.sh
|
|
131
|
+
* site, so the app only ever sends the email. The server answers the same
|
|
132
|
+
* way whether or not the address exists.
|
|
133
|
+
*/
|
|
134
|
+
async requestPasswordReset(email: string): Promise<void> {
|
|
135
|
+
await this.options.request("/auth/request-password-reset", {
|
|
136
|
+
method: "POST",
|
|
137
|
+
body: JSON.stringify({ email }),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
137
141
|
async sendVerification(): Promise<CloudVerificationResponse> {
|
|
138
142
|
return this.options.request<CloudVerificationResponse>("/cloud/auth/send-verification", {
|
|
139
143
|
method: "POST",
|
package/src/api-client/data.ts
CHANGED
|
@@ -4,6 +4,10 @@ import { normalizeTweetSearchResponse } from "./normalizers";
|
|
|
4
4
|
import {
|
|
5
5
|
cloudCongressHousePath,
|
|
6
6
|
cloudExchangeRatePath,
|
|
7
|
+
cloudSec13FPath,
|
|
8
|
+
cloudSecFilingContentPath,
|
|
9
|
+
cloudSecFilingDocumentsPath,
|
|
10
|
+
cloudSecFilingsPath,
|
|
7
11
|
cloudFredSeriesPath,
|
|
8
12
|
cloudHistoryPath,
|
|
9
13
|
cloudMarketSearchPath,
|
|
@@ -17,6 +21,8 @@ import {
|
|
|
17
21
|
type CloudFredSeriesParams,
|
|
18
22
|
type CloudHistoryParams,
|
|
19
23
|
type CloudNewsParams,
|
|
24
|
+
type CloudSecFilingParams,
|
|
25
|
+
type CloudSecFilingsParams,
|
|
20
26
|
type CloudTickerTweetsParams,
|
|
21
27
|
type CloudTweetSearchParams,
|
|
22
28
|
} from "./paths";
|
|
@@ -27,6 +33,8 @@ import type {
|
|
|
27
33
|
CloudCongressHousePayload,
|
|
28
34
|
CloudCorporateActionsPayload,
|
|
29
35
|
CloudEconEventPayload,
|
|
36
|
+
CloudEquityDiagnosticMode,
|
|
37
|
+
CloudEquityDiagnosticResult,
|
|
30
38
|
CloudFredSeriesPayload,
|
|
31
39
|
CloudFundamentals,
|
|
32
40
|
CloudHoldersPayload,
|
|
@@ -37,6 +45,9 @@ import type {
|
|
|
37
45
|
CloudMarketScreenerPayload,
|
|
38
46
|
CloudNewsListResponse,
|
|
39
47
|
CloudNewsPayload,
|
|
48
|
+
CloudSecContentResponse,
|
|
49
|
+
CloudSecDocumentsResponse,
|
|
50
|
+
CloudSecFilingsResponse,
|
|
40
51
|
CloudOptionsChainPayload,
|
|
41
52
|
CloudPricePointPayload,
|
|
42
53
|
CloudQuotePayload,
|
|
@@ -163,6 +174,26 @@ export class CloudDataApi {
|
|
|
163
174
|
return this.request<CloudMarketResponse<{ rate: number }>>(cloudExchangeRatePath(fromCurrency));
|
|
164
175
|
}
|
|
165
176
|
|
|
177
|
+
/**
|
|
178
|
+
* On-demand single-company evidence review. This is a cloud product endpoint,
|
|
179
|
+
* not a market-data capability, so it is called directly instead of routed
|
|
180
|
+
* through the asset-data provider.
|
|
181
|
+
*/
|
|
182
|
+
async getCloudEquityDiagnostic(
|
|
183
|
+
symbol: string,
|
|
184
|
+
exchange?: string,
|
|
185
|
+
mode: CloudEquityDiagnosticMode = "cache-first",
|
|
186
|
+
): Promise<CloudEquityDiagnosticResult> {
|
|
187
|
+
return this.request<CloudEquityDiagnosticResult>("/research/equity-diagnostic", {
|
|
188
|
+
method: "POST",
|
|
189
|
+
body: JSON.stringify({
|
|
190
|
+
symbol: symbol.trim().toUpperCase(),
|
|
191
|
+
...(exchange ? { exchange } : {}),
|
|
192
|
+
mode,
|
|
193
|
+
}),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
166
197
|
async getCloudEconomicCalendar(): Promise<CloudEconEventPayload[]> {
|
|
167
198
|
return this.request<CloudEconEventPayload[]>("/cloud/econ/calendar");
|
|
168
199
|
}
|
|
@@ -182,6 +213,22 @@ export class CloudDataApi {
|
|
|
182
213
|
return this.request<CloudCongressHousePayload>(cloudCongressHousePath(params));
|
|
183
214
|
}
|
|
184
215
|
|
|
216
|
+
async getCloudSecFilings(params: CloudSecFilingsParams): Promise<CloudSecFilingsResponse> {
|
|
217
|
+
return this.request<CloudSecFilingsResponse>(cloudSecFilingsPath(params));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async getCloudSecFilingDocuments(params: CloudSecFilingParams): Promise<CloudSecDocumentsResponse> {
|
|
221
|
+
return this.request<CloudSecDocumentsResponse>(cloudSecFilingDocumentsPath(params));
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async getCloudSecFilingContent(params: CloudSecFilingParams): Promise<CloudSecContentResponse> {
|
|
225
|
+
return this.request<CloudSecContentResponse>(cloudSecFilingContentPath(params));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async getCloudSec13F(path: string, params: Record<string, string | number | undefined> = {}): Promise<unknown> {
|
|
229
|
+
return this.request<unknown>(cloudSec13FPath(path, params));
|
|
230
|
+
}
|
|
231
|
+
|
|
185
232
|
async getCloudNews(params: CloudNewsParams = {}): Promise<CloudNewsListResponse> {
|
|
186
233
|
return this.request<CloudNewsListResponse>(cloudNewsPath(params));
|
|
187
234
|
}
|
|
@@ -104,10 +104,53 @@ afterEach(() => {
|
|
|
104
104
|
setCloudApiFetchTransport(null);
|
|
105
105
|
apiClient.setSessionToken(null);
|
|
106
106
|
apiClient.setWebSocketToken(null);
|
|
107
|
+
apiClient.setCookieSessionMode(false);
|
|
107
108
|
jest.useRealTimers();
|
|
108
109
|
});
|
|
109
110
|
|
|
110
111
|
describe("apiClient auth cookies", () => {
|
|
112
|
+
test("accepts a browser-managed api.gloom.sh cookie without exposing its value", async () => {
|
|
113
|
+
apiClient.setCookieSessionMode(true);
|
|
114
|
+
setCloudApiFetchTransport(mockFetch(() => createResponse({ user: verifiedUser })));
|
|
115
|
+
|
|
116
|
+
await expect(apiClient.signIn("test@example.com", "password")).resolves.toEqual(verifiedUser);
|
|
117
|
+
expect(apiClient.getSessionToken()).toBeNull();
|
|
118
|
+
expect(apiClient.isVerified()).toBe(true);
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
test("reports signed-in from the restored user when the cookie hides the raw token", async () => {
|
|
122
|
+
apiClient.setCookieSessionMode(true);
|
|
123
|
+
setCloudApiFetchTransport(mockFetch(() => createResponse({ user: verifiedUser })));
|
|
124
|
+
|
|
125
|
+
expect(apiClient.isSignedIn()).toBe(false);
|
|
126
|
+
await apiClient.signIn("test@example.com", "password");
|
|
127
|
+
expect(apiClient.getSessionToken()).toBeNull();
|
|
128
|
+
expect(apiClient.isSignedIn()).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("coalesces anonymous browser session checks and remembers the result", async () => {
|
|
132
|
+
apiClient.setCookieSessionMode(true);
|
|
133
|
+
let requests = 0;
|
|
134
|
+
let finishRequest!: () => void;
|
|
135
|
+
setCloudApiFetchTransport(async () => {
|
|
136
|
+
requests += 1;
|
|
137
|
+
await new Promise<void>((resolve) => { finishRequest = resolve; });
|
|
138
|
+
return createResponse({ user: null });
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const checks = [
|
|
142
|
+
apiClient.ensureVerifiedSession(),
|
|
143
|
+
apiClient.ensureVerifiedSession(),
|
|
144
|
+
apiClient.ensureVerifiedSession(),
|
|
145
|
+
];
|
|
146
|
+
expect(requests).toBe(1);
|
|
147
|
+
finishRequest();
|
|
148
|
+
|
|
149
|
+
await expect(Promise.all(checks)).resolves.toEqual([null, null, null]);
|
|
150
|
+
await expect(apiClient.ensureVerifiedSession()).resolves.toBeNull();
|
|
151
|
+
expect(requests).toBe(1);
|
|
152
|
+
});
|
|
153
|
+
|
|
111
154
|
test("captures secure session cookies after login and reuses them on session refresh", async () => {
|
|
112
155
|
const seenCookies: Array<string | null> = [];
|
|
113
156
|
|
|
@@ -1039,3 +1082,37 @@ describe("apiClient cloud news", () => {
|
|
|
1039
1082
|
expect(story.id).toBe("story-1");
|
|
1040
1083
|
});
|
|
1041
1084
|
});
|
|
1085
|
+
|
|
1086
|
+
describe("apiClient equity diagnostic", () => {
|
|
1087
|
+
test("posts the symbol, exchange, and cache mode to the research route", async () => {
|
|
1088
|
+
let seenUrl = "";
|
|
1089
|
+
let seenInit: RequestInit | undefined;
|
|
1090
|
+
globalThis.fetch = mockFetch(async (input: Request | string | URL, init?: RequestInit) => {
|
|
1091
|
+
seenUrl = String(input);
|
|
1092
|
+
seenInit = init;
|
|
1093
|
+
return createResponse({ symbol: "AAPL", status: "complete" });
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
await apiClient.getCloudEquityDiagnostic(" aapl ", "NASDAQ", "refresh");
|
|
1097
|
+
|
|
1098
|
+
expect(new URL(seenUrl).pathname).toBe("/research/equity-diagnostic");
|
|
1099
|
+
expect(seenInit?.method).toBe("POST");
|
|
1100
|
+
expect(JSON.parse(String(seenInit?.body))).toEqual({
|
|
1101
|
+
symbol: "AAPL",
|
|
1102
|
+
exchange: "NASDAQ",
|
|
1103
|
+
mode: "refresh",
|
|
1104
|
+
});
|
|
1105
|
+
});
|
|
1106
|
+
|
|
1107
|
+
test("omits an unknown exchange and defaults to the cached answer", async () => {
|
|
1108
|
+
let seenInit: RequestInit | undefined;
|
|
1109
|
+
globalThis.fetch = mockFetch(async (_input: Request | string | URL, init?: RequestInit) => {
|
|
1110
|
+
seenInit = init;
|
|
1111
|
+
return createResponse({ symbol: "AAPL", status: "complete" });
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
await apiClient.getCloudEquityDiagnostic("AAPL");
|
|
1115
|
+
|
|
1116
|
+
expect(JSON.parse(String(seenInit?.body))).toEqual({ symbol: "AAPL", mode: "cache-first" });
|
|
1117
|
+
});
|
|
1118
|
+
});
|
package/src/api-client/index.ts
CHANGED
|
@@ -8,6 +8,8 @@ import { CloudApiSocket } from "./socket";
|
|
|
8
8
|
import type {
|
|
9
9
|
CloudCongressHouseParams,
|
|
10
10
|
CloudFredSeriesParams,
|
|
11
|
+
CloudSecFilingParams,
|
|
12
|
+
CloudSecFilingsParams,
|
|
11
13
|
CloudHistoryParams,
|
|
12
14
|
CloudNewsParams,
|
|
13
15
|
CloudTickerTweetsParams,
|
|
@@ -40,10 +42,15 @@ import type {
|
|
|
40
42
|
CloudCorporateActionsPayload,
|
|
41
43
|
CloudPricePointPayload,
|
|
42
44
|
CloudEconEventPayload,
|
|
45
|
+
CloudEquityDiagnosticMode,
|
|
46
|
+
CloudEquityDiagnosticResult,
|
|
43
47
|
CloudFredSeriesPayload,
|
|
44
48
|
CloudYieldPointPayload,
|
|
45
49
|
CloudCongressHousePayload,
|
|
46
50
|
CloudNewsPayload,
|
|
51
|
+
CloudSecContentResponse,
|
|
52
|
+
CloudSecDocumentsResponse,
|
|
53
|
+
CloudSecFilingsResponse,
|
|
47
54
|
CloudNewsListResponse,
|
|
48
55
|
CloudTweetSearchResponse,
|
|
49
56
|
CloudMarketResponse,
|
|
@@ -73,6 +80,8 @@ const ASSIST_REQUEST_TIMEOUT_MS = 6_000;
|
|
|
73
80
|
|
|
74
81
|
class GloomApiClient {
|
|
75
82
|
private currentUser: AuthUser | null = null;
|
|
83
|
+
private sessionChecked = false;
|
|
84
|
+
private sessionRequest: Promise<AuthUser | null> | null = null;
|
|
76
85
|
private readonly currentUserListeners = new Set<() => void>();
|
|
77
86
|
private readonly transport = new CloudApiRequestTransport();
|
|
78
87
|
private readonly auth: CloudAuthApi;
|
|
@@ -84,6 +93,7 @@ class GloomApiClient {
|
|
|
84
93
|
this.auth = new CloudAuthApi({
|
|
85
94
|
getCurrentUser: () => this.currentUser,
|
|
86
95
|
getSessionToken: () => this.transport.getSessionToken(),
|
|
96
|
+
hasSessionCredential: () => this.transport.hasSessionCredential(),
|
|
87
97
|
request: (path, options) => this.request(path, options),
|
|
88
98
|
requireCapturedSession: (message) => this.requireCapturedSession(message),
|
|
89
99
|
setCurrentUser: (user) => this.setCurrentUser(user),
|
|
@@ -93,6 +103,7 @@ class GloomApiClient {
|
|
|
93
103
|
this.socket = new CloudApiSocket({
|
|
94
104
|
getBaseUrl: () => this.transport.baseUrl,
|
|
95
105
|
getSocketAuthToken: () => this.getSocketAuthToken(),
|
|
106
|
+
hasSessionCredential: () => this.transport.hasSessionCredential(),
|
|
96
107
|
hasVerifiedUser: () => this.currentUser?.emailVerified === true,
|
|
97
108
|
isUsingWebSocketToken: () => !!this.transport.getWebSocketToken(),
|
|
98
109
|
clearWebSocketTokenForFallback: () => this.transport.clearWebSocketTokenForFallback(),
|
|
@@ -123,8 +134,14 @@ class GloomApiClient {
|
|
|
123
134
|
return this.transport.getWebSocketToken();
|
|
124
135
|
}
|
|
125
136
|
|
|
137
|
+
setCookieSessionMode(enabled: boolean): void {
|
|
138
|
+
this.sessionChecked = false;
|
|
139
|
+
this.transport.setCookieSessionMode(enabled);
|
|
140
|
+
}
|
|
141
|
+
|
|
126
142
|
setSessionToken(token: string | null): void {
|
|
127
143
|
const changed = this.transport.getSessionToken() !== token;
|
|
144
|
+
this.sessionChecked = false;
|
|
128
145
|
this.transport.setSessionToken(token);
|
|
129
146
|
if (!token) {
|
|
130
147
|
this.currentUser = null;
|
|
@@ -143,6 +160,15 @@ class GloomApiClient {
|
|
|
143
160
|
return this.currentUser;
|
|
144
161
|
}
|
|
145
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Whether a signed-in session exists on this surface. Browser builds keep the
|
|
165
|
+
* session in an HttpOnly cookie, so the raw token is deliberately null there
|
|
166
|
+
* and the restored user is the only signal.
|
|
167
|
+
*/
|
|
168
|
+
isSignedIn(): boolean {
|
|
169
|
+
return !!this.transport.getSessionToken() || !!this.currentUser;
|
|
170
|
+
}
|
|
171
|
+
|
|
146
172
|
/** Notifies when the signed-in user changes, including plan and trial entitlement. */
|
|
147
173
|
subscribeCurrentUser(listener: () => void): () => void {
|
|
148
174
|
this.currentUserListeners.add(listener);
|
|
@@ -156,7 +182,7 @@ class GloomApiClient {
|
|
|
156
182
|
}
|
|
157
183
|
|
|
158
184
|
isVerified(): boolean {
|
|
159
|
-
return
|
|
185
|
+
return this.transport.hasSessionCredential() && !!this.currentUser?.emailVerified;
|
|
160
186
|
}
|
|
161
187
|
|
|
162
188
|
private setCurrentUser(user: AuthUser | null): void {
|
|
@@ -187,7 +213,7 @@ class GloomApiClient {
|
|
|
187
213
|
}
|
|
188
214
|
|
|
189
215
|
private requireCapturedSession(message: string): void {
|
|
190
|
-
if (this.transport.
|
|
216
|
+
if (this.transport.hasSessionCredential()) return;
|
|
191
217
|
this.transport.setWebSocketToken(null);
|
|
192
218
|
this.setCurrentUser(null);
|
|
193
219
|
throw new Error(message);
|
|
@@ -202,7 +228,9 @@ class GloomApiClient {
|
|
|
202
228
|
}
|
|
203
229
|
|
|
204
230
|
async ensureVerifiedSession(): Promise<AuthUser | null> {
|
|
205
|
-
|
|
231
|
+
if (!this.transport.hasSessionCredential()) return null;
|
|
232
|
+
if (!this.currentUser && !this.sessionChecked) await this.getSession();
|
|
233
|
+
return this.currentUser?.emailVerified ? this.currentUser : null;
|
|
206
234
|
}
|
|
207
235
|
|
|
208
236
|
async signUp(email: string, username: string, name: string, password: string): Promise<AuthUser> {
|
|
@@ -226,17 +254,39 @@ class GloomApiClient {
|
|
|
226
254
|
}
|
|
227
255
|
|
|
228
256
|
async getSession(): Promise<AuthUser | null> {
|
|
229
|
-
return this.
|
|
257
|
+
if (this.sessionRequest) return this.sessionRequest;
|
|
258
|
+
this.sessionRequest = this.auth.getSession();
|
|
259
|
+
try {
|
|
260
|
+
const user = await this.sessionRequest;
|
|
261
|
+
this.sessionChecked = true;
|
|
262
|
+
return user;
|
|
263
|
+
} finally {
|
|
264
|
+
this.sessionRequest = null;
|
|
265
|
+
}
|
|
230
266
|
}
|
|
231
267
|
|
|
232
268
|
async sendVerification(): Promise<CloudVerificationResponse> {
|
|
233
269
|
return this.auth.sendVerification();
|
|
234
270
|
}
|
|
235
271
|
|
|
272
|
+
async requestPasswordReset(email: string): Promise<void> {
|
|
273
|
+
return this.auth.requestPasswordReset(email);
|
|
274
|
+
}
|
|
275
|
+
|
|
236
276
|
async createBrowserHandoff(): Promise<CloudBrowserHandoffResponse> {
|
|
237
277
|
return this.auth.createBrowserHandoff();
|
|
238
278
|
}
|
|
239
279
|
|
|
280
|
+
/** Creates a Stripe checkout session for Cloud Pro; the URL opens in a browser. */
|
|
281
|
+
async createCloudCheckout(): Promise<{ url: string }> {
|
|
282
|
+
return this.request<{ url: string }>("/stripe/checkout", { method: "POST", body: JSON.stringify({}) });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Stripe billing portal for an account that already has a subscription. */
|
|
286
|
+
async createBillingPortal(): Promise<{ url: string }> {
|
|
287
|
+
return this.request<{ url: string }>("/stripe/portal", { method: "POST", body: JSON.stringify({}) });
|
|
288
|
+
}
|
|
289
|
+
|
|
240
290
|
async getAccountProfile(): Promise<AccountProfile> {
|
|
241
291
|
return this.auth.getAccountProfile();
|
|
242
292
|
}
|
|
@@ -513,6 +563,14 @@ class GloomApiClient {
|
|
|
513
563
|
return this.data.getCloudEconomicCalendar();
|
|
514
564
|
}
|
|
515
565
|
|
|
566
|
+
async getCloudEquityDiagnostic(
|
|
567
|
+
symbol: string,
|
|
568
|
+
exchange?: string,
|
|
569
|
+
mode: CloudEquityDiagnosticMode = "cache-first",
|
|
570
|
+
): Promise<CloudEquityDiagnosticResult> {
|
|
571
|
+
return this.data.getCloudEquityDiagnostic(symbol, exchange, mode);
|
|
572
|
+
}
|
|
573
|
+
|
|
516
574
|
async getCloudFredSeries(
|
|
517
575
|
seriesId: string,
|
|
518
576
|
params: CloudFredSeriesParams = {},
|
|
@@ -528,6 +586,22 @@ class GloomApiClient {
|
|
|
528
586
|
return this.data.getCloudCongressHouse(params);
|
|
529
587
|
}
|
|
530
588
|
|
|
589
|
+
async getCloudSecFilings(params: CloudSecFilingsParams): Promise<CloudSecFilingsResponse> {
|
|
590
|
+
return this.data.getCloudSecFilings(params);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
async getCloudSecFilingDocuments(params: CloudSecFilingParams): Promise<CloudSecDocumentsResponse> {
|
|
594
|
+
return this.data.getCloudSecFilingDocuments(params);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async getCloudSecFilingContent(params: CloudSecFilingParams): Promise<CloudSecContentResponse> {
|
|
598
|
+
return this.data.getCloudSecFilingContent(params);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
async getCloudSec13F(path: string, params: Record<string, string | number | undefined> = {}): Promise<unknown> {
|
|
602
|
+
return this.data.getCloudSec13F(path, params);
|
|
603
|
+
}
|
|
604
|
+
|
|
531
605
|
async getCloudNews(params: CloudNewsParams = {}): Promise<CloudNewsListResponse> {
|
|
532
606
|
return this.data.getCloudNews(params);
|
|
533
607
|
}
|