fix(uploads): store upload bytes per version - #31
Open
TheGreatAxios wants to merge 11 commits into
Conversation
TheGreatAxios
commented
Sep 25, 2026
TheGreatAxios
left a comment
Contributor
Author
There was a problem hiding this comment.
Self-review: the review found that a file revise overwrote the title; this is fixed (title carries forward). Known and unchanged: multipart bodies are buffered before the size check, same as the upload route. The source merge reads the artifact before the lock; it is harmless today because nothing else rewrites source.
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
from
September 25, 2026 14:30
0722cd6 to
7b1c38c
Compare
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
6 times, most recently
from
September 25, 2026 23:57
336466d to
659191d
Compare
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
2 times, most recently
from
September 26, 2026 00:54
c47e831 to
c3c62b1
Compare
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
from
September 26, 2026 01:29
c3c62b1 to
0621cd7
Compare
Each artifact_version records its own source, so ?version=N downloads that version's bytes. POST /artifacts/:id/versions accepts a multipart file to revise an upload with new bytes. The 0004 migration backfills existing versions from their artifact, so 0.1.0 uploads keep downloading.
The version detail route now returns that version's source, not the latest one's. A file revise stores its bytes only after the row is locked and expectedVersion holds, and merges source from the locked row, so a 409 leaves no orphaned blob. A revise with more than one file field is refused.
The run-scoped routes become a sub-app factory like createArtifactRoutes, so the host mounts them with app.route and their bearer-token middleware no longer registers on the host app. MountWorkflowArtifactsOpts is renamed CreateWorkflowArtifactRoutesDeps.
The seeds and the revise could share a millisecond, so the revised artifact was not always strictly newer. Backdate the seeds first.
0.1.0 let any principal create; 0.2.0 requires create on artifact:*. Before dropping the 0.1.0 ledger, 0002 grants it in the host's grant table to every principal that already created an artifact in its tenant, so existing users keep working and new principals need the grant. It runs only while the ledger exists, so a later revoke sticks.
The Interchange section builds the database, grant store and requireGrant from @intx/db, @intx/authz and @intx/hub-api instead of declaring host placeholders, and the install line lists every package the snippets import.
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
from
September 26, 2026 01:37
0621cd7 to
b458038
Compare
TheGreatAxios
added this pull request to stack #32
September 26, 2026 01:57
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
from
September 26, 2026 02:23
b458038 to
910afd3
Compare
TheGreatAxios
force-pushed
the
cl-9336-artifacts-store-upload-bytes-per-version-so-versionn-returns
branch
from
September 26, 2026 02:30
910afd3 to
e64d794
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
artifact_version.sourcerecords each version's content reference and size.GET /artifacts/:id/download?version=NandGET /artifacts/:id/versions/:versionreturn that version's file; omittingversionserves the latest.POST /artifacts/:id/versionswith a multipartfile(and optionalexpectedVersion) revises an upload with new bytes through the ContentStore and upload policy (reviseFileArtifact). The bytes are stored only after the row is locked andexpectedVersionholds, so a 409 writes no blob. More than onefilefield is refused. The title carries forward.0004_version_sourcebackfills every existing version from its artifact, so 0.1.0 uploads download as version 1.createWorkflowArtifactRoutes(deps)replacesmountWorkflowArtifacts(app, opts): the run-scoped routes are a sub-app factory likecreateArtifactRoutes.MountWorkflowArtifactsOptsis renamedCreateWorkflowArtifactRoutesDeps.0002grantscreateonartifact:*in the host'sgranttable to every principal that has already created an artifact in its tenant, before it drops the 0.1.0 ledger. It runs only while the ledger exists, so a later revoke sticks. New principals need the grant.e2e/, with the shared harness ine2e/helpers.tsande2e/fixtures.ts.bun run testrunssrc/,bun run test:e2erunse2e/, andtest:coverageruns both.Verification
bun install --frozen-lockfile,bun run build,bun run typecheck: pass.bun run test:coverageagainst local Postgres (ALLOW_DESTRUCTIVE_ARTIFACT_TESTS=1): 292 pass, 0 fail, coverage floor met.e2e/upgrade-from-0.1.0.test.tsupgrades a database written by the published 0.1.0: a 0.1.0 creator still gets 201 on create, a new principal gets 403, and re-running the migrations adds no grants.e2e/file-round-trip.test.tsasserts each version's bytes andsource, and that a staleexpectedVersionrevise leaves no file on disk.dist.Closes CL-9336