@graftland/package-manager 0.1.0 → 0.2.0-beta.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/README.md +237 -4
- package/README.zh-CN.md +183 -0
- package/README.zh-TW.md +184 -0
- package/dist/PackageManagerDeclaration.d.ts +6 -0
- package/dist/PackageManagerDeclaration.d.ts.map +1 -0
- package/dist/PackageManagerDeclaration.js +24 -0
- package/dist/PackageManagerDeclaration.js.map +1 -0
- package/dist/index.d.ts +46 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +168 -48
- package/dist/index.js.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +113 -10
- package/dist/manifest.js.map +1 -1
- package/dist/process.js +50 -0
- package/dist/process.js.map +1 -0
- package/dist/snapshot.d.ts +15 -0
- package/dist/snapshot.d.ts.map +1 -0
- package/dist/snapshot.js +104 -0
- package/dist/snapshot.js.map +1 -0
- package/package.json +9 -3
- package/src/PackageManagerDeclaration.ts +42 -0
- package/src/index.ts +374 -123
- package/src/manifest.ts +199 -18
- package/src/process.ts +122 -0
- package/src/snapshot.ts +261 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PackageManagerDeclaration.js","names":[],"sources":["../src/PackageManagerDeclaration.ts"],"sourcesContent":["import { Schema } from \"effect\"\n\nexport const PackageManagerName = Schema.Literals([\"npm\", \"pnpm\", \"yarn\"])\n\nconst CorepackHash = Schema.Union([\n\tSchema.Tuple([\n\t\tSchema.Literal(\"sha224\"),\n\t\tSchema.String.check(Schema.isPattern(/^[0-9a-f]{56}$/)),\n\t]),\n\tSchema.Tuple([\n\t\tSchema.Literal(\"sha256\"),\n\t\tSchema.String.check(Schema.isPattern(/^[0-9a-f]{64}$/)),\n\t]),\n\tSchema.Tuple([\n\t\tSchema.Literal(\"sha384\"),\n\t\tSchema.String.check(Schema.isPattern(/^[0-9a-f]{96}$/)),\n\t]),\n\tSchema.Tuple([\n\t\tSchema.Literal(\"sha512\"),\n\t\tSchema.String.check(Schema.isPattern(/^[0-9a-f]{128}$/)),\n\t]),\n])\nconst isCorepackHash = Schema.is(CorepackHash)\nconst Version = Schema.String.check(Schema.isMaxLength(256))\n\t.pipe(Schema.decodeTo(Schema.SemVerFromString))\n\t.check(\n\t\tSchema.makeFilter(\n\t\t\t(version) => version.build.length === 0 || isCorepackHash(version.build),\n\t\t\t{\n\t\t\t\texpected:\n\t\t\t\t\t\"no build metadata, or a Corepack sha224/sha256/sha384/sha512 lowercase hexadecimal hash\",\n\t\t\t},\n\t\t),\n\t)\n\n/** Exact SemVer with optional prerelease and Corepack hash; ranges, URLs and arbitrary build metadata are unsupported. */\nexport const PackageManagerDeclaration = Schema.TemplateLiteralParser([\n\tPackageManagerName,\n\t\"@\",\n\tVersion,\n])\nexport type PackageManagerDeclaration = typeof PackageManagerDeclaration.Type\n"],"mappings":";;AAEA,MAAa,qBAAqB,OAAO,SAAS;CAAC;CAAO;CAAQ;AAAM,CAAC;AAEzE,MAAM,eAAe,OAAO,MAAM;CACjC,OAAO,MAAM,CACZ,OAAO,QAAQ,QAAQ,GACvB,OAAO,OAAO,MAAM,OAAO,UAAU,gBAAgB,CAAC,CACvD,CAAC;CACD,OAAO,MAAM,CACZ,OAAO,QAAQ,QAAQ,GACvB,OAAO,OAAO,MAAM,OAAO,UAAU,gBAAgB,CAAC,CACvD,CAAC;CACD,OAAO,MAAM,CACZ,OAAO,QAAQ,QAAQ,GACvB,OAAO,OAAO,MAAM,OAAO,UAAU,gBAAgB,CAAC,CACvD,CAAC;CACD,OAAO,MAAM,CACZ,OAAO,QAAQ,QAAQ,GACvB,OAAO,OAAO,MAAM,OAAO,UAAU,iBAAiB,CAAC,CACxD,CAAC;AACF,CAAC;AACD,MAAM,iBAAiB,OAAO,GAAG,YAAY;AAC7C,MAAM,UAAU,OAAO,OAAO,MAAM,OAAO,YAAY,GAAG,CAAC,CAAC,CAC1D,KAAK,OAAO,SAAS,OAAO,gBAAgB,CAAC,CAAC,CAC9C,MACA,OAAO,YACL,YAAY,QAAQ,MAAM,WAAW,KAAK,eAAe,QAAQ,KAAK,GACvE,EACC,UACC,0FACF,CACD,CACD;;AAGD,MAAa,4BAA4B,OAAO,sBAAsB;CACrE;CACA;CACA;AACD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { PackageManagerDeclaration } from "./PackageManagerDeclaration.js";
|
|
2
|
+
import { SnapshotCleanupFailure, UnsupportedFileTypeError } from "./snapshot.js";
|
|
1
3
|
import { Changes, PackageName } from "./manifest.js";
|
|
2
|
-
import { Effect, FileSystem, HashMap, Path, PlatformError, Schema } from "effect";
|
|
4
|
+
import { Cause, Effect, FileSystem, HashMap, Option, Path, PlatformError, Schema } from "effect";
|
|
3
5
|
import { ChildProcessSpawner } from "effect/process";
|
|
4
6
|
export declare const Agent: Schema.Literals<readonly ["npm", "pnpm", "yarn-classic", "yarn-berry"]>;
|
|
5
7
|
export type Agent = typeof Agent.Type;
|
|
@@ -7,11 +9,23 @@ declare const PackageManagerError_base: Schema.Class<PackageManagerError, Schema
|
|
|
7
9
|
readonly operation: Schema.Literals<readonly ["detect", "install", "recover", "state"]>;
|
|
8
10
|
readonly message: Schema.String;
|
|
9
11
|
readonly exitCode: Schema.optionalKey<Schema.Int>;
|
|
10
|
-
}>,
|
|
12
|
+
}>, Cause.YieldableError & {
|
|
11
13
|
readonly brand: unique symbol;
|
|
12
14
|
}>;
|
|
13
15
|
export declare class PackageManagerError extends PackageManagerError_base {}
|
|
14
|
-
|
|
16
|
+
declare const RecoveryRequiredError_base: Schema.Class<RecoveryRequiredError, Schema.TaggedStruct<"RecoveryRequiredError", {
|
|
17
|
+
readonly directory: Schema.String;
|
|
18
|
+
readonly snapshotDirectory: Schema.String;
|
|
19
|
+
readonly operation: Schema.Literals<readonly ["install", "recover", "rollback"]>;
|
|
20
|
+
readonly processId: Schema.optionalKey<Schema.Int>;
|
|
21
|
+
readonly message: Schema.String;
|
|
22
|
+
readonly terminationCause: Schema.optionalKey<Schema.Cause<Schema.Unknown, Schema.Unknown>>;
|
|
23
|
+
readonly recoveryCause: Schema.Cause<Schema.Unknown, Schema.Unknown>;
|
|
24
|
+
}>, Cause.YieldableError & {
|
|
25
|
+
readonly brand: unique symbol;
|
|
26
|
+
}>;
|
|
27
|
+
export declare class RecoveryRequiredError extends RecoveryRequiredError_base {}
|
|
28
|
+
export type Error = PackageManagerError | UnsupportedFileTypeError | RecoveryRequiredError | PlatformError.PlatformError | Schema.SchemaError;
|
|
15
29
|
export interface Options {
|
|
16
30
|
/** Project directory, containing package.json. Use the workspace root for workspace installs. */
|
|
17
31
|
readonly directory: string;
|
|
@@ -43,19 +57,44 @@ export interface StateDiff {
|
|
|
43
57
|
export declare const diffState: (before: State, after: State) => StateDiff;
|
|
44
58
|
export interface InstallResult extends StateDiff {
|
|
45
59
|
readonly agent: Agent;
|
|
60
|
+
/** The install committed; retry only snapshot deletion, not installation. */
|
|
61
|
+
readonly snapshotCleanupFailure: Option.Option<SnapshotCleanupFailure>;
|
|
46
62
|
}
|
|
47
63
|
export interface PackageManager {
|
|
48
64
|
readonly directory: string;
|
|
49
65
|
readonly agent: Agent;
|
|
50
66
|
readonly readState: Effect.Effect<State, Error>;
|
|
67
|
+
/** Present when manual recovery is required; the manager cannot be reused. */
|
|
68
|
+
readonly recoveryRequired: Effect.Effect<Option.Option<RecoveryRequiredError>>;
|
|
51
69
|
/** Serialized per manager. Empty changes installs the current manifest, including first installs. */
|
|
52
70
|
readonly install: (changes: Changes) => Effect.Effect<InstallResult, Error>;
|
|
53
71
|
}
|
|
54
72
|
/**
|
|
55
|
-
* Own one manager per project.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
73
|
+
* Own one manager per project. The caller must give this manager and its child
|
|
74
|
+
* processes exclusive write access to the project for each install, including
|
|
75
|
+
* recovery. Do not edit project files or run another installer concurrently.
|
|
76
|
+
* Calls are serialized only within this manager; no cross-process lock is taken.
|
|
77
|
+
* Managed paths must be regular files or absent. make and install reject symbolic
|
|
78
|
+
* links and other file types with UnsupportedFileTypeError before any write.
|
|
79
|
+
*
|
|
80
|
+
* Accepted file writes finish before cancellation can start rollback or release
|
|
81
|
+
* the lock. File writes and the original process group participate in the transaction.
|
|
82
|
+
* Scripts must not create escaped writers in independent groups or daemons.
|
|
83
|
+
* Failed or interrupted installs before commit restore backed-up package files byte-for-byte
|
|
84
|
+
* with recorded permissions and ownership, and remove tracked files that did not
|
|
85
|
+
* exist before installation. Writes made
|
|
86
|
+
* during installation are overwritten by rollback, never merged. When a lockfile
|
|
87
|
+
* existed, recovery also attempts to repair node_modules. Recovery failures are
|
|
88
|
+
* combined with the original cause. If process termination cannot be confirmed,
|
|
89
|
+
* no further restoration or recovery runs. Any failed rollback step also requires
|
|
90
|
+
* manual recovery, even if all writers stopped. Only successful installation or
|
|
91
|
+
* complete rollback permits snapshot deletion and reuse. RecoveryRequiredError
|
|
92
|
+
* and recoveryRequired expose the retained snapshot directory and complete cause;
|
|
93
|
+
* this manager rejects
|
|
94
|
+
* all later installs. Complete manual recovery before making a new manager.
|
|
95
|
+
* Committed installs report snapshot deletion failures in snapshotCleanupFailure
|
|
96
|
+
* rather than failing or rolling back. No crash recovery is promised.
|
|
58
97
|
*/
|
|
59
98
|
export declare const make: (options: Options) => Effect.Effect<PackageManager, Error, FileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner>;
|
|
60
|
-
export { Changes, PackageName };
|
|
99
|
+
export { Changes, PackageManagerDeclaration, PackageName, type SnapshotCleanupFailure, UnsupportedFileTypeError };
|
|
61
100
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;qBA+Ca,OAAK,OAAA;YAMN,eAAe,MAAM;;;;;;WAGd;;qBAFN,4BAA4B;;;;;;;;;;WAUtB;;qBAFN,8BAA8B;YAoC/B,QACT,sBACA,2BACA,wBACA,cAAc,gBACd,OAAO;iBACO;;WAEP;;WAEA,QAAQ;;WAER;;;qBAqDG,cAAW,SAAA,YAAA,OAAA,uDAAA,sBAAA,cAAA,gBAAA,OAAA,aAAA,WAAA,aAAA,KAAA;iBAkDP;WACP;;WAEA;WACA;;;YAGE,QAAQ,QAAQ,gBAAgB;iBAC3B;WACP;WACA,QAAQ;WACR,OAAO;;iBAEA;WACP,OAAO,cAAc;WACrB,SAAS,cAAc;WACvB,SAAS,cAAc;;qBAEpB,YAAS,QAAY,OAAK,OAAS,UAAQ;iBA0BvC,sBAAsB;WAC7B,OAAO;;WAEP,wBAAwB,OAAO,OAAO;;iBAE/B;WACP;WACA,OAAO;WACP,WAAW,OAAO,OAAO,OAAO;;WAEhC,kBAAkB,OAAO,OAAO,OAAO,OAAO;;WAE9C,UAAU,SAAS,YAAY,OAAO,OAAO,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6BzD,OAAI,SACP,YACP,OAAO,OACT,gBACA,OACA,WAAW,aAAa,KAAK,OAAO,oBAAoB"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { PackageManagerDeclaration, PackageManagerName } from "./PackageManagerDeclaration.js";
|
|
2
|
+
import { terminateProcess } from "./process.js";
|
|
3
|
+
import { UnsupportedFileTypeError, inspectManagedFiles, withSnapshot, writeSnapshot } from "./snapshot.js";
|
|
1
4
|
import { Changes, PackageName, applyChanges, decodeManifest, encodeManifest, fields } from "./manifest.js";
|
|
2
|
-
import { Array, Effect, Exit, FileSystem, HashMap, Option, Path, Record, Schema, Semaphore, String } from "effect";
|
|
5
|
+
import { Array, Data, Effect, Exit, FileSystem, HashMap, Option, Path, PlatformError, Record, Ref, Schema, Semaphore, String } from "effect";
|
|
3
6
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
4
7
|
// src/index.ts
|
|
5
8
|
/** Non-interactive package installation. Provide platform services at the application boundary. */
|
|
@@ -19,6 +22,21 @@ var PackageManagerError = class extends Schema.TaggedError()("PackageManagerErro
|
|
|
19
22
|
message: Schema.String,
|
|
20
23
|
exitCode: Schema.optionalKey(Schema.Int)
|
|
21
24
|
}) {};
|
|
25
|
+
var RecoveryRequiredError = class extends Schema.TaggedError()("RecoveryRequiredError", {
|
|
26
|
+
directory: Schema.String,
|
|
27
|
+
snapshotDirectory: Schema.String,
|
|
28
|
+
operation: Schema.Literals([
|
|
29
|
+
"install",
|
|
30
|
+
"recover",
|
|
31
|
+
"rollback"
|
|
32
|
+
]),
|
|
33
|
+
processId: Schema.optionalKey(Schema.Int),
|
|
34
|
+
message: Schema.String,
|
|
35
|
+
terminationCause: Schema.optionalKey(Schema.Cause(Schema.Unknown, Schema.Unknown)),
|
|
36
|
+
recoveryCause: Schema.Cause(Schema.Unknown, Schema.Unknown)
|
|
37
|
+
}) {};
|
|
38
|
+
const WriterState = Data.taggedEnum();
|
|
39
|
+
const ManagerState = Data.taggedEnum();
|
|
22
40
|
const lockfiles = [
|
|
23
41
|
"package-lock.json",
|
|
24
42
|
"npm-shrinkwrap.json",
|
|
@@ -37,20 +55,45 @@ const backupFiles = [
|
|
|
37
55
|
".pnp.loader.mjs"
|
|
38
56
|
];
|
|
39
57
|
const executable = (agent) => String.startsWith("yarn")(agent) ? "yarn" : agent;
|
|
58
|
+
const readSource = Effect.fnUntraced(function* (fs, file) {
|
|
59
|
+
const bytes = yield* fs.readFile(file);
|
|
60
|
+
return yield* Effect.try({
|
|
61
|
+
try: () => new TextDecoder("utf-8", {
|
|
62
|
+
ignoreBOM: true,
|
|
63
|
+
fatal: true
|
|
64
|
+
}).decode(bytes),
|
|
65
|
+
catch: (cause) => PlatformError.badArgument({
|
|
66
|
+
module: "FileSystem",
|
|
67
|
+
method: "readManifest",
|
|
68
|
+
description: "The manifest must contain valid UTF-8",
|
|
69
|
+
cause
|
|
70
|
+
})
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
const Executable = PackageManagerName;
|
|
74
|
+
const Digits = Schema.String.check(Schema.isPattern(/^\d+$/));
|
|
75
|
+
const decodePackageManager = Schema.decodeUnknownOption(PackageManagerDeclaration);
|
|
76
|
+
/** `name/version ...`, as package managers set `npm_config_user_agent`. */
|
|
77
|
+
const decodeUserAgent = Schema.decodeUnknownOption(Schema.TemplateLiteralParser([
|
|
78
|
+
Executable,
|
|
79
|
+
"/",
|
|
80
|
+
Digits,
|
|
81
|
+
Schema.String
|
|
82
|
+
]));
|
|
83
|
+
const agentOf = (name, major) => name === "yarn" ? major === "1" ? "yarn-classic" : "yarn-berry" : name;
|
|
40
84
|
/** packageManager, then lockfile, then caller user-agent, then npm. Conflicting lockfiles fail. */
|
|
41
85
|
const detectAgent = Effect.fnUntraced(function* (options) {
|
|
42
86
|
if (options.agent !== void 0) return yield* Schema.decodeEffect(Agent)(options.agent);
|
|
43
87
|
const fs = yield* FileSystem.FileSystem;
|
|
44
88
|
const path = yield* Path.Path;
|
|
45
|
-
const manifest = yield* fs
|
|
46
|
-
if (manifest.packageManager !== void 0) {
|
|
47
|
-
|
|
48
|
-
if (match === null) return yield* PackageManagerError.make({
|
|
89
|
+
const manifest = yield* readSource(fs, path.join(options.directory, "package.json")).pipe(Effect.flatMap(decodeManifest));
|
|
90
|
+
if (manifest.packageManager !== void 0) return yield* Option.match(decodePackageManager(manifest.packageManager), {
|
|
91
|
+
onNone: () => PackageManagerError.make({
|
|
49
92
|
operation: "detect",
|
|
50
93
|
message: `Unsupported packageManager: ${manifest.packageManager}`
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
}
|
|
94
|
+
}),
|
|
95
|
+
onSome: ([name, , version]) => Effect.succeed(agentOf(name, `${version.major}`))
|
|
96
|
+
});
|
|
54
97
|
const found = yield* Effect.filter(lockfiles, (file) => fs.exists(path.join(options.directory, file)));
|
|
55
98
|
const kinds = Array.dedupe(Array.map(found, (file) => file === "pnpm-lock.yaml" ? "pnpm" : file === "yarn.lock" ? "yarn" : "npm"));
|
|
56
99
|
if (kinds.length > 1) return yield* PackageManagerError.make({
|
|
@@ -62,8 +105,10 @@ const detectAgent = Effect.fnUntraced(function* (options) {
|
|
|
62
105
|
return /^__metadata:/m.test(lock) ? "yarn-berry" : "yarn-classic";
|
|
63
106
|
}
|
|
64
107
|
if (kinds[0] !== void 0) return kinds[0];
|
|
65
|
-
|
|
66
|
-
|
|
108
|
+
return Option.match(decodeUserAgent(options.userAgent ?? ""), {
|
|
109
|
+
onNone: () => "npm",
|
|
110
|
+
onSome: ([name, , major]) => agentOf(name, major)
|
|
111
|
+
});
|
|
67
112
|
});
|
|
68
113
|
const diffState = (before, after) => {
|
|
69
114
|
const changes = Array.map(Array.sort(Array.dedupe([...HashMap.keys(before), ...HashMap.keys(after)]), String.Order), (name) => ({
|
|
@@ -78,22 +123,45 @@ const diffState = (before, after) => {
|
|
|
78
123
|
};
|
|
79
124
|
};
|
|
80
125
|
/**
|
|
81
|
-
* Own one manager per project.
|
|
82
|
-
*
|
|
83
|
-
*
|
|
126
|
+
* Own one manager per project. The caller must give this manager and its child
|
|
127
|
+
* processes exclusive write access to the project for each install, including
|
|
128
|
+
* recovery. Do not edit project files or run another installer concurrently.
|
|
129
|
+
* Calls are serialized only within this manager; no cross-process lock is taken.
|
|
130
|
+
* Managed paths must be regular files or absent. make and install reject symbolic
|
|
131
|
+
* links and other file types with UnsupportedFileTypeError before any write.
|
|
132
|
+
*
|
|
133
|
+
* Accepted file writes finish before cancellation can start rollback or release
|
|
134
|
+
* the lock. File writes and the original process group participate in the transaction.
|
|
135
|
+
* Scripts must not create escaped writers in independent groups or daemons.
|
|
136
|
+
* Failed or interrupted installs before commit restore backed-up package files byte-for-byte
|
|
137
|
+
* with recorded permissions and ownership, and remove tracked files that did not
|
|
138
|
+
* exist before installation. Writes made
|
|
139
|
+
* during installation are overwritten by rollback, never merged. When a lockfile
|
|
140
|
+
* existed, recovery also attempts to repair node_modules. Recovery failures are
|
|
141
|
+
* combined with the original cause. If process termination cannot be confirmed,
|
|
142
|
+
* no further restoration or recovery runs. Any failed rollback step also requires
|
|
143
|
+
* manual recovery, even if all writers stopped. Only successful installation or
|
|
144
|
+
* complete rollback permits snapshot deletion and reuse. RecoveryRequiredError
|
|
145
|
+
* and recoveryRequired expose the retained snapshot directory and complete cause;
|
|
146
|
+
* this manager rejects
|
|
147
|
+
* all later installs. Complete manual recovery before making a new manager.
|
|
148
|
+
* Committed installs report snapshot deletion failures in snapshotCleanupFailure
|
|
149
|
+
* rather than failing or rolling back. No crash recovery is promised.
|
|
84
150
|
*/
|
|
85
151
|
const make = (options) => Effect.gen(function* () {
|
|
86
152
|
const fs = yield* FileSystem.FileSystem;
|
|
87
153
|
const path = yield* Path.Path;
|
|
88
154
|
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
89
155
|
const directory = path.resolve(options.directory);
|
|
156
|
+
yield* inspectManagedFiles(fs, path, directory, backupFiles);
|
|
90
157
|
const agent = yield* detectAgent({
|
|
91
158
|
...options,
|
|
92
159
|
directory
|
|
93
160
|
});
|
|
94
161
|
const lock = yield* Semaphore.make(1);
|
|
162
|
+
const transaction = yield* Ref.make(ManagerState.Ready());
|
|
95
163
|
const manifestFile = path.join(directory, "package.json");
|
|
96
|
-
const readManifest = fs
|
|
164
|
+
const readManifest = readSource(fs, manifestFile).pipe(Effect.flatMap(decodeManifest));
|
|
97
165
|
const installed = Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Struct({ version: Schema.optionalKey(Schema.String) })));
|
|
98
166
|
const stateOf = Effect.fnUntraced(function* (manifest) {
|
|
99
167
|
if (yield* fs.exists(path.join(directory, ".pnp.cjs"))) return yield* PackageManagerError.make({
|
|
@@ -120,6 +188,7 @@ const make = (options) => Effect.gen(function* () {
|
|
|
120
188
|
return HashMap.fromIterable(entries);
|
|
121
189
|
});
|
|
122
190
|
const readState = Effect.flatMap(readManifest, stateOf);
|
|
191
|
+
const termination = { forceKillAfter: "5 seconds" };
|
|
123
192
|
const run = Effect.fnUntraced(function* (operation) {
|
|
124
193
|
const recovery = operation === "recover";
|
|
125
194
|
const args = agent === "npm" ? [
|
|
@@ -136,12 +205,14 @@ const make = (options) => Effect.gen(function* () {
|
|
|
136
205
|
"--non-interactive",
|
|
137
206
|
...recovery ? ["--frozen-lockfile", "--prefer-offline"] : []
|
|
138
207
|
] : ["install", ...recovery ? ["--immutable"] : []];
|
|
139
|
-
|
|
208
|
+
return yield* Effect.acquireUseRelease(spawner.spawn(ChildProcess.make(executable(agent), args, {
|
|
140
209
|
cwd: directory,
|
|
141
210
|
extendEnv: true,
|
|
142
211
|
stdin: "ignore",
|
|
143
212
|
stdout: "inherit",
|
|
144
213
|
stderr: "inherit",
|
|
214
|
+
detached: true,
|
|
215
|
+
...termination,
|
|
145
216
|
env: {
|
|
146
217
|
CI: "true",
|
|
147
218
|
...agent === "yarn-berry" ? {
|
|
@@ -149,56 +220,105 @@ const make = (options) => Effect.gen(function* () {
|
|
|
149
220
|
YARN_NODE_LINKER: "node-modules"
|
|
150
221
|
} : {}
|
|
151
222
|
}
|
|
152
|
-
})).pipe(Effect.
|
|
153
|
-
|
|
154
|
-
|
|
223
|
+
})).pipe(Effect.tap(() => Ref.set(transaction, ManagerState.Active({ writer: WriterState.Running() })))), (process) => Effect.gen(function* () {
|
|
224
|
+
const code = yield* process.exitCode.pipe(Effect.timeoutOrElse({
|
|
225
|
+
duration: "10 minutes",
|
|
226
|
+
orElse: () => PackageManagerError.make({
|
|
227
|
+
operation,
|
|
228
|
+
message: `${executable(agent)} ${operation} timed out`
|
|
229
|
+
})
|
|
230
|
+
}));
|
|
231
|
+
if (code !== 0) return yield* PackageManagerError.make({
|
|
155
232
|
operation,
|
|
156
|
-
|
|
157
|
-
|
|
233
|
+
exitCode: code,
|
|
234
|
+
message: `${executable(agent)} ${operation} exited with code ${code}`
|
|
235
|
+
});
|
|
236
|
+
}), (process) => Effect.gen(function* () {
|
|
237
|
+
const result = yield* terminateProcess(process, termination);
|
|
238
|
+
yield* Ref.set(transaction, ManagerState.Active({ writer: result._tag === "OriginalGroupStopped" ? WriterState.ManagedWritersIdle() : WriterState.Unconfirmed({
|
|
239
|
+
operation,
|
|
240
|
+
processId: process.pid,
|
|
241
|
+
cause: result.cause
|
|
242
|
+
}) }));
|
|
243
|
+
if (result._tag === "Unconfirmed") return yield* Effect.failCause(result.cause);
|
|
158
244
|
}));
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
exitCode: code,
|
|
162
|
-
message: `${executable(agent)} ${operation} exited with code ${code}`
|
|
163
|
-
});
|
|
164
|
-
});
|
|
245
|
+
}, Effect.scoped);
|
|
246
|
+
const withFileWriter = (effect) => Effect.acquireUseRelease(Ref.set(transaction, ManagerState.Active({ writer: WriterState.FileWrite() })), () => effect, () => Ref.set(transaction, ManagerState.Active({ writer: WriterState.ManagedWritersIdle() }))).pipe(Effect.uninterruptible);
|
|
165
247
|
const install = (changes) => lock.withPermits(1)(Effect.gen(function* () {
|
|
248
|
+
const state = yield* Ref.get(transaction);
|
|
249
|
+
if (state._tag === "RecoveryRequired") return yield* state.error;
|
|
166
250
|
const validated = yield* Schema.decodeEffect(Changes)(changes);
|
|
167
|
-
const
|
|
168
|
-
const
|
|
169
|
-
const before = yield* stateOf(manifest);
|
|
170
|
-
const text = yield* encodeManifest(applyChanges(manifest, validated), original);
|
|
171
|
-
const backups = yield* Effect.forEach(backupFiles, (name) => Effect.gen(function* () {
|
|
172
|
-
const file = path.join(directory, name);
|
|
251
|
+
const inspected = yield* inspectManagedFiles(fs, path, directory, backupFiles);
|
|
252
|
+
const backups = yield* Effect.forEach(inspected, ({ name, file, metadata }) => Effect.gen(function* () {
|
|
173
253
|
return {
|
|
174
254
|
name,
|
|
175
255
|
file,
|
|
176
|
-
|
|
256
|
+
contents: yield* Option.match(metadata, {
|
|
257
|
+
onNone: () => Effect.succeedNone,
|
|
258
|
+
onSome: (info) => fs.readFile(file).pipe(Effect.map((bytes) => Option.some({
|
|
259
|
+
...info,
|
|
260
|
+
bytes
|
|
261
|
+
})))
|
|
262
|
+
})
|
|
177
263
|
};
|
|
178
264
|
}));
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
265
|
+
const original = yield* readSource(fs, manifestFile);
|
|
266
|
+
const manifest = yield* decodeManifest(original);
|
|
267
|
+
const before = yield* stateOf(manifest);
|
|
268
|
+
const text = yield* encodeManifest(applyChanges(manifest, validated), original);
|
|
183
269
|
const agentLocks = agent === "npm" ? ["package-lock.json", "npm-shrinkwrap.json"] : agent === "pnpm" ? ["pnpm-lock.yaml"] : ["yarn.lock"];
|
|
184
|
-
const hasLock = Array.some(backups, ({ name,
|
|
185
|
-
|
|
186
|
-
yield* fs
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
270
|
+
const hasLock = Array.some(backups, ({ name, contents }) => Array.contains(agentLocks, name) && Option.isSome(contents));
|
|
271
|
+
const completed = yield* withSnapshot(fs, Ref.get(transaction).pipe(Effect.map((state) => state._tag === "Ready")), (snapshotDirectory) => Effect.gen(function* () {
|
|
272
|
+
const snapshot = yield* writeSnapshot(fs, path, snapshotDirectory, directory, agent, backups);
|
|
273
|
+
const restore = Effect.flatMap(Ref.get(transaction), (state) => state._tag === "Active" && state.writer._tag === "ManagedWritersIdle" ? withFileWriter(snapshot.restore(state.writer)) : Effect.void);
|
|
274
|
+
return yield* Effect.acquireUseRelease(Ref.set(transaction, ManagerState.Active({ writer: WriterState.ManagedWritersIdle() })), () => Effect.gen(function* () {
|
|
275
|
+
yield* withFileWriter(fs.writeFileString(manifestFile, text));
|
|
276
|
+
yield* run("install");
|
|
277
|
+
const after = yield* readState;
|
|
278
|
+
return {
|
|
279
|
+
agent,
|
|
280
|
+
...diffState(before, after)
|
|
281
|
+
};
|
|
282
|
+
}), (_, exit) => Effect.gen(function* () {
|
|
283
|
+
if (Exit.isFailure(exit)) {
|
|
284
|
+
const state = yield* Ref.get(transaction);
|
|
285
|
+
if (state._tag !== "Active" || state.writer._tag !== "ManagedWritersIdle") return;
|
|
286
|
+
yield* withFileWriter(snapshot.restore(state.writer));
|
|
287
|
+
if (hasLock) yield* run("recover").pipe(Effect.onExit(() => restore));
|
|
288
|
+
}
|
|
289
|
+
yield* Ref.set(transaction, ManagerState.Ready());
|
|
290
|
+
})).pipe(Effect.onExit((exit) => Effect.gen(function* () {
|
|
291
|
+
const state = yield* Ref.get(transaction);
|
|
292
|
+
if (Exit.isSuccess(exit) || state._tag !== "Active") return;
|
|
293
|
+
const writer = state.writer;
|
|
294
|
+
const error = RecoveryRequiredError.make({
|
|
295
|
+
directory,
|
|
296
|
+
snapshotDirectory,
|
|
297
|
+
operation: writer._tag === "Unconfirmed" ? writer.operation : "rollback",
|
|
298
|
+
...writer._tag === "Unconfirmed" ? {
|
|
299
|
+
processId: writer.processId,
|
|
300
|
+
terminationCause: writer.cause
|
|
301
|
+
} : {},
|
|
302
|
+
message: `Manual recovery is required. Stop all writers before restoring the snapshot at ${snapshotDirectory}`,
|
|
303
|
+
recoveryCause: exit.cause
|
|
304
|
+
});
|
|
305
|
+
yield* Ref.set(transaction, ManagerState.RecoveryRequired({ error }));
|
|
306
|
+
return yield* error;
|
|
307
|
+
})));
|
|
308
|
+
}));
|
|
309
|
+
return {
|
|
310
|
+
...completed.value,
|
|
311
|
+
snapshotCleanupFailure: completed.snapshotCleanupFailure
|
|
312
|
+
};
|
|
194
313
|
}));
|
|
195
314
|
return {
|
|
196
315
|
directory,
|
|
197
316
|
agent,
|
|
317
|
+
recoveryRequired: Ref.get(transaction).pipe(Effect.map((state) => state._tag === "RecoveryRequired" ? Option.some(state.error) : Option.none())),
|
|
198
318
|
readState: lock.withPermits(1)(readState),
|
|
199
319
|
install
|
|
200
320
|
};
|
|
201
321
|
});
|
|
202
|
-
export { Agent, Changes, PackageManagerError, PackageName, detectAgent, diffState, make };
|
|
322
|
+
export { Agent, Changes, PackageManagerDeclaration, PackageManagerError, PackageName, RecoveryRequiredError, UnsupportedFileTypeError, detectAgent, diffState, make };
|
|
203
323
|
|
|
204
324
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Str","Arr"],"sources":["../src/index.ts"],"sourcesContent":["/** Non-interactive package installation. Provide platform services at the application boundary. */\nimport {\n\tArray as Arr,\n\tEffect,\n\tExit,\n\tFileSystem,\n\tHashMap,\n\tOption,\n\tPath,\n\tRecord,\n\tSchema,\n\tSemaphore,\n\tString as Str,\n} from \"effect\"\nimport type { PlatformError } from \"effect\"\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\"\nimport {\n\tapplyChanges,\n\tChanges,\n\tdecodeManifest,\n\tencodeManifest,\n\tfields,\n\ttype Manifest,\n} from \"./manifest\"\nexport { Changes, PackageName } from \"./manifest\"\n\nexport const Agent = Schema.Literals([\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn-classic\",\n\t\"yarn-berry\",\n])\nexport type Agent = typeof Agent.Type\nexport class PackageManagerError extends Schema.TaggedError<\n\tPackageManagerError,\n\t{ readonly brand: unique symbol }\n>()(\"PackageManagerError\", {\n\toperation: Schema.Literals([\"detect\", \"install\", \"recover\", \"state\"]),\n\tmessage: Schema.String,\n\texitCode: Schema.optionalKey(Schema.Int),\n}) {}\nexport type Error =\n\tPackageManagerError | PlatformError.PlatformError | Schema.SchemaError\nexport interface Options {\n\t/** Project directory, containing package.json. Use the workspace root for workspace installs. */\n\treadonly directory: string\n\t/** Explicit selection takes precedence over detection. */\n\treadonly agent?: Agent\n\t/** Optional npm_config_user_agent supplied by the caller; used only as a fallback. */\n\treadonly userAgent?: string\n}\nconst lockfiles = [\n\t\"package-lock.json\",\n\t\"npm-shrinkwrap.json\",\n\t\"pnpm-lock.yaml\",\n\t\"yarn.lock\",\n] as const\nconst backupFiles = [\n\t\"package.json\",\n\t...lockfiles,\n\t\".npmrc\",\n\t\"pnpm-workspace.yaml\",\n\t\".yarnrc\",\n\t\".yarnrc.yml\",\n\t\".yarn/install-state.gz\",\n\t\".pnp.cjs\",\n\t\".pnp.loader.mjs\",\n]\nconst executable = (agent: Agent) =>\n\tStr.startsWith(\"yarn\")(agent) ? \"yarn\" : agent\n\n/** packageManager, then lockfile, then caller user-agent, then npm. Conflicting lockfiles fail. */\nexport const detectAgent = Effect.fnUntraced(function* (options: Options) {\n\tif (options.agent !== undefined)\n\t\treturn yield* Schema.decodeEffect(Agent)(options.agent)\n\tconst fs = yield* FileSystem.FileSystem\n\tconst path = yield* Path.Path\n\tconst manifest = yield* fs\n\t\t.readFileString(path.join(options.directory, \"package.json\"))\n\t\t.pipe(Effect.flatMap(decodeManifest))\n\tif (manifest.packageManager !== undefined) {\n\t\tconst match = /^(npm|pnpm|yarn)@(\\d+)\\.\\d+\\.\\d+(?:[-+].*)?$/.exec(\n\t\t\tmanifest.packageManager,\n\t\t)\n\t\tif (match === null)\n\t\t\treturn yield* PackageManagerError.make({\n\t\t\t\toperation: \"detect\",\n\t\t\t\tmessage: `Unsupported packageManager: ${manifest.packageManager}`,\n\t\t\t})\n\t\treturn match[1] === \"yarn\"\n\t\t\t? match[2] === \"1\"\n\t\t\t\t? \"yarn-classic\"\n\t\t\t\t: \"yarn-berry\"\n\t\t\t: (match[1] as \"npm\" | \"pnpm\")\n\t}\n\tconst found = yield* Effect.filter(lockfiles, (file) =>\n\t\tfs.exists(path.join(options.directory, file)),\n\t)\n\tconst kinds = Arr.dedupe(\n\t\tArr.map(found, (file) =>\n\t\t\tfile === \"pnpm-lock.yaml\"\n\t\t\t\t? \"pnpm\"\n\t\t\t\t: file === \"yarn.lock\"\n\t\t\t\t\t? \"yarn\"\n\t\t\t\t\t: \"npm\",\n\t\t),\n\t)\n\tif (kinds.length > 1)\n\t\treturn yield* PackageManagerError.make({\n\t\t\toperation: \"detect\",\n\t\t\tmessage: \"Conflicting lockfiles; select an agent explicitly\",\n\t\t})\n\tif (kinds[0] === \"yarn\") {\n\t\tconst lock = yield* fs.readFileString(\n\t\t\tpath.join(options.directory, \"yarn.lock\"),\n\t\t)\n\t\treturn /^__metadata:/m.test(lock) ? \"yarn-berry\" : \"yarn-classic\"\n\t}\n\tif (kinds[0] !== undefined) return kinds[0]\n\tconst caller = /^(npm|pnpm|yarn)\\/(\\d+)/.exec(options.userAgent ?? \"\")\n\treturn caller?.[1] === \"yarn\"\n\t\t? caller[2] === \"1\"\n\t\t\t? \"yarn-classic\"\n\t\t\t: \"yarn-berry\"\n\t\t: caller?.[1] === \"pnpm\"\n\t\t\t? \"pnpm\"\n\t\t\t: \"npm\"\n})\n\nexport interface PackageState {\n\treadonly spec: string\n\t/** Missing optional or not-yet-installed dependencies have no version/path. */\n\treadonly version: string | undefined\n\treadonly path: string | undefined\n}\n/** Direct dependencies only, keyed by their manifest names (including aliases). */\nexport type State = HashMap.HashMap<string, PackageState>\nexport interface PackageChange {\n\treadonly name: string\n\treadonly before: PackageState | undefined\n\treadonly after: PackageState | undefined\n}\nexport interface StateDiff {\n\treadonly added: ReadonlyArray<PackageChange>\n\treadonly removed: ReadonlyArray<PackageChange>\n\treadonly updated: ReadonlyArray<PackageChange>\n}\nexport const diffState = (before: State, after: State): StateDiff => {\n\tconst changes = Arr.map(\n\t\tArr.sort(\n\t\t\tArr.dedupe([...HashMap.keys(before), ...HashMap.keys(after)]),\n\t\t\tStr.Order,\n\t\t),\n\t\t(name) => ({\n\t\t\tname,\n\t\t\tbefore: Option.getOrUndefined(HashMap.get(before, name)),\n\t\t\tafter: Option.getOrUndefined(HashMap.get(after, name)),\n\t\t}),\n\t)\n\treturn {\n\t\tadded: Arr.filter(changes, (change) => change.before === undefined),\n\t\tremoved: Arr.filter(changes, (change) => change.after === undefined),\n\t\tupdated: Arr.filter(\n\t\t\tchanges,\n\t\t\t({ before, after }) =>\n\t\t\t\tbefore !== undefined &&\n\t\t\t\tafter !== undefined &&\n\t\t\t\t(before.spec !== after.spec ||\n\t\t\t\t\tbefore.version !== after.version ||\n\t\t\t\t\tbefore.path !== after.path),\n\t\t),\n\t}\n}\nexport interface InstallResult extends StateDiff {\n\treadonly agent: Agent\n}\nexport interface PackageManager {\n\treadonly directory: string\n\treadonly agent: Agent\n\treadonly readState: Effect.Effect<State, Error>\n\t/** Serialized per manager. Empty changes installs the current manifest, including first installs. */\n\treadonly install: (changes: Changes) => Effect.Effect<InstallResult, Error>\n}\n\n/**\n * Own one manager per project. Failed or interrupted installs restore the exact\n * manifest/lockfiles, then attempt to repair node_modules when a lockfile existed.\n * Recovery failures are combined with the original cause. No crash recovery is promised.\n */\nexport const make = (\n\toptions: Options,\n): Effect.Effect<\n\tPackageManager,\n\tError,\n\tFileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner\n> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem\n\t\tconst path = yield* Path.Path\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner\n\t\tconst directory = path.resolve(options.directory)\n\t\tconst agent = yield* detectAgent({ ...options, directory })\n\t\tconst lock = yield* Semaphore.make(1)\n\t\tconst manifestFile = path.join(directory, \"package.json\")\n\t\tconst readManifest = fs\n\t\t\t.readFileString(manifestFile)\n\t\t\t.pipe(Effect.flatMap(decodeManifest))\n\t\tconst installed = Schema.decodeUnknownEffect(\n\t\t\tSchema.fromJsonString(\n\t\t\t\tSchema.Struct({ version: Schema.optionalKey(Schema.String) }),\n\t\t\t),\n\t\t)\n\t\tconst stateOf = Effect.fnUntraced(function* (manifest: Manifest) {\n\t\t\tif (yield* fs.exists(path.join(directory, \".pnp.cjs\")))\n\t\t\t\treturn yield* PackageManagerError.make({\n\t\t\t\t\toperation: \"state\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Plug'n'Play is not supported; configure Yarn with nodeLinker: node-modules\",\n\t\t\t\t})\n\t\t\tconst deps = Arr.reduce(\n\t\t\t\tfields,\n\t\t\t\t{} as Readonly<Record<string, string>>,\n\t\t\t\t(all, field) => ({ ...all, ...manifest[field] }),\n\t\t\t)\n\t\t\tconst entries = yield* Effect.forEach(\n\t\t\t\tRecord.toEntries(deps),\n\t\t\t\t([name, spec]) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst file = path.join(\n\t\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\t\t\"node_modules\",\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\"package.json\",\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (!(yield* fs.exists(file)))\n\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t{ spec, version: undefined, path: undefined },\n\t\t\t\t\t\t\t] as const\n\t\t\t\t\t\tconst pkg = yield* fs\n\t\t\t\t\t\t\t.readFileString(file)\n\t\t\t\t\t\t\t.pipe(Effect.flatMap(installed))\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tspec,\n\t\t\t\t\t\t\t\tversion: pkg.version,\n\t\t\t\t\t\t\t\tpath: yield* fs.realPath(path.dirname(file)),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t] as const\n\t\t\t\t\t}),\n\t\t\t)\n\t\t\treturn HashMap.fromIterable<string, PackageState>(entries)\n\t\t})\n\t\tconst readState = Effect.flatMap(readManifest, stateOf)\n\t\tconst run = Effect.fnUntraced(function* (operation: \"install\" | \"recover\") {\n\t\t\tconst recovery = operation === \"recover\"\n\t\t\tconst args =\n\t\t\t\tagent === \"npm\"\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\"--no-audit\",\n\t\t\t\t\t\t\t\"--no-fund\",\n\t\t\t\t\t\t\t...(recovery ? [\"--prefer-offline\"] : []),\n\t\t\t\t\t\t]\n\t\t\t\t\t: agent === \"pnpm\"\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\trecovery ? \"--frozen-lockfile\" : \"--no-frozen-lockfile\",\n\t\t\t\t\t\t\t\t\"--config.confirmModulesPurge=false\",\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: agent === \"yarn-classic\"\n\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\t\t\"--non-interactive\",\n\t\t\t\t\t\t\t\t\t...(recovery\n\t\t\t\t\t\t\t\t\t\t? [\"--frozen-lockfile\", \"--prefer-offline\"]\n\t\t\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t: [\"install\", ...(recovery ? [\"--immutable\"] : [])]\n\t\t\tconst code = yield* spawner\n\t\t\t\t.exitCode(\n\t\t\t\t\tChildProcess.make(executable(agent), args, {\n\t\t\t\t\t\tcwd: directory,\n\t\t\t\t\t\textendEnv: true,\n\t\t\t\t\t\tstdin: \"ignore\",\n\t\t\t\t\t\tstdout: \"inherit\",\n\t\t\t\t\t\tstderr: \"inherit\",\n\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\tCI: \"true\",\n\t\t\t\t\t\t\t...(agent === \"yarn-berry\"\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tYARN_ENABLE_IMMUTABLE_INSTALLS: recovery ? \"true\" : \"false\",\n\t\t\t\t\t\t\t\t\t\tYARN_NODE_LINKER: \"node-modules\",\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.pipe(\n\t\t\t\t\tEffect.timeoutOrElse({\n\t\t\t\t\t\tduration: \"10 minutes\",\n\t\t\t\t\t\torElse: () =>\n\t\t\t\t\t\t\tPackageManagerError.make({\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\tmessage: `${executable(agent)} ${operation} timed out`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\tif (code !== 0)\n\t\t\t\treturn yield* PackageManagerError.make({\n\t\t\t\t\toperation,\n\t\t\t\t\texitCode: code,\n\t\t\t\t\tmessage: `${executable(agent)} ${operation} exited with code ${code}`,\n\t\t\t\t})\n\t\t})\n\t\tconst install = (changes: Changes) =>\n\t\t\tlock.withPermits(1)(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst validated = yield* Schema.decodeEffect(Changes)(changes)\n\t\t\t\t\tconst original = yield* fs.readFileString(manifestFile)\n\t\t\t\t\tconst manifest = yield* decodeManifest(original)\n\t\t\t\t\tconst before = yield* stateOf(manifest)\n\t\t\t\t\tconst text = yield* encodeManifest(\n\t\t\t\t\t\tapplyChanges(manifest, validated),\n\t\t\t\t\t\toriginal,\n\t\t\t\t\t)\n\t\t\t\t\tconst backups = yield* Effect.forEach(backupFiles, (name) =>\n\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\tconst file = path.join(directory, name)\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tfile,\n\t\t\t\t\t\t\t\tbytes: (yield* fs.exists(file))\n\t\t\t\t\t\t\t\t\t? yield* fs.readFile(file).pipe(Effect.asSome)\n\t\t\t\t\t\t\t\t\t: Option.none<Uint8Array>(),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t// Every file gets a restoration attempt; onExit combines failures.\n\t\t\t\t\tconst restore = Arr.reduce<\n\t\t\t\t\t\t(typeof backups)[number],\n\t\t\t\t\t\tEffect.Effect<void, PlatformError.PlatformError>\n\t\t\t\t\t>(backups, Effect.void, (previous, { file, bytes }) =>\n\t\t\t\t\t\tprevious.pipe(\n\t\t\t\t\t\t\tEffect.onExit(() =>\n\t\t\t\t\t\t\t\tOption.match(bytes, {\n\t\t\t\t\t\t\t\t\tonNone: () => fs.remove(file, { force: true }),\n\t\t\t\t\t\t\t\t\tonSome: (bytes) => fs.writeFile(file, bytes),\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t\tconst agentLocks =\n\t\t\t\t\t\tagent === \"npm\"\n\t\t\t\t\t\t\t? [\"package-lock.json\", \"npm-shrinkwrap.json\"]\n\t\t\t\t\t\t\t: agent === \"pnpm\"\n\t\t\t\t\t\t\t\t? [\"pnpm-lock.yaml\"]\n\t\t\t\t\t\t\t\t: [\"yarn.lock\"]\n\t\t\t\t\tconst hasLock = Arr.some(\n\t\t\t\t\t\tbackups,\n\t\t\t\t\t\t({ name, bytes }) =>\n\t\t\t\t\t\t\tArr.contains(agentLocks, name) && Option.isSome(bytes),\n\t\t\t\t\t)\n\t\t\t\t\treturn yield* Effect.acquireUseRelease(\n\t\t\t\t\t\tEffect.void,\n\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tyield* fs.writeFileString(manifestFile, text)\n\t\t\t\t\t\t\t\tyield* run(\"install\")\n\t\t\t\t\t\t\t\tconst after = yield* readState\n\t\t\t\t\t\t\t\treturn { agent, ...diffState(before, after) }\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t(_, exit) =>\n\t\t\t\t\t\t\tExit.isSuccess(exit)\n\t\t\t\t\t\t\t\t? Effect.void\n\t\t\t\t\t\t\t\t: restore.pipe(\n\t\t\t\t\t\t\t\t\t\tEffect.andThen(hasLock ? run(\"recover\") : Effect.void),\n\t\t\t\t\t\t\t\t\t\t// Recovery itself may rewrite the manifest or lockfile, including on failure.\n\t\t\t\t\t\t\t\t\t\tEffect.onExit(() => restore),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t)\n\t\t\t\t}),\n\t\t\t)\n\t\treturn {\n\t\t\tdirectory,\n\t\t\tagent,\n\t\t\treadState: lock.withPermits(1)(readState),\n\t\t\tinstall,\n\t\t}\n\t})\n"],"mappings":";;;;;AA0BA,MAAa,QAAQ,OAAO,SAAS;CACpC;CACA;CACA;CACA;AACD,CAAC;AAED,IAAa,sBAAb,cAAyC,OAAO,YAG9C,CAAC,CAAC,uBAAuB;CAC1B,WAAW,OAAO,SAAS;EAAC;EAAU;EAAW;EAAW;CAAO,CAAC;CACpE,SAAS,OAAO;CAChB,UAAU,OAAO,YAAY,OAAO,GAAG;AACxC,CAAC,CAAC,CAAC,CAAC;AAWJ,MAAM,YAAY;CACjB;CACA;CACA;CACA;AACD;AACA,MAAM,cAAc;CACnB;CACA,GAAG;CACH;CACA;CACA;CACA;CACA;CACA;CACA;AACD;AACA,MAAM,cAAc,UACnBA,OAAI,WAAW,MAAM,CAAC,CAAC,KAAK,IAAI,SAAS;;AAG1C,MAAa,cAAc,OAAO,WAAW,WAAW,SAAkB;CACzE,IAAI,QAAQ,UAAU,KAAA,GACrB,OAAO,OAAO,OAAO,aAAa,KAAK,CAAC,CAAC,QAAQ,KAAK;CACvD,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,WAAW,OAAO,GACtB,eAAe,KAAK,KAAK,QAAQ,WAAW,cAAc,CAAC,CAAC,CAC5D,KAAK,OAAO,QAAQ,cAAc,CAAC;CACrC,IAAI,SAAS,mBAAmB,KAAA,GAAW;EAC1C,MAAM,QAAQ,+CAA+C,KAC5D,SAAS,cACV;EACA,IAAI,UAAU,MACb,OAAO,OAAO,oBAAoB,KAAK;GACtC,WAAW;GACX,SAAS,+BAA+B,SAAS;EAClD,CAAC;EACF,OAAO,MAAM,OAAO,SACjB,MAAM,OAAO,MACZ,iBACA,eACA,MAAM;CACX;CACA,MAAM,QAAQ,OAAO,OAAO,OAAO,YAAY,SAC9C,GAAG,OAAO,KAAK,KAAK,QAAQ,WAAW,IAAI,CAAC,CAC7C;CACA,MAAM,QAAQC,MAAI,OACjBA,MAAI,IAAI,QAAQ,SACf,SAAS,mBACN,SACA,SAAS,cACR,SACA,KACL,CACD;CACA,IAAI,MAAM,SAAS,GAClB,OAAO,OAAO,oBAAoB,KAAK;EACtC,WAAW;EACX,SAAS;CACV,CAAC;CACF,IAAI,MAAM,OAAO,QAAQ;EACxB,MAAM,OAAO,OAAO,GAAG,eACtB,KAAK,KAAK,QAAQ,WAAW,WAAW,CACzC;EACA,OAAO,gBAAgB,KAAK,IAAI,IAAI,eAAe;CACpD;CACA,IAAI,MAAM,OAAO,KAAA,GAAW,OAAO,MAAM;CACzC,MAAM,SAAS,0BAA0B,KAAK,QAAQ,aAAa,EAAE;CACrE,OAAO,SAAS,OAAO,SACpB,OAAO,OAAO,MACb,iBACA,eACD,SAAS,OAAO,SACf,SACA;AACL,CAAC;AAoBD,MAAa,aAAa,QAAe,UAA4B;CACpE,MAAM,UAAUA,MAAI,IACnBA,MAAI,KACHA,MAAI,OAAO,CAAC,GAAG,QAAQ,KAAK,MAAM,GAAG,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,GAC5DD,OAAI,KACL,IACC,UAAU;EACV;EACA,QAAQ,OAAO,eAAe,QAAQ,IAAI,QAAQ,IAAI,CAAC;EACvD,OAAO,OAAO,eAAe,QAAQ,IAAI,OAAO,IAAI,CAAC;CACtD,EACD;CACA,OAAO;EACN,OAAOC,MAAI,OAAO,UAAU,WAAW,OAAO,WAAW,KAAA,CAAS;EAClE,SAASA,MAAI,OAAO,UAAU,WAAW,OAAO,UAAU,KAAA,CAAS;EACnE,SAASA,MAAI,OACZ,UACC,EAAE,QAAQ,YACV,WAAW,KAAA,KACX,UAAU,KAAA,MACT,OAAO,SAAS,MAAM,QACtB,OAAO,YAAY,MAAM,WACzB,OAAO,SAAS,MAAM,KACzB;CACD;AACD;;;;;;AAiBA,MAAa,QACZ,YAMA,OAAO,IAAI,aAAa;CACvB,MAAM,KAAK,OAAO,WAAW;CAC7B,MAAM,OAAO,OAAO,KAAK;CACzB,MAAM,UAAU,OAAO,oBAAoB;CAC3C,MAAM,YAAY,KAAK,QAAQ,QAAQ,SAAS;CAChD,MAAM,QAAQ,OAAO,YAAY;EAAE,GAAG;EAAS;CAAU,CAAC;CAC1D,MAAM,OAAO,OAAO,UAAU,KAAK,CAAC;CACpC,MAAM,eAAe,KAAK,KAAK,WAAW,cAAc;CACxD,MAAM,eAAe,GACnB,eAAe,YAAY,CAAC,CAC5B,KAAK,OAAO,QAAQ,cAAc,CAAC;CACrC,MAAM,YAAY,OAAO,oBACxB,OAAO,eACN,OAAO,OAAO,EAAE,SAAS,OAAO,YAAY,OAAO,MAAM,EAAE,CAAC,CAC7D,CACD;CACA,MAAM,UAAU,OAAO,WAAW,WAAW,UAAoB;EAChE,IAAI,OAAO,GAAG,OAAO,KAAK,KAAK,WAAW,UAAU,CAAC,GACpD,OAAO,OAAO,oBAAoB,KAAK;GACtC,WAAW;GACX,SACC;EACF,CAAC;EACF,MAAM,OAAOA,MAAI,OAChB,QACA,CAAC,IACA,KAAK,WAAW;GAAE,GAAG;GAAK,GAAG,SAAS;EAAO,EAC/C;EACA,MAAM,UAAU,OAAO,OAAO,QAC7B,OAAO,UAAU,IAAI,IACpB,CAAC,MAAM,UACP,OAAO,IAAI,aAAa;GACvB,MAAM,OAAO,KAAK,KACjB,WACA,gBACA,MACA,cACD;GACA,IAAI,EAAE,OAAO,GAAG,OAAO,IAAI,IAC1B,OAAO,CACN,MACA;IAAE;IAAM,SAAS,KAAA;IAAW,MAAM,KAAA;GAAU,CAC7C;GAID,OAAO,CACN,MACA;IACC;IACA,UAAS,OAPQ,GACjB,eAAe,IAAI,CAAC,CACpB,KAAK,OAAO,QAAQ,SAAS,CAAC,EAAA,CAKjB;IACb,MAAM,OAAO,GAAG,SAAS,KAAK,QAAQ,IAAI,CAAC;GAC5C,CACD;EACD,CAAC,CACH;EACA,OAAO,QAAQ,aAAmC,OAAO;CAC1D,CAAC;CACD,MAAM,YAAY,OAAO,QAAQ,cAAc,OAAO;CACtD,MAAM,MAAM,OAAO,WAAW,WAAW,WAAkC;EAC1E,MAAM,WAAW,cAAc;EAC/B,MAAM,OACL,UAAU,QACP;GACA;GACA;GACA;GACA,GAAI,WAAW,CAAC,kBAAkB,IAAI,CAAC;EACxC,IACC,UAAU,SACT;GACA;GACA,WAAW,sBAAsB;GACjC;EACD,IACC,UAAU,iBACT;GACA;GACA;GACA,GAAI,WACD,CAAC,qBAAqB,kBAAkB,IACxC,CAAC;EACL,IACC,CAAC,WAAW,GAAI,WAAW,CAAC,aAAa,IAAI,CAAC,CAAE;EACtD,MAAM,OAAO,OAAO,QAClB,SACA,aAAa,KAAK,WAAW,KAAK,GAAG,MAAM;GAC1C,KAAK;GACL,WAAW;GACX,OAAO;GACP,QAAQ;GACR,QAAQ;GACR,KAAK;IACJ,IAAI;IACJ,GAAI,UAAU,eACX;KACA,gCAAgC,WAAW,SAAS;KACpD,kBAAkB;IACnB,IACC,CAAC;GACL;EACD,CAAC,CACF,CAAC,CACA,KACA,OAAO,cAAc;GACpB,UAAU;GACV,cACC,oBAAoB,KAAK;IACxB;IACA,SAAS,GAAG,WAAW,KAAK,EAAE,GAAG,UAAU;GAC5C,CAAC;EACH,CAAC,CACF;EACD,IAAI,SAAS,GACZ,OAAO,OAAO,oBAAoB,KAAK;GACtC;GACA,UAAU;GACV,SAAS,GAAG,WAAW,KAAK,EAAE,GAAG,UAAU,oBAAoB;EAChE,CAAC;CACH,CAAC;CACD,MAAM,WAAW,YAChB,KAAK,YAAY,CAAC,CAAC,CAClB,OAAO,IAAI,aAAa;EACvB,MAAM,YAAY,OAAO,OAAO,aAAa,OAAO,CAAC,CAAC,OAAO;EAC7D,MAAM,WAAW,OAAO,GAAG,eAAe,YAAY;EACtD,MAAM,WAAW,OAAO,eAAe,QAAQ;EAC/C,MAAM,SAAS,OAAO,QAAQ,QAAQ;EACtC,MAAM,OAAO,OAAO,eACnB,aAAa,UAAU,SAAS,GAChC,QACD;EACA,MAAM,UAAU,OAAO,OAAO,QAAQ,cAAc,SACnD,OAAO,IAAI,aAAa;GACvB,MAAM,OAAO,KAAK,KAAK,WAAW,IAAI;GACtC,OAAO;IACN;IACA;IACA,QAAQ,OAAO,GAAG,OAAO,IAAI,KAC1B,OAAO,GAAG,SAAS,IAAI,CAAC,CAAC,KAAK,OAAO,MAAM,IAC3C,OAAO,KAAiB;GAC5B;EACD,CAAC,CACF;EAEA,MAAM,UAAUA,MAAI,OAGlB,SAAS,OAAO,OAAO,UAAU,EAAE,MAAM,YAC1C,SAAS,KACR,OAAO,aACN,OAAO,MAAM,OAAO;GACnB,cAAc,GAAG,OAAO,MAAM,EAAE,OAAO,KAAK,CAAC;GAC7C,SAAS,UAAU,GAAG,UAAU,MAAM,KAAK;EAC5C,CAAC,CACF,CACD,CACD;EACA,MAAM,aACL,UAAU,QACP,CAAC,qBAAqB,qBAAqB,IAC3C,UAAU,SACT,CAAC,gBAAgB,IACjB,CAAC,WAAW;EACjB,MAAM,UAAUA,MAAI,KACnB,UACC,EAAE,MAAM,YACRA,MAAI,SAAS,YAAY,IAAI,KAAK,OAAO,OAAO,KAAK,CACvD;EACA,OAAO,OAAO,OAAO,kBACpB,OAAO,YAEN,OAAO,IAAI,aAAa;GACvB,OAAO,GAAG,gBAAgB,cAAc,IAAI;GAC5C,OAAO,IAAI,SAAS;GACpB,MAAM,QAAQ,OAAO;GACrB,OAAO;IAAE;IAAO,GAAG,UAAU,QAAQ,KAAK;GAAE;EAC7C,CAAC,IACD,GAAG,SACH,KAAK,UAAU,IAAI,IAChB,OAAO,OACP,QAAQ,KACR,OAAO,QAAQ,UAAU,IAAI,SAAS,IAAI,OAAO,IAAI,GAErD,OAAO,aAAa,OAAO,CAC5B,CACJ;CACD,CAAC,CACF;CACD,OAAO;EACN;EACA;EACA,WAAW,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS;EACxC;CACD;AACD,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/** Non-interactive package installation. Provide platform services at the application boundary. */\nimport {\n\tArray,\n\tCause,\n\tData,\n\tRef,\n\tEffect,\n\tExit,\n\tFileSystem,\n\tHashMap,\n\tOption,\n\tPath,\n\tPlatformError,\n\tRecord,\n\tSchema,\n\tSemaphore,\n\tString,\n} from \"effect\"\nimport { ChildProcess, ChildProcessSpawner } from \"effect/process\"\nimport {\n\tPackageManagerDeclaration,\n\tPackageManagerName,\n} from \"./PackageManagerDeclaration\"\nexport { PackageManagerDeclaration } from \"./PackageManagerDeclaration\"\nimport { terminateProcess } from \"./process\"\nimport {\n\twriteSnapshot,\n\twithSnapshot,\n\ttype SnapshotCleanupFailure,\n\tinspectManagedFiles,\n\tUnsupportedFileTypeError,\n\ttype Contents,\n} from \"./snapshot\"\nexport {\n\tUnsupportedFileTypeError,\n\ttype SnapshotCleanupFailure,\n} from \"./snapshot\"\nimport {\n\tapplyChanges,\n\tChanges,\n\tdecodeManifest,\n\tencodeManifest,\n\tfields,\n\ttype Manifest,\n} from \"./manifest\"\nexport { Changes, PackageName } from \"./manifest\"\n\nexport const Agent = Schema.Literals([\n\t\"npm\",\n\t\"pnpm\",\n\t\"yarn-classic\",\n\t\"yarn-berry\",\n])\nexport type Agent = typeof Agent.Type\nexport class PackageManagerError extends Schema.TaggedError<\n\tPackageManagerError,\n\t{ readonly brand: unique symbol }\n>()(\"PackageManagerError\", {\n\toperation: Schema.Literals([\"detect\", \"install\", \"recover\", \"state\"]),\n\tmessage: Schema.String,\n\texitCode: Schema.optionalKey(Schema.Int),\n}) {}\nexport class RecoveryRequiredError extends Schema.TaggedError<\n\tRecoveryRequiredError,\n\t{ readonly brand: unique symbol }\n>()(\"RecoveryRequiredError\", {\n\tdirectory: Schema.String,\n\tsnapshotDirectory: Schema.String,\n\toperation: Schema.Literals([\"install\", \"recover\", \"rollback\"]),\n\tprocessId: Schema.optionalKey(Schema.Int),\n\tmessage: Schema.String,\n\tterminationCause: Schema.optionalKey(\n\t\tSchema.Cause(Schema.Unknown, Schema.Unknown),\n\t),\n\trecoveryCause: Schema.Cause(Schema.Unknown, Schema.Unknown),\n}) {}\n\ntype WriterState = Data.TaggedEnum<{\n\tManagedWritersIdle: {}\n\tRunning: {}\n\tFileWrite: {}\n\tUnconfirmed: {\n\t\treadonly operation: \"install\" | \"recover\"\n\t\treadonly processId: number\n\t\treadonly cause: Cause.Cause<PlatformError.PlatformError>\n\t}\n}>\n\nconst WriterState = Data.taggedEnum<WriterState>()\n\ntype ManagerState = Data.TaggedEnum<{\n\tReady: {}\n\tActive: { readonly writer: WriterState }\n\tRecoveryRequired: { readonly error: RecoveryRequiredError }\n}>\n\nconst ManagerState = Data.taggedEnum<ManagerState>()\n\nexport type Error =\n\t| PackageManagerError\n\t| UnsupportedFileTypeError\n\t| RecoveryRequiredError\n\t| PlatformError.PlatformError\n\t| Schema.SchemaError\nexport interface Options {\n\t/** Project directory, containing package.json. Use the workspace root for workspace installs. */\n\treadonly directory: string\n\t/** Explicit selection takes precedence over detection. */\n\treadonly agent?: Agent\n\t/** Optional npm_config_user_agent supplied by the caller; used only as a fallback. */\n\treadonly userAgent?: string\n}\nconst lockfiles = [\n\t\"package-lock.json\",\n\t\"npm-shrinkwrap.json\",\n\t\"pnpm-lock.yaml\",\n\t\"yarn.lock\",\n] as const\nconst backupFiles = [\n\t\"package.json\",\n\t...lockfiles,\n\t\".npmrc\",\n\t\"pnpm-workspace.yaml\",\n\t\".yarnrc\",\n\t\".yarnrc.yml\",\n\t\".yarn/install-state.gz\",\n\t\".pnp.cjs\",\n\t\".pnp.loader.mjs\",\n]\nconst executable = (agent: Agent) =>\n\tString.startsWith(\"yarn\")(agent) ? \"yarn\" : agent\n\nconst readSource = Effect.fnUntraced(function* (\n\tfs: FileSystem.FileSystem,\n\tfile: string,\n) {\n\tconst bytes = yield* fs.readFile(file)\n\treturn yield* Effect.try({\n\t\ttry: () =>\n\t\t\tnew TextDecoder(\"utf-8\", { ignoreBOM: true, fatal: true }).decode(bytes),\n\t\tcatch: (cause) =>\n\t\t\tPlatformError.badArgument({\n\t\t\t\tmodule: \"FileSystem\",\n\t\t\t\tmethod: \"readManifest\",\n\t\t\t\tdescription: \"The manifest must contain valid UTF-8\",\n\t\t\t\tcause,\n\t\t\t}),\n\t})\n})\n\nconst Executable = PackageManagerName\nconst Digits = Schema.String.check(Schema.isPattern(/^\\d+$/))\nconst decodePackageManager = Schema.decodeUnknownOption(\n\tPackageManagerDeclaration,\n)\n/** `name/version ...`, as package managers set `npm_config_user_agent`. */\nconst decodeUserAgent = Schema.decodeUnknownOption(\n\tSchema.TemplateLiteralParser([Executable, \"/\", Digits, Schema.String]),\n)\nconst agentOf = (name: typeof Executable.Type, major: string): Agent =>\n\tname === \"yarn\" ? (major === \"1\" ? \"yarn-classic\" : \"yarn-berry\") : name\n\n/** packageManager, then lockfile, then caller user-agent, then npm. Conflicting lockfiles fail. */\nexport const detectAgent = Effect.fnUntraced(function* (options: Options) {\n\tif (options.agent !== undefined)\n\t\treturn yield* Schema.decodeEffect(Agent)(options.agent)\n\tconst fs = yield* FileSystem.FileSystem\n\tconst path = yield* Path.Path\n\tconst manifest = yield* readSource(\n\t\tfs,\n\t\tpath.join(options.directory, \"package.json\"),\n\t).pipe(Effect.flatMap(decodeManifest))\n\tif (manifest.packageManager !== undefined) {\n\t\treturn yield* Option.match(decodePackageManager(manifest.packageManager), {\n\t\t\tonNone: () =>\n\t\t\t\tPackageManagerError.make({\n\t\t\t\t\toperation: \"detect\",\n\t\t\t\t\tmessage: `Unsupported packageManager: ${manifest.packageManager}`,\n\t\t\t\t}),\n\t\t\tonSome: ([name, , version]) =>\n\t\t\t\tEffect.succeed(agentOf(name, `${version.major}`)),\n\t\t})\n\t}\n\tconst found = yield* Effect.filter(lockfiles, (file) =>\n\t\tfs.exists(path.join(options.directory, file)),\n\t)\n\tconst kinds = Array.dedupe(\n\t\tArray.map(found, (file) =>\n\t\t\tfile === \"pnpm-lock.yaml\"\n\t\t\t\t? \"pnpm\"\n\t\t\t\t: file === \"yarn.lock\"\n\t\t\t\t\t? \"yarn\"\n\t\t\t\t\t: \"npm\",\n\t\t),\n\t)\n\tif (kinds.length > 1)\n\t\treturn yield* PackageManagerError.make({\n\t\t\toperation: \"detect\",\n\t\t\tmessage: \"Conflicting lockfiles; select an agent explicitly\",\n\t\t})\n\tif (kinds[0] === \"yarn\") {\n\t\tconst lock = yield* fs.readFileString(\n\t\t\tpath.join(options.directory, \"yarn.lock\"),\n\t\t)\n\t\treturn /^__metadata:/m.test(lock) ? \"yarn-berry\" : \"yarn-classic\"\n\t}\n\tif (kinds[0] !== undefined) return kinds[0]\n\treturn Option.match(decodeUserAgent(options.userAgent ?? \"\"), {\n\t\tonNone: () => \"npm\" as const,\n\t\tonSome: ([name, , major]) => agentOf(name, major),\n\t})\n})\n\nexport interface PackageState {\n\treadonly spec: string\n\t/** Missing optional or not-yet-installed dependencies have no version/path. */\n\treadonly version: string | undefined\n\treadonly path: string | undefined\n}\n/** Direct dependencies only, keyed by their manifest names (including aliases). */\nexport type State = HashMap.HashMap<string, PackageState>\nexport interface PackageChange {\n\treadonly name: string\n\treadonly before: PackageState | undefined\n\treadonly after: PackageState | undefined\n}\nexport interface StateDiff {\n\treadonly added: ReadonlyArray<PackageChange>\n\treadonly removed: ReadonlyArray<PackageChange>\n\treadonly updated: ReadonlyArray<PackageChange>\n}\nexport const diffState = (before: State, after: State): StateDiff => {\n\tconst changes = Array.map(\n\t\tArray.sort(\n\t\t\tArray.dedupe([...HashMap.keys(before), ...HashMap.keys(after)]),\n\t\t\tString.Order,\n\t\t),\n\t\t(name) => ({\n\t\t\tname,\n\t\t\tbefore: Option.getOrUndefined(HashMap.get(before, name)),\n\t\t\tafter: Option.getOrUndefined(HashMap.get(after, name)),\n\t\t}),\n\t)\n\treturn {\n\t\tadded: Array.filter(changes, (change) => change.before === undefined),\n\t\tremoved: Array.filter(changes, (change) => change.after === undefined),\n\t\tupdated: Array.filter(\n\t\t\tchanges,\n\t\t\t({ before, after }) =>\n\t\t\t\tbefore !== undefined &&\n\t\t\t\tafter !== undefined &&\n\t\t\t\t(before.spec !== after.spec ||\n\t\t\t\t\tbefore.version !== after.version ||\n\t\t\t\t\tbefore.path !== after.path),\n\t\t),\n\t}\n}\nexport interface InstallResult extends StateDiff {\n\treadonly agent: Agent\n\t/** The install committed; retry only snapshot deletion, not installation. */\n\treadonly snapshotCleanupFailure: Option.Option<SnapshotCleanupFailure>\n}\nexport interface PackageManager {\n\treadonly directory: string\n\treadonly agent: Agent\n\treadonly readState: Effect.Effect<State, Error>\n\t/** Present when manual recovery is required; the manager cannot be reused. */\n\treadonly recoveryRequired: Effect.Effect<Option.Option<RecoveryRequiredError>>\n\t/** Serialized per manager. Empty changes installs the current manifest, including first installs. */\n\treadonly install: (changes: Changes) => Effect.Effect<InstallResult, Error>\n}\n\n/**\n * Own one manager per project. The caller must give this manager and its child\n * processes exclusive write access to the project for each install, including\n * recovery. Do not edit project files or run another installer concurrently.\n * Calls are serialized only within this manager; no cross-process lock is taken.\n * Managed paths must be regular files or absent. make and install reject symbolic\n * links and other file types with UnsupportedFileTypeError before any write.\n *\n * Accepted file writes finish before cancellation can start rollback or release\n * the lock. File writes and the original process group participate in the transaction.\n * Scripts must not create escaped writers in independent groups or daemons.\n * Failed or interrupted installs before commit restore backed-up package files byte-for-byte\n * with recorded permissions and ownership, and remove tracked files that did not\n * exist before installation. Writes made\n * during installation are overwritten by rollback, never merged. When a lockfile\n * existed, recovery also attempts to repair node_modules. Recovery failures are\n * combined with the original cause. If process termination cannot be confirmed,\n * no further restoration or recovery runs. Any failed rollback step also requires\n * manual recovery, even if all writers stopped. Only successful installation or\n * complete rollback permits snapshot deletion and reuse. RecoveryRequiredError\n * and recoveryRequired expose the retained snapshot directory and complete cause;\n * this manager rejects\n * all later installs. Complete manual recovery before making a new manager.\n * Committed installs report snapshot deletion failures in snapshotCleanupFailure\n * rather than failing or rolling back. No crash recovery is promised.\n */\nexport const make = (\n\toptions: Options,\n): Effect.Effect<\n\tPackageManager,\n\tError,\n\tFileSystem.FileSystem | Path.Path | ChildProcessSpawner.ChildProcessSpawner\n> =>\n\tEffect.gen(function* () {\n\t\tconst fs = yield* FileSystem.FileSystem\n\t\tconst path = yield* Path.Path\n\t\tconst spawner = yield* ChildProcessSpawner.ChildProcessSpawner\n\t\tconst directory = path.resolve(options.directory)\n\t\tyield* inspectManagedFiles(fs, path, directory, backupFiles)\n\t\tconst agent = yield* detectAgent({ ...options, directory })\n\t\tconst lock = yield* Semaphore.make(1)\n\t\tconst transaction = yield* Ref.make<ManagerState>(ManagerState.Ready())\n\t\tconst manifestFile = path.join(directory, \"package.json\")\n\t\tconst readManifest = readSource(fs, manifestFile).pipe(\n\t\t\tEffect.flatMap(decodeManifest),\n\t\t)\n\t\tconst installed = Schema.decodeUnknownEffect(\n\t\t\tSchema.fromJsonString(\n\t\t\t\tSchema.Struct({ version: Schema.optionalKey(Schema.String) }),\n\t\t\t),\n\t\t)\n\t\tconst stateOf = Effect.fnUntraced(function* (manifest: Manifest) {\n\t\t\tif (yield* fs.exists(path.join(directory, \".pnp.cjs\")))\n\t\t\t\treturn yield* PackageManagerError.make({\n\t\t\t\t\toperation: \"state\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Plug'n'Play is not supported; configure Yarn with nodeLinker: node-modules\",\n\t\t\t\t})\n\t\t\tconst deps = Array.reduce(\n\t\t\t\tfields,\n\t\t\t\t{} as Readonly<Record<string, string>>,\n\t\t\t\t(all, field) => ({ ...all, ...manifest[field] }),\n\t\t\t)\n\t\t\tconst entries = yield* Effect.forEach(\n\t\t\t\tRecord.toEntries(deps),\n\t\t\t\t([name, spec]) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst file = path.join(\n\t\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\t\t\"node_modules\",\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\"package.json\",\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (!(yield* fs.exists(file)))\n\t\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\t{ spec, version: undefined, path: undefined },\n\t\t\t\t\t\t\t] as const\n\t\t\t\t\t\tconst pkg = yield* fs\n\t\t\t\t\t\t\t.readFileString(file)\n\t\t\t\t\t\t\t.pipe(Effect.flatMap(installed))\n\t\t\t\t\t\treturn [\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tspec,\n\t\t\t\t\t\t\t\tversion: pkg.version,\n\t\t\t\t\t\t\t\tpath: yield* fs.realPath(path.dirname(file)),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t] as const\n\t\t\t\t\t}),\n\t\t\t)\n\t\t\treturn HashMap.fromIterable<string, PackageState>(entries)\n\t\t})\n\t\tconst readState = Effect.flatMap(readManifest, stateOf)\n\t\tconst termination: ChildProcess.KillOptions = {\n\t\t\tforceKillAfter: \"5 seconds\",\n\t\t}\n\t\tconst run = Effect.fnUntraced(function* (operation: \"install\" | \"recover\") {\n\t\t\tconst recovery = operation === \"recover\"\n\t\t\tconst args =\n\t\t\t\tagent === \"npm\"\n\t\t\t\t\t? [\n\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\"--no-audit\",\n\t\t\t\t\t\t\t\"--no-fund\",\n\t\t\t\t\t\t\t...(recovery ? [\"--prefer-offline\"] : []),\n\t\t\t\t\t\t]\n\t\t\t\t\t: agent === \"pnpm\"\n\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\trecovery ? \"--frozen-lockfile\" : \"--no-frozen-lockfile\",\n\t\t\t\t\t\t\t\t\"--config.confirmModulesPurge=false\",\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t: agent === \"yarn-classic\"\n\t\t\t\t\t\t\t? [\n\t\t\t\t\t\t\t\t\t\"install\",\n\t\t\t\t\t\t\t\t\t\"--non-interactive\",\n\t\t\t\t\t\t\t\t\t...(recovery\n\t\t\t\t\t\t\t\t\t\t? [\"--frozen-lockfile\", \"--prefer-offline\"]\n\t\t\t\t\t\t\t\t\t\t: []),\n\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t: [\"install\", ...(recovery ? [\"--immutable\"] : [])]\n\t\t\t// Acquire and install the release handler atomically, then wait interruptibly.\n\t\t\treturn yield* Effect.acquireUseRelease(\n\t\t\t\tspawner\n\t\t\t\t\t.spawn(\n\t\t\t\t\t\tChildProcess.make(executable(agent), args, {\n\t\t\t\t\t\t\tcwd: directory,\n\t\t\t\t\t\t\textendEnv: true,\n\t\t\t\t\t\t\tstdin: \"ignore\",\n\t\t\t\t\t\t\tstdout: \"inherit\",\n\t\t\t\t\t\t\tstderr: \"inherit\",\n\t\t\t\t\t\t\tdetached: true,\n\t\t\t\t\t\t\t...termination,\n\t\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\t\tCI: \"true\",\n\t\t\t\t\t\t\t\t...(agent === \"yarn-berry\"\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\tYARN_ENABLE_IMMUTABLE_INSTALLS: recovery\n\t\t\t\t\t\t\t\t\t\t\t\t? \"true\"\n\t\t\t\t\t\t\t\t\t\t\t\t: \"false\",\n\t\t\t\t\t\t\t\t\t\t\tYARN_NODE_LINKER: \"node-modules\",\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\t.pipe(\n\t\t\t\t\t\tEffect.tap(() =>\n\t\t\t\t\t\t\tRef.set(\n\t\t\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\t\t\tManagerState.Active({ writer: WriterState.Running() }),\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t(process) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst code = yield* process.exitCode.pipe(\n\t\t\t\t\t\t\tEffect.timeoutOrElse({\n\t\t\t\t\t\t\t\tduration: \"10 minutes\",\n\t\t\t\t\t\t\t\torElse: () =>\n\t\t\t\t\t\t\t\t\tPackageManagerError.make({\n\t\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\t\tmessage: `${executable(agent)} ${operation} timed out`,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (code !== 0)\n\t\t\t\t\t\t\treturn yield* PackageManagerError.make({\n\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\texitCode: code,\n\t\t\t\t\t\t\t\tmessage: `${executable(agent)} ${operation} exited with code ${code}`,\n\t\t\t\t\t\t\t})\n\t\t\t\t\t}),\n\t\t\t\t// The command owns its group; a stopped leader may leave live descendants.\n\t\t\t\t// Observe kill failures here rather than relying on best-effort scope cleanup.\n\t\t\t\t(process) =>\n\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\tconst result = yield* terminateProcess(process, termination)\n\t\t\t\t\t\tyield* Ref.set(\n\t\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\t\tManagerState.Active({\n\t\t\t\t\t\t\t\twriter:\n\t\t\t\t\t\t\t\t\tresult._tag === \"OriginalGroupStopped\"\n\t\t\t\t\t\t\t\t\t\t? WriterState.ManagedWritersIdle()\n\t\t\t\t\t\t\t\t\t\t: WriterState.Unconfirmed({\n\t\t\t\t\t\t\t\t\t\t\t\toperation,\n\t\t\t\t\t\t\t\t\t\t\t\tprocessId: process.pid,\n\t\t\t\t\t\t\t\t\t\t\t\tcause: result.cause,\n\t\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t)\n\t\t\t\t\t\tif (result._tag === \"Unconfirmed\")\n\t\t\t\t\t\t\treturn yield* Effect.failCause(result.cause)\n\t\t\t\t\t}),\n\t\t\t)\n\t\t}, Effect.scoped)\n\t\t// AbortSignal does not join accepted OS writes. Keep the writer owned until completion.\n\t\tconst withFileWriter = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n\t\t\tEffect.acquireUseRelease(\n\t\t\t\tRef.set(\n\t\t\t\t\ttransaction,\n\t\t\t\t\tManagerState.Active({ writer: WriterState.FileWrite() }),\n\t\t\t\t),\n\t\t\t\t() => effect,\n\t\t\t\t() =>\n\t\t\t\t\tRef.set(\n\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\tManagerState.Active({ writer: WriterState.ManagedWritersIdle() }),\n\t\t\t\t\t),\n\t\t\t).pipe(Effect.uninterruptible)\n\n\t\tconst install = (changes: Changes) =>\n\t\t\tlock.withPermits(1)(\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst state = yield* Ref.get(transaction)\n\t\t\t\t\tif (state._tag === \"RecoveryRequired\") return yield* state.error\n\t\t\t\t\tconst validated = yield* Schema.decodeEffect(Changes)(changes)\n\t\t\t\t\tconst inspected = yield* inspectManagedFiles(\n\t\t\t\t\t\tfs,\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\tbackupFiles,\n\t\t\t\t\t)\n\t\t\t\t\tconst backups = yield* Effect.forEach(\n\t\t\t\t\t\tinspected,\n\t\t\t\t\t\t({ name, file, metadata }) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tconst contents = yield* Option.match(metadata, {\n\t\t\t\t\t\t\t\t\tonNone: () => Effect.succeedNone,\n\t\t\t\t\t\t\t\t\tonSome: (info) =>\n\t\t\t\t\t\t\t\t\t\tfs\n\t\t\t\t\t\t\t\t\t\t\t.readFile(file)\n\t\t\t\t\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\t\t\t\t\tEffect.map((bytes) =>\n\t\t\t\t\t\t\t\t\t\t\t\t\tOption.some<Contents>({ ...info, bytes }),\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\treturn { name, file, contents }\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\tconst original = yield* readSource(fs, manifestFile)\n\t\t\t\t\tconst manifest = yield* decodeManifest(original)\n\t\t\t\t\tconst before = yield* stateOf(manifest)\n\t\t\t\t\tconst text = yield* encodeManifest(\n\t\t\t\t\t\tapplyChanges(manifest, validated),\n\t\t\t\t\t\toriginal,\n\t\t\t\t\t)\n\n\t\t\t\t\tconst agentLocks =\n\t\t\t\t\t\tagent === \"npm\"\n\t\t\t\t\t\t\t? [\"package-lock.json\", \"npm-shrinkwrap.json\"]\n\t\t\t\t\t\t\t: agent === \"pnpm\"\n\t\t\t\t\t\t\t\t? [\"pnpm-lock.yaml\"]\n\t\t\t\t\t\t\t\t: [\"yarn.lock\"]\n\t\t\t\t\tconst hasLock = Array.some(\n\t\t\t\t\t\tbackups,\n\t\t\t\t\t\t({ name, contents }) =>\n\t\t\t\t\t\t\tArray.contains(agentLocks, name) && Option.isSome(contents),\n\t\t\t\t\t)\n\t\t\t\t\tconst completed = yield* withSnapshot(\n\t\t\t\t\t\tfs,\n\t\t\t\t\t\tRef.get(transaction).pipe(\n\t\t\t\t\t\t\tEffect.map((state) => state._tag === \"Ready\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t\t(snapshotDirectory) =>\n\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\tconst snapshot = yield* writeSnapshot(\n\t\t\t\t\t\t\t\t\tfs,\n\t\t\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\t\t\tsnapshotDirectory,\n\t\t\t\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\t\t\t\tagent,\n\t\t\t\t\t\t\t\t\tbackups,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\tconst restore = Effect.flatMap(Ref.get(transaction), (state) =>\n\t\t\t\t\t\t\t\t\tstate._tag === \"Active\" &&\n\t\t\t\t\t\t\t\t\tstate.writer._tag === \"ManagedWritersIdle\"\n\t\t\t\t\t\t\t\t\t\t? withFileWriter(snapshot.restore(state.writer))\n\t\t\t\t\t\t\t\t\t\t: Effect.void,\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\treturn yield* Effect.acquireUseRelease(\n\t\t\t\t\t\t\t\t\tRef.set(\n\t\t\t\t\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\t\t\t\t\tManagerState.Active({\n\t\t\t\t\t\t\t\t\t\t\twriter: WriterState.ManagedWritersIdle(),\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t() =>\n\t\t\t\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\t\t\t\tyield* withFileWriter(\n\t\t\t\t\t\t\t\t\t\t\t\tfs.writeFileString(manifestFile, text),\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\tyield* run(\"install\")\n\t\t\t\t\t\t\t\t\t\t\tconst after = yield* readState\n\t\t\t\t\t\t\t\t\t\t\treturn { agent, ...diffState(before, after) }\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t(_, exit) =>\n\t\t\t\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\t\t\t\tif (Exit.isFailure(exit)) {\n\t\t\t\t\t\t\t\t\t\t\t\tconst state = yield* Ref.get(transaction)\n\t\t\t\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t\t\t\tstate._tag !== \"Active\" ||\n\t\t\t\t\t\t\t\t\t\t\t\t\tstate.writer._tag !== \"ManagedWritersIdle\"\n\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t\t\tyield* withFileWriter(snapshot.restore(state.writer))\n\t\t\t\t\t\t\t\t\t\t\t\tif (hasLock)\n\t\t\t\t\t\t\t\t\t\t\t\t\tyield* run(\"recover\").pipe(\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// Even a failed recovery must restore files, once its writer has stopped.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tEffect.onExit(() => restore),\n\t\t\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t// Idle managed writers alone do not prove that the transaction completed.\n\t\t\t\t\t\t\t\t\t\t\tyield* Ref.set(transaction, ManagerState.Ready())\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t).pipe(\n\t\t\t\t\t\t\t\t\tEffect.onExit((exit) =>\n\t\t\t\t\t\t\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\t\t\t\t\t\t\tconst state = yield* Ref.get(transaction)\n\t\t\t\t\t\t\t\t\t\t\tif (Exit.isSuccess(exit) || state._tag !== \"Active\")\n\t\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t\tconst writer = state.writer\n\t\t\t\t\t\t\t\t\t\t\tconst error = RecoveryRequiredError.make({\n\t\t\t\t\t\t\t\t\t\t\t\tdirectory,\n\t\t\t\t\t\t\t\t\t\t\t\tsnapshotDirectory,\n\t\t\t\t\t\t\t\t\t\t\t\toperation:\n\t\t\t\t\t\t\t\t\t\t\t\t\twriter._tag === \"Unconfirmed\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t? writer.operation\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t: \"rollback\",\n\t\t\t\t\t\t\t\t\t\t\t\t...(writer._tag === \"Unconfirmed\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tprocessId: writer.processId,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tterminationCause: writer.cause,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t\t\t\t\tmessage: `Manual recovery is required. Stop all writers before restoring the snapshot at ${snapshotDirectory}`,\n\t\t\t\t\t\t\t\t\t\t\t\trecoveryCause: exit.cause,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\tyield* Ref.set(\n\t\t\t\t\t\t\t\t\t\t\t\ttransaction,\n\t\t\t\t\t\t\t\t\t\t\t\tManagerState.RecoveryRequired({ error }),\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\treturn yield* error\n\t\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...completed.value,\n\t\t\t\t\t\tsnapshotCleanupFailure: completed.snapshotCleanupFailure,\n\t\t\t\t\t}\n\t\t\t\t}),\n\t\t\t)\n\t\treturn {\n\t\t\tdirectory,\n\t\t\tagent,\n\t\t\trecoveryRequired: Ref.get(transaction).pipe(\n\t\t\t\tEffect.map((state) =>\n\t\t\t\t\tstate._tag === \"RecoveryRequired\"\n\t\t\t\t\t\t? Option.some(state.error)\n\t\t\t\t\t\t: Option.none(),\n\t\t\t\t),\n\t\t\t),\n\t\t\treadState: lock.withPermits(1)(readState),\n\t\t\tinstall,\n\t\t}\n\t})\n"],"mappings":"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"}
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../src/manifest.ts"],"mappings":";qBAEa,aAAW,OAAA;
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","names":[],"sources":["../src/manifest.ts"],"mappings":";qBAEa,aAAW,OAAA;qBAwCX,SAAO,OAAA,QAAA,OAAA,QAAA,OAAA,gBAAA,OAAA,QAAA,OAAA;;YAKR,iBAAiB,QAAQ"}
|