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 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 };