@suss/adapter-typescript 0.0.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.
@@ -0,0 +1,537 @@
1
+ import { FunctionDeclaration, FunctionExpression, ArrowFunction, MethodDeclaration, Node, CallExpression, SourceFile, Project, Expression } from 'ts-morph';
2
+ import { RawCondition, DiscoveryPattern, PatternPack, ExtractorOptions, InvocationRecognizer, AccessRecognizer, RawCodeStructure, TerminalPattern, RawBranch, RawDeclaredContract, ContractPattern, ResponsePropertyMapping, RawTerminal } from '@suss/extractor';
3
+ import { BehavioralSummary, BoundaryBinding, Predicate, TypeShape, ValueRef } from '@suss/behavioral-ir';
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
+ */
10
+ 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
+ };
30
+ }
31
+ /**
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.
42
+ */
43
+ type CacheLookup = {
44
+ kind: "hit";
45
+ summaries: BehavioralSummary[];
46
+ diagnostic: CacheDiagnostic;
47
+ } | {
48
+ kind: "partial-hit";
49
+ kept: BehavioralSummary[];
50
+ filesToExtract: string[];
51
+ diagnostic: CacheDiagnostic;
52
+ } | {
53
+ kind: "miss";
54
+ diagnostic: CacheDiagnostic;
55
+ };
56
+
57
+ /** One pack's path through the funnel. */
58
+ interface PackFunnel {
59
+ pack: string;
60
+ /**
61
+ * Import specifiers that make a file relevant to this pack. Empty
62
+ * for an ungated pack, which walks every file.
63
+ */
64
+ gates: string[];
65
+ /**
66
+ * Gate specifiers that do not resolve from the tsconfig. Non-empty
67
+ * here usually means the target project's dependencies are not
68
+ * installed, which stops symbol-resolution packs while leaving
69
+ * textual-gate packs working, so the run half-succeeds in a way
70
+ * nothing else surfaces.
71
+ */
72
+ unresolvedGates: string[];
73
+ /** Files the pre-filter selected for this pack. */
74
+ candidateFiles: number;
75
+ /** Units discovered across those files. */
76
+ unitsDiscovered: number;
77
+ /** Summaries built from those units. */
78
+ summariesProduced: number;
79
+ }
80
+ interface ExtractionReport {
81
+ /** Files in the tsconfig include set, or null when the caller supplied a Project. */
82
+ filesInProject: number | null;
83
+ /** Files the bootstrap loaded and the extract walked. */
84
+ filesWalked: number;
85
+ packs: PackFunnel[];
86
+ summaries: number;
87
+ /**
88
+ * The first stage whose count was zero, when the run produced
89
+ * nothing. Null when the run produced summaries.
90
+ */
91
+ emptyStage: EmptyStage | null;
92
+ }
93
+ type EmptyStage = "tsconfig" | "gateResolution" | "candidateFiles" | "discovery" | "assembly";
94
+
95
+ type FunctionRoot = FunctionDeclaration | FunctionExpression | ArrowFunction | MethodDeclaration;
96
+ /**
97
+ * Public API — returns RawCondition[] with structured: null.
98
+ * Use collectAncestorConditionInfos when you need the Expression nodes.
99
+ */
100
+ declare function collectAncestorBranches(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
101
+ /**
102
+ * Public API — returns RawCondition[] with structured: null.
103
+ * Use collectEarlyReturnConditionInfos when you need the Expression nodes.
104
+ */
105
+ declare function collectEarlyReturns(terminalNode: Node, functionRoot: FunctionRoot): RawCondition[];
106
+
107
+ interface ClientCallSite {
108
+ callExpression: CallExpression;
109
+ /** Method name on the client object (e.g. "getUser"), null for bare calls like fetch() */
110
+ methodName: string | null;
111
+ }
112
+ interface DiscoveredUnit {
113
+ func: FunctionRoot;
114
+ kind: string;
115
+ name: string;
116
+ callSite?: ClientCallSite;
117
+ /** The discovery pattern that produced this unit. Set by discoverUnits. */
118
+ pattern?: DiscoveryPattern;
119
+ /**
120
+ * Populated by `resolverMap`-style discovery (GraphQL code-first).
121
+ * The adapter uses it to build a `graphql-resolver` binding directly,
122
+ * without running this through the REST-shaped bindingExtraction
123
+ * path.
124
+ *
125
+ * `schemaSdl` is the typeDefs string captured from the same
126
+ * ApolloServer config object the resolver map came from, when
127
+ * we can statically resolve it (string literal or gql-tagged
128
+ * template, inline or const-bound). Surfaced on the summary so
129
+ * the checker's nested-selection pairing can look up return-type
130
+ * fields without needing a separate schema provenance.
131
+ */
132
+ resolverInfo?: {
133
+ typeName: string;
134
+ fieldName: string;
135
+ schemaSdl?: string;
136
+ };
137
+ /**
138
+ * Populated by `graphqlHookCall` discovery (GraphQL consumer side).
139
+ * Carries the operation shape the adapter uses to build a
140
+ * `graphql-operation` binding. `operationName` is absent for
141
+ * anonymous operations (`gql\`query { ... }\``, no identifier).
142
+ *
143
+ * `document` is the raw GraphQL document source (the inner text of
144
+ * the gql-tagged template literal, backticks stripped). Kept
145
+ * alongside the parsed shape so downstream tools can re-parse if
146
+ * they need additional detail beyond what we surface here. Absent
147
+ * when the document body wasn't statically readable and the header
148
+ * was recovered from `TypedDocumentNode` type arguments — a
149
+ * cross-module codegen reference to a document produced by a helper.
150
+ *
151
+ * `variables` list the `$name: Type` declarations at the operation
152
+ * header. Each becomes an `Input` on the resulting summary so
153
+ * pairing layers can match against resolver args. Empty when the
154
+ * document body wasn't read.
155
+ *
156
+ * `rootFields` is the list of root-level selection names — the
157
+ * fields the operation actually selects under Query / Mutation /
158
+ * Subscription. Used by the checker's pairing pass. Empty when the
159
+ * document body wasn't read.
160
+ *
161
+ * `unresolved` is set when the argument was recognized as a GraphQL
162
+ * document reference but the header couldn't be fully read. The unit
163
+ * is still emitted (operation type comes from the call shape) and the
164
+ * gap surfaces on the summary as `metadata.graphql.unresolvedDocument`
165
+ * so nothing is silently dropped.
166
+ */
167
+ operationInfo?: {
168
+ operationType: "query" | "mutation" | "subscription";
169
+ operationName?: string;
170
+ document?: string;
171
+ variables: Array<{
172
+ name: string;
173
+ type: string;
174
+ required: boolean;
175
+ }>;
176
+ rootFields: string[];
177
+ unresolved?: {
178
+ reference: string;
179
+ reason: string;
180
+ };
181
+ };
182
+ /**
183
+ * Populated by `packageExports` discovery. Carries the package
184
+ * identity the adapter uses to build a `function-call` binding
185
+ * with `package` + `exportPath` fields — i.e. a provider summary
186
+ * for a publicly-exported library function.
187
+ */
188
+ packageExportInfo?: {
189
+ packageName: string;
190
+ exportPath: string[];
191
+ };
192
+ /**
193
+ * Populated by `decoratedRoute` discovery (NestJS-style REST
194
+ * controllers). The adapter uses it to build a `rest` binding
195
+ * with `(method, path)` directly, bypassing the
196
+ * `bindingExtraction` config used by Express / Fastify (which
197
+ * extract from `app.get(...)` registration calls — the wrong
198
+ * shape for decorator-driven controllers).
199
+ */
200
+ routeInfo?: {
201
+ method: string;
202
+ path: string;
203
+ };
204
+ /**
205
+ * Metadata merged onto the assembled summary's `metadata` field.
206
+ * Populated when a pack's `discoverUnits` callback stamps provenance
207
+ * on the units it returns (the discovery-layer sibling of the
208
+ * per-sub-unit `metadata` the `subUnits` hook carries).
209
+ */
210
+ metadata?: Record<string, unknown>;
211
+ }
212
+
213
+ /**
214
+ * Discover code units in `sourceFile` by running all patterns.
215
+ * Deduplicates entries with the same function node and kind.
216
+ */
217
+ declare function discoverUnits(sourceFile: SourceFile, patterns: DiscoveryPattern[]): DiscoveredUnit[];
218
+
219
+ interface TimingReport {
220
+ totalMs: number;
221
+ phases: Array<{
222
+ label: string;
223
+ durationMs: number;
224
+ calls: number;
225
+ }>;
226
+ }
227
+ interface Timer {
228
+ /** Run `fn`, accumulate wall time under `label`, return its result. */
229
+ time<T>(label: string, fn: () => T): T;
230
+ /** Async variant — same accumulation rule. */
231
+ timeAsync<T>(label: string, fn: () => Promise<T>): Promise<T>;
232
+ /** Snapshot of all accumulated phases, ordered by total time descending. */
233
+ report(): TimingReport;
234
+ }
235
+
236
+ /**
237
+ * Nested function nodes a pack claimed as sub-units. The unit-body
238
+ * walkers stop at these so the sub-unit's behavior isn't double-counted
239
+ * on the parent.
240
+ */
241
+ type DescentBarriers = ReadonlySet<Node>;
242
+
243
+ declare function extractCodeStructure(unit: DiscoveredUnit, pack: PatternPack, filePath: string, invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawCodeStructure;
244
+ interface TypeScriptAdapterConfig {
245
+ tsConfigFilePath?: string;
246
+ project?: Project;
247
+ frameworks: PatternPack[];
248
+ extractorOptions?: ExtractorOptions;
249
+ /**
250
+ * Include library summaries for every function reachable through a
251
+ * static call edge from a pack-discovered unit. Defaults to `true` —
252
+ * internal orchestrators, helpers, and utilities that frameworks
253
+ * don't recognise become `library`-kind summaries with
254
+ * `recognition: "reachable"` so readers can see their behaviour.
255
+ * Set to `false` for pack-only extraction (smaller output; only the
256
+ * units packs explicitly claim).
257
+ */
258
+ includeReachable?: boolean;
259
+ /**
260
+ * Called once at the end of each `extractAll` / `extractFromFiles`
261
+ * with the wall-clock breakdown of the major extraction phases.
262
+ * Always-on instrumentation cost is negligible (millisecond-scale
263
+ * `performance.now()` calls); the callback is the opt-in for
264
+ * surfacing it. CLI uses this to render the per-extract summary
265
+ * line and the `--timing` breakdown.
266
+ */
267
+ onTiming?: (report: TimingReport) => void;
268
+ /**
269
+ * Called once per extract with the cache hit/miss decision and the
270
+ * partial-reuse diagnostic — counts of cached summaries that fine-
271
+ * grained invalidation would have salvaged on a coarse miss.
272
+ * Phase 4a uses this to validate the dep-tracking model before
273
+ * activating partial-reuse.
274
+ */
275
+ onCacheDiagnostic?: (diagnostic: CacheDiagnostic) => void;
276
+ /**
277
+ * Called once per `extractAll` with the funnel: files in the
278
+ * tsconfig, files walked, and per-pack gate / candidate / unit /
279
+ * summary counts. The CLI renders it when a run produces nothing,
280
+ * so "wrote 0 summaries" can say which stage the count died at
281
+ * instead of leaving the user to guess.
282
+ *
283
+ * Not called on a cache hit, where no stage ran.
284
+ */
285
+ onExtractionReport?: (report: ExtractionReport) => void;
286
+ /**
287
+ * On-disk cache directory for the coarse-key extraction cache.
288
+ * Pass an absolute path; defaults to `.suss/cache/` next to the
289
+ * tsconfig (or under cwd when no tsconfig path is supplied).
290
+ * Pass `null` to disable caching entirely. The cache stores one
291
+ * `manifest.json` keyed against (adapter version, pack versions,
292
+ * sorted file mtime/size stamps); on a warm run with no changes
293
+ * the lookup is stat-only and skips extraction.
294
+ */
295
+ cacheDir?: string | null;
296
+ }
297
+ interface TypeScriptAdapter {
298
+ project: Project;
299
+ /**
300
+ * Extract summaries from a specific list of files. Returns a
301
+ * Promise so the implementation can do concurrent I/O during
302
+ * the pre-filter / lazy-load phases without bottlenecking on
303
+ * sync `fs.readFileSync`.
304
+ */
305
+ extractFromFiles(filePaths: string[]): Promise<BehavioralSummary[]>;
306
+ /** Extract summaries from every (non-declaration) file the Project knows about. */
307
+ extractAll(): Promise<BehavioralSummary[]>;
308
+ }
309
+ declare function createTypeScriptAdapter(config: TypeScriptAdapterConfig): TypeScriptAdapter;
310
+
311
+ /**
312
+ * Extract all raw branches from a function, composing:
313
+ * 1. findTerminals — locate terminal nodes
314
+ * 2. collectEarlyReturnConditionInfos — prior guard clauses
315
+ * 3. collectAncestorConditionInfos — enclosing branch conditions
316
+ * 4. parseConditionExpression — Expression → Predicate
317
+ * 5. extractInvocationEffects — bare expression-statement calls
318
+ * (Phase 1.5b — attaches to the default branch so handler /
319
+ * useEffect bodies carry their side-effect set)
320
+ *
321
+ * `isDefault` is true when the branch has no conditions, or all
322
+ * conditions come from early returns/throws.
323
+ */
324
+ declare function extractRawBranches(func: FunctionRoot, terminalPatterns: TerminalPattern[], invocationRecognizers?: InvocationRecognizer[], accessRecognizers?: AccessRecognizer[], barriers?: DescentBarriers): RawBranch[];
325
+
326
+ /**
327
+ * A Project covering `rootDir`, for a codebase with no tsconfig to read.
328
+ * Returns the project and the files it loaded.
329
+ */
330
+ declare function createProjectWithoutTsconfig(rootDir: string): {
331
+ project: Project;
332
+ files: string[];
333
+ };
334
+ /** The nearest tsconfig or jsconfig at or above `startDir`, or null. */
335
+ declare function findNearestTsconfig(startDir: string): string | null;
336
+
337
+ interface ContractReadResult {
338
+ declaredContract: RawDeclaredContract;
339
+ boundaryBinding: BoundaryBinding | null;
340
+ }
341
+ /**
342
+ * Read the declared contract for a discovered handler unit.
343
+ *
344
+ * Traces from the handler's registration site (e.g., `s.router(contract, { ... })`)
345
+ * back to the contract definition, then extracts the declared responses for
346
+ * this specific endpoint.
347
+ *
348
+ * Returns null if the handler wasn't registered with a contract or the contract
349
+ * can't be resolved.
350
+ */
351
+ declare function readContract(unit: DiscoveredUnit, pattern: ContractPattern): ContractReadResult | null;
352
+ /**
353
+ * Resolve the contract for a consumer call site.
354
+ *
355
+ * Given `client.getUser(...)`, traces back to the `initClient(contract, ...)`
356
+ * call to find the contract, then extracts the endpoint definition for the
357
+ * matched method name (e.g. "getUser").
358
+ */
359
+ declare function readContractForClientCall(callExpression: Node, methodName: string, pattern: ContractPattern): ContractReadResult | null;
360
+
361
+ interface TsDiscoveryContext {
362
+ /** Full filesystem path of the source file. Useful for excluding
363
+ * test / story files via the pack's own regex. */
364
+ getFilePath(sourceFile: SourceFile): string;
365
+ /**
366
+ * Yield every export from the source file whose declaration is a
367
+ * function — function declarations, arrow / function-expression
368
+ * variable initializers, and re-exports of either. Skips
369
+ * non-function exports (constants, classes, types).
370
+ *
371
+ * Each entry carries the exported name (the binding the consumer
372
+ * uses), the function root, and whether the export is the file's
373
+ * default export. `default` is included; the pack decides whether
374
+ * to handle it (typically the data-driven `namedExport(["default"])`
375
+ * already does, and the callback skips to avoid duplicates).
376
+ */
377
+ exportedFunctions(sourceFile: SourceFile): Array<{
378
+ name: string;
379
+ func: FunctionRoot;
380
+ isDefault: boolean;
381
+ }>;
382
+ /**
383
+ * Walk a function's body for return statements whose value is a
384
+ * JSX element / fragment / self-closing tag. Returns true on the
385
+ * first match; false otherwise. Skips into nested function bodies
386
+ * — nested arrow returning JSX is its own component, not part of
387
+ * this function's output.
388
+ *
389
+ * Concise-arrow bodies (`() => <X/>`) are handled — the body IS
390
+ * the implicit return.
391
+ */
392
+ hasJsxReturn(func: FunctionRoot): boolean;
393
+ }
394
+ declare function createTsDiscoveryContext(): TsDiscoveryContext;
395
+
396
+ /**
397
+ * Parse a ts-morph Expression into a structured Predicate.
398
+ * Returns null when the expression can't be decomposed cleanly.
399
+ * The caller wraps null into { type: "opaque", sourceText, reason: "complexExpression" }.
400
+ *
401
+ * Call expressions are resolved recursively: if the callee is a local
402
+ * function with a single-expression body, the body is parsed as a
403
+ * predicate and parameter references are substituted with the call-site
404
+ * arguments. This reduces opaqueness for patterns like `if (isActive(user))`.
405
+ */
406
+ declare function parseConditionExpression(expr: Expression, depth?: number): Predicate | null;
407
+
408
+ interface BranchFieldAccesses {
409
+ /** Terminal location (start, end lines) — used to match back to transitions */
410
+ terminalLocation: {
411
+ start: number;
412
+ end: number;
413
+ };
414
+ /** The shape of fields the consumer reads from the response in this branch */
415
+ expectedInput: TypeShape | null;
416
+ }
417
+ /**
418
+ * For a client function, collect the fields accessed on the response variable
419
+ * within each branch. Returns one entry per branch (matched by terminal location).
420
+ *
421
+ * @param callExpr The API call expression (fetch(), client.getUser())
422
+ * @param func The enclosing function
423
+ * @param branchLocations Terminal locations from the extracted branches
424
+ * @param responseSemantics Optional response property mappings from the pack —
425
+ * used to filter non-body properties instead of a hardcoded list
426
+ */
427
+ declare function collectClientFieldAccesses(callExpr: CallExpression, func: Node, branchLocations: Array<{
428
+ start: number;
429
+ end: number;
430
+ }>, responseSemantics?: ResponsePropertyMapping[]): BranchFieldAccesses[];
431
+
432
+ /**
433
+ * Resolve a ts-morph Expression node to a structured ValueRef.
434
+ * Uses only expr.getSymbol()?.getDeclarations()[0] for symbol lookup —
435
+ * never findReferencesAsNodes() which is project-wide and quadratic.
436
+ *
437
+ * Follows intermediate variable assignments (const data = result.body)
438
+ * so that property chains through temporaries resolve to their origin.
439
+ * Depth-bounded to prevent infinite recursion on cyclic references.
440
+ */
441
+ declare function resolveSubject(expr: Expression, depth?: number): ValueRef;
442
+
443
+ /**
444
+ * The context the TypeScript adapter passes to a pack's `subUnits`
445
+ * hook. Covers JSX-attribute-walking and call-expression-walking plus
446
+ * the resolution helpers packs need to map AST nodes back to function
447
+ * bodies and source text.
448
+ *
449
+ * All walks are scoped to the parent function and deliberately do NOT
450
+ * recurse into nested function bodies — sub-units of nested functions
451
+ * belong to those functions' summaries, not to the enclosing parent.
452
+ */
453
+ interface TsSubUnitContext {
454
+ /**
455
+ * Yield every JSX attribute on every JSX element / self-closing
456
+ * element in the parent's body, excluding any inside nested
457
+ * function bodies. The tag is the source text of the element's
458
+ * tag-name node.
459
+ */
460
+ findJsxAttributes(parent: FunctionRoot): TsJsxAttributeLocation[];
461
+ /**
462
+ * Yield every call expression matching `name` (bare identifier
463
+ * callee only — e.g. `useEffect(...)`, not `React.useEffect(...)`).
464
+ * Nested function bodies are skipped.
465
+ */
466
+ findCallExpressionsByName(parent: FunctionRoot, name: string): CallExpression[];
467
+ /**
468
+ * Resolve a JSX attribute's value to a function body, if the value
469
+ * is (a) an inline arrow or function expression or (b) an
470
+ * identifier referring to a function declared inside the parent.
471
+ * Returns null for prop-delegating references (`props.onClick`),
472
+ * identifiers that resolve outside the parent's scope, or any
473
+ * non-function expression.
474
+ */
475
+ resolveAttributeValueFunction(attr: TsJsxAttributeLocation, parent: FunctionRoot): {
476
+ func: FunctionRoot;
477
+ localName: string | null;
478
+ } | null;
479
+ /**
480
+ * Return the Nth argument of a call as a function body, if it's an
481
+ * inline arrow or function expression. Returns null for identifier
482
+ * references, property accesses, or non-function values.
483
+ */
484
+ getCallArgumentFunction(call: CallExpression, position: number): FunctionRoot | null;
485
+ /**
486
+ * Return the Nth argument raw node (or null if absent).
487
+ */
488
+ getCallArgument(call: CallExpression, position: number): Node | null;
489
+ /**
490
+ * If `node` is an array literal expression, return each element's
491
+ * source text. If it's some other expression, return a single entry
492
+ * with the node's full text. Null means no deps argument was given.
493
+ */
494
+ readArrayLiteralText(node: Node | null): string[] | null;
495
+ }
496
+ /**
497
+ * A located JSX attribute: which element it's on, its name, and the
498
+ * expression node supplying its value (null for boolean-shorthand
499
+ * attributes like `<input disabled>`).
500
+ */
501
+ interface TsJsxAttributeLocation {
502
+ tag: string;
503
+ name: string;
504
+ valueExpression: Node | null;
505
+ }
506
+ declare function createTsSubUnitContext(): TsSubUnitContext;
507
+
508
+ interface FoundTerminal {
509
+ node: Node;
510
+ terminal: RawTerminal;
511
+ }
512
+
513
+ /**
514
+ * Walk every descendant of `func` and try each pattern in order (first match
515
+ * wins per node). Returns all matched terminals across the whole function.
516
+ *
517
+ * Descends into nested function expressions / arrows so a unit whose
518
+ * terminal output is produced inside a Promise executor or `.then`
519
+ * callback (`res.json(data)` on the unit's own `res` parameter) is still
520
+ * discovered. Inside a nested function only escaping terminals are
521
+ * matched — see `NESTED_ESCAPING_MATCH_TYPES`.
522
+ */
523
+ declare function findTerminals(func: FunctionRoot, patterns: TerminalPattern[], barriers?: DescentBarriers): FoundTerminal[];
524
+
525
+ declare const ADAPTER_VERSION = "0.1.0";
526
+ /**
527
+ * Compute a cache-friendly identity for an adapter+packs combination.
528
+ * Stable across processes given the same inputs; bumps when any pack
529
+ * declares a new version, the adapter version changes, or the loaded
530
+ * adapter dist file changes (dev-mode rebuild auto-invalidation).
531
+ */
532
+ declare function computeAdapterPacksDigest(packVersions: ReadonlyArray<{
533
+ name: string;
534
+ version?: string;
535
+ }>): string;
536
+
537
+ export { ADAPTER_VERSION, type CacheDiagnostic, type CacheLookup, type ClientCallSite, 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, collectEarlyReturns, computeAdapterPacksDigest, createProjectWithoutTsconfig, createTsDiscoveryContext, createTsSubUnitContext, createTypeScriptAdapter, discoverUnits, extractCodeStructure, extractRawBranches, findNearestTsconfig, findTerminals, parseConditionExpression, readContract, readContractForClientCall, resolveSubject };