@effected/runtimes 0.9.0 → 0.10.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/BunResolver.js +8 -1
- package/DenoResolver.js +8 -1
- package/GitHub.js +7 -19
- package/NodeRelease.js +4 -11
- package/NodeResolver.js +9 -1
- package/NodeSchedule.js +3 -10
- package/README.md +4 -4
- package/ResolvedVersions.js +3 -12
- package/index.d.ts +43 -26
- package/internal/feeds.js +1 -2
- package/internal/once.js +0 -27
- package/internal/strategy.js +1 -18
- package/package.json +3 -3
package/BunResolver.js
CHANGED
|
@@ -31,7 +31,14 @@ const BunResolverOptions = Schema.Struct({
|
|
|
31
31
|
defaultVersion: Schema.optionalKey(Schema.String)
|
|
32
32
|
});
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Resolves a semver range to concrete Bun versions, with release data from GitHub
|
|
35
|
+
* (`oven-sh/bun`) or a bundled snapshot.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Choose a strategy with the layer: `layer` tries GitHub and falls back to the
|
|
39
|
+
* snapshot, `layerFresh` fails rather than fall back, and `layerOffline` uses
|
|
40
|
+
* only the snapshot. `resolve` fails with `InvalidRangeError`,
|
|
41
|
+
* `NoMatchingVersionError`, `UnresolvableDefaultError` or `FreshnessError`.
|
|
35
42
|
*
|
|
36
43
|
* @example
|
|
37
44
|
* ```ts
|
package/DenoResolver.js
CHANGED
|
@@ -31,7 +31,14 @@ const DenoResolverOptions = Schema.Struct({
|
|
|
31
31
|
defaultVersion: Schema.optionalKey(Schema.String)
|
|
32
32
|
});
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Resolves a semver range to concrete Deno versions, with release data from GitHub
|
|
35
|
+
* (`denoland/deno`) or a bundled snapshot.
|
|
36
|
+
*
|
|
37
|
+
* @remarks
|
|
38
|
+
* Choose a strategy with the layer: `layer` tries GitHub and falls back to the
|
|
39
|
+
* snapshot, `layerFresh` fails rather than fall back, and `layerOffline` uses
|
|
40
|
+
* only the snapshot. `resolve` fails with `InvalidRangeError`,
|
|
41
|
+
* `NoMatchingVersionError`, `UnresolvableDefaultError` or `FreshnessError`.
|
|
35
42
|
*
|
|
36
43
|
* @example
|
|
37
44
|
* ```ts
|
package/GitHub.js
CHANGED
|
@@ -4,16 +4,6 @@ import { FetchHttpClient, HttpClient } from "effect/http";
|
|
|
4
4
|
|
|
5
5
|
//#region src/GitHub.ts
|
|
6
6
|
/**
|
|
7
|
-
* Talking to GitHub: pluggable authentication, a REST client, and the typed
|
|
8
|
-
* failure ladder that every network fetch in this package reports through.
|
|
9
|
-
*
|
|
10
|
-
* The two nodejs.org feeds reuse this ladder rather than minting a parallel
|
|
11
|
-
* one, so the module is named for its dominant user rather than for the
|
|
12
|
-
* lowest common denominator.
|
|
13
|
-
*
|
|
14
|
-
* @packageDocumentation
|
|
15
|
-
*/
|
|
16
|
-
/**
|
|
17
7
|
* GitHub rejected the credentials.
|
|
18
8
|
*
|
|
19
9
|
* @public
|
|
@@ -70,10 +60,8 @@ var ResponseParseError = class extends Schema.TaggedError()("ResponseParseError"
|
|
|
70
60
|
* records and this is the single place they become errors. That is what keeps
|
|
71
61
|
* the transport layer free of the facade and the import graph acyclic.
|
|
72
62
|
*
|
|
73
|
-
* `method` is what the *caller* actually sent, not a guess
|
|
74
|
-
* `"
|
|
75
|
-
* mislabelled every anonymous rejection — the same shape of lie as v3's
|
|
76
|
-
* hardcoded `source: "api"`.
|
|
63
|
+
* `method` is what the *caller* actually sent, not a guess, so the
|
|
64
|
+
* `"anonymous"` arm of `AuthenticationError` is reachable.
|
|
77
65
|
*
|
|
78
66
|
* @internal
|
|
79
67
|
*/
|
|
@@ -145,8 +133,8 @@ var GitHubAuth = class GitHubAuth extends Context.Service()("@effected/runtimes/
|
|
|
145
133
|
* Detect a credential from the environment, preferring an explicit PAT.
|
|
146
134
|
*
|
|
147
135
|
* Precedence is `GITHUB_PERSONAL_ACCESS_TOKEN`, then `GITHUB_TOKEN`, then
|
|
148
|
-
* unauthenticated
|
|
149
|
-
*
|
|
136
|
+
* unauthenticated. The variables are read through `Config`, so a test can swap
|
|
137
|
+
* the `ConfigProvider` instead of mutating `process.env`.
|
|
150
138
|
*/
|
|
151
139
|
static layer = Layer.effect(GitHubAuth, Effect.gen(function* () {
|
|
152
140
|
const pat = yield* patConfig;
|
|
@@ -169,9 +157,9 @@ const GITHUB_HEADERS = {
|
|
|
169
157
|
/**
|
|
170
158
|
* A GitHub REST client over `HttpClient`.
|
|
171
159
|
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
160
|
+
* Programs against `HttpClient` from `effect` core, so the package stays
|
|
161
|
+
* boundary tier and a consumer can supply any transport. It lists a
|
|
162
|
+
* repository's tags and releases, and fails with the {@link GitHubError} ladder.
|
|
175
163
|
*
|
|
176
164
|
* @public
|
|
177
165
|
*/
|
package/NodeRelease.js
CHANGED
|
@@ -4,22 +4,15 @@ import { Option, Schema } from "effect";
|
|
|
4
4
|
|
|
5
5
|
//#region src/NodeRelease.ts
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* One published Node.js release: its version, bundled npm version and release date.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* One Node.js release.
|
|
13
|
-
*
|
|
14
|
-
* Unlike its v3 ancestor this is an ordinary immutable value. v3's `NodeRelease`
|
|
15
|
-
* carried a `Ref<NodeSchedule>` so that `release.phase()` could reach the
|
|
16
|
-
* schedule, which meant every release held shared mutable state and could not be
|
|
17
|
-
* a data class at all. Phase is now a question you ask *with* a schedule rather
|
|
18
|
-
* than a property the release drags around.
|
|
9
|
+
* An ordinary immutable value. Phase is a question you ask *with* a schedule
|
|
10
|
+
* (`release.phase(schedule, now)`) rather than a property the release carries.
|
|
19
11
|
*
|
|
20
12
|
* @example
|
|
21
13
|
* ```ts
|
|
22
14
|
* import { NodeRelease, NodeSchedule } from "@effected/runtimes";
|
|
15
|
+
* import { SemVer } from "@effected/semver";
|
|
23
16
|
* import { DateTime, Effect } from "effect";
|
|
24
17
|
*
|
|
25
18
|
* const program = Effect.gen(function* () {
|
package/NodeResolver.js
CHANGED
|
@@ -28,7 +28,15 @@ const NodeResolverOptions = Schema.Struct({
|
|
|
28
28
|
});
|
|
29
29
|
const DEFAULT_PHASES = ["current", "active-lts"];
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Resolves a semver range to concrete Node.js versions, filtered by lifecycle
|
|
32
|
+
* phase, with release data from the nodejs.org feeds or a bundled snapshot.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* Choose a strategy with the layer: `layer` tries the live feeds and falls back
|
|
36
|
+
* to the snapshot (recorded as `source: "cache"`), `layerFresh` fails rather
|
|
37
|
+
* than fall back, and `layerOffline` uses only the snapshot. `resolve` fails
|
|
38
|
+
* with `InvalidRangeError`, `NoMatchingVersionError`, `UnresolvableDefaultError`
|
|
39
|
+
* or `FreshnessError`.
|
|
32
40
|
*
|
|
33
41
|
* @example
|
|
34
42
|
* ```ts
|
package/NodeSchedule.js
CHANGED
|
@@ -2,11 +2,6 @@ import { DateTime, Effect, Option, Order, Schema } from "effect";
|
|
|
2
2
|
|
|
3
3
|
//#region src/NodeSchedule.ts
|
|
4
4
|
/**
|
|
5
|
-
* The Node.js release schedule and the lifecycle phases derived from it.
|
|
6
|
-
*
|
|
7
|
-
* @packageDocumentation
|
|
8
|
-
*/
|
|
9
|
-
/**
|
|
10
5
|
* Lifecycle phase of a Node.js major release line.
|
|
11
6
|
*
|
|
12
7
|
* - `current` — actively receiving features and bug fixes.
|
|
@@ -113,11 +108,9 @@ const SCHEDULE_KEY = /^v?(\d+)(?:\.(\d+))?$/;
|
|
|
113
108
|
/**
|
|
114
109
|
* An immutable snapshot of the Node.js release schedule.
|
|
115
110
|
*
|
|
116
|
-
*
|
|
117
|
-
* `release
|
|
118
|
-
*
|
|
119
|
-
* Here the schedule is a value the caller passes in: phase is a function of
|
|
120
|
-
* `(release, schedule, now)`, and nothing in the model is mutable.
|
|
111
|
+
* The schedule is a value the caller passes in: phase is a function of
|
|
112
|
+
* `(release, schedule, now)`, so nothing in the model is mutable and
|
|
113
|
+
* {@link NodeRelease} stays a plain data class.
|
|
121
114
|
*
|
|
122
115
|
* @example
|
|
123
116
|
* ```ts
|
package/README.md
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
Resolve semver-compatible Node.js, Bun and Deno versions from the live release feeds, with a bundled offline snapshot as a fallback. Ask for `>=20` in the `active-lts` phase and get back every match, newest first, plus the LTS pick and whatever you nominated as the default. Node's lifecycle phases come from the real `nodejs/Release` schedule and are evaluated against the clock, so `current`, `active-lts`, `maintenance-lts` and `end-of-life` mean what they mean today rather than on the day the package was published.
|
|
9
9
|
|
|
10
|
-
> **Pre
|
|
11
|
-
>
|
|
12
|
-
> `1.0.0`
|
|
13
|
-
>
|
|
10
|
+
> **Pre-`1.0.0`.** This package is part of the `@effected/*` kit, built on stable
|
|
11
|
+
> Effect v4 (`effect` `^4.0.0`) and still in `0.x` development. Stable Effect
|
|
12
|
+
> makes a kit `1.0.0` possible, not automatic. To keep your `effect` and
|
|
13
|
+
> `@effect/*` versions on the line the kit is built and tested against, install
|
|
14
14
|
> [`@effected/pnpm-plugin-effect`](https://www.npmjs.com/package/@effected/pnpm-plugin-effect).
|
|
15
15
|
>
|
|
16
16
|
> **Stability: unstable.** This package's API surface is not yet considered
|
package/ResolvedVersions.js
CHANGED
|
@@ -3,11 +3,6 @@ import { Schema } from "effect";
|
|
|
3
3
|
|
|
4
4
|
//#region src/ResolvedVersions.ts
|
|
5
5
|
/**
|
|
6
|
-
* The shared vocabulary of resolution: what a resolver returns, and how it fails.
|
|
7
|
-
*
|
|
8
|
-
* @packageDocumentation
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
6
|
* The JavaScript runtime a resolver targets.
|
|
12
7
|
*
|
|
13
8
|
* @public
|
|
@@ -24,10 +19,8 @@ const Runtime = Schema.Literals([
|
|
|
24
19
|
* - `cache` — the bundled snapshot was used, either because the offline
|
|
25
20
|
* strategy was chosen or because the auto strategy fell back to it.
|
|
26
21
|
*
|
|
27
|
-
* This is honest provenance
|
|
28
|
-
*
|
|
29
|
-
* caller could not tell a live answer from a snapshot served after a silent
|
|
30
|
-
* network failure.
|
|
22
|
+
* This is honest provenance: a caller can always tell a live answer from a
|
|
23
|
+
* snapshot served after a network failure.
|
|
31
24
|
*
|
|
32
25
|
* @public
|
|
33
26
|
*/
|
|
@@ -47,7 +40,7 @@ const Increments = Schema.Literals([
|
|
|
47
40
|
"patch"
|
|
48
41
|
]);
|
|
49
42
|
/**
|
|
50
|
-
* What every resolver returns.
|
|
43
|
+
* What every resolver returns: the matching versions, the newest one, and where the data came from.
|
|
51
44
|
*
|
|
52
45
|
* @public
|
|
53
46
|
*/
|
|
@@ -68,8 +61,6 @@ var ResolvedVersions = class extends Schema.Class("ResolvedVersions")({
|
|
|
68
61
|
*
|
|
69
62
|
* Distinct from an invalid constraint: `@effected/semver`'s `InvalidRangeError`
|
|
70
63
|
* says the range is malformed, this says the range is fine and nothing matched.
|
|
71
|
-
* v3 collapsed the former into the latter, so a typo in a range surfaced to the
|
|
72
|
-
* user as "no versions found".
|
|
73
64
|
*
|
|
74
65
|
* @public
|
|
75
66
|
*/
|
package/index.d.ts
CHANGED
|
@@ -121,8 +121,8 @@ export declare class GitHubAuth extends GitHubAuth_base {
|
|
|
121
121
|
* Detect a credential from the environment, preferring an explicit PAT.
|
|
122
122
|
*
|
|
123
123
|
* Precedence is `GITHUB_PERSONAL_ACCESS_TOKEN`, then `GITHUB_TOKEN`, then
|
|
124
|
-
* unauthenticated
|
|
125
|
-
*
|
|
124
|
+
* unauthenticated. The variables are read through `Config`, so a test can swap
|
|
125
|
+
* the `ConfigProvider` instead of mutating `process.env`.
|
|
126
126
|
*/
|
|
127
127
|
static readonly layer: Layer.Layer<GitHubAuth>;
|
|
128
128
|
}
|
|
@@ -159,9 +159,9 @@ declare const GitHubClient_base: Context.ServiceClass<GitHubClient, "@effected/r
|
|
|
159
159
|
/**
|
|
160
160
|
* A GitHub REST client over `HttpClient`.
|
|
161
161
|
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
162
|
+
* Programs against `HttpClient` from `effect` core, so the package stays
|
|
163
|
+
* boundary tier and a consumer can supply any transport. It lists a
|
|
164
|
+
* repository's tags and releases, and fails with the {@link GitHubError} ladder.
|
|
165
165
|
*
|
|
166
166
|
* @public
|
|
167
167
|
*/
|
|
@@ -199,10 +199,8 @@ export type Runtime = typeof Runtime.Type;
|
|
|
199
199
|
* - `cache` — the bundled snapshot was used, either because the offline
|
|
200
200
|
* strategy was chosen or because the auto strategy fell back to it.
|
|
201
201
|
*
|
|
202
|
-
* This is honest provenance
|
|
203
|
-
*
|
|
204
|
-
* caller could not tell a live answer from a snapshot served after a silent
|
|
205
|
-
* network failure.
|
|
202
|
+
* This is honest provenance: a caller can always tell a live answer from a
|
|
203
|
+
* snapshot served after a network failure.
|
|
206
204
|
*
|
|
207
205
|
* @public
|
|
208
206
|
*/
|
|
@@ -242,7 +240,7 @@ declare const ResolvedVersions_base: Schema.Class<ResolvedVersions, Schema.Struc
|
|
|
242
240
|
readonly default: Schema.optionalKey<Schema.String>;
|
|
243
241
|
}>, {}>;
|
|
244
242
|
/**
|
|
245
|
-
* What every resolver returns.
|
|
243
|
+
* What every resolver returns: the matching versions, the newest one, and where the data came from.
|
|
246
244
|
*
|
|
247
245
|
* @public
|
|
248
246
|
*/
|
|
@@ -260,8 +258,6 @@ declare const NoMatchingVersionError_base: Schema.Class<NoMatchingVersionError,
|
|
|
260
258
|
*
|
|
261
259
|
* Distinct from an invalid constraint: `@effected/semver`'s `InvalidRangeError`
|
|
262
260
|
* says the range is malformed, this says the range is fine and nothing matched.
|
|
263
|
-
* v3 collapsed the former into the latter, so a typo in a range surfaced to the
|
|
264
|
-
* user as "no versions found".
|
|
265
261
|
*
|
|
266
262
|
* @public
|
|
267
263
|
*/
|
|
@@ -338,10 +334,18 @@ export declare const BunResolverOptions: Schema.Struct<{
|
|
|
338
334
|
*/
|
|
339
335
|
export type BunResolverOptions = typeof BunResolverOptions.Type;
|
|
340
336
|
declare const BunResolver_base: Context.ServiceClass<BunResolver, "@effected/runtimes/BunResolver", {
|
|
337
|
+
/** Resolve a range to the matching versions, newest first. */
|
|
341
338
|
readonly resolve: (options?: BunResolverOptions) => Effect.Effect<ResolvedVersions, InvalidRangeError | NoMatchingVersionError | UnresolvableDefaultError | FreshnessError>;
|
|
342
339
|
}>;
|
|
343
340
|
/**
|
|
344
|
-
*
|
|
341
|
+
* Resolves a semver range to concrete Bun versions, with release data from GitHub
|
|
342
|
+
* (`oven-sh/bun`) or a bundled snapshot.
|
|
343
|
+
*
|
|
344
|
+
* @remarks
|
|
345
|
+
* Choose a strategy with the layer: `layer` tries GitHub and falls back to the
|
|
346
|
+
* snapshot, `layerFresh` fails rather than fall back, and `layerOffline` uses
|
|
347
|
+
* only the snapshot. `resolve` fails with `InvalidRangeError`,
|
|
348
|
+
* `NoMatchingVersionError`, `UnresolvableDefaultError` or `FreshnessError`.
|
|
345
349
|
*
|
|
346
350
|
* @example
|
|
347
351
|
* ```ts
|
|
@@ -413,10 +417,18 @@ export declare const DenoResolverOptions: Schema.Struct<{
|
|
|
413
417
|
*/
|
|
414
418
|
export type DenoResolverOptions = typeof DenoResolverOptions.Type;
|
|
415
419
|
declare const DenoResolver_base: Context.ServiceClass<DenoResolver, "@effected/runtimes/DenoResolver", {
|
|
420
|
+
/** Resolve a range to the matching versions, newest first. */
|
|
416
421
|
readonly resolve: (options?: DenoResolverOptions) => Effect.Effect<ResolvedVersions, InvalidRangeError | NoMatchingVersionError | UnresolvableDefaultError | FreshnessError>;
|
|
417
422
|
}>;
|
|
418
423
|
/**
|
|
419
|
-
*
|
|
424
|
+
* Resolves a semver range to concrete Deno versions, with release data from GitHub
|
|
425
|
+
* (`denoland/deno`) or a bundled snapshot.
|
|
426
|
+
*
|
|
427
|
+
* @remarks
|
|
428
|
+
* Choose a strategy with the layer: `layer` tries GitHub and falls back to the
|
|
429
|
+
* snapshot, `layerFresh` fails rather than fall back, and `layerOffline` uses
|
|
430
|
+
* only the snapshot. `resolve` fails with `InvalidRangeError`,
|
|
431
|
+
* `NoMatchingVersionError`, `UnresolvableDefaultError` or `FreshnessError`.
|
|
420
432
|
*
|
|
421
433
|
* @example
|
|
422
434
|
* ```ts
|
|
@@ -576,11 +588,9 @@ declare const NodeSchedule_base: Schema.Class<NodeSchedule, Schema.Struct<{
|
|
|
576
588
|
/**
|
|
577
589
|
* An immutable snapshot of the Node.js release schedule.
|
|
578
590
|
*
|
|
579
|
-
*
|
|
580
|
-
* `release
|
|
581
|
-
*
|
|
582
|
-
* Here the schedule is a value the caller passes in: phase is a function of
|
|
583
|
-
* `(release, schedule, now)`, and nothing in the model is mutable.
|
|
591
|
+
* The schedule is a value the caller passes in: phase is a function of
|
|
592
|
+
* `(release, schedule, now)`, so nothing in the model is mutable and
|
|
593
|
+
* {@link NodeRelease} stays a plain data class.
|
|
584
594
|
*
|
|
585
595
|
* @example
|
|
586
596
|
* ```ts
|
|
@@ -655,17 +665,15 @@ declare const NodeRelease_base: Schema.Class<NodeRelease, Schema.Struct<{
|
|
|
655
665
|
readonly date: Schema.DateTimeUtc;
|
|
656
666
|
}>, {}>;
|
|
657
667
|
/**
|
|
658
|
-
* One Node.js release.
|
|
668
|
+
* One published Node.js release: its version, bundled npm version and release date.
|
|
659
669
|
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
* schedule, which meant every release held shared mutable state and could not be
|
|
663
|
-
* a data class at all. Phase is now a question you ask *with* a schedule rather
|
|
664
|
-
* than a property the release drags around.
|
|
670
|
+
* An ordinary immutable value. Phase is a question you ask *with* a schedule
|
|
671
|
+
* (`release.phase(schedule, now)`) rather than a property the release carries.
|
|
665
672
|
*
|
|
666
673
|
* @example
|
|
667
674
|
* ```ts
|
|
668
675
|
* import { NodeRelease, NodeSchedule } from "@effected/runtimes";
|
|
676
|
+
* import { SemVer } from "@effected/semver";
|
|
669
677
|
* import { DateTime, Effect } from "effect";
|
|
670
678
|
*
|
|
671
679
|
* const program = Effect.gen(function* () {
|
|
@@ -726,10 +734,19 @@ export declare const NodeResolverOptions: Schema.Struct<{
|
|
|
726
734
|
*/
|
|
727
735
|
export type NodeResolverOptions = typeof NodeResolverOptions.Type;
|
|
728
736
|
declare const NodeResolver_base: Context.ServiceClass<NodeResolver, "@effected/runtimes/NodeResolver", {
|
|
737
|
+
/** Resolve a range to the matching versions, newest first. */
|
|
729
738
|
readonly resolve: (options?: NodeResolverOptions) => Effect.Effect<ResolvedVersions, InvalidRangeError | NoMatchingVersionError | UnresolvableDefaultError | FreshnessError>;
|
|
730
739
|
}>;
|
|
731
740
|
/**
|
|
732
|
-
*
|
|
741
|
+
* Resolves a semver range to concrete Node.js versions, filtered by lifecycle
|
|
742
|
+
* phase, with release data from the nodejs.org feeds or a bundled snapshot.
|
|
743
|
+
*
|
|
744
|
+
* @remarks
|
|
745
|
+
* Choose a strategy with the layer: `layer` tries the live feeds and falls back
|
|
746
|
+
* to the snapshot (recorded as `source: "cache"`), `layerFresh` fails rather
|
|
747
|
+
* than fall back, and `layerOffline` uses only the snapshot. `resolve` fails
|
|
748
|
+
* with `InvalidRangeError`, `NoMatchingVersionError`, `UnresolvableDefaultError`
|
|
749
|
+
* or `FreshnessError`.
|
|
733
750
|
*
|
|
734
751
|
* @example
|
|
735
752
|
* ```ts
|
package/internal/feeds.js
CHANGED
|
@@ -62,8 +62,7 @@ const buildNodeReleases = (raw) => Effect.gen(function* () {
|
|
|
62
62
|
/**
|
|
63
63
|
* Fetch a runtime's releases from GitHub, dropping drafts and prereleases.
|
|
64
64
|
*
|
|
65
|
-
* Bun and Deno differ by a repository name and a tag prefix.
|
|
66
|
-
* services, two service files and two `*Live` layers for that difference.
|
|
65
|
+
* Bun and Deno differ only by a repository name and a tag prefix.
|
|
67
66
|
*/
|
|
68
67
|
const fetchGitHubReleases = (client, owner, repo) => client.listReleases(owner, repo).pipe(Effect.map((releases) => releases.filter((release) => !release.draft && !release.prerelease).flatMap((release) => {
|
|
69
68
|
const date = release.published_at;
|
package/internal/once.js
CHANGED
|
@@ -2,33 +2,6 @@ import { Effect, Ref, Semaphore } from "effect";
|
|
|
2
2
|
|
|
3
3
|
//#region src/internal/once.ts
|
|
4
4
|
/**
|
|
5
|
-
* A run-at-most-once gate for deferred layer population.
|
|
6
|
-
*
|
|
7
|
-
* The resolver layers are lazy: acquiring one performs no IO, and the feed
|
|
8
|
-
* fetch happens on the first `resolve`. This helper is the memoization behind
|
|
9
|
-
* that contract, chosen over `Effect.cached` deliberately — `cached` memoizes
|
|
10
|
-
* the *Exit*, so a transient network failure (or an interrupted first resolve)
|
|
11
|
-
* would poison the resolver for the layer's whole lifetime.
|
|
12
|
-
*
|
|
13
|
-
* Semantics, exactly:
|
|
14
|
-
*
|
|
15
|
-
* - **Success is memoized.** The first successful run flips the gate; every
|
|
16
|
-
* later and every concurrently-waiting caller skips the work.
|
|
17
|
-
* - **Concurrent first callers share one run.** A semaphore serializes entry;
|
|
18
|
-
* waiters re-check the gate under the permit and skip when the winner
|
|
19
|
-
* succeeded.
|
|
20
|
-
* - **Failure is not memoized.** The gate only flips after success, so a
|
|
21
|
-
* failed run leaves it open and the next caller retries. Same for an
|
|
22
|
-
* interrupted run — `withPermits` releases the permit on interruption.
|
|
23
|
-
*
|
|
24
|
-
* The effect's requirements are captured from the *acquiring* scope
|
|
25
|
-
* (`Effect.context`), so the gated effect needs nothing at call time — which
|
|
26
|
-
* is what lets a lazy `resolve` keep `R = never` while the layer still
|
|
27
|
-
* honestly advertises the strategy's requirements.
|
|
28
|
-
*
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
/**
|
|
32
5
|
* Capture `effect`'s requirements now; return a gated effect that runs it at
|
|
33
6
|
* most once successfully, retrying after failure or interruption.
|
|
34
7
|
*/
|
package/internal/strategy.js
CHANGED
|
@@ -3,22 +3,6 @@ import { Effect } from "effect";
|
|
|
3
3
|
|
|
4
4
|
//#region src/internal/strategy.ts
|
|
5
5
|
/**
|
|
6
|
-
* The three cache strategies, parameterized once.
|
|
7
|
-
*
|
|
8
|
-
* v3 shipped nine layer files for this: {auto, fresh, offline} × {node, bun,
|
|
9
|
-
* deno}, where the Bun and Deno "fresh" layers differed by a repository name.
|
|
10
|
-
* The strategy is a property of *how the index is populated*, not of which
|
|
11
|
-
* runtime it holds, so it is one function per strategy taking a loader.
|
|
12
|
-
*
|
|
13
|
-
* Each is typed exactly, which is the point: `offline` requires nothing and
|
|
14
|
-
* cannot fail, `auto` requires the feed but still cannot fail, and only `fresh`
|
|
15
|
-
* carries a `FreshnessError`. A single function switching on a kind would union
|
|
16
|
-
* all three channels together and force every layer to advertise failures it
|
|
17
|
-
* cannot have.
|
|
18
|
-
*
|
|
19
|
-
* @internal
|
|
20
|
-
*/
|
|
21
|
-
/**
|
|
22
6
|
* Load the bundled snapshot. No IO, no failure, no requirements.
|
|
23
7
|
*/
|
|
24
8
|
const populateOffline = (index, offline) => offline.pipe(Effect.flatMap((releases) => index.load(releases, "cache")));
|
|
@@ -36,8 +20,7 @@ const populateFresh = (index, runtime, live) => live.pipe(Effect.mapError((cause
|
|
|
36
20
|
* Try the live feed; fall back to the bundled snapshot.
|
|
37
21
|
*
|
|
38
22
|
* The fallback is **visible**: provenance becomes `"cache"` and a warning is
|
|
39
|
-
* logged
|
|
40
|
-
* so a caller had no way to tell a live answer from a stale one served after a
|
|
23
|
+
* logged, so a caller can tell a live answer from a stale one served after a
|
|
41
24
|
* network failure.
|
|
42
25
|
*/
|
|
43
26
|
const populateAuto = (index, runtime, live, offline) => live.pipe(Effect.flatMap((releases) => index.load(releases, "api")), Effect.catch((cause) => Effect.gen(function* () {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/runtimes",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Resolve semver-compatible Node.js, Bun and Deno runtime versions with offline fallback.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"./package.json": "./package.json"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@effected/semver": "^0.
|
|
43
|
+
"@effected/semver": "^0.11.0"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|
|
46
|
-
"effect": "4.0.0
|
|
46
|
+
"effect": "^4.0.0"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
49
49
|
"node": ">=24.11.0"
|