gengo-ts 1.0.0
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 +316 -0
- package/dist/common-Bk4hl8fX.d.ts +53 -0
- package/dist/index.d.ts +703 -0
- package/dist/index.js +469 -0
- package/dist/index.js.map +1 -0
- package/dist/webhook/express.d.ts +50 -0
- package/dist/webhook/express.js +24 -0
- package/dist/webhook/express.js.map +1 -0
- package/dist/webhook/hono.d.ts +40 -0
- package/dist/webhook/hono.js +24 -0
- package/dist/webhook/hono.js.map +1 -0
- package/dist/webhook/index.d.ts +95 -0
- package/dist/webhook/index.js +100 -0
- package/dist/webhook/index.js.map +1 -0
- package/package.json +67 -0
package/README.md
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
# gengo-ts
|
|
2
|
+
|
|
3
|
+
Modern TypeScript client for the [Gengo Translation API](https://gengo.com/).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Full TypeScript support with comprehensive types
|
|
8
|
+
- Works across Node.js 18+, Deno, and Bun
|
|
9
|
+
- Zero runtime dependencies
|
|
10
|
+
- Class-based API with namespaced methods
|
|
11
|
+
- Typed error handling
|
|
12
|
+
- Webhook handlers for job updates
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# npm
|
|
18
|
+
npm install gengo-ts
|
|
19
|
+
|
|
20
|
+
# pnpm
|
|
21
|
+
pnpm add gengo-ts
|
|
22
|
+
|
|
23
|
+
# yarn
|
|
24
|
+
yarn add gengo-ts
|
|
25
|
+
|
|
26
|
+
# bun
|
|
27
|
+
bun add gengo-ts
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { GengoClient } from 'gengo-ts';
|
|
34
|
+
|
|
35
|
+
const client = new GengoClient({
|
|
36
|
+
publicKey: 'your_public_key',
|
|
37
|
+
privateKey: 'your_private_key',
|
|
38
|
+
sandbox: true, // Use false for production
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Get account balance
|
|
42
|
+
const balance = await client.account.getBalance();
|
|
43
|
+
console.log(`Balance: ${balance.credits} ${balance.currency}`);
|
|
44
|
+
|
|
45
|
+
// Submit a translation job
|
|
46
|
+
const order = await client.jobs.create({
|
|
47
|
+
job_1: {
|
|
48
|
+
body_src: 'Hello, world!',
|
|
49
|
+
lc_src: 'en',
|
|
50
|
+
lc_tgt: 'ja',
|
|
51
|
+
tier: 'standard',
|
|
52
|
+
slug: 'greeting',
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
console.log(`Order ID: ${order.order_id}`);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## API Reference
|
|
60
|
+
|
|
61
|
+
### Client Configuration
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
const client = new GengoClient({
|
|
65
|
+
publicKey: string; // Your Gengo API public key
|
|
66
|
+
privateKey: string; // Your Gengo API private key
|
|
67
|
+
sandbox?: boolean; // Use sandbox environment (default: false)
|
|
68
|
+
timeout?: number; // Request timeout in ms (default: 30000)
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Account Methods
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
// Get account statistics
|
|
76
|
+
const stats = await client.account.getStats();
|
|
77
|
+
|
|
78
|
+
// Get account information
|
|
79
|
+
const me = await client.account.getMe();
|
|
80
|
+
|
|
81
|
+
// Get account balance
|
|
82
|
+
const balance = await client.account.getBalance();
|
|
83
|
+
|
|
84
|
+
// Get preferred translators
|
|
85
|
+
const translators = await client.account.getPreferredTranslators();
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Jobs Methods
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Submit jobs for translation
|
|
92
|
+
const order = await client.jobs.create({
|
|
93
|
+
job_1: {
|
|
94
|
+
body_src: 'Text to translate',
|
|
95
|
+
lc_src: 'en',
|
|
96
|
+
lc_tgt: 'ja',
|
|
97
|
+
tier: 'standard',
|
|
98
|
+
slug: 'my-job',
|
|
99
|
+
comment: 'Instructions for translator',
|
|
100
|
+
callback_url: 'https://example.com/webhook',
|
|
101
|
+
auto_approve: false,
|
|
102
|
+
custom_data: '{"id": 123}',
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// List recent jobs
|
|
107
|
+
const jobs = await client.jobs.list({ status: 'reviewable', count: 10 });
|
|
108
|
+
|
|
109
|
+
// Get a specific job
|
|
110
|
+
const { job } = await client.jobs.get(jobId);
|
|
111
|
+
|
|
112
|
+
// Get multiple jobs
|
|
113
|
+
const { jobs } = await client.jobs.getMany([1, 2, 3]);
|
|
114
|
+
|
|
115
|
+
// Approve a job
|
|
116
|
+
await client.jobs.update(jobId, {
|
|
117
|
+
action: 'approve',
|
|
118
|
+
rating: 5,
|
|
119
|
+
for_translator: 'Great work!',
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Request revision
|
|
123
|
+
await client.jobs.update(jobId, {
|
|
124
|
+
action: 'revise',
|
|
125
|
+
comment: 'Please use formal language.',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Reject a job
|
|
129
|
+
await client.jobs.update(jobId, {
|
|
130
|
+
action: 'reject',
|
|
131
|
+
reason: 'quality',
|
|
132
|
+
comment: 'Translation is incorrect.',
|
|
133
|
+
follow_up: 'requeue',
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Cancel a job (before translator starts)
|
|
137
|
+
await client.jobs.cancel(jobId);
|
|
138
|
+
|
|
139
|
+
// Get job revisions
|
|
140
|
+
const { revisions } = await client.jobs.getRevisions(jobId);
|
|
141
|
+
|
|
142
|
+
// Get job comments
|
|
143
|
+
const { thread } = await client.jobs.getComments(jobId);
|
|
144
|
+
|
|
145
|
+
// Add a comment
|
|
146
|
+
await client.jobs.addComment(jobId, 'Please clarify the context.');
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Orders Methods
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
// Get order details
|
|
153
|
+
const { order } = await client.orders.get(orderId);
|
|
154
|
+
|
|
155
|
+
// Cancel all available jobs in an order
|
|
156
|
+
await client.orders.cancel(orderId);
|
|
157
|
+
|
|
158
|
+
// Get order comments
|
|
159
|
+
const { thread } = await client.orders.getComments(orderId);
|
|
160
|
+
|
|
161
|
+
// Add comment to order
|
|
162
|
+
await client.orders.addComment(orderId, 'General instructions...');
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Glossary Methods
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// List all glossaries
|
|
169
|
+
const glossaries = await client.glossary.list();
|
|
170
|
+
|
|
171
|
+
// Get a specific glossary
|
|
172
|
+
const glossary = await client.glossary.get(glossaryId);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Service Methods
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// Get supported languages
|
|
179
|
+
const languages = await client.service.getLanguages();
|
|
180
|
+
|
|
181
|
+
// Get language pairs (optionally filtered by source)
|
|
182
|
+
const pairs = await client.service.getLanguagePairs('en');
|
|
183
|
+
|
|
184
|
+
// Get a quote for jobs
|
|
185
|
+
const quote = await client.service.getQuote({
|
|
186
|
+
job_1: {
|
|
187
|
+
body_src: 'Text to translate',
|
|
188
|
+
lc_src: 'en',
|
|
189
|
+
lc_tgt: 'ja',
|
|
190
|
+
tier: 'standard',
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Error Handling
|
|
196
|
+
|
|
197
|
+
The library throws typed errors for different failure modes:
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
import {
|
|
201
|
+
GengoClient,
|
|
202
|
+
GengoError,
|
|
203
|
+
GengoAuthError,
|
|
204
|
+
GengoValidationError,
|
|
205
|
+
GengoNotFoundError,
|
|
206
|
+
GengoRateLimitError,
|
|
207
|
+
GengoInsufficientCreditsError,
|
|
208
|
+
GengoNetworkError,
|
|
209
|
+
GengoJobStateError,
|
|
210
|
+
} from 'gengo-ts';
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
await client.jobs.create(jobs);
|
|
214
|
+
} catch (error) {
|
|
215
|
+
if (error instanceof GengoAuthError) {
|
|
216
|
+
console.error('Authentication failed. Check your API keys.');
|
|
217
|
+
} else if (error instanceof GengoInsufficientCreditsError) {
|
|
218
|
+
console.error('Not enough credits. Please top up.');
|
|
219
|
+
} else if (error instanceof GengoValidationError) {
|
|
220
|
+
console.error(`Validation error (${error.code}): ${error.message}`);
|
|
221
|
+
} else if (error instanceof GengoRateLimitError) {
|
|
222
|
+
console.error('Rate limited. Please slow down.');
|
|
223
|
+
} else if (error instanceof GengoNetworkError) {
|
|
224
|
+
console.error('Network error:', error.message);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
## Webhook Handler
|
|
230
|
+
|
|
231
|
+
Handle job updates and translator comments with the webhook handler:
|
|
232
|
+
|
|
233
|
+
### Express
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import express from 'express';
|
|
237
|
+
import { createWebhookHandler } from 'gengo-ts/webhook';
|
|
238
|
+
import { expressAdapter } from 'gengo-ts/webhook/express';
|
|
239
|
+
|
|
240
|
+
const app = express();
|
|
241
|
+
app.use(express.urlencoded({ extended: true }));
|
|
242
|
+
|
|
243
|
+
const handler = createWebhookHandler({
|
|
244
|
+
onJobUpdate: async (job) => {
|
|
245
|
+
console.log(`Job ${job.job_id}: ${job.status}`);
|
|
246
|
+
if (job.status === 'approved') {
|
|
247
|
+
// Save translation: job.body_tgt
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
onComment: async (comment) => {
|
|
251
|
+
console.log(`Comment on job ${comment.job_id}: ${comment.body}`);
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
app.post('/webhook', expressAdapter(handler));
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Hono (Deno, Bun, Cloudflare Workers)
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { Hono } from 'hono';
|
|
262
|
+
import { createWebhookHandler } from 'gengo-ts/webhook';
|
|
263
|
+
import { honoAdapter } from 'gengo-ts/webhook/hono';
|
|
264
|
+
|
|
265
|
+
const app = new Hono();
|
|
266
|
+
|
|
267
|
+
const handler = createWebhookHandler({
|
|
268
|
+
onJobUpdate: async (job) => {
|
|
269
|
+
console.log(`Job ${job.job_id}: ${job.status}`);
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
app.post('/webhook', honoAdapter(handler));
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Raw Web Request (Deno, Bun, Workers)
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { createWebhookHandler, handleRequest } from 'gengo-ts/webhook';
|
|
280
|
+
|
|
281
|
+
const handler = createWebhookHandler({
|
|
282
|
+
onJobUpdate: async (job) => {
|
|
283
|
+
console.log(`Job ${job.job_id}: ${job.status}`);
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// In your request handler
|
|
288
|
+
const response = await handleRequest(request, handler);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Job Statuses
|
|
292
|
+
|
|
293
|
+
Jobs go through the following statuses:
|
|
294
|
+
|
|
295
|
+
| Status | Description |
|
|
296
|
+
|--------|-------------|
|
|
297
|
+
| `queued` | Being processed, not yet visible to translators |
|
|
298
|
+
| `available` | Waiting for a translator to start |
|
|
299
|
+
| `pending` | Translator is working on it |
|
|
300
|
+
| `reviewable` | Translation complete, awaiting review |
|
|
301
|
+
| `approved` | Approved and complete |
|
|
302
|
+
| `revising` | Sent back for revisions |
|
|
303
|
+
| `rejected` | Rejected by customer |
|
|
304
|
+
| `cancelled` | Cancelled before work started |
|
|
305
|
+
| `hold` | On hold by Gengo support |
|
|
306
|
+
|
|
307
|
+
## Quality Tiers
|
|
308
|
+
|
|
309
|
+
| Tier | Description |
|
|
310
|
+
|------|-------------|
|
|
311
|
+
| `standard` | Native-level fluency, general content |
|
|
312
|
+
| `pro` | Professional translators, specialized content |
|
|
313
|
+
|
|
314
|
+
## License
|
|
315
|
+
|
|
316
|
+
MIT
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quality tier for translation jobs
|
|
3
|
+
*/
|
|
4
|
+
type Tier = 'standard' | 'pro';
|
|
5
|
+
/**
|
|
6
|
+
* Job type
|
|
7
|
+
*/
|
|
8
|
+
type JobType = 'text' | 'file';
|
|
9
|
+
/**
|
|
10
|
+
* Currency code
|
|
11
|
+
*/
|
|
12
|
+
type Currency = 'USD' | string;
|
|
13
|
+
/**
|
|
14
|
+
* Job status values
|
|
15
|
+
*/
|
|
16
|
+
type JobStatus = 'queued' | 'available' | 'pending' | 'reviewable' | 'approved' | 'revising' | 'rejected' | 'cancelled' | 'hold';
|
|
17
|
+
/**
|
|
18
|
+
* Rejection reason
|
|
19
|
+
*/
|
|
20
|
+
type RejectionReason = 'quality' | 'incomplete' | 'other';
|
|
21
|
+
/**
|
|
22
|
+
* Follow-up action after rejection
|
|
23
|
+
*/
|
|
24
|
+
type FollowUp = 'requeue' | 'cancel';
|
|
25
|
+
/**
|
|
26
|
+
* Comment author type
|
|
27
|
+
*/
|
|
28
|
+
type CommentAuthor = 'customer' | 'translator';
|
|
29
|
+
/**
|
|
30
|
+
* File attachment for jobs
|
|
31
|
+
*/
|
|
32
|
+
interface Attachment {
|
|
33
|
+
url: string;
|
|
34
|
+
filename: string;
|
|
35
|
+
mime_type: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Comment in a thread
|
|
39
|
+
*/
|
|
40
|
+
interface Comment {
|
|
41
|
+
body: string;
|
|
42
|
+
author: CommentAuthor;
|
|
43
|
+
ctime: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Pagination options for list endpoints
|
|
47
|
+
*/
|
|
48
|
+
interface PaginationOptions {
|
|
49
|
+
count?: number;
|
|
50
|
+
timestamp_after?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type { Attachment as A, Currency as C, FollowUp as F, JobType as J, PaginationOptions as P, RejectionReason as R, Tier as T, JobStatus as a, Comment as b, CommentAuthor as c };
|