@anyformat/sdk 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,6 +24,22 @@ const result = await af
24
24
  result.field("vendor")?.value; // -> "Acme Corp"
25
25
  ```
26
26
 
27
+ ## Quick parse: one call → markdown
28
+
29
+ `af.parse()` runs the platform's atomic `/parse` operation (a fast lite parse)
30
+ and returns an opaque `jobId`. Poll `getParseMarkdown(jobId)` for the markdown —
31
+ no workflow to author or manage.
32
+
33
+ ```ts
34
+ const jobId = await af.parse(file); // File | Blob
35
+ let markdown = await af.getParseMarkdown(jobId);
36
+ while (markdown === null) {
37
+ await new Promise((r) => setTimeout(r, 3000));
38
+ markdown = await af.getParseMarkdown(jobId); // null until done
39
+ }
40
+ console.log(markdown);
41
+ ```
42
+
27
43
  ## Managing workflows
28
44
 
29
45
  ```ts
@@ -33,6 +49,29 @@ for (const wf of workflows) console.log(wf.id, wf.name);
33
49
  await af.deleteWorkflow(workflows[0].id); // -> the deleted id
34
50
  ```
35
51
 
52
+ ## Smart lookup
53
+
54
+ Resolve a field by matching the document against a reference file (CSV/catalog) instead of
55
+ reading it off the page — flag the field with `{ lookup: true }` and pass the file via
56
+ `lookupFiles`:
57
+
58
+ ```ts
59
+ await af
60
+ .workflow("Invoice + vendor lookup")
61
+ .parse()
62
+ .extract(
63
+ [
64
+ Schema.string("vendor_name", "Vendor as printed on the invoice."),
65
+ Schema.string("vendor_id", "Canonical vendor code from the catalog, joined on vendor_name.", { lookup: true }),
66
+ ],
67
+ { lookupFiles: ["vendor_catalog.csv"], lookupSuggestion: "Join vendor_name → vendor_id." },
68
+ )
69
+ .run(file)
70
+ .wait();
71
+ ```
72
+
73
+ Full runnable example: [`examples/smart-lookup.mjs`](examples/smart-lookup.mjs).
74
+
36
75
  ## How it's built
37
76
 
38
77
  The wire types and the low-level HTTP client are **generated** from the API's
@@ -43,8 +82,8 @@ ergonomic layer (`Schema`, `WorkflowBuilder`, `Result`, `Anyformat`) wraps it.
43
82
  ## Regenerating (and the drift guard)
44
83
 
45
84
  ```bash
46
- npm run gen # dump the v2 OpenAPI offline + regenerate src/sdk
47
- npm run gen:check # regenerate and fail if the committed output drifted
85
+ bun run gen # dump the v2 OpenAPI offline + regenerate src/sdk
86
+ bun run gen:check # regenerate and fail if the committed output drifted
48
87
  ```
49
88
 
50
89
  `gen:check` runs in CI and as a pre-commit hook (scoped to changes under
@@ -55,10 +94,30 @@ caught as a type error, not just a diff.
55
94
 
56
95
  ## Scripts
57
96
 
97
+ Install deps with `bun install --frozen-lockfile` (matches CI + the frontend
98
+ toolchain). Then:
99
+
58
100
  | script | what |
59
101
  | --- | --- |
60
- | `npm run gen` | dump spec + regenerate `src/sdk` |
61
- | `npm run gen:check` | regenerate + assert no drift |
62
- | `npm run build` | bundle to `dist/` (ESM + CJS + types) via tsup |
63
- | `npm run typecheck` | `tsc --noEmit` |
64
- | `npm test` | vitest |
102
+ | `bun run gen` | dump spec + regenerate `src/sdk` |
103
+ | `bun run gen:check` | regenerate + assert no drift |
104
+ | `bun run build` | bundle to `dist/` (ESM + CJS + types) via tsup |
105
+ | `bun run typecheck` | `tsc --noEmit` |
106
+ | `bun run test` | vitest |
107
+
108
+ ## Releasing
109
+
110
+ Cut on demand — a maintainer bumps the version in a PR, then pushes a `sdk-js-vX.Y.Z` tag on the release commit. Full flow + one-time setup: [`../RELEASING.md`](../RELEASING.md). Break-glass: `./publish.sh [--build-only|--dry-run]`.
111
+
112
+ ## Node configuration knobs
113
+
114
+ Every knob is an option on `.parse({...})` / `.extract(fields, {...})`. `parse` options are a
115
+ `mode`-discriminated union, so a wrong-mode knob is a compile-time error.
116
+
117
+ **`.parse({...})`** — `mode` (`"standard"`/`"agentic"`/`"lite"`), `promptHint`, `figureEnhancement`,
118
+ `cache`; **agentic-only** `effort` (`"low"`/`"mid"`/`"accurate"`); **lite-only** `ocrEffort`
119
+ (`"medium"`/`"high"`), `region` (`"eu"`/`"global"`), `skipRoutingReview`, `figures`,
120
+ `textFormatting`, `routingEffort`.
121
+
122
+ **`.extract(fields, {...})`** — `mode` (`"standard"`/`"agentic"`/`"max"`/`"lite"`), `useImages`,
123
+ `lookupSuggestion`, `lookupReasoningEffort` (`"minimal"`/`"low"`/`"medium"`/`"high"`), `lookupFiles`.
package/dist/index.cjs CHANGED
@@ -24,22 +24,72 @@ __export(index_exports, {
24
24
  Anyformat: () => Anyformat,
25
25
  AnyformatError: () => AnyformatError,
26
26
  BadRequest: () => BadRequest,
27
+ BadRequestError: () => BadRequestError,
27
28
  Forbidden: () => Forbidden,
29
+ ForbiddenError: () => ForbiddenError,
28
30
  NotFound: () => NotFound,
31
+ NotFoundError: () => NotFoundError,
29
32
  ParseView: () => ParseView,
30
33
  RateLimited: () => RateLimited,
34
+ RateLimitedError: () => RateLimitedError,
31
35
  Result: () => Result,
32
36
  Run: () => Run,
33
37
  SDKTimeout: () => SDKTimeout,
38
+ SDKTimeoutError: () => SDKTimeoutError,
34
39
  Schema: () => Schema,
35
40
  ServerError: () => ServerError,
36
41
  Unauthorized: () => Unauthorized,
42
+ UnauthorizedError: () => UnauthorizedError,
43
+ Upload: () => Upload,
37
44
  Workflow: () => Workflow,
38
45
  WorkflowBuilder: () => WorkflowBuilder,
39
46
  WorkflowBuilderError: () => WorkflowBuilderError
40
47
  });
41
48
  module.exports = __toCommonJS(index_exports);
42
49
 
50
+ // package.json
51
+ var package_default = {
52
+ name: "@anyformat/sdk",
53
+ version: "0.2.3",
54
+ description: "TypeScript SDK for the AnyFormat API",
55
+ license: "MIT",
56
+ author: "Anyformat <info@anyformat.ai>",
57
+ type: "module",
58
+ main: "./dist/index.cjs",
59
+ module: "./dist/index.js",
60
+ types: "./dist/index.d.ts",
61
+ exports: {
62
+ ".": {
63
+ types: "./dist/index.d.ts",
64
+ import: "./dist/index.js",
65
+ require: "./dist/index.cjs"
66
+ }
67
+ },
68
+ files: [
69
+ "dist"
70
+ ],
71
+ engines: {
72
+ node: ">=18"
73
+ },
74
+ scripts: {
75
+ "gen:spec": 'ROOT=$(unset GIT_DIR && git rev-parse --show-toplevel) && cd "$ROOT/anyformat/services/api" && uv run python "$ROOT/anyformat/libs/public/sdk-js/scripts/dump_openapi.py" "$ROOT/anyformat/libs/public/sdk-js/openapi/v2.json"',
76
+ "gen:client": "openapi-ts",
77
+ gen: "bun run gen:spec && bun run gen:client",
78
+ "gen:check": "bun run gen && git diff --exit-code -- openapi/v2.json src/sdk",
79
+ build: "tsup",
80
+ typecheck: "tsc --noEmit",
81
+ test: "vitest run",
82
+ prepublishOnly: "bun run build"
83
+ },
84
+ devDependencies: {
85
+ "@hey-api/openapi-ts": "^0.99.0",
86
+ "@types/node": "^25.9.1",
87
+ tsup: "^8.3.0",
88
+ typescript: "^5.6.0",
89
+ vitest: "^4.1.7"
90
+ }
91
+ };
92
+
43
93
  // src/builder.ts
44
94
  var import_node_fs = require("fs");
45
95
  var import_node_path = require("path");
@@ -104,10 +154,14 @@ var Result = class {
104
154
  * Convenience accessor for a top-level scalar field on the first
105
155
  * extraction (linear workflows). Returns `undefined` for missing fields
106
156
  * or list-valued fields — read `extractions` directly for those.
157
+ *
158
+ * Parameterise with the declared schema type to type `.value`:
159
+ * `result.field<number>("total").value` is `number | null`.
107
160
  */
108
161
  field(name) {
109
162
  const value = this.extractions[0]?.fields?.[name];
110
- return value !== void 0 && !Array.isArray(value) ? value : void 0;
163
+ if (value === void 0 || Array.isArray(value)) return void 0;
164
+ return value;
111
165
  }
112
166
  };
113
167
 
@@ -124,35 +178,41 @@ var APIError = class extends AnyformatError {
124
178
  status;
125
179
  body;
126
180
  };
127
- var BadRequest = class extends APIError {
181
+ var BadRequestError = class extends APIError {
128
182
  };
129
- var Unauthorized = class extends APIError {
183
+ var UnauthorizedError = class extends APIError {
130
184
  };
131
- var Forbidden = class extends APIError {
185
+ var ForbiddenError = class extends APIError {
132
186
  };
133
- var NotFound = class extends APIError {
187
+ var NotFoundError = class extends APIError {
134
188
  };
135
- var RateLimited = class extends APIError {
189
+ var RateLimitedError = class extends APIError {
136
190
  };
137
191
  var ServerError = class extends APIError {
138
192
  };
139
- var SDKTimeout = class extends AnyformatError {
193
+ var BadRequest = BadRequestError;
194
+ var Unauthorized = UnauthorizedError;
195
+ var Forbidden = ForbiddenError;
196
+ var NotFound = NotFoundError;
197
+ var RateLimited = RateLimitedError;
198
+ var SDKTimeoutError = class extends AnyformatError {
140
199
  };
200
+ var SDKTimeout = SDKTimeoutError;
141
201
  var WorkflowBuilderError = class extends AnyformatError {
142
202
  };
143
203
  function toApiError(status, body) {
144
204
  const message = `AnyFormat API error (${status})`;
145
205
  switch (status) {
146
206
  case 400:
147
- return new BadRequest(status, message, body);
207
+ return new BadRequestError(status, message, body);
148
208
  case 401:
149
- return new Unauthorized(status, message, body);
209
+ return new UnauthorizedError(status, message, body);
150
210
  case 403:
151
- return new Forbidden(status, message, body);
211
+ return new ForbiddenError(status, message, body);
152
212
  case 404:
153
- return new NotFound(status, message, body);
213
+ return new NotFoundError(status, message, body);
154
214
  case 429:
155
- return new RateLimited(status, message, body);
215
+ return new RateLimitedError(status, message, body);
156
216
  default:
157
217
  return status >= 500 ? new ServerError(status, message, body) : new APIError(status, message, body);
158
218
  }
@@ -969,9 +1029,24 @@ var createClient = (config = {}) => {
969
1029
  };
970
1030
 
971
1031
  // src/sdk/client.gen.ts
972
- var client = createClient(createConfig({ baseUrl: "https://api-dev.anyformat.ai" }));
1032
+ var client = createClient(createConfig({ baseUrl: "https://api.anyformat.dev" }));
973
1033
 
974
1034
  // src/sdk/sdk.gen.ts
1035
+ var v2Parse = (options) => (options.client ?? client).post({
1036
+ ...formDataBodySerializer,
1037
+ security: [{ scheme: "bearer", type: "http" }],
1038
+ url: "/v2/operations/parse",
1039
+ ...options,
1040
+ headers: {
1041
+ "Content-Type": null,
1042
+ ...options.headers
1043
+ }
1044
+ });
1045
+ var v2ParseResult = (options) => (options.client ?? client).get({
1046
+ security: [{ scheme: "bearer", type: "http" }],
1047
+ url: "/v2/operations/parse/{job_id}",
1048
+ ...options
1049
+ });
975
1050
  var v2ListWorkflows = (options) => (options?.client ?? client).get({
976
1051
  security: [{ scheme: "bearer", type: "http" }],
977
1052
  url: "/v2/workflows/",
@@ -1005,6 +1080,11 @@ var v2GetFileResults = (options) => (options.client ?? client).get({
1005
1080
  url: "/v2/workflows/{workflow_id}/files/{collection_id}/results/",
1006
1081
  ...options
1007
1082
  });
1083
+ var v2RunFile = (options) => (options.client ?? client).post({
1084
+ security: [{ scheme: "bearer", type: "http" }],
1085
+ url: "/v2/workflows/{workflow_id}/files/{file_id}/run/",
1086
+ ...options
1087
+ });
1008
1088
  var v2RunWorkflow = (options) => (options.client ?? client).post({
1009
1089
  ...formDataBodySerializer,
1010
1090
  security: [{ scheme: "bearer", type: "http" }],
@@ -1015,6 +1095,16 @@ var v2RunWorkflow = (options) => (options.client ?? client).post({
1015
1095
  ...options.headers
1016
1096
  }
1017
1097
  });
1098
+ var v2UploadFile = (options) => (options.client ?? client).post({
1099
+ ...formDataBodySerializer,
1100
+ security: [{ scheme: "bearer", type: "http" }],
1101
+ url: "/v2/workflows/{workflow_id}/upload/",
1102
+ ...options,
1103
+ headers: {
1104
+ "Content-Type": null,
1105
+ ...options.headers
1106
+ }
1107
+ });
1018
1108
 
1019
1109
  // src/run.ts
1020
1110
  var Run = class {
@@ -1042,11 +1132,49 @@ var Run = class {
1042
1132
  }
1043
1133
  await new Promise((resolve) => setTimeout(resolve, pollMs));
1044
1134
  }
1045
- throw new SDKTimeout(`Extraction did not complete within ${timeoutMs}ms`);
1135
+ throw new SDKTimeoutError(`Extraction did not complete within ${timeoutMs}ms`);
1136
+ }
1137
+ };
1138
+
1139
+ // src/upload.ts
1140
+ var Upload = class {
1141
+ /** @internal */
1142
+ constructor(client2, workflowId, collectionId, fileId) {
1143
+ this.client = client2;
1144
+ this.workflowId = workflowId;
1145
+ this.collectionId = collectionId;
1146
+ this.fileId = fileId;
1147
+ }
1148
+ client;
1149
+ workflowId;
1150
+ collectionId;
1151
+ fileId;
1152
+ /** Trigger extraction on the staged file and return a pending `Run`. */
1153
+ async run() {
1154
+ if (!this.fileId) {
1155
+ throw new WorkflowBuilderError("This upload has no file_id \u2014 cannot run it");
1156
+ }
1157
+ const res = await v2RunFile({
1158
+ client: this.client,
1159
+ path: { workflow_id: this.workflowId, file_id: this.fileId }
1160
+ });
1161
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1162
+ return new Run(this.client, this.workflowId, res.data.id ?? this.collectionId);
1046
1163
  }
1047
1164
  };
1048
1165
 
1049
1166
  // src/workflow.ts
1167
+ function validateDocument(file, op) {
1168
+ if (file === null) {
1169
+ throw new WorkflowBuilderError(`${op}() requires a named file`);
1170
+ }
1171
+ const filename = file.name;
1172
+ if (typeof filename !== "string" || filename.length === 0) {
1173
+ throw new WorkflowBuilderError(
1174
+ `${op}() needs a named file so the server can detect its type \u2014 pass a File, e.g. new File([bytes], "invoice.pdf"), not a bare Blob`
1175
+ );
1176
+ }
1177
+ }
1050
1178
  var Workflow = class {
1051
1179
  /** @internal */
1052
1180
  constructor(client2, id, name) {
@@ -1058,29 +1186,36 @@ var Workflow = class {
1058
1186
  id;
1059
1187
  name;
1060
1188
  /** Submit a document against this workflow and return a pending `Run`. */
1061
- async run(file = null, opts = {}) {
1062
- if (file === null && !opts.text) {
1063
- throw new WorkflowBuilderError("run() requires a document \u2014 pass a file or non-empty opts.text");
1064
- }
1065
- if (file !== null && opts.text !== void 0) {
1066
- throw new WorkflowBuilderError("run() accepts either a file or text, not both");
1067
- }
1068
- if (file !== null) {
1069
- const filename = file.name;
1070
- if (typeof filename !== "string" || filename.length === 0) {
1071
- throw new WorkflowBuilderError(
1072
- 'run() needs a named file so the server can detect its type \u2014 pass a File, e.g. new File([bytes], "invoice.pdf"), not a bare Blob'
1073
- );
1074
- }
1075
- }
1189
+ async run(file = null) {
1190
+ validateDocument(file, "run");
1076
1191
  const submitted = await v2RunWorkflow({
1077
1192
  client: this.client,
1078
1193
  path: { workflow_id: this.id },
1079
- body: { file, text: opts.text ?? null }
1194
+ body: { file }
1080
1195
  });
1081
1196
  if (submitted.error) throw toApiError(submitted.response?.status ?? 500, submitted.error);
1082
1197
  return new Run(this.client, this.id, submitted.data.id);
1083
1198
  }
1199
+ /**
1200
+ * Stage a document in this workflow WITHOUT running it (no credits spent).
1201
+ * Returns an `Upload`; call `.run()` on it to start extraction.
1202
+ */
1203
+ async upload(file = null) {
1204
+ validateDocument(file, "upload");
1205
+ const staged = await v2UploadFile({
1206
+ client: this.client,
1207
+ path: { workflow_id: this.id },
1208
+ body: { file }
1209
+ });
1210
+ if (staged.error) throw toApiError(staged.response?.status ?? 500, staged.error);
1211
+ const collectionId = staged.data.file_collection_id;
1212
+ if (!collectionId) {
1213
+ throw new WorkflowBuilderError(
1214
+ "Upload succeeded but the server did not return a file_collection_id \u2014 cannot build an Upload handle"
1215
+ );
1216
+ }
1217
+ return new Upload(this.client, this.id, collectionId, staged.data.file_id ?? null);
1218
+ }
1084
1219
  };
1085
1220
 
1086
1221
  // src/builder.ts
@@ -1109,13 +1244,21 @@ var WorkflowBuilder = class {
1109
1244
  }
1110
1245
  parse(opts = {}) {
1111
1246
  this.require(this.parseNode === null, "parse() can only be called once");
1247
+ const o = opts;
1112
1248
  this.parseNode = {
1113
1249
  type: "parse",
1114
- id: opts.id ?? this.nextId("parse"),
1115
- mode: opts.mode ?? "standard",
1116
- ...opts.promptHint !== void 0 ? { prompt_hint: opts.promptHint } : {},
1117
- figure_enhancement: opts.figureEnhancement ?? false,
1118
- cache: opts.cache ?? true
1250
+ id: o.id ?? this.nextId("parse"),
1251
+ mode: o.mode ?? "standard",
1252
+ ...o.promptHint !== void 0 ? { prompt_hint: o.promptHint } : {},
1253
+ figure_enhancement: o.figureEnhancement ?? false,
1254
+ cache: o.cache ?? true,
1255
+ ...o.effort !== void 0 ? { effort: o.effort } : {},
1256
+ ...o.ocrEffort !== void 0 ? { ocr_effort: o.ocrEffort } : {},
1257
+ ...o.region !== void 0 ? { region: o.region } : {},
1258
+ ...o.skipRoutingReview !== void 0 ? { skip_routing_review: o.skipRoutingReview } : {},
1259
+ ...o.figures !== void 0 ? { figures: o.figures } : {},
1260
+ ...o.textFormatting !== void 0 ? { text_formatting: o.textFormatting } : {},
1261
+ ...o.routingEffort !== void 0 ? { routing_effort: o.routingEffort } : {}
1119
1262
  };
1120
1263
  return this;
1121
1264
  }
@@ -1162,9 +1305,12 @@ var WorkflowBuilder = class {
1162
1305
  const node = {
1163
1306
  type: "extract",
1164
1307
  id: opts.id ?? this.nextId("extract"),
1308
+ ...opts.mode !== void 0 ? { mode: opts.mode } : {},
1165
1309
  extraction_schema: { fields },
1166
1310
  ...lookupFileUploads.length > 0 ? { lookup_file_uploads: lookupFileUploads } : {},
1167
- ...opts.lookupSuggestion !== void 0 ? { lookup_suggestion: opts.lookupSuggestion } : {}
1311
+ ...opts.lookupSuggestion !== void 0 ? { lookup_suggestion: opts.lookupSuggestion } : {},
1312
+ ...opts.lookupReasoningEffort !== void 0 ? { lookup_reasoning_effort: opts.lookupReasoningEffort } : {},
1313
+ ...opts.useImages !== void 0 ? { use_images: opts.useImages } : {}
1168
1314
  };
1169
1315
  this.extracts.push([node, branchId]);
1170
1316
  return this;
@@ -1261,6 +1407,7 @@ var WorkflowBuilder = class {
1261
1407
  };
1262
1408
 
1263
1409
  // src/client.ts
1410
+ var SDK_USER_AGENT = `anyformat-typescript-sdk-${package_default.version}`;
1264
1411
  var Anyformat = class {
1265
1412
  /** @internal */
1266
1413
  _client;
@@ -1270,8 +1417,12 @@ var Anyformat = class {
1270
1417
  baseUrl: opts.baseUrl ?? "https://api.anyformat.ai",
1271
1418
  auth: opts.apiKey,
1272
1419
  // Identifies the caller in our logs (Datadog facet). Plain HTTP callers
1273
- // send no such header and are logged as origin "api".
1274
- headers: { "x-anyformat-origin": "js-sdk" }
1420
+ // send no such header and are logged as origin "api". User-Agent is
1421
+ // ignored by browsers (forbidden header) but used by Node fetch.
1422
+ headers: {
1423
+ "x-anyformat-origin": "js-sdk",
1424
+ "User-Agent": SDK_USER_AGENT
1425
+ }
1275
1426
  })
1276
1427
  );
1277
1428
  }
@@ -1294,6 +1445,42 @@ var Anyformat = class {
1294
1445
  if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1295
1446
  return workflowId;
1296
1447
  }
1448
+ /** Stage a document in a workflow without running it. Returns an `Upload`. */
1449
+ upload(workflowId, file = null) {
1450
+ return new Workflow(this._client, workflowId, "").upload(file);
1451
+ }
1452
+ /** Trigger extraction on already-uploaded files. Returns a pending `Run` per file_id. */
1453
+ async runWorkflow(workflowId, fileIds) {
1454
+ const runs = [];
1455
+ for (const fileId of fileIds) {
1456
+ const res = await v2RunFile({
1457
+ client: this._client,
1458
+ path: { workflow_id: workflowId, file_id: fileId }
1459
+ });
1460
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1461
+ runs.push(new Run(this._client, workflowId, res.data.id ?? fileId));
1462
+ }
1463
+ return runs;
1464
+ }
1465
+ /**
1466
+ * Parse a document with the platform's atomic `/parse` operation (fast lite
1467
+ * parse). Returns an opaque `jobId`; poll `getParseMarkdown(jobId)` for the
1468
+ * parsed markdown.
1469
+ */
1470
+ async parse(file) {
1471
+ const res = await v2Parse({ client: this._client, body: { file } });
1472
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1473
+ return res.data.job_id;
1474
+ }
1475
+ /**
1476
+ * Poll a parse job. Returns the parsed markdown once the job is done, or
1477
+ * `null` while it is still processing.
1478
+ */
1479
+ async getParseMarkdown(jobId) {
1480
+ const res = await v2ParseResult({ client: this._client, path: { job_id: jobId } });
1481
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1482
+ return res.data.status === "done" ? res.data.markdown ?? "" : null;
1483
+ }
1297
1484
  };
1298
1485
 
1299
1486
  // src/schema.ts
@@ -1319,16 +1506,23 @@ var Schema = {
1319
1506
  Anyformat,
1320
1507
  AnyformatError,
1321
1508
  BadRequest,
1509
+ BadRequestError,
1322
1510
  Forbidden,
1511
+ ForbiddenError,
1323
1512
  NotFound,
1513
+ NotFoundError,
1324
1514
  ParseView,
1325
1515
  RateLimited,
1516
+ RateLimitedError,
1326
1517
  Result,
1327
1518
  Run,
1328
1519
  SDKTimeout,
1520
+ SDKTimeoutError,
1329
1521
  Schema,
1330
1522
  ServerError,
1331
1523
  Unauthorized,
1524
+ UnauthorizedError,
1525
+ Upload,
1332
1526
  Workflow,
1333
1527
  WorkflowBuilder,
1334
1528
  WorkflowBuilderError