11import type { BaseTokenResolution } from "openclaw/plugin-sdk/channel-contract" ;
22import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types" ;
3- import { DEFAULT_ACCOUNT_ID , normalizeAccountId } from "openclaw/plugin-sdk/routing" ;
4- import { resolveAccountEntry } from "openclaw/plugin-sdk/routing" ;
5- import { normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input" ;
3+ import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth" ;
4+ import {
5+ DEFAULT_ACCOUNT_ID ,
6+ normalizeAccountId ,
7+ resolveAccountEntry ,
8+ } from "openclaw/plugin-sdk/routing" ;
9+ import {
10+ normalizeResolvedSecretInputString ,
11+ normalizeSecretInputString ,
12+ resolveSecretInputString ,
13+ } from "openclaw/plugin-sdk/secret-input" ;
614
715type DiscordTokenSource = "env" | "config" | "none" ;
816
917export type DiscordTokenResolution = BaseTokenResolution & {
1018 source : DiscordTokenSource ;
1119} ;
1220
21+ const stripDiscordBotPrefix = ( value : string ) => value . replace ( / ^ B o t \s + / i, "" ) ;
22+
1323export function normalizeDiscordToken ( raw : unknown , path : string ) : string | undefined {
1424 const trimmed = normalizeResolvedSecretInputString ( { value : raw , path } ) ;
15- if ( ! trimmed ) {
16- return undefined ;
25+ return trimmed ? stripDiscordBotPrefix ( trimmed ) : undefined ;
26+ }
27+
28+ function resolveDiscordEnvSecretRefValue ( params : {
29+ cfg ?: Pick < OpenClawConfig , "secrets" > ;
30+ provider : string ;
31+ id : string ;
32+ env ?: NodeJS . ProcessEnv ;
33+ } ) : string | undefined {
34+ const prov = params . cfg ?. secrets ?. providers ?. [ params . provider ] ;
35+ if ( prov ) {
36+ if ( prov . source !== "env" ) {
37+ throw new Error (
38+ `Secret provider "${ params . provider } " has source "${ prov . source } " but ref requests "env".` ,
39+ ) ;
40+ }
41+ if ( prov . allowlist && ! prov . allowlist . includes ( params . id ) ) {
42+ throw new Error (
43+ `Environment variable "${ params . id } " is not allowlisted in secrets.providers.${ params . provider } .allowlist.` ,
44+ ) ;
45+ }
46+ } else if (
47+ params . provider !== resolveDefaultSecretProviderAlias ( { secrets : params . cfg ?. secrets } , "env" )
48+ ) {
49+ throw new Error (
50+ `Secret provider "${ params . provider } " is not configured (ref: env:${ params . provider } :${ params . id } ).` ,
51+ ) ;
52+ }
53+ return normalizeSecretInputString ( ( params . env ?? process . env ) [ params . id ] ) ;
54+ }
55+
56+ function resolveDiscordConfiguredToken ( params : {
57+ cfg ?: Pick < OpenClawConfig , "secrets" > ;
58+ value : unknown ;
59+ path : string ;
60+ } ) {
61+ const d = params . cfg ?. secrets ?. defaults ;
62+ const r = resolveSecretInputString ( {
63+ value : params . value ,
64+ path : params . path ,
65+ defaults : d ,
66+ mode : "inspect" ,
67+ } ) ;
68+ if ( r . status === "available" ) {
69+ return { status : "available" as const , value : stripDiscordBotPrefix ( r . value ) } ;
70+ }
71+ if ( r . status === "missing" ) {
72+ return { status : "missing" as const } ;
73+ }
74+ if ( r . ref . source !== "env" ) {
75+ resolveSecretInputString ( {
76+ value : params . value ,
77+ path : params . path ,
78+ defaults : d ,
79+ mode : "strict" ,
80+ } ) ;
81+ return { status : "configured_unavailable" as const } ;
1782 }
18- return trimmed . replace ( / ^ B o t \s + / i, "" ) ;
83+ const envVal = resolveDiscordEnvSecretRefValue ( {
84+ cfg : params . cfg ,
85+ provider : r . ref . provider ,
86+ id : r . ref . id ,
87+ } ) ;
88+ return envVal
89+ ? { status : "available" as const , value : stripDiscordBotPrefix ( envVal ) }
90+ : { status : "configured_unavailable" as const } ;
1991}
2092
2193export function resolveDiscordToken (
@@ -29,32 +101,31 @@ export function resolveDiscordToken(
29101 accountCfg &&
30102 Object . prototype . hasOwnProperty . call ( accountCfg as Record < string , unknown > , "token" ) ,
31103 ) ;
32- const accountToken = normalizeDiscordToken (
33- ( accountCfg as { token ?: unknown } | undefined ) ?. token ?? undefined ,
34- `channels.discord.accounts.${ accountId } .token` ,
35- ) ;
36- if ( accountToken ) {
37- return { token : accountToken , source : "config" } ;
104+ const accountResolved = resolveDiscordConfiguredToken ( {
105+ cfg,
106+ value : ( accountCfg as { token ?: unknown } | undefined ) ?. token ,
107+ path : `channels.discord.accounts.${ accountId } .token` ,
108+ } ) ;
109+ if ( accountResolved . status === "available" ) {
110+ return { token : accountResolved . value , source : "config" } ;
38111 }
39- if ( hasAccountToken ) {
112+ if ( accountResolved . status === "configured_unavailable" || hasAccountToken ) {
40113 return { token : "" , source : "none" } ;
41114 }
42-
43- const configToken = normalizeDiscordToken (
44- discordCfg ?. token ?? undefined ,
45- "channels.discord.token" ,
46- ) ;
47- if ( configToken ) {
48- return { token : configToken , source : "config" } ;
115+ const channelResolved = resolveDiscordConfiguredToken ( {
116+ cfg,
117+ value : discordCfg ?. token ?? undefined ,
118+ path : "channels.discord.token" ,
119+ } ) ;
120+ if ( channelResolved . status === "available" ) {
121+ return { token : channelResolved . value , source : "config" } ;
122+ }
123+ if ( channelResolved . status === "configured_unavailable" ) {
124+ return { token : "" , source : "none" } ;
49125 }
50-
51126 const allowEnv = accountId === DEFAULT_ACCOUNT_ID ;
52127 const envToken = allowEnv
53128 ? normalizeDiscordToken ( opts . envToken ?? process . env . DISCORD_BOT_TOKEN , "DISCORD_BOT_TOKEN" )
54129 : undefined ;
55- if ( envToken ) {
56- return { token : envToken , source : "env" } ;
57- }
58-
59- return { token : "" , source : "none" } ;
130+ return envToken ? { token : envToken , source : "env" } : { token : "" , source : "none" } ;
60131}
0 commit comments