@deepseek-ai/dsh-typert-protocol 0.2.1-alpha.1 → 0.2.1-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +13 -10
- package/README.md +26 -5
- package/README.zh.md +26 -5
- package/lib/index.js +230 -28
- package/lib/types/index.d.ts +64 -12
- package/lib/types/index.js +54 -26
- package/lib/types/principal.d.ts +13 -0
- package/lib/types/principal.js +15 -0
- package/lib/types/remote-access.d.ts +32 -0
- package/lib/types/remote-access.js +9 -0
- package/lib/types/remote-info.d.ts +21 -0
- package/lib/types/remote-info.js +143 -0
- package/lib/types/types.d.ts +226 -13
- package/package.json +9 -4
package/lib/types/index.d.ts
CHANGED
|
@@ -5,18 +5,21 @@
|
|
|
5
5
|
* @module @deepseek-ai/dsh-typert-protocol
|
|
6
6
|
*/
|
|
7
7
|
import { Context, Service } from '@deepseek-ai/cordis';
|
|
8
|
-
import type { TypertContextMap } from './types.ts';
|
|
8
|
+
import type { RemoteWireArgs, TypertContextMap, TypertResourceReader, TypertResourceReaders } from './types.ts';
|
|
9
9
|
export { RemoteError, remoteErrorOf } from './remote-error.ts';
|
|
10
10
|
export { TYPERT_OWNED_VALUE, isTypertOwnedValue, typertOwnedValue } from './owned-value.ts';
|
|
11
11
|
export type { TypertOwnedValue } from './owned-value.ts';
|
|
12
12
|
export { isRemoteJsonValue, isRemoteUplinkItem } from './json-value.ts';
|
|
13
|
+
export { createTypertRemoteInfo, isTypertRemoteMethod } from './remote-info.ts';
|
|
14
|
+
export { principalOf } from './principal.ts';
|
|
15
|
+
export type { RemoteAccessResource, RemoteAccessResourceKind, RemoteAccessResourceOf } from './remote-access.ts';
|
|
13
16
|
/**
|
|
14
17
|
* Test one generated Remote name against the Connection endpoint grammar.
|
|
15
18
|
* @param value - namespace, method, lookup, or Context segment.
|
|
16
19
|
* @returns whether the value can cross the shared RPC carrier unchanged.
|
|
17
20
|
*/
|
|
18
21
|
export declare function isTypertRemoteSegment(value: string): boolean;
|
|
19
|
-
export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, PeerId, PeerScope, RemoteErrorCode, RemoteErrorDetailsMap, RemoteFailure, RemoteInvocation, RemoteResult, RemoteStream, RemoteStreamHandle, TypertClientEventListener, TypertClientRemote, TypertClientContextAdapter, TypertCodec, TypertContext, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertForwardableEventEntry, TypertHostContextAdapter, TypertHostContextResolver, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts';
|
|
22
|
+
export type { InvocationDescriptor, InvocationParameterDescriptor, InvocationSourceLocation, PeerId, PeerScope, Principal, PrincipalMap, RemoteDecoded, RemoteErrorCode, RemoteErrorDetailsMap, RemoteFailure, RemoteInvocation, RemoteResult, RemoteStream, RemoteStreamHandle, RemoteUplinkWindow, RemoteWireArgs, RemoteWireValue, TypertClientEventListener, TypertClientRemote, TypertClientContextAdapter, TypertCodec, TypertContext, TypertContextMap, TypertContextRegistry, TypertContextWire, TypertDisposer, TypertForwardableEvent, TypertForwardableEventEntry, TypertHostContextAdapter, TypertHostContextResolver, TypertResource, TypertResourceDeclaration, TypertResourceEntry, TypertResourceId, TypertResourceKind, TypertResourceMap, TypertResourceReader, TypertResourceReaders, TypertResourceRegistry, TypertLocalRegistry, TypertLookup, TypertLookupDefinition, TypertLookupHost, TypertLookupMap, TypertLookupProvider, TypertLookupResolver, TypertLookupRegistry, TypertLookupWire, TypertRemoteScopeApi, TypertRemoteScopeMap, TypertRemoteScopeNamespace, TypertRemoteContribution, TypertRemoteInfo, TypertRemoteInputOptions, TypertRemoteMethod, TypertRemoteValue, TypertRemoteCodecSpec, TypertRemoteParameterSpec, TypertRemoteMethodSpec, TypertRemoteSpec, TypertRemoteEvent, TypertRemoteEventSelection, TypertRemoteMap, TypertRemoteNamespace, TypertRemoteNamespaceMap, TypertRemoteRegistry, TypertRegistryChange, TypertRegistryListener, TypertSchema, TypertRegistryContract, } from './types.ts';
|
|
20
23
|
/** Options for an explicit Service-to-Gateway binding. */
|
|
21
24
|
export interface TypertGatewayBindingOptions {
|
|
22
25
|
/** Wire namespace; defaults to the Cordis service key. */
|
|
@@ -44,12 +47,48 @@ export interface RemoteMethodMarker {
|
|
|
44
47
|
/** Stream methods yield many independently validated result items. */
|
|
45
48
|
readonly mode?: 'stream';
|
|
46
49
|
readonly invocation: RemoteInvocationMarker;
|
|
50
|
+
/**
|
|
51
|
+
* Declared `resources` readers keyed by resource kind. Callers spread the
|
|
52
|
+
* method's wire arguments into each one and validate its result.
|
|
53
|
+
*/
|
|
54
|
+
readonly resources?: Readonly<Record<string, TypertResourceReader>>;
|
|
47
55
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
56
|
+
/**
|
|
57
|
+
* Explicit endpoint and resource choices for one Remote Scope method.
|
|
58
|
+
* @template WireArgs - the decorated method's positional parameters as the
|
|
59
|
+
* wire carries them; the default `never` admits readers of any tuple.
|
|
60
|
+
*/
|
|
61
|
+
export interface RemoteScopeOptions<WireArgs extends readonly unknown[] = never> {
|
|
62
|
+
/** Exported endpoint method; omission retains the implementation member name. */
|
|
63
|
+
readonly name?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Per-kind readers of the resources one call touches. Each receives the
|
|
66
|
+
* method's arguments as its own parameters, JSON arguments as their Typert
|
|
67
|
+
* codecs validated them, a lookup parameter as its wire identity and a
|
|
68
|
+
* cancellation parameter as the call's signal, so it performs plain reads
|
|
69
|
+
* only, and returns one identity, several, or `undefined` for none. A
|
|
70
|
+
* throw, an empty list, or an identity other than a non-empty string
|
|
71
|
+
* refuses the call. For a kind without a reader, the Gateway reads the
|
|
72
|
+
* identity of a scoped Context whose Host adapter declares that `resource`
|
|
73
|
+
* and of lookup parameters declaring it, else the field registered in
|
|
74
|
+
* `typert.resources`: a top-level argument or, failing that, the first
|
|
75
|
+
* object argument. A call that carries no identity touches `global`. The
|
|
76
|
+
* readers and these defaults together must name every resource the method
|
|
77
|
+
* accesses: access control never checks a resource they omit.
|
|
78
|
+
*/
|
|
79
|
+
readonly resources?: TypertResourceReaders<WireArgs>;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Explicit endpoint, stream, and resource choices for one direct Remote method.
|
|
83
|
+
* @template WireArgs - the decorated method's positional parameters as the
|
|
84
|
+
* wire carries them; the default `never` admits readers of any tuple.
|
|
85
|
+
*/
|
|
86
|
+
export interface RemoteMethodOptions<WireArgs extends readonly unknown[] = never> extends RemoteScopeOptions<WireArgs> {
|
|
50
87
|
/** `stream`: deliver each Iterable item over the shared logical-stream carrier. */
|
|
51
|
-
readonly mode
|
|
88
|
+
readonly mode?: 'stream';
|
|
52
89
|
}
|
|
90
|
+
/** A decorator whose `resources` readers were checked against the decorated method's parameters. */
|
|
91
|
+
type RemoteTypedMethodDecorator<This extends object, Args extends unknown[], Result> = (method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>) => void;
|
|
53
92
|
type RemoteMethodDecorator = <This extends object, Args extends unknown[], Result>(method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>) => void;
|
|
54
93
|
/**
|
|
55
94
|
* Bind one visible Service field to a Cordis key and Remote namespace. A
|
|
@@ -58,7 +97,7 @@ type RemoteMethodDecorator = <This extends object, Args extends unknown[], Resul
|
|
|
58
97
|
* a Host composition to read it.
|
|
59
98
|
* @param service - owning Service instance, normally `this`.
|
|
60
99
|
* @param serviceKey - exact Cordis service key.
|
|
61
|
-
* @param options - optional
|
|
100
|
+
* @param options - optional wire namespace.
|
|
62
101
|
* @returns a frozen, inspectable binding with no compiler-injected metadata.
|
|
63
102
|
*/
|
|
64
103
|
export declare function bindTypertRemote<Service extends object>(service: Service, serviceKey: string, options?: TypertGatewayBindingOptions): TypertGatewayBinding<Service>;
|
|
@@ -70,7 +109,7 @@ export declare abstract class TypertRemoteService<out T = never> extends Service
|
|
|
70
109
|
* Register the Service and bind the same key to Typert Gateway.
|
|
71
110
|
* @param ctx - owning Cordis Context.
|
|
72
111
|
* @param serviceKey - exact Cordis service key and default wire namespace.
|
|
73
|
-
* @param options - optional
|
|
112
|
+
* @param options - optional wire namespace.
|
|
74
113
|
*/
|
|
75
114
|
protected constructor(ctx: Context, serviceKey: string, options?: TypertGatewayBindingOptions);
|
|
76
115
|
}
|
|
@@ -81,18 +120,31 @@ export declare abstract class TypertRemoteService<out T = never> extends Service
|
|
|
81
120
|
*/
|
|
82
121
|
export declare function Remote<This extends object, Args extends unknown[], Result>(_method: (this: This, ...args: Args) => Result, context: ClassMethodDecoratorContext<This, (this: This, ...args: Args) => Result>): void;
|
|
83
122
|
/**
|
|
84
|
-
* Mark one public instance method
|
|
85
|
-
* @param
|
|
123
|
+
* Mark one public instance method with an endpoint name.
|
|
124
|
+
* @param name - exported endpoint method.
|
|
125
|
+
* @returns a standard method decorator.
|
|
126
|
+
*/
|
|
127
|
+
export declare function Remote(name: string): RemoteMethodDecorator;
|
|
128
|
+
/**
|
|
129
|
+
* Mark one public instance method with endpoint, stream, or resource options.
|
|
130
|
+
* @param options - Remote options; each reader's parameters are inferred from the decorated method.
|
|
86
131
|
* @returns a standard method decorator.
|
|
87
132
|
*/
|
|
88
|
-
export declare function Remote(
|
|
133
|
+
export declare function Remote<This extends object, Args extends unknown[], Result>(options: NoInfer<RemoteMethodOptions<RemoteWireArgs<Args>>>): RemoteTypedMethodDecorator<This, Args, Result>;
|
|
89
134
|
/**
|
|
90
135
|
* Create a decorator for a method resolved from one Remote Scope.
|
|
91
136
|
* @param key - scope key declared through the Context map.
|
|
92
|
-
* @param
|
|
137
|
+
* @param name - optional Remote export name; defaults to the method name.
|
|
138
|
+
* @returns a standard method decorator that records a versioned prototype descriptor.
|
|
139
|
+
*/
|
|
140
|
+
export declare function RemoteScope(key: Extract<keyof TypertContextMap, string>, name?: string): RemoteMethodDecorator;
|
|
141
|
+
/**
|
|
142
|
+
* Create a decorator for a Remote Scope method with endpoint or resource options.
|
|
143
|
+
* @param key - scope key declared through the Context map.
|
|
144
|
+
* @param options - Remote Scope options; each reader's parameters are inferred from the decorated method.
|
|
93
145
|
* @returns a standard method decorator that records a versioned prototype descriptor.
|
|
94
146
|
*/
|
|
95
|
-
export declare function RemoteScope(key: Extract<keyof TypertContextMap, string>,
|
|
147
|
+
export declare function RemoteScope<This extends object, Args extends unknown[], Result>(key: Extract<keyof TypertContextMap, string>, options: NoInfer<RemoteScopeOptions<RemoteWireArgs<Args>>>): RemoteTypedMethodDecorator<This, Args, Result>;
|
|
96
148
|
/**
|
|
97
149
|
* Read Remote markers attached to a live Service's class prototype.
|
|
98
150
|
* The returned snapshot cannot mutate the stored descriptor.
|
package/lib/types/index.js
CHANGED
|
@@ -8,6 +8,8 @@ import { Context, Service } from '@deepseek-ai/cordis';
|
|
|
8
8
|
export { RemoteError, remoteErrorOf } from "./remote-error.js";
|
|
9
9
|
export { TYPERT_OWNED_VALUE, isTypertOwnedValue, typertOwnedValue } from "./owned-value.js";
|
|
10
10
|
export { isRemoteJsonValue, isRemoteUplinkItem } from "./json-value.js";
|
|
11
|
+
export { createTypertRemoteInfo, isTypertRemoteMethod } from "./remote-info.js";
|
|
12
|
+
export { principalOf } from "./principal.js";
|
|
11
13
|
const TYPERT_REMOTE_SEGMENT_PATTERN = /^[A-Za-z0-9_$.-]+$/;
|
|
12
14
|
/**
|
|
13
15
|
* Test one generated Remote name against the Connection endpoint grammar.
|
|
@@ -25,7 +27,7 @@ const REMOTE_METHOD_DESCRIPTOR = '@deepseek-ai/dsh-typert-protocol/remote-method
|
|
|
25
27
|
* a Host composition to read it.
|
|
26
28
|
* @param service - owning Service instance, normally `this`.
|
|
27
29
|
* @param serviceKey - exact Cordis service key.
|
|
28
|
-
* @param options - optional
|
|
30
|
+
* @param options - optional wire namespace.
|
|
29
31
|
* @returns a frozen, inspectable binding with no compiler-injected metadata.
|
|
30
32
|
*/
|
|
31
33
|
export function bindTypertRemote(service, serviceKey, options = {}) {
|
|
@@ -33,7 +35,7 @@ export function bindTypertRemote(service, serviceKey, options = {}) {
|
|
|
33
35
|
const namespace = options.namespace ?? serviceKey;
|
|
34
36
|
validateName('namespace', namespace);
|
|
35
37
|
const ctx = Reflect.get(service, 'ctx');
|
|
36
|
-
if (ctx
|
|
38
|
+
if (Context.is(ctx))
|
|
37
39
|
provideInvocationAccessor(ctx);
|
|
38
40
|
return Object.freeze({ service, serviceKey, namespace });
|
|
39
41
|
}
|
|
@@ -45,7 +47,7 @@ export class TypertRemoteService extends Service {
|
|
|
45
47
|
* Register the Service and bind the same key to Typert Gateway.
|
|
46
48
|
* @param ctx - owning Cordis Context.
|
|
47
49
|
* @param serviceKey - exact Cordis service key and default wire namespace.
|
|
48
|
-
* @param options - optional
|
|
50
|
+
* @param options - optional wire namespace.
|
|
49
51
|
*/
|
|
50
52
|
constructor(ctx, serviceKey, options = {}) {
|
|
51
53
|
super(ctx, serviceKey);
|
|
@@ -66,38 +68,61 @@ function provideInvocationAccessor(ctx) {
|
|
|
66
68
|
export function Remote(methodExportOrOptions, context) {
|
|
67
69
|
if (typeof methodExportOrOptions === 'string') {
|
|
68
70
|
validateName('Remote export name', methodExportOrOptions);
|
|
69
|
-
return remoteDecorator({ kind: 'direct' },
|
|
71
|
+
return remoteDecorator({ kind: 'direct' }, { exportName: methodExportOrOptions });
|
|
70
72
|
}
|
|
71
73
|
if (typeof methodExportOrOptions === 'object') {
|
|
72
|
-
|
|
73
|
-
|| Reflect.ownKeys(methodExportOrOptions).length !== 1) {
|
|
74
|
-
throw new TypeError('typert-protocol: Remote options must contain exactly mode: "stream"');
|
|
75
|
-
}
|
|
76
|
-
return remoteDecorator({ kind: 'direct' }, 'stream');
|
|
74
|
+
return remoteDecorator({ kind: 'direct' }, markerOptions(methodExportOrOptions, REMOTE_OPTION_KEYS, 'Remote options require name, mode: "stream", or resources'));
|
|
77
75
|
}
|
|
78
76
|
if (context === undefined)
|
|
79
77
|
throw new TypeError('typert-protocol: Remote decorator context is missing');
|
|
80
78
|
addMarkerInitializer(context, { kind: 'direct' });
|
|
81
79
|
}
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
const REMOTE_OPTION_KEYS = new Set(['name', 'mode', 'resources']);
|
|
81
|
+
const REMOTE_SCOPE_OPTION_KEYS = new Set(['name', 'resources']);
|
|
82
|
+
/** Validate one decorator options object against its accepted keys and select the marker fields. */
|
|
83
|
+
function markerOptions(options, accepted, requirement) {
|
|
84
|
+
const keys = Reflect.ownKeys(options);
|
|
85
|
+
if (keys.length === 0 || keys.some(key => typeof key !== 'string' || !accepted.has(key))
|
|
86
|
+
|| (Object.hasOwn(options, 'mode') && options.mode !== 'stream')) {
|
|
87
|
+
throw new TypeError(`typert-protocol: ${requirement}`);
|
|
88
|
+
}
|
|
89
|
+
const { mode, name, resources } = options;
|
|
90
|
+
if (name !== undefined)
|
|
91
|
+
validateName('Remote export name', name);
|
|
92
|
+
return {
|
|
93
|
+
...(mode === undefined ? {} : { mode }),
|
|
94
|
+
...(name === undefined ? {} : { exportName: name }),
|
|
95
|
+
...(resources === undefined ? {} : { resources: resourceReaders(resources) }),
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Freeze declared readers into the marker record; a misdeclared reader fails at decoration. */
|
|
99
|
+
function resourceReaders(resources) {
|
|
100
|
+
const readers = {};
|
|
101
|
+
for (const [kind, reader] of Object.entries(resources)) {
|
|
102
|
+
if (typeof reader !== 'function') {
|
|
103
|
+
throw new TypeError(`typert-protocol: Remote resource reader "${kind}" must be a function`);
|
|
104
|
+
}
|
|
105
|
+
readers[kind] = reader;
|
|
106
|
+
}
|
|
107
|
+
if (Object.keys(readers).length === 0)
|
|
108
|
+
throw new TypeError('typert-protocol: Remote resources require at least one reader');
|
|
109
|
+
return Object.freeze(readers);
|
|
84
110
|
}
|
|
85
|
-
function remoteDecorator(invocation,
|
|
111
|
+
function remoteDecorator(invocation, options = {}) {
|
|
86
112
|
return function (_method, context) {
|
|
87
|
-
addMarkerInitializer(context, invocation,
|
|
113
|
+
addMarkerInitializer(context, invocation, options);
|
|
88
114
|
};
|
|
89
115
|
}
|
|
90
|
-
|
|
91
|
-
* Create a decorator for a method resolved from one Remote Scope.
|
|
92
|
-
* @param key - scope key declared through the Context map.
|
|
93
|
-
* @param exportName - optional Remote export name; defaults to the method name.
|
|
94
|
-
* @returns a standard method decorator that records a versioned prototype descriptor.
|
|
95
|
-
*/
|
|
96
|
-
export function RemoteScope(key, exportName) {
|
|
116
|
+
export function RemoteScope(key, option) {
|
|
97
117
|
validateName('Scope key', key);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
118
|
+
const invocation = { kind: 'context', context: key };
|
|
119
|
+
if (option === undefined)
|
|
120
|
+
return remoteDecorator(invocation);
|
|
121
|
+
if (typeof option === 'string') {
|
|
122
|
+
validateName('Remote export name', option);
|
|
123
|
+
return remoteDecorator(invocation, { exportName: option });
|
|
124
|
+
}
|
|
125
|
+
return remoteDecorator(invocation, markerOptions(option, REMOTE_SCOPE_OPTION_KEYS, 'RemoteScope options require name or resources'));
|
|
101
126
|
}
|
|
102
127
|
/**
|
|
103
128
|
* Read Remote markers attached to a live Service's class prototype.
|
|
@@ -129,7 +154,7 @@ function readRemoteMethodDescriptor(prototype) {
|
|
|
129
154
|
}
|
|
130
155
|
return descriptor;
|
|
131
156
|
}
|
|
132
|
-
function addMarkerInitializer(context, invocation,
|
|
157
|
+
function addMarkerInitializer(context, invocation, options = {}) {
|
|
133
158
|
if (context.private || context.static || typeof context.name !== 'string') {
|
|
134
159
|
throw new TypeError('typert-protocol: Remote decorators require a public instance method with a string name');
|
|
135
160
|
}
|
|
@@ -139,21 +164,24 @@ function addMarkerInitializer(context, invocation, mode, exportName) {
|
|
|
139
164
|
if (prototype === null) {
|
|
140
165
|
throw new TypeError(`typert-protocol: cannot mark Remote method "${method}" on an object without a prototype`);
|
|
141
166
|
}
|
|
142
|
-
mark(prototype, method, invocation,
|
|
167
|
+
mark(prototype, method, invocation, options);
|
|
143
168
|
});
|
|
144
169
|
}
|
|
145
|
-
function mark(prototype, method, invocation, mode, exportName) {
|
|
170
|
+
function mark(prototype, method, invocation, { mode, exportName, resources }) {
|
|
146
171
|
const descriptor = readRemoteMethodDescriptor(prototype);
|
|
147
172
|
const marker = Object.freeze({
|
|
148
173
|
method,
|
|
149
174
|
...(exportName === undefined || exportName === method ? {} : { exportName }),
|
|
150
175
|
...(mode === undefined ? {} : { mode }),
|
|
151
176
|
invocation: Object.freeze(invocation),
|
|
177
|
+
...(resources === undefined ? {} : { resources }),
|
|
152
178
|
});
|
|
153
179
|
const current = descriptor?.methods.find(candidate => candidate.method === method);
|
|
154
180
|
if (current !== undefined) {
|
|
181
|
+
// One decorator application owns one frozen reader record, so identity marks the same declaration.
|
|
155
182
|
if (current.exportName === marker.exportName
|
|
156
183
|
&& current.mode === marker.mode
|
|
184
|
+
&& current.resources === marker.resources
|
|
157
185
|
&& sameInvocation(current.invocation, invocation))
|
|
158
186
|
return;
|
|
159
187
|
throw new Error(`typert-protocol: Remote method "${method}" has conflicting invocation markers`);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the non-owner caller of the current Remote call.
|
|
3
|
+
* @module @deepseek-ai/dsh-typert-protocol/principal
|
|
4
|
+
*/
|
|
5
|
+
import type { Principal, RemoteInvocation } from './types.ts';
|
|
6
|
+
/**
|
|
7
|
+
* The identity a Remote-call producer records on durable output.
|
|
8
|
+
* @param invocation - `ctx.invocation`; `undefined` outside a Remote call.
|
|
9
|
+
* @returns the caller's principal when it is not the owner; `undefined` for the
|
|
10
|
+
* owner and for trusted in-process code outside a Remote call.
|
|
11
|
+
*/
|
|
12
|
+
export declare function principalOf(invocation: RemoteInvocation | undefined): Principal | undefined;
|
|
13
|
+
//# sourceMappingURL=principal.d.ts.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads the non-owner caller of the current Remote call.
|
|
3
|
+
* @module @deepseek-ai/dsh-typert-protocol/principal
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* The identity a Remote-call producer records on durable output.
|
|
7
|
+
* @param invocation - `ctx.invocation`; `undefined` outside a Remote call.
|
|
8
|
+
* @returns the caller's principal when it is not the owner; `undefined` for the
|
|
9
|
+
* owner and for trusted in-process code outside a Remote call.
|
|
10
|
+
*/
|
|
11
|
+
export function principalOf(invocation) {
|
|
12
|
+
const principal = invocation?.peer.principal;
|
|
13
|
+
return principal?.kind === 'owner' ? undefined : principal;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=principal.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources of Remote access control: the built-in identity-less `global`
|
|
3
|
+
* resource and one resource per identity of a kind declared in
|
|
4
|
+
* `TypertResourceMap`. Resources are independent: access to one resource
|
|
5
|
+
* implies no access to any other.
|
|
6
|
+
* @module @deepseek-ai/dsh-typert-protocol/remote-access
|
|
7
|
+
*/
|
|
8
|
+
import type { TypertResourceId, TypertResourceKind, TypertResourceMap } from './types.ts';
|
|
9
|
+
/** One resource kind: the built-in `global` kind or a declared kind. */
|
|
10
|
+
export type RemoteAccessResourceKind = 'global' | TypertResourceKind;
|
|
11
|
+
/**
|
|
12
|
+
* One resource a call or forwarded event touches: `global`, or one identity
|
|
13
|
+
* of a declared kind. Identities are wire values, read before any lookup
|
|
14
|
+
* resolves or validates them.
|
|
15
|
+
*/
|
|
16
|
+
export type RemoteAccessResource = {
|
|
17
|
+
readonly kind: 'global';
|
|
18
|
+
} | {
|
|
19
|
+
[Kind in TypertResourceKind]: {
|
|
20
|
+
readonly kind: Kind;
|
|
21
|
+
readonly id: TypertResourceId<TypertResourceMap[Kind]>;
|
|
22
|
+
};
|
|
23
|
+
}[TypertResourceKind];
|
|
24
|
+
/**
|
|
25
|
+
* The resource variant of one kind: `{ kind: 'global' }` for `global`, else
|
|
26
|
+
* that kind with its identity.
|
|
27
|
+
* @template K - the resource kind to select.
|
|
28
|
+
*/
|
|
29
|
+
export type RemoteAccessResourceOf<K extends RemoteAccessResourceKind> = Extract<RemoteAccessResource, {
|
|
30
|
+
readonly kind: K;
|
|
31
|
+
}>;
|
|
32
|
+
//# sourceMappingURL=remote-access.d.ts.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resources of Remote access control: the built-in identity-less `global`
|
|
3
|
+
* resource and one resource per identity of a kind declared in
|
|
4
|
+
* `TypertResourceMap`. Resources are independent: access to one resource
|
|
5
|
+
* implies no access to any other.
|
|
6
|
+
* @module @deepseek-ai/dsh-typert-protocol/remote-access
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=remote-access.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Lazy assembly of generated Remote definitions using caller-supplied Zod; no runtime imports. */
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { InvocationDescriptor, TypertRemoteInfo, TypertRemoteMethod, TypertRemoteSpec } from './types.ts';
|
|
4
|
+
type Method = TypertRemoteMethod<object, unknown> | TypertRemoteMethod<object, unknown, 'stream', unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Retain one generated definition per endpoint without constructing parsers or projections.
|
|
7
|
+
* The class instance builds its shared descriptor/method index on first access;
|
|
8
|
+
* input schemas and JSON Schema projections are cached only when requested.
|
|
9
|
+
* @param spec - compiler-produced method facts and Zod factories.
|
|
10
|
+
* @param zod - the generated artifact's Zod runtime for named-input parsers.
|
|
11
|
+
* @returns a lazy, mountable info instance with no registration or transport effects.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createTypertRemoteInfo(spec: TypertRemoteSpec, zod: typeof z): TypertRemoteInfo;
|
|
14
|
+
/**
|
|
15
|
+
* Narrow a Registry descriptor to its generated direct-method capabilities.
|
|
16
|
+
* @param descriptor - a live descriptor, including possible source fallback or Context-only receivers.
|
|
17
|
+
* @returns whether generated named input and direct invocation are available.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isTypertRemoteMethod(descriptor: InvocationDescriptor): descriptor is Method;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=remote-info.d.ts.map
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/** Lazy assembly of generated Remote definitions using caller-supplied Zod; no runtime imports. */
|
|
2
|
+
/**
|
|
3
|
+
* Retain one generated definition per endpoint without constructing parsers or projections.
|
|
4
|
+
* The class instance builds its shared descriptor/method index on first access;
|
|
5
|
+
* input schemas and JSON Schema projections are cached only when requested.
|
|
6
|
+
* @param spec - compiler-produced method facts and Zod factories.
|
|
7
|
+
* @param zod - the generated artifact's Zod runtime for named-input parsers.
|
|
8
|
+
* @returns a lazy, mountable info instance with no registration or transport effects.
|
|
9
|
+
*/
|
|
10
|
+
export function createTypertRemoteInfo(spec, zod) {
|
|
11
|
+
return new RemoteInfo(spec, zod);
|
|
12
|
+
}
|
|
13
|
+
class RemoteInfo {
|
|
14
|
+
spec;
|
|
15
|
+
zod;
|
|
16
|
+
index;
|
|
17
|
+
constructor(spec, zod) {
|
|
18
|
+
this.spec = spec;
|
|
19
|
+
this.zod = zod;
|
|
20
|
+
}
|
|
21
|
+
get package() { return this.spec.package; }
|
|
22
|
+
get descriptors() { return this.resolve().descriptors; }
|
|
23
|
+
get methods() { return this.resolve().methods; }
|
|
24
|
+
resolve() {
|
|
25
|
+
if (this.index !== undefined)
|
|
26
|
+
return this.index;
|
|
27
|
+
const zod = this.zod;
|
|
28
|
+
const descriptors = [];
|
|
29
|
+
const methods = Object.create(null);
|
|
30
|
+
for (const [endpoint, definition] of Object.entries(this.spec.methods)) {
|
|
31
|
+
const separator = endpoint.indexOf('/');
|
|
32
|
+
const namespace = endpoint.slice(0, separator);
|
|
33
|
+
const method = endpoint.slice(separator + 1);
|
|
34
|
+
const parameters = definition.parameters.map(parameter => ({ ...parameter, wire: parameter.wire ?? parameter.name }));
|
|
35
|
+
const descriptor = {
|
|
36
|
+
...definition,
|
|
37
|
+
id: `${this.spec.package}#${endpoint}`,
|
|
38
|
+
namespace,
|
|
39
|
+
method,
|
|
40
|
+
parameters,
|
|
41
|
+
result: definition.result.description === undefined ? definition.result : new ResultValue(definition.result),
|
|
42
|
+
};
|
|
43
|
+
if (definition.invocation.kind === 'direct') {
|
|
44
|
+
const inputs = [];
|
|
45
|
+
const direct = Object.assign(descriptor, {
|
|
46
|
+
input(options) {
|
|
47
|
+
const strict = options?.strict === true;
|
|
48
|
+
return inputs[strict ? 1 : 0] ??= new NamedInput(parameters, strict, zod);
|
|
49
|
+
},
|
|
50
|
+
invoke(remote, input, signal) {
|
|
51
|
+
const named = input;
|
|
52
|
+
const values = parameters.map(parameter => named[parameter.wire]);
|
|
53
|
+
if (definition.cancellation !== undefined)
|
|
54
|
+
values.push(signal);
|
|
55
|
+
// Namespace access retains the Gateway's mount checks and scoped receiver policy.
|
|
56
|
+
const receiver = Reflect.get(remote, namespace);
|
|
57
|
+
const call = Reflect.get(receiver, method);
|
|
58
|
+
return call.apply(receiver, values);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
// The generated namespace return type is selected by this same descriptor's mode.
|
|
62
|
+
methods[endpoint] = direct;
|
|
63
|
+
}
|
|
64
|
+
descriptors.push(descriptor);
|
|
65
|
+
}
|
|
66
|
+
return this.index = { descriptors, methods };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Narrow a Registry descriptor to its generated direct-method capabilities.
|
|
71
|
+
* @param descriptor - a live descriptor, including possible source fallback or Context-only receivers.
|
|
72
|
+
* @returns whether generated named input and direct invocation are available.
|
|
73
|
+
*/
|
|
74
|
+
export function isTypertRemoteMethod(descriptor) {
|
|
75
|
+
return descriptor.invocation.kind === 'direct' && descriptor.result.mode === 'strict'
|
|
76
|
+
&& 'input' in descriptor && typeof descriptor.input === 'function'
|
|
77
|
+
&& 'invoke' in descriptor && typeof descriptor.invoke === 'function';
|
|
78
|
+
}
|
|
79
|
+
function optional(parameter) {
|
|
80
|
+
return parameter.source === 'json' && parameter.acceptsUndefined === true;
|
|
81
|
+
}
|
|
82
|
+
class NamedInput {
|
|
83
|
+
parameters;
|
|
84
|
+
strict;
|
|
85
|
+
zod;
|
|
86
|
+
schema;
|
|
87
|
+
projection;
|
|
88
|
+
constructor(parameters, strict, zod) {
|
|
89
|
+
this.parameters = parameters;
|
|
90
|
+
this.strict = strict;
|
|
91
|
+
this.zod = zod;
|
|
92
|
+
}
|
|
93
|
+
codec(parameter) {
|
|
94
|
+
return this.strict ? parameter.strictCodec : parameter.codec;
|
|
95
|
+
}
|
|
96
|
+
create = () => this.schema ??= this.zod.strictObject(Object.fromEntries(this.parameters.map((parameter) => {
|
|
97
|
+
const value = this.codec(parameter).create();
|
|
98
|
+
return [parameter.wire, optional(parameter) ? value.optional() : value.nonoptional()];
|
|
99
|
+
})));
|
|
100
|
+
get jsonSchema() { return this.project().jsonSchema; }
|
|
101
|
+
get jsonSchemaError() { return this.project().jsonSchemaError; }
|
|
102
|
+
project() {
|
|
103
|
+
if (this.projection !== undefined)
|
|
104
|
+
return this.projection;
|
|
105
|
+
const unavailable = this.parameters.find(parameter => this.codec(parameter).jsonSchema === undefined);
|
|
106
|
+
if (unavailable !== undefined) {
|
|
107
|
+
return this.projection = { jsonSchemaError: this.codec(unavailable).jsonSchemaError ?? `No JSON Schema for parameter ${unavailable.wire}` };
|
|
108
|
+
}
|
|
109
|
+
return this.projection = {
|
|
110
|
+
jsonSchema: {
|
|
111
|
+
type: 'object',
|
|
112
|
+
properties: Object.fromEntries(this.parameters.map(parameter => [parameter.wire, {
|
|
113
|
+
...this.codec(parameter).jsonSchema,
|
|
114
|
+
...(parameter.description === undefined ? {} : { description: parameter.description }),
|
|
115
|
+
}])),
|
|
116
|
+
required: this.parameters.filter(parameter => !optional(parameter)).map(parameter => parameter.wire),
|
|
117
|
+
additionalProperties: false,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
class ResultValue {
|
|
123
|
+
spec;
|
|
124
|
+
projection;
|
|
125
|
+
constructor(spec) {
|
|
126
|
+
this.spec = spec;
|
|
127
|
+
}
|
|
128
|
+
get mode() { return this.spec.mode; }
|
|
129
|
+
get typeSymbol() { return this.spec.typeSymbol; }
|
|
130
|
+
get create() { return this.spec.create; }
|
|
131
|
+
get decode() { return this.spec.decode; }
|
|
132
|
+
get encode() { return this.spec.encode; }
|
|
133
|
+
get description() { return this.spec.description; }
|
|
134
|
+
get jsonSchemaError() { return this.spec.jsonSchemaError; }
|
|
135
|
+
get jsonSchema() {
|
|
136
|
+
if (this.projection === undefined) {
|
|
137
|
+
const schema = this.spec.jsonSchema;
|
|
138
|
+
this.projection = { value: schema === undefined ? undefined : { ...schema, description: this.spec.description } };
|
|
139
|
+
}
|
|
140
|
+
return this.projection.value;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=remote-info.js.map
|