@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.
- package/dist/api/client.d.ts +2 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +2 -0
- package/dist/api/extractions/client.d.ts +124 -0
- package/dist/api/extractions/client.d.ts.map +1 -0
- package/dist/api/extractions/client.js +188 -0
- package/dist/api/projects/client.d.ts +6 -9
- package/dist/api/projects/client.d.ts.map +1 -1
- package/dist/api/projects/client.js +20 -19
- package/dist/client.d.ts +32 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +47 -0
- package/dist/generated_types.d.ts +37295 -28619
- package/dist/generated_types.d.ts.map +1 -1
- package/dist/generated_types.js +1141 -628
- package/dist/types.d.ts +42 -216
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +7 -25
- package/package.json +1 -1
package/dist/api/client.d.ts
CHANGED
|
@@ -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
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/api/client.js
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
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
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;
|
|
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
|
}
|