@vercel/go 3.4.1 → 3.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8495,12 +8495,12 @@ var require_lib4 = __commonJS({
8495
8495
  const dest = new URL$1(destination).hostname;
8496
8496
  return orig === dest || orig[orig.length - dest.length - 1] === "." && orig.endsWith(dest);
8497
8497
  };
8498
- function fetch2(url, opts) {
8499
- if (!fetch2.Promise) {
8498
+ function fetch(url, opts) {
8499
+ if (!fetch.Promise) {
8500
8500
  throw new Error("native promise missing, set fetch.Promise to your favorite alternative");
8501
8501
  }
8502
- Body.Promise = fetch2.Promise;
8503
- return new fetch2.Promise(function(resolve, reject) {
8502
+ Body.Promise = fetch.Promise;
8503
+ return new fetch.Promise(function(resolve, reject) {
8504
8504
  const request = new Request(url, opts);
8505
8505
  const options = getNodeRequestOptions(request);
8506
8506
  const send = (options.protocol === "https:" ? https : http).request;
@@ -8550,7 +8550,7 @@ var require_lib4 = __commonJS({
8550
8550
  req.on("response", function(res) {
8551
8551
  clearTimeout(reqTimeout);
8552
8552
  const headers = createHeadersLenient(res.headers);
8553
- if (fetch2.isRedirect(res.statusCode)) {
8553
+ if (fetch.isRedirect(res.statusCode)) {
8554
8554
  const location = headers.get("Location");
8555
8555
  let locationURL = null;
8556
8556
  try {
@@ -8612,7 +8612,7 @@ var require_lib4 = __commonJS({
8612
8612
  requestOpts.body = void 0;
8613
8613
  requestOpts.headers.delete("content-length");
8614
8614
  }
8615
- resolve(fetch2(new Request(locationURL, requestOpts)));
8615
+ resolve(fetch(new Request(locationURL, requestOpts)));
8616
8616
  finalize();
8617
8617
  return;
8618
8618
  }
@@ -8672,11 +8672,11 @@ var require_lib4 = __commonJS({
8672
8672
  writeToStream(req, request);
8673
8673
  });
8674
8674
  }
8675
- fetch2.isRedirect = function(code2) {
8675
+ fetch.isRedirect = function(code2) {
8676
8676
  return code2 === 301 || code2 === 302 || code2 === 303 || code2 === 307 || code2 === 308;
8677
8677
  };
8678
- fetch2.Promise = global.Promise;
8679
- module2.exports = exports = fetch2;
8678
+ fetch.Promise = global.Promise;
8679
+ module2.exports = exports = fetch;
8680
8680
  Object.defineProperty(exports, "__esModule", { value: true });
8681
8681
  exports.default = exports;
8682
8682
  exports.Headers = Headers;
@@ -17201,11 +17201,13 @@ async function buildStandaloneServer({
17201
17201
  throw err;
17202
17202
  }
17203
17203
  const bootstrapSrc = (0, import_path6.join)(__dirname, "../vc-init.go");
17204
+ const utilsSrc = (0, import_path6.join)(__dirname, "../vc-utils.go");
17204
17205
  (0, import_build_utils3.debug)(`Building bootstrap wrapper: ${bootstrapSrc} -> ${bootstrapPath}`);
17205
17206
  try {
17206
17207
  const bootstrapBuildDir = await (0, import_build_utils3.getWriteableDirectory)();
17207
17208
  const bootstrapGoFile = (0, import_path6.join)(bootstrapBuildDir, "main.go");
17208
17209
  await (0, import_fs_extra3.copy)(bootstrapSrc, bootstrapGoFile);
17210
+ await (0, import_fs_extra3.copy)(utilsSrc, (0, import_path6.join)(bootstrapBuildDir, "vc-utils.go"));
17209
17211
  const bootstrapGoMod = (0, import_path6.join)(bootstrapBuildDir, "go.mod");
17210
17212
  await (0, import_fs_extra3.writeFile)(bootstrapGoMod, "module vc-init\n\ngo 1.21\n");
17211
17213
  const bootstrapGo = await createGo({
@@ -17256,12 +17258,17 @@ async function startStandaloneDevServer(opts, resolvedEntrypoint) {
17256
17258
  PORT: String(port)
17257
17259
  });
17258
17260
  const runTarget = resolvedEntrypoint === "main.go" ? "." : "./" + (0, import_path6.dirname)(resolvedEntrypoint);
17261
+ const devWrapper = (0, import_path6.join)(__dirname, "../vc-init-dev.go");
17262
+ const devUtils = (0, import_path6.join)(__dirname, "../vc-utils.go");
17259
17263
  (0, import_build_utils3.debug)(
17260
- `Starting standalone Go dev server: go run ${runTarget} (port ${port})`
17264
+ `Starting standalone Go dev server wrapper: go run ${devWrapper} (target ${runTarget}, port ${port})`
17261
17265
  );
17262
- const child = (0, import_child_process.spawn)("go", ["run", runTarget], {
17266
+ const child = (0, import_child_process.spawn)("go", ["run", "-tags", "vcdev", devWrapper, devUtils], {
17263
17267
  cwd: workPath,
17264
- env,
17268
+ env: {
17269
+ ...env,
17270
+ __VC_GO_DEV_RUN_TARGET: runTarget
17271
+ },
17265
17272
  stdio: ["ignore", "pipe", "pipe"]
17266
17273
  });
17267
17274
  child.stdout?.on("data", (data) => {
@@ -17280,7 +17287,25 @@ async function startStandaloneDevServer(opts, resolvedEntrypoint) {
17280
17287
  process.stderr.write(chunk.toString());
17281
17288
  }
17282
17289
  });
17283
- await new Promise((resolve) => setTimeout(resolve, 2e3));
17290
+ await new Promise((resolve, reject) => {
17291
+ const timeout = setTimeout(() => {
17292
+ cleanup();
17293
+ resolve();
17294
+ }, 2e3);
17295
+ const onExit = (code2, signal) => {
17296
+ cleanup();
17297
+ reject(
17298
+ new Error(
17299
+ `Standalone Go dev server exited before startup completed (code: ${code2}, signal: ${signal})`
17300
+ )
17301
+ );
17302
+ };
17303
+ const cleanup = () => {
17304
+ clearTimeout(timeout);
17305
+ child.removeListener("exit", onExit);
17306
+ };
17307
+ child.once("exit", onExit);
17308
+ });
17284
17309
  return {
17285
17310
  port,
17286
17311
  pid: child.pid
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vercel/go",
3
- "version": "3.4.1",
3
+ "version": "3.4.3",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./dist/index",
6
6
  "homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -29,10 +29,10 @@
29
29
  "node-fetch": "^2.2.1",
30
30
  "string-argv": "0.3.1",
31
31
  "tar": "7.5.7",
32
- "typescript": "4.3.4",
32
+ "typescript": "4.9.5",
33
33
  "xdg-app-paths": "5.1.0",
34
34
  "yauzl-promise": "2.1.3",
35
- "@vercel/build-utils": "13.4.0"
35
+ "@vercel/build-utils": "13.6.0"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "node ../../utils/build-builder.mjs",
package/vc-init-dev.go ADDED
@@ -0,0 +1,147 @@
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
+ }
package/vc-init.go CHANGED
@@ -94,34 +94,9 @@ func connectIPC() error {
94
94
  return nil
95
95
  }
96
96
 
97
- func findFreePort() (int, error) {
98
- listener, err := net.Listen("tcp", "127.0.0.1:0")
99
- if err != nil {
100
- return 0, err
101
- }
102
- port := listener.Addr().(*net.TCPAddr).Port
103
- listener.Close()
104
- return port, nil
105
- }
106
-
107
- func waitForServer(port int, timeout time.Duration) error {
108
- deadline := time.Now().Add(timeout)
109
- url := fmt.Sprintf("http://127.0.0.1:%d/", port)
110
-
111
- for time.Now().Before(deadline) {
112
- resp, err := http.Get(url)
113
- if err == nil {
114
- resp.Body.Close()
115
- return nil
116
- }
117
- time.Sleep(50 * time.Millisecond)
118
- }
119
-
120
- return fmt.Errorf("server did not start within %v", timeout)
121
- }
122
-
123
97
  func main() {
124
98
  startTime = time.Now()
99
+ serviceRoutePrefix := resolveServiceRoutePrefix()
125
100
 
126
101
  // Connect to IPC socket
127
102
  if err := connectIPC(); err != nil {
@@ -202,6 +177,15 @@ func main() {
202
177
  }
203
178
  }
204
179
 
180
+ if r.URL != nil {
181
+ originalPath := r.URL.Path
182
+ r.URL.Path = stripServiceRoutePrefix(r.URL.Path, serviceRoutePrefix)
183
+ if r.URL.Path != originalPath {
184
+ // Keep URL path encoding fields consistent after rewrite.
185
+ r.URL.RawPath = ""
186
+ }
187
+ }
188
+
205
189
  // Forward request to user's server
206
190
  proxy.ServeHTTP(w, r)
207
191
 
@@ -251,9 +235,3 @@ func main() {
251
235
  // Clean up
252
236
  cmd.Process.Kill()
253
237
  }
254
-
255
- // Ensure we close IPC connection on exit
256
- func init() {
257
- // Note: Using a deferred cleanup in main() is preferred,
258
- // but this provides a fallback
259
- }
package/vc-utils.go ADDED
@@ -0,0 +1,114 @@
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "net"
6
+ "net/http"
7
+ "os"
8
+ "strings"
9
+ "time"
10
+ )
11
+
12
+ func findFreePort() (int, error) {
13
+ listener, err := net.Listen("tcp", "127.0.0.1:0")
14
+ if err != nil {
15
+ return 0, err
16
+ }
17
+ port := listener.Addr().(*net.TCPAddr).Port
18
+ listener.Close()
19
+ return port, nil
20
+ }
21
+
22
+ func waitForServer(port int, timeout time.Duration) error {
23
+ deadline := time.Now().Add(timeout)
24
+ url := fmt.Sprintf("http://127.0.0.1:%d/", port)
25
+
26
+ for time.Now().Before(deadline) {
27
+ resp, err := http.Get(url)
28
+ if err == nil {
29
+ resp.Body.Close()
30
+ return nil
31
+ }
32
+ time.Sleep(50 * time.Millisecond)
33
+ }
34
+
35
+ return fmt.Errorf("server did not start within %v", timeout)
36
+ }
37
+
38
+ func normalizeServiceRoutePrefix(rawPrefix string) string {
39
+ if rawPrefix == "" {
40
+ return ""
41
+ }
42
+
43
+ prefix := strings.TrimSpace(rawPrefix)
44
+ if prefix == "" {
45
+ return ""
46
+ }
47
+
48
+ if !strings.HasPrefix(prefix, "/") {
49
+ prefix = "/" + prefix
50
+ }
51
+
52
+ if prefix != "/" {
53
+ prefix = strings.TrimRight(prefix, "/")
54
+ if prefix == "" {
55
+ prefix = "/"
56
+ }
57
+ }
58
+
59
+ if prefix == "/" {
60
+ return ""
61
+ }
62
+
63
+ return prefix
64
+ }
65
+
66
+ func serviceRoutePrefixStripEnabled() bool {
67
+ raw := strings.TrimSpace(os.Getenv("VERCEL_SERVICE_ROUTE_PREFIX_STRIP"))
68
+ if raw == "" {
69
+ return false
70
+ }
71
+
72
+ normalized := strings.ToLower(raw)
73
+ return normalized == "1" || normalized == "true"
74
+ }
75
+
76
+ func resolveServiceRoutePrefix() string {
77
+ if !serviceRoutePrefixStripEnabled() {
78
+ return ""
79
+ }
80
+
81
+ return normalizeServiceRoutePrefix(os.Getenv("VERCEL_SERVICE_ROUTE_PREFIX"))
82
+ }
83
+
84
+ func stripServiceRoutePrefix(pathValue string, prefix string) string {
85
+ if pathValue == "*" {
86
+ return pathValue
87
+ }
88
+
89
+ normalizedPath := pathValue
90
+ if normalizedPath == "" {
91
+ normalizedPath = "/"
92
+ } else if !strings.HasPrefix(normalizedPath, "/") {
93
+ normalizedPath = "/" + normalizedPath
94
+ }
95
+
96
+ if prefix == "" {
97
+ return normalizedPath
98
+ }
99
+
100
+ if normalizedPath == prefix {
101
+ return "/"
102
+ }
103
+
104
+ prefixWithSlash := prefix + "/"
105
+ if strings.HasPrefix(normalizedPath, prefixWithSlash) {
106
+ stripped := normalizedPath[len(prefix):]
107
+ if stripped == "" {
108
+ return "/"
109
+ }
110
+ return stripped
111
+ }
112
+
113
+ return normalizedPath
114
+ }