The ObjectStore interface
Everything in git-fs-s3 is built on one small interface. createGitFs doesn’t
know or care whether the bytes underneath come from R2, S3, memory, or
something else entirely — it only calls these five methods.
interface ObjectStore { get(key: string): Promise<Uint8Array | null>; getRange?(key: string, start: number, end: number): Promise<Uint8Array | null>; put(key: string, data: Uint8Array): Promise<void>; delete(key: string): Promise<void>; head(key: string): Promise<ObjectStat | null>; list(prefix: string, options?: ListOptions): Promise<ListResult>;}The five methods above are required. getRange is optional — implement it if
your backend can read a byte range without fetching the whole object.
Method contracts
Section titled “Method contracts”getget(key: string): Promise<Uint8Array | null>| Parameter | Type | Description |
|---|---|---|
key | string | The full object key. |
Returns: Uint8Array | null
The object’s bytes, or null if the key doesn’t exist. Never throws for a
missing key.
getRangegetRange?(key: string, start: number, end: number): Promise<Uint8Array | null>| Parameter | Type | Description |
|---|---|---|
key | string | The full object key. |
start | number | First byte to return, inclusive. |
end | number | Last byte to return, inclusive. |
Returns: Uint8Array | null
Optional. Bytes start..end of the object, inclusive at both ends,
or null if the key doesn’t exist. A store that can’t serve ranges leaves
the method undefined, and getObjectSize then reports null (“size
unknown”) rather than fetching a whole pack to answer. That fallback is the
point: range reads are what let a caller ask is this object too large?
without paying for the pack that holds it. Exposed on the git-aware fs as
fs.promises.getRange, again only when the backing store has it, and
forwarded by createCachedStore straight to the backing store — a few
bytes at a known offset gain nothing from the cache.
putput(key: string, data: Uint8Array): Promise<void>| Parameter | Type | Description |
|---|---|---|
key | string | The full object key. |
data | Uint8Array | The bytes to store. |
Writes (or overwrites) an object. Object storage has no atomic multi-key transactions — a caller that needs several keys to become visible together needs its own coordination (see Semantics & limitations).
deletedelete(key: string): Promise<void>| Parameter | Type | Description |
|---|---|---|
key | string | The full object key. |
Removes an object. Deleting a key that doesn’t exist is not an error.
headhead(key: string): Promise<ObjectStat | null>| Parameter | Type | Description |
|---|---|---|
key | string | The full object key. |
Returns: ObjectStat | null
Existence + size, without transferring the object body — { size: number },
or null if the key doesn’t exist.
listlist(prefix: string, options?: ListOptions): Promise<ListResult>| Parameter | Type | Description |
|---|---|---|
prefix | string | Only keys starting with this prefix. |
options? | ListOptions | delimiter (directory-style grouping) and limit. |
Returns: ListResult
{ objects: { key, size }[], prefixes: string[] }. When options.delimiter
is set (git-fs-s3 always uses "/"), keys are grouped: anything after the
first delimiter past prefix collapses into one entry in prefixes
instead of appearing in objects — this is what makes readdir() work
against storage that has no real directories.
Writing your own store
Section titled “Writing your own store”Implement the interface above for any backend and pass it straight to
createGitFs — every other piece (caching, retry, the git-aware layer,
/http, /ops) works unmodified on top of it.
MemoryObjectStore (exported from the root package) is the reference
implementation — read it first. It’s also the store used throughout this
package’s own test suite, and the one you’ll reach for in yours:
import { createGitFs, MemoryObjectStore } from 'git-fs-s3';
const fs = createGitFs(new MemoryObjectStore());S3ObjectStore
Section titled “S3ObjectStore”The one storage backend shipped out of the box, over @aws-sdk/client-s3
(an optional peer dependency, loaded only via the /s3 subpath so
consumers who don’t need it don’t pay for it).
import { S3ObjectStore } from 'git-fs-s3/s3';
const store = new S3ObjectStore({ client, // reuse one S3Client — see the note below bucket: 'my-git-repos', prefix: 'repos/', // optional: a fixed prefix under every key contentType: (key) => /\/(HEAD|config)$|\/refs\//.test(key) ? 'text/plain' : undefined,});S3ObjectStore implements the optional getRange (an S3 Range header,
inclusive at both ends), which getObjectSize uses to answer a size without
fetching the object.