@nextclaw/server 0.5.17 → 0.5.18

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/index.d.ts CHANGED
@@ -147,6 +147,49 @@ type RuntimeConfigUpdate = {
147
147
  bindings?: AgentBindingView[];
148
148
  session?: SessionConfigView;
149
149
  };
150
+ type SecretSourceView = "env" | "file" | "exec";
151
+ type SecretRefView = {
152
+ source: SecretSourceView;
153
+ provider?: string;
154
+ id: string;
155
+ };
156
+ type SecretProviderEnvView = {
157
+ source: "env";
158
+ prefix?: string;
159
+ };
160
+ type SecretProviderFileView = {
161
+ source: "file";
162
+ path: string;
163
+ format?: "json";
164
+ };
165
+ type SecretProviderExecView = {
166
+ source: "exec";
167
+ command: string;
168
+ args?: string[];
169
+ cwd?: string;
170
+ timeoutMs?: number;
171
+ };
172
+ type SecretProviderView = SecretProviderEnvView | SecretProviderFileView | SecretProviderExecView;
173
+ type SecretsView = {
174
+ enabled: boolean;
175
+ defaults: {
176
+ env?: string;
177
+ file?: string;
178
+ exec?: string;
179
+ };
180
+ providers: Record<string, SecretProviderView>;
181
+ refs: Record<string, SecretRefView>;
182
+ };
183
+ type SecretsConfigUpdate = {
184
+ enabled?: boolean;
185
+ defaults?: {
186
+ env?: string | null;
187
+ file?: string | null;
188
+ exec?: string | null;
189
+ };
190
+ providers?: Record<string, SecretProviderView> | null;
191
+ refs?: Record<string, SecretRefView> | null;
192
+ };
150
193
  type ChatTurnRequest = {
151
194
  message: string;
152
195
  sessionKey?: string;
@@ -206,6 +249,7 @@ type ConfigView = {
206
249
  tools?: Record<string, unknown>;
207
250
  gateway?: Record<string, unknown>;
208
251
  ui?: Record<string, unknown>;
252
+ secrets?: SecretsView;
209
253
  };
210
254
  type ProviderSpecView = {
211
255
  name: string;
@@ -522,5 +566,6 @@ declare function getSessionHistory(configPath: string, key: string, limit?: numb
522
566
  declare function patchSession(configPath: string, key: string, patch: SessionPatchUpdate): SessionHistoryView | null;
523
567
  declare function deleteSession(configPath: string, key: string): boolean;
524
568
  declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
569
+ declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
525
570
 
526
- export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderConfigUpdate, type ProviderConfigView, type ProviderSpecView, type RuntimeConfigUpdate, type SessionConfigView, type SessionEntryView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createUiRouter, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime };
571
+ export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type BindingPeerView, type ChannelSpecView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnView, type ConfigActionExecuteRequest, type ConfigActionExecuteResult, type ConfigActionManifest, type ConfigActionType, type ConfigMetaView, type ConfigSchemaResponse, type ConfigUiHint, type ConfigUiHints, type ConfigView, type CronActionResult, type CronEnableRequest, type CronJobStateView, type CronJobView, type CronListView, type CronPayloadView, type CronRunRequest, type CronScheduleView, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderConfigUpdate, type ProviderConfigView, type ProviderSpecView, type RuntimeConfigUpdate, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, type SessionsListView, type UiChatRuntime, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createUiRouter, deleteSession, executeConfigAction, getSessionHistory, listSessions, loadConfigOrDefault, patchSession, startUiServer, updateChannel, updateModel, updateProvider, updateRuntime, updateSecrets };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ import {
23
23
  buildConfigSchema,
24
24
  findProviderByName,
25
25
  getPackageVersion,
26
+ hasSecretRef,
26
27
  isSensitiveConfigPath,
27
28
  SessionManager,
28
29
  getWorkspacePathFromConfig
@@ -230,7 +231,9 @@ function maskApiKey(value) {
230
231
  apiKeyMasked: `${value.slice(0, 2)}****${value.slice(-4)}`
231
232
  };
232
233
  }
233
- function toProviderView(provider, providerName, uiHints, spec) {
234
+ function toProviderView(config, provider, providerName, uiHints, spec) {
235
+ const apiKeyPath = `providers.${providerName}.apiKey`;
236
+ const apiKeyRefSet = hasSecretRef(config, apiKeyPath);
234
237
  const masked = maskApiKey(provider.apiKey);
235
238
  const extraHeaders = provider.extraHeaders && Object.keys(provider.extraHeaders).length > 0 ? sanitizePublicConfigValue(
236
239
  provider.extraHeaders,
@@ -238,8 +241,8 @@ function toProviderView(provider, providerName, uiHints, spec) {
238
241
  uiHints
239
242
  ) : null;
240
243
  const view = {
241
- apiKeySet: masked.apiKeySet,
242
- apiKeyMasked: masked.apiKeyMasked,
244
+ apiKeySet: masked.apiKeySet || apiKeyRefSet,
245
+ apiKeyMasked: masked.apiKeyMasked ?? (apiKeyRefSet ? "****" : void 0),
243
246
  apiBase: provider.apiBase ?? null,
244
247
  extraHeaders: extraHeaders && Object.keys(extraHeaders).length > 0 ? extraHeaders : null
245
248
  };
@@ -253,7 +256,7 @@ function buildConfigView(config) {
253
256
  const providers = {};
254
257
  for (const [name, provider] of Object.entries(config.providers)) {
255
258
  const spec = findProviderByName(name);
256
- providers[name] = toProviderView(provider, name, uiHints, spec);
259
+ providers[name] = toProviderView(config, provider, name, uiHints, spec);
257
260
  }
258
261
  return {
259
262
  agents: config.agents,
@@ -267,9 +270,20 @@ function buildConfigView(config) {
267
270
  session: sanitizePublicConfigValue(config.session, "session", uiHints),
268
271
  tools: sanitizePublicConfigValue(config.tools, "tools", uiHints),
269
272
  gateway: sanitizePublicConfigValue(config.gateway, "gateway", uiHints),
270
- ui: sanitizePublicConfigValue(config.ui, "ui", uiHints)
273
+ ui: sanitizePublicConfigValue(config.ui, "ui", uiHints),
274
+ secrets: {
275
+ enabled: config.secrets.enabled,
276
+ defaults: { ...config.secrets.defaults },
277
+ providers: { ...config.secrets.providers },
278
+ refs: { ...config.secrets.refs }
279
+ }
271
280
  };
272
281
  }
282
+ function clearSecretRef(config, path) {
283
+ if (config.secrets.refs[path]) {
284
+ delete config.secrets.refs[path];
285
+ }
286
+ }
273
287
  function buildConfigMeta(config) {
274
288
  const providers = PROVIDERS.map((spec) => ({
275
289
  name: spec.name,
@@ -369,6 +383,7 @@ function updateProvider(configPath, providerName, patch) {
369
383
  const spec = findProviderByName(providerName);
370
384
  if (Object.prototype.hasOwnProperty.call(patch, "apiKey")) {
371
385
  provider.apiKey = patch.apiKey ?? "";
386
+ clearSecretRef(config, `providers.${providerName}.apiKey`);
372
387
  }
373
388
  if (Object.prototype.hasOwnProperty.call(patch, "apiBase")) {
374
389
  provider.apiBase = patch.apiBase ?? null;
@@ -383,7 +398,7 @@ function updateProvider(configPath, providerName, patch) {
383
398
  saveConfig(next, configPath);
384
399
  const uiHints = buildUiHints(next);
385
400
  const updated = next.providers[providerName];
386
- return toProviderView(updated, providerName, uiHints, spec ?? void 0);
401
+ return toProviderView(next, updated, providerName, uiHints, spec ?? void 0);
387
402
  }
388
403
  function updateChannel(configPath, channelName, patch) {
389
404
  const config = loadConfigOrDefault(configPath);
@@ -391,6 +406,12 @@ function updateChannel(configPath, channelName, patch) {
391
406
  if (!channel) {
392
407
  return null;
393
408
  }
409
+ for (const key of Object.keys(patch)) {
410
+ const path = `channels.${channelName}.${key}`;
411
+ if (isSensitivePath(path)) {
412
+ clearSecretRef(config, path);
413
+ }
414
+ }
394
415
  config.channels[channelName] = { ...channel, ...patch };
395
416
  const next = ConfigSchema.parse(config);
396
417
  saveConfig(next, configPath);
@@ -575,6 +596,41 @@ function updateRuntime(configPath, patch) {
575
596
  session: view.session ?? {}
576
597
  };
577
598
  }
599
+ function updateSecrets(configPath, patch) {
600
+ const config = loadConfigOrDefault(configPath);
601
+ if (Object.prototype.hasOwnProperty.call(patch, "enabled")) {
602
+ config.secrets.enabled = Boolean(patch.enabled);
603
+ }
604
+ if (patch.defaults) {
605
+ const nextDefaults = { ...config.secrets.defaults };
606
+ for (const source of ["env", "file", "exec"]) {
607
+ if (!Object.prototype.hasOwnProperty.call(patch.defaults, source)) {
608
+ continue;
609
+ }
610
+ const value = patch.defaults[source];
611
+ if (typeof value === "string" && value.trim()) {
612
+ nextDefaults[source] = value.trim();
613
+ } else {
614
+ delete nextDefaults[source];
615
+ }
616
+ }
617
+ config.secrets.defaults = nextDefaults;
618
+ }
619
+ if (Object.prototype.hasOwnProperty.call(patch, "providers")) {
620
+ config.secrets.providers = patch.providers ?? {};
621
+ }
622
+ if (Object.prototype.hasOwnProperty.call(patch, "refs")) {
623
+ config.secrets.refs = patch.refs ?? {};
624
+ }
625
+ const next = ConfigSchema.parse(config);
626
+ saveConfig(next, configPath);
627
+ return {
628
+ enabled: next.secrets.enabled,
629
+ defaults: { ...next.secrets.defaults },
630
+ providers: { ...next.secrets.providers },
631
+ refs: { ...next.secrets.refs }
632
+ };
633
+ }
578
634
 
579
635
  // src/ui/router.ts
580
636
  var DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
@@ -1506,6 +1562,15 @@ function createUiRouter(options) {
1506
1562
  options.publish({ type: "config.updated", payload: { path: `channels.${channel}` } });
1507
1563
  return c.json(ok(result));
1508
1564
  });
1565
+ app.put("/api/config/secrets", async (c) => {
1566
+ const body = await readJson(c.req.raw);
1567
+ if (!body.ok) {
1568
+ return c.json(err("INVALID_BODY", "invalid json body"), 400);
1569
+ }
1570
+ const result = updateSecrets(options.configPath, body.data);
1571
+ options.publish({ type: "config.updated", payload: { path: "secrets" } });
1572
+ return c.json(ok(result));
1573
+ });
1509
1574
  app.post("/api/chat/turn", async (c) => {
1510
1575
  if (!options.chatRuntime) {
1511
1576
  return c.json(err("NOT_AVAILABLE", "chat runtime unavailable"), 503);
@@ -1791,5 +1856,6 @@ export {
1791
1856
  updateChannel,
1792
1857
  updateModel,
1793
1858
  updateProvider,
1794
- updateRuntime
1859
+ updateRuntime,
1860
+ updateSecrets
1795
1861
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextclaw/server",
3
- "version": "0.5.17",
3
+ "version": "0.5.18",
4
4
  "private": false,
5
5
  "description": "Nextclaw UI/API server.",
6
6
  "type": "module",
@@ -18,7 +18,7 @@
18
18
  "@nextclaw/openclaw-compat": "^0.1.28",
19
19
  "hono": "^4.6.2",
20
20
  "ws": "^8.18.0",
21
- "@nextclaw/core": "^0.6.34"
21
+ "@nextclaw/core": "^0.6.35"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@types/node": "^20.17.6",