golazy.dev golazy.dev / lazystorage Index | Files | Directories

package lazystorage

import "golazy.dev/lazystorage"

Package lazystorage defines small interfaces for object-style storage.

Storage is the minimum read contract: Open receives an object key and returns a File that can be read, closed, and inspected with Stat. Optional interfaces add capabilities one at a time. Writer stores bytes with Put, Deleter removes a key, Lister returns object metadata below a prefix, URLer resolves an externally usable URL, and Watcher streams backend change events. Callers should test for the optional interface they need instead of assuming every backend can write, list, delete, or sign URLs.

Object keys are slash-separated logical paths, not host filesystem paths. ValidateKey applies io/fs path rules: keys must be relative, clean, and must not be ".". The local filesystem backend maps those keys below its configured root; S3-compatible and PostgreSQL backends store the same logical key in the remote bucket or database row. Prefixes passed to List and Watch use the same logical form and are matched by key prefix.

The variadic options are intentionally open-ended so storage can be composed with higher-level packages. An implementation consumes the options it knows and returns the remaining options to its caller. For example, filesystem Put consumes ContentType and leaves unknown options untouched, while lazystorage/s3 and pg/pgstorage also consume CacheControl and ContentDisposition. URL options such as ExpiresIn, ExpiresAt, Public, Private, and DownloadName are requests; a backend may use them, pass them through, or reject the operation when it cannot provide the requested URL. Use Take when writing decorators or services that need this same consume-and-forward behavior.

Info is metadata about the stored object. Key is always the logical key. ContentType, Size, Checksum, and ModifiedAt are best-effort backend metadata: filesystem writes compute a sha256 checksum and detect content type when not supplied, listing filesystem objects reports file size and modification time, and remote backends expose whatever their implementation can read cheaply. Metadata is reserved for backend-specific values that do not deserve their own portable field.

Higher-level packages depend on these narrow contracts. lazyassets.Registry uploads generated assets through a Writer, forwarding content type and cache policy for permanent hashed files and the manifest. lazyfiles stores file records separately from bytes and writes/opens those bytes through configured lazystorage backends; when a backend implements URLer, lazyfiles can return that direct URL, otherwise it falls back to application routes. lazymedia stores original media and generated variants through lazyfiles and lazystorage-backed file stores.

Use NewFilesystem for standalone local storage or development storage. Package lazystorage/s3 provides an S3-compatible backend for object stores such as AWS S3, MinIO, or SeaweedFS. The pg/pgstorage package in the golazy.dev/pg module provides a PostgreSQL implementation and migrations when keeping object bytes in the application database is the right tradeoff.

Functions

func Take[T any]

Take removes the first option assignable to T and returns it with the remaining options. It is useful for director implementations that consume recognized options and pass unknown ones downstream.

func Take[T any](options []any) (T, []any, bool)

func ValidateKey

ValidateKey validates an object key using io/fs path rules.

func ValidateKey(key string) error

Types

type Deleter

Deleter is implemented by storages that can delete objects.

type Deleter interface {
	Delete(context.Context, string, ...any) ([]any, error)
}

type Event

Event describes a storage change.

type Event struct {
	Key	string
	Op	string
}

type Events

Events streams storage change events.

type Events interface {
	Next(context.Context) (Event, error)
	Close() error
}

type ExpiresIn

ExpiresIn requests a URL or token that expires after Duration.

type ExpiresIn struct {
	Duration time.Duration
}

type File

File is an opened object. Callers must close it.

type File interface {
	io.Reader
	io.Closer
	Stat() (Info, error)
}

type Filesystem

Filesystem stores objects under a local root directory.

type Filesystem struct {
	// contains filtered or unexported fields
}
func NewFilesystem

NewFilesystem creates a filesystem storage rooted at root.

func NewFilesystem(root string, options ...FilesystemOption) *Filesystem
func (s *Filesystem) Delete

Delete removes key.

func (s *Filesystem) Delete(ctx context.Context, key string, options ...any) ([]any, error)
func (s *Filesystem) List

List lists object metadata below prefix.

func (s *Filesystem) List(ctx context.Context, prefix string, options ...any) (Iterator, []any, error)
func (s *Filesystem) Open

Open opens key for reading.

func (s *Filesystem) Open(ctx context.Context, key string, options ...any) (File, []any, error)
func (s *Filesystem) Put

Put writes key atomically where the host filesystem supports rename.

func (s *Filesystem) Put(ctx context.Context, key string, body io.Reader, options ...any) (Info, []any, error)
func (s *Filesystem) URL

URL returns a public URL only when Filesystem was configured with a base URL.

func (s *Filesystem) URL(ctx context.Context, key string, options ...any) (URL, []any, error)

type Info

Info describes a stored object.

type Info struct {
	Key		string
	ContentType	string
	Size		int64
	Checksum	string
	ModifiedAt	time.Time
	Metadata	map[string]any
}

type Lister

Lister is implemented by storages that can list object keys.

type Lister interface {
	List(context.Context, string, ...any) (Iterator, []any, error)
}

type Private

Private requests private access when the backend supports access policy.

type Private struct{}

type Public

Public requests public access when the backend supports access policy.

type Public struct{}

type Storage

Storage is the minimum read capability for a named object store.

type Storage interface {
	Open(context.Context, string, ...any) (File, []any, error)
}

type URLer

URLer is implemented by storages that can expose object URLs.

type URLer interface {
	URL(context.Context, string, ...any) (URL, []any, error)
}

type Watcher

Watcher is implemented by storages that can watch for object changes.

type Watcher interface {
	Watch(context.Context, string, ...any) (Events, []any, error)
}

type Writer

Writer is implemented by storages that can write objects.

type Writer interface {
	Put(context.Context, string, io.Reader, ...any) (Info, []any, error)
}

Directories

Path Synopsis
lazystorage/s3 Package s3 provides an S3-compatible lazystorage backend.