@vercel/go 4.0.0 → 5.0.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.
Binary file
Binary file
package/dist/index.js CHANGED
@@ -2199,14 +2199,14 @@ var require_signal_exit = __commonJS({
2199
2199
  if (opts && opts.alwaysLast) {
2200
2200
  ev = "afterexit";
2201
2201
  }
2202
- var remove3 = function() {
2202
+ var remove4 = function() {
2203
2203
  emitter.removeListener(ev, cb);
2204
2204
  if (emitter.listeners("exit").length === 0 && emitter.listeners("afterexit").length === 0) {
2205
2205
  unload();
2206
2206
  }
2207
2207
  };
2208
2208
  emitter.on(ev, cb);
2209
- return remove3;
2209
+ return remove4;
2210
2210
  };
2211
2211
  unload = function unload2() {
2212
2212
  if (!loaded || !processOk(global.process)) {
@@ -4372,7 +4372,7 @@ var require_copy = __commonJS({
4372
4372
  "use strict";
4373
4373
  var fs3 = require_graceful_fs();
4374
4374
  var path = require("path");
4375
- var mkdirp3 = require_mkdirs2().mkdirs;
4375
+ var mkdirp4 = require_mkdirs2().mkdirs;
4376
4376
  var pathExists5 = require_path_exists().pathExists;
4377
4377
  var utimes = require_utimes().utimesMillis;
4378
4378
  var notExist = Symbol("notExist");
@@ -4408,7 +4408,7 @@ var require_copy = __commonJS({
4408
4408
  return cb(err);
4409
4409
  if (dirExists)
4410
4410
  return startCopy(destStat, src, dest, opts, cb);
4411
- mkdirp3(destParent, (err2) => {
4411
+ mkdirp4(destParent, (err2) => {
4412
4412
  if (err2)
4413
4413
  return cb(err2);
4414
4414
  return startCopy(destStat, src, dest, opts, cb);
@@ -4889,7 +4889,7 @@ var require_empty = __commonJS({
4889
4889
  var fs3 = require("fs");
4890
4890
  var path = require("path");
4891
4891
  var mkdir = require_mkdirs2();
4892
- var remove3 = require_remove();
4892
+ var remove4 = require_remove();
4893
4893
  var emptyDir = u2(function emptyDir2(dir, callback) {
4894
4894
  callback = callback || function() {
4895
4895
  };
@@ -4902,7 +4902,7 @@ var require_empty = __commonJS({
4902
4902
  const item = items.pop();
4903
4903
  if (!item)
4904
4904
  return callback();
4905
- remove3.remove(item, (err2) => {
4905
+ remove4.remove(item, (err2) => {
4906
4906
  if (err2)
4907
4907
  return callback(err2);
4908
4908
  deleteItem();
@@ -4919,7 +4919,7 @@ var require_empty = __commonJS({
4919
4919
  }
4920
4920
  items.forEach((item) => {
4921
4921
  item = path.join(dir, item);
4922
- remove3.removeSync(item);
4922
+ remove4.removeSync(item);
4923
4923
  });
4924
4924
  }
4925
4925
  module2.exports = {
@@ -5574,8 +5574,8 @@ var require_move = __commonJS({
5574
5574
  var fs3 = require_graceful_fs();
5575
5575
  var path = require("path");
5576
5576
  var copy3 = require_copy2().copy;
5577
- var remove3 = require_remove().remove;
5578
- var mkdirp3 = require_mkdirs2().mkdirp;
5577
+ var remove4 = require_remove().remove;
5578
+ var mkdirp4 = require_mkdirs2().mkdirp;
5579
5579
  var pathExists5 = require_path_exists().pathExists;
5580
5580
  function move2(src, dest, opts, cb) {
5581
5581
  if (typeof opts === "function") {
@@ -5593,7 +5593,7 @@ var require_move = __commonJS({
5593
5593
  if (st2.isDirectory() && isSrcSubdir(src, dest)) {
5594
5594
  return cb(new Error(`Cannot move '${src}' to a subdirectory of itself, '${dest}'.`));
5595
5595
  }
5596
- mkdirp3(path.dirname(dest), (err2) => {
5596
+ mkdirp4(path.dirname(dest), (err2) => {
5597
5597
  if (err2)
5598
5598
  return cb(err2);
5599
5599
  return doRename(src, dest, overwrite, cb);
@@ -5602,7 +5602,7 @@ var require_move = __commonJS({
5602
5602
  }
5603
5603
  function doRename(src, dest, overwrite, cb) {
5604
5604
  if (overwrite) {
5605
- return remove3(dest, (err) => {
5605
+ return remove4(dest, (err) => {
5606
5606
  if (err)
5607
5607
  return cb(err);
5608
5608
  return rename(src, dest, overwrite, cb);
@@ -5633,7 +5633,7 @@ var require_move = __commonJS({
5633
5633
  copy3(src, dest, opts, (err) => {
5634
5634
  if (err)
5635
5635
  return cb(err);
5636
- return remove3(src, cb);
5636
+ return remove4(src, cb);
5637
5637
  });
5638
5638
  }
5639
5639
  function isSrcSubdir(src, dest) {
@@ -10967,9 +10967,9 @@ var require_dev_proxy = __commonJS({
10967
10967
  resolveServiceRoutePrefix: () => resolveServiceRoutePrefix,
10968
10968
  rewriteRequestUrl: () => rewriteRequestUrl,
10969
10969
  sanitizeHeaders: () => sanitizeHeaders,
10970
- startDevProxy: () => startDevProxy,
10970
+ startDevProxy: () => startDevProxy2,
10971
10971
  stripServiceRoutePrefix: () => stripServiceRoutePrefix,
10972
- waitForPort: () => waitForPort2
10972
+ waitForPort: () => waitForPort
10973
10973
  });
10974
10974
  module2.exports = __toCommonJS2(dev_proxy_exports);
10975
10975
  var import_node_http = require("http");
@@ -11060,7 +11060,7 @@ var require_dev_proxy = __commonJS({
11060
11060
  });
11061
11061
  });
11062
11062
  }
11063
- function isPortReachable2(port) {
11063
+ function isPortReachable(port) {
11064
11064
  return new Promise((resolve) => {
11065
11065
  const socket = (0, import_node_net.createConnection)({ port, host: LOCALHOST });
11066
11066
  const done = (reachable) => {
@@ -11074,10 +11074,10 @@ var require_dev_proxy = __commonJS({
11074
11074
  socket.once("error", () => done(false));
11075
11075
  });
11076
11076
  }
11077
- function sleep2(ms2) {
11077
+ function sleep(ms2) {
11078
11078
  return new Promise((resolve) => setTimeout(resolve, ms2));
11079
11079
  }
11080
- async function waitForPort2(port, child, timeout, label = "Dev server") {
11080
+ async function waitForPort(port, child, timeout, label = "Dev server") {
11081
11081
  let exited;
11082
11082
  let spawnError;
11083
11083
  const onExit = (code, signal) => {
@@ -11098,9 +11098,9 @@ var require_dev_proxy = __commonJS({
11098
11098
  `${label} exited before it started listening (code: ${exited.code}, signal: ${exited.signal})`
11099
11099
  );
11100
11100
  }
11101
- if (await isPortReachable2(port))
11101
+ if (await isPortReachable(port))
11102
11102
  return;
11103
- await sleep2(READINESS_POLL_INTERVAL);
11103
+ await sleep(READINESS_POLL_INTERVAL);
11104
11104
  }
11105
11105
  throw new Error(`${label} did not start listening within ${timeout}ms`);
11106
11106
  } finally {
@@ -11176,7 +11176,7 @@ var require_dev_proxy = __commonJS({
11176
11176
  });
11177
11177
  return server;
11178
11178
  }
11179
- async function startDevProxy(options) {
11179
+ async function startDevProxy2(options) {
11180
11180
  const {
11181
11181
  spawnServer,
11182
11182
  env = process.env,
@@ -11198,7 +11198,7 @@ var require_dev_proxy = __commonJS({
11198
11198
  }
11199
11199
  };
11200
11200
  try {
11201
- await waitForPort2(internalPort, child, readinessTimeout, label);
11201
+ await waitForPort(internalPort, child, readinessTimeout, label);
11202
11202
  server = createDevProxyServer({
11203
11203
  targetPort: internalPort,
11204
11204
  routePrefix: resolveServiceRoutePrefix(env)
@@ -14753,27 +14753,75 @@ var GoWrapper = class {
14753
14753
  getEnv() {
14754
14754
  return this.env;
14755
14755
  }
14756
- build(src, dest, { vendorMode = false } = {}) {
14757
- (0, import_build_utils.debug)(`Building optimized 'go' binary ${src} -> ${dest}`);
14756
+ build(src, dest, { vendorMode = false, release = true } = {}) {
14757
+ (0, import_build_utils.debug)(
14758
+ `Building ${release ? "optimized" : "debug"} 'go' binary ${src} -> ${dest}`
14759
+ );
14758
14760
  const sources = Array.isArray(src) ? src : [src];
14759
14761
  const envGoBuildFlags = (this.env || this.opts.env).GO_BUILD_FLAGS;
14760
- const flags = envGoBuildFlags ? (0, import_string_argv.default)(envGoBuildFlags) : [...GO_FLAGS];
14762
+ const defaultFlags = release ? GO_FLAGS : [];
14763
+ const flags = envGoBuildFlags ? (0, import_string_argv.default)(envGoBuildFlags) : [...defaultFlags];
14761
14764
  if (vendorMode && !envGoBuildFlags) {
14762
14765
  flags.push("-mod=vendor");
14763
14766
  }
14764
14767
  return this.execute("build", ...flags, "-o", dest, ...sources);
14765
14768
  }
14766
14769
  };
14770
+ function newestSupportedGoVersion() {
14771
+ return Array.from(versionMap.values())[0];
14772
+ }
14773
+ function compareGoVersions(left, right) {
14774
+ const leftParts = left.split(".").map((part) => parseInt(part, 10));
14775
+ const rightParts = right.split(".").map((part) => parseInt(part, 10));
14776
+ for (let index = 0; index < Math.max(leftParts.length, rightParts.length); index++) {
14777
+ const difference = (leftParts[index] ?? 0) - (rightParts[index] ?? 0);
14778
+ if (difference !== 0) {
14779
+ return difference;
14780
+ }
14781
+ }
14782
+ return 0;
14783
+ }
14784
+ function selectGoVersion(preferred, { preferNewestToolchain = false } = {}) {
14785
+ if (preferred?.toolchain) {
14786
+ return preferred.toolchain;
14787
+ }
14788
+ if (preferred && !preferNewestToolchain) {
14789
+ return preferred.go;
14790
+ }
14791
+ const newestSupported = newestSupportedGoVersion();
14792
+ if (preferred && compareGoVersions(preferred.go, newestSupported) > 0) {
14793
+ return preferred.go;
14794
+ }
14795
+ return newestSupported;
14796
+ }
14797
+ var MIN_DARWIN_RUNNABLE_GO = { major: 1, minor: 23 };
14798
+ function isBelowMinDarwinRunnable(version2) {
14799
+ const [major, minor] = version2.split(".").map((part) => parseInt(part, 10));
14800
+ if (!Number.isFinite(major) || !Number.isFinite(minor))
14801
+ return false;
14802
+ if (major !== MIN_DARWIN_RUNNABLE_GO.major) {
14803
+ return major < MIN_DARWIN_RUNNABLE_GO.major;
14804
+ }
14805
+ return minor < MIN_DARWIN_RUNNABLE_GO.minor;
14806
+ }
14767
14807
  async function createGo({
14768
14808
  modulePath,
14769
14809
  opts = {},
14770
- workPath
14810
+ workPath,
14811
+ preferNewestToolchain = false
14771
14812
  }) {
14772
14813
  let goPreferredVersion;
14773
14814
  if (modulePath) {
14774
14815
  goPreferredVersion = await parseGoModVersionFromModule(modulePath);
14775
14816
  }
14776
- const goSelectedVersion = goPreferredVersion ? goPreferredVersion.toolchain || goPreferredVersion.go : Array.from(versionMap.values())[0];
14817
+ const goSelectedVersion = selectGoVersion(goPreferredVersion, {
14818
+ preferNewestToolchain
14819
+ });
14820
+ if (preferNewestToolchain && process.platform === "darwin" && isBelowMinDarwinRunnable(goSelectedVersion)) {
14821
+ console.warn(
14822
+ `Warning: your \`go.mod\` pins Go ${goSelectedVersion} via \`toolchain\`. Binaries built with Go older than ${MIN_DARWIN_RUNNABLE_GO.major}.${MIN_DARWIN_RUNNABLE_GO.minor} do not start on recent macOS. Remove the directive to use Go ${newestSupportedGoVersion()} locally.`
14823
+ );
14824
+ }
14777
14825
  const env = opts.env ? (0, import_build_utils.cloneEnv)(opts.env) : (0, import_build_utils.cloneEnv)(process.env);
14778
14826
  const { PATH } = env;
14779
14827
  const { platform } = process;
@@ -15088,7 +15136,6 @@ var detectEntrypoint = async ({ workPath }) => {
15088
15136
 
15089
15137
  // src/standalone-server.ts
15090
15138
  var import_child_process = require("child_process");
15091
- var import_net = require("net");
15092
15139
  var import_path6 = require("path");
15093
15140
  var import_fs_extra3 = __toESM(require_lib2());
15094
15141
  var import_build_utils4 = require("@vercel/build-utils");
@@ -15333,19 +15380,29 @@ async function createStandaloneServerLambda({
15333
15380
  });
15334
15381
  return lambda;
15335
15382
  }
15336
- var DEV_SERVER_STARTUP_TIMEOUT = 5 * 6e4;
15337
15383
  var PERSISTENT_SERVERS = /* @__PURE__ */ new Map();
15338
15384
  var PENDING_STARTS = /* @__PURE__ */ new Map();
15339
15385
  var cleanupHandlersInstalled = false;
15340
- function killStandaloneDevServer(pid) {
15386
+ function killStandaloneDevServerProcessTree(child) {
15387
+ if (!child.pid)
15388
+ return;
15341
15389
  try {
15342
15390
  if (process.platform === "win32") {
15343
- process.kill(pid, "SIGTERM");
15391
+ child.kill("SIGTERM");
15344
15392
  } else {
15345
- process.kill(-pid, "SIGTERM");
15393
+ process.kill(-child.pid, "SIGTERM");
15346
15394
  }
15347
15395
  } catch (err) {
15348
- (0, import_build_utils4.debug)(`Error killing standalone Go dev server ${pid}: ${err}`);
15396
+ if (err.code !== "ESRCH") {
15397
+ (0, import_build_utils4.debug)(`Error killing standalone Go dev server ${child.pid}: ${err}`);
15398
+ }
15399
+ }
15400
+ }
15401
+ async function closeStandaloneDevServer(handle) {
15402
+ try {
15403
+ await handle.close();
15404
+ } finally {
15405
+ killStandaloneDevServerProcessTree(handle.child);
15349
15406
  }
15350
15407
  }
15351
15408
  function installGlobalCleanupHandlers() {
@@ -15353,162 +15410,151 @@ function installGlobalCleanupHandlers() {
15353
15410
  return;
15354
15411
  cleanupHandlersInstalled = true;
15355
15412
  const killAll = () => {
15356
- for (const [key, info] of PERSISTENT_SERVERS.entries()) {
15357
- killStandaloneDevServer(info.pid);
15413
+ for (const [key, server] of PERSISTENT_SERVERS.entries()) {
15358
15414
  PERSISTENT_SERVERS.delete(key);
15415
+ killStandaloneDevServerProcessTree(server.handle.child);
15359
15416
  }
15360
15417
  };
15361
- process.on("SIGINT", () => {
15362
- killAll();
15363
- });
15364
- process.on("SIGTERM", () => {
15365
- killAll();
15366
- });
15367
- process.on("exit", () => {
15368
- killAll();
15369
- });
15418
+ process.on("SIGINT", killAll);
15419
+ process.on("SIGTERM", killAll);
15420
+ process.on("exit", killAll);
15370
15421
  }
15371
- function isPortReachable(port) {
15372
- return new Promise((resolve) => {
15373
- const socket = (0, import_net.createConnection)({ port, host: "127.0.0.1" });
15374
- const done = (result) => {
15375
- socket.removeAllListeners();
15376
- socket.destroy();
15377
- resolve(result);
15378
- };
15379
- socket.setTimeout(1e3);
15380
- socket.once("connect", () => done(true));
15381
- socket.once("timeout", () => done(false));
15382
- socket.once("error", () => done(false));
15383
- });
15384
- }
15385
- function sleep(ms2) {
15386
- return new Promise((resolve) => setTimeout(resolve, ms2));
15387
- }
15388
- async function waitForPort(port, child, timeout) {
15389
- let exited = null;
15390
- let spawnError = null;
15391
- const onExit = (code, signal) => {
15392
- exited = { code, signal };
15393
- };
15394
- const onError = (err) => {
15395
- spawnError = err;
15396
- };
15397
- child.once("exit", onExit);
15398
- child.once("error", onError);
15399
- try {
15400
- const start = Date.now();
15401
- while (Date.now() - start < timeout) {
15402
- if (spawnError) {
15403
- throw spawnError;
15404
- }
15405
- if (exited) {
15406
- const { code, signal } = exited;
15407
- throw new Error(
15408
- `Standalone Go dev server exited before startup completed (code: ${code}, signal: ${signal})`
15409
- );
15410
- }
15411
- if (await isPortReachable(port)) {
15412
- return;
15422
+ function toDevServerResult(serverKey, handle) {
15423
+ return {
15424
+ port: handle.port,
15425
+ pid: handle.pid,
15426
+ persistent: true,
15427
+ shutdown: async () => {
15428
+ if (PERSISTENT_SERVERS.get(serverKey)?.handle === handle) {
15429
+ PERSISTENT_SERVERS.delete(serverKey);
15413
15430
  }
15414
- await sleep(100);
15431
+ await closeStandaloneDevServer(handle);
15415
15432
  }
15416
- throw new Error(
15417
- `Standalone Go dev server did not start within ${timeout}ms`
15418
- );
15419
- } finally {
15420
- child.removeListener("exit", onExit);
15421
- child.removeListener("error", onError);
15422
- }
15433
+ };
15423
15434
  }
15424
15435
  async function startStandaloneDevServer(opts, resolvedEntrypoint) {
15425
15436
  const { workPath, meta = {} } = opts;
15437
+ const { devCacheDir = (0, import_path6.join)(workPath, ".vercel", "cache") } = meta;
15426
15438
  const serverKey = `${workPath}::${resolvedEntrypoint}`;
15427
15439
  const existing = PERSISTENT_SERVERS.get(serverKey);
15428
15440
  if (existing) {
15429
- return {
15430
- port: existing.port,
15431
- pid: existing.pid,
15432
- shutdown: async () => {
15433
- }
15434
- };
15441
+ return toDevServerResult(serverKey, existing.handle);
15435
15442
  }
15436
15443
  const pending = PENDING_STARTS.get(serverKey);
15437
15444
  if (pending) {
15438
- const { port, pid } = await pending;
15439
- return { port, pid, shutdown: async () => {
15440
- } };
15445
+ await pending;
15446
+ return startStandaloneDevServer(opts, resolvedEntrypoint);
15441
15447
  }
15442
15448
  const startPromise = (async () => {
15443
- const port = typeof meta.port === "number" ? meta.port : Math.floor(Math.random() * (65535 - 49152) + 49152);
15444
- const env = (0, import_build_utils4.cloneEnv)(process.env, meta.env, {
15445
- PORT: String(port)
15446
- });
15449
+ const env = (0, import_build_utils4.cloneEnv)(process.env, meta.env);
15447
15450
  const entrypointDir = (0, import_path6.dirname)((0, import_path6.join)(workPath, resolvedEntrypoint));
15448
15451
  const { goModPath } = await findGoModPath(entrypointDir, workPath);
15449
15452
  const modulePath = goModPath ? (0, import_path6.dirname)(goModPath) : workPath;
15450
15453
  const go = await createGo({
15451
15454
  modulePath,
15452
15455
  opts: { cwd: workPath, env },
15453
- workPath
15456
+ workPath,
15457
+ // The binary has to run on this machine, so don't downgrade.
15458
+ preferNewestToolchain: true
15454
15459
  });
15455
- const runTarget = resolvedEntrypoint === "main.go" ? "." : "./" + (0, import_path6.dirname)(resolvedEntrypoint);
15456
- const devWrapper = (0, import_path6.join)(__dirname, "../bootstrap/vc-init-dev.go");
15457
- const devUtils = (0, import_path6.join)(__dirname, "../bootstrap/utils.go");
15458
- (0, import_build_utils4.debug)(
15459
- `Starting standalone Go dev server wrapper: go run ${devWrapper} (target ${runTarget}, port ${port})`
15460
+ const buildTarget = resolvedEntrypoint === "main.go" ? "." : "./" + (0, import_path6.dirname)(resolvedEntrypoint);
15461
+ const isVendored = await (0, import_fs_extra3.pathExists)(
15462
+ (0, import_path6.join)(workPath, "vendor", "modules.txt")
15460
15463
  );
15461
- const child = (0, import_child_process.spawn)("go", ["run", "-tags", "vcdev", devWrapper, devUtils], {
15462
- cwd: workPath,
15463
- env: {
15464
- ...go.getEnv(),
15465
- __VC_GO_DEV_RUN_TARGET: runTarget
15466
- },
15467
- stdio: ["ignore", "pipe", "pipe"],
15468
- detached: process.platform !== "win32"
15469
- });
15470
- child.stdout?.on("data", (data) => {
15471
- const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
15472
- if (opts.onStdout) {
15473
- opts.onStdout(chunk);
15474
- } else {
15475
- process.stdout.write(chunk.toString());
15476
- }
15477
- });
15478
- child.stderr?.on("data", (data) => {
15479
- const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
15480
- if (opts.onStderr) {
15481
- opts.onStderr(chunk);
15482
- } else {
15483
- process.stderr.write(chunk.toString());
15464
+ if (isVendored) {
15465
+ (0, import_build_utils4.debug)("Detected vendor directory, using -mod=vendor for build");
15466
+ }
15467
+ const outDir = (0, import_path6.join)(
15468
+ devCacheDir,
15469
+ "go-standalone",
15470
+ Math.random().toString(32).substring(2)
15471
+ );
15472
+ await (0, import_fs_extra3.mkdirp)(outDir);
15473
+ const cleanupOutDir = async () => {
15474
+ try {
15475
+ await (0, import_fs_extra3.remove)(outDir);
15476
+ } catch (err) {
15477
+ (0, import_build_utils4.debug)(`Could not delete dev server directory ${outDir}: ${err}`);
15484
15478
  }
15485
- });
15486
- const pid = child.pid;
15479
+ };
15480
+ const executablePath = (0, import_path6.join)(
15481
+ outDir,
15482
+ `dev-server${process.platform === "win32" ? ".exe" : ""}`
15483
+ );
15484
+ (0, import_build_utils4.debug)(
15485
+ `Building standalone Go dev server: go build ${buildTarget} -> ${executablePath}`
15486
+ );
15487
15487
  try {
15488
- await waitForPort(port, child, DEV_SERVER_STARTUP_TIMEOUT);
15488
+ await go.build(buildTarget, executablePath, {
15489
+ vendorMode: isVendored,
15490
+ release: false
15491
+ });
15489
15492
  } catch (err) {
15490
- if (pid) {
15491
- killStandaloneDevServer(pid);
15492
- }
15493
+ console.error(`Failed to build standalone Go server: ${buildTarget}`);
15494
+ await cleanupOutDir();
15493
15495
  throw err;
15494
15496
  }
15495
- if (!pid) {
15496
- throw new Error("Standalone Go dev server started without a PID");
15497
- }
15498
- PERSISTENT_SERVERS.set(serverKey, { port, pid, child });
15499
- child.once("exit", () => {
15500
- PERSISTENT_SERVERS.delete(serverKey);
15497
+ (0, import_build_utils4.debug)(`Starting standalone Go dev server: ${executablePath}`);
15498
+ let spawnedChild;
15499
+ const handle = await (0, import_ipc_proxy.startDevProxy)({
15500
+ port: typeof meta.port === "number" ? meta.port : void 0,
15501
+ env,
15502
+ label: "Standalone Go dev server",
15503
+ // Spawning the binary avoids a `go run` wrapper. On Unix, detaching also
15504
+ // makes it a process-group leader so shutdown can include its helpers.
15505
+ spawnServer: (internalPort) => {
15506
+ const child = (0, import_child_process.spawn)(executablePath, [], {
15507
+ cwd: workPath,
15508
+ env: (0, import_build_utils4.cloneEnv)(go.getEnv(), { PORT: String(internalPort) }),
15509
+ stdio: ["ignore", "pipe", "pipe"],
15510
+ detached: process.platform !== "win32"
15511
+ });
15512
+ spawnedChild = child;
15513
+ const forward = (stream, onData, fallback) => {
15514
+ stream?.on("data", (data) => {
15515
+ const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
15516
+ if (onData) {
15517
+ onData(chunk);
15518
+ } else {
15519
+ fallback.write(
15520
+ new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength)
15521
+ );
15522
+ }
15523
+ });
15524
+ };
15525
+ forward(child.stdout, opts.onStdout, process.stdout);
15526
+ forward(child.stderr, opts.onStderr, process.stderr);
15527
+ return child;
15528
+ }
15529
+ }).catch(async (err) => {
15530
+ if (spawnedChild) {
15531
+ killStandaloneDevServerProcessTree(spawnedChild);
15532
+ }
15533
+ await cleanupOutDir();
15534
+ throw err;
15535
+ });
15536
+ const server = { handle };
15537
+ PERSISTENT_SERVERS.set(serverKey, server);
15538
+ handle.child.once("exit", () => {
15539
+ if (PERSISTENT_SERVERS.get(serverKey)?.handle === handle) {
15540
+ PERSISTENT_SERVERS.delete(serverKey);
15541
+ }
15542
+ closeStandaloneDevServer(handle).catch((err) => {
15543
+ (0, import_build_utils4.debug)(`Error closing standalone Go dev proxy: ${err}`);
15544
+ });
15545
+ void cleanupOutDir();
15501
15546
  });
15502
15547
  installGlobalCleanupHandlers();
15503
- return { port, pid };
15548
+ return server;
15504
15549
  })();
15505
15550
  PENDING_STARTS.set(serverKey, startPromise);
15506
15551
  try {
15507
- const { port, pid } = await startPromise;
15508
- return { port, pid, shutdown: async () => {
15509
- } };
15552
+ const server = await startPromise;
15553
+ return toDevServerResult(serverKey, server.handle);
15510
15554
  } finally {
15511
- PENDING_STARTS.delete(serverKey);
15555
+ if (PENDING_STARTS.get(serverKey) === startPromise) {
15556
+ PENDING_STARTS.delete(serverKey);
15557
+ }
15512
15558
  }
15513
15559
  }
15514
15560
 
@@ -16167,9 +16213,11 @@ async function startDevServer(opts) {
16167
16213
  cwd: tmp,
16168
16214
  env
16169
16215
  },
16170
- workPath
16216
+ workPath,
16217
+ // The binary has to run on this machine, so don't downgrade.
16218
+ preferNewestToolchain: true
16171
16219
  });
16172
- await go.build("./...", executable);
16220
+ await go.build("./...", executable, { release: false });
16173
16221
  (0, import_build_utils5.debug)(`SPAWNING ${executable} CWD=${tmp}`);
16174
16222
  const child = (0, import_child_process2.spawn)(executable, [], {
16175
16223
  cwd: tmp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/go",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -12,12 +12,11 @@
12
12
  "files": [
13
13
  "dist",
14
14
  "*.go",
15
- "bin",
16
- "bootstrap"
15
+ "bin"
17
16
  ],
18
17
  "dependencies": {},
19
18
  "peerDependencies": {
20
- "@vercel/build-utils": "14.3.0"
19
+ "@vercel/build-utils": "14.4.0"
21
20
  },
22
21
  "devDependencies": {
23
22
  "@tootallnate/once": "1.1.2",
@@ -36,7 +35,7 @@
36
35
  "vitest": "4.1.10",
37
36
  "xdg-app-paths": "5.1.0",
38
37
  "yauzl-promise": "2.1.3",
39
- "@vercel/build-utils": "14.3.0",
38
+ "@vercel/build-utils": "14.4.0",
40
39
  "@vercel-internals/ipc-proxy": "1.0.0"
41
40
  },
42
41
  "scripts": {
@@ -1,140 +0,0 @@
1
- package main
2
-
3
- import (
4
- "fmt"
5
- "net"
6
- "os"
7
- "strings"
8
- "time"
9
- )
10
-
11
- func findFreePort() (int, error) {
12
- listener, err := net.Listen("tcp", "127.0.0.1:0")
13
- if err != nil {
14
- return 0, err
15
- }
16
- port := listener.Addr().(*net.TCPAddr).Port
17
- listener.Close()
18
- return port, nil
19
- }
20
-
21
- func waitForServer(port int, timeout time.Duration) error {
22
- const (
23
- dialTimeout = 200 * time.Millisecond
24
- pollInterval = 50 * time.Millisecond
25
- )
26
-
27
- addr := fmt.Sprintf("127.0.0.1:%d", port)
28
- deadline := time.Now().Add(timeout)
29
- var lastErr error
30
-
31
- for time.Now().Before(deadline) {
32
- remaining := time.Until(deadline)
33
- if remaining <= 0 {
34
- break
35
- }
36
-
37
- attemptTimeout := dialTimeout
38
- if remaining < attemptTimeout {
39
- attemptTimeout = remaining
40
- }
41
-
42
- conn, err := net.DialTimeout("tcp", addr, attemptTimeout)
43
- if err == nil {
44
- conn.Close()
45
- return nil
46
- }
47
-
48
- lastErr = err
49
- time.Sleep(pollInterval)
50
- }
51
-
52
- if lastErr != nil {
53
- return fmt.Errorf(
54
- "server did not start listening on %s within %v: %w",
55
- addr,
56
- timeout,
57
- lastErr,
58
- )
59
- }
60
-
61
- return fmt.Errorf("server did not start listening on %s within %v", addr, timeout)
62
- }
63
-
64
- func normalizeServiceRoutePrefix(rawPrefix string) string {
65
- if rawPrefix == "" {
66
- return ""
67
- }
68
-
69
- prefix := strings.TrimSpace(rawPrefix)
70
- if prefix == "" {
71
- return ""
72
- }
73
-
74
- if !strings.HasPrefix(prefix, "/") {
75
- prefix = "/" + prefix
76
- }
77
-
78
- if prefix != "/" {
79
- prefix = strings.TrimRight(prefix, "/")
80
- if prefix == "" {
81
- prefix = "/"
82
- }
83
- }
84
-
85
- if prefix == "/" {
86
- return ""
87
- }
88
-
89
- return prefix
90
- }
91
-
92
- func serviceRoutePrefixStripEnabled() bool {
93
- raw := strings.TrimSpace(os.Getenv("VERCEL_SERVICE_ROUTE_PREFIX_STRIP"))
94
- if raw == "" {
95
- return false
96
- }
97
-
98
- normalized := strings.ToLower(raw)
99
- return normalized == "1" || normalized == "true"
100
- }
101
-
102
- func resolveServiceRoutePrefix() string {
103
- if !serviceRoutePrefixStripEnabled() {
104
- return ""
105
- }
106
-
107
- return normalizeServiceRoutePrefix(os.Getenv("VERCEL_SERVICE_ROUTE_PREFIX"))
108
- }
109
-
110
- func stripServiceRoutePrefix(pathValue string, prefix string) string {
111
- if pathValue == "*" {
112
- return pathValue
113
- }
114
-
115
- normalizedPath := pathValue
116
- if normalizedPath == "" {
117
- normalizedPath = "/"
118
- } else if !strings.HasPrefix(normalizedPath, "/") {
119
- normalizedPath = "/" + normalizedPath
120
- }
121
-
122
- if prefix == "" {
123
- return normalizedPath
124
- }
125
-
126
- if normalizedPath == prefix {
127
- return "/"
128
- }
129
-
130
- prefixWithSlash := prefix + "/"
131
- if strings.HasPrefix(normalizedPath, prefixWithSlash) {
132
- stripped := normalizedPath[len(prefix):]
133
- if stripped == "" {
134
- return "/"
135
- }
136
- return stripped
137
- }
138
-
139
- return normalizedPath
140
- }
@@ -1,147 +0,0 @@
1
- //go:build vcdev
2
- // +build vcdev
3
-
4
- // vc-init-dev.go - Dev wrapper for standalone Go servers on Vercel
5
- //
6
- // This wrapper is used by `vercel dev` for standalone Go mode. It:
7
- // 1. Starts the user's server (`go run <target>`) on an internal port
8
- // 2. Proxies requests from the external dev port to the internal server
9
- // 3. Optionally strips generated services route prefixes before forwarding
10
-
11
- package main
12
-
13
- import (
14
- "context"
15
- "fmt"
16
- "net/http"
17
- "net/http/httputil"
18
- "net/url"
19
- "os"
20
- "os/exec"
21
- "os/signal"
22
- "strconv"
23
- "strings"
24
- "sync"
25
- "syscall"
26
- "time"
27
- )
28
-
29
- func mustEnv(name string) string {
30
- value := strings.TrimSpace(os.Getenv(name))
31
- if value == "" {
32
- fmt.Fprintf(os.Stderr, "%s is not set\n", name)
33
- os.Exit(1)
34
- }
35
- return value
36
- }
37
-
38
- func withEnvOverride(env []string, key, value string) []string {
39
- prefix := key + "="
40
- filtered := make([]string, 0, len(env)+1)
41
- for _, item := range env {
42
- if !strings.HasPrefix(item, prefix) {
43
- filtered = append(filtered, item)
44
- }
45
- }
46
- filtered = append(filtered, prefix+value)
47
- return filtered
48
- }
49
-
50
- func main() {
51
- listenPortRaw := mustEnv("PORT")
52
- listenPort, err := strconv.Atoi(listenPortRaw)
53
- if err != nil || listenPort <= 0 {
54
- fmt.Fprintf(os.Stderr, "Invalid PORT value: %q\n", listenPortRaw)
55
- os.Exit(1)
56
- }
57
-
58
- runTarget := mustEnv("__VC_GO_DEV_RUN_TARGET")
59
- serviceRoutePrefix := resolveServiceRoutePrefix()
60
-
61
- userPort, err := findFreePort()
62
- if err != nil {
63
- fmt.Fprintf(os.Stderr, "Failed to find free port: %v\n", err)
64
- os.Exit(1)
65
- }
66
-
67
- ctx, cancel := context.WithCancel(context.Background())
68
- defer cancel()
69
-
70
- cmd := exec.CommandContext(ctx, "go", "run", runTarget)
71
- cmd.Env = withEnvOverride(os.Environ(), "PORT", strconv.Itoa(userPort))
72
- cmd.Stdout = os.Stdout
73
- cmd.Stderr = os.Stderr
74
-
75
- if err := cmd.Start(); err != nil {
76
- fmt.Fprintf(os.Stderr, "Failed to start Go dev server: %v\n", err)
77
- os.Exit(1)
78
- }
79
-
80
- if err := waitForServer(userPort, 30*time.Second); err != nil {
81
- fmt.Fprintf(os.Stderr, "Go dev server failed to start: %v\n", err)
82
- _ = cmd.Process.Kill()
83
- os.Exit(1)
84
- }
85
-
86
- targetURL, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", userPort))
87
- proxy := httputil.NewSingleHostReverseProxy(targetURL)
88
- originalDirector := proxy.Director
89
- proxy.Director = func(req *http.Request) {
90
- originalDirector(req)
91
- if host := req.Header.Get("X-Forwarded-Host"); host != "" {
92
- req.Host = host
93
- }
94
- }
95
-
96
- server := &http.Server{
97
- Addr: fmt.Sprintf("127.0.0.1:%d", listenPort),
98
- Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
99
- if r.URL.Path == "/_vercel/ping" {
100
- w.WriteHeader(http.StatusOK)
101
- w.Write([]byte("OK"))
102
- return
103
- }
104
-
105
- if r.URL != nil {
106
- originalPath := r.URL.Path
107
- r.URL.Path = stripServiceRoutePrefix(r.URL.Path, serviceRoutePrefix)
108
- if r.URL.Path != originalPath {
109
- r.URL.RawPath = ""
110
- }
111
- }
112
-
113
- proxy.ServeHTTP(w, r)
114
- }),
115
- }
116
-
117
- var closeOnce sync.Once
118
- stop := func() {
119
- closeOnce.Do(func() {
120
- cancel()
121
- _ = server.Close()
122
- if cmd.Process != nil {
123
- _ = cmd.Process.Kill()
124
- }
125
- })
126
- }
127
-
128
- go func() {
129
- _ = cmd.Wait()
130
- stop()
131
- }()
132
-
133
- sigCh := make(chan os.Signal, 1)
134
- signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
135
- go func() {
136
- <-sigCh
137
- stop()
138
- }()
139
-
140
- if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
141
- fmt.Fprintf(os.Stderr, "Dev proxy server error: %v\n", err)
142
- stop()
143
- os.Exit(1)
144
- }
145
-
146
- stop()
147
- }