@opencode-ai/util 0.0.0-dev-18253 → 0.0.0-dev-18259
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/dist/npm.d.ts +2 -0
- package/dist/npm.js +53 -12
- package/package.json +2 -1
package/dist/npm.d.ts
CHANGED
|
@@ -27,6 +27,8 @@ export declare class Service extends Service_base {
|
|
|
27
27
|
}
|
|
28
28
|
export declare function sanitize(pkg: string): string;
|
|
29
29
|
export declare function isRegistryPackage(pkg: string): Promise<boolean>;
|
|
30
|
+
export declare function isInstallablePackage(pkg: string): Promise<boolean>;
|
|
31
|
+
export declare function cacheKey(pkg: string): Promise<string>;
|
|
30
32
|
export declare const node: LayerNode.Node<Service, never, LayerNode.Tag<"global">>;
|
|
31
33
|
export declare function add(...args: Parameters<Interface["add"]>): Promise<EntryPoint>;
|
|
32
34
|
export declare function resolve(...args: Parameters<Interface["resolve"]>): Promise<EntryPoint>;
|
package/dist/npm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export * as Npm from "./npm.js";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
3
4
|
import { Effect, Schema, Context, Layer, Option, FileSystem } from "effect";
|
|
4
|
-
import * as NodeFileSystem from "@effect/platform-node/NodeFileSystem";
|
|
5
5
|
import { FSUtil } from "./fs-util.js";
|
|
6
6
|
import { Global } from "./global.js";
|
|
7
7
|
import { EffectFlock } from "./effect-flock.js";
|
|
@@ -35,6 +35,27 @@ export async function isRegistryPackage(pkg) {
|
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
|
+
export async function isInstallablePackage(pkg) {
|
|
39
|
+
const { default: npa } = await import("npm-package-arg");
|
|
40
|
+
try {
|
|
41
|
+
const result = npa(pkg);
|
|
42
|
+
return result.type === "git" || (result.name !== undefined && ["version", "range", "tag"].includes(result.type));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function cacheKey(pkg) {
|
|
49
|
+
const { default: npa } = await import("npm-package-arg");
|
|
50
|
+
try {
|
|
51
|
+
if (npa(pkg).type === "git")
|
|
52
|
+
return `git-${createHash("sha256").update(pkg).digest("hex")}`;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Preserve the existing fallback for invalid and non-registry package strings.
|
|
56
|
+
}
|
|
57
|
+
return sanitize(pkg);
|
|
58
|
+
}
|
|
38
59
|
const resolveEntryPoint = (name, dir, subpaths = [""]) => {
|
|
39
60
|
const entrypoint = subpaths
|
|
40
61
|
.map((subpath) => {
|
|
@@ -51,12 +72,28 @@ const resolveEntryPoint = (name, dir, subpaths = [""]) => {
|
|
|
51
72
|
entrypoint,
|
|
52
73
|
};
|
|
53
74
|
};
|
|
75
|
+
const PackageJson = Schema.Struct({
|
|
76
|
+
dependencies: Schema.optional(Schema.Record(Schema.String, Schema.String)),
|
|
77
|
+
});
|
|
54
78
|
const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
55
79
|
const afs = yield* FSUtil.Service;
|
|
56
80
|
const global = yield* Global.Service;
|
|
57
81
|
const fs = yield* FileSystem.FileSystem;
|
|
58
82
|
const flock = yield* EffectFlock.Service;
|
|
59
|
-
const directory = (pkg) => path.join(global.cache, "packages",
|
|
83
|
+
const directory = (pkg) => Effect.map(Effect.promise(() => cacheKey(pkg)), (key) => path.join(global.cache, "packages", key));
|
|
84
|
+
const installedName = Effect.fnUntraced(function* (pkg, dir, parsedName) {
|
|
85
|
+
if (parsedName)
|
|
86
|
+
return parsedName;
|
|
87
|
+
const manifest = yield* afs
|
|
88
|
+
.readJson(path.join(dir, "package.json"))
|
|
89
|
+
.pipe(Effect.flatMap(Schema.decodeUnknownEffect(PackageJson)), Effect.option);
|
|
90
|
+
if (Option.isSome(manifest)) {
|
|
91
|
+
const name = Object.keys(manifest.value.dependencies ?? {})[0];
|
|
92
|
+
if (name)
|
|
93
|
+
return name;
|
|
94
|
+
}
|
|
95
|
+
return pkg;
|
|
96
|
+
});
|
|
60
97
|
const reify = (input) => Effect.gen(function* () {
|
|
61
98
|
yield* flock.acquire(`npm-install:${input.dir}`);
|
|
62
99
|
const { Arborist } = yield* Effect.promise(() => import("@npmcli/arborist"));
|
|
@@ -88,22 +125,24 @@ const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
|
88
125
|
}));
|
|
89
126
|
const add = Effect.fn("Npm.add")(function* (pkg, options) {
|
|
90
127
|
const { default: npa } = yield* Effect.promise(() => import("npm-package-arg"));
|
|
91
|
-
const
|
|
92
|
-
const name = (() => {
|
|
128
|
+
const parsedName = (() => {
|
|
93
129
|
try {
|
|
94
|
-
return npa(pkg).name ??
|
|
130
|
+
return npa(pkg).name ?? undefined;
|
|
95
131
|
}
|
|
96
132
|
catch {
|
|
97
|
-
return
|
|
133
|
+
return undefined;
|
|
98
134
|
}
|
|
99
135
|
})();
|
|
136
|
+
const dir = yield* directory(pkg);
|
|
137
|
+
const name = yield* installedName(pkg, dir, parsedName);
|
|
100
138
|
if (yield* afs.existsSafe(path.join(dir, "node_modules", name))) {
|
|
101
139
|
return resolveEntryPoint(name, path.join(dir, "node_modules", name), options?.subpaths);
|
|
102
140
|
}
|
|
103
141
|
const tree = yield* reify({ dir, add: [pkg] });
|
|
104
142
|
const first = tree.edgesOut.values().next().value?.to;
|
|
105
143
|
if (!first) {
|
|
106
|
-
const
|
|
144
|
+
const installed = yield* installedName(pkg, dir, parsedName);
|
|
145
|
+
const result = resolveEntryPoint(installed, path.join(dir, "node_modules", installed), options?.subpaths);
|
|
107
146
|
if (result.entrypoint)
|
|
108
147
|
return result;
|
|
109
148
|
return yield* new InstallFailedError({ add: [pkg], dir });
|
|
@@ -112,21 +151,23 @@ const layer = Layer.effect(Service, Effect.gen(function* () {
|
|
|
112
151
|
}, Effect.scoped);
|
|
113
152
|
const resolve = Effect.fn("Npm.resolve")(function* (pkg, options) {
|
|
114
153
|
const { default: npa } = yield* Effect.promise(() => import("npm-package-arg"));
|
|
115
|
-
const
|
|
154
|
+
const parsedName = (() => {
|
|
116
155
|
try {
|
|
117
|
-
return npa(pkg).name ??
|
|
156
|
+
return npa(pkg).name ?? undefined;
|
|
118
157
|
}
|
|
119
158
|
catch {
|
|
120
|
-
return
|
|
159
|
+
return undefined;
|
|
121
160
|
}
|
|
122
161
|
})();
|
|
123
|
-
const
|
|
162
|
+
const root = yield* directory(pkg);
|
|
163
|
+
const name = yield* installedName(pkg, root, parsedName);
|
|
164
|
+
const dir = path.join(root, "node_modules", name);
|
|
124
165
|
if (!(yield* afs.existsSafe(dir)))
|
|
125
166
|
return { directory: dir };
|
|
126
167
|
return resolveEntryPoint(name, dir, options?.subpaths);
|
|
127
168
|
});
|
|
128
169
|
const which = Effect.fn("Npm.which")(function* (pkg, bin) {
|
|
129
|
-
const dir = directory(pkg);
|
|
170
|
+
const dir = yield* directory(pkg);
|
|
130
171
|
const binDir = path.join(dir, "node_modules", ".bin");
|
|
131
172
|
const pick = Effect.fnUntraced(function* () {
|
|
132
173
|
const files = yield* fs.readDirectory(binDir).pipe(Effect.orElseSucceed(() => []));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@opencode-ai/util",
|
|
4
|
-
"version": "0.0.0-dev-
|
|
4
|
+
"version": "0.0.0-dev-18259",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@effect/opentelemetry": "4.0.0-rc.111",
|
|
47
47
|
"@effect/platform-node": "4.0.0-rc.111",
|
|
48
|
+
"@effect/platform-node-shared": "4.0.0-rc.111",
|
|
48
49
|
"@npmcli/arborist": "9.4.0",
|
|
49
50
|
"@npmcli/config": "10.8.1",
|
|
50
51
|
"@opentelemetry/api": "1.9.0",
|