From 1f6d0d9a90029fb064547fa7b0af9a8779ec367e Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 13:42:06 -0800 Subject: [PATCH 01/11] WIP --- packages/bun-types/bun.d.ts | 28 +--------------------------- src/bun.js/api/BunObject.zig | 8 ++++++-- src/bun.js/bindings/BunObject.cpp | 2 +- src/bun.js/rare_data.zig | 20 ++++++++++++++++++++ test/js/bun/s3/s3.test.ts | 3 ++- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 90f1a50126056f..967566f8fed0fa 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1267,33 +1267,7 @@ declare module "bun" { } var S3Client: S3Client; - - /** - * Creates a new S3File instance for working with a single file. - * - * @param path The path or key of the file - * @param options S3 configuration options - * @returns `S3File` instance for the specified path - * - * @example - * import { s3 } from "bun"; - * const file = s3("my-file.txt", { - * bucket: "my-bucket", - * accessKeyId: "your-access-key", - * secretAccessKey: "your-secret-key" - * }); - * - * // Read the file - * const content = await file.text(); - * - * @example - * // Using s3:// protocol - * const file = s3("s3://my-bucket/my-file.txt", { - * accessKeyId: "your-access-key", - * secretAccessKey: "your-secret-key" - * }); - */ - function s3(path: string | URL, options?: S3Options): S3File; + var s3: S3Client; /** * Configuration options for S3 operations diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index b6e8baa3b2e299..21531ae39b515d 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -30,7 +30,6 @@ pub const BunObject = struct { pub const registerMacro = toJSCallback(Bun.registerMacro); pub const resolve = toJSCallback(Bun.resolve); pub const resolveSync = toJSCallback(Bun.resolveSync); - pub const s3 = S3File.createJSS3File; pub const serve = toJSCallback(Bun.serve); pub const sha = toJSCallback(JSC.wrapStaticMethod(Crypto.SHA512_256, "hash_", true)); pub const shellEscape = toJSCallback(Bun.shellEscape); @@ -72,6 +71,7 @@ pub const BunObject = struct { pub const stdout = toJSGetter(Bun.getStdout); pub const unsafe = toJSGetter(Bun.getUnsafe); pub const S3Client = toJSGetter(Bun.getS3ClientConstructor); + pub const s3 = toJSGetter(Bun.getS3DefaultClient); // --- Getters --- fn getterName(comptime baseName: anytype) [:0]const u8 { @@ -133,6 +133,8 @@ pub const BunObject = struct { @export(BunObject.semver, .{ .name = getterName("semver") }); @export(BunObject.embeddedFiles, .{ .name = getterName("embeddedFiles") }); @export(BunObject.S3Client, .{ .name = getterName("S3Client") }); + @export(BunObject.s3, .{ .name = getterName("s3") }); + // --- Getters -- // -- Callbacks -- @@ -157,7 +159,6 @@ pub const BunObject = struct { @export(BunObject.resolve, .{ .name = callbackName("resolve") }); @export(BunObject.resolveSync, .{ .name = callbackName("resolveSync") }); @export(BunObject.serve, .{ .name = callbackName("serve") }); - @export(BunObject.s3, .{ .name = callbackName("s3") }); @export(BunObject.sha, .{ .name = callbackName("sha") }); @export(BunObject.shellEscape, .{ .name = callbackName("shellEscape") }); @export(BunObject.shrink, .{ .name = callbackName("shrink") }); @@ -3451,6 +3452,9 @@ pub fn getGlobConstructor(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC pub fn getS3ClientConstructor(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { return JSC.WebCore.S3Client.getConstructor(globalThis); } +pub fn getS3DefaultClient(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { + return globalThis.bunVM().rareData().s3DefaultClient(globalThis); +} pub fn getEmbeddedFiles(globalThis: *JSC.JSGlobalObject, _: *JSC.JSObject) JSC.JSValue { const vm = globalThis.bunVM(); const graph = vm.standalone_module_graph orelse return JSC.JSValue.createEmptyArray(globalThis, 0); diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 787a0ba878d039..54535edba3187f 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -701,6 +701,7 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj TOML BunObject_getter_wrap_TOML DontDelete|PropertyCallback Transpiler BunObject_getter_wrap_Transpiler DontDelete|PropertyCallback embeddedFiles BunObject_getter_wrap_embeddedFiles DontDelete|PropertyCallback + s3 BunObject_getter_wrap_s3 DontDelete|PropertyCallback S3Client BunObject_getter_wrap_S3Client DontDelete|PropertyCallback allocUnsafe BunObject_callback_allocUnsafe DontDelete|Function 1 argv BunObject_getter_wrap_argv DontDelete|PropertyCallback @@ -754,7 +755,6 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj resolveSync BunObject_callback_resolveSync DontDelete|Function 1 revision constructBunRevision ReadOnly|DontDelete|PropertyCallback semver BunObject_getter_wrap_semver ReadOnly|DontDelete|PropertyCallback - s3 BunObject_callback_s3 DontDelete|Function 1 sql defaultBunSQLObject DontDelete|PropertyCallback postgres defaultBunSQLObject DontDelete|PropertyCallback SQL constructBunSQLObject DontDelete|PropertyCallback diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index e49925e14828f9..bc5fb49beb71b6 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -50,6 +50,8 @@ temp_pipe_read_buffer: ?*PipeReadBuffer = null, aws_signature_cache: AWSSignatureCache = .{}, +s3_default_client: JSC.Strong = .{}, + const PipeReadBuffer = [256 * 1024]u8; const DIGESTED_HMAC_256_LEN = 32; pub const AWSSignatureCache = struct { @@ -435,6 +437,23 @@ pub fn nodeFSStatWatcherScheduler(rare: *RareData, vm: *JSC.VirtualMachine) *Sta }; } +pub fn s3DefaultClient(rare: *RareData, globalThis: *JSC.JSGlobalObject) JSC.JSValue { + return rare.s3_default_client.get() orelse { + const vm = globalThis.bunVM(); + var aws_options = bun.S3.S3Credentials.getCredentialsWithOptions(vm.transpiler.env.getS3Credentials(), .{}, null, null, globalThis) catch bun.outOfMemory(); + defer aws_options.deinit(); + const client = JSC.WebCore.S3Client.new(.{ + .credentials = aws_options.credentials.dupe(), + .options = aws_options.options, + .acl = aws_options.acl, + }); + const js_client = client.toJS(globalThis); + js_client.ensureStillAlive(); + rare.s3_default_client = JSC.Strong.create(js_client, globalThis); + return js_client; + }; +} + pub fn deinit(this: *RareData) void { if (this.temp_pipe_read_buffer) |pipe| { this.temp_pipe_read_buffer = null; @@ -443,6 +462,7 @@ pub fn deinit(this: *RareData) void { this.aws_signature_cache.deinit(); + this.s3_default_client.deinit(); if (this.boring_ssl_engine) |engine| { _ = bun.BoringSSL.ENGINE_free(engine); } diff --git a/test/js/bun/s3/s3.test.ts b/test/js/bun/s3/s3.test.ts index 10119b242eb66e..5e955032fef36c 100644 --- a/test/js/bun/s3/s3.test.ts +++ b/test/js/bun/s3/s3.test.ts @@ -1,7 +1,8 @@ import { describe, expect, it, beforeAll, afterAll } from "bun:test"; import { bunExe, bunEnv, getSecret, tempDirWithFiles, isLinux } from "harness"; import { randomUUID } from "crypto"; -import { S3Client, s3, file, which } from "bun"; +import { S3Client, s3 as defaultS3, file, which } from "bun"; +const s3 = (...args) => defaultS3.file(...args); const S3 = (...args) => new S3Client(...args); import child_process from "child_process"; import type { S3Options } from "bun"; From a4f19306415a53bd703225a2e9982555b56d04e3 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 13:48:00 -0800 Subject: [PATCH 02/11] maybe --- src/bun.js/api/BunObject.zig | 2 +- src/bun.js/bindings/BunObject.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 21531ae39b515d..7a769d99d13776 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -133,7 +133,7 @@ pub const BunObject = struct { @export(BunObject.semver, .{ .name = getterName("semver") }); @export(BunObject.embeddedFiles, .{ .name = getterName("embeddedFiles") }); @export(BunObject.S3Client, .{ .name = getterName("S3Client") }); - @export(BunObject.s3, .{ .name = getterName("s3") }); + @export(BunObject.s3, .{ .name = getterName("s3DefaultClient") }); // --- Getters -- diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 54535edba3187f..8bf93b2f78e0be 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -701,8 +701,8 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj TOML BunObject_getter_wrap_TOML DontDelete|PropertyCallback Transpiler BunObject_getter_wrap_Transpiler DontDelete|PropertyCallback embeddedFiles BunObject_getter_wrap_embeddedFiles DontDelete|PropertyCallback - s3 BunObject_getter_wrap_s3 DontDelete|PropertyCallback S3Client BunObject_getter_wrap_S3Client DontDelete|PropertyCallback + s3 BunObject_getter_wrap_s3DefaultClient DontDelete|PropertyCallback allocUnsafe BunObject_callback_allocUnsafe DontDelete|Function 1 argv BunObject_getter_wrap_argv DontDelete|PropertyCallback build BunObject_callback_build DontDelete|Function 1 From a0a951eb8c37d64478aa1b5f67d9ada1ef6745d2 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:00:19 -0800 Subject: [PATCH 03/11] Bun.s3 is not writable --- docs/api/s3.md | 1 - src/bun.js/api/BunObject.zig | 2 +- src/bun.js/bindings/BunObject+exports.h | 2 +- src/bun.js/bindings/BunObject.cpp | 2 +- 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index c8f9d88f3c8ff3..dda4fef5daada1 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -68,7 +68,6 @@ const client = new S3Client({ }); // Bun.s3 is a global singleton that is equivalent to `new Bun.S3Client()` -Bun.s3 = client; ``` ### Working with S3 Files diff --git a/src/bun.js/api/BunObject.zig b/src/bun.js/api/BunObject.zig index 7a769d99d13776..21531ae39b515d 100644 --- a/src/bun.js/api/BunObject.zig +++ b/src/bun.js/api/BunObject.zig @@ -133,7 +133,7 @@ pub const BunObject = struct { @export(BunObject.semver, .{ .name = getterName("semver") }); @export(BunObject.embeddedFiles, .{ .name = getterName("embeddedFiles") }); @export(BunObject.S3Client, .{ .name = getterName("S3Client") }); - @export(BunObject.s3, .{ .name = getterName("s3DefaultClient") }); + @export(BunObject.s3, .{ .name = getterName("s3") }); // --- Getters -- diff --git a/src/bun.js/bindings/BunObject+exports.h b/src/bun.js/bindings/BunObject+exports.h index 7ea85829494248..0e2563398dde9f 100644 --- a/src/bun.js/bindings/BunObject+exports.h +++ b/src/bun.js/bindings/BunObject+exports.h @@ -32,6 +32,7 @@ macro(semver) \ macro(embeddedFiles) \ macro(S3Client) \ + macro(s3) \ // --- Callbacks --- #define FOR_EACH_CALLBACK(macro) \ @@ -58,7 +59,6 @@ macro(registerMacro) \ macro(resolve) \ macro(resolveSync) \ - macro(s3) \ macro(serve) \ macro(sha) \ macro(shrink) \ diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index 8bf93b2f78e0be..8290a280d35910 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -702,7 +702,7 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj Transpiler BunObject_getter_wrap_Transpiler DontDelete|PropertyCallback embeddedFiles BunObject_getter_wrap_embeddedFiles DontDelete|PropertyCallback S3Client BunObject_getter_wrap_S3Client DontDelete|PropertyCallback - s3 BunObject_getter_wrap_s3DefaultClient DontDelete|PropertyCallback + s3 BunObject_getter_wrap_s3 DontDelete|PropertyCallback allocUnsafe BunObject_callback_allocUnsafe DontDelete|Function 1 argv BunObject_getter_wrap_argv DontDelete|PropertyCallback build BunObject_callback_build DontDelete|Function 1 From 9de8fe5603d7ac2f3d83072714070f01d7c28aba Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:07:35 -0800 Subject: [PATCH 04/11] fix more --- docs/api/s3.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index dda4fef5daada1..b74875bce3e6d6 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -374,7 +374,7 @@ If the `S3_*` environment variable is not set, Bun will also check for the `AWS_ These environment variables are read from [`.env` files](/docs/runtime/env) or from the process environment at initialization time (`process.env` is not used for this). -These defaults are overridden by the options you pass to `s3(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3()` helper function without having to specify all the credentials again. +These defaults are overridden by the options you pass to `s3.file(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3.file()` helper function without having to specify all the credentials again. ### `S3Client` objects @@ -458,7 +458,7 @@ const exists = await client.exists("my-file.txt"); ## `S3File` -`S3File` instances are created by calling the `S3` instance method or the `s3()` helper function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. +`S3File` instances are created by calling the `S3` instance method or the `s3.file()` helper function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. ```ts interface S3File extends Blob { @@ -599,7 +599,7 @@ const exists = await S3Client.exists("my-file.txt", credentials); The same method also works on `S3File` instances. ```ts -const s3file = Bun.s3("my-file.txt", { +const s3file = Bun.s3.file("my-file.txt", { ...credentials, }); const exists = await s3file.exists(); From 9005ec6ee4b44ad52aa916b46a594e5b7933e64a Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:09:12 -0800 Subject: [PATCH 05/11] this is now only S3Client --- docs/api/s3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index b74875bce3e6d6..83990cdcc8aa5b 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -458,7 +458,7 @@ const exists = await client.exists("my-file.txt"); ## `S3File` -`S3File` instances are created by calling the `S3` instance method or the `s3.file()` helper function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. +`S3File` instances are created by calling the `S3Client` instance method or the `s3.file()` helper function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. ```ts interface S3File extends Blob { From d5fa419442ac12f0c205261811e68a4fe35dc8e6 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:35:38 -0800 Subject: [PATCH 06/11] remove double { --- src/bun.js/webcore/S3Client.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/webcore/S3Client.zig b/src/bun.js/webcore/S3Client.zig index 37b1799cb463ec..5c25ca0969312c 100644 --- a/src/bun.js/webcore/S3Client.zig +++ b/src/bun.js/webcore/S3Client.zig @@ -112,13 +112,13 @@ pub const S3Client = struct { try writer.writeAll(comptime bun.Output.prettyFmt("S3Client", enable_ansi_colors)); if (this.credentials.bucket.len > 0) { try writer.print( - comptime bun.Output.prettyFmt(" (\"{s}\") {{", enable_ansi_colors), + comptime bun.Output.prettyFmt(" (\"{s}\") {", enable_ansi_colors), .{ this.credentials.bucket, }, ); } else { - try writer.writeAll(comptime bun.Output.prettyFmt(" {{", enable_ansi_colors)); + try writer.writeAll(comptime bun.Output.prettyFmt(" {", enable_ansi_colors)); } try writeFormatCredentials(this.credentials, this.options, this.acl, Formatter, formatter, writer, enable_ansi_colors); From 701e0c0472883cc1ce54bc6f966db1d92c5d09a0 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:38:46 -0800 Subject: [PATCH 07/11] not ugly --- docs/api/s3.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index 83990cdcc8aa5b..7d6b8b0799fae6 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -599,7 +599,9 @@ const exists = await S3Client.exists("my-file.txt", credentials); The same method also works on `S3File` instances. ```ts -const s3file = Bun.s3.file("my-file.txt", { +import { s3 } from "bun"; + +const s3file = s3.file("my-file.txt", { ...credentials, }); const exists = await s3file.exists(); From 8bae9b204e80f017806d241073df978d497a896e Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:41:37 -0800 Subject: [PATCH 08/11] fix tests --- test/js/bun/s3/s3-stream-leak-fixture.js | 4 ++-- test/js/bun/s3/s3-text-leak-fixture.js | 4 ++-- test/js/bun/s3/s3-write-leak-fixture.js | 2 +- test/js/bun/s3/s3-writer-leak-fixture.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/js/bun/s3/s3-stream-leak-fixture.js b/test/js/bun/s3/s3-stream-leak-fixture.js index f2ad73edd740aa..b5052d5d86a149 100644 --- a/test/js/bun/s3/s3-stream-leak-fixture.js +++ b/test/js/bun/s3/s3-stream-leak-fixture.js @@ -6,9 +6,9 @@ const { randomUUID } = require("crypto"); const s3Dest = randomUUID() + "-s3-stream-leak-fixture"; -const s3file = Bun.s3(s3Dest); +const s3file = Bun.s3.file(s3Dest); async function readLargeFile() { - const stream = Bun.s3(s3Dest).stream(); + const stream = Bun.s3.file(s3Dest).stream(); const reader = stream.getReader(); while (true) { const { done, value } = await reader.read(); diff --git a/test/js/bun/s3/s3-text-leak-fixture.js b/test/js/bun/s3/s3-text-leak-fixture.js index e564a9edb55122..358d8818db9b42 100644 --- a/test/js/bun/s3/s3-text-leak-fixture.js +++ b/test/js/bun/s3/s3-text-leak-fixture.js @@ -6,9 +6,9 @@ const { randomUUID } = require("crypto"); const s3Dest = randomUUID() + "-s3-stream-leak-fixture"; -const s3file = Bun.s3(s3Dest); +const s3file = Bun.s3.file(s3Dest); async function readLargeFile() { - await Bun.s3(s3Dest).text(); + await Bun.s3.file(s3Dest).text(); } async function run(inputType) { await s3file.write(inputType); diff --git a/test/js/bun/s3/s3-write-leak-fixture.js b/test/js/bun/s3/s3-write-leak-fixture.js index 019b8121a07b36..75a8c2d36a55fc 100644 --- a/test/js/bun/s3/s3-write-leak-fixture.js +++ b/test/js/bun/s3/s3-write-leak-fixture.js @@ -6,7 +6,7 @@ const dest = process.argv.at(-1); const { randomUUID } = require("crypto"); const payload = new Buffer(1024 * 1024 + 1, "A".charCodeAt(0)).toString("utf-8"); async function writeLargeFile() { - const s3file = Bun.s3(randomUUID()); + const s3file = Bun.s3.file(randomUUID()); await s3file.write(payload); await s3file.unlink(); } diff --git a/test/js/bun/s3/s3-writer-leak-fixture.js b/test/js/bun/s3/s3-writer-leak-fixture.js index 80a42b37957a1b..5fc0e7038696fe 100644 --- a/test/js/bun/s3/s3-writer-leak-fixture.js +++ b/test/js/bun/s3/s3-writer-leak-fixture.js @@ -6,7 +6,7 @@ const dest = process.argv.at(-1); const { randomUUID } = require("crypto"); const payload = new Buffer(1024 * 256, "A".charCodeAt(0)).toString("utf-8"); async function writeLargeFile() { - const s3file = Bun.s3(randomUUID()); + const s3file = Bun.s3.file(randomUUID()); const writer = s3file.writer(); writer.write(payload); await Bun.sleep(10); From da8c960678febb8ea97115c99648d41fc3cf496a Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 14:49:32 -0800 Subject: [PATCH 09/11] not helper function anymore --- docs/api/s3.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index 7d6b8b0799fae6..4cf4fb8fcacf5a 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -374,7 +374,7 @@ If the `S3_*` environment variable is not set, Bun will also check for the `AWS_ These environment variables are read from [`.env` files](/docs/runtime/env) or from the process environment at initialization time (`process.env` is not used for this). -These defaults are overridden by the options you pass to `s3.file(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3.file()` helper function without having to specify all the credentials again. +These defaults are overridden by the options you pass to `s3.file(credentials)`, `new Bun.S3Client(credentials)`, or any of the methods that accept credentials. So if, for example, you use the same credentials for different buckets, you can set the credentials once in your `.env` file and then pass `bucket: "my-bucket"` to the `s3.file()` function without having to specify all the credentials again. ### `S3Client` objects @@ -458,7 +458,7 @@ const exists = await client.exists("my-file.txt"); ## `S3File` -`S3File` instances are created by calling the `S3Client` instance method or the `s3.file()` helper function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. +`S3File` instances are created by calling the `S3Client` instance method or the `s3.file()` function. Like `Bun.file()`, `S3File` instances are lazy. They don't refer to something that necessarily exists at the time of creation. That's why all the methods that don't involve network requests are fully synchronous. ```ts interface S3File extends Blob { From b915e5808d7f2a17c981edb709d92b63c7929182 Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 15:13:52 -0800 Subject: [PATCH 10/11] fix --- src/bun.js/webcore/S3Client.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bun.js/webcore/S3Client.zig b/src/bun.js/webcore/S3Client.zig index 5c25ca0969312c..014bfcff38b87a 100644 --- a/src/bun.js/webcore/S3Client.zig +++ b/src/bun.js/webcore/S3Client.zig @@ -112,13 +112,13 @@ pub const S3Client = struct { try writer.writeAll(comptime bun.Output.prettyFmt("S3Client", enable_ansi_colors)); if (this.credentials.bucket.len > 0) { try writer.print( - comptime bun.Output.prettyFmt(" (\"{s}\") {", enable_ansi_colors), + comptime bun.Output.prettyFmt(" (\"{s}\") {{", enable_ansi_colors), .{ this.credentials.bucket, }, ); } else { - try writer.writeAll(comptime bun.Output.prettyFmt(" {", enable_ansi_colors)); + try writer.writeAll(" {"); } try writeFormatCredentials(this.credentials, this.options, this.acl, Formatter, formatter, writer, enable_ansi_colors); From 46371e8c780fe1b155fe993de941f83da0b5a29b Mon Sep 17 00:00:00 2001 From: Ciro Spaciari Date: Tue, 21 Jan 2025 15:30:53 -0800 Subject: [PATCH 11/11] update docs and types --- docs/api/s3.md | 2 +- packages/bun-types/bun.d.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/s3.md b/docs/api/s3.md index 4cf4fb8fcacf5a..1caf35c58f27bc 100644 --- a/docs/api/s3.md +++ b/docs/api/s3.md @@ -481,7 +481,7 @@ interface S3File extends Blob { | Response | Request, options?: BlobPropertyBag, - ): Promise; + ): Promise; exists(options?: S3Options): Promise; unlink(options?: S3Options): Promise; diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 967566f8fed0fa..712ee4ed3e073a 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1571,7 +1571,7 @@ declare module "bun" { * * // Write large chunks of data efficiently * for (const chunk of largeDataChunks) { - * await writer.write(chunk); + * writer.write(chunk); * } * await writer.end(); * @@ -1579,7 +1579,7 @@ declare module "bun" { * // Error handling * const writer = file.writer(); * try { - * await writer.write(data); + * writer.write(data); * await writer.end(); * } catch (err) { * console.error('Upload failed:', err);