@saplingai/sapling-js 1.0.45 → 1.0.52
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 +85 -0
- package/package.json +1 -1
- package/sapling/client.d.ts +245 -11
- package/sapling/client.js +699 -13
package/README.md
CHANGED
|
@@ -76,6 +76,14 @@ You should see something like the following output:
|
|
|
76
76
|
}
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
If you only need to apply the corrections, pass `includeErrorCategories: false`. The API then
|
|
80
|
+
skips error classification (faster and lighter), and each edit comes back without
|
|
81
|
+
`error_type`, `general_error_type` or classifier-generated descriptions:
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
client.edits('I have a apple!', undefined, { includeErrorCategories: false, autoApply: true })
|
|
85
|
+
```
|
|
86
|
+
|
|
79
87
|
### Text classification
|
|
80
88
|
|
|
81
89
|
Zero-shot classification with your own labels (plain names or `{ name, description }` objects, 2–20):
|
|
@@ -94,6 +102,30 @@ client
|
|
|
94
102
|
})
|
|
95
103
|
```
|
|
96
104
|
|
|
105
|
+
### Style-guide rulesets
|
|
106
|
+
|
|
107
|
+
Check text against style rules inline, or save a named ruleset once (owned by
|
|
108
|
+
your API key's account — its team, for team-scoped keys) and check against it
|
|
109
|
+
by name:
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
// Define the house style once…
|
|
113
|
+
await client.saveStyleguideRuleset('House Style', [
|
|
114
|
+
'no exclamation marks',
|
|
115
|
+
{ name: 'no jargon', description: 'No corporate buzzwords or filler.' },
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
// …then check against it by name (names match case-insensitively).
|
|
119
|
+
const response = await client.styleguide('Our synergy-driven solution!!', 'House Style');
|
|
120
|
+
console.log(response.data);
|
|
121
|
+
// { violations: [{ rule: 'no jargon', text: 'synergy-driven solution', ... }],
|
|
122
|
+
// rules: ['no exclamation marks', 'no jargon'], compliant: false }
|
|
123
|
+
|
|
124
|
+
// List and delete:
|
|
125
|
+
await client.styleguideRulesets(); // { rulesets: [{ name, rules, ... }] }
|
|
126
|
+
await client.deleteStyleguideRuleset('House Style');
|
|
127
|
+
```
|
|
128
|
+
|
|
97
129
|
## Frontend Quickstart
|
|
98
130
|
|
|
99
131
|
The SDK provides a way to automatically apply edit suggestions to any HTML contenteditable and textarea elements.
|
|
@@ -159,6 +191,28 @@ as `YYYY-MM-DD`, or `'list'`), and every value must be grounded in a quote from
|
|
|
159
191
|
extraction, not inference, so a value that isn't stated is reported in `missing` rather than
|
|
160
192
|
guessed.
|
|
161
193
|
|
|
194
|
+
## Translation
|
|
195
|
+
|
|
196
|
+
Translate text into a target language, named by ISO 639 code (`'fr'`, `'zh-TW'`) or English
|
|
197
|
+
name (`'French'`). Line breaks and markup are preserved, and the detected source language is
|
|
198
|
+
reported alongside the translation:
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
client
|
|
202
|
+
.translate('Hello world.\nSee you at 5pm.', 'fr', { formality: 'formal' })
|
|
203
|
+
.then(function (response) {
|
|
204
|
+
console.log(response.data);
|
|
205
|
+
// { translation: 'Bonjour le monde.\nÀ 17h.',
|
|
206
|
+
// source_lang: 'en', source_lang_name: 'English',
|
|
207
|
+
// target_lang: 'fr', target_lang_name: 'French' }
|
|
208
|
+
})
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Region variants `zh-CN`/`zh-TW`/`zh-HK`, `pt-BR`/`pt-PT`, `en-GB`/`en-US`, `fr-CA` and
|
|
212
|
+
`es-419` are supported as targets; the optional `source_lang` hint never overrides what the
|
|
213
|
+
text actually is, and `formality` (`'formal'`/`'informal'`) picks the register where the
|
|
214
|
+
target language distinguishes them.
|
|
215
|
+
|
|
162
216
|
## Further Documentation
|
|
163
217
|
|
|
164
218
|
- Full Sapling HTTP API and SDK [documentation](https://sapling.ai/docs).
|
|
@@ -179,3 +233,34 @@ try {
|
|
|
179
233
|
console.error(error.response?.status, error.response?.data ?? error.message);
|
|
180
234
|
}
|
|
181
235
|
```
|
|
236
|
+
|
|
237
|
+
API error bodies are JSON objects with a human-readable `msg`, for example
|
|
238
|
+
`{ msg: 'Invalid API key.' }`. The one exception is the 4MB `413`, which uses
|
|
239
|
+
`message`/`result` keys. When a `402` or `429` body has a numeric `retry_after`,
|
|
240
|
+
the request can succeed after waiting that many seconds. Without it, retrying
|
|
241
|
+
unchanged won't help. See
|
|
242
|
+
[Rate Limits & Errors](https://sapling.ai/docs/rate_limits/).
|
|
243
|
+
|
|
244
|
+
To find out why a key is blocked, and for how long, call `accountStatus()`. It
|
|
245
|
+
is unbilled and works while the key is blocked. It reports account-wide blocks:
|
|
246
|
+
an expired key or subscription, depleted credits, a billing limit, the trial
|
|
247
|
+
daily allowance or the monthly quota. It does not report a single endpoint's
|
|
248
|
+
short-term rate limit, because each endpoint has its own allowance. For a
|
|
249
|
+
`Capacity used.` 429, use that response's `retry_after` instead:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
const { data } = await client.accountStatus();
|
|
253
|
+
if (!data.api_access) {
|
|
254
|
+
// blocked_reason: key_expired | subscription_expired | credits_depleted |
|
|
255
|
+
// monthly_billing_limit | trial_daily_limit | monthly_quota_exhausted
|
|
256
|
+
const retry = data.retry_after ? `, retry in ${data.retry_after}s` : '';
|
|
257
|
+
console.log(`${data.blocked_reason}: ${data.message}${retry}`);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Every response includes `api_access`, `blocked_reason`, `message` and
|
|
262
|
+
`usage.monthly_quota_chars`. Keys that aren't team-scoped also get the
|
|
263
|
+
account's `subscription`, prepaid `credits`, `usage.chars_this_month` and, on a
|
|
264
|
+
free trial, `trial`. See [Account Status](https://sapling.ai/docs/api/account-status/).
|
|
265
|
+
Each call counts as 2,000 characters against the endpoint's own rate-limit
|
|
266
|
+
bucket, so call it when something fails rather than before every request.
|
package/package.json
CHANGED
package/sapling/client.d.ts
CHANGED
|
@@ -32,12 +32,137 @@ export type EditOptions = {
|
|
|
32
32
|
lang?: string,
|
|
33
33
|
medical?: boolean,
|
|
34
34
|
advancedEdits?: AdvancedEditOptions,
|
|
35
|
+
/** Defaults to true. false skips error classification: edits omit error_type,
|
|
36
|
+
* general_error_type and classifier-generated descriptions. */
|
|
37
|
+
includeErrorCategories?: boolean,
|
|
35
38
|
}
|
|
36
39
|
|
|
37
40
|
export type AIDetectOptions = {
|
|
38
41
|
sent_scores?: boolean,
|
|
39
42
|
}
|
|
40
43
|
|
|
44
|
+
export type StyleguideRule = string | { name: string; description?: string };
|
|
45
|
+
|
|
46
|
+
export type StyleguideViolation = {
|
|
47
|
+
rule: string;
|
|
48
|
+
text: string;
|
|
49
|
+
start: number | null;
|
|
50
|
+
end: number | null;
|
|
51
|
+
note: string;
|
|
52
|
+
suggestion: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export type StyleguideResponse = {
|
|
56
|
+
violations: StyleguideViolation[];
|
|
57
|
+
rules: string[];
|
|
58
|
+
compliant: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type StyleguideBatchResponse = {
|
|
62
|
+
results: StyleguideResponse[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type StyleguideRuleset = {
|
|
66
|
+
name: string;
|
|
67
|
+
rules: { name: string; description: string }[];
|
|
68
|
+
created_at: string | null;
|
|
69
|
+
updated_at: string | null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type StyleguideRulesetsResponse = {
|
|
73
|
+
rulesets: StyleguideRuleset[];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export type SaveStyleguideRulesetResponse = {
|
|
77
|
+
ruleset: StyleguideRuleset;
|
|
78
|
+
created: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export type DeleteStyleguideRulesetResponse = {
|
|
82
|
+
deleted: string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type AccountBlockedReason =
|
|
86
|
+
| 'key_expired'
|
|
87
|
+
| 'subscription_expired'
|
|
88
|
+
| 'credits_depleted'
|
|
89
|
+
| 'monthly_billing_limit'
|
|
90
|
+
| 'trial_daily_limit'
|
|
91
|
+
| 'monthly_quota_exhausted';
|
|
92
|
+
|
|
93
|
+
export type AccountCreditSummary = {
|
|
94
|
+
enabled: boolean;
|
|
95
|
+
currency: string;
|
|
96
|
+
alert_threshold_percent: number;
|
|
97
|
+
// Present only when `enabled` is true.
|
|
98
|
+
balance_credits?: number;
|
|
99
|
+
purchased_credits?: number;
|
|
100
|
+
consumed_credits?: number;
|
|
101
|
+
consumed_percent?: number;
|
|
102
|
+
low_balance?: boolean;
|
|
103
|
+
depleted?: boolean;
|
|
104
|
+
billing_mode?: string;
|
|
105
|
+
billing_mode_effective_at?: string | null;
|
|
106
|
+
metered_fallback_available?: boolean;
|
|
107
|
+
stops_when_depleted?: boolean;
|
|
108
|
+
billing_started_at?: string;
|
|
109
|
+
auto_topup?: { enabled: boolean; [field: string]: unknown };
|
|
110
|
+
[field: string]: unknown;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type AccountStatusResponse = {
|
|
114
|
+
api_access: boolean;
|
|
115
|
+
blocked_reason: AccountBlockedReason | null;
|
|
116
|
+
message: string | null;
|
|
117
|
+
// Seconds until the block may clear; present only when blocked.
|
|
118
|
+
retry_after?: number;
|
|
119
|
+
usage: {
|
|
120
|
+
monthly_quota_chars: number | null;
|
|
121
|
+
// Omitted for team-scoped keys, like `subscription`, `credits` and `trial`.
|
|
122
|
+
month_start?: string;
|
|
123
|
+
chars_this_month?: number;
|
|
124
|
+
};
|
|
125
|
+
subscription?: {
|
|
126
|
+
active: boolean;
|
|
127
|
+
trial_only: boolean;
|
|
128
|
+
key_expired: boolean;
|
|
129
|
+
};
|
|
130
|
+
credits?: AccountCreditSummary;
|
|
131
|
+
// Present only for free-trial accounts.
|
|
132
|
+
trial?: {
|
|
133
|
+
daily_limit_chars: number | null;
|
|
134
|
+
chars_used_today: number;
|
|
135
|
+
resets_at: 'utc_midnight';
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type SimplifyReadingLevel = 'plain' | 'elementary' | 'middle_school' | 'high_school';
|
|
140
|
+
|
|
141
|
+
export type SimplifyOptions = {
|
|
142
|
+
reading_level?: SimplifyReadingLevel,
|
|
143
|
+
preserve_terms?: string[],
|
|
144
|
+
lang?: string,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export type SimplifyReadabilityScores = {
|
|
148
|
+
grade: number;
|
|
149
|
+
ease: number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export type SimplifyResponse = {
|
|
153
|
+
simplified: string;
|
|
154
|
+
reading_level: SimplifyReadingLevel;
|
|
155
|
+
lang: string;
|
|
156
|
+
readability?: {
|
|
157
|
+
before: SimplifyReadabilityScores;
|
|
158
|
+
after: SimplifyReadabilityScores;
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export type SimplifyBatchResponse = {
|
|
163
|
+
results: SimplifyResponse[];
|
|
164
|
+
}
|
|
165
|
+
|
|
41
166
|
export type LangdetectOptions = {
|
|
42
167
|
top_k?: number,
|
|
43
168
|
segments?: boolean,
|
|
@@ -59,6 +184,10 @@ export type ClassifyResponse = {
|
|
|
59
184
|
multi_label: boolean;
|
|
60
185
|
}
|
|
61
186
|
|
|
187
|
+
export type ClassifyBatchResponse = {
|
|
188
|
+
results: ClassifyResponse[];
|
|
189
|
+
}
|
|
190
|
+
|
|
62
191
|
export type SeoOptions = {
|
|
63
192
|
keywords?: string[],
|
|
64
193
|
suggestions?: boolean,
|
|
@@ -137,9 +266,14 @@ export type QualityRubric = {
|
|
|
137
266
|
export type QualityResponse = {
|
|
138
267
|
score: number;
|
|
139
268
|
sentences?: QualitySentenceScore[];
|
|
269
|
+
truncated?: boolean;
|
|
140
270
|
rubric?: QualityRubric;
|
|
141
271
|
}
|
|
142
272
|
|
|
273
|
+
export type QualityBatchResponse = {
|
|
274
|
+
results: QualityResponse[];
|
|
275
|
+
}
|
|
276
|
+
|
|
143
277
|
export type PIIType = 'email' | 'phone' | 'ssn' | 'credit_card' | 'ip_address' | 'iban' | 'us_bank_routing';
|
|
144
278
|
|
|
145
279
|
export type PIIOptions = {
|
|
@@ -162,19 +296,55 @@ export type PIIResponse = {
|
|
|
162
296
|
redacted_text?: string;
|
|
163
297
|
}
|
|
164
298
|
|
|
299
|
+
export type NERType = 'person' | 'organization' | 'location' | 'date' | 'time' |
|
|
300
|
+
'money' | 'percent' | 'quantity' | 'product' | 'event';
|
|
301
|
+
|
|
302
|
+
export type NEROptions = {
|
|
303
|
+
types?: NERType[],
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export type NEREntity = {
|
|
307
|
+
text: string;
|
|
308
|
+
type: NERType;
|
|
309
|
+
start: number;
|
|
310
|
+
end: number;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type NERResponse = {
|
|
314
|
+
entities: NEREntity[];
|
|
315
|
+
types: NERType[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export type NERBatchResponse = {
|
|
319
|
+
results: NERResponse[];
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export type SafetyCategory = 'toxicity' | 'profanity' | 'harassment' | 'hate_speech' |
|
|
323
|
+
'self_harm' | 'sexual' | 'violence';
|
|
324
|
+
|
|
325
|
+
export type SafetySpan = {
|
|
326
|
+
text: string;
|
|
327
|
+
start: number | null;
|
|
328
|
+
end: number | null;
|
|
329
|
+
scores: Partial<Record<SafetyCategory, number>>;
|
|
330
|
+
flagged_categories: SafetyCategory[];
|
|
331
|
+
}
|
|
332
|
+
|
|
165
333
|
export type SafetyResponse = {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
334
|
+
scores: Record<SafetyCategory, number>;
|
|
335
|
+
flagged: boolean;
|
|
336
|
+
flagged_categories: SafetyCategory[];
|
|
337
|
+
threshold: number;
|
|
338
|
+
spans?: SafetySpan[];
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export type SafetyBatchResponse = {
|
|
342
|
+
results: SafetyResponse[];
|
|
174
343
|
}
|
|
175
344
|
|
|
176
345
|
export type SafetyOptions = {
|
|
177
346
|
threshold?: number,
|
|
347
|
+
spans?: boolean,
|
|
178
348
|
}
|
|
179
349
|
|
|
180
350
|
export type SpellcheckOptions = {
|
|
@@ -215,6 +385,43 @@ export type ExtractResponse = {
|
|
|
215
385
|
missing: string[],
|
|
216
386
|
}
|
|
217
387
|
|
|
388
|
+
export type ExtractBatchResponse = {
|
|
389
|
+
results: ExtractResponse[];
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export type TranslateOptions = {
|
|
393
|
+
source_lang?: string,
|
|
394
|
+
formality?: 'formal' | 'informal',
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
export type TranslateResponse = {
|
|
398
|
+
translation: string,
|
|
399
|
+
source_lang: string,
|
|
400
|
+
source_lang_name: string | null,
|
|
401
|
+
target_lang: string,
|
|
402
|
+
target_lang_name: string,
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export type TranslateBatchResponse = {
|
|
406
|
+
results: TranslateResponse[];
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
export type SummarizeOptions = {
|
|
410
|
+
length?: 'short' | 'medium' | 'long',
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export type SummarizeResponse = {
|
|
414
|
+
/** Mirrors `summary` — the endpoint's original response key. */
|
|
415
|
+
result: string,
|
|
416
|
+
summary: string,
|
|
417
|
+
key_points: string[],
|
|
418
|
+
length: 'short' | 'medium' | 'long',
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
export type SummarizeBatchResponse = {
|
|
422
|
+
results: SummarizeResponse[];
|
|
423
|
+
}
|
|
424
|
+
|
|
218
425
|
export type UserDetails = {
|
|
219
426
|
userId?: string,
|
|
220
427
|
anonUser?: boolean,
|
|
@@ -233,12 +440,39 @@ export declare class Client {
|
|
|
233
440
|
acceptComplete(completeUUID: string, query: string, completion: string, sessionId?: string): Promise<AxiosResponse>;
|
|
234
441
|
tone(text: string): Promise<AxiosResponse>;
|
|
235
442
|
extract(text: string, fields: ExtractField[], options?: ExtractOptions): Promise<AxiosResponse<ExtractResponse>>;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
443
|
+
extract(texts: string[], fields: ExtractField[], options?: ExtractOptions): Promise<AxiosResponse<ExtractBatchResponse>>;
|
|
444
|
+
extract(text: string | string[], fields: ExtractField[], options?: ExtractOptions): Promise<AxiosResponse<ExtractResponse | ExtractBatchResponse>>;
|
|
445
|
+
translate(text: string, targetLang: string, options?: TranslateOptions): Promise<AxiosResponse<TranslateResponse>>;
|
|
446
|
+
translate(texts: string[], targetLang: string, options?: TranslateOptions): Promise<AxiosResponse<TranslateBatchResponse>>;
|
|
447
|
+
translate(text: string | string[], targetLang: string, options?: TranslateOptions): Promise<AxiosResponse<TranslateResponse | TranslateBatchResponse>>;
|
|
448
|
+
summarize(text: string, options?: SummarizeOptions): Promise<AxiosResponse<SummarizeResponse>>;
|
|
449
|
+
summarize(texts: string[], options?: SummarizeOptions): Promise<AxiosResponse<SummarizeBatchResponse>>;
|
|
450
|
+
summarize(text: string | string[], options?: SummarizeOptions): Promise<AxiosResponse<SummarizeResponse | SummarizeBatchResponse>>;
|
|
451
|
+
|
|
452
|
+
aidetect(text: string | string[], options?: AIDetectOptions): Promise<AxiosResponse>;
|
|
453
|
+
styleguide(text: string, rules: StyleguideRule[] | string): Promise<AxiosResponse<StyleguideResponse>>;
|
|
454
|
+
styleguide(texts: string[], rules: StyleguideRule[] | string): Promise<AxiosResponse<StyleguideBatchResponse>>;
|
|
455
|
+
styleguide(text: string | string[], rules: StyleguideRule[] | string): Promise<AxiosResponse<StyleguideResponse | StyleguideBatchResponse>>;
|
|
456
|
+
styleguideRulesets(): Promise<AxiosResponse<StyleguideRulesetsResponse>>;
|
|
457
|
+
saveStyleguideRuleset(name: string, rules: StyleguideRule[]): Promise<AxiosResponse<SaveStyleguideRulesetResponse>>;
|
|
458
|
+
deleteStyleguideRuleset(name: string): Promise<AxiosResponse<DeleteStyleguideRulesetResponse>>;
|
|
459
|
+
simplify(text: string, options?: SimplifyOptions): Promise<AxiosResponse<SimplifyResponse>>;
|
|
460
|
+
simplify(texts: string[], options?: SimplifyOptions): Promise<AxiosResponse<SimplifyBatchResponse>>;
|
|
461
|
+
simplify(text: string | string[], options?: SimplifyOptions): Promise<AxiosResponse<SimplifyResponse | SimplifyBatchResponse>>;
|
|
462
|
+
langdetect(text: string | string[], options?: LangdetectOptions): Promise<AxiosResponse>;
|
|
239
463
|
quality(text: string, options?: QualityOptions): Promise<AxiosResponse<QualityResponse>>;
|
|
464
|
+
quality(texts: string[], options?: QualityOptions): Promise<AxiosResponse<QualityBatchResponse>>;
|
|
465
|
+
quality(text: string | string[], options?: QualityOptions): Promise<AxiosResponse<QualityResponse | QualityBatchResponse>>;
|
|
240
466
|
pii(text: string, options?: PIIOptions): Promise<AxiosResponse<PIIResponse>>;
|
|
467
|
+
ner(text: string, options?: NEROptions): Promise<AxiosResponse<NERResponse>>;
|
|
468
|
+
ner(texts: string[], options?: NEROptions): Promise<AxiosResponse<NERBatchResponse>>;
|
|
469
|
+
ner(text: string | string[], options?: NEROptions): Promise<AxiosResponse<NERResponse | NERBatchResponse>>;
|
|
241
470
|
safety(text: string, options?: SafetyOptions): Promise<AxiosResponse<SafetyResponse>>;
|
|
471
|
+
safety(texts: string[], options?: SafetyOptions): Promise<AxiosResponse<SafetyBatchResponse>>;
|
|
472
|
+
safety(text: string | string[], options?: SafetyOptions): Promise<AxiosResponse<SafetyResponse | SafetyBatchResponse>>;
|
|
242
473
|
classify(text: string, labels: ClassifyLabel[], options?: ClassifyOptions): Promise<AxiosResponse<ClassifyResponse>>;
|
|
474
|
+
classify(texts: string[], labels: ClassifyLabel[], options?: ClassifyOptions): Promise<AxiosResponse<ClassifyBatchResponse>>;
|
|
475
|
+
classify(text: string | string[], labels: ClassifyLabel[], options?: ClassifyOptions): Promise<AxiosResponse<ClassifyResponse | ClassifyBatchResponse>>;
|
|
243
476
|
seo(text: string, options?: SeoOptions): Promise<AxiosResponse<SeoResponse>>;
|
|
477
|
+
accountStatus(): Promise<AxiosResponse<AccountStatusResponse>>;
|
|
244
478
|
}
|
package/sapling/client.js
CHANGED
|
@@ -3,6 +3,58 @@ import { v4 as uuidv4 } from 'uuid';
|
|
|
3
3
|
|
|
4
4
|
// Value types an extract() field may declare; 'string' is the default.
|
|
5
5
|
const EXTRACT_FIELD_TYPES = ['string', 'number', 'integer', 'boolean', 'date', 'list'];
|
|
6
|
+
// Registers translate() accepts; the API rejects anything else with a 400.
|
|
7
|
+
const TRANSLATE_FORMALITIES = ['formal', 'informal'];
|
|
8
|
+
const SUMMARIZE_LENGTHS = ['short', 'medium', 'long'];
|
|
9
|
+
// Reading levels simplify() accepts; the API rejects anything else with a 400.
|
|
10
|
+
const SIMPLIFY_READING_LEVELS = ['plain', 'elementary', 'middle_school', 'high_school'];
|
|
11
|
+
|
|
12
|
+
// Shared by styleguide() and saveStyleguideRuleset(). Shape/type checks only —
|
|
13
|
+
// size limits (rule/description length) are server configuration and enforced
|
|
14
|
+
// there with a clear 400 (see classify()).
|
|
15
|
+
const validateStyleguideRules = (rules, method) => {
|
|
16
|
+
const isValidRule = (rule) => {
|
|
17
|
+
if (typeof rule === 'string') {
|
|
18
|
+
return rule.trim().length > 0;
|
|
19
|
+
}
|
|
20
|
+
if (rule == null || typeof rule !== 'object' || Array.isArray(rule)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (typeof rule.name !== 'string' || rule.name.trim().length === 0) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
if (rule.description !== undefined && typeof rule.description !== 'string') {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
// Reject unknown keys so a typo like `{ name, descrption: '...' }` fails
|
|
30
|
+
// here rather than being forwarded to the API as a malformed rule (the
|
|
31
|
+
// classify()/extract() convention; the MCP object schema is `.strict()`).
|
|
32
|
+
const allowed = new Set(['name', 'description']);
|
|
33
|
+
if (Object.keys(rule).some((key) => !allowed.has(key))) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
if (
|
|
40
|
+
!Array.isArray(rules)
|
|
41
|
+
|| rules.length < 1
|
|
42
|
+
|| rules.length > 20
|
|
43
|
+
// Array.from() materializes holes in sparse arrays as `undefined` (which
|
|
44
|
+
// isValidRule rejects); a bare `.every()` would skip them and let a hole
|
|
45
|
+
// through to be serialized as `null`.
|
|
46
|
+
|| !Array.from(rules).every(isValidRule)
|
|
47
|
+
) {
|
|
48
|
+
throw new TypeError(`${method}: rules must be an array of 1 to 20 non-empty strings or `
|
|
49
|
+
+ '{name, description?} objects (string name, optional string description).');
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const names = rules.map(
|
|
53
|
+
(rule) => (typeof rule === 'string' ? rule : rule.name).trim().toLowerCase());
|
|
54
|
+
if (names.length !== new Set(names).size) {
|
|
55
|
+
throw new TypeError(`${method}: rule names must be unique (case-insensitive).`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
6
58
|
|
|
7
59
|
export class Client {
|
|
8
60
|
constructor(apiKey, options = {}) {
|
|
@@ -60,6 +112,11 @@ export class Client {
|
|
|
60
112
|
data.advanced_edits = options.advancedEdits;
|
|
61
113
|
}
|
|
62
114
|
|
|
115
|
+
// Omitted unless set; an explicit null is forwarded so the API rejects it.
|
|
116
|
+
if (options.includeErrorCategories !== undefined) {
|
|
117
|
+
data.include_error_categories = options.includeErrorCategories;
|
|
118
|
+
}
|
|
119
|
+
|
|
63
120
|
if (userDetails) {
|
|
64
121
|
const { userId, anonUser } = userDetails;
|
|
65
122
|
data.user_id = userId;
|
|
@@ -195,8 +252,11 @@ export class Client {
|
|
|
195
252
|
* from the text, so this is extraction, not inference: a value that isn't stated is
|
|
196
253
|
* reported missing rather than guessed. Finding nothing is a normal 200.
|
|
197
254
|
*
|
|
198
|
-
* @param {string} text - The document to extract from, plain text or HTML (the
|
|
199
|
-
* it at 10,000 characters).
|
|
255
|
+
* @param {string|string[]} text - The document to extract from, plain text or HTML (the
|
|
256
|
+
* API caps it at 10,000 characters). Pass an array of 1–10 strings to extract from a
|
|
257
|
+
* batch in one request (sent as the API's `texts` parameter; combined length capped at
|
|
258
|
+
* 10,000 chars) — the response is then `{results: [...]}` with one
|
|
259
|
+
* single-response-shaped entry per input, in order.
|
|
200
260
|
* @param {Array<string|{name: string, type?: string, description?: string, required?: boolean}>} fields -
|
|
201
261
|
* The fields to pull out (1–20): field names, or objects. `type` is one of 'string'
|
|
202
262
|
* (default), 'number', 'integer', 'boolean', 'date' (returned as YYYY-MM-DD) or 'list'.
|
|
@@ -215,7 +275,20 @@ export class Client {
|
|
|
215
275
|
// context length) are server configuration and enforced there with a clear
|
|
216
276
|
// 400 — mirroring them here would drift the day they change (and JS
|
|
217
277
|
// `length` counts UTF-16 units, not the characters the API counts).
|
|
218
|
-
|
|
278
|
+
// An array of texts is the batch form (sent as `texts`, one result per
|
|
279
|
+
// item); the 1–10 item bound is structural like the field count below.
|
|
280
|
+
const isBatch = Array.isArray(text);
|
|
281
|
+
if (isBatch) {
|
|
282
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
283
|
+
// undefined and rejected, rather than skipped.
|
|
284
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
285
|
+
for (const item of text) {
|
|
286
|
+
ok = ok && typeof item === 'string' && item.trim().length > 0;
|
|
287
|
+
}
|
|
288
|
+
if (!ok) {
|
|
289
|
+
throw new TypeError('extract: texts must be an array of 1 to 10 non-empty strings.');
|
|
290
|
+
}
|
|
291
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
219
292
|
throw new TypeError('extract: text must be a non-empty string.');
|
|
220
293
|
}
|
|
221
294
|
|
|
@@ -268,7 +341,7 @@ export class Client {
|
|
|
268
341
|
}
|
|
269
342
|
|
|
270
343
|
let data = {
|
|
271
|
-
text,
|
|
344
|
+
...(isBatch ? { texts: text } : { text }),
|
|
272
345
|
fields,
|
|
273
346
|
key: this.apiKey,
|
|
274
347
|
}
|
|
@@ -286,11 +359,182 @@ export class Client {
|
|
|
286
359
|
return this.axiosPromise(url, 'post', data);
|
|
287
360
|
}
|
|
288
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Translate text into a target language with an LLM.
|
|
364
|
+
*
|
|
365
|
+
* Line breaks, markup and placeholders are preserved in place, and the response
|
|
366
|
+
* reports the language the text was actually written in (detected — never assumed
|
|
367
|
+
* from the hint): `translation`, `source_lang`/`source_lang_name` (`'und'`/`null`
|
|
368
|
+
* when undetermined) and the normalized `target_lang`/`target_lang_name`.
|
|
369
|
+
*
|
|
370
|
+
* @param {string|string[]} text - The text to translate (the API caps it at
|
|
371
|
+
* 5,000 characters). Markup and whitespace are preserved, not stripped.
|
|
372
|
+
* Pass an array of 1-10 strings to translate a batch in one request (sent
|
|
373
|
+
* as the API's `texts` parameter; combined length up to 5,000 characters,
|
|
374
|
+
* same target/source/formality applied to every item). A batch response is
|
|
375
|
+
* `{results: [...]}` with one single-response-shaped entry per input, in
|
|
376
|
+
* order.
|
|
377
|
+
* @param {string} targetLang - Language to translate into: an ISO 639 code
|
|
378
|
+
* ('fr', 'zh-TW') or an English language name ('French'). Region variants
|
|
379
|
+
* zh-CN/zh-TW/zh-HK, pt-BR/pt-PT, en-GB/en-US, fr-CA and es-419 are supported
|
|
380
|
+
* as targets.
|
|
381
|
+
* @param {Object} [options]
|
|
382
|
+
* @param {string} [options.source_lang] - Optional hint for the source language,
|
|
383
|
+
* same forms as targetLang. The text itself wins if they disagree.
|
|
384
|
+
* @param {string} [options.formality] - Optional register: 'formal'
|
|
385
|
+
* (vous/Sie/usted) or 'informal' (tu/du/tú). Omit for the model default.
|
|
386
|
+
* @returns {Promise<AxiosResponse>}
|
|
387
|
+
*/
|
|
388
|
+
translate(text, targetLang, options = {}) {
|
|
389
|
+
const url = `${this.urlEndpoint}translate`;
|
|
390
|
+
|
|
391
|
+
// Shape/type checks only; the language vocabulary and length caps are
|
|
392
|
+
// server configuration enforced there with a clear 400 (mirroring the
|
|
393
|
+
// 176-language table here would drift the day it changes).
|
|
394
|
+
// An array of texts is the batch form (SAP-398, sent as `texts`, one
|
|
395
|
+
// result per item); the 1–10 item bound is structural like safety's.
|
|
396
|
+
const isBatch = Array.isArray(text);
|
|
397
|
+
if (isBatch) {
|
|
398
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
399
|
+
// undefined and rejected, rather than skipped.
|
|
400
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
401
|
+
if (ok) {
|
|
402
|
+
for (const item of text) {
|
|
403
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
404
|
+
ok = false;
|
|
405
|
+
break;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
if (!ok) {
|
|
410
|
+
throw new TypeError('translate: texts must be an array of 1 to 10 non-empty strings.');
|
|
411
|
+
}
|
|
412
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
413
|
+
throw new TypeError('translate: text must be a non-empty string.');
|
|
414
|
+
}
|
|
415
|
+
if (typeof targetLang !== 'string' || targetLang.trim().length === 0) {
|
|
416
|
+
throw new TypeError('translate: targetLang must be a non-empty string (an ISO 639 '
|
|
417
|
+
+ 'code like "fr" or an English language name like "French").');
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
let data = {
|
|
421
|
+
...(isBatch ? { texts: text } : { text }),
|
|
422
|
+
target_lang: targetLang,
|
|
423
|
+
key: this.apiKey,
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// `!== undefined` (not `!= null`) so an explicit `null` is rejected as a
|
|
427
|
+
// bad type rather than silently treated as "omitted" (same as extract's
|
|
428
|
+
// context handling).
|
|
429
|
+
if (options?.source_lang !== undefined) {
|
|
430
|
+
if (typeof options.source_lang !== 'string' || options.source_lang.trim().length === 0) {
|
|
431
|
+
throw new TypeError('translate: source_lang must be a non-empty string.');
|
|
432
|
+
}
|
|
433
|
+
data.source_lang = options.source_lang;
|
|
434
|
+
}
|
|
435
|
+
if (options?.formality !== undefined) {
|
|
436
|
+
if (!TRANSLATE_FORMALITIES.includes(options.formality)) {
|
|
437
|
+
throw new TypeError('translate: formality must be one of '
|
|
438
|
+
+ `${TRANSLATE_FORMALITIES.join(', ')}.`);
|
|
439
|
+
}
|
|
440
|
+
data.formality = options.formality;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return this.axiosPromise(url, 'post', data);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Summarize a document, webpage or email thread into a prose summary plus
|
|
448
|
+
* key points.
|
|
449
|
+
*
|
|
450
|
+
* Returns `summary` (the prose summary), `key_points` (an array of strings),
|
|
451
|
+
* `length` (the option the summary was generated with) and `result`
|
|
452
|
+
* (mirrors `summary` — the endpoint's original response key, kept for
|
|
453
|
+
* backward compatibility).
|
|
454
|
+
*
|
|
455
|
+
* @param {string|string[]} text - The document to summarize, plain text or
|
|
456
|
+
* HTML (tags are stripped; the API caps it at 20,000 characters). Pass an
|
|
457
|
+
* array of 1-10 strings to summarize a batch in one request (sent as the
|
|
458
|
+
* API's `texts` parameter; combined length up to 20,000 characters, same
|
|
459
|
+
* length option applied to every item). A batch response is
|
|
460
|
+
* `{results: [...]}` with one single-response-shaped entry per input, in
|
|
461
|
+
* order.
|
|
462
|
+
* @param {Object} [options]
|
|
463
|
+
* @param {string} [options.length] - Optional summary length: 'short',
|
|
464
|
+
* 'medium' (the default) or 'long'.
|
|
465
|
+
* @returns {Promise<AxiosResponse>}
|
|
466
|
+
*/
|
|
467
|
+
summarize(text, options = {}) {
|
|
468
|
+
const url = `${this.urlEndpoint}summarize`;
|
|
469
|
+
|
|
470
|
+
// An array of texts is the batch form (SAP-399, sent as `texts`, one
|
|
471
|
+
// result per item); the 1–10 item bound is structural like translate's.
|
|
472
|
+
const isBatch = Array.isArray(text);
|
|
473
|
+
if (isBatch) {
|
|
474
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
475
|
+
// undefined and rejected, rather than skipped.
|
|
476
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
477
|
+
if (ok) {
|
|
478
|
+
for (const item of text) {
|
|
479
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
480
|
+
ok = false;
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (!ok) {
|
|
486
|
+
throw new TypeError('summarize: texts must be an array of 1 to 10 non-empty strings.');
|
|
487
|
+
}
|
|
488
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
489
|
+
throw new TypeError('summarize: text must be a non-empty string.');
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
let data = {
|
|
493
|
+
...(isBatch ? { texts: text } : { text }),
|
|
494
|
+
key: this.apiKey,
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
// `!== undefined` (not `!= null`) so an explicit `null` is rejected as a
|
|
498
|
+
// bad type rather than silently treated as "omitted" (same as translate's
|
|
499
|
+
// formality handling).
|
|
500
|
+
if (options?.length !== undefined) {
|
|
501
|
+
if (!SUMMARIZE_LENGTHS.includes(options.length)) {
|
|
502
|
+
throw new TypeError('summarize: length must be one of '
|
|
503
|
+
+ `${SUMMARIZE_LENGTHS.join(', ')}.`);
|
|
504
|
+
}
|
|
505
|
+
data.length = options.length;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
return this.axiosPromise(url, 'post', data);
|
|
509
|
+
}
|
|
510
|
+
|
|
289
511
|
langdetect(text, options = {}) {
|
|
290
512
|
const url = `${this.urlEndpoint}langdetect`;
|
|
291
513
|
|
|
514
|
+
// An array of texts is the batch form (SAP-397, sent as `texts`, one
|
|
515
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
516
|
+
// The single (string) form is passed through unvalidated, as it always
|
|
517
|
+
// has been — the server answers a clear 400.
|
|
518
|
+
const isBatch = Array.isArray(text);
|
|
519
|
+
if (isBatch) {
|
|
520
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
521
|
+
// undefined and rejected, rather than skipped.
|
|
522
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
523
|
+
if (ok) {
|
|
524
|
+
for (const item of text) {
|
|
525
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
526
|
+
ok = false;
|
|
527
|
+
break;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
if (!ok) {
|
|
532
|
+
throw new TypeError('langdetect: texts must be an array of 1 to 10 non-empty strings.');
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
292
536
|
let data = {
|
|
293
|
-
text,
|
|
537
|
+
...(isBatch ? { texts: text } : { text }),
|
|
294
538
|
key: this.apiKey,
|
|
295
539
|
}
|
|
296
540
|
|
|
@@ -314,7 +558,11 @@ export class Client {
|
|
|
314
558
|
* empty), `scores` (one `{label, score}` per input label, descending), a one-sentence
|
|
315
559
|
* `rationale` and the echoed `multi_label` mode.
|
|
316
560
|
*
|
|
317
|
-
* @param {string} text - Text to classify, plain text or HTML (the API caps it
|
|
561
|
+
* @param {string|string[]} text - Text to classify, plain text or HTML (the API caps it
|
|
562
|
+
* at 10,000 chars). Pass an array of 1–10 strings to classify a batch in one request
|
|
563
|
+
* (sent as the API's `texts` parameter; combined length capped at 10,000 chars) — the
|
|
564
|
+
* response is then `{results: [...]}` with one single-response-shaped entry per input,
|
|
565
|
+
* in order.
|
|
318
566
|
* @param {Array<string|{name: string, description?: string}>} labels - Candidate labels
|
|
319
567
|
* (2–20). Names unique case-insensitively; the API caps names at 50 and descriptions at 200 chars.
|
|
320
568
|
* @param {Object} [options]
|
|
@@ -333,7 +581,20 @@ export class Client {
|
|
|
333
581
|
// context length) are server configuration and enforced there with a
|
|
334
582
|
// clear 400 — mirroring them here would drift the day they change (and
|
|
335
583
|
// JS `length` counts UTF-16 units, not the characters the API counts).
|
|
336
|
-
|
|
584
|
+
// An array of texts is the batch form (sent as `texts`, one result per
|
|
585
|
+
// item); the 1–10 item bound is structural like the label count below.
|
|
586
|
+
const isBatch = Array.isArray(text);
|
|
587
|
+
if (isBatch) {
|
|
588
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
589
|
+
// undefined and rejected, rather than skipped.
|
|
590
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
591
|
+
for (const item of text) {
|
|
592
|
+
ok = ok && typeof item === 'string' && item.trim().length > 0;
|
|
593
|
+
}
|
|
594
|
+
if (!ok) {
|
|
595
|
+
throw new TypeError('classify: texts must be an array of 1 to 10 non-empty strings.');
|
|
596
|
+
}
|
|
597
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
337
598
|
throw new TypeError('classify: text must be a non-empty string.');
|
|
338
599
|
}
|
|
339
600
|
|
|
@@ -379,7 +640,7 @@ export class Client {
|
|
|
379
640
|
}
|
|
380
641
|
|
|
381
642
|
let data = {
|
|
382
|
-
text,
|
|
643
|
+
...(isBatch ? { texts: text } : { text }),
|
|
383
644
|
labels,
|
|
384
645
|
key: this.apiKey,
|
|
385
646
|
}
|
|
@@ -477,12 +738,30 @@ export class Client {
|
|
|
477
738
|
const url = `${this.urlEndpoint}quality`;
|
|
478
739
|
|
|
479
740
|
// Shape/type checks only; size limits are server configuration (see seo()).
|
|
480
|
-
|
|
741
|
+
// An array of texts is the batch form (SAP-400, sent as `texts`, one
|
|
742
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
743
|
+
const isBatch = Array.isArray(text);
|
|
744
|
+
if (isBatch) {
|
|
745
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
746
|
+
// undefined and rejected, rather than skipped.
|
|
747
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
748
|
+
if (ok) {
|
|
749
|
+
for (const item of text) {
|
|
750
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
751
|
+
ok = false;
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
if (!ok) {
|
|
757
|
+
throw new TypeError('quality: texts must be an array of 1 to 10 non-empty strings.');
|
|
758
|
+
}
|
|
759
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
481
760
|
throw new TypeError('quality: text must be a non-empty string.');
|
|
482
761
|
}
|
|
483
762
|
|
|
484
763
|
let data = {
|
|
485
|
-
text,
|
|
764
|
+
...(isBatch ? { texts: text } : { text }),
|
|
486
765
|
key: this.apiKey,
|
|
487
766
|
}
|
|
488
767
|
|
|
@@ -508,12 +787,30 @@ export class Client {
|
|
|
508
787
|
const url = `${this.urlEndpoint}safety`;
|
|
509
788
|
|
|
510
789
|
// Shape/type checks only; size limits are server configuration (see seo()).
|
|
511
|
-
|
|
790
|
+
// An array of texts is the batch form (SAP-397, sent as `texts`, one
|
|
791
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
792
|
+
const isBatch = Array.isArray(text);
|
|
793
|
+
if (isBatch) {
|
|
794
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
795
|
+
// undefined and rejected, rather than skipped.
|
|
796
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
797
|
+
if (ok) {
|
|
798
|
+
for (const item of text) {
|
|
799
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
800
|
+
ok = false;
|
|
801
|
+
break;
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
if (!ok) {
|
|
806
|
+
throw new TypeError('safety: texts must be an array of 1 to 10 non-empty strings.');
|
|
807
|
+
}
|
|
808
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
512
809
|
throw new TypeError('safety: text must be a non-empty string.');
|
|
513
810
|
}
|
|
514
811
|
|
|
515
812
|
let data = {
|
|
516
|
-
text,
|
|
813
|
+
...(isBatch ? { texts: text } : { text }),
|
|
517
814
|
key: this.apiKey,
|
|
518
815
|
}
|
|
519
816
|
|
|
@@ -526,6 +823,12 @@ export class Client {
|
|
|
526
823
|
}
|
|
527
824
|
data.threshold = options.threshold;
|
|
528
825
|
}
|
|
826
|
+
if (options?.spans !== undefined) {
|
|
827
|
+
if (typeof options.spans !== 'boolean') {
|
|
828
|
+
throw new TypeError('safety: spans must be a boolean.');
|
|
829
|
+
}
|
|
830
|
+
data.spans = options.spans;
|
|
831
|
+
}
|
|
529
832
|
|
|
530
833
|
return this.axiosPromise(url, 'post', data);
|
|
531
834
|
}
|
|
@@ -533,8 +836,30 @@ export class Client {
|
|
|
533
836
|
aidetect(text, options = {}) {
|
|
534
837
|
const url = `${this.urlEndpoint}aidetect`;
|
|
535
838
|
|
|
839
|
+
// An array of texts is the batch form (SAP-403, sent as `texts`, one
|
|
840
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
841
|
+
// The single form keeps its historical no-validation behavior (the
|
|
842
|
+
// server 400s clearly on a bad `text`).
|
|
843
|
+
const isBatch = Array.isArray(text);
|
|
844
|
+
if (isBatch) {
|
|
845
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
846
|
+
// undefined and rejected, rather than skipped.
|
|
847
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
848
|
+
if (ok) {
|
|
849
|
+
for (const item of text) {
|
|
850
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
851
|
+
ok = false;
|
|
852
|
+
break;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (!ok) {
|
|
857
|
+
throw new TypeError('aidetect: texts must be an array of 1 to 10 non-empty strings.');
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
536
861
|
let data = {
|
|
537
|
-
text,
|
|
862
|
+
...(isBatch ? { texts: text } : { text }),
|
|
538
863
|
key: this.apiKey,
|
|
539
864
|
}
|
|
540
865
|
|
|
@@ -545,6 +870,265 @@ export class Client {
|
|
|
545
870
|
return this.axiosPromise(url, 'post', data);
|
|
546
871
|
}
|
|
547
872
|
|
|
873
|
+
/**
|
|
874
|
+
* Check a text for compliance with style rules you supply (house style,
|
|
875
|
+
* brand voice, editorial guidelines). Only the listed rules are enforced.
|
|
876
|
+
*
|
|
877
|
+
* Returns `violations` (one `{rule, text, start, end, note, suggestion}`
|
|
878
|
+
* entry per violation, most important first — `start`/`end` index the
|
|
879
|
+
* submitted text and are null when the passage cannot be located), `rules`
|
|
880
|
+
* (the checked rule names) and `compliant` (true when no violations were
|
|
881
|
+
* found). The text is checked exactly as submitted — markup is NOT
|
|
882
|
+
* stripped, so offsets always index the string you sent.
|
|
883
|
+
*
|
|
884
|
+
* @param {string|string[]} text - The text to check (the API caps it at
|
|
885
|
+
* 10,000 characters), or an array of 1–10 texts for the batch form (sent
|
|
886
|
+
* as the API's `texts` parameter; combined length up to 10,000
|
|
887
|
+
* characters, same rules applied to every item). A batch response is
|
|
888
|
+
* `{results: [...]}` with one single-response-shaped entry per input, in
|
|
889
|
+
* order, each item's violation offsets indexing that item's own text.
|
|
890
|
+
* @param {Array<string|{name: string, description?: string}>|string} rules
|
|
891
|
+
* - 1 to 20 style rules: a rule name (max 80 chars) or a
|
|
892
|
+
* `{name, description}` object whose optional description (max 400
|
|
893
|
+
* chars) carries the nuance the model follows. Names must be unique
|
|
894
|
+
* case-insensitively. OR a string: the name of a saved ruleset (see
|
|
895
|
+
* saveStyleguideRuleset()) to check against, matched case-insensitively
|
|
896
|
+
* within the API key's account.
|
|
897
|
+
* @returns {Promise<AxiosResponse>}
|
|
898
|
+
*/
|
|
899
|
+
styleguide(text, rules) {
|
|
900
|
+
const url = `${this.urlEndpoint}styleguide`;
|
|
901
|
+
|
|
902
|
+
// Shape/type checks only. Size limits (text/rule/description length) are
|
|
903
|
+
// server configuration and enforced there with a clear 400 (see
|
|
904
|
+
// classify()).
|
|
905
|
+
// An array of texts is the batch form (SAP-412, sent as `texts`, one
|
|
906
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
907
|
+
const isBatch = Array.isArray(text);
|
|
908
|
+
if (isBatch) {
|
|
909
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
910
|
+
// undefined and rejected, rather than skipped.
|
|
911
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
912
|
+
if (ok) {
|
|
913
|
+
for (const item of text) {
|
|
914
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
915
|
+
ok = false;
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
if (!ok) {
|
|
921
|
+
throw new TypeError('styleguide: texts must be an array of 1 to 10 non-empty strings.');
|
|
922
|
+
}
|
|
923
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
924
|
+
throw new TypeError('styleguide: text must be a non-empty string.');
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// A string names a saved ruleset (see saveStyleguideRuleset()) and is
|
|
928
|
+
// sent as the API's `ruleset` parameter in place of inline `rules`.
|
|
929
|
+
const isSavedRuleset = typeof rules === 'string';
|
|
930
|
+
if (isSavedRuleset) {
|
|
931
|
+
if (rules.trim().length === 0) {
|
|
932
|
+
throw new TypeError('styleguide: ruleset name must be a non-empty string.');
|
|
933
|
+
}
|
|
934
|
+
} else {
|
|
935
|
+
validateStyleguideRules(rules, 'styleguide');
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
let data = {
|
|
939
|
+
...(isBatch ? { texts: text } : { text }),
|
|
940
|
+
...(isSavedRuleset ? { ruleset: rules } : { rules }),
|
|
941
|
+
key: this.apiKey,
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return this.axiosPromise(url, 'post', data);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* List the saved style-guide rulesets of this API key's account (its team,
|
|
949
|
+
* for team-scoped keys — a team's rulesets are shared by every caller of
|
|
950
|
+
* its keys). Requires a per-account API key.
|
|
951
|
+
*
|
|
952
|
+
* Returns `rulesets`: `{name, rules, created_at, updated_at}` entries whose
|
|
953
|
+
* `rules` are the normalized `{name, description}` objects the check
|
|
954
|
+
* endpoint applies.
|
|
955
|
+
*
|
|
956
|
+
* @returns {Promise<AxiosResponse>}
|
|
957
|
+
*/
|
|
958
|
+
styleguideRulesets() {
|
|
959
|
+
const url = `${this.urlEndpoint}styleguide/rulesets`;
|
|
960
|
+
// Not axiosPromise: this is a GET and the key rides the query string.
|
|
961
|
+
return axios({
|
|
962
|
+
url,
|
|
963
|
+
method: 'get',
|
|
964
|
+
params: { key: this.apiKey },
|
|
965
|
+
timeout: this.timeout,
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* Create — or replace, when the name already exists (matched
|
|
971
|
+
* case-insensitively) — a saved style-guide ruleset, so later
|
|
972
|
+
* `styleguide(text, name)` calls check against it by name. Owned by the
|
|
973
|
+
* API key's account (its team, for team-scoped keys). Requires a
|
|
974
|
+
* per-account API key.
|
|
975
|
+
*
|
|
976
|
+
* Returns `ruleset` (the saved `{name, rules, created_at, updated_at}`)
|
|
977
|
+
* and `created` (false when an existing ruleset was replaced).
|
|
978
|
+
*
|
|
979
|
+
* @param {string} name - The ruleset name (the API caps it at 100
|
|
980
|
+
* characters; surrounding/duplicate whitespace is normalized).
|
|
981
|
+
* @param {Array<string|{name: string, description?: string}>} rules - The
|
|
982
|
+
* rules to save; same shape and bounds as styleguide()'s inline rules.
|
|
983
|
+
* @returns {Promise<AxiosResponse>}
|
|
984
|
+
*/
|
|
985
|
+
saveStyleguideRuleset(name, rules) {
|
|
986
|
+
const url = `${this.urlEndpoint}styleguide/rulesets`;
|
|
987
|
+
if (typeof name !== 'string' || name.trim().length === 0) {
|
|
988
|
+
throw new TypeError('saveStyleguideRuleset: name must be a non-empty string.');
|
|
989
|
+
}
|
|
990
|
+
validateStyleguideRules(rules, 'saveStyleguideRuleset');
|
|
991
|
+
|
|
992
|
+
let data = {
|
|
993
|
+
name,
|
|
994
|
+
rules,
|
|
995
|
+
key: this.apiKey,
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
return this.axiosPromise(url, 'post', data);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Delete a saved style-guide ruleset by name (matched case-insensitively;
|
|
1003
|
+
* 404 when no such ruleset exists). Requires a per-account API key.
|
|
1004
|
+
*
|
|
1005
|
+
* @param {string} name - The ruleset name to delete.
|
|
1006
|
+
* @returns {Promise<AxiosResponse>}
|
|
1007
|
+
*/
|
|
1008
|
+
deleteStyleguideRuleset(name) {
|
|
1009
|
+
const url = `${this.urlEndpoint}styleguide/rulesets`;
|
|
1010
|
+
if (typeof name !== 'string' || name.trim().length === 0) {
|
|
1011
|
+
throw new TypeError('deleteStyleguideRuleset: name must be a non-empty string.');
|
|
1012
|
+
}
|
|
1013
|
+
// The name rides the query string: some HTTP stacks drop DELETE bodies,
|
|
1014
|
+
// and the API accepts the query form for exactly that reason.
|
|
1015
|
+
return axios({
|
|
1016
|
+
url,
|
|
1017
|
+
method: 'delete',
|
|
1018
|
+
params: { key: this.apiKey, name },
|
|
1019
|
+
timeout: this.timeout,
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Rewrite a text in plain language at a target reading level, keeping all
|
|
1025
|
+
* of its content, structure and language — nothing is summarized or
|
|
1026
|
+
* dropped.
|
|
1027
|
+
*
|
|
1028
|
+
* Returns `simplified` (the rewrite, structure preserved), the applied
|
|
1029
|
+
* `reading_level`, the `lang` the readability scores were computed for
|
|
1030
|
+
* (detected when not supplied) and, when that language supports scoring, a
|
|
1031
|
+
* `readability` block: `{before: {grade, ease}, after: {grade, ease}}`
|
|
1032
|
+
* Flesch-Kincaid scores, so the improvement is verifiable.
|
|
1033
|
+
*
|
|
1034
|
+
* @param {string|string[]} text - The text to simplify (the API caps it at
|
|
1035
|
+
* 5,000 characters), or an array of 1–10 texts for the batch form (sent
|
|
1036
|
+
* as the API's `texts` parameter; combined length up to 5,000
|
|
1037
|
+
* characters, same options applied to every item). A batch response is
|
|
1038
|
+
* `{results: [...]}` with one single-response-shaped entry per input, in
|
|
1039
|
+
* order; with `lang` omitted, each item's language (and readability
|
|
1040
|
+
* scores) is detected on its own. Sent to the model as submitted —
|
|
1041
|
+
* markup and line structure are preserved, not stripped.
|
|
1042
|
+
* @param {Object} [options]
|
|
1043
|
+
* @param {string} [options.reading_level] - Target audience: 'plain'
|
|
1044
|
+
* (plain-language style for a general audience, the API default),
|
|
1045
|
+
* 'elementary' (~US grade 3-5), 'middle_school' (~grade 6-8) or
|
|
1046
|
+
* 'high_school' (~grade 9-10).
|
|
1047
|
+
* @param {string[]} [options.preserve_terms] - Up to 20 terms (each up to
|
|
1048
|
+
* 100 characters) the rewrite must keep exactly as written — product
|
|
1049
|
+
* names, defined legal terms. A rewrite that drops one is refused
|
|
1050
|
+
* server-side rather than returned.
|
|
1051
|
+
* @param {string} [options.lang] - ISO 639-1 code used to pick the
|
|
1052
|
+
* readability formula for the before/after scores. Omit for
|
|
1053
|
+
* auto-detection (falls back to 'en'). The rewrite itself always stays
|
|
1054
|
+
* in the text's own language.
|
|
1055
|
+
* @returns {Promise<AxiosResponse>}
|
|
1056
|
+
*/
|
|
1057
|
+
simplify(text, options = {}) {
|
|
1058
|
+
const url = `${this.urlEndpoint}simplify`;
|
|
1059
|
+
|
|
1060
|
+
// Shape/type checks only. Size limits (text/term length) are server
|
|
1061
|
+
// configuration and enforced there with a clear 400 (see classify()).
|
|
1062
|
+
// An array of texts is the batch form (SAP-412, sent as `texts`, one
|
|
1063
|
+
// result per item); the 1–10 item bound is structural like classify's.
|
|
1064
|
+
const isBatch = Array.isArray(text);
|
|
1065
|
+
if (isBatch) {
|
|
1066
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
1067
|
+
// undefined and rejected, rather than skipped.
|
|
1068
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
1069
|
+
if (ok) {
|
|
1070
|
+
for (const item of text) {
|
|
1071
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
1072
|
+
ok = false;
|
|
1073
|
+
break;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
if (!ok) {
|
|
1078
|
+
throw new TypeError('simplify: texts must be an array of 1 to 10 non-empty strings.');
|
|
1079
|
+
}
|
|
1080
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
1081
|
+
throw new TypeError('simplify: text must be a non-empty string.');
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
let data = {
|
|
1085
|
+
...(isBatch ? { texts: text } : { text }),
|
|
1086
|
+
key: this.apiKey,
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
// `!== undefined` (not `!= null`) so an explicit `null` is rejected as a
|
|
1090
|
+
// bad type rather than silently treated as "omitted" (same as translate's
|
|
1091
|
+
// option handling).
|
|
1092
|
+
if (options?.reading_level !== undefined) {
|
|
1093
|
+
if (!SIMPLIFY_READING_LEVELS.includes(options.reading_level)) {
|
|
1094
|
+
throw new TypeError('simplify: reading_level must be one of '
|
|
1095
|
+
+ `${SIMPLIFY_READING_LEVELS.join(', ')}.`);
|
|
1096
|
+
}
|
|
1097
|
+
data.reading_level = options.reading_level;
|
|
1098
|
+
}
|
|
1099
|
+
if (options?.preserve_terms !== undefined) {
|
|
1100
|
+
const terms = options.preserve_terms;
|
|
1101
|
+
// An empty list is a valid no-op (callers may build it dynamically); it
|
|
1102
|
+
// is simply omitted from the payload below rather than rejected.
|
|
1103
|
+
// for...of (not terms.every) so holes in a sparse array are visited as
|
|
1104
|
+
// undefined and rejected, rather than skipped.
|
|
1105
|
+
let ok = Array.isArray(terms) && terms.length <= 20;
|
|
1106
|
+
if (ok) {
|
|
1107
|
+
for (const term of terms) {
|
|
1108
|
+
if (typeof term !== 'string' || term.trim().length === 0) {
|
|
1109
|
+
ok = false;
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
if (!ok) {
|
|
1115
|
+
throw new TypeError('simplify: preserve_terms must be an array of up to 20 '
|
|
1116
|
+
+ 'non-empty strings.');
|
|
1117
|
+
}
|
|
1118
|
+
if (terms.length > 0) {
|
|
1119
|
+
data.preserve_terms = terms;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (options?.lang !== undefined) {
|
|
1123
|
+
if (typeof options.lang !== 'string' || options.lang.trim().length === 0) {
|
|
1124
|
+
throw new TypeError('simplify: lang must be a non-empty string.');
|
|
1125
|
+
}
|
|
1126
|
+
data.lang = options.lang;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
return this.axiosPromise(url, 'post', data);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
548
1132
|
pii(text, options = {}) {
|
|
549
1133
|
const url = `${this.urlEndpoint}pii`;
|
|
550
1134
|
|
|
@@ -577,4 +1161,106 @@ export class Client {
|
|
|
577
1161
|
|
|
578
1162
|
return this.axiosPromise(url, 'post', data);
|
|
579
1163
|
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Named-entity recognition: people, organizations, locations, dates, times,
|
|
1167
|
+
* money amounts, percentages, quantities, products, and events, each with
|
|
1168
|
+
* character offsets into the exact text submitted (nothing is stripped or
|
|
1169
|
+
* normalized, so spans apply directly to your copy of the document).
|
|
1170
|
+
* Complements pii(): that finds checksum-validated identifiers, this finds
|
|
1171
|
+
* names and real-world references.
|
|
1172
|
+
*
|
|
1173
|
+
* @param {string|string[]} text - The text to analyze, or an array of 1–10
|
|
1174
|
+
* texts for the batch form (sent as the API's `texts` parameter; combined
|
|
1175
|
+
* length up to 10,000 characters, same types applied to every item). A
|
|
1176
|
+
* batch response is `{results: [...]}` with one single-response-shaped
|
|
1177
|
+
* entry per input, in order, each item's spans indexing that item's own
|
|
1178
|
+
* text.
|
|
1179
|
+
* @param {Object} [options]
|
|
1180
|
+
* @param {string[]} [options.types] - Entity types to recognize (subset of
|
|
1181
|
+
* the API's supported types). Default: all of them.
|
|
1182
|
+
*/
|
|
1183
|
+
ner(text, options = {}) {
|
|
1184
|
+
const url = `${this.urlEndpoint}ner`;
|
|
1185
|
+
|
|
1186
|
+
// Shape/type checks only; the set of valid entity types is server
|
|
1187
|
+
// configuration and enforced there with a clear 400 (see pii()).
|
|
1188
|
+
// An array of texts is the batch form (SAP-395 series, sent as `texts`,
|
|
1189
|
+
// one result per item); the 1–10 item bound is structural like classify's.
|
|
1190
|
+
const isBatch = Array.isArray(text);
|
|
1191
|
+
if (isBatch) {
|
|
1192
|
+
// for...of (not text.every) so holes in a sparse array are visited as
|
|
1193
|
+
// undefined and rejected, rather than skipped.
|
|
1194
|
+
let ok = text.length >= 1 && text.length <= 10;
|
|
1195
|
+
if (ok) {
|
|
1196
|
+
for (const item of text) {
|
|
1197
|
+
if (typeof item !== 'string' || item.trim().length === 0) {
|
|
1198
|
+
ok = false;
|
|
1199
|
+
break;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (!ok) {
|
|
1204
|
+
throw new TypeError('ner: texts must be an array of 1 to 10 non-empty strings.');
|
|
1205
|
+
}
|
|
1206
|
+
} else if (typeof text !== 'string' || text.trim().length === 0) {
|
|
1207
|
+
throw new TypeError('ner: text must be a non-empty string.');
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
let data = {
|
|
1211
|
+
...(isBatch ? { texts: text } : { text }),
|
|
1212
|
+
key: this.apiKey,
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
// `!== undefined` (not `!= null`) so an explicit `null` is rejected as a bad
|
|
1216
|
+
// type rather than silently treated as "omitted", matching pii().
|
|
1217
|
+
// Reject an empty list too: the MCP schema requires at least one type
|
|
1218
|
+
// (min(1)), so an empty array is typed-valid input that would otherwise
|
|
1219
|
+
// become an avoidable API error.
|
|
1220
|
+
if (options?.types !== undefined) {
|
|
1221
|
+
if (!Array.isArray(options.types) || options.types.length === 0
|
|
1222
|
+
|| !Array.from(options.types).every((type) => typeof type === 'string' && type.trim().length > 0)) {
|
|
1223
|
+
throw new TypeError('ner: types must be a non-empty array of non-empty strings.');
|
|
1224
|
+
}
|
|
1225
|
+
data.types = options.types;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
return this.axiosPromise(url, 'post', data);
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
/**
|
|
1232
|
+
* Check whether an account-wide block (expired key/subscription,
|
|
1233
|
+
* depleted credits, billing limit, trial daily allowance, monthly quota)
|
|
1234
|
+
* stops this API key from making billable calls, and if so why and for
|
|
1235
|
+
* how long. Works while the key is blocked, which is when it is most
|
|
1236
|
+
* useful: call it after an unexpected 402 or monthly-quota 429 instead of
|
|
1237
|
+
* parsing the error text. It does not reflect a single endpoint's
|
|
1238
|
+
* short-term rate limit (each endpoint has its own bucket), so a
|
|
1239
|
+
* "Capacity used." 429 elsewhere can coexist with api_access: true — use
|
|
1240
|
+
* that 429's retry_after / X-RateLimit-* headers instead. Unbilled, but each call draws a fixed 2,000
|
|
1241
|
+
* characters from its own rate-limit bucket, so don't poll it per request.
|
|
1242
|
+
* Requires a per-account API key; the public demo key and MCP OAuth
|
|
1243
|
+
* access tokens get a 403.
|
|
1244
|
+
*
|
|
1245
|
+
* Always returns `api_access`, `blocked_reason` (null, or one of
|
|
1246
|
+
* key_expired, subscription_expired, credits_depleted,
|
|
1247
|
+
* monthly_billing_limit, trial_daily_limit, monthly_quota_exhausted),
|
|
1248
|
+
* `message` and `usage` ({monthly_quota_chars}); `retry_after` (seconds)
|
|
1249
|
+
* only when blocked. Keys that are not team-scoped also get
|
|
1250
|
+
* `usage.month_start`/`usage.chars_this_month`, `subscription`, `credits`
|
|
1251
|
+
* and, for free-trial accounts, `trial`.
|
|
1252
|
+
*
|
|
1253
|
+
* @returns {Promise<AxiosResponse>}
|
|
1254
|
+
*/
|
|
1255
|
+
accountStatus() {
|
|
1256
|
+
const url = `${this.urlEndpoint}account/status`;
|
|
1257
|
+
// Not axiosPromise: this is a GET and the key rides the query string,
|
|
1258
|
+
// like styleguideRulesets().
|
|
1259
|
+
return axios({
|
|
1260
|
+
url,
|
|
1261
|
+
method: 'get',
|
|
1262
|
+
params: { key: this.apiKey },
|
|
1263
|
+
timeout: this.timeout,
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
580
1266
|
}
|