Skip to content

Commit c799b3b

Browse files
V48 (specification-implementation): Artifact storage providers; remove @bitcode/aws
Split ArtifactStorage into generic-artifacts/{aws,supabase,vercel} providers; patch remains the type base. @bitcode/artifacts composes aws → supabase → vercel. Remove standalone @bitcode/aws (stubs inlined into AWS MCP tools). S3 for artifacts is @bitcode/generic-artifacts-aws only.
1 parent 5f36050 commit c799b3b

43 files changed

Lines changed: 830 additions & 598 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

BITCODE_SPEC_V48_NOTES.md

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1654,17 +1654,23 @@ MeasuredPatchAssetPack (path+op patch + provenant paths; never raw source).
16541654

16551655
## Artifact hierarchy: generics + patch + product (Garrett, 2026-07-13)
16561656

1657+
See “Artifact storage providers + remove @bitcode/aws” — providers split into
1658+
`generic-artifacts/{aws,supabase,vercel}`; patch remains the type base;
1659+
`@bitcode/artifacts` composes storage.
1660+
1661+
## Artifact storage providers + remove @bitcode/aws (Garrett, 2026-07-13)
1662+
16571663
```
1658-
@bitcode/artifact-generics # Artifact + ArtifactStorage contract
1659-
→ @bitcode/generic-artifacts-patch # PatchArtifact (path+op patchfiles)
1660-
→ @bitcode/asset-packs-synthesis # AssetPackPatchArtifact (product)
1661-
@bitcode/artifacts # S3/Supabase ArtifactStorage backend (BC)
1664+
@bitcode/artifact-generics
1665+
→ generic-artifacts/patch # type
1666+
→ generic-artifacts/aws # S3 storage provider
1667+
→ generic-artifacts/supabase # Supabase Storage provider
1668+
→ generic-artifacts/vercel # Vercel Blob provider
1669+
@bitcode/artifacts # compose: aws → supabase → vercel
16621670
```
16631671

1664-
Primitive storage requirements live in artifact-generics. Patch base stores
1665-
AssetPack path+op envelopes without requiring raw source. Product binds
1666-
`assetPackId`. Existing `saveArtifact` / `putArtifactAtKey` callers keep
1667-
`@bitcode/artifacts`.
1672+
Removed standalone `@bitcode/aws` (stubs only). AWS MCP tools (location/terraform/aws)
1673+
inline their stubs; S3 for **artifacts** is `@bitcode/generic-artifacts-aws`.
16681674

16691675
## Remove aurora-postgres (Supabase is the data plane) (Garrett, 2026-07-13)
16701676

FAMILIARIZATION.md

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -225,25 +225,28 @@ Package paths: `packages/asset-pack-generics/`, `packages/generic-asset-packs/me
225225
| Base | `MeasuredPatchAssetPack` | + measurements, neediness, provenant paths |
226226
| Product | deposit options / pipeline outputs | project from MeasuredPatchAssetPack |
227227

228-
### 3.1.4 Artifacts (primitive → patch → product)
228+
### 3.1.4 Artifacts (primitive → types + storage providers)
229229

230230
```
231231
@bitcode/artifact-generics Artifact + ArtifactStorage contract
232232
233-
@bitcode/generic-artifacts-patch PatchArtifact (path+op patchfiles)
233+
@bitcode/generic-artifacts-patch type: path+op patch
234+
@bitcode/generic-artifacts-aws storage: S3
235+
@bitcode/generic-artifacts-supabase storage: Supabase
236+
@bitcode/generic-artifacts-vercel storage: Vercel Blob
234237
235-
@bitcode/asset-packs-synthesis AssetPackPatchArtifact (product)
236-
@bitcode/artifacts concrete S3/Supabase storage (BC)
238+
@bitcode/artifacts compose providers (aws → supabase → vercel)
239+
@bitcode/asset-packs-synthesis AssetPackPatchArtifact product
237240
```
238241

239-
Package paths: `packages/artifact-generics/`, `packages/generic-artifacts/patch/`,
240-
`packages/artifacts/`, product in `packages/asset-packs/synthesis/`.
242+
No standalone `@bitcode/aws` package — S3 for artifacts is `generic-artifacts-aws`.
241243

242244
| Layer | Type | Role |
243245
| --- | --- | --- |
244-
| Primitive | `Artifact` / `ArtifactStorage` | identity + storage requirements + save/putAtKey |
245-
| Base | `PatchArtifact` | path+op patchfile envelope for AssetPack patches |
246-
| Product | `AssetPackPatchArtifact` | patch bound to `assetPackId` for synthesis |
246+
| Primitive | `Artifact` / `ArtifactStorage` | identity + storage contract |
247+
| Type base | `PatchArtifact` | path+op patch envelope |
248+
| Storage bases | aws / supabase / vercel | provider implementations |
249+
| Product | `AssetPackPatchArtifact` | patch bound to `assetPackId` |
247250

248251
### 3.1.5 Attachments (primitive → file | external)
249252

@@ -495,8 +498,9 @@ public entries remain stable (`./deposit-asset-pack-options`, `./depository-sear
495498
| `orm` | DB access, generated types, profile contract, data-health |
496499
| `files`, `browser-storage`, `artifacts` | File / storage helpers |
497500
| `streams` | Streaming progress helpers |
498-
| `aws`, `vercel`, `cloudflare`, `docker`, `kubernetes` | Host adapters |
501+
| `vercel`, `cloudflare`, `docker`, `kubernetes` | Host / infra adapters |
499502
| `supabase`, `orm` | Live data plane (Postgres via Supabase) |
503+
| `generic-artifacts-{aws,supabase,vercel}` | Artifact storage providers (S3 / Supabase / Blob) |
500504
| `postgresql`, `mysql` | Optional/legacy DB MCP tool helpers (not product storage) |
501505
| `security`, `sentry`, `observability` | Security + telemetry |
502506

internal-docs/BITCODE_SOURCE_LAYOUT.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,8 @@ packages/generic-<family>/ # README only (no package.json)
226226
| `generic-executions/` | (package root) | `@bitcode/generic-executions` (process-root Execution) |
227227
| `context-generics/` | (package root) | `@bitcode/context-generics` (BC only; no separate Context state) |
228228
| `artifact-generics/` | (package root) | `@bitcode/artifact-generics` (Artifact + storage contract) |
229-
| `generic-artifacts/` | `patch/` | `@bitcode/generic-artifacts-patch` (PatchArtifact base) |
230-
| `artifacts/` | (package root) | `@bitcode/artifacts` (S3/Supabase ArtifactStorage backend) |
229+
| `generic-artifacts/` | `patch/`, `aws/`, `supabase/`, `vercel/` | type + storage providers |
230+
| `artifacts/` | (package root) | `@bitcode/artifacts` (compose providers, BC) |
231231
| `attachment-generics/` | (package root) | `@bitcode/attachment-generics` (file|external primitives) |
232232
| `generic-attachments/` | `file/`, `external/` | `@bitcode/generic-attachments-*` |
233233
| `attachments-generics/` | (package root) | BC barrel over attachment hierarchy |

internal-docs/INTEGRATIONS.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,9 @@ Bitcode provides 20+ MCP tool integrations through the `packages/generic-tools/m
165165
### Available MCP Tools
166166

167167
#### Cloud Infrastructure
168-
1. **AWS** (`aws/`) - Amazon Web Services integration
169-
- EC2, S3, Lambda management
170-
- CloudFormation and CDK support
171-
- IAM and security management
168+
1. **AWS MCP tools** (`generic-tools/mcps-tools/aws/`) - AWS service tool stubs
169+
- Lambda, S3 get/put, Dynamo, CloudWatch placeholders
170+
- Artifact S3 storage is **not** here — use `@bitcode/generic-artifacts-aws`
172171

173172
2. **AWS Location** (`aws-location/`) - AWS Location Services
174173
- Geospatial data management

packages/artifact-generics/README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ artifact and express storage requirements without binding a backend.
88
```
99
@bitcode/artifact-generics # this package (Artifact primitive)
1010
11-
@bitcode/generic-artifacts-patch # PatchArtifact base (patchfile storage)
11+
@bitcode/generic-artifacts-patch # type: path+op patch
12+
@bitcode/generic-artifacts-aws # storage: S3
13+
@bitcode/generic-artifacts-supabase # storage: Supabase
14+
@bitcode/generic-artifacts-vercel # storage: Vercel Blob
1215
13-
@bitcode/asset-packs-synthesis # AssetPackPatchArtifact (product)
14-
@bitcode/artifacts # concrete S3/Supabase storage (BC)
16+
@bitcode/artifacts # compose providers (BC)
17+
@bitcode/asset-packs-synthesis # AssetPackPatchArtifact product
1518
```
1619

1720
## Primitive surface

packages/artifact-generics/src/index.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
* Artifact **primitive** contracts for Bitcode Protocol.
55
*
66
* Prefer:
7-
* @bitcode/artifact-generics # this package
8-
* @bitcode/generic-artifacts-patch # PatchArtifact base
9-
* @bitcode/asset-packs-synthesis # AssetPackPatchArtifact product
10-
* @bitcode/artifacts # concrete S3/Supabase storage
7+
* @bitcode/artifact-generics # this package (primitives)
8+
* @bitcode/generic-artifacts-patch # PatchArtifact type
9+
* @bitcode/generic-artifacts-aws # S3 storage provider
10+
* @bitcode/generic-artifacts-supabase # Supabase storage provider
11+
* @bitcode/generic-artifacts-vercel # Vercel Blob storage provider
12+
* @bitcode/artifacts # compose providers (BC)
1113
*/
1214

1315
export type {

packages/artifact-generics/src/storage.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
/**
22
* Artifact storage contract + requirements (backend-agnostic).
33
*
4-
* Concrete backends (S3, Supabase) implement `ArtifactStorage`.
5-
* Prefer `@bitcode/artifacts` for the default S3→Supabase implementation.
4+
* Provider bases (implement ArtifactStorage):
5+
* @bitcode/generic-artifacts-aws
6+
* @bitcode/generic-artifacts-supabase
7+
* @bitcode/generic-artifacts-vercel
8+
*
9+
* Compose via @bitcode/artifacts (aws → supabase → vercel).
610
*/
711

812
import type { ArtifactBytes, ArtifactInfo } from './types';
@@ -42,7 +46,7 @@ export const DEFAULT_ARTIFACT_CONTENT_TYPE = 'application/octet-stream';
4246

4347
/**
4448
* Backend-agnostic storage port.
45-
* Implementations: `@bitcode/artifacts` (S3 primary, Supabase fallback).
49+
* Implementations: generic-artifacts/{aws,supabase,vercel}.
4650
*/
4751
export interface ArtifactStorage {
4852
/**

packages/artifacts/README.md

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,21 @@
11
# @bitcode/artifacts
22

3-
Concrete **ArtifactStorage** (S3 primary, Supabase fallback) and BC entry for
4-
artifact persistence used by execution and logger.
3+
BC **composition** of ArtifactStorage providers. Prefer leaf packages for new code.
54

65
## Hierarchy
76

87
```
9-
@bitcode/artifact-generics Artifact primitive + storage contract
8+
@bitcode/artifact-generics
109
11-
@bitcode/generic-artifacts-patch PatchArtifact (path+op patchfiles)
10+
@bitcode/generic-artifacts-patch # artifact *type* (path+op patch)
11+
@bitcode/generic-artifacts-aws # S3 storage provider
12+
@bitcode/generic-artifacts-supabase # Supabase Storage provider
13+
@bitcode/generic-artifacts-vercel # Vercel Blob provider
1214
13-
@bitcode/asset-packs-synthesis AssetPackPatchArtifact (product)
14-
@bitcode/artifacts this package (S3/Supabase backend)
15+
@bitcode/artifacts # this package (compose: aws → supabase → vercel)
1516
```
1617

17-
## API
18-
1918
```ts
20-
import { saveArtifact, putArtifactAtKey, defaultArtifactStorage } from '@bitcode/artifacts';
21-
import type { ArtifactStorage } from '@bitcode/artifact-generics';
19+
import { saveArtifact, resolveArtifactStorage } from '@bitcode/artifacts';
20+
import { createAwsS3ArtifactStorage } from '@bitcode/generic-artifacts-aws';
2221
```
23-
24-
Prefer `@bitcode/artifact-generics` for types/contracts and
25-
`@bitcode/generic-artifacts-patch` for patch payloads.

packages/artifacts/package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "@bitcode/artifacts",
33
"version": "0.1.0",
44
"private": true,
5-
"description": "Concrete ArtifactStorage (S3/Supabase) + BC re-exports of artifact-generics",
5+
"description": "BC ArtifactStorage composition (aws | supabase | vercel providers) + artifact-generics re-exports",
66
"main": "src/artifacts.ts",
77
"types": "src/artifacts.ts",
88
"exports": {
@@ -15,7 +15,8 @@
1515
"files": ["src"],
1616
"dependencies": {
1717
"@bitcode/artifact-generics": "workspace:*",
18-
"@aws-sdk/client-s3": "^3.817.0",
19-
"@supabase/supabase-js": "^2.50.2"
18+
"@bitcode/generic-artifacts-aws": "workspace:*",
19+
"@bitcode/generic-artifacts-supabase": "workspace:*",
20+
"@bitcode/generic-artifacts-vercel": "workspace:*"
2021
}
2122
}
Lines changed: 45 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
/**
22
* @bitcode/artifacts
33
*
4-
* Concrete ArtifactStorage (S3 primary, Supabase Storage fallback) + BC barrel.
4+
* BC composition barrel: resolve ArtifactStorage from configured providers.
55
*
66
* Hierarchy:
7-
* @bitcode/artifact-generics Artifact primitive + storage contract
8-
* @bitcode/generic-artifacts-patch PatchArtifact base
9-
* @bitcode/asset-packs-synthesis AssetPackPatchArtifact product
10-
* @bitcode/artifacts this package (backend implementation)
7+
* @bitcode/artifact-generics Artifact + ArtifactStorage contract
8+
* @bitcode/generic-artifacts-patch PatchArtifact (type)
9+
* @bitcode/generic-artifacts-aws S3 provider
10+
* @bitcode/generic-artifacts-supabase Supabase Storage provider
11+
* @bitcode/generic-artifacts-vercel Vercel Blob provider
12+
* @bitcode/artifacts this package (compose + BC saveArtifact)
1113
*
12-
* Prefer importing contracts from artifact-generics and bases from
13-
* generic-artifacts-patch for new code. This package remains the default
14-
* saveArtifact / putArtifactAtKey implementation used by execution + logger.
14+
* Default order: AWS S3 → Supabase → Vercel Blob (first configured wins).
1515
*/
1616

17-
import { createClient as createSupabase } from '@supabase/supabase-js';
18-
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
19-
import * as crypto from 'crypto';
2017
import type {
2118
ArtifactBytes,
2219
ArtifactInfo,
2320
ArtifactStorage,
2421
} from '@bitcode/artifact-generics';
2522
import { DEFAULT_ARTIFACT_CONTENT_TYPE } from '@bitcode/artifact-generics';
23+
import { createAwsS3ArtifactStorage } from '@bitcode/generic-artifacts-aws';
24+
import { createSupabaseArtifactStorage } from '@bitcode/generic-artifacts-supabase';
25+
import { createVercelBlobArtifactStorage } from '@bitcode/generic-artifacts-vercel';
2626

2727
export type { ArtifactInfo, ArtifactBytes, ArtifactStorage } from '@bitcode/artifact-generics';
2828
export {
@@ -33,98 +33,55 @@ export {
3333
assertArtifactId,
3434
} from '@bitcode/artifact-generics';
3535

36-
const s3Bucket = process.env.ARTIFACT_S3_BUCKET;
37-
const supabaseUrl = process.env.SUPABASE_URL;
38-
const supabaseAnonKey =
39-
process.env.SUPABASE_ANON_KEY || process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
36+
export { createAwsS3ArtifactStorage } from '@bitcode/generic-artifacts-aws';
37+
export { createSupabaseArtifactStorage } from '@bitcode/generic-artifacts-supabase';
38+
export { createVercelBlobArtifactStorage } from '@bitcode/generic-artifacts-vercel';
4039

41-
let s3Client: S3Client | null = null;
42-
if (s3Bucket && process.env.AWS_REGION) {
43-
s3Client = new S3Client({ region: process.env.AWS_REGION });
40+
export type ArtifactStorageProviderId = 'aws' | 'supabase' | 'vercel';
41+
42+
/**
43+
* Resolve the first configured ArtifactStorage provider.
44+
* Order: aws (S3) → supabase → vercel.
45+
*/
46+
export function resolveArtifactStorage(): ArtifactStorage | null {
47+
return (
48+
createAwsS3ArtifactStorage() ??
49+
createSupabaseArtifactStorage() ??
50+
createVercelBlobArtifactStorage() ??
51+
null
52+
);
4453
}
4554

46-
let supabaseStorage: ReturnType<typeof createSupabase> | null = null;
47-
if (!s3Client && supabaseUrl && supabaseAnonKey) {
48-
supabaseStorage = createSupabase(supabaseUrl, supabaseAnonKey);
55+
function requireStorage(): ArtifactStorage {
56+
const storage = resolveArtifactStorage();
57+
if (!storage) {
58+
throw new Error(
59+
'No artifact storage backend configured (AWS S3, Supabase, or Vercel Blob).',
60+
);
61+
}
62+
return storage;
4963
}
5064

65+
/** Lazy default bound to process env (first configured provider). */
66+
export const defaultArtifactStorage: ArtifactStorage = {
67+
save: (buffer, name, contentType) =>
68+
requireStorage().save(buffer, name, contentType),
69+
putAtKey: (key, buffer, contentType) =>
70+
requireStorage().putAtKey(key, buffer, contentType),
71+
};
72+
5173
export async function saveArtifact(
5274
buffer: ArtifactBytes,
5375
name: string,
5476
contentType = DEFAULT_ARTIFACT_CONTENT_TYPE,
5577
): Promise<ArtifactInfo> {
56-
const bytes = typeof buffer === 'string' ? Buffer.from(buffer) : Buffer.from(buffer);
57-
const key = `${Date.now()}-${crypto.randomUUID()}-${name}`;
58-
59-
if (s3Client) {
60-
await s3Client.send(
61-
new PutObjectCommand({
62-
Bucket: s3Bucket,
63-
Key: key,
64-
Body: bytes,
65-
ContentType: contentType,
66-
}),
67-
);
68-
69-
const url = `https://${s3Bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`;
70-
return { url, size: bytes.length, name };
71-
}
72-
73-
if (supabaseStorage) {
74-
const { data, error } = await supabaseStorage.storage.from('artifacts').upload(key, bytes, {
75-
contentType,
76-
});
77-
if (error) throw error;
78-
const { data: publicUrlData } = supabaseStorage.storage
79-
.from('artifacts')
80-
.getPublicUrl(data?.path || key);
81-
return { url: publicUrlData.publicUrl, size: bytes.length, name };
82-
}
83-
84-
throw new Error('No artifact storage backend configured (S3 or Supabase).');
78+
return defaultArtifactStorage.save(buffer, name, contentType);
8579
}
8680

87-
/**
88-
* Put an artifact at an explicit key/path in the backing store.
89-
* Useful for stable locations (e.g., logs) that are updated over time.
90-
*/
9181
export async function putArtifactAtKey(
9282
key: string,
9383
buffer: ArtifactBytes,
9484
contentType = DEFAULT_ARTIFACT_CONTENT_TYPE,
9585
): Promise<ArtifactInfo> {
96-
const bytes = typeof buffer === 'string' ? Buffer.from(buffer) : Buffer.from(buffer);
97-
98-
if (s3Client) {
99-
await s3Client.send(
100-
new PutObjectCommand({
101-
Bucket: s3Bucket!,
102-
Key: key,
103-
Body: bytes,
104-
ContentType: contentType,
105-
}),
106-
);
107-
const url = `https://${s3Bucket}.s3.${process.env.AWS_REGION}.amazonaws.com/${key}`;
108-
return { url, size: bytes.length, name: key };
109-
}
110-
111-
if (supabaseStorage) {
112-
const { data, error } = await supabaseStorage.storage.from('artifacts').upload(key, bytes, {
113-
contentType,
114-
upsert: true,
115-
} as any);
116-
if (error) throw error;
117-
const { data: publicUrlData } = supabaseStorage.storage
118-
.from('artifacts')
119-
.getPublicUrl((data as any)?.path || key);
120-
return { url: publicUrlData.publicUrl, size: bytes.length, name: key };
121-
}
122-
123-
throw new Error('No artifact storage backend configured (S3 or Supabase).');
86+
return defaultArtifactStorage.putAtKey(key, buffer, contentType);
12487
}
125-
126-
/** Default ArtifactStorage bound to process env (S3 → Supabase). */
127-
export const defaultArtifactStorage: ArtifactStorage = {
128-
save: saveArtifact,
129-
putAtKey: putArtifactAtKey,
130-
};

0 commit comments

Comments
 (0)