@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.
@@ -5,10 +5,12 @@
5
5
  */
6
6
  import type { Context, Events } from '@deepseek-ai/cordis';
7
7
  import type { Branded } from '@deepseek-ai/dsh-brand';
8
+ import type { ZodType } from 'zod';
8
9
  import type { TypertOwnedValue } from './owned-value.ts';
9
10
  declare const LOOKUP_HOST: unique symbol;
10
11
  declare const LOOKUP_WIRE: unique symbol;
11
12
  declare const CONTEXT_WIRE: unique symbol;
13
+ declare const RESOURCE_ID: unique symbol;
12
14
  /** Type-level association between a Host object and its wire identity. */
13
15
  export interface TypertLookup<Host, Wire> {
14
16
  readonly [LOOKUP_HOST]: Host;
@@ -30,6 +32,47 @@ export interface TypertLookupMap {
30
32
  /** Merge-extensible scoped Context declarations. */
31
33
  export interface TypertContextMap {
32
34
  }
35
+ /** Type-level association between a resource kind and its identity type. */
36
+ export interface TypertResource<Id> {
37
+ readonly [RESOURCE_ID]: Id;
38
+ }
39
+ /** Extract the identity type associated with one resource declaration. */
40
+ export type TypertResourceId<Resource> = Resource extends TypertResource<infer Id> ? Id : never;
41
+ /**
42
+ * Merge-extensible resource kinds whose identities a Remote call or forwarded
43
+ * event may carry. The package that owns an identity type declares its kind;
44
+ * the value is that kind's identity type, a string type such as a branded id.
45
+ * `global` names the built-in identity-less resource and is never a kind here.
46
+ */
47
+ export interface TypertResourceMap {
48
+ }
49
+ /** One declared resource kind. */
50
+ export type TypertResourceKind = Extract<keyof TypertResourceMap, string>;
51
+ /**
52
+ * Per-kind resource readers called with one argument tuple spread
53
+ * positionally: plain reads returning one identity, several, or `undefined`
54
+ * for none.
55
+ * @template Args - the argument tuple the readers receive as parameters.
56
+ */
57
+ export type TypertResourceReaders<Args extends readonly unknown[]> = {
58
+ readonly [Kind in TypertResourceKind]?: (...args: Args) => TypertResourceId<TypertResourceMap[Kind]> | readonly TypertResourceId<TypertResourceMap[Kind]>[] | undefined;
59
+ };
60
+ /**
61
+ * Type-erased resource reader as runtime carriers store it; callers spread
62
+ * the argument tuple into it and validate its result. Declared through a
63
+ * method so a reader typed by its own parameters is assignable without a cast.
64
+ */
65
+ export type TypertResourceReader = {
66
+ read(...args: readonly unknown[]): unknown;
67
+ }['read'];
68
+ type TypertLookupEntry = TypertLookupMap[keyof TypertLookupMap];
69
+ type TypertWireForHost<Value, Entry> = Entry extends unknown ? Value extends TypertLookupHost<Entry> ? TypertLookupWire<Entry> : never : never;
70
+ /** A method parameter as it arrives on the wire: a lookup's Host object becomes its wire identity. */
71
+ export type RemoteWireValue<Value> = Value extends TypertLookupHost<TypertLookupEntry> ? TypertWireForHost<Value, TypertLookupEntry> : Value;
72
+ /** A method's positional parameters as the wire carries them. */
73
+ export type RemoteWireArgs<Args extends unknown[]> = {
74
+ [Index in keyof Args]: RemoteWireValue<Args[Index]>;
75
+ };
33
76
  /** Merge-extensible direct Remote method signatures generated for consumers. */
34
77
  export interface TypertRemoteMap {
35
78
  }
@@ -136,9 +179,19 @@ type TypertForwardingMode<Event extends keyof Events> = unknown extends ThisPara
136
179
  export type TypertForwardableEvent = {
137
180
  [Event in keyof Events]: TypertForwardingMode<Event> extends never ? never : Event;
138
181
  }[keyof Events];
139
- /** Event and dispatch mode accepted by the Remote Event source. */
182
+ /**
183
+ * Event and dispatch mode accepted by the Remote Event source. An `emit` entry
184
+ * may declare readers of the resources its payload carries; an
185
+ * entry without `resources` touches the built-in `global` resource. A
186
+ * non-owner Peer receives an `emit` notification only after an access
187
+ * decision and never receives a `waterfall`.
188
+ */
140
189
  export type TypertForwardableEventEntry = {
141
- [Event in keyof Events]: TypertForwardingMode<Event> extends infer Mode ? Mode extends 'emit' | 'waterfall' ? {
190
+ [Event in keyof Events]: TypertForwardingMode<Event> extends infer Mode ? Mode extends 'emit' ? {
191
+ readonly event: Event;
192
+ readonly mode: Mode;
193
+ readonly resources?: TypertResourceReaders<TypertEventParameters<Event>>;
194
+ } : Mode extends 'waterfall' ? {
142
195
  readonly event: Event;
143
196
  readonly mode: Mode;
144
197
  } : never : never;
@@ -195,32 +248,36 @@ export interface TypertSchema<Output = unknown> {
195
248
  */
196
249
  parse(value: unknown): Output;
197
250
  }
251
+ /** Native byte views reconstructed by a Remote carrier have ordinary ArrayBuffer backing. */
252
+ export type RemoteDecoded<Value> = Value extends Uint8Array ? Uint8Array<ArrayBuffer> : Value extends string | number | boolean | bigint | symbol ? Value : Value extends object ? {
253
+ [Key in keyof Value]: RemoteDecoded<Value[Key]>;
254
+ } : Value;
198
255
  /** Codec attached to one invocation parameter or result. */
199
- export type TypertCodec = {
256
+ export type TypertCodec<Value = unknown> = (TypertRemoteValue<Value> & {
200
257
  readonly mode: 'strict';
201
258
  readonly typeSymbol: string;
202
- /** Materialize and return the process-realm schema on first boundary use. */
203
- readonly create: () => TypertSchema;
204
259
  /**
205
260
  * Decode a unary result whose fields require type-specific handling.
206
261
  * @param value - result reconstructed by the RPC carrier.
207
262
  * @returns the validated result, retaining native byte views.
208
263
  */
209
- readonly decode?: (value: unknown) => unknown;
264
+ readonly decode?: ((value: unknown) => unknown) | undefined;
210
265
  /**
211
266
  * Project typed binary fields into RPC result attachments.
212
267
  * @param value - native unary result.
213
268
  * @param writeBytes - records a byte view at its result-relative path and returns its JSON placeholder.
214
269
  * @returns JSON metadata with untouched JSON subtrees retained.
215
270
  */
216
- readonly encode?: (value: unknown, writeBytes: (bytes: Uint8Array, path: readonly (string | number)[]) => null) => unknown;
217
- } | {
271
+ readonly encode?: ((value: unknown, writeBytes: (bytes: Uint8Array, path: readonly (string | number)[]) => null) => unknown) | undefined;
272
+ }) | {
218
273
  readonly mode: 'src-json';
219
274
  };
220
275
  /** One ordered business parameter in a Remote invocation. */
221
276
  export interface InvocationParameterDescriptor {
222
277
  /** Source-level parameter name. */
223
278
  readonly name: string;
279
+ /** Source parameter documentation, independent of JSON Schema support. */
280
+ readonly description?: string;
224
281
  /** Required key in the wire `args` object. */
225
282
  readonly wire: string;
226
283
  /** Whether the value is JSON or requires a registered Host lookup. */
@@ -287,6 +344,8 @@ export interface InvocationDescriptor {
287
344
  };
288
345
  /** Codec for the unary result or each yielded stream item. */
289
346
  readonly result: TypertCodec;
347
+ /** Source-owned method documentation; ordinary methods need not have JSDoc. */
348
+ readonly description?: string;
290
349
  /** Source declaration used only for diagnostics. */
291
350
  readonly sourceLocation?: InvocationSourceLocation;
292
351
  }
@@ -297,19 +356,46 @@ export interface InvocationDescriptor {
297
356
  */
298
357
  export type PeerId = Branded<'PeerId'>;
299
358
  /**
300
- * One Peer's session on this Host. Connection owns it: `ctx` is the Cordis
359
+ * Merge-extensible caller identities. Each driver declares its own entry.
360
+ * Every entry is a JSON value with a unique literal `kind`, carries no
361
+ * credential, and is safe to persist in a Session log.
362
+ */
363
+ export interface PrincipalMap {
364
+ /** The local user who owns this Host. */
365
+ owner: {
366
+ readonly kind: 'owner';
367
+ };
368
+ }
369
+ /** One caller identity; the authorization layer reads only this. */
370
+ export type Principal = PrincipalMap[keyof PrincipalMap];
371
+ /**
372
+ * One Peer's session on this Host. Its creator owns it: `ctx` is the Cordis
301
373
  * scope that owns connection-lifetime registrations and is disposed with the
302
- * Peer. Who the Peer is and what it may do are not recorded here.
374
+ * Peer, and `principal` is the caller identity fixed when the Peer was created.
303
375
  */
304
376
  export interface PeerScope {
305
377
  readonly id: PeerId;
378
+ /** Connection-lifetime registrations; disposed with the Peer. */
306
379
  readonly ctx: Context;
380
+ /** Caller identity fixed at creation by in-process Host code; no wire field can set it. */
381
+ readonly principal: Principal;
382
+ /** Aborted once the Peer is disposed; Remote streams that speak for the Peer end with it. */
383
+ readonly signal: AbortSignal;
384
+ /** Whether the Peer may open a forwarded-event stream; this does not grant business permissions. */
385
+ readonly interactions: 'answer' | 'none';
307
386
  /**
308
387
  * Tear down every registration made through `ctx`.
309
388
  * @returns settles once the scope has quiesced; racing calls share one completion.
310
389
  */
311
390
  dispose(): Promise<void>;
312
391
  }
392
+ /** Carrier capacity for buffered uplink frames of one logical stream. */
393
+ export interface RemoteUplinkWindow {
394
+ /** Maximum complete encoded frame bytes waiting for the Host consumer. */
395
+ readonly maxBytes: number;
396
+ /** UTF-8 envelope bytes added to a compact JSON item with a present value field. */
397
+ readonly frameOverheadBytes: number;
398
+ }
313
399
  /**
314
400
  * The context of one Remote call, reachable inside the receiving method as
315
401
  * `this.ctx.invocation`. The Gateway derives the receiver from a Context that
@@ -323,10 +409,12 @@ export interface RemoteInvocation {
323
409
  };
324
410
  /** Cordis service key of the receiving Service. */
325
411
  readonly service: string;
326
- /** Peer the call speaks for; an in-process carrier speaks for the operator. */
412
+ /** Peer the call speaks for; every carrier names it explicitly. */
327
413
  readonly peer: PeerScope;
328
414
  /** Carrier cancellation: Client cancel, socket close, or an uplink failure. */
329
415
  readonly signal: AbortSignal;
416
+ /** Carrier frame capacity; absent when the carrier imposes no encoded-frame inbox limit. */
417
+ readonly uplinkWindow?: RemoteUplinkWindow | undefined;
330
418
  /**
331
419
  * The Client's uplink items for this call. Available once; a second call
332
420
  * throws. With an uplink codec on the descriptor every item is decoded to
@@ -347,6 +435,86 @@ export interface TypertRemoteContribution {
347
435
  /** Consumer-side invocation descriptors generated from that package. */
348
436
  readonly descriptors: readonly InvocationDescriptor[];
349
437
  }
438
+ /** Generated parser and optional lossless tool-schema projection of one Remote value. */
439
+ export interface TypertRemoteValue<Value = unknown> {
440
+ /** Materialize the generated parser without loading the owning Service. */
441
+ readonly create: () => TypertSchema<Value>;
442
+ /** Source-owned value documentation, independent of tool projection support. */
443
+ readonly description?: string | undefined;
444
+ /** Present when the value is representable in the tool-schema subset without losing constraints; may be derived lazily. */
445
+ readonly jsonSchema?: Readonly<Record<string, unknown>> | undefined;
446
+ /** Projection failure for consumers that require JSON Schema; parsing remains available. */
447
+ readonly jsonSchemaError?: string | undefined;
448
+ }
449
+ /** Consumer-owned input validation; never changes Host dispatch or the business method declaration. */
450
+ export interface TypertRemoteInputOptions {
451
+ /** Reject undeclared fields in input objects; explicit dictionaries and JSON values remain open. */
452
+ readonly strict?: boolean;
453
+ }
454
+ /** A direct descriptor; DecodedOutput differs from its parser output only for carrier-reconstructed unary bytes. */
455
+ export type TypertRemoteMethod<Input extends object, Output, Mode extends 'unary' | 'stream' = 'unary', Uplink = never, DecodedOutput = Output> = Omit<InvocationDescriptor, 'mode' | 'invocation' | 'result'> & (Mode extends 'stream' ? {
456
+ readonly mode: 'stream';
457
+ } : {
458
+ readonly mode?: never;
459
+ }) & {
460
+ /** Named invocation selects a direct Service method, not a Context receiver. */
461
+ readonly invocation: {
462
+ readonly kind: 'direct';
463
+ };
464
+ /**
465
+ * Select matching named-input parsing and tool-schema projection without changing dispatch.
466
+ * @param options - consumer-owned strictness; omission preserves ordinary Remote object handling.
467
+ * @returns the cached view for this policy; its parser and projection remain lazy.
468
+ */
469
+ input(options?: TypertRemoteInputOptions): TypertRemoteValue<Input>;
470
+ /** The descriptor's result or stream-item parser; parsing alone does not normalize native byte backing. */
471
+ readonly result: Extract<TypertCodec<Output>, {
472
+ readonly mode: 'strict';
473
+ }>;
474
+ /**
475
+ * Invoke the mounted namespace method with named wire arguments.
476
+ * @param remote - caller-owned, unscoped Client Remote service; its mount owns availability.
477
+ * @param input - decoded named wire arguments.
478
+ * @param signal - caller-owned invocation lifetime.
479
+ * @returns the carrier-decoded unary result or complete stream handle, including uplink and disposal.
480
+ */
481
+ invoke(remote: TypertClientRemote, input: Input, signal?: AbortSignal): Mode extends 'stream' ? RemoteStreamHandle<Output, Uplink> : Promise<RemoteResult<DecodedOutput>>;
482
+ };
483
+ /** Ordinary contribution whose method index references its direct invocation descriptors. */
484
+ export interface TypertRemoteInfo<Methods extends Readonly<Record<string, TypertRemoteMethod<object, unknown> | TypertRemoteMethod<object, unknown, 'stream', unknown>>> = Readonly<Record<string, TypertRemoteMethod<object, unknown> | TypertRemoteMethod<object, unknown, 'stream', unknown>>>> extends TypertRemoteContribution {
485
+ /** Exact generated keys and types; Context-only receivers are available only through descriptors. */
486
+ readonly methods: Methods;
487
+ }
488
+ /** Generated Zod factory and optional tool projection for one invocation value. */
489
+ export interface TypertRemoteCodecSpec extends Omit<Extract<TypertCodec, {
490
+ readonly mode: 'strict';
491
+ }>, 'create'> {
492
+ /** Materialize the generated Zod schema only when a parser is requested. */
493
+ readonly create: () => ZodType;
494
+ }
495
+ /** One ordered parameter; omitted wire names resolve to the source parameter name. */
496
+ export interface TypertRemoteParameterSpec extends Omit<InvocationParameterDescriptor, 'wire' | 'codec'> {
497
+ /** Explicit wire alias, notably for a Host lookup identity. */
498
+ readonly wire?: string;
499
+ /** Ordinary Remote parser and projection for this parameter. */
500
+ readonly codec: TypertRemoteCodecSpec;
501
+ /** Consumer-selected counterpart rejecting undeclared fields in explicit input objects. */
502
+ readonly strictCodec: TypertRemoteCodecSpec;
503
+ }
504
+ /** Static method facts; endpoint identity and named-call helpers are derived by the runtime factory. */
505
+ export interface TypertRemoteMethodSpec extends Omit<InvocationDescriptor, 'id' | 'namespace' | 'method' | 'parameters' | 'result'> {
506
+ /** Ordered Host parameters, including their wire representations. */
507
+ readonly parameters: readonly TypertRemoteParameterSpec[];
508
+ /** Successful unary result or stream item, with optional native-byte handling. */
509
+ readonly result: TypertRemoteCodecSpec;
510
+ }
511
+ /** Compiler-produced method definitions, independent of services, registration, and transport. */
512
+ export interface TypertRemoteSpec {
513
+ /** Package owning these methods. */
514
+ readonly package: string;
515
+ /** Public endpoints; each method's invocation facts occur only once. */
516
+ readonly methods: Readonly<Record<`${string}/${string}`, TypertRemoteMethodSpec>>;
517
+ }
350
518
  /** Client Remote capability implemented by the Gateway and consumed by Remote assemblies. */
351
519
  export interface TypertClientRemote extends TypertRemoteNamespaceMap {
352
520
  /**
@@ -372,12 +540,18 @@ export interface TypertClientRemote extends TypertRemoteNamespaceMap {
372
540
  * @returns the Host object, or `undefined` when unavailable.
373
541
  */
374
542
  export type TypertLookupResolver<Host = unknown, Wire = unknown> = (id: Wire) => Host | undefined | Promise<Host | undefined>;
543
+ /** Resource kinds whose identity type is a wire identity; every kind for a type-erased provider. */
544
+ type TypertResourceKindFor<Wire> = unknown extends Wire ? TypertResourceKind : {
545
+ [Kind in TypertResourceKind]: [Wire] extends [TypertResourceId<TypertResourceMap[Kind]>] ? Kind : never;
546
+ }[TypertResourceKind];
375
547
  /** Runtime provider for one declared Host object lookup. */
376
548
  export interface TypertLookupProvider<Host = unknown, Wire = unknown> {
377
549
  /** Source parameter name recognized by the SRC weak parser. */
378
550
  readonly parameter: string;
379
551
  /** Wire field replacing the Host object parameter. */
380
552
  readonly wire: string;
553
+ /** Resource kind the wire identity names; a parameter of this lookup carries that resource. */
554
+ readonly resource?: TypertResourceKindFor<Wire>;
381
555
  /** Canonical Host type symbol used by strict generation. */
382
556
  readonly hostTypeSymbol: string;
383
557
  /** Canonical wire type symbol used by strict generation. */
@@ -408,6 +582,8 @@ export interface TypertHostContextAdapter<Wire = unknown> {
408
582
  readonly wire: string;
409
583
  /** Canonical wire type symbol used by strict generation. */
410
584
  readonly wireTypeSymbol: string;
585
+ /** Resource kind the wire identity names; a call scoped to this Context carries that resource. */
586
+ readonly resource?: TypertResourceKindFor<Wire>;
411
587
  /**
412
588
  * Resolve a validated wire identity to a live Host Context.
413
589
  * @param id - validated wire identity.
@@ -434,7 +610,7 @@ export interface TypertClientContextAdapter<Wire = unknown> {
434
610
  }
435
611
  /** Notification emitted after a Typert runtime registry changes. */
436
612
  export interface TypertRegistryChange {
437
- readonly kind: 'local' | 'remote' | 'lookup' | 'host-context' | 'client-context';
613
+ readonly kind: 'local' | 'remote' | 'lookup' | 'host-context' | 'client-context' | 'resource';
438
614
  readonly key: string;
439
615
  }
440
616
  /** Listener for one Typert runtime registry. */
@@ -544,7 +720,7 @@ export interface TypertContextRegistry {
544
720
  */
545
721
  registerClient<K extends StringKeyOf<TypertContextMap>>(key: K, adapter: TypertClientContextAdapter<TypertContextWire<TypertContextMap[K]>>): TypertDisposer;
546
722
  /**
547
- * Look up a Host Context adapter.
723
+ * Look up a Host Context adapter; a configured resolver keeps the adapter's declaration and `resource`.
548
724
  * @param key - descriptor Context key.
549
725
  * @returns the adapter, or `undefined` when absent.
550
726
  */
@@ -562,12 +738,49 @@ export interface TypertContextRegistry {
562
738
  */
563
739
  subscribe(listener: TypertRegistryListener): TypertDisposer;
564
740
  }
741
+ /** Default wire field of one resource kind. */
742
+ export interface TypertResourceDeclaration {
743
+ /** Top-level or first-object wire field holding one identity of the kind. */
744
+ readonly field: string;
745
+ }
746
+ /** One registered resource kind with its default wire field. */
747
+ export interface TypertResourceEntry extends TypertResourceDeclaration {
748
+ /** Registered resource kind. */
749
+ readonly kind: string;
750
+ }
751
+ /** Runtime registry of resource kinds' default wire fields. */
752
+ export interface TypertResourceRegistry {
753
+ /**
754
+ * Register one kind's default wire field for the calling fiber. Only the
755
+ * domain that owns the kind registers it.
756
+ * @param kind - merge-declared resource kind.
757
+ * @param declaration - the kind's default wire field.
758
+ * @returns disposer withdrawing the exact registration.
759
+ * @throws Error when the kind is already registered or is `global`, the built-in resource kind.
760
+ */
761
+ register(kind: TypertResourceKind, declaration: TypertResourceDeclaration): TypertDisposer;
762
+ /**
763
+ * Look up one kind's declaration.
764
+ * @param kind - resource kind.
765
+ * @returns the live declaration, or `undefined` when unregistered.
766
+ */
767
+ get(kind: string): TypertResourceDeclaration | undefined;
768
+ /** @returns a registration-order snapshot of registered kinds with their fields. */
769
+ entries(): readonly TypertResourceEntry[];
770
+ /**
771
+ * Observe later resource-kind changes.
772
+ * @param listener - synchronous contained observer.
773
+ * @returns disposer for this subscription.
774
+ */
775
+ subscribe(listener: TypertRegistryListener): TypertDisposer;
776
+ }
565
777
  /** Minimal Typert runtime consumed through dependency inversion. */
566
778
  export interface TypertRegistryContract {
567
779
  readonly local: TypertLocalRegistry;
568
780
  readonly remotes: TypertRemoteRegistry;
569
781
  readonly lookups: TypertLookupRegistry;
570
782
  readonly contexts: TypertContextRegistry;
783
+ readonly resources: TypertResourceRegistry;
571
784
  }
572
785
  declare module '@deepseek-ai/cordis' {
573
786
  interface Context {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-typert-protocol",
3
3
  "description": "Compiler-independent Remote metadata and Typert provider protocols",
4
- "version": "0.2.1-alpha.1",
4
+ "version": "0.2.1-alpha.3",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -22,6 +22,10 @@
22
22
  "types": "./lib/types/types.d.ts",
23
23
  "default": "./lib/types/types.js"
24
24
  },
25
+ "./remote-info": {
26
+ "types": "./lib/types/remote-info.d.ts",
27
+ "default": "./lib/types/remote-info.js"
28
+ },
25
29
  "./src/*": "./src/*",
26
30
  "./package.json": "./package.json"
27
31
  },
@@ -32,12 +36,13 @@
32
36
  ],
33
37
  "license": "MIT",
34
38
  "dependencies": {
35
- "@deepseek-ai/dsh-brand": "0.2.1-alpha.1"
39
+ "@deepseek-ai/dsh-brand": "0.2.1-alpha.3",
40
+ "zod": "^4.4.3"
36
41
  },
37
42
  "peerDependencies": {
38
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
43
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2"
39
44
  },
40
45
  "devDependencies": {
41
- "@deepseek-ai/cordis": "~4.0.5-alpha.1"
46
+ "@deepseek-ai/cordis": "~4.0.5-alpha.2"
42
47
  }
43
48
  }