@pnpm/napi 0.0.0-0 → 12.0.0-alpha.10

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/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # @pnpm/napi
2
+
3
+ ## 12.0.0-alpha.10
4
+
5
+ ## 12.0.0-alpha.9
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2016 Rico Sta. Cruz and other contributors
4
+ Copyright (c) 2016-2026 Zoltan Kochan and other contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # @pnpm/napi
2
+
3
+ Node.js bindings for pnpm v12's Rust engine (pacquet), exposing pnpm's
4
+ programmatic API — install, rebuild, dependency resolution, and pack — to a
5
+ JavaScript host. The reference consumer is [Bit](https://bit.dev), which drives
6
+ pnpm entirely through its programmatic API.
7
+
8
+ This package binds only pnpm's **engine**. Pure data utilities that operate on
9
+ in-memory objects or the (byte-stable) on-disk lockfile/store formats stay as
10
+ regular `@pnpm/*` JS packages — both stacks share the same lockfile v9 shape,
11
+ `.modules.yaml` format, and store layout.
12
+
13
+ ## API
14
+
15
+ See [`index.d.ts`](./index.d.ts) for the full typed contract.
16
+
17
+ | Export | Purpose |
18
+ | --- | --- |
19
+ | `install(options, onLog?, readPackageHook?)` | Install in-memory importers (single or workspace); `readPackageHook` transforms each resolved dependency manifest (must be synchronous). Returns `{ stats, depsRequiringBuild?, storeDir }`. |
20
+ | `rebuild(options, onLog?, selectedNames?)` | Re-run dependency build scripts against a materialized install (frozen path). |
21
+ | `resolveDependency(wanted, options)` | Resolve an npm-registry specifier to `{ id, manifest, resolvedVia, … }`. |
22
+ | `pack(options, onLog?)` | Build a publishable `.tgz` from a project directory. |
23
+ | `parseBareSpecifier(spec, alias?)` | Split/validate a dependency specifier; `null` when unparsable. |
24
+ | `engineVersion()` | Version string of the underlying Rust engine (pacquet). |
25
+ | `getPeerDependencyIssues(options)` | **Not yet implemented** — throws `ERR_PNPM_NAPI_UNIMPLEMENTED`. Peer-issue reporting is not ported in pacquet's CLI either; consumers should degrade gracefully. |
26
+
27
+ Errors are plain `Error` objects carrying pnpm's `code` (`ERR_PNPM_*`) and,
28
+ where applicable, `hint` — lifted onto the error by the loader from the engine's
29
+ structured envelope.
30
+
31
+ Auth: pass `authHeaderByUri` — a map of nerf-darted registry URI → `Authorization`
32
+ header value (with `""` for the default registry). The host resolves these from
33
+ its `.npmrc` credentials; the engine applies them as-is.
34
+
35
+ ## Distribution
36
+
37
+ The addon ships as prebuilt per-platform packages, the same model as the
38
+ `@pnpm/exe.*` CLI packages:
39
+
40
+ - `index.js` resolves the addon at load time in this order: a
41
+ `PNPM_NAPI_BINARY` env override, the matching
42
+ `@pnpm/napi.<platform>` optional dependency, then a local build.
43
+ - CI cross-compiles the addon per target (`napi build --release --target
44
+ <rust-triple>`), uploads each as `pnpm-napi.<codeTarget>.node` at the repo
45
+ root, then runs `scripts/generate-packages.mjs` to produce the eight
46
+ `@pnpm/napi.<platform>` packages and wire them as this wrapper's
47
+ `optionalDependencies`.
48
+
49
+ Supported targets: `win32-x64`, `win32-arm64`, `darwin-x64`, `darwin-arm64`,
50
+ `linux-x64`, `linux-arm64`, `linux-x64-musl`, `linux-arm64-musl`.
51
+
52
+ ## Local development
53
+
54
+ Build the Rust crate and point the loader at the artifact:
55
+
56
+ ```sh
57
+ cargo build -p pacquet-napi --profile napi-release
58
+ cp ../../../target/napi-release/libpacquet_napi.dylib \
59
+ ./pnpm-napi.darwin-arm64.node # .so on Linux, .dll on Windows
60
+ node -e "console.log(require('.').engineVersion())"
61
+ ```
62
+
63
+ Or set `PNPM_NAPI_BINARY=/path/to/addon.node`.
package/index.d.ts ADDED
@@ -0,0 +1,309 @@
1
+ /**
2
+ * Node API bindings for the pnpm v12 Rust engine (pacquet).
3
+ *
4
+ * Shapes intentionally mirror the pnpm v11 TypeScript programmatic API
5
+ * (`@pnpm/installing.deps-installer`, `@pnpm/installing.client`) so that
6
+ * consumers migrating from the TS engine keep their call sites stable.
7
+ */
8
+
9
+ export interface PackageManifest {
10
+ name?: string
11
+ version?: string
12
+ dependencies?: Record<string, string>
13
+ devDependencies?: Record<string, string>
14
+ optionalDependencies?: Record<string, string>
15
+ peerDependencies?: Record<string, string>
16
+ peerDependenciesMeta?: Record<string, { optional?: boolean }>
17
+ dependenciesMeta?: Record<string, { injected?: boolean }>
18
+ bundledDependencies?: string[] | boolean
19
+ scripts?: Record<string, string>
20
+ bin?: string | Record<string, string>
21
+ engines?: Record<string, string>
22
+ os?: string[]
23
+ cpu?: string[]
24
+ libc?: string[]
25
+ [key: string]: unknown
26
+ }
27
+
28
+ export interface NodeApiProject {
29
+ /** Absolute path of the importer directory. */
30
+ rootDir: string
31
+ /** In-memory manifest; the engine never reads package.json from disk for listed projects. */
32
+ manifest: PackageManifest
33
+ }
34
+
35
+ export interface ProxyConfig {
36
+ httpProxy?: string
37
+ httpsProxy?: string
38
+ noProxy?: string | boolean
39
+ }
40
+
41
+ export interface NetworkConfig {
42
+ ca?: string | string[]
43
+ cert?: string | string[]
44
+ key?: string
45
+ localAddress?: string
46
+ strictSsl?: boolean
47
+ /**
48
+ * Maximum number of concurrent connections (sockets) to a single registry
49
+ * origin — pnpm's `maxSockets`. Bounds each `scheme://host[:port]` origin
50
+ * independently; the global `networkConcurrency` remains the outer cap.
51
+ */
52
+ maxSockets?: number
53
+ networkConcurrency?: number
54
+ fetchRetries?: number
55
+ fetchRetryFactor?: number
56
+ fetchRetryMintimeout?: number
57
+ fetchRetryMaxtimeout?: number
58
+ fetchTimeout?: number
59
+ userAgent?: string
60
+ }
61
+
62
+ /**
63
+ * A synchronous `readPackage` hook applied to resolved dependency manifests.
64
+ *
65
+ * `resolvedDir` is set when the manifest came from a directory resolution (an
66
+ * injected workspace project or a `file:` dependency); it is the directory
67
+ * recorded in the lockfile, relative to the lockfile root. Hosts use it to
68
+ * recognize a workspace project's dependency instance and substitute the
69
+ * project's raw manifest.
70
+ */
71
+ export type ReadPackageHook = (manifest: PackageManifest, resolvedDir?: string) => PackageManifest
72
+
73
+ /**
74
+ * Receives engine log events. The event stream is wire-compatible with
75
+ * `@pnpm/core-loggers` / the bunyan-shaped objects consumed by
76
+ * `@pnpm/logger`'s streamParser and `@pnpm/cli.default-reporter`.
77
+ */
78
+ export type LogListener = (event: Record<string, unknown>) => void
79
+
80
+ export interface SharedEngineOptions {
81
+ /** Registry routes: `{ default: url, '@scope': url, ... }` */
82
+ registries?: Record<string, string>
83
+ /**
84
+ * Pre-computed `Authorization` header values keyed by nerf-darted registry
85
+ * URI (`//host/path/`), plus `''` for the default registry — e.g.
86
+ * `{ '': 'Bearer abc', '//npm.example.com/': 'Basic <base64(user:pass)>' }`. The
87
+ * host resolves these from its `authConfig`; the engine applies them as-is.
88
+ */
89
+ authHeaderByUri?: Record<string, string>
90
+ proxyConfig?: ProxyConfig
91
+ networkConfig?: NetworkConfig
92
+ cacheDir?: string
93
+ }
94
+
95
+ export interface InstallOptions extends SharedEngineOptions {
96
+ /** Lockfile / workspace root directory. */
97
+ dir: string
98
+ projects: NodeApiProject[]
99
+ storeDir?: string
100
+ nodeLinker?: 'hoisted' | 'isolated'
101
+ /**
102
+ * pnpm's `linkWorkspacePackages`. When `true`/`'deep'`, a bare-semver
103
+ * dependency (including an auto-installed peer) may resolve to a workspace
104
+ * package by name; `false` (the default) matches only `workspace:` ranges.
105
+ */
106
+ linkWorkspacePackages?: boolean | 'deep'
107
+ hoistPattern?: string[]
108
+ publicHoistPattern?: string[]
109
+ /** Packages linked from outside the workspace; excluded from hoisting/pruning. */
110
+ externalDependencies?: string[]
111
+ overrides?: Record<string, string>
112
+ allowBuilds?: Record<string, boolean>
113
+ dangerouslyAllowAllBuilds?: boolean
114
+ autoInstallPeers?: boolean
115
+ excludeLinksFromLockfile?: boolean
116
+ lockfileOnly?: boolean
117
+ frozenLockfile?: boolean
118
+ preferFrozenLockfile?: boolean
119
+ packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone'
120
+ preferOffline?: boolean
121
+ offline?: boolean
122
+ virtualStoreDirMaxLength?: number
123
+ peersSuffixMaxLength?: number
124
+ dedupePeerDependents?: boolean
125
+ dedupeDirectDeps?: boolean
126
+ dedupeInjectedDeps?: boolean
127
+ resolvePeersFromWorkspaceRoot?: boolean
128
+ injectWorkspacePackages?: boolean
129
+ hoistWorkspacePackages?: boolean
130
+ minimumReleaseAge?: number
131
+ minimumReleaseAgeExclude?: string[]
132
+ includeOptionalDeps?: boolean
133
+ ignoreScripts?: boolean
134
+ /**
135
+ * Re-resolve the whole dependency graph to the highest in-range version
136
+ * (pnpm's `update: true` / `depth: Infinity`). The binding takes no package
137
+ * selectors, so an update always targets every dependency.
138
+ */
139
+ update?: boolean
140
+ /**
141
+ * pnpm's `depth`. Accepted for API compatibility; it only toggles pnpm's
142
+ * direct-vs-any-depth selector matching, which has no effect without package
143
+ * selectors, so it does not change the whole-graph `update` behavior.
144
+ */
145
+ depth?: number
146
+ /**
147
+ * Fail the install with `ERR_PNPM_UNSUPPORTED_ENGINE` when a dependency's
148
+ * `engines` / platform constraint the host does not satisfy is required
149
+ * (rather than warning). Defaults to `false`.
150
+ */
151
+ engineStrict?: boolean
152
+ /**
153
+ * Node.js version used as the `engines.node` target for the engine check.
154
+ * Defaults to the version auto-detected from the `node` binary.
155
+ */
156
+ nodeVersion?: string
157
+ /**
158
+ * `false` installs without creating a `node_modules` directory: the graph
159
+ * resolves and the lockfile is written, but nothing is materialized.
160
+ */
161
+ enableModulesDir?: boolean
162
+ /**
163
+ * Install from the lockfile without gating on the `package.json` ↔
164
+ * `pnpm-lock.yaml` freshness check, so an in-memory manifest that disagrees
165
+ * with the lockfile does not block the install.
166
+ */
167
+ ignorePackageManifest?: boolean
168
+ /** pnpm home directory. Accepted for compatibility; unused for project installs. */
169
+ pnpmHomeDir?: string
170
+ /**
171
+ * Fail with `ERR_PNPM_IGNORED_BUILDS` when a dependency build script is
172
+ * blocked. Defaults to `false`: the blocked packages are reported in
173
+ * `InstallResult.depsRequiringBuild` instead.
174
+ */
175
+ strictDepBuilds?: boolean
176
+ /** Customizations for how peer-dependency mismatches are treated. */
177
+ peerDependencyRules?: PeerDependencyRules
178
+ }
179
+
180
+ /** pnpm's `peerDependencyRules`. */
181
+ export interface PeerDependencyRules {
182
+ ignoreMissing?: string[]
183
+ allowAny?: string[]
184
+ allowedVersions?: Record<string, string>
185
+ }
186
+
187
+ export interface InstallResult {
188
+ stats: {
189
+ added: number
190
+ removed: number
191
+ linkedToRoot: number
192
+ }
193
+ /** Dep paths whose build scripts were skipped and require approval to run. */
194
+ depsRequiringBuild?: string[]
195
+ /** The resolved content-addressable store directory used by this install. */
196
+ storeDir: string
197
+ }
198
+
199
+ /**
200
+ * @param onLog receives wire-compatible pnpm log events.
201
+ * @param readPackageHook a **synchronous** `(manifest, resolvedDir?) => manifest`
202
+ * transform applied to every resolved dependency manifest during resolution
203
+ * (the `readPackage` hook). Must return the manifest object, not a promise.
204
+ */
205
+ export function install(
206
+ options: InstallOptions,
207
+ onLog?: LogListener,
208
+ readPackageHook?: ReadPackageHook,
209
+ ): Promise<InstallResult>
210
+
211
+ /**
212
+ * Rebuild dependency build scripts against the already-materialized
213
+ * `node_modules` (frozen path). Takes the same options shape as `install`.
214
+ * @param selectedNames restrict the rebuild to these package names / build
215
+ * keys; omit (or pass an empty array) to rebuild every build-needing package.
216
+ */
217
+ export function rebuild(
218
+ options: InstallOptions,
219
+ onLog?: LogListener,
220
+ selectedNames?: string[],
221
+ ): Promise<void>
222
+
223
+ export interface PeerIssuesOptions extends SharedEngineOptions {
224
+ dir: string
225
+ projects: NodeApiProject[]
226
+ storeDir?: string
227
+ overrides?: Record<string, string>
228
+ peersSuffixMaxLength?: number
229
+ virtualStoreDirMaxLength?: number
230
+ /**
231
+ * Defaults to `false` for this query (unlike `install`): with peers
232
+ * auto-installed the resolver satisfies them itself and nothing is
233
+ * reported, defeating the report's purpose.
234
+ */
235
+ autoInstallPeers?: boolean
236
+ }
237
+
238
+ export interface PeerDependencyIssues {
239
+ missing: Record<string, Array<{ parents: Array<{ name: string; version: string }>; optional: boolean; wantedRange: string }>>
240
+ bad: Record<string, Array<{ parents: Array<{ name: string; version: string }>; foundVersion: string; resolvedFrom: Array<{ name: string; version: string }>; optional: boolean; wantedRange: string }>>
241
+ conflicts: string[]
242
+ intersections: Record<string, string>
243
+ }
244
+
245
+ export type PeerDependencyIssuesByProjects = Record<string, PeerDependencyIssues>
246
+
247
+ export function getPeerDependencyIssues(options: PeerIssuesOptions): Promise<PeerDependencyIssuesByProjects>
248
+
249
+ export interface WantedDependency {
250
+ alias?: string
251
+ bareSpecifier?: string
252
+ }
253
+
254
+ export interface ResolveOptions extends SharedEngineOptions {
255
+ /** Project/lockfile dir used to resolve `link:`/`file:` and workspace specs. */
256
+ dir: string
257
+ /** Return the full packument-derived manifest instead of the abbreviated one. */
258
+ fullMetadata?: boolean
259
+ }
260
+
261
+ export interface ResolveResult {
262
+ id: string
263
+ manifest?: PackageManifest
264
+ resolvedVia: string
265
+ normalizedBareSpecifier?: string
266
+ latest?: string
267
+ resolution?: Record<string, unknown>
268
+ }
269
+
270
+ export function resolveDependency(wanted: WantedDependency, options: ResolveOptions): Promise<ResolveResult>
271
+
272
+ export interface PackOptions {
273
+ dir: string
274
+ workspaceDir?: string
275
+ /** Destination directory for the tarball (defaults to `dir`). */
276
+ packDestination?: string
277
+ /** Exact output path/filename for the tarball. */
278
+ out?: string
279
+ ignoreScripts?: boolean
280
+ packGzipLevel?: number
281
+ embedReadme?: boolean
282
+ dryRun?: boolean
283
+ extraBinPaths?: string[]
284
+ extraEnv?: Record<string, string>
285
+ }
286
+
287
+ export interface PackResult {
288
+ publishedManifest: PackageManifest
289
+ contents: string[]
290
+ tarballPath: string
291
+ unpackedSize: number
292
+ }
293
+
294
+ export function pack(options: PackOptions, onLog?: LogListener): Promise<PackResult>
295
+
296
+ export interface ParsedBareSpecifier {
297
+ alias?: string
298
+ bareSpecifier?: string
299
+ name?: string
300
+ fetchSpec?: string
301
+ normalizedBareSpecifier?: string
302
+ type?: string
303
+ }
304
+
305
+ /** Parses/validates a dependency specifier. Returns null for unparsable input. */
306
+ export function parseBareSpecifier(spec: string, alias?: string): ParsedBareSpecifier | null
307
+
308
+ /** Version of the underlying Rust engine (pacquet). */
309
+ export function engineVersion(): string
package/index.js ADDED
@@ -0,0 +1,169 @@
1
+ 'use strict'
2
+
3
+ // Loader for the pacquet-napi native addon.
4
+ //
5
+ // Resolution order:
6
+ // 1. PNPM_NAPI_BINARY env var — explicit path to a .node file (local dev,
7
+ // custom builds).
8
+ // 2. A platform package (`@pnpm/napi.<platform>`) installed as an
9
+ // optionalDependency (release-time; injected by the package generator like
10
+ // the `@pnpm/exe.*` packages).
11
+ // 3. A locally built artifact next to this file or under the Cargo target dir
12
+ // (development checkouts).
13
+
14
+ const path = require('node:path')
15
+ const fs = require('node:fs')
16
+
17
+ // `'glibc' | 'musl' | null` — `null` when the host isn't Linux or the libc
18
+ // can't be probed (`process.report` may be unavailable/disabled). glibc builds
19
+ // set `glibcVersionRuntime`; musl leaves it unset.
20
+ function detectLinuxLibc() {
21
+ if (process.platform !== 'linux') return null
22
+ try {
23
+ return process.report?.getReport()?.header?.glibcVersionRuntime ? 'glibc' : 'musl'
24
+ } catch {
25
+ return null
26
+ }
27
+ }
28
+
29
+ // Ordered platform triples to try. On Linux both libc variants are attempted
30
+ // (ordered by detection) so a musl host whose libc can't be probed still
31
+ // resolves the `-musl` addon instead of failing on the glibc one; elsewhere
32
+ // there is a single triple.
33
+ function platformTriples() {
34
+ const { platform, arch } = process
35
+ if (platform === 'linux') {
36
+ const order = detectLinuxLibc() === 'musl' ? ['-musl', ''] : ['', '-musl']
37
+ return order.map((suffix) => `linux-${arch}${suffix}`)
38
+ }
39
+ return [`${platform}-${arch}`]
40
+ }
41
+
42
+ function tryLoad(candidate, loadErrors) {
43
+ if (!candidate) return null
44
+ try {
45
+ if (candidate.endsWith('.node') && !fs.existsSync(candidate)) return null
46
+ return require(candidate)
47
+ } catch (err) {
48
+ if (isRetryableLoadError(err, candidate)) {
49
+ loadErrors.push(err)
50
+ return null
51
+ }
52
+ throw err
53
+ }
54
+ }
55
+
56
+ function isRetryableLoadError(err, candidate) {
57
+ if (!err) return false
58
+ // The candidate isn't installed (platform package absent) — try the next one.
59
+ if (isMissingCandidate(err, candidate)) return true
60
+ // The candidate exists but is the wrong libc / ABI: `require()` throws
61
+ // `ERR_DLOPEN_FAILED`. Fall through to the other Linux libc variant rather
62
+ // than aborting the whole load on a wrong first guess.
63
+ return err.code === 'ERR_DLOPEN_FAILED'
64
+ }
65
+
66
+ function isMissingCandidate(err, candidate) {
67
+ return (
68
+ err &&
69
+ err.code === 'MODULE_NOT_FOUND' &&
70
+ typeof err.message === 'string' &&
71
+ err.message.includes(`'${candidate}'`)
72
+ )
73
+ }
74
+
75
+ function loadFailure(triple, loadErrors) {
76
+ const error = new Error(
77
+ `Failed to load the pnpm Rust engine for ${triple}. ` +
78
+ 'Install the matching @pnpm/napi platform package, or point ' +
79
+ 'PNPM_NAPI_BINARY at a locally built .node file.'
80
+ )
81
+ if (loadErrors.length > 0) {
82
+ error.cause = loadErrors[0]
83
+ }
84
+ return error
85
+ }
86
+
87
+ function loadBinding() {
88
+ const triples = platformTriples()
89
+ const loadErrors = []
90
+ // An explicit PNPM_NAPI_BINARY is strict: it must be a `.node` file (so a
91
+ // non-.node value can't be require()'d as an arbitrary module), and if it
92
+ // exists but fails to load we surface that error directly rather than
93
+ // silently falling back to a platform package.
94
+ const explicit = process.env.PNPM_NAPI_BINARY
95
+ if (explicit) {
96
+ if (!explicit.endsWith('.node')) {
97
+ throw new Error(`PNPM_NAPI_BINARY must point to a .node addon file, got: ${explicit}`)
98
+ }
99
+ if (fs.existsSync(explicit)) {
100
+ return require(explicit)
101
+ }
102
+ loadErrors.push(new Error(`PNPM_NAPI_BINARY was set but not found: ${explicit}`))
103
+ }
104
+ // Platform packages / local artifacts. On Linux both libc variants are tried,
105
+ // so a wrong-ABI first candidate (an `ERR_DLOPEN_FAILED`) falls through to the
106
+ // other rather than aborting.
107
+ const candidates = [
108
+ ...triples.flatMap((triple) => [
109
+ `@pnpm/napi.${triple}`,
110
+ path.join(__dirname, `pnpm-napi.${triple}.node`),
111
+ ]),
112
+ path.join(__dirname, 'pnpm-napi.node'),
113
+ ]
114
+ for (const candidate of candidates) {
115
+ const binding = tryLoad(candidate, loadErrors)
116
+ if (binding) return binding
117
+ }
118
+ throw loadFailure(triples[0], loadErrors)
119
+ }
120
+
121
+ // The Rust side encodes structured error fields (code/hint) as a JSON envelope
122
+ // in the thrown error's message, prefixed with PNPM_ERR_JSON:. Lift them back
123
+ // onto the Error object so consumers keep reading `err.code` / `err.hint`.
124
+ const ENVELOPE_PREFIX = 'PNPM_ERR_JSON:'
125
+ function decorateError(err) {
126
+ if (err && typeof err.message === 'string' && err.message.startsWith(ENVELOPE_PREFIX)) {
127
+ try {
128
+ const parsed = JSON.parse(err.message.slice(ENVELOPE_PREFIX.length))
129
+ if (parsed.code != null) err.code = parsed.code
130
+ if (parsed.hint != null) err.hint = parsed.hint
131
+ if (typeof parsed.message === 'string') err.message = parsed.message
132
+ } catch {
133
+ // Leave the error untouched if the envelope doesn't parse.
134
+ }
135
+ }
136
+ return err
137
+ }
138
+
139
+ // Wrap every exported function so both sync throws and rejected promises get
140
+ // the envelope lifted. Non-function exports (if any) pass through unchanged.
141
+ function wrapExports(binding) {
142
+ const wrapped = {}
143
+ for (const key of Object.keys(binding)) {
144
+ const value = binding[key]
145
+ if (typeof value !== 'function') {
146
+ wrapped[key] = value
147
+ continue
148
+ }
149
+ wrapped[key] = function (...args) {
150
+ try {
151
+ const result = value.apply(this, args)
152
+ if (result && typeof result.then === 'function') {
153
+ return result.then(
154
+ (resolved) => resolved,
155
+ (err) => {
156
+ throw decorateError(err)
157
+ }
158
+ )
159
+ }
160
+ return result
161
+ } catch (err) {
162
+ throw decorateError(err)
163
+ }
164
+ }
165
+ }
166
+ return wrapped
167
+ }
168
+
169
+ module.exports = wrapExports(loadBinding())
package/package.json CHANGED
@@ -1,5 +1,42 @@
1
1
  {
2
2
  "name": "@pnpm/napi",
3
- "version": "0.0.0-0",
4
- "license": "MIT"
3
+ "version": "12.0.0-alpha.10",
4
+ "description": "Node.js addon bindings for the pnpm v12 Rust engine (pacquet)",
5
+ "keywords": [
6
+ "pnpm",
7
+ "package manager",
8
+ "rust",
9
+ "napi"
10
+ ],
11
+ "license": "MIT",
12
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm",
13
+ "bugs": "https://github.com/pnpm/pnpm/issues",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/pnpm/pnpm",
17
+ "directory": "pnpm/npm/napi"
18
+ },
19
+ "main": "index.js",
20
+ "types": "index.d.ts",
21
+ "engines": {
22
+ "node": ">=18.*"
23
+ },
24
+ "files": [
25
+ "index.js",
26
+ "index.d.ts",
27
+ "README.md"
28
+ ],
29
+ "optionalDependencies": {
30
+ "@pnpm/napi.win32-x64": "12.0.0-alpha.10",
31
+ "@pnpm/napi.win32-arm64": "12.0.0-alpha.10",
32
+ "@pnpm/napi.darwin-x64": "12.0.0-alpha.10",
33
+ "@pnpm/napi.darwin-arm64": "12.0.0-alpha.10",
34
+ "@pnpm/napi.linux-x64": "12.0.0-alpha.10",
35
+ "@pnpm/napi.linux-arm64": "12.0.0-alpha.10",
36
+ "@pnpm/napi.linux-x64-musl": "12.0.0-alpha.10",
37
+ "@pnpm/napi.linux-arm64-musl": "12.0.0-alpha.10"
38
+ },
39
+ "scripts": {
40
+ "generate-packages": "node scripts/generate-packages.mjs"
41
+ }
5
42
  }