Compare commits

...

199 Commits

Author SHA1 Message Date
Jarred Sumner
07f8b23350 Make Error.captureStackTrace 4x faster 2023-07-12 00:39:11 -07:00
Jarred Sumner
b566573977 Fix another crash in Error.captureStackTrace (#3611)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-11 21:01:35 -07:00
Jarred SUmner
666feb3b7e Fix crash on linux when throwing SystemError from C++ 2023-07-11 20:52:10 -07:00
Jarred Sumner
5ea32a976e Update process.test.js 2023-07-11 19:49:41 -07:00
Jarred Sumner
34b0e7a2bb Update ZigGlobalObject.cpp 2023-07-11 19:06:49 -07:00
Jarred Sumner
c5f2280489 Implement process.kill and process._kill 2023-07-11 19:06:01 -07:00
Jarred Sumner
a686b3bfc1 Fixes #3595 2023-07-11 19:00:51 -07:00
dave caruso
a1fb289c96 typo (#3610) 2023-07-11 18:50:34 -07:00
Dylan Conway
8ca2194a37 fix #3597 (#3609)
* fix #3597

* Update http.ts

* initialize to true
2023-07-11 18:49:35 -07:00
Jarred Sumner
03904f73cc Merge branch 'jarred/throw-if' 2023-07-11 17:48:52 -07:00
Jarred Sumner
2106e1d7f6 Tests 2023-07-11 17:48:13 -07:00
Jarred Sumner
854ddaa909 Implement throwIfNoEntry 2023-07-11 17:44:29 -07:00
Colin McDonnell
609f81a746 Add npmrc note 2023-07-11 15:32:52 -07:00
Jarred Sumner
fd4c8fb871 Merge branch 'jarred/fix-http-compression' 2023-07-11 13:09:37 -07:00
Jarred Sumner
bab58b7541 Avoid Object.getPrototypeOf 2023-07-11 13:07:03 -07:00
Dylan Conway
5c8726d602 process signal events (#3569)
* signal events

* simple tests

* ignore SIGSTOP

* better tests

* use `EventEmitter`

* use `Bun__getDefaultGlobal`

* progress

* don't use 'Bun__getDefaultGlobal`

* fix tests

* remove signals from map

* update tests

* don't overwrite event emitter methods

* avoid two lookups

* use `std::once`

* releaseEarly()

* Remove signal handler after use

* Update call-raise.js

* Create process-signal-handler.fixture.js

* Don't register duplicates

* Add missing lock

* another test

* update test

* revert some changes

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-11 12:48:46 -07:00
Dylan Conway
ae7bc37e94 fix iterating stack trace (#3600)
* `i + 1` and remove `defer`

* a test

* fix test
2023-07-11 12:48:32 -07:00
dave caruso
31ab56d362 Fix: console.log with class constructors (#3602)
* Fix console.log with class constructors

* oops

* fix it

* lol

* fix test
2023-07-11 12:48:19 -07:00
simylein
4b333b2d35 docs(sqlite): database prepare types reflect runtime (#3599)
* docs(sqlite): database prepare types reflect runtime

* Update sqlite.d.ts

---------

Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
2023-07-11 09:09:06 -07:00
Hanaasagi
c4c5eb2d32 use Object.getPrototypeOf 2023-07-11 21:31:49 +09:00
Ai Hoshino
e7afae305c Merge branch 'main' into fix-http 2023-07-11 19:35:11 +08:00
Hanaasagi
17031936c8 small fix, check if the method has been reassigned. 2023-07-11 20:32:09 +09:00
dave caruso
b2c576bba2 fix "readable" event being emitted incorrectly (#3475)
* fix "readable" event being emitted incorrectly

* fix impl and add test

* changes

* asdfghj

* esm
2023-07-10 18:25:20 -07:00
Ciro Spaciari
4af4b508a1 feat(crypto) add getCurves (#3598)
* add getCurves

* add nodefallbacks

* update docs

* oops
2023-07-10 17:14:37 -07:00
Hanaasagi
0c2df4ae01 ignore check 2023-07-10 22:33:07 +09:00
Ai Hoshino
cc0d920018 Merge branch 'main' into fix-http 2023-07-10 21:12:00 +08:00
Hanaasagi
438d54f186 add tests 2023-07-10 22:04:39 +09:00
Hanaasagi
c6e1135548 call writeHead before send headers
Close: #3585
2023-07-10 21:35:10 +09:00
Jarred Sumner
ec11170311 Fixes #3588 (#3590)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-10 02:21:03 -07:00
Jarred Sumner
538bcef731 Update globals.d.ts 2023-07-10 01:33:46 -07:00
Jarred Sumner
93b0e94410 trim node:stream a little 2023-07-10 01:26:02 -07:00
Jarred Sumner
963d4311e6 Fixes #3530 (#3587)
* Fixes #3530

* Handle OOM

* Add test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-09 22:36:24 -07:00
Jarred Sumner
2f5e4fffe9 Implement process.memoryUsage() and process.cpuUsage() (#3586)
* Implement process.memoryUsage() and process.cpuUsage()

* Avoid mi_process_info

* Update bench

* Update Process.cpp

* fixup

* More tests + linux fixup

* Skip it for now since it seems less accurate

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-09 21:50:19 -07:00
Jarred Sumner
ca42c820d2 Implement nearly all of process object methods and properties (#3581)
* Add special case

* Make process object load faster

* Fix openStdin

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-09 16:33:49 -07:00
Ai Hoshino
565d1689e9 fix metadata bits of uuid (randomUUID()) (#3583)
* fix uuid version
Close: https://github.com/oven-sh/bun/issues/3575

* add unittest

* small fix

* avoid unnecessary copying
2023-07-09 07:20:52 -07:00
Jarred Sumner
59570fe237 Handle case with TS decorators and export default anonymous class (#3578)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-08 17:41:24 -07:00
Jarred Sumner
aa8b832ef6 Implement process.on("beforeExit", cb) and process.on("exit", cb) (#3576)
* Support `process.on('beforeExit')` and `process.on('exit')`

* [bun:sqlite] Always call sqlite3_close on exit

* Update process.test.js

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-08 14:26:19 -07:00
Jarred Sumner
fa632c3331 Fix bug with decorators not being generated in export default class (#3577)
* Fix bug with decorators not being generated in `export default class`

* Update decorator-export-default-class-fixture.ts

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-08 04:00:55 -07:00
Jarred Sumner
5846ad00ed Add assertion 2023-07-07 22:01:58 -07:00
Jarred Sumner
e26d3821ce Update settings.json 2023-07-07 22:01:43 -07:00
Jarred Sumner
fceacea37c Unmark as TODO 2023-07-07 22:01:02 -07:00
Jarred Sumner
52b7962dae Use BunString in JSBundlerPlugin (#3557)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-07 21:20:30 -07:00
Jarred Sumner
386d8b7836 Update test 2023-07-07 21:20:16 -07:00
Jarred Sumner
67ee498861 Fix potential coercion issue (#3558)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-07 20:12:39 -07:00
Artur Androsovych
42eacaf3a9 Update installation guide in development.md (#3532)
* Update installation guide in `development.md`

* Updates

---------

Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
2023-07-07 16:24:07 -07:00
Ai Hoshino
c0cf7b4501 fix decoding invalid UTF-8 input (#3563)
* fix decoding invalid UTF-8 input
Close: https://github.com/oven-sh/bun/issues/3562

* add unittest
2023-07-07 15:10:49 -07:00
Colin McDonnell
affd06d05c Update types, partially fix typecheck (#3551)
* Update types

* Remove caret
2023-07-07 15:10:33 -07:00
Jarred Sumner
7ab8d832fb Add obscure HTTP methods (#3553)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-07 00:38:18 -07:00
Jarred Sumner
0ecdbf4793 [node:fs] read, write - support large numbers and BigInt (#3556)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-07 00:33:43 -07:00
Jarred Sumner
284aaec3cd Remove unnecessary @setRuntimeSafety(false) 2023-07-06 23:50:32 -07:00
Dylan Conway
9bebb7f03d add [dir] to default 2023-07-06 20:51:41 -07:00
Jarred Sumner
5c0a5646cd Update list 2023-07-06 17:11:01 -07:00
Jarred Sumner
4d2c86fd5c Add util.toUSVString 2023-07-06 17:08:01 -07:00
Jarred Sumner
d905dbe214 Minify zlib because its huge 2023-07-06 16:50:03 -07:00
Jarred Sumner
038ca83004 Add missing export in url 2023-07-06 16:49:41 -07:00
Colin McDonnell
d377265b67 Update trustedDeps doc 2023-07-06 15:44:48 -07:00
Colin McDonnell
a415f482db Update trustedDeps doc 2023-07-06 15:33:49 -07:00
Ciro Spaciari
954b6fcaf3 refactor (#3543) 2023-07-06 13:55:27 -07:00
Dylan Conway
abe095dd1e fixes #3544 (#3549) 2023-07-06 13:55:00 -07:00
Colin McDonnell
109ebc14fd Various docs updates (#3437)
* Various docs updates

* Add mocks page

* Fix make

* WebKit instructions

* Update instructions

* Updates

* Update nodejs compat table

* Document trusted deps

* Tweak trustedDependencies docs

* Document --exact

* Update test docs

* Tweaks

* Boring

* Remove redundant j

* Undo makefile changes

* Undo makefile changes

* Update page title

* Regen

* Undo changes
2023-07-06 13:02:29 -07:00
Ciro Spaciari
95ddfcc437 fix query without slash (#3547) 2023-07-06 12:01:16 -07:00
Jarred Sumner
ee57935260 Fixes #3537 (#3539)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-06 00:06:43 -07:00
Dylan Conway
6bf8f6f9f2 don't unwrap react below version 18.0.0 (#3538)
* don't unwrap react below version 18

* empty string

* also `react-dom`
2023-07-05 22:23:32 -07:00
Ciro Spaciari
8869bac411 fix callbacks on release version (#3531) 2023-07-05 22:22:56 -07:00
Dylan Conway
f61d9ef476 Update websocket_http_client.zig 2023-07-05 12:45:20 -07:00
Jarred Sumner
3aaec120e7 Fixes #3512 (#3526)
* Fixes #3512

* Fix `clearTimeout` and `clearInterval` not cancelling jobs same-tick

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-05 03:46:10 -07:00
Jarred Sumner
c864976da6 Fixes #3515 (#3523)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-05 01:21:35 -07:00
Jarred Sumner
a7f5a91cfb Fixes #3520 (#3522)
* Fixes #3520

* Update html_rewriter.zig

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-05 00:08:59 -07:00
Ciro Spaciari
75816aa3ab add envs on tests (#3518)
Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2023-07-05 00:08:49 -07:00
Jarred Sumner
cac7dcdc76 Update build-id 2023-07-04 16:59:33 -07:00
Jarred Sumner
9c374eac96 Fix build determinism issue (thanks to @alexlamsl)
cc @dylan-conway this was the cause
2023-07-04 16:59:03 -07:00
Jarred Sumner
b2e28f133e boop 2023-07-04 16:57:46 -07:00
Ciro Spaciari
3a93ddfab3 use sengrid account on nodemailer test (#3517) 2023-07-04 15:41:37 -07:00
Ciro Spaciari
979e999403 [tls] fix servername (#3513)
* fix servername

* add postgres tls tests

* update test packages

* add basic CRUD test
2023-07-04 15:40:26 -07:00
Ai Hoshino
c2755f770c Add alias for readBigUInt64BE ... (#3514)
* Add alias for `readBigUInt64BE` ...
Close: https://github.com/oven-sh/bun/issues/3338

* add some tests for `readBigUint64BE` alias

* format code
2023-07-04 15:38:44 -07:00
Jarred Sumner
31f7f9e2dc reduce count 2023-07-04 04:15:22 -07:00
Jarred Sumner
491e8f7e00 bump 2023-07-04 04:14:06 -07:00
Jarred Sumner
bb96aa5156 Fix crash 2023-07-04 04:07:35 -07:00
Jarred Sumner
f49a308d2c Create readfile-not-found.mjs 2023-07-04 03:48:10 -07:00
Alex Lam S.L
3d0ffc48cb [install] fix run-time module loading (#3510)
- fix version buffer confusion
- improve workaround to handle cached modules

fixes #3507
2023-07-04 02:09:58 -07:00
Jarred Sumner
bc7b5165be less flaky 2023-07-04 01:51:09 -07:00
Jarred Sumner
a76b07a802 cleanup 2023-07-04 01:18:13 -07:00
Jarred SUmner
33bc507f74 Fix napi 2023-07-04 01:04:18 -07:00
Jarred Sumner
3345a7fc3c Allow zero length WebSocket client & server messages (#3488)
* Allow zero length WebSocket client & server messages

* Add test

* Clean this up a little

* Clean up these tests a little

* Hopefully fix the test failure in release build

* Don't copy into the receive buffer

* Less flaky

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-03 20:53:41 -07:00
Jarred Sumner
b26b0d886c Fix napi bug 2023-07-03 15:57:10 -07:00
Ciro Spaciari
034577c9da [fix] patch fs.watch sym link (#3481)
* oopsie

* add tests

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2023-07-03 14:08:49 -07:00
Jarred Sumner
424717a973 Fixes #3317 2023-07-03 13:47:37 -07:00
Jarred Sumner
e5f93ddf55 Update lifecycle.md 2023-07-03 13:46:20 -07:00
Jarred Sumner
983039a18a Fixes #3508 2023-07-03 13:16:57 -07:00
Ciro Spaciari
a7a01bd52f [tls] add socket parameter, setServername and ALPNprotocols support (#3457)
* add socket parameter support

* refactor #socket

* add test and more fixs

* some fixes

* bump uws

* handlers fix

* more fixes

* fix node net and node tls tests

* fix duplicate port

* fix deinit on CallbackJobs

* cleanup

* add setImmediate repro

* add test to setImmediate

* this is necessary?

* fix prependOnce on native listener

* try to findout the error on nodemailer CI

* show error message

* Update bun.lockb

* prettier

* Use exact versions of packages

* add alpnProtocol support

* update

* emit error when connect fails on net.Socket

* format

* fix _write and cleanup

* fixup

* fix connect, add alpn test

* fix socket.io

* add socket parameter to TLSSocket

* add TLSSocket socket first parameter

* fixup and _start

* remove flask tests

* fmt

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-03 12:19:50 -07:00
Jarred Sumner
48d726bfd0 Update time.md 2023-07-02 23:48:31 -07:00
Jarred Sumner
12a342b6c0 Update time.md 2023-07-02 23:47:48 -07:00
Jarred Sumner
1206352b4a Update time.md 2023-07-02 23:46:08 -07:00
Jarred Sumner
9da9bac30c Update time.md 2023-07-02 23:18:58 -07:00
Jarred Sumner
cd243f40ee Update time.md 2023-07-02 23:10:50 -07:00
Jarred Sumner
000417731b Add time doc 2023-07-02 23:07:33 -07:00
Jarred Sumner
c77518ff93 Update writing.md 2023-07-02 22:57:24 -07:00
Jarred Sumner
f0a795b568 Stub out useFakeTimers and useRealTimers 2023-07-02 22:42:13 -07:00
Jarred Sumner
aa38e51afb Support mocking new Date() & Date.now() in bun:test (#3501)
* Support changing the time

* Bump WebKit

* Update bun.lockb

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-02 22:09:50 -07:00
dave caruso
c21fadf9bc set content-length 0 in some cases (#3503) 2023-07-02 20:24:15 -07:00
Jarred Sumner
0db31c2b43 Fixes #3499 2023-07-02 20:18:21 -07:00
Jarred Sumner
3a0a423bce Add comment 2023-07-02 20:17:25 -07:00
Jarred Sumner
eb90ce50c3 Use fast path for Base64 in btoa (#3504)
* Use fast path for Base64 in `atob`

* Fix utf16, crash on linux

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-02 20:16:52 -07:00
Jarred Sumner
c3f8593f8c [node:buffer] Implement isUtf8 and isAscii (#3498)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-02 18:06:21 -07:00
dave caruso
4cbda049e9 fix zero length env var (#3496) 2023-07-02 10:12:31 -07:00
Jarred Sumner
69396aae01 Fixes #3495 2023-07-02 10:09:52 -07:00
Jarred Sumner
b05879e9e2 Fixes #3489 (#3490)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-02 01:06:40 -07:00
Jarred Sumner
8001038376 Use exact versions in tests 2023-07-01 22:43:59 -07:00
Jarred Sumner
c7cc618376 Fix leak in fd (#3487)
* Fix file descriptor leak

* Skip unnecessary clone

* Don't break --hot

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-01 21:58:06 -07:00
Jarred Sumner
9fecb3dfb9 Bump 2023-07-01 21:10:55 -07:00
Jarred Sumner
617226e584 Make this test less flaky 2023-07-01 21:10:43 -07:00
Jarred Sumner
c72c82b970 Make this test less flaky 2023-07-01 21:08:26 -07:00
Jarred Sumner
6cae6ebafe Make buffer.toString("base64") 4x faster (#3486)
* Add libbase64

* Add bench

* Update licensing.md

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-01 20:02:50 -07:00
Jarred Sumner
a2cca6e292 Update WebCoreJSBuiltins.cpp 2023-07-01 18:31:38 -07:00
Jarred Sumner
01d3b130a9 Update build-id 2023-07-01 17:44:40 -07:00
Jarred Sumner
af46a8ded1 Make this test less flaky 2023-07-01 17:38:19 -07:00
Jarred Sumner
f00e2be548 Use BunString in SystemError (#3485)
* Use `BunString` in SystemError

* Use Bun::toStringRef when we will de-ref strings

* Move `napi_create_error` to C++ to support `code` being a Symbol potentially

* Update blob.zig

* Make this test less flaky

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-01 17:37:44 -07:00
Jarred Sumner
a4fe433db7 Slight fixup 2023-07-01 17:09:59 -07:00
Jarred Sumner
f3833376e7 small cleanup 2023-07-01 17:07:37 -07:00
Ai Hoshino
4720fa1207 [WIP]Fix calling Buffer.toString with (offset, length, encoding) (#3467)
* Allow `toString` to be called with `(offset, length, encoding)`.
Close: #3085

* handle undefined value

* add tests for buffer.xxxSlice

* fix parameters

* fix offset and length
2023-07-01 17:01:52 -07:00
Jarred Sumner
df10252979 Make HTTP Request struct use 8 bytes less memory (#3483)
* Make HTTP Request struct use 8 bytes less memory

* Update server.zig

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-07-01 14:40:05 -07:00
Dylan Conway
c033d55c47 skip private class fields (#3484) 2023-07-01 14:38:38 -07:00
Jarred Sumner
c794ea7ea7 Add test 2023-07-01 13:31:12 -07:00
Alex Lam S.L
02f707f231 [jest] fix lifecycle hook execution order (#3461)
* [jest] fix lifecycle hook execution order

* strip `std.debug.assert()` from release build
2023-07-01 11:44:04 -07:00
dave caruso
d356cd5d48 implement perf_hooks.constants (#3476) 2023-06-30 14:58:38 -07:00
Stijn Van Hulle
b83faf8018 fix: export ClientRequest and OutgoingMessage as part of the node:http package (#3470) 2023-06-30 10:04:46 -07:00
Alex Lam S.L
2a73d3c793 [install] handle workspace: specifier correctly (#3474)
fixes #3430
2023-06-30 10:03:53 -07:00
Jarred Sumner
039bbc68ad Add missing "prependListener" function 2023-06-29 21:24:55 -07:00
dave caruso
b9460087e3 Fixes node:http and node:stream so ytdl-core works. (#3452)
* fix crash in readablestate

* make node:https request+get actually use https

* use a native readablestream in IncomingMessage

* tweaks

* fix abort crash

* emit close by default

* remove abort. this isnt a real function

* add validate functions, fixup some other requested changes. not done yet

* Update WebCoreJSBuiltins.cpp

* Update JSReadableState.cpp

* Add some missing exports

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-29 20:36:18 -07:00
Jarred Sumner
c42a00f9df Fixes #3462 (#3465)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-29 20:14:12 -07:00
Dylan Conway
76b9cae259 handle multiple redirects 2023-06-29 17:19:16 -07:00
Jarred Sumner
70a87e1181 Make node:os tmpdir more consistent with Node.js 2023-06-29 16:37:38 -07:00
Dylan Conway
7af757d104 add setters for Agent properties (#3460)
* make `Agent` properties public

* back to private, added setters

* change properties to public
2023-06-29 15:47:00 -07:00
Dylan Conway
9c66fdc703 [bundler] avoid printing unnecessary declarations (#3456)
* skip declarations without values

* tests

* deoptimize cjs when decls are needed
2023-06-29 14:51:24 -07:00
dave caruso
fec0d15c4f cant believe i missed this (#3453) 2023-06-29 08:53:44 -07:00
Jarred Sumner
853e377159 Revert "[jest] fix lifecycle hook execution order (#3447)" (#3455)
This reverts commit 182e8aa139.
2023-06-29 08:30:21 -07:00
Jarred Sumner
8984c81961 Prevent integer overflow 2023-06-28 21:57:31 -07:00
Jarred Sumner
c6f6db95ff Ref the strings 2023-06-28 21:56:45 -07:00
Jarred Sumner
8b2c72300c Another test 2023-06-28 21:56:26 -07:00
Jarred Sumner
8481f2922f Add GC test for errors 2023-06-28 21:45:16 -07:00
Jarred Sumner
68e6fe00a4 Use bun.String for ZigException (#3451)
* Use `bun.String` for `ZigException`

* woopsie

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-28 21:11:06 -07:00
Dylan Conway
3258bed1c0 use main field over module for runtime (#3448)
* use main field over module for runtime

* move flag to `Resolver`

* set `prefer_module_field` in `initWithModuleGraph`
2023-06-28 19:28:53 -07:00
Jarred Sumner
32d9abcc03 Fix bad test 2023-06-28 19:20:41 -07:00
dave caruso
0cee640199 export resolve6 from dns/promises (#3450) 2023-06-28 17:45:18 -07:00
Alex Lam S.L
182e8aa139 [jest] fix lifecycle hook execution order (#3447) 2023-06-28 16:27:15 -07:00
Jarred Sumner
945093ee7e bump! 2023-06-28 16:22:46 -07:00
Jarred Sumner
086ca176be Make these tests do more 2023-06-28 16:19:58 -07:00
Jarred Sumner
292647bd53 Introduce await Bun.file(path).exists() (#3446)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-28 16:09:08 -07:00
Jarred Sumner
42ded70336 [node:http] Stub _implicitHeader fn 2023-06-28 13:55:58 -07:00
Jarred Sumner
3d5573921e Error.prototype.stack gets sourcemapped stacktraces and introduce Error.appendStackTrace (#3441)
* Fix potential crash when reading sourcemapped stack traces

* Format & sourcemap Error.prototype.stack

* prevent double sourcemapping

* Introduce Error.appendStackTrace

* Fix source url

* hide private stack traces in non-debug builds

* fixes #3443

* Bump WebKit

* Fix test failure in vm.test

* Support new() & add test

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-28 13:53:09 -07:00
Jarred Sumner
43752ec3f0 Fix assertion failure in escapeHTML with UTF-16 text (#3436)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-28 11:27:31 -07:00
Silas Rech
e6e3d9e368 Fix .randomInt() export (#3438) 2023-06-28 11:27:02 -07:00
Alex Lam S.L
0de5bb22af [install] workaround run-time module loading issue (#3432) 2023-06-28 01:20:59 -07:00
Dylan Conway
f670c0fc18 don't overwrite __esModule 2023-06-27 18:23:56 -07:00
Dylan Conway
09994d6067 add __esModule 2023-06-27 17:34:31 -07:00
Benjamin Ryan
f81d084f5c [bun:sqlite] enable FTS5 on linux build (#3431)
* [bun:sqlite] enable FTS5 on linux build

* prettier
2023-06-27 17:27:06 -07:00
Jarred Sumner
940c9a8185 Fix some checks 2023-06-27 16:16:47 -07:00
Dylan Conway
28d7507a5d add todo comment 2023-06-27 14:55:13 -07:00
Jarred Sumner
4f34d48029 getIfPropertyExists is safer than getDirect (#3391)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-27 13:42:25 -07:00
Dylan Conway
c78aa5a60f fix macros 2023-06-27 13:23:01 -07:00
Revenity
7ba4ae11c9 Update Stric page in Ecosystem (#3399) 2023-06-27 12:37:57 -07:00
Jarred Sumner
5376b5b5d6 Add builtin exports list 2023-06-27 10:29:22 -07:00
Ashcon Partovi
3ec6c9e4fb Fix docker tag on release 2023-06-27 09:10:43 -07:00
Jarred Sumner
2eb885c1d8 Regenerate 2023-06-27 08:24:35 -07:00
Ai Hoshino
1c46d88728 Fix node:util.callbackify (#3428)
* remove the incorrect parameters
Close: https://github.com/oven-sh/bun/issues/3424

* fix error code

* add callbackify tests

* fix function type

* ensure `done` is called when error occurred
2023-06-27 08:23:25 -07:00
Jarred Sumner
d220d9ee5a Update NodeModuleModule.cpp 2023-06-27 08:21:04 -07:00
Jarred Sumner
e77f593b76 Update build-id 2023-06-27 08:14:34 -07:00
Alex Lam S.L
b305309e64 minor build diffs (#3427) 2023-06-27 14:05:59 +03:00
Jarred Sumner
c96f3b303b Fix default export of "module" module 2023-06-26 20:39:15 -07:00
dave caruso
ecb0bd39b6 fix #3412 (#3422) 2023-06-26 19:27:12 -07:00
Dylan Conway
4e4cae0fc3 webpack test and add empty prototype prop to module (#3421) 2023-06-26 19:16:59 -07:00
Jarred Sumner
4be15cff02 Tweak the ramSize setting because /= 1024 is causing CI to fail on arm64 when there's only 8 GB of ram 2023-06-26 19:07:54 -07:00
Jarred Sumner
f839cf1ce3 Update crypto.mjs 2023-06-26 19:07:54 -07:00
Jarred Sumner
1e6a41b5cf change the text from "error" to "warn" 2023-06-26 19:07:54 -07:00
Dylan Conway
1ed1723a2f Update bundle_v2.zig (#3420) 2023-06-26 19:00:55 -07:00
Peter Weinberg
7a0b1656c7 docs: add troubleshooting section to installation page (#3389)
* docs: add troubleshooting section to installation page

* Add note for unzip

* Update msg in install.sh

---------

Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
2023-06-26 18:25:33 -07:00
Jarred Sumner
28f27f733b [bun install] Implement --exact flag (#3409)
* [bun install] Implement `--exact` flag

* Rename to --save-exact

* Rename --exact to --save-exact

* Update bun-add.test.ts

* We're going with --exact as the flag name

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-26 15:51:57 -07:00
Jarred Sumner
a5100ad380 Fix .rejects 2023-06-26 15:49:26 -07:00
Silas Rech
16598555f1 .randomInt() support (#3357)
* Add initial .randomInt() fallback

* Add basic .randomInt() test

* Attempt creating a native implementation

* Switch to JSC.wrapWithHasContainer

* Switch to .jsNumberFromUint64(), it seems like using just .jsNumber() causes the number to overflow in some cases

* Regenerate out folder after rebasing
2023-06-26 15:35:48 -07:00
Jarred Sumner
a732999da5 Runtime support for __esModule annotations (#3393)
* Runtime support for `__esModule` annotations

* Ignore `__esModule` annotation when `"type": "module"` is set

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-26 12:49:20 -07:00
Dylan Conway
6d01e6e367 test moved to node-module-module.test.js 2023-06-26 12:09:18 -07:00
Jarred Sumner
50e872fc76 Implement writev & readv (#3419)
* [node:fs] Implement `writev` and `readv`

* writev & readv tests

* cast to const type

* woops

* cast

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-26 11:56:53 -07:00
Alex Lam S.L
318879d174 [install] support trustedDependencies (#3288)
* [install] support trustedDependencies

closes #2073

* use `strings.indexOfChar()`

* use hashes instead of strings

* utilise `inline else`
2023-06-26 11:55:26 -07:00
Dylan Conway
ec3ed67bc9 implement _nodeModulePaths and require.main.paths (#3411)
* tests in progress

* add `require.main.paths`, add every dir up to root

* remove imports
2023-06-26 08:12:37 -07:00
Jarred Sumner
76626ac54b Fix test failures in import.meta (#3403)
* Fix test failures in import.meta

* regenerate

* Use bound functions for `import.meta.require` and `import.meta.require.resolve` and `Module.createRequire`

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 19:48:56 -07:00
Jarred Sumner
116bcf4245 Fixes #3334 (#3401)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 18:49:16 -07:00
Jarred Sumner
f2285a6d71 Use bun.String in mkdir (#3404)
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 17:54:55 -07:00
Jarred Sumner
e682ffb61c Update schema.zig 2023-06-25 17:54:21 -07:00
Jarred Sumner
9ebb25427a remove very old stuff 2023-06-25 17:51:24 -07:00
Jarred Sumner
66195ffeed Update WebKit 2023-06-25 17:50:12 -07:00
Brúnó Salomon
662335d81a chore: update lol-html version (#3356)
* chore: update lol-html version

* add tests

---------

Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
2023-06-25 16:48:03 -07:00
Tiago Teixeira
d8817c2d32 Add support for install with --frozen-lockfile (#3365)
* Add support for install with --frozen-lockfile

* Add test

* Add test for frozenLockfile in config file
2023-06-25 16:43:39 -07:00
Jarred Sumner
15ac08474e fixup 2023-06-25 16:40:51 -07:00
Jarred Sumner
fdfbb18531 Support reading embedded files in compiled executables (#3405)
* Support reading embedded files in compiled executables

* 💅

---------

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
2023-06-25 16:32:27 -07:00
Ciro Spaciari
3ed28f2828 [fs.watch] fix reference/deinit (#3396)
* fix js reference

* fix close  oops

* refactor + hasPendingActivity

* fmt

* fix race conditions

* fixup

* add test calling close on error event

* fix close inside close + test

* cleanup
2023-06-25 16:16:25 -07:00
Ai Hoshino
fcf9f0a7ee Fix the parameters of WriteStream constructor. (#3402)
* Fix the parameters of the `WriteStream` constructor.
Close: https://github.com/oven-sh/bun/issues/3395

* test append mode in `createWriteStream`

* fix lint

* wait first stream finished
2023-06-25 16:15:56 -07:00
Alex Lam S.L
33903ea892 [install] fix hang in bun install --production (#3406) 2023-06-26 01:43:58 +03:00
Jarred Sumner
5bd94b8f47 Add process.mainModule 2023-06-25 11:43:54 -07:00
Jarred Sumner
aa5432e162 FIx launch.json cwd 2023-06-25 11:33:13 -07:00
369 changed files with 43922 additions and 17676 deletions

View File

@@ -36,7 +36,7 @@ jobs:
arch: aarch64
build_arch: arm64
runner: linux-arm64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-linux-arm64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-arm64-lto"
build_machine_arch: aarch64

View File

@@ -46,7 +46,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
- cpu: nehalem
@@ -54,7 +54,7 @@ jobs:
arch: x86_64
build_arch: amd64
runner: big-ubuntu
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-linux-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-linux-amd64-lto.tar.gz"
webkit_basename: "bun-webkit-linux-amd64-lto"
build_machine_arch: x86_64
@@ -191,6 +191,11 @@ jobs:
./bun --version
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
PRISMA_POSTGRES_DATABASE_URL: ${{ secrets.PRISMA_POSTGRES_DATABASE_URL }}
PRISMA_MONGODB_DATABASE_URL: ${{ secrets.PRISMA_MONGODB_DATABASE_URL }}
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
bun install

View File

@@ -117,7 +117,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: haswell
@@ -126,7 +126,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
# - cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: haswell
@@ -144,7 +144,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: native
@@ -152,7 +152,7 @@ jobs:
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
dependencies: true
compile_obj: true
@@ -257,7 +257,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -265,14 +265,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: native
arch: aarch64
tag: bun-darwin-aarch64
obj: bun-obj-darwin-aarch64
package: bun-darwin-aarch64
artifact: bun-obj-darwin-aarch64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-arm64-lto.tar.gz"
runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -430,6 +430,11 @@ jobs:
./bun --version
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
PRISMA_POSTGRES_DATABASE_URL: ${{ secrets.PRISMA_POSTGRES_DATABASE_URL }}
PRISMA_MONGODB_DATABASE_URL: ${{ secrets.PRISMA_MONGODB_DATABASE_URL }}
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
bun install

View File

@@ -117,7 +117,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: haswell
@@ -126,7 +126,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
obj: bun-obj-darwin-x64-baseline
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: haswell
@@ -144,7 +144,7 @@ jobs:
# obj: bun-obj-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
# - cpu: native
@@ -152,7 +152,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -258,7 +258,7 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64-baseline
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: haswell
# arch: x86_64
# tag: bun-darwin-x64
@@ -266,14 +266,14 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -434,6 +434,11 @@ jobs:
./bun --version
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
PRISMA_POSTGRES_DATABASE_URL: ${{ secrets.PRISMA_POSTGRES_DATABASE_URL }}
PRISMA_MONGODB_DATABASE_URL: ${{ secrets.PRISMA_MONGODB_DATABASE_URL }}
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
bun install

View File

@@ -117,7 +117,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: true
# compile_obj: false
- cpu: haswell
@@ -126,7 +126,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: true
compile_obj: false
# - cpu: nehalem
@@ -135,7 +135,7 @@ jobs:
# obj: bun-obj-darwin-x64-baseline
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# dependencies: false
# compile_obj: true
- cpu: haswell
@@ -144,7 +144,7 @@ jobs:
obj: bun-obj-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
dependencies: false
compile_obj: true
# - cpu: native
@@ -152,7 +152,7 @@ jobs:
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
# dependencies: true
# compile_obj: true
@@ -260,7 +260,7 @@ jobs:
# package: bun-darwin-x64
# runner: macos-11
# artifact: bun-obj-darwin-x64-baseline
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
- cpu: haswell
arch: x86_64
tag: bun-darwin-x64
@@ -268,14 +268,14 @@ jobs:
package: bun-darwin-x64
runner: macos-11
artifact: bun-obj-darwin-x64
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-amd64-lto.tar.gz"
webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-amd64-lto.tar.gz"
# - cpu: native
# arch: aarch64
# tag: bun-darwin-aarch64
# obj: bun-obj-darwin-aarch64
# package: bun-darwin-aarch64
# artifact: bun-obj-darwin-aarch64
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-1/bun-webkit-macos-arm64-lto.tar.gz"
# webkit_url: "https://github.com/oven-sh/WebKit/releases/download/may20-3/bun-webkit-macos-arm64-lto.tar.gz"
# runner: macos-arm64
steps:
- uses: actions/checkout@v3
@@ -436,6 +436,11 @@ jobs:
./bun --version
- id: test
name: Test (node runner)
env:
SMTP_SENDGRID_SENDER: ${{ secrets.SMTP_SENDGRID_SENDER }}
TLS_POSTGRES_DATABASE_URL: ${{ secrets.TLS_POSTGRES_DATABASE_URL }}
PRISMA_POSTGRES_DATABASE_URL: ${{ secrets.PRISMA_POSTGRES_DATABASE_URL }}
PRISMA_MONGODB_DATABASE_URL: ${{ secrets.PRISMA_MONGODB_DATABASE_URL }}
# if: ${{github.event.inputs.use_bun == 'false'}}
run: |
bun install

View File

@@ -156,8 +156,8 @@ jobs:
with:
images: oven/bun
tags: |
type=match,pattern=(bun-v)?(\d.\d.\d),group=2,value=${{ env.TAG }}
type=match,pattern=(bun-v)?(\d.\d),group=2,value=${{ env.TAG }}
type=match,pattern=(bun-v)?(\d+.\d+.\d+),group=2,value=${{ env.TAG }}
type=match,pattern=(bun-v)?(\d+.\d+),group=2,value=${{ env.TAG }}
- id: login
name: Login to Docker
uses: docker/login-action@v2

8
.gitmodules vendored
View File

@@ -68,4 +68,10 @@ fetchRecurseSubmodules = false
[submodule "src/deps/zstd"]
path = src/deps/zstd
url = https://github.com/facebook/zstd.git
ignore = dirty
ignore = dirty
[submodule "src/deps/base64"]
path = src/deps/base64
url = https://github.com/aklomp/base64.git
ignore = dirty
depth = 1
shallow = true

19
.vscode/launch.json generated vendored
View File

@@ -14,7 +14,8 @@
"name": "bun test [file]",
"program": "bun-debug",
"args": ["test", "${file}"],
"cwd": "${fileDirname}",
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1",
@@ -29,7 +30,8 @@
"name": "bun test [file] (fast)",
"program": "bun-debug",
"args": ["test", "${file}"],
"cwd": "${fileDirname}",
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1"
@@ -44,7 +46,8 @@
"name": "bun test [file] (verbose)",
"program": "bun-debug",
"args": ["test", "${file}"],
"cwd": "${fileDirname}",
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1"
},
@@ -57,7 +60,8 @@
"name": "bun test [file] --watch",
"program": "bun-debug",
"args": ["test", "--watch", "${file}"],
"cwd": "${fileDirname}",
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1"
@@ -71,7 +75,8 @@
"name": "bun test [file] --only",
"program": "bun-debug",
"args": ["test", "--only", "${file}"],
"cwd": "${fileDirname}",
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
"BUN_DEBUG_QUIET_LOGS": "1"
@@ -100,6 +105,7 @@
"name": "bun test [*] (fast)",
"program": "bun-debug",
"args": ["test"],
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
@@ -114,6 +120,7 @@
"name": "bun test [*] --only",
"program": "bun-debug",
"args": ["test", "--only"],
// The cwd here must be the same as in CI. Or you will cause test failures that only happen in CI.
"cwd": "${workspaceFolder}/test",
"env": {
"FORCE_COLOR": "1",
@@ -318,7 +325,7 @@
"name": "bun install",
"program": "bun-debug",
"args": ["install"],
"cwd": "${workspaceFolder}",
"cwd": "${fileDirname}",
"console": "internalConsole",
"env": {
"BUN_DEBUG_QUIET_LOGS": "1"

View File

@@ -7,6 +7,8 @@
"search.followSymlinks": false,
"search.useIgnoreFiles": true,
"zig.buildOnSave": false,
// We do this until we upgrade to latest Zig so that zls doesn't break our code.
"zig.formattingProvider": "extension",
"zig.buildArgs": ["obj", "-Dfor-editor"],
"zig.buildOption": "build",
"zig.buildFilePath": "${workspaceFolder}/build.zig",

View File

@@ -10,7 +10,7 @@ ARG ARCH=x86_64
ARG BUILD_MACHINE_ARCH=x86_64
ARG TRIPLET=${ARCH}-linux-gnu
ARG BUILDARCH=amd64
ARG WEBKIT_TAG=may20-1
ARG WEBKIT_TAG=may20-3
ARG ZIG_TAG=jul1
ARG ZIG_VERSION="0.11.0-dev.3737+9eb008717"
ARG WEBKIT_BASENAME="bun-webkit-linux-$BUILDARCH"
@@ -295,6 +295,27 @@ WORKDIR $BUN_DIR
RUN cd $BUN_DIR && \
make uws && rm -rf src/deps/uws Makefile
FROM bun-base as base64
ARG DEBIAN_FRONTEND
ARG GITHUB_WORKSPACE
ARG ZIG_PATH
# Directory extracts to "bun-webkit"
ARG WEBKIT_DIR
ARG BUN_RELEASE_DIR
ARG BUN_DEPS_OUT_DIR
ARG BUN_DIR
ARG CPU_TARGET
ENV CPU_TARGET=${CPU_TARGET}
COPY Makefile ${BUN_DIR}/Makefile
COPY src/deps/base64 ${BUN_DIR}/src/deps/base64
WORKDIR $BUN_DIR
RUN cd $BUN_DIR && \
make base64 && rm -rf src/deps/base64 Makefile
FROM bun-base as picohttp
ARG DEBIAN_FRONTEND
@@ -556,6 +577,7 @@ ENV JSC_BASE_DIR=${WEBKIT_DIR}
ENV LIB_ICU_PATH=${WEBKIT_DIR}/lib
COPY --from=zlib ${BUN_DEPS_OUT_DIR}/*.a ${BUN_DEPS_OUT_DIR}/
COPY --from=base64 ${BUN_DEPS_OUT_DIR}/*.a ${BUN_DEPS_OUT_DIR}/
COPY --from=libarchive ${BUN_DEPS_OUT_DIR}/*.a ${BUN_DEPS_OUT_DIR}/
COPY --from=boringssl ${BUN_DEPS_OUT_DIR}/*.a ${BUN_DEPS_OUT_DIR}/
COPY --from=lolhtml ${BUN_DEPS_OUT_DIR}/*.a ${BUN_DEPS_OUT_DIR}/

View File

@@ -453,7 +453,8 @@ MINIMUM_ARCHIVE_FILES = -L$(BUN_DEPS_OUT_DIR) \
-ldecrepit \
-lssl \
-lcrypto \
-llolhtml
-llolhtml \
-lbase64
ARCHIVE_FILES_WITHOUT_LIBCRYPTO = $(MINIMUM_ARCHIVE_FILES) \
-larchive \
@@ -1694,7 +1695,7 @@ sizegen:
# Linux uses bundled SQLite3
ifeq ($(OS_NAME),linux)
sqlite:
$(CC) $(EMIT_LLVM_FOR_RELEASE) $(CFLAGS) $(INCLUDE_DIRS) -DSQLITE_ENABLE_COLUMN_METADATA= -DSQLITE_MAX_VARIABLE_NUMBER=250000 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_JSON1=1 $(SRC_DIR)/sqlite/sqlite3.c -c -o $(SQLITE_OBJECT)
$(CC) $(EMIT_LLVM_FOR_RELEASE) $(CFLAGS) $(INCLUDE_DIRS) -DSQLITE_ENABLE_COLUMN_METADATA= -DSQLITE_MAX_VARIABLE_NUMBER=250000 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_FTS3_PARENTHESIS=1 -DSQLITE_ENABLE_FTS5=1 -DSQLITE_ENABLE_JSON1=1 $(SRC_DIR)/sqlite/sqlite3.c -c -o $(SQLITE_OBJECT)
endif
picohttp:
@@ -1850,6 +1851,10 @@ copy-to-bun-release-dir-bin:
PACKAGE_MAP = --pkg-begin async_io $(BUN_DIR)/src/io/io_darwin.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin javascript_core $(BUN_DIR)/src/jsc.zig --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end --pkg-end --pkg-begin bun $(BUN_DIR)/src/bun_redirect.zig --pkg-end
.PHONY: base64
base64:
cd $(BUN_DEPS_DIR)/base64 && make clean && cmake $(CMAKE_FLAGS) . && make
cp $(BUN_DEPS_DIR)/base64/libbase64.a $(BUN_DEPS_OUT_DIR)/libbase64.a
.PHONY: cold-jsc-start
cold-jsc-start:
@@ -1868,7 +1873,8 @@ cold-jsc-start:
misctools/cold-jsc-start.cpp -o cold-jsc-start
.PHONY: vendor-without-npm
vendor-without-npm: node-fallbacks runtime_js fallback_decoder bun_error mimalloc picohttp zlib boringssl libarchive lolhtml sqlite usockets uws tinycc c-ares zstd
vendor-without-npm: node-fallbacks runtime_js fallback_decoder bun_error mimalloc picohttp zlib boringssl libarchive lolhtml sqlite usockets uws tinycc c-ares zstd base64
.PHONY: vendor-without-check
vendor-without-check: npm-install vendor-without-npm

View File

@@ -0,0 +1,14 @@
import { bench, run } from "./runner.mjs";
import { Buffer } from "node:buffer";
const bigBuffer = Buffer.from("hello world".repeat(10000));
const converted = bigBuffer.toString("base64");
bench("Buffer.toString('base64')", () => {
return bigBuffer.toString("base64");
});
// bench("Buffer.from(str, 'base64')", () => {
// return Buffer.from(converted, "base64");
// });
await run();

View File

@@ -1,12 +1,6 @@
// so it can run in environments without node module resolution
import { bench, run } from "../node_modules/mitata/src/cli.mjs";
var crypto = globalThis.crypto;
if (!crypto) {
crypto = await import("node:crypto");
}
import crypto from "node:crypto";
var foo = new Uint8Array(65536);
bench("crypto.getRandomValues(65536)", () => {
crypto.getRandomValues(foo);
@@ -22,4 +16,8 @@ bench("crypto.randomUUID()", () => {
return crypto.randomUUID()[2];
});
bench("crypto.randomInt()", () => {
return crypto.randomInt(0, 100);
});
await run();

View File

@@ -0,0 +1,12 @@
import { bench, run } from "./runner.mjs";
var err = new Error();
bench("Error.captureStackTrace(err)", () => {
Error.captureStackTrace(err);
});
bench("Error.prototype.stack", () => {
new Error().stack;
});
await run();

View File

@@ -0,0 +1,33 @@
import { bench, run } from "./runner.mjs";
import { performance } from "perf_hooks";
bench("process.memoryUsage()", () => {
process.memoryUsage();
});
bench("process.memoryUsage.rss()", () => {
process.memoryUsage.rss();
});
bench("process.cpuUsage()", () => {
process.cpuUsage();
});
const init = process.cpuUsage();
bench("process.cpuUsage(delta)", () => {
process.cpuUsage(init);
});
bench("performance.now()", () => {
performance.now();
});
bench("process.hrtime()", () => {
process.hrtime();
});
bench("process.hrtime.bigint()", () => {
process.hrtime.bigint();
});
await run();

View File

@@ -0,0 +1,17 @@
import { bench, run } from "./runner.mjs";
import { readFileSync, existsSync } from "node:fs";
import { readFile } from "node:fs/promises";
bench(`readFileSync(/tmp/404-not-found)`, () => {
try {
readFileSync("/tmp/404-not-found");
} catch (e) {}
});
bench(`readFile(/tmp/404-not-found)`, async () => {
try {
await readFile("/tmp/404-not-found");
} catch (e) {}
});
await run();

BIN
bun.lockb

Binary file not shown.

View File

@@ -92,10 +92,10 @@ _bun_completions() {
PACKAGE_OPTIONS[REMOVE_OPTIONS_LONG]="";
PACKAGE_OPTIONS[REMOVE_OPTIONS_SHORT]="";
PACKAGE_OPTIONS[SHARED_OPTIONS_LONG]="--config --yarn --production --no-save --dry-run --lockfile --force --cache-dir --no-cache --silent --verbose --global --cwd --backend --link-native-bins --help";
PACKAGE_OPTIONS[SHARED_OPTIONS_LONG]="--config --yarn --production --frozen-lockfile --no-save --dry-run --lockfile --force --cache-dir --no-cache --silent --verbose --global --cwd --backend --link-native-bins --help";
PACKAGE_OPTIONS[SHARED_OPTIONS_SHORT]="-c -y -p -f -g";
PM_OPTIONS[LONG_OPTIONS]="--config --yarn --production --no-save --dry-run --lockfile --force --cache-dir --no-cache --silent --verbose --no-progress --no-summary --no-verify --ignore-scripts --global --cwd --backend --link-native-bins --help"
PM_OPTIONS[LONG_OPTIONS]="--config --yarn --production --frozen-lockfile --no-save --dry-run --lockfile --force --cache-dir --no-cache --silent --verbose --no-progress --no-summary --no-verify --ignore-scripts --global --cwd --backend --link-native-bins --help"
PM_OPTIONS[SHORT_OPTIONS]="-c -y -p -f -g"
local cur_word="${COMP_WORDS[${COMP_CWORD}]}";

View File

@@ -47,6 +47,7 @@ _bun() {
'-g[Add a package globally]' \
'--global[Add a package globally]' \
'--production[Don'"'"'t install devDependencies]' \
'--frozen-lockfile[Disallow changes to lockfile]' \
'--optional[Add dependency to optionalDependencies]' \
'--development[Add dependency to devDependencies]' \
'-d[Add dependency to devDependencies]' \
@@ -88,6 +89,7 @@ _bun() {
'--yarn[Write a yarn.lock file (yarn v1)]' \
'--global[Add a package globally]' \
'--production[Don'"'"'t install devDependencies]' \
'--frozen-lockfile[Disallow changes to lockfile]' \
'--optional[Add dependency to optionalDependencies]' \
'--development[Add dependency to devDependencies]' \
'-d[Add dependency to devDependencies]' \
@@ -123,6 +125,7 @@ _bun() {
'--yarn[Write a yarn.lock file (yarn v1)]' \
'--global[Add a package globally]' \
'--production[Don'"'"'t install devDependencies]' \
'--frozen-lockfile[Disallow changes to lockfile]' \
'--optional[Add dependency to optionalDependencies]' \
'--development[Add dependency to devDependencies]' \
'-d[Add dependency to devDependencies]' \
@@ -278,6 +281,7 @@ _bun() {
'--yarn[Write a yarn.lock file (yarn v1)]'
'-p[Do not install devDependencies]'
'--production[Do not install devDependencies]'
'--frozen-lockfile[Disallow changes to lockfile]' \
'--no-save[Do not save a lockfile]'
'--dry-run[Do not install anything]'
'--lockfile[Store & load a lockfile at a specific filepath]'
@@ -532,6 +536,7 @@ _bun() {
'--yarn[Write a yarn.lock file (yarn v1)]' \
'--production[Don'"'"'t install devDependencies]' \
'-p[Don'"'"'t install devDependencies]' \
'--frozen-lockfile[Disallow changes to lockfile]' \
'--no-save[]' \
'--dry-run[Don'"'"'t install anything]' \
'--force[Always request the latest versions from the registry & reinstall all dependenices]' \
@@ -565,6 +570,7 @@ _bun() {
'--yarn[Write a yarn.lock file (yarn v1)]' \
'--production[Don'"'"'t install devDependencies]' \
'-p[Don'"'"'t install devDependencies]' \
'--frozen-lockfile[Disallow changes to lockfile]' \
'--no-save[]' \
'--dry-run[Don'"'"'t install anything]' \
'-g[Remove a package globally]' \

View File

@@ -115,6 +115,7 @@ subcommands:
- yarn -- "Write a yarn.lock file (yarn v1)"
- production -- "Don't install devDependencies"
- p -- "Don't install devDependencies"
- frozen-lockfile -- "Disallow changes to lockfile"
- no-save --
- dry-run -- "Don't install anything"
- force -- "Always request the latest versions from the registry & reinstall all dependenices"
@@ -152,6 +153,7 @@ subcommands:
- development -- "Add dependency to devDependencies"
- d -- "Add dependency to devDependencies"
- p -- "Don't install devDependencies"
- frozen-lockfile -- "Disallow changes to lockfile"
- no-save --
- dry-run -- "Don't install anything"
- force -- "Always request the latest versions from the registry & reinstall all dependenices"
@@ -192,6 +194,7 @@ subcommands:
- yarn -- "Write a yarn.lock file (yarn v1)"
- production -- "Don't install devDependencies"
- p -- "Don't install devDependencies"
- frozen-lockfile -- "Disallow changes to lockfile"
- no-save --
- dry-run -- "Don't install anything"
- force -- "Always request the latest versions from the registry & reinstall all dependenices"

View File

@@ -285,7 +285,13 @@ interface Bun {
write(
destination: string | number | BunFile | URL,
input: string | Blob | ArrayBuffer | SharedArrayBuffer | TypedArray | Response,
input:
| string
| Blob
| ArrayBuffer
| SharedArrayBuffer
| TypedArray
| Response,
): Promise<number>;
}
@@ -301,7 +307,9 @@ interface BunFile {
}
export interface FileSink {
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
write(
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
): number;
flush(): number | Promise<number>;
end(error?: Error): number | Promise<number>;
start(options?: { highWaterMark?: number }): void;

View File

@@ -67,7 +67,7 @@ Bun.serve({
fetch(req) {
throw new Error("woops!");
},
error(error: Error) {
error(error) {
return new Response(`<pre>${error}\n${error.stack}</pre>`, {
headers: {
"Content-Type": "text/html",
@@ -95,37 +95,37 @@ server.stop();
## TLS
Bun supports TLS out of the box, powered by [OpenSSL](https://www.openssl.org/). Enable TLS by passing in a value for `key` and `cert`; both are required to enable TLS. If needed, supply a `passphrase` to decrypt the `keyFile`.
Bun supports TLS out of the box, powered by [BoringSSL](https://boringssl.googlesource.com/boringssl). Enable TLS by passing in a value for `key` and `cert`; both are required to enable TLS.
```ts
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
```ts-diff
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
// can be string, BunFile, TypedArray, Buffer, or array thereof
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
// passphrase, only required if key is encrypted
passphrase: "super-secret",
});
+ tls: {
+ key: Bun.file("./key.pem"),
+ cert: Bun.file("./cert.pem"),
+ }
});
```
The `key` and `cert` fields expect the _contents_ of your TLS key and certificate. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
The `key` and `cert` fields expect the _contents_ of your TLS key and certificate, _not a path to it_. This can be a string, `BunFile`, `TypedArray`, or `Buffer`.
```ts
Bun.serve({
fetch() {},
// BunFile
key: Bun.file("./key.pem"),
// Buffer
key: fs.readFileSync("./key.pem"),
// string
key: fs.readFileSync("./key.pem", "utf8"),
// array of above
key: [Bun.file('./key1.pem'), Bun.file('./key2.pem')],
tls: {
// BunFile
key: Bun.file("./key.pem"),
// Buffer
key: fs.readFileSync("./key.pem"),
// string
key: fs.readFileSync("./key.pem", "utf8"),
// array of above
key: [Bun.file("./key1.pem"), Bun.file("./key2.pem")],
},
});
```
@@ -135,17 +135,35 @@ Bun.serve({
{% /callout %}
If your private key is encrypted with a passphrase, provide a value for `passphrase` to decrypt it.
```ts-diff
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
tls: {
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
+ passphrase: "my-secret-passphrase",
}
});
```
Optionally, you can override the trusted CA certificates by passing a value for `ca`. By default, the server will trust the list of well-known CAs curated by Mozilla. When `ca` is specified, the Mozilla list is overwritten.
```ts
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
key: Bun.file("./key.pem"), // path to TLS key
cert: Bun.file("./cert.pem"), // path to TLS cert
ca: Bun.file("./ca.pem"), // path to root CA certificate
});
```ts-diff
Bun.serve({
fetch(req) {
return new Response("Hello!!!");
},
tls: {
key: Bun.file("./key.pem"), // path to TLS key
cert: Bun.file("./cert.pem"), // path to TLS cert
+ ca: Bun.file("./ca.pem"), // path to root CA certificate
}
});
```
To override Diffie-Helman parameters:
@@ -153,7 +171,10 @@ To override Diffie-Helman parameters:
```ts
Bun.serve({
// ...
dhParamsFile: "./dhparams.pem", // path to Diffie Helman parameters
tls: {
// other config
dhParamsFile: "/path/to/dhparams.pem", // path to Diffie Helman parameters
},
});
```
@@ -274,11 +295,21 @@ interface Bun {
port?: number;
development?: boolean;
error?: (error: Error) => Response | Promise<Response>;
keyFile?: string;
certFile?: string;
caFile?: string;
dhParamsFile?: string;
passphrase?: string;
tls?: {
key?:
| string
| TypedArray
| BunFile
| Array<string | TypedArray | BunFile>;
cert?:
| string
| TypedArray
| BunFile
| Array<string | TypedArray | BunFile>;
ca?: string | TypedArray | BunFile | Array<string | TypedArray | BunFile>;
passphrase?: string;
dhParamsFile?: string;
};
maxRequestBodySize?: number;
lowMemoryMode?: boolean;
}): Server;

View File

@@ -28,8 +28,6 @@ for await (const chunk of stream) {
}
```
For a more complete discusson of streams in Bun, see [API > Streams](/docs/api/streams).
## Direct `ReadableStream`
Bun implements an optimized version of `ReadableStream` that avoid unnecessary data copying & queue management logic. With a traditional `ReadableStream`, chunks of data are _enqueued_. Each chunk is copied into a queue, where it sits until the stream is ready to send more data.
@@ -154,7 +152,9 @@ export class ArrayBufferSink {
stream?: boolean;
}): void;
write(chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer): number;
write(
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
): number;
/**
* Flush the internal buffer
*

View File

@@ -47,6 +47,9 @@ registry = "https://registry.yarnpkg.com/"
# Install for production? This is the equivalent to the "--production" CLI argument
production = false
# Disallow changes to lockfile? This is the equivalent to the "--fozen-lockfile" CLI argument
frozenLockfile = false
# Don't actually install
dryRun = true
@@ -108,6 +111,7 @@ export interface Install {
scopes: Scopes;
registry: Registry;
production: boolean;
frozenLockfile: boolean;
dryRun: boolean;
optional: boolean;
dev: boolean;

View File

@@ -49,6 +49,12 @@ To install in production mode (i.e. without `devDependencies`):
$ bun install --production
```
To install with reproducible dependencies, use `--frozen-lockfile`. If your `package.json` disagrees with `bun.lockb`, Bun will exit with an error. This is useful for production builds and CI environments.
```bash
$ bun install --frozen-lockfile
```
To perform a dry run (i.e. don't actually install anything):
```bash
@@ -80,6 +86,9 @@ peer = false
# equivalent to `--production` flag
production = false
# equivalent to `--frozen-lockfile` flag
frozenLockfile = false
# equivalent to `--dry-run` flag
dryRun = false
```
@@ -115,6 +124,26 @@ To add a package as an optional dependency (`"optionalDependencies"`):
$ bun add --optional lodash
```
To add a package and pin to the resolved version, use `--exact`. This will resolve the version of the package and add it to your `package.json` with an exact version number instead of a version range.
```bash
$ bun add react --exact
```
This will add the following to your `package.json`:
```jsonc
{
"dependencies": {
// without --exact
"react": "^18.2.0", // this matches >= 18.2.0 < 19.0.0
// with --exact
"react": "18.2.0" // this matches only 18.2.0 exactly
}
}
```
To install a package globally:
```bash
@@ -197,6 +226,46 @@ In addition, the `--save` flag can be used to add `cool-pkg` to the `dependencie
}
```
## Trusted dependencies
Unlike other npm clients, Bun does not execute arbitrary lifecycle scripts for installed dependencies, such as `postinstall`. These scripts represent a potential security risk, as they can execute arbitrary code on your machine.
<!-- Bun maintains an allow-list of popular packages containing `postinstall` scripts that are known to be safe. To run lifecycle scripts for packages that aren't on this list, add the package to `trustedDependencies` in your package.json. -->
To tell Bun to allow lifecycle scripts for a particular package, add the package to `trustedDependencies` in your package.json.
<!-- ```json-diff
{
"name": "my-app",
"version": "1.0.0",
+ "trustedDependencies": {
+ "my-trusted-package": "*"
+ }
}
``` -->
```json-diff
{
"name": "my-app",
"version": "1.0.0",
+ "trustedDependencies": ["my-trusted-package"]
}
```
Bun reads this field and will run lifecycle scripts for `my-trusted-package`.
<!-- If you specify a version range, Bun will only execute lifecycle scripts if the resolved package version matches the range. -->
<!--
```json
{
"name": "my-app",
"version": "1.0.0",
"trustedDependencies": {
"my-trusted-package": "^1.0.0"
}
}
``` -->
## Git dependencies
To add a dependency from a git repository:

View File

@@ -65,6 +65,24 @@ $ bun test --preload ./setup.ts
See [Test > Lifecycle](/docs/test/lifecycle) for complete documentation.
## Mocks
Create mocks with the `mock` function. Mocks are automatically reset between tests.
```
import { test, expect, mock } from "bun:test";
const random = mock(() => Math.random());
test("random", async () => {
const val = random();
expect(val).toBeGreaterThan(0);
expect(random).toHaveBeenCalled();
expect(random).toHaveBeenCalledTimes(1);
});
```
See [Test > Mocks](/docs/test/mocks) for complete documentation.
## Snapshot testing
Snapshots are supported by `bun test`. See [Test > Snapshots](/docs/test/snapshots) for complete documentation.

View File

@@ -1,20 +1,20 @@
[Stric](https://github.com/bunsvr) is a minimalist, fast web framework for Bun.
```ts#index.ts
import { App } from "@stricjs/core";
import { Router } from '@stricjs/router';
// Export the fetch handler and serve with Bun
export default new App()
// Return "Hi!" on every request
.use(() => new Response("Hi!"));
export default new Router()
// Return 'Hi' on every request
.get('/', () => new Response('Hi'));
```
Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces in **native** JavaScript.
Stric provides support for [ArrowJS](https://www.arrow-js.com), a library for building reactive interfaces.
{% codetabs %}
```ts#src/App.ts
import { html } from "@stricjs/arrow/utils";
import { html } from '@stricjs/arrow/utils';
// Code inside this function can use web APIs
export function render() {
@@ -23,10 +23,10 @@ export function render() {
};
// Set the path to handle
export const path = "/";
export const path = '/';
```
```ts#index.ts
import { PageRouter } from "@stricjs/arrow";
import { PageRouter } from '@stricjs/arrow';
// Create a page router, build and serve directly
new PageRouter().serve();

View File

@@ -49,6 +49,12 @@ To install in production mode (i.e. without `devDependencies`):
$ bun install --production
```
To install dependencies without allowing changes to lockfile (useful on CI):
```bash
$ bun install --frozen-lockfile
```
To perform a dry run (i.e. don't actually install anything):
```bash
@@ -80,6 +86,9 @@ peer = false
# equivalent to `--production` flag
production = false
# equivalent to `--frozen-lockfile` flag
frozenLockfile = false
# equivalent to `--dry-run` flag
dryRun = false
```

View File

@@ -24,3 +24,7 @@ To configure a private registry scoped to a particular organization:
# registry with token
"@myorg3" = { token = "$npm_token", url = "https://registry.myorg.com/" }
```
### `.npmrc`
Bun does not currently read `.npmrc` files. For private registries, migrate your registry configuration to `bunfig.toml` as documented above.

View File

@@ -3,17 +3,17 @@ Bun ships as a single executable that can be installed a few different ways.
{% callout %}
**Windows users** — Bun does not currently provide a native Windows build. We're working on this; progress can be tracked at [this issue](https://github.com/oven-sh/bun/issues/43). In the meantime, use one of the installation methods below for Windows Subsystem for Linux.
**Linux users** — Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1.
**Linux users** The `unzip` package is required to install Bun. Kernel version 5.6 or higher is strongly recommended, but the minimum is 5.1.
{% /callout %}
{% codetabs %}
```bash#Native
$ curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
```bash#NPM
$ npm install -g bun # the last `npm` command you'll ever need
```
```bash#npm
$ npm install -g bun # the last `npm` command you'll ever need
```bash#Native
$ curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
```
```bash#Homebrew
@@ -26,7 +26,7 @@ $ docker pull oven/bun
$ docker run --rm --init --ulimit memlock=-1:-1 oven/bun
```
```bash#proto
```bash#Proto
$ proto install bun
```

View File

@@ -135,13 +135,13 @@ export default {
description:
"Install all dependencies with `bun install`, or manage dependencies with `bun add` and `bun remove`.",
}),
page("install/workspaces", "Workspaces", {
description: "Bun's package manager supports workspaces and mono-repo development workflows.",
}),
page("install/cache", "Global cache", {
description:
"Bun's package manager installs all packages into a shared global cache to avoid redundant re-downloads.",
}),
page("install/workspaces", "Workspaces", {
description: "Bun's package manager supports workspaces and mono-repo development workflows.",
}),
page("install/lockfile", "Lockfile", {
description:
"Bun's binary lockfile `bun.lockb` tracks your resolved dependency ytrr, making future installs fast and repeatable.",
@@ -180,6 +180,9 @@ export default {
page("cli/test", "`bun test`", {
description: "Bun's test runner uses Jest-compatible syntax but runs 100x faster.",
}),
page("test/hot", "Watch mode", {
description: "Reload your tests automatically on change.",
}),
page("test/writing", "Writing tests", {
description:
"Write your tests using Jest-like expect matchers, plus setup/teardown hooks, snapshot testing, and more",
@@ -187,15 +190,18 @@ export default {
page("test/lifecycle", "Lifecycle hooks", {
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
}),
page("test/mocks", "Mocks", {
description: "Mocks functions and track method calls",
}),
page("test/snapshots", "Snapshots", {
description: "Add lifecycle hooks to your tests that run before/after each test or test run",
}),
page("test/time", "Dates and times", {
description: "Control the date & time in your tests for more reliable and deterministic tests",
}),
page("test/dom", "DOM testing", {
description: "Write headless tests for UI and React/Vue/Svelte/Lit components with happy-dom",
}),
page("test/hot", "Watch mode", {
description: "Reload your tests automatically on change.",
}),
divider("Package runner"),
page("cli/bunx", "`bunx`", {

View File

@@ -41,9 +41,7 @@ $ brew install llvm@15
```
```bash#Ubuntu/Debian
# On Ubuntu 22.04 and newer, LLVM 15 is available in the default repositories
$ sudo apt install llvm-15 lld-15 clang-15
# On older versions,
$ # LLVM has an automatic installation script that is compatible with all versions of Ubuntu
$ wget https://apt.llvm.org/llvm.sh -O - | sudo bash -s -- 15 all
```
@@ -85,7 +83,7 @@ $ brew install automake ccache cmake coreutils esbuild gnu-sed go libiconv libto
```
```bash#Ubuntu/Debian
$ sudo apt install cargo ccache cmake esbuild git golang libtool ninja-build pkg-config rustc
$ sudo apt install cargo ccache cmake git golang libtool ninja-build pkg-config rustc esbuild
```
```bash#Arch
@@ -94,7 +92,19 @@ $ pacman -S base-devel ccache cmake esbuild git go libiconv libtool make ninja p
{% /codetabs %}
In addition to this, you will need either `bun` or `npm` installed to install the package.json dependencies.
{% details summary="Ubuntu — Unable to locate package esbuild" %}
The `apt install esbuild` command may fail with an `Unable to locate package` error if you are using a Ubuntu mirror that does not contain an exact copy of the original Ubuntu server. Note that the same error may occur if you are not using any mirror but have the Ubuntu Universe enabled in the `sources.list`. In this case, you can install esbuild manually:
```bash
$ curl -fsSL https://esbuild.github.io/dl/latest | sh
$ chmod +x ./esbuild
$ sudo mv ./esbuild /usr/local/bin
```
{% /details %}
In addition to this, you will need an npm package manager (`bun`, `npm`, etc) to install the `package.json` dependencies.
## Install Zig
@@ -107,7 +117,7 @@ $ zigup 0.11.0-dev.3737+9eb008717
## Building
After cloning the repository, prepare bun to be built:
After cloning the repository, run the following command. The runs
```bash
$ make setup
@@ -217,6 +227,37 @@ You'll need a very recent version of Valgrind due to DWARF 5 debug symbols. You
$ valgrind --fair-sched=try --track-origins=yes bun-debug <args>
```
## Updating `WebKit`
The Bun team will occasionally bump the version of WebKit used in Bun. When this happens, you may see something like this with you run `git status`.
```bash
$ git status
On branch my-branch
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: src/bun.js/WebKit (new commits)
```
For performance reasons, `bun submodule update` does not automatically update the WebKit submodule. To update, run the following commands from the root of the Bun repo:
```bash
$ bun install
$ make bindings
```
<!-- Check the [Bun repo](https://github.com/oven-sh/bun/tree/main/src/bun.js) to get the hash of the commit of WebKit is currently being used.
{% image width="270" src="https://github.com/oven-sh/bun/assets/3084745/51730b73-89ef-4358-9a41-9563a60a54be" /%} -->
<!--
```bash
$ cd src/bun.js/WebKit
$ git fetch
$ git checkout <hash>
``` -->
## Troubleshooting
### libarchive

View File

@@ -85,6 +85,11 @@ Bun statically links these libraries:
---
- [`libbase64`](https://github.com/aklomp/base64/blob/master/LICENSE)
- BSD 2-Clause
---
- A fork of [`uWebsockets`](https://github.com/jarred-sumner/uwebsockets)
- Apache 2.0 licensed

View File

@@ -129,6 +129,9 @@ peer = false
# equivalent to `--production` flag
production = false
# equivalent to `--frozen-lockfile` flag
frozenLockfile = false
# equivalent to `--dry-run` flag
dryRun = false
```

View File

@@ -1,6 +1,6 @@
Bun aims for complete Node.js API compatibility. Most `npm` packages intended for `Node.js` environments will work with Bun out of the box; the best way to know for certain is to try it.
This page is updated regularly to reflect compatibility status of the latest version of Bun.
This page is updated regularly to reflect compatibility status of the latest version of Bun. If you run into any bugs with a particular package, please [open an issue](https://bun.sh/issues). Opening issues for compatibility bugs helps us prioritize what to work on next.
## Built-in modules
@@ -51,7 +51,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_crypto" %} [`node:crypto`](https://nodejs.org/api/crypto.html) {% /anchor %}
- 🟡
- Missing `crypto.Certificate` `crypto.ECDH` `crypto.KeyObject` `crypto.X509Certificate` `crypto.checkPrime{Sync}` `crypto.createPrivateKey` `crypto.createPublicKey` `crypto.createSecretKey` `crypto.diffieHellman` `crypto.generateKey{Sync}` `crypto.generateKeyPair{Sync}` `crypto.generatePrime{Sync}` `crypto.getCipherInfo` `crypto.getCurves` `crypto.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.randomInt` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`
- Missing `crypto.Certificate` `crypto.ECDH` `crypto.KeyObject` `crypto.X509Certificate` `crypto.checkPrime{Sync}` `crypto.createPrivateKey` `crypto.createPublicKey` `crypto.createSecretKey` `crypto.diffieHellman` `crypto.generateKey{Sync}` `crypto.generateKeyPair{Sync}` `crypto.generatePrime{Sync}` `crypto.getCipherInfo` `crypto.{get|set}Fips` `crypto.hkdf` `crypto.hkdfSync` `crypto.secureHeapUsed` `crypto.setEngine` `crypto.sign` `crypto.verify`
---
@@ -87,7 +87,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_fs" %} [`node:fs`](https://nodejs.org/api/fs.html) {% /anchor %}
- 🟡
- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.readv{Sync}` `fs.{watch|watchFile|unwatchFile}` `fs.writev{Sync}`.
- Missing `fs.fdatasync{Sync}` `fs.opendir{Sync}` `fs.{watchFile|unwatchFile}` `fs.{cp|cpSync}`.
---
@@ -123,7 +123,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_net" %} [`node:net`](https://nodejs.org/api/net.html) {% /anchor %}
- 🟡
- Missing `net.createServer` `net.{get|set}DefaultAutoSelectFamily` `net.SocketAddress` `net.BlockList`.
- Missing `net.{get|set}DefaultAutoSelectFamily` `net.SocketAddress` `net.BlockList`.
---
@@ -201,7 +201,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_tls" %} [`node:tls`](https://nodejs.org/api/tls.html) {% /anchor %}
- 🟡
- Missing `tls.Server` `tls.createServer` `tls.createSecurePair` `tls.checkServerIdentity` `tls.rootCertificates`
- Missing `tls.createSecurePair` `tls.checkServerIdentity` `tls.rootCertificates`
---
@@ -219,13 +219,13 @@ This page is updated regularly to reflect compatibility status of the latest ver
- {% anchor id="node_url" %} [`node:url`](https://nodejs.org/api/url.html) {% /anchor %}
- 🟡
- Missing `url.domainTo{ASCII|Unicode}` `url.urlToHttpOptions`. Recommended to use `URL` and `URLSearchParams` globals instead.
- Missing `url.domainTo{ASCII|Unicode}`. Recommended to use `URL` and `URLSearchParams` globals instead.
---
- {% anchor id="node_util" %} [`node:util`](https://nodejs.org/api/util.html) {% /anchor %}
- 🟡
- Missing `util.MIMEParams` `util.MIMEType` `util.formatWithOptions()` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.toUSVString()` `util.transferableAbortController()` `util.transferableAbortSignal()`.
- Missing `util.MIMEParams` `util.MIMEType` `util.formatWithOptions()` `util.getSystemErrorMap()` `util.getSystemErrorName()` `util.parseArgs()` `util.stripVTControlCharacters()` `util.transferableAbortController()` `util.transferableAbortSignal()`.
---
@@ -558,7 +558,7 @@ The table below lists all globals implemented by Node.js and Bun's current compa
- {% anchor id="node_require" %} [`require()`](https://nodejs.org/api/globals.html#require) {% /anchor %}
- 🟢
- Fully implemented.
- Fully implemented, as well as [`require.main`](https://nodejs.org/api/modules.html#requiremain), [`require.cache`](https://nodejs.org/api/modules.html#requirecache), and [`require.resolve`](https://nodejs.org/api/modules.html#requireresolverequest-options)
---

View File

@@ -93,6 +93,17 @@ These are the recommended `compilerOptions` for a Bun project.
}
```
### Add DOM types
Settings `"types": ["bun-types"]` means TypeScript will ignore other global type definitions, including `lib: ["dom"]`. To add DOM types into your project, add the following [triple-slash directives](https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html) at the top of any TypeScript file in your project.
```ts
/// <reference lib="dom" />
/// <reference lib="dom.iterable" />
```
The same applies to other global type definition _libs_ like `webworker`.
## Path mapping
When resolving modules, Bun's runtime respects path mappings defined in [`compilerOptions.paths`](https://www.typescriptlang.org/tsconfig#paths) in your `tsconfig.json`. No other runtime does this.

View File

@@ -10,7 +10,7 @@ The test runner supports the following lifecycle hooks. This is useful for loadi
Perform per-test setup and teardown logic with `beforeEach` and `afterEach`.
```ts
import { expect, test } from "bun:test";
import { beforeEach, afterEach } from "bun:test";
beforeEach(() => {
console.log("running test.");
@@ -70,7 +70,7 @@ afterAll(() => {
Then use `--preload` to run the setup script before any test files.
```ts
bun test --preload ./setup.ts
$ bun test --preload ./setup.ts
```
To avoid typing `--preload` every time you run tests, it can be added to your `bunfig.toml`:

55
docs/test/mocks.md Normal file
View File

@@ -0,0 +1,55 @@
Create mocks with the `mock` function.
```ts
import { test, expect, mock } from "bun:test";
const random = mock(() => Math.random());
test("random", async () => {
const val = random();
expect(val).toBeGreaterThan(0);
expect(random).toHaveBeenCalled();
expect(random).toHaveBeenCalledTimes(1);
});
```
The result of `mock()` is a new function that's been decorated with some additional properties.
```ts
import { mock } from "bun:test";
const random = mock((multiplier: number) => multiplier * Math.random());
random(2);
random(10);
random.mock.calls;
// [[ 2 ], [ 10 ]]
random.mock.results;
// [
// { type: "return", value: 0.6533907460954099 },
// { type: "return", value: 0.6452713933037312 }
// ]
```
## `.spyOn()`
It's possible to track calls to a function without replacing it with a mock. Use `spyOn()` to create a spy; these spies can be passed to `.toHaveBeenCalled()` and `.toHaveBeenCalledTimes()`.
```ts
import { test, expect, spyOn } from "bun:test";
const ringo = {
name: "Ringo",
sayHi() {
console.log(`Hello I'm ${this.name}`);
},
};
const spy = spyOn(ringo, "sayHi");
test("spyon", () => {
expect(spy).toHaveBeenCalledTimes(0);
ringo.sayHi();
expect(spy).toHaveBeenCalledTimes(1);
});
```

106
docs/test/time.md Normal file
View File

@@ -0,0 +1,106 @@
`bun:test` lets you change what time it is in your tests. This was introduced in Bun v0.6.13.
This works with any of the following:
- `Date.now`
- `new Date()`
- `new Intl.DateTimeFormat().format()`
Timers are not impacted yet, but may be in a future release of Bun.
## `setSystemTime`
To change the system time, use `setSystemTime`:
```ts
import { setSystemTime, beforeAll, test, expect } from "bun:test";
beforeAll(() => {
setSystemTime(new Date("2020-01-01T00:00:00.000Z"));
});
test("it is 2020", () => {
expect(new Date().getFullYear()).toBe(2020);
});
```
To support existing tests that use Jest's `useFakeTimers` and `useRealTimers`, you can use `useFakeTimers` and `useRealTimers`:
```ts
test("just like in jest", () => {
jest.useFakeTimers();
jest.setSystemTime(new Date("2020-01-01T00:00:00.000Z"));
expect(new Date().getFullYear()).toBe(2020);
jest.useRealTimers();
expect(new Date().getFullYear()).toBeGreaterThan(2020);
});
test("unlike in jest", () => {
const OriginalDate = Date;
jest.useFakeTimers();
if (typeof Bun === "undefined") {
// In Jest, the Date constructor changes
// That can cause all sorts of bugs because suddenly Date !== Date before the test.
expect(Date).not.toBe(OriginalDate);
expect(Date.now).not.toBe(OriginalDate.now);
} else {
// In bun:test, Date constructor does not change when you useFakeTimers
expect(Date).toBe(OriginalDate);
expect(Date.now).toBe(OriginalDate.now);
}
});
```
{% callout %}
**Timers** — Note that we have not implemented builtin support for mocking timers yet, but this is on the roadmap.
{% /callout %}
### Reset the system time
To reset the system time, pass no arguments to `setSystemTime`:
```ts
import { setSystemTime, beforeAll } from "bun:test";
test("it was 2020, for a moment.", () => {
// Set it to something!
setSystemTime(new Date("2020-01-01T00:00:00.000Z"));
expect(new Date().getFullYear()).toBe(2020);
// reset it!
setSystemTime();
expect(new Date().getFullYear()).toBeGreaterThan(2020);
});
```
## Set the time zone
To change the time zone, either pass the `$TZ` environment variable to `bun test`.
```sh
TZ=America/Los_Angeles bun test
```
Or set `process.env.TZ` at runtime:
```ts
import { test, expect } from "bun:test";
test("Welcome to California!", () => {
process.env.TZ = "America/Los_Angeles";
expect(new Date().getTimezoneOffset()).toBe(420);
expect(new Intl.DateTimeFormat().resolvedOptions().timeZone).toBe(
"America/Los_Angeles",
);
});
test("Welcome to New York!", () => {
// Unlike in Jest, you can set the timezone multiple times at runtime and it will work.
process.env.TZ = "America/New_York";
expect(new Date().getTimezoneOffset()).toBe(240);
expect(new Intl.DateTimeFormat().resolvedOptions().timeZone).toBe(
"America/New_York",
);
});
```

View File

@@ -63,6 +63,21 @@ test("2 * 2", done => {
});
```
## Timeouts
Optionally specify a per-test timeout in milliseconds by passing a number as the third argument to `test`.
```ts
import { test } from "bun:test";
test.skip("wat", async () => {
const data = await slowOperation();
expect(data).toBe(42);
}, 500); // test must run in <500ms
```
## `test.skip`
Skip individual tests with `test.skip`. These tests will not be run.
```ts
@@ -74,6 +89,8 @@ test.skip("wat", () => {
});
```
## `test.todo`
Mark a test as a todo with `test.todo`. These tests _will_ be run, and the test runner will expect them to fail. If they pass, you will be prompted to mark it as a regular test.
```ts
@@ -84,6 +101,71 @@ test.todo("fix this", () => {
});
```
To exlusively run tests marked as _todo_, use `bun test --todo`.
```sh
$ bun test --todo
```
## `test.only`
To run a particular test or suite of tests use `test.only()` or `describe.only()`. Once declared, running `bun test --skip` will only execute tests/suites that have been marked with `.only()`.
```ts
import { test, describe } from "bun:test";
test("test #1", () => {
// does not run
});
test.only("test #2", () => {
// runs
});
describe.only("only", () => {
test("test #3", () => {
// runs
});
});
```
The following command will only execute tests #2 and #3.
```sh
$ bun test --only
```
## `test.if`
To run a test conditionally, use `test.if()`. The test will run if the condition is truthy. This is particularly useful for tests that should only run on specific architectures or operating systems.
```ts
test.if(Math.random() > 0.5)("runs half the time", () => {
// ...
});
```
```ts
test.if(Math.random() > 0.5)("runs half the time", () => {
// ...
});
const macOS = process.arch === "darwin";
test.if(macOS)("runs on macOS", () => {
// runs if macOS
});
```
To instead skip a test based on some condition, use `test.skipIf()` or `describe.skipIf()`.
```ts
const macOS = process.arch === "darwin";
test.skipIf(macOS)("runs on non-macOS", () => {
// runs if *not* macOS
});
```
## Matchers
Bun implements the following matchers. Full Jest compatibility is on the roadmap; track progress [here](https://github.com/oven-sh/bun/issues/1825).
@@ -217,13 +299,13 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- [`.resolves()`](https://jestjs.io/docs/expect#resolves)
- 🟢
- [`.resolves()`](https://jestjs.io/docs/expect#resolves) (since Bun v0.6.12+)
---
- 🔴
- [`.rejects()`](https://jestjs.io/docs/expect#rejects)
- 🟢
- [`.rejects()`](https://jestjs.io/docs/expect#rejects) (since Bun v0.6.12+)
---
@@ -277,7 +359,7 @@ Bun implements the following matchers. Full Jest compatibility is on the roadmap
---
- 🔴
- 🟢
- [`.toBeCloseTo()`](https://jestjs.io/docs/expect#tobeclosetonumber-numdigits)
---

View File

@@ -24,7 +24,7 @@
"@types/react": "^18.0.25",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"bun-webkit": "0.0.1-4b3750ddfe644a5bb131d652407653fac528ad51"
"bun-webkit": "0.0.1-26c819733315f0ab64ae8e8e65b77d77d31211e1"
},
"version": "0.0.0",
"prettier": "./.prettierrc.cjs"

View File

@@ -931,7 +931,11 @@ declare module "assert" {
* instance of an `Error` then it will be thrown instead of the `AssertionError`.
*/
// FIXME: assert.doesNotMatch is typed, but not in the browserify polyfill?
// function doesNotMatch(value: string, regExp: RegExp, message?: string | Error): void;
function doesNotMatch(
value: string,
regExp: RegExp,
message?: string | Error,
): void;
const strict: Omit<
typeof assert,

View File

@@ -2084,6 +2084,30 @@ declare module "buffer" {
values(): IterableIterator<number>;
}
var Buffer: BufferConstructor;
/**
* This function returns `true` if `input` contains only valid UTF-8-encoded data,
* including the case in which `input` is empty.
*
* Throws if the `input` is a detached array buffer.
* @since Bun v0.6.13
* @param input The input to validate.
*/
export function isUtf8(
input: TypedArray | ArrayBufferLike | DataView,
): boolean;
/**
* This function returns `true` if `input` contains only valid ASCII-encoded data,
* including the case in which `input` is empty.
*
* Throws if the `input` is a detached array buffer.
* @since Bun v0.6.13
* @param input The input to validate.
*/
export function isAscii(
input: TypedArray | ArrayBufferLike | DataView,
): boolean;
}
}
declare module "node:buffer" {

View File

@@ -29,6 +29,36 @@ declare module "bun:test" {
<T extends AnyFunction>(Function: T): Mock<T>;
};
/**
* Control the system time used by:
* - `Date.now()`
* - `new Date()`
* - `Intl.DateTimeFormat().format()`
*
* In the future, we may add support for more functions, but we haven't done that yet.
*
* @param now The time to set the system time to. If not provided, the system time will be reset.
* @returns `this`
* @since v0.6.13
*
* ## Set Date to a specific time
*
* ```js
* import { setSystemTime } from 'bun:test';
*
* setSystemTime(new Date('2020-01-01T00:00:00.000Z'));
* console.log(new Date().toISOString()); // 2020-01-01T00:00:00.000Z
* ```
* ## Reset Date to the current time
*
* ```js
* import { setSystemTime } from 'bun:test';
*
* setSystemTime();
* ```
*/
export function setSystemTime(now?: Date | number): ThisType<void>;
interface Jest {
restoreAllMocks(): void;
fn<T extends AnyFunction>(func?: T): Mock<T>;

View File

@@ -673,7 +673,29 @@ declare module "bun" {
/**
* The name or path of the file, as specified in the constructor.
*/
name?: number;
readonly name?: string;
/**
* Does the file exist?
*
* This returns true for regular files and FIFOs. It returns false for
* directories. Note that a race condition can occur where the file is
* deleted or renamed after this is called but before you open it.
*
* This does a system call to check if the file exists, which can be
* slow.
*
* If using this in an HTTP server, it's faster to instead use `return new
* Response(Bun.file(path))` and then an `error` handler to handle
* exceptions.
*
* Instead of checking for a file's existence and then performing the
* operation, it is faster to just perform the operation and handle the
* error.
*
* For empty Blob, this always returns true.
*/
exists(): Promise<boolean>;
}
/**
@@ -1890,7 +1912,9 @@ declare module "bun" {
export interface TLSWebSocketServeOptions<WebSocketDataType = undefined>
extends WebSocketServeOptions<WebSocketDataType>,
TLSOptions {}
TLSOptions {
tls?: TLSOptions;
}
export interface Errorlike extends Error {
code?: string;
errno?: number;
@@ -2001,6 +2025,8 @@ declare module "bun" {
* The values are SSL options objects.
*/
serverNames?: Record<string, TLSOptions>;
tls?: TLSOptions;
}
/**

View File

@@ -344,6 +344,7 @@ declare module "bun:ffi" {
*
*/
u64_fast = 16,
function = 17,
}
type UNTYPED = never;

View File

@@ -3932,100 +3932,141 @@ declare module "fs" {
}
export interface FSWatcher extends EventEmitter {
/**
* Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the `fs.FSWatcher` object is no longer usable.
* @since v0.6.8
*/
close(): void;
/**
* When called, requests that the Node.js event loop not exit so long as the <fs.FSWatcher> is active. Calling watcher.ref() multiple times will have no effect.
*/
ref(): void;
/**
* When called, the active <fs.FSWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.FSWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.
*/
unref(): void;
/**
* events.EventEmitter
* 1. change
* 2. error
*/
addListener(event: string, listener: (...args: any[]) => void): this;
addListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
addListener(event: 'error', listener: (error: Error) => void): this;
addListener(event: 'close', listener: () => void): this;
on(event: string, listener: (...args: any[]) => void): this;
on(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
on(event: 'error', listener: (error: Error) => void): this;
on(event: 'close', listener: () => void): this;
once(event: string, listener: (...args: any[]) => void): this;
once(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
once(event: 'error', listener: (error: Error) => void): this;
once(event: 'close', listener: () => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
prependListener(event: 'error', listener: (error: Error) => void): this;
prependListener(event: 'close', listener: () => void): this;
prependOnceListener(event: string, listener: (...args: any[]) => void): this;
prependOnceListener(event: 'change', listener: (eventType: string, filename: string | Buffer) => void): this;
prependOnceListener(event: 'error', listener: (error: Error) => void): this;
prependOnceListener(event: 'close', listener: () => void): this;
}
/**
* Watch for changes on `filename`, where `filename` is either a file or a
* directory.
*
* The second argument is optional. If `options` is provided as a string, it
* specifies the `encoding`. Otherwise `options` should be passed as an object.
*
* The listener callback gets two arguments `(eventType, filename)`. `eventType`is either `'rename'` or `'change'`, and `filename` is the name of the file
* which triggered the event.
*
* On most platforms, `'rename'` is emitted whenever a filename appears or
* disappears in the directory.
*
* The listener callback is attached to the `'change'` event fired by `fs.FSWatcher`, but it is not the same thing as the `'change'` value of`eventType`.
*
* If a `signal` is passed, aborting the corresponding AbortController will close
* the returned `fs.FSWatcher`.
/**
* Stop watching for changes on the given `fs.FSWatcher`. Once stopped, the `fs.FSWatcher` object is no longer usable.
* @since v0.6.8
* @param listener
*/
export function watch(
filename: PathLike,
options:
| (WatchOptions & {
encoding: 'buffer';
})
| 'buffer',
listener?: WatchListener<Buffer>
): FSWatcher;
close(): void;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
* When called, requests that the Node.js event loop not exit so long as the <fs.FSWatcher> is active. Calling watcher.ref() multiple times will have no effect.
*/
export function watch(filename: PathLike, options?: WatchOptions | BufferEncoding | null, listener?: WatchListener<string>): FSWatcher;
ref(): void;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
* When called, the active <fs.FSWatcher> object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the <fs.FSWatcher> object's callback is invoked. Calling watcher.unref() multiple times will have no effect.
*/
export function watch(filename: PathLike, options: WatchOptions | string, listener?: WatchListener<string | Buffer>): FSWatcher;
unref(): void;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* events.EventEmitter
* 1. change
* 2. error
*/
export function watch(filename: PathLike, listener?: WatchListener<string>): FSWatcher;
addListener(event: string, listener: (...args: any[]) => void): this;
addListener(
event: "change",
listener: (eventType: string, filename: string | Buffer) => void,
): this;
addListener(event: "error", listener: (error: Error) => void): this;
addListener(event: "close", listener: () => void): this;
on(event: string, listener: (...args: any[]) => void): this;
on(
event: "change",
listener: (eventType: string, filename: string | Buffer) => void,
): this;
on(event: "error", listener: (error: Error) => void): this;
on(event: "close", listener: () => void): this;
once(event: string, listener: (...args: any[]) => void): this;
once(
event: "change",
listener: (eventType: string, filename: string | Buffer) => void,
): this;
once(event: "error", listener: (error: Error) => void): this;
once(event: "close", listener: () => void): this;
prependListener(event: string, listener: (...args: any[]) => void): this;
prependListener(
event: "change",
listener: (eventType: string, filename: string | Buffer) => void,
): this;
prependListener(event: "error", listener: (error: Error) => void): this;
prependListener(event: "close", listener: () => void): this;
prependOnceListener(
event: string,
listener: (...args: any[]) => void,
): this;
prependOnceListener(
event: "change",
listener: (eventType: string, filename: string | Buffer) => void,
): this;
prependOnceListener(event: "error", listener: (error: Error) => void): this;
prependOnceListener(event: "close", listener: () => void): this;
}
type WatchOptions = {
encoding?: BufferEncoding;
persistent?: boolean;
recursive?: boolean;
signal?: AbortSignal;
};
type WatchEventType = "rename" | "change" | "error" | "close";
type WatchListener<T> = (
event: WatchEventType,
filename: T | Error | undefined,
) => void;
/**
* Watch for changes on `filename`, where `filename` is either a file or a
* directory.
*
* The second argument is optional. If `options` is provided as a string, it
* specifies the `encoding`. Otherwise `options` should be passed as an object.
*
* The listener callback gets two arguments `(eventType, filename)`. `eventType`is either `'rename'` or `'change'`, and `filename` is the name of the file
* which triggered the event.
*
* On most platforms, `'rename'` is emitted whenever a filename appears or
* disappears in the directory.
*
* The listener callback is attached to the `'change'` event fired by `fs.FSWatcher`, but it is not the same thing as the `'change'` value of`eventType`.
*
* If a `signal` is passed, aborting the corresponding AbortController will close
* the returned `fs.FSWatcher`.
* @since v0.6.8
* @param listener
*/
export function watch(
filename: PathLike,
options:
| (WatchOptions & {
encoding: "buffer";
})
| "buffer",
listener?: WatchListener<Buffer>,
): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
export function watch(
filename: PathLike,
options?: WatchOptions | BufferEncoding | null,
listener?: WatchListener<string>,
): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
* @param options Either the encoding for the filename provided to the listener, or an object optionally specifying encoding, persistent, and recursive options.
* If `encoding` is not supplied, the default of `'utf8'` is used.
* If `persistent` is not supplied, the default of `true` is used.
* If `recursive` is not supplied, the default of `false` is used.
*/
export function watch(
filename: PathLike,
options: WatchOptions | string,
listener?: WatchListener<string | Buffer>,
): FSWatcher;
/**
* Watch for changes on `filename`, where `filename` is either a file or a directory, returning an `FSWatcher`.
* @param filename A path to a file or directory. If a URL is provided, it must use the `file:` protocol.
*/
export function watch(
filename: PathLike,
listener?: WatchListener<string>,
): FSWatcher;
}
declare module "node:fs" {

View File

@@ -420,6 +420,34 @@ interface Process {
emitWarning(warning: string | Error /*name?: string, ctor?: Function*/): void;
readonly config: Object;
memoryUsage: {
(delta?: MemoryUsageObject): MemoryUsageObject;
rss(): number;
};
cpuUsage(previousValue?: CPUUsageObject): CPUUsageObject;
/**
* Does nothing in Bun
*/
setSourceMapsEnabled(enabled: boolean): void;
kill(pid: number, signal?: string | number): void;
}
interface MemoryUsageObject {
rss: number;
heapTotal: number;
heapUsed: number;
external: number;
arrayBuffers: number;
}
interface CPUUsageObject {
user: number;
system: number;
}
declare var process: Process;
@@ -888,6 +916,12 @@ type ReadableStreamController<T> = ReadableStreamDefaultController<T>;
type ReadableStreamDefaultReadResult<T> =
| ReadableStreamDefaultReadValueResult<T>
| ReadableStreamDefaultReadDoneResult;
interface ReadableStreamDefaultReadManyResult<T> {
done: boolean;
/** Number of bytes */
size: number;
value: T[];
}
type ReadableStreamReader<T> = ReadableStreamDefaultReader<T>;
interface RequestInit {
@@ -1395,21 +1429,6 @@ declare function clearTimeout(id?: number | Timer): void;
declare function clearImmediate(id?: number | Timer): void;
// declare function createImageBitmap(image: ImageBitmapSource, options?: ImageBitmapOptions): Promise<ImageBitmap>;
// declare function createImageBitmap(image: ImageBitmapSource, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise<ImageBitmap>;
/**
* Send a HTTP(s) request
*
* @param url URL string
* @param init A structured value that contains settings for the fetch() request.
*
* @returns A promise that resolves to {@link Response} object.
*
*
*/
declare function fetch(
url: string | URL | Request,
init?: FetchRequestInit,
): Promise<Response>;
/**
* Send a HTTP(s) request
@@ -1423,6 +1442,20 @@ declare function fetch(
*/
// tslint:disable-next-line:unified-signatures
declare function fetch(request: Request, init?: RequestInit): Promise<Response>;
/**
* Send a HTTP(s) request
*
* @param url URL string
* @param init A structured value that contains settings for the fetch() request.
*
* @returns A promise that resolves to {@link Response} object.
*
*
*/
declare function fetch(
url: string | URL | Request,
init?: FetchRequestInit,
): Promise<Response>;
declare function queueMicrotask(callback: (...args: any[]) => void): void;
/**
@@ -1432,8 +1465,8 @@ declare function queueMicrotask(callback: (...args: any[]) => void): void;
declare function reportError(error: any): void;
interface Timer {
ref(): void;
unref(): void;
ref(): Timer;
unref(): Timer;
hasRef(): boolean;
[Symbol.toPrimitive](): number;
@@ -1945,7 +1978,7 @@ interface URLSearchParams {
): void;
/** Returns a string containing a query string suitable for use in a URL. Does not include the question mark. */
toString(): string;
[Symbol.iterator](): IterableIterator<[string, FormDataEntryValue]>;
[Symbol.iterator](): IterableIterator<[string, string]>;
}
declare var URLSearchParams: {
@@ -2261,7 +2294,8 @@ declare var ReadableStreamDefaultController: {
interface ReadableStreamDefaultReader<R = any>
extends ReadableStreamGenericReader {
read(): Promise<ReadableStreamDefaultReadResult<R>>;
readMany(): Promise<ReadableStreamDefaultReadValueResult<R>>;
/** Only available in Bun. If there are multiple chunks in the queue, this will return all of them at the same time. */
readMany(): Promise<ReadableStreamDefaultReadManyResult<R>>;
releaseLock(): void;
}

View File

@@ -1785,6 +1785,24 @@ declare module "http" {
callback?: (res: IncomingMessage) => void,
): ClientRequest;
/**
* Performs the low-level validations on the provided name that are done when `res.setHeader(name, value)` is called.
* Passing illegal value as name will result in a TypeError being thrown, identified by `code: 'ERR_INVALID_HTTP_TOKEN'`.
* @param name Header name
* @since v14.3.0
*/
function validateHeaderName(name: string): void;
/**
* Performs the low-level validations on the provided value that are done when `res.setHeader(name, value)` is called.
* Passing illegal value as value will result in a TypeError being thrown.
* - Undefined value error is identified by `code: 'ERR_HTTP_INVALID_HEADER_VALUE'`.
* - Invalid value character error is identified by `code: 'ERR_INVALID_CHAR'`.
* @param name Header name
* @param value Header value
* @since v14.3.0
*/
function validateHeaderValue(name: string, value: string): void;
let globalAgent: Agent;
/**

View File

@@ -452,19 +452,19 @@ declare module "perf_hooks" {
// },
// ): void;
// }
// namespace constants {
// const NODE_PERFORMANCE_GC_MAJOR: number;
// const NODE_PERFORMANCE_GC_MINOR: number;
// const NODE_PERFORMANCE_GC_INCREMENTAL: number;
// const NODE_PERFORMANCE_GC_WEAKCB: number;
// const NODE_PERFORMANCE_GC_FLAGS_NO: number;
// const NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED: number;
// const NODE_PERFORMANCE_GC_FLAGS_FORCED: number;
// const NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING: number;
// const NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE: number;
// const NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY: number;
// const NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE: number;
// }
namespace constants {
const NODE_PERFORMANCE_GC_MAJOR: number;
const NODE_PERFORMANCE_GC_MINOR: number;
const NODE_PERFORMANCE_GC_INCREMENTAL: number;
const NODE_PERFORMANCE_GC_WEAKCB: number;
const NODE_PERFORMANCE_GC_FLAGS_NO: number;
const NODE_PERFORMANCE_GC_FLAGS_CONSTRUCT_RETAINED: number;
const NODE_PERFORMANCE_GC_FLAGS_FORCED: number;
const NODE_PERFORMANCE_GC_FLAGS_SYNCHRONOUS_PHANTOM_PROCESSING: number;
const NODE_PERFORMANCE_GC_FLAGS_ALL_AVAILABLE_GARBAGE: number;
const NODE_PERFORMANCE_GC_FLAGS_ALL_EXTERNAL_MEMORY: number;
const NODE_PERFORMANCE_GC_FLAGS_SCHEDULE_IDLE: number;
}
const performance: Performance;
// interface EventLoopMonitorOptions {
// /**

View File

@@ -235,6 +235,7 @@ declare module "bun:sqlite" {
ParamsType extends SQLQueryBindings | SQLQueryBindings[],
>(
sqlQuery: string,
params?: ParamsType
): Statement<
ReturnType,
ParamsType extends Array<any> ? ParamsType : [ParamsType]

View File

@@ -1,6 +1,15 @@
import { watch } from "node:fs";
import * as tsd from "tsd";
import * as fs from "fs";
import { exists } from "fs/promises";
tsd.expectType<Promise<boolean>>(exists("/etc/passwd"));
tsd.expectType<Promise<boolean>>(fs.promises.exists("/etc/passwd"));
// file path
watch(".", (eventType, filename) => {
console.log(`event type = ${eventType}`);
if (filename) {
console.log(`filename = ${filename}`);
}
});

View File

@@ -79,4 +79,27 @@ Bun.serve<User>({
},
});
Bun.serve({
fetch(req) {
throw new Error("woops!");
},
error(error) {
return new Response(`<pre>${error}\n${error.stack}</pre>`, {
headers: {
"Content-Type": "text/html",
},
});
},
});
export {};
Bun.serve({
port: 1234,
fetch(req, server) {
server.upgrade(req);
if (Math.random() > 0.5) return undefined;
return new Response();
},
websocket: { message() {} },
});

View File

@@ -11,8 +11,8 @@
declare module "timers" {
class Timer {
ref(): void;
unref(): void;
ref(): Timer;
unref(): Timer;
hasRef(): boolean;
}

View File

@@ -1,34 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local
# vercel
.vercel

View File

@@ -1,34 +0,0 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

Binary file not shown.

View File

@@ -1,280 +0,0 @@
import * as Schema from "../../schema";
import { ByteBuffer } from "peechy";
import path from "path";
import { Loader } from "../schema";
// import { transform as sucraseTransform } from "sucrase";
export interface WebAssemblyModule {
init(): number;
transform(a: number): number;
bun_malloc(a: number): number;
bun_free(a: number): number;
scan(a: number): number;
}
const wasm_imports_sym: symbol | string =
process.env.NODE_ENV === "development" ? "wasm_imports" : Symbol("wasm_imports");
const ptr_converter = new ArrayBuffer(16);
const ptr_float = new BigUint64Array(ptr_converter);
const slice = new Uint32Array(ptr_converter);
const Wasi = {
clock_time_get(clk_id, tp) {
return Date.now();
},
environ_sizes_get() {
debugger;
return 0;
},
environ_get(__environ, environ_buf) {
debugger;
return 0;
},
fd_close(fd) {
debugger;
return 0;
},
proc_exit() {},
fd_seek(fd, offset_bigint, whence, newOffset) {
debugger;
},
fd_write(fd, iov, iovcnt, pnum) {
debugger;
},
};
var scratch: Uint8Array;
var scratch2: Uint8Array;
export class Bun {
static has_initialized = false;
static wasm_source: WebAssembly.WebAssemblyInstantiatedSource = null;
static get wasm_exports(): WebAssemblyModule {
return Bun.wasm_source.instance.exports as any;
}
static get memory(): WebAssembly.Memory {
return Bun.wasm_source.instance.exports.memory as any;
}
static memory_array: Uint8Array;
static _decoder: TextDecoder;
static _wasmPtrToSlice(offset: number | bigint) {
ptr_float[0] = typeof offset === "number" ? BigInt(offset) : offset;
return new Uint8Array(Bun.memory.buffer, slice[0], slice[1]);
}
static _wasmPtrLenToString(slice: number) {
if (!Bun._decoder) {
Bun._decoder = new TextDecoder("utf8");
}
const region = this._wasmPtrToSlice(slice);
return Bun._decoder.decode(region);
}
// We don't want people to be calling these manually
static [wasm_imports_sym] = {
console_log(slice: number) {
console.log(Bun._wasmPtrLenToString(slice));
},
console_error(slice: number) {
console.error(Bun._wasmPtrLenToString(slice));
},
console_warn(slice: number) {
console.warn(Bun._wasmPtrLenToString(slice));
},
console_info(slice: number) {
console.info(Bun._wasmPtrLenToString(slice));
},
__indirect_function_table: new WebAssembly.Table({
initial: 0,
element: "anyfunc",
}),
__stack_pointer: new WebAssembly.Global({
mutable: true,
value: "i32",
}),
__multi3(one: number, two: number) {
return Math.imul(one | 0, two | 0);
},
fmod(one: number, two: number) {
return one % two;
},
memset(ptr: number, value: number, len: number) {
Bun.memory_array.fill(value, ptr, ptr + len);
},
memcpy(ptr: number, value: number, len: number) {
Bun.memory_array.copyWithin(ptr, value, value + len);
},
// These functions convert a to an unsigned long long, rounding toward zero. Negative values all become zero.
__fixunsdfti(a: number) {
return Math.floor(a);
},
// These functions return the remainder of the unsigned division of a and b.
__umodti3(a: number, b: number) {
return (a | 0) % (b | 0);
},
// These functions return the quotient of the unsigned division of a and b.
__udivti3(a: number, b: number) {
return (a | 0) / (b | 0);
},
// These functions return the result of shifting a left by b bits.
__ashlti3(a: number, b: number) {
return (a | 0) >> (b | 0);
},
/* Returns: convert a to a double, rounding toward even. */
__floatuntidf(a: number) {
const mod = a % 2;
if (mod === 0) {
return Math.ceil(a);
} else if (mod === 1) {
return Math.floor(a);
}
},
emscripten_notify_memory_growth() {},
};
static async init(url) {
// globalThis.sucraseTransform = sucraseTransform;
scratch = new Uint8Array(8096);
if (Bun.has_initialized) {
return;
}
Bun.wasm_source = await globalThis.WebAssembly.instantiateStreaming(fetch(url), {
env: Bun[wasm_imports_sym],
wasi_snapshot_preview1: Wasi,
});
const res = Bun.wasm_exports.init();
if (res < 0) {
throw `[Bun] Failed to initialize WASM module: code ${res}`;
} else {
console.log("WASM loaded.");
}
Bun.has_initialized = true;
}
static transformSync(content: Uint8Array | string, file_name: string) {
if (!Bun.has_initialized) {
throw "Please run await Bun.init(wasm_url) before using this.";
}
// if (process.env.NODE_ENV === "development") {
// console.time("[Bun] Transform " + file_name);
// }
const bb = new ByteBuffer(scratch);
bb.length = 0;
bb.index = 0;
var contents_buffer;
if (typeof content === "string") {
if (!scratch2) {
scratch2 = new Uint8Array(content.length * 2);
}
let i = 0;
for (; i < content.length; i++) {
if (i > scratch2.length) {
var scratch3 = new Uint8Array(scratch2.length * 2);
scratch3.set(scratch2);
scratch2 = scratch3;
}
scratch2[i] = content.charCodeAt(i);
}
contents_buffer = scratch2.subarray(0, i);
} else {
contents_buffer = content;
}
Schema.encodeTransform(
{
contents: contents_buffer,
path: file_name,
loader: {
".jsx": Loader.jsx,
".tsx": Loader.tsx,
".ts": Loader.ts,
".js": Loader.js,
".json": Loader.json,
}[path.extname(file_name)],
},
bb,
);
const data = bb.toUint8Array();
const input_ptr = Bun.wasm_exports.bun_malloc(data.length);
var buffer = this._wasmPtrToSlice(input_ptr);
buffer.set(data);
const resp_ptr = Bun.wasm_exports.transform(input_ptr);
var _bb = new ByteBuffer(this._wasmPtrToSlice(resp_ptr));
const response = Schema.decodeTransformResponse(_bb);
Bun.wasm_exports.bun_free(input_ptr);
scratch = bb.data;
return response;
}
static scan(content: Uint8Array | string, file_name: string, loader?: Loader) {
if (!Bun.has_initialized) {
throw "Please run await Bun.init(wasm_url) before using this.";
}
// if (process.env.NODE_ENV === "development") {
// console.time("[Bun] Transform " + file_name);
// }
scratch.fill(0);
const bb = new ByteBuffer(scratch);
bb.length = 0;
bb.index = 0;
var contents_buffer;
if (typeof content === "string") {
if (!scratch2) {
scratch2 = new Uint8Array(content.length * 2);
}
const encode_into = new TextEncoder().encodeInto(content, scratch2);
contents_buffer = scratch2.subarray(0, encode_into.written);
} else {
contents_buffer = content;
}
Schema.encodeScan(
{
contents: contents_buffer,
path: file_name,
loader:
loader ||
{
".jsx": Loader.jsx,
".tsx": Loader.tsx,
".ts": Loader.ts,
".js": Loader.js,
".json": Loader.json,
}[path.extname(file_name)],
},
bb,
);
const data = bb.toUint8Array();
const input_ptr = Bun.wasm_exports.bun_malloc(data.length);
var buffer = this._wasmPtrToSlice(input_ptr);
buffer.set(data);
const resp_ptr = Bun.wasm_exports.scan(input_ptr);
var _bb = new ByteBuffer(this._wasmPtrToSlice(resp_ptr));
const response = Schema.decodeScanResult(_bb);
Bun.wasm_exports.bun_free(input_ptr);
scratch = bb.data;
return response;
}
}
globalThis.Bun = Bun;

View File

@@ -1,70 +0,0 @@
import { transform as _transform, initialize } from "esbuild-wasm";
import initSwc, { transformSync as transformSyncSWC } from "@swc/wasm-web";
import { Bun } from "./api";
export async function start() {
await initialize({
worker: false,
wasmURL: "/node_modules/esbuild-wasm/esbuild.wasm",
});
await Bun.init("/bun-wasm.wasm");
await initSwc("/node_modules/@swc/wasm-web/wasm_bg.wasm");
}
const swcOptions = {
sourceMaps: false,
inlineSourcesContent: false,
jsc: {
target: "es2022",
parser: {
jsx: true,
syntax: "typescript",
tsx: false,
decorators: false,
dynamicImport: false,
},
},
};
export async function transform(contents, file) {
var result: any = {
timings: {
esbuild: 0,
bun: 0,
swc: 0,
},
};
result.timings.esbuild = performance.now();
result.esbuild = await _transform(contents, {
sourcefile: file,
loader: file.substring(file.lastIndexOf(".") + 1),
});
result.timings.esbuild = performance.now() - result.timings.esbuild;
result.timings.bun = performance.now();
result.bun = Bun.transformSync(contents, file);
result.timings.bun = performance.now() - result.timings.bun;
if (file.substring(file.lastIndexOf(".") + 1) === "tsx") {
swcOptions.jsc.parser.tsx = true;
swcOptions.jsc.parser.syntax = "typescript";
} else if (file.substring(file.lastIndexOf(".") + 1) === "jsx") {
swcOptions.jsc.parser.tsx = false;
swcOptions.jsc.parser.jsx = true;
swcOptions.jsc.parser.syntax = "typescript";
} else {
swcOptions.jsc.parser.tsx = false;
swcOptions.jsc.parser.jsx = false;
swcOptions.jsc.parser.syntax = "javascript";
}
result.timings.swc = performance.now();
result.swc = transformSyncSWC(contents, swcOptions as any);
result.timings.swc = performance.now() - result.timings.swc;
console.log("esbuild:", result.timings.esbuild, "ms");
console.log("Bun:", result.timings.bun, "ms");
console.log("SWC:", result.timings.swc, "ms");
return result;
}

View File

@@ -1,44 +0,0 @@
import { init, parse } from "es-module-lexer";
import { Bun } from "./api";
export async function start() {
await init;
await Bun.init("/bun-wasm.wasm");
}
const swcOptions = {
sourceMaps: false,
inlineSourcesContent: false,
jsc: {
target: "es2022",
parser: {
jsx: true,
syntax: "typescript",
tsx: false,
decorators: false,
dynamicImport: false,
},
},
};
export async function transform(contents, file) {
var result: any = {
timings: {
lexer: 0,
bun: 0,
},
};
result.timings.lexer = performance.now();
result.lexer = await parse(contents, file);
result.timings.lexer = performance.now() - result.timings.lexer;
result.timings.bun = performance.now();
result.bun = Bun.scan(contents, file);
result.timings.bun = performance.now() - result.timings.bun;
console.log("lexer:", result.timings.lexer, "ms");
console.log("Bun:", result.timings.bun, "ms");
return result;
}

View File

@@ -1,5 +0,0 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -1,29 +0,0 @@
{
"name": "demo",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@swc/wasm-web": "^1.2.146",
"bun-framework-next": "^12.1.0",
"es-module-loader": "^2.3.0",
"esbuild": "^0.14.23",
"esbuild-wasm": "^0.14.23",
"next": "12",
"peechy": "0.4.32",
"react": "17.0.2",
"react-dom": "17.0.2",
"sucrase": "^3.18.1"
},
"devDependencies": {
"@types/react": "^17.0.8",
"bun-types": "^0.2.2",
"typescript": "^4.3.2",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0"
}
}

View File

@@ -1,7 +0,0 @@
import "../styles/globals.css";
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
export default MyApp;

View File

@@ -1,5 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default (req, res) => {
res.status(200).json({ name: "John Doe" });
};

View File

@@ -1,68 +0,0 @@
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { readFile } from "fs/promises";
import React from "react";
if (typeof window !== "undefined") {
globalThis.Run = await import("../lib/run");
await import("../lib/api");
}
export async function getStaticProps(ctx) {
return {
props: {
// not tested
code: readFile("/Users/jarred/Build/es-module-lexer/test/samples/magic-string.js", { encoding: "utf-8" }),
},
};
}
var textDecoder = new TextDecoder();
export default function Home({ code }) {
const fileNameRef = React.useRef<HTMLInputElement>(null);
const [esbuildResult, setEsbuildResult] = React.useState("");
const [bunResult, setBunResult] = React.useState("");
const [swcResult, setSWCResult] = React.useState("");
React.useEffect(() => {
globalThis.Run.start();
}, []);
const runBuild = React.useCallback(
event => {
globalThis.Run.transform(event.target.value, fileNameRef?.current?.value).then(result => {
setEsbuildResult(result.esbuild.code);
setBunResult(textDecoder.decode(result.bun.files[0].data));
setSWCResult(result.swc.code);
}, console.error);
},
[fileNameRef, setEsbuildResult, setBunResult, setSWCResult],
);
return (
<div className={styles.container}>
<Head>
<title>Next.js</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<div>
<input
autoComplete="filename"
type="text"
placeholder="filename"
defaultValue="input.tsx"
ref={fileNameRef}
/>
<textarea onChange={runBuild} defaultValue={code}></textarea>
<textarea readOnly value={esbuildResult}></textarea>
<textarea readOnly value={bunResult}></textarea>
<textarea readOnly value={swcResult}></textarea>
</div>
</main>
</div>
);
}

View File

@@ -1,67 +0,0 @@
import Head from "next/head";
import { readFile } from "fs/promises";
import styles from "../styles/Home.module.css";
import React from "react";
if (typeof window !== "undefined") {
globalThis.Scan = await import("../lib/scan");
await import("../lib/api");
}
export async function getStaticProps(ctx) {
return {
props: {
// not tested
code: readFile("/Users/jarred/Build/es-module-lexer/test/samples/magic-string.js", { encoding: "utf-8" }),
defaultFile: "magic-string.js",
},
};
}
var textDecoder = new TextDecoder();
export default function Home({ code, defaultFile }) {
const fileNameRef = React.useRef<HTMLInputElement>(null);
const [lexer, setLexer] = React.useState("");
const [bunResult, setBunResult] = React.useState("");
const [file, setFile] = React.useState(defaultFile);
React.useEffect(() => {
globalThis.Scan.start();
}, []);
const runBuild = React.useCallback(
event => {
globalThis.Scan.transform(event.target.value, fileNameRef?.current?.value).then(result => {
setLexer(JSON.stringify(result.lexer, null, 2));
setBunResult(JSON.stringify(result.bun, null, 2));
}, console.error);
},
[fileNameRef, setBunResult, setLexer],
);
return (
<div className={styles.container}>
<Head>
<title>Next.js</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<div>
<input
autoComplete="filename"
type="text"
placeholder="filename"
value={file}
onChange={event => setFile(event.target.value)}
ref={fileNameRef}
/>
<textarea onChange={runBuild} defaultValue={code}></textarea>
<textarea readOnly value={bunResult}></textarea>
<textarea readOnly value={lexer}></textarea>
</div>
</main>
</div>
);
}

View File

@@ -1 +0,0 @@
export {};

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,4 +0,0 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,799 +0,0 @@
import type { ByteBuffer } from "peechy";
type byte = number;
type float = number;
type int = number;
type alphanumeric = string;
type uint = number;
type int8 = number;
type lowp = number;
type int16 = number;
type int32 = number;
type float32 = number;
type uint16 = number;
type uint32 = number;
export enum Loader {
jsx = 1,
js = 2,
ts = 3,
tsx = 4,
css = 5,
file = 6,
json = 7,
toml = 8,
wasm = 9,
}
export const LoaderKeys = {
1: "jsx",
jsx: "jsx",
2: "js",
js: "js",
3: "ts",
ts: "ts",
4: "tsx",
tsx: "tsx",
5: "css",
css: "css",
6: "file",
file: "file",
7: "json",
json: "json",
8: "toml",
toml: "toml",
9: "wasm",
wasm: "wasm",
};
export enum FrameworkEntryPointType {
client = 1,
server = 2,
fallback = 3,
}
export const FrameworkEntryPointTypeKeys = {
1: "client",
client: "client",
2: "server",
server: "server",
3: "fallback",
fallback: "fallback",
};
export enum StackFrameScope {
Eval = 1,
Module = 2,
Function = 3,
Global = 4,
Wasm = 5,
Constructor = 6,
}
export const StackFrameScopeKeys = {
1: "Eval",
Eval: "Eval",
2: "Module",
Module: "Module",
3: "Function",
Function: "Function",
4: "Global",
Global: "Global",
5: "Wasm",
Wasm: "Wasm",
6: "Constructor",
Constructor: "Constructor",
};
export enum FallbackStep {
ssr_disabled = 1,
create_vm = 2,
configure_router = 3,
configure_defines = 4,
resolve_entry_point = 5,
load_entry_point = 6,
eval_entry_point = 7,
fetch_event_handler = 8,
}
export const FallbackStepKeys = {
1: "ssr_disabled",
ssr_disabled: "ssr_disabled",
2: "create_vm",
create_vm: "create_vm",
3: "configure_router",
configure_router: "configure_router",
4: "configure_defines",
configure_defines: "configure_defines",
5: "resolve_entry_point",
resolve_entry_point: "resolve_entry_point",
6: "load_entry_point",
load_entry_point: "load_entry_point",
7: "eval_entry_point",
eval_entry_point: "eval_entry_point",
8: "fetch_event_handler",
fetch_event_handler: "fetch_event_handler",
};
export enum ResolveMode {
disable = 1,
lazy = 2,
dev = 3,
bundle = 4,
}
export const ResolveModeKeys = {
1: "disable",
disable: "disable",
2: "lazy",
lazy: "lazy",
3: "dev",
dev: "dev",
4: "bundle",
bundle: "bundle",
};
export enum Platform {
browser = 1,
node = 2,
bun = 3,
bun_macro = 4,
}
export const PlatformKeys = {
1: "browser",
browser: "browser",
2: "node",
node: "node",
3: "bun",
bun: "bun",
4: "bun_macro",
bun_macro: "bun_macro",
};
export enum CSSInJSBehavior {
facade = 1,
facade_onimportcss = 2,
auto_onimportcss = 3,
}
export const CSSInJSBehaviorKeys = {
1: "facade",
facade: "facade",
2: "facade_onimportcss",
facade_onimportcss: "facade_onimportcss",
3: "auto_onimportcss",
auto_onimportcss: "auto_onimportcss",
};
export enum JSXRuntime {
automatic = 1,
classic = 2,
}
export const JSXRuntimeKeys = {
1: "automatic",
automatic: "automatic",
2: "classic",
classic: "classic",
};
export enum ScanDependencyMode {
app = 1,
all = 2,
}
export const ScanDependencyModeKeys = {
1: "app",
app: "app",
2: "all",
all: "all",
};
export enum ModuleImportType {
import = 1,
require = 2,
}
export const ModuleImportTypeKeys = {
1: "import",
import: "import",
2: "require",
require: "require",
};
export enum DotEnvBehavior {
disable = 1,
prefix = 2,
load_all = 3,
}
export const DotEnvBehaviorKeys = {
1: "disable",
disable: "disable",
2: "prefix",
prefix: "prefix",
3: "load_all",
load_all: "load_all",
};
export enum ImportKind {
entry_point = 1,
stmt = 2,
require = 3,
dynamic = 4,
require_resolve = 5,
at = 6,
url = 7,
internal = 8,
}
export const ImportKindKeys = {
1: "entry_point",
entry_point: "entry_point",
2: "stmt",
stmt: "stmt",
3: "require",
require: "require",
4: "dynamic",
dynamic: "dynamic",
5: "require_resolve",
require_resolve: "require_resolve",
6: "at",
at: "at",
7: "url",
url: "url",
8: "internal",
internal: "internal",
};
export enum TransformResponseStatus {
success = 1,
fail = 2,
}
export const TransformResponseStatusKeys = {
1: "success",
success: "success",
2: "fail",
fail: "fail",
};
export enum MessageLevel {
err = 1,
warn = 2,
note = 3,
info = 4,
debug = 5,
}
export const MessageLevelKeys = {
1: "err",
err: "err",
2: "warn",
warn: "warn",
3: "note",
note: "note",
4: "info",
info: "info",
5: "debug",
debug: "debug",
};
export enum Reloader {
disable = 1,
live = 2,
fast_refresh = 3,
}
export const ReloaderKeys = {
1: "disable",
disable: "disable",
2: "live",
live: "live",
3: "fast_refresh",
fast_refresh: "fast_refresh",
};
export enum WebsocketMessageKind {
welcome = 1,
file_change_notification = 2,
build_success = 3,
build_fail = 4,
manifest_success = 5,
manifest_fail = 6,
resolve_file = 7,
file_change_notification_with_hint = 8,
}
export const WebsocketMessageKindKeys = {
1: "welcome",
welcome: "welcome",
2: "file_change_notification",
file_change_notification: "file_change_notification",
3: "build_success",
build_success: "build_success",
4: "build_fail",
build_fail: "build_fail",
5: "manifest_success",
manifest_success: "manifest_success",
6: "manifest_fail",
manifest_fail: "manifest_fail",
7: "resolve_file",
resolve_file: "resolve_file",
8: "file_change_notification_with_hint",
file_change_notification_with_hint: "file_change_notification_with_hint",
};
export enum WebsocketCommandKind {
build = 1,
manifest = 2,
build_with_file_path = 3,
}
export const WebsocketCommandKindKeys = {
1: "build",
build: "build",
2: "manifest",
manifest: "manifest",
3: "build_with_file_path",
build_with_file_path: "build_with_file_path",
};
export interface StackFrame {
function_name: string;
file: string;
position: StackFramePosition;
scope: StackFrameScope;
}
export interface StackFramePosition {
source_offset: int32;
line: int32;
line_start: int32;
line_stop: int32;
column_start: int32;
column_stop: int32;
expression_start: int32;
expression_stop: int32;
}
export interface SourceLine {
line: int32;
text: string;
}
export interface StackTrace {
source_lines: SourceLine[];
frames: StackFrame[];
}
export interface JSException {
name?: string;
message?: string;
runtime_type?: uint16;
code?: uint8;
stack?: StackTrace;
}
export interface Problems {
code: uint16;
name: string;
exceptions: JSException[];
build: Log;
}
export interface Router {
routes: StringMap;
route: int32;
params: StringMap;
}
export interface FallbackMessageContainer {
message?: string;
router?: Router;
reason?: FallbackStep;
problems?: Problems;
cwd?: string;
}
export interface JSX {
factory: string;
runtime: JSXRuntime;
fragment: string;
development: boolean;
import_source: string;
react_fast_refresh: boolean;
}
export interface StringPointer {
offset: uint32;
length: uint32;
}
export interface JavascriptBundledModule {
path: StringPointer;
code: StringPointer;
package_id: uint32;
id: uint32;
path_extname_length: byte;
}
export interface JavascriptBundledPackage {
name: StringPointer;
version: StringPointer;
hash: uint32;
modules_offset: uint32;
modules_length: uint32;
}
export interface JavascriptBundle {
modules: JavascriptBundledModule[];
packages: JavascriptBundledPackage[];
etag: Uint8Array;
generated_at: uint32;
app_package_json_dependencies_hash: Uint8Array;
import_from_name: Uint8Array;
manifest_string: Uint8Array;
}
export interface JavascriptBundleContainer {
bundle_format_version?: uint32;
routes?: LoadedRouteConfig;
framework?: LoadedFramework;
bundle?: JavascriptBundle;
code_length?: uint32;
}
export interface ModuleImportRecord {
kind: ModuleImportType;
path: string;
dynamic: boolean;
}
export interface Module {
path: string;
imports: ModuleImportRecord[];
}
export interface StringMap {
keys: string[];
values: string[];
}
export interface LoaderMap {
extensions: string[];
loaders: Loader[];
}
export interface EnvConfig {
prefix?: string;
defaults?: StringMap;
}
export interface LoadedEnvConfig {
dotenv: DotEnvBehavior;
defaults: StringMap;
prefix: string;
}
export interface FrameworkConfig {
package?: string;
client?: FrameworkEntryPointMessage;
server?: FrameworkEntryPointMessage;
fallback?: FrameworkEntryPointMessage;
development?: boolean;
client_css_in_js?: CSSInJSBehavior;
display_name?: string;
overrideModules?: StringMap;
}
export interface FrameworkEntryPoint {
kind: FrameworkEntryPointType;
path: string;
env: LoadedEnvConfig;
}
export interface FrameworkEntryPointMap {
client?: FrameworkEntryPoint;
server?: FrameworkEntryPoint;
fallback?: FrameworkEntryPoint;
}
export interface FrameworkEntryPointMessage {
path?: string;
env?: EnvConfig;
}
export interface LoadedFramework {
package: string;
display_name: string;
development: boolean;
entry_points: FrameworkEntryPointMap;
client_css_in_js: CSSInJSBehavior;
overrideModules: StringMap;
}
export interface LoadedRouteConfig {
dir: string;
extensions: string[];
static_dir: string;
asset_prefix: string;
}
export interface RouteConfig {
dir?: string[];
extensions?: string[];
static_dir?: string;
asset_prefix?: string;
}
export interface TransformOptions {
jsx?: JSX;
tsconfig_override?: string;
resolve?: ResolveMode;
origin?: string;
absolute_working_dir?: string;
define?: StringMap;
preserve_symlinks?: boolean;
entry_points?: string[];
write?: boolean;
inject?: string[];
output_dir?: string;
external?: string[];
loaders?: LoaderMap;
main_fields?: string[];
platform?: Platform;
serve?: boolean;
extension_order?: string[];
generate_node_module_bundle?: boolean;
node_modules_bundle_path?: string;
node_modules_bundle_path_server?: string;
framework?: FrameworkConfig;
router?: RouteConfig;
no_summary?: boolean;
disable_hmr?: boolean;
port?: uint16;
logLevel?: MessageLevel;
}
export interface FileHandle {
path: string;
size: uint;
fd: uint;
}
export interface Transform {
handle?: FileHandle;
path?: string;
contents?: Uint8Array;
loader?: Loader;
options?: TransformOptions;
}
export interface Scan {
path?: string;
contents?: Uint8Array;
loader?: Loader;
}
export interface ScanResult {
exports: string[];
imports: ScannedImport[];
}
export interface ScannedImport {
path: string;
kind: ImportKind;
}
export interface OutputFile {
data: Uint8Array;
path: string;
}
export interface TransformResponse {
status: TransformResponseStatus;
files: OutputFile[];
errors: Message[];
}
export interface Location {
file: string;
namespace: string;
line: int32;
column: int32;
line_text: string;
suggestion: string;
offset: uint;
}
export interface MessageData {
text?: string;
location?: Location;
}
export interface MessageMeta {
resolve?: string;
build?: boolean;
}
export interface Message {
level: MessageLevel;
data: MessageData;
notes: MessageData[];
on: MessageMeta;
}
export interface Log {
warnings: uint32;
errors: uint32;
msgs: Message[];
}
export interface WebsocketMessage {
timestamp: uint32;
kind: WebsocketMessageKind;
}
export interface WebsocketMessageWelcome {
epoch: uint32;
javascriptReloader: Reloader;
cwd: string;
}
export interface WebsocketMessageFileChangeNotification {
id: uint32;
loader: Loader;
}
export interface WebsocketCommand {
kind: WebsocketCommandKind;
timestamp: uint32;
}
export interface WebsocketCommandBuild {
id: uint32;
}
export interface WebsocketCommandManifest {
id: uint32;
}
export interface WebsocketMessageBuildSuccess {
id: uint32;
from_timestamp: uint32;
loader: Loader;
module_path: string;
blob_length: uint32;
}
export interface WebsocketMessageBuildFailure {
id: uint32;
from_timestamp: uint32;
loader: Loader;
module_path: string;
log: Log;
}
export interface WebsocketCommandBuildWithFilePath {
id: uint32;
file_path: string;
}
export interface WebsocketMessageResolveID {
id: uint32;
}
export interface NPMRegistry {
url: string;
username: string;
password: string;
token: string;
}
export interface NPMRegistryMap {
scopes: string[];
registries: NPMRegistry[];
}
export interface BunInstall {
default_registry?: NPMRegistry;
scoped?: NPMRegistryMap;
lockfile_path?: string;
save_lockfile_path?: string;
cache_directory?: string;
dry_run?: boolean;
force?: boolean;
save_dev?: boolean;
save_optional?: boolean;
save_peer?: boolean;
save_lockfile?: boolean;
production?: boolean;
save_yarn_lockfile?: boolean;
native_bin_links?: string[];
disable_cache?: boolean;
disable_manifest_cache?: boolean;
global_dir?: string;
global_bin_dir?: string;
}
export declare function encodeStackFrame(message: StackFrame, bb: ByteBuffer): void;
export declare function decodeStackFrame(buffer: ByteBuffer): StackFrame;
export declare function encodeStackFramePosition(message: StackFramePosition, bb: ByteBuffer): void;
export declare function decodeStackFramePosition(buffer: ByteBuffer): StackFramePosition;
export declare function encodeSourceLine(message: SourceLine, bb: ByteBuffer): void;
export declare function decodeSourceLine(buffer: ByteBuffer): SourceLine;
export declare function encodeStackTrace(message: StackTrace, bb: ByteBuffer): void;
export declare function decodeStackTrace(buffer: ByteBuffer): StackTrace;
export declare function encodeJSException(message: JSException, bb: ByteBuffer): void;
export declare function decodeJSException(buffer: ByteBuffer): JSException;
export declare function encodeProblems(message: Problems, bb: ByteBuffer): void;
export declare function decodeProblems(buffer: ByteBuffer): Problems;
export declare function encodeRouter(message: Router, bb: ByteBuffer): void;
export declare function decodeRouter(buffer: ByteBuffer): Router;
export declare function encodeFallbackMessageContainer(message: FallbackMessageContainer, bb: ByteBuffer): void;
export declare function decodeFallbackMessageContainer(buffer: ByteBuffer): FallbackMessageContainer;
export declare function encodeJSX(message: JSX, bb: ByteBuffer): void;
export declare function decodeJSX(buffer: ByteBuffer): JSX;
export declare function encodeStringPointer(message: StringPointer, bb: ByteBuffer): void;
export declare function decodeStringPointer(buffer: ByteBuffer): StringPointer;
export declare function encodeJavascriptBundledModule(message: JavascriptBundledModule, bb: ByteBuffer): void;
export declare function decodeJavascriptBundledModule(buffer: ByteBuffer): JavascriptBundledModule;
export declare function encodeJavascriptBundledPackage(message: JavascriptBundledPackage, bb: ByteBuffer): void;
export declare function decodeJavascriptBundledPackage(buffer: ByteBuffer): JavascriptBundledPackage;
export declare function encodeJavascriptBundle(message: JavascriptBundle, bb: ByteBuffer): void;
export declare function decodeJavascriptBundle(buffer: ByteBuffer): JavascriptBundle;
export declare function encodeJavascriptBundleContainer(message: JavascriptBundleContainer, bb: ByteBuffer): void;
export declare function decodeJavascriptBundleContainer(buffer: ByteBuffer): JavascriptBundleContainer;
export declare function encodeModuleImportRecord(message: ModuleImportRecord, bb: ByteBuffer): void;
export declare function decodeModuleImportRecord(buffer: ByteBuffer): ModuleImportRecord;
export declare function encodeModule(message: Module, bb: ByteBuffer): void;
export declare function decodeModule(buffer: ByteBuffer): Module;
export declare function encodeStringMap(message: StringMap, bb: ByteBuffer): void;
export declare function decodeStringMap(buffer: ByteBuffer): StringMap;
export declare function encodeLoaderMap(message: LoaderMap, bb: ByteBuffer): void;
export declare function decodeLoaderMap(buffer: ByteBuffer): LoaderMap;
export declare function encodeEnvConfig(message: EnvConfig, bb: ByteBuffer): void;
export declare function decodeEnvConfig(buffer: ByteBuffer): EnvConfig;
export declare function encodeLoadedEnvConfig(message: LoadedEnvConfig, bb: ByteBuffer): void;
export declare function decodeLoadedEnvConfig(buffer: ByteBuffer): LoadedEnvConfig;
export declare function encodeFrameworkConfig(message: FrameworkConfig, bb: ByteBuffer): void;
export declare function decodeFrameworkConfig(buffer: ByteBuffer): FrameworkConfig;
export declare function encodeFrameworkEntryPoint(message: FrameworkEntryPoint, bb: ByteBuffer): void;
export declare function decodeFrameworkEntryPoint(buffer: ByteBuffer): FrameworkEntryPoint;
export declare function encodeFrameworkEntryPointMap(message: FrameworkEntryPointMap, bb: ByteBuffer): void;
export declare function decodeFrameworkEntryPointMap(buffer: ByteBuffer): FrameworkEntryPointMap;
export declare function encodeFrameworkEntryPointMessage(message: FrameworkEntryPointMessage, bb: ByteBuffer): void;
export declare function decodeFrameworkEntryPointMessage(buffer: ByteBuffer): FrameworkEntryPointMessage;
export declare function encodeLoadedFramework(message: LoadedFramework, bb: ByteBuffer): void;
export declare function decodeLoadedFramework(buffer: ByteBuffer): LoadedFramework;
export declare function encodeLoadedRouteConfig(message: LoadedRouteConfig, bb: ByteBuffer): void;
export declare function decodeLoadedRouteConfig(buffer: ByteBuffer): LoadedRouteConfig;
export declare function encodeRouteConfig(message: RouteConfig, bb: ByteBuffer): void;
export declare function decodeRouteConfig(buffer: ByteBuffer): RouteConfig;
export declare function encodeTransformOptions(message: TransformOptions, bb: ByteBuffer): void;
export declare function decodeTransformOptions(buffer: ByteBuffer): TransformOptions;
export declare function encodeFileHandle(message: FileHandle, bb: ByteBuffer): void;
export declare function decodeFileHandle(buffer: ByteBuffer): FileHandle;
export declare function encodeTransform(message: Transform, bb: ByteBuffer): void;
export declare function decodeTransform(buffer: ByteBuffer): Transform;
export declare function encodeScan(message: Scan, bb: ByteBuffer): void;
export declare function decodeScan(buffer: ByteBuffer): Scan;
export declare function encodeScanResult(message: ScanResult, bb: ByteBuffer): void;
export declare function decodeScanResult(buffer: ByteBuffer): ScanResult;
export declare function encodeScannedImport(message: ScannedImport, bb: ByteBuffer): void;
export declare function decodeScannedImport(buffer: ByteBuffer): ScannedImport;
export declare function encodeOutputFile(message: OutputFile, bb: ByteBuffer): void;
export declare function decodeOutputFile(buffer: ByteBuffer): OutputFile;
export declare function encodeTransformResponse(message: TransformResponse, bb: ByteBuffer): void;
export declare function decodeTransformResponse(buffer: ByteBuffer): TransformResponse;
export declare function encodeLocation(message: Location, bb: ByteBuffer): void;
export declare function decodeLocation(buffer: ByteBuffer): Location;
export declare function encodeMessageData(message: MessageData, bb: ByteBuffer): void;
export declare function decodeMessageData(buffer: ByteBuffer): MessageData;
export declare function encodeMessageMeta(message: MessageMeta, bb: ByteBuffer): void;
export declare function decodeMessageMeta(buffer: ByteBuffer): MessageMeta;
export declare function encodeMessage(message: Message, bb: ByteBuffer): void;
export declare function decodeMessage(buffer: ByteBuffer): Message;
export declare function encodeLog(message: Log, bb: ByteBuffer): void;
export declare function decodeLog(buffer: ByteBuffer): Log;
export declare function encodeWebsocketMessage(message: WebsocketMessage, bb: ByteBuffer): void;
export declare function decodeWebsocketMessage(buffer: ByteBuffer): WebsocketMessage;
export declare function encodeWebsocketMessageWelcome(message: WebsocketMessageWelcome, bb: ByteBuffer): void;
export declare function decodeWebsocketMessageWelcome(buffer: ByteBuffer): WebsocketMessageWelcome;
export declare function encodeWebsocketMessageFileChangeNotification(
message: WebsocketMessageFileChangeNotification,
bb: ByteBuffer,
): void;
export declare function decodeWebsocketMessageFileChangeNotification(
buffer: ByteBuffer,
): WebsocketMessageFileChangeNotification;
export declare function encodeWebsocketCommand(message: WebsocketCommand, bb: ByteBuffer): void;
export declare function decodeWebsocketCommand(buffer: ByteBuffer): WebsocketCommand;
export declare function encodeWebsocketCommandBuild(message: WebsocketCommandBuild, bb: ByteBuffer): void;
export declare function decodeWebsocketCommandBuild(buffer: ByteBuffer): WebsocketCommandBuild;
export declare function encodeWebsocketCommandManifest(message: WebsocketCommandManifest, bb: ByteBuffer): void;
export declare function decodeWebsocketCommandManifest(buffer: ByteBuffer): WebsocketCommandManifest;
export declare function encodeWebsocketMessageBuildSuccess(message: WebsocketMessageBuildSuccess, bb: ByteBuffer): void;
export declare function decodeWebsocketMessageBuildSuccess(buffer: ByteBuffer): WebsocketMessageBuildSuccess;
export declare function encodeWebsocketMessageBuildFailure(message: WebsocketMessageBuildFailure, bb: ByteBuffer): void;
export declare function decodeWebsocketMessageBuildFailure(buffer: ByteBuffer): WebsocketMessageBuildFailure;
export declare function encodeWebsocketCommandBuildWithFilePath(
message: WebsocketCommandBuildWithFilePath,
bb: ByteBuffer,
): void;
export declare function decodeWebsocketCommandBuildWithFilePath(buffer: ByteBuffer): WebsocketCommandBuildWithFilePath;
export declare function encodeWebsocketMessageResolveID(message: WebsocketMessageResolveID, bb: ByteBuffer): void;
export declare function decodeWebsocketMessageResolveID(buffer: ByteBuffer): WebsocketMessageResolveID;
export declare function encodeNPMRegistry(message: NPMRegistry, bb: ByteBuffer): void;
export declare function decodeNPMRegistry(buffer: ByteBuffer): NPMRegistry;
export declare function encodeNPMRegistryMap(message: NPMRegistryMap, bb: ByteBuffer): void;
export declare function decodeNPMRegistryMap(buffer: ByteBuffer): NPMRegistryMap;
export declare function encodeBunInstall(message: BunInstall, bb: ByteBuffer): void;
export declare function decodeBunInstall(buffer: ByteBuffer): BunInstall;

File diff suppressed because it is too large Load Diff

View File

@@ -1,553 +0,0 @@
package Api;
smol Loader {
jsx = 1;
js = 2;
ts = 3;
tsx = 4;
css = 5;
file = 6;
json = 7;
toml = 8;
wasm = 9;
}
smol FrameworkEntryPointType {
client = 1;
server = 2;
fallback = 3;
}
smol StackFrameScope {
Eval = 1;
Module = 2;
Function = 3;
Global = 4;
Wasm = 5;
Constructor = 6;
}
struct StackFrame {
string function_name;
string file;
StackFramePosition position;
StackFrameScope scope;
}
struct StackFramePosition {
int32 source_offset;
int32 line;
int32 line_start;
int32 line_stop;
int32 column_start;
int32 column_stop;
int32 expression_start;
int32 expression_stop;
}
struct SourceLine {
int32 line;
string text;
}
struct StackTrace {
SourceLine[] source_lines;
StackFrame[] frames;
}
message JSException {
string name = 1;
string message = 2;
uint16 runtime_type = 3;
uint8 code = 4;
StackTrace stack = 5;
}
smol FallbackStep {
ssr_disabled = 1;
create_vm = 2;
configure_router = 3;
configure_defines = 4;
resolve_entry_point = 5;
load_entry_point = 6;
eval_entry_point = 7;
fetch_event_handler = 8;
}
struct Problems {
uint16 code;
string name;
JSException[] exceptions;
Log build;
}
struct Router {
StringMap routes;
int32 route;
StringMap params;
}
message FallbackMessageContainer {
string message = 1;
Router router = 2;
FallbackStep reason = 3;
Problems problems = 4;
string cwd = 5;
}
smol ResolveMode {
disable = 1;
lazy = 2;
dev = 3;
bundle = 4;
}
smol Target {
browser = 1;
node = 2;
bun = 3;
bun_macro = 4;
}
smol CSSInJSBehavior {
facade = 1;
facade_onimportcss = 2;
auto_onimportcss = 3;
}
smol JSXRuntime {
automatic = 1;
classic = 2;
}
struct JSX {
string factory;
JSXRuntime runtime;
string fragment;
bool development;
// Probably react
string import_source;
bool react_fast_refresh;
}
struct StringPointer {
uint32 offset;
uint32 length;
}
struct JavascriptBundledModule {
// package-relative path including file extension
StringPointer path;
// Source code
StringPointer code;
// index into JavascriptBundle.packages
uint32 package_id;
// The ESM export is this id ("$" + number.toString(16))
uint32 id;
// This lets us efficiently compare strings ignoring the extension
byte path_extname_length;
}
struct JavascriptBundledPackage {
StringPointer name;
StringPointer version;
uint32 hash;
uint32 modules_offset;
uint32 modules_length;
}
struct JavascriptBundle {
// These are sorted alphabetically so you can do binary search
JavascriptBundledModule[] modules;
JavascriptBundledPackage[] packages;
// This is ASCII-encoded so you can send it directly over HTTP
byte[] etag;
uint32 generated_at;
// generated by hashing all ${name}@${version} in sorted order
byte[] app_package_json_dependencies_hash;
byte[] import_from_name;
// This is what StringPointer refers to
byte[] manifest_string;
}
message JavascriptBundleContainer {
uint32 bundle_format_version = 1;
// These go first so if we change JavaScriptBundle we can still read these
LoadedRouteConfig routes = 3;
LoadedFramework framework = 2;
JavascriptBundle bundle = 4;
// Don't technically need to store this, but it may be helpful as a sanity check
uint32 code_length = 5;
}
smol ScanDependencyMode {
app = 1;
all = 2;
}
smol ModuleImportType {
import = 1;
require = 2;
}
struct ModuleImportRecord {
ModuleImportType kind;
string path;
bool dynamic;
}
struct Module {
string path;
ModuleImportRecord[] imports;
}
struct StringMap {
string[] keys;
string[] values;
}
struct LoaderMap {
string[] extensions;
Loader[] loaders;
}
enum DotEnvBehavior {
disable = 1;
prefix = 2;
load_all = 3;
}
message EnvConfig {
string prefix = 1;
StringMap defaults = 2;
}
struct LoadedEnvConfig {
DotEnvBehavior dotenv;
StringMap defaults;
string prefix;
}
message FrameworkConfig {
string package = 1;
FrameworkEntryPointMessage client = 2;
FrameworkEntryPointMessage server = 3;
FrameworkEntryPointMessage fallback = 4;
bool development = 5;
CSSInJSBehavior client_css_in_js = 6;
string display_name = 7;
StringMap overrideModules = 8;
}
struct FrameworkEntryPoint {
FrameworkEntryPointType kind;
string path;
LoadedEnvConfig env;
}
message FrameworkEntryPointMap {
FrameworkEntryPoint client = 1;
FrameworkEntryPoint server = 2;
FrameworkEntryPoint fallback = 3;
}
message FrameworkEntryPointMessage {
string path = 1;
EnvConfig env = 2;
}
struct LoadedFramework {
string package;
string display_name;
bool development;
FrameworkEntryPointMap entry_points;
CSSInJSBehavior client_css_in_js;
StringMap overrideModules;
}
struct LoadedRouteConfig {
string dir;
string[] extensions;
string static_dir;
string asset_prefix;
}
message RouteConfig {
string[] dir = 1;
string[] extensions = 2;
string static_dir = 3;
string asset_prefix = 4;
}
message TransformOptions {
JSX jsx = 1;
string tsconfig_override = 2;
ResolveMode resolve = 3;
string origin = 4;
string absolute_working_dir = 5;
StringMap define = 6;
bool preserve_symlinks = 7;
string[] entry_points = 8;
bool write = 9;
string[] inject = 10;
string output_dir = 11;
string[] external = 12;
LoaderMap loaders = 13;
string[] main_fields = 14;
Target target = 15;
bool serve = 16;
string[] extension_order = 17;
bool generate_node_module_bundle = 18;
string node_modules_bundle_path = 19;
string node_modules_bundle_path_server = 20;
FrameworkConfig framework = 21;
RouteConfig router = 22;
bool no_summary = 23;
bool disable_hmr = 24;
uint16 port = 25;
MessageLevel logLevel = 26;
}
struct FileHandle {
string path;
uint size;
uint fd;
}
message Transform {
FileHandle handle = 1;
string path = 2;
byte[] contents = 3;
Loader loader = 4;
TransformOptions options = 5;
}
enum TransformResponseStatus {
success = 1;
fail = 2;
}
struct OutputFile {
byte[] data;
string path;
}
struct TransformResponse {
TransformResponseStatus status;
OutputFile[] files;
Message[] errors;
}
enum MessageLevel {
err = 1;
warn =2;
note = 3;
info = 4;
debug = 5;
}
struct Location {
string file;
string namespace;
int32 line;
int32 column;
string line_text;
string suggestion;
uint offset;
}
message MessageData {
string text = 1;
Location location = 2;
}
message MessageMeta {
string resolve = 1;
bool build = 2;
}
struct Message {
MessageLevel level;
MessageData data;
MessageData[] notes;
MessageMeta on;
}
struct Log {
uint32 warnings;
uint32 errors;
Message[] msgs;
}
smol Reloader {
disable = 1;
// equivalent of CMD + R
live = 2;
// React Fast Refresh
fast_refresh = 3;
}
// The WebSocket protocol
// Server: "hey, this file changed. Does anyone want it?"
// Browser: *checks array* "uhh yeah, ok. rebuild that for me"
// Server: "here u go"
// This makes the client responsible for tracking which files it needs to listen for.
// From a server perspective, this means the filesystem watching thread can send the same WebSocket message
// to every client, which is good for performance. It means if you have 5 tabs open it won't really be different than one tab
// The clients can just ignore files they don't care about
smol WebsocketMessageKind {
welcome = 1;
file_change_notification = 2;
build_success = 3;
build_fail = 4;
manifest_success = 5;
manifest_fail = 6;
resolve_file = 7;
file_change_notification_with_hint = 8;
}
smol WebsocketCommandKind {
build = 1;
manifest = 2;
build_with_file_path = 3;
}
// Each websocket message has two messages in it!
// This is the first.
struct WebsocketMessage {
uint32 timestamp;
WebsocketMessageKind kind;
}
// This is the first.
struct WebsocketMessageWelcome {
uint32 epoch;
Reloader javascriptReloader;
string cwd;
}
struct WebsocketMessageFileChangeNotification {
uint32 id;
Loader loader;
}
struct WebsocketCommand {
WebsocketCommandKind kind;
uint32 timestamp;
}
// The timestamp is used for client-side deduping
struct WebsocketCommandBuild {
uint32 id;
}
struct WebsocketCommandManifest {
uint32 id;
}
// We copy the module_path here incase they don't already have it
struct WebsocketMessageBuildSuccess {
uint32 id;
uint32 from_timestamp;
Loader loader;
string module_path;
// This is the length of the blob that immediately follows this message.
uint32 blob_length;
}
struct WebsocketMessageBuildFailure {
uint32 id;
uint32 from_timestamp;
Loader loader;
string module_path;
Log log;
}
struct WebsocketCommandBuildWithFilePath {
uint32 id;
string file_path;
}
struct WebsocketMessageResolveID {
uint32 id;
}
struct NPMRegistry {
string url;
string username;
string password;
string token;
}
struct NPMRegistryMap {
string[] scopes;
NPMRegistry[] registries;
}
message BunInstall {
NPMRegistry default_registry = 1;
NPMRegistryMap scoped = 2;
string lockfile_path = 3;
string save_lockfile_path = 4;
string cache_directory = 5;
bool dry_run = 6;
bool force = 7;
bool save_dev = 8;
bool save_optional = 9;
bool save_peer = 10;
bool save_lockfile = 11;
bool production = 12;
bool save_yarn_lockfile = 13;
string[] native_bin_links = 14;
bool disable_cache = 15;
bool disable_manifest_cache = 16;
string global_dir = 17;
string global_bin_dir = 18;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,122 +0,0 @@
.container {
min-height: 100vh;
padding: 0 0.5rem;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
.main {
padding: 5rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.footer {
width: 100%;
height: 100px;
border-top: 1px solid #eaeaea;
display: flex;
justify-content: center;
align-items: center;
}
.footer a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.title a {
color: #0070f3;
text-decoration: none;
}
.title a:hover,
.title a:focus,
.title a:active {
text-decoration: underline;
}
.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
}
.title,
.description {
text-align: center;
}
.description {
line-height: 1.5;
font-size: 1.5rem;
}
.code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
margin-top: 3rem;
}
.card {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
width: 45%;
}
.card:hover,
.card:focus,
.card:active {
color: #0070f3;
border-color: #0070f3;
}
.card h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
.logo {
height: 1em;
margin-left: 0.5rem;
}
@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}

View File

@@ -1,16 +0,0 @@
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}

View File

@@ -1,34 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noImplicitAny": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"types": [
"bun-types"
],
"incremental": true
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}

2
src/api/schema.d.ts generated vendored
View File

@@ -709,6 +709,8 @@ export interface BunInstall {
disable_manifest_cache?: boolean;
global_dir?: string;
global_bin_dir?: string;
frozen_lockfile?: boolean;
exact?: boolean;
}
export interface ClientServerModule {

20
src/api/schema.js generated
View File

@@ -3044,6 +3044,14 @@ function decodeBunInstall(bb) {
result["global_bin_dir"] = bb.readString();
break;
case 19:
result["frozen_lockfile"] = !!bb.readByte();
break;
case 20:
result["exact"] = !!bb.readByte();
break;
default:
throw new Error("Attempted to parse invalid message");
}
@@ -3164,6 +3172,18 @@ function encodeBunInstall(message, bb) {
bb.writeByte(18);
bb.writeString(value);
}
var value = message["frozen_lockfile"];
if (value != null) {
bb.writeByte(19);
bb.writeByte(value);
}
var value = message["exact"];
if (value != null) {
bb.writeByte(20);
bb.writeByte(value);
}
bb.writeByte(0);
}

View File

@@ -590,6 +590,8 @@ message BunInstall {
bool disable_manifest_cache = 16;
string global_dir = 17;
string global_bin_dir = 18;
bool frozen_lockfile = 19;
bool exact = 20;
}
struct ClientServerModule {

View File

@@ -2901,6 +2901,12 @@ pub const Api = struct {
/// global_bin_dir
global_bin_dir: ?[]const u8 = null,
/// frozen_lockfile
frozen_lockfile: ?bool = null,
/// exact
exact: ?bool = null,
pub fn decode(reader: anytype) anyerror!BunInstall {
var this = std.mem.zeroes(BunInstall);
@@ -2964,6 +2970,12 @@ pub const Api = struct {
18 => {
this.global_bin_dir = try reader.readValue([]const u8);
},
19 => {
this.frozen_lockfile = try reader.readValue(bool);
},
20 => {
this.exact = try reader.readValue(bool);
},
else => {
return error.InvalidMessage;
},
@@ -3045,6 +3057,14 @@ pub const Api = struct {
try writer.writeFieldID(18);
try writer.writeValue(@TypeOf(global_bin_dir), global_bin_dir);
}
if (this.frozen_lockfile) |frozen_lockfile| {
try writer.writeFieldID(19);
try writer.writeInt(@as(u8, @intFromBool(frozen_lockfile)));
}
if (this.exact) |exact| {
try writer.writeFieldID(20);
try writer.writeInt(@as(u8, @intFromBool(exact)));
}
try writer.endMessage();
}
};

View File

@@ -5,6 +5,22 @@ pub const DecodeResult = struct {
fail: bool = false,
};
pub const LibBase64 = struct {
pub const State = extern struct {
eof: c_int,
bytes: c_int,
flags: c_int,
carry: u8,
};
pub extern fn base64_encode(src: [*]const u8, srclen: usize, out: [*]u8, outlen: *usize, flags: c_int) void;
pub extern fn base64_stream_encode_init(state: *State, flags: c_int) void;
pub extern fn base64_stream_encode(state: *State, src: [*]const u8, srclen: usize, out: [*]u8, outlen: *usize) void;
pub extern fn base64_stream_encode_final(state: *State, out: [*]u8, outlen: *usize) void;
pub extern fn base64_decode(src: [*]const u8, srclen: usize, out: [*]u8, outlen: *usize, flags: c_int) c_int;
pub extern fn base64_stream_decode_init(state: *State, flags: c_int) void;
pub extern fn base64_stream_decode(state: *State, src: [*]const u8, srclen: usize, out: [*]u8, outlen: *usize) c_int;
};
const mixed_decoder = brk: {
var decoder = zig_base64.standard.decoderWithIgnore("\xff \t\r\n" ++ [_]u8{
std.ascii.control_code.vt,
@@ -30,7 +46,9 @@ pub fn decode(destination: []u8, source: []const u8) DecodeResult {
}
pub fn encode(destination: []u8, source: []const u8) usize {
return zig_base64.standard.Encoder.encode(destination, source).len;
var outlen: usize = destination.len;
LibBase64.base64_encode(source.ptr, source.len, destination.ptr, &outlen, 0);
return outlen;
}
pub fn decodeLenUpperBound(len: usize) usize {

View File

@@ -1 +1 @@
10
14

View File

@@ -26,7 +26,7 @@ const strings = bun.strings;
const NewClass = Base.NewClass;
const To = Base.To;
const Request = WebCore.Request;
const String = bun.String;
const FetchEvent = WebCore.FetchEvent;
const MacroMap = @import("../../resolver/package_json.zig").MacroMap;
const TSConfigJSON = @import("../../resolver/tsconfig_json.zig").TSConfigJSON;
@@ -871,16 +871,16 @@ pub const JSBundler = struct {
extern fn JSBundlerPlugin__anyMatches(
*Plugin,
namespaceString: *const ZigString,
path: *const ZigString,
namespaceString: *const String,
path: *const String,
bool,
) bool;
extern fn JSBundlerPlugin__matchOnLoad(
*JSC.JSGlobalObject,
*Plugin,
namespaceString: *const ZigString,
path: *const ZigString,
namespaceString: *const String,
path: *const String,
context: *anyopaque,
u8,
) void;
@@ -888,9 +888,9 @@ pub const JSBundler = struct {
extern fn JSBundlerPlugin__matchOnResolve(
*JSC.JSGlobalObject,
*Plugin,
namespaceString: *const ZigString,
path: *const ZigString,
importer: *const ZigString,
namespaceString: *const String,
path: *const String,
importer: *const String,
context: *anyopaque,
u8,
) void;
@@ -905,10 +905,10 @@ pub const JSBundler = struct {
defer tracer.end();
const namespace_string = if (path.isFile())
ZigString.Empty
bun.String.empty
else
ZigString.fromUTF8(path.namespace);
const path_string = ZigString.fromUTF8(path.text);
bun.String.create(path.namespace);
const path_string = bun.String.create(path.text);
return JSBundlerPlugin__anyMatches(this, &namespace_string, &path_string, is_onLoad);
}
@@ -924,10 +924,12 @@ pub const JSBundler = struct {
const tracer = bun.tracy.traceNamed(@src(), "JSBundler.matchOnLoad");
defer tracer.end();
const namespace_string = if (namespace.len == 0)
ZigString.init("file")
bun.String.static("file")
else
ZigString.fromUTF8(namespace);
const path_string = ZigString.fromUTF8(path);
bun.String.create(namespace);
const path_string = bun.String.create(path);
defer namespace_string.deref();
defer path_string.deref();
JSBundlerPlugin__matchOnLoad(globalThis, this, &namespace_string, &path_string, context, @intFromEnum(default_loader));
}
@@ -944,11 +946,14 @@ pub const JSBundler = struct {
const tracer = bun.tracy.traceNamed(@src(), "JSBundler.matchOnResolve");
defer tracer.end();
const namespace_string = if (strings.eqlComptime(namespace, "file"))
ZigString.Empty
bun.String.empty
else
ZigString.fromUTF8(namespace);
const path_string = ZigString.fromUTF8(path);
const importer_string = ZigString.fromUTF8(importer);
bun.String.create(namespace);
const path_string = bun.String.create(path);
const importer_string = bun.String.create(importer);
defer namespace_string.deref();
defer path_string.deref();
defer importer_string.deref();
JSBundlerPlugin__matchOnResolve(globalThis, this, &namespace_string, &path_string, &importer_string, context, @intFromEnum(import_record_kind));
}

View File

@@ -896,6 +896,9 @@ pub fn createNodeFS(
) js.JSValueRef {
var module = ctx.allocator().create(JSC.Node.NodeJSFS) catch unreachable;
module.* = .{};
var vm = ctx.bunVM();
if (vm.standalone_module_graph != null)
module.node_fs.vm = vm;
return module.toJS(ctx).asObjectRef();
}
@@ -3712,21 +3715,32 @@ pub const Timer = struct {
const kind = this.kind;
var map: *TimeoutMap = vm.timer.maps.get(kind);
// This doesn't deinit the timer
// Timers are deinit'd separately
// We do need to handle when the timer is cancelled after the job has been enqueued
if (kind != .setInterval) {
if (map.fetchSwapRemove(this.id) == null) {
// if the timeout was cancelled, don't run the callback
this.deinit();
return;
}
} else {
if (!map.contains(this.id)) {
// if the interval was cancelled, don't run the callback
this.deinit();
return;
const should_cancel_job = brk: {
// This doesn't deinit the timer
// Timers are deinit'd separately
// We do need to handle when the timer is cancelled after the job has been enqueued
if (kind != .setInterval) {
if (map.get(this.id)) |tombstone_or_timer| {
break :brk tombstone_or_timer != null;
} else {
// clearTimeout has been called
break :brk true;
}
} else {
if (map.get(this.id)) |tombstone_or_timer| {
// .refresh() was called after CallbackJob enqueued
break :brk tombstone_or_timer == null;
}
}
break :brk false;
};
if (should_cancel_job) {
this.deinit();
return;
} else if (kind != .setInterval) {
_ = map.swapRemove(this.id);
}
var args_buf: [8]JSC.JSValue = undefined;
@@ -3791,6 +3805,8 @@ pub const Timer = struct {
result.then(globalThis, this, CallbackJob__onResolve, CallbackJob__onReject);
},
}
} else {
this.deinit();
}
}
};
@@ -3820,10 +3836,29 @@ pub const Timer = struct {
return timer_js;
}
pub fn doRef(this: *TimerObject, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
pub fn doRef(this: *TimerObject, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
const this_value = callframe.this();
this_value.ensureStillAlive();
if (this.ref_count > 0)
this.ref_count +|= 1;
return JSValue.jsUndefined();
var vm = globalObject.bunVM();
switch (this.kind) {
.setTimeout, .setImmediate, .setInterval => {
if (vm.timer.maps.get(this.kind).getPtr(this.id)) |val_| {
if (val_.*) |*val| {
val.poll_ref.ref(vm);
if (val.did_unref_timer) {
val.did_unref_timer = false;
vm.uws_event_loop.?.num_polls += 1;
}
}
}
},
}
return this_value;
}
pub fn doRefresh(this: *TimerObject, globalThis: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
@@ -3919,20 +3954,27 @@ pub const Timer = struct {
return JSValue.jsUndefined();
}
pub fn doUnref(this: *TimerObject, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
pub fn doUnref(this: *TimerObject, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
const this_value = callframe.this();
this_value.ensureStillAlive();
this.ref_count -|= 1;
if (this.ref_count == 0) {
switch (this.kind) {
.setTimeout, .setImmediate => {
_ = clearTimeout(globalObject, JSValue.jsNumber(this.id));
},
.setInterval => {
_ = clearInterval(globalObject, JSValue.jsNumber(this.id));
},
}
var vm = globalObject.bunVM();
switch (this.kind) {
.setTimeout, .setImmediate, .setInterval => {
if (vm.timer.maps.get(this.kind).getPtr(this.id)) |val_| {
if (val_.*) |*val| {
val.poll_ref.unref(vm);
if (!val.did_unref_timer) {
val.did_unref_timer = true;
vm.uws_event_loop.?.num_polls -= 1;
}
}
}
},
}
return JSValue.jsUndefined();
return this_value;
}
pub fn hasRef(this: *TimerObject, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
return JSValue.jsBoolean(this.ref_count > 0 and globalObject.bunVM().timer.maps.get(this.kind).contains(this.id));
@@ -3954,6 +3996,7 @@ pub const Timer = struct {
callback: JSC.Strong = .{},
globalThis: *JSC.JSGlobalObject,
timer: *uws.Timer,
did_unref_timer: bool = false,
poll_ref: JSC.PollRef = JSC.PollRef.init(),
arguments: JSC.Strong = .{},
@@ -4055,8 +4098,14 @@ pub const Timer = struct {
var vm = this.globalThis.bunVM();
this.poll_ref.unrefOnNextTick(vm);
this.poll_ref.unref(vm);
this.timer.deinit();
if (this.did_unref_timer) {
// balance double-unrefing
vm.uws_event_loop.?.num_polls += 1;
}
this.callback.deinit();
this.arguments.deinit();
}

View File

@@ -1925,8 +1925,8 @@ pub const DNSResolver = struct {
.err => |err| {
const system_error = JSC.SystemError{
.errno = -1,
.code = JSC.ZigString.init(err.code()),
.message = JSC.ZigString.init(err.label()),
.code = bun.String.static(err.code()),
.message = bun.String.static(err.label()),
};
globalThis.throwValue(system_error.toErrorInstance(globalThis));
@@ -1972,8 +1972,8 @@ pub const DNSResolver = struct {
.err => |err| {
const system_error = JSC.SystemError{
.errno = -1,
.code = JSC.ZigString.init(err.code()),
.message = JSC.ZigString.init(err.label()),
.code = bun.String.static(err.code()),
.message = bun.String.static(err.label()),
};
globalThis.throwValue(system_error.toErrorInstance(globalThis));

View File

@@ -69,6 +69,11 @@ fn normalizeHost(input: anytype) @TypeOf(input) {
const BinaryType = JSC.BinaryType;
const WrappedType = enum {
none,
tls,
tcp,
};
const Handlers = struct {
onOpen: JSC.JSValue = .zero,
onClose: JSC.JSValue = .zero,
@@ -97,8 +102,8 @@ const Handlers = struct {
handlers: *Handlers,
socket_context: *uws.SocketContext,
pub fn exit(this: *Scope, ssl: bool) void {
this.handlers.markInactive(ssl, this.socket_context);
pub fn exit(this: *Scope, ssl: bool, wrapped: WrappedType) void {
this.handlers.markInactive(ssl, this.socket_context, wrapped);
}
};
@@ -123,19 +128,24 @@ const Handlers = struct {
return true;
}
pub fn markInactive(this: *Handlers, ssl: bool, ctx: *uws.SocketContext) void {
pub fn markInactive(this: *Handlers, ssl: bool, ctx: *uws.SocketContext, wrapped: WrappedType) void {
Listener.log("markInactive", .{});
this.active_connections -= 1;
if (this.active_connections == 0 and this.is_server) {
var listen_socket: *Listener = @fieldParentPtr(Listener, "handlers", this);
// allow it to be GC'd once the last connection is closed and it's not listening anymore
if (listen_socket.listener == null) {
listen_socket.strong_self.clear();
if (this.active_connections == 0) {
if (this.is_server) {
var listen_socket: *Listener = @fieldParentPtr(Listener, "handlers", this);
// allow it to be GC'd once the last connection is closed and it's not listening anymore
if (listen_socket.listener == null) {
listen_socket.strong_self.clear();
}
} else {
this.unprotect();
// will deinit when is not wrapped or when is the TCP wrapped connection
if (wrapped != .tls) {
ctx.deinit(ssl);
}
bun.default_allocator.destroy(this);
}
} else if (this.active_connections == 0 and !this.is_server) {
this.unprotect();
ctx.deinit(ssl);
bun.default_allocator.destroy(this);
}
}
@@ -364,6 +374,7 @@ pub const Listener = struct {
connection: UnixOrHost,
socket_context: ?*uws.SocketContext = null,
ssl: bool = false,
protos: ?[]const u8 = null,
strong_data: JSC.Strong = .{},
strong_self: JSC.Strong = .{},
@@ -395,6 +406,19 @@ pub const Listener = struct {
port: u16,
},
pub fn clone(this: UnixOrHost) UnixOrHost {
switch (this) {
.unix => |u| {
return .{
.unix = (bun.default_allocator.dupe(u8, u) catch unreachable),
};
},
.host => |h| {
return .{ .host = .{ .host = (bun.default_allocator.dupe(u8, h.host) catch unreachable), .port = this.host.port } };
},
}
}
pub fn deinit(this: UnixOrHost) void {
switch (this) {
.unix => |u| {
@@ -455,10 +479,12 @@ pub const Listener = struct {
var socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
return .zero;
};
var hostname_or_unix = socket_config.hostname_or_unix;
var port = socket_config.port;
var ssl = socket_config.ssl;
var handlers = socket_config.handlers;
var protos: ?[]const u8 = null;
const exclusive = socket_config.exclusive;
handlers.is_server = true;
@@ -496,6 +522,10 @@ pub const Listener = struct {
};
if (ssl_enabled) {
if (ssl.?.protos) |p| {
protos = p[0..ssl.?.protos_len];
}
uws.NewSocketHandler(true).configure(
socket_context,
true,
@@ -593,6 +623,7 @@ pub const Listener = struct {
.ssl = ssl_enabled,
.socket_context = socket_context,
.listener = listen_socket,
.protos = if (protos) |p| (bun.default_allocator.dupe(u8, p) catch unreachable) else null,
};
socket.handlers.protect();
@@ -649,6 +680,8 @@ pub const Listener = struct {
.handlers = &listener.handlers,
.this_value = .zero,
.socket = socket,
.protos = listener.protos,
.owned_protos = false,
};
if (listener.strong_data.get()) |default_data| {
const globalObject = listener.handlers.globalObject;
@@ -715,6 +748,10 @@ pub const Listener = struct {
this.handlers.unprotect();
this.connection.deinit();
if (this.protos) |protos| {
this.protos = null;
bun.default_allocator.destroy(protos);
}
bun.default_allocator.destroy(this);
}
@@ -775,13 +812,17 @@ pub const Listener = struct {
const socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
return .zero;
};
var hostname_or_unix = socket_config.hostname_or_unix;
var port = socket_config.port;
var ssl = socket_config.ssl;
var handlers = socket_config.handlers;
var default_data = socket_config.default_data;
var protos: ?[]const u8 = null;
var server_name: ?[]const u8 = null;
const ssl_enabled = ssl != null;
defer if (ssl != null) ssl.?.deinit();
handlers.protect();
@@ -797,6 +838,12 @@ pub const Listener = struct {
};
if (ssl_enabled) {
if (ssl.?.protos) |p| {
protos = p[0..ssl.?.protos_len];
}
if (ssl.?.server_name) |s| {
server_name = bun.default_allocator.dupe(u8, s[0..bun.len(s)]) catch unreachable;
}
uws.NewSocketHandler(true).configure(
socket_context,
true,
@@ -848,6 +895,8 @@ pub const Listener = struct {
.this_value = .zero,
.socket = undefined,
.connection = connection,
.protos = if (protos) |p| (bun.default_allocator.dupe(u8, p) catch unreachable) else null,
.server_name = server_name,
};
TLSSocket.dataSetCached(tls.getThisValue(globalObject), globalObject, default_data);
@@ -871,6 +920,8 @@ pub const Listener = struct {
.this_value = .zero,
.socket = undefined,
.connection = null,
.protos = null,
.server_name = null,
};
TCPSocket.dataSetCached(tcp.getThisValue(globalObject), globalObject, default_data);
@@ -898,11 +949,41 @@ fn JSSocketType(comptime ssl: bool) type {
}
}
fn selectALPNCallback(
_: ?*BoringSSL.SSL,
out: [*c][*c]const u8,
outlen: [*c]u8,
in: [*c]const u8,
inlen: c_uint,
arg: ?*anyopaque,
) callconv(.C) c_int {
const this = bun.cast(*TLSSocket, arg);
if (this.protos) |protos| {
if (protos.len == 0) {
return BoringSSL.SSL_TLSEXT_ERR_NOACK;
}
const status = BoringSSL.SSL_select_next_proto(bun.cast([*c][*c]u8, out), outlen, protos.ptr, @intCast(c_uint, protos.len), in, inlen);
// Previous versions of Node.js returned SSL_TLSEXT_ERR_NOACK if no protocol
// match was found. This would neither cause a fatal alert nor would it result
// in a useful ALPN response as part of the Server Hello message.
// We now return SSL_TLSEXT_ERR_ALERT_FATAL in that case as per Section 3.2
// of RFC 7301, which causes a fatal no_application_protocol alert.
const expected = if (comptime BoringSSL.OPENSSL_NPN_NEGOTIATED == 1) BoringSSL.SSL_TLSEXT_ERR_OK else BoringSSL.SSL_TLSEXT_ERR_ALERT_FATAL;
return if (status == expected) 1 else 0;
} else {
return BoringSSL.SSL_TLSEXT_ERR_NOACK;
}
}
fn NewSocket(comptime ssl: bool) type {
return struct {
pub const Socket = uws.NewSocketHandler(ssl);
socket: Socket,
detached: bool = false,
wrapped: WrappedType = .none,
handlers: *Handlers,
this_value: JSC.JSValue = .zero,
poll_ref: JSC.PollRef = JSC.PollRef.init(),
@@ -910,6 +991,9 @@ fn NewSocket(comptime ssl: bool) type {
last_4: [4]u8 = .{ 0, 0, 0, 0 },
authorized: bool = false,
connection: ?Listener.UnixOrHost = null,
protos: ?[]const u8,
owned_protos: bool = true,
server_name: ?[]const u8 = null,
// TODO: switch to something that uses `visitAggregate` and have the
// `Listener` keep a list of all the sockets JSValue in there
@@ -1022,8 +1106,8 @@ fn NewSocket(comptime ssl: bool) type {
var globalObject = handlers.globalObject;
const err = JSC.SystemError{
.errno = errno,
.message = ZigString.init("Failed to connect"),
.syscall = ZigString.init("connect"),
.message = bun.String.static("Failed to connect"),
.syscall = bun.String.static("connect"),
};
if (callback == .zero) {
@@ -1079,7 +1163,7 @@ fn NewSocket(comptime ssl: bool) type {
var vm = this.handlers.vm;
this.reffer.unref(vm);
this.handlers.markInactive(ssl, this.socket.context());
this.handlers.markInactive(ssl, this.socket.context(), this.wrapped);
this.poll_ref.unref(vm);
this.has_pending_activity.store(false, .Release);
}
@@ -1091,25 +1175,42 @@ fn NewSocket(comptime ssl: bool) type {
// Add SNI support for TLS (mongodb and others requires this)
if (comptime ssl) {
if (this.connection) |connection| {
if (connection == .host) {
const host = normalizeHost(connection.host.host);
var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, socket.getNativeHandle());
if (!ssl_ptr.isInitFinished()) {
if (this.server_name) |server_name| {
const host = normalizeHost(server_name);
if (host.len > 0) {
var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, socket.getNativeHandle());
if (!ssl_ptr.isInitFinished()) {
var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
defer default_allocator.free(host__);
ssl_ptr.setHostname(host__);
}
} else if (this.connection) |connection| {
if (connection == .host) {
const host = normalizeHost(connection.host.host);
if (host.len > 0) {
var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
defer default_allocator.free(host__);
ssl_ptr.setHostname(host__);
}
}
}
if (this.protos) |protos| {
if (this.handlers.is_server) {
BoringSSL.SSL_CTX_set_alpn_select_cb(BoringSSL.SSL_get_SSL_CTX(ssl_ptr), selectALPNCallback, bun.cast(*anyopaque, this));
} else {
_ = BoringSSL.SSL_set_alpn_protos(ssl_ptr, protos.ptr, @intCast(c_uint, protos.len));
}
}
}
}
this.poll_ref.ref(this.handlers.vm);
this.detached = false;
this.socket = socket;
socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this);
if (this.wrapped == .none) {
socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this);
}
const handlers = this.handlers;
const callback = handlers.onOpen;
@@ -1161,6 +1262,8 @@ fn NewSocket(comptime ssl: bool) type {
pub fn onEnd(this: *This, socket: Socket) void {
JSC.markBinding(@src());
log("onEnd", .{});
if (this.detached) return;
this.detached = true;
defer this.markInactive();
@@ -1174,7 +1277,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
defer scope.exit(ssl);
defer scope.exit(ssl, this.wrapped);
const globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1211,7 +1314,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
defer scope.exit(ssl);
defer scope.exit(ssl, this.wrapped);
const globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1232,8 +1335,8 @@ fn NewSocket(comptime ssl: bool) type {
const reason = if (ssl_error.reason == null) "" else ssl_error.reason[0..bun.len(ssl_error.reason)];
const fallback = JSC.SystemError{
.code = ZigString.init(code),
.message = ZigString.init(reason),
.code = bun.String.create(code),
.message = bun.String.create(reason),
};
authorization_error = fallback.toErrorInstance(globalObject);
@@ -1255,7 +1358,6 @@ fn NewSocket(comptime ssl: bool) type {
log("onClose", .{});
this.detached = true;
defer this.markInactive();
const handlers = this.handlers;
this.poll_ref.unref(handlers.vm);
@@ -1265,7 +1367,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
defer scope.exit(ssl);
defer scope.exit(ssl, this.wrapped);
var globalObject = handlers.globalObject;
const this_value = this.getThisValue(globalObject);
@@ -1295,7 +1397,7 @@ fn NewSocket(comptime ssl: bool) type {
// the handlers must be kept alive for the duration of the function call
// that way if we need to call the error handler, we can
var scope = handlers.enter(socket.context());
defer scope.exit(ssl);
defer scope.exit(ssl, this.wrapped);
// const encoding = handlers.encoding;
const result = callback.callWithThis(globalObject, this_value, &[_]JSValue{
@@ -1409,8 +1511,8 @@ fn NewSocket(comptime ssl: bool) type {
const reason = if (ssl_error.reason == null) "" else ssl_error.reason[0..bun.len(ssl_error.reason)];
const fallback = JSC.SystemError{
.code = ZigString.init(code),
.message = ZigString.init(reason),
.code = bun.String.create(code),
.message = bun.String.create(reason),
};
return fallback.toErrorInstance(globalObject);
@@ -1476,10 +1578,20 @@ fn NewSocket(comptime ssl: bool) type {
}
fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
if (this.socket.isShutdown() or this.socket.isClosed()) {
if (this.detached or this.socket.isShutdown() or this.socket.isClosed()) {
return -1;
}
// we don't cork yet but we might later
if (comptime ssl) {
// TLS wrapped but in TCP mode
if (this.wrapped == .tcp) {
const res = this.socket.rawWrite(buffer, is_end);
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
}
}
const res = this.socket.write(buffer, is_end);
log("write({d}, {any}) = {d}", .{ buffer.len, is_end, res });
return res;
@@ -1487,7 +1599,6 @@ fn NewSocket(comptime ssl: bool) type {
fn writeOrEnd(this: *This, globalObject: *JSC.JSGlobalObject, args: []const JSC.JSValue, is_end: bool) WriteResult {
if (args.len == 0) return .{ .success = .{} };
if (args.ptr[0].asArrayBuffer(globalObject)) |array_buffer| {
var slice = array_buffer.slice();
@@ -1681,9 +1792,6 @@ fn NewSocket(comptime ssl: bool) type {
if (result.wrote == result.total) {
this.socket.flush();
this.detached = true;
if (!this.socket.isClosed()) {
this.socket.close(0, null);
}
this.markInactive();
}
break :brk JSValue.jsNumber(result.wrote);
@@ -1706,17 +1814,32 @@ fn NewSocket(comptime ssl: bool) type {
pub fn finalize(this: *This) callconv(.C) void {
log("finalize()", .{});
if (this.detached) return;
this.detached = true;
if (!this.socket.isClosed()) {
this.socket.close(0, null);
if (!this.detached) {
this.detached = true;
if (!this.socket.isClosed()) {
this.socket.close(0, null);
}
this.markInactive();
}
if (this.connection) |connection| {
connection.deinit();
this.connection = null;
}
this.markInactive();
this.poll_ref.unref(JSC.VirtualMachine.get());
// need to deinit event without being attached
if (this.owned_protos) {
if (this.protos) |protos| {
this.protos = null;
default_allocator.free(protos);
}
}
if (this.server_name) |server_name| {
this.server_name = null;
default_allocator.free(server_name);
}
if (this.connection) |connection| {
this.connection = null;
connection.deinit();
}
}
pub fn reload(this: *This, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
@@ -1756,8 +1879,384 @@ fn NewSocket(comptime ssl: bool) type {
return JSValue.jsUndefined();
}
pub fn getALPNProtocol(
this: *This,
globalObject: *JSC.JSGlobalObject,
) callconv(.C) JSValue {
if (comptime ssl == false) {
return JSValue.jsBoolean(false);
}
if (this.detached) {
return JSValue.jsBoolean(false);
}
var alpn_proto: [*c]const u8 = null;
var alpn_proto_len: u32 = 0;
var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
BoringSSL.SSL_get0_alpn_selected(ssl_ptr, &alpn_proto, &alpn_proto_len);
if (alpn_proto == null or alpn_proto_len == 0) {
return JSValue.jsBoolean(false);
}
const slice = alpn_proto[0..alpn_proto_len];
if (strings.eql(slice, "h2")) {
return ZigString.static("h2").toValue(globalObject);
}
if (strings.eql(slice, "http/1.1")) {
return ZigString.static("http/1.1").toValue(globalObject);
}
return ZigString.fromUTF8(slice).toValueGC(globalObject);
}
pub fn setServername(
this: *This,
globalObject: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) JSValue {
if (comptime ssl == false) {
return JSValue.jsUndefined();
}
if (this.handlers.is_server) {
globalObject.throw("Cannot issue SNI from a TLS server-side socket", .{});
return .zero;
}
const args = callframe.arguments(1);
if (args.len < 1) {
globalObject.throw("Expected 1 argument", .{});
return .zero;
}
const server_name = args.ptr[0];
if (!server_name.isString()) {
globalObject.throw("Expected \"serverName\" to be a string", .{});
return .zero;
}
const slice = server_name.getZigString(globalObject).toOwnedSlice(bun.default_allocator) catch unreachable;
if (this.server_name) |old| {
this.server_name = slice;
default_allocator.free(old);
} else {
this.server_name = slice;
}
if (this.detached) {
// will be attached onOpen
return JSValue.jsUndefined();
}
const host = normalizeHost(@as([]const u8, slice));
if (host.len > 0) {
var ssl_ptr: *BoringSSL.SSL = @ptrCast(*BoringSSL.SSL, this.socket.getNativeHandle());
if (ssl_ptr.isInitFinished()) {
// match node.js exceptions
globalObject.throw("Already started.", .{});
return .zero;
}
var host__ = default_allocator.dupeZ(u8, host) catch unreachable;
defer default_allocator.free(host__);
ssl_ptr.setHostname(host__);
}
return JSValue.jsUndefined();
}
// this invalidates the current socket returning 2 new sockets
// one for non-TLS and another for TLS
// handlers for non-TLS are preserved
pub fn upgradeTLS(
this: *This,
globalObject: *JSC.JSGlobalObject,
callframe: *JSC.CallFrame,
) callconv(.C) JSValue {
JSC.markBinding(@src());
if (comptime ssl) {
return JSValue.jsUndefined();
}
if (this.detached) {
return JSValue.jsUndefined();
}
const args = callframe.arguments(1);
if (args.len < 1) {
globalObject.throw("Expected 1 arguments", .{});
return .zero;
}
var exception: JSC.C.JSValueRef = null;
const opts = args.ptr[0];
if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
globalObject.throw("Expected options object", .{});
return .zero;
}
var socket_obj = opts.get(globalObject, "socket") orelse {
globalObject.throw("Expected \"socket\" option", .{});
return .zero;
};
var handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse {
globalObject.throwValue(exception.?.value());
return .zero;
};
var ssl_opts: ?JSC.API.ServerConfig.SSLConfig = null;
if (opts.getTruthy(globalObject, "tls")) |tls| {
if (tls.isBoolean()) {
if (tls.toBoolean()) {
ssl_opts = JSC.API.ServerConfig.SSLConfig.zero;
}
} else {
if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, tls, &exception)) |ssl_config| {
ssl_opts = ssl_config;
} else if (exception != null) {
return .zero;
}
}
}
if (ssl_opts == null) {
globalObject.throw("Expected \"tls\" option", .{});
return .zero;
}
var default_data = JSValue.zero;
if (opts.getTruthy(globalObject, "data")) |default_data_value| {
default_data = default_data_value;
default_data.ensureStillAlive();
}
var socket_config = ssl_opts.?;
defer socket_config.deinit();
const options = socket_config.asUSockets();
const protos = socket_config.protos;
const protos_len = socket_config.protos_len;
const ext_size = @sizeOf(WrappedSocket);
const is_server = this.handlers.is_server;
var tls = handlers.vm.allocator.create(TLSSocket) catch @panic("OOM");
var handlers_ptr = handlers.vm.allocator.create(Handlers) catch @panic("OOM");
handlers_ptr.* = handlers;
handlers_ptr.is_server = is_server;
handlers_ptr.protect();
tls.* = .{
.handlers = handlers_ptr,
.this_value = .zero,
.socket = undefined,
.connection = if (this.connection) |c| c.clone() else null,
.wrapped = .tls,
.protos = if (protos) |p| (bun.default_allocator.dupe(u8, p[0..protos_len]) catch unreachable) else null,
.server_name = if (socket_config.server_name) |server_name| (bun.default_allocator.dupe(u8, server_name[0..bun.len(server_name)]) catch unreachable) else null,
};
var tls_js_value = tls.getThisValue(globalObject);
TLSSocket.dataSetCached(tls_js_value, globalObject, default_data);
const TCPHandler = NewWrappedHandler(false);
// reconfigure context to use the new wrapper handlers
Socket.unsafeConfigure(this.socket.context(), true, true, WrappedSocket, TCPHandler);
const old_context = this.socket.context();
const TLSHandler = NewWrappedHandler(true);
const new_socket = this.socket.wrapTLS(
options,
ext_size,
true,
WrappedSocket,
TLSHandler,
) orelse {
handlers_ptr.unprotect();
handlers.vm.allocator.destroy(handlers_ptr);
bun.default_allocator.destroy(tls);
return JSValue.jsUndefined();
};
tls.socket = new_socket;
var raw = handlers.vm.allocator.create(TLSSocket) catch @panic("OOM");
var raw_handlers_ptr = handlers.vm.allocator.create(Handlers) catch @panic("OOM");
raw_handlers_ptr.* = .{
.vm = globalObject.bunVM(),
.globalObject = globalObject,
.onOpen = this.handlers.onOpen,
.onClose = this.handlers.onClose,
.onData = this.handlers.onData,
.onWritable = this.handlers.onWritable,
.onTimeout = this.handlers.onTimeout,
.onConnectError = this.handlers.onConnectError,
.onEnd = this.handlers.onEnd,
.onError = this.handlers.onError,
.onHandshake = this.handlers.onHandshake,
.binary_type = this.handlers.binary_type,
.is_server = is_server,
};
this.handlers.onOpen = .zero;
this.handlers.onClose = .zero;
this.handlers.onData = .zero;
this.handlers.onWritable = .zero;
this.handlers.onTimeout = .zero;
this.handlers.onConnectError = .zero;
this.handlers.onEnd = .zero;
this.handlers.onError = .zero;
this.handlers.onHandshake = .zero;
raw.* = .{
.handlers = raw_handlers_ptr,
.this_value = .zero,
.socket = new_socket,
.connection = if (this.connection) |c| c.clone() else null,
.wrapped = .tcp,
.protos = null,
};
var raw_js_value = raw.getThisValue(globalObject);
if (JSSocketType(ssl).dataGetCached(this.getThisValue(globalObject))) |raw_default_data| {
raw_default_data.ensureStillAlive();
TLSSocket.dataSetCached(raw_js_value, globalObject, raw_default_data);
}
// marks both as active
raw.markActive();
// this will keep tls alive until socket.open() is called to start TLS certificate and the handshake process
// open is not immediately called because we need to set bunSocketInternal
tls.markActive();
// mark both instances on socket data
new_socket.ext(WrappedSocket).?.* = .{ .tcp = raw, .tls = tls };
// start TLS handshake after we set ext
new_socket.startTLS(!this.handlers.is_server);
//detach and invalidate the old instance
this.detached = true;
if (this.reffer.has) {
var vm = this.handlers.vm;
this.reffer.unref(vm);
old_context.deinit(ssl);
bun.default_allocator.destroy(this.handlers);
this.poll_ref.unref(vm);
this.has_pending_activity.store(false, .Release);
}
const array = JSC.JSValue.createEmptyArray(globalObject, 2);
array.putIndex(globalObject, 0, raw_js_value);
array.putIndex(globalObject, 1, tls_js_value);
return array;
}
};
}
pub const TCPSocket = NewSocket(false);
pub const TLSSocket = NewSocket(true);
pub const WrappedSocket = extern struct {
// both shares the same socket but one behaves as TLS and the other as TCP
tls: *TLSSocket,
tcp: *TLSSocket,
};
pub fn NewWrappedHandler(comptime tls: bool) type {
const Socket = uws.NewSocketHandler(true);
return struct {
pub fn onOpen(
this: WrappedSocket,
socket: Socket,
) void {
// only TLS will call onOpen
if (comptime tls) {
TLSSocket.onOpen(this.tls, socket);
}
}
pub fn onEnd(
this: WrappedSocket,
socket: Socket,
) void {
if (comptime tls) {
TLSSocket.onEnd(this.tls, socket);
} else {
TLSSocket.onEnd(this.tcp, socket);
}
}
pub fn onHandshake(
this: WrappedSocket,
socket: Socket,
success: i32,
ssl_error: uws.us_bun_verify_error_t,
) void {
// only TLS will call onHandshake
if (comptime tls) {
TLSSocket.onHandshake(this.tls, socket, success, ssl_error);
}
}
pub fn onClose(
this: WrappedSocket,
socket: Socket,
err: c_int,
data: ?*anyopaque,
) void {
if (comptime tls) {
TLSSocket.onClose(this.tls, socket, err, data);
} else {
TLSSocket.onClose(this.tcp, socket, err, data);
}
}
pub fn onData(
this: WrappedSocket,
socket: Socket,
data: []const u8,
) void {
if (comptime tls) {
TLSSocket.onData(this.tls, socket, data);
} else {
TLSSocket.onData(this.tcp, socket, data);
}
}
pub fn onWritable(
this: WrappedSocket,
socket: Socket,
) void {
if (comptime tls) {
TLSSocket.onWritable(this.tls, socket);
} else {
TLSSocket.onWritable(this.tcp, socket);
}
}
pub fn onTimeout(
this: WrappedSocket,
socket: Socket,
) void {
if (comptime tls) {
TLSSocket.onTimeout(this.tls, socket);
} else {
TLSSocket.onTimeout(this.tcp, socket);
}
}
pub fn onConnectError(
this: WrappedSocket,
socket: Socket,
errno: c_int,
) void {
if (comptime tls) {
TLSSocket.onConnectError(this.tls, socket, errno);
} else {
TLSSocket.onConnectError(this.tcp, socket, errno);
}
}
};
}

View File

@@ -311,9 +311,9 @@ pub const FFI = struct {
break :brk std.DynLib.open(backup_name) catch {
// Then, if that fails, report an error.
const system_error = JSC.SystemError{
.code = ZigString.init(@tagName(JSC.Node.ErrorCode.ERR_DLOPEN_FAILED)),
.message = ZigString.init("Failed to open library. This is usually caused by a missing library or an invalid library path."),
.syscall = ZigString.init("dlopen"),
.code = bun.String.create(@tagName(JSC.Node.ErrorCode.ERR_DLOPEN_FAILED)),
.message = bun.String.create("Failed to open library. This is usually caused by a missing library or an invalid library path."),
.syscall = bun.String.create("dlopen"),
};
return system_error.toErrorInstance(global);
};

View File

@@ -106,7 +106,7 @@ pub const HTMLRewriter = struct {
var selector = LOLHTML.HTMLSelector.parse(selector_slice) catch
return throwLOLHTMLError(global);
var handler_ = ElementHandler.init(global, listener, exception);
var handler_ = ElementHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
selector.deinit();
return JSValue.fromRef(exception.*);
@@ -154,7 +154,7 @@ pub const HTMLRewriter = struct {
thisObject: JSC.C.JSObjectRef,
exception: JSC.C.ExceptionRef,
) JSValue {
var handler_ = DocumentHandler.init(global, listener, exception);
var handler_ = DocumentHandler.init(global, listener, exception) catch return .zero;
if (exception.* != null) {
return JSValue.fromRef(exception.*);
}
@@ -446,10 +446,14 @@ pub const HTMLRewriter = struct {
},
};
result.body.init.headers = original.body.init.headers;
result.body.init.method = original.body.init.method;
result.body.init.status_code = original.body.init.status_code;
// https://github.com/oven-sh/bun/issues/3334
if (original.body.init.headers) |headers| {
result.body.init.headers = headers.cloneThis(global);
}
result.url = bun.default_allocator.dupe(u8, original.url) catch unreachable;
result.status_text = bun.default_allocator.dupe(u8, original.status_text) catch unreachable;
@@ -723,29 +727,44 @@ const DocumentHandler = struct {
"onEndCallback",
);
pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) DocumentHandler {
pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !DocumentHandler {
var handler = DocumentHandler{
.thisObject = thisObject,
.global = global,
};
switch (thisObject.jsType()) {
.Object, .ProxyObject, .Cell, .FinalObject => {},
else => |kind| {
JSC.throwInvalidArguments(
"Expected object but received {s}",
.{@as(string, @tagName(kind))},
global,
exception,
);
return undefined;
},
if (!thisObject.isObject()) {
JSC.throwInvalidArguments(
"Expected object",
.{},
global,
exception,
);
return error.InvalidArguments;
}
errdefer {
if (handler.onDocTypeCallback) |cb| {
cb.unprotect();
}
if (handler.onCommentCallback) |cb| {
cb.unprotect();
}
if (handler.onTextCallback) |cb| {
cb.unprotect();
}
if (handler.onEndCallback) |cb| {
cb.unprotect();
}
}
if (thisObject.get(global, "doctype")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("doctype must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onDocTypeCallback = val;
@@ -754,7 +773,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -763,7 +782,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -772,7 +791,7 @@ const DocumentHandler = struct {
if (thisObject.get(global, "end")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("end must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onEndCallback = val;
@@ -863,29 +882,39 @@ const ElementHandler = struct {
global: *JSGlobalObject,
ctx: ?*HTMLRewriter.BufferOutputSink = null,
pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) ElementHandler {
pub fn init(global: *JSGlobalObject, thisObject: JSValue, exception: JSC.C.ExceptionRef) !ElementHandler {
var handler = ElementHandler{
.thisObject = thisObject,
.global = global,
};
errdefer {
if (handler.onCommentCallback) |cb| {
cb.unprotect();
}
switch (thisObject.jsType()) {
.Object, .ProxyObject, .Cell, .FinalObject => {},
else => |kind| {
JSC.throwInvalidArguments(
"Expected object but received {s}",
.{@as(string, @tagName(kind))},
global,
exception,
);
return undefined;
},
if (handler.onElementCallback) |cb| {
cb.unprotect();
}
if (handler.onTextCallback) |cb| {
cb.unprotect();
}
}
if (!thisObject.isObject()) {
JSC.throwInvalidArguments(
"Expected object",
.{},
global,
exception,
);
return error.InvalidArguments;
}
if (thisObject.get(global, "element")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("element must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onElementCallback = val;
@@ -894,7 +923,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "comments")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("comments must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onCommentCallback = val;
@@ -903,7 +932,7 @@ const ElementHandler = struct {
if (thisObject.get(global, "text")) |val| {
if (val.isUndefinedOrNull() or !val.isCell() or !val.isCallable(global.vm())) {
JSC.throwInvalidArguments("text must be a function", .{}, global, exception);
return undefined;
return error.InvalidArguments;
}
JSC.C.JSValueProtect(global, val.asObjectRef());
handler.onTextCallback = val;
@@ -967,26 +996,14 @@ const getterWrap = JSC.getterWrap;
const setterWrap = JSC.setterWrap;
const wrap = JSC.wrapSync;
pub fn free_html_writer_string(_: ?*anyopaque, ptr: ?*anyopaque, len: usize) callconv(.C) void {
var str = LOLHTML.HTMLString{ .ptr = bun.cast([*]const u8, ptr.?), .len = len };
str.deinit();
}
fn throwLOLHTMLError(global: *JSGlobalObject) JSValue {
var err = LOLHTML.HTMLString.lastError();
return ZigString.init(err.slice()).toErrorInstance(global);
const err = LOLHTML.HTMLString.lastError();
defer err.deinit();
return ZigString.fromUTF8(err.slice()).toErrorInstance(global);
}
fn htmlStringValue(input: LOLHTML.HTMLString, globalObject: *JSGlobalObject) JSValue {
var str = ZigString.init(
input.slice(),
);
str.detectEncoding();
return str.toExternalValueWithCallback(
globalObject,
free_html_writer_string,
);
return input.toJS(globalObject);
}
pub const TextChunk = struct {
@@ -1016,6 +1033,9 @@ pub const TextChunk = struct {
.removed = .{
.get = getterWrap(TextChunk, "removed"),
},
.lastInTextNode = .{
.get = getterWrap(TextChunk, "lastInTextNode"),
},
.text = .{
.get = getterWrap(TextChunk, "getText"),
},
@@ -1084,6 +1104,10 @@ pub const TextChunk = struct {
return JSC.JSValue.jsBoolean(this.text_chunk.?.isRemoved());
}
pub fn lastInTextNode(this: *TextChunk, _: *JSGlobalObject) JSValue {
return JSC.JSValue.jsBoolean(this.text_chunk.?.isLastInTextNode());
}
pub fn finalize(this: *TextChunk) void {
this.text_chunk = null;
bun.default_allocator.destroy(this);
@@ -1292,7 +1316,7 @@ pub const Comment = struct {
pub fn getText(this: *Comment, global: *JSGlobalObject) JSValue {
if (this.comment == null)
return JSValue.jsNull();
return ZigString.init(this.comment.?.getText().slice()).withEncoding().toValueGC(global);
return this.comment.?.getText().toJS(global);
}
pub fn setText(
@@ -1422,7 +1446,7 @@ pub const EndTag = struct {
if (this.end_tag == null)
return JSC.JSValue.jsUndefined();
return ZigString.init(this.end_tag.?.getName().slice()).withEncoding().toValueGC(global);
return this.end_tag.?.getName().toJS(global);
}
pub fn setName(
@@ -1534,27 +1558,16 @@ pub const AttributeIterator = struct {
return JSC.JSValue.jsNull();
};
// TODO: don't clone here
const value = attribute.value();
const name = attribute.name();
defer name.deinit();
defer value.deinit();
var strs = [2]ZigString{
ZigString.init(name.slice()),
ZigString.init(value.slice()),
};
var valid_strs: []ZigString = strs[0..2];
var array = JSC.JSValue.createStringArray(
return bun.String.toJSArray(
globalObject,
valid_strs.ptr,
valid_strs.len,
true,
&[_]bun.String{
name.toString(),
value.toString(),
},
);
return array;
}
};
pub const Element = struct {
@@ -1660,19 +1673,12 @@ pub const Element = struct {
var slice = name.toSlice(bun.default_allocator);
defer slice.deinit();
var attr = this.element.?.getAttribute(slice.slice()).slice();
var attr = this.element.?.getAttribute(slice.slice());
if (attr.len == 0)
return JSC.JSValue.jsNull();
var str = ZigString.init(
attr,
);
return str.toExternalValueWithCallback(
globalObject,
free_html_writer_string,
);
return attr.toJS(globalObject);
}
/// Returns a boolean indicating whether an attribute exists on the element.
@@ -1847,8 +1853,9 @@ pub const Element = struct {
pub fn getNamespaceURI(this: *Element, globalObject: *JSGlobalObject) JSValue {
if (this.element == null)
return JSValue.jsUndefined();
return ZigString.init(std.mem.span(this.element.?.namespaceURI())).toValueGC(globalObject);
var str = bun.String.create(std.mem.span(this.element.?.namespaceURI()));
defer str.deref();
return str.toJS(globalObject);
}
pub fn getAttributes(this: *Element, globalObject: *JSGlobalObject) JSValue {

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,17 @@ function generate(ssl) {
authorized: {
getter: "getAuthorized",
},
alpnProtocol: {
getter: "getALPNProtocol",
},
write: {
fn: "write",
length: 3,
},
upgradeTLS: {
fn: "upgradeTLS",
length: 1,
},
end: {
fn: "end",
length: 3,
@@ -82,6 +89,11 @@ function generate(ssl) {
fn: "reload",
length: 1,
},
setServername: {
fn: "setServername",
length: 1,
},
},
finalize: true,
construct: true,

View File

@@ -86,31 +86,69 @@ BunString toString(JSC::JSGlobalObject* globalObject, JSValue value)
return fromJS(globalObject, value);
}
BunString toStringRef(JSC::JSGlobalObject* globalObject, JSValue value)
{
auto str = value.toWTFString(globalObject);
if (str.isEmpty()) {
return { BunStringTag::Empty };
}
str.impl()->ref();
return { BunStringTag::WTFStringImpl, { .wtf = str.impl() } };
}
BunString toString(WTF::String& wtfString)
{
if (wtfString.length() == 0)
if (wtfString.isEmpty())
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toString(const WTF::String& wtfString)
{
if (wtfString.length() == 0)
if (wtfString.isEmpty())
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toString(WTF::StringImpl* wtfString)
{
if (wtfString->length() == 0)
if (wtfString->isEmpty())
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
}
BunString toStringRef(WTF::String& wtfString)
{
if (wtfString.isEmpty())
return { BunStringTag::Empty };
wtfString.impl()->ref();
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toStringRef(const WTF::String& wtfString)
{
if (wtfString.isEmpty())
return { BunStringTag::Empty };
wtfString.impl()->ref();
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
}
BunString toStringRef(WTF::StringImpl* wtfString)
{
if (wtfString->isEmpty())
return { BunStringTag::Empty };
wtfString->ref();
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
}
BunString fromString(WTF::String& wtfString)
{
if (wtfString.length() == 0)
if (wtfString.isEmpty())
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString.impl() } };
@@ -118,7 +156,7 @@ BunString fromString(WTF::String& wtfString)
BunString fromString(WTF::StringImpl* wtfString)
{
if (wtfString->length() == 0)
if (wtfString->isEmpty())
return { BunStringTag::Empty };
return { BunStringTag::WTFStringImpl, { .wtf = wtfString } };
@@ -131,6 +169,29 @@ extern "C" JSC::EncodedJSValue BunString__toJS(JSC::JSGlobalObject* globalObject
return JSValue::encode(Bun::toJS(globalObject, *bunString));
}
extern "C" BunString BunString__fromUTF16Unitialized(size_t length)
{
unsigned utf16Length = length;
UChar* ptr;
auto impl = WTF::StringImpl::createUninitialized(utf16Length, ptr);
if (UNLIKELY(!ptr))
return { BunStringTag::Dead };
impl->ref();
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
}
extern "C" BunString BunString__fromLatin1Unitialized(size_t length)
{
unsigned latin1Length = length;
LChar* ptr;
auto impl = WTF::StringImpl::createUninitialized(latin1Length, ptr);
if (UNLIKELY(!ptr))
return { BunStringTag::Dead };
impl->ref();
return { BunStringTag::WTFStringImpl, { .wtf = &impl.leakRef() } };
}
extern "C" BunString BunString__fromUTF8(const char* bytes, size_t length)
{
if (simdutf::validate_utf8(bytes, length)) {

View File

@@ -295,6 +295,35 @@ JSC_DEFINE_CUSTOM_SETTER(setterPath,
return true;
}
extern "C" EncodedJSValue Resolver__propForRequireMainPaths(JSGlobalObject*);
JSC_DEFINE_CUSTOM_GETTER(getterPaths, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (UNLIKELY(!thisObject)) {
return JSValue::encode(jsUndefined());
}
if (!thisObject->m_paths) {
JSValue paths = JSValue::decode(Resolver__propForRequireMainPaths(globalObject));
thisObject->m_paths.set(globalObject->vm(), thisObject, paths);
}
return JSValue::encode(thisObject->m_paths.get());
}
JSC_DEFINE_CUSTOM_SETTER(setterPaths,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
{
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(JSValue::decode(thisValue));
if (!thisObject)
return false;
thisObject->m_paths.set(globalObject->vm(), thisObject, JSValue::decode(value));
return true;
}
JSC_DEFINE_CUSTOM_SETTER(setterFilename,
(JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue,
JSC::EncodedJSValue value, JSC::PropertyName propertyName))
@@ -340,6 +369,7 @@ static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = {
{ "loaded"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createLoaded } },
{ "parent"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createParent } },
{ "path"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPath, setterPath } },
{ "paths"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPaths, setterPaths } },
};
class JSCommonJSModulePrototype final : public JSC::JSNonFinalObject {
@@ -556,13 +586,41 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject,
auto result = this->exportsObject();
auto& vm = globalObject->vm();
exportNames.append(vm.propertyNames->defaultKeyword);
exportValues.append(result);
// This exists to tell ImportMetaObject.ts that this is a CommonJS module.
exportNames.append(Identifier::fromUid(vm.symbolRegistry().symbolForKey("CommonJS"_s)));
exportValues.append(jsNumber(0));
// Bun's intepretation of the "__esModule" annotation:
//
// - If a "default" export does not exist OR the __esModule annotation is not present, then we
// set the default export to the exports object
//
// - If a "default" export also exists, then we set the default export
// to the value of it (matching Babel behavior)
//
// https://stackoverflow.com/questions/50943704/whats-the-purpose-of-object-definepropertyexports-esmodule-value-0
// https://github.com/nodejs/node/issues/40891
// https://github.com/evanw/bundler-esm-cjs-tests
// https://github.com/evanw/esbuild/issues/1591
// https://github.com/oven-sh/bun/issues/3383
//
// Note that this interpretation is slightly different
//
// - We do not ignore when "type": "module" or when the file
// extension is ".mjs". Build tools determine that based on the
// caller's behavior, but in a JS runtime, there is only one ModuleNamespaceObject.
//
// It would be possible to match the behavior at runtime, but
// it would need further engine changes which do not match the ES Module spec
//
// - We ignore the value of the annotation. We only look for the
// existence of the value being set. This is for performance reasons, but also
// this annotation is meant for tooling and the only usages of setting
// it to something that does NOT evaluate to "true" I could find were in
// unit tests of build tools. Happy to revisit this if users file an issue.
bool needsToAssignDefault = true;
if (result.isObject()) {
auto* exports = asObject(result);
@@ -571,21 +629,78 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject,
exportNames.reserveCapacity(size + 2);
exportValues.ensureCapacity(size + 2);
if (canPerformFastEnumeration(structure)) {
auto catchScope = DECLARE_CATCH_SCOPE(vm);
Identifier esModuleMarker = builtinNames(vm).__esModulePublicName();
bool hasESModuleMarker = !this->ignoreESModuleAnnotation && exports->hasProperty(globalObject, esModuleMarker);
if (catchScope.exception()) {
catchScope.clearException();
}
if (hasESModuleMarker) {
if (canPerformFastEnumeration(structure)) {
exports->structure()->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool {
auto key = entry.key();
if (key->isSymbol() || entry.attributes() & PropertyAttribute::DontEnum || key == esModuleMarker)
return true;
needsToAssignDefault = needsToAssignDefault && key != vm.propertyNames->defaultKeyword;
JSValue value = exports->getDirect(entry.offset());
exportNames.append(Identifier::fromUid(vm, key));
exportValues.append(value);
return true;
});
} else {
JSC::PropertyNameArray properties(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
exports->methodTable()->getOwnPropertyNames(exports, globalObject, properties, DontEnumPropertiesMode::Exclude);
if (catchScope.exception()) {
catchScope.clearExceptionExceptTermination();
return;
}
for (auto property : properties) {
if (UNLIKELY(property.isEmpty() || property.isNull() || property == esModuleMarker || property.isPrivateName() || property.isSymbol()))
continue;
// ignore constructor
if (property == vm.propertyNames->constructor)
continue;
JSC::PropertySlot slot(exports, PropertySlot::InternalMethodType::Get);
if (!exports->getPropertySlot(globalObject, property, slot))
continue;
exportNames.append(property);
JSValue getterResult = slot.getValue(globalObject, property);
// If it throws, we keep them in the exports list, but mark it as undefined
// This is consistent with what Node.js does.
if (catchScope.exception()) {
catchScope.clearException();
getterResult = jsUndefined();
}
exportValues.append(getterResult);
needsToAssignDefault = needsToAssignDefault && property != vm.propertyNames->defaultKeyword;
}
}
} else if (canPerformFastEnumeration(structure)) {
exports->structure()->forEachProperty(vm, [&](const PropertyTableEntry& entry) -> bool {
auto key = entry.key();
if (key->isSymbol() || key == vm.propertyNames->defaultKeyword || entry.attributes() & PropertyAttribute::DontEnum)
if (key->isSymbol() || entry.attributes() & PropertyAttribute::DontEnum || key == vm.propertyNames->defaultKeyword)
return true;
exportNames.append(Identifier::fromUid(vm, key));
JSValue value = exports->getDirect(entry.offset());
exportNames.append(Identifier::fromUid(vm, key));
exportValues.append(value);
return true;
});
} else {
auto catchScope = DECLARE_CATCH_SCOPE(vm);
JSC::PropertyNameArray properties(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
exports->methodTable()->getOwnPropertyNames(exports, globalObject, properties, DontEnumPropertiesMode::Exclude);
if (catchScope.exception()) {
@@ -594,11 +709,11 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject,
}
for (auto property : properties) {
if (UNLIKELY(property.isEmpty() || property.isNull() || property.isPrivateName() || property.isSymbol()))
if (UNLIKELY(property.isEmpty() || property.isNull() || property == vm.propertyNames->defaultKeyword || property.isPrivateName() || property.isSymbol()))
continue;
// ignore constructor
if (property == vm.propertyNames->constructor || property == vm.propertyNames->defaultKeyword)
if (property == vm.propertyNames->constructor)
continue;
JSC::PropertySlot slot(exports, PropertySlot::InternalMethodType::Get);
@@ -620,6 +735,11 @@ void JSCommonJSModule::toSyntheticSource(JSC::JSGlobalObject* globalObject,
}
}
}
if (needsToAssignDefault) {
exportNames.append(vm.propertyNames->defaultKeyword);
exportValues.append(result);
}
}
JSValue JSCommonJSModule::exportsObject()
@@ -675,6 +795,7 @@ void JSCommonJSModule::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.append(thisObject->sourceCode);
visitor.append(thisObject->m_filename);
visitor.append(thisObject->m_dirname);
visitor.append(thisObject->m_paths);
}
DEFINE_VISIT_CHILDREN(JSCommonJSModule);
@@ -696,6 +817,12 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo
WTF::String specifier = specifierValue.toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
// Special-case for "process" to just return the process object directly.
if (UNLIKELY(specifier == "process"_s || specifier == "node:process"_s)) {
jsDynamicCast<JSCommonJSModule*>(callframe->argument(1))->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0);
return JSValue::encode(globalObject->processObject());
}
WTF::String referrer = thisObject->id().toWTFString(globalObject);
RETURN_IF_EXCEPTION(throwScope, {});
@@ -728,6 +855,7 @@ bool JSCommonJSModule::evaluate(
{
auto& vm = globalObject->vm();
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program);
this->ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
JSC::SourceCode rawInputSource(
WTFMove(sourceProvider));
@@ -735,6 +863,7 @@ bool JSCommonJSModule::evaluate(
return true;
this->sourceCode.set(vm, this, JSC::JSSourceCode::create(vm, WTFMove(rawInputSource)));
WTF::NakedPtr<JSC::Exception> exception;
evaluateCommonJSModuleOnce(vm, globalObject, this, this->m_dirname.get(), this->m_filename.get(), exception);
@@ -765,6 +894,7 @@ std::optional<JSC::SourceCode> createCommonJSModule(
JSValue entry = globalObject->requireMap()->get(globalObject, specifierValue);
auto sourceProvider = Zig::SourceProvider::create(jsCast<Zig::GlobalObject*>(globalObject), source, JSC::SourceProviderSourceType::Program);
bool ignoreESModuleAnnotation = source.tag == ResolvedSourceTagPackageJSONTypeModule;
SourceOrigin sourceOrigin = sourceProvider->sourceOrigin();
if (entry) {
@@ -796,6 +926,8 @@ std::optional<JSC::SourceCode> createCommonJSModule(
globalObject->requireMap()->set(globalObject, requireMapKey, moduleObject);
}
moduleObject->ignoreESModuleAnnotation = ignoreESModuleAnnotation;
return JSC::SourceCode(
JSC::SyntheticSourceProvider::create(
[](JSC::JSGlobalObject* lexicalGlobalObject,

View File

@@ -24,7 +24,9 @@ public:
mutable JSC::WriteBarrier<JSC::JSString> m_id;
mutable JSC::WriteBarrier<JSC::JSString> m_filename;
mutable JSC::WriteBarrier<JSC::JSString> m_dirname;
mutable JSC::WriteBarrier<Unknown> m_paths;
mutable JSC::WriteBarrier<JSC::JSSourceCode> sourceCode;
bool ignoreESModuleAnnotation { false };
static void destroy(JSC::JSCell*);
~JSCommonJSModule();

View File

@@ -19,7 +19,7 @@ using namespace WebCore;
namespace Zig {
JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames)
JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames, int skipCount)
{
WTF::Vector<JSCStackFrame> newFrames;
@@ -29,7 +29,7 @@ JSCStackTrace JSCStackTrace::fromExisting(JSC::VM& vm, const WTF::Vector<JSC::St
}
newFrames.reserveInitialCapacity(frameCount);
for (size_t i = 0; i < frameCount; i++) {
for (size_t i = skipCount; i < frameCount; i++) {
newFrames.constructAndAppend(vm, existingFrames.at(i));
}

View File

@@ -139,7 +139,7 @@ public:
bool isEmpty() const { return m_frames.isEmpty(); }
JSCStackFrame& at(size_t i) { return m_frames.at(i); }
static JSCStackTrace fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames);
static JSCStackTrace fromExisting(JSC::VM& vm, const WTF::Vector<JSC::StackFrame>& existingFrames, int skipCount = 0);
/* This is based on JSC::Interpreter::getStackTrace, but skips native (non js and not wasm)
* frames, which is what v8 does. Note that we could have just called JSC::Interpreter::getStackTrace

View File

@@ -59,6 +59,7 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject,
return JSC::JSValue::encode(JSC::JSValue {});
}
default: {
JSValue thisValue = callFrame->thisValue();
JSC::JSValue moduleName = callFrame->argument(0);
auto doIt = [&](const WTF::String& fromStr) -> JSC::EncodedJSValue {
@@ -130,7 +131,14 @@ Zig::ImportMetaObject* Zig::ImportMetaObject::create(JSC::JSGlobalObject* global
JSC_DECLARE_HOST_FUNCTION(jsFunctionRequireResolve);
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireResolve, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame))
{
return functionRequireResolve(globalObject, callFrame, callFrame->thisValue().toWTFString(globalObject));
JSValue thisValue = callFrame->thisValue();
WTF::String fromStr;
if (thisValue.isString()) {
fromStr = thisValue.toWTFString(globalObject);
}
return functionRequireResolve(globalObject, callFrame, fromStr);
}
JSC_DEFINE_CUSTOM_GETTER(jsRequireCacheGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
@@ -224,32 +232,49 @@ public:
}
};
Structure* Zig::ImportMetaObject::createRequireFunctionStructure(VM& vm, JSGlobalObject* globalObject)
JSObject* Zig::ImportMetaObject::createRequireResolveFunctionUnbound(VM& vm, JSGlobalObject* globalObject)
{
return nullptr;
return ResolveFunction::create(globalObject);
}
JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString)
JSObject* Zig::ImportMetaObject::createRequireFunctionUnbound(VM& vm, JSGlobalObject* globalObject)
{
auto* globalObject = lexicalGlobalObject;
JSFunction* requireFunction = JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), lexicalGlobalObject);
auto& builtinNames = WebCore::builtinNames(vm);
JSC::JSFunction* requireDotMainFunction = JSFunction::create(
vm,
moduleMainCodeGenerator(vm),
globalObject->globalScope());
requireFunction->putDirect(
auto* prototype = JSC::constructEmptyObject(globalObject, globalObject->functionPrototype());
prototype->putDirect(
vm,
JSC::Identifier::fromString(vm, "main"_s),
JSC::GetterSetter::create(vm, globalObject, requireDotMainFunction, JSValue()),
PropertyAttribute::Builtin | PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0);
prototype->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), constructEmptyObject(globalObject), 0);
prototype->putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "cache"_s), JSC::CustomGetterSetter::create(vm, Zig::jsRequireCacheGetter, Zig::jsRequireCacheSetter), 0);
return JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), globalObject, JSFunction::createStructure(vm, globalObject, prototype));
}
requireFunction->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), JSC::constructEmptyObject(globalObject), 0);
requireFunction->putDirectCustomAccessor(vm, JSC::Identifier::fromString(vm, "cache"_s), JSC::CustomGetterSetter::create(vm, Zig::jsRequireCacheGetter, Zig::jsRequireCacheSetter), 0);
requireFunction->putDirect(vm, JSC::Identifier::fromString(vm, "resolve"_s), ResolveFunction::create(globalObject), JSC::PropertyAttribute::Function | 0);
requireFunction->putDirect(vm, JSC::Identifier::fromString(vm, "path"_s), jsString(vm, pathString));
JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString)
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& builtinNames = WebCore::builtinNames(vm);
JSFunction* resolveFunctionUnbound = jsCast<JSFunction*>(globalObject->importMetaRequireResolveFunctionUnbound());
JSFunction* requireFunctionUnbound = jsCast<JSFunction*>(globalObject->importMetaRequireFunctionUnbound());
auto str = jsString(vm, pathString);
JSFunction* requireFunction = JSC::JSBoundFunction::create(vm,
globalObject, requireFunctionUnbound,
str, ArgList(), 1, jsString(vm, String("require"_s)));
JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm,
globalObject, resolveFunctionUnbound,
str, ArgList(), 2, jsString(vm, String("resolve"_s)));
requireFunction->putDirect(vm, builtinNames.resolvePublicName(), resolveFunction, PropertyAttribute::Function | 0);
return requireFunction;
}
@@ -262,84 +287,107 @@ extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* g
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
switch (callFrame->argumentCount()) {
case 0: {
JSValue thisValue = callFrame->thisValue();
JSC::JSValue moduleName = callFrame->argument(0);
JSC::JSValue fromValue = callFrame->argument(1);
// not "requires" because "require" could be confusing
JSC::throwTypeError(globalObject, scope, "needs 1 argument (a string)"_s);
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, scope, "expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
default: {
JSC::JSValue moduleName = callFrame->argument(0);
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, scope, "expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
JSC__JSValue from;
bool isESM = true;
JSC__JSValue from;
bool isESM = true;
if (callFrame->argumentCount() > 1) {
if (callFrame->argumentCount() > 1) {
JSC::JSValue fromValue = callFrame->argument(1);
if (callFrame->argumentCount() > 2) {
JSC::JSValue isESMValue = callFrame->argument(2);
if (isESMValue.isBoolean()) {
isESM = isESMValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
}
if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) {
if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) {
auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject);
if (pathsArray->length() > 0) {
fromValue = pathsArray->getIndex(globalObject, 0);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
}
}
} else if (fromValue.isBoolean()) {
isESM = fromValue.toBoolean(globalObject);
if (callFrame->argumentCount() > 2) {
JSC::JSValue isESMValue = callFrame->argument(2);
if (isESMValue.isBoolean()) {
isESM = isESMValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
if (fromValue.isString()) {
from = JSC::JSValue::encode(fromValue);
}
} else {
JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync must be bound to an import.meta object"_s);
return JSC::JSValue::encode(JSC::JSValue {});
}
auto clientData = WebCore::clientData(vm);
JSValue pathProperty = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName());
if (pathProperty && pathProperty.isString())
from = JSC::JSValue::encode(pathProperty);
}
auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM);
if (!fromValue.isUndefinedOrNull() && fromValue.isObject()) {
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
if (auto pathsObject = fromValue.getObject()->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "paths"_s))) {
if (pathsObject.isCell() && pathsObject.asCell()->type() == JSC::JSType::ArrayType) {
auto pathsArray = JSC::jsCast<JSC::JSArray*>(pathsObject);
if (pathsArray->length() > 0) {
fromValue = pathsArray->getIndex(globalObject, 0);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
}
}
} else if (fromValue.isBoolean()) {
isESM = fromValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
fromValue = JSC::jsUndefined();
}
if (fromValue.isString()) {
from = JSC::JSValue::encode(fromValue);
} else if (thisValue.isString()) {
from = JSC::JSValue::encode(thisValue);
}
} else if (thisValue.isString()) {
from = JSC::JSValue::encode(thisValue);
} else {
JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(thisValue);
if (UNLIKELY(!thisObject)) {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync must be bound to an import.meta object"_s);
return JSC::JSValue::encode(JSC::JSValue {});
}
auto clientData = WebCore::clientData(vm);
JSValue pathProperty = thisObject->getIfPropertyExists(globalObject, clientData->builtinNames().pathPublicName());
if (pathProperty && pathProperty.isString())
from = JSC::JSValue::encode(pathProperty);
}
auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
return JSC::JSValue::encode(JSC::JSValue {});
}
scope.release();
return result;
}
extern "C" EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
{
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::JSValue moduleName = callFrame->argument(0);
JSValue from = callFrame->argument(1);
bool isESM = callFrame->argument(2).asBoolean();
if (moduleName.isUndefinedOrNull()) {
JSC::throwTypeError(globalObject, scope, "expected module name as a string"_s);
scope.release();
return result;
return JSC::JSValue::encode(JSC::JSValue {});
}
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), JSValue::encode(from), isESM);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
return JSC::JSValue::encode(JSC::JSValue {});
}
scope.release();
return result;
}
JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolve);
@@ -536,7 +584,16 @@ void ImportMetaObject::finishCreation(VM& vm)
this->requireProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSFunction>::Initializer& init) {
ImportMetaObject* meta = jsCast<ImportMetaObject*>(init.owner);
JSFunction* value = jsCast<JSFunction*>(ImportMetaObject::createRequireFunction(init.vm, meta->globalObject(), meta->url));
WTF::URL url = meta->url.startsWith('/') ? WTF::URL::fileURLWithFileSystemPath(meta->url) : WTF::URL(meta->url);
WTF::StringView path;
if (url.protocolIs("file"_s)) {
path = url.fileSystemPath();
} else {
path = url.path();
}
JSFunction* value = jsCast<JSFunction*>(ImportMetaObject::createRequireFunction(init.vm, meta->globalObject(), path.toString()));
init.set(value);
});
this->urlProperty.initLater([](const JSC::LazyProperty<JSC::JSObject, JSC::JSString>::Initializer& init) {

View File

@@ -9,6 +9,7 @@
#include "JSDOMWrapperCache.h"
extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSync);
extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSyncPrivate);
extern "C" JSC::EncodedJSValue Bun__resolve(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
extern "C" JSC::EncodedJSValue Bun__resolveSync(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
extern "C" JSC::EncodedJSValue Bun__resolveSyncWithSource(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, BunString* from, bool is_esm);
@@ -27,7 +28,8 @@ public:
static ImportMetaObject* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, const WTF::String& url);
static JSC::Structure* createRequireFunctionStructure(JSC::VM& vm, JSGlobalObject* globalObject);
static JSC::JSObject* createRequireFunctionUnbound(JSC::VM& vm, JSGlobalObject* globalObject);
static JSC::JSObject* createRequireResolveFunctionUnbound(JSC::VM& vm, JSGlobalObject* globalObject);
static JSObject* createRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString);
static ImportMetaObject* create(JSC::JSGlobalObject* globalObject, JSC::JSString* keyString);

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