mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
113 lines
4.2 KiB
TypeScript
113 lines
4.2 KiB
TypeScript
/**
|
|
* Scoped-context primitive: mint a Cordis context that tags registrations with
|
|
* an opaque identity and build routing-only event carriers for that identity.
|
|
*
|
|
* @module @deepseek-ai/dsh-scope
|
|
*/
|
|
|
|
import type { Context, Fiber } from 'cordis'
|
|
import { Context as CordisContext } from 'cordis'
|
|
|
|
/** An opaque, identity-compared scope key. */
|
|
export type ScopeKey = object
|
|
|
|
/** Context tag written by {@link createScope}. */
|
|
const kScope = Symbol('dsh.scope')
|
|
|
|
declare const ScopedBrand: unique symbol
|
|
|
|
/**
|
|
* A routing-only event receiver built by {@link scopeTarget}. The type
|
|
* parameter records the subject type for dispatch checking; the carrier does
|
|
* not expose the subject's properties. Event payloads carry the real subject.
|
|
*/
|
|
export type Scoped<T extends object> = object & { readonly [ScopedBrand]: T }
|
|
|
|
/** The key associated with each carrier. Presence distinguishes an unkeyed carrier from a non-carrier. */
|
|
const carrierKeys = new WeakMap<object, ScopeKey | undefined>()
|
|
|
|
/** A minted registration scope and its quiescent disposal boundaries. */
|
|
export interface Scope {
|
|
/** Context through which scope-owned registrations are made. */
|
|
ctx: Context
|
|
/** Exact Cordis disposer, used when nesting this scope in an ordered composite effect. */
|
|
rawDispose: () => Promise<void> | void
|
|
/** Dispose every scope-owned registration; racing calls await the same completion. */
|
|
dispose(): Promise<void>
|
|
}
|
|
|
|
/** Follow a Cordis fiber through asynchronous teardown even if its raw disposer was already claimed. */
|
|
async function quiesceFiber(fiber: Fiber): Promise<void> {
|
|
await Promise.resolve(fiber.dispose())
|
|
while (fiber.inertia !== undefined) await fiber.inertia
|
|
}
|
|
|
|
/** Shared no-op plugin used as the backing scope fiber. */
|
|
function scope(): void {}
|
|
|
|
/**
|
|
* Mint a scope under `ctx`. The scoped context inherits the minting plugin's
|
|
* dependency surface and owns every registration made through it.
|
|
* @param ctx - active context whose dependency surface the scope inherits.
|
|
* @param key - opaque identity used for listener routing.
|
|
* @returns the scoped context and exact/shared disposal boundaries.
|
|
*/
|
|
export function createScope(ctx: Context, key: ScopeKey): Scope {
|
|
const fiber = ctx.plugin(scope)
|
|
const scoped: Context = fiber.ctx.extend({ [kScope]: key })
|
|
let disposing: Promise<void> | undefined
|
|
return {
|
|
ctx: scoped,
|
|
rawDispose: fiber.dispose,
|
|
dispose: () => (disposing ??= quiesceFiber(fiber)),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Read the nearest scope tag inherited by a context.
|
|
* @param ctx - context to inspect.
|
|
* @returns its scope key, or `undefined` for an unscoped context.
|
|
*/
|
|
export function scopeOf(ctx: Context): ScopeKey | undefined {
|
|
return (ctx as Context & { [kScope]?: ScopeKey })[kScope]
|
|
}
|
|
|
|
/**
|
|
* Build an opaque receiver that preserves the base filter, admits untagged
|
|
* listeners globally, and admits tagged listeners only for a matching key.
|
|
* @param base - subject or service whose existing Cordis filter is preserved.
|
|
* @param key - routed scope identity, or `undefined` for an unscoped subject.
|
|
* @returns a carrier whose subject remains available only through event arguments.
|
|
*/
|
|
export function scopeTarget<T extends object>(base: T, key: ScopeKey | undefined): Scoped<T> {
|
|
const baseFilter = (base as { [CordisContext.filter]?: (ctx: Context) => boolean })[CordisContext.filter]
|
|
const carrier = {
|
|
[CordisContext.filter](ctx: Context): boolean {
|
|
if (baseFilter !== undefined && !baseFilter.call(base, ctx)) return false
|
|
const tag = scopeOf(ctx)
|
|
return tag === undefined || tag === key
|
|
},
|
|
}
|
|
carrierKeys.set(carrier, key)
|
|
return carrier as unknown as Scoped<T>
|
|
}
|
|
|
|
/**
|
|
* Test whether a value is a scope carrier.
|
|
* @param value - dispatch receiver to inspect.
|
|
* @returns whether {@link scopeTarget} created it.
|
|
*/
|
|
export function isScopeCarrier(value: unknown): value is Scoped<object> {
|
|
return typeof value === 'object' && value !== null && carrierKeys.has(value)
|
|
}
|
|
|
|
/**
|
|
* Read a carrier's routing key.
|
|
* @param value - dispatch receiver to inspect.
|
|
* @returns the carrier key, or `undefined` for an unkeyed/non-carrier value.
|
|
*/
|
|
export function carrierKeyOf(value: unknown): ScopeKey | undefined {
|
|
if (!isScopeCarrier(value)) return undefined
|
|
return carrierKeys.get(value)
|
|
}
|