@undefineds.co/xpod 0.4.3 → 0.4.5
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/config/cloud.json +1 -1
- package/config/main.json +36 -2
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +3 -0
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +2 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +101 -32
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.d.ts +80 -0
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.js +3 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +38 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +63 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.d.ts +24 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.js +136 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.js +2 -1
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.d.ts +17 -13
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.js +52 -19
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.d.ts +4 -28
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.js +7 -58
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.d.ts +4 -0
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.js +116 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +10 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.js +112 -0
- package/dist/api/ai-gateway/connect/index.d.ts +125 -23
- package/dist/api/ai-gateway/connect/index.js +1277 -260
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +4 -1
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +154 -19
- package/dist/api/ai-gateway/providers/DeepSeekRuntimeAdapter.js +10 -6
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -0
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +25 -1
- package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +24 -0
- package/dist/api/ai-gateway/providers/OfferingAuthorization.js +37 -0
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.d.ts +1 -1
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.js +5 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +6 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +55 -16
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.js +37 -4
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +7 -0
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +2 -1
- package/dist/api/ai-gateway/routing/ModelRouter.js +3 -1
- package/dist/api/container/common.js +30 -40
- package/dist/api/container/index.js +6 -2
- package/dist/api/container/routes.js +5 -22
- package/dist/api/handlers/AiClientConfigurationHandler.js +39 -1
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +3 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +173 -58
- package/dist/api/service/AiClientConfigurationService.d.ts +4 -15
- package/dist/api/service/AiClientConfigurationService.js +17 -64
- package/dist/cli/commands/start.js +2 -0
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +80 -0
- package/dist/http/InternalPodDataHttpHandler.d.ts +3 -0
- package/dist/http/InternalPodDataHttpHandler.js +13 -2
- package/dist/http/InternalPodDataHttpHandler.jsonld +12 -0
- package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +1 -1
- package/dist/identity/oidc/RememberedClientPromptFactory.js +5 -2
- package/dist/identity/oidc/RememberedConsentHandler.js +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +1 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +26 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +4 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.d.ts +10 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.js +21 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.jsonld +172 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/runtime/component-parameter-keys.js +18 -2
- package/dist/storage/accessors/MixDataAccessor.js +6 -2
- package/dist/storage/rdf/PostgresRdfEngine.js +10 -2
- package/dist/storage/rdf/RdfContentTypes.js +4 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +3 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -16
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +1 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +127 -57
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +436 -83
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +212 -76
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +58 -41
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.js +63 -4
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +46 -6
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +143 -14
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +19 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +45 -7
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.d.ts +7 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.js +305 -40
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +383 -50
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/json-env-adapter.js +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/pi.js +12 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.js +39 -4
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/types.d.ts +8 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.js +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +216 -57
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +3 -1
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +16 -2
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +6 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +31 -0
- package/package.json +2 -2
- package/static/app/assets/{index-BikOyGPu.js → index-BCZVzMpj.js} +44 -44
- package/static/app/assets/inrupt-smoke.js +2 -2
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +10 -10
- package/static/auth-callback/assets/{AiConfigContext-DrCH6ckh.js → AiConfigContext-DVkh8Kg2.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DVrlSSdA.js → AiConfigPage-HWVWpe-P.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-_Md-v2R2.js → DocumentProcessingPanel-DDq-mH17.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-BbWwe23H.js → IndexLifecyclePanel-Cx4cjrdP.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-upH9MjU-.js → IndexSubjectPanel-DzSw8M9j.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-CVGH4t4g.js → ModelAssignmentsPanel-BsRxGc2p.js} +1 -1
- package/static/auth-callback/assets/ModelsPage-DEe1lo6Q.js +10 -0
- package/static/auth-callback/assets/{NetworkPage-Dcbrb1fd.js → NetworkPage-DBiEh1Oz.js} +1 -1
- package/static/auth-callback/assets/{PaneListHeader-DrY-1wBq.js → PaneListHeader-lEEgjyN9.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-Dw25y53v.js → SearchIndexingPanel-CZCUUGt6.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-BHlz9rNF.js → StatusSubjectPanel-21qdueMr.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-BH7exQP5.js → StatusWorkspace-R8RKsqVz.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BYLKnM9f.js → SystemSettingsPage-BQ4e-4Wy.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DT34LKku.js → SystemSettingsSubjectPanel-BopXD7SE.js} +1 -1
- package/static/auth-callback/assets/{activity-DdULRcSI.js → activity-DSfmTGfY.js} +1 -1
- package/static/auth-callback/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/auth-callback/assets/{auth-callback-D7l2P25I.js → auth-callback-DleaitAS.js} +91 -91
- package/static/auth-callback/assets/auth-callback-vPSC2d2F.css +1 -0
- package/static/auth-callback/assets/{badge-j4zjFnmg.js → badge-B0aLu1sl.js} +1 -1
- package/static/auth-callback/assets/{download-DGXoks01.js → download-D_bFwdYJ.js} +1 -1
- package/static/auth-callback/assets/{external-link-CvbgXXaI.js → external-link-DRfjTaQu.js} +1 -1
- package/static/auth-callback/assets/{index-LRWvKJ2i.js → index-CG23cLYQ.js} +1 -1
- package/static/auth-callback/assets/{index-BOK3j1dz.js → index-CyV9ejwx.js} +1 -1
- package/static/auth-callback/assets/{index-browser-C1Qpe0g4.js → index-browser-D70paxIg.js} +1 -1
- package/static/auth-callback/assets/{key-round-CmgS5UdQ.js → key-round-BjV_mVYH.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-c4CSG6Rq.js → rotate-ccw-CKoOAfse.js} +1 -1
- package/static/auth-callback/assets/{skeleton-ZPMTiRSM.js → skeleton-BZNjZaHx.js} +1 -1
- package/static/auth-callback/assets/{waypoints-xjyBflU5.js → waypoints-DoaJVzZv.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-B9nj6F5J.js → workspace-layout-CaP46_ZR.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BWOOSYNr.js → AiConfigContext-BSrR27yD.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-CG2kQ9Wy.js → AiConfigPage-D65Z2LET.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-B4VXajfj.js → DocumentProcessingPanel-DyTe7Nei.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-CWCy0CC8.js → IndexLifecyclePanel-fK8ZGlrL.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-CSgyQnG_.js → IndexSubjectPanel-CZPGor7v.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-CdGIGidT.js → ModelAssignmentsPanel-CfYn5LMQ.js} +1 -1
- package/static/dashboard/assets/ModelsPage-djlJsghe.js +25 -0
- package/static/dashboard/assets/{NetworkPage-COia9NCH.js → NetworkPage-Coj6GnPl.js} +1 -1
- package/static/dashboard/assets/{PaneListHeader-SZWyr602.js → PaneListHeader-CUuFNSsZ.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-D6PZtG6k.js → SearchIndexingPanel-CyJLioXS.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-CxRD4kv0.js → StatusSubjectPanel-Cv26GSVC.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-D3PfmY9-.js → StatusWorkspace-CDjFrsmB.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-COg1MmMj.js → SystemSettingsPage-BuNOyNoa.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-BSVVB9Ol.js → SystemSettingsSubjectPanel-B2dasdez.js} +1 -1
- package/static/dashboard/assets/{activity-BJJx5cN-.js → activity-D1d2j_4Z.js} +1 -1
- package/static/dashboard/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/dashboard/assets/{badge-elmrFSCj.js → badge-BeAAv6sp.js} +1 -1
- package/static/dashboard/assets/{dashboard-IvQrNmru.js → dashboard-BnGrUGv8.js} +68 -68
- package/static/dashboard/assets/dashboard-vPSC2d2F.css +1 -0
- package/static/dashboard/assets/{download-C3FH2KzG.js → download-DfFGiZRn.js} +1 -1
- package/static/dashboard/assets/{external-link-Bx7F0uKb.js → external-link-IsjU_LC9.js} +1 -1
- package/static/dashboard/assets/{index-liRoRIP1.js → index-BWQTucPe.js} +1 -1
- package/static/dashboard/assets/{index-M4-kWiGz.js → index-Dj75OjnW.js} +1 -1
- package/static/dashboard/assets/{key-round-CXg0bKAj.js → key-round-BJ_9wmQ_.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-yxJKOBrX.js → rotate-ccw-D3JGiFbR.js} +1 -1
- package/static/dashboard/assets/{skeleton-x9jNGrQT.js → skeleton-CC4nc-z-.js} +1 -1
- package/static/dashboard/assets/{waypoints-CTKeRsGp.js → waypoints-h7sqFqiG.js} +1 -1
- package/static/dashboard/assets/{workspace-layout--YkgkS38.js → workspace-layout-ZAPTOHhs.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-CelxXFcQ.js → AiConfigContext-lGkWpvKP.js} +1 -1
- package/static/settings/assets/{AiConfigPage-BaP-EovM.js → AiConfigPage-BbZWIBZq.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-DzLZluFv.js → DocumentProcessingPanel-DvYdjT-V.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-Bzj1-_oI.js → IndexLifecyclePanel-W5OGQZj7.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-B263QLUh.js → IndexSubjectPanel-g_Aa5soq.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BAdT4UR0.js → ModelAssignmentsPanel-COlMBKXj.js} +1 -1
- package/static/settings/assets/ModelsPage-mApKi-aw.js +10 -0
- package/static/settings/assets/{NetworkPage-BK6a7l4g.js → NetworkPage-BDT05JUq.js} +1 -1
- package/static/settings/assets/{PaneListHeader-BAS2ICPq.js → PaneListHeader-CByhNpMG.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-Cb_p-NgW.js → SearchIndexingPanel-BFAyzXls.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CcjqUua6.js → StatusSubjectPanel-Bz_XZ3VU.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-7Ibty3_k.js → StatusWorkspace-CeVypHcW.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-DPSz4dg4.js → SystemSettingsPage-Dh7cQIfx.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-Cb4HkKT5.js → SystemSettingsSubjectPanel-CSnpciO0.js} +1 -1
- package/static/settings/assets/{activity-Qhsr5Pxu.js → activity-DXz3EfFN.js} +1 -1
- package/static/settings/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/settings/assets/{badge-B1vf2qCl.js → badge-1ZA144i4.js} +1 -1
- package/static/settings/assets/{download-CYNt0aZ-.js → download-CUHimlYa.js} +1 -1
- package/static/settings/assets/{external-link-ClKb39NT.js → external-link-BYHSVj2Z.js} +1 -1
- package/static/settings/assets/{index-y8ew3MLM.js → index-DKPDMdW5.js} +1 -1
- package/static/settings/assets/{index-browser-DJhvgpNI.js → index-browser-BaEFz0e0.js} +1 -1
- package/static/settings/assets/{index-BgiIDSch.js → index-viSgSvbO.js} +1 -1
- package/static/settings/assets/{key-round-5d-DrJz-.js → key-round-COByPOg8.js} +1 -1
- package/static/settings/assets/{rotate-ccw-CHZY7kS5.js → rotate-ccw-BC2EN6cE.js} +1 -1
- package/static/settings/assets/{settings-D5VRWyx6.js → settings-DLH9XUoT.js} +86 -86
- package/static/settings/assets/settings-vPSC2d2F.css +1 -0
- package/static/settings/assets/{skeleton-FNabNxNE.js → skeleton-B0-FOhKL.js} +1 -1
- package/static/settings/assets/{waypoints-BnL_8ljo.js → waypoints-DGMsvqWo.js} +1 -1
- package/static/settings/assets/{workspace-layout-D5q3F59S.js → workspace-layout-B0SVrJIu.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/static/auth-callback/assets/ModelsPage-BpkVFKbf.js +0 -10
- package/static/auth-callback/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/auth-callback/assets/auth-callback-01yz-UDU.css +0 -1
- package/static/dashboard/assets/ModelsPage-Chd5UK0D.js +0 -25
- package/static/dashboard/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/dashboard/assets/dashboard-01yz-UDU.css +0 -1
- package/static/settings/assets/ModelsPage-C0NFa1zq.js +0 -10
- package/static/settings/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/settings/assets/settings-01yz-UDU.css +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { AiConnectionsClient } from './ai-connections-client';
|
|
1
|
+
import type { AiConnectionsClient, AiGatewayModel } from './ai-connections-client';
|
|
2
2
|
import { type AiClientConfigurationBridge } from './AiClientConfigurationSection';
|
|
3
|
-
export declare function AiGatewayKeysSection({ client, clientConfigurationBridge, }: {
|
|
3
|
+
export declare function AiGatewayKeysSection({ client, clientConfigurationBridge, gatewayModels, }: {
|
|
4
4
|
client: AiConnectionsClient;
|
|
5
5
|
clientConfigurationBridge?: AiClientConfigurationBridge;
|
|
6
|
+
gatewayModels?: AiGatewayModel[];
|
|
6
7
|
}): import("react").JSX.Element;
|
|
@@ -1,68 +1,178 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import {
|
|
4
|
-
import { Copy, KeyRound, Loader2,
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Button, Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, cn, dismissToast, toast } from '@undefineds.co/shared-ui';
|
|
4
|
+
import { Check, ChevronDown, Copy, KeyRound, Loader2, Power, RefreshCw, Trash2, } from 'lucide-react';
|
|
5
5
|
import { AI_CONNECTIONS_CLIENTS, AI_CLIENT_LABELS, AiClientIcon, manualConfigurationText, } from './AiClientConfigurationSection.js';
|
|
6
6
|
const DEFAULT_KEY_NAME = '我的 API Key';
|
|
7
|
-
export function AiGatewayKeysSection({ client, clientConfigurationBridge, }) {
|
|
7
|
+
export function AiGatewayKeysSection({ client, clientConfigurationBridge, gatewayModels, }) {
|
|
8
8
|
const [keys, setKeys] = useState([]);
|
|
9
9
|
const [loading, setLoading] = useState(true);
|
|
10
10
|
const [name, setName] = useState(DEFAULT_KEY_NAME);
|
|
11
|
-
const [
|
|
11
|
+
const [showCreate, setShowCreate] = useState(false);
|
|
12
|
+
const applicationVersions = useRef({});
|
|
13
|
+
const [openMenuKeyId, setOpenMenuKeyId] = useState();
|
|
14
|
+
const [applications, setApplications] = useState({});
|
|
15
|
+
const plaintexts = useRef(new Map());
|
|
16
|
+
const operation = useRef(false);
|
|
12
17
|
const [creating, setCreating] = useState(false);
|
|
13
18
|
const [busyKeyId, setBusyKeyId] = useState();
|
|
14
|
-
const [
|
|
19
|
+
const [applying, setApplying] = useState();
|
|
15
20
|
const [error, setError] = useState();
|
|
21
|
+
const [copied, setCopied] = useState({});
|
|
22
|
+
const copyTimers = useRef(new Map());
|
|
23
|
+
const copyGeneration = useRef(0);
|
|
24
|
+
const notification = useRef(undefined);
|
|
25
|
+
const notify = useCallback((options) => {
|
|
26
|
+
if (notification.current)
|
|
27
|
+
dismissToast(notification.current);
|
|
28
|
+
notification.current = toast(options);
|
|
29
|
+
}, []);
|
|
30
|
+
const notifyError = useCallback((cause) => {
|
|
31
|
+
notify({ variant: 'destructive', description: errorMessage(cause), duration: 8000 });
|
|
32
|
+
}, [notify]);
|
|
33
|
+
const clearCopyFeedback = (keyId) => {
|
|
34
|
+
clearTimeout(copyTimers.current.get(keyId));
|
|
35
|
+
copyTimers.current.delete(keyId);
|
|
36
|
+
setCopied((current) => {
|
|
37
|
+
const next = { ...current };
|
|
38
|
+
delete next[keyId];
|
|
39
|
+
return next;
|
|
40
|
+
});
|
|
41
|
+
};
|
|
16
42
|
useEffect(() => {
|
|
17
43
|
let active = true;
|
|
44
|
+
copyGeneration.current += 1;
|
|
45
|
+
const timers = copyTimers.current;
|
|
18
46
|
setLoading(true);
|
|
19
47
|
setError(undefined);
|
|
48
|
+
setApplications({});
|
|
49
|
+
plaintexts.current.clear();
|
|
50
|
+
const versions = { ...applicationVersions.current };
|
|
20
51
|
void client.listGatewayKeys()
|
|
21
52
|
.then((records) => {
|
|
22
|
-
if (active)
|
|
23
|
-
|
|
53
|
+
if (!active)
|
|
54
|
+
return;
|
|
55
|
+
const visible = records.filter((record) => !record.revokedAt);
|
|
56
|
+
setKeys(visible);
|
|
57
|
+
if (!clientConfigurationBridge)
|
|
58
|
+
return;
|
|
59
|
+
void Promise.all(AI_CONNECTIONS_CLIENTS.map(async (clientId) => {
|
|
60
|
+
try {
|
|
61
|
+
const status = await clientConfigurationBridge.inspect(clientId);
|
|
62
|
+
if (!active || applicationVersions.current[clientId] !== versions[clientId] ||
|
|
63
|
+
status.status !== 'configured' || !status.appliedKeyFingerprint)
|
|
64
|
+
return;
|
|
65
|
+
const matches = visible.filter((record) => record.fingerprint === status.appliedKeyFingerprint);
|
|
66
|
+
if (matches.length !== 1)
|
|
67
|
+
return;
|
|
68
|
+
const keyId = matches[0].id;
|
|
69
|
+
setApplications((current) => ({ ...current, [clientId]: keyId }));
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Unavailable inspection must not infer ownership from historical metadata.
|
|
73
|
+
}
|
|
74
|
+
}));
|
|
24
75
|
})
|
|
25
76
|
.catch((cause) => {
|
|
26
77
|
if (active)
|
|
27
|
-
|
|
78
|
+
notifyError(cause);
|
|
28
79
|
})
|
|
29
80
|
.finally(() => {
|
|
30
|
-
if (active)
|
|
81
|
+
if (active) {
|
|
82
|
+
setCopied({});
|
|
83
|
+
setOpenMenuKeyId(undefined);
|
|
31
84
|
setLoading(false);
|
|
85
|
+
}
|
|
32
86
|
});
|
|
33
87
|
return () => {
|
|
34
88
|
active = false;
|
|
89
|
+
copyGeneration.current += 1;
|
|
90
|
+
timers.forEach(clearTimeout);
|
|
91
|
+
timers.clear();
|
|
92
|
+
if (notification.current)
|
|
93
|
+
dismissToast(notification.current);
|
|
35
94
|
};
|
|
36
|
-
}, [client]);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
? manualConfigurationText(selectedTarget, client.apiBase, plaintext)
|
|
40
|
-
: genericConfigurationText(client.apiBase, plaintext);
|
|
41
|
-
if (!navigator.clipboard?.writeText) {
|
|
42
|
-
throw new Error('当前浏览器无法访问剪贴板,请从下方复制新创建的 API Key。');
|
|
43
|
-
}
|
|
44
|
-
await navigator.clipboard.writeText(content);
|
|
45
|
-
};
|
|
46
|
-
const applyConfiguration = async (plaintext, selectedTarget) => {
|
|
47
|
-
if (!clientConfigurationBridge) {
|
|
48
|
-
await copyConfiguration(plaintext, selectedTarget);
|
|
95
|
+
}, [client, clientConfigurationBridge, notifyError]);
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (!openMenuKeyId)
|
|
49
98
|
return;
|
|
99
|
+
const closeOutside = (event) => {
|
|
100
|
+
const target = event.target;
|
|
101
|
+
if (target instanceof Element && target.closest('[data-client-menu]')?.getAttribute('data-client-menu') === openMenuKeyId)
|
|
102
|
+
return;
|
|
103
|
+
setOpenMenuKeyId(undefined);
|
|
104
|
+
};
|
|
105
|
+
document.addEventListener('pointerdown', closeOutside);
|
|
106
|
+
return () => document.removeEventListener('pointerdown', closeOutside);
|
|
107
|
+
}, [openMenuKeyId]);
|
|
108
|
+
const runKeyOperation = async (keyId, action) => {
|
|
109
|
+
if (operation.current)
|
|
110
|
+
return;
|
|
111
|
+
operation.current = true;
|
|
112
|
+
setBusyKeyId(keyId);
|
|
113
|
+
setError(undefined);
|
|
114
|
+
try {
|
|
115
|
+
await action();
|
|
116
|
+
}
|
|
117
|
+
catch (cause) {
|
|
118
|
+
notifyError(cause);
|
|
50
119
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
120
|
+
finally {
|
|
121
|
+
operation.current = false;
|
|
122
|
+
setBusyKeyId(undefined);
|
|
123
|
+
setApplying(undefined);
|
|
55
124
|
}
|
|
125
|
+
};
|
|
126
|
+
const applyPlan = async (keyId, plan, refresh = false) => {
|
|
127
|
+
if (!clientConfigurationBridge)
|
|
128
|
+
return;
|
|
129
|
+
setApplying({ keyId, clientId: plan.client });
|
|
130
|
+
const plaintext = plaintexts.current.get(keyId) ?? await client.revealGatewayKey(keyId);
|
|
56
131
|
await clientConfigurationBridge.apply({
|
|
57
|
-
client:
|
|
132
|
+
client: plan.client,
|
|
58
133
|
planId: plan.planId,
|
|
59
134
|
apiKey: plaintext,
|
|
135
|
+
...(plan.confirmation?.required ? { confirmation: {
|
|
136
|
+
token: plan.confirmation.token,
|
|
137
|
+
targetHash: plan.confirmation.targetHash,
|
|
138
|
+
} } : {}),
|
|
60
139
|
});
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
140
|
+
setApplications((current) => ({ ...current, [plan.client]: keyId }));
|
|
141
|
+
notify({ variant: 'success', description: plan.client === 'codex' && gatewayModels === undefined
|
|
142
|
+
? 'Codex 连接配置已应用,模型目录尚未加载,请稍后刷新配置。'
|
|
143
|
+
: `${AI_CLIENT_LABELS[plan.client]} ${refresh ? 'endpoint 已刷新。' : '配置已应用。'}` });
|
|
65
144
|
};
|
|
145
|
+
const applyExistingConfiguration = (record, selectedTarget, refresh = false) => runKeyOperation(record.id, async () => {
|
|
146
|
+
if (!clientConfigurationBridge || (refresh && applications[selectedTarget] !== record.id))
|
|
147
|
+
return;
|
|
148
|
+
setApplying({ keyId: record.id, clientId: selectedTarget });
|
|
149
|
+
applicationVersions.current[selectedTarget] = (applicationVersions.current[selectedTarget] ?? 0) + 1;
|
|
150
|
+
const plan = await clientConfigurationBridge.plan({
|
|
151
|
+
client: selectedTarget,
|
|
152
|
+
endpoint: client.apiBase,
|
|
153
|
+
...(selectedTarget === 'codex' && gatewayModels !== undefined ? {
|
|
154
|
+
activeModels: gatewayModels.map(({ id, provider, displayName, availability, contextWindow, inputModalities, capabilities }) => ({
|
|
155
|
+
id, provider, displayName, availability, contextWindow, inputModalities, capabilities,
|
|
156
|
+
})),
|
|
157
|
+
} : {}),
|
|
158
|
+
});
|
|
159
|
+
await applyPlan(record.id, plan, refresh);
|
|
160
|
+
});
|
|
161
|
+
const restore = (record, selectedTarget) => runKeyOperation(record.id, async () => {
|
|
162
|
+
if (!clientConfigurationBridge || applications[selectedTarget] !== record.id)
|
|
163
|
+
return;
|
|
164
|
+
applicationVersions.current[selectedTarget] = (applicationVersions.current[selectedTarget] ?? 0) + 1;
|
|
165
|
+
const status = await clientConfigurationBridge.restore(selectedTarget);
|
|
166
|
+
if (status.status !== 'notConfigured' && status.status !== 'failedAndRestored') {
|
|
167
|
+
throw new Error(status.message ?? '撤回未完成,请重试。');
|
|
168
|
+
}
|
|
169
|
+
setApplications((current) => {
|
|
170
|
+
const next = { ...current };
|
|
171
|
+
delete next[selectedTarget];
|
|
172
|
+
return next;
|
|
173
|
+
});
|
|
174
|
+
notify({ description: `${AI_CLIENT_LABELS[selectedTarget]} 配置已撤回,API Key 已保留。` });
|
|
175
|
+
});
|
|
66
176
|
const create = async () => {
|
|
67
177
|
const trimmedName = name.trim();
|
|
68
178
|
if (!trimmedName) {
|
|
@@ -71,19 +181,15 @@ export function AiGatewayKeysSection({ client, clientConfigurationBridge, }) {
|
|
|
71
181
|
}
|
|
72
182
|
setCreating(true);
|
|
73
183
|
setError(undefined);
|
|
74
|
-
setNewPlaintext(undefined);
|
|
75
184
|
try {
|
|
76
185
|
const created = await client.createGatewayKey({
|
|
77
186
|
name: trimmedName,
|
|
78
|
-
...(target ? { appliedClient: target } : {}),
|
|
79
187
|
});
|
|
80
188
|
setKeys((current) => [created.record, ...current.filter((record) => record.id !== created.record.id)]);
|
|
81
|
-
|
|
189
|
+
plaintexts.current.set(created.record.id, created.plaintext);
|
|
190
|
+
notify({ variant: 'success', description: 'API Key 已创建,可在列表中复制或应用配置。' });
|
|
82
191
|
setName(DEFAULT_KEY_NAME);
|
|
83
|
-
|
|
84
|
-
await applyConfiguration(created.plaintext, target);
|
|
85
|
-
else
|
|
86
|
-
await copyConfiguration(created.plaintext);
|
|
192
|
+
setShowCreate(false);
|
|
87
193
|
}
|
|
88
194
|
catch (cause) {
|
|
89
195
|
setError(errorMessage(cause));
|
|
@@ -100,58 +206,78 @@ export function AiGatewayKeysSection({ client, clientConfigurationBridge, }) {
|
|
|
100
206
|
setKeys((current) => current.map((item) => item.id === record.id ? updated : item));
|
|
101
207
|
}
|
|
102
208
|
catch (cause) {
|
|
103
|
-
|
|
209
|
+
notifyError(cause);
|
|
104
210
|
}
|
|
105
211
|
finally {
|
|
106
212
|
setBusyKeyId(undefined);
|
|
107
213
|
}
|
|
108
214
|
};
|
|
109
|
-
const copyExistingConfiguration = async (
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
catch (cause) {
|
|
118
|
-
setError(errorMessage(cause));
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
setBusyKeyId(undefined);
|
|
215
|
+
const copyExistingConfiguration = (record, selectedTarget) => runKeyOperation(record.id, async () => {
|
|
216
|
+
const generation = copyGeneration.current;
|
|
217
|
+
const plaintext = plaintexts.current.get(record.id) ?? await client.revealGatewayKey(record.id);
|
|
218
|
+
if (generation !== copyGeneration.current)
|
|
219
|
+
return;
|
|
220
|
+
if (!navigator.clipboard?.writeText) {
|
|
221
|
+
throw new Error('当前浏览器无法访问剪贴板,请允许剪贴板访问后重试。');
|
|
122
222
|
}
|
|
123
|
-
|
|
223
|
+
await navigator.clipboard.writeText(selectedTarget === 'key'
|
|
224
|
+
? plaintext
|
|
225
|
+
: manualConfigurationText(selectedTarget, client.apiBase, plaintext));
|
|
226
|
+
if (generation !== copyGeneration.current)
|
|
227
|
+
return;
|
|
228
|
+
clearTimeout(copyTimers.current.get(record.id));
|
|
229
|
+
setCopied((current) => ({ ...current, [record.id]: selectedTarget }));
|
|
230
|
+
copyTimers.current.set(record.id, setTimeout(() => clearCopyFeedback(record.id), 2000));
|
|
231
|
+
});
|
|
124
232
|
const remove = async (record) => {
|
|
125
233
|
setBusyKeyId(record.id);
|
|
126
234
|
setError(undefined);
|
|
127
235
|
try {
|
|
128
236
|
await client.deleteGatewayKey(record.id);
|
|
237
|
+
plaintexts.current.delete(record.id);
|
|
238
|
+
clearCopyFeedback(record.id);
|
|
129
239
|
setKeys((current) => current.filter((item) => item.id !== record.id));
|
|
130
240
|
}
|
|
131
241
|
catch (cause) {
|
|
132
|
-
|
|
242
|
+
notifyError(cause);
|
|
133
243
|
}
|
|
134
244
|
finally {
|
|
135
245
|
setBusyKeyId(undefined);
|
|
136
246
|
}
|
|
137
247
|
};
|
|
138
|
-
return (_jsxs("section", { className: "space-y-6", "aria-label": "API Keys", children: [_jsx("p", { className: "max-w-3xl text-sm text-muted-foreground", children: "API Key \u7528\u4E8E\u8BBF\u95EE Xpod Gateway\u3002Provider \u5BC6\u94A5\u4E0D\u4F1A\u5199\u5165\u5BA2\u6237\u7AEF\uFF1B\u5BA2\u6237\u7AEF\u53EA\u83B7\u5F97 Xpod \u5730\u5740\u548C\u8FD9\u91CC\u521B\u5EFA\u7684 Key\u3002" }), _jsxs("div", { className: "
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
248
|
+
return (_jsxs("section", { className: "[container-type:inline-size] space-y-6", "aria-label": "API Keys", children: [_jsx("p", { className: "max-w-3xl text-sm text-muted-foreground", children: "API Key \u7528\u4E8E\u8BBF\u95EE Xpod Gateway\u3002Provider \u5BC6\u94A5\u4E0D\u4F1A\u5199\u5165\u5BA2\u6237\u7AEF\uFF1B\u5BA2\u6237\u7AEF\u53EA\u83B7\u5F97 Xpod \u5730\u5740\u548C\u8FD9\u91CC\u521B\u5EFA\u7684 Key\u3002" }), _jsxs("div", { className: "flex items-center justify-between gap-3 border-b border-border/60 pb-2", children: [_jsxs("span", { className: "text-xs text-muted-foreground", children: [keys.length, " \u4E2A API Key"] }), _jsxs(Button, { size: "sm", "aria-label": "\u65B0\u5EFA API Key", disabled: creating || loading, onClick: () => { setError(undefined); setName(DEFAULT_KEY_NAME); setShowCreate(true); }, children: [_jsx(KeyRound, { className: "mr-2 h-4 w-4" }), "\u65B0\u5EFA API Key"] })] }), _jsx(Dialog, { open: showCreate, onOpenChange: (open) => { if (!creating)
|
|
249
|
+
setShowCreate(open); }, children: _jsxs(DialogContent, { className: "sm:max-w-md", "aria-describedby": undefined, children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: "\u65B0\u5EFA API Key" }) }), _jsxs("form", { className: "space-y-5", onSubmit: (event) => { event.preventDefault(); if (!creating)
|
|
250
|
+
void create(); }, children: [_jsxs("label", { className: "block space-y-2", children: [_jsx("span", { className: "text-sm font-medium", children: "\u540D\u79F0" }), _jsx(Input, { autoFocus: true, "aria-label": "API Key \u540D\u79F0", value: name, disabled: creating, onChange: (event) => setName(event.target.value) })] }), error ? _jsx("p", { role: "alert", className: "text-sm text-destructive", children: error }) : null, _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "outline", disabled: creating, onClick: () => setShowCreate(false), children: "\u53D6\u6D88" }), _jsxs(Button, { type: "submit", "aria-label": "\u521B\u5EFA API Key", disabled: creating || !name.trim(), children: [creating ? _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }) : null, creating ? '正在创建…' : '创建 API Key'] })] })] })] }) }), !clientConfigurationBridge ? _jsx("p", { className: "text-xs text-muted-foreground", children: "\u5F53\u524D Web \u73AF\u5883\u53EF\u590D\u5236\u914D\u7F6E\uFF1B\u81EA\u52A8\u5E94\u7528\u548C\u64A4\u56DE\u9700\u8981\u672C\u673A\u8FDE\u63A5\u3002" }) : null, _jsx("div", { className: "space-y-2", children: loading ? (_jsxs("div", { className: "flex items-center gap-2 py-6 text-sm text-muted-foreground", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin" }), "\u6B63\u5728\u8BFB\u53D6 API Keys"] })) : keys.length === 0 ? (_jsx("p", { className: "py-8 text-center text-sm text-muted-foreground", children: "\u5C1A\u672A\u521B\u5EFA API Key\u3002" })) : (_jsx("div", { className: "rounded-xl border border-border/70", children: keys.map((record) => {
|
|
251
|
+
const disabled = Boolean(record.disabledAt);
|
|
252
|
+
const label = record.name || '未命名 API Key';
|
|
253
|
+
const busy = Boolean(busyKeyId);
|
|
254
|
+
const appliedClients = AI_CONNECTIONS_CLIENTS.filter((clientId) => applications[clientId] === record.id);
|
|
255
|
+
const hasApplication = appliedClients.length > 0;
|
|
256
|
+
return (_jsxs("div", { "data-key-state": disabled ? 'disabled' : 'active', className: cn('flex min-w-0 items-center gap-1 border-b border-border/60 px-2 py-2.5 sm:gap-2 sm:px-4 first:rounded-t-xl last:rounded-b-xl last:border-b-0', disabled ? 'bg-muted/30 text-muted-foreground' : 'bg-emerald-500/[0.035]'), children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-1 sm:gap-2", children: [_jsx("span", { className: "min-w-0 truncate text-sm font-medium", title: label, children: label }), _jsx("code", { dir: "rtl", className: "min-w-0 max-w-36 truncate text-left text-xs text-muted-foreground", children: _jsx("span", { dir: "ltr", children: record.maskedHint ?? suffixHint(record.id) }) }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8 shrink-0", "aria-label": `复制 ${label}`, title: copied[record.id] === 'key' ? '已复制' : '复制 API Key', disabled: busy, onClick: () => void copyExistingConfiguration(record, 'key'), children: copied[record.id] === 'key' ? _jsx(Check, { className: "h-4 w-4 text-emerald-600" }) : _jsx(Copy, { className: "h-4 w-4" }) }), _jsx("span", { role: "status", "aria-live": "polite", className: "sr-only", children: copied[record.id] === 'key' ? 'API Key 已复制' : '' }), hasApplication ? _jsx("div", { className: "flex shrink-0 items-center gap-1 text-muted-foreground", children: appliedClients.map((clientId) => _jsx("span", { role: "img", "aria-label": `${AI_CLIENT_LABELS[clientId]} 已应用`, title: `${AI_CLIENT_LABELS[clientId]} 已应用`, className: "shrink-0", children: _jsx(AiClientIcon, { client: clientId }) }, clientId)) }) : null] }), _jsx("span", { className: "hidden shrink-0 text-xs text-muted-foreground [@container(min-width:850px)]:inline", children: record.lastUsedAt ? `最后使用 ${formatTimestamp(record.lastUsedAt)}` : '暂无调用记录 · 尚未使用' }), _jsxs("details", { "data-client-menu": record.id, open: openMenuKeyId === record.id, className: "relative shrink-0", onKeyDown: (event) => {
|
|
257
|
+
if (event.key !== 'Escape')
|
|
258
|
+
return;
|
|
259
|
+
event.preventDefault();
|
|
260
|
+
setOpenMenuKeyId(undefined);
|
|
261
|
+
event.currentTarget.querySelector('summary')?.focus();
|
|
262
|
+
}, children: [_jsxs("summary", { role: "button", "aria-label": `${label} 客户端配置`, "aria-expanded": openMenuKeyId === record.id, onClick: (event) => {
|
|
263
|
+
event.preventDefault();
|
|
264
|
+
if (busy && openMenuKeyId !== record.id)
|
|
265
|
+
return;
|
|
266
|
+
setOpenMenuKeyId((current) => current === record.id ? undefined : record.id);
|
|
267
|
+
}, className: "inline-flex min-h-9 max-w-full cursor-pointer list-none items-center gap-2 rounded-md border border-input bg-background px-2 text-sm outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring [&::-webkit-details-marker]:hidden", children: [_jsx("span", { children: "\u5E94\u7528" }), _jsx(ChevronDown, { "aria-hidden": "true", className: "h-3.5 w-3.5 shrink-0" })] }), _jsx("div", { role: "group", "aria-label": `${label} 客户端选项`, className: "absolute right-0 top-full z-20 mt-1 w-72 max-w-[calc(100cqw-6rem)] space-y-1 rounded-lg border border-border bg-popover p-2 text-popover-foreground shadow-lg", children: AI_CONNECTIONS_CLIENTS.map((clientId) => {
|
|
268
|
+
const application = applications[clientId];
|
|
269
|
+
const checked = application === record.id;
|
|
270
|
+
const copiedClient = copied[record.id] === clientId;
|
|
271
|
+
return _jsxs("div", { className: "flex items-center gap-2 rounded-md px-2 py-1.5", children: [clientConfigurationBridge ? _jsxs("label", { className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 text-sm", children: [_jsx("input", { type: "checkbox", "aria-label": `${label} 应用到 ${AI_CLIENT_LABELS[clientId]}`, checked: checked, disabled: busy || (disabled && !checked), className: "h-4 w-4 shrink-0 accent-primary", onChange: (event) => {
|
|
272
|
+
if (event.target.checked)
|
|
273
|
+
void applyExistingConfiguration(record, clientId);
|
|
274
|
+
else
|
|
275
|
+
void restore(record, clientId);
|
|
276
|
+
} }), _jsx("span", { children: AI_CLIENT_LABELS[clientId] }), applying?.keyId === record.id && applying.clientId === clientId
|
|
277
|
+
? _jsx("span", { role: "status", className: "text-xs text-muted-foreground", children: "\u5E94\u7528\u4E2D\u2026" })
|
|
278
|
+
: null] }) : _jsx("span", { className: "min-w-0 flex-1 text-sm", children: AI_CLIENT_LABELS[clientId] }), clientConfigurationBridge ? _jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8 shrink-0", "aria-label": `刷新 ${label} 的 ${AI_CLIENT_LABELS[clientId]} endpoint`, title: checked ? '保留当前 Key,刷新客户端连接地址' : '应用后可刷新连接地址', disabled: busy || disabled || !checked, onClick: () => void applyExistingConfiguration(record, clientId, true), children: _jsx(RefreshCw, { className: cn('h-4 w-4', applying?.keyId === record.id && applying.clientId === clientId && 'animate-spin') }) }) : null, _jsx("span", { role: "status", "aria-live": "polite", "aria-atomic": "true", className: "sr-only", children: copiedClient ? '已复制' : '' }), _jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8 shrink-0", "aria-label": `复制 ${label} 的 ${AI_CLIENT_LABELS[clientId]} 配置`, title: copiedClient ? '已复制' : `复制 ${AI_CLIENT_LABELS[clientId]} 配置`, disabled: busy, onClick: () => void copyExistingConfiguration(record, clientId), children: copiedClient ? _jsx(Check, { className: "h-4 w-4 text-emerald-600" }) : _jsx(Copy, { className: "h-4 w-4" }) })] }, clientId);
|
|
279
|
+
}) })] }), _jsxs("div", { className: "flex shrink-0 items-center", children: [record.kind !== 'client-credentials' ? (_jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", "aria-pressed": !disabled, "aria-label": `${disabled ? '启用' : '停用'} ${label}`, title: `${disabled ? '启用' : '停用'} ${label}`, disabled: busy, onClick: () => void setEnabled(record, disabled), children: _jsx(Power, { className: cn('h-4 w-4', !disabled && 'text-emerald-600') }) })) : null, _jsx(Button, { variant: "ghost", size: "icon", className: "h-8 w-8", "aria-label": `删除 ${label}`, title: hasApplication ? '请先撤回已应用的配置' : `删除 ${label}`, disabled: busy || hasApplication, onClick: () => void remove(record), children: _jsx(Trash2, { className: "h-4 w-4" }) })] })] }, record.id));
|
|
280
|
+
}) })) })] }));
|
|
155
281
|
}
|
|
156
282
|
function suffixHint(id) {
|
|
157
283
|
return `••••••••${id.slice(-8)}`;
|
|
@@ -161,8 +287,18 @@ function formatTimestamp(value) {
|
|
|
161
287
|
return Number.isNaN(date.getTime()) ? value : date.toLocaleString();
|
|
162
288
|
}
|
|
163
289
|
function errorMessage(error) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
290
|
+
const message = error instanceof Error ? error.message.trim() : '';
|
|
291
|
+
if (/failed to fetch|networkerror|load failed/i.test(message)) {
|
|
292
|
+
return '无法连接配置服务,请检查连接后重试。';
|
|
293
|
+
}
|
|
294
|
+
if (/EACCES|permission denied/i.test(message)) {
|
|
295
|
+
return '没有权限写入配置文件,请检查文件权限后重试。';
|
|
296
|
+
}
|
|
297
|
+
if (message === 'Client configuration could not be verified locally.') {
|
|
298
|
+
return '配置文件写入后的本地检查未通过,请检查文件内容和权限后重试。';
|
|
299
|
+
}
|
|
300
|
+
if (!message || /^(?:AI Connection |AI client configuration )?request failed(?:\. Please try again\.)?$/i.test(message)) {
|
|
301
|
+
return 'API Key 操作失败,请重试。';
|
|
302
|
+
}
|
|
303
|
+
return message;
|
|
168
304
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { AiConnectAttempt, AiConnectionsMode, AiGatewayModel, AiProviderCredentialSummary, AiProviderOffering, AiProviderSummary } from './ai-connections-client';
|
|
1
|
+
import type { AiConnectAttempt, AiConnectionsMode, AiGatewayModel, AiProviderCredentialSummary, AiProviderAuthorizationMethod, AiProviderOffering, AiProviderSummary } from './ai-connections-client';
|
|
2
2
|
import { type AiOfferingActionError, type AiOfferingQuotaState } from './AiCredentialPoolSection';
|
|
3
3
|
export type { AiProviderDefinition } from './controller';
|
|
4
4
|
import type { AiProviderDefinition } from './controller';
|
|
5
5
|
export type ProviderConnectionState = 'unknown' | 'pending' | 'configured' | 'connected' | 'disconnected' | 'reauthRequired' | 'failed';
|
|
6
|
-
export declare function AiProviderCard({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl, busy, disabled, error, quotas, models, verifyPending, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onVerify, onAddModel, onEditModel, onDeleteModel, selectedModelIds, onModelSelectionChange, onDismissError, }: {
|
|
6
|
+
export declare function AiProviderCard({ definition, product, status, accountLabel, attempt, attemptOfferingId, apiKey, baseUrl, busy, disabled, error, quotas, models, verifyPending, onApiKeyChange, onBaseUrlChange, onBeginApiKey, onBeginOffering, onCancelConnect, onBeginBrowser, onSaveApiKey, onDisconnect, onCreateApiKeyCredential, onCreateLocalCredential, onUpdateCredential, onDeleteCredential, onTestCredential, onReorderCredentials, onRefreshQuota, onVerify, onAddModel, onEditModel, onDeleteModel, selectedModelIds, modelSelectionStatus, onModelSelectionChange, onDismissError, }: {
|
|
7
7
|
definition: AiProviderDefinition;
|
|
8
8
|
product?: AiProviderSummary;
|
|
9
9
|
status: ProviderConnectionState;
|
|
@@ -21,7 +21,8 @@ export declare function AiProviderCard({ definition, product, status, accountLab
|
|
|
21
21
|
onApiKeyChange: (value: string) => void;
|
|
22
22
|
onBaseUrlChange?: (value: string) => void;
|
|
23
23
|
onBeginApiKey: () => void;
|
|
24
|
-
onBeginOffering?: (offering: AiProviderOffering, mode: AiConnectionsMode) => void;
|
|
24
|
+
onBeginOffering?: (offering: AiProviderOffering, mode: AiConnectionsMode, method?: AiProviderAuthorizationMethod) => void;
|
|
25
|
+
onCancelConnect?: (attempt: Pick<AiConnectAttempt, 'attemptId' | 'state' | 'signature'>) => void;
|
|
25
26
|
onBeginBrowser: () => void;
|
|
26
27
|
onSaveApiKey: () => void;
|
|
27
28
|
onDisconnect: (credential?: AiProviderCredentialSummary) => void;
|
|
@@ -32,7 +33,7 @@ export declare function AiProviderCard({ definition, product, status, accountLab
|
|
|
32
33
|
proxyUrl?: string;
|
|
33
34
|
priority: number;
|
|
34
35
|
}) => Promise<void>;
|
|
35
|
-
onCreateLocalCredential?: (offering: AiProviderOffering) => Promise<void>;
|
|
36
|
+
onCreateLocalCredential?: (offering: AiProviderOffering, method?: AiProviderAuthorizationMethod) => Promise<void>;
|
|
36
37
|
onUpdateCredential?: (credential: AiProviderCredentialSummary, patch: {
|
|
37
38
|
label?: string;
|
|
38
39
|
enabled?: boolean;
|
|
@@ -48,6 +49,7 @@ export declare function AiProviderCard({ definition, product, status, accountLab
|
|
|
48
49
|
onAddModel?: () => void;
|
|
49
50
|
onEditModel?: (model: AiGatewayModel) => void;
|
|
50
51
|
onDeleteModel?: (model: AiGatewayModel) => void;
|
|
52
|
+
modelSelectionStatus?: 'saving' | 'saved' | 'error';
|
|
51
53
|
selectedModelIds?: string[];
|
|
52
54
|
onModelSelectionChange?: (provider: AiProviderSummary['id'], modelIds: string[]) => void;
|
|
53
55
|
onDismissError?: () => void;
|