@vocoder/cli 0.15.0 → 0.16.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/dist/bin.mjs +184 -154
- package/dist/bin.mjs.map +1 -1
- package/dist/{chunk-62KCB6C6.mjs → chunk-IK4ZCESQ.mjs} +10 -168
- package/dist/chunk-IK4ZCESQ.mjs.map +1 -0
- package/dist/lib.d.mts +7 -7
- package/dist/lib.mjs +159 -2
- package/dist/lib.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-62KCB6C6.mjs.map +0 -1
package/dist/lib.d.mts
CHANGED
|
@@ -11,14 +11,12 @@ interface ExtractedString {
|
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Supported
|
|
14
|
+
* Supported industry classifications for an app.
|
|
15
15
|
* Set once in vocoder.config.ts; synced to App at extraction time.
|
|
16
|
+
* Used as a TM pool bucket key — matching values across orgs share cache entries.
|
|
16
17
|
* Cannot be edited from the dashboard — config file is the source of truth.
|
|
17
|
-
*
|
|
18
|
-
* Keep in sync with APP_INDUSTRIES in
|
|
19
|
-
* vocoder-app/lib/vocoder/translation/context-constants.ts.
|
|
20
18
|
*/
|
|
21
|
-
type
|
|
19
|
+
type Industry = "ecommerce" | "b2b_saas" | "healthcare" | "fintech" | "gaming" | "education" | "media" | "productivity" | "travel" | "legal" | "government" | "nonprofit" | "other";
|
|
22
20
|
/**
|
|
23
21
|
* Translation formality level.
|
|
24
22
|
* Can be set project-wide in vocoder.config.ts or overridden per-string
|
|
@@ -51,7 +49,9 @@ interface VocoderConfig {
|
|
|
51
49
|
* and to isolate cache entries by industry in the global translation cache.
|
|
52
50
|
* Synced to App at extraction time.
|
|
53
51
|
*/
|
|
54
|
-
|
|
52
|
+
industry?: Industry;
|
|
53
|
+
/** @deprecated Use `industry` */
|
|
54
|
+
appIndustry?: Industry;
|
|
55
55
|
/**
|
|
56
56
|
* Project-wide default formality level for translations.
|
|
57
57
|
* Can be overridden per-string via <T formality="..."> on the AI plan.
|
|
@@ -274,7 +274,7 @@ declare class VocoderAPI {
|
|
|
274
274
|
clientRunId?: string;
|
|
275
275
|
force?: boolean;
|
|
276
276
|
/** From vocoder.config.ts — synced to App on every push */
|
|
277
|
-
|
|
277
|
+
industry?: string;
|
|
278
278
|
}, repoIdentity?: RepoIdentityPayload): Promise<TranslationBatchResponse>;
|
|
279
279
|
/**
|
|
280
280
|
* Check translation status
|
package/dist/lib.mjs
CHANGED
|
@@ -7,17 +7,174 @@ import {
|
|
|
7
7
|
clearAuthData,
|
|
8
8
|
detectLocalEcosystem,
|
|
9
9
|
getPackagesToInstall,
|
|
10
|
-
getSetupSnippets,
|
|
11
10
|
loadVocoderConfig,
|
|
12
11
|
readAuthData,
|
|
13
12
|
verifyStoredAuth,
|
|
14
13
|
writeAuthData
|
|
15
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-IK4ZCESQ.mjs";
|
|
16
15
|
|
|
17
16
|
// ../config/src/index.ts
|
|
18
17
|
function defineConfig(config) {
|
|
19
18
|
return config;
|
|
20
19
|
}
|
|
20
|
+
|
|
21
|
+
// src/utils/setup-snippets.ts
|
|
22
|
+
function getSetupSnippets(params) {
|
|
23
|
+
const { framework, ecosystem, sourceLocale } = params;
|
|
24
|
+
return {
|
|
25
|
+
pluginStep: getPluginSnippet(framework, ecosystem),
|
|
26
|
+
providerStep: getProviderSnippet(ecosystem, sourceLocale),
|
|
27
|
+
wrapStep: getWrapSnippet(ecosystem),
|
|
28
|
+
whatsNext: "Push to a target branch to trigger translations."
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function getPluginSnippet(framework, ecosystem) {
|
|
32
|
+
switch (framework) {
|
|
33
|
+
case "nextjs":
|
|
34
|
+
return {
|
|
35
|
+
file: "next.config.ts",
|
|
36
|
+
code: `import { withVocoder } from '@vocoder/plugin/next';
|
|
37
|
+
|
|
38
|
+
export default withVocoder({
|
|
39
|
+
// your existing Next.js config
|
|
40
|
+
});`
|
|
41
|
+
};
|
|
42
|
+
case "vite":
|
|
43
|
+
case "remix":
|
|
44
|
+
return {
|
|
45
|
+
file: "vite.config.ts",
|
|
46
|
+
code: `import vocoder from '@vocoder/plugin/vite';
|
|
47
|
+
|
|
48
|
+
export default defineConfig({
|
|
49
|
+
plugins: [
|
|
50
|
+
vocoder(),
|
|
51
|
+
// your other plugins
|
|
52
|
+
],
|
|
53
|
+
});`
|
|
54
|
+
};
|
|
55
|
+
case "nuxt":
|
|
56
|
+
return {
|
|
57
|
+
file: "nuxt.config.ts",
|
|
58
|
+
code: `import vocoder from '@vocoder/plugin/vite';
|
|
59
|
+
|
|
60
|
+
export default defineNuxtConfig({
|
|
61
|
+
vite: {
|
|
62
|
+
plugins: [vocoder()],
|
|
63
|
+
},
|
|
64
|
+
});`
|
|
65
|
+
};
|
|
66
|
+
case "sveltekit":
|
|
67
|
+
return {
|
|
68
|
+
file: "vite.config.ts",
|
|
69
|
+
code: `import vocoder from '@vocoder/plugin/vite';
|
|
70
|
+
import { sveltekit } from '@sveltejs/kit/vite';
|
|
71
|
+
|
|
72
|
+
export default defineConfig({
|
|
73
|
+
plugins: [
|
|
74
|
+
sveltekit(),
|
|
75
|
+
vocoder(),
|
|
76
|
+
],
|
|
77
|
+
});`
|
|
78
|
+
};
|
|
79
|
+
case "gatsby":
|
|
80
|
+
return {
|
|
81
|
+
file: "gatsby-node.js",
|
|
82
|
+
code: `const vocoder = require('@vocoder/plugin/webpack');
|
|
83
|
+
|
|
84
|
+
exports.onCreateWebpackConfig = ({ actions }) => {
|
|
85
|
+
actions.setWebpackConfig({
|
|
86
|
+
plugins: [vocoder()],
|
|
87
|
+
});
|
|
88
|
+
};`
|
|
89
|
+
};
|
|
90
|
+
case "angular":
|
|
91
|
+
return null;
|
|
92
|
+
// Angular CLI doesn't expose plugin config easily
|
|
93
|
+
default:
|
|
94
|
+
if (ecosystem) {
|
|
95
|
+
return {
|
|
96
|
+
file: "your bundler config",
|
|
97
|
+
code: `// Vite
|
|
98
|
+
import vocoder from '@vocoder/plugin/vite';
|
|
99
|
+
// Webpack
|
|
100
|
+
const vocoder = require('@vocoder/plugin/webpack');
|
|
101
|
+
|
|
102
|
+
// Add vocoder() to your plugins array`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function getProviderSnippet(ecosystem, sourceLocale) {
|
|
109
|
+
switch (ecosystem) {
|
|
110
|
+
case "react":
|
|
111
|
+
return {
|
|
112
|
+
file: "your root layout or App component",
|
|
113
|
+
code: `import { VocoderProvider } from '@vocoder/react';
|
|
114
|
+
|
|
115
|
+
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
116
|
+
{children}
|
|
117
|
+
</VocoderProvider>`
|
|
118
|
+
};
|
|
119
|
+
case "vue":
|
|
120
|
+
return {
|
|
121
|
+
file: "your app entry",
|
|
122
|
+
code: `import { createVocoder } from '@vocoder/vue';
|
|
123
|
+
|
|
124
|
+
const vocoder = createVocoder({
|
|
125
|
+
defaultLocale: '${sourceLocale}',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
app.use(vocoder);`
|
|
129
|
+
};
|
|
130
|
+
case "svelte":
|
|
131
|
+
return {
|
|
132
|
+
file: "your root layout",
|
|
133
|
+
code: `<script>
|
|
134
|
+
import { VocoderProvider } from '@vocoder/svelte';
|
|
135
|
+
</script>
|
|
136
|
+
|
|
137
|
+
<VocoderProvider defaultLocale="${sourceLocale}">
|
|
138
|
+
<slot />
|
|
139
|
+
</VocoderProvider>`
|
|
140
|
+
};
|
|
141
|
+
default:
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function getWrapSnippet(ecosystem) {
|
|
146
|
+
switch (ecosystem) {
|
|
147
|
+
case "react":
|
|
148
|
+
return {
|
|
149
|
+
code: `import { T } from '@vocoder/react';
|
|
150
|
+
|
|
151
|
+
<T>Hello, world!</T>`
|
|
152
|
+
};
|
|
153
|
+
case "vue":
|
|
154
|
+
return {
|
|
155
|
+
code: `<template>
|
|
156
|
+
<T>Hello, world!</T>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script setup>
|
|
160
|
+
import { T } from '@vocoder/vue';
|
|
161
|
+
</script>`
|
|
162
|
+
};
|
|
163
|
+
case "svelte":
|
|
164
|
+
return {
|
|
165
|
+
code: `<script>
|
|
166
|
+
import { T } from '@vocoder/svelte';
|
|
167
|
+
</script>
|
|
168
|
+
|
|
169
|
+
<T>Hello, world!</T>`
|
|
170
|
+
};
|
|
171
|
+
default:
|
|
172
|
+
return {
|
|
173
|
+
code: `// Wrap translatable strings with <T>
|
|
174
|
+
<T>Hello, world!</T>`
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
21
178
|
export {
|
|
22
179
|
StringExtractor,
|
|
23
180
|
VocoderAPI,
|
package/dist/lib.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../config/src/index.ts"],"sourcesContent":["/**\n * Supported
|
|
1
|
+
{"version":3,"sources":["../../config/src/index.ts","../src/utils/setup-snippets.ts"],"sourcesContent":["/**\n * Supported industry classifications for an app.\n * Set once in vocoder.config.ts; synced to App at extraction time.\n * Used as a TM pool bucket key — matching values across orgs share cache entries.\n * Cannot be edited from the dashboard — config file is the source of truth.\n */\nexport type Industry =\n\t| \"ecommerce\"\n\t| \"b2b_saas\"\n\t| \"healthcare\"\n\t| \"fintech\"\n\t| \"gaming\"\n\t| \"education\"\n\t| \"media\"\n\t| \"productivity\"\n\t| \"travel\"\n\t| \"legal\"\n\t| \"government\"\n\t| \"nonprofit\"\n\t| \"other\";\n\n/** @deprecated Use `Industry` */\nexport type AppIndustry = Industry;\n\n/**\n * Translation formality level.\n * Can be set project-wide in vocoder.config.ts or overridden per-string\n * via <T formality=\"formal\"> (requires allowAiTranslations plan).\n */\nexport type Formality = \"formal\" | \"informal\" | \"neutral\";\n\nexport interface VocoderConfig {\n\t/**\n\t * Unique identifier for this app. Written by `vocoder init` — do not edit manually.\n\t * Used by the CLI to identify which app to update when syncing locales.\n\t */\n\tappId?: string;\n\t/** Glob patterns for files to extract strings from. */\n\tinclude?: string[];\n\t/** Glob patterns to exclude. */\n\texclude?: string[];\n\t/**\n\t * Git branches that trigger string extraction and translation.\n\t * Synced to the Vocoder dashboard on each push — change here to update.\n\t */\n\ttargetBranches?: string[];\n\t/**\n\t * Directory to write translated locale files after sync (optional).\n\t * If set, `vocoder sync` writes {locale}.json files to this path.\n\t */\n\tlocalesPath?: string;\n\t/**\n\t * The industry or domain of this application.\n\t * Used to improve translation quality for domain-specific terminology\n\t * and to isolate cache entries by industry in the global translation cache.\n\t * Synced to App at extraction time.\n\t */\n\tindustry?: Industry;\n\t/** @deprecated Use `industry` */\n\tappIndustry?: Industry;\n\t/**\n\t * Project-wide default formality level for translations.\n\t * Can be overridden per-string via <T formality=\"...\"> on the AI plan.\n\t * Synced to App at extraction time.\n\t */\n\tformality?: Formality;\n}\n\n/** Type helper for vocoder.config.ts — provides autocomplete and type checking. */\nexport function defineConfig(config: VocoderConfig): VocoderConfig {\n\treturn config;\n}\n\n// Canonical translation bundle format — defined in @vocoder/core and re-exported here\n// so consumers can import it from either package.\nexport type { VocoderTranslationData } from \"@vocoder/core\";\n","import type { DetectedEcosystem, DetectedFramework } from \"./detect-local.js\";\n\nexport interface SetupSnippets {\n\tpluginStep: { file: string; code: string } | null;\n\tproviderStep: { file: string; code: string } | null;\n\twrapStep: { code: string };\n\twhatsNext: string;\n}\n\n/**\n * Generate framework-specific setup snippets.\n */\nexport function getSetupSnippets(params: {\n\tframework: DetectedFramework;\n\tecosystem: DetectedEcosystem;\n\tsourceLocale: string;\n\ttargetBranches: string[];\n\tappDir?: string;\n}): SetupSnippets {\n\tconst { framework, ecosystem, sourceLocale } = params;\n\n\treturn {\n\t\tpluginStep: getPluginSnippet(framework, ecosystem),\n\t\tproviderStep: getProviderSnippet(ecosystem, sourceLocale),\n\t\twrapStep: getWrapSnippet(ecosystem),\n\t\twhatsNext: \"Push to a target branch to trigger translations.\",\n\t};\n}\n\nfunction getPluginSnippet(\n\tframework: DetectedFramework,\n\tecosystem: DetectedEcosystem,\n): { file: string; code: string } | null {\n\tswitch (framework) {\n\t\tcase \"nextjs\":\n\t\t\treturn {\n\t\t\t\tfile: \"next.config.ts\",\n\t\t\t\tcode: `import { withVocoder } from '@vocoder/plugin/next';\n\nexport default withVocoder({\n // your existing Next.js config\n});`,\n\t\t\t};\n\n\t\tcase \"vite\":\n\t\tcase \"remix\":\n\t\t\treturn {\n\t\t\t\tfile: \"vite.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\n\nexport default defineConfig({\n plugins: [\n vocoder(),\n // your other plugins\n ],\n});`,\n\t\t\t};\n\n\t\tcase \"nuxt\":\n\t\t\treturn {\n\t\t\t\tfile: \"nuxt.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\n\nexport default defineNuxtConfig({\n vite: {\n plugins: [vocoder()],\n },\n});`,\n\t\t\t};\n\n\t\tcase \"sveltekit\":\n\t\t\treturn {\n\t\t\t\tfile: \"vite.config.ts\",\n\t\t\t\tcode: `import vocoder from '@vocoder/plugin/vite';\nimport { sveltekit } from '@sveltejs/kit/vite';\n\nexport default defineConfig({\n plugins: [\n sveltekit(),\n vocoder(),\n ],\n});`,\n\t\t\t};\n\n\t\tcase \"gatsby\":\n\t\t\treturn {\n\t\t\t\tfile: \"gatsby-node.js\",\n\t\t\t\tcode: `const vocoder = require('@vocoder/plugin/webpack');\n\nexports.onCreateWebpackConfig = ({ actions }) => {\n actions.setWebpackConfig({\n plugins: [vocoder()],\n });\n};`,\n\t\t\t};\n\n\t\tcase \"angular\":\n\t\t\treturn null; // Angular CLI doesn't expose plugin config easily\n\n\t\tdefault:\n\t\t\t// No known framework — if they have React/Vue/Svelte, they likely have a bundler\n\t\t\t// but we can't guess which config file. Give generic advice.\n\t\t\tif (ecosystem) {\n\t\t\t\treturn {\n\t\t\t\t\tfile: \"your bundler config\",\n\t\t\t\t\tcode: `// Vite\nimport vocoder from '@vocoder/plugin/vite';\n// Webpack\nconst vocoder = require('@vocoder/plugin/webpack');\n\n// Add vocoder() to your plugins array`,\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn null;\n\t}\n}\n\nfunction getProviderSnippet(\n\tecosystem: DetectedEcosystem,\n\tsourceLocale: string,\n): { file: string; code: string } | null {\n\tswitch (ecosystem) {\n\t\tcase \"react\":\n\t\t\treturn {\n\t\t\t\tfile: \"your root layout or App component\",\n\t\t\t\tcode: `import { VocoderProvider } from '@vocoder/react';\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n {children}\n</VocoderProvider>`,\n\t\t\t};\n\n\t\tcase \"vue\":\n\t\t\treturn {\n\t\t\t\tfile: \"your app entry\",\n\t\t\t\tcode: `import { createVocoder } from '@vocoder/vue';\n\nconst vocoder = createVocoder({\n defaultLocale: '${sourceLocale}',\n});\n\napp.use(vocoder);`,\n\t\t\t};\n\n\t\tcase \"svelte\":\n\t\t\treturn {\n\t\t\t\tfile: \"your root layout\",\n\t\t\t\tcode: `<script>\n import { VocoderProvider } from '@vocoder/svelte';\n</script>\n\n<VocoderProvider defaultLocale=\"${sourceLocale}\">\n <slot />\n</VocoderProvider>`,\n\t\t\t};\n\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nfunction getWrapSnippet(ecosystem: DetectedEcosystem): { code: string } {\n\tswitch (ecosystem) {\n\t\tcase \"react\":\n\t\t\treturn {\n\t\t\t\tcode: `import { T } from '@vocoder/react';\n\n<T>Hello, world!</T>`,\n\t\t\t};\n\n\t\tcase \"vue\":\n\t\t\treturn {\n\t\t\t\tcode: `<template>\n <T>Hello, world!</T>\n</template>\n\n<script setup>\nimport { T } from '@vocoder/vue';\n</script>`,\n\t\t\t};\n\n\t\tcase \"svelte\":\n\t\t\treturn {\n\t\t\t\tcode: `<script>\n import { T } from '@vocoder/svelte';\n</script>\n\n<T>Hello, world!</T>`,\n\t\t\t};\n\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tcode: `// Wrap translatable strings with <T>\n<T>Hello, world!</T>`,\n\t\t\t};\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAqEO,SAAS,aAAa,QAAsC;AAClE,SAAO;AACR;;;AC3DO,SAAS,iBAAiB,QAMf;AACjB,QAAM,EAAE,WAAW,WAAW,aAAa,IAAI;AAE/C,SAAO;AAAA,IACN,YAAY,iBAAiB,WAAW,SAAS;AAAA,IACjD,cAAc,mBAAmB,WAAW,YAAY;AAAA,IACxD,UAAU,eAAe,SAAS;AAAA,IAClC,WAAW;AAAA,EACZ;AACD;AAEA,SAAS,iBACR,WACA,WACwC;AACxC,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,MAKP;AAAA,IAED,KAAK;AAAA,IACL,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA;AAAA,IAER;AAGC,UAAI,WAAW;AACd,eAAO;AAAA,UACN,MAAM;AAAA,UACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMP;AAAA,MACD;AACA,aAAO;AAAA,EACT;AACD;AAEA,SAAS,mBACR,WACA,cACwC;AACxC,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA,kCAEwB,YAAY;AAAA;AAAA;AAAA,MAG3C;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA,oBAGU,YAAY;AAAA;AAAA;AAAA;AAAA,MAI7B;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA,kCAIwB,YAAY;AAAA;AAAA;AAAA,MAG3C;AAAA,IAED;AACC,aAAO;AAAA,EACT;AACD;AAEA,SAAS,eAAe,WAAgD;AACvE,UAAQ,WAAW;AAAA,IAClB,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA,MAGP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOP;AAAA,IAED,KAAK;AACJ,aAAO;AAAA,QACN,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,MAKP;AAAA,IAED;AACC,aAAO;AAAA,QACN,MAAM;AAAA;AAAA,MAEP;AAAA,EACF;AACD;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vocoder/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "CLI tool for Vocoder translation workflow",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"tsup": "^8.0.0",
|
|
52
52
|
"typescript": "^5.4.0",
|
|
53
53
|
"vitest": "^1.0.0",
|
|
54
|
-
"@vocoder/extractor": "0.
|
|
55
|
-
"@vocoder/config": "0.
|
|
54
|
+
"@vocoder/extractor": "0.16.0",
|
|
55
|
+
"@vocoder/config": "0.16.0"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"node": ">=18"
|