@suss/adapter-typescript 0.1.0 → 0.1.1

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/dist/index.d.cts CHANGED
@@ -1,54 +1,27 @@
1
- import { Node, SourceFile, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, Project, Expression } from 'ts-morph';
1
+ import { SourceFile, Node, FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, CallExpression, Project, Expression } from 'ts-morph';
2
2
  import { TransparentWrapper, RawCondition, DiscoveryPattern, TerminalPattern, InputMappingPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, RawTerminal, RawBranch, EffectArg, RawDeclaredContract, ContractPattern, ResponsePropertyMapping } from '@suss/extractor';
3
- import { BehavioralSummary, MessageBusSemantics, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
3
+ import { BehavioralSummary, MessageBusSemantics, DeployableUnit, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
4
4
 
5
- /**
6
- * Reported by `lookup`. Surfaces what the cache decided and, for
7
- * partial-hits, the file-churn breakdown so callers can render a
8
- * diagnostic.
9
- */
5
+ /** Reported by `lookup`: what the cache decided, and why. */
10
6
  interface CacheDiagnostic {
11
- kind: "hit" | "partial-hit" | "miss";
12
- /** Reason the lookup missed (only set when kind === "miss"). */
13
- missReason?: "no-manifest" | "schema-mismatch" | "packs-changed" | "tsconfig-changed";
14
- /**
15
- * Counts describing the file churn that produced a partial hit.
16
- * Only populated when kind === "partial-hit".
17
- */
18
- partial?: {
19
- /** Cached summaries whose location.file is in the unchanged set. */
20
- reusedSummaries: number;
21
- /** Files the adapter needs to re-extract per-file from. */
22
- filesToReExtract: number;
23
- /** Files added to the include set since the cached run. */
24
- addedFiles: number;
25
- /** Files removed from the include set since the cached run. */
26
- removedFiles: number;
27
- /** Files whose mtime/size differs (excludes added/removed). */
28
- changedFiles: number;
29
- };
7
+ kind: "hit" | "miss";
8
+ /**
9
+ * Reason the lookup missed (only set when kind === "miss").
10
+ * `key-changed` means the cache directory holds entries, but none
11
+ * under this run's schema, adapter, packs and tsconfig path.
12
+ * `files-changed` means the include set is not the one the entry
13
+ * was written from.
14
+ */
15
+ missReason?: "no-manifest" | "key-changed" | "tsconfig-changed" | "files-changed";
30
16
  }
31
17
  /**
32
- * Result of a cache lookup. The adapter dispatches on `kind`:
33
- *
34
- * - "hit" — the entire summary set is valid; return it
35
- * verbatim, skip extraction.
36
- * - "partial-hit" — `kept` is correct as far as their location.file
37
- * went; re-extract `filesToExtract` per-file and
38
- * re-run the closure / rethrow passes over the
39
- * merged set.
40
- * - "miss" — manifest absent or coarse keys (schema, packs,
41
- * tsconfig) changed; full re-extract.
18
+ * Result of a cache lookup. A hit carries the whole summary set; a miss
19
+ * says why, so a caller can render the reason.
42
20
  */
43
21
  type CacheLookup = {
44
22
  kind: "hit";
45
23
  summaries: BehavioralSummary[];
46
24
  diagnostic: CacheDiagnostic;
47
- } | {
48
- kind: "partial-hit";
49
- kept: BehavioralSummary[];
50
- filesToExtract: string[];
51
- diagnostic: CacheDiagnostic;
52
25
  } | {
53
26
  kind: "miss";
54
27
  diagnostic: CacheDiagnostic;
@@ -57,6 +30,25 @@ type CacheLookup = {
57
30
  /** One pack's path through the funnel. */
58
31
  interface PackFunnel {
59
32
  pack: string;
33
+ /**
34
+ * What the pack calls this build of itself, or null when it declares
35
+ * nothing. The cache keys on it, so a pack that never changes its
36
+ * stamp can answer a later run with an earlier build's results.
37
+ */
38
+ version: string | null;
39
+ /**
40
+ * Whether the pack looks for units of its own at all. A pack made
41
+ * only of recognisers contributes effects to units other packs found,
42
+ * so discovering nothing is how it always behaves and says nothing
43
+ * about whether it is working.
44
+ */
45
+ discovers: boolean;
46
+ /**
47
+ * Whether the pack carries recognisers. Those fire inside units other
48
+ * packs discovered, so a pack made only of them contributes effects
49
+ * and never a summary.
50
+ */
51
+ recognizes: boolean;
60
52
  /**
61
53
  * Import specifiers that make a file relevant to this pack. Empty
62
54
  * for an ungated pack, which walks every file.
@@ -74,8 +66,51 @@ interface PackFunnel {
74
66
  candidateFiles: number;
75
67
  /** Units discovered across those files. */
76
68
  unitsDiscovered: number;
69
+ /**
70
+ * Unit bodies any pack walked in the files this pack's gate selected.
71
+ *
72
+ * This is what a recogniser pack had the chance to fire on. Its own
73
+ * discovery count says nothing, since it discovers nothing by design,
74
+ * and its candidate-file count says nothing either, because a
75
+ * recogniser only runs where some pack found a unit to walk.
76
+ */
77
+ unitsInGatedFiles: number;
78
+ /** Effects this pack's recognisers returned. */
79
+ effectsRecognized: number;
80
+ /**
81
+ * Units this pack kept. A unit an earlier pack already claimed is
82
+ * dropped here, so a pack can discover plenty and keep none when it
83
+ * sits behind a pack that recognises the same code.
84
+ */
85
+ unitsClaimed: number;
86
+ /**
87
+ * Units this pack discovered twice over. Cross-pack dedup is the
88
+ * point of the claim set, but a pack colliding with itself means its
89
+ * own discovery patterns overlap and one of the two is being thrown
90
+ * away without anybody deciding which.
91
+ */
92
+ selfCollisions: number;
77
93
  /** Summaries built from those units. */
78
94
  summariesProduced: number;
95
+ /** Summaries in the finished run that name this pack as what recognised them. */
96
+ summariesBound: number;
97
+ /**
98
+ * Bound summaries on the provider side of their boundary.
99
+ *
100
+ * Transitions say what a unit does with a request, which is a
101
+ * question only a provider answers. A consumer records what it reads
102
+ * back from the response instead, and that lives on the summary's
103
+ * metadata. Measuring a client pack against transitions would report
104
+ * every working one as extracting nothing.
105
+ */
106
+ providerSummaries: number;
107
+ /** Provider summaries carrying at least one transition. */
108
+ summariesWithBehavior: number;
109
+ /**
110
+ * Where one of this pack's hooks threw. Every count above is a floor
111
+ * while this is non-empty.
112
+ */
113
+ failures: PackFailure[];
79
114
  }
80
115
  interface ExtractionReport {
81
116
  /** Files in the tsconfig include set, or null when the caller supplied a Project. */
@@ -91,15 +126,35 @@ interface ExtractionReport {
91
126
  emptyStage: EmptyStage | null;
92
127
  }
93
128
  type EmptyStage = "tsconfig" | "gateResolution" | "candidateFiles" | "discovery" | "assembly";
129
+ /**
130
+ * A pack's hook throwing on one file.
131
+ *
132
+ * The run carries on with the other files, so every count for that pack
133
+ * afterwards is a floor rather than a total. Somebody reading those
134
+ * counts has to be told, or a pack that broke reads the same as a pack
135
+ * that looked and found nothing.
136
+ */
137
+ interface PackFailure {
138
+ /** The hook that threw, named as a pack author would know it. */
139
+ hook: string;
140
+ /** The file the pack was reading. */
141
+ file: string;
142
+ message: string;
143
+ }
144
+
145
+ /** One question: do these files reach any of these packages. */
146
+ interface FileSetQuery {
147
+ sourceFiles: ReadonlyArray<SourceFile>;
148
+ packages: ReadonlyArray<string>;
149
+ }
94
150
 
95
151
  declare class ResolutionStore {
96
152
  private readonly db;
97
153
  private readonly table;
98
154
  private readonly fullyExtracted;
99
155
  private readonly seededValues;
100
- private readonly gateAnswers;
101
- private resolvedBySource;
102
- private comesToBySource;
156
+ private readonly importedNames;
157
+ private readonly graph;
103
158
  private stale;
104
159
  constructor(wrappers?: TransparentWrapper[]);
105
160
  /**
@@ -119,7 +174,73 @@ declare class ResolutionStore {
119
174
  * another file, and this is how discovery reads it back.
120
175
  */
121
176
  resolveObject(value: Node): Node | null;
177
+ /**
178
+ * The expression `value` is written as, or null. Unlike the other two
179
+ * questions this one does not care what kind of expression it lands
180
+ * on, so it answers for values that are neither functions nor
181
+ * objects: a GraphQL document held in a named constant in another
182
+ * file comes back as the template literal or tag call that built it.
183
+ *
184
+ * A value the code computes has no written form to report, so the
185
+ * answer is the computing expression itself and the caller gets
186
+ * nothing it can use, which is the point.
187
+ */
188
+ resolveWrittenValue(value: Node): Node | null;
189
+ /**
190
+ * The names from `modules` this value stands for. A value stands for
191
+ * a library name two ways, and a caller asking which library concept
192
+ * something is wants both:
193
+ *
194
+ * - it is that name, under whatever local spelling. `import
195
+ * { Controller as Resource }` makes `Resource` the library's
196
+ * `Controller`.
197
+ * - calling it calls that name. A project decorator written as
198
+ * `(path) => Controller(path)` marks a controller, and so does
199
+ * one written as `applyDecorators(Controller(path))`.
200
+ *
201
+ * Several names is the normal answer rather than an ambiguity, since
202
+ * a wrapper composing two library decorators applies both. The caller
203
+ * asks whether the name it cares about is among them.
204
+ *
205
+ * One wrapper is applied across hundreds of files, so the answer is
206
+ * memoized against the declaration it was asked about. Without that,
207
+ * every use site seeds a fresh value and pays another fixpoint.
208
+ */
209
+ importedNamesOf(value: Node, modules: string[]): string[];
210
+ /**
211
+ * The names from `modules` this value stands for, or null while the
212
+ * walk should keep widening.
213
+ *
214
+ * The distinction is what keeps the cost down. A value that has
215
+ * arrived at a package has nothing more to give, because a library's
216
+ * own body is not here to read, so a decorator from a library the
217
+ * caller did not ask about stops on the first wave rather than
218
+ * running out the import closure looking for a match it will never
219
+ * find. A value that has only arrived at another file in the project
220
+ * keeps going, since the wrapper it names is declared somewhere the
221
+ * walk has not reached yet.
222
+ */
223
+ private lookupImportedNames;
122
224
  private resolveByWaves;
225
+ private walkForAnswer;
226
+ /**
227
+ * The answer has been read, so the question and the chain that
228
+ * answered it can go. What the query extracted stays: files are the
229
+ * expensive part and the next query reads the same facts.
230
+ *
231
+ * Nothing is owed after this. The rules have seen every fact the
232
+ * database holds and concluded what the demand still present asks
233
+ * for, which is none, so the next query starts from its own asking
234
+ * fact.
235
+ */
236
+ private forgetQuery;
237
+ /**
238
+ * Somebody asked about this value, which is what the rules follow
239
+ * chains for. Separate from `seedValue`, which only speaks for values
240
+ * that are expressions; a caller can ask about a declaration too, and
241
+ * the answer is still owed.
242
+ */
243
+ private wantValue;
123
244
  /**
124
245
  * Facts for the queried value itself. File extraction only reaches
125
246
  * values that hang off exports, and a query can be rooted anywhere:
@@ -129,14 +250,19 @@ declare class ResolutionStore {
129
250
  private seedValue;
130
251
  private lookupObject;
131
252
  /**
132
- * Whether `file` reaches any of `packages` through its imports,
133
- * following project-local re-export chains.
134
- *
135
- * A walk rather than a rule: the answer is one boolean per file, and
136
- * deriving the full reachable-module relation for every file in a
137
- * large repo costs far more than the question is worth.
253
+ * Reaching two different expressions means the rules cannot tell
254
+ * which one the value is written as, and the same reasoning applies
255
+ * as for the other two questions: ambiguity is nothing. The value
256
+ * itself is not an answer, or every identifier would answer with
257
+ * itself the moment its chain went nowhere.
138
258
  */
139
- importsTransitively(sourceFile: SourceFile, packages: string[]): boolean;
259
+ private lookupWritten;
260
+ /**
261
+ * For each set of files and packages, which of those files reach any
262
+ * of those packages through their imports, following project-local
263
+ * re-export chains.
264
+ */
265
+ filesImportingTransitively(fileSets: ReadonlyArray<FileSetQuery>): ReadonlyArray<ReadonlySet<SourceFile>>;
140
266
  /**
141
267
  * The one function this value resolves to. Several rules can reach
142
268
  * the same answer, which is fine, but reaching two different
@@ -145,11 +271,17 @@ declare class ResolutionStore {
145
271
  * answer depend on the order facts arrived in. Ambiguity is nothing.
146
272
  */
147
273
  private lookup;
274
+ /** Run the rules to fixpoint. */
275
+ private derive;
148
276
  /**
149
- * Run the rules to fixpoint and index `resolves` by its source, so
150
- * a lookup is a map hit rather than a scan of every derived tuple.
277
+ * The second column of an answer relation, for the value asked about.
278
+ * The database indexes a column the first time somebody looks it up
279
+ * and keeps that index as facts arrive, so this is a map hit and the
280
+ * answers a query never asks about cost nothing.
151
281
  */
152
- private derive;
282
+ private answersFor;
283
+ /** The trailing pair of a three-column answer relation, joined. */
284
+ private answerPairsFor;
153
285
  /** Emit a file's facts, unless some earlier query already did. */
154
286
  private extractFile;
155
287
  }
@@ -167,7 +299,18 @@ interface ClientCallSite {
167
299
  methodName: string | null;
168
300
  }
169
301
  interface DiscoveredUnit {
170
- func: FunctionRoot;
302
+ /**
303
+ * The function this unit is. Null when a registration announced a
304
+ * boundary and the handler it names comes from outside everything
305
+ * this run reads, in which case `announcedAt` is where the unit is
306
+ * and the summary describes a boundary with nothing behind it.
307
+ */
308
+ func: FunctionRoot | null;
309
+ /**
310
+ * The registration that announced a boundary whose handler was never
311
+ * reached. Set exactly when `func` is null, and the unit's location.
312
+ */
313
+ announcedAt?: Node;
171
314
  kind: string;
172
315
  name: string;
173
316
  callSite?: ClientCallSite;
@@ -284,6 +427,8 @@ interface DiscoveredUnit {
284
427
  messageBus: MessageBusSemantics["messageBus"];
285
428
  channel: string;
286
429
  };
430
+ /** The thing that gets deployed and runs this unit, when known. */
431
+ deployableUnit?: DeployableUnit;
287
432
  /**
288
433
  * Metadata merged onto the assembled summary's `metadata` field.
289
434
  * Populated when a pack's `discoverUnits` callback stamps provenance
@@ -323,7 +468,7 @@ interface Timer {
323
468
  */
324
469
  type DescentBarriers = ReadonlySet<Node>;
325
470
 
326
- declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, filePath: string, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawCodeStructure;
471
+ declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawCodeStructure;
327
472
  interface TypeScriptAdapterConfig {
328
473
  tsConfigFilePath?: string;
329
474
  project?: Project;
@@ -367,13 +512,15 @@ interface TypeScriptAdapterConfig {
367
512
  */
368
513
  onExtractionReport?: (report: ExtractionReport) => void;
369
514
  /**
370
- * On-disk cache directory for the coarse-key extraction cache.
371
- * Pass an absolute path; defaults to `.suss/cache/` next to the
372
- * tsconfig (or under cwd when no tsconfig path is supplied).
373
- * Pass `null` to disable caching entirely. The cache stores one
374
- * `manifest.json` keyed against (adapter version, pack versions,
375
- * sorted file mtime/size stamps); on a warm run with no changes
376
- * the lookup is stat-only and skips extraction.
515
+ * On-disk cache directory for the extraction cache. Pass an absolute
516
+ * path; defaults to `.suss/cache/` next to the tsconfig, and to no
517
+ * cache at all when no tsconfig path is supplied. Pass `null` to turn
518
+ * caching off. A warm run with nothing changed costs one stat per
519
+ * file and returns the previous run's summaries whole.
520
+ *
521
+ * A process that loaded the adapter from source gets no cache
522
+ * whatever this says, because a key made there cannot tell one build
523
+ * of the adapter from another.
377
524
  */
378
525
  cacheDir?: string | null;
379
526
  }
@@ -404,6 +551,16 @@ interface FoundTerminal {
404
551
  * Anything downstream that guessed instead got it wrong.
405
552
  */
406
553
  source?: Node;
554
+ /**
555
+ * A test that also has to hold for this terminal to be the one that
556
+ * fires, on top of whatever the path to it required.
557
+ *
558
+ * One call site answers with more than one status when the status is
559
+ * written as a choice, and the arms are told apart by nothing else:
560
+ * they share a node, so the path engine gives them the same
561
+ * conditions.
562
+ */
563
+ whenAlso?: RawCondition;
407
564
  }
408
565
 
409
566
  /**
@@ -516,7 +673,7 @@ interface ContractReadResult {
516
673
  * Returns null if the handler wasn't registered with a contract or the contract
517
674
  * can't be resolved.
518
675
  */
519
- declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern): ContractReadResult | null;
676
+ declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern, framework: string): ContractReadResult | null;
520
677
  /**
521
678
  * Resolve the contract for a consumer call site.
522
679
  *
@@ -524,7 +681,7 @@ declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern): C
524
681
  * call to find the contract, then extracts the endpoint definition for the
525
682
  * matched method name (e.g. "getUser").
526
683
  */
527
- declare function readContractForClientCall(callExpression: Node, methodName: string, pattern: ContractPattern): ContractReadResult | null;
684
+ declare function readContractForClientCall(callExpression: Node, methodName: string, pattern: ContractPattern, framework: string): ContractReadResult | null;
528
685
 
529
686
  interface TsDiscoveryContext {
530
687
  /** Full filesystem path of the source file. Useful for excluding
@@ -548,11 +705,18 @@ interface TsDiscoveryContext {
548
705
  isDefault: boolean;
549
706
  }>;
550
707
  /**
551
- * For an export whose declaration is a call to one of `callees`,
552
- * read the string a property of the call's config object holds:
553
- * `export const handler = createEventHandler({ expected: "a.b" }, ...)`
554
- * with `{ callees: ["createEventHandler"], argIndex: 0, property:
555
- * "expected" }` answers `"a.b"`.
708
+ * For an export the project builds by calling a factory, the string a
709
+ * property of that call's config object holds:
710
+ * `export const handler = makeWidgetHandler({ subject: "a.b" }, ...)`
711
+ * with `{ property: "subject" }` answers `"a.b"`.
712
+ *
713
+ * Which function was called and which argument carried the config are
714
+ * questions the caller does not have to answer. Every object argument
715
+ * is read. Naming the callee or fixing the argument position narrows
716
+ * that, for a project whose factories would otherwise collide.
717
+ *
718
+ * Two arguments holding the property under different values answers
719
+ * null, since nothing says which one was meant.
556
720
  *
557
721
  * The config argument is usually an object literal at the call site;
558
722
  * a variable or import is followed to the literal it resolves to.
@@ -562,8 +726,8 @@ interface TsDiscoveryContext {
562
726
  * rather than guessing.
563
727
  */
564
728
  exportedCallConfigString(sourceFile: SourceFile, exportName: string, spec: {
565
- callees: string[];
566
- argIndex: number;
729
+ callees?: string[];
730
+ argIndex?: number;
567
731
  property: string;
568
732
  }): string | null;
569
733
  /**
@@ -580,6 +744,50 @@ interface TsDiscoveryContext {
580
744
  }
581
745
  declare function createTsDiscoveryContext(resolution?: ResolutionStore): TsDiscoveryContext;
582
746
 
747
+ /** One thing that looks wrong, in the same shape the dogfood invariants report. */
748
+ interface HealthViolation {
749
+ label: string;
750
+ detail: string;
751
+ }
752
+ interface HealthCheck {
753
+ /** The property, as something that either holds or does not. */
754
+ name: string;
755
+ /**
756
+ * The heading printed when this check finds something.
757
+ *
758
+ * The property reads as an assertion, so printing `name` above the
759
+ * violations of it says "no pack collides with itself" and then lists
760
+ * a pack colliding with itself.
761
+ */
762
+ whenBroken: string;
763
+ /**
764
+ * Who the finding is addressed to.
765
+ *
766
+ * A `run` check found something about the code in front of it, and
767
+ * the person who started the run can do something about it: drop a
768
+ * pack, install a dependency, open an issue with the file that
769
+ * broke. A `pack` check found something about how a pack was built,
770
+ * which only whoever ships that pack can fix. Printing the second
771
+ * kind on every run would teach people to skim past the first.
772
+ */
773
+ audience: "run" | "pack";
774
+ violations: HealthViolation[];
775
+ }
776
+ /**
777
+ * Run every health check over one extraction report and return what
778
+ * fired, grouped by which check caught it.
779
+ */
780
+ declare function evaluatePackHealth(report: ExtractionReport): HealthCheck[];
781
+ /**
782
+ * The health checks that fired, as lines for a terminal.
783
+ *
784
+ * `audiences` is who the caller is printing for, and it is required
785
+ * because there is no answer that suits every caller: a CLI run prints
786
+ * what the person who started it can act on, and a run whose reader is
787
+ * a pack author wants both.
788
+ */
789
+ declare function formatPackHealth(checks: ReadonlyArray<HealthCheck>, audiences: ReadonlyArray<HealthCheck["audience"]>): string;
790
+
583
791
  /**
584
792
  * Parse a ts-morph Expression into a structured Predicate.
585
793
  * Returns null when the expression can't be decomposed cleanly.
@@ -695,15 +903,34 @@ interface TsJsxAttributeLocation {
695
903
  declare function createTsSubUnitContext(): TsSubUnitContext;
696
904
 
697
905
  declare const ADAPTER_VERSION = "0.2.0";
906
+ /**
907
+ * Content hash of the given files, in the order they arrive. Empty when
908
+ * the list is empty or a file cannot be read, so a caller that could not
909
+ * place a file gets the same "no stamp" answer as a run from source
910
+ * rather than a hash of a shorter list.
911
+ *
912
+ * The caller resolves the paths, because who a specifier resolves to
913
+ * depends on which package is asking.
914
+ */
915
+ declare function computeContentHash(paths: readonly string[]): string;
698
916
  /**
699
917
  * Compute a cache-friendly identity for an adapter+packs combination.
700
918
  * Stable across processes given the same inputs; bumps when any pack
701
- * declares a new version, the adapter version changes, or the loaded
702
- * adapter dist file changes (dev-mode rebuild auto-invalidation).
919
+ * arrives with a new version stamp, the adapter version changes, or the
920
+ * loaded adapter dist file changes (dev-mode rebuild auto-invalidation).
921
+ *
922
+ * A pack's stamp is whatever the caller that loaded the pack put there.
923
+ * The adapter takes packs as plain objects and cannot tell where one
924
+ * came from, so folding the config and the code into the stamp is the
925
+ * loader's job.
926
+ *
927
+ * A source run says so in the digest rather than leaving the adapter
928
+ * out of it. Nothing writes under that digest today, and a key that
929
+ * names the mode cannot be mistaken for a key that named the code.
703
930
  */
704
931
  declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
705
932
  name: string;
706
933
  version?: string;
707
934
  }>): string;
708
935
 
709
- export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, isImportedFrom, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, resolveSubject };
936
+ export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, type ConfiguredCallContext, type ConfiguredCallRead, type ConfiguredCallSpec, type ContractReadResult, type DiscoveredUnit, type EmptyStage, type ExtractionReport, type FoundTerminal, type FunctionRoot, type HealthCheck, type HealthViolation, type PackFunnel, type Timer, type TimingReport, type TsDiscoveryContext, type TsJsxAttributeLocation, type TsSubUnitContext, type TypeScriptAdapter, type TypeScriptAdapterConfig, collectAncestorBranches, collectClientFieldAccesses, computeAdapterPacksDigest, computeContentHash, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, evaluatePackHealth, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, formatPackHealth, isImportedFrom, parseConditionExpression, readConfiguredCall, readContract, readContractForClientCall, resolveSubject };