cartethyia 2.6.6 → 2.7.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/.env.example +106 -113
- package/dist/dashboard/assets/{BannedPage-1v5rzKMl.js → BannedPage-P76QLGJA.js} +1 -1
- package/dist/dashboard/assets/BannedPage-P76QLGJA.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolDetailPage-chMg74ct.js → CliToolDetailPage-DdBggJS9.js} +1 -1
- package/dist/dashboard/assets/CliToolDetailPage-DdBggJS9.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-CKG-Vxrt.js → CliToolsPage-aN1iXhhP.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-aN1iXhhP.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-JYmVKzIx.js → CombosPage-DE-F1nxZ.js} +1 -1
- package/dist/dashboard/assets/CombosPage-DE-F1nxZ.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-CPflWDry.js → ConsoleLogPage-5SpmfLyw.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-5SpmfLyw.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-B0EYUE47.js → CustomizationPage-3CUxMy2X.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-3CUxMy2X.js.gz +0 -0
- package/dist/dashboard/assets/{HealthEventsModal-F1c4lkNG.js → HealthEventsModal-BkmJQKC0.js} +1 -1
- package/dist/dashboard/assets/HealthEventsModal-BkmJQKC0.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-BYTpzcoU.js → LoginPage-B_0FUKWc.js} +1 -1
- package/dist/dashboard/assets/LoginPage-B_0FUKWc.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-CA1kLs45.js → ModelPicker-DKVslqG3.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-DKVslqG3.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-D-H4MEiT.js +1 -0
- package/dist/dashboard/assets/OverviewPage-D-H4MEiT.js.gz +0 -0
- package/dist/dashboard/assets/{ProviderDetailPage-CM4MNy45.js → ProviderDetailPage-CEJw6Guo.js} +3 -3
- package/dist/dashboard/assets/ProviderDetailPage-CEJw6Guo.js.gz +0 -0
- package/dist/dashboard/assets/{ProvidersPage-Bsoqg2HG.js → ProvidersPage-CEplAR-i.js} +1 -1
- package/dist/dashboard/assets/ProvidersPage-CEplAR-i.js.gz +0 -0
- package/dist/dashboard/assets/{ProxyPage-8G3doV7j.js → ProxyPage-CAN7hy0f.js} +1 -1
- package/dist/dashboard/assets/ProxyPage-CAN7hy0f.js.gz +0 -0
- package/dist/dashboard/assets/{QuotaPage-CVIQq6JG.js → QuotaPage-BjldQwIU.js} +1 -1
- package/dist/dashboard/assets/QuotaPage-BjldQwIU.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DUIoLRxk.js +1 -0
- package/dist/dashboard/assets/SettingsPage-DUIoLRxk.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-BCx07-bj.js → SetupPage-_bCaTM0v.js} +1 -1
- package/dist/dashboard/assets/SetupPage-_bCaTM0v.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-MhkB6msu.js → SortableList-fI7JkdIB.js} +1 -1
- package/dist/dashboard/assets/SortableList-fI7JkdIB.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CTqK6Nsj.js → StudioPage-CHVZqskZ.js} +1 -1
- package/dist/dashboard/assets/StudioPage-CHVZqskZ.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-DiFBymHj.js +56 -0
- package/dist/dashboard/assets/UsagePage-DiFBymHj.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-C23S9sgp.js → api-keys-DFY_fZU4.js} +1 -1
- package/dist/dashboard/assets/api-keys-DFY_fZU4.js.gz +0 -0
- package/dist/dashboard/assets/app-BOJ1_xUB.css +2 -0
- package/dist/dashboard/assets/app-BOJ1_xUB.css.gz +0 -0
- package/dist/dashboard/assets/{assert-DU6qrMA_.js → assert-CwdnZARt.js} +1 -1
- package/dist/dashboard/assets/assert-CwdnZARt.js.gz +0 -0
- package/dist/dashboard/assets/{badge-Bkz_-RrM.js → badge-Dr-uf0Au.js} +1 -1
- package/dist/dashboard/assets/badge-Dr-uf0Au.js.gz +0 -0
- package/dist/dashboard/assets/{banner-C-7y3VKV.js → banner-BddmMdoS.js} +1 -1
- package/dist/dashboard/assets/banner-BddmMdoS.js.gz +0 -0
- package/dist/dashboard/assets/{card-BOPBuBzD.js → card-CK0PXWlX.js} +1 -1
- package/dist/dashboard/assets/card-CK0PXWlX.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-BaFUuFFF.js → cli-tools-CcB6mGh2.js} +1 -1
- package/dist/dashboard/assets/cli-tools-CcB6mGh2.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-e-Mlk0FH.js → clipboard-button-DGb2P9Yx.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-DGb2P9Yx.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-Iec_ywbD.js → dialog-LkfuL50u.js} +1 -1
- package/dist/dashboard/assets/dialog-LkfuL50u.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-Bs8MIIHc.js → drawer-ZbEZ_84c.js} +1 -1
- package/dist/dashboard/assets/drawer-ZbEZ_84c.js.gz +0 -0
- package/dist/dashboard/assets/{entry-DcobaKFu.js → entry-BJfsVMvA.js} +1 -1
- package/dist/dashboard/assets/entry-BJfsVMvA.js.gz +0 -0
- package/dist/dashboard/assets/{entry-CBHzQ6Qh.js → entry-CWBY5A0f.js} +3 -3
- package/dist/dashboard/assets/entry-CWBY5A0f.js.gz +0 -0
- package/dist/dashboard/assets/{entry-BRszm4_Z.js → entry-CvC1-Zqx.js} +1 -1
- package/dist/dashboard/assets/entry-CvC1-Zqx.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-BuDsrsPn.js → github-badge-BxpznFLt.js} +1 -1
- package/dist/dashboard/assets/github-badge-BxpznFLt.js.gz +0 -0
- package/dist/dashboard/assets/{index-Ck4uwuYb.js → index-CDzP3ovJ.js} +2 -2
- package/dist/dashboard/assets/index-CDzP3ovJ.js.gz +0 -0
- package/dist/dashboard/assets/{inline-DToMICwl.js → inline-Ae13MQ5w.js} +1 -1
- package/dist/dashboard/assets/inline-Ae13MQ5w.js.gz +0 -0
- package/dist/dashboard/assets/{input-WlyHWeG2.js → input-D23fo7cp.js} +1 -1
- package/dist/dashboard/assets/input-D23fo7cp.js.gz +0 -0
- package/dist/dashboard/assets/{layout-DaJ5baJr.js → layout-CSsxjj5P.js} +1 -1
- package/dist/dashboard/assets/layout-CSsxjj5P.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-B3oSK13z.js → list-row-dmbwZMDY.js} +1 -1
- package/dist/dashboard/assets/list-row-dmbwZMDY.js.gz +0 -0
- package/dist/dashboard/assets/{live-ta6GMb-8.js → live-BG1oUsZZ.js} +1 -1
- package/dist/dashboard/assets/live-BG1oUsZZ.js.gz +0 -0
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js +1 -0
- package/dist/dashboard/assets/minimize-2-D-MN8W8a.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-g_fduiNw.js → mutation-DSF-e4ho.js} +1 -1
- package/dist/dashboard/assets/mutation-DSF-e4ho.js.gz +0 -0
- package/dist/dashboard/assets/{numbers-Dulqgys5.js → numbers-Bm_aECY7.js} +1 -1
- package/dist/dashboard/assets/{numbers-Dulqgys5.js.gz → numbers-Bm_aECY7.js.gz} +0 -0
- package/dist/dashboard/assets/{query-keys-UETqfytp.js → query-keys-CF56nYIV.js} +1 -1
- package/dist/dashboard/assets/query-keys-CF56nYIV.js.gz +0 -0
- package/dist/dashboard/assets/{routing-BPUo-W8d.js → routing-CeA71n7G.js} +1 -1
- package/dist/dashboard/assets/routing-CeA71n7G.js.gz +0 -0
- package/dist/dashboard/assets/{select-BrrUDUPc.js → select-KIT0rC6G.js} +1 -1
- package/dist/dashboard/assets/select-KIT0rC6G.js.gz +0 -0
- package/dist/dashboard/assets/settings-B_2gkePf.js +1 -0
- package/dist/dashboard/assets/settings-B_2gkePf.js.gz +0 -0
- package/dist/dashboard/assets/{stack-B1w5BM0u.js → stack-D7WOSzcX.js} +1 -1
- package/dist/dashboard/assets/stack-D7WOSzcX.js.gz +0 -0
- package/dist/dashboard/assets/{state-DhZBfWgx.js → state-BBxtKZOQ.js} +1 -1
- package/dist/dashboard/assets/state-BBxtKZOQ.js.gz +0 -0
- package/dist/dashboard/assets/{switch-yD7D99Lg.js → switch-DNS_D5Ea.js} +1 -1
- package/dist/dashboard/assets/switch-DNS_D5Ea.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-EDFRkn1i.js → useMutation-BgoxdoMk.js} +1 -1
- package/dist/dashboard/assets/useMutation-BgoxdoMk.js.gz +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +51 -51
- package/package.json +96 -96
- package/src/boot/app.ts +714 -722
- package/src/boot/dependencies.ts +729 -750
- package/src/config/resources.ts +70 -137
- package/src/config/security.ts +37 -73
- package/src/config/spec.ts +358 -378
- package/src/console/console-router.ts +225 -233
- package/src/console/domain-registration.ts +381 -391
- package/src/console/remote-support/contracts.ts +3 -1
- package/src/console/remote-support/service.ts +115 -6
- package/src/main.ts +167 -169
- package/src/observability/metrics.ts +467 -457
- package/src/observability/runtime-metrics.ts +269 -254
- package/src/protocol/gateway-error.ts +232 -233
- package/src/providers/integrations/commandcode/commandcode.ts +134 -104
- package/src/providers/integrations/commandcode/discovery.ts +6 -5
- package/src/providers/integrations/qoder/qoder.ts +597 -23
- package/src/providers/operations/account-health-service.ts +52 -3
- package/src/security/abuse.ts +17 -0
- package/src/transport/guards/auth-guard.ts +109 -127
- package/src/transport/guards/pipeline.ts +220 -226
- package/src/transport/guards/request-context.ts +238 -318
- package/src/transport/request/inflight.ts +21 -2
- package/src/workers/scheduler.ts +73 -6
- package/dist/dashboard/assets/BannedPage-1v5rzKMl.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-chMg74ct.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-CKG-Vxrt.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-JYmVKzIx.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-CPflWDry.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-B0EYUE47.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-F1c4lkNG.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-BYTpzcoU.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-CA1kLs45.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DIYZRAcb.js +0 -1
- package/dist/dashboard/assets/OverviewPage-DIYZRAcb.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-CM4MNy45.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Bsoqg2HG.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-8G3doV7j.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-CVIQq6JG.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-BgXvRN2Q.js +0 -1
- package/dist/dashboard/assets/SettingsPage-BgXvRN2Q.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-BCx07-bj.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-MhkB6msu.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-CTqK6Nsj.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-Do65OWbr.js +0 -56
- package/dist/dashboard/assets/UsagePage-Do65OWbr.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-C23S9sgp.js.gz +0 -0
- package/dist/dashboard/assets/app-BUSiYL6F.css +0 -2
- package/dist/dashboard/assets/app-BUSiYL6F.css.gz +0 -0
- package/dist/dashboard/assets/assert-DU6qrMA_.js.gz +0 -0
- package/dist/dashboard/assets/badge-Bkz_-RrM.js.gz +0 -0
- package/dist/dashboard/assets/banner-C-7y3VKV.js.gz +0 -0
- package/dist/dashboard/assets/card-BOPBuBzD.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-BaFUuFFF.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-e-Mlk0FH.js.gz +0 -0
- package/dist/dashboard/assets/dialog-Iec_ywbD.js.gz +0 -0
- package/dist/dashboard/assets/drawer-Bs8MIIHc.js.gz +0 -0
- package/dist/dashboard/assets/entry-BRszm4_Z.js.gz +0 -0
- package/dist/dashboard/assets/entry-CBHzQ6Qh.js.gz +0 -0
- package/dist/dashboard/assets/entry-DcobaKFu.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-BuDsrsPn.js.gz +0 -0
- package/dist/dashboard/assets/index-Ck4uwuYb.js.gz +0 -0
- package/dist/dashboard/assets/inline-DToMICwl.js.gz +0 -0
- package/dist/dashboard/assets/input-WlyHWeG2.js.gz +0 -0
- package/dist/dashboard/assets/layout-DaJ5baJr.js.gz +0 -0
- package/dist/dashboard/assets/list-row-B3oSK13z.js.gz +0 -0
- package/dist/dashboard/assets/live-ta6GMb-8.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-BmYTmbAk.js +0 -1
- package/dist/dashboard/assets/model-bans-BmYTmbAk.js.gz +0 -0
- package/dist/dashboard/assets/mutation-g_fduiNw.js.gz +0 -0
- package/dist/dashboard/assets/query-keys-UETqfytp.js.gz +0 -0
- package/dist/dashboard/assets/routing-BPUo-W8d.js.gz +0 -0
- package/dist/dashboard/assets/select-BrrUDUPc.js.gz +0 -0
- package/dist/dashboard/assets/settings--3hxSyry.js +0 -1
- package/dist/dashboard/assets/settings--3hxSyry.js.gz +0 -0
- package/dist/dashboard/assets/stack-B1w5BM0u.js.gz +0 -0
- package/dist/dashboard/assets/state-DhZBfWgx.js.gz +0 -0
- package/dist/dashboard/assets/switch-yD7D99Lg.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-EDFRkn1i.js.gz +0 -0
- package/src/console/admin/model-abuse/contracts.ts +0 -38
- package/src/console/admin/model-abuse/routes.ts +0 -97
- package/src/security/model-abuse.ts +0 -704
- package/src/transport/guards/concurrency-guard.ts +0 -125
- /package/dist/dashboard/assets/{app-MdVfwraB.js → app-CaXZ9SCn.js} +0 -0
- /package/dist/dashboard/assets/{app-MdVfwraB.js.gz → app-CaXZ9SCn.js.gz} +0 -0
|
@@ -1,391 +1,381 @@
|
|
|
1
|
-
import { Elysia } from "elysia";
|
|
2
|
-
import { ConsoleDomainError } from "./shared/errors";
|
|
3
|
-
import { createCliToolsRoutes } from "./cli-tools/routes";
|
|
4
|
-
import { createAccountQuotaRoutes } from "./quota/account-quota";
|
|
5
|
-
import { createApiKeyRoutes } from "./api-keys/routes";
|
|
6
|
-
import { familyBucketSpend } from "./api-keys/bucket-spend";
|
|
7
|
-
import { createProviderCatalogRoutes } from "./providers/catalog/routes";
|
|
8
|
-
import { createInferhubRoutes } from "./inferhub/routes";
|
|
9
|
-
import { createInferhubKeyStore } from "./inferhub/key-store";
|
|
10
|
-
import {
|
|
11
|
-
createProviderDetailRoutes,
|
|
12
|
-
} from "./providers/detail/routes";
|
|
13
|
-
import {
|
|
14
|
-
createOAuthLoginRoutes,
|
|
15
|
-
completeLogin,
|
|
16
|
-
DrizzleOAuthAccountStore,
|
|
17
|
-
type OAuthLoginConfig,
|
|
18
|
-
} from "./providers/oauth/routes";
|
|
19
|
-
import {
|
|
20
|
-
DrizzleProviderCatalogStore,
|
|
21
|
-
} from "./providers/catalog/store";
|
|
22
|
-
import { DrizzleProviderDetailStore } from "./providers/detail/store";
|
|
23
|
-
import { createModelRoutingRoutes } from "./routing/model/routes";
|
|
24
|
-
import { createNetworkPoolRoutes } from "./routing/pools/routes";
|
|
25
|
-
import { DrizzleModelRoutingStore } from "./routing/model/store";
|
|
26
|
-
import { DrizzleNetworkPoolStore } from "./routing/pools/store";
|
|
27
|
-
import { createRuntimeSettingsRoutes } from "./settings/routes";
|
|
28
|
-
import { createDataManagementRoutes } from "./data-management/routes";
|
|
29
|
-
import { healthEventBuffer } from "../persistence/health-event-flush";
|
|
30
|
-
import { countAllHealthEvents, deleteAllHealthEvents } from "../providers/operations/account-health-service";
|
|
31
|
-
import { DrizzleRuntimeSettingsStore } from "./settings/store";
|
|
32
|
-
import { createObservabilityRoutes } from "./observability/routes";
|
|
33
|
-
import { DrizzleObservabilityStore } from "./observability/store";
|
|
34
|
-
import { createLiveRoutes } from "./observability/live";
|
|
35
|
-
import { createLogRoutes } from "./observability/logs";
|
|
36
|
-
import { createAuditRoutes } from "./audit/routes";
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
44
|
-
import {
|
|
45
|
-
import {
|
|
46
|
-
import
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
} from "../providers/operations/provider-
|
|
57
|
-
import {
|
|
58
|
-
import {
|
|
59
|
-
import {
|
|
60
|
-
import {
|
|
61
|
-
import {
|
|
62
|
-
import {
|
|
63
|
-
import type {
|
|
64
|
-
import type {
|
|
65
|
-
import type {
|
|
66
|
-
import type {
|
|
67
|
-
import type {
|
|
68
|
-
import type {
|
|
69
|
-
import
|
|
70
|
-
import type {
|
|
71
|
-
import {
|
|
72
|
-
import type {
|
|
73
|
-
import type {
|
|
74
|
-
import type {
|
|
75
|
-
import type {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
readonly
|
|
81
|
-
readonly
|
|
82
|
-
readonly
|
|
83
|
-
readonly
|
|
84
|
-
readonly
|
|
85
|
-
readonly
|
|
86
|
-
readonly
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
readonly
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
readonly
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
import {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
console.use(
|
|
246
|
-
accessResolver: ctx.accessResolver,
|
|
247
|
-
|
|
248
|
-
}));
|
|
249
|
-
console.use(
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
console.use(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
}));
|
|
291
|
-
console.use(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
const oauthConfig: OAuthLoginConfig = {
|
|
383
|
-
providerRegistry: ctx.providerRegistry,
|
|
384
|
-
oauthFlowStore: ctx.redis ? new OAuthFlowStore(ctx.redis) : new InMemoryOAuthFlowStore(),
|
|
385
|
-
accountStore: new DrizzleOAuthAccountStore(ctx.db),
|
|
386
|
-
accessResolver: ctx.accessResolver,
|
|
387
|
-
snapshotInvalidator: ctx.routeSnapshotService,
|
|
388
|
-
callbackListener: oauthCallbackListener,
|
|
389
|
-
};
|
|
390
|
-
console.use(createOAuthLoginRoutes(oauthConfig));
|
|
391
|
-
}
|
|
1
|
+
import { Elysia } from "elysia";
|
|
2
|
+
import { ConsoleDomainError } from "./shared/errors";
|
|
3
|
+
import { createCliToolsRoutes } from "./cli-tools/routes";
|
|
4
|
+
import { createAccountQuotaRoutes } from "./quota/account-quota";
|
|
5
|
+
import { createApiKeyRoutes } from "./api-keys/routes";
|
|
6
|
+
import { familyBucketSpend } from "./api-keys/bucket-spend";
|
|
7
|
+
import { createProviderCatalogRoutes } from "./providers/catalog/routes";
|
|
8
|
+
import { createInferhubRoutes } from "./inferhub/routes";
|
|
9
|
+
import { createInferhubKeyStore } from "./inferhub/key-store";
|
|
10
|
+
import {
|
|
11
|
+
createProviderDetailRoutes,
|
|
12
|
+
} from "./providers/detail/routes";
|
|
13
|
+
import {
|
|
14
|
+
createOAuthLoginRoutes,
|
|
15
|
+
completeLogin,
|
|
16
|
+
DrizzleOAuthAccountStore,
|
|
17
|
+
type OAuthLoginConfig,
|
|
18
|
+
} from "./providers/oauth/routes";
|
|
19
|
+
import {
|
|
20
|
+
DrizzleProviderCatalogStore,
|
|
21
|
+
} from "./providers/catalog/store";
|
|
22
|
+
import { DrizzleProviderDetailStore } from "./providers/detail/store";
|
|
23
|
+
import { createModelRoutingRoutes } from "./routing/model/routes";
|
|
24
|
+
import { createNetworkPoolRoutes } from "./routing/pools/routes";
|
|
25
|
+
import { DrizzleModelRoutingStore } from "./routing/model/store";
|
|
26
|
+
import { DrizzleNetworkPoolStore } from "./routing/pools/store";
|
|
27
|
+
import { createRuntimeSettingsRoutes } from "./settings/routes";
|
|
28
|
+
import { createDataManagementRoutes } from "./data-management/routes";
|
|
29
|
+
import { healthEventBuffer } from "../persistence/health-event-flush";
|
|
30
|
+
import { countAllHealthEvents, deleteAllHealthEvents } from "../providers/operations/account-health-service";
|
|
31
|
+
import { DrizzleRuntimeSettingsStore } from "./settings/store";
|
|
32
|
+
import { createObservabilityRoutes } from "./observability/routes";
|
|
33
|
+
import { DrizzleObservabilityStore } from "./observability/store";
|
|
34
|
+
import { createLiveRoutes } from "./observability/live";
|
|
35
|
+
import { createLogRoutes } from "./observability/logs";
|
|
36
|
+
import { createAuditRoutes } from "./audit/routes";
|
|
37
|
+
import { DrizzleAuditReadStore } from "./audit/store";
|
|
38
|
+
import { createPerformanceRoutes } from "./observability/performance";
|
|
39
|
+
import { createUpdateRoutes } from "./updates/routes";
|
|
40
|
+
import { createRemoteSupportRoutes } from "./remote-support/routes";
|
|
41
|
+
import { createRemoteSupportService } from "./remote-support/service";
|
|
42
|
+
import { resolvePort } from "../config/runtime";
|
|
43
|
+
import { createBackupRoutes } from "./backup/routes";
|
|
44
|
+
import { BackupService } from "./backup/service";
|
|
45
|
+
import type { ConsoleCredentialService } from "./auth/credentials";
|
|
46
|
+
import { resolveTelemetryRetentionDays } from "../config/telemetry";
|
|
47
|
+
import { payloadRetentionMs, resolvePayloadCapture } from "../observability/payload-capture";
|
|
48
|
+
import { TELEMETRY_EVENT_DIR } from "../observability/event-log";
|
|
49
|
+
|
|
50
|
+
import { InMemoryOAuthFlowStore, OAuthFlowStore } from "../providers/authentication/oauth-flow-store";
|
|
51
|
+
import { OAuthCallbackListener } from "./providers/oauth/callback-listener";
|
|
52
|
+
import {
|
|
53
|
+
createAccountExportCredentialsResolver,
|
|
54
|
+
createAccountSecretResolver,
|
|
55
|
+
} from "../providers/operations/provider-credential-service";
|
|
56
|
+
import { syncByokProvider } from "../providers/operations/provider-catalog-service";
|
|
57
|
+
import { DrizzleApiKeyStore } from "../persistence/stores/api-key-store";
|
|
58
|
+
import { DrizzleShareLinkStore } from "../persistence/stores/share-store";
|
|
59
|
+
import { createShareUsagePort } from "./share/share-usage";
|
|
60
|
+
import { resolveSsrfPolicy } from "../config/network";
|
|
61
|
+
import { createValidatedFetch } from "../network/outbound-fetch";
|
|
62
|
+
import type { AuditRecorder } from "./auth/audit-recorder";
|
|
63
|
+
import type { CliToolService } from "./cli-tools/service";
|
|
64
|
+
import type { NetworkPoolSelector } from "../network/pool/selector";
|
|
65
|
+
import type { LiveInFlightSource } from "./observability/live";
|
|
66
|
+
import type { ApiKeyAdmissionService } from "../security/admission/service";
|
|
67
|
+
import type { TelemetryBatchBuffer } from "../observability/telemetry-buffer";
|
|
68
|
+
import type { OAuthRefreshService } from "../providers/authentication/oauth-refresh-service";
|
|
69
|
+
import { resolveRedisBackend } from "../persistence/redis";
|
|
70
|
+
import type { RedisClient } from "../persistence/redis";
|
|
71
|
+
import type { ProviderRegistry } from "../providers/provider-registry";
|
|
72
|
+
import type { BundledProviderCatalog } from "../providers/operations/provider-catalog-service";
|
|
73
|
+
import type { ValidatedNetworkBindingFactory } from "../network/pool/resolver";
|
|
74
|
+
import type { CartethyiaDatabase } from "../persistence/db-handle";
|
|
75
|
+
import type { ConsoleAccessResolver } from "./auth/access";
|
|
76
|
+
|
|
77
|
+
export interface ConsoleDomainContext {
|
|
78
|
+
readonly db: CartethyiaDatabase;
|
|
79
|
+
readonly accessResolver: ConsoleAccessResolver;
|
|
80
|
+
readonly providerRegistry: ProviderRegistry;
|
|
81
|
+
readonly bundledModelCatalog: BundledProviderCatalog;
|
|
82
|
+
readonly networkBindingFactory: ValidatedNetworkBindingFactory;
|
|
83
|
+
readonly oauthRefreshService: OAuthRefreshService;
|
|
84
|
+
readonly auditRecorder: AuditRecorder;
|
|
85
|
+
readonly cliToolService: CliToolService;
|
|
86
|
+
readonly redis: RedisClient | undefined;
|
|
87
|
+
/** Drops the cached route snapshot after a catalog write. Structurally
|
|
88
|
+
* satisfied by `RouteSnapshotService`. */
|
|
89
|
+
readonly routeSnapshotService: { invalidate(): Promise<number> };
|
|
90
|
+
readonly poolSelector: NetworkPoolSelector;
|
|
91
|
+
readonly telemetryBuffer: TelemetryBatchBuffer;
|
|
92
|
+
/**
|
|
93
|
+
* Queued writers the console can drain on demand. Optional because a flush
|
|
94
|
+
* is only meaningful when the process owns the buffers; a caller that does
|
|
95
|
+
* not pass them simply loses the button rather than failing to boot.
|
|
96
|
+
*/
|
|
97
|
+
readonly flushBuffers?: {
|
|
98
|
+
flush(): Promise<void>;
|
|
99
|
+
};
|
|
100
|
+
/** Owns the live in-flight gauge the console surfaces. */
|
|
101
|
+
readonly stateStore?: LiveInFlightSource;
|
|
102
|
+
readonly admissionService: Pick<ApiKeyAdmissionService, "purgeKey">;
|
|
103
|
+
readonly readRoutingAccountInflight?:
|
|
104
|
+
| ((
|
|
105
|
+
providerId: string,
|
|
106
|
+
tenantId: string | null,
|
|
107
|
+
) => Promise<readonly { accountId: string; inflight: number }[]>)
|
|
108
|
+
| undefined;
|
|
109
|
+
/**
|
|
110
|
+
* Loads the signed-in console user, for surfaces that re-authenticate the
|
|
111
|
+
* operator rather than trusting the session alone (backup export/restore).
|
|
112
|
+
*/
|
|
113
|
+
readonly loadConsoleUser: (request: Request) => Promise<{ readonly passwordHash: string } | null>;
|
|
114
|
+
/** Password verification against the console user's stored hash. */
|
|
115
|
+
readonly credentialService: Pick<ConsoleCredentialService, "verifyPassword">;
|
|
116
|
+
}
|
|
117
|
+
import { and, eq, isNull, or } from "drizzle-orm";
|
|
118
|
+
import { networkPools, providerRoutingSettings } from "../persistence/schema";
|
|
119
|
+
import { resolveTenantOverride } from "../persistence/tenant-scope";
|
|
120
|
+
import { DEFAULT_PROXY_SKIP_PROVIDER_IDS } from "../providers/provider-metadata";
|
|
121
|
+
import type { ProbeOutboundBinding } from "../providers/discovery/probing-service";
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
export function registerConsoleDomains(
|
|
125
|
+
console: Elysia<any, any, any, any, any, any, any, any>,
|
|
126
|
+
ctx: ConsoleDomainContext,
|
|
127
|
+
): void {
|
|
128
|
+
const observabilityStore = new DrizzleObservabilityStore(ctx.db, ctx.redis);
|
|
129
|
+
const auditReadStore = new DrizzleAuditReadStore(ctx.db);
|
|
130
|
+
/** Refresh-aware credential resolution for quota routes. */
|
|
131
|
+
const resolveCredential = createAccountSecretResolver({
|
|
132
|
+
db: ctx.db,
|
|
133
|
+
resolveRefresher: (id) => ctx.providerRegistry.resolveRefresher(id),
|
|
134
|
+
refreshService: ctx.oauthRefreshService,
|
|
135
|
+
});
|
|
136
|
+
const resolveExportCredentials = createAccountExportCredentialsResolver({
|
|
137
|
+
db: ctx.db,
|
|
138
|
+
resolveRefresher: (id) => ctx.providerRegistry.resolveRefresher(id),
|
|
139
|
+
refreshService: ctx.oauthRefreshService,
|
|
140
|
+
});
|
|
141
|
+
const providerCatalogStore = new DrizzleProviderCatalogStore(ctx.db, {
|
|
142
|
+
telemetryBuffer: ctx.telemetryBuffer,
|
|
143
|
+
bundledModelCatalog: ctx.bundledModelCatalog,
|
|
144
|
+
providerRegistry: ctx.providerRegistry,
|
|
145
|
+
outboundFetchFor: async (tenantId: string, providerId?: string): Promise<ProbeOutboundBinding> => {
|
|
146
|
+
let bypass = false;
|
|
147
|
+
if (providerId) {
|
|
148
|
+
const rows = await ctx.db
|
|
149
|
+
.select({
|
|
150
|
+
tenantId: providerRoutingSettings.tenantId,
|
|
151
|
+
skipProxy: providerRoutingSettings.skipProxy,
|
|
152
|
+
})
|
|
153
|
+
.from(providerRoutingSettings)
|
|
154
|
+
.where(
|
|
155
|
+
and(
|
|
156
|
+
eq(providerRoutingSettings.providerId, providerId),
|
|
157
|
+
or(
|
|
158
|
+
eq(providerRoutingSettings.tenantId, tenantId),
|
|
159
|
+
isNull(providerRoutingSettings.tenantId),
|
|
160
|
+
),
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
const tenantSetting = rows.find((row) => row.tenantId === tenantId)?.skipProxy;
|
|
164
|
+
const globalSetting = rows.find((row) => row.tenantId === null)?.skipProxy;
|
|
165
|
+
bypass = resolveTenantOverride(
|
|
166
|
+
tenantSetting,
|
|
167
|
+
globalSetting,
|
|
168
|
+
DEFAULT_PROXY_SKIP_PROVIDER_IDS.has(providerId),
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (!bypass) {
|
|
173
|
+
const activePools = await ctx.db
|
|
174
|
+
.select({
|
|
175
|
+
id: networkPools.id,
|
|
176
|
+
maxInflight: networkPools.maxInflight,
|
|
177
|
+
weight: networkPools.weight,
|
|
178
|
+
})
|
|
179
|
+
.from(networkPools)
|
|
180
|
+
.where(and(eq(networkPools.tenantId, tenantId), eq(networkPools.status, "active")));
|
|
181
|
+
|
|
182
|
+
if (activePools.length > 0) {
|
|
183
|
+
const limits: Record<string, number> = {};
|
|
184
|
+
const weights: Record<string, number> = {};
|
|
185
|
+
for (const p of activePools) {
|
|
186
|
+
limits[p.id] = p.maxInflight ?? 10;
|
|
187
|
+
weights[p.id] = p.weight ?? 100;
|
|
188
|
+
}
|
|
189
|
+
const slot = await ctx.poolSelector.tryAcquireAvailablePool(
|
|
190
|
+
activePools.map((p) => p.id),
|
|
191
|
+
providerId ?? "default",
|
|
192
|
+
limits,
|
|
193
|
+
weights,
|
|
194
|
+
);
|
|
195
|
+
if (slot) {
|
|
196
|
+
return {
|
|
197
|
+
fetch: ctx.networkBindingFactory.fetch(slot.poolId, tenantId),
|
|
198
|
+
http2Bidi: ctx.networkBindingFactory.http2Bidi(slot.poolId, tenantId),
|
|
199
|
+
networkPoolId: slot.poolId,
|
|
200
|
+
release: slot.release,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
// Every pool is saturated or cooling down: fail closed with an
|
|
204
|
+
// explicit 503 rather than pinning the first pool and bypassing its
|
|
205
|
+
// capacity accounting and cooldown.
|
|
206
|
+
throw new ConsoleDomainError(
|
|
207
|
+
"pool_unavailable",
|
|
208
|
+
503,
|
|
209
|
+
`All network pools are saturated for provider ${providerId ?? "default"}`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
fetch: ctx.networkBindingFactory.fetch(undefined, tenantId),
|
|
216
|
+
http2Bidi: ctx.networkBindingFactory.http2Bidi(undefined, tenantId),
|
|
217
|
+
};
|
|
218
|
+
},
|
|
219
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
220
|
+
readAccountInflight: async (providerId, tenantId) =>
|
|
221
|
+
ctx.readRoutingAccountInflight ? ctx.readRoutingAccountInflight(providerId, tenantId) : [],
|
|
222
|
+
});
|
|
223
|
+
const providerDetailStore = new DrizzleProviderDetailStore(ctx.db);
|
|
224
|
+
const networkPoolStore = new DrizzleNetworkPoolStore(ctx.db, resolveSsrfPolicy());
|
|
225
|
+
const runtimeSettingsStore = new DrizzleRuntimeSettingsStore(ctx.db, resolveRedisBackend(ctx.redis));
|
|
226
|
+
const modelRoutingStore = new DrizzleModelRoutingStore(ctx.db);
|
|
227
|
+
const apiKeyStore = new DrizzleApiKeyStore(ctx.db);
|
|
228
|
+
const shareStore = new DrizzleShareLinkStore(ctx.db);
|
|
229
|
+
const shareActivity = createShareUsagePort({ db: ctx.db, redis: ctx.redis });
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
console.use(createObservabilityRoutes({ store: observabilityStore, accessResolver: ctx.accessResolver }));
|
|
233
|
+
console.use(createLiveRoutes({
|
|
234
|
+
accessResolver: ctx.accessResolver,
|
|
235
|
+
poolSelector: ctx.poolSelector,
|
|
236
|
+
db: ctx.db,
|
|
237
|
+
...(ctx.stateStore ? { stateStore: ctx.stateStore } : {}),
|
|
238
|
+
}));
|
|
239
|
+
console.use(createLogRoutes({ accessResolver: ctx.accessResolver, auditSink: ctx.auditRecorder }));
|
|
240
|
+
console.use(createPerformanceRoutes({ accessResolver: ctx.accessResolver }));
|
|
241
|
+
console.use(createUpdateRoutes({
|
|
242
|
+
accessResolver: ctx.accessResolver,
|
|
243
|
+
observabilityStore,
|
|
244
|
+
}));
|
|
245
|
+
console.use(createRemoteSupportRoutes({
|
|
246
|
+
accessResolver: ctx.accessResolver,
|
|
247
|
+
service: createRemoteSupportService({ port: resolvePort() }),
|
|
248
|
+
}));
|
|
249
|
+
console.use(createAuditRoutes({ store: auditReadStore, accessResolver: ctx.accessResolver }));
|
|
250
|
+
// InferHub market data. On demand only: a route fetches when its snapshot is
|
|
251
|
+
// past its freshness window, so a page nobody opens causes no upstream calls.
|
|
252
|
+
const inferhubKeys = createInferhubKeyStore(ctx.db);
|
|
253
|
+
console.use(createInferhubRoutes({
|
|
254
|
+
accessResolver: ctx.accessResolver,
|
|
255
|
+
resolveConfigKey: () => inferhubKeys.read(),
|
|
256
|
+
keyStore: inferhubKeys,
|
|
257
|
+
}));
|
|
258
|
+
console.use(createProviderCatalogRoutes({
|
|
259
|
+
store: providerCatalogStore,
|
|
260
|
+
accessResolver: ctx.accessResolver,
|
|
261
|
+
auditSink: ctx.auditRecorder,
|
|
262
|
+
providerRegistry: ctx.providerRegistry,
|
|
263
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
264
|
+
resolveExportCredentials,
|
|
265
|
+
// Without this, a custom provider only becomes dispatchable after a
|
|
266
|
+
// restart: boot registers BYOK rows once, and the catalog routes are the
|
|
267
|
+
syncByokProvider: (providerId) =>
|
|
268
|
+
syncByokProvider(ctx.providerRegistry, ctx.db, providerId, resolveSsrfPolicy()),
|
|
269
|
+
listRoutingTargets: async (tenantId) => ({
|
|
270
|
+
aliases: await modelRoutingStore.listAliases(tenantId),
|
|
271
|
+
combos: await modelRoutingStore.listCombos(tenantId),
|
|
272
|
+
}),
|
|
273
|
+
}));
|
|
274
|
+
console.use(createProviderDetailRoutes({
|
|
275
|
+
store: providerDetailStore,
|
|
276
|
+
accessResolver: ctx.accessResolver,
|
|
277
|
+
auditSink: ctx.auditRecorder,
|
|
278
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
279
|
+
accountInflight: ctx.readRoutingAccountInflight,
|
|
280
|
+
}));
|
|
281
|
+
console.use(createNetworkPoolRoutes({
|
|
282
|
+
store: networkPoolStore,
|
|
283
|
+
accessResolver: ctx.accessResolver,
|
|
284
|
+
auditSink: ctx.auditRecorder,
|
|
285
|
+
poolSelector: ctx.poolSelector,
|
|
286
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
287
|
+
// Hosted-relay deploys reach Cloudflare/Vercel/Deno APIs, so they use the
|
|
288
|
+
// same SSRF-validated fetch as every other egress.
|
|
289
|
+
relayFetch: createValidatedFetch({ policy: resolveSsrfPolicy() }),
|
|
290
|
+
}));
|
|
291
|
+
console.use(createRuntimeSettingsRoutes({ store: runtimeSettingsStore, accessResolver: ctx.accessResolver, auditSink: ctx.auditRecorder, snapshotInvalidator: ctx.routeSnapshotService }));
|
|
292
|
+
console.use(
|
|
293
|
+
createDataManagementRoutes({
|
|
294
|
+
telemetryDir: TELEMETRY_EVENT_DIR,
|
|
295
|
+
retentionDays: resolveTelemetryRetentionDays(),
|
|
296
|
+
/*
|
|
297
|
+
* Resolved per tenant, not once at boot: the Request detail window is a
|
|
298
|
+
* per-tenant setting, and this panel is the only place that reports the
|
|
299
|
+
* number back. A deployment-level value made it show the default while
|
|
300
|
+
* the gateway applied the tenant's own window.
|
|
301
|
+
*
|
|
302
|
+
* It goes through the same `resolvePayloadCapture` the dispatch path
|
|
303
|
+
* uses, so the panel and the gateway cannot disagree about how long a
|
|
304
|
+
* frame lives.
|
|
305
|
+
*/
|
|
306
|
+
payloadRetentionMs: async (tenantId) => {
|
|
307
|
+
const resolved = await resolvePayloadCapture(ctx.db, tenantId);
|
|
308
|
+
return resolved.ok ? resolved.retentionMs : payloadRetentionMs();
|
|
309
|
+
},
|
|
310
|
+
accessResolver: ctx.accessResolver,
|
|
311
|
+
auditSink: ctx.auditRecorder,
|
|
312
|
+
flusher: ctx.flushBuffers,
|
|
313
|
+
// The console's one row-level purge: the health & error log is a
|
|
314
|
+
// diagnostic trail no request-path code reads. Dropping the buffered
|
|
315
|
+
// writes before the DELETE is what makes it sound — otherwise a batch
|
|
316
|
+
// in flight would land behind the purge and resurrect history that was
|
|
317
|
+
// just counted as deleted.
|
|
318
|
+
healthEvents: {
|
|
319
|
+
count: () => countAllHealthEvents(ctx.db),
|
|
320
|
+
purgeAll: async () => {
|
|
321
|
+
await healthEventBuffer()?.drain();
|
|
322
|
+
return await deleteAllHealthEvents(ctx.db);
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
}),
|
|
326
|
+
);
|
|
327
|
+
console.use(
|
|
328
|
+
createBackupRoutes({
|
|
329
|
+
accessResolver: ctx.accessResolver,
|
|
330
|
+
// The service is built per request: re-authenticating the operator needs
|
|
331
|
+
// the request's session, and holding a request-bound closure in a
|
|
332
|
+
// long-lived object would leak one request's identity into the next.
|
|
333
|
+
backupFor: (request: Request) =>
|
|
334
|
+
new BackupService({
|
|
335
|
+
db: ctx.db,
|
|
336
|
+
verifyPassword: async (password: string) => {
|
|
337
|
+
const user = await ctx.loadConsoleUser(request);
|
|
338
|
+
if (user === null) return false;
|
|
339
|
+
return ctx.credentialService.verifyPassword(password, user.passwordHash);
|
|
340
|
+
},
|
|
341
|
+
}),
|
|
342
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
343
|
+
apiKeyStore,
|
|
344
|
+
admissionService: ctx.admissionService,
|
|
345
|
+
auditSink: ctx.auditRecorder,
|
|
346
|
+
}),
|
|
347
|
+
);
|
|
348
|
+
console.use(createModelRoutingRoutes({ store: modelRoutingStore, accessResolver: ctx.accessResolver, auditSink: ctx.auditRecorder, snapshotInvalidator: ctx.routeSnapshotService }));
|
|
349
|
+
console.use(createApiKeyRoutes({ store: apiKeyStore, accessResolver: ctx.accessResolver, auditSink: ctx.auditRecorder, shareStore, shareActivity, admissionService: ctx.admissionService, bucketSpend: (keyId, now) => familyBucketSpend(ctx.db, keyId, now) }));
|
|
350
|
+
console.use(createCliToolsRoutes({ service: ctx.cliToolService, accessResolver: ctx.accessResolver, auditSink: ctx.auditRecorder, snapshotInvalidator: ctx.routeSnapshotService }));
|
|
351
|
+
console.use(createAccountQuotaRoutes({
|
|
352
|
+
db: ctx.db,
|
|
353
|
+
accessResolver: ctx.accessResolver,
|
|
354
|
+
auditRecorder: ctx.auditRecorder,
|
|
355
|
+
redis: ctx.redis,
|
|
356
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
357
|
+
providerRegistry: ctx.providerRegistry,
|
|
358
|
+
resolveCredential,
|
|
359
|
+
poolSelector: ctx.poolSelector,
|
|
360
|
+
networkBindingFactory: ctx.networkBindingFactory,
|
|
361
|
+
}));
|
|
362
|
+
// The listener binds the loopback port a browser redirect names, so the
|
|
363
|
+
// callback delivers itself instead of waiting for a manual paste. One
|
|
364
|
+
// instance per console: a port is shared by every flow registered on it, and
|
|
365
|
+
// it is released when the last of those flows settles.
|
|
366
|
+
const oauthCallbackListener = new OAuthCallbackListener({
|
|
367
|
+
completer: {
|
|
368
|
+
complete: (providerId, code, state) =>
|
|
369
|
+
completeLogin(oauthConfig, providerId, code, state),
|
|
370
|
+
},
|
|
371
|
+
});
|
|
372
|
+
const oauthConfig: OAuthLoginConfig = {
|
|
373
|
+
providerRegistry: ctx.providerRegistry,
|
|
374
|
+
oauthFlowStore: ctx.redis ? new OAuthFlowStore(ctx.redis) : new InMemoryOAuthFlowStore(),
|
|
375
|
+
accountStore: new DrizzleOAuthAccountStore(ctx.db),
|
|
376
|
+
accessResolver: ctx.accessResolver,
|
|
377
|
+
snapshotInvalidator: ctx.routeSnapshotService,
|
|
378
|
+
callbackListener: oauthCallbackListener,
|
|
379
|
+
};
|
|
380
|
+
console.use(createOAuthLoginRoutes(oauthConfig));
|
|
381
|
+
}
|