attachments

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2026 License: MIT Imports: 48 Imported by: 0

Documentation

Overview

Package attachments owns typed model collections and recoverable storage workflows. Applications declare policy once and pass typed owner references.

Index

Constants

View Source
const (
	MaxUploadBytes     int64 = 64 << 20
	MaxCollectionFiles       = 256
	MaxOwnerIntents          = 4096
	MaxPropertiesBytes       = 64 << 10
)
View Source
const (
	DefaultMaxReads    = 64
	DefaultSettleAfter = 15 * time.Minute
	// MaxOwnerCleanup bounds concurrent owner-delete observers per manager.
	MaxOwnerCleanup = 4096
)
View Source
const (
	MigrationOrigin   migrate.Origin  = "foundry.attachments"
	CreateAttachments migrate.ID      = "000001_create_attachments"
	CreateVariants    migrate.ID      = "000002_create_variants"
	Introduced        migrate.Version = "v0.1.0"
)
View Source
const (
	MaxBatchFiles           = 4096
	MaxBatchPropertiesBytes = 4 << 20
)
View Source
const MaxRegenerationBatch = 100
View Source
const (
	// MaxVariants bounds declared variants per collection.
	MaxVariants = 8
)

Variables

View Source
var ActiveContentRefused = safeerror.Sentinel(fault.Invalid, "script-capable attachment cannot be linked inline")

ActiveContentRefused reports an inline link to a script-capable attachment (SVG, HTML, XML, JavaScript) whose policy does not set InlineActiveContent. It matches fault.Invalid.

View Source
var VariantUnavailable = safeerror.Sentinel(fault.Missing, "attachment variant is not available")

VariantUnavailable reports a declared variant that has not been generated (yet) for an attachment, for example while its job is queued. It matches fault.Missing.

Functions

func Cleanup

func Cleanup[M any, K comparable](ctx context.Context, tx *database.Tx, m *Manager, owner extensions.Owner[M, K], reference model.Reference[M, K], operation lifecycle.Operation, queue *Queue) error

Cleanup joins a generated owner's transactional Deleted/ForceDeleted observer. Soft deletion preserves files for restoration. Ready/stored ownership changes and optional job outbox rows roll back with the owner. Writing/uncertain intents remain visible for settlement; they cannot be deleted based on owner absence.

func CleanupIdentity

func CleanupIdentity(ctx context.Context, tx *database.Tx, m *Manager, owner extensions.OwnerName, identity model.Identity, queue *Queue) error

CleanupIdentity is Cleanup for an owner known by its registered name and persisted identity, such as a durable cleanup job's request. It joins tx, rejects an owner that still exists and deletes stored objects after commit.

func Matching

func Matching[M any, K comparable](ctx context.Context, manager *Manager, collection Collection[M, K]) (orm.Predicate[M], error)

Matching materializes a bounded ORM owner predicate for ready attachments in the collection and exact locale. It uses the manager's existing matching limits, validation and cancellation. The declaration must have an ORM owner. No match produces a false predicate; the subsequent owner query retains its own fresh visibility and authorization. This is a snapshot of matching keys, not a live subquery. Example: predicate, err := attachments.Matching(ctx, manager, Avatar.ForLocale("en")); then Owners.Query().Where(predicate).

func Migrations

func Migrations() []migrate.Definition

func Module

func Module(name foundation.ProviderID, key foundation.Key[*Manager], requires []foundation.ProviderID, construct func(foundation.Resolver) (*Manager, error)) foundation.Module

Module owns the manager and requires providers owning its borrowed store, disks, image engine and locale catalog. Workers invoking it must stop first.

Types

type Attachment

type Attachment[M any, K comparable] struct {
	File[M]
	// contains filtered or unexported fields
}

Attachment is a ready File with its typed owner reference.

func (Attachment[M, K]) Format

func (Attachment[M, K]) Format(s fmt.State, _ rune)

func (Attachment[M, K]) MarshalJSON

func (Attachment[M, K]) MarshalJSON() ([]byte, error)

func (Attachment[M, K]) Owner

func (a Attachment[M, K]) Owner() model.Reference[M, K]

type Batch

type Batch[M any, K comparable] struct {
	// contains filtered or unexported fields
}

func (Batch[M, K]) Get

func (b Batch[M, K]) Get(owner model.Reference[M, K]) ([]Attachment[M, K], error)

type BeforeContext

type BeforeContext[M any, K comparable] struct {
	Owner      model.Reference[M, K]
	Collection Name
	Locale     value.Optional[i18n.LocaleID]
	Upload     UploadInfo
}

BeforeContext contains detected metadata, not the caller-owned reader or a mutable image buffer. The application can authorize through Owner.Key().

type Cardinality

type Cardinality uint8
const (
	Single Cardinality = iota + 1
	Multiple
)

type ChangeResult

type ChangeResult struct {
	Publication    Publication
	Affected       int
	PendingCleanup []OperationID
}

type Collection

type Collection[M any, K comparable] struct {
	// contains filtered or unexported fields
}

func Define

func Define[M any, K comparable](owner extensions.Owner[M, K], name Name, policy Policy, hooks ...Hook[M, K]) Collection[M, K]

func ManyCollection

func ManyCollection[M any, K comparable](slot ManyHandle[M, K]) Collection[M, K]

ManyCollection returns the multiple-slot declaration for explicit batch reads and matching. It preserves registration identity and policy; a zero handle returns an invalid zero collection. Example: attachments.ManyCollection(bound.Gallery).List(ctx,manager,reference).

func OneCollection

func OneCollection[M any, K comparable](slot OneHandle[M, K]) Collection[M, K]

OneCollection returns the single-slot declaration for explicit collection operations. It preserves registration identity and policy; a zero handle returns an invalid zero collection. Example: attachments.OneCollection(bound.Logo).List(ctx,manager,reference).

func (Collection[M, K]) Add

func (c Collection[M, K]) Add(ctx context.Context, m *Manager, owner model.Reference[M, K], upload Upload) (Result[M, K], error)

Add appends to a multiple collection and replaces a single collection.

func (Collection[M, K]) AddFromURL

func (c Collection[M, K]) AddFromURL(ctx context.Context, m *Manager, owner model.Reference[M, K], source RemoteSource) (Result[M, K], error)

AddFromURL downloads one remote file within the collection's MaxBytes and adds it exactly like Add. Acceptance is detected from the downloaded bytes; the response Content-Type is only a hint. Redirects and non-2xx responses fail without adding a file. Manager admission covers the complete download, validation, storage and publication, retaining one bounded input buffer. Image processing remains subject to the image engine's separate limits.

func (Collection[M, K]) AddIn

func (c Collection[M, K]) AddIn(ctx context.Context, tx *database.Tx, m *Manager, owner model.Reference[M, K], prepared Prepared[M, K]) (Result[M, K], error)

AddIn publishes a prepared upload into owner's collection inside tx, a transaction of the extension store's pool, using only that transaction: the owner may be one tx created, and the attachment becomes visible when tx commits. A failure, including a rollback, leaves the prepared upload for Discard or ReconcilePending. Old-object cleanup and unqueued variant generation run after tx commits; their failure is the transaction's after-commit error and leaves work for ReconcilePending.

func (Collection[M, K]) Clear

func (c Collection[M, K]) Clear(ctx context.Context, m *Manager, owner model.Reference[M, K]) (ChangeResult, error)

func (Collection[M, K]) Detach

func (c Collection[M, K]) Detach(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M]) (ChangeResult, error)

func (Collection[M, K]) DetachKeepFile

func (c Collection[M, K]) DetachKeepFile(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M]) (RetainResult, error)

DetachKeepFile removes collection membership without deleting storage. The durable retained state survives owner deletion and ordinary orphan pruning.

func (Collection[M, K]) Discard

func (c Collection[M, K]) Discard(ctx context.Context, m *Manager, prepared Prepared[M, K]) error

Discard reclaims a prepared upload that will not be published, instead of leaving it to ReconcilePending. A published upload is refused and kept.

func (Collection[M, K]) Find

func (c Collection[M, K]) Find(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M]) (Attachment[M, K], error)

func (Collection[M, K]) First

func (c Collection[M, K]) First(ctx context.Context, m *Manager, owner model.Reference[M, K]) (value.Optional[Attachment[M, K]], error)

func (Collection[M, K]) ForLocale

func (c Collection[M, K]) ForLocale(locale i18n.LocaleID) Collection[M, K]

func (Collection[M, K]) Format

func (Collection[M, K]) Format(s fmt.State, _ rune)

func (Collection[M, K]) Image

func (c Collection[M, K]) Image(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M], plan imaging.Plan) (imaging.Result, error)

func (Collection[M, K]) List

func (c Collection[M, K]) List(ctx context.Context, m *Manager, owner model.Reference[M, K]) ([]Attachment[M, K], error)

func (Collection[M, K]) Load

func (c Collection[M, K]) Load(ctx context.Context, m *Manager, owners []model.Reference[M, K]) (Batch[M, K], error)

func (Collection[M, K]) LoadLocalized

func (c Collection[M, K]) LoadLocalized(ctx context.Context, m *Manager, owners []model.Reference[M, K]) (LocalizedBatch[M, K], error)

func (Collection[M, K]) Name

func (c Collection[M, K]) Name() Name

func (Collection[M, K]) Open

func (c Collection[M, K]) Open(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M]) (io.ReadCloser, Attachment[M, K], error)

Open streams an attachment pinned to its stored ETag/version. The full SHA-256 and length are verified at EOF (by the disk when the stored checksum matches the pin, otherwise here). Only the lookup uses manager read admission; the returned reader holds one disk stream slot until Close. Always close it, and close it before closing the disk.

func (Collection[M, K]) Prepare

func (c Collection[M, K]) Prepare(ctx context.Context, m *Manager, owner model.Reference[M, K], upload Upload) (Prepared[M, K], error)

Prepare reads, checks and stores upload for owner's collection without publishing it, in the manager's own transactions. Call it before the transaction that publishes it begins, so that transaction needs only its own connection and sees the stored upload. An existing owner is locked while the upload is recorded, keeping its intent bound exact; owner may also be a model the publishing transaction creates, with its key chosen beforehand. On an error the returned value names any recorded intent.

func (Collection[M, K]) PublicURL

func (c Collection[M, K]) PublicURL(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M]) (string, error)

PublicURL rechecks ready membership, then derives the public URL of the pinned object. Keys are immutable per upload, so no storage request is made.

func (Collection[M, K]) PublicURLOf

func (c Collection[M, K]) PublicURLOf(ctx context.Context, m *Manager, file Attachment[M, K]) (string, error)

PublicURLOf derives the public URL of an attachment already loaded through this collection (for example from Load or List) without database or storage I/O. Authorize access to the attachment first; the URL does not.

func (Collection[M, K]) PublicURLsOf

func (c Collection[M, K]) PublicURLsOf(ctx context.Context, m *Manager, files []Attachment[M, K]) ([]string, error)

PublicURLsOf maps loaded attachments to public URLs in order, for listing responses. It performs no database or storage I/O.

func (Collection[M, K]) ReadBytes

func (c Collection[M, K]) ReadBytes(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M], maximum int64) ([]byte, error)

func (Collection[M, K]) RegenerateVariants

func (c Collection[M, K]) RegenerateVariants(ctx context.Context, m *Manager, options RegenerationOptions) (RegenerationPage, error)

RegenerateVariants processes one batch of this collection's ready attachments in ID order under one write admission slot.

func (Collection[M, K]) Registration

func (c Collection[M, K]) Registration() Registration

func (Collection[M, K]) Reorder

func (c Collection[M, K]) Reorder(ctx context.Context, m *Manager, owner model.Reference[M, K], order []ID[M]) ([]Attachment[M, K], error)

Reorder accepts an exact permutation of current ready collection IDs. No omission, duplicate or foreign ID can partially change the stored ordering.

func (Collection[M, K]) Replace

func (c Collection[M, K]) Replace(ctx context.Context, m *Manager, owner model.Reference[M, K], upload Upload) (Result[M, K], error)

Replace atomically replaces the complete collection membership. Old objects are eligible for cleanup only after this ownership transaction commits.

func (Collection[M, K]) ReplaceIn

func (c Collection[M, K]) ReplaceIn(ctx context.Context, tx *database.Tx, m *Manager, owner model.Reference[M, K], prepared Prepared[M, K]) (Result[M, K], error)

ReplaceIn publishes a prepared upload as owner's complete collection inside tx; see AddIn.

func (Collection[M, K]) Resolve

func (c Collection[M, K]) Resolve(ctx context.Context, m *Manager, owner model.Reference[M, K], requested i18n.LocaleID) (value.Optional[Resolved[M, K]], error)

func (Collection[M, K]) SetProperties

func (c Collection[M, K]) SetProperties(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M], properties value.JSON[json.RawMessage]) (Attachment[M, K], error)

SetProperties replaces explicit dynamic object metadata, never storage pins, owner identity or collection policy.

func (Collection[M, K]) TemporaryURL

func (c Collection[M, K]) TemporaryURL(ctx context.Context, m *Manager, owner model.Reference[M, K], id ID[M], expires time.Duration) (storage.TemporaryURL, error)

TemporaryURL rechecks ready membership, then signs a read link pinned to the stored version. Signing performs no storage request.

func (Collection[M, K]) TemporaryURLOf

func (c Collection[M, K]) TemporaryURLOf(ctx context.Context, m *Manager, file Attachment[M, K], options storage.LinkOptions) (storage.TemporaryURL, error)

TemporaryURLOf signs a read link for a loaded attachment, pinned to its stored version, without database or storage I/O. options.Version must be zero; response overrides (for example a download Content-Disposition using the original name) are signed into the link.

func (Collection[M, K]) Validate

func (c Collection[M, K]) Validate() error

func (Collection[M, K]) VariantPublicURLOf

func (c Collection[M, K]) VariantPublicURLOf(ctx context.Context, m *Manager, file Attachment[M, K], variant Variant) (string, error)

VariantPublicURLOf derives the public URL of a generated variant of a loaded attachment without database or storage I/O. It fails with VariantUnavailable until the variant has been generated.

func (Collection[M, K]) VariantTemporaryURLOf

func (c Collection[M, K]) VariantTemporaryURLOf(ctx context.Context, m *Manager, file Attachment[M, K], variant Variant, options storage.LinkOptions) (storage.TemporaryURL, error)

VariantTemporaryURLOf signs a read link for a generated variant, pinned to its stored version, without database or storage I/O.

func (Collection[M, K]) WithReconciliation

func (c Collection[M, K]) WithReconciliation(queue Queue) Collection[M, K]

WithReconciliation binds ordinary job/outbox publication after service assembly without changing this collection's registered policy or identity.

func (Collection[M, K]) WithVariantQueue

func (c Collection[M, K]) WithVariantQueue(queue VariantQueue) Collection[M, K]

WithVariantQueue generates this collection's variants through the queued job instead of synchronously after each upload. It does not change the collection's registered policy or identity.

type Config

type Config struct {
	MaxActive      int
	MaxReads       int
	Timeout        time.Duration
	CleanupTimeout time.Duration
	StoredGrace    time.Duration
	SettleAfter    time.Duration
}

Config bounds manager work. MaxActive admits uploads and other mutations, including the complete remote download, validation and persistence lifetime; MaxReads separately admits loads, lookups, reads and link signing, so a burst of reads cannot starve writes (or the reverse). Both queue briefly (at most min(Timeout, 5s)) before failing as retryable overload. Owner-delete cleanup joined from model observers uses its own MaxOwnerCleanup pool so it does not compete with application reads/writes. SettleAfter is added to a disk's operation Timeout before ReconcilePending may inspect an unresolved write. Zero MaxReads or SettleAfter selects its default.

func DefaultConfig

func DefaultConfig() Config

func (Config) Validate

func (c Config) Validate() error

type Cursor

type Dependencies

type Dependencies struct {
	Store   *extensions.Store
	Disks   *storage.Registry
	Image   *imaging.Engine
	Locales i18n.LocaleCatalog
}

Dependencies are borrowed. Image and Locales are required only by collections that use them. Their owners must outlive this manager's actual operations.

type File

type File[M any] struct {
	// contains filtered or unexported fields
}

File is the owner-free view of one ready attachment: identity, collection, detected metadata, properties and ready variants. Model slots hold Files; Attachment adds the typed owner reference.

func (File[M]) Collection

func (f File[M]) Collection() Name

func (File[M]) CreatedAt

func (f File[M]) CreatedAt() temporal.DateTime

func (File[M]) EmailAttachment

func (f File[M]) EmailAttachment() (email.Attachment, error)

EmailAttachment snapshots this ready file into email's durable reference. No bytes are read. Authorize the file before use and retain its object for queued delivery. The mailer must have access to the same configured disk. Attachment promotes this method from its embedded File.

func (File[M]) Format

func (File[M]) Format(s fmt.State, _ rune)

func (File[M]) ID

func (f File[M]) ID() ID[M]

func (File[M]) Info

func (f File[M]) Info() UploadInfo

func (File[M]) IsZero

func (f File[M]) IsZero() bool

func (File[M]) Locale

func (f File[M]) Locale() value.Optional[i18n.LocaleID]

func (File[M]) MarshalJSON

func (File[M]) MarshalJSON() ([]byte, error)

func (File[M]) Position

func (f File[M]) Position() int32

func (File[M]) Properties

func (f File[M]) Properties() (json.RawMessage, error)

func (File[M]) Variant

func (f File[M]) Variant(variant Variant) (VariantInfo, bool)

Variant reports whether the declared variant has been generated.

func (File[M]) Variants

func (f File[M]) Variants() []VariantInfo

Variants returns the attachment's generated variants, ordered by name.

type FileOf

type FileOf[M any] struct {
	// contains filtered or unexported fields
}

type FileSource

type FileSource = upload.Source

FileSource is an upload the framework can open and read, such as foundryhttp.UploadedFile, which satisfies it without attachments importing HTTP. An operation opens it, reads within the policy's MaxBytes and closes its reader before returning; the caller keeps owning the underlying file. Detected bytes decide acceptance: Name is display metadata and ClientContentType only the existing text-specialization hint.

type Hook

type Hook[M any, K comparable] struct {
	Before      func(context.Context, BeforeContext[M, K]) error
	AfterStored func(context.Context, *database.Tx, Attachment[M, K]) error
}

Hooks execute in declaration order. AfterStored runs inside the ownership transaction after storage succeeds and can veto publication. External effects from that hook must use an ordinary transactional outbox or after-commit hook.

type ID

type ID[M any] = model.ID[FileOf[M]]

type LocalizedBatch

type LocalizedBatch[M any, K comparable] struct {
	// contains filtered or unexported fields
}

LocalizedBatch captures one catalog and owner/attachment snapshot. Resolving many owners or changing the requested locale performs no further I/O.

func (LocalizedBatch[M, K]) Get

func (b LocalizedBatch[M, K]) Get(owner model.Reference[M, K]) (LocalizedFiles[M, K], error)

type LocalizedFiles

type LocalizedFiles[M any, K comparable] struct {
	// contains filtered or unexported fields
}

func (LocalizedFiles[M, K]) List

func (f LocalizedFiles[M, K]) List(locale i18n.LocaleID) ([]Attachment[M, K], error)

func (LocalizedFiles[M, K]) Resolve

func (f LocalizedFiles[M, K]) Resolve(requested i18n.LocaleID) (value.Optional[Resolved[M, K]], error)

Resolve chooses the first nonempty collection in requested/default/remaining lexical locale order. It never mixes files from different locale collections.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

func New

func New(dependencies Dependencies, config Config, collections ...Registration) (*Manager, error)

func (*Manager) Close

func (m *Manager) Close(ctx context.Context) error

Close cancels reads, writes and owner cleanup together and waits for their actual exit. A timed-out wait keeps ownership visible through Done.

func (*Manager) Done

func (m *Manager) Done() <-chan struct{}

func (*Manager) GenerateVariants

func (m *Manager) GenerateVariants(ctx context.Context, id OperationID) error

GenerateVariants derives every declared variant still missing for one ready attachment. It is idempotent and is the handler of the variant job; an original that is no longer ready has nothing to generate.

func (*Manager) Inspect

func (m *Manager) Inspect(ctx context.Context, id OperationID) (ReconcileResult, error)

Inspect is an administrative, read-only lookup of a durable upload operation. Ready confirms publication; cleanup/cleaned confirms retirement. A writing or uncertain state cannot establish that a remote storage request has settled.

func (*Manager) InspectOrphans

func (m *Manager) InspectOrphans(ctx context.Context, owner extensions.OwnerName, cursor Cursor, limit int) (OrphanPage, error)

func (*Manager) InspectStorage

func (m *Manager) InspectStorage(ctx context.Context, options StorageInspection) (StorageOrphanPage, error)

InspectStorage lists one bounded page under this owner's exact framework prefix on a registered collection disk, then checks those keys in one query. Every journal state protects its object, including unsettled writes. Untracked candidates are inspection results only: their age never authorizes deletion.

func (*Manager) PruneOrphans

func (m *Manager) PruneOrphans(ctx context.Context, owner extensions.OwnerName, ids []OperationID, queue *Queue) (ChangeResult, error)

PruneOrphans only retires ready/stored orphan rows selected explicitly. It preserves soft-deleted owners, and refuses unsettled writers instead of treating owner absence as permission to delete a possibly in-flight upload.

func (*Manager) Reconcile

func (m *Manager) Reconcile(ctx context.Context, id OperationID) (ReconcileResult, error)

func (*Manager) ReconcilePending

func (m *Manager) ReconcilePending(ctx context.Context, limit int) ([]ReconcileResult, error)

ReconcilePending is an explicit bounded sweep, suitable for an ordinary scheduled job. It retries Cleanup and abandons old Stored intents after the configured grace. Writing/Uncertain intents older than the settlement cutoff are inspected with Stat and settled only when storage is unambiguous: absent, or present with this intent's exact size and full checksum. Anything else stays Uncertain for operator Settle. Locally active writers are excluded. The same sweep retries variant cleanup and settles aged variant intents.

func (*Manager) RegenerateVariants

func (m *Manager) RegenerateVariants(ctx context.Context, owner extensions.OwnerName, collection Name, options RegenerationOptions) (RegenerationPage, error)

RegenerateVariants is the name-addressed form used by operational commands.

func (*Manager) RetainedObject

func (m *Manager) RetainedObject(ctx context.Context, id OperationID) (RetainedFile, error)

RetainedObject is an administrative recovery lookup after an uncertain DetachKeepFile commit. It grants no access to ready or unsettled upload pins.

func (*Manager) Settle

func (m *Manager) Settle(ctx context.Context, id OperationID, settlement Settlement, queue *Queue) (ReconcileResult, error)

Settle abandons an unresolved upload after an explicit operator assertion. It never publishes attachment ownership. A matching object is read through a pinned validator and checksum-verified before being scheduled for cleanup.

func (*Manager) Validate

func (m *Manager) Validate() error

type Many

type Many[M any] struct {
	// contains filtered or unexported fields
}

Many is a model slot holding the ready files of a multiple-file collection in collection order. The zero value is not loaded.

func (Many[M]) All

func (m Many[M]) All() iter.Seq2[int, File[M]]

All yields each loaded file in collection order without copying the slice.

func (Many[M]) Format

func (Many[M]) Format(s fmt.State, _ rune)

func (Many[M]) Get

func (m Many[M]) Get() ([]File[M], bool)

Get returns a caller-owned copy of the files and whether the slot was loaded.

func (Many[M]) IsLoaded

func (m Many[M]) IsLoaded() bool

IsLoaded reports whether the slot was filled by a loader.

func (Many[M]) Len

func (m Many[M]) Len() int

Len reports the number of loaded files; it is zero when not loaded.

func (Many[M]) MarshalJSON

func (Many[M]) MarshalJSON() ([]byte, error)

type ManyHandle

type ManyHandle[M any, K comparable] struct {
	// contains filtered or unexported fields
}

ManyHandle retains typed slot capabilities behind shared callback state. Example: slot.From(manager).Relation(Fields.Slot).

func ManyOf

func ManyOf[M any, K comparable](owner extensions.Owner[M, K], name Name, policy Policy, binding extensions.SlotBinding[M, K, Many[M]]) ManyHandle[M, K]

ManyOf declares a thin multiple-file handle with the existing manager policy. Example: attachments.ManyOf(owner,"files",policy,binding).

func (ManyHandle[M, K]) Accepts

func (s ManyHandle[M, K]) Accepts(ctx context.Context, file FileSource) (bool, error)

Accepts checks policy using the existing manager admission and media checks. Example: slot.Accepts(ctx,file).

func (ManyHandle[M, K]) Add

func (s ManyHandle[M, K]) Add(ctx context.Context, owner M, upload Upload) (Result[M, K], error)

Add appends an upload to the multiple-file collection. Example: slot.Add(ctx,article,upload).

func (ManyHandle[M, K]) AddFile

func (s ManyHandle[M, K]) AddFile(ctx context.Context, owner M, file FileSource) (Result[M, K], error)

AddFile appends a file to the multiple-file collection. Example: slot.AddFile(ctx,article,file).

func (ManyHandle[M, K]) AddIn

func (s ManyHandle[M, K]) AddIn(ctx context.Context, tx *database.Tx, owner M, prepared Prepared[M, K]) (Result[M, K], error)

AddIn publishes a prepared upload in the caller transaction. Example: slot.AddIn(ctx,tx,article,prepared).

func (ManyHandle[M, K]) Clear

func (s ManyHandle[M, K]) Clear(ctx context.Context, owner M) (ChangeResult, error)

Clear retires every file and schedules storage cleanup. Example: slot.Clear(ctx,article).

func (ManyHandle[M, K]) Describe

func (s ManyHandle[M, K]) Describe() extensions.SlotDescription

Describe returns an owned inspection snapshot. Example: slot.Describe().

func (ManyHandle[M, K]) Detach

func (s ManyHandle[M, K]) Detach(ctx context.Context, owner M, id ID[M]) (ChangeResult, error)

Detach retires one file and schedules storage cleanup. Example: slot.Detach(ctx,article,id).

func (ManyHandle[M, K]) Discard

func (s ManyHandle[M, K]) Discard(ctx context.Context, prepared Prepared[M, K]) error

Discard reclaims an unpublished prepared upload. Example: slot.Discard(ctx,prepared).

func (ManyHandle[M, K]) Format

func (ManyHandle[M, K]) Format(s fmt.State, _ rune)

Format omits retained runtime state. Example: fmt.Sprintf("%+v",slot).

func (ManyHandle[M, K]) From

func (s ManyHandle[M, K]) From(m *Manager) ManyHandle[M, K]

From returns a copy borrowing this family's manager; nil leaves it unbound. Example: slot.From(manager).

func (ManyHandle[M, K]) Name

func (s ManyHandle[M, K]) Name() Name

Name returns the stored name. Example: slot.Name().

func (ManyHandle[M, K]) Prepare

func (s ManyHandle[M, K]) Prepare(ctx context.Context, owner M, upload Upload) (Prepared[M, K], error)

Prepare prepares storage before a transaction without publishing it. Example: slot.Prepare(ctx,article,upload).

func (ManyHandle[M, K]) PrepareFile

func (s ManyHandle[M, K]) PrepareFile(ctx context.Context, owner M, file FileSource) (Prepared[M, K], error)

PrepareFile prepares file storage before a transaction without publishing it. Example: slot.PrepareFile(ctx,article,file).

func (ManyHandle[M, K]) PublicURLs

func (s ManyHandle[M, K]) PublicURLs(ctx context.Context, owner M) ([]string, error)

PublicURLs derives loaded file URLs in collection order without I/O. Example: slot.PublicURLs(ctx,article).

func (ManyHandle[M, K]) Registration

func (s ManyHandle[M, K]) Registration() Registration

Registration returns the existing manager registration. Example: slot.Registration().

func (ManyHandle[M, K]) Relation

func (s ManyHandle[M, K]) Relation(slot orm.Slot[M, Many[M]]) orm.ExtensionRelation[M]

Relation binds the loader to its concrete ORM field; mismatched fields fail validation. Example: Articles.Query().With(slot.Relation(Articles.Gallery)).

func (ManyHandle[M, K]) Reorder

func (s ManyHandle[M, K]) Reorder(ctx context.Context, owner M, order []ID[M]) ([]Attachment[M, K], error)

Reorder sets an exact permutation of the collection file IDs. Example: slot.Reorder(ctx,article,order).

func (ManyHandle[M, K]) Replace

func (s ManyHandle[M, K]) Replace(ctx context.Context, owner M, upload Upload) (Result[M, K], error)

Replace replaces the collection; inspect the publication outcome when an error is returned. Example: slot.Replace(ctx,article,upload).

func (ManyHandle[M, K]) ReplaceFile

func (s ManyHandle[M, K]) ReplaceFile(ctx context.Context, owner M, file FileSource) (Result[M, K], error)

ReplaceFile replaces the collection from a file; inspect the publication outcome on error. Example: slot.ReplaceFile(ctx,article,file).

func (ManyHandle[M, K]) ReplaceIn

func (s ManyHandle[M, K]) ReplaceIn(ctx context.Context, tx *database.Tx, owner M, prepared Prepared[M, K]) (Result[M, K], error)

ReplaceIn publishes a prepared upload in the caller transaction. Example: slot.ReplaceIn(ctx,tx,article,prepared).

func (ManyHandle[M, K]) TemporaryURL

func (s ManyHandle[M, K]) TemporaryURL(ctx context.Context, owner M, file File[M], options storage.LinkOptions) (storage.TemporaryURL, error)

TemporaryURL signs a loaded file URL pinned to its stored version. Example: slot.TemporaryURL(ctx,article,file,options).

func (ManyHandle[M, K]) URL

func (s ManyHandle[M, K]) URL(ctx context.Context, owner M, file File[M]) (string, error)

URL derives a loaded file URL without I/O; authorize access first. Example: slot.URL(ctx,article,file).

func (ManyHandle[M, K]) Validate

func (s ManyHandle[M, K]) Validate() error

Validate checks the declaration and slot binding. Example: slot.Validate().

func (ManyHandle[M, K]) VariantURL

func (s ManyHandle[M, K]) VariantURL(ctx context.Context, owner M, file File[M], variant Variant) (string, error)

VariantURL derives a generated variant URL without I/O. Example: slot.VariantURL(ctx,article,file,variant).

type Name

type Name string

type One

type One[M any] struct {
	// contains filtered or unexported fields
}

One is a model slot holding the ready file of a single-file collection. The zero value is not loaded. Reading a slot performs no I/O.

func (One[M]) EmailAttachment

func (o One[M]) EmailAttachment() (email.Attachment, error)

EmailAttachment accepts a loaded, present single-file slot directly through Message.AttachStored. An unloaded or absent slot is an error.

func (One[M]) Format

func (One[M]) Format(s fmt.State, _ rune)

func (One[M]) Get

func (o One[M]) Get() (value.Optional[File[M]], bool)

Get returns the optional file and whether the slot was loaded. A loaded but absent file differs from a slot that was not loaded.

func (One[M]) IsLoaded

func (o One[M]) IsLoaded() bool

IsLoaded reports whether the slot was filled by a loader.

func (One[M]) MarshalJSON

func (One[M]) MarshalJSON() ([]byte, error)

type OneHandle

type OneHandle[M any, K comparable] struct {
	// contains filtered or unexported fields
}

OneHandle retains typed slot capabilities behind shared callback state. Example: slot.From(manager).Relation(Fields.Slot).

func OneOf

func OneOf[M any, K comparable](owner extensions.Owner[M, K], name Name, policy Policy, binding extensions.SlotBinding[M, K, One[M]]) OneHandle[M, K]

OneOf declares a thin single-file handle with the existing manager policy. Example: attachments.OneOf(owner,"files",policy,binding).

func (OneHandle[M, K]) Accepts

func (s OneHandle[M, K]) Accepts(ctx context.Context, file FileSource) (bool, error)

Accepts checks policy using the existing manager admission and media checks. Example: slot.Accepts(ctx,file).

func (OneHandle[M, K]) Clear

func (s OneHandle[M, K]) Clear(ctx context.Context, owner M) (ChangeResult, error)

Clear retires every file and schedules storage cleanup. Example: slot.Clear(ctx,article).

func (OneHandle[M, K]) Describe

func (s OneHandle[M, K]) Describe() extensions.SlotDescription

Describe returns an owned inspection snapshot. Example: slot.Describe().

func (OneHandle[M, K]) Detach

func (s OneHandle[M, K]) Detach(ctx context.Context, owner M, id ID[M]) (ChangeResult, error)

Detach retires one file and schedules storage cleanup. Example: slot.Detach(ctx,article,id).

func (OneHandle[M, K]) Discard

func (s OneHandle[M, K]) Discard(ctx context.Context, prepared Prepared[M, K]) error

Discard reclaims an unpublished prepared upload. Example: slot.Discard(ctx,prepared).

func (OneHandle[M, K]) Format

func (OneHandle[M, K]) Format(s fmt.State, _ rune)

Format omits retained runtime state. Example: fmt.Sprintf("%+v",slot).

func (OneHandle[M, K]) From

func (s OneHandle[M, K]) From(m *Manager) OneHandle[M, K]

From returns a copy borrowing this family's manager; nil leaves it unbound. Example: slot.From(manager).

func (OneHandle[M, K]) Name

func (s OneHandle[M, K]) Name() Name

Name returns the stored name. Example: slot.Name().

func (OneHandle[M, K]) Prepare

func (s OneHandle[M, K]) Prepare(ctx context.Context, owner M, upload Upload) (Prepared[M, K], error)

Prepare prepares storage before a transaction without publishing it. Example: slot.Prepare(ctx,article,upload).

func (OneHandle[M, K]) PrepareFile

func (s OneHandle[M, K]) PrepareFile(ctx context.Context, owner M, file FileSource) (Prepared[M, K], error)

PrepareFile prepares file storage before a transaction without publishing it. Example: slot.PrepareFile(ctx,article,file).

func (OneHandle[M, K]) PublicURL

func (s OneHandle[M, K]) PublicURL(ctx context.Context, owner M) (value.Optional[string], error)

PublicURL derives the loaded single file URL without I/O. Example: slot.PublicURL(ctx,article).

func (OneHandle[M, K]) Registration

func (s OneHandle[M, K]) Registration() Registration

Registration returns the existing manager registration. Example: slot.Registration().

func (OneHandle[M, K]) Relation

func (s OneHandle[M, K]) Relation(slot orm.Slot[M, One[M]]) orm.ExtensionRelation[M]

Relation binds the loader to its concrete ORM field; mismatched fields fail validation. Example: Articles.Query().With(slot.Relation(Articles.Cover)).

func (OneHandle[M, K]) Replace

func (s OneHandle[M, K]) Replace(ctx context.Context, owner M, upload Upload) (Result[M, K], error)

Replace replaces the collection; inspect the publication outcome when an error is returned. Example: slot.Replace(ctx,article,upload).

func (OneHandle[M, K]) ReplaceFile

func (s OneHandle[M, K]) ReplaceFile(ctx context.Context, owner M, file FileSource) (Result[M, K], error)

ReplaceFile replaces the collection from a file; inspect the publication outcome on error. Example: slot.ReplaceFile(ctx,article,file).

func (OneHandle[M, K]) ReplaceIn

func (s OneHandle[M, K]) ReplaceIn(ctx context.Context, tx *database.Tx, owner M, prepared Prepared[M, K]) (Result[M, K], error)

ReplaceIn publishes a prepared upload in the caller transaction. Example: slot.ReplaceIn(ctx,tx,article,prepared).

func (OneHandle[M, K]) TemporaryURL

func (s OneHandle[M, K]) TemporaryURL(ctx context.Context, owner M, file File[M], options storage.LinkOptions) (storage.TemporaryURL, error)

TemporaryURL signs a loaded file URL pinned to its stored version. Example: slot.TemporaryURL(ctx,article,file,options).

func (OneHandle[M, K]) URL

func (s OneHandle[M, K]) URL(ctx context.Context, owner M, file File[M]) (string, error)

URL derives a loaded file URL without I/O; authorize access first. Example: slot.URL(ctx,article,file).

func (OneHandle[M, K]) Validate

func (s OneHandle[M, K]) Validate() error

Validate checks the declaration and slot binding. Example: slot.Validate().

func (OneHandle[M, K]) VariantURL

func (s OneHandle[M, K]) VariantURL(ctx context.Context, owner M, file File[M], variant Variant) (string, error)

VariantURL derives a generated variant URL without I/O. Example: slot.VariantURL(ctx,article,file,variant).

type Operation

type Operation struct{}

OperationID is the administrative/job reference for one durable upload intent. Application collection operations use model-owned ID[M] instead.

type OperationID

type OperationID = model.ID[Operation]

type Orphan

type Orphan struct {
	Operation  OperationID   `json:"operation"`
	Collection Name          `json:"collection"`
	Locale     i18n.LocaleID `json:"locale"`
	State      State         `json:"state"`
}

type OrphanPage

type OrphanPage struct {
	Orphans []Orphan
	Scanned int
	Next    Cursor
}

type Policy

type Policy struct {
	Disk           storage.Declaration
	Cardinality    Cardinality
	Localized      bool
	MaxFiles       int
	MaxBytes       int64
	MaxStoredBytes int64
	Accepted       []storage.MediaType
	AnyMedia       bool
	Image          value.Optional[imaging.Plan]
	// Variants are named derived images (for example thumbnails) generated
	// from each ready original and stored beside it. They require image input:
	// an Image plan or an Accepted list of decodable image types.
	Variants []Variant
	// InlineActiveContent allows public URLs and inline signed links for
	// script-capable files (SVG, HTML, XML, JavaScript). By default public URLs
	// are refused and signed links force a download disposition, because such
	// files served inline run scripts in the serving origin (stored XSS). Only
	// set it when that origin is isolated and cookie-less.
	InlineActiveContent bool
}

func (Policy) Validate

func (p Policy) Validate() error

type Prepared

type Prepared[M any, K comparable] struct {
	// contains filtered or unexported fields
}

Prepared is an upload read, checked and stored for one owner's collection but not yet published. Publish it with ReplaceIn or AddIn inside a transaction that begins after Prepare returned, within StoredGrace; otherwise ReconcilePending reclaims it. Discard reclaims it at once.

func (Prepared[M, K]) Format

func (Prepared[M, K]) Format(s fmt.State, _ rune)

func (Prepared[M, K]) IsZero

func (p Prepared[M, K]) IsZero() bool

func (Prepared[M, K]) Operation

func (p Prepared[M, K]) Operation() OperationID

Operation is the durable upload intent, for Manager.Inspect.

type Publication

type Publication uint8
const (
	Unpublished Publication = iota
	Published
	PublicationUnknown
)

type Queue

type Queue struct {
	// contains filtered or unexported fields
}

Queue is a borrowed job/outbox binding. Construct the manager, declare its reconcile job, assemble the ordinary dispatcher/outbox, then bind the queue to collections. This avoids constructor dependency cycles.

func (Queue) Enqueue

func (q Queue) Enqueue(ctx context.Context, tx *database.Tx, id OperationID) error

Enqueue is available for explicit operator retries. The cleanup operation itself is idempotent; each requested enqueue receives a normal new execution ID.

func (Queue) Validate

func (q Queue) Validate() error

type ReconcileJob

type ReconcileJob struct {
	// contains filtered or unexported fields
}

func DefineReconcileJob

func DefineReconcileJob(name jobs.Name, policy jobs.Policy) ReconcileJob

func (ReconcileJob) Declare

func (j ReconcileJob) Declare(manager *Manager) (jobs.Declaration, error)

func (ReconcileJob) ToOutbox

func (j ReconcileJob) ToOutbox(producer *jobs.Outbox) (Queue, error)

type ReconcileRequest

type ReconcileRequest struct {
	Operation OperationID `json:"operation"`
}

func (ReconcileRequest) Format

func (ReconcileRequest) Format(s fmt.State, _ rune)

type ReconcileResult

type ReconcileResult struct {
	Operation OperationID
	State     State
	Attempts  uint32
	Failure   string
}

type RegenerationCursor

type RegenerationCursor struct {
	// contains filtered or unexported fields
}

RegenerationCursor continues a regeneration run within one process.

func (RegenerationCursor) IsZero

func (c RegenerationCursor) IsZero() bool

type RegenerationOptions

type RegenerationOptions struct {
	Missing bool
	Cursor  RegenerationCursor
	Limit   int
}

RegenerationOptions selects one bounded batch of ready attachments. Missing generates only variants without a ready file; otherwise every declared variant is regenerated and replaces the previous one.

type RegenerationPage

type RegenerationPage struct {
	Regenerated []OperationID
	Failed      []OperationID
	Next        RegenerationCursor
}

RegenerationPage reports one batch. Failed attachments keep their previous variants; rerun them after resolving the cause. Continue with Next until it is zero.

type Registration

type Registration struct {
	// contains filtered or unexported fields
}

type RemoteSource

type RemoteSource struct {
	Client       *httpclient.Client
	URL          string
	OriginalName string
}

RemoteSource names a remote file to import. URL is untrusted input, so Client must enforce a restricted destination policy (for example httpclient.PublicDestinations) that keeps imports away from internal services. OriginalName defaults to the URL's last path segment.

type Resolved

type Resolved[M any, K comparable] struct {
	// contains filtered or unexported fields
}

func (Resolved[M, K]) Files

func (r Resolved[M, K]) Files() []Attachment[M, K]

func (Resolved[M, K]) Locale

func (r Resolved[M, K]) Locale() i18n.LocaleID

type Result

type Result[M any, K comparable] struct {
	Operation       OperationID
	Publication     Publication
	Attachment      value.Optional[Attachment[M, K]]
	PendingCleanup  []OperationID
	PendingVariants bool
}

Result distinguishes ownership publication from storage cleanup. A published attachment remains published when old-object cleanup returns an error. An uncertain publication is never described as rolled back or automatically retried. Inspect the durable Operation before deciding the next action. PendingVariants reports that declared variants were queued, or that their synchronous generation failed; the original is published either way.

func AddFilesTo

func AddFilesTo[F FileSource, M any, K comparable](ctx context.Context, slot ManyHandle[M, K], owner M, files []F) ([]Result[M, K], error)

AddFilesTo appends files through a bound ORM many-slot handle in input order. The slot and batch limit are checked before any file opens. Results include every attempted file, including the first failure; earlier publications remain published. Inspect each Result.Publication and never retry unknown outcomes. Example: results, err := attachments.AddFilesTo(ctx, bound.Galleries, article, files).

func (Result[M, K]) Format

func (Result[M, K]) Format(s fmt.State, _ rune)

func (Result[M, K]) MarshalJSON

func (Result[M, K]) MarshalJSON() ([]byte, error)

type RetainResult

type RetainResult struct {
	Operation   OperationID
	Publication Publication
	File        value.Optional[RetainedFile]
}

type RetainedFile

type RetainedFile struct {
	Operation OperationID
	Disk      storage.DiskID
	Key       storage.ObjectKey
	ETag      storage.ETag
	Version   storage.VersionID
}

RetainedFile transfers cleanup responsibility to the application. Its exact storage pins are explicit; automatic attachment maintenance never deletes it.

func (RetainedFile) Format

func (RetainedFile) Format(s fmt.State, _ rune)

func (RetainedFile) MarshalJSON

func (RetainedFile) MarshalJSON() ([]byte, error)

type Settlement

type Settlement uint8

Settlement is an operator assertion, after inspecting the writer and storage provider, that no request can still publish this upload. It is never inferred from a lease, canceled context or one missing-object response; the automatic path relies instead on the configured writer/provider time bound.

const WriterStoppedAndStorageSettled Settlement = 1

type State

type State string

State is persisted, public diagnostic state, not a caller-controlled upload option. Writing/Uncertain require settlement; a timeout alone is not proof that a remote storage request has stopped. ReconcilePending settles them only after the disk Timeout plus Config.SettleAfter and only when storage is unambiguous; everything else waits for an operator Settle.

const (
	Writing        State = "writing"
	Stored         State = "stored"
	Ready          State = "ready"
	CleanupPending State = "cleanup"
	Cleaned        State = "cleaned"
	Retained       State = "retained"
	Uncertain      State = "uncertain"
)

func (State) Validate

func (s State) Validate() error

type StorageCursor

type StorageCursor struct {
	// contains filtered or unexported fields
}

StorageCursor preserves the disk/owner/age policy and first-page cutoff. Listings are not transactional snapshots. Copy only a returned Next cursor.

func (StorageCursor) IsZero

func (c StorageCursor) IsZero() bool

type StorageInspection

type StorageInspection struct {
	Disk       storage.Declaration
	Owner      extensions.OwnerName
	MinimumAge time.Duration
	Limit      int
	Cursor     StorageCursor
}

type StorageOrphanPage

type StorageOrphanPage struct {
	Candidates []storage.ObjectInfo
	Scanned    int
	Next       StorageCursor
}

type Undeclared

type Undeclared = extensionmaintenance.Undeclared

Undeclared lists stored names that no current registration declares.

func InspectUndeclared

func InspectUndeclared(ctx context.Context, m *Manager, owner extensions.OwnerName) (Undeclared, error)

InspectUndeclared lists stored collection names in owner's current scope that no collection registered with m declares, in any journal state, for example after renaming a slot field without pinning its stored name. It reads names only and modifies no row or object.

type Upload

type Upload struct {
	Source       io.Reader
	OriginalName string
	ContentType  storage.MediaType
	Properties   value.JSON[json.RawMessage]
}

Upload borrows Source until the operation actually returns and never closes it. OriginalName and ContentType are untrusted metadata hints. Media acceptance is based on bytes; ContentType can only specialize generic plain text to a compatible textual type (CSV, TSV, Markdown, calendar, valid JSON) that the policy accepts, otherwise the file stays text/plain. Image policy performs actual bounded decode/re-encoding. Invisible bidirectional and zero-width characters are removed from OriginalName.

type UploadInfo

type UploadInfo struct {
	OriginalName  string
	MediaType     storage.MediaType
	Size          int64
	Width, Height int
}

type Variant

type Variant struct {
	// contains filtered or unexported fields
}

Variant declares a named derived image, for example a thumbnail or preview. It is generated from each ready original with an imaging plan and stored beside it; the original is never changed. Declare it once and reuse the same value in collection policies and link helpers.

func DefineVariant

func DefineVariant(name VariantName, plan imaging.Plan) Variant

func (Variant) Format

func (Variant) Format(s fmt.State, _ rune)

func (Variant) Name

func (v Variant) Name() VariantName

func (Variant) Validate

func (v Variant) Validate() error

type VariantInfo

type VariantInfo struct {
	Name          VariantName
	MediaType     storage.MediaType
	Size          int64
	Width, Height int
}

VariantInfo describes one generated variant of a loaded attachment.

type VariantJob

type VariantJob struct {
	// contains filtered or unexported fields
}

VariantJob generates missing variants of one ready attachment. Retries are idempotent: completed variants are not generated again.

func DefineVariantJob

func DefineVariantJob(name jobs.Name, policy jobs.Policy) VariantJob

func (VariantJob) Declare

func (j VariantJob) Declare(manager *Manager) (jobs.Declaration, error)

func (VariantJob) ToOutbox

func (j VariantJob) ToOutbox(producer *jobs.Outbox) (VariantQueue, error)

type VariantName

type VariantName string

VariantName is a stable semantic identifier stored with each derived file.

func (VariantName) Validate

func (n VariantName) Validate() error

type VariantQueue

type VariantQueue struct {
	// contains filtered or unexported fields
}

VariantQueue is a borrowed job/outbox binding for queued variant generation. Bind it with Collection.WithVariantQueue after the manager and its job are declared; the publication transaction then enqueues one job per upload.

func (VariantQueue) Validate

func (q VariantQueue) Validate() error

type VariantRequest

type VariantRequest struct {
	Operation OperationID `json:"operation"`
}

VariantRequest identifies one attachment whose declared variants are generated.

func (VariantRequest) Format

func (VariantRequest) Format(s fmt.State, _ rune)

type VariantState

type VariantState string

VariantState is the persisted journal state of one derived file.

const (
	VariantWriting   VariantState = "writing"
	VariantReady     VariantState = "ready"
	VariantCleanup   VariantState = "cleanup"
	VariantCleaned   VariantState = "cleaned"
	VariantUncertain VariantState = "uncertain"
)

func (VariantState) Validate

func (s VariantState) Validate() error

Directories

Path Synopsis
Package command provides read-only attachment owner-orphan inspection and bounded regeneration of declared image variants.
Package command provides read-only attachment owner-orphan inspection and bounded regeneration of declared image variants.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL