dshmarket 1.71.0 → 1.72.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/client/client.js +767 -3
- package/lib/http.js +22 -2
- package/lib/types/http.d.ts +4 -1
- package/package.json +1 -1
- package/src/client/MarketSection.tsx +9 -1
- package/src/client/index.ts +3 -3
- package/src/client/locales.ts +763 -1
- package/src/http.ts +21 -2
package/lib/http.js
CHANGED
|
@@ -147,7 +147,10 @@ export function trustedAuthority(host, trustedHosts) {
|
|
|
147
147
|
* - a cross-site page is refused — its Origin is present and different;
|
|
148
148
|
* - `Origin: null` (a sandboxed iframe, a `data:` document) is refused, because
|
|
149
149
|
* `null` is a present-but-unparseable origin, not an absent one;
|
|
150
|
-
* - a same-host-but-different-port request is refused
|
|
150
|
+
* - a same-host-but-different-port request is refused, except that a loopback
|
|
151
|
+
* Host accepts a port-less same-hostname Origin (#1031: Chrome 151+ omits
|
|
152
|
+
* the port on loopback Origins, and the dsh core fence follows the same
|
|
153
|
+
* rule);
|
|
151
154
|
* - an EMPTY Origin is refused too: the header being present and unparseable
|
|
152
155
|
* is not the same statement as its being absent, and only absence is what
|
|
153
156
|
* a stripping proxy produces.
|
|
@@ -202,6 +205,16 @@ export function sameOrigin(request) {
|
|
|
202
205
|
// equality cannot: a cross-site request whose Origin happens to match.
|
|
203
206
|
if (request.headers['sec-fetch-site'] === 'cross-site')
|
|
204
207
|
return false;
|
|
208
|
+
// Chrome 151+ serializes a loopback Origin WITHOUT its explicit port
|
|
209
|
+
// (#1031): the page at `http://127.0.0.1:3080` now states `Origin:
|
|
210
|
+
// http://127.0.0.1` on its same-origin POSTs, so the strict `host` equality
|
|
211
|
+
// below refuses installs and updates from the newest browsers. Mirror the
|
|
212
|
+
// dsh core rule (`isSameAuthorityOrigin`): the hostname must match, and the
|
|
213
|
+
// omitted port is honoured only on the loopback fence — `loopbackAuthority`
|
|
214
|
+
// above has already decided the Host names loopback, a cross-site page still
|
|
215
|
+
// fails the hostname test, and a rebinding page still cannot get its own
|
|
216
|
+
// name through both. Declared LAN names and proxies keep needing the exact
|
|
217
|
+
// port, as before.
|
|
205
218
|
const origin = request.headers.origin;
|
|
206
219
|
// A missing Origin is not a cross-site request: browsers send it on every
|
|
207
220
|
// POST, same-origin included, so its absence means the caller is not a
|
|
@@ -211,7 +224,14 @@ export function sameOrigin(request) {
|
|
|
211
224
|
if (origin === undefined)
|
|
212
225
|
return true;
|
|
213
226
|
try {
|
|
214
|
-
|
|
227
|
+
const originUrl = new URL(origin);
|
|
228
|
+
if (originUrl.host === host)
|
|
229
|
+
return true;
|
|
230
|
+
if (originUrl.port === '' && host !== undefined && loopbackAuthority(host)) {
|
|
231
|
+
const hostUrl = parseAuthority(host);
|
|
232
|
+
return hostUrl !== null && originUrl.hostname === hostUrl.hostname;
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
215
235
|
}
|
|
216
236
|
catch {
|
|
217
237
|
return false;
|
package/lib/types/http.d.ts
CHANGED
|
@@ -77,7 +77,10 @@ export declare function trustedAuthority(host: string, trustedHosts: readonly st
|
|
|
77
77
|
* - a cross-site page is refused — its Origin is present and different;
|
|
78
78
|
* - `Origin: null` (a sandboxed iframe, a `data:` document) is refused, because
|
|
79
79
|
* `null` is a present-but-unparseable origin, not an absent one;
|
|
80
|
-
* - a same-host-but-different-port request is refused
|
|
80
|
+
* - a same-host-but-different-port request is refused, except that a loopback
|
|
81
|
+
* Host accepts a port-less same-hostname Origin (#1031: Chrome 151+ omits
|
|
82
|
+
* the port on loopback Origins, and the dsh core fence follows the same
|
|
83
|
+
* rule);
|
|
81
84
|
* - an EMPTY Origin is refused too: the header being present and unparseable
|
|
82
85
|
* is not the same statement as its being absent, and only absence is what
|
|
83
86
|
* a stripping proxy produces.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dshmarket",
|
|
3
3
|
"description": "Visual plugin market inside DeepSeek Harness — browse, search, and one-click install community plugins. · DSH 可视化插件市场:逛一逛,点一下,装好。",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.72.0",
|
|
5
5
|
"icon": "assets/logo.svg",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "lib/index.js",
|
|
@@ -3424,15 +3424,23 @@ export function MarketSection(props: MarketSectionProps) {
|
|
|
3424
3424
|
// pluginBlocked closes over the installed map and the catalog match.
|
|
3425
3425
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3426
3426
|
[pluginsAll, blockedNameSet, installed, repoIdentities, data, repoHints])
|
|
3427
|
+
// A sort the user chose is a request to see the list in THAT order, and
|
|
3428
|
+
// this block ignores the sort by design (it is "what was added in the last
|
|
3429
|
+
// seven days", ordered by downloads). Left in place it sits between the
|
|
3430
|
+
// control and the list it just reordered: on a 1166px window it fills the
|
|
3431
|
+
// screen, so switching to Stars looked like it did nothing (#1016). The
|
|
3432
|
+
// block is a front-page teaser for the unfiltered default view — one more
|
|
3433
|
+
// narrowing, alongside query, category and time range.
|
|
3427
3434
|
const recentlyAdded = useMemo(
|
|
3428
3435
|
() => data === null || tab !== 'discover' || q.trim() !== '' || cat !== 'all' || timeRange !== 'all'
|
|
3436
|
+
|| sortField !== 'downloads' || sortDir !== 'desc'
|
|
3429
3437
|
? []
|
|
3430
3438
|
: visiblePlugins(data.plugins, {
|
|
3431
3439
|
category: 'all', query: '', lang, sort: 'downloads-desc', sinceDays: 7,
|
|
3432
3440
|
hostCompatibility, compatibleWithHost,
|
|
3433
3441
|
}).filter(plugin => !pluginBlocked(plugin)),
|
|
3434
3442
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3435
|
-
[data, tab, q, cat, timeRange, lang, hostCompatibility, compatibleWithHost, blockedNameSet, installed, repoIdentities, repoHints])
|
|
3443
|
+
[data, tab, q, cat, timeRange, sortField, sortDir, lang, hostCompatibility, compatibleWithHost, blockedNameSet, installed, repoIdentities, repoHints])
|
|
3436
3444
|
const recentRowRef = useRef<HTMLDivElement>(null)
|
|
3437
3445
|
// Two per row, like the grid below it: three across read as a different
|
|
3438
3446
|
// list rather than the same one (and left an odd one out at any width).
|
package/src/client/index.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { createElement as h } from 'react'
|
|
|
9
9
|
import type { ReactNode } from 'react'
|
|
10
10
|
import * as primitives from '@deepseek-ai/dsh-client-ui-primitives'
|
|
11
11
|
import { missingIcons } from './icons.ts'
|
|
12
|
-
import { en, zh } from './locales.ts'
|
|
12
|
+
import { en, ja, zh } from './locales.ts'
|
|
13
13
|
import { InstallToast } from './InstallToast.tsx'
|
|
14
14
|
import { MarketErrorBoundary } from './ErrorBoundary.tsx'
|
|
15
15
|
import { MarketSection } from './MarketSection.tsx'
|
|
@@ -75,7 +75,7 @@ interface ThemeService {
|
|
|
75
75
|
|
|
76
76
|
/** The subset of the locale service this plugin touches. */
|
|
77
77
|
interface LocaleService {
|
|
78
|
-
register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string> }): unknown
|
|
78
|
+
register(namespace: string, dicts: { zh: Record<string, string>; en: Record<string, string>; ja?: Record<string, string> }): unknown
|
|
79
79
|
bind(namespace: string): Translate
|
|
80
80
|
subscribe(callback: () => void): () => void
|
|
81
81
|
getSnapshot(): { active: string }
|
|
@@ -155,7 +155,7 @@ export function apply(ctx: MarketClientContext): void {
|
|
|
155
155
|
* of them. Not exported: the split is a guard, not a surface.
|
|
156
156
|
*/
|
|
157
157
|
function mountMarket(ctx: MarketClientContext): void {
|
|
158
|
-
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-market: dictionaries')
|
|
158
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en, ja }), 'dsh-market: dictionaries')
|
|
159
159
|
const t = ctx.locale.bind(NS)
|
|
160
160
|
|
|
161
161
|
// The section's nav glyph. The shell picks nav icons from its own built-in
|