refactor(typert): rename RemoteContext to RemoteScope

This commit is contained in:
imccyu
2026-08-07 18:35:50 +08:00
parent d6ffd87c5f
commit d362cdb54f
27 changed files with 127 additions and 127 deletions

View File

@@ -1032,10 +1032,10 @@ class FaceAnalyzer {
if (invocation.kind === 'context') {
const context = this.contextDeclarations().get(invocation.context)
if (context === undefined) {
this.fail(method, `Remote Context ${invocation.context} has no TypeRTContextMap entry`)
this.fail(method, `Remote Scope ${invocation.context} has no TypeRTContextMap entry`)
}
const wire = `${invocation.context}Id`
if (wires.has(wire)) this.fail(method, `Remote Context wire field ${wire} conflicts with a method parameter`)
if (wires.has(wire)) this.fail(method, `Remote Scope wire field ${wire} conflicts with a method parameter`)
receiver = {
kind: 'context',
context: invocation.context,
@@ -1200,18 +1200,18 @@ class FaceAnalyzer {
}
marker = { kind: 'direct', exportName }
} else if (ts.isCallExpression(expression)
&& this.isTypeMetaSymbol(expression.expression, 'RemoteContext')) {
&& this.isTypeMetaSymbol(expression.expression, 'RemoteScope')) {
if (expression.arguments.length < 1 || expression.arguments.length > 2) {
this.fail(expression, 'RemoteContext() requires a Context key and optional exported method name')
this.fail(expression, 'RemoteScope() requires a Context key and optional exported method name')
}
const context = stringLiteralValue(expression.arguments[0])
if (context === undefined || !isRemoteSegment(context)) {
this.fail(expression.arguments[0] ?? expression, 'RemoteContext() key must be a string literal containing only RPC endpoint segment characters')
this.fail(expression.arguments[0] ?? expression, 'RemoteScope() key must be a string literal containing only RPC endpoint segment characters')
}
const exportArgument = expression.arguments[1]
const exportName = exportArgument === undefined ? undefined : stringLiteralValue(exportArgument)
if (exportArgument !== undefined && (exportName === undefined || !isRemoteSegment(exportName))) {
this.fail(exportArgument, 'RemoteContext() name must be a string literal containing only RPC endpoint segment characters')
this.fail(exportArgument, 'RemoteScope() name must be a string literal containing only RPC endpoint segment characters')
}
marker = { kind: 'context', context, ...exportName === undefined ? {} : { exportName } }
} else {
@@ -2529,7 +2529,7 @@ function sourceFileHasSurface(sourceFile: ts.SourceFile): boolean {
? decorator.expression.expression
: decorator.expression
const name = expressionName(expression)
if (name === 'Remote' || name === 'RemoteContext') return true
if (name === 'Remote' || name === 'RemoteScope') return true
}
}
}

View File

@@ -376,7 +376,7 @@ export class FaceModelEmitter {
lines.push(' }')
}
if (scoped.length > 0) {
lines.push(' interface TypeRTRemoteContextMap {')
lines.push(' interface TypeRTRemoteScopeMap {')
for (const invocation of scoped) {
this.pushRemoteSignature(lines, sourceMap, packageModel, invocation, referenceNames, true)
}

View File

@@ -1,4 +1,4 @@
import { GatewayService, Remote, RemoteContext } from '@deepseek-ai/dsh-type-meta'
import { GatewayService, Remote, RemoteScope } from '@deepseek-ai/dsh-type-meta'
import type { Agent } from '@fixture/domain'
import type {
CreateGoalRequest,
@@ -19,7 +19,7 @@ export class GoalService extends GatewayService {
return { ref: `${agent.id}:${request.title}` }
}
@RemoteContext('agent')
@RemoteScope('agent')
rename(request: RenameGoalRequest): RenameGoalResult {
return { renamed: request.title.length > 0 }
}

View File

@@ -11,7 +11,7 @@ declare module '@deepseek-ai/dsh-type-meta' {
export interface TypeRTLookupMap {}
export interface TypeRTContextMap {}
export interface TypeRTRemoteMap {}
export interface TypeRTRemoteContextMap {}
export interface TypeRTRemoteScopeMap {}
export type TypeRTRemoteNamespace<Namespace extends string> = {
[Endpoint in keyof TypeRTRemoteMap as Endpoint extends `${Namespace}/${infer Method}`
@@ -56,7 +56,7 @@ declare module '@deepseek-ai/dsh-type-meta' {
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>,
) => void
export function RemoteContext(key: Extract<keyof TypeRTContextMap, string>, exportName?: string):
export function RemoteScope(key: Extract<keyof TypeRTContextMap, string>, exportName?: string):
<This extends object, Args extends unknown[], Result>(
method: (this: This, ...args: Args) => Result,
context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>,

View File

@@ -288,7 +288,7 @@ export interface BoxPayload {
const root = copyFixture()
editFile(root, 'packages/remote/src/index.ts', source => source
.replace(' @Remote\n', '')
.replace(" @RemoteContext('agent')\n", ''))
.replace(" @RemoteScope('agent')\n", ''))
editFile(root, 'packages/remote/src/types.ts', source => `${source}
/** @typert schema */
@@ -377,8 +377,8 @@ export interface ClientMarker {
name: 'duplicate GatewayService field binding',
edit: (source: string) => source
.replace(
'import { GatewayService, Remote, RemoteContext }',
'import { GatewayService, Remote, RemoteContext, bindTypeRTGateway }',
'import { GatewayService, Remote, RemoteScope }',
'import { GatewayService, Remote, RemoteScope, bindTypeRTGateway }',
)
.replace(
'export class GoalService extends GatewayService {',
@@ -495,11 +495,11 @@ export interface ClientMarker {
expect(() => analyzeRemote(root)).not.toThrow()
})
it('rejects a Remote Context without a static Context declaration', () => {
it('rejects a Remote Scope without a static Context declaration', () => {
const root = copyFixture()
editFile(root, 'packages/remote/src/index.ts', source => source.replace("@RemoteContext('agent')", "@RemoteContext('missing')"))
editFile(root, 'packages/remote/src/index.ts', source => source.replace("@RemoteScope('agent')", "@RemoteScope('missing')"))
expect(() => analyzeRemote(root, false)).toThrow(/Remote Context missing has no TypeRTContextMap entry/)
expect(() => analyzeRemote(root, false)).toThrow(/Remote Scope missing has no TypeRTContextMap entry/)
})
it('rejects a direct scoped projection whose Context and lookup wire symbols differ', () => {
@@ -579,7 +579,7 @@ function assertRemoteConsumerTypechecks(
import remote from '@fixture/remote/remote'
import type {
TypeRTRemoteContribution,
TypeRTRemoteContextMap,
TypeRTRemoteScopeMap,
TypeRTRemoteMap,
TypeRTRemoteNamespaceMap,
} from '@deepseek-ai/dsh-type-meta'
@@ -587,8 +587,8 @@ import type { CreateGoalResult, RenameGoalResult } from '@fixture/remote/types'
const contribution: TypeRTRemoteContribution = remote
declare const create: TypeRTRemoteMap['goals/create']
declare const createScoped: TypeRTRemoteContextMap['agent:goals/create']
declare const rename: TypeRTRemoteContextMap['agent:goals/rename']
declare const createScoped: TypeRTRemoteScopeMap['agent:goals/create']
declare const rename: TypeRTRemoteScopeMap['agent:goals/rename']
const created: Promise<CreateGoalResult> = create('agent-1', { title: 'ship' })
const cancellable: Promise<CreateGoalResult> = create('agent-1', { title: 'ship' }, new AbortController().signal)
const createdScoped: Promise<CreateGoalResult> = createScoped({ title: 'ship' })

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/typert/type-meta/README.md
README.md: a76169742cb78d0d19814bcd0f978c71036a5a1c
README.zh.md: 6f2d2fd6e241441fae8102c0639608e9b27b9bec
README.md: 9bd475f8973ec54756fe0e63d5b7fa485381697d
README.zh.md: 10a6309bc47001d572abb3dd3f794ebfcf6252e8

View File

@@ -7,7 +7,7 @@ Compiler-independent declarations shared by business packages, generated TypeRT
## Remote declarations
- `@Remote` marks a public instance method for direct invocation on its registered Cordis Service.
- `@RemoteContext(key)` marks a method whose receiver is selected from a merge-declared scoped Context kind.
- `@RemoteScope(key)` marks a method whose receiver is selected from a merge-declared scoped Context kind.
- `GatewayService` binds the Cordis key passed to `super(ctx, serviceKey, options?)` to the same default wire namespace.
- `bindTypeRTGateway(this, serviceKey, options?)` provides the same visible, frozen binding for a Service that cannot inherit from `GatewayService`.
- `remoteMethods(service)` returns a detached declaration-order snapshot used by the Gateway's SRC fallback.
@@ -18,7 +18,7 @@ Decorator initializers retain markers in a module-private `WeakMap` keyed by the
## TypeRT protocol
Business packages extend `TypeRTLookupMap` and `TypeRTContextMap` to associate Host objects or scoped Contexts with their wire identities. Generated artifacts extend `TypeRTRemoteMap`, `TypeRTRemoteContextMap`, and `TypeRTRemoteNamespaceMap` so Client imports expose only selected Remote methods. `InvocationDescriptor` is the shared runtime form consumed by the registry, Gateway, and Client API.
Business packages extend `TypeRTLookupMap` and `TypeRTContextMap` to associate Host objects or scoped Contexts with their wire identities. Generated artifacts extend `TypeRTRemoteMap`, `TypeRTRemoteScopeMap`, and `TypeRTRemoteNamespaceMap` so Client imports expose only selected Remote methods. `InvocationDescriptor` is the shared runtime form consumed by the registry, Gateway, and Client Remote.
Lookup and Context packages own both sides of their contract: declaration merging supplies the static association, while runtime providers register identity resolution with `ctx.typert`. A lookup or Host Context provider supplies the stable declaration and default resolver, while Host composition may separately configure a synchronous or asynchronous resolver; policy rejections may use `TypeRTLookupFailure` to carry a failure value owned by the boundary adapter. Strict codecs carry generated schemas; `src-json` codecs identify the weaker source-launch path.

View File

@@ -7,7 +7,7 @@
## Remote 声明
- `@Remote` 将公开实例方法标记为可在其注册的 Cordis 服务上直接调用。
- `@RemoteContext(key)` 标记接收者选自合并声明的作用域 Context 类型的方法。
- `@RemoteScope(key)` 标记接收者选自合并声明的作用域 Context 类型的方法。
- `GatewayService` 将 `super(ctx, serviceKey, options?)` 接收的 Cordis key 同时绑定为默认 wire namespace。
- `bindTypeRTGateway(this, serviceKey, options?)` 为无法继承 `GatewayService` 的 Service 提供同样可见且冻结的绑定。
- `remoteMethods(service)` 返回按声明顺序排列、与内部状态分离的快照,供 Gateway 的 SRC 回退路径使用。
@@ -18,7 +18,7 @@ Host 方法通过将 `signal: AbortSignal` 声明为最后一个参数来启用
## TypeRT 协议
业务包扩展 `TypeRTLookupMap` 和 `TypeRTContextMap`,以关联 Host 对象或作用域 Context 与其协议身份。生成的产物扩展 `TypeRTRemoteMap`、`TypeRTRemoteContextMap` 和 `TypeRTRemoteNamespaceMap`,使 Client 导入后仅暴露选定的 Remote 方法。`InvocationDescriptor` 是供注册表、Gateway 和 Client API 使用的共享运行时形式。
业务包扩展 `TypeRTLookupMap` 和 `TypeRTContextMap`,以关联 Host 对象或作用域 Context 与其协议身份。生成的产物扩展 `TypeRTRemoteMap`、`TypeRTRemoteScopeMap` 和 `TypeRTRemoteNamespaceMap`,使 Client 导入后仅暴露选定的 Remote 方法。`InvocationDescriptor` 是供注册表、Gateway 和 Client Remote 使用的共享运行时形式。
查找包与 Context 包同时负责其契约的两侧:声明合并提供静态关联,运行时提供方则向 `ctx.typert` 注册身份解析。lookup 或 Host Context provider 提供稳定声明与默认 resolver,Host 组合可以另行配置同步或异步 resolver;策略拒绝可用 `TypeRTLookupFailure` 携带由边界适配器拥有的失败值。严格编解码器携带生成的 schema;`src-json` 编解码器标识约束更弱的源码启动路径。

View File

@@ -60,9 +60,9 @@ export type {
TypeRTLookupResolver,
TypeRTLookupRegistry,
TypeRTLookupWire,
TypeRTRemoteContextApi,
TypeRTRemoteContextMap,
TypeRTRemoteContextNamespace,
TypeRTRemoteScopeApi,
TypeRTRemoteScopeMap,
TypeRTRemoteScopeNamespace,
TypeRTRemoteContribution,
TypeRTRemoteMap,
TypeRTRemoteNamespace,
@@ -191,16 +191,16 @@ export function Remote<This extends object, Args extends unknown[], Result>(
}
/**
* Create a decorator for a method resolved from one scoped Remote Context.
* @param key - merge-declared Context key.
* Create a decorator for a method resolved from one Remote Scope.
* @param key - scope key declared through the Context map.
* @param exportName - optional Remote export name; defaults to the method name.
* @returns a standard method decorator that records only private module state.
*/
export function RemoteContext(
export function RemoteScope(
key: Extract<keyof TypeRTContextMap, string>,
exportName?: string,
): RemoteMethodDecorator {
validateName('Context key', key)
validateName('Scope key', key)
if (exportName !== undefined) validateName('Remote export name', exportName)
return function <This extends object, Args extends unknown[], Result>(
_method: (this: This, ...args: Args) => Result,

View File

@@ -40,7 +40,7 @@ export interface TypeRTContextMap {}
export interface TypeRTRemoteMap {}
/** Merge-extensible scoped Remote method signatures generated for consumers. */
export interface TypeRTRemoteContextMap {}
export interface TypeRTRemoteScopeMap {}
/**
* Resolve one direct Remote namespace from the generated flat endpoint map.
@@ -57,24 +57,24 @@ export type TypeRTRemoteNamespace<Namespace extends string> = {
* The calling Cordis Context supplies the concrete identity at runtime.
* @template Namespace - wire namespace between the Context prefix and method.
*/
export type TypeRTRemoteContextNamespace<
export type TypeRTRemoteScopeNamespace<
Namespace extends string,
ContextKey extends string = string,
> = {
[Endpoint in keyof TypeRTRemoteContextMap as Endpoint extends `${ContextKey}:${Namespace}/${infer Method}`
[Endpoint in keyof TypeRTRemoteScopeMap as Endpoint extends `${ContextKey}:${Namespace}/${infer Method}`
? Method
: never]: TypeRTRemoteContextMap[Endpoint]
: never]: TypeRTRemoteScopeMap[Endpoint]
}
type TypeRTRemoteContextNamespaceKey<
type TypeRTRemoteScopeNamespaceKey<
ContextKey extends string,
Endpoint = keyof TypeRTRemoteContextMap,
Endpoint = keyof TypeRTRemoteScopeMap,
> = Endpoint extends `${ContextKey}:${infer Namespace}/${string}` ? Namespace : never
/** Generated scoped Remote namespaces available to one Context kind. */
export type TypeRTRemoteContextApi<ContextKey extends string> = {
[Namespace in TypeRTRemoteContextNamespaceKey<ContextKey>]:
TypeRTRemoteContextNamespace<Namespace, ContextKey>
export type TypeRTRemoteScopeApi<ContextKey extends string> = {
[Namespace in TypeRTRemoteScopeNamespaceKey<ContextKey>]:
TypeRTRemoteScopeNamespace<Namespace, ContextKey>
}
/** Merge-extensible direct namespace surface generated for Client Remote services. */
@@ -227,7 +227,7 @@ export interface TypeRTLookupDefinition {
readonly wireTypeSymbol: string
}
/** Host resolver for one scoped Remote Context kind. */
/** Host resolver for one scoped Remote kind. */
export interface TypeRTHostContextProvider<Wire = unknown> {
/** Wire field carrying the Context identity. */
readonly wire: string

View File

@@ -2,7 +2,7 @@ import { Context } from 'cordis'
import {
GatewayService,
Remote,
RemoteContext,
RemoteScope,
remoteMethods,
} from '@deepseek-ai/dsh-type-meta'
@@ -16,7 +16,7 @@ class Goals extends GatewayService {
return value
}
@RemoteContext('agent')
@RemoteScope('agent')
scoped(value: string): string {
return value
}

View File

@@ -6,7 +6,7 @@ import {
bindTypeRTGateway,
GatewayService,
Remote,
RemoteContext,
RemoteScope,
remoteMethods,
type TypeRTContext,
} from '@deepseek-ai/dsh-type-meta'
@@ -29,7 +29,7 @@ describe('type-meta Remote declarations', () => {
return value
}
@RemoteContext('metaFixture')
@RemoteScope('metaFixture')
scoped(value: string): string {
return value
}
@@ -84,7 +84,7 @@ describe('type-meta Remote declarations', () => {
Reflect.get(Goals.prototype, 'create') as (this: Goals, ...args: unknown[]) => unknown,
methodContext('create', initializers),
)
RemoteContext('metaFixture')(
RemoteScope('metaFixture')(
Reflect.get(Goals.prototype, 'scoped') as (this: Goals, ...args: unknown[]) => unknown,
methodContext('scoped', initializers),
)
@@ -141,7 +141,7 @@ describe('type-meta Remote declarations', () => {
Reflect.get(Service.prototype, 'run') as (this: Service, ...args: unknown[]) => unknown,
methodContext('run', initializers),
)
RemoteContext('metaFixture', 'inspect')(
RemoteScope('metaFixture', 'inspect')(
Reflect.get(Service.prototype, 'scoped') as (this: Service, ...args: unknown[]) => unknown,
methodContext('scoped', initializers),
)
@@ -166,8 +166,8 @@ describe('type-meta Remote declarations', () => {
expect(() => Remote('bad name')).toThrow('export name')
expect(() => Remote('.')).toThrow('export name')
expect(() => Remote('..')).toThrow('export name')
expect(() => RemoteContext('' as 'metaFixture')).toThrow('Context key')
expect(() => RemoteContext('metaFixture', 'bad/name')).toThrow('export name')
expect(() => RemoteScope('' as 'metaFixture')).toThrow('Scope key')
expect(() => RemoteScope('metaFixture', 'bad/name')).toThrow('export name')
for (const context of [
{ ...methodContext('run', []), private: true },
@@ -195,7 +195,7 @@ describe('type-meta Remote declarations', () => {
Reflect.get(Service.prototype, 'run'),
methodContext('run', conflicting),
)
RemoteContext('metaFixture')(
RemoteScope('metaFixture')(
Reflect.get(Service.prototype, 'run'),
methodContext('run', conflicting),
)