Skip to content

Commit ee044f4

Browse files
committed
fix(files): handle R2 NoSuchKey on empty listing; fix passkey list method
R2 returns NoSuchKey (404) for empty buckets/prefixes where S3 returns an empty Contents array. listUserObjects now catches and returns [] so /api/files succeeds for users with no files. PasskeySection was calling authClient.listPasskeys (undefined) instead of authClient.passkey.listUserPasskeys — wrong path, 404, undefined return that probably crashed downstream. Same fix for deletePasskey.
1 parent c51e863 commit ee044f4

5 files changed

Lines changed: 26 additions & 23 deletions

File tree

apps/admin/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/types/routes.d.ts";
3+
import "./.next/dev/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

apps/marketing/next-env.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="next" />
22
/// <reference types="next/image-types/global" />
3-
import "./.next/types/routes.d.ts";
3+
import "./.next/dev/types/routes.d.ts";
44

55
// NOTE: This file should not be edited
66
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

apps/web/src/components/app/passkey-section.tsx

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,10 @@ export function PasskeySection() {
2828

2929
const refresh = async () => {
3030
try {
31-
// Better Auth's passkey plugin exposes listUserPasskeys on the client.
32-
// The shape isn't strongly typed for arbitrary plugins so we coerce.
33-
const res = await (
34-
authClient as unknown as {
35-
listPasskeys: () => Promise<{ data?: PasskeyRow[] | null }>;
36-
}
37-
).listPasskeys();
38-
setPasskeys(res?.data ?? []);
31+
// Better Auth's passkey plugin exposes listUserPasskeys on the
32+
// `passkey` namespace of the client.
33+
const res = await authClient.passkey.listUserPasskeys();
34+
setPasskeys((res?.data ?? []) as PasskeyRow[]);
3935
} catch {
4036
setPasskeys([]);
4137
}
@@ -71,11 +67,7 @@ export function PasskeySection() {
7167

7268
const remove = async (passkeyId: string) => {
7369
try {
74-
await (
75-
authClient as unknown as {
76-
deletePasskey: (args: { id: string }) => Promise<unknown>;
77-
}
78-
).deletePasskey({ id: passkeyId });
70+
await authClient.passkey.deletePasskey({ id: passkeyId });
7971
toast.success("Passkey removed");
8072
await refresh();
8173
} catch (err) {

packages/email/src/lib/client.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export const resend = new Proxy({} as Resend, {
2121
get(_target, prop) {
2222
const r = getResend();
2323
const value = (r as unknown as Record<string | symbol, unknown>)[prop];
24-
return typeof value === "function" ? (value as () => unknown).bind(r) : value;
24+
return typeof value === "function"
25+
? (value as () => unknown).bind(r)
26+
: value;
2527
},
2628
});
2729

packages/storage/src/upload.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,22 @@ export async function listUserObjects(
185185
opts: { limit?: number } = {},
186186
): Promise<UserObject[]> {
187187
const prefix = `${userPrefix(ownerId)}/`;
188-
const result = await r2.send(
189-
new ListObjectsV2Command({
190-
Bucket: R2_BUCKET,
191-
Prefix: prefix,
192-
MaxKeys: opts.limit ?? 200,
193-
}),
194-
);
188+
const result = await r2
189+
.send(
190+
new ListObjectsV2Command({
191+
Bucket: R2_BUCKET,
192+
Prefix: prefix,
193+
MaxKeys: opts.limit ?? 200,
194+
}),
195+
)
196+
.catch((err: { Code?: string } | undefined) => {
197+
// Cloudflare R2 returns NoSuchKey (404) for empty buckets/prefixes
198+
// where S3 returns an empty Contents array — treat as "no files".
199+
if (err?.Code === "NoSuchKey") {
200+
return { Contents: [] };
201+
}
202+
throw err;
203+
});
195204
const contents = result.Contents ?? [];
196205
return contents
197206
.map((o) => ({

0 commit comments

Comments
 (0)