cartethyia 2.5.3 → 2.5.4
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/dist/dashboard/assets/{BannedPage-hfCzi-Ux.js → BannedPage-C2orBsI2.js} +1 -1
- package/dist/dashboard/assets/BannedPage-C2orBsI2.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js +1 -0
- package/dist/dashboard/assets/CliToolDetailPage-DUcZ6pMB.js.gz +0 -0
- package/dist/dashboard/assets/{CliToolsPage-DEDyKBlC.js → CliToolsPage-BV6pxVQo.js} +1 -1
- package/dist/dashboard/assets/CliToolsPage-BV6pxVQo.js.gz +0 -0
- package/dist/dashboard/assets/{CombosPage-CfuYiQ8Z.js → CombosPage-Bsan4679.js} +1 -1
- package/dist/dashboard/assets/CombosPage-Bsan4679.js.gz +0 -0
- package/dist/dashboard/assets/{ConsoleLogPage-bsLuZmYH.js → ConsoleLogPage-CW-wPmJ6.js} +1 -1
- package/dist/dashboard/assets/ConsoleLogPage-CW-wPmJ6.js.gz +0 -0
- package/dist/dashboard/assets/{CustomizationPage-_UWhwziJ.js → CustomizationPage-0p8uX7vB.js} +1 -1
- package/dist/dashboard/assets/CustomizationPage-0p8uX7vB.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js +1 -0
- package/dist/dashboard/assets/HealthEventsModal-BjqSMfko.js.gz +0 -0
- package/dist/dashboard/assets/{LoginPage-DDVIfZGW.js → LoginPage-BvzCx8Kr.js} +1 -1
- package/dist/dashboard/assets/LoginPage-BvzCx8Kr.js.gz +0 -0
- package/dist/dashboard/assets/{ModelPicker-CWkTUtpX.js → ModelPicker-BY1aKEkP.js} +1 -1
- package/dist/dashboard/assets/ModelPicker-BY1aKEkP.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js +1 -0
- package/dist/dashboard/assets/OverviewPage-DOQpy1y0.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js +3 -0
- package/dist/dashboard/assets/ProviderDetailPage-ecxyUMzt.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js +1 -0
- package/dist/dashboard/assets/ProvidersPage-Js9jUPSb.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js +7 -0
- package/dist/dashboard/assets/ProxyPage-J3TBi3Kx.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js +1 -0
- package/dist/dashboard/assets/QuotaPage-C1gZS6xr.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js +1 -0
- package/dist/dashboard/assets/SettingsPage-CS86ho5X.js.gz +0 -0
- package/dist/dashboard/assets/{SetupPage-D6pmQ86L.js → SetupPage-DDbMQsoo.js} +1 -1
- package/dist/dashboard/assets/SetupPage-DDbMQsoo.js.gz +0 -0
- package/dist/dashboard/assets/{SortableList-DWvKiuSl.js → SortableList-CB3Z7VTf.js} +1 -1
- package/dist/dashboard/assets/SortableList-CB3Z7VTf.js.gz +0 -0
- package/dist/dashboard/assets/{StudioPage-CmkUrgdj.js → StudioPage-D95UCPHI.js} +3 -3
- package/dist/dashboard/assets/StudioPage-D95UCPHI.js.gz +0 -0
- package/dist/dashboard/assets/{UsagePage-B47uOydr.js → UsagePage-Cnae9SWA.js} +13 -13
- package/dist/dashboard/assets/UsagePage-Cnae9SWA.js.gz +0 -0
- package/dist/dashboard/assets/{api-keys-uNywYlfv.js → api-keys-VY68Mhd1.js} +1 -1
- package/dist/dashboard/assets/api-keys-VY68Mhd1.js.gz +0 -0
- package/dist/dashboard/assets/app-COlK95oi.css +2 -0
- package/dist/dashboard/assets/app-COlK95oi.css.gz +0 -0
- package/dist/dashboard/assets/{assert-NHwYq95t.js → assert-Chi7pCnt.js} +1 -1
- package/dist/dashboard/assets/assert-Chi7pCnt.js.gz +0 -0
- package/dist/dashboard/assets/{badge-6uzDDvqs.js → badge-D4pQapKj.js} +1 -1
- package/dist/dashboard/assets/badge-D4pQapKj.js.gz +0 -0
- package/dist/dashboard/assets/{banner-4_WNg2WZ.js → banner-DH6cg-_B.js} +1 -1
- package/dist/dashboard/assets/banner-DH6cg-_B.js.gz +0 -0
- package/dist/dashboard/assets/{card--AtFedAq.js → card-BKqlUOe4.js} +1 -1
- package/dist/dashboard/assets/card-BKqlUOe4.js.gz +0 -0
- package/dist/dashboard/assets/{cli-tools-B3e7dx3N.js → cli-tools-fTgljTGA.js} +1 -1
- package/dist/dashboard/assets/cli-tools-fTgljTGA.js.gz +0 -0
- package/dist/dashboard/assets/{clipboard-button-NreUx6c8.js → clipboard-button-D5Ys_sM0.js} +1 -1
- package/dist/dashboard/assets/clipboard-button-D5Ys_sM0.js.gz +0 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js +1 -0
- package/dist/dashboard/assets/database-Dz9N3zGd.js.gz +0 -0
- package/dist/dashboard/assets/{dialog-BtpsJU98.js → dialog-BYj-8WuK.js} +1 -1
- package/dist/dashboard/assets/dialog-BYj-8WuK.js.gz +0 -0
- package/dist/dashboard/assets/{drawer-WwwtzihF.js → drawer-CmXIZ6H1.js} +1 -1
- package/dist/dashboard/assets/drawer-CmXIZ6H1.js.gz +0 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js +1 -0
- package/dist/dashboard/assets/entry-CBg5zeu8.js.gz +0 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js +1 -0
- package/dist/dashboard/assets/entry-CQBr6U9c.js.gz +0 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js +4 -0
- package/dist/dashboard/assets/entry-CgdSAzEV.js.gz +0 -0
- package/dist/dashboard/assets/{github-badge-D_eM3IgG.js → github-badge-BlptL8Uf.js} +1 -1
- package/dist/dashboard/assets/github-badge-BlptL8Uf.js.gz +0 -0
- package/dist/dashboard/assets/{index-BydyKaDz.js → index-js6TJvdr.js} +2 -2
- package/dist/dashboard/assets/index-js6TJvdr.js.gz +0 -0
- package/dist/dashboard/assets/{inline-BcNGF8Gr.js → inline-DUWDSmDV.js} +1 -1
- package/dist/dashboard/assets/inline-DUWDSmDV.js.gz +0 -0
- package/dist/dashboard/assets/{input-BG41et9G.js → input-LVjgZq4f.js} +1 -1
- package/dist/dashboard/assets/input-LVjgZq4f.js.gz +0 -0
- package/dist/dashboard/assets/{layout-C8mer_Ak.js → layout-CPfxpsfy.js} +1 -1
- package/dist/dashboard/assets/layout-CPfxpsfy.js.gz +0 -0
- package/dist/dashboard/assets/{list-row-Gh_W4OR_.js → list-row-DupvLfDx.js} +1 -1
- package/dist/dashboard/assets/list-row-DupvLfDx.js.gz +0 -0
- package/dist/dashboard/assets/{live-BJGYRBnR.js → live-C4pEJUqI.js} +1 -1
- package/dist/dashboard/assets/live-C4pEJUqI.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js +1 -0
- package/dist/dashboard/assets/model-bans-BRiuufkB.js.gz +0 -0
- package/dist/dashboard/assets/{mutation-BkoLM5Ba.js → mutation-B4ROwk8L.js} +1 -1
- package/dist/dashboard/assets/mutation-B4ROwk8L.js.gz +0 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js +2 -0
- package/dist/dashboard/assets/numbers-YNcHvRY7.js.gz +0 -0
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js → query-keys-gmjzC3RS.js} +1 -1
- package/dist/dashboard/assets/{query-keys-D7wX2vM5.js.gz → query-keys-gmjzC3RS.js.gz} +0 -0
- package/dist/dashboard/assets/{routing-CcusqXA7.js → routing-C7tBT5o-.js} +1 -1
- package/dist/dashboard/assets/routing-C7tBT5o-.js.gz +0 -0
- package/dist/dashboard/assets/{select-BO6h8yNv.js → select-WUCXorXw.js} +2 -2
- package/dist/dashboard/assets/select-WUCXorXw.js.gz +0 -0
- package/dist/dashboard/assets/{settings-mpmXTgUa.js → settings-C_zKl1GS.js} +1 -1
- package/dist/dashboard/assets/settings-C_zKl1GS.js.gz +0 -0
- package/dist/dashboard/assets/{stack-DwLmjUFK.js → stack-_3O0F8Xn.js} +1 -1
- package/dist/dashboard/assets/stack-_3O0F8Xn.js.gz +0 -0
- package/dist/dashboard/assets/{state-DYdQmdAl.js → state-BgTxHcJS.js} +1 -1
- package/dist/dashboard/assets/state-BgTxHcJS.js.gz +0 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js +1 -0
- package/dist/dashboard/assets/switch-DEjTtOWf.js.gz +0 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js +1 -0
- package/dist/dashboard/assets/terminal-0_IjPWTk.js.gz +0 -0
- package/dist/dashboard/assets/{useMutation-w4u4CVue.js → useMutation-BWSC0UAS.js} +1 -1
- package/dist/dashboard/assets/useMutation-BWSC0UAS.js.gz +0 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js +1 -0
- package/dist/dashboard/assets/zap-C4EeVW4q.js.gz +0 -0
- package/dist/dashboard/donation/qris-risun-marke.png +0 -0
- package/dist/dashboard/index.html +1 -1
- package/dist/dashboard/index.html.gz +0 -0
- package/dist/dashboard/precompressed-assets.json +54 -54
- package/package.json +1 -1
- package/scripts/cli/autostart.ts +237 -0
- package/scripts/cli/command/console-menu.ts +4 -8
- package/scripts/cli/command/update.ts +27 -10
- package/scripts/cli/main.ts +28 -1
- package/src/boot/app.ts +693 -693
- package/src/boot/dependencies.ts +646 -616
- package/src/config/spec.ts +55 -0
- package/src/config/telemetry.ts +46 -0
- package/src/console/api-keys/bucket-spend.ts +15 -4
- package/src/console/backup/contracts.ts +15 -2
- package/src/console/console-router.ts +8 -0
- package/src/console/data-management/contracts.ts +93 -0
- package/src/console/data-management/operations.ts +229 -0
- package/src/console/data-management/routes.ts +104 -0
- package/src/console/domain-registration.ts +39 -0
- package/src/console/observability/contracts.ts +524 -485
- package/src/console/observability/store.ts +1115 -1018
- package/src/console/providers/catalog/contracts.ts +6 -0
- package/src/console/providers/catalog/provider-operations.ts +20 -0
- package/src/console/providers/catalog/routes.ts +7 -0
- package/src/console/providers/catalog/store.ts +22 -1
- package/src/console/quota/account-quota-shared.ts +52 -39
- package/src/console/quota/refresh.ts +441 -429
- package/src/console/routing/pools/import-parse.ts +206 -0
- package/src/console/routing/pools/operations.ts +543 -501
- package/src/console/routing/pools/routes.ts +181 -164
- package/src/console/settings/contracts.ts +37 -0
- package/src/console/settings/store.ts +51 -0
- package/src/console/updates/routes.ts +16 -0
- package/src/main.ts +10 -0
- package/src/observability/event-compaction.ts +315 -0
- package/src/observability/event-day-index.ts +442 -0
- package/src/observability/event-log.ts +152 -3
- package/src/observability/payload-capture.ts +8 -1
- package/src/observability/payload-store.ts +440 -376
- package/src/persistence/health-event-flush.ts +36 -0
- package/src/persistence/schema.ts +1402 -1360
- package/src/persistence/stores/telemetry-store.ts +237 -214
- package/src/protocol/codecs.ts +1 -2
- package/src/protocol/image-clamp.ts +19 -1
- package/src/protocol/registry.ts +8 -0
- package/src/protocol/request/gemini.ts +9 -2
- package/src/protocol/request/messages.ts +14 -2
- package/src/providers/adapters/compatible-adapter.ts +3 -0
- package/src/providers/bundled-discovery-providers.ts +122 -119
- package/src/providers/configured-openai-providers.ts +136 -134
- package/src/providers/default-registry.ts +5 -4
- package/src/providers/discovery/openai-model-discovery.ts +5 -0
- package/src/providers/discovery/openrouter-free-roster.ts +15 -17
- package/src/providers/integrations/cline/cline-quota.ts +132 -125
- package/src/providers/integrations/codex/codex-headers.ts +25 -39
- package/src/providers/integrations/codex/codex.ts +2 -29
- package/src/providers/integrations/cursor/cursor-quota.ts +310 -0
- package/src/providers/integrations/cursor/cursor-request.ts +616 -471
- package/src/providers/integrations/cursor/cursor-session-manager.ts +319 -281
- package/src/providers/integrations/cursor/cursor.ts +1485 -960
- package/src/providers/integrations/cursor/protocol/messages.ts +25 -0
- package/src/providers/integrations/factory/factory.ts +8 -1
- package/src/providers/integrations/gemini.ts +6 -1
- package/src/providers/integrations/grok/grok-quota.ts +279 -177
- package/src/providers/integrations/grok/grok-ratelimit-store.ts +73 -0
- package/src/providers/integrations/grok/grok-ratelimit.ts +218 -0
- package/src/providers/integrations/opencode/provider.ts +12 -13
- package/src/providers/integrations/qoder/qoder-quota.ts +192 -0
- package/src/providers/integrations/trae/trae-quota.ts +384 -0
- package/src/providers/operations/account-health-service.ts +1523 -1480
- package/src/providers/provider-contracts.ts +7 -0
- package/src/providers/provider-metadata.ts +6 -0
- package/src/providers/quota/quota-support.ts +8 -0
- package/src/security/api-key-auth.ts +504 -494
- package/src/transport/dispatch/generation.ts +6 -0
- package/src/transport/dispatch/proxy-request.ts +24 -1
- package/src/transport/dispatch/ratelimit-capture.ts +37 -0
- package/src/transport/dispatch/streaming/stream.ts +14 -0
- package/src/transport/dispatch/upstream.ts +9 -0
- package/src/transport/request/preparer.ts +7 -6
- package/src/transport/request/state.ts +9 -0
- package/src/transport/request/tenant-preferences.ts +60 -0
- package/src/transport/routing/route-catalog.ts +58 -10
- package/dist/dashboard/assets/BannedPage-hfCzi-Ux.js.gz +0 -0
- package/dist/dashboard/assets/CliToolDetailPage-DLGqYEwI.js +0 -1
- package/dist/dashboard/assets/CliToolDetailPage-DLGqYEwI.js.gz +0 -0
- package/dist/dashboard/assets/CliToolsPage-DEDyKBlC.js.gz +0 -0
- package/dist/dashboard/assets/CombosPage-CfuYiQ8Z.js.gz +0 -0
- package/dist/dashboard/assets/ConsoleLogPage-bsLuZmYH.js.gz +0 -0
- package/dist/dashboard/assets/CustomizationPage-_UWhwziJ.js.gz +0 -0
- package/dist/dashboard/assets/HealthEventsModal-Cjfc5WFS.js +0 -1
- package/dist/dashboard/assets/HealthEventsModal-Cjfc5WFS.js.gz +0 -0
- package/dist/dashboard/assets/LoginPage-DDVIfZGW.js.gz +0 -0
- package/dist/dashboard/assets/ModelPicker-CWkTUtpX.js.gz +0 -0
- package/dist/dashboard/assets/OverviewPage-B53YYMng.js +0 -1
- package/dist/dashboard/assets/OverviewPage-B53YYMng.js.gz +0 -0
- package/dist/dashboard/assets/ProviderDetailPage-B0KaAQf0.js +0 -3
- package/dist/dashboard/assets/ProviderDetailPage-B0KaAQf0.js.gz +0 -0
- package/dist/dashboard/assets/ProvidersPage-Dx31DgIO.js +0 -1
- package/dist/dashboard/assets/ProvidersPage-Dx31DgIO.js.gz +0 -0
- package/dist/dashboard/assets/ProxyPage-BpnR4kXT.js +0 -7
- package/dist/dashboard/assets/ProxyPage-BpnR4kXT.js.gz +0 -0
- package/dist/dashboard/assets/QuotaPage-BpOQCnun.js +0 -1
- package/dist/dashboard/assets/QuotaPage-BpOQCnun.js.gz +0 -0
- package/dist/dashboard/assets/SettingsPage-DV1eo2J_.js +0 -1
- package/dist/dashboard/assets/SettingsPage-DV1eo2J_.js.gz +0 -0
- package/dist/dashboard/assets/SetupPage-D6pmQ86L.js.gz +0 -0
- package/dist/dashboard/assets/SortableList-DWvKiuSl.js.gz +0 -0
- package/dist/dashboard/assets/StudioPage-CmkUrgdj.js.gz +0 -0
- package/dist/dashboard/assets/UsagePage-B47uOydr.js.gz +0 -0
- package/dist/dashboard/assets/api-keys-uNywYlfv.js.gz +0 -0
- package/dist/dashboard/assets/app-DxivpfYG.css +0 -2
- package/dist/dashboard/assets/app-DxivpfYG.css.gz +0 -0
- package/dist/dashboard/assets/assert-NHwYq95t.js.gz +0 -0
- package/dist/dashboard/assets/badge-6uzDDvqs.js.gz +0 -0
- package/dist/dashboard/assets/banner-4_WNg2WZ.js.gz +0 -0
- package/dist/dashboard/assets/card--AtFedAq.js.gz +0 -0
- package/dist/dashboard/assets/cli-tools-B3e7dx3N.js.gz +0 -0
- package/dist/dashboard/assets/clipboard-button-NreUx6c8.js.gz +0 -0
- package/dist/dashboard/assets/dialog-BtpsJU98.js.gz +0 -0
- package/dist/dashboard/assets/download-A0SW9OCW.js +0 -1
- package/dist/dashboard/assets/download-A0SW9OCW.js.gz +0 -0
- package/dist/dashboard/assets/drawer-WwwtzihF.js.gz +0 -0
- package/dist/dashboard/assets/entry-CkryrIea.js +0 -4
- package/dist/dashboard/assets/entry-CkryrIea.js.gz +0 -0
- package/dist/dashboard/assets/entry-TJIye_jT.js +0 -1
- package/dist/dashboard/assets/entry-TJIye_jT.js.gz +0 -0
- package/dist/dashboard/assets/entry-jy9_4-Ke.js +0 -1
- package/dist/dashboard/assets/entry-jy9_4-Ke.js.gz +0 -0
- package/dist/dashboard/assets/github-badge-D_eM3IgG.js.gz +0 -0
- package/dist/dashboard/assets/index-BydyKaDz.js.gz +0 -0
- package/dist/dashboard/assets/inline-BcNGF8Gr.js.gz +0 -0
- package/dist/dashboard/assets/input-BG41et9G.js.gz +0 -0
- package/dist/dashboard/assets/layout-C8mer_Ak.js.gz +0 -0
- package/dist/dashboard/assets/list-row-Gh_W4OR_.js.gz +0 -0
- package/dist/dashboard/assets/live-BJGYRBnR.js.gz +0 -0
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js +0 -1
- package/dist/dashboard/assets/model-bans-DeVLDA7I.js.gz +0 -0
- package/dist/dashboard/assets/mutation-BkoLM5Ba.js.gz +0 -0
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js +0 -2
- package/dist/dashboard/assets/numbers-Bs4LOOuf.js.gz +0 -0
- package/dist/dashboard/assets/routing-CcusqXA7.js.gz +0 -0
- package/dist/dashboard/assets/select-BO6h8yNv.js.gz +0 -0
- package/dist/dashboard/assets/settings-mpmXTgUa.js.gz +0 -0
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js +0 -1
- package/dist/dashboard/assets/sparkles-BRaRUxAU.js.gz +0 -0
- package/dist/dashboard/assets/stack-DwLmjUFK.js.gz +0 -0
- package/dist/dashboard/assets/state-DYdQmdAl.js.gz +0 -0
- package/dist/dashboard/assets/switch-CidSfbG7.js +0 -1
- package/dist/dashboard/assets/switch-CidSfbG7.js.gz +0 -0
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js +0 -1
- package/dist/dashboard/assets/terminal-Bd4ee8TA.js.gz +0 -0
- package/dist/dashboard/assets/useMutation-w4u4CVue.js.gz +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js → app-DCQZRmHY.js} +0 -0
- /package/dist/dashboard/assets/{app-CafWtVXA.js.gz → app-DCQZRmHY.js.gz} +0 -0
|
@@ -1,164 +1,181 @@
|
|
|
1
|
-
// Network-pool control-plane HTTP routes. The only module that touches Elysia.
|
|
2
|
-
import { Elysia, t } from "elysia";
|
|
3
|
-
import { consoleErrorHandler } from "../../shared/errors";
|
|
4
|
-
import { literalUnion } from "../../shared/elysia-schema";
|
|
5
|
-
import { RELAY_TARGETS, type RelayDeployRequest } from "./relay-deploy";
|
|
6
|
-
import { RELAY_REGIONS } from "./relay-regions";
|
|
7
|
-
import { SPEED_TEST_DEFAULT_BYTES } from "./speed-test-sizes";
|
|
8
|
-
import {
|
|
9
|
-
MAX_BATCH_PROBE_TARGETS,
|
|
10
|
-
POOL_KINDS,
|
|
11
|
-
POOL_ROUTING_STRATEGIES,
|
|
12
|
-
POOL_STATUSES,
|
|
13
|
-
type CreateNetworkPoolRequest,
|
|
14
|
-
type NetworkPoolConfig,
|
|
15
|
-
type PoolStrategySetting,
|
|
16
|
-
} from "./contracts";
|
|
17
|
-
import { createNetworkPoolOperations } from "./operations";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
family
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
region
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.
|
|
64
|
-
return await factory.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
return await factory.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
})
|
|
76
|
-
.post("
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.
|
|
91
|
-
return await factory.
|
|
92
|
-
})
|
|
93
|
-
.post(
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
);
|
|
109
|
-
})
|
|
110
|
-
.post(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
1
|
+
// Network-pool control-plane HTTP routes. The only module that touches Elysia.
|
|
2
|
+
import { Elysia, t } from "elysia";
|
|
3
|
+
import { consoleErrorHandler } from "../../shared/errors";
|
|
4
|
+
import { literalUnion } from "../../shared/elysia-schema";
|
|
5
|
+
import { RELAY_TARGETS, type RelayDeployRequest } from "./relay-deploy";
|
|
6
|
+
import { RELAY_REGIONS } from "./relay-regions";
|
|
7
|
+
import { SPEED_TEST_DEFAULT_BYTES } from "./speed-test-sizes";
|
|
8
|
+
import {
|
|
9
|
+
MAX_BATCH_PROBE_TARGETS,
|
|
10
|
+
POOL_KINDS,
|
|
11
|
+
POOL_ROUTING_STRATEGIES,
|
|
12
|
+
POOL_STATUSES,
|
|
13
|
+
type CreateNetworkPoolRequest,
|
|
14
|
+
type NetworkPoolConfig,
|
|
15
|
+
type PoolStrategySetting,
|
|
16
|
+
} from "./contracts";
|
|
17
|
+
import { createNetworkPoolOperations } from "./operations";
|
|
18
|
+
import { parseProxyFile } from "./import-parse";
|
|
19
|
+
|
|
20
|
+
const poolKindSchema = literalUnion(POOL_KINDS);
|
|
21
|
+
const createPoolBody = t.Object({
|
|
22
|
+
kind: poolKindSchema,
|
|
23
|
+
label: t.Optional(t.String()),
|
|
24
|
+
endpoint: t.String(),
|
|
25
|
+
credential: t.Optional(t.String()),
|
|
26
|
+
maxInflight: t.Optional(t.Number()),
|
|
27
|
+
weight: t.Optional(t.Number()),
|
|
28
|
+
status: t.Optional(literalUnion(POOL_STATUSES)),
|
|
29
|
+
config: t.Optional(t.Record(t.String(), t.Unknown())),
|
|
30
|
+
/** Egress allowance in bytes; `null` clears it back to unmetered. */
|
|
31
|
+
quotaBytes: t.Optional(t.Union([t.Number({ minimum: 1 }), t.Null()])),
|
|
32
|
+
/** Operator-set family/tag naming which family this node belongs to. */
|
|
33
|
+
family: t.Optional(t.Union([t.String(), t.Null()])),
|
|
34
|
+
});
|
|
35
|
+
const deployRelayBody = t.Object({
|
|
36
|
+
target: literalUnion(RELAY_TARGETS),
|
|
37
|
+
token: t.String({ minLength: 1 }),
|
|
38
|
+
accountId: t.Optional(t.String()),
|
|
39
|
+
projectName: t.Optional(t.String()),
|
|
40
|
+
/** Vercel function region; ignored for targets that have no region control. */
|
|
41
|
+
region: t.Optional(literalUnion(RELAY_REGIONS)),
|
|
42
|
+
});
|
|
43
|
+
const testBatchBody = t.Object({
|
|
44
|
+
targets: t.Array(createPoolBody, { minItems: 1, maxItems: MAX_BATCH_PROBE_TARGETS }),
|
|
45
|
+
});
|
|
46
|
+
const updatePoolBody = t.Partial(createPoolBody);
|
|
47
|
+
/**
|
|
48
|
+
* A pasted proxy list. `content` is the file's text; the shapes accepted are
|
|
49
|
+
* documented on {@link parseProxyFile}. `maxInflight` and `weight` apply to
|
|
50
|
+
* every imported row, because a file carries no per-row tuning.
|
|
51
|
+
*/
|
|
52
|
+
const importPoolsBody = t.Object({
|
|
53
|
+
content: t.String({ minLength: 1 }),
|
|
54
|
+
maxInflight: t.Optional(t.Number()),
|
|
55
|
+
weight: t.Optional(t.Number()),
|
|
56
|
+
family: t.Optional(t.Union([t.String(), t.Null()])),
|
|
57
|
+
labelPrefix: t.Optional(t.String()),
|
|
58
|
+
});
|
|
59
|
+
export function createNetworkPoolRoutes(config: NetworkPoolConfig): Elysia {
|
|
60
|
+
const factory = createNetworkPoolOperations(config);
|
|
61
|
+
return new Elysia({ prefix: "/network/pools" })
|
|
62
|
+
.error(consoleErrorHandler("Network pool operation failed"))
|
|
63
|
+
.get("/", async ({ request }) => {
|
|
64
|
+
return await factory.listPools(config.accessResolver(request));
|
|
65
|
+
})
|
|
66
|
+
.get("/:poolId", async ({ request, params }) => {
|
|
67
|
+
return await factory.getPoolDetail(config.accessResolver(request), params.poolId);
|
|
68
|
+
})
|
|
69
|
+
.post("/", { body: createPoolBody }, async ({ request, body, set }) => {
|
|
70
|
+
set.status = 201;
|
|
71
|
+
return await factory.createPool(
|
|
72
|
+
config.accessResolver(request),
|
|
73
|
+
body as CreateNetworkPoolRequest,
|
|
74
|
+
);
|
|
75
|
+
})
|
|
76
|
+
.post("/import", { body: importPoolsBody }, async ({ request, body, set }) => {
|
|
77
|
+
set.status = 200;
|
|
78
|
+
return await factory.importPools(config.accessResolver(request), body);
|
|
79
|
+
})
|
|
80
|
+
.patch("/:poolId", { body: updatePoolBody }, async ({ request, params, body }) => {
|
|
81
|
+
return await factory.updatePool(
|
|
82
|
+
config.accessResolver(request),
|
|
83
|
+
params.poolId,
|
|
84
|
+
body as Partial<CreateNetworkPoolRequest>,
|
|
85
|
+
);
|
|
86
|
+
})
|
|
87
|
+
.delete("/:poolId", async ({ request, params }) => {
|
|
88
|
+
return await factory.deletePool(config.accessResolver(request), params.poolId);
|
|
89
|
+
})
|
|
90
|
+
.get("/:poolId/health-events", async ({ request, params }) => {
|
|
91
|
+
return await factory.listPoolHealthEvents(config.accessResolver(request), params.poolId);
|
|
92
|
+
})
|
|
93
|
+
.post("/:poolId/recover", async ({ request, params }) => {
|
|
94
|
+
return await factory.recoverPool(config.accessResolver(request), params.poolId);
|
|
95
|
+
})
|
|
96
|
+
.post(
|
|
97
|
+
"/:poolId/provider-probe",
|
|
98
|
+
{ body: t.Object({ providerId: t.String() }) },
|
|
99
|
+
async ({ request, params, body }) => {
|
|
100
|
+
return await factory.providerProbe(
|
|
101
|
+
config.accessResolver(request),
|
|
102
|
+
params.poolId,
|
|
103
|
+
body.providerId,
|
|
104
|
+
);
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
.post("/:poolId/health-check", async ({ request, params }) => {
|
|
108
|
+
return await factory.healthCheck(config.accessResolver(request), params.poolId);
|
|
109
|
+
})
|
|
110
|
+
.post(
|
|
111
|
+
"/:poolId/speed-test",
|
|
112
|
+
{ body: t.Optional(t.Object({ bytes: t.Optional(t.Number()) })) },
|
|
113
|
+
async ({ request, params, body }) => {
|
|
114
|
+
return await factory.speedTest(
|
|
115
|
+
config.accessResolver(request),
|
|
116
|
+
params.poolId,
|
|
117
|
+
body?.bytes ?? SPEED_TEST_DEFAULT_BYTES,
|
|
118
|
+
);
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
.post("/test", { body: createPoolBody }, async ({ request, body }) => {
|
|
122
|
+
return await factory.probeAdHocPool(
|
|
123
|
+
config.accessResolver(request),
|
|
124
|
+
body as CreateNetworkPoolRequest,
|
|
125
|
+
);
|
|
126
|
+
})
|
|
127
|
+
.post("/test-batch", { body: testBatchBody }, async ({ request, body }) => {
|
|
128
|
+
return await factory.probeAdHocPoolBatch(
|
|
129
|
+
config.accessResolver(request),
|
|
130
|
+
body.targets as CreateNetworkPoolRequest[],
|
|
131
|
+
);
|
|
132
|
+
})
|
|
133
|
+
.post(
|
|
134
|
+
"/test-batch/provider",
|
|
135
|
+
{
|
|
136
|
+
body: t.Object({
|
|
137
|
+
providerId: t.String(),
|
|
138
|
+
targets: t.Array(createPoolBody, { minItems: 1, maxItems: MAX_BATCH_PROBE_TARGETS }),
|
|
139
|
+
}),
|
|
140
|
+
},
|
|
141
|
+
async ({ request, body }) => {
|
|
142
|
+
return await factory.probeAdHocProviderBatch(
|
|
143
|
+
config.accessResolver(request),
|
|
144
|
+
body.targets as CreateNetworkPoolRequest[],
|
|
145
|
+
body.providerId,
|
|
146
|
+
);
|
|
147
|
+
},
|
|
148
|
+
)
|
|
149
|
+
.post(
|
|
150
|
+
"/:poolId/cooldowns/clear",
|
|
151
|
+
{ body: t.Optional(t.Object({ providerId: t.Optional(t.String()) })) },
|
|
152
|
+
async ({ request, params, body }) => {
|
|
153
|
+
return await factory.clearPoolCooldown(
|
|
154
|
+
config.accessResolver(request),
|
|
155
|
+
params.poolId,
|
|
156
|
+
body?.providerId,
|
|
157
|
+
);
|
|
158
|
+
},
|
|
159
|
+
)
|
|
160
|
+
.post("/relay/deploy", { body: deployRelayBody }, async ({ request, body }) => {
|
|
161
|
+
return await factory.deployRelay(config.accessResolver(request), body as RelayDeployRequest);
|
|
162
|
+
})
|
|
163
|
+
.get("/strategy", async ({ request }) => {
|
|
164
|
+
return await factory.getStrategy(config.accessResolver(request));
|
|
165
|
+
})
|
|
166
|
+
.patch(
|
|
167
|
+
"/strategy",
|
|
168
|
+
{
|
|
169
|
+
body: t.Object({
|
|
170
|
+
strategy: t.Optional(literalUnion(POOL_ROUTING_STRATEGIES)),
|
|
171
|
+
rotateCount: t.Optional(t.Number()),
|
|
172
|
+
}),
|
|
173
|
+
},
|
|
174
|
+
async ({ request, body }) => {
|
|
175
|
+
return await factory.updateStrategy(
|
|
176
|
+
config.accessResolver(request),
|
|
177
|
+
body as Partial<PoolStrategySetting>,
|
|
178
|
+
);
|
|
179
|
+
},
|
|
180
|
+
) as unknown as Elysia;
|
|
181
|
+
}
|
|
@@ -26,6 +26,19 @@ export interface RuntimeSettingsResponse {
|
|
|
26
26
|
readonly ponyTailEnabled: boolean;
|
|
27
27
|
/** PonyTail directive intensity; `full` by default. */
|
|
28
28
|
readonly ponyTailLevel: PonyTailLevel;
|
|
29
|
+
/**
|
|
30
|
+
* Ignores an account-wide cooldown when building route candidates. Off by
|
|
31
|
+
* default: dialing a cooled-down account reproduces the refusal that parked
|
|
32
|
+
* it, and can exhaust the candidate list. Overrides nothing else — the
|
|
33
|
+
* cooldown is still recorded and still recovered by the sweep.
|
|
34
|
+
*/
|
|
35
|
+
readonly forceDisableCooldown: boolean;
|
|
36
|
+
/** Per-tenant upstream request timeout in seconds; null means deployment default. */
|
|
37
|
+
readonly upstreamTimeoutSeconds: number | null;
|
|
38
|
+
/** Per-tenant telemetry compaction age in days; null means deployment default. */
|
|
39
|
+
readonly telemetryWindowMinutes: number | null;
|
|
40
|
+
/** Per-tenant inline attachment ceiling in bytes; null means deployment default. */
|
|
41
|
+
readonly imageClampMaxBytes: number | null;
|
|
29
42
|
readonly updatedAt: string;
|
|
30
43
|
}
|
|
31
44
|
|
|
@@ -150,4 +163,28 @@ export const runtimeUpdateBody = t.Object({
|
|
|
150
163
|
rtkPruneLevel: t.Optional(literalUnion(RTK_LEVELS)),
|
|
151
164
|
ponyTailEnabled: t.Optional(t.Boolean()),
|
|
152
165
|
ponyTailLevel: t.Optional(literalUnion(PONYTAIL_LEVELS)),
|
|
166
|
+
/*
|
|
167
|
+
* Operational overrides. Every field a caller may patch must appear here:
|
|
168
|
+
* this schema is what the route parses the body against, and a key it does
|
|
169
|
+
* not name is dropped before the store sees it. These four were added to the
|
|
170
|
+
* request type and the store but never to this object, so a save returned
|
|
171
|
+
* 200 and changed nothing — the mutation's toast fired while the stored
|
|
172
|
+
* value stayed put.
|
|
173
|
+
*
|
|
174
|
+
* `t.Null()` is what "Deployment default" sends, and it must survive:
|
|
175
|
+
* clearing an override is a real edit, not an absent one.
|
|
176
|
+
*
|
|
177
|
+
* The bounds mirror the store's own normalizers, so an out-of-range value is
|
|
178
|
+
* rejected here rather than silently clamped on the way in.
|
|
179
|
+
*/
|
|
180
|
+
forceDisableCooldown: t.Optional(t.Boolean()),
|
|
181
|
+
upstreamTimeoutSeconds: t.Optional(
|
|
182
|
+
t.Union([t.Null(), t.Number({ minimum: 5, maximum: 600 })]),
|
|
183
|
+
),
|
|
184
|
+
telemetryWindowMinutes: t.Optional(
|
|
185
|
+
t.Union([t.Null(), t.Number({ minimum: 1, maximum: 1440 })]),
|
|
186
|
+
),
|
|
187
|
+
imageClampMaxBytes: t.Optional(
|
|
188
|
+
t.Union([t.Null(), t.Number({ minimum: 64 * 1024, maximum: 100 * 1024 * 1024 })]),
|
|
189
|
+
),
|
|
153
190
|
});
|
|
@@ -68,6 +68,43 @@ function normalizeTelemetryPayloadDepth(value: unknown): TelemetryPayloadDepth {
|
|
|
68
68
|
return "minimum";
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/**
|
|
72
|
+
* Bounds a per-tenant numeric override, or `null` for "use the default".
|
|
73
|
+
*
|
|
74
|
+
* Clamped rather than rejected: these are operational knobs an operator tunes
|
|
75
|
+
* live, and a PATCH that throws on an out-of-range value leaves them stuck at
|
|
76
|
+
* whatever was stored. Clamping keeps the value inside the range the request
|
|
77
|
+
* path can actually honour — the same range the deployment env var accepts.
|
|
78
|
+
*
|
|
79
|
+
* `null` (and every non-finite value) means "no override", which is distinct
|
|
80
|
+
* from "override with zero".
|
|
81
|
+
*/
|
|
82
|
+
function normalizeBoundedNumber(value: unknown, min: number, max: number): number | null {
|
|
83
|
+
if (value === null || value === undefined) return null;
|
|
84
|
+
const parsed = typeof value === "number" ? value : Number(value);
|
|
85
|
+
if (!Number.isFinite(parsed)) return null;
|
|
86
|
+
// A value at or below zero is not a setting, it is a typo: clamping it to
|
|
87
|
+
// the floor would silently give the request a 5-second budget when the
|
|
88
|
+
// operator meant "no override". Non-positive therefore reads as absent.
|
|
89
|
+
if (parsed <= 0) return null;
|
|
90
|
+
return Math.min(max, Math.max(min, Math.floor(parsed)));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Upstream timeout in seconds: 5 s floor, 600 s ceiling, matching the env var. */
|
|
94
|
+
function normalizeUpstreamTimeoutSeconds(value: unknown): number | null {
|
|
95
|
+
return normalizeBoundedNumber(value, 5, 600);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Source window in minutes: 1 floor, 1440 (one day) ceiling, matching the env var. */
|
|
99
|
+
function normalizeTelemetryWindowMinutes(value: unknown): number | null {
|
|
100
|
+
return normalizeBoundedNumber(value, 1, 1440);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Inline attachment ceiling in bytes: 64 KB floor, 100 MB ceiling. */
|
|
104
|
+
function normalizeImageClampMaxBytes(value: unknown): number | null {
|
|
105
|
+
return normalizeBoundedNumber(value, 64 * 1024, 100 * 1024 * 1024);
|
|
106
|
+
}
|
|
107
|
+
|
|
71
108
|
function mapRuntimeSettingsRow(
|
|
72
109
|
row: typeof consoleSettings.$inferSelect | undefined,
|
|
73
110
|
redisBackend: RedisBackend,
|
|
@@ -95,6 +132,10 @@ function mapRuntimeSettingsRow(
|
|
|
95
132
|
// requires the flag — never injected it.
|
|
96
133
|
ponyTailEnabled: prefs.ponyTailEnabled === true,
|
|
97
134
|
ponyTailLevel: normalizePonyTailLevel(prefs.ponyTailLevel),
|
|
135
|
+
forceDisableCooldown: prefs.forceDisableCooldown === true,
|
|
136
|
+
upstreamTimeoutSeconds: normalizeUpstreamTimeoutSeconds(prefs.upstreamTimeoutSeconds),
|
|
137
|
+
telemetryWindowMinutes: normalizeTelemetryWindowMinutes(prefs.telemetryWindowMinutes),
|
|
138
|
+
imageClampMaxBytes: normalizeImageClampMaxBytes(prefs.imageClampMaxBytes),
|
|
98
139
|
updatedAt,
|
|
99
140
|
};
|
|
100
141
|
}
|
|
@@ -133,6 +174,16 @@ export class DrizzleRuntimeSettingsStore implements RuntimeSettingsStore {
|
|
|
133
174
|
if (patch.rtkPruneLevel !== undefined) patchPrefs.rtkPruneLevel = patch.rtkPruneLevel;
|
|
134
175
|
if (patch.ponyTailEnabled !== undefined) patchPrefs.ponyTailEnabled = patch.ponyTailEnabled;
|
|
135
176
|
if (patch.ponyTailLevel !== undefined) patchPrefs.ponyTailLevel = patch.ponyTailLevel;
|
|
177
|
+
if (patch.forceDisableCooldown !== undefined)
|
|
178
|
+
patchPrefs.forceDisableCooldown = patch.forceDisableCooldown === true;
|
|
179
|
+
if (patch.upstreamTimeoutSeconds !== undefined)
|
|
180
|
+
patchPrefs.upstreamTimeoutSeconds = normalizeUpstreamTimeoutSeconds(patch.upstreamTimeoutSeconds);
|
|
181
|
+
if (patch.telemetryWindowMinutes !== undefined)
|
|
182
|
+
patchPrefs.telemetryWindowMinutes = normalizeTelemetryWindowMinutes(
|
|
183
|
+
patch.telemetryWindowMinutes,
|
|
184
|
+
);
|
|
185
|
+
if (patch.imageClampMaxBytes !== undefined)
|
|
186
|
+
patchPrefs.imageClampMaxBytes = normalizeImageClampMaxBytes(patch.imageClampMaxBytes);
|
|
136
187
|
|
|
137
188
|
const rows = await this.db
|
|
138
189
|
.insert(consoleSettings)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Elysia } from "elysia";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
2
3
|
import { consoleErrorHandler, requireTenantScope } from "../shared/errors";
|
|
3
4
|
import { consoleSseResponse, createConsoleSseStream } from "../observability/sse";
|
|
4
5
|
import type { ObservabilityStore } from "../observability/contracts";
|
|
@@ -86,6 +87,21 @@ export function createUpdateRoutes(config: {
|
|
|
86
87
|
return new Elysia()
|
|
87
88
|
.error(consoleErrorHandler("Update check failed"))
|
|
88
89
|
.get("/updates/release", async () => await fetchRelease())
|
|
90
|
+
.post("/updates/apply", ({ request }) => {
|
|
91
|
+
requireTenantScope(config.accessResolver(request), "dashboard:write");
|
|
92
|
+
const isWin = process.platform === "win32";
|
|
93
|
+
const shell = isWin ? "cmd.exe" : "/bin/sh";
|
|
94
|
+
const install = "npm install -g cartethyia@latest --prefer-online";
|
|
95
|
+
const restart = isWin
|
|
96
|
+
? "cartethyia start"
|
|
97
|
+
: "systemctl restart cartethyia 2>/dev/null || cartethyia start";
|
|
98
|
+
const script = `${install} && ${restart}`;
|
|
99
|
+
const args = isWin ? ["/c", script] : ["-c", script];
|
|
100
|
+
const child = spawn(shell, args, { detached: true, stdio: "ignore" });
|
|
101
|
+
child.unref();
|
|
102
|
+
setTimeout(() => process.exit(0), 1500);
|
|
103
|
+
return { started: true };
|
|
104
|
+
})
|
|
89
105
|
.get("/notifications/stream", ({ request }) => {
|
|
90
106
|
const tenantId = requireTenantScope(
|
|
91
107
|
config.accessResolver(request),
|
package/src/main.ts
CHANGED
|
@@ -68,6 +68,16 @@ const app = boot
|
|
|
68
68
|
admissionService: boot.deps.admissionService,
|
|
69
69
|
modelStrikes: boot.deps.modelStrikes,
|
|
70
70
|
readRoutingAccountInflight: boot.deps.readRoutingAccountInflight,
|
|
71
|
+
// The same three writers the shutdown coordinator drains, so a manual
|
|
72
|
+
// flush from the console does exactly what a graceful stop would do
|
|
73
|
+
// for the queues, minus the stop.
|
|
74
|
+
flushBuffers: {
|
|
75
|
+
flush: async () => {
|
|
76
|
+
await boot.deps.telemetryBuffer.flush();
|
|
77
|
+
await boot.deps.usageFlush.flush();
|
|
78
|
+
await boot.deps.healthEventFlush.flush();
|
|
79
|
+
},
|
|
80
|
+
},
|
|
71
81
|
},
|
|
72
82
|
})
|
|
73
83
|
: createGatewayShell();
|