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,242 +0,0 @@
1
- import { AutoBunCacheLive } from "../../layers/AutoBunCacheLive.js";
2
- import { AutoDenoCacheLive } from "../../layers/AutoDenoCacheLive.js";
3
- import { AutoNodeCacheLive } from "../../layers/AutoNodeCacheLive.js";
4
- import { BunResolver } from "../../services/BunResolver.js";
5
- import { BunResolverLive } from "../../layers/BunResolverLive.js";
6
- import { BunVersionFetcherLive } from "../../layers/BunVersionFetcherLive.js";
7
- import { DenoResolver } from "../../services/DenoResolver.js";
8
- import { DenoResolverLive } from "../../layers/DenoResolverLive.js";
9
- import { DenoVersionFetcherLive } from "../../layers/DenoVersionFetcherLive.js";
10
- import { GitHubAppAuth } from "../../layers/GitHubAppAuth.js";
11
- import { GitHubAutoAuth } from "../../layers/GitHubAutoAuth.js";
12
- import { GitHubClientLive } from "../../layers/GitHubClientLive.js";
13
- import { NodeResolver } from "../../services/NodeResolver.js";
14
- import { NodeResolverLive } from "../../layers/NodeResolverLive.js";
15
- import { NodeScheduleFetcherLive } from "../../layers/NodeScheduleFetcherLive.js";
16
- import { NodeVersionFetcherLive } from "../../layers/NodeVersionFetcherLive.js";
17
- import { GitHubTokenAuthFromToken } from "../../layers/GitHubTokenAuth.js";
18
- import { Console, Effect, Layer, Option } from "effect";
19
- import { Options } from "@effect/cli";
20
- import { readFileSync } from "node:fs";
21
-
22
- //#region src/cli/commands/resolve.ts
23
- /* v8 ignore start */
24
- const GitHubLayer = GitHubClientLive.pipe(Layer.provide(GitHubAutoAuth));
25
- const makeNodeLayer = (authOverride) => {
26
- const ghLayer = authOverride ? GitHubClientLive.pipe(Layer.provide(authOverride)) : GitHubLayer;
27
- const fetchersLayer = Layer.merge(NodeVersionFetcherLive.pipe(Layer.provide(ghLayer)), NodeScheduleFetcherLive.pipe(Layer.provide(ghLayer)));
28
- return NodeResolverLive.pipe(Layer.provide(AutoNodeCacheLive.pipe(Layer.provide(fetchersLayer))));
29
- };
30
- const makeBunLayer = (authOverride) => {
31
- const ghLayer = authOverride ? GitHubClientLive.pipe(Layer.provide(authOverride)) : GitHubLayer;
32
- return BunResolverLive.pipe(Layer.provide(AutoBunCacheLive.pipe(Layer.provide(BunVersionFetcherLive.pipe(Layer.provide(ghLayer))))));
33
- };
34
- const makeDenoLayer = (authOverride) => {
35
- const ghLayer = authOverride ? GitHubClientLive.pipe(Layer.provide(authOverride)) : GitHubLayer;
36
- return DenoResolverLive.pipe(Layer.provide(AutoDenoCacheLive.pipe(Layer.provide(DenoVersionFetcherLive.pipe(Layer.provide(ghLayer))))));
37
- };
38
- const SCHEMA_URL = "https://raw.githubusercontent.com/spencerbeggs/runtime-resolver/main/runtime-resolver.schema.json";
39
- const nodeOption = Options.text("node").pipe(Options.optional);
40
- const bunOption = Options.text("bun").pipe(Options.optional);
41
- const denoOption = Options.text("deno").pipe(Options.optional);
42
- const nodePhasesOption = Options.text("node-phases").pipe(Options.optional);
43
- const incrementsOption = Options.text("increments").pipe(Options.optional);
44
- const nodeDefaultOption = Options.text("node-default").pipe(Options.optional);
45
- const bunDefaultOption = Options.text("bun-default").pipe(Options.optional);
46
- const denoDefaultOption = Options.text("deno-default").pipe(Options.optional);
47
- const nodeDateOption = Options.text("node-date").pipe(Options.optional);
48
- const prettyOption = Options.boolean("pretty").pipe(Options.withDefault(false));
49
- const schemaOption = Options.boolean("schema").pipe(Options.withDefault(false));
50
- const tokenOption = Options.text("token").pipe(Options.optional);
51
- const appIdOption = Options.text("app-id").pipe(Options.optional);
52
- const appPrivateKeyOption = Options.text("app-private-key").pipe(Options.optional);
53
- const appInstallationIdOption = Options.text("app-installation-id").pipe(Options.optional);
54
- const VALID_PHASES = [
55
- "current",
56
- "active-lts",
57
- "maintenance-lts",
58
- "end-of-life"
59
- ];
60
- const VALID_INCREMENTS = [
61
- "latest",
62
- "minor",
63
- "patch"
64
- ];
65
- const validatePhases = (raw) => {
66
- const phases = raw.split(",").map((s) => s.trim());
67
- for (const p of phases) if (!VALID_PHASES.includes(p)) throw new Error(`Invalid phase: "${p}". Valid values: ${VALID_PHASES.join(", ")}`);
68
- return phases;
69
- };
70
- const validateIncrements = (raw) => {
71
- if (!VALID_INCREMENTS.includes(raw)) throw new Error(`Invalid increments value: "${raw}". Valid values: ${VALID_INCREMENTS.join(", ")}`);
72
- return raw;
73
- };
74
- const serializeError = (error) => {
75
- if (error && typeof error === "object" && "_tag" in error && "message" in error) {
76
- const { _tag, message, ...rest } = error;
77
- return {
78
- _tag,
79
- message,
80
- ...rest
81
- };
82
- }
83
- return {
84
- _tag: "UnknownError",
85
- message: error instanceof Error ? error.message : String(error)
86
- };
87
- };
88
- const toSuccess = (name, result) => [name, {
89
- ok: true,
90
- source: result.source,
91
- versions: [...result.versions],
92
- latest: result.latest,
93
- ...result.lts !== void 0 ? { lts: result.lts } : {},
94
- ...result.default !== void 0 ? { default: result.default } : {}
95
- }];
96
- const toError = (name, error) => [name, {
97
- ok: false,
98
- error: serializeError(error)
99
- }];
100
- const resolveNode = (semverRange, phases, increments, defaultVersion, date, authOverride) => Effect.gen(function* () {
101
- const result = yield* (yield* NodeResolver).resolve({
102
- semverRange,
103
- ...phases ? { phases } : {},
104
- ...increments ? { increments } : {},
105
- ...defaultVersion ? { defaultVersion } : {},
106
- ...date ? { date } : {}
107
- });
108
- return toSuccess("node", result);
109
- }).pipe(Effect.provide(makeNodeLayer(authOverride)), Effect.catchAll((error) => Effect.succeed(toError("node", error))));
110
- const resolveBun = (semverRange, increments, defaultVersion, authOverride) => Effect.gen(function* () {
111
- const result = yield* (yield* BunResolver).resolve({
112
- semverRange,
113
- ...increments ? { increments } : {},
114
- ...defaultVersion ? { defaultVersion } : {}
115
- });
116
- return toSuccess("bun", result);
117
- }).pipe(Effect.provide(makeBunLayer(authOverride)), Effect.catchAll((error) => Effect.succeed(toError("bun", error))));
118
- const resolveDeno = (semverRange, increments, defaultVersion, authOverride) => Effect.gen(function* () {
119
- const result = yield* (yield* DenoResolver).resolve({
120
- semverRange,
121
- ...increments ? { increments } : {},
122
- ...defaultVersion ? { defaultVersion } : {}
123
- });
124
- return toSuccess("deno", result);
125
- }).pipe(Effect.provide(makeDenoLayer(authOverride)), Effect.catchAll((error) => Effect.succeed(toError("deno", error))));
126
- const formatResponse = (ok, results, pretty) => {
127
- return JSON.stringify({
128
- $schema: SCHEMA_URL,
129
- ok,
130
- results
131
- }, null, pretty ? 2 : void 0);
132
- };
133
- const resolveHandler = (args) => Effect.gen(function* () {
134
- if (args.schema) {
135
- if ([
136
- args.node,
137
- args.bun,
138
- args.deno,
139
- args.nodePhases,
140
- args.increments,
141
- args.nodeDefault,
142
- args.bunDefault,
143
- args.denoDefault,
144
- args.nodeDate,
145
- args.token,
146
- args.appId,
147
- args.appPrivateKey,
148
- args.appInstallationId
149
- ].some((f) => Option.isSome(f))) {
150
- yield* Console.error("Error: --schema cannot be combined with resolve flags (--node, --bun, --deno, etc.)");
151
- return;
152
- }
153
- const { cliJsonSchema } = yield* Effect.promise(() => import("../schemas/json-schema.js"));
154
- yield* Console.log(JSON.stringify(cliJsonSchema, null, 2));
155
- return;
156
- }
157
- const hasToken = Option.isSome(args.token);
158
- const hasAppId = Option.isSome(args.appId);
159
- const hasAppPrivateKey = Option.isSome(args.appPrivateKey);
160
- const hasAppInstallationId = Option.isSome(args.appInstallationId);
161
- if (hasToken && (hasAppId || hasAppPrivateKey)) {
162
- yield* Console.error("Error: --token and --app-id/--app-private-key are mutually exclusive");
163
- return;
164
- }
165
- if (hasAppId !== hasAppPrivateKey) {
166
- yield* Console.error("Error: --app-id and --app-private-key must both be provided");
167
- return;
168
- }
169
- if (hasAppInstallationId && !hasAppId) {
170
- yield* Console.error("Error: --app-installation-id requires --app-id and --app-private-key");
171
- return;
172
- }
173
- let resolvedPrivateKey;
174
- if (hasAppPrivateKey) {
175
- const keyValue = args.appPrivateKey.value;
176
- if (keyValue.startsWith("@")) {
177
- const filePath = keyValue.slice(1);
178
- try {
179
- resolvedPrivateKey = readFileSync(filePath, "utf-8");
180
- } catch {
181
- yield* Console.error(`Error: Cannot read private key file: ${filePath}`);
182
- return;
183
- }
184
- } else resolvedPrivateKey = keyValue;
185
- }
186
- let authLayerOverride;
187
- if (hasToken) authLayerOverride = GitHubTokenAuthFromToken(args.token.value);
188
- else if (hasAppId && resolvedPrivateKey) authLayerOverride = GitHubAppAuth({
189
- appId: args.appId.value,
190
- privateKey: resolvedPrivateKey,
191
- ...hasAppInstallationId ? { installationId: Number(args.appInstallationId.value) } : {}
192
- });
193
- const hasNode = Option.isSome(args.node);
194
- const hasBun = Option.isSome(args.bun);
195
- const hasDeno = Option.isSome(args.deno);
196
- if (!hasNode && !hasBun && !hasDeno) {
197
- yield* Console.error("No runtime specified. Use --node, --bun, or --deno to resolve versions.\nRun with --help for usage information.");
198
- return;
199
- }
200
- let validatedPhases;
201
- if (Option.isSome(args.nodePhases)) try {
202
- validatedPhases = validatePhases(args.nodePhases.value);
203
- } catch (e) {
204
- yield* Console.error(e.message);
205
- return;
206
- }
207
- let validatedIncrements;
208
- if (Option.isSome(args.increments)) try {
209
- validatedIncrements = validateIncrements(args.increments.value);
210
- } catch (e) {
211
- yield* Console.error(e.message);
212
- return;
213
- }
214
- let nodeDate;
215
- if (Option.isSome(args.nodeDate)) {
216
- nodeDate = new Date(args.nodeDate.value);
217
- if (Number.isNaN(nodeDate.getTime())) {
218
- yield* Console.error(`Invalid date: "${args.nodeDate.value}". Use ISO 8601 format (e.g. 2024-01-15).`);
219
- return;
220
- }
221
- }
222
- const tasks = [];
223
- if (hasNode) {
224
- const nodeDefaultVersion = Option.isSome(args.nodeDefault) ? args.nodeDefault.value : void 0;
225
- tasks.push(resolveNode(args.node.value, validatedPhases, validatedIncrements, nodeDefaultVersion, nodeDate, authLayerOverride));
226
- }
227
- if (hasBun) {
228
- const bunDefaultVersion = Option.isSome(args.bunDefault) ? args.bunDefault.value : void 0;
229
- tasks.push(resolveBun(args.bun.value, validatedIncrements, bunDefaultVersion, authLayerOverride));
230
- }
231
- if (hasDeno) {
232
- const denoDefaultVersion = Option.isSome(args.denoDefault) ? args.denoDefault.value : void 0;
233
- tasks.push(resolveDeno(args.deno.value, validatedIncrements, denoDefaultVersion, authLayerOverride));
234
- }
235
- const entries = yield* Effect.all(tasks, { concurrency: "unbounded" });
236
- const results = Object.fromEntries(entries);
237
- const hasError = Object.values(results).some((r) => !r.ok);
238
- yield* Console.log(formatResponse(!hasError, results, args.pretty));
239
- });
240
-
241
- //#endregion
242
- export { appIdOption, appInstallationIdOption, appPrivateKeyOption, bunDefaultOption, bunOption, denoDefaultOption, denoOption, incrementsOption, nodeDateOption, nodeDefaultOption, nodeOption, nodePhasesOption, prettyOption, resolveHandler, schemaOption, tokenOption };
@@ -1,12 +0,0 @@
1
- import { CliResponse } from "./response.js";
2
- import { JSONSchema } from "effect";
3
-
4
- //#region src/cli/schemas/json-schema.ts
5
- /**
6
- * JSON Schema for the CLI response envelope.
7
- * Used by --schema flag and can be published alongside the package.
8
- */
9
- const cliJsonSchema = JSONSchema.make(CliResponse);
10
-
11
- //#endregion
12
- export { cliJsonSchema };
@@ -1,86 +0,0 @@
1
- import { Schema } from "effect";
2
-
3
- //#region src/cli/schemas/response.ts
4
- /**
5
- * Structured error in CLI output. Uses _tag to identify the error type.
6
- * Additional fields vary by error type and are passed through as-is.
7
- */
8
- const CliErrorDetail = Schema.Struct({
9
- _tag: Schema.String.annotations({ description: "Error type identifier (e.g. RateLimitError, SemverError)" }),
10
- message: Schema.String.annotations({ description: "Human-readable error message" })
11
- }).pipe(Schema.extend(Schema.Record({
12
- key: Schema.String,
13
- value: Schema.Unknown.annotations({
14
- description: "Additional error-specific metadata",
15
- title: "ErrorMetadata"
16
- })
17
- })), Schema.annotations({
18
- identifier: "CliErrorDetail",
19
- description: "Structured error with type tag, message, and optional metadata"
20
- }));
21
- /**
22
- * Successful resolution for a single runtime.
23
- */
24
- const CliRuntimeSuccess = Schema.Struct({
25
- ok: Schema.Literal(true).annotations({ description: "Indicates successful resolution" }),
26
- source: Schema.String.annotations({ description: "Data source: 'api' or 'cache'" }),
27
- versions: Schema.Array(Schema.String.annotations({ description: "Semver version string" })).annotations({ description: "All resolved versions matching the semver range" }),
28
- latest: Schema.String.annotations({ description: "Most recent version matching the range" }),
29
- lts: Schema.optional(Schema.String.annotations({ description: "Current LTS version (Node.js only)" })),
30
- default: Schema.optional(Schema.String.annotations({ description: "Default recommended version" }))
31
- }).annotations({
32
- identifier: "CliRuntimeSuccess",
33
- description: "Successful version resolution for a single runtime"
34
- });
35
- /**
36
- * Failed resolution for a single runtime.
37
- */
38
- const CliRuntimeError = Schema.Struct({
39
- ok: Schema.Literal(false).annotations({ description: "Indicates failed resolution" }),
40
- error: CliErrorDetail
41
- }).annotations({
42
- identifier: "CliRuntimeError",
43
- description: "Failed version resolution for a single runtime"
44
- });
45
- /**
46
- * Per-runtime result: success or error.
47
- */
48
- const CliRuntimeResult = Schema.Union(CliRuntimeSuccess, CliRuntimeError).annotations({
49
- identifier: "CliRuntimeResult",
50
- description: "Per-runtime resolution result: either success with versions or error with details"
51
- });
52
- const CliResultsMap = Schema.Record({
53
- key: Schema.String.annotations({ description: "Runtime name (node, bun, or deno)" }),
54
- value: CliRuntimeResult
55
- }).annotations({ description: "Map of runtime name to resolution result" });
56
- /**
57
- * Full CLI success response — all runtimes resolved.
58
- */
59
- const CliSuccessResponse = Schema.Struct({
60
- ok: Schema.Literal(true).annotations({ description: "True when all requested runtimes resolved successfully" }),
61
- results: CliResultsMap
62
- }).annotations({
63
- identifier: "CliSuccessResponse",
64
- description: "All requested runtimes resolved successfully"
65
- });
66
- /**
67
- * Full CLI error response — at least one runtime failed.
68
- */
69
- const CliErrorResponse = Schema.Struct({
70
- ok: Schema.Literal(false).annotations({ description: "False when one or more requested runtimes failed to resolve" }),
71
- results: CliResultsMap
72
- }).annotations({
73
- identifier: "CliErrorResponse",
74
- description: "One or more requested runtimes failed to resolve"
75
- });
76
- /**
77
- * Top-level CLI response envelope.
78
- */
79
- const CliResponse = Schema.Union(CliSuccessResponse, CliErrorResponse).annotations({
80
- identifier: "CliResponse",
81
- title: "RuntimeResolverResponse",
82
- description: "CLI response envelope. Contains an ok discriminator and a results map with per-runtime resolution outcomes."
83
- });
84
-
85
- //#endregion
86
- export { CliErrorDetail, CliErrorResponse, CliResponse, CliRuntimeError, CliRuntimeResult, CliRuntimeSuccess, CliSuccessResponse };