@nextclaw/server 0.10.1 → 0.10.2
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 +27 -9
- package/dist/index.js +76 -14
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -283,6 +283,26 @@ type MarketplaceApiConfig = {
|
|
|
283
283
|
installer?: MarketplaceInstaller;
|
|
284
284
|
};
|
|
285
285
|
|
|
286
|
+
type ChatSessionTypeCtaView = {
|
|
287
|
+
kind: string;
|
|
288
|
+
label?: string;
|
|
289
|
+
href?: string;
|
|
290
|
+
};
|
|
291
|
+
type ChatSessionTypeOptionView = {
|
|
292
|
+
value: string;
|
|
293
|
+
label: string;
|
|
294
|
+
ready?: boolean;
|
|
295
|
+
reason?: string | null;
|
|
296
|
+
reasonMessage?: string | null;
|
|
297
|
+
supportedModels?: string[];
|
|
298
|
+
recommendedModel?: string | null;
|
|
299
|
+
cta?: ChatSessionTypeCtaView | null;
|
|
300
|
+
};
|
|
301
|
+
type ChatSessionTypesView = {
|
|
302
|
+
defaultType: string;
|
|
303
|
+
options: ChatSessionTypeOptionView[];
|
|
304
|
+
};
|
|
305
|
+
|
|
286
306
|
type ApiError = {
|
|
287
307
|
code: string;
|
|
288
308
|
message: string;
|
|
@@ -462,6 +482,7 @@ type SessionConfigView = {
|
|
|
462
482
|
maxPingPongTurns?: number;
|
|
463
483
|
};
|
|
464
484
|
};
|
|
485
|
+
|
|
465
486
|
type SessionEntryView = {
|
|
466
487
|
key: string;
|
|
467
488
|
createdAt: string;
|
|
@@ -658,14 +679,6 @@ type ChatCapabilitiesView = {
|
|
|
658
679
|
stopSupported: boolean;
|
|
659
680
|
stopReason?: string;
|
|
660
681
|
};
|
|
661
|
-
type ChatSessionTypeOptionView = {
|
|
662
|
-
value: string;
|
|
663
|
-
label: string;
|
|
664
|
-
};
|
|
665
|
-
type ChatSessionTypesView = {
|
|
666
|
-
defaultType: string;
|
|
667
|
-
options: ChatSessionTypeOptionView[];
|
|
668
|
-
};
|
|
669
682
|
type ChatCommandOptionView = {
|
|
670
683
|
name: string;
|
|
671
684
|
description: string;
|
|
@@ -980,6 +993,7 @@ declare class UiAuthService {
|
|
|
980
993
|
private clearAllSessions;
|
|
981
994
|
private deleteRequestSession;
|
|
982
995
|
private buildLoginCookie;
|
|
996
|
+
buildTrustedRequestCookieHeader(): string | null;
|
|
983
997
|
buildLogoutCookie(request: Request): string;
|
|
984
998
|
setup(request: Request, payload: AuthSetupRequest): {
|
|
985
999
|
status: AuthStatusView;
|
|
@@ -1057,4 +1071,8 @@ declare function deleteSession(configPath: string, key: string): boolean;
|
|
|
1057
1071
|
declare function updateRuntime(configPath: string, patch: RuntimeConfigUpdate): Pick<ConfigView, "agents" | "bindings" | "session">;
|
|
1058
1072
|
declare function updateSecrets(configPath: string, patch: SecretsConfigUpdate): SecretsView;
|
|
1059
1073
|
|
|
1060
|
-
|
|
1074
|
+
declare function getUiBridgeSecretPath(): string;
|
|
1075
|
+
declare function readUiBridgeSecret(): string | null;
|
|
1076
|
+
declare function ensureUiBridgeSecret(): string;
|
|
1077
|
+
|
|
1078
|
+
export { type AgentBindingView, type AgentProfileView, type ApiError, type ApiResponse, type AppMetaView, type AuthEnabledUpdateRequest, type AuthLoginRequest, type AuthPasswordUpdateRequest, type AuthSetupRequest, type AuthStatusView, type BindingPeerView, type BochaFreshnessValue, type ChannelSpecView, type ChatCapabilitiesView, type ChatCommandOptionView, type ChatCommandView, type ChatCommandsView, type ChatRunListView, type ChatRunState, type ChatRunView, type ChatSessionTypeCtaView, type ChatSessionTypeOptionView, type ChatSessionTypesView, type ChatTurnRequest, type ChatTurnResult, type ChatTurnStopRequest, type ChatTurnStopResult, type ChatTurnStreamEvent, 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, DEFAULT_SESSION_TYPE, type MarketplaceApiConfig, type MarketplaceInstallKind, type MarketplaceInstallSkillParams, type MarketplaceInstallSpec, type MarketplaceInstalledRecord, type MarketplaceInstalledView, type MarketplaceInstaller, type MarketplaceItemSummary, type MarketplaceItemType, type MarketplaceItemView, type MarketplaceListView, type MarketplaceLocalizedTextMap, type MarketplaceMcpContentView, type MarketplaceMcpDoctorResult, type MarketplaceMcpInstallKind, type MarketplaceMcpInstallRequest, type MarketplaceMcpInstallResult, type MarketplaceMcpInstallSpec, type MarketplaceMcpManageAction, type MarketplaceMcpManageRequest, type MarketplaceMcpManageResult, type MarketplaceMcpTemplateInput, type MarketplacePluginContentView, type MarketplacePluginInstallKind, type MarketplacePluginInstallRequest, type MarketplacePluginInstallResult, type MarketplacePluginManageAction, type MarketplacePluginManageRequest, type MarketplacePluginManageResult, type MarketplaceRecommendationView, type MarketplaceSkillContentView, type MarketplaceSkillInstallKind, type MarketplaceSkillInstallRequest, type MarketplaceSkillInstallResult, type MarketplaceSkillManageAction, type MarketplaceSkillManageRequest, type MarketplaceSkillManageResult, type MarketplaceSort, type ProviderAuthImportResult, type ProviderAuthPollRequest, type ProviderAuthPollResult, type ProviderAuthStartRequest, type ProviderAuthStartResult, type ProviderConfigUpdate, type ProviderConfigView, type ProviderConnectionTestRequest, type ProviderConnectionTestResult, type ProviderCreateRequest, type ProviderCreateResult, type ProviderDeleteResult, type ProviderSpecView, type RuntimeConfigUpdate, type SearchConfigUpdate, type SearchConfigView, type SearchProviderConfigView, type SearchProviderName, type SearchProviderSpecView, type SecretProviderEnvView, type SecretProviderExecView, type SecretProviderFileView, type SecretProviderView, type SecretRefView, type SecretSourceView, type SecretsConfigUpdate, type SecretsView, type SessionConfigView, type SessionEntryView, type SessionEventView, type SessionHistoryView, type SessionMessageView, type SessionPatchUpdate, SessionPatchValidationError, type SessionsListView, type UiChatRuntime, type UiNcpAgent, type UiNcpSessionListView, type UiNcpSessionMessagesView, type UiServerEvent, type UiServerHandle, type UiServerOptions, buildConfigMeta, buildConfigSchemaView, buildConfigView, createCustomProvider, createUiRouter, deleteCustomProvider, deleteSession, ensureUiBridgeSecret, executeConfigAction, getSessionHistory, getUiBridgeSecretPath, listSessions, loadConfigOrDefault, patchSession, readUiBridgeSecret, startUiServer, testProviderConnection, updateChannel, updateModel, updateProvider, updateRuntime, updateSearch, updateSecrets };
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,9 @@ import { compress } from "hono/compress";
|
|
|
4
4
|
import { cors } from "hono/cors";
|
|
5
5
|
import { serve } from "@hono/node-server";
|
|
6
6
|
import { WebSocketServer, WebSocket } from "ws";
|
|
7
|
-
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
8
8
|
import { readFile as readFile2, stat } from "fs/promises";
|
|
9
|
-
import { join } from "path";
|
|
9
|
+
import { join as join2 } from "path";
|
|
10
10
|
|
|
11
11
|
// src/ui/auth.service.ts
|
|
12
12
|
import { ConfigSchema, loadConfig, saveConfig } from "@nextclaw/core";
|
|
@@ -179,6 +179,18 @@ var UiAuthService = class {
|
|
|
179
179
|
secure: resolveSecureRequest(request.url, request.headers.get("x-forwarded-proto"))
|
|
180
180
|
});
|
|
181
181
|
}
|
|
182
|
+
buildTrustedRequestCookieHeader() {
|
|
183
|
+
const auth = this.readAuthConfig();
|
|
184
|
+
if (!auth.enabled || !this.isConfigured(auth)) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const username = normalizeUsername(auth.username);
|
|
188
|
+
if (!username) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const sessionId = this.createSession(username);
|
|
192
|
+
return `${SESSION_COOKIE_NAME}=${encodeURIComponent(sessionId)}`;
|
|
193
|
+
}
|
|
182
194
|
buildLogoutCookie(request) {
|
|
183
195
|
return buildSetCookie({
|
|
184
196
|
value: "",
|
|
@@ -393,6 +405,39 @@ var AppRoutesController = class {
|
|
|
393
405
|
appMeta = (c) => c.json(ok(buildAppMetaView(this.options)));
|
|
394
406
|
};
|
|
395
407
|
|
|
408
|
+
// src/ui/auth-bridge.ts
|
|
409
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
410
|
+
import { join } from "path";
|
|
411
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
412
|
+
import { getDataDir } from "@nextclaw/core";
|
|
413
|
+
var REMOTE_BRIDGE_DIR = join(getDataDir(), "remote");
|
|
414
|
+
var REMOTE_BRIDGE_SECRET_PATH = join(REMOTE_BRIDGE_DIR, "ui-bridge-secret");
|
|
415
|
+
function getUiBridgeSecretPath() {
|
|
416
|
+
return REMOTE_BRIDGE_SECRET_PATH;
|
|
417
|
+
}
|
|
418
|
+
function readUiBridgeSecret() {
|
|
419
|
+
if (!existsSync(REMOTE_BRIDGE_SECRET_PATH)) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
try {
|
|
423
|
+
const raw = readFileSync(REMOTE_BRIDGE_SECRET_PATH, "utf-8").trim();
|
|
424
|
+
return raw.length > 0 ? raw : null;
|
|
425
|
+
} catch {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function ensureUiBridgeSecret() {
|
|
430
|
+
const existing = readUiBridgeSecret();
|
|
431
|
+
if (existing) {
|
|
432
|
+
return existing;
|
|
433
|
+
}
|
|
434
|
+
mkdirSync(REMOTE_BRIDGE_DIR, { recursive: true });
|
|
435
|
+
const secret = randomBytes2(24).toString("hex");
|
|
436
|
+
writeFileSync(REMOTE_BRIDGE_SECRET_PATH, `${secret}
|
|
437
|
+
`, "utf-8");
|
|
438
|
+
return secret;
|
|
439
|
+
}
|
|
440
|
+
|
|
396
441
|
// src/ui/router/auth.controller.ts
|
|
397
442
|
function isAuthenticationRequiredError(message) {
|
|
398
443
|
return message === "Authentication required.";
|
|
@@ -492,6 +537,16 @@ var AuthRoutesController = class {
|
|
|
492
537
|
return c.json(err(code, message), status);
|
|
493
538
|
}
|
|
494
539
|
};
|
|
540
|
+
issueBridgeSession = (c) => {
|
|
541
|
+
const providedSecret = c.req.header("x-nextclaw-ui-bridge-secret")?.trim();
|
|
542
|
+
const expectedSecret = ensureUiBridgeSecret();
|
|
543
|
+
if (!providedSecret || providedSecret !== expectedSecret) {
|
|
544
|
+
return c.json(err("FORBIDDEN", "Invalid bridge secret."), 403);
|
|
545
|
+
}
|
|
546
|
+
return c.json(ok({
|
|
547
|
+
cookie: this.authService.buildTrustedRequestCookieHeader()
|
|
548
|
+
}));
|
|
549
|
+
};
|
|
495
550
|
};
|
|
496
551
|
|
|
497
552
|
// src/ui/router/chat.controller.ts
|
|
@@ -2441,7 +2496,7 @@ var ChatRoutesController = class {
|
|
|
2441
2496
|
};
|
|
2442
2497
|
|
|
2443
2498
|
// src/ui/provider-auth.ts
|
|
2444
|
-
import { createHash, randomBytes as
|
|
2499
|
+
import { createHash, randomBytes as randomBytes3, randomUUID as randomUUID2 } from "crypto";
|
|
2445
2500
|
import { readFile } from "fs/promises";
|
|
2446
2501
|
import { homedir } from "os";
|
|
2447
2502
|
import { isAbsolute, resolve } from "path";
|
|
@@ -2469,7 +2524,7 @@ function toBase64Url(buffer) {
|
|
|
2469
2524
|
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
2470
2525
|
}
|
|
2471
2526
|
function buildPkce() {
|
|
2472
|
-
const verifier = toBase64Url(
|
|
2527
|
+
const verifier = toBase64Url(randomBytes3(48));
|
|
2473
2528
|
const challenge = toBase64Url(createHash("sha256").update(verifier).digest());
|
|
2474
2529
|
return { verifier, challenge };
|
|
2475
2530
|
}
|
|
@@ -2686,7 +2741,7 @@ async function startProviderAuth(configPath, providerName, options) {
|
|
|
2686
2741
|
if (!pkce) {
|
|
2687
2742
|
throw new Error("MiniMax OAuth requires PKCE");
|
|
2688
2743
|
}
|
|
2689
|
-
const state = toBase64Url(
|
|
2744
|
+
const state = toBase64Url(randomBytes3(16));
|
|
2690
2745
|
const body = new URLSearchParams({
|
|
2691
2746
|
response_type: "code",
|
|
2692
2747
|
client_id: resolvedMethod.clientId,
|
|
@@ -4862,6 +4917,15 @@ var SessionRoutesController = class {
|
|
|
4862
4917
|
};
|
|
4863
4918
|
|
|
4864
4919
|
// src/ui/router.ts
|
|
4920
|
+
function registerAuthRoutes(app, authController) {
|
|
4921
|
+
app.get("/api/auth/status", authController.getStatus);
|
|
4922
|
+
app.post("/api/auth/setup", authController.setup);
|
|
4923
|
+
app.post("/api/auth/login", authController.login);
|
|
4924
|
+
app.post("/api/auth/logout", authController.logout);
|
|
4925
|
+
app.put("/api/auth/password", authController.updatePassword);
|
|
4926
|
+
app.put("/api/auth/enabled", authController.updateEnabled);
|
|
4927
|
+
app.post("/api/auth/bridge", authController.issueBridgeSession);
|
|
4928
|
+
}
|
|
4865
4929
|
function createUiRouter(options) {
|
|
4866
4930
|
const app = new Hono();
|
|
4867
4931
|
const marketplaceBaseUrl = normalizeMarketplaceBaseUrl(options);
|
|
@@ -4892,12 +4956,7 @@ function createUiRouter(options) {
|
|
|
4892
4956
|
});
|
|
4893
4957
|
app.get("/api/health", appController.health);
|
|
4894
4958
|
app.get("/api/app/meta", appController.appMeta);
|
|
4895
|
-
app
|
|
4896
|
-
app.post("/api/auth/setup", authController.setup);
|
|
4897
|
-
app.post("/api/auth/login", authController.login);
|
|
4898
|
-
app.post("/api/auth/logout", authController.logout);
|
|
4899
|
-
app.put("/api/auth/password", authController.updatePassword);
|
|
4900
|
-
app.put("/api/auth/enabled", authController.updateEnabled);
|
|
4959
|
+
registerAuthRoutes(app, authController);
|
|
4901
4960
|
app.get("/api/config", configController.getConfig);
|
|
4902
4961
|
app.get("/api/config/meta", configController.getConfigMeta);
|
|
4903
4962
|
app.get("/api/config/schema", configController.getConfigSchema);
|
|
@@ -4992,13 +5051,13 @@ function startUiServer(options) {
|
|
|
4992
5051
|
})
|
|
4993
5052
|
);
|
|
4994
5053
|
const staticDir = options.staticDir;
|
|
4995
|
-
if (staticDir &&
|
|
4996
|
-
const indexHtml =
|
|
5054
|
+
if (staticDir && existsSync2(join2(staticDir, "index.html"))) {
|
|
5055
|
+
const indexHtml = readFileSync2(join2(staticDir, "index.html"), "utf-8");
|
|
4997
5056
|
app.use(
|
|
4998
5057
|
"/*",
|
|
4999
5058
|
serveStatic({
|
|
5000
5059
|
root: staticDir,
|
|
5001
|
-
join,
|
|
5060
|
+
join: join2,
|
|
5002
5061
|
getContent: async (path) => {
|
|
5003
5062
|
try {
|
|
5004
5063
|
return await readFile2(path);
|
|
@@ -5073,11 +5132,14 @@ export {
|
|
|
5073
5132
|
createUiRouter,
|
|
5074
5133
|
deleteCustomProvider,
|
|
5075
5134
|
deleteSession,
|
|
5135
|
+
ensureUiBridgeSecret,
|
|
5076
5136
|
executeConfigAction,
|
|
5077
5137
|
getSessionHistory,
|
|
5138
|
+
getUiBridgeSecretPath,
|
|
5078
5139
|
listSessions,
|
|
5079
5140
|
loadConfigOrDefault,
|
|
5080
5141
|
patchSession,
|
|
5142
|
+
readUiBridgeSecret,
|
|
5081
5143
|
startUiServer,
|
|
5082
5144
|
testProviderConnection,
|
|
5083
5145
|
updateChannel,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextclaw/server",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Nextclaw UI/API server.",
|
|
6
6
|
"type": "module",
|
|
@@ -18,12 +18,12 @@
|
|
|
18
18
|
"@hono/node-server": "^1.13.3",
|
|
19
19
|
"hono": "^4.6.2",
|
|
20
20
|
"ws": "^8.18.0",
|
|
21
|
-
"@nextclaw/
|
|
21
|
+
"@nextclaw/mcp": "0.1.2",
|
|
22
22
|
"@nextclaw/ncp": "0.3.1",
|
|
23
23
|
"@nextclaw/ncp-http-agent-server": "0.3.1",
|
|
24
|
-
"@nextclaw/
|
|
25
|
-
"@nextclaw/core": "0.9.
|
|
26
|
-
"@nextclaw/
|
|
24
|
+
"@nextclaw/openclaw-compat": "0.3.6",
|
|
25
|
+
"@nextclaw/core": "0.9.3",
|
|
26
|
+
"@nextclaw/runtime": "0.2.3"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@types/node": "^20.17.6",
|