@i18nprune/core 0.1.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.
Files changed (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/adapters-gp1lXp0T.d.ts +12 -0
  4. package/dist/capabilities-x74cD2Hu.d.ts +48 -0
  5. package/dist/cleanup.d.ts +64 -0
  6. package/dist/cleanup.js +3999 -0
  7. package/dist/config.d.ts +201 -0
  8. package/dist/config.js +2865 -0
  9. package/dist/coreContext-DMaWLvmB.d.ts +388 -0
  10. package/dist/fs-BUYD8ZhA.d.ts +20 -0
  11. package/dist/generate.d.ts +487 -0
  12. package/dist/generate.js +9389 -0
  13. package/dist/humanEmit-ygNlYX-S.d.ts +79 -0
  14. package/dist/index-BQuLEQ9b.d.ts +7 -0
  15. package/dist/index-B_ow_Xvr.d.ts +97 -0
  16. package/dist/index-BgG01AKL.d.ts +287 -0
  17. package/dist/index-CIzZl4W8.d.ts +124 -0
  18. package/dist/index-Csm1w7XD.d.ts +58 -0
  19. package/dist/index-DLwTogCo.d.ts +43 -0
  20. package/dist/index-DVT26v11.d.ts +61 -0
  21. package/dist/index-DdjljwMj.d.ts +39 -0
  22. package/dist/index-DeIw-cZd.d.ts +52 -0
  23. package/dist/index-X50E1FIX.d.ts +50 -0
  24. package/dist/index.d.ts +9180 -0
  25. package/dist/index.js +21888 -0
  26. package/dist/init.d.ts +86 -0
  27. package/dist/init.js +848 -0
  28. package/dist/listWindow-XEFxQZi1.d.ts +30 -0
  29. package/dist/localeTargetCodes-BBIQjauw.d.ts +11 -0
  30. package/dist/locales.d.ts +39 -0
  31. package/dist/locales.js +2288 -0
  32. package/dist/missing-BVCvgUC8.d.ts +10 -0
  33. package/dist/missing.d.ts +85 -0
  34. package/dist/missing.js +5892 -0
  35. package/dist/modeResolve-cGVaY5Hh.d.ts +25 -0
  36. package/dist/path-Bfn3SAts.d.ts +11 -0
  37. package/dist/profile-BwOP9WKh.d.ts +9 -0
  38. package/dist/providers-0uMEfT6q.d.ts +82 -0
  39. package/dist/prune-c6hKZCv_.d.ts +33 -0
  40. package/dist/quality.d.ts +36 -0
  41. package/dist/quality.js +3868 -0
  42. package/dist/report-D5-6bVFj.d.ts +8 -0
  43. package/dist/report-schema.d.ts +102 -0
  44. package/dist/report-schema.js +42 -0
  45. package/dist/resumeCandidates-xR13eEwt.d.ts +200 -0
  46. package/dist/root-2-kCaBvQ.d.ts +1110 -0
  47. package/dist/runtime/edge.d.ts +21 -0
  48. package/dist/runtime/edge.js +87 -0
  49. package/dist/runtime/helpers/sync.d.ts +16 -0
  50. package/dist/runtime/helpers/sync.js +117 -0
  51. package/dist/runtime/node.d.ts +24 -0
  52. package/dist/runtime/node.js +204 -0
  53. package/dist/runtime/web.d.ts +21 -0
  54. package/dist/runtime/web.js +84 -0
  55. package/dist/shared.d.ts +1177 -0
  56. package/dist/shared.js +4897 -0
  57. package/dist/sourceContext-1LQg3HiQ.d.ts +36 -0
  58. package/dist/sourceSurface-mDtwGo1E.d.ts +122 -0
  59. package/dist/sync.d.ts +86 -0
  60. package/dist/sync.js +4971 -0
  61. package/dist/syncSegment-Bx6He2Mu.d.ts +149 -0
  62. package/dist/targets-EmtKyr6F.d.ts +23 -0
  63. package/dist/template-CGM-_WLT.d.ts +139 -0
  64. package/dist/translate-CIHYp7wi.d.ts +77 -0
  65. package/dist/types/shared.d.ts +21 -0
  66. package/dist/types/shared.js +1 -0
  67. package/dist/types.d.ts +1345 -0
  68. package/dist/types.js +1 -0
  69. package/dist/validate.d.ts +126 -0
  70. package/dist/validate.js +3717 -0
  71. package/package.json +128 -0
@@ -0,0 +1,1110 @@
1
+ import { z } from 'zod';
2
+ import { R as RuntimePathPort } from './path-Bfn3SAts.js';
3
+ import { R as RuntimeFsPort } from './fs-BUYD8ZhA.js';
4
+ import { T as TranslationProviderId } from './providers-0uMEfT6q.js';
5
+
6
+ /**
7
+ * Minimal path surface for computing {@link LocaleSegmentSource} without importing a concrete runtime.
8
+ */
9
+ type LocaleLeafPathApi = {
10
+ basename(path: string, suffix?: string): string;
11
+ dirname(path: string): string;
12
+ join(...paths: string[]): string;
13
+ relative(from: string, to: string): string;
14
+ isAbsolute(path: string): boolean;
15
+ };
16
+ /**
17
+ * On-disk locale JSON segment that contributed a normalized translation row.
18
+ *
19
+ * @remarks Distinct from {@link TranslationSurfaceLeaf.source} (structured JSON metadata on disk).
20
+ */
21
+ type LocaleSegmentSource = {
22
+ file: string;
23
+ locale: string;
24
+ relativePath: string;
25
+ };
26
+
27
+ /** Single user rule for directory or file basename, or an extension token (see `ScanExcludeConfig.extensions`). */
28
+ type ScanExcludeRule = string | RegExp;
29
+ /** Built-in presets for scan exclusion defaults. */
30
+ type ScanExcludePreset = 'production';
31
+ /**
32
+ * Optional scan exclusions (directories while walking, files, extensions, path patterns).
33
+ * Used by {@link listSourceFiles} and extractor project scans. Omitted fields mean “no extra rule”.
34
+ *
35
+ * `useDefaultSkip` defaults to **true** when `exclude` is absent or the field is omitted — built-in
36
+ * directory skips (e.g. `node_modules`, `dist`) stay on unless explicitly disabled.
37
+ *
38
+ * **Validation:** empty string rules are ignored. **`RegExp`** values are used as-is; a bad pattern can
39
+ * still throw when the walk runs (same as any invalid regex in app code). There is no silent disk I/O
40
+ * or scan-tree warning channel in core — hosts that want UX warnings should validate config before calling.
41
+ */
42
+ type ScanExcludeConfig = {
43
+ /**
44
+ * Optional built-in preset. At resolve time, preset `dirs` / `files` / `extensions` / `patterns` are merged **before**
45
+ * the same fields from this config object (preset first, then your lists). **`useDefaultSkip`** uses your value when set,
46
+ * otherwise the preset’s. **CLI** may append `--exclude` directory names after load.
47
+ */
48
+ preset?: ScanExcludePreset;
49
+ /** Skip directory entries with this basename while recursing (string equality or `RegExp.test(name)`). */
50
+ dirs?: ScanExcludeRule[];
51
+ /** After a path matches a scanned source extension, skip if basename matches. */
52
+ files?: ScanExcludeRule[];
53
+ /**
54
+ * Skip if any suffix of the basename after the first dot matches (e.g. `d.ts`, `ts`, `stories.tsx`).
55
+ * Strings are normalized: trimmed, lowercased, leading `.` stripped. Regexes are tested on each suffix.
56
+ */
57
+ extensions?: ScanExcludeRule[];
58
+ /** Skip when the path relative to the scan root (POSIX `/`) matches any regex. */
59
+ patterns?: RegExp[];
60
+ /**
61
+ * When true (default), apply built-in directory skips in addition to `dirs`.
62
+ * When false, only `dirs` / `files` / `extensions` / `patterns` apply.
63
+ */
64
+ useDefaultSkip?: boolean;
65
+ };
66
+
67
+ /**
68
+ * How parallel file scanning is scheduled.
69
+ * - **`auto`** — host picks serial vs concurrent.
70
+ * - **`serial`** — single-threaded walk (predictable, slower on huge trees).
71
+ * - **`concurrent`** — bounded worker pool up to **`concurrency`** / **`hardCap`**.
72
+ */
73
+ type ScannerExecutionMode = 'serial' | 'concurrent' | 'auto';
74
+ /** Optional tuning for source-tree scans (extractor / discovery). Safe defaults apply when omitted. */
75
+ type ScannerConfigInput = {
76
+ /**
77
+ * Execution strategy hint.
78
+ * - **`auto`**: runtime chooses strategy.
79
+ * - **`serial`**: force single-worker execution.
80
+ * - **`concurrent`**: allow multi-worker execution with limits.
81
+ */
82
+ mode?: ScannerExecutionMode;
83
+ /**
84
+ * Requested worker count when mode is **`concurrent`** (or **`auto`** if runtime supports it).
85
+ * Clamped to **`[1, hardCap]`** by core resolver.
86
+ */
87
+ concurrency?: number;
88
+ /**
89
+ * Safety ceiling for worker count. Core clamps this to at least 1.
90
+ * Hosts may still apply stricter runtime-specific ceilings.
91
+ */
92
+ hardCap?: number;
93
+ };
94
+ type ScannerConfigResolved = {
95
+ mode: ScannerExecutionMode;
96
+ concurrency: number;
97
+ hardCap: number;
98
+ effectiveConcurrency: number;
99
+ };
100
+ type ResolveScannerConfigOptions = {
101
+ defaultMode?: ScannerExecutionMode;
102
+ defaultConcurrency?: number;
103
+ defaultHardCap?: number;
104
+ };
105
+
106
+ /**
107
+ * Public translate-policy surface.
108
+ *
109
+ * Locked verb dictionary, per-outcome action keys, and defaults that drive
110
+ * `runGenerate`'s provider chain through `resolveProviderActionFor` (step 5).
111
+ * SDK consumers author this shape inside `defineConfig({ translate: { policy } })`.
112
+ *
113
+ * Source of truth: `translate-policy (shipped)` §3 (schema) + §4 (verb
114
+ * dictionary) + §6 (defaults). When the plan moves a key, this file moves with it.
115
+ */
116
+ /**
117
+ * Single action verb returned by the policy resolver for one observed outcome.
118
+ *
119
+ * The verb names *what the orchestrator does*, not which outcome triggered it. The
120
+ * resolver consults the matching `on*` key in {@link TranslatePolicy} (e.g.
121
+ * `onRateLimit` for `rate_limited`) and returns one verb from this set.
122
+ *
123
+ * - `'retry'` — re-attempt the leaf on the **same** provider; counts toward `maxAttempts`.
124
+ * - `'backoff'` — pause via `ProviderHealthMonitor` (`Retry-After` or fallback decay), then `'retry'`.
125
+ * - `'fallback'` — advance to the next entry in `providers[]`; resume from the partial locale.
126
+ * - `'prompt'` — TTY: open the handoff picker (step 7); non-TTY: degrade to `'fallback'` if
127
+ * eligible, else `'abort'`.
128
+ * - `'abort'` — stop the run with a structured issue. Reserved for auth / hard-stop.
129
+ * - `'flag'` — only used by `onIdentityOutput`: write source as the leaf and continue;
130
+ * the structured leaf gets `needsReview: true` when `--metadata` is on.
131
+ */
132
+ type TranslatePolicyVerb = 'retry' | 'backoff' | 'fallback' | 'prompt' | 'abort' | 'flag';
133
+ /** Verbs accepted by `onRateLimit`. */
134
+ type OnRateLimitVerb = 'backoff' | 'retry' | 'fallback' | 'abort';
135
+ /** Verbs accepted by `onTransientFailure`. */
136
+ type OnTransientFailureVerb = 'retry' | 'fallback' | 'abort';
137
+ /** Verbs accepted by `onQuotaExceeded`. */
138
+ type OnQuotaExceededVerb = 'fallback' | 'prompt' | 'abort';
139
+ /** Verbs accepted by `onAuthFailure`. */
140
+ type OnAuthFailureVerb = 'abort' | 'prompt';
141
+ /** Verbs accepted by `onProviderUnavailable`. */
142
+ type OnProviderUnavailableVerb = 'fallback' | 'abort';
143
+ /** Verbs accepted by `onIdentityOutput`. */
144
+ type OnIdentityOutputVerb = 'flag' | 'fallback' | 'abort';
145
+ /** Verbs accepted by `onIncompleteRun`. */
146
+ type OnIncompleteRunVerb = 'confirm' | 'write' | 'discard';
147
+ /** Chain mode. `'single'` runs one provider; `'auto'` walks `providers[]` on retryable failures. */
148
+ type TranslateRoutingMode = 'single' | 'auto';
149
+ /**
150
+ * Mid-run handoff picker mode (step 7).
151
+ * - `'auto'` — TTY: prompt when `routing: 'single'`; non-TTY: silent fallback.
152
+ * - `'on'` — always prompt (TTY only; non-TTY degrades to fallback).
153
+ * - `'off'` — never prompt.
154
+ */
155
+ type TranslateHandoffMode = 'auto' | 'on' | 'off';
156
+ /**
157
+ * Resolved per-outcome translate-policy. **All keys optional** — defaults are documented
158
+ * in {@link TRANSLATE_POLICY_DEFAULTS} and applied during config parse.
159
+ *
160
+ * Authored under `defineConfig({ translate: { policy } })`. Consumers should never
161
+ * read partial fields directly; use the resolved policy from `runGenerate` context
162
+ * (or `parseI18nPruneConfig`'s output) which has every key filled in.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * import { defineConfig } from 'i18nprune/core/config';
167
+ *
168
+ * export default defineConfig({
169
+ * locales: {
170
+ * source: 'en',
171
+ * directory: 'locales',
172
+ * },
173
+ * src: 'src',
174
+ * functions: ['t'],
175
+ * translate: {
176
+ * primary: 'google',
177
+ * providers: [{ id: 'google' }, { id: 'mymemory', enabled: false }],
178
+ * policy: {
179
+ * routing: 'auto',
180
+ * onRateLimit: 'backoff',
181
+ * onQuotaExceeded: 'fallback',
182
+ * handoff: 'auto',
183
+ * },
184
+ * },
185
+ * });
186
+ * ```
187
+ */
188
+ type TranslatePolicy = {
189
+ routing?: TranslateRoutingMode;
190
+ /** Action when the provider returns HTTP 429 / "too many requests". */
191
+ onRateLimit?: OnRateLimitVerb;
192
+ /** Action for transient network blips and `ECONNRESET`-style errors. */
193
+ onTransientFailure?: OnTransientFailureVerb;
194
+ /** Action when the provider explicitly says daily/monthly quota is exhausted. */
195
+ onQuotaExceeded?: OnQuotaExceededVerb;
196
+ /** Action for HTTP 401 / 403. Defaults to `'abort'` — never silently swap on auth failure. */
197
+ onAuthFailure?: OnAuthFailureVerb;
198
+ /** Action for sustained 5xx / DNS / "wall of unavailable". */
199
+ onProviderUnavailable?: OnProviderUnavailableVerb;
200
+ /** Action when the provider returned the source string unchanged. */
201
+ onIdentityOutput?: OnIdentityOutputVerb;
202
+ /**
203
+ * Action when a run can't finish all leaves (cap hit, abort verb fired, or interrupt).
204
+ * Step 10 of the plan wires this into a host hook.
205
+ */
206
+ onIncompleteRun?: OnIncompleteRunVerb;
207
+ /**
208
+ * Cross-provider attempts per leaf. Default = `providers.length` (one shot per provider in chain).
209
+ * On cap hit, the leaf is **flagged** (per `onIdentityOutput`) — the run is **never** aborted.
210
+ */
211
+ maxAttempts?: number;
212
+ /** Mid-run rescue prompt control (step 7). */
213
+ handoff?: TranslateHandoffMode;
214
+ };
215
+ /**
216
+ * Frozen defaults for {@link TranslatePolicy}. Mirrors `translate-policy (shipped)` §6.
217
+ * `maxAttempts` is intentionally absent here — it's resolved against `providers.length` at parse time.
218
+ *
219
+ * @remarks
220
+ * Step 4 of `translate-policy (shipped)`. Consumed by `parseI18nPruneConfig` /
221
+ * `defineConfig`'s policy merge and by step 5's resolver as the fallback for missing keys.
222
+ */
223
+ declare const TRANSLATE_POLICY_DEFAULTS: Readonly<Required<Omit<TranslatePolicy, 'maxAttempts'>>>;
224
+
225
+ /** Locale bundle paths and layout hints (`locales` config block). */
226
+ type LocalesFilesystemConfig$1 = {
227
+ source: string;
228
+ directory: string;
229
+ mode?: 'flat_file' | 'locale_directory';
230
+ structure?: 'locale_file' | 'locale_per_dir' | 'feature_bundle';
231
+ };
232
+
233
+ /**
234
+ * How JSON key paths that may be referenced only via partial/dynamic templates are treated
235
+ * for destructive or shape-changing operations (sync, cleanup, generate, …).
236
+ */
237
+ type UncertainKeyPolicy = 'protect' | 'allow' | 'warn_only';
238
+ /**
239
+ * Secondary signal: locale **string value** appears as a literal substring in `src/`
240
+ * (via ripgrep). Does not prove static key usage; orthogonal to key-path extraction.
241
+ */
242
+ type StringPresencePolicy = 'guard' | 'warn' | 'off';
243
+ /**
244
+ * Defaults merged with optional per-operation overrides (see `ReferenceConfig.commands` — property name mirrors config file keys).
245
+ */
246
+ type ReferenceDefaults = {
247
+ /**
248
+ * When false, translation calls inside comments do not contribute uncertain prefixes
249
+ * or runtime evidence (dynamic sites with `commented` / `isCommented`).
250
+ * @default false
251
+ */
252
+ treatCommentedCallSitesAsRuntime?: boolean;
253
+ /**
254
+ * When false, sites with `isSourceFile === false` are ignored for uncertainty.
255
+ * @default false
256
+ */
257
+ treatNonSourceFileSitesAsRuntime?: boolean;
258
+ /**
259
+ * `protect` — do not remove / do not generate resume candidates / keep extras on sync under uncertain prefixes.
260
+ * `allow` — ignore uncertain-prefix protection (risky).
261
+ * `warn_only` — same protection as `protect` for now; reserved for softer UX.
262
+ * @default 'protect'
263
+ */
264
+ uncertainKeyPolicy?: UncertainKeyPolicy;
265
+ /**
266
+ * `guard` — skip cleanup removal if rg finds the locale string in src.
267
+ * `warn` — log rg hit locations but still allow removal when uncertain policy allows.
268
+ * `off` — do not run rg.
269
+ * @default 'guard'
270
+ */
271
+ stringPresence?: StringPresencePolicy;
272
+ /** Max rg JSON matches recorded per key (performance). @default 5 */
273
+ stringPresenceMaxHitsPerKey?: number;
274
+ /**
275
+ * When true (default), `generate --resume` skips paths matching `policies.preserve`. Other operations ignore this.
276
+ * @default true
277
+ */
278
+ respectPreserve?: boolean;
279
+ };
280
+ /**
281
+ * Override block for one **`reference.commands`** entry (same fields as **`ReferenceDefaults`**).
282
+ * Type name uses “Command” because keys mirror config JSON — not every CLI subcommand.
283
+ */
284
+ type ReferenceCommandOverrides = ReferenceDefaults;
285
+ /**
286
+ * Per-operation entries under **`reference.commands`** in config.
287
+ * Known keys: **`cleanup`**, **`sync`**, **`generate`** — each overrides **`defaults`** for that operation only.
288
+ */
289
+ type ReferenceCommands = {
290
+ /** Reference policy when running **`i18nprune cleanup`**. */
291
+ cleanup?: ReferenceCommandOverrides;
292
+ /** Reference policy when running **`i18nprune sync`**. */
293
+ sync?: ReferenceCommandOverrides;
294
+ /** Reference policy when running **`i18nprune generate`**. */
295
+ generate?: ReferenceCommandOverrides;
296
+ };
297
+ /** Root **`reference`** namespace: uncertainty + string-presence defaults and per-operation overrides. */
298
+ type ReferenceConfig = {
299
+ /** Baseline policy merged before any **`commands.*`** block. */
300
+ defaults?: ReferenceDefaults;
301
+ /**
302
+ * Per-operation overrides (**`cleanup`**, **`sync`**, **`generate`**) deep-merged onto **`defaults`**.
303
+ * Unknown keys are preserved for forward compatibility.
304
+ */
305
+ commands?: ReferenceCommands & Record<string, ReferenceCommandOverrides | undefined>;
306
+ };
307
+ /**
308
+ * Fully merged reference policy for one operation (defaults + optional **`commands.<op>`** slice).
309
+ */
310
+ type EffectiveReferenceConfig = Required<Pick<ReferenceDefaults, 'treatCommentedCallSitesAsRuntime' | 'treatNonSourceFileSitesAsRuntime' | 'uncertainKeyPolicy' | 'stringPresence' | 'stringPresenceMaxHitsPerKey' | 'respectPreserve'>>;
311
+ /** Config slice required to resolve effective reference policy (matches `I18nPruneConfig.reference`). */
312
+ type ReferenceConfigSource = {
313
+ reference?: ReferenceConfig;
314
+ };
315
+ /**
316
+ * Aggregated key-path evidence from keySites + dynamic scans for policy-driven operations.
317
+ */
318
+ type KeyReferenceContext = {
319
+ /** Literal + template_resolved keys (after optional per-file comment filtering in orchestrate). */
320
+ provenKeys: ReadonlySet<string>;
321
+ /**
322
+ * Dotted key path prefixes that may cover runtime-only suffixes (`${…}`, partial templates).
323
+ */
324
+ uncertainPrefixes: string[];
325
+ };
326
+
327
+ /**
328
+ * Fine-grained exclusions for parity / “still matches source?” checks (**`quality`**, **`generate --resume`**, …).
329
+ */
330
+ type ParityPolicy = {
331
+ /** Dotted keys ignored when comparing target vs source for drift / source-identical hints. */
332
+ excludeKeys?: string[];
333
+ /** Key prefixes ignored for the same checks. */
334
+ excludePrefixes?: string[];
335
+ /** Concrete string values ignored (e.g. placeholder **`TODO`**). */
336
+ excludeValues?: string[];
337
+ };
338
+
339
+ /**
340
+ * Dotted key paths that must always be copied verbatim from the **source** locale during merge/sync
341
+ * (and are respected by **`generate --resume`** when **`respectPreserve`** is on).
342
+ */
343
+ type PreservePolicy = {
344
+ /** Exact dotted keys to preserve (e.g. **`brand.tagline`**). */
345
+ copyKeys?: string[];
346
+ /** Any key whose path starts with one of these prefixes is preserved. */
347
+ copyPrefixes?: string[];
348
+ };
349
+
350
+ /** Supported auto-patch recipe (today: lazy **`loader_generated`** bundle). */
351
+ type PatchingRecipeId = 'loader_generated';
352
+ /** Commands that may trigger patching side effects after locale writes. */
353
+ type PatchingCommandName = 'generate' | 'sync' | 'locales-delete';
354
+ /** Whether patching is upserting locale rows or removing them from generated config. */
355
+ type PatchingAction = 'upsert_locales' | 'delete_locales';
356
+ /**
357
+ * **`warn_skip`** — log/skip on analyzer issues; **`strict`** — fail the run when auto-patch preconditions break.
358
+ */
359
+ type PatchingMode = 'warn_skip' | 'strict';
360
+ /** User-facing **`patching`** block in **`i18nprune` config** (optional; default off). */
361
+ type PatchingConfigInput = {
362
+ /** Master switch: when **`false`** or omitted, **`patch`** / **`--patch`** no-op aside from diagnostics. */
363
+ enabled?: boolean;
364
+ /** Which patch strategy to run (only **`loader_generated`** today). */
365
+ recipe?: PatchingRecipeId;
366
+ /** Path to the CLI-owned generated loader module (typically `src/i18n/loaders.generated.ts`). */
367
+ loaderPath?: string;
368
+ /** App-owned **`config.json`** (or similar) listing locale codes for the loader. */
369
+ configPath?: string;
370
+ /**
371
+ * Directory of locale `*.json` files, expressed **relative to the directory that contains your
372
+ * `i18nprune` config file** (the CLI passes that as `projectRoot`, usually the repo root). Use the same path
373
+ * segment as top-level **`localesDir`** when locales live beside **`src`** — typically **`locales`**.
374
+ *
375
+ * **`import()` inside `loaders.generated.ts`** is always rewritten as a path **relative to the directory
376
+ * containing `loaderPath`** (e.g. **`../../locales`** when **`loaders.generated.ts`** sits under **`src/i18n/`**
377
+ * and **`localeJsonImportBase`** is **`locales`** at repo root). You configure the locales root here; core
378
+ * derives the literal import prefix automatically.
379
+ *
380
+ * Hosts/tests that omit **`projectRoot`** resolve this segment **relative to **`loaderPath`**’s directory** instead.
381
+ */
382
+ localeJsonImportBase?: string;
383
+ /** Max bytes read per patched file before skipping (guard against huge accidental paths). */
384
+ sizeLimitBytes?: number;
385
+ /** Analyzer / applier strictness when preconditions fail. */
386
+ mode?: PatchingMode;
387
+ };
388
+ type ResolvedPatchingConfig = {
389
+ enabled: boolean;
390
+ recipe: PatchingRecipeId;
391
+ loaderPath: string;
392
+ configPath: string;
393
+ localeJsonImportBase: string;
394
+ sizeLimitBytes: number;
395
+ mode: PatchingMode;
396
+ };
397
+ type PatchingSkipReason = 'disabled' | 'missing_path' | 'not_found' | 'not_file' | 'too_large' | 'unsupported_pattern' | 'parse_error' | 'no_changes' | 'apply_failed' | 'strict_mode_failure';
398
+ type PatchingDiagnostic = {
399
+ severity: 'info' | 'warn' | 'error';
400
+ code: string;
401
+ message: string;
402
+ docPath?: string;
403
+ path?: string;
404
+ };
405
+ type LocaleDirection = 'ltr' | 'rtl';
406
+ type PatchingLocaleRecord = {
407
+ code: string;
408
+ englishName: string;
409
+ nativeName: string;
410
+ direction: LocaleDirection;
411
+ [extra: string]: unknown;
412
+ };
413
+ /** Catalog vs config row mismatch (resolver output). */
414
+ type LocaleConfigMismatch = {
415
+ code: string;
416
+ field: 'englishName' | 'nativeName' | 'direction';
417
+ current: string;
418
+ recommended: string;
419
+ };
420
+ /** Result of {@link resolvePatchingConfigLocales} (patching `config.json` locale metadata). */
421
+ type ResolvePatchingLocalesResult = {
422
+ ok: false;
423
+ error: 'parse_error' | 'invalid_schema';
424
+ message: string;
425
+ } | {
426
+ ok: true;
427
+ nextConfigText: string;
428
+ autofilled: Array<{
429
+ code: string;
430
+ field: 'englishName' | 'nativeName' | 'direction';
431
+ value: string;
432
+ }>;
433
+ mismatches: LocaleConfigMismatch[];
434
+ changed: boolean;
435
+ };
436
+ /**
437
+ * Summary for hosts that apply locale-row metadata repair to patching `config.json`
438
+ * (CLI wraps with logging / prompts; values align with {@link resolvePatchingConfigLocales} failures).
439
+ */
440
+ type RepairPatchingConfigLocalesResult = {
441
+ detectedCount: number;
442
+ autofilledCount: number;
443
+ correctedCount: number;
444
+ skipped: boolean;
445
+ metadataRepairBlocked?: Extract<ResolvePatchingLocalesResult, {
446
+ ok: false;
447
+ }>['error'];
448
+ };
449
+ type PatchingAnalyzeOutput = {
450
+ config: ResolvedPatchingConfig;
451
+ localeRecords: PatchingLocaleRecord[];
452
+ configOnlyCodes: string[];
453
+ fileOnlyCodes: string[];
454
+ diagnostics: PatchingDiagnostic[];
455
+ hasError: boolean;
456
+ canAutoPatch: boolean;
457
+ };
458
+ type PatchingFileEdit = {
459
+ path: string;
460
+ before: string;
461
+ after: string;
462
+ kind: 'loader' | 'config' | 'generated';
463
+ };
464
+ type PatchingPlan = {
465
+ recipe: PatchingRecipeId;
466
+ action: PatchingAction;
467
+ changedLocaleCodes: string[];
468
+ edits: PatchingFileEdit[];
469
+ };
470
+ type PatchingRuntimePorts = {
471
+ fs: RuntimeFsPort;
472
+ path: RuntimePathPort;
473
+ };
474
+ /** How generated loaders import locale JSON for a layout mode. */
475
+ type PatchingLocaleImportSpec = {
476
+ kind: 'flat_file';
477
+ } | {
478
+ kind: 'locale_per_dir';
479
+ segmentBasenames: readonly string[];
480
+ } | {
481
+ kind: 'feature_bundle';
482
+ featureBasenames: readonly string[];
483
+ };
484
+ type PatchingResult = {
485
+ ok: boolean;
486
+ applied: boolean;
487
+ skipped: boolean;
488
+ recipe?: PatchingRecipeId;
489
+ action?: PatchingAction;
490
+ changedFiles: string[];
491
+ skipReason?: PatchingSkipReason;
492
+ diagnostics: PatchingDiagnostic[];
493
+ };
494
+
495
+ /**
496
+ * Zod schema for `i18nprune` project config. Field `.describe()` text is surfaced in parse errors
497
+ * and documents the runtime shape of `I18nPruneConfig`.
498
+ */
499
+
500
+ /** Locale bundle paths and optional storage layout (flat files today; directory topologies later). */
501
+ declare const localesFilesystemSchema: z.ZodObject<{
502
+ source: z.ZodString;
503
+ directory: z.ZodString;
504
+ mode: z.ZodOptional<z.ZodEnum<{
505
+ flat_file: "flat_file";
506
+ locale_directory: "locale_directory";
507
+ }>>;
508
+ structure: z.ZodOptional<z.ZodEnum<{
509
+ locale_file: "locale_file";
510
+ locale_per_dir: "locale_per_dir";
511
+ feature_bundle: "feature_bundle";
512
+ }>>;
513
+ }, z.core.$strict>;
514
+ type LocalesFilesystemConfig = z.infer<typeof localesFilesystemSchema>;
515
+ declare const configSchema: z.ZodObject<{
516
+ locales: z.ZodObject<{
517
+ source: z.ZodString;
518
+ directory: z.ZodString;
519
+ mode: z.ZodOptional<z.ZodEnum<{
520
+ flat_file: "flat_file";
521
+ locale_directory: "locale_directory";
522
+ }>>;
523
+ structure: z.ZodOptional<z.ZodEnum<{
524
+ locale_file: "locale_file";
525
+ locale_per_dir: "locale_per_dir";
526
+ feature_bundle: "feature_bundle";
527
+ }>>;
528
+ }, z.core.$strict>;
529
+ src: z.ZodString;
530
+ functions: z.ZodArray<z.ZodString>;
531
+ exclude: z.ZodOptional<z.ZodObject<{
532
+ preset: z.ZodOptional<z.ZodEnum<{
533
+ production: "production";
534
+ }>>;
535
+ dirs: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodCustom<RegExp, RegExp>]>>>;
536
+ files: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodCustom<RegExp, RegExp>]>>>;
537
+ extensions: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodCustom<RegExp, RegExp>]>>>;
538
+ patterns: z.ZodOptional<z.ZodArray<z.ZodCustom<RegExp, RegExp>>>;
539
+ useDefaultSkip: z.ZodOptional<z.ZodBoolean>;
540
+ }, z.core.$strict>>;
541
+ output: z.ZodOptional<z.ZodObject<{
542
+ list: z.ZodOptional<z.ZodObject<{
543
+ top: z.ZodOptional<z.ZodNumber>;
544
+ full: z.ZodOptional<z.ZodBoolean>;
545
+ maxCap: z.ZodOptional<z.ZodNumber>;
546
+ }, z.core.$strict>>;
547
+ }, z.core.$strict>>;
548
+ scanner: z.ZodOptional<z.ZodObject<{
549
+ mode: z.ZodOptional<z.ZodEnum<{
550
+ serial: "serial";
551
+ concurrent: "concurrent";
552
+ auto: "auto";
553
+ }>>;
554
+ concurrency: z.ZodOptional<z.ZodNumber>;
555
+ hardCap: z.ZodOptional<z.ZodNumber>;
556
+ }, z.core.$strict>>;
557
+ cache: z.ZodOptional<z.ZodObject<{
558
+ enabled: z.ZodOptional<z.ZodBoolean>;
559
+ dir: z.ZodOptional<z.ZodString>;
560
+ profile: z.ZodOptional<z.ZodEnum<{
561
+ safe: "safe";
562
+ balanced: "balanced";
563
+ fast: "fast";
564
+ }>>;
565
+ mode: z.ZodOptional<z.ZodEnum<{
566
+ readWrite: "readWrite";
567
+ readOnly: "readOnly";
568
+ }>>;
569
+ rebuild: z.ZodOptional<z.ZodEnum<{
570
+ partial: "partial";
571
+ full: "full";
572
+ }>>;
573
+ fullRescanThresholdPercent: z.ZodOptional<z.ZodNumber>;
574
+ }, z.core.$strict>>;
575
+ policies: z.ZodOptional<z.ZodObject<{
576
+ preserve: z.ZodOptional<z.ZodObject<{
577
+ copyKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
578
+ copyPrefixes: z.ZodOptional<z.ZodArray<z.ZodString>>;
579
+ }, z.core.$strip>>;
580
+ parity: z.ZodOptional<z.ZodObject<{
581
+ excludeKeys: z.ZodOptional<z.ZodArray<z.ZodString>>;
582
+ excludePrefixes: z.ZodOptional<z.ZodArray<z.ZodString>>;
583
+ excludeValues: z.ZodOptional<z.ZodArray<z.ZodString>>;
584
+ }, z.core.$strip>>;
585
+ }, z.core.$strip>>;
586
+ reference: z.ZodOptional<z.ZodObject<{
587
+ defaults: z.ZodOptional<z.ZodObject<{
588
+ treatCommentedCallSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
589
+ treatNonSourceFileSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
590
+ uncertainKeyPolicy: z.ZodOptional<z.ZodEnum<{
591
+ protect: "protect";
592
+ allow: "allow";
593
+ warn_only: "warn_only";
594
+ }>>;
595
+ stringPresence: z.ZodOptional<z.ZodEnum<{
596
+ off: "off";
597
+ guard: "guard";
598
+ warn: "warn";
599
+ }>>;
600
+ stringPresenceMaxHitsPerKey: z.ZodOptional<z.ZodNumber>;
601
+ respectPreserve: z.ZodOptional<z.ZodBoolean>;
602
+ }, z.core.$loose>>;
603
+ commands: z.ZodOptional<z.ZodObject<{
604
+ cleanup: z.ZodOptional<z.ZodObject<{
605
+ treatCommentedCallSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
606
+ treatNonSourceFileSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
607
+ uncertainKeyPolicy: z.ZodOptional<z.ZodEnum<{
608
+ protect: "protect";
609
+ allow: "allow";
610
+ warn_only: "warn_only";
611
+ }>>;
612
+ stringPresence: z.ZodOptional<z.ZodEnum<{
613
+ off: "off";
614
+ guard: "guard";
615
+ warn: "warn";
616
+ }>>;
617
+ stringPresenceMaxHitsPerKey: z.ZodOptional<z.ZodNumber>;
618
+ respectPreserve: z.ZodOptional<z.ZodBoolean>;
619
+ }, z.core.$loose>>;
620
+ sync: z.ZodOptional<z.ZodObject<{
621
+ treatCommentedCallSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
622
+ treatNonSourceFileSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
623
+ uncertainKeyPolicy: z.ZodOptional<z.ZodEnum<{
624
+ protect: "protect";
625
+ allow: "allow";
626
+ warn_only: "warn_only";
627
+ }>>;
628
+ stringPresence: z.ZodOptional<z.ZodEnum<{
629
+ off: "off";
630
+ guard: "guard";
631
+ warn: "warn";
632
+ }>>;
633
+ stringPresenceMaxHitsPerKey: z.ZodOptional<z.ZodNumber>;
634
+ respectPreserve: z.ZodOptional<z.ZodBoolean>;
635
+ }, z.core.$loose>>;
636
+ generate: z.ZodOptional<z.ZodObject<{
637
+ treatCommentedCallSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
638
+ treatNonSourceFileSitesAsRuntime: z.ZodOptional<z.ZodBoolean>;
639
+ uncertainKeyPolicy: z.ZodOptional<z.ZodEnum<{
640
+ protect: "protect";
641
+ allow: "allow";
642
+ warn_only: "warn_only";
643
+ }>>;
644
+ stringPresence: z.ZodOptional<z.ZodEnum<{
645
+ off: "off";
646
+ guard: "guard";
647
+ warn: "warn";
648
+ }>>;
649
+ stringPresenceMaxHitsPerKey: z.ZodOptional<z.ZodNumber>;
650
+ respectPreserve: z.ZodOptional<z.ZodBoolean>;
651
+ }, z.core.$loose>>;
652
+ }, z.core.$loose>>;
653
+ }, z.core.$loose>>;
654
+ localeLeaves: z.ZodOptional<z.ZodObject<{
655
+ mode: z.ZodOptional<z.ZodEnum<{
656
+ legacy_string: "legacy_string";
657
+ structured: "structured";
658
+ }>>;
659
+ sync: z.ZodOptional<z.ZodObject<{
660
+ stripMetadata: z.ZodOptional<z.ZodBoolean>;
661
+ }, z.core.$strict>>;
662
+ }, z.core.$strict>>;
663
+ patching: z.ZodOptional<z.ZodObject<{
664
+ enabled: z.ZodOptional<z.ZodBoolean>;
665
+ recipe: z.ZodOptional<z.ZodEnum<{
666
+ loader_generated: "loader_generated";
667
+ }>>;
668
+ loaderPath: z.ZodOptional<z.ZodString>;
669
+ configPath: z.ZodOptional<z.ZodString>;
670
+ localeJsonImportBase: z.ZodOptional<z.ZodString>;
671
+ sizeLimitBytes: z.ZodOptional<z.ZodNumber>;
672
+ mode: z.ZodOptional<z.ZodEnum<{
673
+ strict: "strict";
674
+ warn_skip: "warn_skip";
675
+ }>>;
676
+ }, z.core.$strict>>;
677
+ missing: z.ZodOptional<z.ZodObject<{
678
+ placeholder: z.ZodOptional<z.ZodString>;
679
+ }, z.core.$strict>>;
680
+ translate: z.ZodOptional<z.ZodPipe<z.ZodObject<{
681
+ primary: z.ZodEnum<{
682
+ google: "google";
683
+ mymemory: "mymemory";
684
+ deepl: "deepl";
685
+ libre: "libre";
686
+ llm: "llm";
687
+ }>;
688
+ providers: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
689
+ id: z.ZodLiteral<"google">;
690
+ enabled: z.ZodOptional<z.ZodBoolean>;
691
+ rateLimit: z.ZodOptional<z.ZodPipe<z.ZodObject<{
692
+ maxConcurrency: z.ZodOptional<z.ZodNumber>;
693
+ rpm: z.ZodOptional<z.ZodNumber>;
694
+ rps: z.ZodOptional<z.ZodNumber>;
695
+ intervalMs: z.ZodOptional<z.ZodNumber>;
696
+ }, z.core.$strict>, z.ZodTransform<{
697
+ maxConcurrency: number | undefined;
698
+ rpm: number | undefined;
699
+ rps: number | undefined;
700
+ intervalMs: number | undefined;
701
+ }, {
702
+ maxConcurrency?: number | undefined;
703
+ rpm?: number | undefined;
704
+ rps?: number | undefined;
705
+ intervalMs?: number | undefined;
706
+ }>>>;
707
+ }, z.core.$strict>, z.ZodObject<{
708
+ id: z.ZodLiteral<"mymemory">;
709
+ enabled: z.ZodOptional<z.ZodBoolean>;
710
+ contactEmail: z.ZodOptional<z.ZodString>;
711
+ rateLimit: z.ZodOptional<z.ZodPipe<z.ZodObject<{
712
+ maxConcurrency: z.ZodOptional<z.ZodNumber>;
713
+ rpm: z.ZodOptional<z.ZodNumber>;
714
+ rps: z.ZodOptional<z.ZodNumber>;
715
+ intervalMs: z.ZodOptional<z.ZodNumber>;
716
+ }, z.core.$strict>, z.ZodTransform<{
717
+ maxConcurrency: number | undefined;
718
+ rpm: number | undefined;
719
+ rps: number | undefined;
720
+ intervalMs: number | undefined;
721
+ }, {
722
+ maxConcurrency?: number | undefined;
723
+ rpm?: number | undefined;
724
+ rps?: number | undefined;
725
+ intervalMs?: number | undefined;
726
+ }>>>;
727
+ }, z.core.$strict>, z.ZodObject<{
728
+ id: z.ZodLiteral<"libre">;
729
+ enabled: z.ZodOptional<z.ZodBoolean>;
730
+ baseUrl: z.ZodOptional<z.ZodString>;
731
+ rateLimit: z.ZodOptional<z.ZodPipe<z.ZodObject<{
732
+ maxConcurrency: z.ZodOptional<z.ZodNumber>;
733
+ rpm: z.ZodOptional<z.ZodNumber>;
734
+ rps: z.ZodOptional<z.ZodNumber>;
735
+ intervalMs: z.ZodOptional<z.ZodNumber>;
736
+ }, z.core.$strict>, z.ZodTransform<{
737
+ maxConcurrency: number | undefined;
738
+ rpm: number | undefined;
739
+ rps: number | undefined;
740
+ intervalMs: number | undefined;
741
+ }, {
742
+ maxConcurrency?: number | undefined;
743
+ rpm?: number | undefined;
744
+ rps?: number | undefined;
745
+ intervalMs?: number | undefined;
746
+ }>>>;
747
+ }, z.core.$strict>, z.ZodObject<{
748
+ id: z.ZodLiteral<"deepl">;
749
+ enabled: z.ZodOptional<z.ZodBoolean>;
750
+ apiKey: z.ZodOptional<z.ZodString>;
751
+ rateLimit: z.ZodOptional<z.ZodPipe<z.ZodObject<{
752
+ maxConcurrency: z.ZodOptional<z.ZodNumber>;
753
+ rpm: z.ZodOptional<z.ZodNumber>;
754
+ rps: z.ZodOptional<z.ZodNumber>;
755
+ intervalMs: z.ZodOptional<z.ZodNumber>;
756
+ }, z.core.$strict>, z.ZodTransform<{
757
+ maxConcurrency: number | undefined;
758
+ rpm: number | undefined;
759
+ rps: number | undefined;
760
+ intervalMs: number | undefined;
761
+ }, {
762
+ maxConcurrency?: number | undefined;
763
+ rpm?: number | undefined;
764
+ rps?: number | undefined;
765
+ intervalMs?: number | undefined;
766
+ }>>>;
767
+ }, z.core.$strict>, z.ZodObject<{
768
+ id: z.ZodLiteral<"llm">;
769
+ enabled: z.ZodOptional<z.ZodBoolean>;
770
+ apiKey: z.ZodOptional<z.ZodString>;
771
+ baseUrl: z.ZodOptional<z.ZodString>;
772
+ model: z.ZodOptional<z.ZodString>;
773
+ rateLimit: z.ZodOptional<z.ZodPipe<z.ZodObject<{
774
+ maxConcurrency: z.ZodOptional<z.ZodNumber>;
775
+ rpm: z.ZodOptional<z.ZodNumber>;
776
+ rps: z.ZodOptional<z.ZodNumber>;
777
+ intervalMs: z.ZodOptional<z.ZodNumber>;
778
+ }, z.core.$strict>, z.ZodTransform<{
779
+ maxConcurrency: number | undefined;
780
+ rpm: number | undefined;
781
+ rps: number | undefined;
782
+ intervalMs: number | undefined;
783
+ }, {
784
+ maxConcurrency?: number | undefined;
785
+ rpm?: number | undefined;
786
+ rps?: number | undefined;
787
+ intervalMs?: number | undefined;
788
+ }>>>;
789
+ }, z.core.$strict>], "id">>;
790
+ policy: z.ZodDefault<z.ZodObject<{
791
+ routing: z.ZodDefault<z.ZodEnum<{
792
+ auto: "auto";
793
+ single: "single";
794
+ }>>;
795
+ onRateLimit: z.ZodDefault<z.ZodEnum<{
796
+ retry: "retry";
797
+ backoff: "backoff";
798
+ fallback: "fallback";
799
+ abort: "abort";
800
+ }>>;
801
+ onTransientFailure: z.ZodDefault<z.ZodEnum<{
802
+ retry: "retry";
803
+ fallback: "fallback";
804
+ abort: "abort";
805
+ }>>;
806
+ onQuotaExceeded: z.ZodDefault<z.ZodEnum<{
807
+ fallback: "fallback";
808
+ prompt: "prompt";
809
+ abort: "abort";
810
+ }>>;
811
+ onAuthFailure: z.ZodDefault<z.ZodEnum<{
812
+ prompt: "prompt";
813
+ abort: "abort";
814
+ }>>;
815
+ onProviderUnavailable: z.ZodDefault<z.ZodEnum<{
816
+ fallback: "fallback";
817
+ abort: "abort";
818
+ }>>;
819
+ onIdentityOutput: z.ZodDefault<z.ZodEnum<{
820
+ fallback: "fallback";
821
+ abort: "abort";
822
+ flag: "flag";
823
+ }>>;
824
+ onIncompleteRun: z.ZodDefault<z.ZodEnum<{
825
+ confirm: "confirm";
826
+ write: "write";
827
+ discard: "discard";
828
+ }>>;
829
+ maxAttempts: z.ZodOptional<z.ZodNumber>;
830
+ handoff: z.ZodDefault<z.ZodEnum<{
831
+ auto: "auto";
832
+ on: "on";
833
+ off: "off";
834
+ }>>;
835
+ }, z.core.$strict>>;
836
+ workers: z.ZodOptional<z.ZodNumber>;
837
+ }, z.core.$strict>, z.ZodTransform<{
838
+ primary: "google" | "mymemory" | "deepl" | "libre" | "llm";
839
+ providers: ({
840
+ id: "google";
841
+ enabled?: boolean | undefined;
842
+ rateLimit?: {
843
+ maxConcurrency: number | undefined;
844
+ rpm: number | undefined;
845
+ rps: number | undefined;
846
+ intervalMs: number | undefined;
847
+ } | undefined;
848
+ } | {
849
+ id: "mymemory";
850
+ enabled?: boolean | undefined;
851
+ contactEmail?: string | undefined;
852
+ rateLimit?: {
853
+ maxConcurrency: number | undefined;
854
+ rpm: number | undefined;
855
+ rps: number | undefined;
856
+ intervalMs: number | undefined;
857
+ } | undefined;
858
+ } | {
859
+ id: "libre";
860
+ enabled?: boolean | undefined;
861
+ baseUrl?: string | undefined;
862
+ rateLimit?: {
863
+ maxConcurrency: number | undefined;
864
+ rpm: number | undefined;
865
+ rps: number | undefined;
866
+ intervalMs: number | undefined;
867
+ } | undefined;
868
+ } | {
869
+ id: "deepl";
870
+ enabled?: boolean | undefined;
871
+ apiKey?: string | undefined;
872
+ rateLimit?: {
873
+ maxConcurrency: number | undefined;
874
+ rpm: number | undefined;
875
+ rps: number | undefined;
876
+ intervalMs: number | undefined;
877
+ } | undefined;
878
+ } | {
879
+ id: "llm";
880
+ enabled?: boolean | undefined;
881
+ apiKey?: string | undefined;
882
+ baseUrl?: string | undefined;
883
+ model?: string | undefined;
884
+ rateLimit?: {
885
+ maxConcurrency: number | undefined;
886
+ rpm: number | undefined;
887
+ rps: number | undefined;
888
+ intervalMs: number | undefined;
889
+ } | undefined;
890
+ })[];
891
+ policy: {
892
+ maxAttempts: number;
893
+ routing: "auto" | "single";
894
+ onRateLimit: "retry" | "backoff" | "fallback" | "abort";
895
+ onTransientFailure: "retry" | "fallback" | "abort";
896
+ onQuotaExceeded: "fallback" | "prompt" | "abort";
897
+ onAuthFailure: "prompt" | "abort";
898
+ onProviderUnavailable: "fallback" | "abort";
899
+ onIdentityOutput: "fallback" | "abort" | "flag";
900
+ onIncompleteRun: "confirm" | "write" | "discard";
901
+ handoff: "auto" | "on" | "off";
902
+ };
903
+ workers: number;
904
+ }, {
905
+ primary: "google" | "mymemory" | "deepl" | "libre" | "llm";
906
+ providers: ({
907
+ id: "google";
908
+ enabled?: boolean | undefined;
909
+ rateLimit?: {
910
+ maxConcurrency: number | undefined;
911
+ rpm: number | undefined;
912
+ rps: number | undefined;
913
+ intervalMs: number | undefined;
914
+ } | undefined;
915
+ } | {
916
+ id: "mymemory";
917
+ enabled?: boolean | undefined;
918
+ contactEmail?: string | undefined;
919
+ rateLimit?: {
920
+ maxConcurrency: number | undefined;
921
+ rpm: number | undefined;
922
+ rps: number | undefined;
923
+ intervalMs: number | undefined;
924
+ } | undefined;
925
+ } | {
926
+ id: "libre";
927
+ enabled?: boolean | undefined;
928
+ baseUrl?: string | undefined;
929
+ rateLimit?: {
930
+ maxConcurrency: number | undefined;
931
+ rpm: number | undefined;
932
+ rps: number | undefined;
933
+ intervalMs: number | undefined;
934
+ } | undefined;
935
+ } | {
936
+ id: "deepl";
937
+ enabled?: boolean | undefined;
938
+ apiKey?: string | undefined;
939
+ rateLimit?: {
940
+ maxConcurrency: number | undefined;
941
+ rpm: number | undefined;
942
+ rps: number | undefined;
943
+ intervalMs: number | undefined;
944
+ } | undefined;
945
+ } | {
946
+ id: "llm";
947
+ enabled?: boolean | undefined;
948
+ apiKey?: string | undefined;
949
+ baseUrl?: string | undefined;
950
+ model?: string | undefined;
951
+ rateLimit?: {
952
+ maxConcurrency: number | undefined;
953
+ rpm: number | undefined;
954
+ rps: number | undefined;
955
+ intervalMs: number | undefined;
956
+ } | undefined;
957
+ })[];
958
+ policy: {
959
+ routing: "auto" | "single";
960
+ onRateLimit: "retry" | "backoff" | "fallback" | "abort";
961
+ onTransientFailure: "retry" | "fallback" | "abort";
962
+ onQuotaExceeded: "fallback" | "prompt" | "abort";
963
+ onAuthFailure: "prompt" | "abort";
964
+ onProviderUnavailable: "fallback" | "abort";
965
+ onIdentityOutput: "fallback" | "abort" | "flag";
966
+ onIncompleteRun: "confirm" | "write" | "discard";
967
+ handoff: "auto" | "on" | "off";
968
+ maxAttempts?: number | undefined;
969
+ };
970
+ workers?: number | undefined;
971
+ }>>>;
972
+ }, z.core.$strip>;
973
+ /**
974
+ * Direct **`z.infer`** of {@link configSchema}. Internal — used by **`schema/define.ts`** /
975
+ * **`defaults/app.ts`** to type the spread / merge bodies. Public callers should use the friendly
976
+ * **`I18nPruneConfig`** from **`@i18nprune/core/config`** (or the root barrel).
977
+ *
978
+ * The two shapes are runtime-identical; the friendly version retypes **`reference`**,
979
+ * **`translate`**, and **`policies`** with stricter authoring-time interfaces.
980
+ */
981
+ type I18nPruneConfigParsed = z.infer<typeof configSchema>;
982
+ /** Optional per-backend rate-limit knobs (merged with provider defaults when omitted). */
983
+ type TranslateRateLimitConfig = {
984
+ maxConcurrency?: number;
985
+ rpm?: number;
986
+ rps?: number;
987
+ intervalMs?: number;
988
+ };
989
+ type TranslateProviderRowGoogle = {
990
+ id: 'google';
991
+ enabled?: boolean;
992
+ rateLimit?: TranslateRateLimitConfig;
993
+ };
994
+ type TranslateProviderRowMymemory = {
995
+ id: 'mymemory';
996
+ enabled?: boolean;
997
+ contactEmail?: string;
998
+ rateLimit?: TranslateRateLimitConfig;
999
+ };
1000
+ type TranslateProviderRowLibre = {
1001
+ id: 'libre';
1002
+ enabled?: boolean;
1003
+ baseUrl?: string;
1004
+ rateLimit?: TranslateRateLimitConfig;
1005
+ };
1006
+ type TranslateProviderRowDeepL = {
1007
+ id: 'deepl';
1008
+ enabled?: boolean;
1009
+ apiKey?: string;
1010
+ rateLimit?: TranslateRateLimitConfig;
1011
+ };
1012
+ type TranslateProviderRowLlm = {
1013
+ id: 'llm';
1014
+ enabled?: boolean;
1015
+ apiKey?: string;
1016
+ baseUrl?: string;
1017
+ model?: string;
1018
+ rateLimit?: TranslateRateLimitConfig;
1019
+ };
1020
+ type TranslateProviderRow = TranslateProviderRowGoogle | TranslateProviderRowMymemory | TranslateProviderRowLibre | TranslateProviderRowDeepL | TranslateProviderRowLlm;
1021
+ type TranslateMaxWorkersConfig = number;
1022
+ type TranslatePolicyConfig = TranslatePolicy;
1023
+ type Policies = {
1024
+ preserve?: PreservePolicy;
1025
+ parity?: ParityPolicy;
1026
+ };
1027
+ type LocaleLeavesConfig = {
1028
+ mode?: 'structured' | 'legacy_string';
1029
+ sync?: {
1030
+ stripMetadata?: boolean;
1031
+ };
1032
+ };
1033
+ type MissingCommandConfig = {
1034
+ placeholder?: string;
1035
+ };
1036
+ type OutputListConfig = {
1037
+ top?: number;
1038
+ full?: boolean;
1039
+ maxCap?: number;
1040
+ };
1041
+ type OutputConfig = {
1042
+ list?: OutputListConfig;
1043
+ };
1044
+ type CacheConfig = {
1045
+ enabled?: boolean;
1046
+ dir?: string;
1047
+ mode?: 'readWrite' | 'readOnly';
1048
+ };
1049
+ type PatchingConfig = PatchingConfigInput;
1050
+ type TranslateConfig = {
1051
+ primary: TranslationProviderId;
1052
+ providers: TranslateProviderRow[];
1053
+ policy?: TranslatePolicyConfig;
1054
+ workers?: TranslateMaxWorkersConfig;
1055
+ };
1056
+ /**
1057
+ * Fully merged i18nprune project config (file + defaults + parse normalization).
1058
+ */
1059
+ type I18nPruneConfig = Omit<I18nPruneConfigParsed, 'reference' | 'translate' | 'policies'> & {
1060
+ locales: LocalesFilesystemConfig;
1061
+ src: string;
1062
+ functions: string[];
1063
+ output?: OutputConfig;
1064
+ cache?: CacheConfig;
1065
+ exclude?: ScanExcludeConfig;
1066
+ scanner?: ScannerConfigInput;
1067
+ policies?: Policies;
1068
+ reference?: ReferenceConfig;
1069
+ localeLeaves?: LocaleLeavesConfig;
1070
+ missing?: MissingCommandConfig;
1071
+ patching?: PatchingConfig;
1072
+ translate?: TranslateConfig;
1073
+ };
1074
+ /**
1075
+ * Thrown by **`parseI18nPruneConfig`** (and **`loadCoreConfigFromPath`**) when an input value
1076
+ * fails the zod schema. Carries the underlying **`zodError`** so callers can surface field-level
1077
+ * issues (CLI uses it to emit **`ConfigValidationError`** issue codes).
1078
+ */
1079
+ declare class ConfigValidationError extends Error {
1080
+ readonly zodError?: z.ZodError | undefined;
1081
+ readonly issueCode?: string | undefined;
1082
+ constructor(message: string, zodError?: z.ZodError | undefined, issueCode?: string | undefined);
1083
+ }
1084
+ /**
1085
+ * Recognize {@link ConfigValidationError} across bundle boundaries (CLI loads
1086
+ * `i18nprune/core/config` for `defineConfig` while handling errors from `dist/cli.js`).
1087
+ */
1088
+ declare function isConfigValidationError(err: unknown): err is ConfigValidationError;
1089
+ /**
1090
+ * Validate a raw object against the zod-backed config schema and return the public friendly
1091
+ * **`I18nPruneConfig`**. Throws **`ConfigValidationError`** on invalid input.
1092
+ *
1093
+ * Use this when accepting config from untrusted sources (REST, DB, CLI args, generated
1094
+ * fixtures). For files on disk prefer **`loadCoreConfigFromPath`** — it handles TS / JS
1095
+ * loaders, layering with **`DEFAULT_CONFIG`**, and warning collection on top of this primitive.
1096
+ *
1097
+ * The returned value drops straight into **`createCoreContext`** and **`createTranslateContext`**
1098
+ * with no further cast.
1099
+ *
1100
+ * @example
1101
+ * ```ts
1102
+ * import { parseI18nPruneConfig } from '@i18nprune/core';
1103
+ *
1104
+ * const config = parseI18nPruneConfig(await db.fetchProjectConfig(projectId));
1105
+ * const ctx = createCoreContext({ config, adapters, env, paths });
1106
+ * ```
1107
+ */
1108
+ declare function parseI18nPruneConfig(raw: unknown): I18nPruneConfig;
1109
+
1110
+ export { type OnIncompleteRunVerb as $, isConfigValidationError as A, localesFilesystemSchema as B, type CacheConfig as C, parseI18nPruneConfig as D, type EffectiveReferenceConfig as E, type LocaleSegmentSource as F, type ScanExcludeConfig as G, type TranslatePolicyVerb as H, type I18nPruneConfig as I, type PatchingCommandName as J, type PatchingAction as K, type LocalesFilesystemConfig as L, type MissingCommandConfig as M, type PatchingLocaleRecord as N, type OutputConfig as O, type ParityPolicy as P, type PatchingConfigInput as Q, type ResolveScannerConfigOptions as R, type StringPresencePolicy as S, type TranslatePolicy as T, type UncertainKeyPolicy as U, type PatchingRuntimePorts as V, type KeyReferenceContext as W, type LocaleConfigMismatch as X, type LocaleDirection as Y, type OnAuthFailureVerb as Z, type OnIdentityOutputVerb as _, type PreservePolicy as a, type OnProviderUnavailableVerb as a0, type OnQuotaExceededVerb as a1, type OnRateLimitVerb as a2, type OnTransientFailureVerb as a3, type PatchingAnalyzeOutput as a4, type PatchingDiagnostic as a5, type PatchingFileEdit as a6, type PatchingLocaleImportSpec as a7, type PatchingMode as a8, type PatchingPlan as a9, type PatchingRecipeId as aa, type PatchingResult as ab, type PatchingSkipReason as ac, type ReferenceConfigSource as ad, type RepairPatchingConfigLocalesResult as ae, type ResolvePatchingLocalesResult as af, type ResolvedPatchingConfig as ag, type ScanExcludePreset as ah, type ScanExcludeRule as ai, type ScannerExecutionMode as aj, TRANSLATE_POLICY_DEFAULTS as ak, type TranslateHandoffMode as al, type TranslateRoutingMode as am, type LocalesFilesystemConfig$1 as b, type LocaleLeafPathApi as c, type ScannerConfigInput as d, type ScannerConfigResolved as e, type I18nPruneConfigParsed as f, type ReferenceCommandOverrides as g, ConfigValidationError as h, type LocaleLeavesConfig as i, type OutputListConfig as j, type PatchingConfig as k, type Policies as l, type ReferenceCommands as m, type ReferenceConfig as n, type ReferenceDefaults as o, type TranslateConfig as p, type TranslateMaxWorkersConfig as q, type TranslatePolicyConfig as r, type TranslateProviderRow as s, type TranslateProviderRowDeepL as t, type TranslateProviderRowGoogle as u, type TranslateProviderRowLibre as v, type TranslateProviderRowLlm as w, type TranslateProviderRowMymemory as x, type TranslateRateLimitConfig as y, configSchema as z };