@verbatra/sdk 0.2.2 → 0.3.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 +4 -4
- package/dist/index.cjs +558 -73
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +135 -47
- package/dist/index.d.ts +135 -47
- package/dist/index.js +554 -69
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.d.cts
CHANGED
|
@@ -38,12 +38,6 @@ declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
38
38
|
type ProviderConfig = z.infer<typeof providerConfigSchema>;
|
|
39
39
|
type ProviderId = ProviderConfig["id"];
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* The verbatra project configuration. Non-secret only: it carries no API key (the
|
|
43
|
-
* provider reads its key from the environment), and unknown top-level keys are rejected
|
|
44
|
-
* so a stray secret cannot hide in the config. Validated with zod at the boundary
|
|
45
|
-
* regardless of where it was loaded from.
|
|
46
|
-
*/
|
|
47
41
|
declare const verbatraConfigSchema: z.ZodObject<{
|
|
48
42
|
sourceLocale: z.ZodString;
|
|
49
43
|
targetLocales: z.ZodArray<z.ZodString>;
|
|
@@ -86,27 +80,24 @@ declare const verbatraConfigSchema: z.ZodObject<{
|
|
|
86
80
|
informal: "informal";
|
|
87
81
|
neutral: "neutral";
|
|
88
82
|
}>>;
|
|
83
|
+
prune: z.ZodOptional<z.ZodBoolean>;
|
|
84
|
+
generatePlurals: z.ZodOptional<z.ZodBoolean>;
|
|
85
|
+
maxBatchSize: z.ZodOptional<z.ZodNumber>;
|
|
89
86
|
}, z.core.$strict>;
|
|
90
87
|
type VerbatraConfig = z.infer<typeof verbatraConfigSchema>;
|
|
91
88
|
|
|
92
89
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* The authoring view of one provider variant: its runtime config with `options.model`
|
|
103
|
-
* narrowed to that provider's open model union. LLM providers (anthropic, openai,
|
|
104
|
-
* gemini) get suggestions; DeepL has no model field and is carried through unchanged.
|
|
90
|
+
* The closed set of a provider's known model IDs: exactly the string literals its SDK
|
|
91
|
+
* model type ships, with the SDK's own open `string & {}` arm stripped out. Distributing
|
|
92
|
+
* over the union and dropping any arm the wide `string` extends leaves only the literals,
|
|
93
|
+
* so the authoring field offers and ACCEPTS only the selected provider's known models. A
|
|
94
|
+
* foreign or unknown model (for example a Claude model under `id: "gemini"`) is a type
|
|
95
|
+
* error at authoring time. This is a static authoring constraint only; the runtime schema
|
|
96
|
+
* stays `z.string().min(1)` and still accepts any non-empty string, so a brand-new model
|
|
97
|
+
* the installed SDK does not yet list is flagged in the editor but still runs.
|
|
105
98
|
*/
|
|
106
|
-
type
|
|
107
|
-
|
|
108
|
-
}>;
|
|
109
|
-
type AuthoringVariant<Id extends ProviderConfig["id"], M extends string> = Extract<ProviderConfig, {
|
|
99
|
+
type KnownModels<M extends string> = M extends string ? (string extends M ? never : M) : never;
|
|
100
|
+
type AuthoringVariant<Id extends ProviderId, M extends string> = Extract<ProviderConfig, {
|
|
110
101
|
id: Id;
|
|
111
102
|
}> extends infer Variant ? Variant extends {
|
|
112
103
|
options: {
|
|
@@ -114,30 +105,80 @@ type AuthoringVariant<Id extends ProviderConfig["id"], M extends string> = Extra
|
|
|
114
105
|
};
|
|
115
106
|
} ? Omit<Variant, "options"> & {
|
|
116
107
|
options: Omit<Variant["options"], "model"> & {
|
|
117
|
-
model:
|
|
108
|
+
model: KnownModels<M>;
|
|
118
109
|
};
|
|
119
110
|
} : never : never;
|
|
120
111
|
/**
|
|
121
|
-
* The authoring view of
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
112
|
+
* The authoring view of one provider variant, keyed by id. LLM providers (anthropic,
|
|
113
|
+
* openai, gemini) restrict `options.model` to that provider's known model literals; DeepL
|
|
114
|
+
* has no model field and is carried through unchanged. Keying by id (rather than a flat
|
|
115
|
+
* union) lets {@link AuthoringConfigFor} select exactly one variant for a literal id, so
|
|
116
|
+
* the `options.model` site is one provider's literal set and never a multi-provider union.
|
|
125
117
|
*/
|
|
126
|
-
type
|
|
127
|
-
|
|
118
|
+
type AuthoringProviderVariant = {
|
|
119
|
+
anthropic: AuthoringVariant<"anthropic", AnthropicModel>;
|
|
120
|
+
openai: AuthoringVariant<"openai", OpenAiModel>;
|
|
121
|
+
gemini: AuthoringVariant<"gemini", GeminiModel>;
|
|
122
|
+
deepl: Extract<ProviderConfig, {
|
|
123
|
+
id: "deepl";
|
|
124
|
+
}>;
|
|
128
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* The authoring view of the whole config for a given provider id. It is structurally a
|
|
128
|
+
* {@link VerbatraConfig} whose `provider` is the single authoring variant for `TId`.
|
|
129
|
+
*
|
|
130
|
+
* When `TId` is a single provider literal, `provider` is one concrete variant, so
|
|
131
|
+
* `options.model` is that provider's known model literals alone and not a union across
|
|
132
|
+
* providers. `defineConfig` declares one overload per provider parameterized on this type
|
|
133
|
+
* (`AuthoringConfigFor<"openai">` and so on), so overload resolution picks the variant from
|
|
134
|
+
* the `provider.id` literal. That, together with the closed {@link KnownModels} set, makes a
|
|
135
|
+
* foreign model (for example a Claude model under `id: "gemini"`) a type error and aims to
|
|
136
|
+
* keep editors with weaker discriminated-union narrowing (for example the JetBrains/WebStorm
|
|
137
|
+
* completion engine) offering only the selected provider's models, since each overload's
|
|
138
|
+
* parameter is already a single variant with no nested union to narrow. When `TId` defaults
|
|
139
|
+
* to `ProviderId`, `provider` is the full authoring union. Every value assignable here is
|
|
140
|
+
* assignable to {@link VerbatraConfig}, because a model literal is a subtype of `string`.
|
|
141
|
+
*/
|
|
142
|
+
type AuthoringConfigFor<TId extends ProviderId = ProviderId> = Omit<VerbatraConfig, "provider"> & {
|
|
143
|
+
provider: AuthoringProviderVariant[TId];
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* The authoring view of the whole config across every provider (the `TId = ProviderId`
|
|
147
|
+
* case of {@link AuthoringConfigFor}): identical to {@link VerbatraConfig} except that
|
|
148
|
+
* `provider` offers per-provider model completions.
|
|
149
|
+
*/
|
|
150
|
+
type AuthoringConfig = AuthoringConfigFor;
|
|
129
151
|
|
|
130
152
|
/**
|
|
131
153
|
* Identity helper for authoring a code-defined verbatra.config.ts. It returns its
|
|
132
154
|
* argument unchanged; its only purpose is to give the author full type inference and
|
|
133
155
|
* editor autocomplete on the config object.
|
|
134
156
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
157
|
+
* It is declared as one overload per provider id rather than a single generic. Each
|
|
158
|
+
* overload's parameter is the concrete single-provider authoring config
|
|
159
|
+
* ({@link AuthoringConfigFor}), so `provider.options.model` is already that one provider's
|
|
160
|
+
* known model literals, with no union across providers and no generic for an editor to
|
|
161
|
+
* infer. Overload resolution selects the matching overload from the `provider.id` literal,
|
|
162
|
+
* so the editor offers only the selected provider's models and a foreign or unknown model
|
|
163
|
+
* (for example a Claude model under `id: "gemini"`) is a type error. This is deliberately
|
|
164
|
+
* overload-based: a generic whose type parameter is inferred from a nested `provider.id`
|
|
165
|
+
* collapses correctly in tsserver but not in editors with weaker inference (notably the
|
|
166
|
+
* JetBrains/WebStorm completion engine), which then fall back to the full union and offer
|
|
167
|
+
* every provider's models. Concrete per-provider signatures avoid that inference step.
|
|
168
|
+
*
|
|
169
|
+
* The final overload accepts the full {@link AuthoringConfig} union, so a config whose
|
|
170
|
+
* provider id is not a single literal (for example a value typed as the union) still
|
|
171
|
+
* type-checks.
|
|
172
|
+
*
|
|
173
|
+
* The return type is the runtime {@link VerbatraConfig}. The model restriction is a static
|
|
174
|
+
* authoring constraint, not a runtime one: `loadConfig` still validates `model` as
|
|
175
|
+
* `z.string().min(1)`, so a model the installed provider SDK does not yet list is flagged
|
|
176
|
+
* in the editor but still runs.
|
|
140
177
|
*/
|
|
178
|
+
declare function defineConfig(config: AuthoringConfigFor<"anthropic">): VerbatraConfig;
|
|
179
|
+
declare function defineConfig(config: AuthoringConfigFor<"openai">): VerbatraConfig;
|
|
180
|
+
declare function defineConfig(config: AuthoringConfigFor<"gemini">): VerbatraConfig;
|
|
181
|
+
declare function defineConfig(config: AuthoringConfigFor<"deepl">): VerbatraConfig;
|
|
141
182
|
declare function defineConfig(config: AuthoringConfig): VerbatraConfig;
|
|
142
183
|
|
|
143
184
|
interface LoadConfigOptions {
|
|
@@ -192,16 +233,16 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
192
233
|
* any message: provider/adapter/core errors are already secret-free, and the SDK never
|
|
193
234
|
* reads or holds a key. Each names a distinct boundary:
|
|
194
235
|
*
|
|
195
|
-
* - `CONFIG_NOT_FOUND`:no config was found by search, or an explicit `configPath` does not exist
|
|
236
|
+
* - `CONFIG_NOT_FOUND`: no config was found by search, or an explicit `configPath` does not exist
|
|
196
237
|
* (thrown by `loadConfig`).
|
|
197
|
-
* - `CONFIG_INVALID`:a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
198
|
-
* - `UNKNOWN_FORMAT`:no adapter is registered for the configured format (thrown by `translate`).
|
|
199
|
-
* - `PROVIDER_CONSTRUCTION_FAILED`:the provider factory threw; wraps the provider's own error, including
|
|
238
|
+
* - `CONFIG_INVALID`: a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
239
|
+
* - `UNKNOWN_FORMAT`: no adapter is registered for the configured format (thrown by `translate`).
|
|
240
|
+
* - `PROVIDER_CONSTRUCTION_FAILED`: the provider factory threw; wraps the provider's own error, including
|
|
200
241
|
* a missing `*_API_KEY` reported as `MISSING_API_KEY` (thrown by `translate`, non-dry-run only).
|
|
201
|
-
* - `SOURCE_UNREADABLE`:the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
202
|
-
* - `SOURCE_INVALID`:the source locale file could not be read or parsed; wraps the adapter read error
|
|
242
|
+
* - `SOURCE_UNREADABLE`: the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
243
|
+
* - `SOURCE_INVALID`: the source locale file could not be read or parsed; wraps the adapter read error
|
|
203
244
|
* (thrown by `translate`).
|
|
204
|
-
* - `LOCK_FILE_INVALID`:the lock-file is present but corrupt or oversized (thrown by `translate`).
|
|
245
|
+
* - `LOCK_FILE_INVALID`: the lock-file is present but corrupt or oversized (thrown by `translate`).
|
|
205
246
|
* - `LOCALE_FAILED` (NOT thrown): the fallback `code` recorded on a failed `LocaleSummary` when a
|
|
206
247
|
* per-locale failure carries no string code of its own. See the surfaced-not-thrown distinction on
|
|
207
248
|
* `translate`.
|
|
@@ -218,6 +259,23 @@ declare class SdkError extends Error {
|
|
|
218
259
|
constructor(code: SdkErrorCode, message: string);
|
|
219
260
|
}
|
|
220
261
|
|
|
262
|
+
/** A stable code for an SDK-originated notice (not a provider notice). */
|
|
263
|
+
type SdkNoticeCode = "PLURAL_CATEGORIES_INCOMPLETE" | "SUB_BATCH_FAILED";
|
|
264
|
+
/**
|
|
265
|
+
* A notice raised by the SDK itself (not a provider), structurally identical to a {@link ProviderNotice}
|
|
266
|
+
* so both share the {@link LocaleSummary.notices} channel. Carries only a stable code and a static,
|
|
267
|
+
* secret-free message; never a key value or translatable content. The SDK keeps its own codes here so
|
|
268
|
+
* the ai-providers `ProviderNoticeCode` union stays free of SDK concerns (the dependency arrow points
|
|
269
|
+
* sdk -> ai-providers, never the reverse).
|
|
270
|
+
*/
|
|
271
|
+
interface SdkNotice {
|
|
272
|
+
/** The stable {@link SdkNoticeCode} for what the SDK is reporting. */
|
|
273
|
+
readonly code: SdkNoticeCode;
|
|
274
|
+
/** A static, safe description; never a key or translatable content. */
|
|
275
|
+
readonly message: string;
|
|
276
|
+
}
|
|
277
|
+
/** A notice on a locale summary: either a provider-emitted notice or an SDK-emitted one. */
|
|
278
|
+
type LocaleNotice = ProviderNotice | SdkNotice;
|
|
221
279
|
/** Structured outcome for one target locale; surfaced as data on the run, never thrown. */
|
|
222
280
|
interface LocaleSummary {
|
|
223
281
|
/** The target locale this summary is for. */
|
|
@@ -231,14 +289,31 @@ interface LocaleSummary {
|
|
|
231
289
|
readonly translated: readonly string[];
|
|
232
290
|
/** Keys already up to date, left unchanged this run. */
|
|
233
291
|
readonly unchanged: readonly string[];
|
|
234
|
-
/** Target keys with no corresponding source key (candidates for removal). */
|
|
292
|
+
/** Target keys with no corresponding source key (candidates for removal). Reported regardless of pruning. */
|
|
235
293
|
readonly orphaned: readonly string[];
|
|
294
|
+
/**
|
|
295
|
+
* Orphaned keys actually removed this run because pruning was on. In a dry-run with pruning on, the keys
|
|
296
|
+
* that WOULD be removed. Empty when pruning is off (the orphans then survive and are reported in
|
|
297
|
+
* `orphaned` only). A subset of `orphaned`; never includes a source-present key.
|
|
298
|
+
*/
|
|
299
|
+
readonly pruned: readonly string[];
|
|
236
300
|
/** Source keys flagged invalid-ICU that were skipped for translation this run. */
|
|
237
301
|
readonly invalidIcuSource: readonly string[];
|
|
238
302
|
/** Translated keys that failed the placeholder-integrity check and were withheld. */
|
|
239
303
|
readonly integrityMismatches: readonly string[];
|
|
240
|
-
/**
|
|
241
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Plural-category keys verbatra SYNTHESIZED this run (for example a Polish `items_few` the source
|
|
306
|
+
* never supplied), kept distinct from {@link translated} because they were generated from the meaning
|
|
307
|
+
* of the source plural forms, not translated 1:1 from a source string. Empty unless plural generation
|
|
308
|
+
* was enabled and acted. In a dry-run this is empty (the provider is not called).
|
|
309
|
+
*/
|
|
310
|
+
readonly generated: readonly string[];
|
|
311
|
+
/**
|
|
312
|
+
* Notices for this locale: provider notices (e.g. DeepL graceful-degradation) and SDK notices
|
|
313
|
+
* (e.g. a target language needing more CLDR plural categories than the source supplies). Empty when
|
|
314
|
+
* nothing was degraded or flagged.
|
|
315
|
+
*/
|
|
316
|
+
readonly notices: readonly LocaleNotice[];
|
|
242
317
|
/**
|
|
243
318
|
* Present only when status is "failed": a structured, secret-free error. `code` is a PRESERVED string
|
|
244
319
|
* (the underlying provider/adapter error's `code`, or `"LOCALE_FAILED"` as a fallback), intentionally
|
|
@@ -320,6 +395,19 @@ interface TranslateInput {
|
|
|
320
395
|
readonly cwd?: string;
|
|
321
396
|
/** When true, read + diff + report only: the provider is never constructed or called and nothing is written. */
|
|
322
397
|
readonly dryRun?: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* When true, remove orphaned keys (target keys absent from source) from the written file and the lock.
|
|
400
|
+
* Off by default. When set, takes precedence over the config's `prune` option for this run; when unset,
|
|
401
|
+
* the config's `prune` applies. Only `diff.orphaned` keys are ever removed; no other key is touched.
|
|
402
|
+
*/
|
|
403
|
+
readonly prune?: boolean;
|
|
404
|
+
/**
|
|
405
|
+
* When true, synthesize the CLDR plural forms a richer target language requires but the source lacks
|
|
406
|
+
* (i18next-JSON + LLM providers only; every other case falls back to the existing warning). Off by
|
|
407
|
+
* default. When set, takes precedence over the config's `generatePlurals` option for this run; when
|
|
408
|
+
* unset, the config's `generatePlurals` applies.
|
|
409
|
+
*/
|
|
410
|
+
readonly generatePlurals?: boolean;
|
|
323
411
|
}
|
|
324
412
|
/** Composition seam: inject a registry, a provider builder, and a file system for tests. */
|
|
325
413
|
interface TranslateDeps {
|
|
@@ -344,7 +432,7 @@ interface TranslateDeps {
|
|
|
344
432
|
* {@link SdkErrorCode}. DeepL notices, integrity mismatches, and invalid-ICU source keys likewise
|
|
345
433
|
* surface on each `LocaleSummary`, never as throws.
|
|
346
434
|
*
|
|
347
|
-
* @param input - The validated config and run options (cwd, dryRun).
|
|
435
|
+
* @param input - The validated config and run options (cwd, dryRun, prune, generatePlurals).
|
|
348
436
|
* @param deps - Optional composition seams (registry, provider builder, file system) for tests.
|
|
349
437
|
* @returns A {@link RunSummary}: the per-locale {@link LocaleSummary}s and the succeeded/failed locale lists.
|
|
350
438
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`: no adapter is registered for the configured format.
|
|
@@ -470,7 +558,7 @@ interface Watcher {
|
|
|
470
558
|
}
|
|
471
559
|
/** Builds a {@link Watcher} for the given paths; the seam production fills with chokidar. */
|
|
472
560
|
type CreateWatcher = (paths: readonly string[]) => Watcher;
|
|
473
|
-
/** The run a watch trigger performs: the
|
|
561
|
+
/** The run a watch trigger performs: the one-shot translate, unchanged. */
|
|
474
562
|
type RunTranslate = (input: TranslateInput) => Promise<RunSummary>;
|
|
475
563
|
/** The outcome of one run, surfaced to the caller; never carries a secret. */
|
|
476
564
|
type WatchRunResult = {
|
|
@@ -558,4 +646,4 @@ interface WatchController {
|
|
|
558
646
|
*/
|
|
559
647
|
declare function watch(input: WatchInput, deps?: WatchDeps): Promise<WatchController>;
|
|
560
648
|
|
|
561
|
-
export { type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, defineConfig, exportWorkbook, importWorkbook, loadConfig, translate, verbatraConfigSchema, watch };
|
|
649
|
+
export { type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleNotice, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, defineConfig, exportWorkbook, importWorkbook, loadConfig, translate, verbatraConfigSchema, watch };
|
package/dist/index.d.ts
CHANGED
|
@@ -38,12 +38,6 @@ declare const providerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
38
38
|
type ProviderConfig = z.infer<typeof providerConfigSchema>;
|
|
39
39
|
type ProviderId = ProviderConfig["id"];
|
|
40
40
|
|
|
41
|
-
/**
|
|
42
|
-
* The verbatra project configuration. Non-secret only: it carries no API key (the
|
|
43
|
-
* provider reads its key from the environment), and unknown top-level keys are rejected
|
|
44
|
-
* so a stray secret cannot hide in the config. Validated with zod at the boundary
|
|
45
|
-
* regardless of where it was loaded from.
|
|
46
|
-
*/
|
|
47
41
|
declare const verbatraConfigSchema: z.ZodObject<{
|
|
48
42
|
sourceLocale: z.ZodString;
|
|
49
43
|
targetLocales: z.ZodArray<z.ZodString>;
|
|
@@ -86,27 +80,24 @@ declare const verbatraConfigSchema: z.ZodObject<{
|
|
|
86
80
|
informal: "informal";
|
|
87
81
|
neutral: "neutral";
|
|
88
82
|
}>>;
|
|
83
|
+
prune: z.ZodOptional<z.ZodBoolean>;
|
|
84
|
+
generatePlurals: z.ZodOptional<z.ZodBoolean>;
|
|
85
|
+
maxBatchSize: z.ZodOptional<z.ZodNumber>;
|
|
89
86
|
}, z.core.$strict>;
|
|
90
87
|
type VerbatraConfig = z.infer<typeof verbatraConfigSchema>;
|
|
91
88
|
|
|
92
89
|
/**
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* The authoring view of one provider variant: its runtime config with `options.model`
|
|
103
|
-
* narrowed to that provider's open model union. LLM providers (anthropic, openai,
|
|
104
|
-
* gemini) get suggestions; DeepL has no model field and is carried through unchanged.
|
|
90
|
+
* The closed set of a provider's known model IDs: exactly the string literals its SDK
|
|
91
|
+
* model type ships, with the SDK's own open `string & {}` arm stripped out. Distributing
|
|
92
|
+
* over the union and dropping any arm the wide `string` extends leaves only the literals,
|
|
93
|
+
* so the authoring field offers and ACCEPTS only the selected provider's known models. A
|
|
94
|
+
* foreign or unknown model (for example a Claude model under `id: "gemini"`) is a type
|
|
95
|
+
* error at authoring time. This is a static authoring constraint only; the runtime schema
|
|
96
|
+
* stays `z.string().min(1)` and still accepts any non-empty string, so a brand-new model
|
|
97
|
+
* the installed SDK does not yet list is flagged in the editor but still runs.
|
|
105
98
|
*/
|
|
106
|
-
type
|
|
107
|
-
|
|
108
|
-
}>;
|
|
109
|
-
type AuthoringVariant<Id extends ProviderConfig["id"], M extends string> = Extract<ProviderConfig, {
|
|
99
|
+
type KnownModels<M extends string> = M extends string ? (string extends M ? never : M) : never;
|
|
100
|
+
type AuthoringVariant<Id extends ProviderId, M extends string> = Extract<ProviderConfig, {
|
|
110
101
|
id: Id;
|
|
111
102
|
}> extends infer Variant ? Variant extends {
|
|
112
103
|
options: {
|
|
@@ -114,30 +105,80 @@ type AuthoringVariant<Id extends ProviderConfig["id"], M extends string> = Extra
|
|
|
114
105
|
};
|
|
115
106
|
} ? Omit<Variant, "options"> & {
|
|
116
107
|
options: Omit<Variant["options"], "model"> & {
|
|
117
|
-
model:
|
|
108
|
+
model: KnownModels<M>;
|
|
118
109
|
};
|
|
119
110
|
} : never : never;
|
|
120
111
|
/**
|
|
121
|
-
* The authoring view of
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
112
|
+
* The authoring view of one provider variant, keyed by id. LLM providers (anthropic,
|
|
113
|
+
* openai, gemini) restrict `options.model` to that provider's known model literals; DeepL
|
|
114
|
+
* has no model field and is carried through unchanged. Keying by id (rather than a flat
|
|
115
|
+
* union) lets {@link AuthoringConfigFor} select exactly one variant for a literal id, so
|
|
116
|
+
* the `options.model` site is one provider's literal set and never a multi-provider union.
|
|
125
117
|
*/
|
|
126
|
-
type
|
|
127
|
-
|
|
118
|
+
type AuthoringProviderVariant = {
|
|
119
|
+
anthropic: AuthoringVariant<"anthropic", AnthropicModel>;
|
|
120
|
+
openai: AuthoringVariant<"openai", OpenAiModel>;
|
|
121
|
+
gemini: AuthoringVariant<"gemini", GeminiModel>;
|
|
122
|
+
deepl: Extract<ProviderConfig, {
|
|
123
|
+
id: "deepl";
|
|
124
|
+
}>;
|
|
128
125
|
};
|
|
126
|
+
/**
|
|
127
|
+
* The authoring view of the whole config for a given provider id. It is structurally a
|
|
128
|
+
* {@link VerbatraConfig} whose `provider` is the single authoring variant for `TId`.
|
|
129
|
+
*
|
|
130
|
+
* When `TId` is a single provider literal, `provider` is one concrete variant, so
|
|
131
|
+
* `options.model` is that provider's known model literals alone and not a union across
|
|
132
|
+
* providers. `defineConfig` declares one overload per provider parameterized on this type
|
|
133
|
+
* (`AuthoringConfigFor<"openai">` and so on), so overload resolution picks the variant from
|
|
134
|
+
* the `provider.id` literal. That, together with the closed {@link KnownModels} set, makes a
|
|
135
|
+
* foreign model (for example a Claude model under `id: "gemini"`) a type error and aims to
|
|
136
|
+
* keep editors with weaker discriminated-union narrowing (for example the JetBrains/WebStorm
|
|
137
|
+
* completion engine) offering only the selected provider's models, since each overload's
|
|
138
|
+
* parameter is already a single variant with no nested union to narrow. When `TId` defaults
|
|
139
|
+
* to `ProviderId`, `provider` is the full authoring union. Every value assignable here is
|
|
140
|
+
* assignable to {@link VerbatraConfig}, because a model literal is a subtype of `string`.
|
|
141
|
+
*/
|
|
142
|
+
type AuthoringConfigFor<TId extends ProviderId = ProviderId> = Omit<VerbatraConfig, "provider"> & {
|
|
143
|
+
provider: AuthoringProviderVariant[TId];
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* The authoring view of the whole config across every provider (the `TId = ProviderId`
|
|
147
|
+
* case of {@link AuthoringConfigFor}): identical to {@link VerbatraConfig} except that
|
|
148
|
+
* `provider` offers per-provider model completions.
|
|
149
|
+
*/
|
|
150
|
+
type AuthoringConfig = AuthoringConfigFor;
|
|
129
151
|
|
|
130
152
|
/**
|
|
131
153
|
* Identity helper for authoring a code-defined verbatra.config.ts. It returns its
|
|
132
154
|
* argument unchanged; its only purpose is to give the author full type inference and
|
|
133
155
|
* editor autocomplete on the config object.
|
|
134
156
|
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
157
|
+
* It is declared as one overload per provider id rather than a single generic. Each
|
|
158
|
+
* overload's parameter is the concrete single-provider authoring config
|
|
159
|
+
* ({@link AuthoringConfigFor}), so `provider.options.model` is already that one provider's
|
|
160
|
+
* known model literals, with no union across providers and no generic for an editor to
|
|
161
|
+
* infer. Overload resolution selects the matching overload from the `provider.id` literal,
|
|
162
|
+
* so the editor offers only the selected provider's models and a foreign or unknown model
|
|
163
|
+
* (for example a Claude model under `id: "gemini"`) is a type error. This is deliberately
|
|
164
|
+
* overload-based: a generic whose type parameter is inferred from a nested `provider.id`
|
|
165
|
+
* collapses correctly in tsserver but not in editors with weaker inference (notably the
|
|
166
|
+
* JetBrains/WebStorm completion engine), which then fall back to the full union and offer
|
|
167
|
+
* every provider's models. Concrete per-provider signatures avoid that inference step.
|
|
168
|
+
*
|
|
169
|
+
* The final overload accepts the full {@link AuthoringConfig} union, so a config whose
|
|
170
|
+
* provider id is not a single literal (for example a value typed as the union) still
|
|
171
|
+
* type-checks.
|
|
172
|
+
*
|
|
173
|
+
* The return type is the runtime {@link VerbatraConfig}. The model restriction is a static
|
|
174
|
+
* authoring constraint, not a runtime one: `loadConfig` still validates `model` as
|
|
175
|
+
* `z.string().min(1)`, so a model the installed provider SDK does not yet list is flagged
|
|
176
|
+
* in the editor but still runs.
|
|
140
177
|
*/
|
|
178
|
+
declare function defineConfig(config: AuthoringConfigFor<"anthropic">): VerbatraConfig;
|
|
179
|
+
declare function defineConfig(config: AuthoringConfigFor<"openai">): VerbatraConfig;
|
|
180
|
+
declare function defineConfig(config: AuthoringConfigFor<"gemini">): VerbatraConfig;
|
|
181
|
+
declare function defineConfig(config: AuthoringConfigFor<"deepl">): VerbatraConfig;
|
|
141
182
|
declare function defineConfig(config: AuthoringConfig): VerbatraConfig;
|
|
142
183
|
|
|
143
184
|
interface LoadConfigOptions {
|
|
@@ -192,16 +233,16 @@ declare function loadConfig(options?: LoadConfigOptions): Promise<VerbatraConfig
|
|
|
192
233
|
* any message: provider/adapter/core errors are already secret-free, and the SDK never
|
|
193
234
|
* reads or holds a key. Each names a distinct boundary:
|
|
194
235
|
*
|
|
195
|
-
* - `CONFIG_NOT_FOUND`:no config was found by search, or an explicit `configPath` does not exist
|
|
236
|
+
* - `CONFIG_NOT_FOUND`: no config was found by search, or an explicit `configPath` does not exist
|
|
196
237
|
* (thrown by `loadConfig`).
|
|
197
|
-
* - `CONFIG_INVALID`:a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
198
|
-
* - `UNKNOWN_FORMAT`:no adapter is registered for the configured format (thrown by `translate`).
|
|
199
|
-
* - `PROVIDER_CONSTRUCTION_FAILED`:the provider factory threw; wraps the provider's own error, including
|
|
238
|
+
* - `CONFIG_INVALID`: a config was found but is unparseable or fails validation (thrown by `loadConfig`).
|
|
239
|
+
* - `UNKNOWN_FORMAT`: no adapter is registered for the configured format (thrown by `translate`).
|
|
240
|
+
* - `PROVIDER_CONSTRUCTION_FAILED`: the provider factory threw; wraps the provider's own error, including
|
|
200
241
|
* a missing `*_API_KEY` reported as `MISSING_API_KEY` (thrown by `translate`, non-dry-run only).
|
|
201
|
-
* - `SOURCE_UNREADABLE`:the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
202
|
-
* - `SOURCE_INVALID`:the source locale file could not be read or parsed; wraps the adapter read error
|
|
242
|
+
* - `SOURCE_UNREADABLE`: the source locale file is absent (thrown by `translate`, and by `watch` at startup).
|
|
243
|
+
* - `SOURCE_INVALID`: the source locale file could not be read or parsed; wraps the adapter read error
|
|
203
244
|
* (thrown by `translate`).
|
|
204
|
-
* - `LOCK_FILE_INVALID`:the lock-file is present but corrupt or oversized (thrown by `translate`).
|
|
245
|
+
* - `LOCK_FILE_INVALID`: the lock-file is present but corrupt or oversized (thrown by `translate`).
|
|
205
246
|
* - `LOCALE_FAILED` (NOT thrown): the fallback `code` recorded on a failed `LocaleSummary` when a
|
|
206
247
|
* per-locale failure carries no string code of its own. See the surfaced-not-thrown distinction on
|
|
207
248
|
* `translate`.
|
|
@@ -218,6 +259,23 @@ declare class SdkError extends Error {
|
|
|
218
259
|
constructor(code: SdkErrorCode, message: string);
|
|
219
260
|
}
|
|
220
261
|
|
|
262
|
+
/** A stable code for an SDK-originated notice (not a provider notice). */
|
|
263
|
+
type SdkNoticeCode = "PLURAL_CATEGORIES_INCOMPLETE" | "SUB_BATCH_FAILED";
|
|
264
|
+
/**
|
|
265
|
+
* A notice raised by the SDK itself (not a provider), structurally identical to a {@link ProviderNotice}
|
|
266
|
+
* so both share the {@link LocaleSummary.notices} channel. Carries only a stable code and a static,
|
|
267
|
+
* secret-free message; never a key value or translatable content. The SDK keeps its own codes here so
|
|
268
|
+
* the ai-providers `ProviderNoticeCode` union stays free of SDK concerns (the dependency arrow points
|
|
269
|
+
* sdk -> ai-providers, never the reverse).
|
|
270
|
+
*/
|
|
271
|
+
interface SdkNotice {
|
|
272
|
+
/** The stable {@link SdkNoticeCode} for what the SDK is reporting. */
|
|
273
|
+
readonly code: SdkNoticeCode;
|
|
274
|
+
/** A static, safe description; never a key or translatable content. */
|
|
275
|
+
readonly message: string;
|
|
276
|
+
}
|
|
277
|
+
/** A notice on a locale summary: either a provider-emitted notice or an SDK-emitted one. */
|
|
278
|
+
type LocaleNotice = ProviderNotice | SdkNotice;
|
|
221
279
|
/** Structured outcome for one target locale; surfaced as data on the run, never thrown. */
|
|
222
280
|
interface LocaleSummary {
|
|
223
281
|
/** The target locale this summary is for. */
|
|
@@ -231,14 +289,31 @@ interface LocaleSummary {
|
|
|
231
289
|
readonly translated: readonly string[];
|
|
232
290
|
/** Keys already up to date, left unchanged this run. */
|
|
233
291
|
readonly unchanged: readonly string[];
|
|
234
|
-
/** Target keys with no corresponding source key (candidates for removal). */
|
|
292
|
+
/** Target keys with no corresponding source key (candidates for removal). Reported regardless of pruning. */
|
|
235
293
|
readonly orphaned: readonly string[];
|
|
294
|
+
/**
|
|
295
|
+
* Orphaned keys actually removed this run because pruning was on. In a dry-run with pruning on, the keys
|
|
296
|
+
* that WOULD be removed. Empty when pruning is off (the orphans then survive and are reported in
|
|
297
|
+
* `orphaned` only). A subset of `orphaned`; never includes a source-present key.
|
|
298
|
+
*/
|
|
299
|
+
readonly pruned: readonly string[];
|
|
236
300
|
/** Source keys flagged invalid-ICU that were skipped for translation this run. */
|
|
237
301
|
readonly invalidIcuSource: readonly string[];
|
|
238
302
|
/** Translated keys that failed the placeholder-integrity check and were withheld. */
|
|
239
303
|
readonly integrityMismatches: readonly string[];
|
|
240
|
-
/**
|
|
241
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Plural-category keys verbatra SYNTHESIZED this run (for example a Polish `items_few` the source
|
|
306
|
+
* never supplied), kept distinct from {@link translated} because they were generated from the meaning
|
|
307
|
+
* of the source plural forms, not translated 1:1 from a source string. Empty unless plural generation
|
|
308
|
+
* was enabled and acted. In a dry-run this is empty (the provider is not called).
|
|
309
|
+
*/
|
|
310
|
+
readonly generated: readonly string[];
|
|
311
|
+
/**
|
|
312
|
+
* Notices for this locale: provider notices (e.g. DeepL graceful-degradation) and SDK notices
|
|
313
|
+
* (e.g. a target language needing more CLDR plural categories than the source supplies). Empty when
|
|
314
|
+
* nothing was degraded or flagged.
|
|
315
|
+
*/
|
|
316
|
+
readonly notices: readonly LocaleNotice[];
|
|
242
317
|
/**
|
|
243
318
|
* Present only when status is "failed": a structured, secret-free error. `code` is a PRESERVED string
|
|
244
319
|
* (the underlying provider/adapter error's `code`, or `"LOCALE_FAILED"` as a fallback), intentionally
|
|
@@ -320,6 +395,19 @@ interface TranslateInput {
|
|
|
320
395
|
readonly cwd?: string;
|
|
321
396
|
/** When true, read + diff + report only: the provider is never constructed or called and nothing is written. */
|
|
322
397
|
readonly dryRun?: boolean;
|
|
398
|
+
/**
|
|
399
|
+
* When true, remove orphaned keys (target keys absent from source) from the written file and the lock.
|
|
400
|
+
* Off by default. When set, takes precedence over the config's `prune` option for this run; when unset,
|
|
401
|
+
* the config's `prune` applies. Only `diff.orphaned` keys are ever removed; no other key is touched.
|
|
402
|
+
*/
|
|
403
|
+
readonly prune?: boolean;
|
|
404
|
+
/**
|
|
405
|
+
* When true, synthesize the CLDR plural forms a richer target language requires but the source lacks
|
|
406
|
+
* (i18next-JSON + LLM providers only; every other case falls back to the existing warning). Off by
|
|
407
|
+
* default. When set, takes precedence over the config's `generatePlurals` option for this run; when
|
|
408
|
+
* unset, the config's `generatePlurals` applies.
|
|
409
|
+
*/
|
|
410
|
+
readonly generatePlurals?: boolean;
|
|
323
411
|
}
|
|
324
412
|
/** Composition seam: inject a registry, a provider builder, and a file system for tests. */
|
|
325
413
|
interface TranslateDeps {
|
|
@@ -344,7 +432,7 @@ interface TranslateDeps {
|
|
|
344
432
|
* {@link SdkErrorCode}. DeepL notices, integrity mismatches, and invalid-ICU source keys likewise
|
|
345
433
|
* surface on each `LocaleSummary`, never as throws.
|
|
346
434
|
*
|
|
347
|
-
* @param input - The validated config and run options (cwd, dryRun).
|
|
435
|
+
* @param input - The validated config and run options (cwd, dryRun, prune, generatePlurals).
|
|
348
436
|
* @param deps - Optional composition seams (registry, provider builder, file system) for tests.
|
|
349
437
|
* @returns A {@link RunSummary}: the per-locale {@link LocaleSummary}s and the succeeded/failed locale lists.
|
|
350
438
|
* @throws {@link SdkError} `UNKNOWN_FORMAT`: no adapter is registered for the configured format.
|
|
@@ -470,7 +558,7 @@ interface Watcher {
|
|
|
470
558
|
}
|
|
471
559
|
/** Builds a {@link Watcher} for the given paths; the seam production fills with chokidar. */
|
|
472
560
|
type CreateWatcher = (paths: readonly string[]) => Watcher;
|
|
473
|
-
/** The run a watch trigger performs: the
|
|
561
|
+
/** The run a watch trigger performs: the one-shot translate, unchanged. */
|
|
474
562
|
type RunTranslate = (input: TranslateInput) => Promise<RunSummary>;
|
|
475
563
|
/** The outcome of one run, surfaced to the caller; never carries a secret. */
|
|
476
564
|
type WatchRunResult = {
|
|
@@ -558,4 +646,4 @@ interface WatchController {
|
|
|
558
646
|
*/
|
|
559
647
|
declare function watch(input: WatchInput, deps?: WatchDeps): Promise<WatchController>;
|
|
560
648
|
|
|
561
|
-
export { type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, defineConfig, exportWorkbook, importWorkbook, loadConfig, translate, verbatraConfigSchema, watch };
|
|
649
|
+
export { type CreateProvider, type CreateWatcher, DEFAULT_WORKBOOK_PATH, type ExportWorkbookDeps, type ExportWorkbookInput, type ExportWorkbookResult, type ImportWorkbookDeps, type ImportWorkbookInput, type LoadConfigOptions, type LocaleNotice, type LocaleSummary, type ProviderConfig, type ProviderId, type RunSummary, type RunTranslate, SdkError, type SdkErrorCode, type SdkFs, type SdkNotice, type SdkNoticeCode, type TranslateDeps, type TranslateInput, type VerbatraConfig, type WatchController, type WatchDeps, type WatchInput, type WatchRunResult, type Watcher, defineConfig, exportWorkbook, importWorkbook, loadConfig, translate, verbatraConfigSchema, watch };
|