aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/analytics/analytics_schema.zig317
-rw-r--r--src/analytics/analytics_thread.zig157
-rw-r--r--src/analytics/schema.peechy4
-rw-r--r--src/bundler.zig26
-rw-r--r--src/env.zig2
-rw-r--r--src/env_loader.zig11
-rw-r--r--src/feature_flags.zig5
-rw-r--r--src/http.zig21
-rw-r--r--src/javascript/jsc/javascript.zig2
-rw-r--r--src/options.zig14
10 files changed, 415 insertions, 144 deletions
diff --git a/src/analytics/analytics_schema.zig b/src/analytics/analytics_schema.zig
index 917422ba5..08cecd8b3 100644
--- a/src/analytics/analytics_schema.zig
+++ b/src/analytics/analytics_schema.zig
@@ -1,3 +1,4 @@
+
const std = @import("std");
pub const Reader = struct {
@@ -281,193 +282,229 @@ pub fn Writer(comptime WritableStream: type) type {
pub const ByteWriter = Writer(*std.io.FixedBufferStream([]u8));
pub const FileWriter = Writer(std.fs.File);
-pub const analytics = struct {
- pub const OperatingSystem = enum(u8) {
- _none,
- /// linux
- linux,
- /// macos
- macos,
- /// windows
- windows,
- /// wsl
- wsl,
+pub const analytics = struct {
- _,
+pub const OperatingSystem = enum(u8) {
- pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
- return try std.json.stringify(@tagName(self), opts, o);
- }
- };
+_none,
+ /// linux
+ linux,
- pub const Architecture = enum(u8) {
- _none,
- /// x64
- x64,
+ /// macos
+ macos,
- /// arm
- arm,
+ /// windows
+ windows,
- _,
+ /// wsl
+ wsl,
- pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
- return try std.json.stringify(@tagName(self), opts, o);
- }
- };
+_,
- pub const Platform = struct {
- /// os
- os: OperatingSystem,
+ pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
+ return try std.json.stringify(@tagName(self), opts, o);
+ }
- /// arch
- arch: Architecture,
+
+};
- /// version
- version: []const u8,
+pub const Architecture = enum(u8) {
- pub fn decode(reader: anytype) anyerror!Platform {
- var this = std.mem.zeroes(Platform);
+_none,
+ /// x64
+ x64,
- this.os = try reader.readValue(OperatingSystem);
- this.arch = try reader.readValue(Architecture);
- this.version = try reader.readArray(u8);
- return this;
- }
+ /// arm
+ arm,
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeEnum(this.os);
- try writer.writeEnum(this.arch);
- try writer.writeArray(u8, this.version);
- }
- };
+_,
- pub const EventKind = enum(u32) {
- _none,
- /// bundle_success
- bundle_success,
+ pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
+ return try std.json.stringify(@tagName(self), opts, o);
+ }
- /// bundle_fail
- bundle_fail,
+
+};
- /// http_start
- http_start,
+pub const Platform = struct {
+/// os
+os: OperatingSystem,
- /// http_build
- http_build,
+/// arch
+arch: Architecture,
- /// bundle_start
- bundle_start,
+/// version
+version: []const u8,
- _,
- pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
- return try std.json.stringify(@tagName(self), opts, o);
- }
- };
+pub fn decode(reader: anytype) anyerror!Platform {
+ var this = std.mem.zeroes(Platform);
- pub const Uint64 = packed struct {
- /// first
- first: u32 = 0,
+ this.os = try reader.readValue(OperatingSystem);
+ this.arch = try reader.readValue(Architecture);
+ this.version = try reader.readArray(u8);
+ return this;
+}
- /// second
- second: u32 = 0,
+pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeEnum(this.os);
+ try writer.writeEnum(this.arch);
+ try writer.writeArray(u8, this.version);
+}
- pub fn decode(reader: anytype) anyerror!Uint64 {
- var this = std.mem.zeroes(Uint64);
+};
- this.first = try reader.readValue(u32);
- this.second = try reader.readValue(u32);
- return this;
- }
+pub const EventKind = enum(u32) {
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeInt(this.first);
- try writer.writeInt(this.second);
- }
- };
+_none,
+ /// bundle_success
+ bundle_success,
- pub const EventListHeader = struct {
- /// machine_id
- machine_id: Uint64,
+ /// bundle_fail
+ bundle_fail,
- /// session_id
- session_id: u32 = 0,
+ /// http_start
+ http_start,
- /// platform
- platform: Platform,
+ /// http_build
+ http_build,
- /// build_id
- build_id: u32 = 0,
+ /// bundle_start
+ bundle_start,
- /// session_length
- session_length: u32 = 0,
+_,
- pub fn decode(reader: anytype) anyerror!EventListHeader {
- var this = std.mem.zeroes(EventListHeader);
+ pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void {
+ return try std.json.stringify(@tagName(self), opts, o);
+ }
- this.machine_id = try reader.readValue(Uint64);
- this.session_id = try reader.readValue(u32);
- this.platform = try reader.readValue(Platform);
- this.build_id = try reader.readValue(u32);
- this.session_length = try reader.readValue(u32);
- return this;
- }
+
+};
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeValue(this.machine_id);
- try writer.writeInt(this.session_id);
- try writer.writeValue(this.platform);
- try writer.writeInt(this.build_id);
- try writer.writeInt(this.session_length);
- }
- };
+pub const Uint64 = packed struct {
+/// first
+first: u32 = 0,
- pub const EventHeader = struct {
- /// timestamp
- timestamp: Uint64,
+/// second
+second: u32 = 0,
- /// kind
- kind: EventKind,
- pub fn decode(reader: anytype) anyerror!EventHeader {
- var this = std.mem.zeroes(EventHeader);
+pub fn decode(reader: anytype) anyerror!Uint64 {
+ var this = std.mem.zeroes(Uint64);
- this.timestamp = try reader.readValue(Uint64);
- this.kind = try reader.readValue(EventKind);
- return this;
- }
+ this.first = try reader.readValue(u32);
+ this.second = try reader.readValue(u32);
+ return this;
+}
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeValue(this.timestamp);
- try writer.writeEnum(this.kind);
- }
- };
+pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeInt(this.first);
+ try writer.writeInt(this.second);
+}
- pub const EventList = struct {
- /// header
- header: EventListHeader,
+};
- /// event_count
- event_count: u32 = 0,
+pub const EventListHeader = struct {
+/// machine_id
+machine_id: Uint64,
- pub fn decode(reader: anytype) anyerror!EventList {
- var this = std.mem.zeroes(EventList);
+/// session_id
+session_id: u32 = 0,
- this.header = try reader.readValue(EventListHeader);
- this.event_count = try reader.readValue(u32);
- return this;
- }
+/// platform
+platform: Platform,
+
+/// build_id
+build_id: u32 = 0,
+
+/// project_id
+project_id: Uint64,
+
+/// session_length
+session_length: u32 = 0,
+
+/// feature_usage
+feature_usage: u32 = 0,
+
+
+pub fn decode(reader: anytype) anyerror!EventListHeader {
+ var this = std.mem.zeroes(EventListHeader);
+
+ this.machine_id = try reader.readValue(Uint64);
+ this.session_id = try reader.readValue(u32);
+ this.platform = try reader.readValue(Platform);
+ this.build_id = try reader.readValue(u32);
+ this.project_id = try reader.readValue(Uint64);
+ this.session_length = try reader.readValue(u32);
+ this.feature_usage = try reader.readValue(u32);
+ return this;
+}
+
+pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeValue(this.machine_id);
+ try writer.writeInt(this.session_id);
+ try writer.writeValue(this.platform);
+ try writer.writeInt(this.build_id);
+ try writer.writeValue(this.project_id);
+ try writer.writeInt(this.session_length);
+ try writer.writeInt(this.feature_usage);
+}
+
+};
+
+pub const EventHeader = struct {
+/// timestamp
+timestamp: Uint64,
+
+/// kind
+kind: EventKind,
+
+
+pub fn decode(reader: anytype) anyerror!EventHeader {
+ var this = std.mem.zeroes(EventHeader);
+
+ this.timestamp = try reader.readValue(Uint64);
+ this.kind = try reader.readValue(EventKind);
+ return this;
+}
+
+pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeValue(this.timestamp);
+ try writer.writeEnum(this.kind);
+}
- pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
- try writer.writeValue(this.header);
- try writer.writeInt(this.event_count);
- }
- };
};
+pub const EventList = struct {
+/// header
+header: EventListHeader,
+
+/// event_count
+event_count: u32 = 0,
+
+
+pub fn decode(reader: anytype) anyerror!EventList {
+ var this = std.mem.zeroes(EventList);
+
+ this.header = try reader.readValue(EventListHeader);
+ this.event_count = try reader.readValue(u32);
+ return this;
+}
+
+pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
+ try writer.writeValue(this.header);
+ try writer.writeInt(this.event_count);
+}
+
+};
+
+
+};
+
+
const ExamplePackedStruct = packed struct {
len: u32 = 0,
offset: u32 = 0,
diff --git a/src/analytics/analytics_thread.zig b/src/analytics/analytics_thread.zig
index 5484c3c0f..434bc0c7d 100644
--- a/src/analytics/analytics_thread.zig
+++ b/src/analytics/analytics_thread.zig
@@ -9,6 +9,124 @@ const Analytics = @import("./analytics_schema.zig").analytics;
const Writer = @import("./analytics_schema.zig").Writer;
const Headers = @import("../javascript/jsc/webcore/response.zig").Headers;
+fn NewUint64(val: u64) Analytics.Uint64 {
+ const bytes = std.mem.asBytes(&val);
+ return .{
+ .first = std.mem.readIntNative(u32, bytes[0..4]),
+ .second = std.mem.readIntNative(u32, bytes[4..]),
+ };
+}
+
+// This answers, "What parts of Bun are people actually using?"
+pub const Features = struct {
+ pub var single_page_app_routing = false;
+ pub var tsconfig_paths = false;
+ pub var fast_refresh = false;
+ pub var hot_module_reloading = false;
+ pub var jsx = false;
+ pub var always_bundle = false;
+ pub var tsconfig = false;
+ pub var bun_bun = false;
+ pub var filesystem_router = false;
+ pub var framework = false;
+ pub var bunjs = false;
+ pub var macros = false;
+ pub var public_folder = false;
+ pub var dotenv = false;
+ pub var define = false;
+ pub var loaders = false;
+ pub var origin = false;
+ pub var external = false;
+ pub var fetch = false;
+
+ const Bitset = std.bit_set.IntegerBitSet(32);
+
+ pub const Serializer = struct {
+ inline fn shiftIndex(index: u32) !u32 {
+ return @intCast(u32, @as(Bitset.MaskInt, 1) << @intCast(Bitset.ShiftInt, index));
+ }
+
+ fn writeField(comptime WriterType: type, writer: WriterType, field_name: string, index: u32) !void {
+ var output: [64]u8 = undefined;
+ const name = std.ascii.upperString(&output, field_name);
+
+ try writer.print("const Features_{s} = {d}\n", .{ name, shiftIndex(index) });
+ }
+
+ pub fn writeAll(comptime WriterType: type, writer: WriterType) !void {
+ try writer.writeAll("package analytics\n\n");
+ try writeField(WriterType, writer, "single_page_app_routing", 1);
+ try writeField(WriterType, writer, "tsconfig_paths", 2);
+ try writeField(WriterType, writer, "fast_refresh", 3);
+ try writeField(WriterType, writer, "hot_module_reloading", 4);
+ try writeField(WriterType, writer, "jsx", 5);
+ try writeField(WriterType, writer, "always_bundle", 6);
+ try writeField(WriterType, writer, "tsconfig", 7);
+ try writeField(WriterType, writer, "bun_bun", 8);
+ try writeField(WriterType, writer, "filesystem_router", 9);
+ try writeField(WriterType, writer, "framework", 10);
+ try writeField(WriterType, writer, "bunjs", 11);
+ try writeField(WriterType, writer, "macros", 12);
+ try writeField(WriterType, writer, "public_folder", 13);
+ try writeField(WriterType, writer, "dotenv", 14);
+ try writeField(WriterType, writer, "define", 15);
+ try writeField(WriterType, writer, "loaders", 16);
+ try writeField(WriterType, writer, "origin", 17);
+ try writeField(WriterType, writer, "external", 18);
+ try writeField(WriterType, writer, "fetch", 19);
+ try writer.writeAll("\n");
+ }
+ };
+
+ pub fn toInt() u32 {
+ var list = Bitset.initEmpty();
+ list.setValue(1, Features.single_page_app_routing);
+ list.setValue(2, Features.tsconfig_paths);
+ list.setValue(3, Features.fast_refresh);
+ list.setValue(4, Features.hot_module_reloading);
+ list.setValue(5, Features.jsx);
+ list.setValue(6, Features.always_bundle);
+ list.setValue(7, Features.tsconfig);
+ list.setValue(8, Features.bun_bun);
+ list.setValue(9, Features.filesystem_router);
+ list.setValue(10, Features.framework);
+ list.setValue(11, Features.bunjs);
+ list.setValue(12, Features.macros);
+ list.setValue(13, Features.public_folder);
+ list.setValue(14, Features.dotenv);
+ list.setValue(15, Features.define);
+ list.setValue(16, Features.loaders);
+ list.setValue(17, Features.origin);
+ list.setValue(18, Features.external);
+ list.setValue(19, Features.fetch);
+
+ if (comptime FeatureFlags.verbose_analytics) {
+ if (Features.single_page_app_routing) Output.pretty("<r><d>single_page_app_routing<r>,", .{});
+ if (Features.tsconfig_paths) Output.pretty("<r><d>tsconfig_paths<r>,", .{});
+ if (Features.fast_refresh) Output.pretty("<r><d>fast_refresh<r>,", .{});
+ if (Features.hot_module_reloading) Output.pretty("<r><d>hot_module_reloading<r>,", .{});
+ if (Features.jsx) Output.pretty("<r><d>jsx<r>,", .{});
+ if (Features.always_bundle) Output.pretty("<r><d>always_bundle<r>,", .{});
+ if (Features.tsconfig) Output.pretty("<r><d>tsconfig<r>,", .{});
+ if (Features.bun_bun) Output.pretty("<r><d>bun_bun<r>,", .{});
+ if (Features.filesystem_router) Output.pretty("<r><d>filesystem_router<r>,", .{});
+ if (Features.framework) Output.pretty("<r><d>framework<r>,", .{});
+ if (Features.bunjs) Output.pretty("<r><d>bunjs<r>,", .{});
+ if (Features.macros) Output.pretty("<r><d>macros<r>,", .{});
+ if (Features.public_folder) Output.pretty("<r><d>public_folder<r>,", .{});
+ if (Features.dotenv) Output.pretty("<r><d>dotenv<r>,", .{});
+ if (Features.define) Output.pretty("<r><d>define<r>,", .{});
+ if (Features.loaders) Output.pretty("<r><d>loaders<r>,", .{});
+ if (Features.origin) Output.pretty("<r><d>origin<r>,", .{});
+ if (Features.external) Output.pretty("<r><d>external<r>,", .{});
+ if (Features.fetch) Output.pretty("<r><d>fetch<r>,", .{});
+ Output.prettyln("\n", .{});
+ }
+
+ return @as(u32, list.mask);
+ }
+};
+
pub const EventName = enum(u8) {
bundle_success,
bundle_fail,
@@ -21,6 +139,7 @@ var random: std.rand.DefaultPrng = undefined;
const DotEnv = @import("../env_loader.zig");
const platform_arch = if (Environment.isAarch64) Analytics.Architecture.arm else Analytics.Architecture.x64;
+var project_id: Analytics.Uint64 = .{};
pub const Event = struct {
timestamp: u64,
@@ -58,12 +177,19 @@ var event_queue: EventQueue = undefined;
pub const GenerateHeader = struct {
pub fn generate() Analytics.EventListHeader {
+ if (comptime isDebug) {
+ if (project_id.first == 0 and project_id.second == 0) {
+ Output.prettyErrorln("warn: project_id is 0", .{});
+ }
+ }
+
if (Environment.isMac) {
return Analytics.EventListHeader{
.machine_id = GenerateMachineID.forMac() catch Analytics.Uint64{},
.platform = GeneratePlatform.forMac(),
.build_id = comptime @truncate(u32, Global.build_id),
.session_id = random.random.int(u32),
+ .project_id = project_id,
};
}
@@ -73,6 +199,7 @@ pub const GenerateHeader = struct {
.platform = GeneratePlatform.forLinux(),
.build_id = comptime @truncate(u32, Global.build_id),
.session_id = random.random.int(u32),
+ .project_id = project_id,
};
}
@@ -292,6 +419,7 @@ pub const EventList = struct {
const now = std.time.nanoTimestamp();
this.header.session_length = @truncate(u32, @intCast(u64, (now - start_time)) / std.time.ns_per_ms);
+ this.header.feature_usage = Features.toInt();
var list = Analytics.EventList{
.header = this.header,
@@ -372,3 +500,32 @@ pub const EventList = struct {
};
pub var is_ci = false;
+
+pub var username_only_for_determining_project_id_and_never_sent: string = "";
+pub fn setProjectID(folder_name_: string, package_name: string) void {
+ if (disabled) return;
+
+ var hasher = std.hash.Wyhash.init(10);
+
+ var folder_name = folder_name_;
+
+ // The idea here is
+ // When you're working at a mid-large company
+ // Basically everyone has standardized laptops
+ // The hardware may differ, but the folder structure is typically identical
+ // But the username or home folder may differ
+ // So when we hash, we skip that if it exists
+ if (username_only_for_determining_project_id_and_never_sent.len > 0) {
+ if (std.mem.indexOf(u8, folder_name, username_only_for_determining_project_id_and_never_sent)) |i| {
+ const offset = i + username_only_for_determining_project_id_and_never_sent.len + 1;
+ if (folder_name.len > offset) {
+ folder_name = folder_name[offset..];
+ }
+ }
+ }
+ hasher.update(folder_name);
+ hasher.update("@");
+ if (package_name.len > 0) hasher.update(package_name);
+ if (package_name.len == 0) hasher.update("\"\"");
+ project_id = NewUint64(hasher.final());
+}
diff --git a/src/analytics/schema.peechy b/src/analytics/schema.peechy
index 0caad6615..6d924cf09 100644
--- a/src/analytics/schema.peechy
+++ b/src/analytics/schema.peechy
@@ -36,7 +36,11 @@ struct EventListHeader {
uint32 session_id;
Platform platform;
uint32 build_id;
+ // hash of the folder name
+ Uint64 project_id;
uint32 session_length;
+ // enum flags
+ uint32 feature_usage;
}
struct EventHeader {
diff --git a/src/bundler.zig b/src/bundler.zig
index f2487502f..f348230f9 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -772,6 +772,8 @@ pub const Bundler = struct {
bundler.resolver.debug_logs = try DebugLogs.init(allocator);
}
+ Analytics.Features.bun_bun = true;
+
always_bundled: {
const root_package_json_resolved: _resolver.Result = bundler.resolver.resolve(bundler.fs.top_level_dir, "./package.json", .stmt) catch |err| {
generator.log.addWarning(null, logger.Loc.Empty, "Please run `bun bun` from a directory containing a package.json.") catch unreachable;
@@ -779,9 +781,14 @@ pub const Bundler = struct {
};
const root_package_json = root_package_json_resolved.package_json orelse brk: {
const read_dir = (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch unreachable).?;
+ Analytics.Features.tsconfig = Analytics.Features.tsconfig or read_dir.tsconfig_json != null;
break :brk read_dir.package_json.?;
};
+ Analytics.setProjectID(std.fs.path.dirname(root_package_json.source.path.text) orelse "/", root_package_json.name);
+ Analytics.Features.macros = Analytics.Features.macros or root_package_json.macros.count() > 0;
+
if (root_package_json.always_bundle.len > 0) {
+ Analytics.Features.always_bundle = true;
var always_bundled_package_jsons = bundler.allocator.alloc(*PackageJSON, root_package_json.always_bundle.len) catch unreachable;
var always_bundled_package_hashes = bundler.allocator.alloc(u32, root_package_json.always_bundle.len) catch unreachable;
var i: u16 = 0;
@@ -838,6 +845,8 @@ pub const Bundler = struct {
this.bundler.options.jsx.supports_fast_refresh and
bundler.options.platform.isWebLike();
+ Analytics.Features.fast_refresh = this.bundler.options.jsx.supports_fast_refresh;
+
const resolve_queue_estimate = bundler.options.entry_points.len +
@intCast(usize, @boolToInt(framework_config != null)) +
@intCast(usize, @boolToInt(include_refresh_runtime)) +
@@ -845,6 +854,7 @@ pub const Bundler = struct {
if (bundler.router) |router| {
defer this.bundler.resetStore();
+ Analytics.Features.filesystem_router = true;
const entry_points = try router.getEntryPoints(allocator);
for (entry_points) |entry_point| {
@@ -870,6 +880,8 @@ pub const Bundler = struct {
try this.bundler.configureFramework(true);
if (bundler.options.framework) |framework| {
+ Analytics.Features.framework = true;
+
if (framework.override_modules.keys.len > 0) {
bundler.options.framework.?.override_modules_hashes = allocator.alloc(u64, framework.override_modules.keys.len) catch unreachable;
for (framework.override_modules.keys) |key, i| {
@@ -878,6 +890,7 @@ pub const Bundler = struct {
}
if (bundler.options.platform.isBun()) {
if (framework.server.isEnabled()) {
+ Analytics.Features.bunjs = true;
const resolved = try bundler.linker.resolver.resolve(
bundler.fs.top_level_dir,
framework.server.path,
@@ -938,8 +951,17 @@ pub const Bundler = struct {
this.bundler.resetStore();
- try this.pool.start(this);
- try this.pool.wait(this);
+ if (bundler.options.platform != .bun) Analytics.enqueue(Analytics.EventName.bundle_start);
+ this.pool.start(this) catch |err| {
+ Analytics.enqueue(Analytics.EventName.bundle_fail);
+ return err;
+ };
+ this.pool.wait(this) catch |err| {
+ Analytics.enqueue(Analytics.EventName.bundle_fail);
+ return err;
+ };
+ if (bundler.options.platform != .bun) Analytics.enqueue(Analytics.EventName.bundle_success);
+
estimated_input_lines_of_code.* = generator.estimated_input_lines_of_code;
// if (comptime !isRelease) {
diff --git a/src/env.zig b/src/env.zig
index 351b295b2..4dd26d56b 100644
--- a/src/env.zig
+++ b/src/env.zig
@@ -23,4 +23,4 @@ pub const isTest = std.builtin.is_test;
pub const isLinux = std.Target.current.os.tag == .linux;
pub const isAarch64 = std.Target.current.cpu.arch == .aarch64;
-pub const analytics_url = "http://localhost:4000/events";
+pub const analytics_url = if (isDebug) "http://localhost:4000/events" else "http://i.bun.sh/events";
diff --git a/src/env_loader.zig b/src/env_loader.zig
index 3be39003b..7b1acdc95 100644
--- a/src/env_loader.zig
+++ b/src/env_loader.zig
@@ -2,6 +2,7 @@ const std = @import("std");
const logger = @import("./logger.zig");
usingnamespace @import("./global.zig");
const CodepointIterator = @import("./string_immutable.zig").CodepointIterator;
+const Analytics = @import("./analytics/analytics_thread.zig");
const Fs = @import("./fs.zig");
const Api = @import("./api/schema.zig").Api;
const Variable = struct {
@@ -461,6 +462,12 @@ pub const Loader = struct {
Parser.parse(&source, this.allocator, this.map, true);
}
this.did_load_process = true;
+
+ if (this.map.get("HOME")) |home_folder| {
+ Analytics.username_only_for_determining_project_id_and_never_sent = home_folder;
+ } else if (this.map.get("USER")) |home_folder| {
+ Analytics.username_only_for_determining_project_id_and_never_sent = home_folder;
+ }
}
// mostly for tests
@@ -486,20 +493,24 @@ pub const Loader = struct {
if (dir.hasComptimeQuery(".env.local")) {
try this.loadEnvFile(fs, dir_handle, ".env.local", false);
+ Analytics.Features.dotenv = true;
}
if (comptime development) {
if (dir.hasComptimeQuery(".env.development")) {
try this.loadEnvFile(fs, dir_handle, ".env.development", false);
+ Analytics.Features.dotenv = true;
}
} else {
if (dir.hasComptimeQuery(".env.production")) {
try this.loadEnvFile(fs, dir_handle, ".env.production", false);
+ Analytics.Features.dotenv = true;
}
}
if (dir.hasComptimeQuery(".env")) {
try this.loadEnvFile(fs, dir_handle, ".env", false);
+ Analytics.Features.dotenv = true;
}
this.printLoaded(start);
diff --git a/src/feature_flags.zig b/src/feature_flags.zig
index a132d0642..777753561 100644
--- a/src/feature_flags.zig
+++ b/src/feature_flags.zig
@@ -70,7 +70,10 @@ pub const auto_import_buffer = false;
pub const is_macro_enabled = true;
+// pretend everything is always the macro environment
+// useful for debugging the macro's JSX transform
pub const force_macro = false;
+
pub const include_filename_in_jsx = false;
-pub const verbose_analytics = true;
+pub const verbose_analytics = false;
diff --git a/src/http.zig b/src/http.zig
index a9b0c14a3..0baa3b3b5 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -1556,6 +1556,7 @@ pub const RequestContext = struct {
try ctx.flushHeaders();
// Output.prettyln("<r><green>101<r><d> Hot Module Reloading connected.<r>", .{});
// Output.flush();
+ Analytics.Features.hot_module_reloading = true;
var cmd: Api.WebsocketCommand = undefined;
var msg: Api.WebsocketMessage = .{
@@ -2682,6 +2683,11 @@ pub const Server = struct {
Output.flush();
+ Analytics.Features.bun_bun = server.bundler.options.node_modules_bundle != null;
+ Analytics.Features.framework = server.bundler.options.framework != null;
+ Analytics.Features.filesystem_router = server.bundler.router != null;
+ Analytics.Features.bunjs = server.transform_options.node_modules_bundle_path_server != null;
+
var did_init = false;
while (!did_init) {
defer Output.flush();
@@ -2692,6 +2698,7 @@ pub const Server = struct {
// We want to bind to the network socket as quickly as possible so that opening the URL works
// We use a secondary loop so that we avoid the extra branch in a hot code path
server.detectFastRefresh();
+ Analytics.Features.fast_refresh = server.bundler.options.jsx.supports_fast_refresh;
server.detectTSConfig();
try server.initWatcher();
did_init = true;
@@ -2977,8 +2984,20 @@ pub const Server = struct {
defer this.bundler.resetStore();
const dir_info = (this.bundler.resolver.readDirInfo(this.bundler.fs.top_level_dir) catch return) orelse return;
+
+ if (dir_info.package_json) |pkg| {
+ Analytics.Features.macros = Analytics.Features.macros or pkg.macros.count() > 0;
+ Analytics.Features.always_bundle = pkg.always_bundle.len > 0;
+ Analytics.setProjectID(dir_info.abs_path, pkg.name);
+ } else {
+ Analytics.setProjectID(dir_info.abs_path, "");
+ }
+
const tsconfig = dir_info.tsconfig_json orelse return;
+ Analytics.Features.tsconfig = true;
+
serve_as_package_path = tsconfig.base_url_for_paths.len > 0 or tsconfig.base_url.len > 0;
+ Analytics.Features.tsconfig_paths = tsconfig.paths.count() > 0;
}
pub var global_start_time: std.time.Timer = undefined;
@@ -2999,6 +3018,8 @@ pub const Server = struct {
server.bundler.configureLinker();
try server.bundler.configureRouter(true);
+ Analytics.Features.filesystem_router = server.bundler.router != null;
+
const public_folder_is_top_level = server.bundler.options.routes.static_dir_enabled and strings.eql(
server.bundler.fs.top_level_dir,
server.bundler.options.routes.static_dir,
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index f15fc08f5..d693bad68 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -16,6 +16,7 @@ const js_ast = @import("../../js_ast.zig");
const hash_map = @import("../../hash_map.zig");
const http = @import("../../http.zig");
const ImportKind = ast.ImportKind;
+const Analytics = @import("../../analytics/analytics_thread.zig");
usingnamespace @import("./node_env_buf_map.zig");
usingnamespace @import("./base.zig");
usingnamespace @import("./webcore/response.zig");
@@ -579,6 +580,7 @@ pub const VirtualMachine = struct {
pub fn enableMacroMode(this: *VirtualMachine) void {
this.bundler.options.platform = .bun_macro;
this.macro_mode = true;
+ Analytics.Features.macros = true;
}
pub fn disableMacroMode(this: *VirtualMachine) void {
diff --git a/src/options.zig b/src/options.zig
index d6c96034c..e734a59e6 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -14,6 +14,8 @@ const URL = @import("./query_string_map.zig").URL;
const ConditionsMap = @import("./resolver/package_json.zig").ESModule.ConditionsMap;
usingnamespace @import("global.zig");
+const Analytics = @import("./analytics/analytics_thread.zig");
+
const DotEnv = @import("./env_loader.zig");
const assert = std.debug.assert;
@@ -1034,6 +1036,9 @@ pub const BundleOptions = struct {
.transform_options = transform,
};
+ Analytics.Features.define = Analytics.Features.define or transform.define != null;
+ Analytics.Features.loaders = Analytics.Features.loaders or transform.loaders != null;
+
if (transform.origin) |origin| {
opts.origin = URL.parse(origin);
}
@@ -1324,6 +1329,15 @@ pub const BundleOptions = struct {
opts.polyfill_node_globals = opts.platform != .node;
+ Analytics.Features.framework = Analytics.Features.framework or opts.framework != null;
+ Analytics.Features.filesystem_router = Analytics.Features.filesystem_router or opts.routes.routes_enabled;
+ Analytics.Features.origin = Analytics.Features.origin or transform.origin != null;
+ Analytics.Features.public_folder = Analytics.Features.public_folder or opts.routes.static_dir_enabled;
+ Analytics.Features.bun_bun = Analytics.Features.bun_bun or transform.node_modules_bundle_path != null;
+ Analytics.Features.bunjs = Analytics.Features.bunjs or transform.node_modules_bundle_path_server != null;
+ Analytics.Features.macros = Analytics.Features.macros or opts.platform == .bun_macro;
+ Analytics.Features.external = Analytics.Features.external or transform.external.len > 0;
+ Analytics.Features.single_page_app_routing = Analytics.Features.single_page_app_routing or opts.routes.single_page_app_routing;
return opts;
}
};