resourcewrite

package
v1.126.0 Latest Latest
Warning

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

Go to latest
Published: Aug 26, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package resourcewrite lets something other than a browser write a managed resource (#1487).

A managed resource is the only kind of file an asset can reference, and until now the only way to put one there was a person at an upload form. That left the data half of a referencing asset unrefreshable by the platform itself: an agent could rewrite the report on a schedule and could not rewrite the CSV the report reads.

This is the same two writes the REST surface makes, against the same store, the same blob client and the same version trail, with the same scope permission rule applied to the caller's own claims. A revision written here is indistinguishable from one uploaded through the portal: same id, same canonical URI, same filename, same history, same retention -- which is what keeps every citation, prompt attachment and asset reference pointing at it resolving across the write.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrRefused is a permission decision: the caller may not write where they
	// asked. The message it wraps states what to change.
	ErrRefused = errors.New("managed-resource write refused")
	// ErrNoSuchResource is a replacement naming a file that is not there, or
	// one the caller cannot see. The two are deliberately the same answer: a
	// caller who should not learn the resource exists must not be able to tell
	// them apart.
	ErrNoSuchResource = errors.New("no such managed resource")
	// ErrUnavailable is the deployment lacking the layer the write needs. It is
	// reported as itself rather than as a failure, so a caller is never told a
	// write happened that could not have.
	ErrUnavailable = errors.New("managed-resource write unavailable")
)

The three ways a write does not happen, told apart because each is the caller's to act on differently.

Functions

func ScopePhrase

func ScopePhrase(scope resource.Scope, scopeID string) string

ScopePhrase names a scope the way a refusal has to name it: the thing the caller must change, in words they can act on, never the id of a record they may not be allowed to know exists.

Types

type Deps

type Deps struct {
	Store       resource.Store
	Blobs       resource.S3Client
	Bucket      string
	URIScheme   string
	MaxVersions int
	Registered  func(*resource.Resource)
}

Deps is what a writer is assembled from: the record store, the blob client the content lives in, and the callback that tells connected clients the resource list moved.

type Writer

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

Writer creates managed resources and replaces their content.

func New

func New(d Deps) *Writer

New builds the writer, or nil when the deployment has no managed-resource layer to write into: no record store, or nowhere to put the bytes. A nil writer is what a deployment without managed resources has, and the surfaces bound to it report that reason rather than accepting a write that goes nowhere.

A store with no version trail still yields a writer. Creating does not need one -- the trail is recorded when it is there and skipped when it is not, exactly as the upload route treats it -- while replacing does, and says so.

func (*Writer) Create

func (w *Writer) Create(
	ctx context.Context, in resource.NewResource, claims resource.Claims,
) (*resource.Resource, error)

Create files new content as a managed resource under the caller's identity.

The scope permission is checked before anything is written, and the refusal names the scope rather than the file: what the caller has to change is where they filed it, not what they filed.

func (*Writer) Get

func (w *Writer) Get(ctx context.Context, id string, claims resource.Claims) (*resource.Resource, error)

Get reads a resource the caller may see, so a surface can settle what a replacement is about to change before it changes it -- the stored filename a replacement must keep, and whether the file is there at all, before a payload is decoded.

A resource the caller cannot see reads as absent: those two are deliberately one answer, because a caller who should not learn the resource exists must not be able to tell them apart. A read that FAILED is a third answer and stays one, for the reason given at the check below.

func (*Writer) Replace

func (w *Writer) Replace(
	ctx context.Context, id string, up resource.RevisionUpload, claims resource.Claims,
) (*resource.Resource, int, error)

Replace records new content as the resource's next revision. The id, the canonical mcp:// URI and the filename are unchanged by contract -- the revision path keys the new blob on a fresh per-revision directory and moves the head onto it -- so every asset referencing the resource resolves to the new bytes without being re-saved.

It returns the version number the content was recorded as, which is what makes the write checkable from the version history rather than only from the bytes.

Jump to

Keyboard shortcuts

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