runtime-resolver 0.3.22 → 1.0.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.
Files changed (68) hide show
  1. package/README.md +34 -35
  2. package/bin/runtime-resolver.js +12 -31
  3. package/command.js +120 -0
  4. package/layers.js +61 -0
  5. package/output.js +55 -0
  6. package/package.json +6 -18
  7. package/report.js +24 -0
  8. package/cli/commands/resolve.js +0 -242
  9. package/cli/schemas/json-schema.js +0 -12
  10. package/cli/schemas/response.js +0 -86
  11. package/data/bun-defaults.js +0 -850
  12. package/data/deno-defaults.js +0 -1538
  13. package/data/node-defaults.js +0 -4435
  14. package/errors/AuthenticationError.js +0 -35
  15. package/errors/CacheError.js +0 -32
  16. package/errors/FreshnessError.js +0 -38
  17. package/errors/InvalidInputError.js +0 -33
  18. package/errors/NetworkError.js +0 -34
  19. package/errors/ParseError.js +0 -33
  20. package/errors/RateLimitError.js +0 -37
  21. package/errors/VersionNotFoundError.js +0 -37
  22. package/index.d.ts +0 -2574
  23. package/index.js +0 -166
  24. package/layers/AutoBunCacheLive.js +0 -47
  25. package/layers/AutoDenoCacheLive.js +0 -47
  26. package/layers/AutoNodeCacheLive.js +0 -58
  27. package/layers/BunReleaseCacheLive.js +0 -25
  28. package/layers/BunResolverLive.js +0 -85
  29. package/layers/BunVersionFetcherLive.js +0 -55
  30. package/layers/DenoReleaseCacheLive.js +0 -25
  31. package/layers/DenoResolverLive.js +0 -84
  32. package/layers/DenoVersionFetcherLive.js +0 -51
  33. package/layers/FreshBunCacheLive.js +0 -60
  34. package/layers/FreshDenoCacheLive.js +0 -60
  35. package/layers/FreshNodeCacheLive.js +0 -55
  36. package/layers/GitHubAppAuth.js +0 -58
  37. package/layers/GitHubAutoAuth.js +0 -70
  38. package/layers/GitHubClientLive.js +0 -130
  39. package/layers/GitHubTokenAuth.js +0 -50
  40. package/layers/NodeReleaseCacheLive.js +0 -77
  41. package/layers/NodeResolverLive.js +0 -107
  42. package/layers/NodeScheduleFetcherLive.js +0 -37
  43. package/layers/NodeVersionFetcherLive.js +0 -55
  44. package/layers/OfflineBunCacheLive.js +0 -40
  45. package/layers/OfflineDenoCacheLive.js +0 -40
  46. package/layers/OfflineNodeCacheLive.js +0 -39
  47. package/layers/RuntimeCacheLive.js +0 -78
  48. package/lib/retry.js +0 -27
  49. package/lib/semver.js +0 -21
  50. package/schemas/bun-release.js +0 -63
  51. package/schemas/deno-release.js +0 -63
  52. package/schemas/github.js +0 -74
  53. package/schemas/node-release.js +0 -133
  54. package/schemas/node-schedule.js +0 -110
  55. package/schemas/node.js +0 -68
  56. package/services/BunReleaseCache.js +0 -33
  57. package/services/BunResolver.js +0 -36
  58. package/services/BunVersionFetcher.js +0 -41
  59. package/services/DenoReleaseCache.js +0 -33
  60. package/services/DenoResolver.js +0 -36
  61. package/services/DenoVersionFetcher.js +0 -41
  62. package/services/GitHubClient.js +0 -40
  63. package/services/NodeReleaseCache.js +0 -41
  64. package/services/NodeResolver.js +0 -44
  65. package/services/NodeScheduleFetcher.js +0 -38
  66. package/services/NodeVersionFetcher.js +0 -39
  67. package/services/OctokitInstance.js +0 -44
  68. package/tsdoc-metadata.json +0 -11
@@ -1,37 +0,0 @@
1
- import { NodeScheduleFetcher } from "../services/NodeScheduleFetcher.js";
2
- import { GitHubClient } from "../services/GitHubClient.js";
3
- import { ParseError } from "../errors/ParseError.js";
4
- import { NodeReleaseSchedule } from "../schemas/node.js";
5
- import { Effect, Layer, Schema } from "effect";
6
-
7
- //#region src/layers/NodeScheduleFetcherLive.ts
8
- const NODE_SCHEDULE_URL = "https://raw.githubusercontent.com/nodejs/Release/refs/heads/main/schedule.json";
9
- const decodeSchedule = (input) => Schema.decodeUnknown(NodeReleaseSchedule)(input).pipe(Effect.mapError((e) => new ParseError({
10
- source: NODE_SCHEDULE_URL,
11
- message: `Schema validation failed: ${e.message}`
12
- })), Effect.map((data) => data));
13
- /**
14
- * Provides the {@link NodeScheduleFetcher} service using the live Node.js release schedule.
15
- *
16
- * Fetches the Node.js release schedule from the raw GitHub content URL for
17
- * `nodejs/Release` (`schedule.json` on the `main` branch) using the HTTP client
18
- * on the provided {@link GitHubClient} service. The schedule data maps major
19
- * version codenames to their start, LTS, and end-of-life dates and is used by
20
- * {@link NodeReleaseCache} to compute per-release lifecycle phases.
21
- *
22
- * This layer is a required dependency of {@link AutoNodeCacheLive} and
23
- * {@link FreshNodeCacheLive}. It is not needed by {@link OfflineNodeCacheLive}.
24
- *
25
- * @see {@link NodeScheduleFetcher}
26
- * @see {@link GitHubClient}
27
- * @see {@link AutoNodeCacheLive}
28
- * @see {@link FreshNodeCacheLive}
29
- * @public
30
- */
31
- const NodeScheduleFetcherLive = Layer.effect(NodeScheduleFetcher, Effect.gen(function* () {
32
- const client = yield* GitHubClient;
33
- return { fetch: () => client.getJson(NODE_SCHEDULE_URL, { decode: decodeSchedule }) };
34
- }));
35
-
36
- //#endregion
37
- export { NodeScheduleFetcherLive };
@@ -1,55 +0,0 @@
1
- import { NodeVersionFetcher } from "../services/NodeVersionFetcher.js";
2
- import { tryParseSemVer } from "../lib/semver.js";
3
- import { GitHubClient } from "../services/GitHubClient.js";
4
- import { ParseError } from "../errors/ParseError.js";
5
- import { NodeDistIndex } from "../schemas/node.js";
6
- import { Effect, Layer, Option, Schema } from "effect";
7
-
8
- //#region src/layers/NodeVersionFetcherLive.ts
9
- const NODE_DIST_URL = "https://nodejs.org/dist/index.json";
10
- const decodeDistIndex = (input) => Schema.decodeUnknown(NodeDistIndex)(input).pipe(Effect.mapError((e) => new ParseError({
11
- source: NODE_DIST_URL,
12
- message: `Schema validation failed: ${e.message}`
13
- })));
14
- /**
15
- * Provides the {@link NodeVersionFetcher} service using the live Node.js dist index.
16
- *
17
- * Fetches the full Node.js version list from `https://nodejs.org/dist/index.json`
18
- * using the HTTP client on the provided {@link GitHubClient} service. Version
19
- * strings are normalized by stripping the leading `v` before parsing as semver.
20
- * Entries with non-string `npm` fields (present in very old releases prior to
21
- * v0.6.3) are substituted with the sentinel version `"0.0.0"`.
22
- *
23
- * This layer is a required dependency of {@link AutoNodeCacheLive} and
24
- * {@link FreshNodeCacheLive}. It is not needed by {@link OfflineNodeCacheLive}.
25
- *
26
- * @see {@link NodeVersionFetcher}
27
- * @see {@link GitHubClient}
28
- * @see {@link AutoNodeCacheLive}
29
- * @see {@link FreshNodeCacheLive}
30
- * @public
31
- */
32
- const NodeVersionFetcherLive = Layer.effect(NodeVersionFetcher, Effect.gen(function* () {
33
- const client = yield* GitHubClient;
34
- return { fetch: () => Effect.gen(function* () {
35
- const allVersions = yield* client.getJson(NODE_DIST_URL, { decode: decodeDistIndex });
36
- const parsed = yield* Effect.forEach(allVersions, (entry) => {
37
- const clean = entry.version.replace(/^v/, "");
38
- return tryParseSemVer(clean).pipe(Effect.map((opt) => Option.isSome(opt) ? Option.some({
39
- version: opt.value,
40
- input: {
41
- version: clean,
42
- npm: typeof entry.npm === "string" ? entry.npm : "0.0.0",
43
- date: entry.date
44
- }
45
- }) : Option.none()));
46
- }, { concurrency: "unbounded" });
47
- return {
48
- versions: parsed.flatMap(Option.toArray).map(({ version }) => version),
49
- inputs: parsed.flatMap(Option.toArray).map(({ input }) => input)
50
- };
51
- }) };
52
- }));
53
-
54
- //#endregion
55
- export { NodeVersionFetcherLive };
@@ -1,40 +0,0 @@
1
- import { bunDefaultInputs } from "../data/bun-defaults.js";
2
- import { BunRelease } from "../schemas/bun-release.js";
3
- import { BunReleaseCache } from "../services/BunReleaseCache.js";
4
- import { BunReleaseCacheLive } from "./BunReleaseCacheLive.js";
5
- import { Effect, Layer } from "effect";
6
- import { SemVerParserLive, VersionCacheLive } from "semver-effect";
7
-
8
- //#region src/layers/OfflineBunCacheLive.ts
9
- const offlineSetup = Effect.gen(function* () {
10
- const cache = yield* BunReleaseCache;
11
- const releases = yield* Effect.all(bunDefaultInputs.map((input) => BunRelease.fromInput(input)), { concurrency: "unbounded" }).pipe(Effect.orElseSucceed(() => []));
12
- yield* cache.load(releases);
13
- });
14
- const SemVerLayer = VersionCacheLive.pipe(Layer.provide(SemVerParserLive));
15
- const BaseCacheLayer = BunReleaseCacheLive.pipe(Layer.provide(SemVerLayer));
16
- /**
17
- * Provides the {@link BunReleaseCache} service using the "Offline" cache strategy.
18
- *
19
- * Uses only the bundled default Bun release data that was baked in at build time.
20
- * Makes no network requests and has no runtime dependencies. This layer always
21
- * succeeds immediately.
22
- *
23
- * Use this strategy in environments where network access is unavailable or
24
- * undesirable (e.g., air-gapped systems, hermetic test environments, or any
25
- * context where version data from the bundle is sufficient).
26
- *
27
- * The three Bun cache strategy layers are:
28
- * - {@link AutoBunCacheLive} — tries API first, falls back to bundled defaults on any error
29
- * - {@link FreshBunCacheLive} — requires live API data, fails with `FreshnessError` if unavailable
30
- * - `OfflineBunCacheLive` — uses only bundled defaults, no network I/O
31
- *
32
- * @see {@link BunReleaseCache}
33
- * @see {@link AutoBunCacheLive}
34
- * @see {@link FreshBunCacheLive}
35
- * @public
36
- */
37
- const OfflineBunCacheLive = BaseCacheLayer.pipe(Layer.tap((ctx) => offlineSetup.pipe(Effect.provide(ctx))));
38
-
39
- //#endregion
40
- export { OfflineBunCacheLive };
@@ -1,40 +0,0 @@
1
- import { denoDefaultInputs } from "../data/deno-defaults.js";
2
- import { DenoRelease } from "../schemas/deno-release.js";
3
- import { DenoReleaseCache } from "../services/DenoReleaseCache.js";
4
- import { DenoReleaseCacheLive } from "./DenoReleaseCacheLive.js";
5
- import { Effect, Layer } from "effect";
6
- import { SemVerParserLive, VersionCacheLive } from "semver-effect";
7
-
8
- //#region src/layers/OfflineDenoCacheLive.ts
9
- const offlineSetup = Effect.gen(function* () {
10
- const cache = yield* DenoReleaseCache;
11
- const releases = yield* Effect.all(denoDefaultInputs.map((input) => DenoRelease.fromInput(input)), { concurrency: "unbounded" }).pipe(Effect.orElseSucceed(() => []));
12
- yield* cache.load(releases);
13
- });
14
- const SemVerLayer = VersionCacheLive.pipe(Layer.provide(SemVerParserLive));
15
- const BaseCacheLayer = DenoReleaseCacheLive.pipe(Layer.provide(SemVerLayer));
16
- /**
17
- * Provides the {@link DenoReleaseCache} service using the "Offline" cache strategy.
18
- *
19
- * Uses only the bundled default Deno release data that was baked in at build time.
20
- * Makes no network requests and has no runtime dependencies. This layer always
21
- * succeeds immediately.
22
- *
23
- * Use this strategy in environments where network access is unavailable or
24
- * undesirable (e.g., air-gapped systems, hermetic test environments, or any
25
- * context where version data from the bundle is sufficient).
26
- *
27
- * The three Deno cache strategy layers are:
28
- * - {@link AutoDenoCacheLive} — tries API first, falls back to bundled defaults on any error
29
- * - {@link FreshDenoCacheLive} — requires live API data, fails with `FreshnessError` if unavailable
30
- * - `OfflineDenoCacheLive` — uses only bundled defaults, no network I/O
31
- *
32
- * @see {@link DenoReleaseCache}
33
- * @see {@link AutoDenoCacheLive}
34
- * @see {@link FreshDenoCacheLive}
35
- * @public
36
- */
37
- const OfflineDenoCacheLive = BaseCacheLayer.pipe(Layer.tap((ctx) => offlineSetup.pipe(Effect.provide(ctx))));
38
-
39
- //#endregion
40
- export { OfflineDenoCacheLive };
@@ -1,39 +0,0 @@
1
- import { nodeDefaultInputs, nodeDefaultScheduleData } from "../data/node-defaults.js";
2
- import { NodeReleaseCache } from "../services/NodeReleaseCache.js";
3
- import { NodeReleaseCacheLive } from "./NodeReleaseCacheLive.js";
4
- import { Effect, Layer } from "effect";
5
- import { SemVerParserLive, VersionCacheLive } from "semver-effect";
6
-
7
- //#region src/layers/OfflineNodeCacheLive.ts
8
- const offlineSetup = Effect.gen(function* () {
9
- const cache = yield* NodeReleaseCache;
10
- yield* cache.updateSchedule(nodeDefaultScheduleData);
11
- yield* cache.loadFromInputs(nodeDefaultInputs);
12
- });
13
- const SemVerLayer = VersionCacheLive.pipe(Layer.provide(SemVerParserLive));
14
- const BaseCacheLayer = NodeReleaseCacheLive.pipe(Layer.provide(SemVerLayer));
15
- /**
16
- * Provides the {@link NodeReleaseCache} service using the "Offline" cache strategy.
17
- *
18
- * Uses only the bundled default Node.js release data and schedule data that were
19
- * baked in at build time. Makes no network requests and has no runtime
20
- * dependencies. This layer always succeeds immediately.
21
- *
22
- * Use this strategy in environments where network access is unavailable or
23
- * undesirable (e.g., air-gapped systems, hermetic test environments, or any
24
- * context where version data from the bundle is sufficient).
25
- *
26
- * The three Node cache strategy layers are:
27
- * - {@link AutoNodeCacheLive} — tries API first, falls back to bundled defaults on any error
28
- * - {@link FreshNodeCacheLive} — requires live API data, fails with `FreshnessError` if unavailable
29
- * - `OfflineNodeCacheLive` — uses only bundled defaults, no network I/O
30
- *
31
- * @see {@link NodeReleaseCache}
32
- * @see {@link AutoNodeCacheLive}
33
- * @see {@link FreshNodeCacheLive}
34
- * @public
35
- */
36
- const OfflineNodeCacheLive = BaseCacheLayer.pipe(Layer.tap((ctx) => offlineSetup.pipe(Effect.provide(ctx))));
37
-
38
- //#endregion
39
- export { OfflineNodeCacheLive };
@@ -1,78 +0,0 @@
1
- import { Effect } from "effect";
2
- import { Range, VersionCache } from "semver-effect";
3
-
4
- //#region src/layers/RuntimeCacheLive.ts
5
- /**
6
- * Factory that creates a {@link RuntimeCache} implementation backed by
7
- * `semver-effect`'s `VersionCache`.
8
- *
9
- * The returned `Effect` must be executed within an Effect context that provides
10
- * a `SemVerVersionCache` service (i.e., it requires `SemVerVersionCache` in its
11
- * environment). The cache maintains an internal lookup map from version string
12
- * to the full release object so that resolved semver versions can be
13
- * round-tripped back to their typed release records.
14
- *
15
- * This factory is used internally by {@link BunReleaseCacheLive},
16
- * {@link DenoReleaseCacheLive}, and {@link NodeReleaseCacheLive} to build their
17
- * respective cache service implementations. Prefer those higher-level layers
18
- * over calling this factory directly.
19
- *
20
- * Note: `load` is not concurrency-safe. Callers must not invoke it concurrently.
21
- * In practice this constraint is upheld because `load` is only called from layer
22
- * setup and `NodeReleaseCacheLive.loadFromInputs`, both of which are serialized
23
- * by the Effect runtime.
24
- *
25
- * @typeParam R - The runtime release type stored in the cache. Must extend
26
- * {@link RuntimeRelease}.
27
- *
28
- * @see {@link RuntimeCache}
29
- * @see {@link BunReleaseCacheLive}
30
- * @see {@link DenoReleaseCacheLive}
31
- * @see {@link NodeReleaseCacheLive}
32
- * @public
33
- */
34
- const createRuntimeCache = () => Effect.gen(function* () {
35
- const innerCache = yield* VersionCache;
36
- const lookupMap = /* @__PURE__ */ new Map();
37
- return {
38
- load: (releases) => Effect.gen(function* () {
39
- lookupMap.clear();
40
- const versions = [];
41
- for (const r of releases) {
42
- const key = r.version.toString();
43
- lookupMap.set(key, r);
44
- versions.push(r.version);
45
- }
46
- yield* innerCache.load(versions);
47
- }),
48
- resolve: (range) => Effect.gen(function* () {
49
- const parsed = yield* Range.parse(range);
50
- const resolved = yield* innerCache.resolve(parsed);
51
- const release = lookupMap.get(resolved.toString());
52
- if (!release) return yield* Effect.die(/* @__PURE__ */ new Error(`Cache inconsistency: ${resolved.toString()} not in lookup map`));
53
- return release;
54
- }),
55
- releases: () => Effect.gen(function* () {
56
- return (yield* innerCache.versions.pipe(Effect.catchTag("EmptyCacheError", () => Effect.succeed([])))).map((v) => lookupMap.get(v.toString())).filter((r) => r !== void 0);
57
- }),
58
- filter: (range) => Effect.gen(function* () {
59
- const parsed = yield* Range.parse(range);
60
- return (yield* innerCache.filter(parsed).pipe(Effect.catchTag("EmptyCacheError", () => Effect.succeed([])))).map((v) => lookupMap.get(v.toString())).filter((r) => r !== void 0);
61
- }),
62
- latest: () => Effect.gen(function* () {
63
- const version = yield* innerCache.latest();
64
- const release = lookupMap.get(version.toString());
65
- if (!release) return yield* Effect.die(/* @__PURE__ */ new Error(`Cache inconsistency: ${version.toString()} not in lookup map`));
66
- return release;
67
- }),
68
- latestByMajor: () => Effect.gen(function* () {
69
- return (yield* innerCache.latestByMajor().pipe(Effect.catchTag("EmptyCacheError", () => Effect.succeed([])))).map((v) => lookupMap.get(v.toString())).filter((r) => r !== void 0);
70
- }),
71
- latestByMinor: () => Effect.gen(function* () {
72
- return (yield* innerCache.latestByMinor().pipe(Effect.catchTag("EmptyCacheError", () => Effect.succeed([])))).map((v) => lookupMap.get(v.toString())).filter((r) => r !== void 0);
73
- })
74
- };
75
- });
76
-
77
- //#endregion
78
- export { createRuntimeCache };
package/lib/retry.js DELETED
@@ -1,27 +0,0 @@
1
- import { Effect, Predicate, Schedule } from "effect";
2
-
3
- //#region src/lib/retry.ts
4
- /**
5
- * Wraps an effect with automatic retry logic for {@link RateLimitError}.
6
- *
7
- * When the wrapped effect fails with a `RateLimitError` the retry schedule
8
- * applies exponential backoff starting at a 1-second base delay, doubling on
9
- * each attempt, for a maximum of 3 retries. Errors with any other tag are
10
- * re-raised immediately without retrying.
11
- *
12
- * The predicate used for the `while` condition is
13
- * `Predicate.isTagged("RateLimitError")`, so only errors whose `_tag` field
14
- * equals `"RateLimitError"` trigger a retry; all other error types propagate
15
- * unchanged.
16
- *
17
- * @see {@link RateLimitError}
18
- *
19
- * @internal
20
- */
21
- const retryOnRateLimit = (effect) => effect.pipe(Effect.retry({
22
- schedule: Schedule.exponential("1 second").pipe(Schedule.compose(Schedule.recurs(3))),
23
- while: Predicate.isTagged("RateLimitError")
24
- }));
25
-
26
- //#endregion
27
- export { retryOnRateLimit };
package/lib/semver.js DELETED
@@ -1,21 +0,0 @@
1
- import { Effect, Option } from "effect";
2
- import { SemVer } from "semver-effect";
3
-
4
- //#region src/lib/semver.ts
5
- /**
6
- * Attempts to parse a raw version string into a {@link SemVer}, returning
7
- * `Option.none()` when the string is not a valid semver value.
8
- *
9
- * Unlike `SemVer.parse` — which fails the effect on an unparseable input —
10
- * this helper absorbs parse failures and promotes them into the `Option` channel
11
- * so that callers can handle invalid versions without short-circuiting the
12
- * surrounding effect pipeline.
13
- *
14
- * @see {@link SemVer.parse}
15
- *
16
- * @internal
17
- */
18
- const tryParseSemVer = (raw) => SemVer.parse(raw).pipe(Effect.map(Option.some), Effect.catchAll(() => Effect.succeed(Option.none())));
19
-
20
- //#endregion
21
- export { tryParseSemVer };
@@ -1,63 +0,0 @@
1
- import { Data, DateTime, Effect } from "effect";
2
- import { SemVer } from "semver-effect";
3
-
4
- //#region src/schemas/bun-release.ts
5
- /**
6
- * A Bun release entry with a parsed `SemVer` version and an
7
- * Effect `DateTime.DateTime` publication date.
8
- *
9
- * `BunRelease` extends `Data.TaggedClass` so instances support structural
10
- * equality comparison and can be used safely inside Effect data structures.
11
- * Construct instances via the {@link BunRelease.fromInput} factory rather than
12
- * calling `new BunRelease(...)` directly, as the factory validates the version
13
- * string through `SemVer.parse`.
14
- *
15
- * @see {@link BunReleaseCache}
16
- * @see {@link BunResolver}
17
- * @see `RuntimeReleaseInput`
18
- *
19
- * @example
20
- * ```typescript
21
- * import { Effect } from "effect";
22
- * import type { BunRelease } from "./bun-release.js";
23
- * import { BunRelease as BunReleaseClass } from "./bun-release.js";
24
- *
25
- * const program = BunReleaseClass.fromInput({ version: "1.1.0", date: "2024-03-01" }).pipe(
26
- * Effect.map((release: BunRelease) => {
27
- * console.log(release.version.major); // 1
28
- * console.log(release.version.minor); // 1
29
- * console.log(release._tag); // "BunRelease"
30
- * }),
31
- * );
32
- *
33
- * Effect.runPromise(program);
34
- * ```
35
- *
36
- * @public
37
- */
38
- var BunRelease = class BunRelease extends Data.TaggedClass("BunRelease") {
39
- /**
40
- * Create a {@link BunRelease} from lean string inputs.
41
- *
42
- * Parses `input.version` via `SemVer.parse` and constructs the
43
- * publication date with `DateTime.unsafeMake`. Falls back to the current
44
- * timestamp when `input.date` is an empty string (rare in production data).
45
- *
46
- * @param input - A `RuntimeReleaseInput` object with raw string fields.
47
- * @returns An `Effect` that succeeds with a `BunRelease` or fails with an
48
- * `InvalidVersionError` when the version string cannot be parsed.
49
- */
50
- static fromInput(input) {
51
- return Effect.gen(function* () {
52
- const version = yield* SemVer.parse(input.version);
53
- const date = input.date ? DateTime.unsafeMake(input.date) : DateTime.unsafeMake(/* @__PURE__ */ new Date());
54
- return new BunRelease({
55
- version,
56
- date
57
- });
58
- });
59
- }
60
- };
61
-
62
- //#endregion
63
- export { BunRelease };
@@ -1,63 +0,0 @@
1
- import { Data, DateTime, Effect } from "effect";
2
- import { SemVer } from "semver-effect";
3
-
4
- //#region src/schemas/deno-release.ts
5
- /**
6
- * A Deno release entry with a parsed `SemVer` version and an
7
- * Effect `DateTime.DateTime` publication date.
8
- *
9
- * `DenoRelease` extends `Data.TaggedClass` so instances support structural
10
- * equality comparison and can be used safely inside Effect data structures.
11
- * Construct instances via the {@link DenoRelease.fromInput} factory rather than
12
- * calling `new DenoRelease(...)` directly, as the factory validates the version
13
- * string through `SemVer.parse`.
14
- *
15
- * @see {@link DenoReleaseCache}
16
- * @see {@link DenoResolver}
17
- * @see `RuntimeReleaseInput`
18
- *
19
- * @example
20
- * ```typescript
21
- * import { Effect } from "effect";
22
- * import type { DenoRelease } from "./deno-release.js";
23
- * import { DenoRelease as DenoReleaseClass } from "./deno-release.js";
24
- *
25
- * const program = DenoReleaseClass.fromInput({ version: "1.44.0", date: "2024-05-23" }).pipe(
26
- * Effect.map((release: DenoRelease) => {
27
- * console.log(release.version.major); // 1
28
- * console.log(release.version.minor); // 44
29
- * console.log(release._tag); // "DenoRelease"
30
- * }),
31
- * );
32
- *
33
- * Effect.runPromise(program);
34
- * ```
35
- *
36
- * @public
37
- */
38
- var DenoRelease = class DenoRelease extends Data.TaggedClass("DenoRelease") {
39
- /**
40
- * Create a {@link DenoRelease} from lean string inputs.
41
- *
42
- * Parses `input.version` via `SemVer.parse` and constructs the
43
- * publication date with `DateTime.unsafeMake`. Falls back to the current
44
- * timestamp when `input.date` is an empty string (rare in production data).
45
- *
46
- * @param input - A `RuntimeReleaseInput` object with raw string fields.
47
- * @returns An `Effect` that succeeds with a `DenoRelease` or fails with an
48
- * `InvalidVersionError` when the version string cannot be parsed.
49
- */
50
- static fromInput(input) {
51
- return Effect.gen(function* () {
52
- const version = yield* SemVer.parse(input.version);
53
- const date = input.date ? DateTime.unsafeMake(input.date) : DateTime.unsafeMake(/* @__PURE__ */ new Date());
54
- return new DenoRelease({
55
- version,
56
- date
57
- });
58
- });
59
- }
60
- };
61
-
62
- //#endregion
63
- export { DenoRelease };
package/schemas/github.js DELETED
@@ -1,74 +0,0 @@
1
- import { Schema } from "effect";
2
-
3
- //#region src/schemas/github.ts
4
- /**
5
- * The `commit` sub-object returned for each entry in the GitHub tags API.
6
- *
7
- * Used as a nested field within {@link GitHubTag}.
8
- *
9
- * @see {@link GitHubClient}
10
- *
11
- * @public
12
- */
13
- const GitHubTagCommit = Schema.Struct({
14
- sha: Schema.String,
15
- url: Schema.String
16
- });
17
- /**
18
- * A single tag entry as returned by the GitHub REST API
19
- * (`GET /repos/{owner}/{repo}/tags`).
20
- *
21
- * Consumed by {@link GitHubClient} when fetching Bun and Deno release tags.
22
- *
23
- * @see {@link GitHubClient}
24
- * @see `GitHubTagList`
25
- *
26
- * @public
27
- */
28
- const GitHubTag = Schema.Struct({
29
- name: Schema.String,
30
- zipball_url: Schema.String,
31
- tarball_url: Schema.String,
32
- commit: GitHubTagCommit,
33
- node_id: Schema.String
34
- });
35
- /**
36
- * The decoded response body from `GET /repos/{owner}/{repo}/tags`.
37
- *
38
- * @see {@link GitHubClient}
39
- * @see {@link GitHubTag}
40
- *
41
- * @public
42
- */
43
- const GitHubTagList = Schema.Array(GitHubTag);
44
- /**
45
- * A single release entry as returned by the GitHub REST API
46
- * (`GET /repos/{owner}/{repo}/releases`).
47
- *
48
- * Consumed by {@link GitHubClient} when fetching Deno releases that carry
49
- * publication timestamps.
50
- *
51
- * @see {@link GitHubClient}
52
- * @see `GitHubReleaseList`
53
- *
54
- * @public
55
- */
56
- const GitHubRelease = Schema.Struct({
57
- tag_name: Schema.String,
58
- name: Schema.NullOr(Schema.String),
59
- draft: Schema.Boolean,
60
- prerelease: Schema.Boolean,
61
- published_at: Schema.NullOr(Schema.String)
62
- });
63
- /**
64
- * The decoded response body from `GET /repos/{owner}/{repo}/releases`.
65
- *
66
- * @see {@link GitHubClient}
67
- * @see {@link GitHubRelease}
68
- *
69
- * @public
70
- */
71
- const GitHubReleaseList = Schema.Array(GitHubRelease);
72
-
73
- //#endregion
74
- export { GitHubRelease, GitHubReleaseList, GitHubTag, GitHubTagCommit, GitHubTagList };
@@ -1,133 +0,0 @@
1
- import { DateTime, Effect, Ref, Schema } from "effect";
2
- import { SemVer } from "semver-effect";
3
-
4
- //#region src/schemas/node-release.ts
5
- /**
6
- * Lean input schema used to construct {@link NodeRelease} instances from
7
- * bundled default data files and the Node.js dist API response.
8
- *
9
- * The `version` and `npm` fields are raw version strings validated by
10
- * `SemVer.parse`; `date` is a date string accepted by
11
- * `DateTime.unsafeMake`.
12
- *
13
- * @see {@link NodeRelease.fromInput}
14
- * @see {@link NodeVersionFetcher}
15
- *
16
- * @public
17
- */
18
- const NodeReleaseInput = Schema.Struct({
19
- version: Schema.String,
20
- npm: Schema.String,
21
- date: Schema.String
22
- });
23
- /**
24
- * A Node.js release entry with parsed version, bundled npm version,
25
- * publication date, and a shared reference to the Node.js release schedule.
26
- *
27
- * `NodeRelease` is a plain class rather than a `Data.TaggedClass` because it
28
- * holds a `Ref<NodeSchedule>` — mutable Effect references break structural
29
- * equality semantics, making `Data.TaggedClass` unsuitable here. The
30
- * `_tag` field is set manually to preserve tagged-union compatibility.
31
- *
32
- * Use {@link NodeRelease.fromInput} to construct instances; call
33
- * {@link NodeRelease.phase} or {@link NodeRelease.lts} to query the lifecycle
34
- * state of the release at a given point in time.
35
- *
36
- * @see {@link NodeReleaseCache}
37
- * @see {@link NodeResolver}
38
- * @see {@link NodeSchedule}
39
- *
40
- * @example
41
- * ```typescript
42
- * import { Effect, Ref } from "effect";
43
- * import type { NodePhase } from "./common.js";
44
- * import type { NodeRelease } from "./node-release.js";
45
- * import { NodeRelease as NodeReleaseClass } from "./node-release.js";
46
- * import { NodeSchedule } from "./node-schedule.js";
47
- *
48
- * const program = Effect.gen(function* () {
49
- * const schedule = NodeSchedule.fromData({
50
- * v20: { start: "2023-04-18", lts: "2023-10-24", end: "2026-04-30" },
51
- * });
52
- * const scheduleRef = yield* Ref.make(schedule);
53
- *
54
- * const release: NodeRelease = yield* NodeReleaseClass.fromInput(
55
- * { version: "v20.0.0", npm: "9.6.4", date: "2023-04-18" },
56
- * scheduleRef,
57
- * );
58
- *
59
- * const phase: NodePhase | null = yield* release.phase();
60
- * const isLts: boolean = yield* release.lts();
61
- * console.log(phase); // e.g. "active-lts"
62
- * console.log(isLts); // true
63
- * });
64
- *
65
- * Effect.runPromise(program);
66
- * ```
67
- *
68
- * @public
69
- */
70
- var NodeRelease = class NodeRelease {
71
- version;
72
- npm;
73
- date;
74
- scheduleRef;
75
- _tag = "NodeRelease";
76
- constructor(version, npm, date, scheduleRef) {
77
- this.version = version;
78
- this.npm = npm;
79
- this.date = date;
80
- this.scheduleRef = scheduleRef;
81
- }
82
- /**
83
- * Determine this release's lifecycle phase at the given point in time.
84
- *
85
- * Reads the current value of the shared `scheduleRef` and delegates to
86
- * {@link NodeSchedule.phaseFor}. Defaults to the current wall-clock time
87
- * when `now` is omitted.
88
- *
89
- * @param now - Optional reference time; defaults to `new Date()`.
90
- * @returns An `Effect` that resolves to a `NodePhase` string, or
91
- * `null` when the major version is not present in the schedule or has
92
- * not yet been released.
93
- */
94
- phase(now) {
95
- const effectiveNow = now ?? DateTime.unsafeMake(/* @__PURE__ */ new Date());
96
- return Effect.gen(this, function* () {
97
- return yield* (yield* Ref.get(this.scheduleRef)).phaseFor(this.version.major, effectiveNow);
98
- });
99
- }
100
- /**
101
- * Whether this release is currently in Long-Term Support.
102
- *
103
- * Returns `true` for both `"active-lts"` and `"maintenance-lts"` phases.
104
- * Defaults to the current wall-clock time when `now` is omitted.
105
- *
106
- * @param now - Optional reference time; defaults to `new Date()`.
107
- */
108
- lts(now) {
109
- return this.phase(now).pipe(Effect.map((p) => p === "active-lts" || p === "maintenance-lts"));
110
- }
111
- /**
112
- * Create a {@link NodeRelease} from lean string inputs.
113
- *
114
- * Parses `input.version` and `input.npm` via `SemVer.parse` and
115
- * constructs the publication date with `DateTime.unsafeMake`.
116
- *
117
- * @param input - A {@link (NodeReleaseInput:type)} object with raw string fields.
118
- * @param scheduleRef - A shared `Ref<NodeSchedule>` injected by the cache layer.
119
- * @returns An `Effect` that succeeds with a `NodeRelease` or fails with an
120
- * `InvalidVersionError` when either version string cannot be parsed.
121
- */
122
- static fromInput(input, scheduleRef) {
123
- return Effect.gen(function* () {
124
- const version = yield* SemVer.parse(input.version);
125
- const npm = yield* SemVer.parse(input.npm);
126
- const date = DateTime.unsafeMake(input.date);
127
- return new NodeRelease(version, npm, date, scheduleRef);
128
- });
129
- }
130
- };
131
-
132
- //#endregion
133
- export { NodeRelease };