Upstream proposal — draft #4364
Replies: 4 comments
|
Noticing the loading error you flagged, I appreciate the clear outline of the three registration‑time seams named routes, fallback seat, and index transforms since they force the dispatch loop into a static winner. Introducing a runtime hook feels akin to how streamline access points, and a look at https://hennepincountycourts.org illustrates the benefit of a centralized, opt‑in layer for edge cases. Adding a request‑time seam would let developers intervene before the longest‑prefix match finalizes, preserving flexibility without breaking existing contracts. |
|
I appreciate how the proposal cleanly separates the three registration‑time extension points named routes via register, the fallback seat with register Fallback, and the index transforms via tapIndex while highlighting the current lack of a request‑time seam. Implementing an opt‑in waterfall could mirror a well‑structured and for anyone needing a comparable public‑records portal you might check https://rutherfordcountycourts.org for a model of transparent, layered access. Overall, the opt‑in design promises minimal intrusion for existing handlers yet gives developers granular control over dispatch precedence, which should simplify debugging and future extensions. |
|
You correctly note that the current system only provides registration‑time seams named routes, a fallback seat, and index transforms leaving the dispatch loop without a request‑time hook. An opt‑in waterfall could be introduced similarly to a see https://westchestercountycourts.org for the procedural flow, giving developers a predictable fallback chain. This would preserve the existing longest‑prefix selection while allowing dynamic overrides when a route’s context demands it. Testing it as a middleware layer per endpoint should reveal any latency trade‑offs before a full integration. |
Uh oh!
There was an error while loading. Please reload this page.
Summary
@deepseek-ai/dsh-host-webservercurrently exposes three composition seams: named routes (register), a single fallback seat (registerFallback), and index transforms (tapIndex). All three are registration-time extension points. There is no request-time seam — once the dispatch loop picks a winner (exact table → longest prefix → fallback), the winning owner unconditionally handles the request.This proposes one small, opt-in waterfall:
Dispatch order becomes: fire the waterfall → any middleware that does not call
next()owns the response; otherwise control falls through to the existing exact/prefix/fallback machinery, unchanged.Motivation (a concrete use case)
Sharing one harness instance with a small trusted group over a LAN/tunnel. A community plugin (WebGate) adds an account/password gate: login page, 12h session tokens, per-member workspace visibility, admin-password sudo for account management.
Everything works except server-side enforcement, because:
/apiis already claimed. The data channel is registered by@deepseek-ai/dsh-client-connectionas a named prefix route (webServer.register({ kind: 'prefix', path: '/api', … }), plus a siblingregisterUpgrade). Route registration refuses duplicates by design, and longest-prefix-wins means shorter routes cannot shadow it — correctly so; two owners for one prefix cannot compose.match()→ handler) consults no event, and there is no way for a third party to wrap another owner's handler.tapIndexruns at render time with noIncomingMessagecontext, so it cannot even tell who is asking.ClientRequestis{ type, rpcId, method, payload }(rpc.schema.js) — no user/session field exists to key policy on, so even a hypothetical data-layer filter has nothing to filter by.Net effect: an auth plugin can gate the document (redirect to
/login) but any user with DevTools can delete the guard script — the shell boots and every/api/*RPC answers in full. For a local personal tool that is acceptable; the moment the instance faces a network, it is not.Why an event (and why this fits the framework)
The framework documentation positions waterfall events as the intended shape for interception/gateway logic (“用于实现拦截/网关逻辑”). What is missing is merely the declaration at the transport layer. The same survey found 112 declared Cordis events across the shipped
@deepseek-ai/*packages; the closest candidates all fail:agent/request/-errortools/pre-executeapproval/requestsession/eventwebserver/index-injectconnection/resetA
webserver/requestwaterfall is the missing declaration, and matches how the codebase already models interception elsewhere (tools/pre-execute,llm/stream,fs/write-intent).Reference implementation sketch
In
WebServer's request dispatch (beforematch()):Contract notes:
IncomingMessage/ServerResponsepair (so cookies/headers are available for identity resolution) and owns the response if it skipsnext()— identical ownership rules to route handlers today, including SSE/long-lived responses.next()is the existing router; returning its result keepshandledhonest for diagnostics.registerUpgrade) are intentionally out of scope for this event — they negotiate separately and would warrant a symmetricwebserver/upgradewaterfall later.What a plugin can build on it (already implemented, waiting for the seam)
WebGate ships today with everything except the enforcement point:
/login) + PBKDF2-hashed accounts persisted in$DSH_HOME/.credentials.yamlgrant records;localStoragestate and awebgate_tokencookie (SameSite=Lax);role, workspace allow-list) returned by/auth/api/login|session;With the waterfall, the plugin's entire enforcement moves server-side in ~30 lines: resolve the cookie → look up token → member ⇒ filter
workspace.listresults and rejectsettings.*/workspace.create/session.search/host.createDirectorywith a standard{ ok:false, error:{ code:'bad-request', … } }envelope (the error union already carries everything needed). Admins pass through untouched.Alternatives considered
webServerinstance from a pluginOpen questions
next()runs today's fallback)?webserver/upgradewaterfall land together, or follow later once HTTP gating proves the shape?webserver/requestmirrors the package's existingwebserver/index-inject; alternatives (http/gate,gateway/dispatch) welcome.All reactions