Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 5b8f84e

Browse files
authored
R2 API (#355)
* R2 API
1 parent 50a2f4d commit 5b8f84e

File tree

7 files changed

+1005
-49
lines changed

7 files changed

+1005
-49
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import { Response } from "undici";
2+
import { R2Object } from "./r2Object";
3+
import { CfHeader } from "./router";
4+
5+
enum Status {
6+
BadRequest = 400,
7+
NotFound = 404,
8+
PreconditionFailed = 412,
9+
RangeNotSatisfiable = 416,
10+
InternalError = 500,
11+
}
12+
enum CfCode {
13+
InternalError = 10001,
14+
NoSuchObjectKey = 10007,
15+
EntityTooLarge = 100100,
16+
InvalidDigest = 10014,
17+
InvalidObjectName = 10020,
18+
InvalidMaxKeys = 10022,
19+
InvalidArgument = 10029,
20+
PreconditionFailed = 10031,
21+
BadDigest = 10037,
22+
InvalidRange = 10039,
23+
}
24+
25+
export class R2Error extends Error {
26+
status: number;
27+
v4Code: number;
28+
object?: R2Object;
29+
constructor(status: number, message: string, v4Code: number) {
30+
super(message);
31+
this.name = "R2Error";
32+
this.status = status;
33+
this.v4Code = v4Code;
34+
}
35+
36+
toResponse() {
37+
if (this.object !== undefined) {
38+
const { metadataSize, value } = this.object.encode();
39+
return new Response(value, {
40+
status: this.status,
41+
headers: {
42+
[CfHeader.MetadataSize]: `${metadataSize}`,
43+
"Content-Type": "application/json",
44+
[CfHeader.Error]: JSON.stringify({
45+
message: this.message,
46+
version: 1,
47+
// Note the lowercase 'c', which the runtime expects
48+
v4code: this.v4Code,
49+
}),
50+
},
51+
});
52+
}
53+
return new Response(null, {
54+
status: this.status,
55+
headers: {
56+
[CfHeader.Error]: JSON.stringify({
57+
message: this.message,
58+
version: 1,
59+
// Note the lowercase 'c', which the runtime expects
60+
v4code: this.v4Code,
61+
}),
62+
},
63+
});
64+
}
65+
66+
context(info: string) {
67+
this.message += ` (${info})`;
68+
return this;
69+
}
70+
71+
attach(object: R2Object) {
72+
this.object = object;
73+
return this;
74+
}
75+
}
76+
77+
export class InvalidMetadata extends R2Error {
78+
constructor() {
79+
super(
80+
Status.BadRequest,
81+
"Metadata missing or invalid",
82+
CfCode.InvalidArgument
83+
);
84+
}
85+
}
86+
87+
export class InternalError extends R2Error {
88+
constructor() {
89+
super(
90+
Status.InternalError,
91+
"We encountered an internal error. Please try again.",
92+
CfCode.InternalError
93+
);
94+
}
95+
}
96+
export class NoSuchKey extends R2Error {
97+
constructor() {
98+
super(
99+
Status.NotFound,
100+
"The specified key does not exist.",
101+
CfCode.NoSuchObjectKey
102+
);
103+
}
104+
}
105+
106+
export class EntityTooLarge extends R2Error {
107+
constructor() {
108+
super(
109+
Status.BadRequest,
110+
"Your proposed upload exceeds the maximum allowed object size.",
111+
CfCode.EntityTooLarge
112+
);
113+
}
114+
}
115+
116+
export class InvalidDigest extends R2Error {
117+
constructor() {
118+
super(
119+
Status.BadRequest,
120+
"The Content-MD5 you specified is not valid.",
121+
CfCode.InvalidDigest
122+
);
123+
}
124+
}
125+
126+
export class BadDigest extends R2Error {
127+
constructor() {
128+
super(
129+
Status.BadRequest,
130+
"The Content-MD5 you specified did not match what we received.",
131+
CfCode.BadDigest
132+
);
133+
}
134+
}
135+
136+
export class InvalidObjectName extends R2Error {
137+
constructor() {
138+
super(
139+
Status.BadRequest,
140+
"The specified object name is not valid.",
141+
CfCode.InvalidObjectName
142+
);
143+
}
144+
}
145+
146+
export class InvalidMaxKeys extends R2Error {
147+
constructor() {
148+
super(
149+
Status.BadRequest,
150+
"MaxKeys params must be positive integer <= 1000.",
151+
CfCode.InvalidMaxKeys
152+
);
153+
}
154+
}
155+
156+
export class PreconditionFailed extends R2Error {
157+
constructor() {
158+
super(
159+
Status.PreconditionFailed,
160+
"At least one of the pre-conditions you specified did not hold.",
161+
CfCode.PreconditionFailed
162+
);
163+
}
164+
}
165+
166+
export class InvalidRange extends R2Error {
167+
constructor() {
168+
super(
169+
Status.RangeNotSatisfiable,
170+
"The requested range is not satisfiable",
171+
CfCode.InvalidRange
172+
);
173+
}
174+
}

0 commit comments

Comments
 (0)