@parcel/parcel3 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/bin/parcel3 +227 -0
  2. package/package.json +26 -7
  3. package/README.md +0 -45
package/bin/parcel3 ADDED
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Shipped as `bin/parcel3`. Parcel itself is a native executable, published one
6
+ * platform package per target and pulled in through optionalDependencies, so all
7
+ * this file does is hand off to whichever one npm installed for this host.
8
+ *
9
+ * It also tries to take itself out of the loop. Starting Node costs ~30ms on
10
+ * every single `parcel3` invocation, which is a large tax on a tool whose whole
11
+ * point is being fast, so on the first run it rewrites the `node_modules/.bin`
12
+ * entry that launched it into a launcher that execs the binary without Node.
13
+ * See `launcher` for why that launcher looks the way it does.
14
+ *
15
+ * Install scripts would be the natural place for this, but npm and pnpm both
16
+ * block them by default now, so first run is the earliest moment available.
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ /** The command, which is also the `node_modules/.bin` entry `optimize` rewrites. */
23
+ const NAME = 'parcel3';
24
+
25
+ /** Prefix of the platform packages. Scoped; only `parcel3` itself is not. */
26
+ const PLATFORM_PACKAGE = '@parcel/parcel3';
27
+
28
+ const EXECUTABLE = process.platform === 'win32' ? 'parcel3.exe' : 'parcel3';
29
+
30
+ /**
31
+ * The platform packages that could serve this host, best first.
32
+ *
33
+ * The names are derived rather than listed, matching what `matrix.mjs` builds
34
+ * from the target table: `process.platform` and `process.arch` are already the
35
+ * values npm's `os` and `cpu` fields use, so a new target needs no change here.
36
+ *
37
+ * On Linux the name also depends on the C library, and rather than detect it and
38
+ * trust the answer we try both: npm, pnpm and Bun all honour the `libc` field,
39
+ * so only the right one is installed and the wrong one simply fails to resolve.
40
+ * The musl check just decides which to try first, for the package managers that
41
+ * ignore `libc` and install both.
42
+ */
43
+ function candidates() {
44
+ const base = `${PLATFORM_PACKAGE}-${process.platform}-${process.arch}`;
45
+ if (process.platform !== 'linux') return [base];
46
+ return isMusl() ? [`${base}-musl`, base] : [base, `${base}-musl`];
47
+ }
48
+
49
+ /**
50
+ * Whether this is a musl system. Biome and friends shell out to `ldd --version`
51
+ * for this; a directory listing costs a fraction of a process.
52
+ */
53
+ function isMusl() {
54
+ try {
55
+ return fs.readdirSync('/lib').some(entry => entry.startsWith('ld-musl-'));
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ function resolveBinary() {
62
+ for (const pkg of candidates()) {
63
+ try {
64
+ return require.resolve(`${pkg}/${EXECUTABLE}`);
65
+ } catch {}
66
+ }
67
+ return null;
68
+ }
69
+
70
+ const binPath = resolveBinary();
71
+ if (binPath == null) {
72
+ // Both cases land here, and the message covers both: the package is missing
73
+ // either because this platform has no prebuilt binary, or because it was
74
+ // skipped at install time.
75
+ process.stderr.write(
76
+ `Parcel could not find the "${
77
+ candidates()[0]
78
+ }" package, which would hold the parcel3 ` +
79
+ `binary for ${process.platform} ${process.arch}.\n\n` +
80
+ `Either Parcel publishes no binary for this platform, or the one it does publish was not ` +
81
+ `installed: it comes in through optionalDependencies, so --no-optional and --omit=optional ` +
82
+ `both skip it, as does copying node_modules here from a machine of a different platform. ` +
83
+ `Reinstalling on this machine fixes the second case.\n`,
84
+ );
85
+ process.exit(1);
86
+ }
87
+
88
+ optimize();
89
+ run();
90
+
91
+ /**
92
+ * Rewrite the `.bin` entry that launched us so it runs the binary directly.
93
+ *
94
+ * Only an entry that can be proven to refer to this file is ever touched, the
95
+ * write goes through a temp file and an atomic rename, and every failure leaves
96
+ * the entry alone - a slow parcel3 is fine, a broken one is not.
97
+ */
98
+ function optimize() {
99
+ // Windows generates .cmd and .ps1 shims with `node` baked in at install time,
100
+ // so replacing what they point at would only break them.
101
+ if (process.platform === 'win32' || process.env.PARCEL_NO_OPTIMIZE) return;
102
+
103
+ for (const entry of binEntries()) {
104
+ try {
105
+ const stat = fs.lstatSync(entry);
106
+ if (stat.isSymbolicLink()) {
107
+ // npm and Yarn: .bin/parcel3 is a symlink to this file.
108
+ if (fs.realpathSync(entry) !== __filename) continue;
109
+ } else if (stat.isFile()) {
110
+ // pnpm: .bin/parcel3 is a generated sh wrapper that runs `node <this>`.
111
+ if (!wrapsThisFile(fs.readFileSync(entry, 'utf8'))) continue;
112
+ } else {
113
+ continue;
114
+ }
115
+
116
+ replace(entry);
117
+ } catch {}
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Whether a generated wrapper points at this file. Package managers write the
123
+ * path relative to their own layout, so the tail below the last `node_modules`
124
+ * is the longest part that is guaranteed to appear verbatim.
125
+ */
126
+ function wrapsThisFile(contents) {
127
+ const tail = __filename.split(/node_modules[\\/]/).pop();
128
+ return contents.includes(tail) && contents.includes('node');
129
+ }
130
+
131
+ /** Every `.bin/parcel3` that could have launched this file. */
132
+ function* binEntries() {
133
+ // What the kernel was handed, before symlinks were resolved: npm and Yarn
134
+ // launch us through the .bin symlink itself.
135
+ const argv1 = process.argv[1];
136
+ if (argv1 && path.basename(path.dirname(argv1)) === '.bin') {
137
+ yield argv1;
138
+ }
139
+
140
+ // Otherwise walk up. `node_modules/.bin` covers a hoisted layout; pnpm keeps
141
+ // the package under `node_modules/.pnpm/...` and the bin beside the store
142
+ // rather than next to the package, so that one is checked separately.
143
+ let dir = path.dirname(__filename);
144
+ for (
145
+ let parent = path.dirname(dir);
146
+ parent !== dir;
147
+ parent = path.dirname(dir)
148
+ ) {
149
+ const base = path.basename(dir);
150
+ if (base === 'node_modules') yield path.join(dir, '.bin', NAME);
151
+ if (base === '.pnpm') yield path.join(parent, '.bin', NAME);
152
+ dir = parent;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * The launcher gets read two different ways and has to work as both.
158
+ *
159
+ * Normally the kernel reads `#!/bin/sh` and sh execs the binary, which is the
160
+ * whole point: no Node anywhere. But an invocation that started just before the
161
+ * rename has already told Node to load this path as its entry module, and Node
162
+ * opens it ~30ms later - after the swap. Writing anything Node cannot parse, a
163
+ * symlink to the binary included, makes those invocations die trying to read a
164
+ * Mach-O or ELF file as JavaScript.
165
+ *
166
+ * So the rest of the file is also valid JavaScript. `":"` is the sh no-op and a
167
+ * bare string in JS; everything after `//` is an sh argument and a JS comment.
168
+ * A straggler falls through to the last line and runs the binary anyway, paying
169
+ * for Node one final time.
170
+ */
171
+ function launcher(entry) {
172
+ // Relative to the launcher, so the tree stays movable: renaming the project or
173
+ // copying node_modules into an image keeps it working.
174
+ const rel = path.relative(path.dirname(entry), binPath);
175
+ if (/["$`\\\n]/.test(rel)) return null; // not safely quotable for sh
176
+
177
+ return (
178
+ '#!/bin/sh\n' +
179
+ `":" //# ; exec "\${0%/*}/${rel}" "$@"\n` +
180
+ `require("child_process").spawnSync(require("path").join(__dirname, ${JSON.stringify(
181
+ rel,
182
+ )}), ` +
183
+ `process.argv.slice(2), {stdio: "inherit"});\n`
184
+ );
185
+ }
186
+
187
+ /**
188
+ * Write beside the entry, then rename over it. A concurrent invocation sees
189
+ * either the old entry or the new one, never a half-written file.
190
+ */
191
+ function replace(entry) {
192
+ const contents = launcher(entry);
193
+ if (contents == null) return;
194
+
195
+ const tmp = `${entry}.${process.pid}.tmp`;
196
+ try {
197
+ fs.writeFileSync(tmp, contents, {mode: 0o755});
198
+ fs.renameSync(tmp, entry);
199
+ } catch (err) {
200
+ try {
201
+ fs.unlinkSync(tmp);
202
+ } catch {}
203
+ throw err;
204
+ }
205
+ }
206
+
207
+ function run() {
208
+ const args = process.argv.slice(2);
209
+
210
+ // Replacing this process rather than forking one keeps signals, the exit code
211
+ // and terminal handling native. Node gained execve in 23.11 and never has it
212
+ // on Windows, hence the fallback.
213
+ if (typeof process.execve === 'function') {
214
+ process.execve(binPath, [binPath, ...args], process.env);
215
+ }
216
+
217
+ const result = require('child_process').spawnSync(binPath, args, {
218
+ stdio: 'inherit',
219
+ });
220
+ if (result.error) throw result.error;
221
+ // Signal death has no exit code of its own; 128 + signal is what a shell reports.
222
+ process.exit(
223
+ result.signal
224
+ ? 128 + require('os').constants.signals[result.signal]
225
+ : result.status,
226
+ );
227
+ }
package/package.json CHANGED
@@ -1,10 +1,29 @@
1
1
  {
2
2
  "name": "@parcel/parcel3",
3
- "version": "0.0.0",
4
- "description": "OIDC trusted publishing setup package for @parcel/parcel3",
5
- "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
3
+ "version": "0.0.1",
4
+ "description": "Blazing fast, zero configuration web application bundler",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/parcel-bundler/parcel.git"
9
+ },
10
+ "bin": {
11
+ "parcel3": "bin/parcel3"
12
+ },
13
+ "files": [
14
+ "bin"
15
+ ],
16
+ "engines": {
17
+ "node": ">= 18"
18
+ },
19
+ "optionalDependencies": {
20
+ "@parcel/parcel3-darwin-arm64": "0.0.1",
21
+ "@parcel/parcel3-win32-arm64": "0.0.1",
22
+ "@parcel/parcel3-linux-arm64": "0.0.1",
23
+ "@parcel/parcel3-linux-arm64-musl": "0.0.1",
24
+ "@parcel/parcel3-darwin-x64": "0.0.1",
25
+ "@parcel/parcel3-win32-x64": "0.0.1",
26
+ "@parcel/parcel3-linux-x64": "0.0.1",
27
+ "@parcel/parcel3-linux-x64-musl": "0.0.1"
28
+ }
10
29
  }
package/README.md DELETED
@@ -1,45 +0,0 @@
1
- # @parcel/parcel3
2
-
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
4
-
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
6
-
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
8
-
9
- ## Purpose
10
-
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@parcel/parcel3`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
15
-
16
- ## What is OIDC Trusted Publishing?
17
-
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
19
-
20
- ## Setup Instructions
21
-
22
- To properly configure OIDC trusted publishing for this package:
23
-
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
28
-
29
- ## DO NOT USE THIS PACKAGE
30
-
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
36
-
37
- ## More Information
38
-
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
42
-
43
- ---
44
-
45
- **Maintained for OIDC setup purposes only**