Skip to content

Commit c61b5e9

Browse files
committed
feat: add status field to RequestUploadUrlPayload
Return the file status in requestUploadUrl responses so clients can immediately determine whether a deduplicated file is usable: - deduplicated files: status is 'ready' or 'processed' (from DB) - fresh uploads: status is 'pending' (awaiting PUT + confirmUpload) Changes: - graphile-presigned-url-plugin: add status to GraphQL schema, TS type, and both dedup/fresh return paths - upload-client: add status to query string, types, and use server value instead of hard-coding 'ready' for dedup - Tests: update all mock fixtures and add status assertions
1 parent 662e599 commit c61b5e9

7 files changed

Lines changed: 22 additions & 4 deletions

File tree

graphile/graphile-presigned-url-plugin/src/plugin.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ export function createPresignedUrlPlugin(
175175
deduplicated: Boolean!
176176
"""Presigned URL expiry time (null if deduplicated)"""
177177
expiresAt: Datetime
178+
"""File status — 'pending' for fresh uploads, 'ready' or 'processed' for deduplicated files. Clients can use this to know immediately whether the file is usable."""
179+
status: String!
178180
}
179181
180182
input ConfirmUploadInput {
@@ -324,11 +326,12 @@ export function createPresignedUrlPlugin(
324326
});
325327

326328
return {
327-
uploadUrl: null,
328-
fileId: existingFile.id,
329+
uploadUrl: null as string | null,
330+
fileId: existingFile.id as string,
329331
key: s3Key,
330332
deduplicated: true,
331-
expiresAt: null,
333+
expiresAt: null as string | null,
334+
status: existingFile.status as string,
332335
};
333336
}
334337

@@ -396,6 +399,7 @@ export function createPresignedUrlPlugin(
396399
key: s3Key,
397400
deduplicated: false,
398401
expiresAt,
402+
status: 'pending',
399403
};
400404
});
401405
});

graphile/graphile-presigned-url-plugin/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ export interface RequestUploadUrlPayload {
105105
deduplicated: boolean;
106106
/** Presigned URL expiry time (null if deduplicated) */
107107
expiresAt: string | null;
108+
/** File status — 'pending' for fresh uploads, 'ready' or 'processed' for deduplicated files */
109+
status: string;
108110
}
109111

110112
/**

graphql/server-test/__tests__/upload.integration.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ const REQUEST_UPLOAD_URL = `
4949
key
5050
deduplicated
5151
expiresAt
52+
status
5253
}
5354
}
5455
`;
@@ -158,6 +159,7 @@ describe('Upload integration (presigned URL flow)', () => {
158159
expect(payload.key).toBe(contentHash);
159160
expect(payload.deduplicated).toBe(false);
160161
expect(payload.expiresAt).toBeTruthy();
162+
expect(payload.status).toBe('pending');
161163

162164
uploadUrl = payload.uploadUrl;
163165
fileId = payload.fileId;
@@ -216,6 +218,7 @@ describe('Upload integration (presigned URL flow)', () => {
216218
expect(payload.key).toBe(contentHash);
217219
expect(payload.deduplicated).toBe(false);
218220
expect(payload.expiresAt).toBeTruthy();
221+
expect(payload.status).toBe('pending');
219222

220223
uploadUrl = payload.uploadUrl;
221224
fileId = payload.fileId;
@@ -271,6 +274,7 @@ describe('Upload integration (presigned URL flow)', () => {
271274
expect(payload.uploadUrl).toBeNull();
272275
expect(payload.expiresAt).toBeNull();
273276
expect(payload.fileId).toBeTruthy();
277+
expect(payload.status).toBe('ready');
274278
});
275279
});
276280
});

packages/upload-client/__tests__/upload.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ describe('uploadFile', () => {
5959
key: HELLO_WORLD_HASH,
6060
deduplicated: false,
6161
expiresAt: new Date(Date.now() + 900_000).toISOString(),
62+
status: 'pending',
6263
},
6364
};
6465
}
@@ -135,6 +136,7 @@ describe('uploadFile', () => {
135136
key: HELLO_WORLD_HASH,
136137
deduplicated: true,
137138
expiresAt: null,
139+
status: 'ready',
138140
},
139141
};
140142
}
@@ -199,6 +201,7 @@ describe('uploadFile', () => {
199201
key: 'hash',
200202
deduplicated: false,
201203
expiresAt: new Date().toISOString(),
204+
status: 'pending',
202205
},
203206
};
204207
}
@@ -230,6 +233,7 @@ describe('uploadFile', () => {
230233
key: 'hash',
231234
deduplicated: false,
232235
expiresAt: new Date().toISOString(),
236+
status: 'pending',
233237
},
234238
};
235239
}
@@ -279,6 +283,7 @@ describe('uploadFile', () => {
279283
key: 'hash',
280284
deduplicated: false,
281285
expiresAt: new Date().toISOString(),
286+
status: 'pending',
282287
},
283288
};
284289
}

packages/upload-client/src/queries.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const REQUEST_UPLOAD_URL_MUTATION = `
1313
key
1414
deduplicated
1515
expiresAt
16+
status
1617
}
1718
}
1819
`;

packages/upload-client/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ export interface RequestUploadUrlPayload {
3232
deduplicated: boolean;
3333
/** Presigned URL expiry time (ISO string, null if deduplicated) */
3434
expiresAt: string | null;
35+
/** File status — 'pending' for fresh uploads, 'ready' or 'processed' for deduplicated files */
36+
status: string;
3537
}
3638

3739
export interface ConfirmUploadInput {

packages/upload-client/src/upload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export async function uploadFile(options: UploadFileOptions): Promise<UploadResu
7979
fileId: requestPayload.fileId,
8080
key: requestPayload.key,
8181
deduplicated: true,
82-
status: 'ready',
82+
status: requestPayload.status,
8383
};
8484
}
8585

0 commit comments

Comments
 (0)