Driven adapter: LessonRepository backed by declared manifest rows whose
content keys are resolved through a BlobStore on every read.
Rows are stored in insertion order and hold opaque content KEYS in
source and poster. Resolution happens at read time, not when the
time, so repointing storage (local folder → S3/R2 bucket) is a change of
BlobStore driver rather than an edit to the course manifests. It is
also what makes per-request signed URLs possible: a signed URL expires and
therefore cannot be baked into a committed file.
Parsing happens after resolution — urlOrRelativePath() rejects a bare
key — so a row that resolves to a malformed URL is rejected here rather
than reaching a src attribute in the UI.
Driven adapter:
LessonRepositorybacked by declared manifest rows whose content keys are resolved through aBlobStoreon every read.Rows are stored in insertion order and hold opaque content KEYS in
sourceandposter. Resolution happens at read time, not when the time, so repointing storage (local folder → S3/R2 bucket) is a change ofBlobStoredriver rather than an edit to the course manifests. It is also what makes per-request signed URLs possible: a signed URL expires and therefore cannot be baked into a committed file.Parsing happens after resolution —
urlOrRelativePath()rejects a bare key — so a row that resolves to a malformed URL is rejected here rather than reaching asrcattribute in the UI.