@anyformat/sdk 0.2.1 → 0.2.2

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,15 @@ const result = await af
24
24
  result.field("vendor")?.value; // -> "Acme Corp"
25
25
  ```
26
26
 
27
+ ## Managing workflows
28
+
29
+ ```ts
30
+ const workflows = await af.listWorkflows({ pageSize: 50 }); // -> Workflow[]
31
+ for (const wf of workflows) console.log(wf.id, wf.name);
32
+
33
+ await af.deleteWorkflow(workflows[0].id); // -> the deleted id
34
+ ```
35
+
27
36
  ## How it's built
28
37
 
29
38
  The wire types and the low-level HTTP client are **generated** from the API's
package/dist/index.cjs CHANGED
@@ -26,6 +26,7 @@ __export(index_exports, {
26
26
  BadRequest: () => BadRequest,
27
27
  Forbidden: () => Forbidden,
28
28
  NotFound: () => NotFound,
29
+ ParseView: () => ParseView,
29
30
  RateLimited: () => RateLimited,
30
31
  Result: () => Result,
31
32
  Run: () => Run,
@@ -33,6 +34,7 @@ __export(index_exports, {
33
34
  Schema: () => Schema,
34
35
  ServerError: () => ServerError,
35
36
  Unauthorized: () => Unauthorized,
37
+ Workflow: () => Workflow,
36
38
  WorkflowBuilder: () => WorkflowBuilder,
37
39
  WorkflowBuilderError: () => WorkflowBuilderError
38
40
  });
@@ -42,18 +44,62 @@ module.exports = __toCommonJS(index_exports);
42
44
  var import_node_fs = require("fs");
43
45
  var import_node_path = require("path");
44
46
 
47
+ // src/parse-view.ts
48
+ var ParseView = class {
49
+ /** @internal */
50
+ constructor(parse) {
51
+ this.parse = parse;
52
+ }
53
+ parse;
54
+ get markdown() {
55
+ return this.parse.markdown ?? null;
56
+ }
57
+ get text() {
58
+ return this.parse.text ?? null;
59
+ }
60
+ get blocks() {
61
+ return this.parse.blocks ?? [];
62
+ }
63
+ /**
64
+ * Document-level confidence (0-100) in the parsed content. May be `null` for
65
+ * some parse modes — fall back to `layoutConfidence`.
66
+ */
67
+ get parseConfidence() {
68
+ return this.parse.parse_confidence ?? null;
69
+ }
70
+ /**
71
+ * Document-level confidence (0-100) in the page layout (block positions).
72
+ * `null` when not available.
73
+ */
74
+ get layoutConfidence() {
75
+ return this.parse.layout_confidence ?? null;
76
+ }
77
+ };
78
+
45
79
  // src/result.ts
46
80
  var Result = class {
47
81
  constructor(raw) {
48
82
  this.raw = raw;
49
83
  }
50
84
  raw;
85
+ _parse;
51
86
  get collectionId() {
52
87
  return this.raw.collection_id;
53
88
  }
54
89
  get extractions() {
55
90
  return this.raw.extractions ?? [];
56
91
  }
92
+ /**
93
+ * Typed view over the parse node's output, or `null` when the workflow has
94
+ * no parse node. Cached so repeated access doesn't re-wrap.
95
+ */
96
+ get parse() {
97
+ if (this._parse === void 0) {
98
+ const raw = this.raw.parse;
99
+ this._parse = raw ? new ParseView(raw) : null;
100
+ }
101
+ return this._parse;
102
+ }
57
103
  /**
58
104
  * Convenience accessor for a top-level scalar field on the first
59
105
  * extraction (linear workflows). Returns `undefined` for missing fields
@@ -926,6 +972,11 @@ var createClient = (config = {}) => {
926
972
  var client = createClient(createConfig({ baseUrl: "https://api-dev.anyformat.ai" }));
927
973
 
928
974
  // src/sdk/sdk.gen.ts
975
+ var v2ListWorkflows = (options) => (options?.client ?? client).get({
976
+ security: [{ scheme: "bearer", type: "http" }],
977
+ url: "/v2/workflows/",
978
+ ...options
979
+ });
929
980
  var v2CreateWorkflow = (options) => (options.client ?? client).post({
930
981
  security: [{ scheme: "bearer", type: "http" }],
931
982
  url: "/v2/workflows/",
@@ -935,6 +986,20 @@ var v2CreateWorkflow = (options) => (options.client ?? client).post({
935
986
  ...options.headers
936
987
  }
937
988
  });
989
+ var v2DeleteWorkflow = (options) => (options.client ?? client).delete({
990
+ security: [{ scheme: "bearer", type: "http" }],
991
+ url: "/v2/workflows/{workflow_id}/",
992
+ ...options
993
+ });
994
+ var v2UpdateWorkflow = (options) => (options.client ?? client).put({
995
+ security: [{ scheme: "bearer", type: "http" }],
996
+ url: "/v2/workflows/{workflow_id}/",
997
+ ...options,
998
+ headers: {
999
+ "Content-Type": "application/json",
1000
+ ...options.headers
1001
+ }
1002
+ });
938
1003
  var v2GetFileResults = (options) => (options.client ?? client).get({
939
1004
  security: [{ scheme: "bearer", type: "http" }],
940
1005
  url: "/v2/workflows/{workflow_id}/files/{collection_id}/results/",
@@ -953,45 +1018,23 @@ var v2RunWorkflow = (options) => (options.client ?? client).post({
953
1018
 
954
1019
  // src/run.ts
955
1020
  var Run = class {
956
- constructor(client2, request, file, text) {
1021
+ /** @internal */
1022
+ constructor(client2, workflowId, id) {
957
1023
  this.client = client2;
958
- this.request = request;
959
- this.file = file;
960
- this.text = text;
1024
+ this.workflowId = workflowId;
1025
+ this.id = id;
961
1026
  }
962
1027
  client;
963
- request;
964
- file;
965
- text;
966
- workflowId = null;
967
- collectionId = null;
968
- /**
969
- * Create the workflow and submit the document — exactly once per `Run`.
970
- * Memoized so that retrying `wait()` after an `SDKTimeout` resumes polling
971
- * the in-flight run instead of creating a duplicate workflow + submission.
972
- */
973
- async submit() {
974
- if (this.collectionId !== null) return;
975
- const created = await v2CreateWorkflow({ client: this.client, body: this.request });
976
- if (created.error) throw toApiError(created.response?.status ?? 500, created.error);
977
- this.workflowId = created.data.id;
978
- const submitted = await v2RunWorkflow({
979
- client: this.client,
980
- path: { workflow_id: this.workflowId },
981
- body: { file: this.file, text: this.text }
982
- });
983
- if (submitted.error) throw toApiError(submitted.response?.status ?? 500, submitted.error);
984
- this.collectionId = submitted.data.id;
985
- }
1028
+ workflowId;
1029
+ id;
986
1030
  async wait(opts = {}) {
987
- const timeoutMs = opts.timeoutMs ?? 12e4;
988
- const pollMs = opts.pollMs ?? 2e3;
989
- await this.submit();
1031
+ const timeoutMs = opts.timeoutMs ?? 3e5;
1032
+ const pollMs = opts.pollMs ?? 3e3;
990
1033
  const deadline = Date.now() + timeoutMs;
991
1034
  while (Date.now() < deadline) {
992
1035
  const results = await v2GetFileResults({
993
1036
  client: this.client,
994
- path: { workflow_id: this.workflowId, collection_id: this.collectionId }
1037
+ path: { workflow_id: this.workflowId, collection_id: this.id }
995
1038
  });
996
1039
  if (!results.error) return new Result(results.data);
997
1040
  if (results.response?.status !== 412) {
@@ -1003,6 +1046,43 @@ var Run = class {
1003
1046
  }
1004
1047
  };
1005
1048
 
1049
+ // src/workflow.ts
1050
+ var Workflow = class {
1051
+ /** @internal */
1052
+ constructor(client2, id, name) {
1053
+ this.client = client2;
1054
+ this.id = id;
1055
+ this.name = name;
1056
+ }
1057
+ client;
1058
+ id;
1059
+ name;
1060
+ /** 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
+ }
1076
+ const submitted = await v2RunWorkflow({
1077
+ client: this.client,
1078
+ path: { workflow_id: this.id },
1079
+ body: { file, text: opts.text ?? null }
1080
+ });
1081
+ if (submitted.error) throw toApiError(submitted.response?.status ?? 500, submitted.error);
1082
+ return new Run(this.client, this.id, submitted.data.id);
1083
+ }
1084
+ };
1085
+
1006
1086
  // src/builder.ts
1007
1087
  var WorkflowBuilder = class {
1008
1088
  constructor(client2, name, description) {
@@ -1034,7 +1114,8 @@ var WorkflowBuilder = class {
1034
1114
  id: opts.id ?? this.nextId("parse"),
1035
1115
  mode: opts.mode ?? "standard",
1036
1116
  ...opts.promptHint !== void 0 ? { prompt_hint: opts.promptHint } : {},
1037
- figure_enhancement: opts.figureEnhancement ?? false
1117
+ figure_enhancement: opts.figureEnhancement ?? false,
1118
+ cache: opts.cache ?? true
1038
1119
  };
1039
1120
  return this;
1040
1121
  }
@@ -1165,26 +1246,17 @@ var WorkflowBuilder = class {
1165
1246
  }
1166
1247
  return { name: this.name, description: this.description, nodes, edges };
1167
1248
  }
1168
- /** Persist the workflow and return its id. */
1249
+ /** Persist the workflow and return a handle you can `.run(file)` on. */
1169
1250
  async create() {
1170
1251
  const res = await v2CreateWorkflow({ client: this.client, body: this.build() });
1171
1252
  if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1172
- return res.data.id;
1253
+ return new Workflow(this.client, res.data.id, res.data.name);
1173
1254
  }
1174
- /** Create the workflow, submit a document, and return a pending `Run`. */
1175
- run(file = null, opts = {}) {
1176
- this.require(
1177
- !(file === null && opts.text === void 0),
1178
- "run() requires a document \u2014 pass a file or opts.text"
1179
- );
1180
- if (file !== null) {
1181
- const filename = file.name;
1182
- this.require(
1183
- typeof filename === "string" && filename.length > 0,
1184
- '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'
1185
- );
1186
- }
1187
- return new Run(this.client, this.build(), file, opts.text ?? null);
1255
+ /** Replace an existing workflow's definition and return a handle you can `.run(file)` on. */
1256
+ async update(workflowId) {
1257
+ const res = await v2UpdateWorkflow({ client: this.client, path: { workflow_id: workflowId }, body: this.build() });
1258
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1259
+ return new Workflow(this.client, res.data.id, res.data.name);
1188
1260
  }
1189
1261
  };
1190
1262
 
@@ -1196,13 +1268,32 @@ var Anyformat = class {
1196
1268
  this._client = createClient(
1197
1269
  createConfig({
1198
1270
  baseUrl: opts.baseUrl ?? "https://api.anyformat.ai",
1199
- auth: opts.apiKey
1271
+ auth: opts.apiKey,
1272
+ // 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" }
1200
1275
  })
1201
1276
  );
1202
1277
  }
1203
1278
  workflow(name, description) {
1204
1279
  return new WorkflowBuilder(this._client, name, description);
1205
1280
  }
1281
+ async listWorkflows(opts) {
1282
+ const res = await v2ListWorkflows({
1283
+ client: this._client,
1284
+ query: { page: opts?.page, page_size: opts?.pageSize, status: opts?.status }
1285
+ });
1286
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1287
+ return res.data.results.map((r) => new Workflow(this._client, r.id, r.name ?? ""));
1288
+ }
1289
+ async deleteWorkflow(workflowId) {
1290
+ const res = await v2DeleteWorkflow({
1291
+ client: this._client,
1292
+ path: { workflow_id: workflowId }
1293
+ });
1294
+ if (res.error) throw toApiError(res.response?.status ?? 500, res.error);
1295
+ return workflowId;
1296
+ }
1206
1297
  };
1207
1298
 
1208
1299
  // src/schema.ts
@@ -1230,6 +1321,7 @@ var Schema = {
1230
1321
  BadRequest,
1231
1322
  Forbidden,
1232
1323
  NotFound,
1324
+ ParseView,
1233
1325
  RateLimited,
1234
1326
  Result,
1235
1327
  Run,
@@ -1237,6 +1329,7 @@ var Schema = {
1237
1329
  Schema,
1238
1330
  ServerError,
1239
1331
  Unauthorized,
1332
+ Workflow,
1240
1333
  WorkflowBuilder,
1241
1334
  WorkflowBuilderError
1242
1335
  });