@vercel/go 3.11.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.
- package/bin/proxy-linux-amd64 +0 -0
- package/bin/proxy-linux-arm64 +0 -0
- package/dist/index.js +477 -145
- package/package.json +9 -5
- package/bootstrap/utils.go +0 -140
- package/bootstrap/vc-init-dev.go +0 -147
package/bin/proxy-linux-amd64
CHANGED
|
Binary file
|
package/bin/proxy-linux-arm64
CHANGED
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
5578
|
-
var
|
|
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
|
-
|
|
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
|
|
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
|
|
5636
|
+
return remove4(src, cb);
|
|
5637
5637
|
});
|
|
5638
5638
|
}
|
|
5639
5639
|
function isSrcSubdir(src, dest) {
|
|
@@ -10938,6 +10938,288 @@ var require_xdg_app_paths = __commonJS({
|
|
|
10938
10938
|
}
|
|
10939
10939
|
});
|
|
10940
10940
|
|
|
10941
|
+
// ../../internals/ipc-proxy/dist/dev-proxy.js
|
|
10942
|
+
var require_dev_proxy = __commonJS({
|
|
10943
|
+
"../../internals/ipc-proxy/dist/dev-proxy.js"(exports, module2) {
|
|
10944
|
+
"use strict";
|
|
10945
|
+
var __defProp2 = Object.defineProperty;
|
|
10946
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
10947
|
+
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
10948
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
10949
|
+
var __export2 = (target, all) => {
|
|
10950
|
+
for (var name in all)
|
|
10951
|
+
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
10952
|
+
};
|
|
10953
|
+
var __copyProps2 = (to2, from, except, desc) => {
|
|
10954
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10955
|
+
for (let key of __getOwnPropNames2(from))
|
|
10956
|
+
if (!__hasOwnProp2.call(to2, key) && key !== except)
|
|
10957
|
+
__defProp2(to2, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
10958
|
+
}
|
|
10959
|
+
return to2;
|
|
10960
|
+
};
|
|
10961
|
+
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
10962
|
+
var dev_proxy_exports = {};
|
|
10963
|
+
__export2(dev_proxy_exports, {
|
|
10964
|
+
createDevProxyServer: () => createDevProxyServer,
|
|
10965
|
+
findFreePort: () => findFreePort,
|
|
10966
|
+
normalizeServiceRoutePrefix: () => normalizeServiceRoutePrefix,
|
|
10967
|
+
resolveServiceRoutePrefix: () => resolveServiceRoutePrefix,
|
|
10968
|
+
rewriteRequestUrl: () => rewriteRequestUrl,
|
|
10969
|
+
sanitizeHeaders: () => sanitizeHeaders,
|
|
10970
|
+
startDevProxy: () => startDevProxy2,
|
|
10971
|
+
stripServiceRoutePrefix: () => stripServiceRoutePrefix,
|
|
10972
|
+
waitForPort: () => waitForPort
|
|
10973
|
+
});
|
|
10974
|
+
module2.exports = __toCommonJS2(dev_proxy_exports);
|
|
10975
|
+
var import_node_http = require("http");
|
|
10976
|
+
var import_node_net = require("net");
|
|
10977
|
+
var PING_PATH = "/_vercel/ping";
|
|
10978
|
+
var INTERNAL_HEADER_PREFIX = "x-vercel-internal-";
|
|
10979
|
+
var LOCALHOST = "127.0.0.1";
|
|
10980
|
+
var DEFAULT_READINESS_TIMEOUT = 5 * 6e4;
|
|
10981
|
+
var READINESS_POLL_INTERVAL = 100;
|
|
10982
|
+
var READINESS_DIAL_TIMEOUT = 1e3;
|
|
10983
|
+
function normalizeServiceRoutePrefix(rawPrefix) {
|
|
10984
|
+
if (!rawPrefix)
|
|
10985
|
+
return "";
|
|
10986
|
+
let prefix = rawPrefix.trim();
|
|
10987
|
+
if (!prefix)
|
|
10988
|
+
return "";
|
|
10989
|
+
if (!prefix.startsWith("/")) {
|
|
10990
|
+
prefix = `/${prefix}`;
|
|
10991
|
+
}
|
|
10992
|
+
if (prefix !== "/") {
|
|
10993
|
+
prefix = prefix.replace(/\/+$/, "");
|
|
10994
|
+
if (!prefix)
|
|
10995
|
+
prefix = "/";
|
|
10996
|
+
}
|
|
10997
|
+
return prefix === "/" ? "" : prefix;
|
|
10998
|
+
}
|
|
10999
|
+
function resolveServiceRoutePrefix(env = process.env) {
|
|
11000
|
+
const strip = (env.VERCEL_SERVICE_ROUTE_PREFIX_STRIP ?? "").trim().toLowerCase();
|
|
11001
|
+
if (strip !== "1" && strip !== "true")
|
|
11002
|
+
return "";
|
|
11003
|
+
return normalizeServiceRoutePrefix(env.VERCEL_SERVICE_ROUTE_PREFIX);
|
|
11004
|
+
}
|
|
11005
|
+
function stripServiceRoutePrefix(pathValue, prefix) {
|
|
11006
|
+
if (pathValue === "*")
|
|
11007
|
+
return pathValue;
|
|
11008
|
+
let normalized = pathValue;
|
|
11009
|
+
if (!normalized) {
|
|
11010
|
+
normalized = "/";
|
|
11011
|
+
} else if (!normalized.startsWith("/")) {
|
|
11012
|
+
normalized = `/${normalized}`;
|
|
11013
|
+
}
|
|
11014
|
+
if (!prefix)
|
|
11015
|
+
return normalized;
|
|
11016
|
+
if (normalized === prefix)
|
|
11017
|
+
return "/";
|
|
11018
|
+
if (normalized.startsWith(`${prefix}/`)) {
|
|
11019
|
+
return normalized.slice(prefix.length) || "/";
|
|
11020
|
+
}
|
|
11021
|
+
return normalized;
|
|
11022
|
+
}
|
|
11023
|
+
function splitUrl(url) {
|
|
11024
|
+
const queryIndex = url.indexOf("?");
|
|
11025
|
+
if (queryIndex === -1)
|
|
11026
|
+
return { pathname: url, search: "" };
|
|
11027
|
+
return { pathname: url.slice(0, queryIndex), search: url.slice(queryIndex) };
|
|
11028
|
+
}
|
|
11029
|
+
function rewriteRequestUrl(url, prefix) {
|
|
11030
|
+
const { pathname, search } = splitUrl(url || "/");
|
|
11031
|
+
return `${stripServiceRoutePrefix(pathname, prefix)}${search}`;
|
|
11032
|
+
}
|
|
11033
|
+
function sanitizeHeaders(headers) {
|
|
11034
|
+
const sanitized = {};
|
|
11035
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
11036
|
+
if (key.toLowerCase().startsWith(INTERNAL_HEADER_PREFIX))
|
|
11037
|
+
continue;
|
|
11038
|
+
sanitized[key] = value;
|
|
11039
|
+
}
|
|
11040
|
+
const forwardedHost = headers["x-forwarded-host"];
|
|
11041
|
+
const host = Array.isArray(forwardedHost) ? forwardedHost[0] : forwardedHost;
|
|
11042
|
+
if (host) {
|
|
11043
|
+
sanitized.host = host;
|
|
11044
|
+
}
|
|
11045
|
+
return sanitized;
|
|
11046
|
+
}
|
|
11047
|
+
function findFreePort() {
|
|
11048
|
+
return new Promise((resolve, reject) => {
|
|
11049
|
+
const server = (0, import_node_net.createServer)();
|
|
11050
|
+
server.unref();
|
|
11051
|
+
server.once("error", reject);
|
|
11052
|
+
server.listen(0, LOCALHOST, () => {
|
|
11053
|
+
const address = server.address();
|
|
11054
|
+
if (!address || typeof address === "string") {
|
|
11055
|
+
server.close(() => reject(new Error("Failed to allocate a free port")));
|
|
11056
|
+
return;
|
|
11057
|
+
}
|
|
11058
|
+
const { port } = address;
|
|
11059
|
+
server.close(() => resolve(port));
|
|
11060
|
+
});
|
|
11061
|
+
});
|
|
11062
|
+
}
|
|
11063
|
+
function isPortReachable(port) {
|
|
11064
|
+
return new Promise((resolve) => {
|
|
11065
|
+
const socket = (0, import_node_net.createConnection)({ port, host: LOCALHOST });
|
|
11066
|
+
const done = (reachable) => {
|
|
11067
|
+
socket.removeAllListeners();
|
|
11068
|
+
socket.destroy();
|
|
11069
|
+
resolve(reachable);
|
|
11070
|
+
};
|
|
11071
|
+
socket.setTimeout(READINESS_DIAL_TIMEOUT);
|
|
11072
|
+
socket.once("connect", () => done(true));
|
|
11073
|
+
socket.once("timeout", () => done(false));
|
|
11074
|
+
socket.once("error", () => done(false));
|
|
11075
|
+
});
|
|
11076
|
+
}
|
|
11077
|
+
function sleep(ms2) {
|
|
11078
|
+
return new Promise((resolve) => setTimeout(resolve, ms2));
|
|
11079
|
+
}
|
|
11080
|
+
async function waitForPort(port, child, timeout, label = "Dev server") {
|
|
11081
|
+
let exited;
|
|
11082
|
+
let spawnError;
|
|
11083
|
+
const onExit = (code, signal) => {
|
|
11084
|
+
exited = { code, signal };
|
|
11085
|
+
};
|
|
11086
|
+
const onError = (err) => {
|
|
11087
|
+
spawnError = err;
|
|
11088
|
+
};
|
|
11089
|
+
child.once("exit", onExit);
|
|
11090
|
+
child.once("error", onError);
|
|
11091
|
+
try {
|
|
11092
|
+
const start = Date.now();
|
|
11093
|
+
while (Date.now() - start < timeout) {
|
|
11094
|
+
if (spawnError)
|
|
11095
|
+
throw spawnError;
|
|
11096
|
+
if (exited) {
|
|
11097
|
+
throw new Error(
|
|
11098
|
+
`${label} exited before it started listening (code: ${exited.code}, signal: ${exited.signal})`
|
|
11099
|
+
);
|
|
11100
|
+
}
|
|
11101
|
+
if (await isPortReachable(port))
|
|
11102
|
+
return;
|
|
11103
|
+
await sleep(READINESS_POLL_INTERVAL);
|
|
11104
|
+
}
|
|
11105
|
+
throw new Error(`${label} did not start listening within ${timeout}ms`);
|
|
11106
|
+
} finally {
|
|
11107
|
+
child.removeListener("exit", onExit);
|
|
11108
|
+
child.removeListener("error", onError);
|
|
11109
|
+
}
|
|
11110
|
+
}
|
|
11111
|
+
function createDevProxyServer(options) {
|
|
11112
|
+
const { targetPort } = options;
|
|
11113
|
+
const routePrefix = normalizeServiceRoutePrefix(options.routePrefix);
|
|
11114
|
+
const server = (0, import_node_http.createServer)((req, res) => {
|
|
11115
|
+
const { pathname } = splitUrl(req.url || "/");
|
|
11116
|
+
if (pathname === PING_PATH) {
|
|
11117
|
+
res.writeHead(200, { "content-type": "text/plain" });
|
|
11118
|
+
res.end("OK");
|
|
11119
|
+
return;
|
|
11120
|
+
}
|
|
11121
|
+
const proxyReq = (0, import_node_http.request)(
|
|
11122
|
+
{
|
|
11123
|
+
host: LOCALHOST,
|
|
11124
|
+
port: targetPort,
|
|
11125
|
+
method: req.method,
|
|
11126
|
+
path: rewriteRequestUrl(req.url || "/", routePrefix),
|
|
11127
|
+
headers: sanitizeHeaders(req.headers)
|
|
11128
|
+
},
|
|
11129
|
+
(proxyRes) => {
|
|
11130
|
+
res.writeHead(proxyRes.statusCode ?? 502, proxyRes.headers);
|
|
11131
|
+
proxyRes.pipe(res);
|
|
11132
|
+
}
|
|
11133
|
+
);
|
|
11134
|
+
proxyReq.once("error", (err) => {
|
|
11135
|
+
if (!res.headersSent) {
|
|
11136
|
+
res.writeHead(502, { "content-type": "text/plain" });
|
|
11137
|
+
}
|
|
11138
|
+
res.end(`Dev proxy error: ${err.message}`);
|
|
11139
|
+
});
|
|
11140
|
+
res.once("close", () => {
|
|
11141
|
+
if (!res.writableFinished)
|
|
11142
|
+
proxyReq.destroy();
|
|
11143
|
+
});
|
|
11144
|
+
req.pipe(proxyReq);
|
|
11145
|
+
});
|
|
11146
|
+
server.on("upgrade", (req, clientSocket, head) => {
|
|
11147
|
+
const headers = sanitizeHeaders(req.headers);
|
|
11148
|
+
const path = rewriteRequestUrl(req.url || "/", routePrefix);
|
|
11149
|
+
const upstream = (0, import_node_net.createConnection)(
|
|
11150
|
+
{ host: LOCALHOST, port: targetPort },
|
|
11151
|
+
() => {
|
|
11152
|
+
const lines = [`${req.method} ${path} HTTP/${req.httpVersion}`];
|
|
11153
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
11154
|
+
if (Array.isArray(value)) {
|
|
11155
|
+
for (const entry of value)
|
|
11156
|
+
lines.push(`${key}: ${entry}`);
|
|
11157
|
+
} else if (value !== void 0) {
|
|
11158
|
+
lines.push(`${key}: ${value}`);
|
|
11159
|
+
}
|
|
11160
|
+
}
|
|
11161
|
+
upstream.write(`${lines.join("\r\n")}\r
|
|
11162
|
+
\r
|
|
11163
|
+
`);
|
|
11164
|
+
if (head?.length)
|
|
11165
|
+
upstream.write(new Uint8Array(head));
|
|
11166
|
+
upstream.pipe(clientSocket);
|
|
11167
|
+
clientSocket.pipe(upstream);
|
|
11168
|
+
}
|
|
11169
|
+
);
|
|
11170
|
+
const destroy = () => {
|
|
11171
|
+
upstream.destroy();
|
|
11172
|
+
clientSocket.destroy();
|
|
11173
|
+
};
|
|
11174
|
+
upstream.once("error", destroy);
|
|
11175
|
+
clientSocket.once("error", destroy);
|
|
11176
|
+
});
|
|
11177
|
+
return server;
|
|
11178
|
+
}
|
|
11179
|
+
async function startDevProxy2(options) {
|
|
11180
|
+
const {
|
|
11181
|
+
spawnServer,
|
|
11182
|
+
env = process.env,
|
|
11183
|
+
readinessTimeout = DEFAULT_READINESS_TIMEOUT,
|
|
11184
|
+
label = "Dev server"
|
|
11185
|
+
} = options;
|
|
11186
|
+
const internalPort = await findFreePort();
|
|
11187
|
+
const child = spawnServer(internalPort);
|
|
11188
|
+
let server;
|
|
11189
|
+
const close = async () => {
|
|
11190
|
+
if (server) {
|
|
11191
|
+
await new Promise((resolve) => {
|
|
11192
|
+
server?.close(() => resolve());
|
|
11193
|
+
server?.closeAllConnections?.();
|
|
11194
|
+
});
|
|
11195
|
+
}
|
|
11196
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
11197
|
+
child.kill("SIGTERM");
|
|
11198
|
+
}
|
|
11199
|
+
};
|
|
11200
|
+
try {
|
|
11201
|
+
await waitForPort(internalPort, child, readinessTimeout, label);
|
|
11202
|
+
server = createDevProxyServer({
|
|
11203
|
+
targetPort: internalPort,
|
|
11204
|
+
routePrefix: resolveServiceRoutePrefix(env)
|
|
11205
|
+
});
|
|
11206
|
+
const listenPort = options.port ?? await findFreePort();
|
|
11207
|
+
await new Promise((resolve, reject) => {
|
|
11208
|
+
server?.once("error", reject);
|
|
11209
|
+
server?.listen(listenPort, () => resolve());
|
|
11210
|
+
});
|
|
11211
|
+
if (!child.pid) {
|
|
11212
|
+
throw new Error(`${label} started without a PID`);
|
|
11213
|
+
}
|
|
11214
|
+
return { port: listenPort, pid: child.pid, child, close };
|
|
11215
|
+
} catch (err) {
|
|
11216
|
+
await close();
|
|
11217
|
+
throw err;
|
|
11218
|
+
}
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
11221
|
+
});
|
|
11222
|
+
|
|
10941
11223
|
// ../../internals/ipc-proxy/dist/index.js
|
|
10942
11224
|
var require_dist2 = __commonJS({
|
|
10943
11225
|
"../../internals/ipc-proxy/dist/index.js"(exports, module2) {
|
|
@@ -10958,6 +11240,7 @@ var require_dist2 = __commonJS({
|
|
|
10958
11240
|
}
|
|
10959
11241
|
return to2;
|
|
10960
11242
|
};
|
|
11243
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps2(target, mod, "default"), secondTarget && __copyProps2(secondTarget, mod, "default"));
|
|
10961
11244
|
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
|
|
10962
11245
|
var src_exports2 = {};
|
|
10963
11246
|
__export2(src_exports2, {
|
|
@@ -10970,6 +11253,7 @@ var require_dist2 = __commonJS({
|
|
|
10970
11253
|
var import_node_fs7 = require("fs");
|
|
10971
11254
|
var import_promises2 = require("fs/promises");
|
|
10972
11255
|
var import_build_utils6 = require("@vercel/build-utils");
|
|
11256
|
+
__reExport(src_exports2, require_dev_proxy(), module2.exports);
|
|
10973
11257
|
function proxyBinaryName(architecture) {
|
|
10974
11258
|
return architecture === "arm64" ? "proxy-linux-arm64" : "proxy-linux-amd64";
|
|
10975
11259
|
}
|
|
@@ -14469,27 +14753,75 @@ var GoWrapper = class {
|
|
|
14469
14753
|
getEnv() {
|
|
14470
14754
|
return this.env;
|
|
14471
14755
|
}
|
|
14472
|
-
build(src, dest, { vendorMode = false } = {}) {
|
|
14473
|
-
(0, import_build_utils.debug)(
|
|
14756
|
+
build(src, dest, { vendorMode = false, release = true } = {}) {
|
|
14757
|
+
(0, import_build_utils.debug)(
|
|
14758
|
+
`Building ${release ? "optimized" : "debug"} 'go' binary ${src} -> ${dest}`
|
|
14759
|
+
);
|
|
14474
14760
|
const sources = Array.isArray(src) ? src : [src];
|
|
14475
14761
|
const envGoBuildFlags = (this.env || this.opts.env).GO_BUILD_FLAGS;
|
|
14476
|
-
const
|
|
14762
|
+
const defaultFlags = release ? GO_FLAGS : [];
|
|
14763
|
+
const flags = envGoBuildFlags ? (0, import_string_argv.default)(envGoBuildFlags) : [...defaultFlags];
|
|
14477
14764
|
if (vendorMode && !envGoBuildFlags) {
|
|
14478
14765
|
flags.push("-mod=vendor");
|
|
14479
14766
|
}
|
|
14480
14767
|
return this.execute("build", ...flags, "-o", dest, ...sources);
|
|
14481
14768
|
}
|
|
14482
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
|
+
}
|
|
14483
14807
|
async function createGo({
|
|
14484
14808
|
modulePath,
|
|
14485
14809
|
opts = {},
|
|
14486
|
-
workPath
|
|
14810
|
+
workPath,
|
|
14811
|
+
preferNewestToolchain = false
|
|
14487
14812
|
}) {
|
|
14488
14813
|
let goPreferredVersion;
|
|
14489
14814
|
if (modulePath) {
|
|
14490
14815
|
goPreferredVersion = await parseGoModVersionFromModule(modulePath);
|
|
14491
14816
|
}
|
|
14492
|
-
const goSelectedVersion = goPreferredVersion
|
|
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
|
+
}
|
|
14493
14825
|
const env = opts.env ? (0, import_build_utils.cloneEnv)(opts.env) : (0, import_build_utils.cloneEnv)(process.env);
|
|
14494
14826
|
const { PATH } = env;
|
|
14495
14827
|
const { platform } = process;
|
|
@@ -14804,7 +15136,6 @@ var detectEntrypoint = async ({ workPath }) => {
|
|
|
14804
15136
|
|
|
14805
15137
|
// src/standalone-server.ts
|
|
14806
15138
|
var import_child_process = require("child_process");
|
|
14807
|
-
var import_net = require("net");
|
|
14808
15139
|
var import_path6 = require("path");
|
|
14809
15140
|
var import_fs_extra3 = __toESM(require_lib2());
|
|
14810
15141
|
var import_build_utils4 = require("@vercel/build-utils");
|
|
@@ -15049,19 +15380,29 @@ async function createStandaloneServerLambda({
|
|
|
15049
15380
|
});
|
|
15050
15381
|
return lambda;
|
|
15051
15382
|
}
|
|
15052
|
-
var DEV_SERVER_STARTUP_TIMEOUT = 5 * 6e4;
|
|
15053
15383
|
var PERSISTENT_SERVERS = /* @__PURE__ */ new Map();
|
|
15054
15384
|
var PENDING_STARTS = /* @__PURE__ */ new Map();
|
|
15055
15385
|
var cleanupHandlersInstalled = false;
|
|
15056
|
-
function
|
|
15386
|
+
function killStandaloneDevServerProcessTree(child) {
|
|
15387
|
+
if (!child.pid)
|
|
15388
|
+
return;
|
|
15057
15389
|
try {
|
|
15058
15390
|
if (process.platform === "win32") {
|
|
15059
|
-
|
|
15391
|
+
child.kill("SIGTERM");
|
|
15060
15392
|
} else {
|
|
15061
|
-
process.kill(-pid, "SIGTERM");
|
|
15393
|
+
process.kill(-child.pid, "SIGTERM");
|
|
15062
15394
|
}
|
|
15063
15395
|
} catch (err) {
|
|
15064
|
-
(
|
|
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);
|
|
15065
15406
|
}
|
|
15066
15407
|
}
|
|
15067
15408
|
function installGlobalCleanupHandlers() {
|
|
@@ -15069,162 +15410,151 @@ function installGlobalCleanupHandlers() {
|
|
|
15069
15410
|
return;
|
|
15070
15411
|
cleanupHandlersInstalled = true;
|
|
15071
15412
|
const killAll = () => {
|
|
15072
|
-
for (const [key,
|
|
15073
|
-
killStandaloneDevServer(info.pid);
|
|
15413
|
+
for (const [key, server] of PERSISTENT_SERVERS.entries()) {
|
|
15074
15414
|
PERSISTENT_SERVERS.delete(key);
|
|
15415
|
+
killStandaloneDevServerProcessTree(server.handle.child);
|
|
15075
15416
|
}
|
|
15076
15417
|
};
|
|
15077
|
-
process.on("SIGINT",
|
|
15078
|
-
|
|
15079
|
-
|
|
15080
|
-
process.on("SIGTERM", () => {
|
|
15081
|
-
killAll();
|
|
15082
|
-
});
|
|
15083
|
-
process.on("exit", () => {
|
|
15084
|
-
killAll();
|
|
15085
|
-
});
|
|
15086
|
-
}
|
|
15087
|
-
function isPortReachable(port) {
|
|
15088
|
-
return new Promise((resolve) => {
|
|
15089
|
-
const socket = (0, import_net.createConnection)({ port, host: "127.0.0.1" });
|
|
15090
|
-
const done = (result) => {
|
|
15091
|
-
socket.removeAllListeners();
|
|
15092
|
-
socket.destroy();
|
|
15093
|
-
resolve(result);
|
|
15094
|
-
};
|
|
15095
|
-
socket.setTimeout(1e3);
|
|
15096
|
-
socket.once("connect", () => done(true));
|
|
15097
|
-
socket.once("timeout", () => done(false));
|
|
15098
|
-
socket.once("error", () => done(false));
|
|
15099
|
-
});
|
|
15100
|
-
}
|
|
15101
|
-
function sleep(ms2) {
|
|
15102
|
-
return new Promise((resolve) => setTimeout(resolve, ms2));
|
|
15418
|
+
process.on("SIGINT", killAll);
|
|
15419
|
+
process.on("SIGTERM", killAll);
|
|
15420
|
+
process.on("exit", killAll);
|
|
15103
15421
|
}
|
|
15104
|
-
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15111
|
-
|
|
15112
|
-
};
|
|
15113
|
-
child.once("exit", onExit);
|
|
15114
|
-
child.once("error", onError);
|
|
15115
|
-
try {
|
|
15116
|
-
const start = Date.now();
|
|
15117
|
-
while (Date.now() - start < timeout) {
|
|
15118
|
-
if (spawnError) {
|
|
15119
|
-
throw spawnError;
|
|
15120
|
-
}
|
|
15121
|
-
if (exited) {
|
|
15122
|
-
const { code, signal } = exited;
|
|
15123
|
-
throw new Error(
|
|
15124
|
-
`Standalone Go dev server exited before startup completed (code: ${code}, signal: ${signal})`
|
|
15125
|
-
);
|
|
15126
|
-
}
|
|
15127
|
-
if (await isPortReachable(port)) {
|
|
15128
|
-
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);
|
|
15129
15430
|
}
|
|
15130
|
-
await
|
|
15431
|
+
await closeStandaloneDevServer(handle);
|
|
15131
15432
|
}
|
|
15132
|
-
|
|
15133
|
-
`Standalone Go dev server did not start within ${timeout}ms`
|
|
15134
|
-
);
|
|
15135
|
-
} finally {
|
|
15136
|
-
child.removeListener("exit", onExit);
|
|
15137
|
-
child.removeListener("error", onError);
|
|
15138
|
-
}
|
|
15433
|
+
};
|
|
15139
15434
|
}
|
|
15140
15435
|
async function startStandaloneDevServer(opts, resolvedEntrypoint) {
|
|
15141
15436
|
const { workPath, meta = {} } = opts;
|
|
15437
|
+
const { devCacheDir = (0, import_path6.join)(workPath, ".vercel", "cache") } = meta;
|
|
15142
15438
|
const serverKey = `${workPath}::${resolvedEntrypoint}`;
|
|
15143
15439
|
const existing = PERSISTENT_SERVERS.get(serverKey);
|
|
15144
15440
|
if (existing) {
|
|
15145
|
-
return
|
|
15146
|
-
port: existing.port,
|
|
15147
|
-
pid: existing.pid,
|
|
15148
|
-
shutdown: async () => {
|
|
15149
|
-
}
|
|
15150
|
-
};
|
|
15441
|
+
return toDevServerResult(serverKey, existing.handle);
|
|
15151
15442
|
}
|
|
15152
15443
|
const pending = PENDING_STARTS.get(serverKey);
|
|
15153
15444
|
if (pending) {
|
|
15154
|
-
|
|
15155
|
-
return
|
|
15156
|
-
} };
|
|
15445
|
+
await pending;
|
|
15446
|
+
return startStandaloneDevServer(opts, resolvedEntrypoint);
|
|
15157
15447
|
}
|
|
15158
15448
|
const startPromise = (async () => {
|
|
15159
|
-
const
|
|
15160
|
-
const env = (0, import_build_utils4.cloneEnv)(process.env, meta.env, {
|
|
15161
|
-
PORT: String(port)
|
|
15162
|
-
});
|
|
15449
|
+
const env = (0, import_build_utils4.cloneEnv)(process.env, meta.env);
|
|
15163
15450
|
const entrypointDir = (0, import_path6.dirname)((0, import_path6.join)(workPath, resolvedEntrypoint));
|
|
15164
15451
|
const { goModPath } = await findGoModPath(entrypointDir, workPath);
|
|
15165
15452
|
const modulePath = goModPath ? (0, import_path6.dirname)(goModPath) : workPath;
|
|
15166
15453
|
const go = await createGo({
|
|
15167
15454
|
modulePath,
|
|
15168
15455
|
opts: { cwd: workPath, env },
|
|
15169
|
-
workPath
|
|
15456
|
+
workPath,
|
|
15457
|
+
// The binary has to run on this machine, so don't downgrade.
|
|
15458
|
+
preferNewestToolchain: true
|
|
15170
15459
|
});
|
|
15171
|
-
const
|
|
15172
|
-
const
|
|
15173
|
-
|
|
15174
|
-
(0, import_build_utils4.debug)(
|
|
15175
|
-
`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")
|
|
15176
15463
|
);
|
|
15177
|
-
|
|
15178
|
-
|
|
15179
|
-
|
|
15180
|
-
|
|
15181
|
-
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
process.stdout.write(chunk.toString());
|
|
15192
|
-
}
|
|
15193
|
-
});
|
|
15194
|
-
child.stderr?.on("data", (data) => {
|
|
15195
|
-
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
15196
|
-
if (opts.onStderr) {
|
|
15197
|
-
opts.onStderr(chunk);
|
|
15198
|
-
} else {
|
|
15199
|
-
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}`);
|
|
15200
15478
|
}
|
|
15201
|
-
}
|
|
15202
|
-
const
|
|
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
|
+
);
|
|
15203
15487
|
try {
|
|
15204
|
-
await
|
|
15488
|
+
await go.build(buildTarget, executablePath, {
|
|
15489
|
+
vendorMode: isVendored,
|
|
15490
|
+
release: false
|
|
15491
|
+
});
|
|
15205
15492
|
} catch (err) {
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
}
|
|
15493
|
+
console.error(`Failed to build standalone Go server: ${buildTarget}`);
|
|
15494
|
+
await cleanupOutDir();
|
|
15209
15495
|
throw err;
|
|
15210
15496
|
}
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
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();
|
|
15217
15546
|
});
|
|
15218
15547
|
installGlobalCleanupHandlers();
|
|
15219
|
-
return
|
|
15548
|
+
return server;
|
|
15220
15549
|
})();
|
|
15221
15550
|
PENDING_STARTS.set(serverKey, startPromise);
|
|
15222
15551
|
try {
|
|
15223
|
-
const
|
|
15224
|
-
return
|
|
15225
|
-
} };
|
|
15552
|
+
const server = await startPromise;
|
|
15553
|
+
return toDevServerResult(serverKey, server.handle);
|
|
15226
15554
|
} finally {
|
|
15227
|
-
PENDING_STARTS.
|
|
15555
|
+
if (PENDING_STARTS.get(serverKey) === startPromise) {
|
|
15556
|
+
PENDING_STARTS.delete(serverKey);
|
|
15557
|
+
}
|
|
15228
15558
|
}
|
|
15229
15559
|
}
|
|
15230
15560
|
|
|
@@ -15883,9 +16213,11 @@ async function startDevServer(opts) {
|
|
|
15883
16213
|
cwd: tmp,
|
|
15884
16214
|
env
|
|
15885
16215
|
},
|
|
15886
|
-
workPath
|
|
16216
|
+
workPath,
|
|
16217
|
+
// The binary has to run on this machine, so don't downgrade.
|
|
16218
|
+
preferNewestToolchain: true
|
|
15887
16219
|
});
|
|
15888
|
-
await go.build("./...", executable);
|
|
16220
|
+
await go.build("./...", executable, { release: false });
|
|
15889
16221
|
(0, import_build_utils5.debug)(`SPAWNING ${executable} CWD=${tmp}`);
|
|
15890
16222
|
const child = (0, import_child_process2.spawn)(executable, [], {
|
|
15891
16223
|
cwd: tmp,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/go",
|
|
3
|
-
"version": "
|
|
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,9 +12,12 @@
|
|
|
12
12
|
"files": [
|
|
13
13
|
"dist",
|
|
14
14
|
"*.go",
|
|
15
|
-
"bin"
|
|
16
|
-
"bootstrap"
|
|
15
|
+
"bin"
|
|
17
16
|
],
|
|
17
|
+
"dependencies": {},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@vercel/build-utils": "14.4.0"
|
|
20
|
+
},
|
|
18
21
|
"devDependencies": {
|
|
19
22
|
"@tootallnate/once": "1.1.2",
|
|
20
23
|
"@types/async-retry": "1.4.5",
|
|
@@ -32,13 +35,14 @@
|
|
|
32
35
|
"vitest": "4.1.10",
|
|
33
36
|
"xdg-app-paths": "5.1.0",
|
|
34
37
|
"yauzl-promise": "2.1.3",
|
|
35
|
-
"@vercel
|
|
36
|
-
"@vercel/
|
|
38
|
+
"@vercel/build-utils": "14.4.0",
|
|
39
|
+
"@vercel-internals/ipc-proxy": "1.0.0"
|
|
37
40
|
},
|
|
38
41
|
"scripts": {
|
|
39
42
|
"build": "node build.mjs",
|
|
40
43
|
"test": "vitest run --config ../../vitest.config.mts",
|
|
41
44
|
"test-e2e": "vitest run --config ../../vitest.config.mts test/integration-",
|
|
45
|
+
"test-e2e-builder": "pnpm run test-e2e",
|
|
42
46
|
"type-check": "tsc --noEmit"
|
|
43
47
|
}
|
|
44
48
|
}
|
package/bootstrap/utils.go
DELETED
|
@@ -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
|
-
}
|
package/bootstrap/vc-init-dev.go
DELETED
|
@@ -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
|
-
}
|