Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
commit
03634b1ca3
11340 files changed
+3442369
No files matched your search
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* Fail-closed owner resolution for session-scoped RPCs.
|
||||
*
|
||||
* A request that carries a `session_id` only means anything on the backend
|
||||
* that OWNS that session. When every rung of the owner ladder (tile route →
|
||||
* exact owner hint → connection-tagged / profiled row → cross-profile REST
|
||||
* probe) misses, the request must NOT quietly ride the ambient presentation
|
||||
* gateway: "active" is presentation state with no routing authority, and an
|
||||
* ambient fallback turns missing ownership metadata into a misleading backend
|
||||
* "session not found" (or, worse, an answer from a backend that merely happens
|
||||
* to know a same-named session). Surface an explicit owner-resolution error
|
||||
* instead — the caller's error UX shows it, and the runtime that minted the
|
||||
* session is left untouched for the next correctly-routed attempt.
|
||||
*
|
||||
* The ONE case where the ambient gateway is not a fallback but the owner by
|
||||
* construction: no registry topology exists (legacy v1 primary) AND at most
|
||||
* one profile exists — a single backend serves every session, so there is
|
||||
* nothing to misroute to. Older single-profile backends omit `profile` on
|
||||
* their rows entirely; those users keep working unchanged.
|
||||
*/
|
||||
import { hasRegistryTopology } from './connection-registry-state'
|
||||
import { $profiles } from './profile'
|
||||
import { isSessionOwnerRoute, type SessionOwnerScope } from './session-request-router'
|
||||
|
||||
export class SessionOwnerResolutionError extends Error {
|
||||
constructor(
|
||||
readonly sessionId: string,
|
||||
readonly method: string
|
||||
) {
|
||||
super(
|
||||
`Session owner could not be resolved for "${sessionId}" (${method}): ` +
|
||||
'no owner route, hint, connection-tagged row or profile probe named the backend that holds this session, ' +
|
||||
'and routing it to the active gateway would be a guess.'
|
||||
)
|
||||
this.name = 'SessionOwnerResolutionError'
|
||||
}
|
||||
}
|
||||
|
||||
export function isSessionOwnerResolutionError(error: unknown): error is SessionOwnerResolutionError {
|
||||
return (
|
||||
error instanceof SessionOwnerResolutionError ||
|
||||
(error as { name?: unknown })?.name === 'SessionOwnerResolutionError'
|
||||
)
|
||||
}
|
||||
|
||||
/** True when the ambient gateway is provably the only backend any session
|
||||
* can live on (legacy single-backend Desktop): Electron has published no
|
||||
* connection registry and there is at most one profile. The active route is
|
||||
* presentation state; a null active connection does not prove sole topology. */
|
||||
export function ambientGatewayOwnsEverySession(): boolean {
|
||||
return !hasRegistryTopology() && $profiles.get().length <= 1
|
||||
}
|
||||
|
||||
/** True when `owner` names a backend: an exact connection route, or a bare
|
||||
* profile. A bare profile stays an owner in registry topology too — a profile
|
||||
* pick on the primary or the explicit `local` source takes the legacy
|
||||
* profile-only door (store/profile activateOnCurrentSource, so a per-profile
|
||||
* remote override resolves), and a session minted there is owned by that
|
||||
* profile's pool socket, which requestForSessionProfile dials by name. */
|
||||
export function sessionOwnerIsKnown(owner: SessionOwnerScope): boolean {
|
||||
if (isSessionOwnerRoute(owner)) {
|
||||
return Boolean(owner.connectionId.trim())
|
||||
}
|
||||
|
||||
return owner != null && Boolean(String(owner).trim())
|
||||
}
|
||||
|
||||
/**
|
||||
* Gate before a session-scoped RPC falls to the ambient dispatcher. Throws
|
||||
* SessionOwnerResolutionError when the session's owner is unknown and the
|
||||
* ambient gateway is not the sole backend; otherwise returns normally.
|
||||
*/
|
||||
export function assertSessionOwnerResolved(
|
||||
owner: SessionOwnerScope,
|
||||
context: { method: string; sessionId: null | string | undefined }
|
||||
): void {
|
||||
if (!context.sessionId || sessionOwnerIsKnown(owner) || ambientGatewayOwnsEverySession()) {
|
||||
return
|
||||
}
|
||||
|
||||
throw new SessionOwnerResolutionError(context.sessionId, context.method)
|
||||
}
|
||||
Reference in new issue
Block a user