Skip to content

Commit

Permalink
v2: add user error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
calebcase committed Dec 16, 2024
1 parent 258462a commit a34b154
Showing 1 changed file with 43 additions and 7 deletions.
50 changes: 43 additions & 7 deletions v2/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,24 @@ type JsonValue = JsonPrimitive | JsonObject | JsonArray;
export type ProdiaJob = Record<string, JsonValue>;

export type ProdiaJobOptions = {
accept:
| "image/png"
accept?:
| "application/json"
| "image/jpeg"
| "image/png"
| "image/webp"
| "multipart/form-data"
| "video/mp4";
inputs?: (File | Blob | ArrayBuffer)[];
};

const defaultJobOptions: ProdiaJobOptions = {
accept: "image/jpeg",
accept: undefined,
};

export type ProdiaJobResponse = {
arrayBuffer: () => Promise<ArrayBuffer>; // we only support direct image response now
// Currently only one output field is expected for all job types.
//This will return the raw bytes for that output.
arrayBuffer: () => Promise<ArrayBuffer>;
};

/* client & client configuration*/
Expand All @@ -62,6 +65,7 @@ export type CreateProdiaOptions = {

/* error types */

export class ProdiaUserError extends Error {}
export class ProdiaCapacityError extends Error {}
export class ProdiaBadResponseError extends Error {}

Expand All @@ -87,6 +91,9 @@ export const createProdia = ({

const formData = new FormData();

// TODO: The input content-type is assumed here, but it shouldn't be.
// Eventually we will support non-image inputs and we will need some way
// to specify the content-type of the input.
if (options.inputs !== undefined) {
for (const input of options.inputs) {
if (typeof File !== "undefined" && input instanceof File) {
Expand Down Expand Up @@ -122,11 +129,18 @@ export const createProdia = ({
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
Accept: options.accept,
Accept: ["multipart/form-data", options.accept].filter(
Boolean,
).join("; "),
},
body: formData,
});

// We bail from the loop if we get a 2xx response to avoid sleeping unnecessarily.
if (response.status >= 200 && response.status < 300) {
break;
}

if (response.status === 429) {
retries += 1;
} else if (response.status < 200 || response.status > 299) {
Expand All @@ -138,25 +152,47 @@ export const createProdia = ({
setTimeout(resolve, retryAfter * 1000)
);
} while (
response.status !== 400 &&
response.status !== 401 &&
response.status !== 403 &&
(response.status < 200 || response.status > 299) &&
errors <= maxErrors &&
retries <= maxRetries
);

if (response.status === 429) {
throw new ProdiaCapacityError(
"Unable to schedule job with current token",
"Unable to schedule the job with current token.",
);
}

const body = await response.formData();
const job = JSON.parse(
new TextDecoder().decode(
await (body.get("job") as Blob).arrayBuffer()
)
);
if (job.error) {
throw new ProdiaUserError(job.error);
}

if (response.status < 200 || response.status > 299) {
throw new ProdiaBadResponseError(
`${response.status} ${response.statusText}`,
);
}

return {
arrayBuffer: () => response.arrayBuffer(),
arrayBuffer: () => {
return new Promise<ArrayBuffer>((resolve, reject) => {
const output = body.get("output") as File;
const reader = new FileReader();
reader.readAsArrayBuffer(output);
reader.onload = () => resolve(reader.result as ArrayBuffer);
reader.onerror = () =>
reject(new Error("Failed to read output"));
});
},
};
};

Expand Down

0 comments on commit a34b154

Please sign in to comment.