dsh-plugin-shop 0.3.1 → 0.4.0
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/lib/client.js +207 -10
- package/lib/index.js +43 -5
- package/lib/typert.host.js +7 -6
- package/lib/typert.remote-client.js +6 -5
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -1890,6 +1890,115 @@ window.__ModuleLoader__.load({
|
|
|
1890
1890
|
result.value = merged.data;
|
|
1891
1891
|
return result;
|
|
1892
1892
|
}
|
|
1893
|
+
const $ZodRecord = /*@__PURE__*/ $constructor("$ZodRecord", (inst, def) => {
|
|
1894
|
+
$ZodType.init(inst, def);
|
|
1895
|
+
inst._zod.parse = (payload, ctx) => {
|
|
1896
|
+
const input = payload.value;
|
|
1897
|
+
if (!isPlainObject(input)) {
|
|
1898
|
+
payload.issues.push({
|
|
1899
|
+
expected: "record",
|
|
1900
|
+
code: "invalid_type",
|
|
1901
|
+
input,
|
|
1902
|
+
inst
|
|
1903
|
+
});
|
|
1904
|
+
return payload;
|
|
1905
|
+
}
|
|
1906
|
+
const proms = [];
|
|
1907
|
+
const values = def.keyType._zod.values;
|
|
1908
|
+
if (values) {
|
|
1909
|
+
payload.value = {};
|
|
1910
|
+
const recordKeys = /* @__PURE__ */ new Set();
|
|
1911
|
+
for (const key of values) if (typeof key === "string" || typeof key === "number" || typeof key === "symbol") {
|
|
1912
|
+
recordKeys.add(typeof key === "number" ? key.toString() : key);
|
|
1913
|
+
const keyResult = def.keyType._zod.run({
|
|
1914
|
+
value: key,
|
|
1915
|
+
issues: []
|
|
1916
|
+
}, ctx);
|
|
1917
|
+
if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
1918
|
+
if (keyResult.issues.length) {
|
|
1919
|
+
payload.issues.push({
|
|
1920
|
+
code: "invalid_key",
|
|
1921
|
+
origin: "record",
|
|
1922
|
+
issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
|
|
1923
|
+
input: key,
|
|
1924
|
+
path: [key],
|
|
1925
|
+
inst
|
|
1926
|
+
});
|
|
1927
|
+
continue;
|
|
1928
|
+
}
|
|
1929
|
+
const outKey = keyResult.value;
|
|
1930
|
+
const result = def.valueType._zod.run({
|
|
1931
|
+
value: input[key],
|
|
1932
|
+
issues: []
|
|
1933
|
+
}, ctx);
|
|
1934
|
+
if (result instanceof Promise) proms.push(result.then((result) => {
|
|
1935
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1936
|
+
payload.value[outKey] = result.value;
|
|
1937
|
+
}));
|
|
1938
|
+
else {
|
|
1939
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1940
|
+
payload.value[outKey] = result.value;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
let unrecognized;
|
|
1944
|
+
for (const key in input) if (!recordKeys.has(key)) {
|
|
1945
|
+
unrecognized = unrecognized ?? [];
|
|
1946
|
+
unrecognized.push(key);
|
|
1947
|
+
}
|
|
1948
|
+
if (unrecognized && unrecognized.length > 0) payload.issues.push({
|
|
1949
|
+
code: "unrecognized_keys",
|
|
1950
|
+
input,
|
|
1951
|
+
inst,
|
|
1952
|
+
keys: unrecognized
|
|
1953
|
+
});
|
|
1954
|
+
} else {
|
|
1955
|
+
payload.value = {};
|
|
1956
|
+
for (const key of Reflect.ownKeys(input)) {
|
|
1957
|
+
if (key === "__proto__") continue;
|
|
1958
|
+
if (!Object.prototype.propertyIsEnumerable.call(input, key)) continue;
|
|
1959
|
+
let keyResult = def.keyType._zod.run({
|
|
1960
|
+
value: key,
|
|
1961
|
+
issues: []
|
|
1962
|
+
}, ctx);
|
|
1963
|
+
if (keyResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
1964
|
+
if (typeof key === "string" && number$1.test(key) && keyResult.issues.length) {
|
|
1965
|
+
const retryResult = def.keyType._zod.run({
|
|
1966
|
+
value: Number(key),
|
|
1967
|
+
issues: []
|
|
1968
|
+
}, ctx);
|
|
1969
|
+
if (retryResult instanceof Promise) throw new Error("Async schemas not supported in object keys currently");
|
|
1970
|
+
if (retryResult.issues.length === 0) keyResult = retryResult;
|
|
1971
|
+
}
|
|
1972
|
+
if (keyResult.issues.length) {
|
|
1973
|
+
if (def.mode === "loose") payload.value[key] = input[key];
|
|
1974
|
+
else payload.issues.push({
|
|
1975
|
+
code: "invalid_key",
|
|
1976
|
+
origin: "record",
|
|
1977
|
+
issues: keyResult.issues.map((iss) => finalizeIssue(iss, ctx, config())),
|
|
1978
|
+
input: key,
|
|
1979
|
+
path: [key],
|
|
1980
|
+
inst
|
|
1981
|
+
});
|
|
1982
|
+
continue;
|
|
1983
|
+
}
|
|
1984
|
+
const result = def.valueType._zod.run({
|
|
1985
|
+
value: input[key],
|
|
1986
|
+
issues: []
|
|
1987
|
+
}, ctx);
|
|
1988
|
+
if (result instanceof Promise) proms.push(result.then((result) => {
|
|
1989
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1990
|
+
payload.value[keyResult.value] = result.value;
|
|
1991
|
+
}));
|
|
1992
|
+
else {
|
|
1993
|
+
if (result.issues.length) payload.issues.push(...prefixIssues(key, result.issues));
|
|
1994
|
+
payload.value[keyResult.value] = result.value;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
if (proms.length) return Promise.all(proms).then(() => payload);
|
|
1999
|
+
return payload;
|
|
2000
|
+
};
|
|
2001
|
+
});
|
|
1893
2002
|
const $ZodEnum = /*@__PURE__*/ $constructor("$ZodEnum", (inst, def) => {
|
|
1894
2003
|
$ZodType.init(inst, def);
|
|
1895
2004
|
const values = getEnumValues(def.entries);
|
|
@@ -3180,6 +3289,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3180
3289
|
const isSimpleIntersection = (val) => "allOf" in val && Object.keys(val).length === 1;
|
|
3181
3290
|
json.allOf = [...isSimpleIntersection(a) ? a.allOf : [a], ...isSimpleIntersection(b) ? b.allOf : [b]];
|
|
3182
3291
|
};
|
|
3292
|
+
const recordProcessor = (schema, ctx, _json, params) => {
|
|
3293
|
+
const json = _json;
|
|
3294
|
+
const def = schema._zod.def;
|
|
3295
|
+
json.type = "object";
|
|
3296
|
+
const keyType = def.keyType;
|
|
3297
|
+
const patterns = keyType._zod.bag?.patterns;
|
|
3298
|
+
if (def.mode === "loose" && patterns && patterns.size > 0) {
|
|
3299
|
+
const valueSchema = process(def.valueType, ctx, {
|
|
3300
|
+
...params,
|
|
3301
|
+
path: [
|
|
3302
|
+
...params.path,
|
|
3303
|
+
"patternProperties",
|
|
3304
|
+
"*"
|
|
3305
|
+
]
|
|
3306
|
+
});
|
|
3307
|
+
json.patternProperties = {};
|
|
3308
|
+
for (const pattern of patterns) json.patternProperties[pattern.source] = valueSchema;
|
|
3309
|
+
} else {
|
|
3310
|
+
if (ctx.target === "draft-07" || ctx.target === "draft-2020-12") json.propertyNames = process(def.keyType, ctx, {
|
|
3311
|
+
...params,
|
|
3312
|
+
path: [...params.path, "propertyNames"]
|
|
3313
|
+
});
|
|
3314
|
+
json.additionalProperties = process(def.valueType, ctx, {
|
|
3315
|
+
...params,
|
|
3316
|
+
path: [...params.path, "additionalProperties"]
|
|
3317
|
+
});
|
|
3318
|
+
}
|
|
3319
|
+
const keyValues = keyType._zod.values;
|
|
3320
|
+
if (keyValues) {
|
|
3321
|
+
const validKeyValues = [...keyValues].filter((v) => typeof v === "string" || typeof v === "number");
|
|
3322
|
+
if (validKeyValues.length > 0) json.required = validKeyValues;
|
|
3323
|
+
}
|
|
3324
|
+
};
|
|
3183
3325
|
const nullableProcessor = (schema, ctx, json, params) => {
|
|
3184
3326
|
const def = schema._zod.def;
|
|
3185
3327
|
const inner = process(def.innerType, ctx, params);
|
|
@@ -3871,6 +4013,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
3871
4013
|
right
|
|
3872
4014
|
});
|
|
3873
4015
|
}
|
|
4016
|
+
const ZodRecord = /*@__PURE__*/ $constructor("ZodRecord", (inst, def) => {
|
|
4017
|
+
$ZodRecord.init(inst, def);
|
|
4018
|
+
ZodType.init(inst, def);
|
|
4019
|
+
inst._zod.processJSONSchema = (ctx, json, params) => recordProcessor(inst, ctx, json, params);
|
|
4020
|
+
inst.keyType = def.keyType;
|
|
4021
|
+
inst.valueType = def.valueType;
|
|
4022
|
+
});
|
|
4023
|
+
function record(keyType, valueType, params) {
|
|
4024
|
+
if (!valueType || !valueType._zod) return new ZodRecord({
|
|
4025
|
+
type: "record",
|
|
4026
|
+
keyType: string(),
|
|
4027
|
+
valueType: keyType,
|
|
4028
|
+
...normalizeParams(valueType)
|
|
4029
|
+
});
|
|
4030
|
+
return new ZodRecord({
|
|
4031
|
+
type: "record",
|
|
4032
|
+
keyType,
|
|
4033
|
+
valueType,
|
|
4034
|
+
...normalizeParams(params)
|
|
4035
|
+
});
|
|
4036
|
+
}
|
|
3874
4037
|
const ZodEnum = /*@__PURE__*/ $constructor("ZodEnum", (inst, def) => {
|
|
3875
4038
|
$ZodEnum.init(inst, def);
|
|
3876
4039
|
ZodType.init(inst, def);
|
|
@@ -4140,7 +4303,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4140
4303
|
"denied": array(object({
|
|
4141
4304
|
"name": string(),
|
|
4142
4305
|
"detail": string()
|
|
4143
|
-
}))
|
|
4306
|
+
})),
|
|
4307
|
+
"stars": record(string(), number())
|
|
4144
4308
|
});
|
|
4145
4309
|
const dsh_plugin_shop_shop_installStart_parameter_0$schema = object({
|
|
4146
4310
|
"name": string(),
|
|
@@ -4220,7 +4384,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4220
4384
|
},
|
|
4221
4385
|
sourceLocation: {
|
|
4222
4386
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4223
|
-
"line":
|
|
4387
|
+
"line": 180,
|
|
4224
4388
|
"column": 9
|
|
4225
4389
|
}
|
|
4226
4390
|
},
|
|
@@ -4248,7 +4412,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4248
4412
|
},
|
|
4249
4413
|
sourceLocation: {
|
|
4250
4414
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4251
|
-
"line":
|
|
4415
|
+
"line": 206,
|
|
4252
4416
|
"column": 9
|
|
4253
4417
|
}
|
|
4254
4418
|
},
|
|
@@ -4275,7 +4439,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4275
4439
|
},
|
|
4276
4440
|
sourceLocation: {
|
|
4277
4441
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4278
|
-
"line":
|
|
4442
|
+
"line": 244,
|
|
4279
4443
|
"column": 3
|
|
4280
4444
|
}
|
|
4281
4445
|
},
|
|
@@ -4293,7 +4457,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4293
4457
|
},
|
|
4294
4458
|
sourceLocation: {
|
|
4295
4459
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4296
|
-
"line":
|
|
4460
|
+
"line": 252,
|
|
4297
4461
|
"column": 9
|
|
4298
4462
|
}
|
|
4299
4463
|
},
|
|
@@ -4320,7 +4484,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4320
4484
|
},
|
|
4321
4485
|
sourceLocation: {
|
|
4322
4486
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4323
|
-
"line":
|
|
4487
|
+
"line": 149,
|
|
4324
4488
|
"column": 3
|
|
4325
4489
|
}
|
|
4326
4490
|
}
|
|
@@ -4442,6 +4606,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4442
4606
|
function categoryKey(entry) {
|
|
4443
4607
|
return CATEGORY_KEYS[entry.catalog?.category ?? "other"];
|
|
4444
4608
|
}
|
|
4609
|
+
/** Sort the shelf: stars descending, un-starred entries last, name ascending
|
|
4610
|
+
* (case-insensitive) on ties (spec 2026-08-26-github-stars-design.md D1).
|
|
4611
|
+
* Display-time only — the catalog's own name sort is untouched. */
|
|
4612
|
+
function sortByStars(entries, stars) {
|
|
4613
|
+
const count = (e) => stars[e.name] ?? -1;
|
|
4614
|
+
return [...entries].sort((a, b) => {
|
|
4615
|
+
const byStars = count(b) - count(a);
|
|
4616
|
+
if (byStars !== 0) return byStars;
|
|
4617
|
+
return a.name.localeCompare(b.name, void 0, { sensitivity: "base" });
|
|
4618
|
+
});
|
|
4619
|
+
}
|
|
4620
|
+
/** 999 → "999"; 1000 → "1k"; 1234 → "1.2k"; 1500 → "1.5k"; 99999 → "100k". */
|
|
4621
|
+
function formatStars(n) {
|
|
4622
|
+
if (n < 1e3) return String(n);
|
|
4623
|
+
return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}k`;
|
|
4624
|
+
}
|
|
4445
4625
|
//#endregion
|
|
4446
4626
|
//#region src/client/locales.ts
|
|
4447
4627
|
/** Copy dictionaries for the shop Settings tab. */
|
|
@@ -4454,6 +4634,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4454
4634
|
search: "搜索插件",
|
|
4455
4635
|
catalog: "插件目录",
|
|
4456
4636
|
catalogStats: "{count} 个插件 · 构建于 {date}",
|
|
4637
|
+
stars: "{count} 星",
|
|
4457
4638
|
categoryTool: "工具",
|
|
4458
4639
|
categoryProvider: "模型服务",
|
|
4459
4640
|
categoryUi: "界面",
|
|
@@ -4505,6 +4686,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4505
4686
|
search: "Search plugins",
|
|
4506
4687
|
catalog: "Plugin catalog",
|
|
4507
4688
|
catalogStats: "{count} packages · built {date}",
|
|
4689
|
+
stars: "{count} stars",
|
|
4508
4690
|
categoryTool: "Tool",
|
|
4509
4691
|
categoryProvider: "Provider",
|
|
4510
4692
|
categoryUi: "UI",
|
|
@@ -4600,7 +4782,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4600
4782
|
}
|
|
4601
4783
|
//#endregion
|
|
4602
4784
|
//#region \0dsh-plugin-shop-css:e3675a89
|
|
4603
|
-
const css = "/* Shop tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). The signature is the category spine: one HUE per\n * category (six fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so six brand opacities read as six shades\n * of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.s8583e3_client.s942a79_config.s5f67aa_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` pins this. */\n\n.s255e5a_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.s44a3ec_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s3a0ece_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n}\n\n.s520416_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s520416_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s30e662_skeletonCover {\n display: block;\n height: 26px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);\n}\n\n.s8c7d6f_skeletonName {\n width: 55%;\n height: 14px;\n margin: 12px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sf5179e_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sbb0d25_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 14px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s520416_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s73242a_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s232ec4_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s232ec4_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s1555aa_staleBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s3946f1_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.s668774_catalogHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.sccc4d1_catalogStats {\n margin: -8px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s6de1ab_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n.sf657f5_cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshShopCardsIn 220ms ease;\n}\n\n@keyframes dshShopCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sf657f5_cards { animation: none; }\n}\n\n.s65f383_card {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n /* Off-screen cards skip layout and paint; the placeholder keeps scrollbar\n * estimation sane before the browser has measured the real height. */\n content-visibility: auto;\n contain-intrinsic-size: auto 240px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.sd7ee01_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s705cc6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s65f383_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s65f383_card { transition: none; }\n .s65f383_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.s4ce25d_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--spine-hue, #8B8E96);\n}\n\n.s65f383_card[data-category='tool'] { --spine-hue: #4C8DFF; }\n.s65f383_card[data-category='provider'] { --spine-hue: #A78BFA; }\n.s65f383_card[data-category='ui'] { --spine-hue: #2DD4BF; }\n.s65f383_card[data-category='workflow'] { --spine-hue: #F59E0B; }\n.s65f383_card[data-category='integration'] { --spine-hue: #34D399; }\n.s65f383_card[data-category='other'] { --spine-hue: #8B8E96; }\n\n.s9e2bec_cardCover {\n display: block;\n padding: 5px 12px 5px 12px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n background: color-mix(in srgb, var(--spine-hue, #8B8E96) 12%, transparent);\n}\n\n.s1a7c5b_coverLabel {\n display: block;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--spine-hue, #8B8E96);\n}\n\n.sa97234_entryHeader {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n padding: 10px 12px 6px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.sa97234_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name owns the full header width; badges sit on their own line below. */\n.sc3f149_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n.s513026_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.s5e82cb_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s5e82cb_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s23e3e1_unclaimedBadge {\n padding: 1px 7px;\n border-radius: 999px;\n border: 1px dashed var(--dsw-alias-border-l2);\n font-size: 11px;\n line-height: 1.6;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s73f7fb_chevron, .s61393c_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s61393c_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s73f7fb_chevron, .s61393c_chevronOpen { transition: none; }\n}\n\n.s820ebf_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px 12px;\n}\n\n.sb8fbc8_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.se507db_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sd58c6d_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s4d374c_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se7aaed_installButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.se7aaed_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb43a49_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sb43a49_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6e45d1_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s6e45d1_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se7aaed_installButton:focus-visible, .sb43a49_confirmButton:focus-visible, .s6e45d1_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sc4f2ac_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s3c0ace_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s4b2373_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s52b5a5_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s64ab71_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s1531a8_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf20dda_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sfd3021_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s50ba35_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se75489_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Installed section. */\n.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s877c68_outdatedVersions {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa1f556_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.s11c019_switch {\n position: relative;\n width: 32px;\n height: 18px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.s7580e8_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 55%, transparent);\n}\n\n.saab2b3_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11c019_switch, .saab2b3_switchKnob { transition: none; }\n}\n";
|
|
4785
|
+
const css = "/* Shop tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). The signature is the category spine: one HUE per\n * category (six fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so six brand opacities read as six shades\n * of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.s8583e3_client.s942a79_config.s5f67aa_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` pins this. */\n\n.s255e5a_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n.s44a3ec_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s3a0ece_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n}\n\n.s520416_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s520416_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s30e662_skeletonCover {\n display: block;\n height: 26px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);\n}\n\n.s8c7d6f_skeletonName {\n width: 55%;\n height: 14px;\n margin: 12px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sf5179e_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sbb0d25_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 14px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s520416_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s73242a_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s232ec4_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s232ec4_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s1555aa_staleBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s3946f1_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.s668774_catalogHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.sccc4d1_catalogStats {\n margin: -8px 0 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s6de1ab_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n.sf657f5_cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));\n gap: 12px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshShopCardsIn 220ms ease;\n}\n\n@keyframes dshShopCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sf657f5_cards { animation: none; }\n}\n\n.s65f383_card {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n /* Off-screen cards skip layout and paint; the placeholder keeps scrollbar\n * estimation sane before the browser has measured the real height. */\n content-visibility: auto;\n contain-intrinsic-size: auto 240px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.sd7ee01_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s705cc6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s65f383_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s65f383_card { transition: none; }\n .s65f383_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.s4ce25d_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--spine-hue, #8B8E96);\n}\n\n.s65f383_card[data-category='tool'] { --spine-hue: #4C8DFF; }\n.s65f383_card[data-category='provider'] { --spine-hue: #A78BFA; }\n.s65f383_card[data-category='ui'] { --spine-hue: #2DD4BF; }\n.s65f383_card[data-category='workflow'] { --spine-hue: #F59E0B; }\n.s65f383_card[data-category='integration'] { --spine-hue: #34D399; }\n.s65f383_card[data-category='other'] { --spine-hue: #8B8E96; }\n\n.s9e2bec_cardCover {\n display: block;\n padding: 5px 12px 5px 12px;\n border-bottom: 1px solid var(--dsw-alias-border-l1);\n background: color-mix(in srgb, var(--spine-hue, #8B8E96) 12%, transparent);\n}\n\n.s1a7c5b_coverLabel {\n display: block;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--spine-hue, #8B8E96);\n}\n\n.sa97234_entryHeader {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n padding: 10px 12px 6px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.sa97234_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name owns the full header width; badges sit on their own line below. */\n.sc3f149_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n\n.s513026_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n.s5e82cb_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s5e82cb_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s23e3e1_unclaimedBadge {\n padding: 1px 7px;\n border-radius: 999px;\n border: 1px dashed var(--dsw-alias-border-l2);\n font-size: 11px;\n line-height: 1.6;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sff43b4_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s73f7fb_chevron, .s61393c_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s61393c_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s73f7fb_chevron, .s61393c_chevronOpen { transition: none; }\n}\n\n.s820ebf_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px 12px;\n}\n\n.sb8fbc8_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.se507db_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sfb4d2f_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sfb4d2f_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sfb4d2f_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sd58c6d_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s4d374c_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se7aaed_installButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.se7aaed_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb43a49_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sb43a49_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6e45d1_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s6e45d1_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se7aaed_installButton:focus-visible, .sb43a49_confirmButton:focus-visible, .s6e45d1_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sc4f2ac_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s3c0ace_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s4b2373_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s52b5a5_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s64ab71_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s1531a8_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf20dda_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sfd3021_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s50ba35_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se75489_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Installed section. */\n.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s877c68_outdatedVersions {\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa1f556_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.s11c019_switch {\n position: relative;\n width: 32px;\n height: 18px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n.s7580e8_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 55%, transparent);\n}\n\n.saab2b3_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11c019_switch, .saab2b3_switchKnob { transition: none; }\n}\n";
|
|
4604
4786
|
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"e3675a89\"]")) {
|
|
4605
4787
|
const tag = document.createElement("style");
|
|
4606
4788
|
tag.dataset.pluginCss = "e3675a89";
|
|
@@ -4641,6 +4823,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4641
4823
|
"badges": "s513026_badges",
|
|
4642
4824
|
"tierBadge": "s5e82cb_tierBadge",
|
|
4643
4825
|
"unclaimedBadge": "s23e3e1_unclaimedBadge",
|
|
4826
|
+
"starsBadge": "sff43b4_starsBadge",
|
|
4644
4827
|
"chevron": "s73f7fb_chevron",
|
|
4645
4828
|
"chevronOpen": "s61393c_chevronOpen",
|
|
4646
4829
|
"body": "s820ebf_body",
|
|
@@ -4703,7 +4886,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4703
4886
|
* (name, tier, category, unclaimed marker), the plain-text summary in both
|
|
4704
4887
|
* languages, the self-declared capabilities, the detail section, and the
|
|
4705
4888
|
* install controls. */
|
|
4706
|
-
const EntryCard = (0, react.memo)(function EntryCard({ entry, t, install, installStatus }) {
|
|
4889
|
+
const EntryCard = (0, react.memo)(function EntryCard({ entry, stars, t, install, installStatus }) {
|
|
4707
4890
|
const [open, setOpen] = (0, react.useState)(false);
|
|
4708
4891
|
const detailId = (0, react.useId)();
|
|
4709
4892
|
const summary = entry.catalog?.summary;
|
|
@@ -4746,6 +4929,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4746
4929
|
className: _dsh_plugin_shop_css_e3675a89_default.unclaimedBadge,
|
|
4747
4930
|
children: t("unclaimed")
|
|
4748
4931
|
}),
|
|
4932
|
+
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4933
|
+
className: _dsh_plugin_shop_css_e3675a89_default.starsBadge,
|
|
4934
|
+
role: "img",
|
|
4935
|
+
"aria-label": t("stars", { count: stars }),
|
|
4936
|
+
children: ["★ ", formatStars(stars)]
|
|
4937
|
+
}),
|
|
4749
4938
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { open })
|
|
4750
4939
|
]
|
|
4751
4940
|
})]
|
|
@@ -4783,7 +4972,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4783
4972
|
}),
|
|
4784
4973
|
entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4785
4974
|
className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
|
|
4786
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("repository") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: entry.repository
|
|
4975
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("repository") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /^https?:\/\//.test(entry.repository) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
4976
|
+
href: entry.repository,
|
|
4977
|
+
target: "_blank",
|
|
4978
|
+
rel: "noopener noreferrer",
|
|
4979
|
+
children: entry.repository
|
|
4980
|
+
}) : entry.repository })]
|
|
4787
4981
|
}),
|
|
4788
4982
|
entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
4789
4983
|
className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
|
|
@@ -5097,6 +5291,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5097
5291
|
});
|
|
5098
5292
|
}, [catalogState, query]);
|
|
5099
5293
|
filteredLenRef.current = filtered.length;
|
|
5294
|
+
const stars = catalogState.kind === "ready" ? catalogState.result.stars : {};
|
|
5295
|
+
const sorted = (0, react.useMemo)(() => sortByStars(filtered, stars), [filtered, stars]);
|
|
5100
5296
|
(0, react.useEffect)(() => {
|
|
5101
5297
|
if (!incremental) return;
|
|
5102
5298
|
const node = sentinelRef.current;
|
|
@@ -5111,7 +5307,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5111
5307
|
visibleCount,
|
|
5112
5308
|
filtered.length
|
|
5113
5309
|
]);
|
|
5114
|
-
const visible = incremental ?
|
|
5310
|
+
const visible = incremental ? sorted.slice(0, visibleCount) : sorted;
|
|
5115
5311
|
const tiers = (0, react.useMemo)(() => {
|
|
5116
5312
|
const map = /* @__PURE__ */ new Map();
|
|
5117
5313
|
if (catalogState.kind === "ready") for (const entry of catalogState.result.plugins) map.set(entry.name, entry.tier);
|
|
@@ -5203,6 +5399,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5203
5399
|
className: _dsh_plugin_shop_css_e3675a89_default.cards,
|
|
5204
5400
|
children: [visible.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
|
|
5205
5401
|
entry,
|
|
5402
|
+
stars: stars[entry.name],
|
|
5206
5403
|
t,
|
|
5207
5404
|
install,
|
|
5208
5405
|
installStatus
|
package/lib/index.js
CHANGED
|
@@ -63,7 +63,11 @@ const pointerSchema = z.object({
|
|
|
63
63
|
plugins: z.object({
|
|
64
64
|
url: z.string(),
|
|
65
65
|
sha256: z.string()
|
|
66
|
-
})
|
|
66
|
+
}),
|
|
67
|
+
stars: z.object({
|
|
68
|
+
url: z.string(),
|
|
69
|
+
sha256: z.string()
|
|
70
|
+
}).optional()
|
|
67
71
|
});
|
|
68
72
|
const nodeFs = {
|
|
69
73
|
exists: (path) => existsSync(path),
|
|
@@ -85,13 +89,28 @@ function resolveDataUrl(baseUrl, url) {
|
|
|
85
89
|
if (resolved.origin !== new URL(baseUrl).origin) throw new Error("catalog data url must be relative to the catalog base");
|
|
86
90
|
return resolved.href;
|
|
87
91
|
}
|
|
92
|
+
/** Read and verify a cached/fetched stars sidecar; ANY irregularity degrades
|
|
93
|
+
* to an empty map — stars are advisory (spec §5). */
|
|
94
|
+
function parseStarsText(text) {
|
|
95
|
+
try {
|
|
96
|
+
const parsed = JSON.parse(text);
|
|
97
|
+
if (typeof parsed.stars !== "object" || parsed.stars === null) return {};
|
|
98
|
+
const out = {};
|
|
99
|
+
for (const [key, value] of Object.entries(parsed.stars)) if (typeof value === "number") out[key] = value;
|
|
100
|
+
return out;
|
|
101
|
+
} catch {
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
88
105
|
/**
|
|
89
106
|
* Load the catalog snapshot: fetch the pointer, verify the data file's sha256
|
|
90
107
|
* against it, cache both on disk, and serve the cached copy with `stale: true`
|
|
91
108
|
* only when the transport itself failed — the fetch threw or returned a
|
|
92
109
|
* non-2xx (§10). A schemaVersion higher than this build supports, a malformed
|
|
93
110
|
* pointer or data file, an absolute data URL, or a sha256 mismatch — fresh or
|
|
94
|
-
* cached — throws even when a cache exists; never silently degraded.
|
|
111
|
+
* cached — throws even when a cache exists; never silently degraded. The stars
|
|
112
|
+
* sidecar is the sole exception: any irregularity there, a refused url
|
|
113
|
+
* included, degrades to no stars (spec §5).
|
|
95
114
|
*/
|
|
96
115
|
async function loadCatalog(options) {
|
|
97
116
|
const { baseUrl, cacheDir, refresh = false, fetchImpl = fetch, now = () => /* @__PURE__ */ new Date(), fsImpl = nodeFs } = options;
|
|
@@ -118,11 +137,17 @@ async function loadCatalog(options) {
|
|
|
118
137
|
if (actual !== pointer.plugins.sha256) throw new Error(`cached catalog data failed integrity check: expected ${pointer.plugins.sha256}, got ${actual}`);
|
|
119
138
|
const data = dataSchema.parse(JSON.parse(dataText));
|
|
120
139
|
if (data.schemaVersion > 2) throw new Error(`catalog schemaVersion ${data.schemaVersion} is newer than this build supports (2)`);
|
|
140
|
+
let stars = {};
|
|
141
|
+
if (pointer.stars !== void 0) try {
|
|
142
|
+
const starsText = fsImpl.read(join(cacheDir, basename(pointer.stars.url)));
|
|
143
|
+
if (createHash("sha256").update(starsText).digest("hex") === pointer.stars.sha256) stars = parseStarsText(starsText);
|
|
144
|
+
} catch {}
|
|
121
145
|
return {
|
|
122
146
|
schemaVersion: pointer.schemaVersion,
|
|
123
147
|
builtAt: pointer.builtAt,
|
|
124
148
|
entries: data.plugins,
|
|
125
|
-
denied: data.denied
|
|
149
|
+
denied: data.denied,
|
|
150
|
+
stars
|
|
126
151
|
};
|
|
127
152
|
} catch {
|
|
128
153
|
return null;
|
|
@@ -171,11 +196,23 @@ async function loadCatalog(options) {
|
|
|
171
196
|
if (actual !== pointer.plugins.sha256) throw new Error(`catalog data failed integrity check: expected ${pointer.plugins.sha256}, got ${actual}`);
|
|
172
197
|
const data = dataSchema.parse(JSON.parse(dataText));
|
|
173
198
|
if (data.schemaVersion > 2) throw new Error(`catalog schemaVersion ${data.schemaVersion} is newer than this build supports (2)`);
|
|
199
|
+
let stars = {};
|
|
200
|
+
if (pointer.stars !== void 0) try {
|
|
201
|
+
const starsResponse = await fetchImpl(resolveDataUrl(baseUrl, pointer.stars.url));
|
|
202
|
+
if (starsResponse.ok) {
|
|
203
|
+
const starsText = await starsResponse.text();
|
|
204
|
+
if (createHash("sha256").update(starsText).digest("hex") === pointer.stars.sha256) {
|
|
205
|
+
stars = parseStarsText(starsText);
|
|
206
|
+
fsImpl.write(join(cacheDir, basename(pointer.stars.url)), starsText);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
} catch {}
|
|
174
210
|
const snapshot = {
|
|
175
211
|
schemaVersion: pointer.schemaVersion,
|
|
176
212
|
builtAt: pointer.builtAt,
|
|
177
213
|
entries: data.plugins,
|
|
178
|
-
denied: data.denied
|
|
214
|
+
denied: data.denied,
|
|
215
|
+
stars
|
|
179
216
|
};
|
|
180
217
|
fsImpl.write(indexPath, JSON.stringify(pointer));
|
|
181
218
|
fsImpl.write(join(cacheDir, basename(pointer.plugins.url)), dataText);
|
|
@@ -626,7 +663,8 @@ let ShopGateway = (() => {
|
|
|
626
663
|
builtAt: snapshot.builtAt,
|
|
627
664
|
stale,
|
|
628
665
|
plugins: snapshot.entries,
|
|
629
|
-
denied: snapshot.denied
|
|
666
|
+
denied: snapshot.denied,
|
|
667
|
+
stars: snapshot.stars
|
|
630
668
|
};
|
|
631
669
|
}
|
|
632
670
|
/**
|
package/lib/typert.host.js
CHANGED
|
@@ -36,6 +36,7 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
|
|
|
36
36
|
'name': z.string(),
|
|
37
37
|
'detail': z.string(),
|
|
38
38
|
})),
|
|
39
|
+
'stars': z.record(z.string(), z.number()),
|
|
39
40
|
})
|
|
40
41
|
const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
|
|
41
42
|
'name': z.string(),
|
|
@@ -104,7 +105,7 @@ export const TYPERT = {
|
|
|
104
105
|
typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
|
|
105
106
|
schema: dsh_plugin_shop_shop_catalog_result$schema,
|
|
106
107
|
},
|
|
107
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
108
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":180,"column":9},
|
|
108
109
|
},
|
|
109
110
|
{
|
|
110
111
|
id: 'dsh-plugin-shop#shop/installStart',
|
|
@@ -130,7 +131,7 @@ export const TYPERT = {
|
|
|
130
131
|
typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
|
|
131
132
|
schema: dsh_plugin_shop_shop_installStart_result$schema,
|
|
132
133
|
},
|
|
133
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
134
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":206,"column":9},
|
|
134
135
|
},
|
|
135
136
|
{
|
|
136
137
|
id: 'dsh-plugin-shop#shop/installStatus',
|
|
@@ -155,7 +156,7 @@ export const TYPERT = {
|
|
|
155
156
|
typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
|
|
156
157
|
schema: dsh_plugin_shop_shop_installStatus_result$schema,
|
|
157
158
|
},
|
|
158
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
159
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":3},
|
|
159
160
|
},
|
|
160
161
|
{
|
|
161
162
|
id: 'dsh-plugin-shop#shop/outdated',
|
|
@@ -170,7 +171,7 @@ export const TYPERT = {
|
|
|
170
171
|
typeSymbol: 'dsh-plugin-shop#shop/outdated:result',
|
|
171
172
|
schema: dsh_plugin_shop_shop_outdated_result$schema,
|
|
172
173
|
},
|
|
173
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
174
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":252,"column":9},
|
|
174
175
|
},
|
|
175
176
|
{
|
|
176
177
|
id: 'dsh-plugin-shop#shop/setEnabled',
|
|
@@ -195,7 +196,7 @@ export const TYPERT = {
|
|
|
195
196
|
typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
|
|
196
197
|
schema: dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
197
198
|
},
|
|
198
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
199
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":149,"column":3},
|
|
199
200
|
},
|
|
200
201
|
],
|
|
201
202
|
model: {
|
|
@@ -285,7 +286,7 @@ export const TYPERT = {
|
|
|
285
286
|
},
|
|
286
287
|
{
|
|
287
288
|
"name": "ShopCatalogResult",
|
|
288
|
-
"declaration": "export interface ShopCatalogResult {\n schemaVersion: number;\n builtAt: string;\n stale: boolean;\n plugins: CatalogEntry[];\n denied: DeniedEntry[];\n}"
|
|
289
|
+
"declaration": "export interface ShopCatalogResult {\n schemaVersion: number;\n builtAt: string;\n stale: boolean;\n plugins: CatalogEntry[];\n denied: DeniedEntry[];\n stars: Record<string, number>;\n}"
|
|
289
290
|
},
|
|
290
291
|
{
|
|
291
292
|
"name": "ShopInstallResult",
|
|
@@ -36,6 +36,7 @@ const dsh_plugin_shop_shop_catalog_result$schema = z.object({
|
|
|
36
36
|
'name': z.string(),
|
|
37
37
|
'detail': z.string(),
|
|
38
38
|
})),
|
|
39
|
+
'stars': z.record(z.string(), z.number()),
|
|
39
40
|
})
|
|
40
41
|
const dsh_plugin_shop_shop_installStart_parameter_0$schema = z.object({
|
|
41
42
|
'name': z.string(),
|
|
@@ -101,7 +102,7 @@ export const TYPERT_REMOTE = {
|
|
|
101
102
|
typeSymbol: 'dsh-plugin-shop/types#ShopCatalogResult',
|
|
102
103
|
schema: dsh_plugin_shop_shop_catalog_result$schema,
|
|
103
104
|
},
|
|
104
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
105
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":180,"column":9},
|
|
105
106
|
},
|
|
106
107
|
{
|
|
107
108
|
id: 'dsh-plugin-shop#shop/installStart',
|
|
@@ -127,7 +128,7 @@ export const TYPERT_REMOTE = {
|
|
|
127
128
|
typeSymbol: 'dsh-plugin-shop/types#ShopInstallResult',
|
|
128
129
|
schema: dsh_plugin_shop_shop_installStart_result$schema,
|
|
129
130
|
},
|
|
130
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
131
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":206,"column":9},
|
|
131
132
|
},
|
|
132
133
|
{
|
|
133
134
|
id: 'dsh-plugin-shop#shop/installStatus',
|
|
@@ -152,7 +153,7 @@ export const TYPERT_REMOTE = {
|
|
|
152
153
|
typeSymbol: 'dsh-plugin-shop/types#ShopInstallStatusResult',
|
|
153
154
|
schema: dsh_plugin_shop_shop_installStatus_result$schema,
|
|
154
155
|
},
|
|
155
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
156
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":244,"column":3},
|
|
156
157
|
},
|
|
157
158
|
{
|
|
158
159
|
id: 'dsh-plugin-shop#shop/outdated',
|
|
@@ -167,7 +168,7 @@ export const TYPERT_REMOTE = {
|
|
|
167
168
|
typeSymbol: 'dsh-plugin-shop#shop/outdated:result',
|
|
168
169
|
schema: dsh_plugin_shop_shop_outdated_result$schema,
|
|
169
170
|
},
|
|
170
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
171
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":252,"column":9},
|
|
171
172
|
},
|
|
172
173
|
{
|
|
173
174
|
id: 'dsh-plugin-shop#shop/setEnabled',
|
|
@@ -192,7 +193,7 @@ export const TYPERT_REMOTE = {
|
|
|
192
193
|
typeSymbol: 'dsh-plugin-shop/types#ShopSetEnabledResult',
|
|
193
194
|
schema: dsh_plugin_shop_shop_setEnabled_result$schema,
|
|
194
195
|
},
|
|
195
|
-
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":
|
|
196
|
+
sourceLocation: {"file":"packages/dsh-plugin-shop/src/host/index.ts","line":149,"column":3},
|
|
196
197
|
},
|
|
197
198
|
],
|
|
198
199
|
}
|
package/package.json
CHANGED