type-registry-effect 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/node.d.ts ADDED
@@ -0,0 +1,890 @@
1
+ /**
2
+ * type-registry-effect/node — Node.js platform layer and Promise convenience API.
3
+ *
4
+ * @remarks
5
+ * This entry point provides {@link NodeLayer}, a fully-closed Effect layer that
6
+ * composes {@link TypeRegistryLive} with `NodeFileSystem` and `NodeHttpClient`
7
+ * from `@effect/platform-node`. It also re-exports every {@link TypeRegistry}
8
+ * namespace function as a plain `Promise`-returning wrapper so consumers who do
9
+ * not use Effect directly can call `await fetchAndCache(pkg)` without managing
10
+ * layers.
11
+ *
12
+ * Install the optional peer dependency before importing this entry point:
13
+ *
14
+ * ```bash
15
+ * npm install @effect/platform-node
16
+ * ```
17
+ *
18
+ * @example
19
+ * ```typescript
20
+ * import { Effect } from "effect";
21
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
22
+ * import { NodeLayer } from "type-registry-effect/node";
23
+ *
24
+ * const program = TypeRegistry.getVFS([
25
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
26
+ * ]);
27
+ *
28
+ * const vfs = await Effect.runPromise(Effect.provide(program, NodeLayer));
29
+ * ```
30
+ *
31
+ * @example
32
+ * ```typescript
33
+ * import { PackageSpec } from "type-registry-effect";
34
+ * import { fetchAndCache, getVFS } from "type-registry-effect/node";
35
+ *
36
+ * const pkg = new PackageSpec({ name: "zod", version: "3.23.8" });
37
+ * await fetchAndCache(pkg);
38
+ * const vfs = await getVFS([pkg]);
39
+ * ```
40
+ *
41
+ * @packageDocumentation
42
+ */
43
+
44
+ import { Context } from 'effect';
45
+ import type { Effect } from 'effect';
46
+ import { Equals } from 'effect/Types';
47
+ import { Layer } from 'effect';
48
+ import { Schema } from 'effect';
49
+ import * as ts from 'typescript';
50
+ import { VirtualTypeScriptEnvironment } from '@typescript/vfs';
51
+ import { YieldableError } from 'effect/Cause';
52
+
53
+ /**
54
+ * Raised when a disk cache operation (read, write, delete, or list) fails.
55
+ *
56
+ * @remarks
57
+ * The `operation` field indicates which cache operation triggered the failure,
58
+ * `path` is the filesystem path involved, and `message` describes the
59
+ * underlying cause (e.g. permission denied, disk full). Use `Effect.catchTag`
60
+ * with the `"CacheError"` tag to handle this error selectively.
61
+ *
62
+ * @example
63
+ * ```typescript
64
+ * import { Effect } from "effect";
65
+ * import type { CacheError } from "type-registry-effect";
66
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
67
+ * import { NodeLayer } from "type-registry-effect/node";
68
+ *
69
+ * const program = TypeRegistry.fetchAndCache(
70
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
71
+ * ).pipe(
72
+ * Effect.catchTag("CacheError", (err: CacheError) =>
73
+ * Effect.logWarning(`Cache ${err.operation} failed at ${err.path}: ${err.message}`),
74
+ * ),
75
+ * );
76
+ *
77
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
78
+ * ```
79
+ *
80
+ * @see {@link CacheService}
81
+ * @public
82
+ */
83
+ export declare class CacheError extends CacheErrorBase<{
84
+ readonly operation: "read" | "write" | "delete" | "list";
85
+ readonly path: string;
86
+ readonly message: string;
87
+ }> {
88
+ }
89
+
90
+ /**
91
+ * @internal
92
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
93
+ * a class whose `extends` expression is an inline call like
94
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
95
+ * the declaration file. Splitting the base into a named export gives the
96
+ * bundler a stable reference.
97
+ *
98
+ * @privateRemarks
99
+ * This base constant must remain a named export so that api-extractor can
100
+ * resolve the extends clause of {@link CacheError} to a stable
101
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
102
+ * `_base` symbol that cannot be referenced by downstream consumers.
103
+ */
104
+ export declare const CacheErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
105
+ readonly _tag: "CacheError";
106
+ } & Readonly<A>;
107
+
108
+ /**
109
+ * Metadata stored alongside cached packages on disk.
110
+ *
111
+ * @remarks
112
+ * Each cached package directory contains a metadata file recording when it was
113
+ * cached and the version that was resolved. The optional `ttl` field (in
114
+ * milliseconds) allows per-package cache expiration policies. When `ttl` is
115
+ * omitted the cache entry never expires automatically.
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * import { CacheMetadata } from "type-registry-effect";
120
+ *
121
+ * // Metadata with an explicit 1-hour TTL
122
+ * const meta: CacheMetadata = {
123
+ * version: "3.23.8",
124
+ * cachedAt: Date.now(),
125
+ * ttl: 60 * 60 * 1000,
126
+ * };
127
+ *
128
+ * // Metadata that never expires
129
+ * const permanent: CacheMetadata = {
130
+ * version: "5.4.2",
131
+ * cachedAt: Date.now(),
132
+ * };
133
+ * ```
134
+ *
135
+ * @see {@link CacheServiceLive}
136
+ * @see {@link TypeRegistry.fetchAndCache}
137
+ * @public
138
+ */
139
+ export declare interface CacheMetadata {
140
+ readonly version: string;
141
+ readonly cachedAt: number;
142
+ readonly ttl?: number | undefined;
143
+ }
144
+
145
+ /**
146
+ * Effect Schema for validating and encoding {@link CacheMetadata}.
147
+ *
148
+ * @see {@link CacheMetadata}
149
+ */
150
+ export declare const CacheMetadata: Schema.Schema<CacheMetadata>;
151
+
152
+ /**
153
+ * Effect service interface for the disk-based type definition cache.
154
+ *
155
+ * @remarks
156
+ * Implementations store type definition files and metadata on disk using a
157
+ * platform-specific {@link @effect/platform#FileSystem | FileSystem} service.
158
+ * Platform dependencies are resolved **within the layer**, so consumers of this
159
+ * interface never interact with the filesystem directly.
160
+ *
161
+ * Use this tag to access cache methods inside an `Effect.gen` block. The live
162
+ * implementation is provided by {@link CacheServiceLive} (or the lower-level
163
+ * {@link makeNodeCacheLayer}).
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * import { Effect } from "effect";
168
+ * import { CacheService } from "type-registry-effect";
169
+ * import type { PackageSpec } from "type-registry-effect";
170
+ *
171
+ * const program = Effect.gen(function* () {
172
+ * const cache = yield* CacheService;
173
+ * const exists = yield* cache.exists({ name: "lodash", version: "4.17.21" } as PackageSpec);
174
+ * console.log("cached:", exists);
175
+ * });
176
+ * ```
177
+ *
178
+ * @see {@link CacheServiceLive}
179
+ * @see {@link makeNodeCacheLayer}
180
+ *
181
+ * @public
182
+ */
183
+ export declare interface CacheService {
184
+ /** Check whether cached type definitions exist for a package. */
185
+ readonly exists: (pkg: PackageSpec) => Effect.Effect<boolean, CacheError>;
186
+ /** Read a single cached file by relative path within the package cache directory. */
187
+ readonly read: (pkg: PackageSpec, filePath: string) => Effect.Effect<string, CacheError>;
188
+ /** Write a single file into the package cache directory, creating parent directories as needed. */
189
+ readonly write: (pkg: PackageSpec, filePath: string, content: string) => Effect.Effect<void, CacheError>;
190
+ /** List all cached file paths (relative) for a package. */
191
+ readonly listFiles: (pkg: PackageSpec) => Effect.Effect<ReadonlyArray<string>, CacheError>;
192
+ /** Read the `.metadata.json` sidecar for a cached package. */
193
+ readonly readMetadata: (pkg: PackageSpec) => Effect.Effect<CacheMetadata, CacheError>;
194
+ /** Write or overwrite the `.metadata.json` sidecar for a cached package. */
195
+ readonly writeMetadata: (pkg: PackageSpec, metadata: CacheMetadata) => Effect.Effect<void, CacheError>;
196
+ /** Build a {@link VirtualFileSystem} from the cache, suitable for an in-memory TS compiler host. */
197
+ readonly getVFS: (pkg: PackageSpec) => Effect.Effect<VirtualFileSystem, CacheError>;
198
+ /** Remove all cached data for a package, including metadata. */
199
+ readonly remove: (pkg: PackageSpec) => Effect.Effect<void, CacheError>;
200
+ }
201
+
202
+ /**
203
+ * Effect Context tag for the {@link CacheService} service.
204
+ *
205
+ * @see {@link CacheServiceLive}
206
+ * @see {@link makeNodeCacheLayer}
207
+ */
208
+ export declare const CacheService: Context.Tag<CacheService, CacheService>;
209
+
210
+ /**
211
+ * Create a TypeScript virtual environment cache for use with Twoslash
212
+ * or other TypeScript language service consumers (Promise API).
213
+ */
214
+ export declare const createTypeScriptCache: (packages: readonly PackageSpec[], compilerOptions: ts.CompilerOptions) => Promise<Map<string, VirtualTypeScriptEnvironment>>;
215
+
216
+ /**
217
+ * Fetch and cache a package's type definitions (Promise API).
218
+ */
219
+ export declare const fetchAndCache: (pkg: PackageSpec, options?: {
220
+ readonly ttl?: number;
221
+ } | undefined) => Promise<void>;
222
+
223
+ /**
224
+ * Schema for the jsDelivr flat file tree API response.
225
+ *
226
+ * @remarks
227
+ * The response includes a `default` field indicating the package's default
228
+ * branch/tag and a `files` array of {@link FileTreeEntry} objects. This
229
+ * corresponds to the `GET /v1/packages/npm/:package@:version/flat` endpoint.
230
+ *
231
+ * @example
232
+ * ```typescript
233
+ * import { Schema } from "effect";
234
+ * import { FileTreeResponse } from "type-registry-effect";
235
+ *
236
+ * const decode = Schema.decodeUnknownSync(FileTreeResponse);
237
+ * const tree = decode({
238
+ * default: "/dist/index.js",
239
+ * files: [
240
+ * { name: "/dist/index.js", hash: "abc123", time: "2024-01-15T10:30:00.000Z", size: 2048 },
241
+ * { name: "/dist/index.d.ts", hash: "def456", time: "2024-01-15T10:30:00.000Z", size: 4096 },
242
+ * ],
243
+ * });
244
+ * ```
245
+ *
246
+ * @see {@link PackageFetcher.getFileTree}
247
+ * @see {@link https://www.jsdelivr.com/docs/data.jsdelivr.com | jsDelivr Data API}
248
+ * @public
249
+ */
250
+ export declare const FileTreeResponse: Schema.Struct<{
251
+ default: typeof Schema.String;
252
+ files: Schema.Array$<Schema.Struct<{
253
+ name: typeof Schema.String;
254
+ hash: typeof Schema.String;
255
+ time: typeof Schema.String;
256
+ size: typeof Schema.Number;
257
+ }>>;
258
+ }>;
259
+
260
+ export declare type FileTreeResponse = Schema.Schema.Type<typeof FileTreeResponse>;
261
+
262
+ /**
263
+ * Get combined VFS for multiple packages (Promise API).
264
+ */
265
+ export declare const getVFS: (packages: readonly PackageSpec[], options?: {
266
+ readonly autoFetch?: boolean;
267
+ readonly ttl?: number;
268
+ } | undefined) => Promise<VirtualFileSystem>;
269
+
270
+ /**
271
+ * Check if a package is cached (Promise API).
272
+ */
273
+ export declare const hasCached: (pkg: PackageSpec) => Promise<boolean>;
274
+
275
+ /**
276
+ * Raised when an HTTP request to the jsDelivr CDN fails.
277
+ *
278
+ * @remarks
279
+ * The `url` field contains the request URL, `status` is the HTTP status code
280
+ * (when available), and `message` describes the failure. Network errors may be
281
+ * transient (e.g. DNS resolution, connection reset) or permanent (e.g. 403
282
+ * Forbidden). Use `Effect.catchTag` with the `"NetworkError"` tag to handle
283
+ * this error selectively.
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * import { Effect } from "effect";
288
+ * import type { NetworkError } from "type-registry-effect";
289
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
290
+ * import { NodeLayer } from "type-registry-effect/node";
291
+ *
292
+ * const program = TypeRegistry.fetchAndCache(
293
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
294
+ * ).pipe(
295
+ * Effect.catchTag("NetworkError", (err: NetworkError) =>
296
+ * Effect.logError(`Request to ${err.url} failed (${err.status ?? "no status"}): ${err.message}`),
297
+ * ),
298
+ * );
299
+ *
300
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
301
+ * ```
302
+ *
303
+ * @see {@link PackageFetcher}
304
+ * @public
305
+ */
306
+ export declare class NetworkError extends NetworkErrorBase<{
307
+ readonly url: string;
308
+ readonly status?: number;
309
+ readonly message: string;
310
+ }> {
311
+ }
312
+
313
+ /**
314
+ * @internal
315
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
316
+ * a class whose `extends` expression is an inline call like
317
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
318
+ * the declaration file. Splitting the base into a named export gives the
319
+ * bundler a stable reference.
320
+ *
321
+ * @privateRemarks
322
+ * This base constant must remain a named export so that api-extractor can
323
+ * resolve the extends clause of {@link NetworkError} to a stable
324
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
325
+ * `_base` symbol that cannot be referenced by downstream consumers.
326
+ */
327
+ export declare const NetworkErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
328
+ readonly _tag: "NetworkError";
329
+ } & Readonly<A>;
330
+
331
+ /**
332
+ * Node.js platform layer that provides FileSystem and HttpClient,
333
+ * composed with all TypeRegistry service layers.
334
+ */
335
+ export declare const NodeLayer: Layer.Layer<CacheService | PackageFetcher | TypeResolver, never, never>;
336
+
337
+ /**
338
+ * Effect service interface for fetching type definitions and package metadata
339
+ * from the jsDelivr CDN.
340
+ *
341
+ * @remarks
342
+ * All network calls are retried up to 3 times with exponential back-off
343
+ * (starting at 100 ms) and are subject to a 30-second timeout. The live
344
+ * implementation is provided by {@link PackageFetcherLive}.
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * import { Effect } from "effect";
349
+ * import { PackageFetcher } from "type-registry-effect";
350
+ *
351
+ * const program = Effect.gen(function* () {
352
+ * const fetcher = yield* PackageFetcher;
353
+ * const meta = yield* fetcher.getVersions("lodash");
354
+ * console.log("latest:", meta.tags["latest"]);
355
+ * });
356
+ * ```
357
+ *
358
+ * @see {@link PackageFetcherLive}
359
+ *
360
+ * @public
361
+ */
362
+ export declare interface PackageFetcher {
363
+ /** Fetch all published versions and dist-tags for a package. */
364
+ readonly getVersions: (name: string) => Effect.Effect<PackageMetadata, NetworkError | ParseError>;
365
+ /** Resolve a semver range or dist-tag to a concrete version string. */
366
+ readonly resolveVersion: (name: string, ref: string) => Effect.Effect<string, NetworkError | PackageNotFoundError>;
367
+ /** Retrieve the flat file tree listing for a specific package version. */
368
+ readonly getFileTree: (pkg: PackageSpec) => Effect.Effect<FileTreeResponse, NetworkError | ParseError>;
369
+ /** Download a single file from the CDN by path. */
370
+ readonly downloadFile: (pkg: PackageSpec, path: string) => Effect.Effect<string, NetworkError>;
371
+ /** Download and schema-validate the `package.json` for a package version. */
372
+ readonly getPackageJson: (pkg: PackageSpec) => Effect.Effect<PackageJson, NetworkError | ParseError>;
373
+ /** Download all TypeScript declaration files for a package version, returned as a path-to-content map. */
374
+ readonly getTypeFiles: (pkg: PackageSpec) => Effect.Effect<Map<string, string>, NetworkError | ParseError>;
375
+ }
376
+
377
+ /**
378
+ * Effect Context tag for the {@link PackageFetcher} service.
379
+ *
380
+ * @see {@link PackageFetcherLive}
381
+ */
382
+ export declare const PackageFetcher: Context.Tag<PackageFetcher, PackageFetcher>;
383
+
384
+ /**
385
+ * Schema for a validated subset of npm `package.json` fields relevant to type resolution.
386
+ *
387
+ * @remarks
388
+ * This schema captures only the fields the type resolver needs to locate
389
+ * declaration files within a published package:
390
+ *
391
+ * - **`name`** and **`version`** -- identity fields (always required).
392
+ * - **`types`** / **`typings`** -- legacy top-level type entry points.
393
+ * - **`main`** / **`module`** -- JavaScript entry points used as fallbacks
394
+ * when no explicit type entry is declared.
395
+ * - **`exports`** -- the modern Node.js conditional exports map; may be a
396
+ * simple string or a nested record of conditions.
397
+ * - **`typesVersions`** -- TypeScript path-mapping overrides keyed by TS
398
+ * version ranges (e.g. `">=4.0"`).
399
+ * - **`dependencies`** / **`peerDependencies`** / **`devDependencies`** --
400
+ * used to discover transitive type packages (e.g. `@types/*`).
401
+ *
402
+ * Fields outside this set are intentionally ignored to keep validation fast
403
+ * and the attack surface small.
404
+ *
405
+ * @example
406
+ * ```typescript
407
+ * import { Schema } from "effect";
408
+ * import { PackageJson } from "type-registry-effect";
409
+ *
410
+ * const decode = Schema.decodeUnknownSync(PackageJson);
411
+ * const pkg = decode({
412
+ * name: "zod",
413
+ * version: "3.23.8",
414
+ * types: "./lib/types.d.ts",
415
+ * main: "./lib/index.js",
416
+ * exports: {
417
+ * ".": { types: "./lib/types.d.ts", import: "./lib/index.mjs" },
418
+ * },
419
+ * });
420
+ * ```
421
+ *
422
+ * @see {@link TypeResolver}
423
+ * @public
424
+ */
425
+ export declare const PackageJson: Schema.Struct<{
426
+ name: typeof Schema.String;
427
+ version: typeof Schema.String;
428
+ types: Schema.optional<typeof Schema.String>;
429
+ typings: Schema.optional<typeof Schema.String>;
430
+ main: Schema.optional<typeof Schema.String>;
431
+ module: Schema.optional<typeof Schema.String>;
432
+ exports: Schema.optional<Schema.Union<[typeof Schema.String, Schema.Record$<typeof Schema.String, typeof Schema.Unknown>]>>;
433
+ typesVersions: Schema.optional<Schema.Record$<typeof Schema.String, Schema.Record$<typeof Schema.String, Schema.Array$<typeof Schema.String>>>>;
434
+ dependencies: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
435
+ peerDependencies: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
436
+ devDependencies: Schema.optional<Schema.Record$<typeof Schema.String, typeof Schema.String>>;
437
+ }>;
438
+
439
+ export declare type PackageJson = Schema.Schema.Type<typeof PackageJson>;
440
+
441
+ /**
442
+ * Version and tag metadata for an npm package as returned by the jsDelivr API.
443
+ *
444
+ * @remarks
445
+ * The `versions` array contains every published version string. The `tags`
446
+ * record maps dist-tags (e.g. `"latest"`, `"next"`) to their corresponding
447
+ * version strings.
448
+ *
449
+ * @public
450
+ */
451
+ export declare interface PackageMetadata {
452
+ readonly versions: string[];
453
+ readonly tags: Record<string, string>;
454
+ }
455
+
456
+ /**
457
+ * Raised when a package or version does not exist on the CDN.
458
+ *
459
+ * @remarks
460
+ * The `name` and `version` fields identify the package that could not be
461
+ * found, and `message` provides additional context. This typically occurs
462
+ * when a typo is present in the package name or the requested version has
463
+ * not been published. Use `Effect.catchTag` with the
464
+ * `"PackageNotFoundError"` tag to handle this error selectively.
465
+ *
466
+ * @example
467
+ * ```typescript
468
+ * import { Effect } from "effect";
469
+ * import type { PackageNotFoundError } from "type-registry-effect";
470
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
471
+ * import { NodeLayer } from "type-registry-effect/node";
472
+ *
473
+ * const program = TypeRegistry.fetchAndCache(
474
+ * new PackageSpec({ name: "nonexistent-pkg", version: "0.0.0" }),
475
+ * ).pipe(
476
+ * Effect.catchTag("PackageNotFoundError", (err: PackageNotFoundError) =>
477
+ * Effect.logWarning(`Package ${err.name}@${err.version} not found: ${err.message}`),
478
+ * ),
479
+ * );
480
+ *
481
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
482
+ * ```
483
+ *
484
+ * @see {@link PackageFetcher.resolveVersion}
485
+ * @public
486
+ */
487
+ export declare class PackageNotFoundError extends PackageNotFoundErrorBase<{
488
+ readonly name: string;
489
+ readonly version: string;
490
+ readonly message: string;
491
+ }> {
492
+ }
493
+
494
+ /**
495
+ * @internal
496
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
497
+ * a class whose `extends` expression is an inline call like
498
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
499
+ * the declaration file. Splitting the base into a named export gives the
500
+ * bundler a stable reference.
501
+ *
502
+ * @privateRemarks
503
+ * This base constant must remain a named export so that api-extractor can
504
+ * resolve the extends clause of {@link PackageNotFoundError} to a stable
505
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
506
+ * `_base` symbol that cannot be referenced by downstream consumers.
507
+ */
508
+ export declare const PackageNotFoundErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
509
+ readonly _tag: "PackageNotFoundError";
510
+ } & Readonly<A>;
511
+
512
+ /**
513
+ * Immutable value object identifying a package at a specific version.
514
+ *
515
+ * @remarks
516
+ * `PackageSpec` uses {@link https://effect.website/docs/data-types/data/#taggedclass | Data.TaggedClass}
517
+ * to provide structural equality out of the box. Two `PackageSpec` instances
518
+ * with the same `name` and `version` are considered equal via `Equal.equals`.
519
+ * The optional `registry` field allows targeting alternative registries.
520
+ *
521
+ * @example
522
+ * ```typescript
523
+ * import { Equal } from "effect";
524
+ * import type { PackageSpec } from "type-registry-effect";
525
+ * import { PackageSpec as PackageSpecClass } from "type-registry-effect";
526
+ *
527
+ * const pkg = new PackageSpecClass({ name: "zod", version: "3.23.8" });
528
+ * const same = new PackageSpecClass({ name: "zod", version: "3.23.8" });
529
+ *
530
+ * // Structural equality via Data.TaggedClass
531
+ * console.assert(Equal.equals(pkg, same) === true);
532
+ *
533
+ * // String representation: "zod@3.23.8"
534
+ * console.assert(pkg.toString() === "zod@3.23.8");
535
+ *
536
+ * // Optional registry for alternative sources
537
+ * const custom = new PackageSpecClass({
538
+ * name: "@myorg/types",
539
+ * version: "1.0.0",
540
+ * registry: "https://npm.pkg.github.com",
541
+ * });
542
+ * ```
543
+ *
544
+ * @see {@link CacheService}
545
+ * @see {@link TypeRegistry}
546
+ * @public
547
+ */
548
+ export declare class PackageSpec extends PackageSpecBase<{
549
+ readonly name: string;
550
+ readonly version: string;
551
+ readonly registry?: string;
552
+ }> {
553
+ toString(): string;
554
+ }
555
+
556
+ /**
557
+ * @internal
558
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
559
+ * a class whose `extends` expression is an inline call like
560
+ * `Data.TaggedClass(...)`, TypeScript emits an un-nameable `_base` symbol in
561
+ * the declaration file. Splitting the base into a named export gives the
562
+ * bundler a stable reference.
563
+ *
564
+ * @privateRemarks
565
+ * This base constant must remain a named export so that api-extractor can
566
+ * resolve the extends clause of {@link PackageSpec} to a stable
567
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
568
+ * `_base` symbol that cannot be referenced by downstream consumers.
569
+ */
570
+ export declare const PackageSpecBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
571
+ readonly _tag: "PackageSpec";
572
+ };
573
+
574
+ /**
575
+ * Raised when a CDN response fails schema validation or JSON parsing.
576
+ *
577
+ * @remarks
578
+ * The `source` field identifies what was being parsed (e.g. `"package.json"`,
579
+ * `"file-tree"`) and `message` describes the validation failure. This
580
+ * typically indicates the CDN returned an unexpected response shape or
581
+ * corrupted data. Use `Effect.catchTag` with the `"ParseError"` tag to
582
+ * handle this error selectively.
583
+ *
584
+ * @example
585
+ * ```typescript
586
+ * import { Effect } from "effect";
587
+ * import type { ParseError } from "type-registry-effect";
588
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
589
+ * import { NodeLayer } from "type-registry-effect/node";
590
+ *
591
+ * const program = TypeRegistry.fetchAndCache(
592
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
593
+ * ).pipe(
594
+ * Effect.catchTag("ParseError", (err: ParseError) =>
595
+ * Effect.logError(`Failed to parse ${err.source}: ${err.message}`),
596
+ * ),
597
+ * );
598
+ *
599
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
600
+ * ```
601
+ *
602
+ * @see {@link PackageFetcher.getPackageJson}
603
+ * @public
604
+ */
605
+ export declare class ParseError extends ParseErrorBase<{
606
+ readonly source: string;
607
+ readonly message: string;
608
+ }> {
609
+ }
610
+
611
+ /**
612
+ * @internal
613
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
614
+ * a class whose `extends` expression is an inline call like
615
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
616
+ * the declaration file. Splitting the base into a named export gives the
617
+ * bundler a stable reference.
618
+ *
619
+ * @privateRemarks
620
+ * This base constant must remain a named export so that api-extractor can
621
+ * resolve the extends clause of {@link ParseError} to a stable
622
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
623
+ * `_base` symbol that cannot be referenced by downstream consumers.
624
+ */
625
+ export declare const ParseErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
626
+ readonly _tag: "ParseError";
627
+ } & Readonly<A>;
628
+
629
+ /**
630
+ * Raised when an import specifier cannot be resolved to a module within a package.
631
+ *
632
+ * @remarks
633
+ * The `package` field is the package name, `specifier` is the import path
634
+ * that could not be resolved, and `message` describes the failure cause.
635
+ * This occurs when the package's exports map, `typesVersions`, or file tree
636
+ * do not contain a matching entry for the requested specifier. Use
637
+ * `Effect.catchTag` with the `"ResolutionError"` tag to handle this error
638
+ * selectively.
639
+ *
640
+ * @example
641
+ * ```typescript
642
+ * import { Effect } from "effect";
643
+ * import type { ResolutionError } from "type-registry-effect";
644
+ * import { TypeResolver, PackageSpec } from "type-registry-effect";
645
+ * import { NodeLayer } from "type-registry-effect/node";
646
+ *
647
+ * const program = TypeResolver.resolveImport(
648
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
649
+ * "./nonexistent",
650
+ * ).pipe(
651
+ * Effect.catchTag("ResolutionError", (err: ResolutionError) =>
652
+ * Effect.logWarning(`Cannot resolve "${err.specifier}" in ${err.package}: ${err.message}`),
653
+ * ),
654
+ * );
655
+ *
656
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
657
+ * ```
658
+ *
659
+ * @see {@link TypeResolver.resolveImport}
660
+ * @public
661
+ */
662
+ export declare class ResolutionError extends ResolutionErrorBase<{
663
+ readonly package: string;
664
+ readonly specifier: string;
665
+ readonly message: string;
666
+ }> {
667
+ }
668
+
669
+ /**
670
+ * @internal
671
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
672
+ * a class whose `extends` expression is an inline call like
673
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
674
+ * the declaration file. Splitting the base into a named export gives the
675
+ * bundler a stable reference.
676
+ *
677
+ * @privateRemarks
678
+ * This base constant must remain a named export so that api-extractor can
679
+ * resolve the extends clause of {@link ResolutionError} to a stable
680
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
681
+ * `_base` symbol that cannot be referenced by downstream consumers.
682
+ */
683
+ export declare const ResolutionErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
684
+ readonly _tag: "ResolutionError";
685
+ } & Readonly<A>;
686
+
687
+ /**
688
+ * Represents a resolved module path within a package.
689
+ *
690
+ * @remarks
691
+ * After the {@link TypeResolver} walks a package's exports and file tree, each
692
+ * resolvable import specifier maps to a `ResolvedModule`. The `filePath` is
693
+ * relative to the package root, and `isTypeDefinition` indicates whether the
694
+ * file is a `.d.ts` (or `.d.mts` / `.d.cts`) declaration file. The `package`
695
+ * field links back to the originating {@link PackageSpec}.
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * import type { ResolvedModule, PackageSpec } from "type-registry-effect";
700
+ * import {
701
+ * ResolvedModule as ResolvedModuleClass,
702
+ * PackageSpec as PackageSpecClass,
703
+ * } from "type-registry-effect";
704
+ *
705
+ * const mod = new ResolvedModuleClass({
706
+ * filePath: "dist/index.d.ts",
707
+ * isTypeDefinition: true,
708
+ * package: new PackageSpecClass({ name: "zod", version: "3.23.8" }),
709
+ * });
710
+ * ```
711
+ *
712
+ * @see {@link TypeResolver.resolveImport}
713
+ * @see {@link TypeResolver.resolveTypeEntries}
714
+ * @public
715
+ */
716
+ export declare class ResolvedModule extends ResolvedModuleBase<{
717
+ readonly filePath: string;
718
+ readonly isTypeDefinition: boolean;
719
+ readonly package: PackageSpec;
720
+ }> {
721
+ }
722
+
723
+ /**
724
+ * @internal
725
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
726
+ * a class whose `extends` expression is an inline call like
727
+ * `Data.TaggedClass(...)`, TypeScript emits an un-nameable `_base` symbol in
728
+ * the declaration file. Splitting the base into a named export gives the
729
+ * bundler a stable reference.
730
+ *
731
+ * @privateRemarks
732
+ * This base constant must remain a named export so that api-extractor can
733
+ * resolve the extends clause of {@link ResolvedModule} to a stable
734
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
735
+ * `_base` symbol that cannot be referenced by downstream consumers.
736
+ */
737
+ export declare const ResolvedModuleBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => Readonly<A> & {
738
+ readonly _tag: "ResolvedModule";
739
+ };
740
+
741
+ /**
742
+ * Resolve a version reference to a specific version (Promise API).
743
+ */
744
+ export declare const resolveVersion: (name: string, ref: string) => Promise<string>;
745
+
746
+ /**
747
+ * Raised when an operation exceeds its configured time limit.
748
+ *
749
+ * @remarks
750
+ * The `operation` field describes what was being performed (e.g.
751
+ * `"fetchFileTree"`, `"resolveVersion"`), `duration` is the elapsed time in
752
+ * milliseconds, and `message` provides additional context. Use
753
+ * `Effect.catchTag` with the `"TimeoutError"` tag to handle this error
754
+ * selectively.
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * import { Effect } from "effect";
759
+ * import type { TimeoutError } from "type-registry-effect";
760
+ * import { TypeRegistry, PackageSpec } from "type-registry-effect";
761
+ * import { NodeLayer } from "type-registry-effect/node";
762
+ *
763
+ * const program = TypeRegistry.fetchAndCache(
764
+ * new PackageSpec({ name: "zod", version: "3.23.8" }),
765
+ * ).pipe(
766
+ * Effect.catchTag("TimeoutError", (err: TimeoutError) =>
767
+ * Effect.logWarning(`${err.operation} timed out after ${err.duration}ms: ${err.message}`),
768
+ * ),
769
+ * );
770
+ *
771
+ * await Effect.runPromise(Effect.provide(program, NodeLayer));
772
+ * ```
773
+ *
774
+ * @public
775
+ */
776
+ export declare class TimeoutError extends TimeoutErrorBase<{
777
+ readonly operation: string;
778
+ readonly duration: number;
779
+ readonly message: string;
780
+ }> {
781
+ }
782
+
783
+ /**
784
+ * @internal
785
+ * Exported for declaration bundling (api-extractor). When `export *` re-exports
786
+ * a class whose `extends` expression is an inline call like
787
+ * `Data.TaggedError(...)`, TypeScript emits an un-nameable `_base` symbol in
788
+ * the declaration file. Splitting the base into a named export gives the
789
+ * bundler a stable reference.
790
+ *
791
+ * @privateRemarks
792
+ * This base constant must remain a named export so that api-extractor can
793
+ * resolve the extends clause of {@link TimeoutError} to a stable
794
+ * declaration. Without it the bundled `.d.ts` would contain an anonymous
795
+ * `_base` symbol that cannot be referenced by downstream consumers.
796
+ */
797
+ export declare const TimeoutErrorBase: new <A extends Record<string, any> = {}>(args: Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => YieldableError & {
798
+ readonly _tag: "TimeoutError";
799
+ } & Readonly<A>;
800
+
801
+ /**
802
+ * Effect service interface for import resolution using `package.json` metadata.
803
+ *
804
+ * @remarks
805
+ * Resolution is attempted in the following order:
806
+ *
807
+ * 1. **`exports`** -- the `"types"` condition inside the package's exports map.
808
+ * 2. **`typesVersions`** -- the `"*"` entry of `typesVersions` with wildcard
809
+ * matching.
810
+ * 3. **`types` / `typings`** -- top-level fields pointing at the main
811
+ * declaration file.
812
+ * 4. **Conventional** -- extension swapping (`.js` to `.d.ts`) and
813
+ * `index.d.ts` fallback.
814
+ *
815
+ * @example
816
+ * ```typescript
817
+ * import { Effect } from "effect";
818
+ * import { TypeResolver } from "type-registry-effect";
819
+ * import type { PackageJson } from "type-registry-effect";
820
+ * import type { PackageSpec } from "type-registry-effect";
821
+ *
822
+ * const program = Effect.gen(function* () {
823
+ * const resolver = yield* TypeResolver;
824
+ * const resolved = yield* resolver.resolveMainEntry(
825
+ * { name: "lodash", version: "4.17.21" } as unknown as PackageJson,
826
+ * { name: "lodash", version: "4.17.21" } as PackageSpec,
827
+ * );
828
+ * console.log("main types:", resolved.filePath);
829
+ * });
830
+ * ```
831
+ *
832
+ * @see {@link TypeResolverLive}
833
+ *
834
+ * @public
835
+ */
836
+ export declare interface TypeResolver {
837
+ /**
838
+ * Resolve a bare or deep-import specifier to a type definition path within
839
+ * the package.
840
+ */
841
+ readonly resolveImport: (specifier: string, packageJson: PackageJson, pkg: PackageSpec) => Effect.Effect<ResolvedModule, ResolutionError>;
842
+ /**
843
+ * Resolve the main (root `"."`) type entry point for a package.
844
+ */
845
+ readonly resolveMainEntry: (packageJson: PackageJson, pkg: PackageSpec) => Effect.Effect<ResolvedModule, ResolutionError>;
846
+ /**
847
+ * Collect all type entry points declared by the package, including the main
848
+ * entry and any additional sub-path exports that expose types.
849
+ */
850
+ readonly resolveTypeEntries: (packageJson: PackageJson, pkg: PackageSpec) => Effect.Effect<ReadonlyArray<ResolvedModule>, ResolutionError>;
851
+ /**
852
+ * Given a JavaScript file path, derive the corresponding `.d.ts` / `.d.mts`
853
+ * / `.d.cts` path. Returns `null` when no type definition can be inferred.
854
+ */
855
+ readonly findTypeDefinition: (jsFilePath: string, packageJson: PackageJson, pkg: PackageSpec) => Effect.Effect<ResolvedModule | null, ResolutionError>;
856
+ }
857
+
858
+ /**
859
+ * Effect Context tag for the {@link TypeResolver} service.
860
+ *
861
+ * @see {@link TypeResolverLive}
862
+ */
863
+ export declare const TypeResolver: Context.Tag<TypeResolver, TypeResolver>;
864
+
865
+ /**
866
+ * A `Map<string, string>` that maps virtual file paths to their contents.
867
+ *
868
+ * @remarks
869
+ * Keys are prefixed with `node_modules/` so the map can be fed directly into
870
+ * an in-memory TypeScript compiler host. Values are the UTF-8 file contents
871
+ * (typically `.d.ts` declarations).
872
+ *
873
+ * @example
874
+ * ```typescript
875
+ * import type { VirtualFileSystem } from "type-registry-effect";
876
+ *
877
+ * const vfs: VirtualFileSystem = new Map([
878
+ * ["node_modules/lodash/index.d.ts", "declare module 'lodash' { ... }"],
879
+ * ]);
880
+ * ```
881
+ *
882
+ * @see {@link CacheService}
883
+ *
884
+ * @public
885
+ */
886
+ export declare type VirtualFileSystem = Map<string, string>;
887
+
888
+ export { VirtualTypeScriptEnvironment }
889
+
890
+ export { }