mirror of
https://github.com/oven-sh/bun
synced 2026-02-18 23:01:58 +00:00
### What does this PR do?
Fixes a crash related to the dev server overwriting the uws user context
pointer when setting abort callback.
Adds support for `return new Response(<jsx />, { ... })` and `return
Response.render(...)` and `return Response.redirect(...)`:
- Created a `SSRResponse` class to handle this (see
`JSBakeResponse.{h,cpp}`)
- `SSRResponse` is designed to "fake" being a React component
- This is done in JSBakeResponse::create inside of
src/bun.js/bindings/JSBakeResponse.cpp
- And `src/js/builtins/BakeSSRResponse.ts` defines a `wrapComponent`
function which wraps
the passed in component (when doing `new Response(<jsx />, ...)`). It
does
this to throw an error (in redirect()/render() case) or return the
component.
- Created a `BakeAdditionsToGlobal` struct which contains some
properties
needed for this
- Added some of the properties we need to fake to BunBuiltinNames.h
(e.g.
`$$typeof`), the rationale behind this is that we couldn't use
`structure->addPropertyTransition` because JSBakeResponse is not a final
JSObject.
- When bake and server-side, bundler rewrites `Response ->
Bun.SSRResponse` (see `src/ast/P.zig` and `src/ast/visitExpr.zig`)
- Created a new WebCore body variant (`Render: struct { path: []const u8
}`)
- Created when `return Response.render(...)`
- When handled, it re-invokes dev server to render the new path
Enables server-side sourcemaps for the dev server:
- New source providers for server-side:
(`DevServerSourceProvider.{h,cpp}`)
- IncrementalGraph and SourceMapStore are updated to support this
There are numerous other stuff:
- allow `app` configuration from Bun.serve(...)
- fix errors stopping dev server
- fix use after free related to in
RequestContext.finishRunningErrorHandler
- Request.cookies
- Make `"use client";` components work
- Fix some bugs using `require(...)` in dev server
- Fix catch-all routes not working in the dev server
- Updates `findSourceMappingURL(...)` to use `std.mem.lastIndexOf(...)`
because
the sourcemap that should be used is the last one anyway
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Alistair Smith <hi@alistair.sh>
129 lines
4.6 KiB
Zig
129 lines
4.6 KiB
Zig
//! Web APIs implemented in Zig live here
|
|
|
|
comptime {
|
|
if (bun.Environment.export_cpp_apis) {
|
|
_ = &@import("./webcore/prompt.zig");
|
|
}
|
|
_ = &@import("./webcore/TextEncoder.zig");
|
|
}
|
|
|
|
pub const DOMExceptionCode = @import("./bindings/JSErrorCode.zig").DOMExceptionCode;
|
|
|
|
// TODO: make this JSGlobalObject local for better security
|
|
pub const ByteListPool = bun.ObjectPool(bun.ByteList, null, true, 8);
|
|
|
|
pub const Crypto = @import("./webcore/Crypto.zig");
|
|
pub const AbortSignal = @import("./bindings/AbortSignal.zig").AbortSignal;
|
|
pub const WebWorker = @import("./web_worker.zig");
|
|
pub const AutoFlusher = @import("./webcore/AutoFlusher.zig");
|
|
pub const EncodingLabel = @import("./webcore/EncodingLabel.zig").EncodingLabel;
|
|
pub const Fetch = @import("./webcore/fetch.zig");
|
|
pub const Response = @import("./webcore/Response.zig");
|
|
pub const BakeResponse = @import("./webcore/BakeResponse.zig");
|
|
pub const TextDecoder = @import("./webcore/TextDecoder.zig");
|
|
pub const TextEncoder = @import("./webcore/TextEncoder.zig");
|
|
pub const TextEncoderStreamEncoder = @import("./webcore/TextEncoderStreamEncoder.zig");
|
|
pub const encoding = @import("./webcore/encoding.zig");
|
|
pub const ReadableStream = @import("./webcore/ReadableStream.zig");
|
|
pub const Blob = @import("./webcore/Blob.zig");
|
|
pub const S3Stat = @import("./webcore/S3Stat.zig").S3Stat;
|
|
pub const ResumableFetchSink = @import("./webcore/ResumableSink.zig").ResumableFetchSink;
|
|
pub const ResumableS3UploadSink = @import("./webcore/ResumableSink.zig").ResumableS3UploadSink;
|
|
pub const ResumableSinkBackpressure = @import("./webcore/ResumableSink.zig").ResumableSinkBackpressure;
|
|
pub const S3Client = @import("./webcore/S3Client.zig").S3Client;
|
|
pub const Request = @import("./webcore/Request.zig");
|
|
pub const Body = @import("./webcore/Body.zig");
|
|
pub const CookieMap = @import("./webcore/CookieMap.zig").CookieMap;
|
|
pub const ObjectURLRegistry = @import("./webcore/ObjectURLRegistry.zig");
|
|
pub const Sink = @import("./webcore/Sink.zig");
|
|
pub const FileSink = @import("./webcore/FileSink.zig");
|
|
pub const FetchHeaders = @import("./bindings/FetchHeaders.zig").FetchHeaders;
|
|
pub const ByteBlobLoader = @import("./webcore/ByteBlobLoader.zig");
|
|
pub const ByteStream = @import("./webcore/ByteStream.zig");
|
|
pub const FileReader = @import("./webcore/FileReader.zig");
|
|
pub const ScriptExecutionContext = @import("./webcore/ScriptExecutionContext.zig");
|
|
|
|
pub const streams = @import("./webcore/streams.zig");
|
|
pub const NetworkSink = streams.NetworkSink;
|
|
pub const HTTPResponseSink = streams.HTTPResponseSink;
|
|
pub const HTTPSResponseSink = streams.HTTPSResponseSink;
|
|
pub const HTTPServerWritable = streams.HTTPServerWritable;
|
|
|
|
comptime {
|
|
WebSocketClient.exportAll();
|
|
WebSocketClientTLS.exportAll();
|
|
WebSocketHTTPClient.exportAll();
|
|
WebSocketHTTPSClient.exportAll();
|
|
}
|
|
|
|
pub const PathOrFileDescriptor = union(enum) {
|
|
path: jsc.ZigString.Slice,
|
|
fd: bun.FileDescriptor,
|
|
|
|
pub fn deinit(this: *const PathOrFileDescriptor) void {
|
|
if (this.* == .path) this.path.deinit();
|
|
}
|
|
};
|
|
|
|
pub const Pipe = struct {
|
|
ctx: ?*anyopaque = null,
|
|
onPipe: ?Function = null,
|
|
|
|
pub inline fn isEmpty(this: *const Pipe) bool {
|
|
return this.ctx == null and this.onPipe == null;
|
|
}
|
|
|
|
pub const Function = *const fn (
|
|
ctx: *anyopaque,
|
|
stream: streams.Result,
|
|
allocator: std.mem.Allocator,
|
|
) void;
|
|
|
|
pub fn Wrap(comptime Type: type, comptime function: anytype) type {
|
|
return struct {
|
|
pub fn pipe(self: *anyopaque, stream: streams.Result, allocator: std.mem.Allocator) void {
|
|
function(
|
|
@as(*Type, @ptrCast(@alignCast(self))),
|
|
stream,
|
|
allocator,
|
|
);
|
|
}
|
|
|
|
pub fn init(self: *Type) Pipe {
|
|
return Pipe{
|
|
.ctx = self,
|
|
.onPipe = pipe,
|
|
};
|
|
}
|
|
};
|
|
}
|
|
};
|
|
|
|
pub const DrainResult = union(enum) {
|
|
owned: struct {
|
|
list: std.ArrayList(u8),
|
|
size_hint: usize,
|
|
},
|
|
estimated_size: usize,
|
|
empty: void,
|
|
aborted: void,
|
|
};
|
|
|
|
pub const Lifetime = enum {
|
|
clone,
|
|
transfer,
|
|
share,
|
|
/// When reading from a fifo like STDIN/STDERR
|
|
temporary,
|
|
};
|
|
|
|
const std = @import("std");
|
|
|
|
const WebSocketClient = @import("../http/websocket_http_client.zig").WebSocketClient;
|
|
const WebSocketClientTLS = @import("../http/websocket_http_client.zig").WebSocketClientTLS;
|
|
const WebSocketHTTPClient = @import("../http/websocket_http_client.zig").WebSocketHTTPClient;
|
|
const WebSocketHTTPSClient = @import("../http/websocket_http_client.zig").WebSocketHTTPSClient;
|
|
|
|
const bun = @import("bun");
|
|
const jsc = bun.jsc;
|