@nextclaw/server 0.14.7 → 0.14.8

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.js CHANGED
@@ -2986,9 +2986,7 @@ async function normalizeSessionProjectRoot(value) {
2986
2986
  function isSessionProjectRootValidationError(error) {
2987
2987
  return error instanceof SessionProjectRootValidationError;
2988
2988
  }
2989
- //#endregion
2990
- //#region src/features/marketplace/configs/marketplace.constants.config.ts
2991
- const DEFAULT_MARKETPLACE_API_BASE = "https://marketplace-api.nextclaw.io";
2989
+ const DEFAULT_MARKETPLACE_READ_API_BASES = ["https://api.nextclaw.net", "https://marketplace-api.nextclaw.io"];
2992
2990
  const MARKETPLACE_ZH_COPY_BY_SLUG = {
2993
2991
  weather: {
2994
2992
  summary: "NextClaw 内置技能,用于天气查询工作流。",
@@ -3040,6 +3038,33 @@ const MARKETPLACE_ZH_COPY_BY_SLUG = {
3040
3038
  }
3041
3039
  };
3042
3040
  //#endregion
3041
+ //#region src/features/marketplace/utils/marketplace-read-source.utils.ts
3042
+ const MARKETPLACE_FETCH_TIMEOUT_MS = 12e3;
3043
+ const DOMESTIC_MARKETPLACE_FETCH_TIMEOUT_MS = 2e3;
3044
+ const DOMESTIC_MARKETPLACE_RETRY_ATTEMPTS = 2;
3045
+ function resolveMarketplaceBaseUrls(options) {
3046
+ const configured = options.marketplace?.apiBaseUrl?.trim();
3047
+ if (configured) return [configured.replace(/\/$/, "")];
3048
+ return DEFAULT_MARKETPLACE_READ_API_BASES;
3049
+ }
3050
+ function normalizeMarketplaceBaseUrls(baseUrls, baseUrl) {
3051
+ const candidates = baseUrls && baseUrls.length > 0 ? baseUrls : [baseUrl ?? "https://marketplace-api.nextclaw.io"];
3052
+ return [...new Set(candidates.map((candidate) => candidate.trim().replace(/\/$/, "")).filter(Boolean))];
3053
+ }
3054
+ function getMarketplaceFetchOptions(baseUrl) {
3055
+ if (baseUrl.replace(/\/$/, "") !== "https://api.nextclaw.net") return {
3056
+ timeoutMs: MARKETPLACE_FETCH_TIMEOUT_MS,
3057
+ retryAttempts: 5
3058
+ };
3059
+ return {
3060
+ timeoutMs: DOMESTIC_MARKETPLACE_FETCH_TIMEOUT_MS,
3061
+ retryAttempts: DOMESTIC_MARKETPLACE_RETRY_ATTEMPTS
3062
+ };
3063
+ }
3064
+ function shouldFallbackMarketplaceResult(status) {
3065
+ return status === 408 || status === 429 || status >= 500;
3066
+ }
3067
+ //#endregion
3043
3068
  //#region src/features/marketplace/utils/marketplace-network-retry.utils.ts
3044
3069
  const MARKETPLACE_NETWORK_RETRY_ATTEMPTS = 5;
3045
3070
  const MARKETPLACE_NETWORK_RETRY_BASE_MS = 350;
@@ -3059,39 +3084,56 @@ function isRetryableMarketplaceNetworkError(error) {
3059
3084
  if (error instanceof TypeError && error.message === "fetch failed") return true;
3060
3085
  return false;
3061
3086
  }
3062
- async function runWithMarketplaceNetworkRetry(action) {
3087
+ async function runWithMarketplaceNetworkRetry(action, options = {}) {
3088
+ const attempts = options.attempts ?? MARKETPLACE_NETWORK_RETRY_ATTEMPTS;
3089
+ const baseDelayMs = options.baseDelayMs ?? MARKETPLACE_NETWORK_RETRY_BASE_MS;
3063
3090
  let lastError;
3064
- for (let attempt = 1; attempt <= MARKETPLACE_NETWORK_RETRY_ATTEMPTS; attempt += 1) try {
3091
+ for (let attempt = 1; attempt <= attempts; attempt += 1) try {
3065
3092
  return await action();
3066
3093
  } catch (error) {
3067
3094
  lastError = error;
3068
- if (attempt === MARKETPLACE_NETWORK_RETRY_ATTEMPTS || !isRetryableMarketplaceNetworkError(error)) throw error;
3069
- await sleepMs(MARKETPLACE_NETWORK_RETRY_BASE_MS * 2 ** (attempt - 1));
3095
+ if (attempt === attempts || !isRetryableMarketplaceNetworkError(error)) throw error;
3096
+ await sleepMs(baseDelayMs * 2 ** (attempt - 1));
3070
3097
  }
3071
3098
  throw lastError;
3072
3099
  }
3073
3100
  //#endregion
3074
3101
  //#region src/features/marketplace/utils/marketplace-catalog.utils.ts
3075
- const MARKETPLACE_FETCH_TIMEOUT_MS = 12e3;
3076
- function normalizeMarketplaceBaseUrl(options) {
3077
- const configured = options.marketplace?.apiBaseUrl?.trim();
3078
- if (!configured) return DEFAULT_MARKETPLACE_API_BASE;
3079
- return configured.replace(/\/$/, "");
3080
- }
3081
3102
  function toMarketplaceUrl(baseUrl, path, query = {}) {
3082
3103
  const url = new URL(path, `${baseUrl.replace(/\/$/, "")}/`);
3083
3104
  for (const [key, value] of Object.entries(query)) if (typeof value === "string" && value.length > 0) url.searchParams.set(key, value);
3084
3105
  return url.toString();
3085
3106
  }
3086
3107
  async function fetchMarketplaceData(params) {
3087
- const endpoint = toMarketplaceUrl(params.baseUrl, params.path, params.query);
3108
+ const { baseUrl, baseUrls: rawBaseUrls, path, query } = params;
3109
+ const baseUrls = normalizeMarketplaceBaseUrls(rawBaseUrls, baseUrl);
3110
+ let lastError = null;
3111
+ for (const sourceBaseUrl of baseUrls) {
3112
+ const result = await fetchMarketplaceDataFromBase({
3113
+ baseUrl: sourceBaseUrl,
3114
+ path,
3115
+ query
3116
+ });
3117
+ if (result.ok || !shouldFallbackMarketplaceResult(result.status)) return result;
3118
+ lastError = result;
3119
+ }
3120
+ return lastError ?? {
3121
+ ok: false,
3122
+ status: 503,
3123
+ message: "marketplace source is not configured"
3124
+ };
3125
+ }
3126
+ async function fetchMarketplaceDataFromBase(params) {
3127
+ const { baseUrl, path, query } = params;
3128
+ const endpoint = toMarketplaceUrl(baseUrl, path, query);
3129
+ const fetchOptions = getMarketplaceFetchOptions(baseUrl);
3088
3130
  let response;
3089
3131
  try {
3090
3132
  response = await runWithMarketplaceNetworkRetry(() => fetch(endpoint, {
3091
3133
  method: "GET",
3092
3134
  headers: { Accept: "application/json" },
3093
- signal: AbortSignal.timeout(MARKETPLACE_FETCH_TIMEOUT_MS)
3094
- }));
3135
+ signal: AbortSignal.timeout(fetchOptions.timeoutMs)
3136
+ }), { attempts: fetchOptions.retryAttempts });
3095
3137
  } catch (error) {
3096
3138
  return {
3097
3139
  ok: false,
@@ -3186,15 +3228,17 @@ function toPositiveInt(raw, fallback) {
3186
3228
  return parsed;
3187
3229
  }
3188
3230
  async function fetchAllMarketplaceItems(params) {
3231
+ const { baseUrl, baseUrls, path, query: rawQuery } = params;
3189
3232
  const items = [];
3190
3233
  let sort = "relevance";
3191
3234
  let query;
3192
3235
  for (let page = 1; page <= 20; page += 1) {
3193
3236
  const result = await fetchMarketplaceData({
3194
- baseUrl: params.baseUrl,
3195
- path: params.path,
3237
+ baseUrl,
3238
+ baseUrls,
3239
+ path,
3196
3240
  query: {
3197
- ...params.query,
3241
+ ...rawQuery,
3198
3242
  page: String(page),
3199
3243
  pageSize: String(100)
3200
3244
  }
@@ -3220,6 +3264,7 @@ async function fetchAllMarketplaceItems(params) {
3220
3264
  async function fetchAllMcpMarketplaceItems(params) {
3221
3265
  return fetchAllMarketplaceItems({
3222
3266
  baseUrl: params.baseUrl,
3267
+ baseUrls: params.baseUrls,
3223
3268
  path: "/api/v1/mcp/items",
3224
3269
  query: params.query
3225
3270
  });
@@ -3233,9 +3278,9 @@ function sanitizeMarketplaceItemView(item) {
3233
3278
  //#endregion
3234
3279
  //#region src/features/marketplace/controllers/mcp-marketplace.controller.ts
3235
3280
  var McpMarketplaceController = class {
3236
- constructor(options, marketplaceBaseUrl) {
3281
+ constructor(options, marketplaceBaseUrls) {
3237
3282
  this.options = options;
3238
- this.marketplaceBaseUrl = marketplaceBaseUrl;
3283
+ this.marketplaceBaseUrls = marketplaceBaseUrls;
3239
3284
  }
3240
3285
  getInstalled = (c) => {
3241
3286
  const records = new McpInstalledViewService({ getConfig: () => loadConfigOrDefault(this.options.configPath) }).listInstalled().map((record) => ({
@@ -3270,7 +3315,7 @@ var McpMarketplaceController = class {
3270
3315
  listItems = async (c) => {
3271
3316
  const query = c.req.query();
3272
3317
  const result = await fetchAllMcpMarketplaceItems({
3273
- baseUrl: this.marketplaceBaseUrl,
3318
+ baseUrls: this.marketplaceBaseUrls,
3274
3319
  query: {
3275
3320
  q: query.q,
3276
3321
  tag: query.tag,
@@ -3298,7 +3343,7 @@ var McpMarketplaceController = class {
3298
3343
  getItem = async (c) => {
3299
3344
  const slug = encodeURIComponent(c.req.param("slug"));
3300
3345
  const result = await fetchMarketplaceData({
3301
- baseUrl: this.marketplaceBaseUrl,
3346
+ baseUrls: this.marketplaceBaseUrls,
3302
3347
  path: `/api/v1/mcp/items/${slug}`
3303
3348
  });
3304
3349
  if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
@@ -3307,7 +3352,7 @@ var McpMarketplaceController = class {
3307
3352
  getItemContent = async (c) => {
3308
3353
  const slug = encodeURIComponent(c.req.param("slug"));
3309
3354
  const result = await fetchMarketplaceData({
3310
- baseUrl: this.marketplaceBaseUrl,
3355
+ baseUrls: this.marketplaceBaseUrls,
3311
3356
  path: `/api/v1/mcp/items/${slug}/content`
3312
3357
  });
3313
3358
  if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
@@ -3322,7 +3367,7 @@ var McpMarketplaceController = class {
3322
3367
  const installer = this.options.marketplace?.installer;
3323
3368
  if (!installer?.installMcp) return c.json(err("NOT_AVAILABLE", "mcp installer is not configured"), 503);
3324
3369
  const itemResult = await fetchMarketplaceData({
3325
- baseUrl: this.marketplaceBaseUrl,
3370
+ baseUrls: this.marketplaceBaseUrls,
3326
3371
  path: `/api/v1/mcp/items/${encodeURIComponent(slug)}`
3327
3372
  });
3328
3373
  if (!itemResult.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", itemResult.message), itemResult.status);
@@ -3386,7 +3431,7 @@ var McpMarketplaceController = class {
3386
3431
  getRecommendations = async (c) => {
3387
3432
  const query = c.req.query();
3388
3433
  const result = await fetchMarketplaceData({
3389
- baseUrl: this.marketplaceBaseUrl,
3434
+ baseUrls: this.marketplaceBaseUrls,
3390
3435
  path: "/api/v1/mcp/recommendations",
3391
3436
  query: {
3392
3437
  scene: query.scene,
@@ -3539,9 +3584,9 @@ async function manageMarketplaceSkill(params) {
3539
3584
  };
3540
3585
  }
3541
3586
  var SkillMarketplaceController = class {
3542
- constructor(options, marketplaceBaseUrl) {
3587
+ constructor(options, marketplaceBaseUrls) {
3543
3588
  this.options = options;
3544
- this.marketplaceBaseUrl = marketplaceBaseUrl;
3589
+ this.marketplaceBaseUrls = marketplaceBaseUrls;
3545
3590
  }
3546
3591
  getInstalled = (c) => {
3547
3592
  return c.json(ok(collectSkillMarketplaceInstalledView(this.options)));
@@ -3566,7 +3611,7 @@ var SkillMarketplaceController = class {
3566
3611
  };
3567
3612
  loadSupportedListPage = async (query) => {
3568
3613
  const result = await fetchMarketplaceData({
3569
- baseUrl: this.marketplaceBaseUrl,
3614
+ baseUrls: this.marketplaceBaseUrls,
3570
3615
  path: "/api/v1/skills/items",
3571
3616
  query
3572
3617
  });
@@ -3578,7 +3623,7 @@ var SkillMarketplaceController = class {
3578
3623
  };
3579
3624
  listScenes = async (c) => {
3580
3625
  const result = await fetchMarketplaceData({
3581
- baseUrl: this.marketplaceBaseUrl,
3626
+ baseUrls: this.marketplaceBaseUrls,
3582
3627
  path: "/api/v1/skills/scenes"
3583
3628
  });
3584
3629
  if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
@@ -3600,7 +3645,7 @@ var SkillMarketplaceController = class {
3600
3645
  getItem = async (c) => {
3601
3646
  const slug = encodeURIComponent(c.req.param("slug"));
3602
3647
  const result = await fetchMarketplaceData({
3603
- baseUrl: this.marketplaceBaseUrl,
3648
+ baseUrls: this.marketplaceBaseUrls,
3604
3649
  path: `/api/v1/skills/items/${slug}`
3605
3650
  });
3606
3651
  if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
@@ -3614,7 +3659,7 @@ var SkillMarketplaceController = class {
3614
3659
  getItemContent = async (c) => {
3615
3660
  const slug = encodeURIComponent(c.req.param("slug"));
3616
3661
  const result = await fetchMarketplaceData({
3617
- baseUrl: this.marketplaceBaseUrl,
3662
+ baseUrls: this.marketplaceBaseUrls,
3618
3663
  path: `/api/v1/skills/items/${slug}`
3619
3664
  });
3620
3665
  if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
@@ -3624,7 +3669,7 @@ var SkillMarketplaceController = class {
3624
3669
  if (unsupportedKind) return c.json(err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`), 502);
3625
3670
  if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
3626
3671
  const contentResult = await fetchMarketplaceData({
3627
- baseUrl: this.marketplaceBaseUrl,
3672
+ baseUrls: this.marketplaceBaseUrls,
3628
3673
  path: `/api/v1/skills/items/${slug}/content`
3629
3674
  });
3630
3675
  if (!contentResult.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", contentResult.message), contentResult.status);
@@ -3667,7 +3712,7 @@ var SkillMarketplaceController = class {
3667
3712
  getRecommendations = async (c) => {
3668
3713
  const query = c.req.query();
3669
3714
  const result = await fetchMarketplaceData({
3670
- baseUrl: this.marketplaceBaseUrl,
3715
+ baseUrls: this.marketplaceBaseUrls,
3671
3716
  path: "/api/v1/skills/recommendations",
3672
3717
  query: {
3673
3718
  scene: query.scene,
@@ -4849,7 +4894,7 @@ var ServerPathRoutesController = class {
4849
4894
  //#region src/app/router.ts
4850
4895
  const NCP_AGENT_BASE_PATH = "/api/ncp/agent";
4851
4896
  const AGENT_RUNS_BASE_PATH = "/api/agent-runs";
4852
- function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
4897
+ function createUiRouteControllers(options, authService, marketplaceBaseUrls) {
4853
4898
  const { kernel, panelAppClientSdkScript, remoteAccess, runtimeControl, runtimeUpdate } = options;
4854
4899
  return {
4855
4900
  app: new AppRoutesController(options),
@@ -4869,8 +4914,8 @@ function createUiRouteControllers(options, authService, marketplaceBaseUrl) {
4869
4914
  remote: remoteAccess ? new RemoteRoutesController(remoteAccess) : null,
4870
4915
  runtimeControl: runtimeControl ? new RuntimeControlRoutesController(runtimeControl) : null,
4871
4916
  runtimeUpdate: runtimeUpdate ? new RuntimeUpdateRoutesController(runtimeUpdate) : null,
4872
- skillMarketplace: new SkillMarketplaceController(options, marketplaceBaseUrl),
4873
- mcpMarketplace: new McpMarketplaceController(options, marketplaceBaseUrl)
4917
+ skillMarketplace: new SkillMarketplaceController(options, marketplaceBaseUrls),
4918
+ mcpMarketplace: new McpMarketplaceController(options, marketplaceBaseUrls)
4874
4919
  };
4875
4920
  }
4876
4921
  function isRecord(value) {
@@ -5493,9 +5538,9 @@ var UiRouteRegistry = class {
5493
5538
  };
5494
5539
  function createUiRouter(options, authServiceOverride) {
5495
5540
  const app = new Hono();
5496
- const marketplaceBaseUrl = normalizeMarketplaceBaseUrl(options);
5541
+ const marketplaceBaseUrls = resolveMarketplaceBaseUrls(options);
5497
5542
  const authService = authServiceOverride ?? options.authService ?? new UiAuthService(options.kernel.accessManager ?? new AccessManager({ configPath: options.configPath }));
5498
- const controllers = createUiRouteControllers(options, authService, marketplaceBaseUrl);
5543
+ const controllers = createUiRouteControllers(options, authService, marketplaceBaseUrls);
5499
5544
  app.notFound((c) => c.json(err("NOT_FOUND", "endpoint not found"), 404));
5500
5545
  app.use("/api/*", async (c, next) => {
5501
5546
  const path = c.req.path;