Compare commits

..

95 Commits

Author SHA1 Message Date
Don Isaac
adc431e319 Merge branch 'main' into don/net/blocklist 2025-02-07 12:25:21 -08:00
Ciro Spaciari
c970922456 fix(sql) expose alias in SQLOption type (#17122) 2025-02-06 19:14:34 -08:00
Jarred Sumner
93af28751f Update CMakeLists.txt 2025-02-06 18:07:55 -08:00
190n
4d2a8650e5 test: bump pglite version (#17117) 2025-02-06 14:33:44 -08:00
Don Isaac
146ec7791b fix(node/assert): port more test cases from node (#16895)
Co-authored-by: DonIsaac <22823424+DonIsaac@users.noreply.github.com>
Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
2025-02-06 14:29:59 -08:00
Ciro Spaciari
253faed1cf fix(sql) types (#17118) 2025-02-06 13:37:58 -08:00
Don Isaac
b123577a6a cleanup 2025-02-06 12:13:59 -05:00
Don Isaac
81a4469e6d Merge branch 'main' of github.com:oven-sh/bun into don/net/blocklist 2025-02-06 12:11:43 -05:00
Ciro Spaciari
1fe2c3b426 feat(sql) support retrieving array values (#17094) 2025-02-06 02:45:05 -08:00
Jarred Sumner
fad856c03c Support fs.stat, fs.existsSync, fs.readFile, fs.promises.stat, fs.promises.readFile in bun build --compile (#17102)
Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
2025-02-06 00:06:52 -08:00
Jarred Sumner
2770ecad5c Fixes #16995 (#17101) 2025-02-05 22:35:53 -08:00
Michael H
1684c6246d fix bunx on windows with postinstall scripts (#17076) 2025-02-05 22:31:42 -08:00
Jarred Sumner
d2cdb5031d Fix potential crash when printing errors in bun install (#17027) 2025-02-05 22:17:02 -08:00
pfg
0c8658b350 Fix test-fs-promises-writefile.js on windows (#17053) 2025-02-05 22:12:52 -08:00
pfg
fc7bd569f5 Fix UAF in throwCommandNotFound (#17097) 2025-02-05 21:22:52 -08:00
pfg
5620a7dfac Enable asan on debug macos aarch64 builds (#17058) 2025-02-05 17:24:32 -08:00
Don Isaac
cfbea14b2e feat(node/net): add missing BlockList shims 2025-02-05 18:47:21 -05:00
Don Isaac
1e164743a6 refactor(node/net): isIP et al mirror node's implementation 2025-02-05 18:47:21 -05:00
Bartłomiej Kalemba
1ccc13ecf7 docs(bunfig): update test runner options (#17040) 2025-02-04 23:56:12 -08:00
Dylan Conway
4d004b90ca Fix bun.lock formatting of bin (#17041) 2025-02-04 23:55:57 -08:00
Zack Radisic
dcf0b719a5 CSS Fixes: light dark, color down-leveling bugs, implement minify for box-shadow (#17055) 2025-02-04 22:50:41 -08:00
Meghan Denny
8634ee3065 fix test-buffer-copy.js (#16640) 2025-02-04 20:19:22 -08:00
Meghan Denny
1819b01932 node: fix test-buffer-fill.js (#16738) 2025-02-04 19:52:11 -08:00
Meghan Denny
b39d84690c implement process.binding('buffer') (#16741)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-02-04 17:59:48 -08:00
Kai Tamkun
d63fe71a6d Fix node:dgram addMembership/dropMembership segfault (#17049) 2025-02-04 15:22:44 -08:00
Dylan Conway
fa55ca31e1 Fix occasional crash on FilePoll deinit (#17050) 2025-02-04 15:22:28 -08:00
190n
a8d159da22 Fix napi_is_buffer/napi_is_typedarray to match Node.js (#17034) 2025-02-03 21:49:27 -08:00
Jarred Sumner
0861c03b37 Fix memory leak in the SQL query string (#17026)
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
2025-02-03 17:38:17 -08:00
Jarred Sumner
7a918d24a7 Fix loading react-jsxdev instead of react-jsx (#17013)
Co-authored-by: chloe caruso <git@paperclover.net>
2025-02-03 14:10:09 -08:00
Bkh
7bef462257 Fix typo in html.ts (#17023) 2025-02-03 12:28:19 -08:00
Jarred Sumner
9cfa3a558b Bump 2025-02-03 07:15:33 -08:00
Jarred Sumner
97ae35dfde Update html.md 2025-02-03 04:08:46 -08:00
Jarred Sumner
1ea14f483c Introduce bun ./index.html (#16993) 2025-02-03 04:06:12 -08:00
Jarred Sumner
ec751159c6 Update typescript.md 2025-02-03 02:40:20 -08:00
Minsoo Choo
fa502506e5 Fix formatting for extern "c" (#16983) 2025-02-02 21:34:58 -08:00
Dylan Conway
06b16fc11e fix 16939 (#16991) 2025-02-02 21:31:40 -08:00
Ciro Spaciari
00a5c4af5a fix(sql) disable idle timeout when still processing data (#16984) 2025-02-02 21:27:22 -08:00
Dylan Conway
cc68f4f025 Fix occasional crash starting debugger thread (#16989) 2025-02-02 05:11:15 -08:00
Jarred Sumner
aac951bd47 Move semver-related structs into their own files (#16987) 2025-02-02 00:20:45 -08:00
Meghan Denny
34419c5f0d zig: only call strlen/wcslen in indexOfSentinel if libc is linked (#16986) 2025-02-01 23:59:45 -08:00
Jarred Sumner
1595b1cc2b Disable stop if necessary timer (#16962) 2025-02-01 22:56:34 -08:00
Michael H
5366c9db33 hopefully auto pr to DT (#16956) 2025-02-01 22:55:19 -08:00
Okinea Dev
87281b6d48 fix: add file association for *.mdc files (#16963) 2025-02-01 22:18:17 -08:00
Jarred Sumner
43fd9326ba Use a more reliable zig download url 2025-02-01 22:12:22 -08:00
Meghan Denny
26d3688e53 zig: update to 0.14.0-dev (#16862)
Co-authored-by: nektro <5464072+nektro@users.noreply.github.com>
2025-02-01 01:11:02 -08:00
pfg
1ddf3fc097 Fix fetch with formdata on some servers (#16947) 2025-01-31 22:39:43 -08:00
Dylan Conway
73bcff9d01 fix 16842 (#16952) 2025-01-31 22:39:30 -08:00
Jarred Sumner
c1708ea6ab Try bringing release/acquire heap access back (#16865)
Co-authored-by: Ben Grant <ben@bun.sh>
2025-01-31 16:13:03 -08:00
Meghan Denny
447121235c node:vm: this error was super confusing without the period 2025-01-31 15:54:06 -08:00
Jarred Sumner
1fa42d81af Bump 2025-01-31 07:08:40 -08:00
Jarred Sumner
22a23add8d Fix import("bun") in Vite (#16938) 2025-01-31 06:34:14 -08:00
Dylan Conway
d4ce421982 Fix node:fs memory leak with AbortSignal (#16788)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-01-31 05:25:53 -08:00
chloe caruso
322098fa54 allow resolution to work when the source file does not exist (#16851)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-01-31 05:24:57 -08:00
Jarred Sumner
9acb72d2ad Correctly handle __esModule for loader: "object" (#16885)
Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2025-01-31 05:24:33 -08:00
Ciro Spaciari
25f6cbd471 fix(s3) fix queue and multipart flow (#16890)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-01-31 05:19:23 -08:00
Dylan Conway
b098c9ed89 fix(fs): WriteStream pending write fastpath (#16856)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2025-01-31 05:14:41 -08:00
Jarred Sumner
212944a5b6 Reduce memory usage of fs.readdir withFileTypes (#16897) 2025-01-31 04:25:58 -08:00
Jarred Sumner
61bf221510 Get pnpm to run inside bun (#16934) 2025-01-31 04:22:03 -08:00
Michael H
891057cd20 fix bun init -h (#16896) 2025-01-31 04:15:44 -08:00
Don Isaac
c51196a8dc fix(install): crash from invalid SemVer with extra wildcard (#16489) 2025-01-31 04:14:53 -08:00
Zack Radisic
f6ec0da125 Various CSS fixing and stability stuff (#16889) 2025-01-31 03:47:49 -08:00
Jarred Sumner
b59b793a32 Fix lifetime issue in BunString (#16930) 2025-01-30 20:46:19 -08:00
Matt Sutkowski
3a4df79a64 chore(docs): remove await from migrate cmd in drizzle.md (#16919) 2025-01-30 17:09:16 -08:00
190n
91f2be57b5 fix(node:os): loadavg() return values on Darwin (#16922) 2025-01-30 17:08:44 -08:00
Don Isaac
b612bc4f47 feat(node/fs): add fs.glob, fs.globSync, and fs.promises.glob (#16676) 2025-01-30 13:20:19 -08:00
Don Isaac
f454c27365 fix: Bun.deepEquals on empty objects with the same prototype (#16894)
Co-authored-by: DonIsaac <22823424+DonIsaac@users.noreply.github.com>
2025-01-30 12:12:51 -08:00
Ciro Spaciari
892764ec43 fix(sql) fix execution queue (#16854) 2025-01-29 23:52:19 -08:00
190n
574a41b03f chore: bump to v1.2.1 (#16891) 2025-01-29 20:19:12 -08:00
Don Isaac
c8f8d2c0bb fix(node/http): re-export WebSocket, CloseEvent, and MessageEvent (#16888) 2025-01-29 18:52:02 -08:00
Meghan Denny
29839737df cpp: synchronize on JSC::getVM since its more likely to be forward compatible (#16688) 2025-01-29 15:50:57 -08:00
Jarred Sumner
4d5ece3f63 Run stopIfNecessary GC timer more (#16871) 2025-01-29 14:40:51 -08:00
Meghan Denny
93a89e5866 meta: update bun.locks with bun 1.2 (#16867)
Co-authored-by: nektro <5464072+nektro@users.noreply.github.com>
2025-01-29 01:47:43 -08:00
Meghan Denny
676e8d1632 zig: delete is_bindgen (#16858) 2025-01-28 23:51:24 -08:00
Meghan Denny
5633ec4334 docker: fix distroless build (#16820) 2025-01-28 18:08:40 -08:00
Meghan Denny
160bf9d563 zig: make install.Resolution.init() not use anytype (#16852) 2025-01-28 18:08:10 -08:00
190n
af27f9e697 Allow WTF timers to participate in the event loop (#15557)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Co-authored-by: 190n <190n@users.noreply.github.com>
Co-authored-by: 190n <7763597+190n@users.noreply.github.com>
2025-01-28 17:47:53 -08:00
Jarred Sumner
f826586e78 Remove incorrect assertion 2025-01-28 17:38:52 -08:00
Jarred Sumner
c8344dd3ed Deflake AsyncLocalStorage test 2025-01-28 17:36:29 -08:00
pfg
76f5c91ffb Regression test for 16702 (#16853) 2025-01-28 17:23:57 -08:00
Jarred Sumner
ea301d7235 More docs on fetch 2025-01-28 15:28:15 -08:00
Don Isaac
33fefdda6b fix(node/fs): better validation in fs.Dir (#16806) 2025-01-28 13:38:28 -08:00
Jarred Sumner
8c75c777c2 Update http.md 2025-01-28 00:56:56 -08:00
Jarred Sumner
1da2f4c0ec More Bun.serve() docs 2025-01-28 00:55:54 -08:00
Michael H
e8a0464f03 docs: for fullstack let people know to install bun-plugin-tailwind (#16826) 2025-01-27 21:47:28 -08:00
Aiello
dd93f08215 feat(resolver): Add NODE_PATH support (#14089)
Co-authored-by: chloe caruso <git@paperclover.net>
2025-01-27 20:16:04 -08:00
190n
71eb1476db Fix crash when napi_register_module_v1 returns nullptr (#16816) 2025-01-27 20:13:22 -08:00
Michael H
f8cbb32343 bun build --env defaults to disable now (#16822) 2025-01-27 18:54:17 -08:00
chloe caruso
c08f4abb6a fix(node:fs): set allow above root (#16814)
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
2025-01-27 16:02:15 -08:00
Jarred Sumner
ce532901ce Support disabling minification in Bun.serve with development: false (#16796) 2025-01-27 06:51:40 -08:00
Jarred Sumner
68ee83067e Revert "Rewrite the internal Web Stream native bindings to use less m… (#16795) 2025-01-27 05:39:37 -08:00
Jarred Sumner
0d73927440 Add a way to disable RWF_NONBLOCK 2025-01-27 04:27:41 -08:00
Jarred Sumner
06a7499853 Add a couple more assertions (#16791) 2025-01-27 02:48:37 -08:00
Jarred Sumner
5262c7bffd Fixes Bun.fileURLToPath throwing error when it should not (#16789) 2025-01-27 02:14:03 -08:00
Jarred Sumner
cd53d32ccf Fix memory leak in certain cases when long URLs are passed to req.url (#16787) 2025-01-26 23:16:35 -08:00
Jarred Sumner
843cb38d3b Fix memory leak in pathToFileURL (#16784) 2025-01-26 22:35:45 -08:00
786 changed files with 40018 additions and 11871 deletions

View File

@@ -0,0 +1,378 @@
---
description: JavaScript class implemented in C++
globs: *.cpp
---
# Implementing JavaScript classes in C++
If there is a publicly accessible Constructor and Prototype, then there are 3 classes:
- IF there are C++ class members we need a destructor, so `class Foo : public JSC::DestructibleObject`, if no C++ class fields (only JS properties) then we don't need a class at all usually. We can instead use JSC::constructEmptyObject(vm, structure) and `putDirectOffset` like in [NodeFSBinding.cpp](mdc:src/bun.js/bindings/NodeFSBinding.cpp).
- class FooPrototype : public JSC::JSNonFinalObject
- class FooConstructor : public JSC::InternalFunction
If there is no publicly accessible Constructor, just the Prototype and the class is necessary. In some cases, we can avoid the prototype entirely (but that's rare).
If there are C++ fields on the Foo class, the Foo class will need an iso subspace added to [DOMClientIsoSubspaces.h](mdc:src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h) and [DOMIsoSubspaces.h](mdc:src/bun.js/bindings/webcore/DOMIsoSubspaces.h). Prototype and Constructor do not need subspaces.
Usually you'll need to #include "root.h" at the top of C++ files or you'll get lint errors.
Generally, defining the subspace looks like this:
```c++
class Foo : public JSC::DestructibleObject {
// ...
template<typename MyClassT, JSC::SubspaceAccess mode>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
if constexpr (mode == JSC::SubspaceAccess::Concurrently)
return nullptr;
return WebCore::subspaceForImpl<MyClassT, WebCore::UseCustomHeapCellType::No>(
vm,
[](auto& spaces) { return spaces.m_clientSubspaceFor${MyClassT}.get(); },
[](auto& spaces, auto&& space) { spaces.m_clientSubspaceFor${MyClassT} = std::forward<decltype(space)>(space); },
[](auto& spaces) { return spaces.m_subspaceFo${MyClassT}.get(); },
[](auto& spaces, auto&& space) { spaces.m_subspaceFor${MyClassT} = std::forward<decltype(space)>(space); });
}
```
It's better to put it in the .cpp file instead of the .h file, when possible.
## Defining properties
Define properties on the prototype. Use a const HashTableValues like this:
```C++
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckEmail);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckHost);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckIP);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckIssued);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncCheckPrivateKey);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncToJSON);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncToLegacyObject);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncToString);
static JSC_DECLARE_HOST_FUNCTION(jsX509CertificateProtoFuncVerify);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_ca);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_fingerprint);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_fingerprint256);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_fingerprint512);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_subject);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_subjectAltName);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_infoAccess);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_keyUsage);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_issuer);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_issuerCertificate);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_publicKey);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_raw);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_serialNumber);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_validFrom);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_validTo);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_validFromDate);
static JSC_DECLARE_CUSTOM_GETTER(jsX509CertificateGetter_validToDate);
static const HashTableValue JSX509CertificatePrototypeTableValues[] = {
{ "ca"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_ca, 0 } },
{ "checkEmail"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncCheckEmail, 2 } },
{ "checkHost"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncCheckHost, 2 } },
{ "checkIP"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncCheckIP, 1 } },
{ "checkIssued"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncCheckIssued, 1 } },
{ "checkPrivateKey"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncCheckPrivateKey, 1 } },
{ "fingerprint"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_fingerprint, 0 } },
{ "fingerprint256"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_fingerprint256, 0 } },
{ "fingerprint512"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_fingerprint512, 0 } },
{ "infoAccess"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_infoAccess, 0 } },
{ "issuer"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_issuer, 0 } },
{ "issuerCertificate"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_issuerCertificate, 0 } },
{ "keyUsage"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_keyUsage, 0 } },
{ "publicKey"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_publicKey, 0 } },
{ "raw"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_raw, 0 } },
{ "serialNumber"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_serialNumber, 0 } },
{ "subject"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_subject, 0 } },
{ "subjectAltName"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_subjectAltName, 0 } },
{ "toJSON"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncToJSON, 0 } },
{ "toLegacyObject"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncToLegacyObject, 0 } },
{ "toString"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncToString, 0 } },
{ "validFrom"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_validFrom, 0 } },
{ "validFromDate"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessorOrValue), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_validFromDate, 0 } },
{ "validTo"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_validTo, 0 } },
{ "validToDate"_s, static_cast<unsigned>(PropertyAttribute::ReadOnly | PropertyAttribute::CustomAccessorOrValue), NoIntrinsic, { HashTableValue::GetterSetterType, jsX509CertificateGetter_validToDate, 0 } },
{ "verify"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsX509CertificateProtoFuncVerify, 1 } },
};
```
### Creating a prototype class
Follow a pattern like this:
```c++
class JSX509CertificatePrototype final : public JSC::JSNonFinalObject {
public:
using Base = JSC::JSNonFinalObject;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSX509CertificatePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
{
JSX509CertificatePrototype* prototype = new (NotNull, allocateCell<JSX509CertificatePrototype>(vm)) JSX509CertificatePrototype(vm, structure);
prototype->finishCreation(vm);
return prototype;
}
template<typename, JSC::SubspaceAccess>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
return &vm.plainObjectSpace();
}
DECLARE_INFO;
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
auto* structure = JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
structure->setMayBePrototype(true);
return structure;
}
private:
JSX509CertificatePrototype(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure)
{
}
void finishCreation(JSC::VM& vm);
};
const ClassInfo JSX509CertificatePrototype::s_info = { "X509Certificate"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSX509CertificatePrototype) };
void JSX509CertificatePrototype::finishCreation(VM& vm)
{
Base::finishCreation(vm);
reifyStaticProperties(vm, JSX509Certificate::info(), JSX509CertificatePrototypeTableValues, *this);
JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
}
} // namespace Bun
```
### Getter definition:
```C++
JSC_DEFINE_CUSTOM_GETTER(jsX509CertificateGetter_ca, (JSGlobalObject * globalObject, EncodedJSValue thisValue, PropertyName))
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSX509Certificate* thisObject = jsDynamicCast<JSX509Certificate*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
Bun::throwThisTypeError(*globalObject, scope, "JSX509Certificate"_s, "ca"_s);
return {};
}
return JSValue::encode(jsBoolean(thisObject->view().isCA()));
}
```
### Setter definition
```C++
JSC_DEFINE_CUSTOM_SETTER(jsImportMetaObjectSetter_require, (JSGlobalObject * jsGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue encodedValue, PropertyName propertyName))
{
ImportMetaObject* thisObject = jsDynamicCast<ImportMetaObject*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject))
return false;
JSValue value = JSValue::decode(encodedValue);
if (!value.isCell()) {
// TODO:
return true;
}
thisObject->requireProperty.set(thisObject->vm(), thisObject, value.asCell());
return true;
}
```
### Function definition
```C++
JSC_DEFINE_HOST_FUNCTION(jsX509CertificateProtoFuncToJSON, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
auto *thisObject = jsDynamicCast<MyClassT*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
Bun::throwThisTypeError(*globalObject, scope, "MyClass"_s, "myFunctionName"_s);
return {};
}
return JSValue::encode(functionThatReturnsJSValue(vm, globalObject, thisObject));
}
```
### Constructor definition
```C++
JSC_DECLARE_HOST_FUNCTION(callStats);
JSC_DECLARE_HOST_FUNCTION(constructStats);
class JSStatsConstructor final : public JSC::InternalFunction {
public:
using Base = JSC::InternalFunction;
static constexpr unsigned StructureFlags = Base::StructureFlags;
static JSStatsConstructor* create(JSC::VM& vm, JSC::Structure* structure, JSC::JSObject* prototype)
{
JSStatsConstructor* constructor = new (NotNull, JSC::allocateCell<JSStatsConstructor>(vm)) JSStatsConstructor(vm, structure);
constructor->finishCreation(vm, prototype);
return constructor;
}
DECLARE_INFO;
template<typename CellType, JSC::SubspaceAccess>
static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
{
return &vm.internalFunctionSpace();
}
static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
{
return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
}
private:
JSStatsConstructor(JSC::VM& vm, JSC::Structure* structure)
: Base(vm, structure, callStats, constructStats)
{
}
void finishCreation(JSC::VM& vm, JSC::JSObject* prototype)
{
Base::finishCreation(vm, 0, "Stats"_s);
putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, JSC::PropertyAttribute::DontEnum | JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
}
};
```
### Structure caching
If there's a class, prototype, and constructor:
1. Add the `JSC::LazyClassStructure` to [ZigGlobalObject.h](mdc:src/bun.js/bindings/ZigGlobalObject.h)
2. Initialize the class structure in [ZigGlobalObject.cpp](mdc:src/bun.js/bindings/ZigGlobalObject.cpp) in `void GlobalObject::finishCreation(VM& vm)`
3. Visit the class structure in visitChildren in [ZigGlobalObject.cpp](mdc:src/bun.js/bindings/ZigGlobalObject.cpp) in `void GlobalObject::visitChildrenImpl`
```c++
m_JSStatsBigIntClassStructure.initLater(
[](LazyClassStructure::Initializer& init) {
Bun::initJSBigIntStatsClassStructure(init);
});
```
If there's only a class, use `JSC::LazyProperty<JSGlobalObject, Structure>` instead of `JSC::LazyClassStructure`.
Then, implement the function that creates the structure:
```c++
void setupX509CertificateClassStructure(LazyClassStructure::Initializer& init)
{
auto* prototypeStructure = JSX509CertificatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype());
auto* prototype = JSX509CertificatePrototype::create(init.vm, init.global, prototypeStructure);
auto* constructorStructure = JSX509CertificateConstructor::createStructure(init.vm, init.global, init.global->functionPrototype());
auto* constructor = JSX509CertificateConstructor::create(init.vm, init.global, constructorStructure, prototype);
auto* structure = JSX509Certificate::createStructure(init.vm, init.global, prototype);
init.setPrototype(prototype);
init.setStructure(structure);
init.setConstructor(constructor);
}
```
Then, use the structure by calling `globalObject.m_myStructureName.get(globalObject)`
```C++
JSC_DEFINE_HOST_FUNCTION(x509CertificateConstructorConstruct, (JSGlobalObject * globalObject, CallFrame* callFrame))
{
VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (!callFrame->argumentCount()) {
Bun::throwError(globalObject, scope, ErrorCode::ERR_MISSING_ARGS, "X509Certificate constructor requires at least one argument"_s);
return {};
}
JSValue arg = callFrame->uncheckedArgument(0);
if (!arg.isCell()) {
Bun::throwError(globalObject, scope, ErrorCode::ERR_INVALID_ARG_TYPE, "X509Certificate constructor argument must be a Buffer, TypedArray, or string"_s);
return {};
}
auto* zigGlobalObject = defaultGlobalObject(globalObject);
Structure* structure = zigGlobalObject->m_JSX509CertificateClassStructure.get(zigGlobalObject);
JSValue newTarget = callFrame->newTarget();
if (UNLIKELY(zigGlobalObject->m_JSX509CertificateClassStructure.constructor(zigGlobalObject) != newTarget)) {
auto scope = DECLARE_THROW_SCOPE(vm);
if (!newTarget) {
throwTypeError(globalObject, scope, "Class constructor X509Certificate cannot be invoked without 'new'"_s);
return {};
}
auto* functionGlobalObject = defaultGlobalObject(getFunctionRealm(globalObject, newTarget.getObject()));
RETURN_IF_EXCEPTION(scope, {});
structure = InternalFunction::createSubclassStructure(
globalObject, newTarget.getObject(), functionGlobalObject->NodeVMScriptStructure());
scope.release();
}
return JSValue::encode(createX509Certificate(vm, globalObject, structure, arg));
}
```
### Expose to Zig
To expose the constructor to zig:
```c++
extern "C" JSC::EncodedJSValue Bun__JSBigIntStatsObjectConstructor(Zig::GlobalObject* globalobject)
{
return JSValue::encode(globalobject->m_JSStatsBigIntClassStructure.constructor(globalobject));
}
```
Zig:
```zig
extern "c" fn Bun__JSBigIntStatsObjectConstructor(*JSC.JSGlobalObject) JSC.JSValue;
pub const getBigIntStatsConstructor = Bun__JSBigIntStatsObjectConstructor;
```
To create an object (instance) of a JS class defined in C++ from Zig, follow the __toJS convention like this:
```c++
// X509* is whatever we need to create the object
extern "C" EncodedJSValue Bun__X509__toJS(Zig::GlobalObject* globalObject, X509* cert)
{
// ... implementation details
auto* structure = globalObject->m_JSX509CertificateClassStructure.get(globalObject);
return JSValue::encode(JSX509Certificate::create(globalObject->vm(), structure, globalObject, WTFMove(cert)));
}
```
And from Zig:
```zig
const X509 = opaque {
// ... class
extern fn Bun__X509__toJS(*JSC.JSGlobalObject, *X509) JSC.JSValue;
pub fn toJS(this: *X509, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
return Bun__X509__toJS(globalObject, this);
}
};
```

1
.gitattributes vendored
View File

@@ -15,6 +15,7 @@
*.lock text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.map text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.md text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mdc text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mjs text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2
*.mts text eol=lf whitespace=blank-at-eol,-blank-at-eof,-space-before-tab,tab-in-indent,tabwidth=2

View File

@@ -4,7 +4,7 @@ description: An internal version of the 'oven-sh/setup-bun' action.
inputs:
bun-version:
type: string
description: "The version of bun to install: 'latest', 'canary', 'bun-v1.0.0', etc."
description: "The version of bun to install: 'latest', 'canary', 'bun-v1.2.0', etc."
default: latest
required: false
baseline:

View File

@@ -10,7 +10,7 @@ on:
merge_group:
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
LLVM_VERSION: "18.1.8"
LLVM_VERSION_MAJOR: "18"

View File

@@ -10,7 +10,7 @@ on:
merge_group:
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
LLVM_VERSION: "18.1.8"
LLVM_VERSION_MAJOR: "18"

View File

@@ -5,7 +5,7 @@ on:
workflow_dispatch:
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
OXLINT_VERSION: "0.15.0"
jobs:

View File

@@ -10,7 +10,7 @@ on:
merge_group:
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
jobs:
prettier-format:

View File

@@ -44,6 +44,10 @@ on:
description: Should types be released to npm?
type: boolean
default: false
use-definitelytyped:
description: "Should types be PR'd to DefinitelyTyped?"
type: boolean
default: false
jobs:
sign:
@@ -66,7 +70,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: "1.1.44"
bun-version: "1.2.0"
- name: Install Dependencies
run: bun install
- name: Sign Release
@@ -94,7 +98,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: "1.1.44"
bun-version: "1.2.0"
- name: Install Dependencies
run: bun install
- name: Release
@@ -123,7 +127,7 @@ jobs:
if: ${{ env.BUN_VERSION != 'canary' }}
uses: ./.github/actions/setup-bun
with:
bun-version: "1.1.44"
bun-version: "1.2.0"
- name: Setup Bun
if: ${{ env.BUN_VERSION == 'canary' }}
uses: ./.github/actions/setup-bun
@@ -155,6 +159,48 @@ jobs:
with:
package: packages/bun-types/package.json
token: ${{ secrets.NPM_TOKEN }}
definitelytyped:
name: Make pr to DefinitelyTyped to update `bun-types` version
runs-on: ubuntu-latest
needs: npm-types
if: ${{ github.event_name == 'release' || github.event.inputs.use-definitelytyped == 'true' }}
permissions:
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
with:
repository: DefinitelyTyped/DefinitelyTyped
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: "1.2.0"
- id: bun-version
run: echo "BUN_VERSION=${BUN_VERSION#bun-v}" >> "$GITHUB_OUTPUT"
- name: Update bun-types version in package.json
run: |
bun -e '
const file = Bun.file("./types/bun/package.json");
const json = await file.json();
const version = "${{ steps.bun-version.outputs.BUN_VERSION }}";
json.dependencies["bun-types"] = version;
json.version = version.slice(0, version.lastIndexOf(".")) + ".9999";
await file.write(JSON.stringify(json, null, 4) + "\n");
'
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
if: ${{ env.BUN_LATEST == 'true' && env.BUN_VERSION != 'canary'}}
with:
token: ${{ secrets.ROBOBUN_TOKEN }}
add-paths: ./types/bun/package.json
title: "[bun] update to ${{ steps.bun-version.outputs.BUN_VERSION }}"
commit-message: "[bun] update to ${{ steps.bun-version.outputs.BUN_VERSION }}"
body: |
Update `bun-types` version to ${{ steps.bun-version.outputs.BUN_VERSION }}
https://bun.sh/blog/${{ env.BUN_VERSION }}
push-to-fork: oven-sh/DefinitelyTyped
branch: ${{env.BUN_VERSION}}
docker:
name: Release to Dockerhub
runs-on: ubuntu-latest
@@ -265,7 +311,7 @@ jobs:
- name: Setup Bun
uses: ./.github/actions/setup-bun
with:
bun-version: "1.1.44"
bun-version: "1.2.0"
- name: Install Dependencies
run: bun install
- name: Release
@@ -309,7 +355,7 @@ jobs:
uses: ./.github/actions/setup-bun
if: ${{ env.BUN_LATEST == 'true' }}
with:
bun-version: "1.1.44"
bun-version: "1.2.0"
- name: Bump version
uses: ./.github/actions/bump
if: ${{ env.BUN_LATEST == 'true' }}

View File

@@ -4,7 +4,7 @@ permissions:
contents: read
env:
LLVM_VERSION: 16
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
on:
workflow_call:

View File

@@ -9,7 +9,7 @@ on:
required: true
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
jobs:
bump:

View File

@@ -10,7 +10,7 @@ on:
merge_group:
env:
BUN_VERSION: "1.1.44"
BUN_VERSION: "1.2.0"
jobs:
zig-format:

3
.gitignore vendored
View File

@@ -151,6 +151,7 @@ src/bake/generated.ts
test/cli/install/registry/packages/publish-pkg-*
test/cli/install/registry/packages/@secret/publish-pkg-8
test/js/third_party/prisma/prisma/sqlite/dev.db-journal
tmp
# Dependencies
/vendor
@@ -178,4 +179,4 @@ test/js/third_party/prisma/prisma/sqlite/dev.db-journal
.buildkite/ci.yml
*.sock
scratch*.{js,ts,tsx,cjs,mjs}
scratch*.{js,ts,tsx,cjs,mjs}

View File

@@ -7,3 +7,4 @@ src/react-refresh.js
*.min.js
test/snippets
test/js/node/test
bun.lock

13
.vscode/launch.json generated vendored
View File

@@ -7,6 +7,19 @@
// - "cppvsdbg" is used instead of "lldb" on Windows, because "lldb" is too slow
"version": "0.2.0",
"configurations": [
{
"type": "bun",
"request": "launch",
"name": "[js] bun test [file]",
"runtime": "${workspaceFolder}/build/debug/bun-debug",
"args": ["test", "${file}"],
"cwd": "${workspaceFolder}",
"env": {
"BUN_DEBUG_QUIET_LOGS": "1",
"BUN_DEBUG_jest": "1",
"BUN_GARBAGE_COLLECTOR_LEVEL": "1",
},
},
// bun test [file]
{
"type": "lldb",

View File

@@ -140,6 +140,7 @@
},
"files.associations": {
"*.idl": "cpp",
"*.mdc": "markdown",
"array": "cpp",
},
"C_Cpp.files.exclude": {

View File

@@ -12,6 +12,12 @@ list(APPEND CMAKE_MODULE_PATH
include(Policies)
include(Globals)
if (CMAKE_HOST_WIN32)
# Workaround for TLS certificate verification issue on Windows when downloading from GitHub
# Remove this once we've bumped the CI machines build image
set(CMAKE_TLS_VERIFY 0)
endif()
# --- Compilers ---
if(CMAKE_HOST_APPLE)

2
LATEST
View File

@@ -1 +1 @@
1.2.0
1.2.2

View File

@@ -91,9 +91,9 @@ ZIG ?= $(shell which zig 2>/dev/null || echo -e "error: Missing zig. Please make
# This is easier to happen than you'd expect.
# Using realpath here causes issues because clang uses clang++ as a symlink
# so if that's resolved, it won't build for C++
REAL_CC = $(shell which clang-16 2>/dev/null || which clang 2>/dev/null)
REAL_CXX = $(shell which clang++-16 2>/dev/null || which clang++ 2>/dev/null)
CLANG_FORMAT = $(shell which clang-format-16 2>/dev/null || which clang-format 2>/dev/null)
REAL_CC = $(shell which clang-18 2>/dev/null || which clang 2>/dev/null)
REAL_CXX = $(shell which clang++-18 2>/dev/null || which clang++ 2>/dev/null)
CLANG_FORMAT = $(shell which clang-format-18 2>/dev/null || which clang-format 2>/dev/null)
CC = $(REAL_CC)
CXX = $(REAL_CXX)
@@ -117,14 +117,14 @@ CC_WITH_CCACHE = $(CCACHE_PATH) $(CC)
ifeq ($(OS_NAME),darwin)
# Find LLVM
ifeq ($(wildcard $(LLVM_PREFIX)),)
LLVM_PREFIX = $(shell brew --prefix llvm@16)
LLVM_PREFIX = $(shell brew --prefix llvm@18)
endif
ifeq ($(wildcard $(LLVM_PREFIX)),)
LLVM_PREFIX = $(shell brew --prefix llvm)
endif
ifeq ($(wildcard $(LLVM_PREFIX)),)
# This is kinda ugly, but I can't find a better way to error :(
LLVM_PREFIX = $(shell echo -e "error: Unable to find llvm. Please run 'brew install llvm@16' or set LLVM_PREFIX=/path/to/llvm")
LLVM_PREFIX = $(shell echo -e "error: Unable to find llvm. Please run 'brew install llvm@18' or set LLVM_PREFIX=/path/to/llvm")
endif
LDFLAGS += -L$(LLVM_PREFIX)/lib
@@ -164,7 +164,7 @@ CMAKE_FLAGS_WITHOUT_RELEASE = -DCMAKE_C_COMPILER=$(CC) \
-DCMAKE_OSX_DEPLOYMENT_TARGET=$(MIN_MACOS_VERSION) \
$(CMAKE_CXX_COMPILER_LAUNCHER_FLAG) \
-DCMAKE_AR=$(AR) \
-DCMAKE_RANLIB=$(which llvm-16-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null) \
-DCMAKE_RANLIB=$(which llvm-18-ranlib 2>/dev/null || which llvm-ranlib 2>/dev/null) \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_C_STANDARD=17 \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
@@ -191,7 +191,7 @@ endif
ifeq ($(OS_NAME),linux)
LIBICONV_PATH =
AR = $(shell which llvm-ar-16 2>/dev/null || which llvm-ar 2>/dev/null || which ar 2>/dev/null)
AR = $(shell which llvm-ar-18 2>/dev/null || which llvm-ar 2>/dev/null || which ar 2>/dev/null)
endif
OPTIMIZATION_LEVEL=-O3 $(MARCH_NATIVE)
@@ -286,7 +286,7 @@ STRIP=/usr/bin/strip
endif
ifeq ($(OS_NAME),linux)
STRIP=$(shell which llvm-strip 2>/dev/null || which llvm-strip-16 2>/dev/null || which strip 2>/dev/null || echo "Missing strip")
STRIP=$(shell which llvm-strip 2>/dev/null || which llvm-strip-18 2>/dev/null || which strip 2>/dev/null || echo "Missing strip")
endif
@@ -674,7 +674,7 @@ endif
.PHONY: assert-deps
assert-deps:
@echo "Checking if the required utilities are available..."
@if [ $(CLANG_VERSION) -lt "15" ]; then echo -e "ERROR: clang version >=15 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@16"; exit 1; fi
@if [ $(CLANG_VERSION) -lt "18" ]; then echo -e "ERROR: clang version >=18 required, found: $(CLANG_VERSION). Install with:\n\n $(POSIX_PKG_MANAGER) install llvm@18"; exit 1; fi
@cmake --version >/dev/null 2>&1 || (echo -e "ERROR: cmake is required."; exit 1)
@$(PYTHON) --version >/dev/null 2>&1 || (echo -e "ERROR: python is required."; exit 1)
@$(ESBUILD) --version >/dev/null 2>&1 || (echo -e "ERROR: esbuild is required."; exit 1)
@@ -1261,6 +1261,7 @@ jsc-build-mac-compile:
-DBUN_FAST_TLS=ON \
-DENABLE_FTL_JIT=ON \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DUSE_BUN_EVENT_LOOP=ON \
-G Ninja \
$(CMAKE_FLAGS_WITHOUT_RELEASE) \
-DPTHREAD_JIT_PERMISSIONS_API=1 \
@@ -1284,6 +1285,7 @@ jsc-build-mac-compile-lto:
-DUSE_THIN_ARCHIVES=OFF \
-DBUN_FAST_TLS=ON \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DUSE_BUN_EVENT_LOOP=ON \
-DCMAKE_C_FLAGS="-flto=full" \
-DCMAKE_CXX_FLAGS="-flto=full" \
-DENABLE_FTL_JIT=ON \
@@ -1299,6 +1301,7 @@ jsc-build-mac-compile-lto:
.PHONY: jsc-build-mac-compile-debug
jsc-build-mac-compile-debug:
mkdir -p $(WEBKIT_DEBUG_DIR) $(WEBKIT_DIR);
# to disable asan, remove -DENABLE_SANITIZERS=address and add -DENABLE_MALLOC_HEAP_BREAKDOWN=ON
cd $(WEBKIT_DEBUG_DIR) && \
ICU_INCLUDE_DIRS="$(HOMEBREW_PREFIX)opt/icu4c/include" \
cmake \
@@ -1307,9 +1310,9 @@ jsc-build-mac-compile-debug:
-DCMAKE_BUILD_TYPE=Debug \
-DUSE_THIN_ARCHIVES=OFF \
-DENABLE_FTL_JIT=ON \
-DENABLE_MALLOC_HEAP_BREAKDOWN=ON \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DUSE_BUN_EVENT_LOOP=ON \
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \
-DALLOW_LINE_AND_COLUMN_NUMBER_IN_BUILTINS=ON \
-G Ninja \
@@ -1318,6 +1321,7 @@ jsc-build-mac-compile-debug:
-DUSE_PTHREAD_JIT_PERMISSIONS_API=ON \
-DENABLE_REMOTE_INSPECTOR=ON \
-DUSE_VISIBILITY_ATTRIBUTE=1 \
-DENABLE_SANITIZERS=address \
$(WEBKIT_DIR) \
$(WEBKIT_DEBUG_DIR) && \
CFLAGS="$(CFLAGS) -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -ffat-lto-objects" \
@@ -1334,6 +1338,7 @@ jsc-build-linux-compile-config:
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \
-DUSE_THIN_ARCHIVES=OFF \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DUSE_BUN_EVENT_LOOP=ON \
-DENABLE_FTL_JIT=ON \
-DENABLE_REMOTE_INSPECTOR=ON \
-DJSEXPORT_PRIVATE=WTF_EXPORT_DECLARATION \
@@ -1357,6 +1362,7 @@ jsc-build-linux-compile-config-debug:
-DENABLE_BUN_SKIP_FAILING_ASSERTIONS=ON \
-DUSE_THIN_ARCHIVES=OFF \
-DUSE_BUN_JSC_ADDITIONS=ON \
-DUSE_BUN_EVENT_LOOP=ON \
-DENABLE_FTL_JIT=ON \
-DENABLE_REMOTE_INSPECTOR=ON \
-DJSEXPORT_PRIVATE=WTF_EXPORT_DECLARATION \
@@ -1375,14 +1381,14 @@ jsc-build-linux-compile-config-debug:
jsc-build-linux-compile-build:
mkdir -p $(WEBKIT_RELEASE_DIR) && \
cd $(WEBKIT_RELEASE_DIR) && \
CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON" \
CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON -DUSE_BUN_EVENT_LOOP=ON" \
cmake --build $(WEBKIT_RELEASE_DIR) --config relwithdebuginfo --target jsc
.PHONY: jsc-build-linux-compile-build-debug
jsc-build-linux-compile-build-debug:
mkdir -p $(WEBKIT_DEBUG_DIR) && \
cd $(WEBKIT_DEBUG_DIR) && \
CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON" \
CFLAGS="$(CFLAGS) -Wl,--whole-archive -ffat-lto-objects" CXXFLAGS="$(CXXFLAGS) -Wl,--whole-archive -ffat-lto-objects -DUSE_BUN_JSC_ADDITIONS=ON -DUSE_BUN_EVENT_LOOP=ON" \
cmake --build $(WEBKIT_DEBUG_DIR) --config Debug --target jsc

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bench",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "expect-to-equal",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bench",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bench",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "simple-react",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "react-hello-world",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "scan",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bench",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "websocket-server",

View File

@@ -19,7 +19,7 @@ const OperatingSystem = @import("src/env.zig").OperatingSystem;
const pathRel = fs.path.relative;
/// Do not rename this constant. It is scanned by some scripts to determine which zig version to install.
const recommended_zig_version = "0.13.0";
const recommended_zig_version = "0.14.0-dev.2987+183bb8b08";
comptime {
if (!std.mem.eql(u8, builtin.zig_version_string, recommended_zig_version)) {
@@ -46,6 +46,7 @@ const BunBuildOptions = struct {
sha: []const u8,
/// enable debug logs in release builds
enable_logs: bool = false,
enable_asan: bool,
tracy_callstack_depth: u16,
reported_nodejs_version: Version,
/// To make iterating on some '@embedFile's faster, we load them at runtime
@@ -154,8 +155,6 @@ pub fn build(b: *Build) !void {
std.log.info("zig compiler v{s}", .{builtin.zig_version_string});
checked_file_exists = std.AutoHashMap(u64, void).init(b.allocator);
b.zig_lib_dir = b.zig_lib_dir orelse b.path("vendor/zig/lib");
// TODO: Upgrade path for 0.14.0
// b.graph.zig_lib_directory = brk: {
// const sub_path = "vendor/zig/lib";
@@ -209,7 +208,7 @@ pub fn build(b: *Build) !void {
const bun_version = b.option([]const u8, "version", "Value of `Bun.version`") orelse "0.0.0";
b.reference_trace = ref_trace: {
const trace = b.option(u32, "reference-trace", "Set the reference trace") orelse 16;
const trace = b.option(u32, "reference-trace", "Set the reference trace") orelse 24;
break :ref_trace if (trace == 0) null else trace;
};
@@ -277,6 +276,7 @@ pub fn build(b: *Build) !void {
.tracy_callstack_depth = b.option(u16, "tracy_callstack_depth", "") orelse 10,
.enable_logs = b.option(bool, "enable_logs", "Enable logs in release") orelse false,
.enable_asan = b.option(bool, "enable_asan", "Enable asan") orelse false,
};
// zig build obj
@@ -331,11 +331,25 @@ pub fn build(b: *Build) !void {
.{ .os = .windows, .arch = .x86_64 },
});
}
{
const step = b.step("check-macos", "Check for semantic analysis errors on Windows");
addMultiCheck(b, step, build_options, &.{
.{ .os = .mac, .arch = .x86_64 },
.{ .os = .mac, .arch = .aarch64 },
});
}
{
const step = b.step("check-linux", "Check for semantic analysis errors on Windows");
addMultiCheck(b, step, build_options, &.{
.{ .os = .linux, .arch = .x86_64 },
.{ .os = .linux, .arch = .aarch64 },
});
}
// zig build translate-c-headers
{
const step = b.step("translate-c", "Copy generated translated-c-headers.zig to zig-out");
step.dependOn(&b.addInstallFile(getTranslateC(b, b.host, .Debug).getOutput(), "translated-c-headers.zig").step);
step.dependOn(&b.addInstallFile(getTranslateC(b, b.graph.host, .Debug).getOutput(), "translated-c-headers.zig").step);
}
// zig build enum-extractor
@@ -363,7 +377,7 @@ pub fn addMultiCheck(
const check_target = b.resolveTargetQuery(.{
.os_tag = OperatingSystem.stdOSTag(check.os),
.cpu_arch = check.arch,
.cpu_model = getCpuModel(check.os, check.arch) orelse .determined_by_cpu_arch,
.cpu_model = getCpuModel(check.os, check.arch) orelse .determined_by_arch_os,
.os_version_min = getOSVersionMin(check.os),
.glibc_version = if (check.musl) null else getOSGlibCVersion(check.os),
});
@@ -381,6 +395,7 @@ pub fn addMultiCheck(
.reported_nodejs_version = root_build_options.reported_nodejs_version,
.codegen_path = root_build_options.codegen_path,
.no_llvm = root_build_options.no_llvm,
.enable_asan = root_build_options.enable_asan,
};
var obj = addBunObject(b, &options);
@@ -428,8 +443,15 @@ pub fn addBunObject(b: *Build, opts: *BunBuildOptions) *Compile {
.omit_frame_pointer = false,
.strip = false, // stripped at the end
});
if (opts.enable_asan) {
if (@hasField(Build.Module, "sanitize_address")) {
obj.root_module.sanitize_address = true;
} else {
const fail_step = b.addFail("asan is not supported on this platform");
obj.step.dependOn(&fail_step.step);
}
}
obj.bundle_compiler_rt = false;
obj.formatted_panics = true;
obj.root_module.omit_frame_pointer = false;
// Link libc
@@ -614,7 +636,7 @@ const WindowsShim = struct {
.optimize = .ReleaseFast,
.use_llvm = true,
.use_lld = true,
.unwind_tables = false,
.unwind_tables = .none,
.omit_frame_pointer = true,
.strip = true,
.linkage = .static,

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun",
@@ -10,8 +10,8 @@
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.11.0",
"@vscode/debugadapter": "^1.65.0",
"autoprefixer": "^10.4.19",
"caniuse-lite": "^1.0.30001620",
"autoprefixer": "^10.4.20",
"caniuse-lite": "^1.0.30001660",
"esbuild": "^0.21.4",
"eslint": "^9.4.0",
"eslint-config-prettier": "^9.1.0",
@@ -257,7 +257,7 @@
"builtins": ["builtins@1.0.3", "", {}, "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ=="],
"bun-types": ["bun-types@workspace:packages/bun-types", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" }, "devDependencies": { "@biomejs/biome": "^1.5.3", "@definitelytyped/dtslint": "^0.0.199", "@definitelytyped/eslint-plugin": "^0.0.197", "typescript": "^5.0.2" } }],
"bun-types": ["bun-types@workspace:packages/bun-types"],
"call-bind": ["call-bind@1.0.7", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.1" } }, "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w=="],
@@ -265,7 +265,7 @@
"camel-case": ["camel-case@4.1.2", "", { "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" } }, "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001653", "", {}, "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001695", "", {}, "sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw=="],
"capital-case": ["capital-case@1.0.4", "", { "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", "upper-case-first": "^2.0.2" } }, "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A=="],
@@ -923,10 +923,14 @@
"are-we-there-yet/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
"autoprefixer/caniuse-lite": ["caniuse-lite@1.0.30001653", "", {}, "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw=="],
"babel-code-frame/chalk": ["chalk@1.1.3", "", { "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", "has-ansi": "^2.0.0", "strip-ansi": "^3.0.0", "supports-color": "^2.0.0" } }, "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A=="],
"babel-code-frame/js-tokens": ["js-tokens@3.0.2", "", {}, "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg=="],
"browserslist/caniuse-lite": ["caniuse-lite@1.0.30001653", "", {}, "sha512-XGWQVB8wFQ2+9NZwZ10GxTYC5hk0Fa+q8cSkr0tgvMhYhMHP/QC+WTgrePMDBWiWc/pV+1ik82Al20XOK25Gcw=="],
"eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],
"eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "^2.1.1" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="],

View File

@@ -44,6 +44,13 @@ if(WIN32)
)
endif()
if(ENABLE_ASAN)
register_compiler_flags(
DESCRIPTION "Enable AddressSanitizer"
-fsanitize=address
)
endif()
# --- Optimization level ---
if(DEBUG)
register_compiler_flags(

View File

@@ -86,6 +86,11 @@ optionx(ENABLE_LTO BOOL "If LTO (link-time optimization) should be used" DEFAULT
if(LINUX)
optionx(ENABLE_VALGRIND BOOL "If Valgrind support should be enabled" DEFAULT OFF)
endif()
if(DEBUG AND APPLE AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
optionx(ENABLE_ASAN BOOL "If ASAN support should be enabled" DEFAULT ON)
else()
optionx(ENABLE_ASAN BOOL "If ASAN support should be enabled" DEFAULT OFF)
endif()
optionx(ENABLE_PRETTIER BOOL "If prettier should be ran" DEFAULT OFF)

View File

@@ -28,7 +28,12 @@ else()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
set(ZIG_NAME zig-${ZIG_OS}-${ZIG_ARCH}-${ZIG_VERSION})
set(ZIG_ASAN "")
if(ENABLE_ASAN)
set(ZIG_ASAN "+asan")
endif()
set(ZIG_NAME zig-${ZIG_OS}-${ZIG_ARCH}-${ZIG_VERSION}${ZIG_ASAN})
if(CMAKE_HOST_WIN32)
set(ZIG_EXE "zig.exe")
@@ -38,7 +43,7 @@ else()
set(ZIG_FILENAME ${ZIG_NAME}.tar.xz)
endif()
set(ZIG_DOWNLOAD_URL https://ziglang.org/download/${ZIG_VERSION}/${ZIG_FILENAME})
set(ZIG_DOWNLOAD_URL https://bun-ci-assets.bun.sh/${ZIG_FILENAME})
execute_process(
COMMAND

View File

@@ -404,6 +404,7 @@ set(BUN_OBJECT_LUT_SOURCES
${CWD}/src/bun.js/bindings/ZigGlobalObject.lut.txt
${CWD}/src/bun.js/bindings/JSBuffer.cpp
${CWD}/src/bun.js/bindings/BunProcess.cpp
${CWD}/src/bun.js/bindings/ProcessBindingBuffer.cpp
${CWD}/src/bun.js/bindings/ProcessBindingConstants.cpp
${CWD}/src/bun.js/bindings/ProcessBindingNatives.cpp
${CWD}/src/bun.js/modules/NodeModuleModule.cpp
@@ -415,6 +416,7 @@ set(BUN_OBJECT_LUT_OUTPUTS
${CODEGEN_PATH}/ZigGlobalObject.lut.h
${CODEGEN_PATH}/JSBuffer.lut.h
${CODEGEN_PATH}/BunProcess.lut.h
${CODEGEN_PATH}/ProcessBindingBuffer.lut.h
${CODEGEN_PATH}/ProcessBindingConstants.lut.h
${CODEGEN_PATH}/ProcessBindingNatives.lut.h
${CODEGEN_PATH}/NodeModuleModule.lut.h
@@ -565,6 +567,7 @@ register_command(
-Dcanary=${CANARY_REVISION}
-Dcodegen_path=${CODEGEN_PATH}
-Dcodegen_embed=$<IF:$<BOOL:${CODEGEN_EMBED}>,true,false>
-Denable_asan=$<IF:$<BOOL:${ENABLE_ASAN}>,true,false>
--prominent-compile-errors
${ZIG_FLAGS_BUN}
ARTIFACTS
@@ -827,6 +830,15 @@ if(NOT WIN32)
)
endif()
if (ENABLE_ASAN)
target_compile_options(${bun} PUBLIC
-fsanitize=address
)
target_link_libraries(${bun} PUBLIC
-fsanitize=address
)
endif()
target_compile_options(${bun} PUBLIC
-Werror=return-type
-Werror=return-stack-address

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
oven-sh/mimalloc
COMMIT
82b2c2277a4d570187c07b376557dc5bde81d848
1beadf9651a7bfdec6b5367c380ecc3fe1c40d1a
)
set(MIMALLOC_CMAKE_ARGS
@@ -19,6 +19,10 @@ set(MIMALLOC_CMAKE_ARGS
-DMI_SKIP_COLLECT_ON_EXIT=ON
)
if(ENABLE_ASAN)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_TRACK_ASAN=ON)
endif()
if(DEBUG)
list(APPEND MIMALLOC_CMAKE_ARGS -DMI_DEBUG_FULL=ON)
endif()

View File

@@ -2,7 +2,7 @@ option(WEBKIT_VERSION "The version of WebKit to use")
option(WEBKIT_LOCAL "If a local version of WebKit should be used instead of downloading")
if(NOT WEBKIT_VERSION)
set(WEBKIT_VERSION 9e3b60e4a6438d20ee6f8aa5bec6b71d2b7d213f)
set(WEBKIT_VERSION 851aabf42b06ba583cc0485ff9088e3f84c22f3d)
endif()
string(SUBSTRING ${WEBKIT_VERSION} 0 16 WEBKIT_VERSION_PREFIX)
@@ -79,6 +79,10 @@ else()
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}")
endif()
if(ENABLE_ASAN)
set(WEBKIT_SUFFIX "${WEBKIT_SUFFIX}-asan")
endif()
set(WEBKIT_NAME bun-webkit-${WEBKIT_OS}-${WEBKIT_ARCH}${WEBKIT_SUFFIX})
set(WEBKIT_FILENAME ${WEBKIT_NAME}.tar.gz)
setx(WEBKIT_DOWNLOAD_URL https://github.com/oven-sh/WebKit/releases/download/autobuild-${WEBKIT_VERSION}/${WEBKIT_FILENAME})

View File

@@ -20,8 +20,8 @@ else()
unsupported(CMAKE_SYSTEM_NAME)
endif()
optionx(ZIG_VERSION STRING "The zig version of the compiler to download" DEFAULT "0.13.0")
optionx(ZIG_COMMIT STRING "The zig commit to use in oven-sh/zig" DEFAULT "131a009ba2eb127a3447d05b9e12f710429aa5ee")
optionx(ZIG_VERSION STRING "The zig version of the compiler to download" DEFAULT "0.14.0-dev.2987+183bb8b08")
optionx(ZIG_COMMIT STRING "The zig commit to use in oven-sh/zig" DEFAULT "63f8ed52c011beafde83216efba766492491ef4b")
optionx(ZIG_TARGET STRING "The zig target to use" DEFAULT ${DEFAULT_ZIG_TARGET})
if(CMAKE_BUILD_TYPE STREQUAL "Release")
@@ -79,6 +79,7 @@ register_command(
-DZIG_PATH=${ZIG_PATH}
-DZIG_VERSION=${ZIG_VERSION}
-DZIG_COMMIT=${ZIG_COMMIT}
-DENABLE_ASAN=${ENABLE_ASAN}
-P ${CWD}/cmake/scripts/DownloadZig.cmake
SOURCES
${CWD}/cmake/scripts/DownloadZig.cmake

View File

@@ -67,14 +67,18 @@ ARG BUN_INSTALL_BIN=/usr/local/bin
ENV BUN_INSTALL_BIN=${BUN_INSTALL_BIN}
COPY --from=build /usr/local/bin/bun /usr/local/bin/
RUN mkdir -p /usr/local/bun-node-fallback-bin && ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/node
ENV PATH "${PATH}:/usr/local/bun-node-fallback-bin"
# Temporarily use the `build`-stage image binaries to create a symlink:
RUN --mount=type=bind,from=build,source=/usr/bin,target=/usr/bin \
--mount=type=bind,from=build,source=/bin,target=/bin <<EOF
--mount=type=bind,from=build,source=/bin,target=/bin \
--mount=type=bind,from=build,source=/usr/lib,target=/usr/lib \
--mount=type=bind,from=build,source=/lib,target=/lib \
<<EOF
ln -s /usr/local/bin/bun /usr/local/bin/bunx
which bunx
mkdir -p /usr/local/bun-node-fallback-bin
ln -s /usr/local/bin/bun /usr/local/bun-node-fallback-bin/nodebun
EOF
ENTRYPOINT ["/usr/local/bin/bun"]

View File

@@ -111,6 +111,38 @@ const reader = stream.getReader();
const { value, done } = await reader.read();
```
### Streaming request bodies
You can also stream data in request bodies using a `ReadableStream`:
```ts
const stream = new ReadableStream({
start(controller) {
controller.enqueue("Hello");
controller.enqueue(" ");
controller.enqueue("World");
controller.close();
},
});
const response = await fetch("http://example.com", {
method: "POST",
body: stream,
});
```
When using streams with HTTP(S):
- The data is streamed directly to the network without buffering the entire body in memory
- If the connection is lost, the stream will be canceled
- The `Content-Length` header is not automatically set unless the stream has a known size
When using streams with S3:
- For PUT/POST requests, Bun automatically uses multipart upload
- The stream is consumed in chunks and uploaded in parallel
- Progress can be monitored through the S3 options
### Fetching a URL with a timeout
To fetch a URL with a timeout, use `AbortSignal.timeout`:
@@ -180,6 +212,116 @@ await fetch("https://example.com", {
This is similar to how it works in Node's `net` module.
#### Disable TLS validation
To disable TLS validation, set `rejectUnauthorized` to `false`:
```ts
await fetch("https://example.com", {
tls: {
rejectUnauthorized: false,
},
});
```
This is especially useful to avoid SSL errors when using self-signed certificates, but this disables TLS validation and should be used with caution.
### Request options
In addition to the standard fetch options, Bun provides several extensions:
```ts
const response = await fetch("http://example.com", {
// Control automatic response decompression (default: true)
decompress: true,
// Disable connection reuse for this request
keepalive: false,
// Debug logging level
verbose: true, // or "curl" for more detailed output
});
```
### Protocol support
Beyond HTTP(S), Bun's fetch supports several additional protocols:
#### S3 URLs - `s3://`
Bun supports fetching from S3 buckets directly.
```ts
// Using environment variables for credentials
const response = await fetch("s3://my-bucket/path/to/object");
// Or passing credentials explicitly
const response = await fetch("s3://my-bucket/path/to/object", {
s3: {
accessKeyId: "YOUR_ACCESS_KEY",
secretAccessKey: "YOUR_SECRET_KEY",
region: "us-east-1",
},
});
```
Note: Only PUT and POST methods support request bodies when using S3. For uploads, Bun automatically uses multipart upload for streaming bodies.
You can read more about Bun's S3 support in the [S3](https://bun.sh/docs/api/s3) documentation.
#### File URLs - `file://`
You can fetch local files using the `file:` protocol:
```ts
const response = await fetch("file:///path/to/file.txt");
const text = await response.text();
```
On Windows, paths are automatically normalized:
```ts
// Both work on Windows
const response = await fetch("file:///C:/path/to/file.txt");
const response2 = await fetch("file:///c:/path\\to/file.txt");
```
#### Data URLs - `data:`
Bun supports the `data:` URL scheme:
```ts
const response = await fetch("data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==");
const text = await response.text(); // "Hello, World!"
```
#### Blob URLs - `blob:`
You can fetch blobs using URLs created by `URL.createObjectURL()`:
```ts
const blob = new Blob(["Hello, World!"], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const response = await fetch(url);
```
### Error handling
Bun's fetch implementation includes several specific error cases:
- Using a request body with GET/HEAD methods will throw an error (which is expected for the fetch API)
- Attempting to use both `proxy` and `unix` options together will throw an error
- TLS certificate validation failures when `rejectUnauthorized` is true (or undefined)
- S3 operations may throw specific errors related to authentication or permissions
### Content-Type handling
Bun automatically sets the `Content-Type` header for request bodies when not explicitly provided:
- For `Blob` objects, uses the blob's `type`
- For `FormData`, sets appropriate multipart boundary
- For JSON objects, sets `application/json`
## Debugging
To help with debugging, you can pass `verbose: true` to `fetch`:
@@ -306,3 +448,16 @@ import { write } from "bun";
await write("output.txt", response);
```
### Implementation details
- Connection pooling is enabled by default but can be disabled per-request with `keepalive: false`. The `"Connection: close"` header can also be used to disable keep-alive.
- Large file uploads are optimized using the operating system's `sendfile` syscall under specific conditions:
- The file must be larger than 32KB
- The request must not be using a proxy
- On macOS, only regular files (not pipes, sockets, or devices) can use `sendfile`
- When these conditions aren't met, or when using S3/streaming uploads, Bun falls back to reading the file into memory
- This optimization is particularly effective for HTTP (not HTTPS) requests where the file can be sent directly from the kernel to the network stack
- S3 operations automatically handle signing requests and merging authentication headers
Note: Many of these features are Bun-specific extensions to the standard fetch API.

View File

@@ -513,6 +513,241 @@ Bun.serve({
});
```
## Server Lifecycle Methods
### server.stop() - Stop the server
To stop the server from accepting new connections:
```ts
const server = Bun.serve({
fetch(req) {
return new Response("Hello!");
},
});
// Gracefully stop the server (waits for in-flight requests)
await server.stop();
// Force stop and close all active connections
await server.stop(true);
```
By default, `stop()` allows in-flight requests and WebSocket connections to complete. Pass `true` to immediately terminate all connections.
### server.ref() and server.unref() - Process lifecycle control
Control whether the server keeps the Bun process alive:
```ts
// Don't keep process alive if server is the only thing running
server.unref();
// Restore default behavior - keep process alive
server.ref();
```
### server.reload() - Hot reload handlers
Update the server's handlers without restarting:
```ts
const server = Bun.serve({
static: {
"/api/version": Response.json({ version: "v1" }),
},
fetch(req) {
return new Response("v1");
},
});
// Update to new handler
server.reload({
static: {
"/api/version": Response.json({ version: "v2" }),
},
fetch(req) {
return new Response("v2");
},
});
```
This is useful for development and hot reloading. Only `fetch`, `error`, and `static` handlers can be updated.
## Per-Request Controls
<!-- ### server.abort(Request) - Abort requests
The `server.abort(request: Request)` method:
- Returns `true` if request was aborted, `false` if already aborted/completed
- Triggers the request's `AbortSignal`
- Cancels any attached `ReadableStream`
- Rejects any pending body promises (like `.text()`)
```ts
const server = Bun.serve({
fetch(req, server) {
// abort if the url contains "slow"
if (req.url.includes("slow")) {
server.abort(req);
// When aborted, the server will not error due to the lack of a `Response` object
// If you return a `Response` anyway, it will be ignored.
return;
}
return new Response("Processing...");
},
});
``` -->
### server.timeout(Request, seconds) - Custom request timeouts
Set a custom idle timeout for individual requests:
```ts
const server = Bun.serve({
fetch(req, server) {
// Set 60 second timeout for this request
server.timeout(req, 60);
// If they take longer than 60 seconds to send the body, the request will be aborted
await req.text();
return new Response("Done!");
},
});
```
Pass `0` to disable the timeout for a request.
### server.requestIP(Request) - Get client information
Get client IP and port information:
```ts
const server = Bun.serve({
fetch(req, server) {
const address = server.requestIP(req);
if (address) {
return new Response(
`Client IP: ${address.address}, Port: ${address.port}`,
);
}
return new Response("Unknown client");
},
});
```
Returns `null` for closed requests or Unix domain sockets.
## Server Metrics
### server.pendingRequests and server.pendingWebSockets
Monitor server activity with built-in counters:
```ts
const server = Bun.serve({
fetch(req, server) {
return new Response(
`Active requests: ${server.pendingRequests}\n` +
`Active WebSockets: ${server.pendingWebSockets}`,
);
},
});
```
### server.subscriberCount(topic) - WebSocket subscribers
Get count of subscribers for a WebSocket topic:
```ts
const server = Bun.serve({
fetch(req, server) {
const chatUsers = server.subscriberCount("chat");
return new Response(`${chatUsers} users in chat`);
},
websocket: {
message(ws) {
ws.subscribe("chat");
},
},
});
```
## WebSocket Configuration
### server.publish(topic, data, compress) - WebSocket Message Publishing
The server can publish messages to all WebSocket clients subscribed to a topic:
```ts
const server = Bun.serve({
websocket: {
message(ws) {
// Publish to all "chat" subscribers
server.publish("chat", "Hello everyone!");
},
},
fetch(req) {
// ...
},
});
```
The `publish()` method returns:
- Number of bytes sent if successful
- `0` if the message was dropped
- `-1` if backpressure was applied
### WebSocket Handler Options
When configuring WebSockets, several advanced options are available through the `websocket` handler:
```ts
Bun.serve({
websocket: {
// Maximum message size (in bytes)
maxPayloadLength: 64 * 1024,
// Backpressure limit before messages are dropped
backpressureLimit: 1024 * 1024,
// Close connection if backpressure limit is hit
closeOnBackpressureLimit: true,
// Handler called when backpressure is relieved
drain(ws) {
console.log("Backpressure relieved");
},
// Enable per-message deflate compression
perMessageDeflate: {
compress: true,
decompress: true,
},
// Send ping frames to keep connection alive
sendPings: true,
// Handlers for ping/pong frames
ping(ws, data) {
console.log("Received ping");
},
pong(ws, data) {
console.log("Received pong");
},
// Whether server receives its own published messages
publishToSelf: false,
},
});
```
## Benchmarks
Below are Bun and Node.js implementations of a simple HTTP server that responds `Bun!` to each incoming `Request`.
@@ -561,100 +796,174 @@ The `Bun.serve` server can handle roughly 2.5x more requests per second than Nod
{% details summary="See TypeScript definitions" %}
```ts
interface Bun {
serve(options: {
development?: boolean;
error?: (
request: ErrorLike,
) => Response | Promise<Response> | undefined | Promise<undefined>;
fetch(request: Request, server: Server): Response | Promise<Response>;
hostname?: string;
id?: string | null;
maxRequestBodySize?: number;
port?: string | number;
reusePort?: boolean;
tls?: TLSOptions | Array<TLSOptions>;
unix: string;
websocket: WebSocketHandler<WebSocketDataType>;
}): Server;
}
interface Server extends Disposable {
/**
* Stop the server from accepting new connections.
* @param closeActiveConnections If true, immediately terminates all connections
* @returns Promise that resolves when the server has stopped
*/
stop(closeActiveConnections?: boolean): Promise<void>;
interface TLSOptions {
ca?: string | Buffer | BunFile | Array<string | Buffer | BunFile> | undefined;
cert?:
| string
| Buffer
| BunFile
| Array<string | Buffer | BunFile>
| undefined;
dhParamsFile?: string;
key?:
| string
| Buffer
| BunFile
| Array<string | Buffer | BunFile>
| undefined;
lowMemoryMode?: boolean;
passphrase?: string;
secureOptions?: number | undefined;
serverName?: string;
/**
* Update handlers without restarting the server.
* Only fetch and error handlers can be updated.
*/
reload(options: Serve): void;
/**
* Make a request to the running server.
* Useful for testing or internal routing.
*/
fetch(request: Request | string): Response | Promise<Response>;
/**
* Upgrade an HTTP request to a WebSocket connection.
* @returns true if upgrade successful, false if failed
*/
upgrade<T = undefined>(
request: Request,
options?: {
headers?: Bun.HeadersInit;
data?: T;
},
): boolean;
/**
* Publish a message to all WebSocket clients subscribed to a topic.
* @returns Bytes sent, 0 if dropped, -1 if backpressure applied
*/
publish(
topic: string,
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
compress?: boolean,
): ServerWebSocketSendStatus;
/**
* Get count of WebSocket clients subscribed to a topic.
*/
subscriberCount(topic: string): number;
/**
* Get client IP address and port.
* @returns null for closed requests or Unix sockets
*/
requestIP(request: Request): SocketAddress | null;
/**
* Set custom idle timeout for a request.
* @param seconds Timeout in seconds, 0 to disable
*/
timeout(request: Request, seconds: number): void;
/**
* Keep process alive while server is running.
*/
ref(): void;
/**
* Allow process to exit if server is only thing running.
*/
unref(): void;
/** Number of in-flight HTTP requests */
readonly pendingRequests: number;
/** Number of active WebSocket connections */
readonly pendingWebSockets: number;
/** Server URL including protocol, hostname and port */
readonly url: URL;
/** Port server is listening on */
readonly port: number;
/** Hostname server is bound to */
readonly hostname: string;
/** Whether server is in development mode */
readonly development: boolean;
/** Server instance identifier */
readonly id: string;
}
interface WebSocketHandler<T = undefined> {
backpressureLimit?: number;
close?(
ws: ServerWebSocket<T>,
code: number,
reason: string,
): void | Promise<void>;
closeOnBackpressureLimit?: boolean;
drain?(ws: ServerWebSocket<T>): void | Promise<void>;
idleTimeout?: number;
/** Maximum WebSocket message size in bytes */
maxPayloadLength?: number;
message(
ws: ServerWebSocket<T>,
message: string | Buffer,
): void | Promise<void>;
open?(ws: ServerWebSocket<T>): void | Promise<void>;
/** Bytes of queued messages before applying backpressure */
backpressureLimit?: number;
/** Whether to close connection when backpressure limit hit */
closeOnBackpressureLimit?: boolean;
/** Called when backpressure is relieved */
drain?(ws: ServerWebSocket<T>): void | Promise<void>;
/** Seconds before idle timeout */
idleTimeout?: number;
/** Enable per-message deflate compression */
perMessageDeflate?:
| boolean
| {
compress?: WebSocketCompressor | boolean;
decompress?: WebSocketCompressor | boolean;
};
ping?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
pong?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
publishToSelf?: boolean;
/** Send ping frames to keep connection alive */
sendPings?: boolean;
/** Whether server receives its own published messages */
publishToSelf?: boolean;
/** Called when connection opened */
open?(ws: ServerWebSocket<T>): void | Promise<void>;
/** Called when message received */
message(
ws: ServerWebSocket<T>,
message: string | Buffer,
): void | Promise<void>;
/** Called when connection closed */
close?(
ws: ServerWebSocket<T>,
code: number,
reason: string,
): void | Promise<void>;
/** Called when ping frame received */
ping?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
/** Called when pong frame received */
pong?(ws: ServerWebSocket<T>, data: Buffer): void | Promise<void>;
}
interface Server {
fetch(request: Request | string): Response | Promise<Response>;
publish(
compress?: boolean,
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
topic: string,
): ServerWebSocketSendStatus;
ref(): void;
reload(options: Serve): void;
requestIP(request: Request): SocketAddress | null;
stop(closeActiveConnections?: boolean): void;
unref(): void;
upgrade<T = undefined>(
options?: {
data?: T;
headers?: Bun.HeadersInit;
},
request: Request,
): boolean;
interface TLSOptions {
/** Certificate authority chain */
ca?: string | Buffer | BunFile | Array<string | Buffer | BunFile>;
readonly development: boolean;
readonly hostname: string;
readonly id: string;
readonly pendingRequests: number;
readonly pendingWebSockets: number;
readonly port: number;
readonly url: URL;
/** Server certificate */
cert?: string | Buffer | BunFile | Array<string | Buffer | BunFile>;
/** Path to DH parameters file */
dhParamsFile?: string;
/** Private key */
key?: string | Buffer | BunFile | Array<string | Buffer | BunFile>;
/** Reduce TLS memory usage */
lowMemoryMode?: boolean;
/** Private key passphrase */
passphrase?: string;
/** OpenSSL options flags */
secureOptions?: number;
/** Server name for SNI */
serverName?: string;
}
```

View File

@@ -1,12 +1,12 @@
As of Bun v1.1.44, we've added initial support for bundling frontend apps directly in Bun's HTTP server: `Bun.serve()`. Run your frontend and backend in the same app with no extra steps.
Using `Bun.serve()`'s `static` option, you can run your frontend and backend in the same app with no extra steps.
To get started, import your HTML files and pass them to the `static` option in `Bun.serve()`.
To get started, import HTML files and pass them to the `static` option in `Bun.serve()`.
```ts
import dashboard from "./dashboard.html";
import homepage from "./index.html";
Bun.serve({
const server = Bun.serve({
// Add HTML imports to `static`
static: {
// Bundle & route index.html to "/"
@@ -32,6 +32,8 @@ Bun.serve({
return new Response("Not Found", { status: 404 });
},
});
console.log(`Listening on ${server.url}`);
```
```bash
@@ -107,7 +109,7 @@ To use React in your client-side code, import `react-dom/client` and render your
{% codetabs %}
```ts#src/backend.ts
import dashboard from "./public/dashboard.html";
import dashboard from "../public/dashboard.html";
import { serve } from "bun";
serve({
@@ -204,18 +206,20 @@ To configure plugins for `Bun.serve`, add a `plugins` array in the `[serve.stati
### Using TailwindCSS in HTML routes
For example, enable TailwindCSS on your routes by adding add the `bun-plugin-tailwind` plugin:
For example, enable TailwindCSS on your routes by installing and adding the `bun-plugin-tailwind` plugin:
```toml
```sh
$ bun add bun-plugin-tailwind
```
```toml#bunfig.toml
[serve.static]
plugins = ["bun-plugin-tailwind"]
```
This will allow you to use TailwindCSS utility classes in your HTML and CSS files. All you need to do is import `tailwindcss` somewhere:
```html
<!-- index.html -->
```html#index.html
<!doctype html>
<html>
<head>
@@ -230,14 +234,15 @@ This will allow you to use TailwindCSS utility classes in your HTML and CSS file
Or in your CSS:
```css
/* style.css */
```css#style.css
@import "tailwindcss";
```
### Custom plugins
Any JS file or module which exports a [valid bundler plugin object](https://bun.sh/docs/bundler/plugins#usage) (essentially an object with a `name` and `setup` field) can be placed inside the `plugins` array:
```toml
```toml#bunfig.toml
[serve.static]
plugins = ["./my-plugin-implementation.ts"]
```

View File

@@ -1,4 +1,4 @@
As of Bun v1.1.43, Bun's bundler now has first-class support for HTML. Build static sites, landing pages, and web applications with zero configuration. Just point Bun at your HTML file and it handles everything else.
Bun's bundler has first-class support for HTML. Build static sites, landing pages, and web applications with zero configuration. Just point Bun at your HTML file and it handles everything else.
```html#index.html
<!doctype html>
@@ -13,45 +13,228 @@ As of Bun v1.1.43, Bun's bundler now has first-class support for HTML. Build sta
</html>
```
One command is all you need (won't be experimental after Bun v1.2):
To get started, pass HTML files to `bun`.
{% bunDevServerTerminal alt="bun ./index.html" path="./index.html" routes="" /%}
Bun's development server provides powerful features with zero configuration:
- **Automatic Bundling** - Bundles and serves your HTML, JavaScript, and CSS
- **Multi-Entry Support** - Handles multiple HTML entry points and glob entry points
- **Modern JavaScript** - TypeScript & JSX support out of the box
- **Smart Configuration** - Reads `tsconfig.json` for paths, JSX options, experimental decorators, and more
- **Plugins** - Plugins for TailwindCSS and more
- **ESM & CommonJS** - Use ESM and CommonJS in your JavaScript, TypeScript, and JSX files
- **CSS Bundling & Minification** - Bundles CSS from `<link>` tags and `@import` statements
- **Asset Management**
- Automatic copying & hashing of images and assets
- Rewrites asset paths in JavaScript, CSS, and HTML
## Single Page Apps (SPA)
When you pass a single .html file to Bun, Bun will use it as a fallback route for all paths. This makes it perfect for single page apps that use client-side routing:
{% bunDevServerTerminal alt="bun index.html" path="index.html" routes="" /%}
Your React or other SPA will work out of the box — no configuration needed. All routes like `/about`, `/users/123`, etc. will serve the same HTML file, letting your client-side router handle the navigation.
```html#index.html
<!doctype html>
<html>
<head>
<title>My SPA</title>
<script src="./app.tsx" type="module"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
```
## Multi-page apps (MPA)
Some projects have several separate routes or HTML files as entry points. To support multiple entry points, pass them all to `bun`
{% bunDevServerTerminal alt="bun ./index.html ./about.html" path="./index.html ./about.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
This will serve:
- `index.html` at `/`
- `about.html` at `/about`
### Glob patterns
To specify multiple files, you can use glob patterns that end in `.html`:
{% bunDevServerTerminal alt="bun ./**/*.html" path="./**/*.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about.html\"}]" /%}
### Path normalization
The base path is chosen from the longest common prefix among all the files.
{% bunDevServerTerminal alt="bun ./index.html ./about/index.html ./about/foo/index.html" path="./index.html ./about/index.html ./about/foo/index.html" routes="[{\"path\": \"/\", \"file\": \"./index.html\"}, {\"path\": \"/about\", \"file\": \"./about/index.html\"}, {\"path\": \"/about/foo\", \"file\": \"./about/foo/index.html\"}]" /%}
## JavaScript, TypeScript, and JSX
Bun's transpiler natively implements JavaScript, TypeScript, and JSX support. [Learn more about loaders in Bun](/docs/bundler/loaders).
Bun's transpiler is also used at runtime.
### ES Modules & CommonJS
You can use ESM and CJS in your JavaScript, TypeScript, and JSX files. Bun will handle the transpilation and bundling automatically.
There is no pre-build or separate optimization step. It's all done at the same time.
Learn more about [module resolution in Bun](/docs/runtime/modules).
## CSS
Bun's CSS parser is also natively implemented (clocking in around 58,000 lines of Zig).
It's also a CSS bundler. You can use `@import` in your CSS files to import other CSS files.
For example:
```css#styles.css
@import "./abc.css";
.container {
background-color: blue;
}
```
```css#abc.css
body {
background-color: red;
}
```
This outputs:
```css#styles.css
body {
background-color: red;
}
.container {
background-color: blue;
}
```
### Referencing local assets in CSS
You can reference local assets in your CSS files.
```css#styles.css
body {
background-image: url("./logo.png");
}
```
This will copy `./logo.png` to the output directory and rewrite the path in the CSS file to include a content hash.
```css#styles.css
body {
background-image: url("./logo-[ABC123].png");
}
```
### Importing CSS in JavaScript
To associate a CSS file with a JavaScript file, you can import it in your JavaScript file.
```ts#app.ts
import "./styles.css";
import "./more-styles.css";
```
This generates `./app.css` and `./app.js` in the output directory. All CSS files imported from JavaScript will be bundled into a single CSS file per entry point. If you import the same CSS file from multiple JavaScript files, it will only be included once in the output CSS file.
## Plugins
The dev server supports plugins.
### Tailwind CSS
To use TailwindCSS, install the `bun-plugin-tailwind` plugin:
```bash
# Or any npm client
$ bun install --dev bun-plugin-tailwind
```
Then, add the plugin to your `bunfig.toml`:
```toml
[serve.static]
plugins = ["bun-plugin-tailwind"]
```
Then, reference TailwindCSS in your HTML via `<link>` tag, `@import` in CSS, or `import` in JavaScript.
{% codetabs %}
```html#index.html
<!-- Reference TailwindCSS in your HTML -->
<link rel="stylesheet" href="tailwindcss" />
```
```css#styles.css
/* Import TailwindCSS in your CSS */
@import "tailwindcss";
```
```ts#app.ts
/* Import TailwindCSS in your JavaScript */
import "tailwindcss";
```
{% /codetabs %}
Only one of those are necessary, not all three.
## Keyboard Shortcuts
While the server is running:
- `o + Enter` - Open in browser
- `c + Enter` - Clear console
- `q + Enter` (or Ctrl+C) - Quit server
## Build for Production
When you're ready to deploy, use `bun build` to create optimized production bundles:
{% codetabs %}
```bash#CLI
$ bun build ./index.html --outdir=dist
$ bun build ./index.html --minify --outdir=dist
```
```ts#API
Bun.build({
entrypoints: ["./index.html"],
outdir: "./dist",
minify: {
whitespace: true,
identifiers: true,
syntax: true,
}
});
```
{% /codetabs %}
Bun automatically:
Currently, plugins are only supported through `Bun.build`'s API or through `bunfig.toml` with the frontend dev server - not yet supported in `bun build`'s CLI.
- Bundles, tree-shakes, and optimizes your JavaScript, JSX and TypeScript
- Bundles and optimizes your CSS
- Copies & hashes images and other assets
- Updates all references to local files or packages in your HTML
### Watch Mode
## Zero Config, Maximum Performance
The HTML bundler is enabled by default after Bun v1.2+. Drop in your existing HTML files and Bun will handle:
- **TypeScript & JSX** - Write modern JavaScript for browsers without the setup
- **CSS** - Bundle CSS stylesheets directly from `<link rel="stylesheet">` or `@import`
- **Images & Assets** - Automatic copying & hashing & rewriting of assets in JavaScript, CSS, and HTML
## Watch mode
You can run `bun build --watch` to watch for changes and rebuild automatically.
You can run `bun build --watch` to watch for changes and rebuild automatically. This works nicely for library development.
You've never seen a watch mode this fast.
## Plugin API
### Plugin API
Need more control? Configure the bundler through the JavaScript API and use Bun's builtin `HTMLRewriter` to preprocess HTML.
@@ -102,3 +285,22 @@ Bun automatically handles all common web assets:
- Any `<link>` tag with an `href` attribute pointing to a local file is rewritten to the new path, and hashed
All paths are resolved relative to your HTML file, making it easy to organize your project however you want.
## This is a work in progress
- No HMR support yet
- Need more plugins
- Need more configuration options for things like asset handling
- Need a way to configure CORS, headers, etc.
If you want to submit a PR, most of the [code is here](https://github.com/oven-sh/bun/blob/main/src/js/internal/html.ts). You could even copy paste that file into your project and use it as a starting point.
## How this works
This is a small wrapper around Bun's support for HTML imports in JavaScript.
### Adding a backend to your frontend
To add a backend to your frontend, you can use the `"static"` option in `Bun.serve`.
Learn more in [the full-stack docs](/docs/bundler/fullstack).

View File

@@ -98,7 +98,7 @@ import { Database } from "bun:sqlite";
const sqlite = new Database("sqlite.db");
const db = drizzle(sqlite);
await migrate(db, { migrationsFolder: "./drizzle" });
migrate(db, { migrationsFolder: "./drizzle" });
```
---

View File

@@ -35,7 +35,7 @@ jobs:
# ...
- uses: oven-sh/setup-bun@v2
+ with:
+ bun-version: 1.0.11 # or "latest", "canary", <sha>
+ bun-version: 1.2.0 # or "latest", "canary", <sha>
```
---

View File

@@ -214,7 +214,7 @@ export default {
page("bundler", "`Bun.build`", {
description: "Bundle code for consumption in the browser with Bun's native bundler.",
}),
page("bundler/html", "HTML", {
page("bundler/html", "Frontend & static sites", {
description: `Bundle html files with Bun's native bundler.`,
}),
page("bundler/fullstack", "Fullstack Dev Server", {

View File

@@ -180,6 +180,25 @@ Whether to skip test files when computing coverage statistics. Default `false`.
coverageSkipTestFiles = false
```
### `test.coverageReporter`
By default, coverage reports will be printed to the console. For persistent code coverage reports in CI environments and for other tools use `lcov`.
```toml
[test]
coverageReporter = ["text", "lcov"] # default ["text"]
```
### `test.coverageDir`
Set path where coverage reports will be saved. Please notice, that it works only for persistent `coverageReporter` like `lcov`.
```toml
[test]
coverageDir = "path/to/somewhere" # default "coverage"
```
## Package manager
Package management is a complex issue; to support a range of use cases, the behavior of `bun install` can be configured under the `[install]` section.

View File

@@ -58,3 +58,82 @@ export const foo = "Hello world!"
```
{% /codetabs %}
## Experimental Decorators
Bun supports the pre-TypeScript 5.0 experimental decorators syntax.
```ts#hello.ts
// Simple logging decorator
function log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args: any[]) {
console.log(`Calling ${propertyKey} with:`, args);
return originalMethod.apply(this, args);
};
}
class Example {
@log
greet(name: string) {
return `Hello ${name}!`;
}
}
// Usage
const example = new Example();
example.greet("world"); // Logs: "Calling greet with: ['world']"
```
To enable it, add `"experimentalDecorators": true` to your `tsconfig.json`:
```jsonc#tsconfig.json
{
"compilerOptions": {
// ... rest of your config
"experimentalDecorators": true,
},
}
```
We generally don't recommend using this in new codebases, but plenty of existing codebases have come to rely on it.
### emitDecoratorMetadata
Bun supports `emitDecoratorMetadata` in your `tsconfig.json`. This enables emitting design-time type metadata for decorated declarations in source files.
```ts#emit-decorator-metadata.ts
import "reflect-metadata";
class User {
id: number;
name: string;
}
function Injectable(target: Function) {
// Get metadata about constructor parameters
const params = Reflect.getMetadata("design:paramtypes", target);
console.log("Dependencies:", params); // [User]
}
@Injectable
class UserService {
constructor(private user: User) {}
}
// Creates new UserService instance with dependencies
const container = new UserService(new User());
```
To enable it, add `"emitDecoratorMetadata": true` to your `tsconfig.json`:
```jsonc#tsconfig.json
{
"compilerOptions": {
// ... rest of your config
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
},
}
```

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "macros",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "simple-react",
@@ -1659,7 +1659,7 @@
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"ws": ["ws@7.5.9", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="],
"ws": ["ws@7.5.9", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q=="],
"xml-name-validator": ["xml-name-validator@3.0.0", "", {}, "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="],

View File

@@ -20,6 +20,7 @@
"build",
"test/snapshots/**",
"bench/react-hello-world/*.js",
"bun.lock",
"test/js/node/**/parallel/**",
"test/js/node/test/fixtures", // full of JS with intentional syntax errors

View File

@@ -1,7 +1,7 @@
{
"private": true,
"name": "bun",
"version": "1.2.1",
"version": "1.2.3",
"workspaces": [
"./packages/bun-types"
],
@@ -22,8 +22,8 @@
"react-dom": "^18.3.1",
"source-map-js": "^1.2.0",
"typescript": "^5.7.2",
"caniuse-lite": "^1.0.30001620",
"autoprefixer": "^10.4.19",
"caniuse-lite": "^1.0.30001660",
"autoprefixer": "^10.4.20",
"@mdn/browser-compat-data": "~5.5.28"
},
"resolutions": {

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-debug-adapter-protocol",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "web-inspector-bun",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-inspector-protocol",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {
@@ -26,7 +26,7 @@
"@types/p-queue": ["@types/p-queue@3.2.1", "", { "dependencies": { "p-queue": "*" } }, "sha512-tgAdn5zEs05NuHzOyRM34cMO0rczStphR/kLo/ZJwwwJ5S2+QVxwA6gST3vDHWPB1oDfUuT6wOouhJvJkBCA0w=="],
"bun": ["bun@workspace:runners/bun", {}],
"bun": ["bun@workspace:runners/bun"],
"bun-types": ["bun-types@1.0.4-canary.20230929T233451", "", {}, "sha512-Ke/y3GX0T2ZYKx0UKKCnFRRP9bXzVRcRZCrIlF5/aRNEpgbfrMBw+s5imPqrV2CqJ7q6kIbMikCahzMr4N9PTg=="],
@@ -38,7 +38,7 @@
"prettier": ["prettier@2.8.8", "", { "bin": { "prettier": "bin-prettier.js" } }, "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q=="],
"qunit": ["qunit@workspace:runners/qunit", {}],
"qunit": ["qunit@workspace:runners/qunit"],
"tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="],

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {

View File

@@ -2,16 +2,12 @@
name = "bun-native-plugin"
description = "Rustified wrapper for writing native plugins for Bun."
license = "MIT"
version = "0.1.2"
version = "0.2.0"
edition = "2021"
[dependencies]
anyhow = "1.0.94"
# use local path in dev and publish to crates.io in prod
bun-macro = { path = "./bun-macro", version = "0.1.0" }
napi = { version = "2.14.1", default-features = false, features = ["napi4"] }
[features]
default = ["napi"]
napi = []

View File

@@ -473,6 +473,10 @@ impl<'a> OnBeforeParse<'a> {
}
}
/// # Safety
/// This is unsafe as you must ensure that no other invocation of the plugin (or JS!)
/// simultaneously holds a mutable reference to the external.
///
/// Get the external object from the `OnBeforeParse` arguments.
///
/// The external object is set by the plugin definition inside of JS:
@@ -521,42 +525,35 @@ impl<'a> OnBeforeParse<'a> {
/// },
/// };
/// ```
pub unsafe fn external<T: 'static + Sync>(&self) -> PluginResult<Option<&'static T>> {
pub unsafe fn external<'b, T: 'static + Sync>(
&self,
from_raw: unsafe fn(*mut c_void) -> Option<&'b T>,
) -> PluginResult<Option<&'b T>> {
if unsafe { (*self.args_raw).external.is_null() } {
return Ok(None);
}
let external: *mut TaggedObject<T> =
unsafe { (*self.args_raw).external as *mut TaggedObject<T> };
let external = unsafe { from_raw((*self.args_raw).external as *mut _) };
unsafe {
if (*external).type_id != TypeId::of::<T>() {
return Err(Error::ExternalTypeMismatch);
}
Ok((*external).object.as_ref())
}
Ok(external)
}
/// The same as [`crate::bun_native_plugin::OnBeforeParse::external`], but returns a mutable reference.
///
/// This is unsafe as you must ensure that no other invocation of the plugin
/// # Safety
/// This is unsafe as you must ensure that no other invocation of the plugin (or JS!)
/// simultaneously holds a mutable reference to the external.
pub unsafe fn external_mut<T: 'static + Sync>(&mut self) -> PluginResult<Option<&mut T>> {
pub unsafe fn external_mut<'b, T: 'static + Sync>(
&mut self,
from_raw: unsafe fn(*mut c_void) -> Option<&'b mut T>,
) -> PluginResult<Option<&'b mut T>> {
if unsafe { (*self.args_raw).external.is_null() } {
return Ok(None);
}
let external: *mut TaggedObject<T> =
unsafe { (*self.args_raw).external as *mut TaggedObject<T> };
let external = unsafe { from_raw((*self.args_raw).external as *mut _) };
unsafe {
if (*external).type_id != TypeId::of::<T>() {
return Err(Error::ExternalTypeMismatch);
}
Ok((*external).object.as_mut())
}
Ok(external)
}
/// Get the input source code for the current file.

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-plugin",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-polyfills",

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {

View File

@@ -2009,35 +2009,51 @@ declare module "bun" {
*/
type SQLOptions = {
/** Connection URL (can be string or URL object) */
url: URL | string;
url?: URL | string;
/** Database server hostname */
host: string;
host?: string;
/** Database server hostname (alias for host) */
hostname?: string;
/** Database server port number */
port: number | string;
port?: number | string;
/** Database user for authentication */
username: string;
username?: string;
/** Database user for authentication (alias for username) */
user?: string;
/** Database password for authentication */
password: string;
password?: string;
/** Database password for authentication (alias for password) */
pass?: string;
/** Name of the database to connect to */
database: string;
database?: string;
/** Name of the database to connect to (alias for database) */
db?: string;
/** Database adapter/driver to use */
adapter: string;
/** Maximum time in milliseconds to wait for connection to become available */
idleTimeout: number;
/** Maximum time in milliseconds to wait when establishing a connection */
connectionTimeout: number;
/** Maximum lifetime in milliseconds of a connection */
maxLifetime: number;
adapter?: string;
/** Maximum time in seconds to wait for connection to become available */
idleTimeout?: number;
/** Maximum time in seconds to wait for connection to become available (alias for idleTimeout) */
idle_timeout?: number;
/** Maximum time in seconds to wait when establishing a connection */
connectionTimeout?: number;
/** Maximum time in seconds to wait when establishing a connection (alias for connectionTimeout) */
connection_timeout?: number;
/** Maximum lifetime in seconds of a connection */
maxLifetime?: number;
/** Maximum lifetime in seconds of a connection (alias for maxLifetime) */
max_lifetime?: number;
/** Whether to use TLS/SSL for the connection */
tls: boolean;
tls?: TLSOptions | boolean;
/** Whether to use TLS/SSL for the connection (alias for tls) */
ssl?: TLSOptions | boolean;
/** Callback function executed when a connection is established */
onconnect: (client: SQL) => void;
onconnect?: (client: SQL) => void;
/** Callback function executed when a connection is closed */
onclose: (client: SQL) => void;
onclose?: (client: SQL) => void;
/** Maximum number of connections in the pool */
max: number;
max?: number;
/** By default values outside i32 range are returned as strings. If this is true, values outside i32 range are returned as BigInts. */
bigint: boolean;
bigint?: boolean;
};
/**

View File

@@ -27,7 +27,7 @@
},
"scripts": {
"prebuild": "echo $(pwd)",
"copy-docs": "rm -rf docs && cp -rL ../../docs/ ./docs && sed -i 's/\\$BUN_LATEST_VERSION/'\"${BUN_VERSION:-1.0.0}\"'/g' ./docs/**/*.md",
"copy-docs": "rm -rf docs && cp -rL ../../docs/ ./docs && find ./docs -type f -name '*.md' -exec sed -i 's/\\$BUN_LATEST_VERSION/'\"${BUN_VERSION#bun-v:-1.0.0}\"'/g' {} +",
"build": "bun run copy-docs && bun scripts/build.ts && bun run fmt",
"test": "tsc",
"fmt": "echo $(which biome) && biome format --write ."

View File

@@ -387,8 +387,15 @@ int bsd_socket_multicast_interface(LIBUS_SOCKET_DESCRIPTOR fd, const struct sock
static int bsd_socket_set_membership4(LIBUS_SOCKET_DESCRIPTOR fd, const struct sockaddr_in *addr, const struct sockaddr_in *iface, int drop) {
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
mreq.imr_interface.s_addr = iface->sin_addr.s_addr;
if (iface != NULL) {
mreq.imr_interface.s_addr = iface->sin_addr.s_addr;
} else {
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
}
int option = drop ? IP_DROP_MEMBERSHIP : IP_ADD_MEMBERSHIP;
return setsockopt(fd, IPPROTO_IP, option, &mreq, sizeof(mreq));
}
@@ -397,13 +404,15 @@ static int bsd_socket_set_membership6(LIBUS_SOCKET_DESCRIPTOR fd, const struct s
struct ipv6_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.ipv6mr_multiaddr = addr->sin6_addr;
mreq.ipv6mr_interface = iface->sin6_scope_id;
if (iface != NULL) {
mreq.ipv6mr_interface = iface->sin6_scope_id;
}
int option = drop ? IPV6_LEAVE_GROUP : IPV6_JOIN_GROUP;
return setsockopt(fd, IPPROTO_IP, option, &mreq, sizeof(mreq));
}
int bsd_socket_set_membership(LIBUS_SOCKET_DESCRIPTOR fd, const struct sockaddr_storage *addr, const struct sockaddr_storage *iface, int drop) {
if (addr->ss_family != iface->ss_family) {
if (iface != NULL && addr->ss_family != iface->ss_family) {
errno = EINVAL;
return -1;
}

View File

@@ -1589,22 +1589,40 @@ struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix(
socket_ext_size, error);
}
// https://github.com/oven-sh/bun/issues/16995
static void us_internal_zero_ssl_data_for_connected_socket_before_onopen(struct us_internal_ssl_socket_t *s) {
s->ssl = NULL;
s->ssl_write_wants_read = 0;
s->ssl_read_wants_write = 0;
s->fatal_error = 0;
s->handshake_state = HANDSHAKE_PENDING;
}
// TODO does this need more changes?
struct us_connecting_socket_t *us_internal_ssl_socket_context_connect(
struct us_socket_t *us_internal_ssl_socket_context_connect(
struct us_internal_ssl_socket_context_t *context, const char *host,
int port, int options, int socket_ext_size, int* is_connected) {
return us_socket_context_connect(
int port, int options, int socket_ext_size, int* is_connecting) {
struct us_internal_ssl_socket_t *s = (struct us_internal_ssl_socket_t *)us_socket_context_connect(
2, &context->sc, host, port, options,
sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) +
socket_ext_size, is_connected);
socket_ext_size, is_connecting);
if (*is_connecting) {
us_internal_zero_ssl_data_for_connected_socket_before_onopen(s);
}
return (struct us_socket_t*)s;
}
struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_connect_unix(
struct us_socket_t *us_internal_ssl_socket_context_connect_unix(
struct us_internal_ssl_socket_context_t *context, const char *server_path,
size_t pathlen, int options, int socket_ext_size) {
return (struct us_internal_ssl_socket_t *)us_socket_context_connect_unix(
struct us_socket_t *s = (struct us_socket_t *)us_socket_context_connect_unix(
0, &context->sc, server_path, pathlen, options,
sizeof(struct us_internal_ssl_socket_t) - sizeof(struct us_socket_t) +
socket_ext_size);
if (s) {
us_internal_zero_ssl_data_for_connected_socket_before_onopen((struct us_internal_ssl_socket_t*) s);
}
return s;
}
static void ssl_on_open_without_sni(struct us_internal_ssl_socket_t *s, int is_client, char *ip, int ip_length) {

View File

@@ -247,7 +247,7 @@ void us_loop_run(struct us_loop_t *loop) {
}
}
extern int Bun__JSC_onBeforeWait(void*);
extern void Bun__JSC_onBeforeWait(void*);
extern void Bun__JSC_onAfterWait(void*);
void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout) {
@@ -265,10 +265,8 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
/* Emit pre callback */
us_internal_loop_pre(loop);
int needs_after_wait = 0;
if (loop->data.jsc_vm) {
needs_after_wait = Bun__JSC_onBeforeWait(loop->data.jsc_vm);
}
/* Safe if jsc_vm is NULL */
Bun__JSC_onBeforeWait(loop->data.jsc_vm);
/* Fetch ready polls */
#ifdef LIBUS_USE_EPOLL
@@ -280,9 +278,7 @@ void us_loop_run_bun_tick(struct us_loop_t *loop, const struct timespec* timeout
} while (IS_EINTR(loop->num_ready_polls));
#endif
if (needs_after_wait) {
Bun__JSC_onAfterWait(loop->data.jsc_vm);
}
Bun__JSC_onAfterWait(loop->data.jsc_vm);
/* Iterate ready polls, dispatching them by type */
for (loop->current_ready_poll = 0; loop->current_ready_poll < loop->num_ready_polls; loop->current_ready_poll++) {

View File

@@ -400,11 +400,11 @@ struct us_listen_socket_t *us_internal_ssl_socket_context_listen_unix(
us_internal_ssl_socket_context_r context, const char *path,
size_t pathlen, int options, int socket_ext_size, int* error);
struct us_connecting_socket_t *us_internal_ssl_socket_context_connect(
struct us_socket_t *us_internal_ssl_socket_context_connect(
us_internal_ssl_socket_context_r context, const char *host,
int port, int options, int socket_ext_size, int* is_resolved);
struct us_internal_ssl_socket_t *us_internal_ssl_socket_context_connect_unix(
struct us_socket_t *us_internal_ssl_socket_context_connect_unix(
us_internal_ssl_socket_context_r context, const char *server_path,
size_t pathlen, int options, int socket_ext_size);

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "mock-debug",
@@ -148,9 +148,9 @@
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
"bun-debug-adapter-protocol": ["bun-debug-adapter-protocol@workspace:../bun-debug-adapter-protocol", { "dependencies": { "semver": "^7.5.4", "source-map-js": "^1.0.2" } }],
"bun-debug-adapter-protocol": ["bun-debug-adapter-protocol@workspace:../bun-debug-adapter-protocol"],
"bun-inspector-protocol": ["bun-inspector-protocol@workspace:../bun-inspector-protocol", { "dependencies": { "ws": "^8.13.0" } }],
"bun-inspector-protocol": ["bun-inspector-protocol@workspace:../bun-inspector-protocol"],
"bun-types": ["bun-types@1.1.29", "", { "dependencies": { "@types/node": "~20.12.8", "@types/ws": "~8.5.10" } }, "sha512-En3/TzSPMPyl5UlUB1MHzHpcrZDakTm7mS203eLoX1fBoEa3PW+aSS8GAqVJ7Is/m34Z5ogL+ECniLY0uDaCPw=="],

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"dependencies": {

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-wasm",

View File

@@ -3,7 +3,6 @@ pub usingnamespace @import("src/main_wasm.zig");
pub const bun = @import("src/bun.zig");
pub const completions = struct {};
pub const is_bindgen = true;
pub const JavaScriptCore = struct {
pub fn markBinding(_: @import("std").builtin.SourceLocation) void {
unreachable;

View File

@@ -765,7 +765,7 @@ install_nodejs_headers() {
}
bun_version_exact() {
print "1.1.38"
print "1.2.0"
}
install_bun() {

View File

@@ -170,13 +170,13 @@ pub inline fn configureAllocator(_: AllocatorConfiguration) void {
}
pub fn notimpl() noreturn {
@setCold(true);
@branchHint(.cold);
Output.panic("Not implemented yet!!!!!", .{});
}
// Make sure we always print any leftover
pub fn crash() noreturn {
@setCold(true);
@branchHint(.cold);
Global.exit(1);
}

View File

@@ -164,7 +164,7 @@ const FutexImpl = struct {
}
fn lockSlow(self: *@This()) void {
@setCold(true);
@branchHint(.cold);
// Avoid doing an atomic swap below if we already know the state is contended.
// An atomic swap unconditionally stores which marks the cache-line as modified unnecessarily.

View File

@@ -36,6 +36,17 @@ pub const StandaloneModuleGraph = struct {
pub const base_public_path = targetBasePublicPath(Environment.os, "");
pub const base_public_path_with_default_suffix = targetBasePublicPath(Environment.os, "root/");
const Instance = struct {
pub var instance: ?*StandaloneModuleGraph = null;
};
pub fn get() ?*StandaloneModuleGraph {
return Instance.instance;
}
pub fn set(instance: *StandaloneModuleGraph) void {
Instance.instance = instance;
}
pub fn targetBasePublicPath(target: Environment.OperatingSystem, comptime suffix: [:0]const u8) [:0]const u8 {
return switch (target) {
@@ -62,10 +73,16 @@ pub const StandaloneModuleGraph = struct {
return this.findAssumeStandalonePath(name);
}
pub fn stat(this: *const StandaloneModuleGraph, name: []const u8) ?bun.Stat {
const file = this.find(name) orelse return null;
return file.stat();
}
pub fn findAssumeStandalonePath(this: *const StandaloneModuleGraph, name: []const u8) ?*File {
if (Environment.isWindows) {
var normalized_buf: bun.PathBuffer = undefined;
const normalized = bun.path.platformToPosixBuf(u8, name, &normalized_buf);
const input = strings.withoutNTPrefix(u8, name);
const normalized = bun.path.platformToPosixBuf(u8, input, &normalized_buf);
return this.files.getPtr(normalized);
}
return this.files.getPtr(name);
@@ -107,6 +124,13 @@ pub const StandaloneModuleGraph = struct {
bytecode: []u8 = "",
module_format: ModuleFormat = .none,
pub fn stat(this: *const File) bun.Stat {
var result = std.mem.zeroes(bun.Stat);
result.size = @intCast(this.contents.len);
result.mode = bun.S.IFREG | 0o644;
return result;
}
pub fn lessThanByIndex(ctx: []const File, lhs_i: u32, rhs_i: u32) bool {
const lhs = ctx[lhs_i];
const rhs = ctx[rhs_i];

View File

@@ -333,11 +333,11 @@ fn appendFileAssumeCapacity(
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
var event = std.mem.zeroes(KEvent);
event.flags = std.c.EV_ADD | std.c.EV_CLEAR | std.c.EV_ENABLE;
event.flags = std.c.EV.ADD | std.c.EV.CLEAR | std.c.EV.ENABLE;
// we want to know about the vnode
event.filter = std.c.EVFILT_VNODE;
event.filter = std.c.EVFILT.VNODE;
event.fflags = std.c.NOTE_WRITE | std.c.NOTE_RENAME | std.c.NOTE_DELETE;
event.fflags = std.c.NOTE.WRITE | std.c.NOTE.RENAME | std.c.NOTE.DELETE;
// id
event.ident = @intCast(fd.int());
@@ -425,15 +425,15 @@ fn appendDirectoryAssumeCapacity(
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/kqueue.2.html
var event = std.mem.zeroes(KEvent);
event.flags = std.c.EV_ADD | std.c.EV_CLEAR | std.c.EV_ENABLE;
event.flags = std.c.EV.ADD | std.c.EV.CLEAR | std.c.EV.ENABLE;
// we want to know about the vnode
event.filter = std.c.EVFILT_VNODE;
event.filter = std.c.EVFILT.VNODE;
// monitor:
// - Write
// - Rename
// - Delete
event.fflags = std.c.NOTE_WRITE | std.c.NOTE_RENAME | std.c.NOTE_DELETE;
event.fflags = std.c.NOTE.WRITE | std.c.NOTE.RENAME | std.c.NOTE.DELETE;
// id
event.ident = @intCast(fd.int());

View File

@@ -20,7 +20,7 @@ const Analytics = @import("./analytics_schema.zig").analytics;
const Writer = @import("./analytics_schema.zig").Writer;
const Headers = bun.http.Headers;
const Futex = @import("../futex.zig");
const Semver = @import("../install/semver.zig");
const Semver = bun.Semver;
/// Enables analytics. This is used by:
/// - crash_handler.zig's `report` function to anonymously report crashes
@@ -122,10 +122,12 @@ pub const Features = struct {
pub var workers_terminated: usize = 0;
pub var napi_module_register: usize = 0;
pub var process_dlopen: usize = 0;
pub var postgres_connections: usize = 0;
pub var s3: usize = 0;
comptime {
@export(napi_module_register, .{ .name = "Bun__napi_module_register_count" });
@export(process_dlopen, .{ .name = "Bun__process_dlopen_count" });
@export(&napi_module_register, .{ .name = "Bun__napi_module_register_count" });
@export(&process_dlopen, .{ .name = "Bun__process_dlopen_count" });
}
pub fn formatter() Formatter {
@@ -136,14 +138,14 @@ pub const Features = struct {
pub fn format(_: Formatter, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
const fields = comptime brk: {
const info: std.builtin.Type = @typeInfo(Features);
var buffer: [info.Struct.decls.len][]const u8 = .{""} ** info.Struct.decls.len;
var buffer: [info.@"struct".decls.len][]const u8 = .{""} ** info.@"struct".decls.len;
var count: usize = 0;
for (info.Struct.decls) |decl| {
for (info.@"struct".decls) |decl| {
var f = &@field(Features, decl.name);
_ = &f;
const Field = @TypeOf(f);
const FieldT: std.builtin.Type = @typeInfo(Field);
if (FieldT.Pointer.child != usize) continue;
if (FieldT.pointer.child != usize) continue;
buffer[count] = decl.name;
count += 1;
}
@@ -214,7 +216,7 @@ pub const packed_features_list = brk: {
};
pub const PackedFeatures = @Type(.{
.Struct = .{
.@"struct" = .{
.layout = .@"packed",
.backing_integer = u64,
.fields = brk: {
@@ -224,7 +226,7 @@ pub const PackedFeatures = @Type(.{
fields[i] = .{
.name = name,
.type = bool,
.default_value = &false,
.default_value_ptr = &false,
.is_comptime = false,
.alignment = 0,
};
@@ -234,7 +236,7 @@ pub const PackedFeatures = @Type(.{
fields[i] = .{
.name = std.fmt.comptimePrint("_{d}", .{i}),
.type = bool,
.default_value = &false,
.default_value_ptr = &false,
.is_comptime = false,
.alignment = 0,
};

View File

@@ -1,5 +1,5 @@
{
"lockfileVersion": 0,
"lockfileVersion": 1,
"workspaces": {
"": {
"name": "bun-api",

View File

@@ -1702,6 +1702,9 @@ pub const Api = struct {
/// [serve.static]
/// plugins = ["tailwindcss"]
serve_plugins: ?[]const []const u8 = null,
serve_minify_syntax: ?bool = null,
serve_minify_whitespace: ?bool = null,
serve_minify_identifiers: ?bool = null,
bunfig_path: []const u8,
pub fn decode(reader: anytype) anyerror!TransformOptions {

View File

@@ -62,7 +62,7 @@ pub const Index = packed struct(u32) {
pub fn init(num: anytype) Index {
const NumType = @TypeOf(num);
if (comptime @typeInfo(NumType) == .Pointer) {
if (comptime @typeInfo(NumType) == .pointer) {
return init(num.*);
}

View File

@@ -366,42 +366,42 @@ pub const FilePoll = struct {
// var loader = ptr.as(ShellSubprocessCapturedBufferedWriterMini);
// loader.onPoll(size_or_offset, 0);
// },
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(ShellBufferedWriter))) => {
@field(Owner.Tag, @typeName(ShellBufferedWriter)) => {
var handler: *ShellBufferedWriter = ptr.as(ShellBufferedWriter);
handler.onPoll(size_or_offset, poll.flags.contains(.hup));
},
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(ShellStaticPipeWriter))) => {
@field(Owner.Tag, @typeName(ShellStaticPipeWriter)) => {
var handler: *ShellStaticPipeWriter = ptr.as(ShellStaticPipeWriter);
handler.onPoll(size_or_offset, poll.flags.contains(.hup));
},
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(StaticPipeWriter))) => {
@field(Owner.Tag, @typeName(StaticPipeWriter)) => {
var handler: *StaticPipeWriter = ptr.as(StaticPipeWriter);
handler.onPoll(size_or_offset, poll.flags.contains(.hup));
},
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(FileSink))) => {
@field(Owner.Tag, @typeName(FileSink)) => {
var handler: *FileSink = ptr.as(FileSink);
handler.onPoll(size_or_offset, poll.flags.contains(.hup));
},
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(BufferedReader))) => {
@field(Owner.Tag, @typeName(BufferedReader)) => {
log("onUpdate " ++ kqueue_or_epoll ++ " (fd: {}) Reader", .{poll.fd});
var handler: *BufferedReader = ptr.as(BufferedReader);
handler.onPoll(size_or_offset, poll.flags.contains(.hup));
},
@field(Owner.Tag, bun.meta.typeBaseName(@typeName(Process))) => {
@field(Owner.Tag, @typeName(Process)) => {
log("onUpdate " ++ kqueue_or_epoll ++ " (fd: {}) Process", .{poll.fd});
var loader = ptr.as(Process);
loader.onWaitPidFromEventLoopTask();
},
@field(Owner.Tag, "DNSResolver") => {
@field(Owner.Tag, @typeName(DNSResolver)) => {
log("onUpdate " ++ kqueue_or_epoll ++ " (fd: {}) DNSResolver", .{poll.fd});
var loader: *DNSResolver = ptr.as(DNSResolver);
loader.onDNSPoll(poll);
},
@field(Owner.Tag, "GetAddrInfoRequest") => {
@field(Owner.Tag, @typeName(GetAddrInfoRequest)) => {
if (comptime !Environment.isMac) {
unreachable;
}
@@ -411,7 +411,7 @@ pub const FilePoll = struct {
loader.onMachportChange();
},
@field(Owner.Tag, "Request") => {
@field(Owner.Tag, @typeName(Request)) => {
if (comptime !Environment.isMac) {
unreachable;
}
@@ -503,19 +503,19 @@ pub const FilePoll = struct {
pub fn fromKQueueEvent(kqueue_event: std.posix.system.kevent64_s) Flags.Set {
var flags = Flags.Set{};
if (kqueue_event.filter == std.posix.system.EVFILT_READ) {
if (kqueue_event.filter == std.posix.system.EVFILT.READ) {
flags.insert(Flags.readable);
if (kqueue_event.flags & std.posix.system.EV_EOF != 0) {
if (kqueue_event.flags & std.posix.system.EV.EOF != 0) {
flags.insert(Flags.hup);
}
} else if (kqueue_event.filter == std.posix.system.EVFILT_WRITE) {
} else if (kqueue_event.filter == std.posix.system.EVFILT.WRITE) {
flags.insert(Flags.writable);
if (kqueue_event.flags & std.posix.system.EV_EOF != 0) {
if (kqueue_event.flags & std.posix.system.EV.EOF != 0) {
flags.insert(Flags.hup);
}
} else if (kqueue_event.filter == std.posix.system.EVFILT_PROC) {
} else if (kqueue_event.filter == std.posix.system.EVFILT.PROC) {
flags.insert(Flags.process);
} else if (kqueue_event.filter == std.posix.system.EVFILT_MACHPORT) {
} else if (kqueue_event.filter == std.posix.system.EVFILT.MACHPORT) {
flags.insert(Flags.machport);
}
return flags;
@@ -592,8 +592,10 @@ pub const FilePoll = struct {
poll.flags.insert(.ignore_updates);
this.pending_free_tail = poll;
bun.assert(vm.after_event_loop_callback == null or vm.after_event_loop_callback == @as(?JSC.OpaqueCallback, @ptrCast(&processDeferredFrees)));
vm.after_event_loop_callback = @ptrCast(&processDeferredFrees);
const callback = JSC.OpaqueWrap(Store, processDeferredFrees);
bun.assert(vm.after_event_loop_callback == null or vm.after_event_loop_callback == @as(?JSC.OpaqueCallback, callback));
vm.after_event_loop_callback = callback;
vm.after_event_loop_callback_ctx = this;
}
};
@@ -763,7 +765,7 @@ pub const FilePoll = struct {
pub fn onTick(loop: *Loop, tagged_pointer: ?*anyopaque) callconv(.C) void {
var tag = Pollable.from(tagged_pointer);
if (tag.tag() != @field(Pollable.Tag, "FilePoll"))
if (tag.tag() != @field(Pollable.Tag, @typeName(FilePoll)))
return;
var file_poll: *FilePoll = tag.as(FilePoll);
@@ -782,7 +784,7 @@ pub const FilePoll = struct {
});
comptime {
@export(onTick, .{ .name = "Bun__internal_dispatch_ready_poll" });
@export(&onTick, .{ .name = "Bun__internal_dispatch_ready_poll" });
}
const timeout = std.mem.zeroes(std.posix.timespec);
@@ -837,45 +839,45 @@ pub const FilePoll = struct {
const one_shot_flag: u16 = if (!this.flags.contains(.one_shot))
0
else if (one_shot == .dispatch)
std.c.EV_DISPATCH | std.c.EV_ENABLE
std.c.EV.DISPATCH | std.c.EV.ENABLE
else
std.c.EV_ONESHOT;
std.c.EV.ONESHOT;
changelist[0] = switch (flag) {
.readable => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_READ,
.filter = std.posix.system.EVFILT.READ,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.flags = std.c.EV.ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
.writable => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_WRITE,
.filter = std.posix.system.EVFILT.WRITE,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.flags = std.c.EV.ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
.process => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_PROC,
.filter = std.posix.system.EVFILT.PROC,
.data = 0,
.fflags = std.c.NOTE_EXIT,
.fflags = std.c.NOTE.EXIT,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.flags = std.c.EV.ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
.machport => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_MACHPORT,
.filter = std.posix.system.EVFILT.MACHPORT,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_ADD | one_shot_flag,
.flags = std.c.EV.ADD | one_shot_flag,
.ext = .{ this.generation_number, 0 },
},
else => unreachable,
@@ -913,7 +915,7 @@ pub const FilePoll = struct {
// processing an element of the changelist and there is enough room
// in the eventlist, then the event will be placed in the eventlist
// with EV_ERROR set in flags and the system error in data.
if (changelist[0].flags == std.c.EV_ERROR and changelist[0].data != 0) {
if (changelist[0].flags == std.c.EV.ERROR and changelist[0].data != 0) {
return JSC.Maybe(void).errnoSys(changelist[0].data, .kevent).?;
// Otherwise, -1 will be returned, and errno will be set to
// indicate the error condition.
@@ -1008,38 +1010,38 @@ pub const FilePoll = struct {
changelist[0] = switch (flag) {
.readable => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_READ,
.filter = std.posix.system.EVFILT.READ,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.flags = std.c.EV.DELETE,
.ext = .{ 0, 0 },
},
.machport => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_MACHPORT,
.filter = std.posix.system.EVFILT.MACHPORT,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.flags = std.c.EV.DELETE,
.ext = .{ 0, 0 },
},
.writable => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_WRITE,
.filter = std.posix.system.EVFILT.WRITE,
.data = 0,
.fflags = 0,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.flags = std.c.EV.DELETE,
.ext = .{ 0, 0 },
},
.process => .{
.ident = @intCast(fd.cast()),
.filter = std.posix.system.EVFILT_PROC,
.filter = std.posix.system.EVFILT.PROC,
.data = 0,
.fflags = std.c.NOTE_EXIT,
.fflags = std.c.NOTE.EXIT,
.udata = @intFromPtr(Pollable.init(this).ptr()),
.flags = std.c.EV_DELETE,
.flags = std.c.EV.DELETE,
.ext = .{ 0, 0 },
},
else => unreachable,
@@ -1065,7 +1067,7 @@ pub const FilePoll = struct {
// processing an element of the changelist and there is enough room
// in the eventlist, then the event will be placed in the eventlist
// with EV_ERROR set in flags and the system error in data.
if (changelist[0].flags == std.c.EV_ERROR) {
if (changelist[0].flags == std.c.EV.ERROR) {
return JSC.Maybe(void).errnoSys(changelist[0].data, .kevent).?;
// Otherwise, -1 will be returned, and errno will be set to
// indicate the error condition.

View File

@@ -358,8 +358,10 @@ pub const FilePoll = struct {
poll.flags.insert(.ignore_updates);
this.pending_free_tail = poll;
bun.assert(vm.after_event_loop_callback == null or vm.after_event_loop_callback == @as(?JSC.OpaqueCallback, @ptrCast(&processDeferredFrees)));
vm.after_event_loop_callback = @ptrCast(&processDeferredFrees);
const callback = JSC.OpaqueWrap(Store, processDeferredFrees);
bun.assert(vm.after_event_loop_callback == null or vm.after_event_loop_callback == @as(?JSC.OpaqueCallback, callback));
vm.after_event_loop_callback = callback;
vm.after_event_loop_callback_ctx = this;
}
};

View File

@@ -342,7 +342,7 @@ pub fn BabyList(comptime Type: type) type {
return this.len - initial;
}
pub fn writeLatin1(this: *@This(), allocator: std.mem.Allocator, str: []const u8) !u32 {
pub fn writeLatin1(this: *@This(), allocator: std.mem.Allocator, str: []const u8) OOM!u32 {
if (comptime Type != u8)
@compileError("Unsupported for type " ++ @typeName(Type));
const initial = this.len;
@@ -352,7 +352,7 @@ pub fn BabyList(comptime Type: type) type {
return this.len - initial;
}
pub fn writeUTF16(this: *@This(), allocator: std.mem.Allocator, str: []const u16) !u32 {
pub fn writeUTF16(this: *@This(), allocator: std.mem.Allocator, str: []const u16) OOM!u32 {
if (comptime Type != u8)
@compileError("Unsupported for type " ++ @typeName(Type));

View File

@@ -21,13 +21,13 @@ bakeModuleLoaderImportModule(JSC::JSGlobalObject* global,
{
WTF::String keyString = moduleNameValue->getString(global);
if (keyString.startsWith("bake:/"_s)) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
return JSC::importModule(global, JSC::Identifier::fromString(vm, keyString),
JSC::jsUndefined(), parameters, JSC::jsUndefined());
}
if (!sourceOrigin.isNull() && sourceOrigin.string().startsWith("bake:/"_s)) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);
WTF::String refererString = sourceOrigin.string();
@@ -55,7 +55,7 @@ JSC::Identifier bakeModuleLoaderResolve(JSC::JSGlobalObject* jsGlobal,
JSC::JSValue referrer, JSC::JSValue origin)
{
Bake::GlobalObject* global = jsCast<Bake::GlobalObject*>(jsGlobal);
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);
ASSERT(referrer.isString());
@@ -77,7 +77,7 @@ JSC::Identifier bakeModuleLoaderResolve(JSC::JSGlobalObject* jsGlobal,
static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value)
{
JSC::VM& vm = globalObject->vm();
auto& vm = JSC::getVM(globalObject);
JSC::JSInternalPromise* promise = JSC::JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
promise->internalField(JSC::JSPromise::Field::ReactionsOrResult).set(vm, promise, value);
promise->internalField(JSC::JSPromise::Field::Flags).set(vm, promise, JSC::jsNumber(promise->internalField(JSC::JSPromise::Field::Flags).get().asUInt32AsAnyInt() | JSC::JSPromise::isFirstResolvingFunctionCalledFlag | static_cast<unsigned>(JSC::JSPromise::Status::Rejected)));
@@ -86,7 +86,7 @@ static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* glob
static JSC::JSInternalPromise* resolvedInternalPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value)
{
JSC::VM& vm = globalObject->vm();
auto& vm = JSC::getVM(globalObject);
JSC::JSInternalPromise* promise = JSC::JSInternalPromise::create(vm, globalObject->internalPromiseStructure());
promise->internalField(JSC::JSPromise::Field::ReactionsOrResult).set(vm, promise, value);
promise->internalField(JSC::JSPromise::Field::Flags).set(vm, promise, JSC::jsNumber(promise->internalField(JSC::JSPromise::Field::Flags).get().asUInt32AsAnyInt() | JSC::JSPromise::isFirstResolvingFunctionCalledFlag | static_cast<unsigned>(JSC::JSPromise::Status::Fulfilled)));
@@ -100,7 +100,7 @@ JSC::JSInternalPromise* bakeModuleLoaderFetch(JSC::JSGlobalObject* globalObject,
JSC::JSValue parameters, JSC::JSValue script)
{
Bake::GlobalObject* global = jsCast<Bake::GlobalObject*>(globalObject);
JSC::VM& vm = globalObject->vm();
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
auto moduleKey = key.toWTFString(globalObject);
if (UNLIKELY(scope.exception()))

View File

@@ -21,7 +21,7 @@ extern "C" JSC::JSPromise* BakeRenderRoutesForProdStatic(
JSC::JSValue paramInformation,
JSC::JSValue styles)
{
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
JSC::JSFunction* cb = JSC::JSFunction::create(vm, global, WebCore::bakeRenderRoutesForProdStaticCodeGenerator(vm), global);
JSC::CallData callData = JSC::getCallData(cb);

View File

@@ -17,7 +17,7 @@
namespace Bake {
extern "C" JSC::EncodedJSValue BakeLoadInitialServerCode(GlobalObject* global, BunString source, bool separateSSRGraph) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);
String string = "bake://server-runtime.js"_s;
@@ -75,7 +75,7 @@ extern "C" JSC::EncodedJSValue BakeGetModuleNamespace(
JSC::JSValue keyValue
) {
JSC::JSString* key = JSC::jsCast<JSC::JSString*>(keyValue);
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
JSC::JSMap* map = JSC::jsCast<JSC::JSMap*>(
global->moduleLoader()->getDirect(
vm, JSC::Identifier::fromString(global->vm(), "registry"_s)
@@ -93,7 +93,7 @@ extern "C" JSC::EncodedJSValue BakeGetDefaultExportFromModule(
JSC::JSGlobalObject* global,
JSC::JSValue keyValue
) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
return JSC::JSValue::encode(jsCast<JSC::JSModuleNamespaceObject*>(JSC::JSValue::decode(BakeGetModuleNamespace(global, keyValue)))->get(global, vm.propertyNames->defaultKeyword));
}
@@ -104,7 +104,7 @@ extern "C" JSC::EncodedJSValue BakeGetOnModuleNamespace(
const unsigned char* key,
size_t keyLength
) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
const auto propertyString = String(StringImpl::createWithoutCopying({ key, keyLength }));
const auto identifier = JSC::Identifier::fromString(vm, propertyString);
const auto property = JSC::PropertyName(identifier);
@@ -112,7 +112,7 @@ extern "C" JSC::EncodedJSValue BakeGetOnModuleNamespace(
}
extern "C" JSC::EncodedJSValue BakeRegisterProductionChunk(JSC::JSGlobalObject* global, BunString virtualPathName, BunString source) {
JSC::VM& vm = global->vm();
auto& vm = JSC::getVM(global);
auto scope = DECLARE_THROW_SCOPE(vm);
String string = virtualPathName.toWTFString();

View File

@@ -865,7 +865,7 @@ const DeferredRequest = struct {
server_handler: bun.JSC.API.SavedRequest,
js_payload: *Response,
const Tag = @typeInfo(Data).Union.tag_type.?;
const Tag = @typeInfo(Data).@"union".tag_type.?;
};
};
@@ -3715,20 +3715,20 @@ const HmrTopic = enum(u8) {
/// Invalid data
_,
pub const max_count = @typeInfo(HmrTopic).Enum.fields.len;
pub const Bits = @Type(.{ .Struct = .{
.backing_integer = @Type(.{ .Int = .{
pub const max_count = @typeInfo(HmrTopic).@"enum".fields.len;
pub const Bits = @Type(.{ .@"struct" = .{
.backing_integer = @Type(.{ .int = .{
.bits = max_count,
.signedness = .unsigned,
} }),
.fields = &brk: {
const enum_fields = @typeInfo(HmrTopic).Enum.fields;
const enum_fields = @typeInfo(HmrTopic).@"enum".fields;
var fields: [enum_fields.len]std.builtin.Type.StructField = undefined;
for (enum_fields, &fields) |e, *s| {
s.* = .{
.name = e.name,
.type = bool,
.default_value = &false,
.default_value_ptr = &false,
.is_comptime = false,
.alignment = 0,
};
@@ -3768,7 +3768,7 @@ const HmrSocket = struct {
const topics = msg[1..];
if (topics.len > HmrTopic.max_count) return;
outer: for (topics) |char| {
inline for (@typeInfo(HmrTopic).Enum.fields) |field| {
inline for (@typeInfo(HmrTopic).@"enum".fields) |field| {
if (char == field.value) {
@field(new_bits, field.name) = true;
continue :outer;
@@ -4063,7 +4063,7 @@ const WatcherAtomics = struct {
ev.timer = std.time.Timer.start() catch unreachable;
},
1 => {
// @branchHint(.unlikely);
@branchHint(.unlikely);
// DevServer stole this event. Unlikely but possible when
// the user is saving very heavily (10-30 times per second)
state.current +%= 1;
@@ -4087,12 +4087,12 @@ const WatcherAtomics = struct {
ev.owner.bun_watcher.thread_lock.assertLocked();
if (ev.files.count() > 0) {
// @branchHint(.likely);
@branchHint(.likely);
// There are files to be processed, increment this count first.
const prev_count = state.watcher_events_emitted.fetchAdd(1, .seq_cst);
if (prev_count == 0) {
// @branchHint(.likely);
@branchHint(.likely);
// Submit a task to the DevServer, notifying it that there is
// work to do. The watcher will move to the other event.
ev.concurrent_task = .{
@@ -4434,7 +4434,7 @@ pub const EntryPointList = struct {
pub fn append(entry_points: *EntryPointList, allocator: std.mem.Allocator, abs_path: []const u8, flags: Flags) !void {
const gop = try entry_points.set.getOrPut(allocator, abs_path);
if (gop.found_existing) {
const T = @typeInfo(Flags).Struct.backing_integer.?;
const T = @typeInfo(Flags).@"struct".backing_integer.?;
gop.value_ptr.* = @bitCast(@as(T, @bitCast(gop.value_ptr.*)) | @as(T, @bitCast(flags)));
} else {
gop.value_ptr.* = flags;

View File

@@ -331,7 +331,7 @@ pub const Part = union(enum(u3)) {
group: []const u8,
const SerializedHeader = packed struct(u32) {
tag: @typeInfo(Part).Union.tag_type.?,
tag: @typeInfo(Part).@"union".tag_type.?,
len: u29,
};

View File

@@ -325,10 +325,10 @@ pub fn ArrayBitSet(comptime MaskIntType: type, comptime size: usize) type {
const mask_info: std.builtin.Type = @typeInfo(MaskIntType);
// Make sure the mask int is indeed an int
if (mask_info != .Int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType));
if (mask_info != .int) @compileError("ArrayBitSet can only operate on integer masks, but was passed " ++ @typeName(MaskIntType));
// It must also be unsigned.
if (mask_info.Int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType));
if (mask_info.int.signedness != .unsigned) @compileError("ArrayBitSet requires an unsigned integer mask type, but was passed " ++ @typeName(MaskIntType));
// And it must not be empty.
if (MaskIntType == u0)
@@ -1620,7 +1620,7 @@ fn testSupersetOf(empty: anytype, full: anytype, even: anytype, odd: anytype, le
fn testBitSet(a: anytype, b: anytype, len: usize) !void {
try testing.expectEqual(len, a.capacity());
try testing.expectEqual(len, b.capacity());
const needs_ptr = @hasField(std.meta.Child(@TypeOf(a)), "masks") and @typeInfo(@TypeOf(@field(a, "masks"))) != .Pointer;
const needs_ptr = @hasField(std.meta.Child(@TypeOf(a)), "masks") and @typeInfo(@TypeOf(@field(a, "masks"))) != .pointer;
{
for (0..len) |i| {
@@ -1844,7 +1844,7 @@ fn fillOdd(set: anytype, len: usize) void {
fn testPureBitSet(comptime Set: type) !void {
var empty_ = Set.initEmpty();
var full_ = Set.initFull();
const needs_ptr = @hasField(Set, "masks") and @typeInfo(@TypeOf(empty_.masks)) != .Pointer;
const needs_ptr = @hasField(Set, "masks") and @typeInfo(@TypeOf(empty_.masks)) != .pointer;
var even_ = even: {
var bit_set = Set.initEmpty();
@@ -1900,7 +1900,7 @@ fn testPureBitSet(comptime Set: type) !void {
try testing.expect(full.differenceWith(even).eql(odd));
}
fn testStaticBitSet(comptime Set: type, comptime Container: @Type(.EnumLiteral)) !void {
fn testStaticBitSet(comptime Set: type, comptime Container: @Type(.enum_literal)) !void {
var a = Set.initEmpty();
var b = Set.initFull();
try testing.expectEqual(@as(usize, 0), a.count());

View File

@@ -2,11 +2,13 @@ const std = @import("std");
pub fn Bitflags(comptime T: type) type {
const tyinfo = @typeInfo(T);
const IntType = tyinfo.Struct.backing_integer.?;
const IntType = tyinfo.@"struct".backing_integer.?;
const IntTypeInfo = @typeInfo(IntType);
const IntRepresentingNumOfBits = std.math.IntFittingRange(0, IntTypeInfo.Int.bits);
const IntRepresentingNumOfBits = std.math.IntFittingRange(0, IntTypeInfo.int.bits);
return struct {
pub const IMPL_BITFLAGS: u0 = 0;
pub inline fn empty() T {
return @bitCast(@as(IntType, 0));
}

View File

@@ -8,7 +8,6 @@ const String = bun.String;
const JSGlobalObject = JSC.JSGlobalObject;
const JSValue = JSC.JSValue;
const strings = bun.strings;
const is_bindgen = JSC.is_bindgen;
const ZigException = JSC.ZigException;
const ZigString = JSC.ZigString;
const VirtualMachine = JSC.VirtualMachine;
@@ -104,10 +103,6 @@ fn messageWithTypeAndLevel_(
vals: [*]const JSValue,
len: usize,
) bun.JSError!void {
if (comptime is_bindgen) {
return;
}
var console = global.bunVM().console;
defer console.default_indent +|= @as(u16, @intFromBool(message_type == .StartGroup));
@@ -3438,7 +3433,7 @@ pub const Formatter = struct {
"<r><d>, ... {d} more<r>";
writer.print(comptime Output.prettyFmt(fmt_, enable_ansi_colors), .{
if (@typeInfo(Number) == .Float) bun.fmt.double(@floatCast(slice[0])) else slice[0],
if (@typeInfo(Number) == .float) bun.fmt.double(@floatCast(slice[0])) else slice[0],
});
var leftover = slice[1..];
const max = 512;
@@ -3448,7 +3443,7 @@ pub const Formatter = struct {
writer.space();
writer.print(comptime Output.prettyFmt(fmt_, enable_ansi_colors), .{
if (@typeInfo(Number) == .Float) bun.fmt.double(@floatCast(el)) else el,
if (@typeInfo(Number) == .float) bun.fmt.double(@floatCast(el)) else el,
});
}
@@ -3691,17 +3686,17 @@ pub fn screenshot(
) callconv(JSC.conv) void {}
comptime {
@export(messageWithTypeAndLevel, .{ .name = shim.symbolName("messageWithTypeAndLevel") });
@export(count, .{ .name = shim.symbolName("count") });
@export(countReset, .{ .name = shim.symbolName("countReset") });
@export(time, .{ .name = shim.symbolName("time") });
@export(timeLog, .{ .name = shim.symbolName("timeLog") });
@export(timeEnd, .{ .name = shim.symbolName("timeEnd") });
@export(profile, .{ .name = shim.symbolName("profile") });
@export(profileEnd, .{ .name = shim.symbolName("profileEnd") });
@export(takeHeapSnapshot, .{ .name = shim.symbolName("takeHeapSnapshot") });
@export(timeStamp, .{ .name = shim.symbolName("timeStamp") });
@export(record, .{ .name = shim.symbolName("record") });
@export(recordEnd, .{ .name = shim.symbolName("recordEnd") });
@export(screenshot, .{ .name = shim.symbolName("screenshot") });
@export(&messageWithTypeAndLevel, .{ .name = shim.symbolName("messageWithTypeAndLevel") });
@export(&count, .{ .name = shim.symbolName("count") });
@export(&countReset, .{ .name = shim.symbolName("countReset") });
@export(&time, .{ .name = shim.symbolName("time") });
@export(&timeLog, .{ .name = shim.symbolName("timeLog") });
@export(&timeEnd, .{ .name = shim.symbolName("timeEnd") });
@export(&profile, .{ .name = shim.symbolName("profile") });
@export(&profileEnd, .{ .name = shim.symbolName("profileEnd") });
@export(&takeHeapSnapshot, .{ .name = shim.symbolName("takeHeapSnapshot") });
@export(&timeStamp, .{ .name = shim.symbolName("timeStamp") });
@export(&record, .{ .name = shim.symbolName("record") });
@export(&recordEnd, .{ .name = shim.symbolName("recordEnd") });
@export(&screenshot, .{ .name = shim.symbolName("screenshot") });
}

View File

@@ -99,75 +99,71 @@ pub const BunObject = struct {
@compileError("Must be comptime");
}
if (JSC.is_bindgen) {
return;
}
// --- Getters ---
@export(BunObject.CryptoHasher, .{ .name = getterName("CryptoHasher") });
@export(BunObject.FFI, .{ .name = getterName("FFI") });
@export(BunObject.FileSystemRouter, .{ .name = getterName("FileSystemRouter") });
@export(BunObject.MD4, .{ .name = getterName("MD4") });
@export(BunObject.MD5, .{ .name = getterName("MD5") });
@export(BunObject.SHA1, .{ .name = getterName("SHA1") });
@export(BunObject.SHA224, .{ .name = getterName("SHA224") });
@export(BunObject.SHA256, .{ .name = getterName("SHA256") });
@export(BunObject.SHA384, .{ .name = getterName("SHA384") });
@export(BunObject.SHA512, .{ .name = getterName("SHA512") });
@export(BunObject.SHA512_256, .{ .name = getterName("SHA512_256") });
@export(&BunObject.CryptoHasher, .{ .name = getterName("CryptoHasher") });
@export(&BunObject.FFI, .{ .name = getterName("FFI") });
@export(&BunObject.FileSystemRouter, .{ .name = getterName("FileSystemRouter") });
@export(&BunObject.MD4, .{ .name = getterName("MD4") });
@export(&BunObject.MD5, .{ .name = getterName("MD5") });
@export(&BunObject.SHA1, .{ .name = getterName("SHA1") });
@export(&BunObject.SHA224, .{ .name = getterName("SHA224") });
@export(&BunObject.SHA256, .{ .name = getterName("SHA256") });
@export(&BunObject.SHA384, .{ .name = getterName("SHA384") });
@export(&BunObject.SHA512, .{ .name = getterName("SHA512") });
@export(&BunObject.SHA512_256, .{ .name = getterName("SHA512_256") });
@export(BunObject.TOML, .{ .name = getterName("TOML") });
@export(BunObject.Glob, .{ .name = getterName("Glob") });
@export(BunObject.Transpiler, .{ .name = getterName("Transpiler") });
@export(BunObject.argv, .{ .name = getterName("argv") });
@export(BunObject.cwd, .{ .name = getterName("cwd") });
@export(BunObject.enableANSIColors, .{ .name = getterName("enableANSIColors") });
@export(BunObject.hash, .{ .name = getterName("hash") });
@export(BunObject.inspect, .{ .name = getterName("inspect") });
@export(BunObject.main, .{ .name = getterName("main") });
@export(BunObject.origin, .{ .name = getterName("origin") });
@export(BunObject.stderr, .{ .name = getterName("stderr") });
@export(BunObject.stdin, .{ .name = getterName("stdin") });
@export(BunObject.stdout, .{ .name = getterName("stdout") });
@export(BunObject.unsafe, .{ .name = getterName("unsafe") });
@export(BunObject.semver, .{ .name = getterName("semver") });
@export(BunObject.embeddedFiles, .{ .name = getterName("embeddedFiles") });
@export(BunObject.S3Client, .{ .name = getterName("S3Client") });
@export(BunObject.s3, .{ .name = getterName("s3") });
@export(&BunObject.TOML, .{ .name = getterName("TOML") });
@export(&BunObject.Glob, .{ .name = getterName("Glob") });
@export(&BunObject.Transpiler, .{ .name = getterName("Transpiler") });
@export(&BunObject.argv, .{ .name = getterName("argv") });
@export(&BunObject.cwd, .{ .name = getterName("cwd") });
@export(&BunObject.enableANSIColors, .{ .name = getterName("enableANSIColors") });
@export(&BunObject.hash, .{ .name = getterName("hash") });
@export(&BunObject.inspect, .{ .name = getterName("inspect") });
@export(&BunObject.main, .{ .name = getterName("main") });
@export(&BunObject.origin, .{ .name = getterName("origin") });
@export(&BunObject.stderr, .{ .name = getterName("stderr") });
@export(&BunObject.stdin, .{ .name = getterName("stdin") });
@export(&BunObject.stdout, .{ .name = getterName("stdout") });
@export(&BunObject.unsafe, .{ .name = getterName("unsafe") });
@export(&BunObject.semver, .{ .name = getterName("semver") });
@export(&BunObject.embeddedFiles, .{ .name = getterName("embeddedFiles") });
@export(&BunObject.S3Client, .{ .name = getterName("S3Client") });
@export(&BunObject.s3, .{ .name = getterName("s3") });
// --- Getters --
// -- Callbacks --
@export(BunObject.allocUnsafe, .{ .name = callbackName("allocUnsafe") });
@export(BunObject.build, .{ .name = callbackName("build") });
@export(BunObject.color, .{ .name = callbackName("color") });
@export(BunObject.connect, .{ .name = callbackName("connect") });
@export(BunObject.createParsedShellScript, .{ .name = callbackName("createParsedShellScript") });
@export(BunObject.createShellInterpreter, .{ .name = callbackName("createShellInterpreter") });
@export(BunObject.deflateSync, .{ .name = callbackName("deflateSync") });
@export(BunObject.file, .{ .name = callbackName("file") });
@export(BunObject.gunzipSync, .{ .name = callbackName("gunzipSync") });
@export(BunObject.gzipSync, .{ .name = callbackName("gzipSync") });
@export(BunObject.indexOfLine, .{ .name = callbackName("indexOfLine") });
@export(BunObject.inflateSync, .{ .name = callbackName("inflateSync") });
@export(BunObject.jest, .{ .name = callbackName("jest") });
@export(BunObject.listen, .{ .name = callbackName("listen") });
@export(BunObject.mmap, .{ .name = callbackName("mmap") });
@export(BunObject.nanoseconds, .{ .name = callbackName("nanoseconds") });
@export(BunObject.openInEditor, .{ .name = callbackName("openInEditor") });
@export(BunObject.registerMacro, .{ .name = callbackName("registerMacro") });
@export(BunObject.resolve, .{ .name = callbackName("resolve") });
@export(BunObject.resolveSync, .{ .name = callbackName("resolveSync") });
@export(BunObject.serve, .{ .name = callbackName("serve") });
@export(BunObject.sha, .{ .name = callbackName("sha") });
@export(BunObject.shellEscape, .{ .name = callbackName("shellEscape") });
@export(BunObject.shrink, .{ .name = callbackName("shrink") });
@export(BunObject.sleepSync, .{ .name = callbackName("sleepSync") });
@export(BunObject.spawn, .{ .name = callbackName("spawn") });
@export(BunObject.spawnSync, .{ .name = callbackName("spawnSync") });
@export(BunObject.udpSocket, .{ .name = callbackName("udpSocket") });
@export(BunObject.which, .{ .name = callbackName("which") });
@export(BunObject.write, .{ .name = callbackName("write") });
@export(&BunObject.allocUnsafe, .{ .name = callbackName("allocUnsafe") });
@export(&BunObject.build, .{ .name = callbackName("build") });
@export(&BunObject.color, .{ .name = callbackName("color") });
@export(&BunObject.connect, .{ .name = callbackName("connect") });
@export(&BunObject.createParsedShellScript, .{ .name = callbackName("createParsedShellScript") });
@export(&BunObject.createShellInterpreter, .{ .name = callbackName("createShellInterpreter") });
@export(&BunObject.deflateSync, .{ .name = callbackName("deflateSync") });
@export(&BunObject.file, .{ .name = callbackName("file") });
@export(&BunObject.gunzipSync, .{ .name = callbackName("gunzipSync") });
@export(&BunObject.gzipSync, .{ .name = callbackName("gzipSync") });
@export(&BunObject.indexOfLine, .{ .name = callbackName("indexOfLine") });
@export(&BunObject.inflateSync, .{ .name = callbackName("inflateSync") });
@export(&BunObject.jest, .{ .name = callbackName("jest") });
@export(&BunObject.listen, .{ .name = callbackName("listen") });
@export(&BunObject.mmap, .{ .name = callbackName("mmap") });
@export(&BunObject.nanoseconds, .{ .name = callbackName("nanoseconds") });
@export(&BunObject.openInEditor, .{ .name = callbackName("openInEditor") });
@export(&BunObject.registerMacro, .{ .name = callbackName("registerMacro") });
@export(&BunObject.resolve, .{ .name = callbackName("resolve") });
@export(&BunObject.resolveSync, .{ .name = callbackName("resolveSync") });
@export(&BunObject.serve, .{ .name = callbackName("serve") });
@export(&BunObject.sha, .{ .name = callbackName("sha") });
@export(&BunObject.shellEscape, .{ .name = callbackName("shellEscape") });
@export(&BunObject.shrink, .{ .name = callbackName("shrink") });
@export(&BunObject.sleepSync, .{ .name = callbackName("sleepSync") });
@export(&BunObject.spawn, .{ .name = callbackName("spawn") });
@export(&BunObject.spawnSync, .{ .name = callbackName("spawnSync") });
@export(&BunObject.udpSocket, .{ .name = callbackName("udpSocket") });
@export(&BunObject.which, .{ .name = callbackName("which") });
@export(&BunObject.write, .{ .name = callbackName("write") });
// -- Callbacks --
}
};
@@ -248,11 +244,10 @@ const IOTask = JSC.IOTask;
const zlib = @import("../../zlib.zig");
const Which = @import("../../which.zig");
const ErrorableString = JSC.ErrorableString;
const is_bindgen = JSC.is_bindgen;
const max_addressable_memory = std.math.maxInt(u56);
const glob = @import("../../glob.zig");
const Async = bun.Async;
const SemverObject = @import("../../install/semver.zig").SemverObject;
const SemverObject = bun.Semver.SemverObject;
const Braces = @import("../../shell/braces.zig");
const Shell = @import("../../shell/shell.zig");
@@ -1925,7 +1920,7 @@ pub const Crypto = struct {
hash: []const u8,
pub fn toErrorInstance(this: Value, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
const error_code = std.fmt.allocPrint(bun.default_allocator, "PASSWORD_{}", .{PascalToUpperUnderscoreCaseFormatter{ .input = @errorName(this.err) }}) catch bun.outOfMemory();
const error_code = std.fmt.allocPrint(bun.default_allocator, "PASSWORD{}", .{PascalToUpperUnderscoreCaseFormatter{ .input = @errorName(this.err) }}) catch bun.outOfMemory();
defer bun.default_allocator.free(error_code);
const instance = globalObject.createErrorInstance("Password hashing failed with error \"{s}\"", .{@errorName(this.err)});
instance.put(globalObject, ZigString.static("code"), JSC.ZigString.init(error_code).toJS(globalObject));
@@ -2862,7 +2857,7 @@ pub const Crypto = struct {
return globalThis.throw("Bun.file() is not supported here yet (it needs an async version)", .{});
}
if (comptime @typeInfo(@TypeOf(Hasher.hash)).Fn.params.len == 3) {
if (comptime @typeInfo(@TypeOf(Hasher.hash)).@"fn".params.len == 3) {
Hasher.hash(input.slice(), &output_digest_buf, JSC.VirtualMachine.get().rareData().boringEngine());
} else {
Hasher.hash(input.slice(), &output_digest_buf);
@@ -2882,7 +2877,7 @@ pub const Crypto = struct {
output_digest_slice = bytes[0..Hasher.digest];
}
if (comptime @typeInfo(@TypeOf(Hasher.hash)).Fn.params.len == 3) {
if (comptime @typeInfo(@TypeOf(Hasher.hash)).@"fn".params.len == 3) {
Hasher.hash(input.slice(), output_digest_slice, JSC.VirtualMachine.get().rareData().boringEngine());
} else {
Hasher.hash(input.slice(), output_digest_slice);
@@ -3204,10 +3199,8 @@ pub export fn Bun__escapeHTML8(globalObject: *JSC.JSGlobalObject, input_value: J
}
comptime {
if (!JSC.is_bindgen) {
_ = Bun__escapeHTML8;
_ = Bun__escapeHTML16;
}
_ = Bun__escapeHTML8;
_ = Bun__escapeHTML16;
}
pub fn allocUnsafe(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.JSError!JSC.JSValue {
@@ -3273,7 +3266,7 @@ pub fn mmapFile(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) bun.
if (try opts.get(globalThis, "offset")) |value| {
offset = @as(usize, @intCast(value.toInt64()));
offset = std.mem.alignBackwardAnyAlign(offset, std.mem.page_size);
offset = std.mem.alignBackwardAnyAlign(usize, offset, std.mem.page_size);
}
}
@@ -3536,7 +3529,7 @@ const UnsafeObject = struct {
callframe: *JSC.CallFrame,
) bun.JSError!JSC.JSValue {
const args = callframe.arguments_old(2).slice();
if (args.len < 1 or !args[0].isCell() or !args[0].jsType().isTypedArray()) {
if (args.len < 1 or !args[0].isCell() or !args[0].jsType().isTypedArrayOrArrayBuffer()) {
return globalThis.throwInvalidArguments("Expected an ArrayBuffer", .{});
}
@@ -4302,12 +4295,10 @@ export fn Bun__reportError(globalObject: *JSGlobalObject, err: JSC.JSValue) void
}
comptime {
if (!is_bindgen) {
_ = Bun__reportError;
_ = EnvironmentVariables.Bun__getEnvCount;
_ = EnvironmentVariables.Bun__getEnvKey;
_ = EnvironmentVariables.Bun__getEnvValue;
}
_ = Bun__reportError;
_ = EnvironmentVariables.Bun__getEnvCount;
_ = EnvironmentVariables.Bun__getEnvKey;
_ = EnvironmentVariables.Bun__getEnvValue;
}
pub const JSZlib = struct {

View File

@@ -1,6 +1,5 @@
const std = @import("std");
const Api = @import("../../api/schema.zig").Api;
const JavaScript = @import("../javascript.zig");
const QueryStringMap = @import("../../url.zig").QueryStringMap;
const CombinedScanner = @import("../../url.zig").CombinedScanner;
const bun = @import("root").bun;
@@ -11,7 +10,6 @@ const WebCore = @import("../webcore/response.zig");
const Transpiler = bun.transpiler;
const options = @import("../../options.zig");
const resolve_path = @import("../../resolver/resolve_path.zig");
const VirtualMachine = JavaScript.VirtualMachine;
const ScriptSrcStream = std.io.FixedBufferStream([]u8);
const ZigString = JSC.ZigString;
const Fs = @import("../../fs.zig");
@@ -60,6 +58,7 @@ pub const JSBundler = struct {
rootdir: OwnedString = OwnedString.initEmpty(bun.default_allocator),
serve: Serve = .{},
jsx: options.JSX.Pragma = .{},
force_node_env: options.BundleOptions.ForceNodeEnv = .unspecified,
code_splitting: bool = false,
minify: Minify = .{},
no_macros: bool = false,

View File

@@ -1,6 +1,5 @@
const std = @import("std");
const Api = @import("../../api/schema.zig").Api;
const JavaScript = @import("../javascript.zig");
const QueryStringMap = @import("../../url.zig").QueryStringMap;
const CombinedScanner = @import("../../url.zig").CombinedScanner;
const bun = @import("root").bun;
@@ -10,7 +9,6 @@ const js = JSC.C;
const WebCore = @import("../webcore/response.zig");
const Transpiler = bun.transpiler;
const options = @import("../../options.zig");
const VirtualMachine = JavaScript.VirtualMachine;
const ScriptSrcStream = std.io.FixedBufferStream([]u8);
const ZigString = JSC.ZigString;
const Fs = @import("../../fs.zig");
@@ -454,7 +452,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
allocator,
&transpiler.log,
logger.Source.initPathString("tsconfig.json", transpiler.tsconfig_buf),
&VirtualMachine.get().transpiler.resolver.caches.json,
&JSC.VirtualMachine.get().transpiler.resolver.caches.json,
) catch null) |parsed_tsconfig| {
transpiler.tsconfig = parsed_tsconfig;
}
@@ -488,7 +486,7 @@ fn transformOptionsFromJSC(globalObject: JSC.C.JSContextRef, temp_allocator: std
if (out.isEmpty()) break :macros;
transpiler.macros_buf = out.toOwnedSlice(allocator) catch bun.outOfMemory();
const source = logger.Source.initPathString("macros.json", transpiler.macros_buf);
const json = (VirtualMachine.get().transpiler.resolver.caches.json.parseJSON(
const json = (JSC.VirtualMachine.get().transpiler.resolver.caches.json.parseJSON(
&transpiler.log,
source,
allocator,
@@ -731,7 +729,7 @@ pub fn constructor(globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) b
allocator,
log,
transpiler_options.transform,
JavaScript.VirtualMachine.get().transpiler.env,
JSC.VirtualMachine.get().transpiler.env,
) catch |err| {
if ((log.warnings + log.errors) > 0) {
return globalThis.throwValue(log.toJS(globalThis, allocator, "Failed to create transpiler"));
@@ -1022,7 +1020,7 @@ pub fn transformSync(
arena.allocator(),
code,
loader,
if (comptime JSC.is_bindgen) Transpiler.MacroJSValueType.zero else js_ctx_value,
js_ctx_value,
) orelse {
if ((this.transpiler.log.warnings + this.transpiler.log.errors) > 0) {
return globalThis.throwValue(this.transpiler.log.toJS(globalThis, globalThis.allocator(), "Parse error"));

View File

@@ -28,6 +28,8 @@ const TimerHeap = heap.Intrusive(EventLoopTimer, void, EventLoopTimer.less);
pub const All = struct {
last_id: i32 = 1,
lock: bun.Mutex = .{},
thread_id: std.Thread.Id,
timers: TimerHeap = .{
.context = {},
},
@@ -49,7 +51,15 @@ pub const All = struct {
}
} = .{},
pub fn init() @This() {
return .{
.thread_id = std.Thread.getCurrentId(),
};
}
pub fn insert(this: *All, timer: *EventLoopTimer) void {
this.lock.lock();
defer this.lock.unlock();
this.timers.insert(timer);
timer.state = .ACTIVE;
@@ -59,12 +69,36 @@ pub const All = struct {
}
pub fn remove(this: *All, timer: *EventLoopTimer) void {
this.lock.lock();
defer this.lock.unlock();
this.timers.remove(timer);
timer.state = .CANCELLED;
timer.heap = .{};
}
/// Remove the EventLoopTimer if necessary.
pub fn update(this: *All, timer: *EventLoopTimer, time: *const timespec) void {
this.lock.lock();
defer this.lock.unlock();
if (timer.state == .ACTIVE) {
this.timers.remove(timer);
}
timer.state = .ACTIVE;
if (comptime Environment.isDebug) {
if (&timer.next == time) {
@panic("timer.next == time. For threadsafety reasons, time and timer.next must always be a different pointer.");
}
}
timer.next = time.*;
this.timers.insert(timer);
if (Environment.isWindows) {
this.ensureUVTimer(@alignCast(@fieldParentPtr("timer", this)));
}
}
fn ensureUVTimer(this: *All, vm: *VirtualMachine) void {
if (this.uv_timer.data == null) {
this.uv_timer.init(vm.uvLoop());
@@ -129,15 +163,28 @@ pub const All = struct {
return VirtualMachine.get().timer.last_id;
}
pub fn getTimeout(this: *const All, spec: *timespec) bool {
pub fn getTimeout(this: *All, spec: *timespec, vm: *VirtualMachine) bool {
if (this.active_timer_count == 0) {
return false;
}
if (this.timers.peek()) |min| {
const now = timespec.now();
var now: timespec = undefined;
var has_set_now: bool = false;
while (this.timers.peek()) |min| {
if (!has_set_now) {
now = timespec.now();
has_set_now = true;
}
switch (now.order(&min.next)) {
.gt, .eq => {
// Side-effect: potentially call the StopIfNecessary timer.
if (min.tag == .WTFTimer) {
_ = this.timers.deleteMin();
_ = min.fire(&now, vm);
continue;
}
spec.* = .{ .nsec = 0, .sec = 0 };
return true;
},
@@ -146,6 +193,8 @@ pub const All = struct {
return true;
},
}
unreachable;
}
return false;
@@ -159,22 +208,40 @@ pub const All = struct {
_ = &Bun__internal_drainTimers;
}
pub fn drainTimers(this: *All, vm: *VirtualMachine) void {
if (this.timers.peek() == null) {
return;
}
// Getting the current time is expensive on certain platforms.
// We don't want to call it when there are no timers.
// And when we do call it, we want to be sure we only call it once.
// and we do NOT want to hold the lock while the timer is running it's code.
// This function has to be thread-safe.
fn next(this: *All, has_set_now: *bool, now: *timespec) ?*EventLoopTimer {
this.lock.lock();
defer this.lock.unlock();
const now = &timespec.now();
while (this.timers.peek()) |t| {
if (t.next.greater(now)) {
break;
if (this.timers.peek()) |timer| {
if (!has_set_now.*) {
now.* = timespec.now();
has_set_now.* = true;
}
if (timer.next.greater(now)) {
return null;
}
assert(this.timers.deleteMin().? == t);
assert(this.timers.deleteMin().? == timer);
return timer;
}
return null;
}
pub fn drainTimers(this: *All, vm: *VirtualMachine) void {
// Set in next().
var now: timespec = undefined;
// Split into a separate variable to avoid increasing the size of the timespec type.
var has_set_now: bool = false;
while (this.next(&has_set_now, &now)) |t| {
switch (t.fire(
now,
&now,
vm,
)) {
.disarm => {},
@@ -235,9 +302,7 @@ pub const All = struct {
}
comptime {
if (!JSC.is_bindgen) {
@export(setImmediate, .{ .name = "Bun__Timer__setImmediate" });
}
@export(&setImmediate, .{ .name = "Bun__Timer__setImmediate" });
}
pub fn setTimeout(
@@ -347,13 +412,11 @@ pub const All = struct {
});
comptime {
if (!JSC.is_bindgen) {
@export(setTimeout, .{ .name = Export[0].symbol_name });
@export(setInterval, .{ .name = Export[1].symbol_name });
@export(clearTimeout, .{ .name = Export[2].symbol_name });
@export(clearInterval, .{ .name = Export[3].symbol_name });
@export(getNextID, .{ .name = Export[4].symbol_name });
}
@export(&setTimeout, .{ .name = Export[0].symbol_name });
@export(&setInterval, .{ .name = Export[1].symbol_name });
@export(&clearTimeout, .{ .name = Export[2].symbol_name });
@export(&clearInterval, .{ .name = Export[3].symbol_name });
@export(&getNextID, .{ .name = Export[4].symbol_name });
}
};
@@ -381,9 +444,9 @@ pub const TimerObject = struct {
},
pub usingnamespace JSC.Codegen.JSTimeout;
pub usingnamespace bun.NewRefCounted(@This(), deinit);
pub usingnamespace bun.NewRefCounted(@This(), deinit, null);
extern "C" fn Bun__JSTimeout__call(encodedTimeoutValue: JSValue, globalObject: *JSC.JSGlobalObject) void;
extern "c" fn Bun__JSTimeout__call(encodedTimeoutValue: JSValue, globalObject: *JSC.JSGlobalObject) void;
pub fn runImmediateTask(this: *TimerObject, vm: *VirtualMachine) void {
if (this.has_cleared_timer) {
@@ -467,8 +530,7 @@ pub const TimerObject = struct {
switch (this.event_loop_timer.state) {
.FIRED => {
// If we didn't clear the setInterval, reschedule it starting from
this.event_loop_timer.next = time_before_call;
vm.timer.insert(&this.event_loop_timer);
vm.timer.update(&this.event_loop_timer, &time_before_call);
if (this.has_js_ref) {
this.setEnableKeepingEventLoopAlive(vm, true);
@@ -478,10 +540,7 @@ pub const TimerObject = struct {
},
.ACTIVE => {
// The developer called timer.refresh() synchronously in the callback.
vm.timer.remove(&this.event_loop_timer);
this.event_loop_timer.next = time_before_call;
vm.timer.insert(&this.event_loop_timer);
vm.timer.update(&this.event_loop_timer, &time_before_call);
// Balance out the ref count.
// the transition from "FIRED" -> "ACTIVE" caused it to increment.
@@ -620,8 +679,7 @@ pub const TimerObject = struct {
this.ref();
}
this.event_loop_timer.next = now;
vm.timer.insert(&this.event_loop_timer);
vm.timer.update(&this.event_loop_timer, &now);
this.has_cleared_timer = false;
if (this.has_js_ref) {
@@ -722,7 +780,7 @@ pub const EventLoopTimer = struct {
state: State = .PENDING,
tag: Tag = .TimerCallback,
tag: Tag,
pub const Tag = if (Environment.isWindows) enum {
TimerCallback,
@@ -732,6 +790,7 @@ pub const EventLoopTimer = struct {
UpgradedDuplex,
DNSResolver,
WindowsNamedPipe,
WTFTimer,
PostgresSQLConnectionTimeout,
PostgresSQLConnectionMaxLifetime,
@@ -744,6 +803,7 @@ pub const EventLoopTimer = struct {
.UpgradedDuplex => uws.UpgradedDuplex,
.DNSResolver => DNSResolver,
.WindowsNamedPipe => uws.WindowsNamedPipe,
.WTFTimer => WTFTimer,
.PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection,
.PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection,
};
@@ -754,6 +814,7 @@ pub const EventLoopTimer = struct {
TestRunner,
StatWatcherScheduler,
UpgradedDuplex,
WTFTimer,
DNSResolver,
PostgresSQLConnectionTimeout,
PostgresSQLConnectionMaxLifetime,
@@ -765,6 +826,7 @@ pub const EventLoopTimer = struct {
.TestRunner => JSC.Jest.TestRunner,
.StatWatcherScheduler => StatWatcherScheduler,
.UpgradedDuplex => uws.UpgradedDuplex,
.WTFTimer => WTFTimer,
.DNSResolver => DNSResolver,
.PostgresSQLConnectionTimeout => JSC.Postgres.PostgresSQLConnection,
.PostgresSQLConnectionMaxLifetime => JSC.Postgres.PostgresSQLConnection,
@@ -824,6 +886,10 @@ pub const EventLoopTimer = struct {
.PostgresSQLConnectionMaxLifetime => return @as(*JSC.Postgres.PostgresSQLConnection, @alignCast(@fieldParentPtr("max_lifetime_timer", this))).onMaxLifetimeTimeout(),
inline else => |t| {
var container: *t.Type() = @alignCast(@fieldParentPtr("event_loop_timer", this));
if (comptime t.Type() == WTFTimer) {
return container.fire(now, vm);
}
if (comptime t.Type() == TimerObject) {
return container.fire(now, vm);
}
@@ -858,3 +924,134 @@ pub const EventLoopTimer = struct {
};
const timespec = bun.timespec;
/// A timer created by WTF code and invoked by Bun's event loop
pub const WTFTimer = struct {
/// This is WTF::RunLoop::TimerBase from WebKit
const RunLoopTimer = opaque {};
vm: *VirtualMachine,
run_loop_timer: *RunLoopTimer,
event_loop_timer: EventLoopTimer,
imminent: *std.atomic.Value(?*WTFTimer),
repeat: bool,
lock: bun.Mutex = .{},
pub usingnamespace bun.New(@This());
pub fn init(run_loop_timer: *RunLoopTimer, js_vm: *VirtualMachine) *WTFTimer {
const this = WTFTimer.new(.{
.vm = js_vm,
.imminent = &js_vm.eventLoop().imminent_gc_timer,
.event_loop_timer = .{
.next = .{
.sec = std.math.maxInt(i64),
.nsec = 0,
},
.tag = .WTFTimer,
.state = .CANCELLED,
},
.run_loop_timer = run_loop_timer,
.repeat = false,
});
return this;
}
pub export fn WTFTimer__runIfImminent(vm: *VirtualMachine) void {
vm.eventLoop().runImminentGCTimer();
}
pub fn run(this: *WTFTimer, vm: *VirtualMachine) void {
if (this.event_loop_timer.state == .ACTIVE) {
vm.timer.remove(&this.event_loop_timer);
}
this.runWithoutRemoving();
}
inline fn runWithoutRemoving(this: *const WTFTimer) void {
WTFTimer__fire(this.run_loop_timer);
}
pub fn update(this: *WTFTimer, seconds: f64, repeat: bool) void {
// There's only one of these per VM, and each VM has its own imminent_gc_timer
this.imminent.store(if (seconds == 0) this else null, .seq_cst);
if (seconds == 0.0) {
return;
}
const modf = std.math.modf(seconds);
var interval = bun.timespec.now();
interval.sec += @intFromFloat(modf.ipart);
interval.nsec += @intFromFloat(modf.fpart * std.time.ns_per_s);
if (interval.nsec >= std.time.ns_per_s) {
interval.sec += 1;
interval.nsec -= std.time.ns_per_s;
}
this.vm.timer.update(&this.event_loop_timer, &interval);
this.repeat = repeat;
}
pub fn cancel(this: *WTFTimer) void {
this.lock.lock();
defer this.lock.unlock();
this.imminent.store(null, .monotonic);
if (this.event_loop_timer.state == .ACTIVE) {
this.vm.timer.remove(&this.event_loop_timer);
}
}
pub fn fire(this: *WTFTimer, _: *const bun.timespec, _: *VirtualMachine) EventLoopTimer.Arm {
this.event_loop_timer.state = .FIRED;
this.imminent.store(null, .monotonic);
this.runWithoutRemoving();
return if (this.repeat)
.{ .rearm = this.event_loop_timer.next }
else
.disarm;
}
pub fn deinit(this: *WTFTimer) void {
this.cancel();
this.destroy();
}
export fn WTFTimer__create(run_loop_timer: *RunLoopTimer) ?*anyopaque {
if (VirtualMachine.is_bundler_thread_for_bytecode_cache) {
return null;
}
return init(run_loop_timer, VirtualMachine.get());
}
export fn WTFTimer__update(this: *WTFTimer, seconds: f64, repeat: bool) void {
this.update(seconds, repeat);
}
export fn WTFTimer__deinit(this: *WTFTimer) void {
this.deinit();
}
export fn WTFTimer__isActive(this: *const WTFTimer) bool {
return this.event_loop_timer.state == .ACTIVE or (this.imminent.load(.monotonic) orelse return false) == this;
}
export fn WTFTimer__cancel(this: *WTFTimer) void {
this.cancel();
}
export fn WTFTimer__secondsUntilTimer(this: *WTFTimer) f64 {
this.lock.lock();
defer this.lock.unlock();
if (this.event_loop_timer.state == .ACTIVE) {
const until = this.event_loop_timer.next.duration(&bun.timespec.now());
const sec: f64, const nsec: f64 = .{ @floatFromInt(until.sec), @floatFromInt(until.nsec) };
return sec + nsec / std.time.ns_per_s;
}
return std.math.inf(f64);
}
extern fn WTFTimer__fire(this: *RunLoopTimer) void;
};

View File

@@ -41,10 +41,7 @@ const LibInfo = struct {
if (loaded)
return handle;
loaded = true;
const RTLD_LAZY = 1;
const RTLD_LOCAL = 4;
handle = bun.C.dlopen("libinfo.dylib", RTLD_LAZY | RTLD_LOCAL);
handle = bun.C.dlopen("libinfo.dylib", .{ .LAZY = true, .LOCAL = true });
if (handle == null)
Output.debug("libinfo.dylib not found", .{});
return handle;
@@ -1395,7 +1392,7 @@ pub const InternalDNS = struct {
// https://github.com/nodejs/node/issues/33816
// https://github.com/aio-libs/aiohttp/issues/5357
// https://github.com/libuv/libuv/issues/2225
.flags = if (Environment.isPosix) bun.C.translated.AI_ADDRCONFIG else 0,
.flags = if (Environment.isPosix) .{ .ADDRCONFIG = true } else .{},
.next = null,
.protocol = 0,
.socktype = std.c.SOCK.STREAM,
@@ -1527,7 +1524,7 @@ pub const InternalDNS = struct {
if (Environment.isWindows) {
const wsa = std.os.windows.ws2_32;
const wsa_hints = wsa.addrinfo{
.flags = 0,
.flags = .{},
.family = wsa.AF.UNSPEC,
.socktype = wsa.SOCK.STREAM,
.protocol = 0,
@@ -1756,16 +1753,16 @@ pub const InternalDNS = struct {
pub const InternalDNSRequest = InternalDNS.Request;
comptime {
@export(InternalDNS.us_getaddrinfo_set, .{
@export(&InternalDNS.us_getaddrinfo_set, .{
.name = "Bun__addrinfo_set",
});
@export(InternalDNS.us_getaddrinfo, .{
@export(&InternalDNS.us_getaddrinfo, .{
.name = "Bun__addrinfo_get",
});
@export(InternalDNS.freeaddrinfo, .{
@export(&InternalDNS.freeaddrinfo, .{
.name = "Bun__addrinfo_freeRequest",
});
@export(InternalDNS.getRequestResult, .{
@export(&InternalDNS.getRequestResult, .{
.name = "Bun__addrinfo_getRequestResult",
});
}
@@ -1802,7 +1799,7 @@ pub const DNSResolver = struct {
pending_nameinfo_cache_cares: NameInfoPendingCache = NameInfoPendingCache.init(),
pub usingnamespace JSC.Codegen.JSDNSResolver;
pub usingnamespace bun.NewRefCounted(@This(), deinit);
pub usingnamespace bun.NewRefCounted(@This(), deinit, null);
const PollsMap = std.AutoArrayHashMap(c_ares.ares_socket_t, *PollType);
@@ -1912,7 +1909,7 @@ pub const DNSResolver = struct {
}
fn anyRequestsPending(this: *DNSResolver) bool {
inline for (@typeInfo(DNSResolver).Struct.fields) |field| {
inline for (@typeInfo(DNSResolver).@"struct".fields) |field| {
if (comptime std.mem.startsWith(u8, field.name, "pending_")) {
const set = &@field(this, field.name).available;
if (set.count() < set.capacity()) {
@@ -2522,7 +2519,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolve", "name", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
switch (record_type) {
RecordType.A => {
@@ -2585,7 +2582,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("reverse", "ip", "non-empty string");
}
const ip_slice = ip_str.toSliceClone(globalThis, bun.default_allocator);
const ip_slice = try ip_str.toSliceClone(globalThis, bun.default_allocator);
const ip = ip_slice.slice();
const channel: *c_ares.Channel = switch (this.getChannel()) {
.result => |res| res,
@@ -2721,7 +2718,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveSrv", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_srv_reply, "srv", name.slice(), globalThis);
}
@@ -2747,7 +2744,7 @@ pub const DNSResolver = struct {
return .zero;
};
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_soa_reply, "soa", name.slice(), globalThis);
}
@@ -2777,7 +2774,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveCaa", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_caa_reply, "caa", name.slice(), globalThis);
}
@@ -2803,7 +2800,7 @@ pub const DNSResolver = struct {
return .zero;
};
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_hostent, "ns", name.slice(), globalThis);
}
@@ -2833,7 +2830,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolvePtr", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_hostent, "ptr", name.slice(), globalThis);
}
@@ -2863,7 +2860,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveCname", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_hostent, "cname", name.slice(), globalThis);
}
@@ -2893,7 +2890,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveMx", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_mx_reply, "mx", name.slice(), globalThis);
}
@@ -2923,7 +2920,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveNaptr", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_naptr_reply, "naptr", name.slice(), globalThis);
}
@@ -2953,7 +2950,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveTxt", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_ares_txt_reply, "txt", name.slice(), globalThis);
}
@@ -2983,7 +2980,7 @@ pub const DNSResolver = struct {
return globalThis.throwInvalidArgumentType("resolveAny", "hostname", "non-empty string");
}
const name = name_str.toSliceClone(globalThis, bun.default_allocator);
const name = try name_str.toSliceClone(globalThis, bun.default_allocator);
return this.doResolveCAres(c_ares.struct_any_reply, "any", name.slice(), globalThis);
}
@@ -3396,40 +3393,40 @@ pub const DNSResolver = struct {
comptime {
const js_resolve = JSC.toJSHostFunction(globalResolve);
@export(js_resolve, .{ .name = "Bun__DNS__resolve" });
@export(&js_resolve, .{ .name = "Bun__DNS__resolve" });
const js_lookup = JSC.toJSHostFunction(globalLookup);
@export(js_lookup, .{ .name = "Bun__DNS__lookup" });
@export(&js_lookup, .{ .name = "Bun__DNS__lookup" });
const js_resolveTxt = JSC.toJSHostFunction(globalResolveTxt);
@export(js_resolveTxt, .{ .name = "Bun__DNS__resolveTxt" });
@export(&js_resolveTxt, .{ .name = "Bun__DNS__resolveTxt" });
const js_resolveSoa = JSC.toJSHostFunction(globalResolveSoa);
@export(js_resolveSoa, .{ .name = "Bun__DNS__resolveSoa" });
@export(&js_resolveSoa, .{ .name = "Bun__DNS__resolveSoa" });
const js_resolveMx = JSC.toJSHostFunction(globalResolveMx);
@export(js_resolveMx, .{ .name = "Bun__DNS__resolveMx" });
@export(&js_resolveMx, .{ .name = "Bun__DNS__resolveMx" });
const js_resolveNaptr = JSC.toJSHostFunction(globalResolveNaptr);
@export(js_resolveNaptr, .{ .name = "Bun__DNS__resolveNaptr" });
@export(&js_resolveNaptr, .{ .name = "Bun__DNS__resolveNaptr" });
const js_resolveSrv = JSC.toJSHostFunction(globalResolveSrv);
@export(js_resolveSrv, .{ .name = "Bun__DNS__resolveSrv" });
@export(&js_resolveSrv, .{ .name = "Bun__DNS__resolveSrv" });
const js_resolveCaa = JSC.toJSHostFunction(globalResolveCaa);
@export(js_resolveCaa, .{ .name = "Bun__DNS__resolveCaa" });
@export(&js_resolveCaa, .{ .name = "Bun__DNS__resolveCaa" });
const js_resolveNs = JSC.toJSHostFunction(globalResolveNs);
@export(js_resolveNs, .{ .name = "Bun__DNS__resolveNs" });
@export(&js_resolveNs, .{ .name = "Bun__DNS__resolveNs" });
const js_resolvePtr = JSC.toJSHostFunction(globalResolvePtr);
@export(js_resolvePtr, .{ .name = "Bun__DNS__resolvePtr" });
@export(&js_resolvePtr, .{ .name = "Bun__DNS__resolvePtr" });
const js_resolveCname = JSC.toJSHostFunction(globalResolveCname);
@export(js_resolveCname, .{ .name = "Bun__DNS__resolveCname" });
@export(&js_resolveCname, .{ .name = "Bun__DNS__resolveCname" });
const js_resolveAny = JSC.toJSHostFunction(globalResolveAny);
@export(js_resolveAny, .{ .name = "Bun__DNS__resolveAny" });
@export(&js_resolveAny, .{ .name = "Bun__DNS__resolveAny" });
const js_getGlobalServers = JSC.toJSHostFunction(getGlobalServers);
@export(js_getGlobalServers, .{ .name = "Bun__DNS__getServers" });
@export(&js_getGlobalServers, .{ .name = "Bun__DNS__getServers" });
const js_setGlobalServers = JSC.toJSHostFunction(setGlobalServers);
@export(js_setGlobalServers, .{ .name = "Bun__DNS__setServers" });
@export(&js_setGlobalServers, .{ .name = "Bun__DNS__setServers" });
const js_reverse = JSC.toJSHostFunction(globalReverse);
@export(js_reverse, .{ .name = "Bun__DNS__reverse" });
@export(&js_reverse, .{ .name = "Bun__DNS__reverse" });
const js_lookupService = JSC.toJSHostFunction(globalLookupService);
@export(js_lookupService, .{ .name = "Bun__DNS__lookupService" });
@export(&js_lookupService, .{ .name = "Bun__DNS__lookupService" });
const js_prefetchFromJS = JSC.toJSHostFunction(InternalDNS.prefetchFromJS);
@export(js_prefetchFromJS, .{ .name = "Bun__DNS__prefetch" });
@export(&js_prefetchFromJS, .{ .name = "Bun__DNS__prefetch" });
const js_getDNSCacheStats = JSC.toJSHostFunction(InternalDNS.getDNSCacheStats);
@export(js_getDNSCacheStats, .{ .name = "Bun__DNS__getCacheStats" });
@export(&js_getDNSCacheStats, .{ .name = "Bun__DNS__getCacheStats" });
}
};

View File

@@ -530,7 +530,7 @@ const Handlers = struct {
globalObject: *JSC.JSGlobalObject,
strong_ctx: JSC.Strong = .{},
pub fn callEventHandler(this: *Handlers, comptime event: @Type(.EnumLiteral), thisValue: JSValue, data: []const JSValue) bool {
pub fn callEventHandler(this: *Handlers, comptime event: @Type(.enum_literal), thisValue: JSValue, data: []const JSValue) bool {
const callback = @field(this, @tagName(event));
if (callback == .zero) {
return false;
@@ -546,7 +546,7 @@ const Handlers = struct {
return true;
}
pub fn callEventHandlerWithResult(this: *Handlers, comptime event: @Type(.EnumLiteral), thisValue: JSValue, data: []const JSValue) JSValue {
pub fn callEventHandlerWithResult(this: *Handlers, comptime event: @Type(.enum_literal), thisValue: JSValue, data: []const JSValue) JSValue {
const callback = @field(this, @tagName(event));
if (callback == .zero) {
return JSC.JSValue.zero;
@@ -643,8 +643,7 @@ const Handlers = struct {
pub const H2FrameParser = struct {
pub const log = Output.scoped(.H2FrameParser, false);
pub usingnamespace JSC.Codegen.JSH2FrameParser;
pub usingnamespace bun.NewRefCounted(@This(), @This().deinit);
pub const DEBUG_REFCOUNT_NAME = "H2";
pub usingnamespace bun.NewRefCounted(@This(), deinit, "H2");
const ENABLE_AUTO_CORK = true; // ENABLE CORK OPTIMIZATION
const ENABLE_ALLOCATOR_POOL = true; // ENABLE HIVE ALLOCATOR OPTIMIZATION
@@ -1104,7 +1103,10 @@ pub const H2FrameParser = struct {
this.signal = null;
signal.deinit();
}
JSC.VirtualMachine.get().eventLoop().processGCTimer();
// unsafe to ask GC to run if we are already inside GC
if (!finalizing) {
JSC.VirtualMachine.get().eventLoop().processGCTimer();
}
}
};
@@ -1353,7 +1355,7 @@ pub const H2FrameParser = struct {
_ = this.write(&buffer);
}
pub fn dispatch(this: *H2FrameParser, comptime event: @Type(.EnumLiteral), value: JSC.JSValue) void {
pub fn dispatch(this: *H2FrameParser, comptime event: @Type(.enum_literal), value: JSC.JSValue) void {
JSC.markBinding(@src());
const ctx_value = this.strong_ctx.get() orelse return;
@@ -1361,7 +1363,7 @@ pub const H2FrameParser = struct {
_ = this.handlers.callEventHandler(event, ctx_value, &[_]JSC.JSValue{ ctx_value, value });
}
pub fn call(this: *H2FrameParser, comptime event: @Type(.EnumLiteral), value: JSC.JSValue) JSValue {
pub fn call(this: *H2FrameParser, comptime event: @Type(.enum_literal), value: JSC.JSValue) JSValue {
JSC.markBinding(@src());
const ctx_value = this.strong_ctx.get() orelse return .zero;
@@ -1373,7 +1375,7 @@ pub const H2FrameParser = struct {
_ = this.handlers.callWriteCallback(callback, &[_]JSC.JSValue{});
}
pub fn dispatchWithExtra(this: *H2FrameParser, comptime event: @Type(.EnumLiteral), value: JSC.JSValue, extra: JSC.JSValue) void {
pub fn dispatchWithExtra(this: *H2FrameParser, comptime event: @Type(.enum_literal), value: JSC.JSValue, extra: JSC.JSValue) void {
JSC.markBinding(@src());
const ctx_value = this.strong_ctx.get() orelse return;
@@ -1382,7 +1384,7 @@ pub const H2FrameParser = struct {
_ = this.handlers.callEventHandler(event, ctx_value, &[_]JSC.JSValue{ ctx_value, value, extra });
}
pub fn dispatchWith2Extra(this: *H2FrameParser, comptime event: @Type(.EnumLiteral), value: JSC.JSValue, extra: JSC.JSValue, extra2: JSC.JSValue) void {
pub fn dispatchWith2Extra(this: *H2FrameParser, comptime event: @Type(.enum_literal), value: JSC.JSValue, extra: JSC.JSValue, extra2: JSC.JSValue) void {
JSC.markBinding(@src());
const ctx_value = this.strong_ctx.get() orelse return;
@@ -1391,7 +1393,7 @@ pub const H2FrameParser = struct {
extra2.ensureStillAlive();
_ = this.handlers.callEventHandler(event, ctx_value, &[_]JSC.JSValue{ ctx_value, value, extra, extra2 });
}
pub fn dispatchWith3Extra(this: *H2FrameParser, comptime event: @Type(.EnumLiteral), value: JSC.JSValue, extra: JSC.JSValue, extra2: JSC.JSValue, extra3: JSC.JSValue) void {
pub fn dispatchWith3Extra(this: *H2FrameParser, comptime event: @Type(.enum_literal), value: JSC.JSValue, extra: JSC.JSValue, extra2: JSC.JSValue, extra3: JSC.JSValue) void {
JSC.markBinding(@src());
const ctx_value = this.strong_ctx.get() orelse return;

View File

@@ -11,12 +11,12 @@ const Maybe = JSC.Maybe;
const win_rusage = struct {
utime: struct {
tv_sec: i64 = 0,
tv_usec: i64 = 0,
sec: i64 = 0,
usec: i64 = 0,
},
stime: struct {
tv_sec: i64 = 0,
tv_usec: i64 = 0,
sec: i64 = 0,
usec: i64 = 0,
},
maxrss: u64 = 0,
ixrss: u0 = 0,
@@ -54,16 +54,16 @@ pub fn uv_getrusage(process: *uv.uv_process_t) win_rusage {
var kerneltime: WinTime = undefined;
var usertime: WinTime = undefined;
// We at least get process times
if (std.os.windows.kernel32.GetProcessTimes(process_pid, &starttime, &exittime, &kerneltime, &usertime) == 1) {
if (bun.windows.GetProcessTimes(process_pid, &starttime, &exittime, &kerneltime, &usertime) == 1) {
var temp: u64 = (@as(u64, kerneltime.dwHighDateTime) << 32) | kerneltime.dwLowDateTime;
if (temp > 0) {
usage_info.stime.tv_sec = @intCast(temp / 10000000);
usage_info.stime.tv_usec = @intCast(temp % 1000000);
usage_info.stime.sec = @intCast(temp / 10000000);
usage_info.stime.usec = @intCast(temp % 1000000);
}
temp = (@as(u64, usertime.dwHighDateTime) << 32) | usertime.dwLowDateTime;
if (temp > 0) {
usage_info.utime.tv_sec = @intCast(temp / 10000000);
usage_info.utime.tv_usec = @intCast(temp % 1000000);
usage_info.utime.sec = @intCast(temp / 10000000);
usage_info.utime.usec = @intCast(temp % 1000000);
}
}
var counters: IO_COUNTERS = .{};
@@ -110,23 +110,23 @@ pub const ProcessExitHandler = struct {
}
switch (this.ptr.tag()) {
.Subprocess => {
@field(TaggedPointer.Tag, @typeName(Subprocess)) => {
const subprocess = this.ptr.as(Subprocess);
subprocess.onProcessExit(process, status, rusage);
},
.LifecycleScriptSubprocess => {
@field(TaggedPointer.Tag, @typeName(LifecycleScriptSubprocess)) => {
const subprocess = this.ptr.as(LifecycleScriptSubprocess);
subprocess.onProcessExit(process, status, rusage);
},
.ProcessHandle => {
@field(TaggedPointer.Tag, @typeName(ProcessHandle)) => {
const subprocess = this.ptr.as(ProcessHandle);
subprocess.onProcessExit(process, status, rusage);
},
@field(TaggedPointer.Tag, bun.meta.typeBaseName(@typeName(ShellSubprocess))) => {
@field(TaggedPointer.Tag, @typeName(ShellSubprocess)) => {
const subprocess = this.ptr.as(ShellSubprocess);
subprocess.onProcessExit(process, status, rusage);
},
@field(TaggedPointer.Tag, bun.meta.typeBaseName(@typeName(SyncProcess))) => {
@field(TaggedPointer.Tag, @typeName(SyncProcess)) => {
const subprocess = this.ptr.as(SyncProcess);
if (comptime Environment.isPosix) {
@panic("This code should not reached");
@@ -157,7 +157,7 @@ pub const Process = struct {
return @sizeOf(@This());
}
pub usingnamespace bun.NewRefCounted(Process, deinit);
pub usingnamespace bun.NewRefCounted(Process, deinit, null);
pub fn setExitHandler(this: *Process, handler: anytype) void {
this.exit_handler.init(handler);
@@ -924,7 +924,7 @@ const WaiterThreadPosix = struct {
.mask = current_mask,
.flags = std.posix.SA.NOCLDSTOP,
};
std.posix.sigaction(std.posix.SIG.CHLD, &act, null) catch {};
std.posix.sigaction(std.posix.SIG.CHLD, &act, null);
}
}
@@ -2018,7 +2018,9 @@ pub const sync = struct {
pub fn spawn(
options: *const Options,
) !Maybe(Result) {
const envp = options.envp orelse std.c.environ;
// [*:null]?[*:0]const u8
// [*:null]?[*:0]u8
const envp = options.envp orelse @as([*:null]?[*:0]const u8, @ptrCast(std.c.environ));
const argv = options.argv;
var string_builder = bun.StringBuilder{};
defer string_builder.deinit(bun.default_allocator);
@@ -2040,16 +2042,16 @@ pub const sync = struct {
}
// Forward signals from parent to the child process.
extern "C" fn Bun__registerSignalsForForwarding() void;
extern "C" fn Bun__unregisterSignalsForForwarding() void;
extern "c" fn Bun__registerSignalsForForwarding() void;
extern "c" fn Bun__unregisterSignalsForForwarding() void;
// The PID to forward signals to.
// Set to 0 when unregistering.
extern "C" var Bun__currentSyncPID: i64;
extern "c" var Bun__currentSyncPID: i64;
// Race condition: a signal could be sent before spawnProcessPosix returns.
// We need to make sure to send it after the process is spawned.
extern "C" fn Bun__sendPendingSignalIfNecessary() void;
extern "c" fn Bun__sendPendingSignalIfNecessary() void;
fn spawnPosix(
options: *const Options,

View File

@@ -1342,9 +1342,7 @@ fn NewSocket(comptime ssl: bool) type {
// This is wasteful because it means we are keeping a JSC::Weak for every single open socket
has_pending_activity: std.atomic.Value(bool) = std.atomic.Value(bool).init(true),
native_callback: NativeCallbacks = .none,
pub usingnamespace bun.NewRefCounted(@This(), @This().deinit);
pub const DEBUG_REFCOUNT_NAME = "Socket";
pub usingnamespace bun.NewRefCounted(@This(), deinit, "Socket");
// We use this direct callbacks on HTTP2 when available
pub const NativeCallbacks = union(enum) {
@@ -1395,8 +1393,6 @@ fn NewSocket(comptime ssl: bool) type {
JSC.Codegen.JSTLSSocket;
pub fn hasPendingActivity(this: *This) callconv(.C) bool {
@fence(.acquire);
return this.has_pending_activity.load(.acquire);
}
@@ -4378,6 +4374,9 @@ pub fn jsCreateSocketPair(global: *JSC.JSGlobalObject, _: *JSC.CallFrame) bun.JS
return global.throwValue(err.toJSC(global));
}
_ = bun.sys.setNonblocking(bun.toFD(fds_[0]));
_ = bun.sys.setNonblocking(bun.toFD(fds_[1]));
const array = JSC.JSValue.createEmptyArray(global, 2);
array.putIndex(global, 0, JSC.jsNumber(fds_[0]));
array.putIndex(global, 1, JSC.jsNumber(fds_[1]));

View File

@@ -48,8 +48,8 @@ pub const ResourceUsage = struct {
var cpu = JSC.JSValue.createEmptyObjectWithNullPrototype(globalObject);
const rusage = this.rusage;
const usrTime = JSValue.fromTimevalNoTruncate(globalObject, rusage.utime.tv_usec, rusage.utime.tv_sec);
const sysTime = JSValue.fromTimevalNoTruncate(globalObject, rusage.stime.tv_usec, rusage.stime.tv_sec);
const usrTime = JSValue.fromTimevalNoTruncate(globalObject, rusage.utime.usec, rusage.utime.sec);
const sysTime = JSValue.fromTimevalNoTruncate(globalObject, rusage.stime.usec, rusage.stime.sec);
cpu.put(globalObject, JSC.ZigString.static("user"), usrTime);
cpu.put(globalObject, JSC.ZigString.static("system"), sysTime);
@@ -199,7 +199,7 @@ pub const Subprocess = struct {
ref_count: u32 = 1,
abort_signal: ?*JSC.AbortSignal = null,
usingnamespace bun.NewRefCounted(@This(), Subprocess.deinit);
usingnamespace bun.NewRefCounted(@This(), deinit, null);
pub const Flags = packed struct {
is_sync: bool = false,
@@ -279,7 +279,6 @@ pub const Subprocess = struct {
}
pub fn updateHasPendingActivity(this: *Subprocess) void {
@fence(.seq_cst);
if (comptime Environment.isDebug) {
log("updateHasPendingActivity() {any} -> {any}", .{
this.has_pending_activity.raw,
@@ -342,7 +341,6 @@ pub const Subprocess = struct {
}
pub fn hasPendingActivity(this: *Subprocess) callconv(.C) bool {
@fence(.acquire);
return this.has_pending_activity.load(.acquire);
}
@@ -684,7 +682,7 @@ pub const Subprocess = struct {
return this.process.kill(@intCast(sig));
}
fn hasCalledGetter(this: *Subprocess, comptime getter: @Type(.EnumLiteral)) bool {
fn hasCalledGetter(this: *Subprocess, comptime getter: @Type(.enum_literal)) bool {
return this.observable_getters.contains(getter);
}
@@ -853,7 +851,7 @@ pub const Subprocess = struct {
ref_count: u32 = 1,
buffer: []const u8 = "",
pub usingnamespace bun.NewRefCounted(@This(), @This().deinit);
pub usingnamespace bun.NewRefCounted(@This(), _deinit, null);
const This = @This();
const print = bun.Output.scoped(.StaticPipeWriter, false);
@@ -940,7 +938,7 @@ pub const Subprocess = struct {
this.process.onCloseIO(.stdin);
}
pub fn deinit(this: *This) void {
fn _deinit(this: *This) void {
this.writer.end();
this.source.detach();
this.destroy();
@@ -981,7 +979,7 @@ pub const Subprocess = struct {
pub const IOReader = bun.io.BufferedReader;
pub const Poll = IOReader;
pub usingnamespace bun.NewRefCounted(PipeReader, PipeReader.deinit);
pub usingnamespace bun.NewRefCounted(PipeReader, _deinit, null);
pub fn memoryCost(this: *const PipeReader) usize {
return this.reader.memoryCost();
@@ -1148,7 +1146,7 @@ pub const Subprocess = struct {
return this.event_loop.virtual_machine.uwsLoop();
}
fn deinit(this: *PipeReader) void {
fn _deinit(this: *PipeReader) void {
if (comptime Environment.isPosix) {
bun.assert(this.reader.isDone());
}
@@ -1570,7 +1568,7 @@ pub const Subprocess = struct {
}
}
fn closeIO(this: *Subprocess, comptime io: @Type(.EnumLiteral)) void {
fn closeIO(this: *Subprocess, comptime io: @Type(.enum_literal)) void {
if (this.closed.contains(io)) return;
this.closed.insert(io);
@@ -2388,21 +2386,29 @@ pub const Subprocess = struct {
jsc_vm.onSubprocessSpawn(subprocess.process);
}
while (subprocess.hasPendingActivityNonThreadsafe()) {
if (subprocess.stdin == .buffer) {
subprocess.stdin.buffer.watch();
// We cannot release heap access while JS is running
{
const old_vm = jsc_vm.uwsLoop().internal_loop_data.jsc_vm;
jsc_vm.uwsLoop().internal_loop_data.jsc_vm = null;
defer {
jsc_vm.uwsLoop().internal_loop_data.jsc_vm = old_vm;
}
while (subprocess.hasPendingActivityNonThreadsafe()) {
if (subprocess.stdin == .buffer) {
subprocess.stdin.buffer.watch();
}
if (subprocess.stderr == .pipe) {
subprocess.stderr.pipe.watch();
if (subprocess.stderr == .pipe) {
subprocess.stderr.pipe.watch();
}
if (subprocess.stdout == .pipe) {
subprocess.stdout.pipe.watch();
}
jsc_vm.tick();
jsc_vm.eventLoop().autoTick();
}
if (subprocess.stdout == .pipe) {
subprocess.stdout.pipe.watch();
}
jsc_vm.tick();
jsc_vm.eventLoop().autoTick();
}
subprocess.updateHasPendingActivity();
@@ -2433,12 +2439,12 @@ pub const Subprocess = struct {
}
fn throwCommandNotFound(globalThis: *JSC.JSGlobalObject, command: []const u8) bun.JSError {
const message = bun.String.createFormat("Executable not found in $PATH: \"{s}\"", .{command}) catch bun.outOfMemory();
defer message.deref();
const err = message.toZigString().toErrorInstance(globalThis);
err.putZigString(globalThis, JSC.ZigString.static("code"), JSC.ZigString.init("ENOENT").toJS(globalThis));
err.putZigString(globalThis, JSC.ZigString.static("path"), JSC.ZigString.init(command).toJS(globalThis));
return globalThis.throwValue(err);
const err = JSC.SystemError{
.message = bun.String.createFormat("Executable not found in $PATH: \"{s}\"", .{command}) catch bun.outOfMemory(),
.code = bun.String.static("ENOENT"),
.path = bun.String.createUTF8(command),
};
return globalThis.throwValue(err.toErrorInstance(globalThis));
}
const node_cluster_binding = @import("./../../node/node_cluster_binding.zig");

View File

@@ -282,7 +282,7 @@ pub const UDPSocket = struct {
globalThis: *JSGlobalObject,
thisValue: JSValue = .zero,
ref: JSC.Ref = JSC.Ref.init(),
jsc_ref: JSC.Ref = JSC.Ref.init(),
poll_ref: Async.KeepAlive = Async.KeepAlive.init(),
// if marked as closed the socket pointer may be stale
closed: bool = false,

Some files were not shown because too many files have changed in this diff Show More