@powerduck/openapi-request 0.2.2

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.
@@ -0,0 +1,783 @@
1
+ import { d as GrpcEndpoint, H as GrpcMethodKind, L as GrpcResult, G as GrpcTarget, N as GrpcSendOptions, r as GrpcCredentialsOptions } from './types-C9ifzKqk.cjs';
2
+ import * as _grpc_grpc_js from '@grpc/grpc-js';
3
+ import * as _grpc_proto_loader from '@grpc/proto-loader';
4
+
5
+ /**
6
+ * Loader options are part of the contract, not an implementation detail:
7
+ * `keepCase` decides whether request JSON keys are snake_case or camelCase, and
8
+ * `enums`/`longs` decide the JSON form of values. template.ts derives the shape
9
+ * it generates from these, so the two can never drift.
10
+ */
11
+ declare const LOADER_OPTIONS: {
12
+ readonly keepCase: true;
13
+ readonly longs: StringConstructor;
14
+ readonly enums: StringConstructor;
15
+ readonly defaults: true;
16
+ readonly oneofs: true;
17
+ };
18
+ type SymbolKind = "service" | "message" | "enum";
19
+ interface SymbolEntry {
20
+ kind: SymbolKind;
21
+ /**
22
+ * The decoded descriptor. Always present — a symbol we cannot describe is not
23
+ * registered at all, because an entry with an absent descriptor is exactly the
24
+ * failure mode that made method lists silently empty.
25
+ */
26
+ type: unknown;
27
+ /**
28
+ * File the symbol was declared in. Unnamed descriptors get a stable synthetic
29
+ * label ("(unnamed #1)"), never a shared placeholder: duplicate-definition
30
+ * diagnostics compare these labels, and a constant would make every pair of
31
+ * duplicates look like the same declaration seen twice.
32
+ */
33
+ file: string;
34
+ }
35
+ interface Catalog {
36
+ source: "proto" | "reflection";
37
+ /** Fully-qualified name (no leading dot) -> entry. Map entries excluded. */
38
+ symbols: Map<string, SymbolEntry>;
39
+ /** Service names known from descriptors, sorted. */
40
+ services: string[];
41
+ /** Service names the runtime can actually dial, sorted. */
42
+ invocableServices: string[];
43
+ /** Fully-qualified service name -> ServiceDescriptorProto. */
44
+ serviceDescriptors: Map<string, unknown>;
45
+ /** Non-fatal facts worth surfacing to the user. */
46
+ notes: string[];
47
+ /** Proto files loaded, or descriptor file names when source is reflection. */
48
+ files?: string[];
49
+ /**
50
+ * File names carried by the descriptors that were decoded and indexed.
51
+ *
52
+ * Deliberately separate from `files`: under the proto source `files` is what
53
+ * was found on disk. Note that the two are not always the same *kind* of
54
+ * name — see crossCheckFiles.
55
+ */
56
+ descriptorFiles: string[];
57
+ /**
58
+ * Fully-qualified names of synthetic map-entry messages.
59
+ *
60
+ * They are deliberately absent from `symbols` — a user can never name one —
61
+ * but anything resolving a field's `type_name` still has to tell "this is a
62
+ * map entry" apart from "this type is missing".
63
+ */
64
+ mapEntries: Set<string>;
65
+ /**
66
+ * True when none of the decoded descriptors carried a file name.
67
+ *
68
+ * Diagnostic wording only. It is deliberately NOT a switch for any check:
69
+ * treating "names exist" as "names are comparable to paths" is what produced
70
+ * a confidently false coverage warning for two files whose symbols were all
71
+ * present.
72
+ */
73
+ descriptorFilesUnnamed: boolean;
74
+ }
75
+ declare function buildCatalog(endpoint: GrpcEndpoint): Promise<{
76
+ catalog: Catalog;
77
+ packageDefinition: Record<string, unknown>;
78
+ }>;
79
+
80
+ interface OneofHint {
81
+ /** Dot path of the containing message; "" means the root message. */
82
+ at: string;
83
+ oneof: string;
84
+ /** Field names in this oneof, in declaration order. Exactly one may be set. */
85
+ branches: string[];
86
+ /** Which branch the generated template pre-fills. */
87
+ chosen: string;
88
+ /**
89
+ * Per-branch shape, so a UI can switch branches without re-describing the
90
+ * method. Values are the same proto3-JSON form the example uses.
91
+ *
92
+ * A branch may be absent here: a message-typed branch under
93
+ * fillMessageFields:false has no value to offer, and inventing `{}` for it
94
+ * would claim "set with all defaults" rather than "not set".
95
+ */
96
+ branchValues: Record<string, unknown>;
97
+ }
98
+ interface EnumHint {
99
+ /** Dot path of the field. */
100
+ at: string;
101
+ /** Fully-qualified enum name. */
102
+ enum: string;
103
+ values: string[];
104
+ }
105
+ interface CollectionHint {
106
+ at: string;
107
+ kind: "repeated" | "map";
108
+ /** Element / value type, for UI display. */
109
+ of: string;
110
+ /** Map key type, for maps only. */
111
+ keyOf?: string;
112
+ }
113
+ interface PresenceHint {
114
+ at: string;
115
+ /**
116
+ * Explicit-presence field: omitting it and setting it to the zero value are
117
+ * distinguishable on the wire, so the UI must not conflate them.
118
+ *
119
+ * Exactly one hint is emitted per path. An `optional` message field is
120
+ * reported as "proto3_optional" only — two entries for one path, each with
121
+ * its own presentInExample, would leave the UI no way to pick.
122
+ */
123
+ reason: "proto3_optional" | "message";
124
+ /** Whether the generated example includes this key. */
125
+ presentInExample: boolean;
126
+ /**
127
+ * Value to use if the user chooses to set it. Always computed, including when
128
+ * the example omits the key — that is the whole purpose of the hint, and
129
+ * re-describing the method to recover it is what these hints exist to avoid.
130
+ */
131
+ valueIfSet: unknown;
132
+ }
133
+ interface MessageTemplate {
134
+ /** Fully-qualified message name, no leading dot. */
135
+ message: string;
136
+ /** Editable example in proto3 JSON shape. */
137
+ example: Record<string, unknown>;
138
+ /**
139
+ * Which key spelling the example uses. Mirrors the loader configuration the
140
+ * request will actually be serialised with; editing tools should not assume.
141
+ */
142
+ keyStyle: "declared" | "json";
143
+ oneofs: OneofHint[];
144
+ enums: EnumHint[];
145
+ collections: CollectionHint[];
146
+ presence: PresenceHint[];
147
+ /** Truncated recursion, unresolvable types, unsupported well-known types. */
148
+ warnings: string[];
149
+ }
150
+ interface BuildTemplateOptions {
151
+ /** Recursion cap for self-referential or deep messages. Default 4. */
152
+ maxDepth?: number;
153
+ /**
154
+ * When true, repeated/map fields get one sample element so the user has
155
+ * something to edit. When false they start empty. Default true.
156
+ */
157
+ seedCollections?: boolean;
158
+ /**
159
+ * When true, `optional` (explicit-presence) fields are pre-filled with their
160
+ * zero value. Default FALSE: presence is observable on the wire, and a
161
+ * template that silently sets every optional field would make "omitted" the
162
+ * one state the user cannot reach by accident. The hints tell the UI what to
163
+ * offer instead.
164
+ */
165
+ fillExplicitOptional?: boolean;
166
+ /**
167
+ * When true, singular message-typed fields are pre-filled. Message fields
168
+ * also have explicit presence, but omitting them entirely would leave the
169
+ * user with nothing to expand, so the default is TRUE and the presence hint
170
+ * records that the key may be removed.
171
+ */
172
+ fillMessageFields?: boolean;
173
+ }
174
+ /**
175
+ * Builds an editable proto3-JSON example for a message.
176
+ *
177
+ * The shape is fixed by the descriptor and is NOT user-editable; what the user
178
+ * edits are the values, plus four structural choices the schema leaves open:
179
+ * which oneof branch is set, whether an explicit-presence field is present at
180
+ * all, how many elements a repeated field or map has, and (outside this
181
+ * function) metadata / deadline / flow control. Those four are reported as
182
+ * hints rather than baked into the example.
183
+ */
184
+ declare function buildMessageTemplate(catalog: Catalog, messageName: string, options?: BuildTemplateOptions): MessageTemplate;
185
+
186
+ interface DiscoveredMethod {
187
+ /** Method name as declared in proto. */
188
+ name: string;
189
+ /** "/pkg.Service/Method" */
190
+ path: string;
191
+ kind: GrpcMethodKind;
192
+ /**
193
+ * Fully-qualified request message name, or undefined when only the runtime
194
+ * view was available. Undefined means "unknown", never "empty" — a template
195
+ * cannot be generated for it.
196
+ */
197
+ inputType?: string;
198
+ /** Fully-qualified response message name. See inputType. */
199
+ outputType?: string;
200
+ requestStream: boolean;
201
+ responseStream: boolean;
202
+ /** False when the method appears in the descriptor but has no runtime codec. */
203
+ invocable: boolean;
204
+ }
205
+ interface DiscoveredService {
206
+ /** Fully-qualified service name. */
207
+ name: string;
208
+ /** Proto package, "" when the service is at the top level. */
209
+ package: string;
210
+ methods: DiscoveredMethod[];
211
+ /**
212
+ * Which views contributed. "both" is the healthy case; anything else means
213
+ * the corresponding capability is degraded and `notes` explains why.
214
+ */
215
+ views: "both" | "descriptor_only" | "runtime_only";
216
+ }
217
+ interface DiscoveryResult {
218
+ address: string;
219
+ source: "proto" | "reflection";
220
+ services: DiscoveredService[];
221
+ /** Files loaded, when source === "proto". */
222
+ files?: string[];
223
+ notes: string[];
224
+ }
225
+ interface MethodDetail extends DiscoveredMethod {
226
+ service: string;
227
+ /** Editable request body plus the structural choices the schema leaves open. */
228
+ request?: MessageTemplate;
229
+ /** Shape of the response, for display. */
230
+ response?: MessageTemplate;
231
+ notes: string[];
232
+ }
233
+ interface DescribeOptions {
234
+ includeResponse?: boolean;
235
+ maxDepth?: number;
236
+ seedCollections?: boolean;
237
+ fillExplicitOptional?: boolean;
238
+ fillMessageFields?: boolean;
239
+ }
240
+ /**
241
+ * Discovery plus a generated request template, i.e. everything needed to render
242
+ * a request editor for one method.
243
+ *
244
+ * Each call rebuilds the catalog, which under reflection means a full handshake
245
+ * per method. Callers that describe many methods should build the catalog once
246
+ * and use `describeFromCatalog`. No cache lives here on purpose: adding one
247
+ * later is a minor change, while shipping the wrong invalidation rule is a
248
+ * breaking one.
249
+ */
250
+ declare function describeMethod(endpoint: GrpcEndpoint, service: string, method: string, options?: DescribeOptions): Promise<MethodDetail>;
251
+ declare function describeFromCatalog(catalog: Catalog, packageDefinition: Record<string, unknown>, service: string, method: string, options?: DescribeOptions): MethodDetail;
252
+ /**
253
+ * Enumerates services from an already-built catalog.
254
+ *
255
+ * Split out so a caller holding a catalog — the adapter's cache, or a UI that
256
+ * already listed services — never rebuilds it just to re-enumerate. Under
257
+ * reflection a rebuild also means observing a server that may have been
258
+ * redeployed in between, so the two results could legitimately disagree.
259
+ */
260
+ declare function discoverFromCatalog(endpoint: GrpcEndpoint, catalog: Catalog, packageDefinition: Record<string, unknown>): DiscoveryResult;
261
+ /** Builds a catalog for the endpoint, then enumerates it. */
262
+ declare function discover(endpoint: GrpcEndpoint): Promise<DiscoveryResult>;
263
+
264
+ interface GrpcPlan {
265
+ collection: unknown;
266
+ environment: unknown;
267
+ warnings: string[];
268
+ streaming: boolean;
269
+ }
270
+ interface CachedCatalog {
271
+ catalog: Catalog;
272
+ packageDefinition: Record<string, unknown>;
273
+ at: number;
274
+ }
275
+ interface GrpcAdapterOptions {
276
+ /**
277
+ * How long a catalog may be reused, in ms. Default 30_000.
278
+ *
279
+ * A server can be redeployed with a different schema, so this is a staleness
280
+ * budget rather than a permanent cache; 0 disables reuse entirely.
281
+ */
282
+ catalogTtlMs?: number;
283
+ /**
284
+ * Maximum number of cached catalogs. Default 32.
285
+ *
286
+ * A descriptor set is large, and a long-lived process pointed at many
287
+ * endpoints would otherwise grow this map without bound — a cache with a
288
+ * staleness budget but no size budget is still a leak.
289
+ */
290
+ maxCachedCatalogs?: number;
291
+ }
292
+ declare class GrpcAdapter {
293
+ readonly protocol: "grpc";
294
+ private readonly catalogTtlMs;
295
+ private readonly maxCachedCatalogs;
296
+ /** Insertion-ordered, so the oldest key is the first one Map yields. */
297
+ private readonly catalogs;
298
+ /** In-flight builds, so concurrent first calls dial once. */
299
+ private readonly building;
300
+ constructor(options?: GrpcAdapterOptions);
301
+ /**
302
+ * True only for targets this adapter can actually process. One without a
303
+ * descriptor source is rejected here rather than accepted and then failed in
304
+ * plan(), because claiming support for something that always throws makes the
305
+ * dispatcher's decision meaningless.
306
+ */
307
+ supports(target: unknown): boolean;
308
+ private assertSupported;
309
+ /**
310
+ * Guards the endpoint-only entry points.
311
+ *
312
+ * These are public and are reached directly by discovery UIs, so they cannot
313
+ * rely on assertSupported having run — and they must not require a service or
314
+ * method, which is the whole point of discovery.
315
+ */
316
+ private assertEndpoint;
317
+ /**
318
+ * Builds or reuses the catalog for an endpoint.
319
+ *
320
+ * In-flight de-duplication applies even when caching is off. With
321
+ * catalogTtlMs: 0 the intent is "never reuse a stale catalog", not "dial the
322
+ * server once per concurrent caller"; the second reading would make disabling
323
+ * the cache a way to multiply reflection round-trips.
324
+ */
325
+ catalogFor(endpoint: GrpcEndpoint): Promise<CachedCatalog>;
326
+ /** Drops the oldest entries once the cache exceeds its size budget. */
327
+ private evict;
328
+ /**
329
+ * Drops cached descriptors, for when the server or the proto tree changed.
330
+ *
331
+ * In-flight builds are dropped too. A build already running was started
332
+ * against the state the caller is now declaring stale, so handing its result
333
+ * to the next caller would serve exactly what invalidate() was called to
334
+ * avoid. Callers already awaiting that promise still receive it — the
335
+ * alternative is rejecting a request that has done nothing wrong.
336
+ */
337
+ invalidate(endpoint?: GrpcEndpoint): void;
338
+ /** Diagnostics about the descriptor source, reported once per endpoint. */
339
+ sourceNotes(endpoint: GrpcEndpoint): Promise<string[]>;
340
+ /**
341
+ * Produces an export bundle for one method.
342
+ *
343
+ * Unlike the HTTP adapter this performs I/O — reading the proto tree, or
344
+ * dialling the server when reflection is the source — because a gRPC method's
345
+ * streaming kind and message shapes exist nowhere else.
346
+ */
347
+ plan(target: unknown): Promise<GrpcPlan>;
348
+ /**
349
+ * Invokes the method, reusing the cached descriptor source.
350
+ *
351
+ * Passing the catalog through is not an optimisation. Left to build its own,
352
+ * grpcCall would re-read the proto tree or — under reflection — dial again,
353
+ * so plan() and run() could observe two different server states, and the
354
+ * runtime/descriptor cross-check inside resolveMethod would be comparing two
355
+ * moments instead of two views.
356
+ */
357
+ run(target: unknown, options?: unknown): Promise<GrpcResult>;
358
+ /** Not part of ProtocolAdapter; exposed for discovery UIs. */
359
+ discover(endpoint: GrpcEndpoint): Promise<DiscoveryResult>;
360
+ describeMethod(endpoint: GrpcEndpoint, service: string, method: string, options?: DescribeOptions): Promise<MethodDetail>;
361
+ }
362
+
363
+ /**
364
+ * A descriptor source already built by the caller.
365
+ *
366
+ * Passing one is not merely an optimisation. Under reflection every
367
+ * `buildCatalog` is a fresh dial, so resolving the method again here would
368
+ * compare the runtime and descriptor views of two different server states —
369
+ * exactly the disagreement `resolveMethod` refuses to guess through. A host
370
+ * that already holds a catalog (GrpcAdapter does) must hand it over.
371
+ */
372
+ interface GrpcCallContext {
373
+ catalog: Catalog;
374
+ packageDefinition: Record<string, unknown>;
375
+ /**
376
+ * Whether catalog-wide diagnostics belong in this call's `warnings`.
377
+ *
378
+ * Default false. A catalog note describes the descriptor source — "3 .proto
379
+ * files were merged", "these type references do not resolve" — and is a
380
+ * property of the endpoint, not of one invocation. Repeating it on every call
381
+ * buries the notes that are about the call, which is what turned the warning
382
+ * list into scrollback. Surface them once, from discover()/describeMethod().
383
+ */
384
+ includeSourceNotes?: boolean;
385
+ }
386
+ /**
387
+ * Invokes one gRPC method. All four streaming kinds converge on a single event
388
+ * log and a single set of termination conditions.
389
+ *
390
+ * Transport-level failures are reported in the result rather than thrown; only
391
+ * option validation and descriptor resolution — both of which happen before any
392
+ * bytes move — throw.
393
+ *
394
+ * Without a `context`, this builds a descriptor source on every call, which
395
+ * means reading the proto tree or dialling reflection each time. Calling it in
396
+ * a loop that way is wasteful and, under reflection, unsound; go through
397
+ * GrpcAdapter, or pass the catalog yourself.
398
+ */
399
+ declare function grpcCall(target: GrpcTarget, options?: GrpcSendOptions, context?: GrpcCallContext): Promise<GrpcResult>;
400
+
401
+ interface ResolvedMethod {
402
+ /**
403
+ * The method name as declared in the descriptor, which may differ in case
404
+ * from what the caller passed. Anything that records the call — exports,
405
+ * logs, collection items — must use this rather than the input, or it will
406
+ * record a name the server does not have.
407
+ */
408
+ name: string;
409
+ kind: GrpcMethodKind;
410
+ /** "/pkg.Service/Method" */
411
+ path: string;
412
+ requestStream: boolean;
413
+ responseStream: boolean;
414
+ serialize: (value: unknown) => Buffer;
415
+ deserialize: (buffer: Buffer) => unknown;
416
+ /**
417
+ * Fully-qualified request/response message names, when the descriptor had
418
+ * them. "Fully-qualified" is a promise to the caller: these are written into
419
+ * exported collections and quoted in client-side error messages, so a
420
+ * relative name here is a wrong name, not a shorter one.
421
+ */
422
+ inputType?: string;
423
+ outputType?: string;
424
+ /** How the descriptor was obtained. */
425
+ source: "proto" | "reflection";
426
+ /** Non-fatal notes worth surfacing. */
427
+ notes: string[];
428
+ }
429
+ /**
430
+ * A catalog already built for this endpoint, supplied to avoid re-reading the
431
+ * proto tree and, under reflection, to avoid a second dial.
432
+ *
433
+ * Both halves are required together because they must come from ONE
434
+ * buildCatalog call: the package definition is the runtime view and the catalog
435
+ * is the metadata view of the same descriptors. Mixing views from two builds
436
+ * would let the streaming cross-check below compare two different moments of
437
+ * the server and refuse a call for a disagreement that never existed.
438
+ */
439
+ interface ResolveMethodOptions {
440
+ catalog: Catalog;
441
+ packageDefinition: Record<string, unknown>;
442
+ }
443
+ /**
444
+ * Resolves one method to the codecs and streaming flags needed to invoke it.
445
+ *
446
+ * Two views are consulted and both must agree. The runtime view (proto-loader's
447
+ * package definition) is the only source of codecs and paths; the descriptor
448
+ * view is the only source of message type names. Where they overlap — the
449
+ * streaming flags — a disagreement means one of them is describing a different
450
+ * method, and the call is refused rather than guessed: choosing wrongly leaves
451
+ * a stream that should be half-closed open, or closes one that should stay open,
452
+ * and both present as a hang instead of an error.
453
+ *
454
+ * Called without `options` it builds a catalog itself, which means re-reading
455
+ * the proto tree or re-dialling for reflection on every call. That cost is
456
+ * accepted so that `grpcCall` stays usable on its own; anything issuing more
457
+ * than one call should build the catalog once (or go through GrpcAdapter, which
458
+ * caches it) and pass it here.
459
+ */
460
+ declare function resolveMethod(target: GrpcTarget, options?: ResolveMethodOptions): Promise<ResolvedMethod>;
461
+
462
+ interface CollectProtoOptions {
463
+ paths: string[];
464
+ /** Directory names skipped during traversal. Defaults below. */
465
+ ignoreDirs?: string[];
466
+ /**
467
+ * Follow symlinks. Off by default: a link cycle is common in monorepos and
468
+ * following one silently doubles or hangs the scan. Cycles are detected by
469
+ * real path either way, so enabling this is safe.
470
+ */
471
+ followSymlinks?: boolean;
472
+ /** Cap on files collected, to bound a mistakenly broad root. Default 5000. */
473
+ maxFiles?: number;
474
+ }
475
+ interface ProtoScanResult {
476
+ /** Absolute .proto paths, de-duplicated, sorted by byte order. */
477
+ files: string[];
478
+ /** Roots as given, resolved to absolute directories. */
479
+ rootDirs: string[];
480
+ /** Roots that pointed at a single file rather than a tree. */
481
+ fileRoots: string[];
482
+ /** Non-fatal facts: skipped links, unreadable dirs, caps hit. */
483
+ notes: string[];
484
+ }
485
+ /**
486
+ * Expands a mix of files and directories into a de-duplicated, sorted list of
487
+ * absolute .proto paths.
488
+ *
489
+ * The sort is load-order significant: when two files declare the same
490
+ * fully-qualified symbol, proto-loader lets one of them win without complaint,
491
+ * so a stable order is what makes such a conflict reproducible rather than
492
+ * dependent on directory iteration order.
493
+ */
494
+ declare function scanProtoFiles(options: CollectProtoOptions): Promise<ProtoScanResult>;
495
+ interface IncludeDirsResult {
496
+ includeDirs: string[];
497
+ notes: string[];
498
+ }
499
+ /**
500
+ * Derives include dirs so that `import "common/types.proto"` resolves.
501
+ *
502
+ * A bare directory scan without this loads files that cannot resolve their own
503
+ * imports. But note what the fallback costs: adding every containing directory
504
+ * makes `import "types.proto"` resolve from any directory in the tree, so a
505
+ * proto that `protoc -I <root>` would reject can load here. That is a guess in
506
+ * the user's favour, and guesses that loosen resolution have to be announced —
507
+ * otherwise this library reports a proto tree as healthy when the real build
508
+ * will fail. Pass includeDirs explicitly to switch the guess off.
509
+ */
510
+ declare function deriveIncludeDirsDetailed(scan: ProtoScanResult): IncludeDirsResult;
511
+
512
+ /**
513
+ * The server could not be asked at all: no reflection service on either
514
+ * version. Distinct from "reflection works and the answer is empty", which
515
+ * is a legitimate (if unhelpful) reply and must not be reported the same way.
516
+ */
517
+ declare class ReflectionUnavailableError extends Error {
518
+ readonly address: string;
519
+ readonly versionsTried: readonly ReflectionVersion[];
520
+ constructor(address: string, versionsTried: readonly ReflectionVersion[], cause?: unknown);
521
+ }
522
+ /** The reflection service answered, but the answer was an error or unusable. */
523
+ declare class ReflectionProtocolError extends Error {
524
+ readonly detail?: string;
525
+ constructor(message: string, detail?: string);
526
+ }
527
+ type ReflectionVersion = "v1" | "v1alpha";
528
+ interface ReflectionSessionOptions {
529
+ address: string;
530
+ credentials: _grpc_grpc_js.ChannelCredentials;
531
+ metadata?: Record<string, string | string[] | Buffer | Buffer[]>;
532
+ /** Wall-clock budget for the whole session. Default 5000. */
533
+ timeoutMs?: number;
534
+ channelOptions?: Record<string, unknown>;
535
+ /** Pin a version. Omit to try v1 then fall back to v1alpha. */
536
+ version?: ReflectionVersion;
537
+ /** `host` field on each request. Only meaningful for virtual-hosted servers. */
538
+ host?: string;
539
+ /** Hard cap on files pulled in one session. Default 2000. */
540
+ maxFiles?: number;
541
+ /** Hard cap on total descriptor bytes. Default 32 MiB. */
542
+ maxBytes?: number;
543
+ }
544
+ /** What the session should ask for. */
545
+ type ReflectionOp =
546
+ /** list_services only. */
547
+ {
548
+ kind: "list";
549
+ }
550
+ /** Descriptor closure for the given symbols. */
551
+ | {
552
+ kind: "symbols";
553
+ symbols: string[];
554
+ }
555
+ /**
556
+ * list_services, then the closure for everything it returned — on one
557
+ * stream, so the two halves cannot disagree about what the server exposes.
558
+ */
559
+ | {
560
+ kind: "list_then_symbols";
561
+ };
562
+ interface ReflectionOutcome {
563
+ /** Present iff the op asked for a service list. */
564
+ services?: string[];
565
+ /** filename -> raw FileDescriptorProto bytes. */
566
+ descriptors: Map<string, Buffer>;
567
+ /** Which version actually answered. */
568
+ version: ReflectionVersion;
569
+ /** Non-fatal facts the caller should surface. */
570
+ notes: string[];
571
+ }
572
+ /**
573
+ * Serialises files in dependency order.
574
+ *
575
+ * FileDescriptorSet { repeated FileDescriptorProto file = 1; }
576
+ */
577
+ declare function serializeDescriptorSet(descriptors: Map<string, Buffer>): Buffer;
578
+ interface ListServicesResult {
579
+ /** Service names, excluding the reflection service itself. */
580
+ services: string[];
581
+ version: ReflectionVersion;
582
+ notes: string[];
583
+ }
584
+ /**
585
+ * Service names exposed by the server.
586
+ *
587
+ * An empty array is a legitimate answer: it means reflection works and the
588
+ * server registered nothing. That is a different fact from "the server has
589
+ * no reflection service", which throws ReflectionUnavailableError, and callers
590
+ * must not collapse the two into one message.
591
+ */
592
+ declare function listServicesDetailed(options: ReflectionSessionOptions): Promise<ListServicesResult>;
593
+ /** Convenience wrapper for callers that only want the names. */
594
+ declare function listServices(options: ReflectionSessionOptions): Promise<string[]>;
595
+ interface DescriptorSetResult {
596
+ /** Serialised FileDescriptorSet, in dependency order. */
597
+ descriptorSet: Buffer;
598
+ /**
599
+ * Filenames included, in the same order as the descriptors inside
600
+ * `descriptorSet`.
601
+ *
602
+ * The correspondence is positional and load-bearing: `files[i]` names the
603
+ * i-th FileDescriptorProto in the set. Sorting this list independently — which
604
+ * it used to be — silently broke that pairing for anyone who relied on it.
605
+ */
606
+ files: string[];
607
+ version: ReflectionVersion;
608
+ notes: string[];
609
+ }
610
+ /** Transitive descriptor closure for the given symbols, merged and de-duplicated. */
611
+ declare function fetchDescriptorSet(options: ReflectionSessionOptions & {
612
+ symbols: string[];
613
+ }): Promise<DescriptorSetResult>;
614
+ interface FullDescriptorSetResult extends DescriptorSetResult {
615
+ services: string[];
616
+ }
617
+ /**
618
+ * Lists services and fetches their descriptor closure over a single stream.
619
+ *
620
+ * Doing both on one call is not just an optimisation: two separate sessions can
621
+ * observe two different server states, so the service list could name a service
622
+ * whose descriptors the second session never asked for.
623
+ */
624
+ declare function fetchFullDescriptorSet(options: ReflectionSessionOptions): Promise<FullDescriptorSetResult>;
625
+
626
+ /**
627
+ * Minimal protobuf wire decoder for descriptor.proto.
628
+ *
629
+ * Why hand-rolled: the descriptor bytes arrive from two places — a reflection
630
+ * response and proto-loader's `fileDescriptorProtos` — and both must produce
631
+ * one identical symbol table. Decoding them ourselves is the only way to
632
+ * guarantee that without depending on proto-loader internals (the previous
633
+ * implementation matched on its private `format` string, which meant a service
634
+ * could vanish from the catalog without any error).
635
+ *
636
+ * Output convention: plain objects with snake_case keys, matching
637
+ * descriptor.proto field names. Repeated containers are ALWAYS present (empty
638
+ * array when absent) so downstream shape guards can distinguish "no methods"
639
+ * from "not a descriptor at all". Enums stay numeric; the readers in
640
+ * descriptor-types.ts normalise them.
641
+ */
642
+ declare class DescriptorDecodeError extends Error {
643
+ constructor(message: string);
644
+ }
645
+ interface DecodedFile {
646
+ name?: string;
647
+ package?: string;
648
+ syntax?: string;
649
+ dependency: string[];
650
+ message_type: DecodedMessage[];
651
+ enum_type: DecodedEnum[];
652
+ service: DecodedService[];
653
+ }
654
+ interface DecodedMessage {
655
+ name: string;
656
+ field: DecodedField[];
657
+ nested_type: DecodedMessage[];
658
+ enum_type: DecodedEnum[];
659
+ oneof_decl: {
660
+ name: string;
661
+ }[];
662
+ options: {
663
+ map_entry: boolean;
664
+ };
665
+ }
666
+ interface DecodedField {
667
+ name: string;
668
+ number: number;
669
+ label: number;
670
+ type: number;
671
+ type_name?: string;
672
+ json_name?: string;
673
+ oneof_index?: number;
674
+ proto3_optional: boolean;
675
+ }
676
+ interface DecodedEnum {
677
+ name: string;
678
+ value: {
679
+ name: string;
680
+ number: number;
681
+ }[];
682
+ }
683
+ interface DecodedService {
684
+ name: string;
685
+ method: DecodedMethod[];
686
+ }
687
+ interface DecodedMethod {
688
+ name: string;
689
+ input_type: string;
690
+ output_type: string;
691
+ client_streaming: boolean;
692
+ server_streaming: boolean;
693
+ }
694
+ /** Decodes a single FileDescriptorProto. */
695
+ declare function decodeFileDescriptorProto(buf: Uint8Array): DecodedFile;
696
+ declare function decodeFileDescriptorSet(buf: Uint8Array): DecodedFile[];
697
+
698
+ type GrpcJs = typeof _grpc_grpc_js;
699
+ type ProtoLoader = typeof _grpc_proto_loader;
700
+ interface LoadedGrpc {
701
+ grpc: GrpcJs;
702
+ protoLoader: ProtoLoader;
703
+ /** Capabilities probed once at load time, so call sites never re-check. */
704
+ capabilities: GrpcCapabilities;
705
+ }
706
+ interface GrpcCapabilities {
707
+ /** proto-loader >= 0.7. Required by reflection. */
708
+ descriptorSetFromBuffer: boolean;
709
+ /** Versions read from each package.json, when readable. Diagnostics only. */
710
+ grpcVersion?: string;
711
+ protoLoaderVersion?: string;
712
+ }
713
+ /**
714
+ * The optional gRPC peer dependencies are missing.
715
+ *
716
+ * Distinguished from every other load failure because it is the only one the
717
+ * user can fix with an install command; telling someone to install a package
718
+ * they already have is worse than saying nothing.
719
+ */
720
+ declare class GrpcDependencyMissingError extends Error {
721
+ readonly missing: readonly string[];
722
+ constructor(missing: readonly string[], cause?: unknown);
723
+ }
724
+ /**
725
+ * The package is installed but unusable: it failed to evaluate, or its shape is
726
+ * not what this library requires. Actionable in a completely different way from
727
+ * a missing install, so it is a separate type.
728
+ */
729
+ declare class GrpcDependencyBrokenError extends Error {
730
+ readonly packageName: string;
731
+ constructor(packageName: string, reason: string, cause?: unknown);
732
+ }
733
+ /**
734
+ * Loads the optional gRPC peer dependencies on first use, so HTTP-only
735
+ * consumers never pay for them and never need them installed.
736
+ */
737
+ declare function loadGrpc(): Promise<LoadedGrpc>;
738
+ /** Non-throwing probe, for callers deciding whether to offer gRPC at all. */
739
+ declare function isGrpcAvailable(): Promise<boolean>;
740
+ /**
741
+ * Asserts a capability, naming the version that provides it.
742
+ *
743
+ * Centralised here because the loader is the only place that knows what was
744
+ * actually loaded; probing at each call site means each new call site can
745
+ * forget to probe.
746
+ *
747
+ * Unknown keys throw rather than pass. The previous early return made this a
748
+ * no-op for anything but one capability, so adding a capability and forgetting
749
+ * to handle it here would silently disable its check.
750
+ */
751
+ declare function requireCapability(loaded: LoadedGrpc, capability: keyof GrpcCapabilities): void;
752
+
753
+ /** Reported alongside a result so a relaxed check is never silent. */
754
+ interface CredentialsBuildResult {
755
+ credentials: _grpc_grpc_js.ChannelCredentials;
756
+ /**
757
+ * What was actually built, derived from the inputs rather than from intent:
758
+ * "tls-system-roots" is also what you get from `tls: { skipHostnameVerification: true }`
759
+ * with no rootCerts, which is a very different configuration than it looks.
760
+ */
761
+ mode: "insecure" | "tls-system-roots" | "tls-custom-roots" | "mtls";
762
+ warnings: string[];
763
+ }
764
+ /**
765
+ * Builds channel credentials, reporting what was actually built.
766
+ *
767
+ * The reported mode is derived from the inputs rather than from the caller's
768
+ * intent, so a config that silently degrades to system roots (or to plaintext)
769
+ * is visible in the result instead of being discovered at the first failed
770
+ * handshake.
771
+ */
772
+ declare function buildCredentialsChecked(source: GrpcCredentialsOptions, { grpc }: LoadedGrpc): CredentialsBuildResult;
773
+ /**
774
+ * Convenience wrapper for call sites that have nowhere to put warnings.
775
+ *
776
+ * Prefer `buildCredentialsChecked` anywhere the warnings can reach the user;
777
+ * dropping them is a deliberate loss, not a free simplification.
778
+ */
779
+ declare function buildCredentials(source: GrpcCredentialsOptions, loaded: LoadedGrpc): _grpc_grpc_js.ChannelCredentials;
780
+ declare function buildCredentialsAsync(source: GrpcCredentialsOptions): Promise<_grpc_grpc_js.ChannelCredentials>;
781
+ declare function buildCredentialsCheckedAsync(source: GrpcCredentialsOptions): Promise<CredentialsBuildResult>;
782
+
783
+ export { type MethodDetail as $, serializeDescriptorSet as A, type BuildTemplateOptions as B, type Catalog as C, type DiscoveryResult as D, type CollectProtoOptions as E, type CollectionHint as F, GrpcAdapter as G, type CredentialsBuildResult as H, type DecodedEnum as I, type DecodedField as J, type DecodedFile as K, LOADER_OPTIONS as L, type DecodedMessage as M, type DecodedMethod as N, type DecodedService as O, type DescribeOptions as P, type DescriptorSetResult as Q, ReflectionProtocolError as R, type EnumHint as S, type FullDescriptorSetResult as T, type GrpcAdapterOptions as U, type GrpcCapabilities as V, type GrpcPlan as W, type IncludeDirsResult as X, type ListServicesResult as Y, type LoadedGrpc as Z, type MessageTemplate as _, DescriptorDecodeError as a, type OneofHint as a0, type PresenceHint as a1, type ProtoScanResult as a2, type ReflectionOp as a3, type ReflectionOutcome as a4, type ReflectionSessionOptions as a5, type ReflectionVersion as a6, type ResolveMethodOptions as a7, type ResolvedMethod as a8, type SymbolEntry as a9, type SymbolKind as aa, describeFromCatalog as ab, describeMethod as ac, discoverFromCatalog as ad, GrpcDependencyBrokenError as b, GrpcDependencyMissingError as c, type DiscoveredMethod as d, type DiscoveredService as e, ReflectionUnavailableError as f, buildCatalog as g, buildCredentials as h, buildCredentialsAsync as i, buildCredentialsChecked as j, buildCredentialsCheckedAsync as k, buildMessageTemplate as l, decodeFileDescriptorProto as m, decodeFileDescriptorSet as n, deriveIncludeDirsDetailed as o, discover as p, fetchDescriptorSet as q, fetchFullDescriptorSet as r, grpcCall as s, isGrpcAvailable as t, listServices as u, listServicesDetailed as v, loadGrpc as w, requireCapability as x, resolveMethod as y, scanProtoFiles as z };