diff options
| author | Dax Raad <[email protected]> | 2025-11-25 12:43:22 -0500 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-11-25 12:43:36 -0500 |
| commit | 40007057010aef7e006ca1a23a2ad27575c01160 (patch) | |
| tree | 034d5228a6a1917e61d05822d8104c8517787c5f | |
| parent | 673dbeee09d30c32bf4a6c93a96cfa7bb147dfa1 (diff) | |
| download | opencode-40007057010aef7e006ca1a23a2ad27575c01160.tar.gz opencode-40007057010aef7e006ca1a23a2ad27575c01160.zip | |
core(enterprise): use aws4fetch for smaller bundle size on edge runtimes
| -rw-r--r-- | bun.lock | 1 | ||||
| -rw-r--r-- | packages/enterprise/package.json | 1 | ||||
| -rw-r--r-- | packages/enterprise/src/core/storage.ts | 95 |
3 files changed, 40 insertions, 57 deletions
@@ -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(() => { |
