@tsdoctor/bundle 0.1.0

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/index.d.ts ADDED
@@ -0,0 +1,885 @@
1
+ import { PackageManifest } from "@effected/package-json";
2
+ import { CompilerOptions, ResolvedTsconfig } from "@effected/tsconfig-json";
3
+ import { Effect, FileSystem, Option, Path, Schema } from "effect";
4
+ import { GitHubRelease } from "@effected/github";
5
+ import { NpmRegistry, PackageTarball, RegistryTarget } from "@effected/npm";
6
+ import { Cache } from "@effected/store";
7
+ import { AppDirs } from "@effected/xdg";
8
+ //#region src/BundleManifest.d.ts
9
+ /**
10
+ * The registry protocol families this reader knows how to do more than link
11
+ * to. `"npm"` means an npm-compatible registry — install commands and tarball
12
+ * fetching work against any instance of it — and `"jsr"` the jsr protocol.
13
+ *
14
+ * @remarks
15
+ * The manifest's `type` field is deliberately NOT constrained to these
16
+ * values: unknown future types must degrade to link-only rendering, not
17
+ * reject the manifest. Use {@link isKnownRegistryType} to branch.
18
+ *
19
+ * @public
20
+ */
21
+ declare const KNOWN_REGISTRY_TYPES: readonly ["npm", "jsr"];
22
+ /**
23
+ * A registry protocol family this reader recognizes.
24
+ *
25
+ * @public
26
+ */
27
+ type KnownRegistryType = (typeof KNOWN_REGISTRY_TYPES)[number];
28
+ /**
29
+ * Whether a registry `type` value is a protocol family this reader
30
+ * recognizes. `false` means the registry entry should degrade to link-only
31
+ * rendering — it is never a validation failure.
32
+ *
33
+ * @public
34
+ */
35
+ declare function isKnownRegistryType(type: string): type is KnownRegistryType;
36
+ /**
37
+ * One registry the documented package is published to.
38
+ *
39
+ * @remarks
40
+ * `type` is the PROTOCOL FAMILY (`"npm"` covers every npm-compatible
41
+ * registry), `name` the human instance label, `url` the package's page on
42
+ * that instance. Unknown `type` values decode successfully and degrade to
43
+ * link-only rendering (see {@link isKnownRegistryType}).
44
+ *
45
+ * @public
46
+ */
47
+ declare const RegistryRef: Schema.Struct<{
48
+ /** The protocol family, e.g. `"npm"` or `"jsr"`. Unknown values are accepted. */
49
+ readonly type: Schema.String;
50
+ /** The human instance label, e.g. `"npm"` or `"Savvy Web Registry"`. */
51
+ readonly name: Schema.String;
52
+ /** The package's URL on that registry instance. */
53
+ readonly url: Schema.String;
54
+ }>;
55
+ /**
56
+ * The decoded type of {@link (RegistryRef:variable)}.
57
+ *
58
+ * @public
59
+ */
60
+ type RegistryRef = typeof RegistryRef.Type;
61
+ /**
62
+ * One Open Graph image declared by the manifest.
63
+ *
64
+ * @remarks
65
+ * Exactly ONE of `path` (a bundle-relative asset the consuming platform
66
+ * publishes and resolves to a URL) or `url` (an absolute external URL used
67
+ * verbatim) must be present — the schema enforces the XOR. `type` is a MIME
68
+ * type, inferred from the file extension by the resolver when omitted; `alt`
69
+ * has a documented inference chain (tagline → description →
70
+ * `"<name> API documentation"`).
71
+ *
72
+ * @public
73
+ */
74
+ declare const OpenGraphImage: Schema.Struct<{
75
+ /** Bundle-relative asset path. Mutually exclusive with `url`. */
76
+ readonly path: Schema.optionalKey<Schema.String>;
77
+ /** Absolute external URL, used verbatim. Mutually exclusive with `path`. */
78
+ readonly url: Schema.optionalKey<Schema.String>;
79
+ /** MIME type; inferred from the extension when omitted. */
80
+ readonly type: Schema.optionalKey<Schema.String>;
81
+ /** Pixel width; 1200×630 (1.91:1) is the cross-platform safe default. */
82
+ readonly width: Schema.optionalKey<Schema.Int>;
83
+ /** Pixel height. */
84
+ readonly height: Schema.optionalKey<Schema.Int>;
85
+ /** Alt text; inferred (tagline → description → fallback) when omitted. */
86
+ readonly alt: Schema.optionalKey<Schema.String>;
87
+ }>;
88
+ /**
89
+ * The decoded type of {@link (OpenGraphImage:variable)}.
90
+ *
91
+ * @public
92
+ */
93
+ type OpenGraphImage = typeof OpenGraphImage.Type;
94
+ /**
95
+ * The manifest's Open Graph block: the asset-ish pieces only — most OG tags
96
+ * are page-level and derive at render time in the consuming platform.
97
+ *
98
+ * @remarks
99
+ * Multiple images follow OG array semantics: the first declared wins, extras
100
+ * are alternates (e.g. a portrait 1000×1500 variant).
101
+ *
102
+ * @public
103
+ */
104
+ declare const OpenGraphConfig: Schema.Struct<{
105
+ /** Declared images, first-wins per OG array semantics. */
106
+ readonly images: Schema.optionalKey<Schema.$Array<Schema.Struct<{
107
+ /** Bundle-relative asset path. Mutually exclusive with `url`. */
108
+ readonly path: Schema.optionalKey<Schema.String>;
109
+ /** Absolute external URL, used verbatim. Mutually exclusive with `path`. */
110
+ readonly url: Schema.optionalKey<Schema.String>;
111
+ /** MIME type; inferred from the extension when omitted. */
112
+ readonly type: Schema.optionalKey<Schema.String>;
113
+ /** Pixel width; 1200×630 (1.91:1) is the cross-platform safe default. */
114
+ readonly width: Schema.optionalKey<Schema.Int>;
115
+ /** Pixel height. */
116
+ readonly height: Schema.optionalKey<Schema.Int>;
117
+ /** Alt text; inferred (tagline → description → fallback) when omitted. */
118
+ readonly alt: Schema.optionalKey<Schema.String>;
119
+ }>>>;
120
+ /** Embed accent color (e.g. Discord), a CSS color string. */
121
+ readonly themeColor: Schema.optionalKey<Schema.String>;
122
+ }>;
123
+ /**
124
+ * The decoded type of {@link (OpenGraphConfig:variable)}.
125
+ *
126
+ * @public
127
+ */
128
+ type OpenGraphConfig = typeof OpenGraphConfig.Type;
129
+ /**
130
+ * A pointer to the bundle's SBOM, computed by the bundler at publish and
131
+ * served as a downloadable static asset.
132
+ *
133
+ * @public
134
+ */
135
+ declare const SbomRef: Schema.Struct<{
136
+ /** Bundle-relative path to the SBOM file. */
137
+ readonly path: Schema.String;
138
+ /** SBOM format label, e.g. `"spdx-json"`. Unknown values are accepted. */
139
+ readonly format: Schema.optionalKey<Schema.String>;
140
+ }>;
141
+ /**
142
+ * The decoded type of {@link (SbomRef:variable)}.
143
+ *
144
+ * @public
145
+ */
146
+ type SbomRef = typeof SbomRef.Type;
147
+ /**
148
+ * The inherited project tier, flattened into the emitted manifest by the
149
+ * bundler (a fetched bundle has no parent directory to walk). Kept nested —
150
+ * structurally distinguishable from the leaf fields — because provenance is
151
+ * load-bearing for override detection.
152
+ *
153
+ * @public
154
+ */
155
+ declare const ProjectIdentity: Schema.Struct<{
156
+ /** The project display name, e.g. `"Effected"` over leaf `@effected/store`. */
157
+ readonly name: Schema.optionalKey<Schema.String>;
158
+ /** The project tagline. */
159
+ readonly tagline: Schema.optionalKey<Schema.String>;
160
+ }>;
161
+ /**
162
+ * The decoded type of {@link (ProjectIdentity:variable)}.
163
+ *
164
+ * @public
165
+ */
166
+ type ProjectIdentity = typeof ProjectIdentity.Type;
167
+ /**
168
+ * The versioned `tsdoctor.json` sidecar manifest — bundle layer 3.
169
+ *
170
+ * @remarks
171
+ * `spec` is the only required field; every other field enriches. Unknown
172
+ * top-level fields are ignored on decode (additive fields are minor spec
173
+ * revisions) and unknown enum-ish values (registry `type`, sbom `format`)
174
+ * degrade gracefully instead of rejecting — an old reader must be able to
175
+ * consume a new bundle.
176
+ *
177
+ * @public
178
+ */
179
+ declare const BundleManifest: Schema.Struct<{
180
+ /** The integer spec version. This reader understands spec 1. */
181
+ readonly spec: Schema.Literal<1>;
182
+ /** Human display name (the npm name is dry; this one is SEO-friendly). */
183
+ readonly name: Schema.optionalKey<Schema.String>;
184
+ /** Short tagline. */
185
+ readonly tagline: Schema.optionalKey<Schema.String>;
186
+ /** Long description; overrides the package.json description when present. */
187
+ readonly description: Schema.optionalKey<Schema.String>;
188
+ /** The inherited project tier, flattened in at emit time. */
189
+ readonly project: Schema.optionalKey<Schema.Struct<{
190
+ /** The project display name, e.g. `"Effected"` over leaf `@effected/store`. */
191
+ readonly name: Schema.optionalKey<Schema.String>;
192
+ /** The project tagline. */
193
+ readonly tagline: Schema.optionalKey<Schema.String>;
194
+ }>>;
195
+ /** Open Graph assets. */
196
+ readonly openGraph: Schema.optionalKey<Schema.Struct<{
197
+ /** Declared images, first-wins per OG array semantics. */
198
+ readonly images: Schema.optionalKey<Schema.$Array<Schema.Struct<{
199
+ /** Bundle-relative asset path. Mutually exclusive with `url`. */
200
+ readonly path: Schema.optionalKey<Schema.String>;
201
+ /** Absolute external URL, used verbatim. Mutually exclusive with `path`. */
202
+ readonly url: Schema.optionalKey<Schema.String>;
203
+ /** MIME type; inferred from the extension when omitted. */
204
+ readonly type: Schema.optionalKey<Schema.String>;
205
+ /** Pixel width; 1200×630 (1.91:1) is the cross-platform safe default. */
206
+ readonly width: Schema.optionalKey<Schema.Int>;
207
+ /** Pixel height. */
208
+ readonly height: Schema.optionalKey<Schema.Int>;
209
+ /** Alt text; inferred (tagline → description → fallback) when omitted. */
210
+ readonly alt: Schema.optionalKey<Schema.String>;
211
+ }>>>;
212
+ /** Embed accent color (e.g. Discord), a CSS color string. */
213
+ readonly themeColor: Schema.optionalKey<Schema.String>;
214
+ }>>;
215
+ /** SBOM pointer. */
216
+ readonly sbom: Schema.optionalKey<Schema.Struct<{
217
+ /** Bundle-relative path to the SBOM file. */
218
+ readonly path: Schema.String;
219
+ /** SBOM format label, e.g. `"spdx-json"`. Unknown values are accepted. */
220
+ readonly format: Schema.optionalKey<Schema.String>;
221
+ }>>;
222
+ /** Registries the package is published to. */
223
+ readonly registries: Schema.optionalKey<Schema.$Array<Schema.Struct<{
224
+ /** The protocol family, e.g. `"npm"` or `"jsr"`. Unknown values are accepted. */
225
+ readonly type: Schema.String;
226
+ /** The human instance label, e.g. `"npm"` or `"Savvy Web Registry"`. */
227
+ readonly name: Schema.String;
228
+ /** The package's URL on that registry instance. */
229
+ readonly url: Schema.String;
230
+ }>>>;
231
+ }>;
232
+ /**
233
+ * The decoded type of {@link (BundleManifest:variable)}.
234
+ *
235
+ * @public
236
+ */
237
+ type BundleManifest = typeof BundleManifest.Type;
238
+ declare const BundleManifestError_base: Schema.Class<BundleManifestError, Schema.TaggedStruct<"BundleManifestError", {
239
+ /** The manifest file path, when the failure is tied to a file on disk. */
240
+ readonly path: Schema.optionalKey<Schema.String>;
241
+ /** The underlying failure (JSON syntax or schema decode), preserved structurally. */
242
+ readonly cause: Schema.Defect;
243
+ }>, import("effect/Cause").YieldableError>;
244
+ /**
245
+ * Raised when a present `tsdoctor.json` cannot be parsed or does not satisfy
246
+ * the {@link (BundleManifest:variable)} schema.
247
+ *
248
+ * @remarks
249
+ * Absence of the manifest is NEVER this error — layers enrich, never gate,
250
+ * so a missing sidecar is the normal case and reads as `Option.none()`.
251
+ *
252
+ * @public
253
+ */
254
+ declare class BundleManifestError extends BundleManifestError_base {
255
+ get message(): string;
256
+ }
257
+ /**
258
+ * Decode an unknown value into a {@link (BundleManifest:type)}.
259
+ *
260
+ * @remarks
261
+ * The typed boundary for manifest input that has already been parsed from
262
+ * JSON (plugin options, fetched payloads). File-based reading lives in
263
+ * `readBundle`, which routes through this after parsing.
264
+ *
265
+ * @public
266
+ */
267
+ declare function decodeBundleManifest(input: unknown, path?: string): Effect.Effect<BundleManifest, BundleManifestError>;
268
+ //#endregion
269
+ //#region src/Bundle.d.ts
270
+ /**
271
+ * The sidecar manifest's file name inside a bundle folder.
272
+ *
273
+ * @public
274
+ */
275
+ declare const TSDOCTOR_MANIFEST_FILENAME = "tsdoctor.json";
276
+ /**
277
+ * The subset of a `<name>.api.json` model this package reads: the package
278
+ * name from the model's own metadata.
279
+ *
280
+ * @remarks
281
+ * Full model loading (entry points, members, TSDoc) is `@tsdoctor/model`'s
282
+ * job — this package deliberately stays free of
283
+ * `@microsoft/api-extractor-model` and reads only what discovery and
284
+ * resolution need.
285
+ *
286
+ * @public
287
+ */
288
+ interface ApiModelInfo {
289
+ /** The documented package's npm name, from the model's `name` field. */
290
+ readonly name: string;
291
+ }
292
+ declare const BundleLayerError_base: Schema.Class<BundleLayerError, Schema.TaggedStruct<"BundleLayerError", {
293
+ /** Which bundle layer failed. */
294
+ readonly layer: Schema.Literals<readonly ["apiModel", "packageJson", "tsconfig"]>;
295
+ /** The file that failed. */
296
+ readonly path: Schema.String;
297
+ /** The underlying failure, preserved structurally. */
298
+ readonly cause: Schema.Defect;
299
+ }>, import("effect/Cause").YieldableError>;
300
+ /**
301
+ * Raised when a PRESENT bundle layer file cannot be read, parsed or decoded.
302
+ *
303
+ * @remarks
304
+ * Absence of layers 1–3 is the normal case (layers enrich, never gate) and
305
+ * reads as `Option.none()`, never as this error. A file that exists but is
306
+ * malformed is a real problem worth surfacing, not degrading past. Manifest
307
+ * (layer 3) failures use {@link BundleManifestError} instead, so manifest
308
+ * consumers handle one tag across the file and non-file boundaries.
309
+ *
310
+ * @public
311
+ */
312
+ declare class BundleLayerError extends BundleLayerError_base {
313
+ get message(): string;
314
+ }
315
+ /**
316
+ * Where a bundle's layer files live: the output of discovery, the input of
317
+ * {@link readBundle}.
318
+ *
319
+ * @remarks
320
+ * `modelPath` is the one required layer; the optional path fields are present
321
+ * iff the corresponding file existed at discovery time. `name` and `version`
322
+ * are pre-parsed during discovery (name from package.json, falling back to
323
+ * the api.json model; version from package.json when present).
324
+ *
325
+ * @public
326
+ */
327
+ interface BundleDescriptor {
328
+ /** Absolute path to the bundle folder. */
329
+ readonly dir: string;
330
+ /** Last path segment of `dir`, e.g. `"kitchensink"`. */
331
+ readonly dirname: string;
332
+ /** The documented package's npm name. */
333
+ readonly name: string;
334
+ /** The package version from package.json, when present. */
335
+ readonly version?: string;
336
+ /** Absolute path to the layer-0 `*.api.json` model. */
337
+ readonly modelPath: string;
338
+ /** Absolute path to the layer-1 package.json, when present. */
339
+ readonly packageJsonPath?: string;
340
+ /** Absolute path to the layer-2 tsconfig.json, when present. */
341
+ readonly tsconfigPath?: string;
342
+ /** Absolute path to the layer-3 tsdoctor.json manifest, when present. */
343
+ readonly manifestPath?: string;
344
+ }
345
+ /**
346
+ * A bundle with all four layers read into typed structures. Layers 1–3 are
347
+ * `Option`s because their absence is the normal case.
348
+ *
349
+ * @public
350
+ */
351
+ interface Bundle {
352
+ /** The descriptor the bundle was read from. */
353
+ readonly descriptor: BundleDescriptor;
354
+ /** Layer 0: the api.json model header (always present). */
355
+ readonly apiModel: ApiModelInfo;
356
+ /** Layer 1: the package.json manifest, presence-lenient. */
357
+ readonly packageJson: Option.Option<PackageManifest>;
358
+ /** Layer 2: the tsconfig, extends-resolved. */
359
+ readonly tsconfig: Option.Option<ResolvedTsconfig>;
360
+ /** Layer 3: the tsdoctor.json sidecar manifest. */
361
+ readonly manifest: Option.Option<BundleManifest>;
362
+ }
363
+ /**
364
+ * Read the layer-0 model header — the package name — from a `*.api.json`
365
+ * file.
366
+ *
367
+ * @remarks
368
+ * Parses the whole file as JSON but validates only the `name` field; see
369
+ * {@link ApiModelInfo} for why nothing more is read here.
370
+ *
371
+ * @public
372
+ */
373
+ declare function readApiModelInfo(modelPath: string): Effect.Effect<ApiModelInfo, BundleLayerError, FileSystem.FileSystem>;
374
+ /**
375
+ * Read all four layers of a discovered bundle into a {@link Bundle}.
376
+ *
377
+ * @remarks
378
+ * Layer 0 is required; layers 1–3 read to `Option.none()` when the
379
+ * descriptor recorded no file for them. A layer file that is present but
380
+ * malformed fails typed ({@link BundleLayerError}, or
381
+ * {@link BundleManifestError} for the manifest) — lenient about absence,
382
+ * strict about shape. `FileSystem` and `Path` stay in the `R` channel;
383
+ * provide the platform layer once at the application boundary.
384
+ *
385
+ * @public
386
+ */
387
+ declare function readBundle(descriptor: BundleDescriptor): Effect.Effect<Bundle, BundleLayerError | BundleManifestError, FileSystem.FileSystem | Path.Path>;
388
+ //#endregion
389
+ //#region src/BundleDiscovery.d.ts
390
+ declare const BundleDiscoveryError_base: Schema.Class<BundleDiscoveryError, Schema.TaggedStruct<"BundleDiscoveryError", {
391
+ /** The directory (or file) the failure is about. */
392
+ readonly path: Schema.String;
393
+ /** What went wrong, structurally. */
394
+ readonly reason: Schema.Literals<readonly ["notFound", "notADirectory", "noApiModel", "ambiguousApiModel", "invalidPackageJson", "unreadableDirectory", "notABundleFolder", "emptyParent"]>;
395
+ /** Human context for the failure (candidate lists, offending names). */
396
+ readonly detail: Schema.optionalKey<Schema.String>;
397
+ /** The underlying failure, when one exists, preserved structurally. */
398
+ readonly cause: Schema.optionalKey<Schema.Defect>;
399
+ }>, import("effect/Cause").YieldableError>;
400
+ /**
401
+ * Raised when a directory cannot be resolved into a bundle descriptor.
402
+ *
403
+ * @remarks
404
+ * Discovery failures are USER-facing wiring problems — a missing folder, no
405
+ * model file, an ambiguous model set — so the `reason` is a typed literal a
406
+ * consumer can branch on for actionable messaging.
407
+ *
408
+ * @public
409
+ */
410
+ declare class BundleDiscoveryError extends BundleDiscoveryError_base {
411
+ get message(): string;
412
+ }
413
+ /**
414
+ * Overrides for {@link discoverBundle}. Any supplied field wins over
415
+ * discovery.
416
+ *
417
+ * @public
418
+ */
419
+ interface BundleOverrides {
420
+ /** The package name to use instead of the discovered one. */
421
+ readonly name?: string;
422
+ /** The version to use instead of the discovered one. */
423
+ readonly version?: string;
424
+ /** The model path to use instead of `*.api.json` discovery (resolved against the bundle dir when relative). */
425
+ readonly modelPath?: string;
426
+ }
427
+ /**
428
+ * Options for {@link discoverBundle}.
429
+ *
430
+ * @public
431
+ */
432
+ interface DiscoverBundleOptions {
433
+ /** Base for resolving a relative `dir`. When omitted, a relative `dir` resolves per the injected `Path` service. */
434
+ readonly cwd?: string;
435
+ /** Caller-supplied fields that win over discovery. */
436
+ readonly overrides?: BundleOverrides;
437
+ }
438
+ /**
439
+ * Options for {@link discoverBundles}.
440
+ *
441
+ * @public
442
+ */
443
+ interface DiscoverBundlesOptions {
444
+ /** Base for resolving a relative `parentDir`. */
445
+ readonly cwd?: string;
446
+ }
447
+ /**
448
+ * Discover a single bundle folder into a {@link BundleDescriptor}.
449
+ *
450
+ * @remarks
451
+ * Generalizes the RSPress plugin's `api.fromDir` helper, framework-neutral:
452
+ * no route derivation — that stays in the adapter. Layer 0 (`*.api.json`) is
453
+ * required; package.json, tsconfig.json and tsdoctor.json are recorded when
454
+ * present. The package name comes from package.json when it has one, falling
455
+ * back to the api.json model's own name; the version comes from package.json
456
+ * alone. Caller overrides win over discovery. `FileSystem` and `Path` stay
457
+ * in the `R` channel — provide the platform layer at the application
458
+ * boundary.
459
+ *
460
+ * @public
461
+ */
462
+ declare function discoverBundle(dir: string, options?: DiscoverBundleOptions): Effect.Effect<BundleDescriptor, BundleDiscoveryError | BundleLayerError, FileSystem.FileSystem | Path.Path>;
463
+ /**
464
+ * Strictly scan a parent directory and discover one bundle per subfolder.
465
+ *
466
+ * @remarks
467
+ * Generalizes the RSPress plugin's `apis.fromDir`: every non-dotfile
468
+ * subdirectory MUST be a valid bundle folder (contain at least one
469
+ * `*.api.json`) — a stray subfolder fails discovery with guidance to use
470
+ * {@link discoverBundle} for selective inclusion — and an empty scan is a
471
+ * failure, not an empty array (the models have probably not been built).
472
+ * Subfolders are processed in sorted order.
473
+ *
474
+ * @public
475
+ */
476
+ declare function discoverBundles(parentDir: string, options?: DiscoverBundlesOptions): Effect.Effect<ReadonlyArray<BundleDescriptor>, BundleDiscoveryError | BundleLayerError, FileSystem.FileSystem | Path.Path>;
477
+ /**
478
+ * Discover and read a single bundle in one call.
479
+ *
480
+ * @public
481
+ */
482
+ declare function loadBundle(dir: string, options?: DiscoverBundleOptions): Effect.Effect<Bundle, BundleDiscoveryError | BundleLayerError | BundleManifestError, FileSystem.FileSystem | Path.Path>;
483
+ /**
484
+ * Discover and read every bundle under a parent directory in one call.
485
+ *
486
+ * @public
487
+ */
488
+ declare function loadBundles(parentDir: string, options?: DiscoverBundlesOptions): Effect.Effect<ReadonlyArray<Bundle>, BundleDiscoveryError | BundleLayerError | BundleManifestError, FileSystem.FileSystem | Path.Path>;
489
+ //#endregion
490
+ //#region src/BundleFetch.d.ts
491
+ declare const BundleFetchError_base: Schema.Class<BundleFetchError, Schema.TaggedStruct<"BundleFetchError", {
492
+ /** Which fetcher failed. */
493
+ readonly source: Schema.Literals<readonly ["npm", "github"]>;
494
+ /** What went wrong, structurally. */
495
+ readonly reason: Schema.Literals<readonly ["invalidRef", "versionNotFound", "releaseNotFound", "assetNotFound", "assetAmbiguous", "download", "notABundle", "cache"]>;
496
+ /** The remote coordinate: `name@version` or `owner/repo@tag#asset`. */
497
+ readonly ref: Schema.String;
498
+ /** Human context for the failure. */
499
+ readonly detail: Schema.optionalKey<Schema.String>;
500
+ /** The underlying failure, when one exists, preserved structurally. */
501
+ readonly cause: Schema.optionalKey<Schema.Defect>;
502
+ }>, import("effect/Cause").YieldableError>;
503
+ /**
504
+ * Raised when a remote bundle cannot be fetched into the local cache.
505
+ *
506
+ * @remarks
507
+ * Fetch-plane failures speak in remote terms (`ref` names the coordinate the
508
+ * caller asked for, never a temp directory). Post-fetch READ failures — a
509
+ * fetched artifact whose layer files are malformed — surface as the same
510
+ * typed errors local reads produce (`BundleLayerError`,
511
+ * `BundleManifestError`), so a consumer handles one vocabulary for both.
512
+ *
513
+ * @public
514
+ */
515
+ declare class BundleFetchError extends BundleFetchError_base {
516
+ get message(): string;
517
+ }
518
+ /**
519
+ * Options for {@link fetchNpmBundle}.
520
+ *
521
+ * @public
522
+ */
523
+ interface FetchNpmBundleOptions {
524
+ /** The published package name. */
525
+ readonly name: string;
526
+ /**
527
+ * An exact version or a dist-tag (e.g. `"latest"`). Ranges are not
528
+ * resolved by this fetcher — resolve them upstream.
529
+ */
530
+ readonly version: string;
531
+ /**
532
+ * The registry to read — any `type: "npm"` (npm-protocol-family) registry,
533
+ * per the manifest's registries semantics. Defaults to the public npm
534
+ * registry.
535
+ */
536
+ readonly target?: RegistryTarget;
537
+ /** Bypass the cache and refetch. */
538
+ readonly refresh?: boolean;
539
+ }
540
+ /**
541
+ * Options for {@link fetchGitHubReleaseBundle}.
542
+ *
543
+ * @public
544
+ */
545
+ interface FetchGitHubReleaseBundleOptions {
546
+ /** The repository owner. */
547
+ readonly owner: string;
548
+ /** The repository name. */
549
+ readonly repo: string;
550
+ /** The release tag. */
551
+ readonly tag: string;
552
+ /**
553
+ * The exact asset file name. When omitted, the release must carry exactly
554
+ * ONE `*.npm.meta.tgz` asset (the bundle release variant) and that asset
555
+ * is used.
556
+ */
557
+ readonly asset?: string;
558
+ /**
559
+ * Bypass the cache and refetch. Unlike npm versions, a git tag CAN move —
560
+ * the cache treats tags as immutable by default, and this is the escape
561
+ * hatch when one has.
562
+ */
563
+ readonly refresh?: boolean;
564
+ }
565
+ /**
566
+ * Fetch one published npm package version as a bundle, through the durable
567
+ * XDG cache.
568
+ *
569
+ * @remarks
570
+ * Works against any npm-protocol-family registry via `target` (the
571
+ * `type: "npm"` semantics of the manifest's registries block). The tarball is
572
+ * downloaded, integrity-verified and extracted by `@effected/npm`'s
573
+ * `PackageTarball`, its bundle layer files are copied into
574
+ * `<xdg-cache>/tsdoctor/bundles/npm/<name>/<version>/`, and the returned
575
+ * {@link Bundle}'s descriptor points at that durable directory. A published
576
+ * npm version is immutable, so a cache hit skips the network entirely;
577
+ * `refresh: true` forces a refetch.
578
+ *
579
+ * Provide the `NpmRegistry`, `PackageTarball`, `Cache` and `AppDirs`
580
+ * services (plus `FileSystem`/`Path`) at the application boundary.
581
+ *
582
+ * @public
583
+ */
584
+ declare function fetchNpmBundle(options: FetchNpmBundleOptions): Effect.Effect<Bundle, BundleFetchError | BundleLayerError | BundleManifestError, NpmRegistry | PackageTarball | Cache | AppDirs | FileSystem.FileSystem | Path.Path>;
585
+ /**
586
+ * Fetch a bundle attached to a GitHub release as a `*.npm.meta.tgz`-style
587
+ * asset, through the durable XDG cache.
588
+ *
589
+ * @remarks
590
+ * The release is looked up by tag via `@effected/github`'s `GitHubRelease`
591
+ * (the `Repo` context is provided internally from `owner`/`repo`), the chosen
592
+ * asset is downloaded and extracted through the same verified
593
+ * `PackageTarball` path the npm fetcher uses (no integrity is available for
594
+ * release assets, so the download is unverified — the extractor logs this),
595
+ * and the layer files land in
596
+ * `<xdg-cache>/tsdoctor/bundles/github/<owner>/<repo>/<tag>/<asset>/`.
597
+ *
598
+ * A tarball with an npm-style `package/` root and one with its files at the
599
+ * archive root are both accepted. Git tags CAN move; the cache treats them as
600
+ * immutable and `refresh: true` is the escape hatch. Private-repo assets are
601
+ * not supported yet: the asset's browser download URL is fetched directly,
602
+ * which works for public releases only.
603
+ *
604
+ * @public
605
+ */
606
+ declare function fetchGitHubReleaseBundle(options: FetchGitHubReleaseBundleOptions): Effect.Effect<Bundle, BundleFetchError | BundleLayerError | BundleManifestError, GitHubRelease | PackageTarball | Cache | AppDirs | FileSystem.FileSystem | Path.Path>;
607
+ //#endregion
608
+ //#region src/PlatformOverrides.d.ts
609
+ /**
610
+ * The `manifest.platform` tier: a data-override object a consumer passes
611
+ * through platform options (e.g. `ApiExtractorPlugin(options)`), sitting at
612
+ * the TOP of the tier ranking.
613
+ *
614
+ * @remarks
615
+ * Same field surface as the authored manifest tiers — name, tagline,
616
+ * description, openGraph, sbom, registries — with no `spec` field (it is not
617
+ * a file with an independent version) and no `project` block (it is a single
618
+ * tier, not a flattened hierarchy). Lets a user with ONLY an api.json declare
619
+ * identity/OG/registries declaratively; the resolver does the merging.
620
+ *
621
+ * @public
622
+ */
623
+ declare const PlatformOverrides: Schema.Struct<{
624
+ /** Human display name override. */
625
+ readonly name: Schema.optionalKey<Schema.String>;
626
+ /** Tagline override. */
627
+ readonly tagline: Schema.optionalKey<Schema.String>;
628
+ /** Description override. */
629
+ readonly description: Schema.optionalKey<Schema.String>;
630
+ /** Open Graph override. */
631
+ readonly openGraph: Schema.optionalKey<Schema.Struct<{
632
+ readonly images: Schema.optionalKey<Schema.$Array<Schema.Struct<{
633
+ readonly path: Schema.optionalKey<Schema.String>;
634
+ readonly url: Schema.optionalKey<Schema.String>;
635
+ readonly type: Schema.optionalKey<Schema.String>;
636
+ readonly width: Schema.optionalKey<Schema.Int>;
637
+ readonly height: Schema.optionalKey<Schema.Int>;
638
+ readonly alt: Schema.optionalKey<Schema.String>;
639
+ }>>>;
640
+ readonly themeColor: Schema.optionalKey<Schema.String>;
641
+ }>>;
642
+ /** SBOM pointer override. */
643
+ readonly sbom: Schema.optionalKey<Schema.Struct<{
644
+ readonly path: Schema.String;
645
+ readonly format: Schema.optionalKey<Schema.String>;
646
+ }>>;
647
+ /** Registries override. */
648
+ readonly registries: Schema.optionalKey<Schema.$Array<Schema.Struct<{
649
+ readonly type: Schema.String;
650
+ readonly name: Schema.String;
651
+ readonly url: Schema.String;
652
+ }>>>;
653
+ }>;
654
+ /**
655
+ * The decoded type of {@link (PlatformOverrides:variable)}.
656
+ *
657
+ * @public
658
+ */
659
+ type PlatformOverrides = typeof PlatformOverrides.Type;
660
+ /**
661
+ * Decode an unknown value into a {@link (PlatformOverrides:type)}.
662
+ *
663
+ * @remarks
664
+ * For adapters decoding raw platform options. Failures share
665
+ * {@link BundleManifestError} — the platform tier is manifest data by another
666
+ * route, and a caller handles both boundaries with one tag.
667
+ *
668
+ * @public
669
+ */
670
+ declare function decodePlatformOverrides(input: unknown): Effect.Effect<PlatformOverrides, BundleManifestError>;
671
+ //#endregion
672
+ //#region src/BundleResolver.d.ts
673
+ /**
674
+ * Where a resolved field's value came from, highest-ranked tier first.
675
+ *
676
+ * @remarks
677
+ * The first six values are the spec's tier ladder. `"tsconfig"` is this
678
+ * package's one addition: the spec passes tsconfig compiler options through
679
+ * as a resolved field but its ladder has no source that names the tsconfig
680
+ * layer, so the union carries one.
681
+ *
682
+ * @public
683
+ */
684
+ type ProvenanceSource = "manifest.platform" | "manifest.leaf" | "manifest.project" | "packageJson" | "apiModel" | "tsconfig" | "inferred";
685
+ /**
686
+ * A resolved value carrying its provenance.
687
+ *
688
+ * @remarks
689
+ * Provenance is load-bearing: a field is user-overridden iff its source
690
+ * outranks the derivation that would otherwise supply it, an `inferred`
691
+ * field tracks upstream changes while an authored field is pinned, and the
692
+ * change-detection fingerprints hash value AND source together so an
693
+ * override flip is a visible diff.
694
+ *
695
+ * @public
696
+ */
697
+ interface Provenanced<A> {
698
+ /** The resolved value. */
699
+ readonly value: A;
700
+ /** The tier that supplied it. */
701
+ readonly source: ProvenanceSource;
702
+ }
703
+ /**
704
+ * One Open Graph image after resolution: authored fields passed through,
705
+ * `type` and `alt` filled by the documented inference rules when absent.
706
+ *
707
+ * @public
708
+ */
709
+ interface ResolvedOpenGraphImage {
710
+ /** Bundle-relative asset path, when the image is bundle-supplied. */
711
+ readonly path?: string;
712
+ /** Absolute external URL, when the image is external. */
713
+ readonly url?: string;
714
+ /** MIME type — authored, or inferred from the file extension. */
715
+ readonly type?: Provenanced<string>;
716
+ /** Pixel width, as authored. */
717
+ readonly width?: number;
718
+ /** Pixel height, as authored. */
719
+ readonly height?: number;
720
+ /** Alt text — authored, or inferred (tagline → description → `"<name> API documentation"`); never empty. */
721
+ readonly alt: Provenanced<string>;
722
+ }
723
+ /**
724
+ * The Open Graph block after resolution.
725
+ *
726
+ * @public
727
+ */
728
+ interface ResolvedOpenGraph {
729
+ /** Resolved images, first-declared-wins per OG array semantics. */
730
+ readonly images: ReadonlyArray<ResolvedOpenGraphImage>;
731
+ /** Embed accent color, when authored. */
732
+ readonly themeColor?: string;
733
+ }
734
+ /**
735
+ * A bundle's manifest data resolved across the six tiers, every field
736
+ * carrying value + provenance.
737
+ *
738
+ * @remarks
739
+ * Fields that no tier supplies are absent — with two floors: `name` always
740
+ * resolves (the api.json model always has one) and every resolved image's
741
+ * `alt` always resolves (the inference chain bottoms out on `name`).
742
+ *
743
+ * @public
744
+ */
745
+ interface ResolvedBundle {
746
+ /** Display name: platform → leaf manifest → package.json → api.json model. */
747
+ readonly name: Provenanced<string>;
748
+ /** Package version, from package.json. */
749
+ readonly version?: Provenanced<string>;
750
+ /** Tagline: platform → leaf manifest → project tier. */
751
+ readonly tagline?: Provenanced<string>;
752
+ /** Description: platform → leaf manifest → package.json. */
753
+ readonly description?: Provenanced<string>;
754
+ /** The project identity block, when the manifest carries one. */
755
+ readonly project?: Provenanced<ProjectIdentity>;
756
+ /** Open Graph block: platform → leaf manifest, with per-image inference applied. */
757
+ readonly openGraph?: Provenanced<ResolvedOpenGraph>;
758
+ /** SBOM pointer: platform → leaf manifest. */
759
+ readonly sbom?: Provenanced<SbomRef>;
760
+ /** Registries: platform → leaf manifest. */
761
+ readonly registries?: Provenanced<ReadonlyArray<RegistryRef>>;
762
+ /** Runtime dependencies from package.json, key-sorted. Feeds the type registry's rendering scope. */
763
+ readonly dependencies?: Provenanced<Readonly<Record<string, string>>>;
764
+ /** Peer dependencies from package.json, key-sorted. Feeds the type registry's rendering scope. */
765
+ readonly peerDependencies?: Provenanced<Readonly<Record<string, string>>>;
766
+ /** Extends-resolved compiler options from tsconfig.json. Feeds the Twoslash environment. */
767
+ readonly compilerOptions?: Provenanced<CompilerOptions.Type>;
768
+ }
769
+ /**
770
+ * The parsed layers {@link resolveBundle} resolves — plain optional fields,
771
+ * so pure call sites (and tests) need no `Option` wrapping.
772
+ *
773
+ * @public
774
+ */
775
+ interface ResolveBundleInput {
776
+ /** Layer 0: the model header (required — the one layer a bundle must have). */
777
+ readonly apiModel: ApiModelInfo;
778
+ /** Layer 1: the package.json manifest, when present. */
779
+ readonly packageJson?: PackageManifest;
780
+ /** Layer 2: the extends-resolved tsconfig, when present. */
781
+ readonly tsconfig?: ResolvedTsconfig;
782
+ /** Layer 3: the tsdoctor.json sidecar manifest, when present. */
783
+ readonly manifest?: BundleManifest;
784
+ /** The `manifest.platform` tier, from platform options. */
785
+ readonly platform?: PlatformOverrides;
786
+ }
787
+ /**
788
+ * Resolve a bundle's layers into a {@link ResolvedBundle}, pure.
789
+ *
790
+ * @remarks
791
+ * Highest tier wins per FIELD: `manifest.platform` → `manifest.leaf` →
792
+ * `manifest.project` → `packageJson` → `apiModel` → `inferred`. The project
793
+ * tier participates only in the fields it carries site/project identity for
794
+ * (tagline); the display `name` chain deliberately skips it — a project name
795
+ * outranking every leaf's own name would render each package in a monorepo
796
+ * under the same title, and the spec's `og:title` derivation reads
797
+ * `leaf name/tagline ← package name`. Inference (image `alt` and MIME
798
+ * `type`) runs on the RESOLVED tagline/description, so a tagline change at
799
+ * any tier propagates into inferred alt text.
800
+ *
801
+ * @public
802
+ */
803
+ declare function resolveBundle(input: ResolveBundleInput): ResolvedBundle;
804
+ /**
805
+ * Resolve a read {@link Bundle}, unwrapping its `Option` layers.
806
+ *
807
+ * @public
808
+ */
809
+ declare function resolveBundleFrom(bundle: Bundle, platform?: PlatformOverrides): ResolvedBundle;
810
+ //#endregion
811
+ //#region src/BundleHash.d.ts
812
+ /**
813
+ * Serialize a JSON-shaped value canonically: object keys sorted recursively,
814
+ * `undefined`-valued keys dropped, arrays in declared order, no whitespace.
815
+ *
816
+ * @remarks
817
+ * The normalization half of the change-detection discipline: two values that
818
+ * differ only in key order or optional-key presence-as-`undefined` serialize
819
+ * identically, so their hashes match. Non-JSON leaves (functions, symbols)
820
+ * serialize as `null`, matching `JSON.stringify` semantics inside arrays.
821
+ *
822
+ * @public
823
+ */
824
+ declare function canonicalJson(value: unknown): string;
825
+ /**
826
+ * Normalize text for hashing: CRLF/CR line endings become LF and trailing
827
+ * whitespace at the end of the content is trimmed.
828
+ *
829
+ * @remarks
830
+ * The same file checked out with different line-ending settings must hash
831
+ * identically — coarse layer-hash comparison otherwise reports every file
832
+ * changed on the first cross-platform build.
833
+ *
834
+ * @public
835
+ */
836
+ declare function normalizeText(text: string): string;
837
+ /**
838
+ * The lowercase hex SHA-256 of a string, UTF-8 encoded.
839
+ *
840
+ * @public
841
+ */
842
+ declare function sha256Hex(text: string): string;
843
+ /**
844
+ * Hash text content: {@link normalizeText} then {@link sha256Hex}.
845
+ *
846
+ * @public
847
+ */
848
+ declare function hashText(text: string): string;
849
+ /**
850
+ * Hash a JSON-shaped value: {@link canonicalJson} then {@link sha256Hex}.
851
+ *
852
+ * @public
853
+ */
854
+ declare function hashJsonValue(value: unknown): string;
855
+ /**
856
+ * Hash one bundle layer file's raw text — the COARSE half of change
857
+ * detection (all layer hashes match → skip resolution entirely).
858
+ *
859
+ * @remarks
860
+ * Total: text that parses as JSON hashes canonically (key order and
861
+ * formatting churn do not read as change); text that does not parse falls
862
+ * back to {@link hashText}, so a broken file still gets a stable hash
863
+ * rather than an error — hashing is bookkeeping, not validation.
864
+ *
865
+ * @public
866
+ */
867
+ declare function hashLayerText(text: string): string;
868
+ /**
869
+ * Fingerprint every present field of a {@link ResolvedBundle} — the FINE
870
+ * half of change detection, hashing each field's `{ value, source }` pair.
871
+ *
872
+ * @remarks
873
+ * The source participates deliberately: an override flip (a field moving
874
+ * from `inferred` to an authored tier without changing value) is a
875
+ * semantically meaningful change and must read as one. Absent fields carry
876
+ * no fingerprint — their appearance or disappearance is itself the diff.
877
+ * The consuming store maps each key to its invalidation scope (version →
878
+ * version-embedding surfaces, tsconfig → all code blocks, …).
879
+ *
880
+ * @public
881
+ */
882
+ declare function fingerprintResolvedBundle(resolved: ResolvedBundle): Readonly<Record<string, string>>;
883
+ //#endregion
884
+ export { type ApiModelInfo, type Bundle, type BundleDescriptor, BundleDiscoveryError, BundleFetchError, BundleLayerError, BundleManifest, BundleManifestError, type BundleOverrides, type DiscoverBundleOptions, type DiscoverBundlesOptions, type FetchGitHubReleaseBundleOptions, type FetchNpmBundleOptions, KNOWN_REGISTRY_TYPES, type KnownRegistryType, OpenGraphConfig, OpenGraphImage, PlatformOverrides, ProjectIdentity, type ProvenanceSource, type Provenanced, RegistryRef, type ResolveBundleInput, type ResolvedBundle, type ResolvedOpenGraph, type ResolvedOpenGraphImage, SbomRef, TSDOCTOR_MANIFEST_FILENAME, canonicalJson, decodeBundleManifest, decodePlatformOverrides, discoverBundle, discoverBundles, fetchGitHubReleaseBundle, fetchNpmBundle, fingerprintResolvedBundle, hashJsonValue, hashLayerText, hashText, isKnownRegistryType, loadBundle, loadBundles, normalizeText, readApiModelInfo, readBundle, resolveBundle, resolveBundleFrom, sha256Hex };
885
+ //# sourceMappingURL=index.d.ts.map