bun-types 1.1.39-canary.20241204T140703 → 1.1.39-canary.20241205T140550

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bun.d.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  * This module aliases `globalThis.Bun`.
15
15
  */
16
16
  declare module "bun" {
17
+ import type { FFIFunctionCallableSymbol } from "bun:ffi";
17
18
  import type { Encoding as CryptoEncoding } from "crypto";
18
19
  import type {
19
20
  CipherNameAndProtocol,
@@ -4043,7 +4044,11 @@ declare module "bun" {
4043
4044
  defer: () => Promise<void>;
4044
4045
  }
4045
4046
 
4046
- type OnLoadResult = OnLoadResultSourceCode | OnLoadResultObject | undefined;
4047
+ type OnLoadResult =
4048
+ | OnLoadResultSourceCode
4049
+ | OnLoadResultObject
4050
+ | undefined
4051
+ | void;
4047
4052
  type OnLoadCallback = (
4048
4053
  args: OnLoadArgs,
4049
4054
  ) => OnLoadResult | Promise<OnLoadResult>;
@@ -4099,7 +4104,34 @@ declare module "bun" {
4099
4104
  | undefined
4100
4105
  | null;
4101
4106
 
4107
+ type FFIFunctionCallable = Function & {
4108
+ // Making a nominally typed function so that the user must get it from dlopen
4109
+ readonly __ffi_function_callable: typeof FFIFunctionCallableSymbol;
4110
+ };
4111
+
4102
4112
  interface PluginBuilder {
4113
+ /**
4114
+ * Register a callback which will be invoked when bundling starts.
4115
+ * @example
4116
+ * ```ts
4117
+ * Bun.plugin({
4118
+ * setup(builder) {
4119
+ * builder.onStart(() => {
4120
+ * console.log("bundle just started!!")
4121
+ * });
4122
+ * },
4123
+ * });
4124
+ * ```
4125
+ */
4126
+ onStart(callback: OnStartCallback): void;
4127
+ onBeforeParse(
4128
+ constraints: PluginConstraints,
4129
+ callback: {
4130
+ napiModule: unknown;
4131
+ symbol: string;
4132
+ external?: unknown | undefined;
4133
+ },
4134
+ ): void;
4103
4135
  /**
4104
4136
  * Register a callback to load imports with a specific import specifier
4105
4137
  * @param constraints The constraints to apply the plugin to
@@ -4135,20 +4167,6 @@ declare module "bun" {
4135
4167
  constraints: PluginConstraints,
4136
4168
  callback: OnResolveCallback,
4137
4169
  ): void;
4138
- /**
4139
- * Register a callback which will be invoked when bundling starts.
4140
- * @example
4141
- * ```ts
4142
- * Bun.plugin({
4143
- * setup(builder) {
4144
- * builder.onStart(() => {
4145
- * console.log("bundle just started!!")
4146
- * });
4147
- * },
4148
- * });
4149
- * ```
4150
- */
4151
- onStart(callback: OnStartCallback): void;
4152
4170
  /**
4153
4171
  * The config object passed to `Bun.build` as is. Can be mutated.
4154
4172
  */
@@ -355,7 +355,7 @@ Bun.build({
355
355
 
356
356
  {% /callout %}
357
357
 
358
- ## Lifecycle callbacks
358
+ ## Lifecycle hooks
359
359
 
360
360
  Plugins can register callbacks to be run at various points in the lifecycle of a bundle:
361
361
 
@@ -363,6 +363,8 @@ Plugins can register callbacks to be run at various points in the lifecycle of a
363
363
  - [`onResolve()`](#onresolve): Run before a module is resolved
364
364
  - [`onLoad()`](#onload): Run before a module is loaded.
365
365
 
366
+ ### Reference
367
+
366
368
  A rough overview of the types (please refer to Bun's `bun.d.ts` for the full type definitions):
367
369
 
368
370
  ```ts
@@ -603,3 +605,98 @@ plugin({
603
605
  ```
604
606
 
605
607
  Note that the `.defer()` function currently has the limitation that it can only be called once per `onLoad` callback.
608
+
609
+ ## Native plugins
610
+
611
+ {% callout %}
612
+ **NOTE** — This is an advanced and experiemental API recommended for plugin developers who are familiar with systems programming and the C ABI. Use with caution.
613
+ {% /callout %}
614
+
615
+ One of the reasons why Bun's bundler is so fast is that it is written in native code and leverages multi-threading to load and parse modules in parallel.
616
+
617
+ However, one limitation of plugins written in JavaScript is that JavaScript itself is single-threaded.
618
+
619
+ Native plugins are written as [NAPI](/docs/node-api) modules and can be run on multiple threads. This allows native plugins to run much faster than JavaScript plugins.
620
+
621
+ In addition, native plugins can skip unnecessary work such as the UTF-8 -> UTF-16 conversion needed to pass strings to JavaScript.
622
+
623
+ These are the following lifecycle hooks which are available to native plugins:
624
+
625
+ - [`onBeforeParse()`](#onbeforeparse): Called on any thread before a file is parsed by Bun's bundler.
626
+
627
+ ### Creating a native plugin
628
+
629
+ Native plugins are NAPI modules which expose lifecycle hooks as C ABI functions.
630
+
631
+ To create a native plugin, you must export a C ABI function which matches the signature of the native lifecycle hook you want to implement.
632
+
633
+ #### Example: Rust with napi-rs
634
+
635
+ First initialize a napi project (see [here](https://napi.rs/docs/introduction/getting-started) for a more comprehensive guide).
636
+
637
+ Then install Bun's official safe plugin wrapper crate:
638
+
639
+ ```bash
640
+ cargo add bun-native-plugin
641
+ ```
642
+
643
+ Now you can export an `extern "C" fn` which is the implementation of your plugin:
644
+
645
+ ```rust
646
+ #[no_mangle]
647
+ extern "C" fn on_before_parse_impl(
648
+ args: *const bun_native_plugin::sys::OnBeforeParseArguments,
649
+ result: *mut bun_native_plugin::sys::OnBeforeParseResult,
650
+ ) {
651
+ let args = unsafe { &*args };
652
+ let result = unsafe { &mut *result };
653
+
654
+ let mut handle = match bun_native_plugin::OnBeforeParse::from_raw(args, result) {
655
+ Ok(handle) => handle,
656
+ Err(_) => {
657
+ return;
658
+ }
659
+ };
660
+
661
+ let source_code = match handle.input_source_code() {
662
+ Ok(source_code) => source_code,
663
+ Err(_) => {
664
+ handle.log_error("Fetching source code failed!");
665
+ return;
666
+ }
667
+ };
668
+
669
+ let loader = handle.output_loader();
670
+ handle.set_output_source_code(source_code.replace("foo", "bar"), loader);
671
+ ```
672
+
673
+ Use napi-rs to compile the plugin to a `.node` file, then you can `require()` it from JS and use it:
674
+
675
+ ```js
676
+ await Bun.build({
677
+ entrypoints: ["index.ts"],
678
+ setup(build) {
679
+ const myNativePlugin = require("./path/to/plugin.node");
680
+
681
+ build.onBeforeParse(
682
+ { filter: /\.ts/ },
683
+ { napiModule: myNativePlugin, symbol: "on_before_parse_impl" },
684
+ );
685
+ },
686
+ });
687
+ ```
688
+
689
+ ### `onBeforeParse`
690
+
691
+ ```ts
692
+ onBeforeParse(
693
+ args: { filter: RegExp; namespace?: string },
694
+ callback: { napiModule: NapiModule; symbol: string; external?: unknown },
695
+ ): void;
696
+ ```
697
+
698
+ This lifecycle callback is run immediately before a file is parsed by Bun's bundler.
699
+
700
+ As input, it receives the file's contents and can optionally return new source code.
701
+
702
+ This callback can be called from any thread and so the napi module implementation must be thread-safe.
package/ffi.d.ts CHANGED
@@ -570,17 +570,22 @@ declare module "bun:ffi" {
570
570
  ? FFITypeStringToType[T]
571
571
  : never;
572
572
 
573
+ const FFIFunctionCallableSymbol: unique symbol;
573
574
  type ConvertFns<Fns extends Symbols> = {
574
- [K in keyof Fns]: (
575
- ...args: Fns[K]["args"] extends infer A extends readonly FFITypeOrString[]
576
- ? { [L in keyof A]: FFITypeToArgsType[ToFFIType<A[L]>] }
577
- : // eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
578
- [unknown] extends [Fns[K]["args"]]
579
- ? []
580
- : never
581
- ) => [unknown] extends [Fns[K]["returns"]] // eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
582
- ? undefined
583
- : FFITypeToReturnsType[ToFFIType<NonNullable<Fns[K]["returns"]>>];
575
+ [K in keyof Fns]: {
576
+ (
577
+ ...args: Fns[K]["args"] extends infer A extends
578
+ readonly FFITypeOrString[]
579
+ ? { [L in keyof A]: FFITypeToArgsType[ToFFIType<A[L]>] }
580
+ : // eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
581
+ [unknown] extends [Fns[K]["args"]]
582
+ ? []
583
+ : never
584
+ ): [unknown] extends [Fns[K]["returns"]] // eslint-disable-next-line @definitelytyped/no-single-element-tuple-type
585
+ ? undefined
586
+ : FFITypeToReturnsType[ToFFIType<NonNullable<Fns[K]["returns"]>>];
587
+ __ffi_function_callable: typeof FFIFunctionCallableSymbol;
588
+ };
584
589
  };
585
590
 
586
591
  /**
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.39-canary.20241204T140703",
2
+ "version": "1.1.39-canary.20241205T140550",
3
3
  "name": "bun-types",
4
4
  "license": "MIT",
5
5
  "main": "",