summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-11-25 12:43:22 -0500
committerDax Raad <[email protected]>2025-11-25 12:43:36 -0500
commit40007057010aef7e006ca1a23a2ad27575c01160 (patch)
tree034d5228a6a1917e61d05822d8104c8517787c5f
parent673dbeee09d30c32bf4a6c93a96cfa7bb147dfa1 (diff)
downloadopencode-40007057010aef7e006ca1a23a2ad27575c01160.tar.gz
opencode-40007057010aef7e006ca1a23a2ad27575c01160.zip
core(enterprise): use aws4fetch for smaller bundle size on edge runtimes
-rw-r--r--bun.lock1
-rw-r--r--packages/enterprise/package.json1
-rw-r--r--packages/enterprise/src/core/storage.ts95
3 files changed, 40 insertions, 57 deletions
diff --git a/bun.lock b/bun.lock
index b7949547b..171e06e58 100644
--- a/bun.lock
+++ b/bun.lock
@@ -171,6 +171,7 @@
"@solidjs/meta": "catalog:",
"@solidjs/router": "catalog:",
"@solidjs/start": "catalog:",
+ "aws4fetch": "^1.0.20",
"hono": "catalog:",
"hono-openapi": "catalog:",
"luxon": "catalog:",
diff --git a/packages/enterprise/package.json b/packages/enterprise/package.json
index 6f94a4b2c..c562358d1 100644
--- a/packages/enterprise/package.json
+++ b/packages/enterprise/package.json
@@ -13,6 +13,7 @@
"dependencies": {
"@opencode-ai/util": "workspace:*",
"@opencode-ai/ui": "workspace:*",
+ "aws4fetch": "^1.0.20",
"@pierre/precision-diffs": "catalog:",
"@solidjs/router": "catalog:",
"@solidjs/start": "catalog:",
diff --git a/packages/enterprise/src/core/storage.ts b/packages/enterprise/src/core/storage.ts
index db03e2160..ee711458b 100644
--- a/packages/enterprise/src/core/storage.ts
+++ b/packages/enterprise/src/core/storage.ts
@@ -1,10 +1,4 @@
-import {
- S3Client,
- PutObjectCommand,
- GetObjectCommand,
- DeleteObjectCommand,
- ListObjectsV2Command,
-} from "@aws-sdk/client-s3"
+import { AwsClient } from "aws4fetch"
import { lazy } from "@opencode-ai/util/lazy"
export namespace Storage {
@@ -15,81 +9,68 @@ export namespace Storage {
list(prefix: string): Promise<string[]>
}
- function createAdapter(client: S3Client, bucket: string): Adapter {
+ function createAdapter(client: AwsClient, endpoint: string, bucket: string): Adapter {
+ const base = `${endpoint}/${bucket}`
return {
async read(path: string): Promise<string | undefined> {
- try {
- const command = new GetObjectCommand({
- Bucket: bucket,
- Key: path,
- })
- const response = await client.send(command)
- if (!response.Body) return undefined
- return response.Body.transformToString()
- } catch (e: any) {
- if (e.name === "NoSuchKey") return undefined
- throw e
- }
+ const response = await client.fetch(`${base}/${path}`)
+ if (response.status === 404) return undefined
+ if (!response.ok) throw new Error(`Failed to read ${path}: ${response.status}`)
+ return response.text()
},
async write(path: string, value: string): Promise<void> {
- const command = new PutObjectCommand({
- Bucket: bucket,
- Key: path,
- Body: value,
- ContentType: "application/json",
+ const response = await client.fetch(`${base}/${path}`, {
+ method: "PUT",
+ body: value,
+ headers: {
+ "Content-Type": "application/json",
+ },
})
- await client.send(command)
+ if (!response.ok) throw new Error(`Failed to write ${path}: ${response.status}`)
},
async remove(path: string): Promise<void> {
- const command = new DeleteObjectCommand({
- Bucket: bucket,
- Key: path,
+ const response = await client.fetch(`${base}/${path}`, {
+ method: "DELETE",
})
- await client.send(command)
+ if (!response.ok) throw new Error(`Failed to remove ${path}: ${response.status}`)
},
async list(prefix: string): Promise<string[]> {
- const command = new ListObjectsV2Command({
- Bucket: bucket,
- Prefix: prefix,
- })
- const response = await client.send(command)
- return response.Contents?.map((c) => c.Key!) || []
+ const params = new URLSearchParams({ "list-type": "2", prefix })
+ const response = await client.fetch(`${base}?${params}`)
+ if (!response.ok) throw new Error(`Failed to list ${prefix}: ${response.status}`)
+ const xml = await response.text()
+ const keys: string[] = []
+ const regex = /<Key>([^<]+)<\/Key>/g
+ let match
+ while ((match = regex.exec(xml)) !== null) {
+ keys.push(match[1])
+ }
+ return keys
},
}
}
function s3(): Adapter {
const bucket = process.env.OPENCODE_STORAGE_BUCKET!
- const client = new S3Client({
- region: process.env.OPENCODE_STORAGE_REGION,
- credentials: process.env.OPENCODE_STORAGE_ACCESS_KEY_ID
- ? {
- accessKeyId: process.env.OPENCODE_STORAGE_ACCESS_KEY_ID!,
- secretAccessKey: process.env.OPENCODE_STORAGE_SECRET_ACCESS_KEY!,
- }
- : undefined,
+ const region = process.env.OPENCODE_STORAGE_REGION || "us-east-1"
+ const client = new AwsClient({
+ region,
+ accessKeyId: process.env.OPENCODE_STORAGE_ACCESS_KEY_ID!,
+ secretAccessKey: process.env.OPENCODE_STORAGE_SECRET_ACCESS_KEY!,
})
- return createAdapter(client, bucket)
+ return createAdapter(client, `https://s3.${region}.amazonaws.com`, bucket)
}
function r2() {
const accountId = process.env.OPENCODE_STORAGE_ACCOUNT_ID!
- const accessKeyId = process.env.OPENCODE_STORAGE_ACCESS_KEY_ID!
- const secretAccessKey = process.env.OPENCODE_STORAGE_SECRET_ACCESS_KEY!
- const bucket = process.env.OPENCODE_STORAGE_BUCKET!
-
- const client = new S3Client({
- region: "auto",
- endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
- credentials: {
- accessKeyId,
- secretAccessKey,
- },
+ const client = new AwsClient({
+ accessKeyId: process.env.OPENCODE_STORAGE_ACCESS_KEY_ID!,
+ secretAccessKey: process.env.OPENCODE_STORAGE_SECRET_ACCESS_KEY!,
})
- return createAdapter(client, bucket)
+ return createAdapter(client, `https://${accountId}.r2.cloudflarestorage.com`, process.env.OPENCODE_STORAGE_BUCKET!)
}
const adapter = lazy(() => {