@retab/node 1.0.64 → 1.0.67

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.
@@ -3,11 +3,13 @@ import APIModels from "./models/client";
3
3
  import APIDocuments from "./documents/client";
4
4
  import APISchemas from "./schemas/client";
5
5
  import APIProjects from "./projects/client";
6
+ import APIExtractions from "./extractions/client";
6
7
  export default class APIV1 extends CompositionClient {
7
8
  constructor(client: AbstractClient);
8
9
  models: APIModels;
9
10
  documents: APIDocuments;
10
11
  schemas: APISchemas;
11
12
  projects: APIProjects;
13
+ extractions: APIExtractions;
12
14
  }
13
15
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAE5C,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAAiB;gBACpC,MAAM,EAAE,cAAc;IAGlC,MAAM,YAAuB;IAC7B,SAAS,eAA0B;IACnC,OAAO,aAAwB;IAC/B,QAAQ,cAAyB;CACpC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,SAAS,MAAM,iBAAiB,CAAC;AACxC,OAAO,YAAY,MAAM,oBAAoB,CAAC;AAC9C,OAAO,UAAU,MAAM,kBAAkB,CAAC;AAC1C,OAAO,WAAW,MAAM,mBAAmB,CAAC;AAC5C,OAAO,cAAc,MAAM,sBAAsB,CAAC;AAElD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAAiB;gBACpC,MAAM,EAAE,cAAc;IAGlC,MAAM,YAAuB;IAC7B,SAAS,eAA0B;IACnC,OAAO,aAAwB;IAC/B,QAAQ,cAAyB;IACjC,WAAW,iBAA4B;CAC1C"}
@@ -3,6 +3,7 @@ import APIModels from "./models/client";
3
3
  import APIDocuments from "./documents/client";
4
4
  import APISchemas from "./schemas/client";
5
5
  import APIProjects from "./projects/client";
6
+ import APIExtractions from "./extractions/client";
6
7
  export default class APIV1 extends CompositionClient {
7
8
  constructor(client) {
8
9
  super(client);
@@ -10,5 +11,6 @@ export default class APIV1 extends CompositionClient {
10
11
  this.documents = new APIDocuments(this);
11
12
  this.schemas = new APISchemas(this);
12
13
  this.projects = new APIProjects(this);
14
+ this.extractions = new APIExtractions(this);
13
15
  }
14
16
  }
@@ -0,0 +1,124 @@
1
+ import { CompositionClient, RequestOptions } from "../../client.js";
2
+ import { PaginatedList } from "../../types.js";
3
+ import * as z from "zod";
4
+ declare const ZExtractionCountResponse: z.ZodObject<{
5
+ count: z.ZodNumber;
6
+ }, "strip", z.ZodTypeAny, {
7
+ count: number;
8
+ }, {
9
+ count: number;
10
+ }>;
11
+ type ExtractionCountResponse = z.infer<typeof ZExtractionCountResponse>;
12
+ declare const ZDownloadResponse: z.ZodObject<{
13
+ download_url: z.ZodString;
14
+ filename: z.ZodString;
15
+ expires_at: z.ZodString;
16
+ }, "strip", z.ZodTypeAny, {
17
+ filename: string;
18
+ expires_at: string;
19
+ download_url: string;
20
+ }, {
21
+ filename: string;
22
+ expires_at: string;
23
+ download_url: string;
24
+ }>;
25
+ type DownloadResponse = z.infer<typeof ZDownloadResponse>;
26
+ declare const ZExportToCsvResponse: z.ZodObject<{
27
+ csv_data: z.ZodString;
28
+ rows: z.ZodNumber;
29
+ columns: z.ZodNumber;
30
+ }, "strip", z.ZodTypeAny, {
31
+ rows: number;
32
+ csv_data: string;
33
+ columns: number;
34
+ }, {
35
+ rows: number;
36
+ csv_data: string;
37
+ columns: number;
38
+ }>;
39
+ type ExportToCsvResponse = z.infer<typeof ZExportToCsvResponse>;
40
+ declare const ZDistinctFieldValues: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString, "many">>;
41
+ type DistinctFieldValues = z.infer<typeof ZDistinctFieldValues>;
42
+ declare const ZExtraction: z.ZodRecord<z.ZodString, z.ZodAny>;
43
+ type Extraction = z.infer<typeof ZExtraction>;
44
+ export default class APIExtractions extends CompositionClient {
45
+ constructor(client: CompositionClient);
46
+ /**
47
+ * List extractions with pagination and filtering.
48
+ */
49
+ list({ before, after, limit, order, origin_dot_type, origin_dot_id, from_date, to_date, human_review_status, metadata, filename, }?: {
50
+ before?: string;
51
+ after?: string;
52
+ limit?: number;
53
+ order?: "asc" | "desc";
54
+ origin_dot_type?: string;
55
+ origin_dot_id?: string;
56
+ from_date?: string;
57
+ to_date?: string;
58
+ human_review_status?: string;
59
+ metadata?: Record<string, string>;
60
+ filename?: string;
61
+ }, options?: RequestOptions): Promise<PaginatedList>;
62
+ /**
63
+ * Count extractions matching filters.
64
+ */
65
+ count({ origin_dot_type, origin_dot_id, human_review_status, metadata, }?: {
66
+ origin_dot_type?: string;
67
+ origin_dot_id?: string;
68
+ human_review_status?: string;
69
+ metadata?: Record<string, string>;
70
+ }, options?: RequestOptions): Promise<ExtractionCountResponse>;
71
+ /**
72
+ * Download extractions in various formats. Returns download_url, filename, and expires_at.
73
+ */
74
+ download({ order, origin_dot_id, from_date, to_date, human_review_status, metadata, filename, format, }?: {
75
+ order?: "asc" | "desc";
76
+ origin_dot_id?: string;
77
+ from_date?: string;
78
+ to_date?: string;
79
+ human_review_status?: string;
80
+ metadata?: Record<string, string>;
81
+ filename?: string;
82
+ format?: "jsonl" | "csv" | "xlsx";
83
+ }, options?: RequestOptions): Promise<DownloadResponse>;
84
+ /**
85
+ * Export extractions as CSV. Returns csv_data, rows, and columns.
86
+ */
87
+ getPayloadForExport({ project_id, extraction_ids, json_schema, delimiter, line_delimiter, quote, }: {
88
+ project_id: string;
89
+ extraction_ids: string[];
90
+ json_schema: Record<string, any>;
91
+ delimiter?: string;
92
+ line_delimiter?: string;
93
+ quote?: string;
94
+ }, options?: RequestOptions): Promise<ExportToCsvResponse>;
95
+ /**
96
+ * Update an extraction.
97
+ */
98
+ update(extraction_id: string, { predictions, predictions_draft, human_review_status, json_schema, inference_settings, metadata, }: {
99
+ predictions?: Record<string, any>;
100
+ predictions_draft?: Record<string, any>;
101
+ human_review_status?: string;
102
+ json_schema?: Record<string, any>;
103
+ inference_settings?: Record<string, any>;
104
+ metadata?: Record<string, string>;
105
+ }, options?: RequestOptions): Promise<Extraction>;
106
+ /**
107
+ * Get an extraction by ID.
108
+ */
109
+ get(extraction_id: string, options?: RequestOptions): Promise<Extraction>;
110
+ /**
111
+ * Delete an extraction by ID.
112
+ */
113
+ delete(extraction_id: string, options?: RequestOptions): Promise<void>;
114
+ /**
115
+ * Get distinct values for filterable fields.
116
+ */
117
+ getDistinctFieldValues(options?: RequestOptions): Promise<DistinctFieldValues>;
118
+ /**
119
+ * Download the sample document for an extraction.
120
+ */
121
+ downloadSampleDocument(extraction_id: string, options?: RequestOptions): Promise<ArrayBuffer>;
122
+ }
123
+ export {};
124
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/api/extractions/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,188 @@
1
+ import { CompositionClient } from "../../client.js";
2
+ import { ZPaginatedList } from "../../types.js";
3
+ import * as z from "zod";
4
+ // Response types for extractions API
5
+ const ZExtractionCountResponse = z.object({
6
+ count: z.number(),
7
+ });
8
+ const ZDownloadResponse = z.object({
9
+ download_url: z.string(),
10
+ filename: z.string(),
11
+ expires_at: z.string(),
12
+ });
13
+ const ZExportToCsvResponse = z.object({
14
+ csv_data: z.string(),
15
+ rows: z.number(),
16
+ columns: z.number(),
17
+ });
18
+ const ZDistinctFieldValues = z.record(z.array(z.string()));
19
+ // Generic extraction object (flexible since schema varies)
20
+ const ZExtraction = z.record(z.any());
21
+ export default class APIExtractions extends CompositionClient {
22
+ constructor(client) {
23
+ super(client);
24
+ }
25
+ /**
26
+ * List extractions with pagination and filtering.
27
+ */
28
+ async list({ before, after, limit = 10, order = "desc", origin_dot_type, origin_dot_id, from_date, to_date, human_review_status, metadata, filename, } = {}, options) {
29
+ const params = {
30
+ before,
31
+ after,
32
+ limit,
33
+ order,
34
+ origin_dot_type,
35
+ origin_dot_id,
36
+ from_date,
37
+ to_date,
38
+ human_review_status,
39
+ filename,
40
+ // Note: metadata must be JSON-serialized as the backend expects a JSON string
41
+ metadata: metadata ? JSON.stringify(metadata) : undefined,
42
+ };
43
+ // Remove undefined values
44
+ const cleanParams = Object.fromEntries(Object.entries(params).filter(([_, v]) => v !== undefined));
45
+ return this._fetchJson(ZPaginatedList, {
46
+ url: "/v1/extractions",
47
+ method: "GET",
48
+ params: { ...cleanParams, ...(options?.params || {}) },
49
+ headers: options?.headers,
50
+ });
51
+ }
52
+ /**
53
+ * Count extractions matching filters.
54
+ */
55
+ async count({ origin_dot_type, origin_dot_id, human_review_status = "review_required", metadata, } = {}, options) {
56
+ const params = {
57
+ origin_dot_type,
58
+ origin_dot_id,
59
+ human_review_status,
60
+ // Note: metadata must be JSON-serialized as the backend expects a JSON string
61
+ metadata: metadata ? JSON.stringify(metadata) : undefined,
62
+ };
63
+ // Remove undefined values
64
+ const cleanParams = Object.fromEntries(Object.entries(params).filter(([_, v]) => v !== undefined));
65
+ return this._fetchJson(ZExtractionCountResponse, {
66
+ url: "/v1/extractions/count",
67
+ method: "GET",
68
+ params: { ...cleanParams, ...(options?.params || {}) },
69
+ headers: options?.headers,
70
+ });
71
+ }
72
+ /**
73
+ * Download extractions in various formats. Returns download_url, filename, and expires_at.
74
+ */
75
+ async download({ order = "desc", origin_dot_id, from_date, to_date, human_review_status, metadata, filename, format = "jsonl", } = {}, options) {
76
+ const params = {
77
+ order,
78
+ origin_dot_id,
79
+ from_date,
80
+ to_date,
81
+ human_review_status,
82
+ filename,
83
+ format,
84
+ // Note: metadata must be JSON-serialized as the backend expects a JSON string
85
+ metadata: metadata ? JSON.stringify(metadata) : undefined,
86
+ };
87
+ // Remove undefined values
88
+ const cleanParams = Object.fromEntries(Object.entries(params).filter(([_, v]) => v !== undefined));
89
+ return this._fetchJson(ZDownloadResponse, {
90
+ url: "/v1/extractions/download",
91
+ method: "GET",
92
+ params: { ...cleanParams, ...(options?.params || {}) },
93
+ headers: options?.headers,
94
+ });
95
+ }
96
+ /**
97
+ * Export extractions as CSV. Returns csv_data, rows, and columns.
98
+ */
99
+ async getPayloadForExport({ project_id, extraction_ids, json_schema, delimiter = ";", line_delimiter = "\n", quote = '"', }, options) {
100
+ return this._fetchJson(ZExportToCsvResponse, {
101
+ url: "/v1/extractions/get_payload_for_export",
102
+ method: "POST",
103
+ body: {
104
+ project_id,
105
+ extraction_ids,
106
+ json_schema,
107
+ ...(options?.body || {}),
108
+ },
109
+ params: {
110
+ delimiter,
111
+ line_delimiter,
112
+ quote,
113
+ ...(options?.params || {}),
114
+ },
115
+ headers: options?.headers,
116
+ });
117
+ }
118
+ /**
119
+ * Update an extraction.
120
+ */
121
+ async update(extraction_id, { predictions, predictions_draft, human_review_status, json_schema, inference_settings, metadata, }, options) {
122
+ const body = {};
123
+ if (predictions !== undefined)
124
+ body.predictions = predictions;
125
+ if (predictions_draft !== undefined)
126
+ body.predictions_draft = predictions_draft;
127
+ if (human_review_status !== undefined)
128
+ body.human_review_status = human_review_status;
129
+ if (json_schema !== undefined)
130
+ body.json_schema = json_schema;
131
+ if (inference_settings !== undefined)
132
+ body.inference_settings = inference_settings;
133
+ if (metadata !== undefined)
134
+ body.metadata = metadata;
135
+ return this._fetchJson(ZExtraction, {
136
+ url: `/v1/extractions/${extraction_id}`,
137
+ method: "PATCH",
138
+ body: { ...body, ...(options?.body || {}) },
139
+ params: options?.params,
140
+ headers: options?.headers,
141
+ });
142
+ }
143
+ /**
144
+ * Get an extraction by ID.
145
+ */
146
+ async get(extraction_id, options) {
147
+ return this._fetchJson(ZExtraction, {
148
+ url: `/v1/extractions/${extraction_id}`,
149
+ method: "GET",
150
+ params: options?.params,
151
+ headers: options?.headers,
152
+ });
153
+ }
154
+ /**
155
+ * Delete an extraction by ID.
156
+ */
157
+ async delete(extraction_id, options) {
158
+ return this._fetchJson({
159
+ url: `/v1/extractions/${extraction_id}`,
160
+ method: "DELETE",
161
+ params: options?.params,
162
+ headers: options?.headers,
163
+ });
164
+ }
165
+ /**
166
+ * Get distinct values for filterable fields.
167
+ */
168
+ async getDistinctFieldValues(options) {
169
+ return this._fetchJson(ZDistinctFieldValues, {
170
+ url: "/v1/extractions/fields",
171
+ method: "GET",
172
+ params: options?.params,
173
+ headers: options?.headers,
174
+ });
175
+ }
176
+ /**
177
+ * Download the sample document for an extraction.
178
+ */
179
+ async downloadSampleDocument(extraction_id, options) {
180
+ const response = await this._fetch({
181
+ url: `/v1/extractions/${extraction_id}/sample-document`,
182
+ method: "GET",
183
+ params: options?.params,
184
+ headers: options?.headers,
185
+ });
186
+ return response.arrayBuffer();
187
+ }
188
+ }
@@ -1,27 +1,24 @@
1
1
  import { CompositionClient, RequestOptions } from "../../client.js";
2
- import { BaseProjectInput, Project, CreateProjectRequest, MIMEDataInput, RetabParsedChatCompletion } from "../../types.js";
3
- import APIProjectsDocuments from "./documents/client";
4
- import APIProjectsIterations from "./iterations/client";
2
+ import { Project, CreateProjectRequest, MIMEDataInput, RetabParsedChatCompletion } from "../../types.js";
5
3
  export default class APIProjects extends CompositionClient {
6
4
  constructor(client: CompositionClient);
7
- documents: APIProjectsDocuments;
8
- iterations: APIProjectsIterations;
9
5
  create(body: CreateProjectRequest, options?: RequestOptions): Promise<Project>;
10
- update(projectId: string, body: Partial<BaseProjectInput>, options?: RequestOptions): Promise<Project>;
11
6
  list(options?: RequestOptions): Promise<Project[]>;
12
7
  get(projectId: string, options?: RequestOptions): Promise<Project>;
13
8
  delete(projectId: string, options?: RequestOptions): Promise<void>;
14
- extract({ project_id, iteration_id, document, documents, model, image_resolution_dpi, n_consensus, temperature, seed, store }: {
9
+ publish(projectId: string, body?: Record<string, unknown>, options?: RequestOptions): Promise<Project>;
10
+ extract({ project_id, iteration_id, document, model, image_resolution_dpi, n_consensus, temperature, seed, store, metadata, extraction_id }: {
15
11
  project_id: string;
16
12
  iteration_id?: string;
17
- document?: MIMEDataInput;
18
- documents?: MIMEDataInput[];
13
+ document: MIMEDataInput;
19
14
  model?: string;
20
15
  image_resolution_dpi?: number;
21
16
  n_consensus?: number;
22
17
  temperature?: number;
23
18
  seed?: number;
24
19
  store?: boolean;
20
+ metadata?: Record<string, string>;
21
+ extraction_id?: string;
25
22
  }, options?: RequestOptions): Promise<RetabParsedChatCompletion>;
26
23
  }
27
24
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/api/projects/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,gBAAgB,EAAa,OAAO,EAAkE,oBAAoB,EAAE,aAAa,EAAa,yBAAyB,EAA8B,MAAM,gBAAgB,CAAC;AAC7O,OAAO,oBAAoB,MAAM,oBAAoB,CAAC;AACtD,OAAO,qBAAqB,MAAM,qBAAqB,CAAC;AAExD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,iBAAiB;gBAC1C,MAAM,EAAE,iBAAiB;IAIrC,SAAS,uBAAkC;IAC3C,UAAU,wBAAmC;IAEvC,MAAM,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAU9E,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAUtG,IAAI,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IASlD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IASlE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE,OAAO,CAAC,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,SAAS,EACT,KAAK,EACL,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,IAAI,EACJ,KAAK,EACR,EAAE;QACC,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,EAAE,aAAa,CAAC;QACzB,SAAS,CAAC,EAAE,aAAa,EAAE,CAAC;QAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,OAAO,CAAC;KACnB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,yBAAyB,CAAC;CA2BnE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/api/projects/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAa,OAAO,EAAmC,oBAAoB,EAAE,aAAa,EAAa,yBAAyB,EAA8B,MAAM,gBAAgB,CAAC;AAE5L,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,iBAAiB;gBAC1C,MAAM,EAAE,iBAAiB;IAI/B,MAAM,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAU9E,IAAI,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IASlD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IASlE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC;IAYtG,OAAO,CAAC,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,KAAK,EACL,oBAAoB,EACpB,WAAW,EACX,WAAW,EACX,IAAI,EACJ,KAAK,EACL,QAAQ,EACR,aAAa,EAChB,EAAE;QACC,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,QAAQ,EAAE,aAAa,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAClC,aAAa,CAAC,EAAE,MAAM,CAAC;KAC1B,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,yBAAyB,CAAC;CA8BnE"}
@@ -1,13 +1,9 @@
1
1
  import { CompositionClient } from "../../client.js";
2
2
  import { mimeToBlob } from "../../mime.js";
3
- import { dataArray, ZBaseProject, ZProjectLoose as ZProject, ZCreateProjectRequest, ZMIMEData, ZRetabParsedChatCompletion } from "../../types.js";
4
- import APIProjectsDocuments from "./documents/client";
5
- import APIProjectsIterations from "./iterations/client";
3
+ import { dataArray, ZProject, ZCreateProjectRequest, ZMIMEData, ZRetabParsedChatCompletion } from "../../types.js";
6
4
  export default class APIProjects extends CompositionClient {
7
5
  constructor(client) {
8
6
  super(client);
9
- this.documents = new APIProjectsDocuments(this);
10
- this.iterations = new APIProjectsIterations(this);
11
7
  }
12
8
  async create(body, options) {
13
9
  return this._fetchJson(ZProject, {
@@ -18,15 +14,6 @@ export default class APIProjects extends CompositionClient {
18
14
  headers: options?.headers,
19
15
  });
20
16
  }
21
- async update(projectId, body, options) {
22
- return this._fetchJson(ZProject, {
23
- url: `/v1/projects/${projectId}`,
24
- method: "PATCH",
25
- body: { ...(await ZBaseProject.partial().parseAsync(body)), ...(options?.body || {}) },
26
- params: options?.params,
27
- headers: options?.headers,
28
- });
29
- }
30
17
  async list(options) {
31
18
  return this._fetchJson(dataArray(ZProject), {
32
19
  url: "/v1/projects",
@@ -51,14 +38,23 @@ export default class APIProjects extends CompositionClient {
51
38
  headers: options?.headers,
52
39
  });
53
40
  }
54
- async extract({ project_id, iteration_id, document, documents, model, image_resolution_dpi, n_consensus, temperature, seed, store }, options) {
55
- if (!document && (!documents || documents.length === 0)) {
56
- throw new Error("Either 'document' or 'documents' must be provided.");
57
- }
41
+ async publish(projectId, body, options) {
42
+ const mergedBody = body || options?.body ? { ...(body || {}), ...(options?.body || {}) } : undefined;
43
+ return this._fetchJson(ZProject, {
44
+ url: `/v1/projects/${projectId}/publish`,
45
+ method: "POST",
46
+ body: mergedBody,
47
+ params: options?.params,
48
+ headers: options?.headers,
49
+ });
50
+ }
51
+ async extract({ project_id, iteration_id, document, model, image_resolution_dpi, n_consensus, temperature, seed, store, metadata, extraction_id }, options) {
58
52
  const url = iteration_id ? `/v1/projects/extract/${project_id}/${iteration_id}` : `/v1/projects/extract/${project_id}`;
53
+ // Parse and convert document to blob for multipart form upload
54
+ const parsedDocument = await ZMIMEData.parseAsync(document);
59
55
  // Only include optional parameters if they are provided
60
56
  const bodyParams = {
61
- documents: (await ZMIMEData.array().parseAsync([...document ? [document] : [], ...(documents || [])])).map(mimeToBlob)
57
+ document: mimeToBlob(parsedDocument)
62
58
  };
63
59
  if (model !== undefined)
64
60
  bodyParams.model = model;
@@ -72,6 +68,11 @@ export default class APIProjects extends CompositionClient {
72
68
  bodyParams.seed = seed;
73
69
  if (store !== undefined)
74
70
  bodyParams.store = store;
71
+ // Note: metadata must be JSON-serialized since multipart forms only accept primitive types
72
+ if (metadata !== undefined)
73
+ bodyParams.metadata = JSON.stringify(metadata);
74
+ if (extraction_id !== undefined)
75
+ bodyParams.extraction_id = extraction_id;
75
76
  return this._fetchJson(ZRetabParsedChatCompletion, {
76
77
  url,
77
78
  method: "POST",
package/dist/client.d.ts CHANGED
@@ -24,12 +24,16 @@ export declare class APIError extends Error {
24
24
  info: string;
25
25
  constructor(status: number, info: string);
26
26
  }
27
+ export declare class SignatureVerificationError extends Error {
28
+ constructor(message: string);
29
+ }
27
30
  export declare const DateOrISO: z.ZodUnion<[z.ZodDate, z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, Date, string>]>;
28
31
  type AuthTypes = {
29
32
  apiKey: string;
30
33
  } | {};
31
34
  export type ClientOptions = {
32
35
  baseUrl?: string;
36
+ timeout?: number;
33
37
  } & AuthTypes;
34
38
  export type RequestOptions = {
35
39
  params?: Record<string, any>;
@@ -38,6 +42,7 @@ export type RequestOptions = {
38
42
  };
39
43
  export declare class FetcherClient extends AbstractClient {
40
44
  options: ClientOptions;
45
+ timeout: number;
41
46
  constructor(options?: ClientOptions);
42
47
  _fetch(params: {
43
48
  url: string;
@@ -47,6 +52,33 @@ export declare class FetcherClient extends AbstractClient {
47
52
  bodyMime?: "application/json" | "multipart/form-data";
48
53
  body?: Record<string, any>;
49
54
  }): Promise<Response>;
55
+ /**
56
+ * Verify the signature of a webhook event.
57
+ *
58
+ * @param eventBody - The raw request body as a string or Buffer
59
+ * @param eventSignature - The signature from the request header (x-retab-signature)
60
+ * @param secret - The webhook secret key used for signing
61
+ * @returns The parsed event payload (JSON)
62
+ * @throws {SignatureVerificationError} If the signature verification fails
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * import { FetcherClient } from './client';
67
+ *
68
+ * // In your webhook handler
69
+ * const secret = "your_webhook_secret";
70
+ * const body = req.body; // Raw string or Buffer
71
+ * const signature = req.headers['x-retab-signature'];
72
+ *
73
+ * try {
74
+ * const event = FetcherClient.verifyEvent(body, signature, secret);
75
+ * console.log(`Verified event: ${event}`);
76
+ * } catch (error) {
77
+ * console.log("Invalid signature!");
78
+ * }
79
+ * ```
80
+ */
81
+ static verifyEvent(eventBody: string | Buffer, eventSignature: string, secret: string): any;
50
82
  }
51
83
  export {};
52
84
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAEzB,KAAK,WAAW,GAAG;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;IACtD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC;AAyCF,qBAAa,cAAc;IACzB,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;cAGnC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;cAC9C,UAAU,CAAC,SAAS,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;cAc9H,YAAY,CAAC,SAAS,SAAS,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;CAQ/J;AAED,qBAAa,iBAAkB,SAAQ,cAAc;IACnD,SAAS,CAAC,OAAO,EAAE,cAAc,CAAC;gBACtB,MAAM,EAAE,cAAc;IAIlC,SAAS,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;CAGzD;AAED,qBAAa,QAAS,SAAQ,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;gBACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;CAKzC;AAED,eAAO,MAAM,SAAS,gGAKpB,CAAC;AAEH,KAAK,SAAS,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,EAAE,CAAC;AACzC,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,SAAS,CAAC;AAEd,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B,CAAC;AAEF,qBAAa,aAAc,SAAQ,cAAc;IAC/C,OAAO,EAAE,aAAa,CAAC;gBACX,OAAO,CAAC,EAAE,aAAa;IAe7B,MAAM,CAAC,MAAM,EAAE;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC7B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,QAAQ,CAAC,EAAE,kBAAkB,GAAG,qBAAqB,CAAC;QACtD,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC5B,GAAG,OAAO,CAAC,QAAQ,CAAC;CA2CtB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as z from "zod";
2
+ import * as crypto from "crypto";
2
3
  async function* streamResponse(schema, response) {
3
4
  let body = "";
4
5
  let depth = 0;
@@ -86,6 +87,12 @@ export class APIError extends Error {
86
87
  this.info = info;
87
88
  }
88
89
  }
90
+ export class SignatureVerificationError extends Error {
91
+ constructor(message) {
92
+ super(message);
93
+ this.name = "SignatureVerificationError";
94
+ }
95
+ }
89
96
  export const DateOrISO = z.union([
90
97
  z.date(),
91
98
  z.string().refine(val => !isNaN(Date.parse(val)), {
@@ -96,6 +103,7 @@ export class FetcherClient extends AbstractClient {
96
103
  constructor(options) {
97
104
  super();
98
105
  this.options = options || {};
106
+ this.timeout = this.options.timeout ?? 1800000; // Default 1800 seconds (in milliseconds)
99
107
  // Validate that at least one authentication method is provided
100
108
  const apiKey = "apiKey" in this.options ? this.options.apiKey : process.env["RETAB_API_KEY"];
101
109
  if (!apiKey) {
@@ -137,10 +145,49 @@ export class FetcherClient extends AbstractClient {
137
145
  const apiKey = "apiKey" in this.options ? this.options.apiKey : process.env["RETAB_API_KEY"];
138
146
  headers["Api-Key"] = apiKey;
139
147
  init.headers = headers;
148
+ init.signal = AbortSignal.timeout(this.timeout);
140
149
  let res = await fetch(url, init);
141
150
  if (!res.ok) {
142
151
  throw new APIError(res.status, await res.text());
143
152
  }
144
153
  return res;
145
154
  }
155
+ /**
156
+ * Verify the signature of a webhook event.
157
+ *
158
+ * @param eventBody - The raw request body as a string or Buffer
159
+ * @param eventSignature - The signature from the request header (x-retab-signature)
160
+ * @param secret - The webhook secret key used for signing
161
+ * @returns The parsed event payload (JSON)
162
+ * @throws {SignatureVerificationError} If the signature verification fails
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * import { FetcherClient } from './client';
167
+ *
168
+ * // In your webhook handler
169
+ * const secret = "your_webhook_secret";
170
+ * const body = req.body; // Raw string or Buffer
171
+ * const signature = req.headers['x-retab-signature'];
172
+ *
173
+ * try {
174
+ * const event = FetcherClient.verifyEvent(body, signature, secret);
175
+ * console.log(`Verified event: ${event}`);
176
+ * } catch (error) {
177
+ * console.log("Invalid signature!");
178
+ * }
179
+ * ```
180
+ */
181
+ static verifyEvent(eventBody, eventSignature, secret) {
182
+ const bodyBuffer = typeof eventBody === 'string' ? Buffer.from(eventBody, 'utf-8') : eventBody;
183
+ const expectedSignature = crypto
184
+ .createHmac('sha256', secret)
185
+ .update(bodyBuffer)
186
+ .digest('hex');
187
+ // Use constant-time comparison to prevent timing attacks
188
+ if (!crypto.timingSafeEqual(Buffer.from(eventSignature), Buffer.from(expectedSignature))) {
189
+ throw new SignatureVerificationError("Invalid signature");
190
+ }
191
+ return JSON.parse(bodyBuffer.toString('utf-8'));
192
+ }
146
193
  }