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 ¶
- Variables
- func ScopePhrase(scope resource.Scope, scopeID string) string
- type Deps
- type Writer
- func (w *Writer) Create(ctx context.Context, in resource.NewResource, claims resource.Claims) (*resource.Resource, error)
- func (w *Writer) Get(ctx context.Context, id string, claims resource.Claims) (*resource.Resource, error)
- func (w *Writer) Replace(ctx context.Context, id string, up resource.RevisionUpload, ...) (*resource.Resource, int, error)
Constants ¶
This section is empty.
Variables ¶
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") // 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 ¶
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 ¶
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.