Uploads carry the name the file came with (#83)
An upload sends its file name next to the raw bytes, and the server keeps it in a sidecar next to the content-addressed file. Both pickers caption every tile and row with it, and an asset made there is named after the file instead of "Texture" / "Font". Last upload of the same content wins. The API's own set_error_handler ignores error_reporting(), so @-silenced warnings still throw: a missing sidecar took the whole listing down with a 500. Existence is checked instead of suppressed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
86b5363a01
commit
99c5d2ad78
21 files changed
+347
-61
No files matched your search
@@ -61,6 +61,20 @@ describe('HttpTextureStore', () => {
|
||||
expect(init?.headers).toEqual({ 'Content-Type': 'image/png' });
|
||||
});
|
||||
|
||||
it('sends the file name beside the route, and omits it when there is none', async () => {
|
||||
const answer = JSON.stringify({ file: FILE, name: 'hero idle.png', width: 2, height: 3, bytes: 4 });
|
||||
const bytes = new Blob([new Uint8Array(4)]);
|
||||
|
||||
let mock = stubFetch(answer, { status: 201 });
|
||||
await new HttpTextureStore('/api').upload(bytes, 'image/png', 'hero idle.png');
|
||||
// The body stays the raw image, so the name travels in the query – encoded, not as a path.
|
||||
expect(mock.mock.calls[0]![0]).toBe('/api?r=textures&name=hero%20idle.png');
|
||||
|
||||
mock = stubFetch(answer, { status: 201 });
|
||||
await new HttpTextureStore('/api').upload(bytes, 'image/png');
|
||||
expect(mock.mock.calls[0]![0]).toBe('/api?r=textures');
|
||||
});
|
||||
|
||||
it('reports the nginx size limit as a size problem', async () => {
|
||||
stubFetch(NGINX_413, { status: 413, statusText: 'Request Entity Too Large' });
|
||||
const bytes = new Blob([new Uint8Array(8)]);
|
||||
|
||||
@@ -24,6 +24,19 @@ describe('CreateTextureCommand', () => {
|
||||
expect(findAsset(project, command.asset.id)?.name).toBe('Hero');
|
||||
});
|
||||
|
||||
it('keeps the caller’s name even though the upload result carries one of its own', () => {
|
||||
const { project, stack } = makeProject();
|
||||
// What `TextureStore.upload` actually answers: the file's original name and its byte count
|
||||
// ride along. Copied wholesale they would land in the asset and rename it behind the caller.
|
||||
const upload = { file: FILE, name: 'hero-idle.png', width: 64, height: 32, bytes: 900 };
|
||||
const command = new CreateTextureCommand('Hero', upload);
|
||||
stack.execute(command);
|
||||
|
||||
const asset = findAsset(project, command.asset.id);
|
||||
expect(asset?.name).toBe('Hero');
|
||||
expect(asset).not.toHaveProperty('bytes');
|
||||
});
|
||||
|
||||
it('rejects a file name the server cannot have produced – in execute, not in the constructor', () => {
|
||||
const { project, stack } = makeProject();
|
||||
const command = new CreateTextureCommand('Hero', { file: '../secrets.png', width: 1, height: 1 });
|
||||
|
||||
Reference in new issue
Block a user