feat(remote): deliver allowlisted Host events through ctx.remote.$on

api/remotes owns the allowlist and its type projection; type-meta owns the shape
predicate, the selection seat, and the internal remote/host-event carrier
signal; api/gateway's Client half turns that signal into $on callbacks through a
private dispatch. apiproxy forwards each allowlisted emission verbatim in one
host/remote-event frame, registered ahead of the derived invalidation frames so
frame order is unchanged, and drops the three per-event variants it replaces.
Owner packages move their Events declarations into client-safe ./types exports,
so a consumer's listener signature is the Host's own declaration.
This commit is contained in:
imccyu
2026-08-10 21:32:50 +08:00
parent b64da061a8
commit d88f771e19
59 changed files with 956 additions and 257 deletions

View File

@@ -22,12 +22,17 @@
"types": "./lib/types/invariant.d.ts",
"default": "./lib/invariant.js"
},
"./types": {
"types": "./lib/types/types.d.ts",
"default": "./lib/types/types.js"
},
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.js",
"lib/types/**/*.d.ts"
],
"license": "BSD-3-Clause",

View File

@@ -9,10 +9,9 @@
*/
import { Context, Service } from '@deepseek-ai/cordis'
import type { Branded } from '@deepseek-ai/dsh-brand'
import type { CredentialRef } from './types.ts'
/** Nominal reference to one credential: a POSIX-style environment-variable name. */
export type CredentialRef = Branded<'CredentialRef'>
export type { CredentialRef } from './types.ts'
const REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/
@@ -50,22 +49,6 @@ declare module '@deepseek-ai/cordis' {
interface Context {
credentials: Credentials
}
interface Events {
/**
* Committed change to a provider-managed credential source: a `set`, an
* `unset`, or an external edit observed in storage. Ambient
* process-environment changes are not observable and never emit. Listener
* failures are contained and logged — a sync throw and an async rejection
* alike — without changing the committed operation's outcome, except
* `INVARIANT`-coded failures, which rethrow after every listener ran;
* that rethrow reaches the emitter only from synchronous listeners, so
* invariant checks on this event must not be async functions.
* @param ref - the reference whose stored value changed.
* @mode emit
*/
'credentials/updated'(ref: CredentialRef): void
}
}
/**

View File

@@ -0,0 +1,31 @@
/**
* Client-safe type surface of the credential-reference seam: the reference
* brand and the seam's Cordis event declaration. Types only — no runtime code,
* and nothing here reaches a Host-only symbol, so a Client compilation face
* reads exactly the signature the Host emits.
*
* @module @deepseek-ai/dsh-credentials/types
*/
import type { Branded } from '@deepseek-ai/dsh-brand'
/** Nominal reference to one credential: a POSIX-style environment-variable name. */
export type CredentialRef = Branded<'CredentialRef'>
declare module '@deepseek-ai/cordis' {
interface Events {
/**
* Committed change to a provider-managed credential source: a `set`, an
* `unset`, or an external edit observed in storage. Ambient
* process-environment changes are not observable and never emit. Listener
* failures are contained and logged — a sync throw and an async rejection
* alike — without changing the committed operation's outcome, except
* `INVARIANT`-coded failures, which rethrow after every listener ran;
* that rethrow reaches the emitter only from synchronous listeners, so
* invariant checks on this event must not be async functions.
* @param ref - the reference whose stored value changed.
* @mode emit
*/
'credentials/updated'(ref: CredentialRef): void
}
}