@vercel/ruby 2.3.0 → 2.3.2
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 +42 -13
- package/package.json +4 -3
- package/vc_init.rb +12 -2
- package/vc_init_dev.rb +21 -3
- package/vc_utils.rb +101 -0
package/dist/index.js
CHANGED
|
@@ -7232,10 +7232,14 @@ function createDevRubyShim(workPath, entrypoint) {
|
|
|
7232
7232
|
const vercelRubyDir = (0, import_path2.join)(workPath, ".vercel", "ruby");
|
|
7233
7233
|
(0, import_fs.mkdirSync)(vercelRubyDir, { recursive: true });
|
|
7234
7234
|
const shimPath = (0, import_path2.join)(vercelRubyDir, `vc_init_dev.rb`);
|
|
7235
|
+
const utilsPath = (0, import_path2.join)(vercelRubyDir, "vc__utils__ruby.rb");
|
|
7235
7236
|
const templatePath = (0, import_path2.join)(__dirname, "..", "vc_init_dev.rb");
|
|
7237
|
+
const utilsTemplatePath = (0, import_path2.join)(__dirname, "..", "vc_utils.rb");
|
|
7236
7238
|
const template = (0, import_fs.readFileSync)(templatePath, "utf8");
|
|
7239
|
+
const utilsTemplate = (0, import_fs.readFileSync)(utilsTemplatePath, "utf8");
|
|
7237
7240
|
const shimSource = template.replace(/__VC_DEV_ENTRYPOINT__/g, entrypoint);
|
|
7238
7241
|
(0, import_fs.writeFileSync)(shimPath, shimSource, "utf8");
|
|
7242
|
+
(0, import_fs.writeFileSync)(utilsPath, utilsTemplate, "utf8");
|
|
7239
7243
|
(0, import_build_utils2.debug)(`Prepared Ruby dev shim at ${shimPath}`);
|
|
7240
7244
|
return shimPath;
|
|
7241
7245
|
} catch (err) {
|
|
@@ -7260,8 +7264,22 @@ async function run(cmd, args, opts) {
|
|
|
7260
7264
|
env: opts.env,
|
|
7261
7265
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7262
7266
|
});
|
|
7263
|
-
child.stdout?.on("data", (
|
|
7264
|
-
|
|
7267
|
+
child.stdout?.on("data", (data) => {
|
|
7268
|
+
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
7269
|
+
if (opts.onStdout) {
|
|
7270
|
+
opts.onStdout(chunk);
|
|
7271
|
+
} else {
|
|
7272
|
+
process.stdout.write(chunk.toString());
|
|
7273
|
+
}
|
|
7274
|
+
});
|
|
7275
|
+
child.stderr?.on("data", (data) => {
|
|
7276
|
+
const chunk = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
7277
|
+
if (opts.onStderr) {
|
|
7278
|
+
opts.onStderr(chunk);
|
|
7279
|
+
} else {
|
|
7280
|
+
process.stderr.write(chunk.toString());
|
|
7281
|
+
}
|
|
7282
|
+
});
|
|
7265
7283
|
child.on("close", (code, signal) => resolve({ code, signal }));
|
|
7266
7284
|
});
|
|
7267
7285
|
}
|
|
@@ -7329,7 +7347,12 @@ var startDevServer = async (opts) => {
|
|
|
7329
7347
|
const check = await run(
|
|
7330
7348
|
bundlerPath,
|
|
7331
7349
|
["check", "--gemfile", gemfile],
|
|
7332
|
-
{
|
|
7350
|
+
{
|
|
7351
|
+
cwd: projectDir,
|
|
7352
|
+
env,
|
|
7353
|
+
onStdout: opts.onStdout,
|
|
7354
|
+
onStderr: opts.onStderr
|
|
7355
|
+
}
|
|
7333
7356
|
);
|
|
7334
7357
|
if (check.code !== 0) {
|
|
7335
7358
|
return false;
|
|
@@ -7356,21 +7379,21 @@ var startDevServer = async (opts) => {
|
|
|
7356
7379
|
const child = (0, import_child_process2.spawn)(cmd, args, {
|
|
7357
7380
|
cwd: workPath,
|
|
7358
7381
|
env,
|
|
7359
|
-
stdio: ["
|
|
7382
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
7360
7383
|
});
|
|
7361
7384
|
childProcess = child;
|
|
7362
7385
|
stdoutLogListener = (buf) => {
|
|
7363
|
-
|
|
7364
|
-
|
|
7365
|
-
|
|
7366
|
-
|
|
7386
|
+
if (opts.onStdout) {
|
|
7387
|
+
opts.onStdout(buf);
|
|
7388
|
+
} else {
|
|
7389
|
+
process.stdout.write(buf.toString());
|
|
7367
7390
|
}
|
|
7368
7391
|
};
|
|
7369
7392
|
stderrLogListener = (buf) => {
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7393
|
+
if (opts.onStderr) {
|
|
7394
|
+
opts.onStderr(buf);
|
|
7395
|
+
} else {
|
|
7396
|
+
process.stderr.write(buf.toString());
|
|
7374
7397
|
}
|
|
7375
7398
|
};
|
|
7376
7399
|
child.stdout?.on("data", stdoutLogListener);
|
|
@@ -7597,6 +7620,8 @@ var build = async ({
|
|
|
7597
7620
|
}
|
|
7598
7621
|
const originalRbPath = (0, import_path3.join)(__dirname, "..", "vc_init.rb");
|
|
7599
7622
|
const originalHandlerRbContents = await (0, import_fs_extra.readFile)(originalRbPath, "utf8");
|
|
7623
|
+
const originalUtilsRbPath = (0, import_path3.join)(__dirname, "..", "vc_utils.rb");
|
|
7624
|
+
const originalUtilsRbContents = await (0, import_fs_extra.readFile)(originalUtilsRbPath, "utf8");
|
|
7600
7625
|
(0, import_build_utils3.debug)("entrypoint is", entrypoint);
|
|
7601
7626
|
const userHandlerFilePath = entrypoint.replace(/\.rb$/, "");
|
|
7602
7627
|
const nowHandlerRbContents = originalHandlerRbContents.replace(
|
|
@@ -7604,6 +7629,7 @@ var build = async ({
|
|
|
7604
7629
|
userHandlerFilePath
|
|
7605
7630
|
);
|
|
7606
7631
|
const handlerRbFilename = "vc__handler__ruby";
|
|
7632
|
+
const utilsRbFilename = "vc__utils__ruby.rb";
|
|
7607
7633
|
const predefinedExcludes = [
|
|
7608
7634
|
".git/**",
|
|
7609
7635
|
".gitignore",
|
|
@@ -7621,6 +7647,9 @@ var build = async ({
|
|
|
7621
7647
|
outputFiles[`${handlerRbFilename}.rb`] = new import_build_utils3.FileBlob({
|
|
7622
7648
|
data: nowHandlerRbContents
|
|
7623
7649
|
});
|
|
7650
|
+
outputFiles[utilsRbFilename] = new import_build_utils3.FileBlob({
|
|
7651
|
+
data: originalUtilsRbContents
|
|
7652
|
+
});
|
|
7624
7653
|
if (config && (config.includeFiles || config.excludeFiles)) {
|
|
7625
7654
|
const includedPaths = await matchPaths(config.includeFiles, workPath);
|
|
7626
7655
|
const excludedPaths = await matchPaths(
|
|
@@ -7631,7 +7660,7 @@ var build = async ({
|
|
|
7631
7660
|
if (includedPaths.includes(excludedPaths[i])) {
|
|
7632
7661
|
continue;
|
|
7633
7662
|
}
|
|
7634
|
-
if (excludedPaths[i] === `${handlerRbFilename}.rb`) {
|
|
7663
|
+
if (excludedPaths[i] === `${handlerRbFilename}.rb` || excludedPaths[i] === utilsRbFilename) {
|
|
7635
7664
|
continue;
|
|
7636
7665
|
}
|
|
7637
7666
|
if (excludedPaths[i].startsWith(vendorPath)) {
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercel/ruby",
|
|
3
3
|
"author": "Nathan Cahill <nathan@nathancahill.com>",
|
|
4
|
-
"version": "2.3.
|
|
4
|
+
"version": "2.3.2",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index",
|
|
7
7
|
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist",
|
|
10
10
|
"vc_init.rb",
|
|
11
|
-
"vc_init_dev.rb"
|
|
11
|
+
"vc_init_dev.rb",
|
|
12
|
+
"vc_utils.rb"
|
|
12
13
|
],
|
|
13
14
|
"repository": {
|
|
14
15
|
"type": "git",
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
"jest-junit": "16.0.0",
|
|
25
26
|
"semver": "6.3.1",
|
|
26
27
|
"which": "3.0.0",
|
|
27
|
-
"@vercel/build-utils": "13.
|
|
28
|
+
"@vercel/build-utils": "13.5.0"
|
|
28
29
|
},
|
|
29
30
|
"scripts": {
|
|
30
31
|
"build": "node ../../utils/build-builder.mjs",
|
package/vc_init.rb
CHANGED
|
@@ -3,6 +3,7 @@ require 'webrick'
|
|
|
3
3
|
require 'net/http'
|
|
4
4
|
require 'base64'
|
|
5
5
|
require 'json'
|
|
6
|
+
require_relative 'vc__utils__ruby'
|
|
6
7
|
|
|
7
8
|
$entrypoint = '__VC_HANDLER_FILENAME'
|
|
8
9
|
|
|
@@ -10,13 +11,17 @@ ENV['RAILS_ENV'] ||= 'production'
|
|
|
10
11
|
ENV['RACK_ENV'] ||= 'production'
|
|
11
12
|
ENV['RAILS_LOG_TO_STDOUT'] ||= '1'
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
$service_route_prefix = resolve_service_route_prefix
|
|
16
|
+
|
|
17
|
+
def rack_handler(httpMethod, path, body, headers, script_name = '')
|
|
14
18
|
require 'rack'
|
|
15
19
|
|
|
16
20
|
app, _ = Rack::Builder.parse_file($entrypoint)
|
|
17
21
|
server = Rack::MockRequest.new app
|
|
18
22
|
|
|
19
23
|
env = headers.transform_keys { |k| k.split('-').join('_').prepend('HTTP_').upcase }
|
|
24
|
+
env['SCRIPT_NAME'] = script_name unless script_name.empty?
|
|
20
25
|
res = server.request(httpMethod, path, env.merge({ :input => body }))
|
|
21
26
|
|
|
22
27
|
{
|
|
@@ -96,8 +101,13 @@ def vc__handler(event:, context:)
|
|
|
96
101
|
body = Base64.decode64(body)
|
|
97
102
|
end
|
|
98
103
|
|
|
104
|
+
path, script_name = apply_service_route_prefix_to_target(
|
|
105
|
+
path,
|
|
106
|
+
$service_route_prefix
|
|
107
|
+
)
|
|
108
|
+
|
|
99
109
|
if $entrypoint.end_with? '.ru'
|
|
100
|
-
return rack_handler(httpMethod, path, body, headers)
|
|
110
|
+
return rack_handler(httpMethod, path, body, headers, script_name)
|
|
101
111
|
end
|
|
102
112
|
|
|
103
113
|
return webrick_handler(httpMethod, path, body, headers)
|
package/vc_init_dev.rb
CHANGED
|
@@ -10,12 +10,14 @@ require 'rack'
|
|
|
10
10
|
require 'rack/handler/webrick'
|
|
11
11
|
require 'webrick'
|
|
12
12
|
require 'socket'
|
|
13
|
+
require_relative 'vc__utils__ruby'
|
|
13
14
|
|
|
14
15
|
$stdout.sync = true
|
|
15
16
|
$stderr.sync = true
|
|
16
17
|
|
|
17
18
|
USER_ENTRYPOINT = "__VC_DEV_ENTRYPOINT__"
|
|
18
19
|
PUBLIC_DIR = 'public'
|
|
20
|
+
SERVICE_ROUTE_PREFIX = resolve_service_route_prefix
|
|
19
21
|
|
|
20
22
|
def build_user_app
|
|
21
23
|
if USER_ENTRYPOINT.end_with?('.ru')
|
|
@@ -36,17 +38,33 @@ class StaticThenApp
|
|
|
36
38
|
end
|
|
37
39
|
|
|
38
40
|
def call(env)
|
|
39
|
-
|
|
41
|
+
effective_env = env.dup
|
|
42
|
+
req_path, matched_prefix = strip_service_route_prefix(
|
|
43
|
+
effective_env['PATH_INFO'] || '/',
|
|
44
|
+
SERVICE_ROUTE_PREFIX
|
|
45
|
+
)
|
|
46
|
+
effective_env['PATH_INFO'] = req_path
|
|
47
|
+
|
|
48
|
+
unless matched_prefix.empty?
|
|
49
|
+
script_name = effective_env['SCRIPT_NAME'] || ''
|
|
50
|
+
if !script_name.empty? && script_name != '/'
|
|
51
|
+
script_name = script_name.sub(%r{/+\z}, '')
|
|
52
|
+
else
|
|
53
|
+
script_name = ''
|
|
54
|
+
end
|
|
55
|
+
effective_env['SCRIPT_NAME'] = "#{script_name}#{matched_prefix}"
|
|
56
|
+
end
|
|
57
|
+
|
|
40
58
|
# Normalize path and guard against traversal
|
|
41
59
|
safe = req_path.sub(/^\//, '')
|
|
42
60
|
full = File.expand_path(safe, @base)
|
|
43
61
|
|
|
44
62
|
if full.start_with?(@base + File::SEPARATOR) && File.file?(full)
|
|
45
63
|
# Delegate to Rack::File which handles HEAD/GET correctly
|
|
46
|
-
return @file_server.call(
|
|
64
|
+
return @file_server.call(effective_env)
|
|
47
65
|
end
|
|
48
66
|
|
|
49
|
-
@app.call(
|
|
67
|
+
@app.call(effective_env)
|
|
50
68
|
end
|
|
51
69
|
end
|
|
52
70
|
|
package/vc_utils.rb
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
|
|
3
|
+
# Normalize a configured service prefix into canonical mount-path form.
|
|
4
|
+
#
|
|
5
|
+
# Returns an empty string when unset/blank/root ("/"), otherwise:
|
|
6
|
+
# - always starts with "/"
|
|
7
|
+
# - has no trailing slash
|
|
8
|
+
def normalize_service_route_prefix(raw_prefix)
|
|
9
|
+
return '' if raw_prefix.nil?
|
|
10
|
+
|
|
11
|
+
prefix = raw_prefix.strip
|
|
12
|
+
return '' if prefix.empty?
|
|
13
|
+
|
|
14
|
+
prefix = "/#{prefix}" unless prefix.start_with?('/')
|
|
15
|
+
|
|
16
|
+
if prefix != '/'
|
|
17
|
+
prefix = prefix.sub(%r{/+\z}, '')
|
|
18
|
+
prefix = '/' if prefix.empty?
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
prefix == '/' ? '' : prefix
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Return whether service-prefix stripping is explicitly enabled.
|
|
25
|
+
#
|
|
26
|
+
# Stripping is gated behind a dedicated env var so manually configured
|
|
27
|
+
# route prefixes can be preserved by default.
|
|
28
|
+
def service_route_prefix_strip_enabled?
|
|
29
|
+
raw = ENV['VERCEL_SERVICE_ROUTE_PREFIX_STRIP']
|
|
30
|
+
return false if raw.nil? || raw.empty?
|
|
31
|
+
|
|
32
|
+
%w[1 true].include?(raw.downcase)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def resolve_service_route_prefix
|
|
36
|
+
return '' unless service_route_prefix_strip_enabled?
|
|
37
|
+
|
|
38
|
+
normalize_service_route_prefix(ENV['VERCEL_SERVICE_ROUTE_PREFIX'])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Split an HTTP request-target into [path, query].
|
|
42
|
+
#
|
|
43
|
+
# Supports:
|
|
44
|
+
# - origin-form: "/a/b?x=1"
|
|
45
|
+
# - absolute-form: "https://example.com/a/b?x=1"
|
|
46
|
+
# - asterisk-form: "*"
|
|
47
|
+
def split_request_target(target)
|
|
48
|
+
return ['/', ''] if target.nil? || target.empty?
|
|
49
|
+
|
|
50
|
+
begin
|
|
51
|
+
parsed = URI.parse(target)
|
|
52
|
+
if parsed.scheme && parsed.host
|
|
53
|
+
path = parsed.path.nil? || parsed.path.empty? ? '/' : parsed.path
|
|
54
|
+
return [path, parsed.query.to_s]
|
|
55
|
+
end
|
|
56
|
+
rescue URI::InvalidURIError
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
return ['*', ''] if target == '*'
|
|
60
|
+
|
|
61
|
+
path, query = target.split('?', 2)
|
|
62
|
+
path = '/' if path.nil? || path.empty?
|
|
63
|
+
path = "/#{path}" unless path.start_with?('/')
|
|
64
|
+
[path, query.to_s]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Strip the configured service route prefix from a request path.
|
|
68
|
+
#
|
|
69
|
+
# Returns:
|
|
70
|
+
# - stripped path passed to the user app
|
|
71
|
+
# - matched mount prefix (empty when no prefix matched)
|
|
72
|
+
def strip_service_route_prefix(path, prefix)
|
|
73
|
+
return [path, ''] if path == '*'
|
|
74
|
+
|
|
75
|
+
normalized_path = path.nil? || path.empty? ? '/' : path
|
|
76
|
+
normalized_path = "/#{normalized_path}" unless normalized_path.start_with?('/')
|
|
77
|
+
|
|
78
|
+
normalized_prefix = prefix.to_s
|
|
79
|
+
return [normalized_path, ''] if normalized_prefix.empty?
|
|
80
|
+
|
|
81
|
+
return ['/', normalized_prefix] if normalized_path == normalized_prefix
|
|
82
|
+
|
|
83
|
+
if normalized_path.start_with?("#{normalized_prefix}/")
|
|
84
|
+
stripped = normalized_path[normalized_prefix.length..]
|
|
85
|
+
return [stripped.nil? || stripped.empty? ? '/' : stripped, normalized_prefix]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
[normalized_path, '']
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Apply service-prefix stripping to a full request-target.
|
|
92
|
+
#
|
|
93
|
+
# Returns:
|
|
94
|
+
# - updated request-target (path + optional query)
|
|
95
|
+
# - matched mount prefix for Rack SCRIPT_NAME (or "")
|
|
96
|
+
def apply_service_route_prefix_to_target(target, prefix)
|
|
97
|
+
path, query = split_request_target(target)
|
|
98
|
+
path, script_name = strip_service_route_prefix(path, prefix)
|
|
99
|
+
updated = query.empty? ? path : "#{path}?#{query}"
|
|
100
|
+
[updated, script_name]
|
|
101
|
+
end
|