@nextclaw/server 0.15.6 → 0.15.7
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 +26 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2987,6 +2987,7 @@ const MARKETPLACE_ZH_COPY_BY_SLUG = {
|
|
|
2987
2987
|
const MARKETPLACE_FETCH_TIMEOUT_MS = 12e3;
|
|
2988
2988
|
const DOMESTIC_MARKETPLACE_FETCH_TIMEOUT_MS = 2e3;
|
|
2989
2989
|
const DOMESTIC_MARKETPLACE_RETRY_ATTEMPTS = 2;
|
|
2990
|
+
const DOMESTIC_MARKETPLACE_MAX_SNAPSHOT_AGE_MS = 1200 * 1e3;
|
|
2990
2991
|
function resolveMarketplaceBaseUrls(options) {
|
|
2991
2992
|
const configured = options.marketplace?.apiBaseUrl?.trim();
|
|
2992
2993
|
if (configured) return [configured.replace(/\/$/, "")];
|
|
@@ -3009,6 +3010,11 @@ function getMarketplaceFetchOptions(baseUrl) {
|
|
|
3009
3010
|
function shouldFallbackMarketplaceResult(status) {
|
|
3010
3011
|
return status === 408 || status === 429 || status >= 500;
|
|
3011
3012
|
}
|
|
3013
|
+
function isStaleDomesticMarketplaceSnapshot(baseUrl, cachedAt, now = Date.now()) {
|
|
3014
|
+
if (baseUrl.replace(/\/$/, "") !== "https://api.nextclaw.net" || cachedAt === null) return false;
|
|
3015
|
+
const cachedAtMs = Date.parse(cachedAt);
|
|
3016
|
+
return !Number.isFinite(cachedAtMs) || now - cachedAtMs > DOMESTIC_MARKETPLACE_MAX_SNAPSHOT_AGE_MS;
|
|
3017
|
+
}
|
|
3012
3018
|
//#endregion
|
|
3013
3019
|
//#region src/features/marketplace/utils/marketplace-network-retry.utils.ts
|
|
3014
3020
|
const MARKETPLACE_NETWORK_RETRY_ATTEMPTS = 5;
|
|
@@ -3086,6 +3092,11 @@ async function fetchMarketplaceDataFromBase(params) {
|
|
|
3086
3092
|
message: error instanceof Error ? error.message : String(error)
|
|
3087
3093
|
};
|
|
3088
3094
|
}
|
|
3095
|
+
if (isStaleDomesticMarketplaceSnapshot(baseUrl, response.headers.get("x-nextclaw-mirror-cached-at"))) return {
|
|
3096
|
+
ok: false,
|
|
3097
|
+
status: 503,
|
|
3098
|
+
message: "domestic marketplace mirror snapshot is stale"
|
|
3099
|
+
};
|
|
3089
3100
|
let payload = null;
|
|
3090
3101
|
try {
|
|
3091
3102
|
payload = await response.json();
|
|
@@ -3454,15 +3465,6 @@ function collectSkillMarketplaceInstalledView(options) {
|
|
|
3454
3465
|
records: installed.records
|
|
3455
3466
|
};
|
|
3456
3467
|
}
|
|
3457
|
-
function collectKnownSkillNames(options) {
|
|
3458
|
-
const loader = createSkillsLoader(getWorkspacePathFromConfig(loadConfigOrDefault(options.configPath)));
|
|
3459
|
-
return new Set((loader?.listSkills(false) ?? []).map((skill) => skill.name));
|
|
3460
|
-
}
|
|
3461
|
-
function isSupportedMarketplaceSkillItem(item, knownSkillNames) {
|
|
3462
|
-
if (item.type !== "skill") return false;
|
|
3463
|
-
if (item.install.kind === "marketplace") return true;
|
|
3464
|
-
return item.install.kind === "builtin" && knownSkillNames.has(item.install.spec);
|
|
3465
|
-
}
|
|
3466
3468
|
function findUnsupportedSkillInstallKind(items) {
|
|
3467
3469
|
for (const item of items) {
|
|
3468
3470
|
if (item.type !== "skill") continue;
|
|
@@ -3545,12 +3547,11 @@ var SkillMarketplaceController = class {
|
|
|
3545
3547
|
status: 502,
|
|
3546
3548
|
message: `unsupported skill install kind from marketplace api: ${unsupportedKind}`
|
|
3547
3549
|
};
|
|
3548
|
-
const knownSkillNames = collectKnownSkillNames(this.options);
|
|
3549
3550
|
return {
|
|
3550
3551
|
ok: true,
|
|
3551
3552
|
data: {
|
|
3552
3553
|
...data,
|
|
3553
|
-
items: normalizedItems
|
|
3554
|
+
items: normalizedItems
|
|
3554
3555
|
}
|
|
3555
3556
|
};
|
|
3556
3557
|
};
|
|
@@ -3594,11 +3595,9 @@ var SkillMarketplaceController = class {
|
|
|
3594
3595
|
path: `/api/v1/skills/items/${slug}`
|
|
3595
3596
|
});
|
|
3596
3597
|
if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
3597
|
-
const knownSkillNames = collectKnownSkillNames(this.options);
|
|
3598
3598
|
const sanitized = normalizeMarketplaceItemForUi(sanitizeMarketplaceItemView(result.data));
|
|
3599
3599
|
const unsupportedKind = findUnsupportedSkillInstallKind([sanitized]);
|
|
3600
3600
|
if (unsupportedKind) return c.json(err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`), 502);
|
|
3601
|
-
if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
3602
3601
|
return c.json(ok(sanitized));
|
|
3603
3602
|
};
|
|
3604
3603
|
getItemContent = async (c) => {
|
|
@@ -3608,11 +3607,8 @@ var SkillMarketplaceController = class {
|
|
|
3608
3607
|
path: `/api/v1/skills/items/${slug}`
|
|
3609
3608
|
});
|
|
3610
3609
|
if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
3611
|
-
const
|
|
3612
|
-
const sanitized = normalizeMarketplaceItemForUi(sanitizeMarketplaceItemView(result.data));
|
|
3613
|
-
const unsupportedKind = findUnsupportedSkillInstallKind([sanitized]);
|
|
3610
|
+
const unsupportedKind = findUnsupportedSkillInstallKind([normalizeMarketplaceItemForUi(sanitizeMarketplaceItemView(result.data))]);
|
|
3614
3611
|
if (unsupportedKind) return c.json(err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`), 502);
|
|
3615
|
-
if (!isSupportedMarketplaceSkillItem(sanitized, knownSkillNames)) return c.json(err("NOT_FOUND", "marketplace item not supported by nextclaw"), 404);
|
|
3616
3612
|
const contentResult = await fetchMarketplaceData({
|
|
3617
3613
|
baseUrls: this.marketplaceBaseUrls,
|
|
3618
3614
|
path: `/api/v1/skills/items/${slug}/content`
|
|
@@ -3665,12 +3661,13 @@ var SkillMarketplaceController = class {
|
|
|
3665
3661
|
}
|
|
3666
3662
|
});
|
|
3667
3663
|
if (!result.ok) return c.json(err("MARKETPLACE_UNAVAILABLE", result.message), result.status);
|
|
3668
|
-
const
|
|
3669
|
-
const
|
|
3664
|
+
const items = sanitizeMarketplaceListItems(result.data.items).map((item) => normalizeMarketplaceItemForUi(item));
|
|
3665
|
+
const unsupportedKind = findUnsupportedSkillInstallKind(items);
|
|
3666
|
+
if (unsupportedKind) return c.json(err("MARKETPLACE_CONTRACT_MISMATCH", `unsupported skill install kind from marketplace api: ${unsupportedKind}`), 502);
|
|
3670
3667
|
return c.json(ok({
|
|
3671
3668
|
...result.data,
|
|
3672
|
-
total:
|
|
3673
|
-
items
|
|
3669
|
+
total: items.length,
|
|
3670
|
+
items
|
|
3674
3671
|
}));
|
|
3675
3672
|
};
|
|
3676
3673
|
};
|
|
@@ -6255,6 +6252,14 @@ async function startUiServer(gateway) {
|
|
|
6255
6252
|
const resolvedAllowOrigin = allowOrigin ?? (isPanelAppRuntimeCors ? NULL_ORIGIN : null);
|
|
6256
6253
|
if (resolvedAllowOrigin) for (const [name, value] of createCorsHeaders(resolvedAllowOrigin, allowHeaders, c.res.headers.get("Vary"))) c.res.headers.set(name, value);
|
|
6257
6254
|
});
|
|
6255
|
+
const uiInjectionPath = join(dirname(gateway.configPath), "ui-inject.js");
|
|
6256
|
+
app.get("/api/ui-inject.js", async (c) => c.body(await readFile(uiInjectionPath, "utf-8").catch((error) => {
|
|
6257
|
+
if (error.code === "ENOENT") return "";
|
|
6258
|
+
throw error;
|
|
6259
|
+
}), 200, {
|
|
6260
|
+
"content-type": "application/javascript; charset=utf-8",
|
|
6261
|
+
"cache-control": "no-store"
|
|
6262
|
+
}));
|
|
6258
6263
|
const eventStreamAuth = new EventStreamAuthService({
|
|
6259
6264
|
uiAuth: authService,
|
|
6260
6265
|
extensionAuth: gateway.extensions,
|