@verbaly/next 0.19.0 → 0.20.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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["ReactVerbalyProvider","useVerbaly"],"sources":["../src/client.ts"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport {\n createElement,\n useCallback,\n useEffect,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { VerbalyProvider as ReactVerbalyProvider, useVerbaly } from '@verbaly/react';\nimport { switchLocale, type SwitchLocaleOptions } from 'verbaly';\nimport { createInstance, requestOptions, sourceLocale } from 'virtual:verbaly';\n\nexport { Trans, useLocale, useT, useVerbaly } from '@verbaly/react';\n\nexport interface VerbalyProviderProps {\n locale: string;\n messages?: Record<string, string>;\n children?: ReactNode;\n}\n\n// client side of the boundary: instance seeded synchronously from the serialized\n// catalog → hydration renders exactly the server's output, no flash\nexport function VerbalyProvider(props: VerbalyProviderProps): ReactElement {\n const [instance] = useState(() => {\n const created = createInstance({ locale: props.locale });\n if (props.messages && props.locale !== sourceLocale) {\n created.addMessages(props.locale, props.messages);\n }\n return created;\n });\n\n // server changed the locale out-of-band (cookie edit + refresh) follow it\n useEffect(() => {\n if (props.locale === instance.locale) return;\n if (props.messages) {\n instance.addMessages(props.locale, props.messages);\n instance.setLocale(props.locale);\n } else {\n void instance.loadLocale(props.locale).then(() => instance.setLocale(props.locale));\n }\n }, [props.locale, props.messages, instance]);\n\n return createElement(ReactVerbalyProvider, { instance }, props.children);\n}\n\n// core switchLocale (catalog → locale → cookie + <html lang>) + RSC re-render\nexport function useSwitchLocale(): (\n locale: string,\n options?: SwitchLocaleOptions,\n) => Promise<void> {\n const instance = useVerbaly();\n const router = useRouter();\n return useCallback(\n async (locale, options) => {\n await switchLocale(instance, locale, { cookie: requestOptions?.cookie, ...options });\n router.refresh();\n },\n [instance, router],\n );\n}\n"],"mappings":";;;;;;;AAyBA,SAAgB,gBAAgB,OAA2C;CACzE,MAAM,CAAC,YAAY,eAAe;EAChC,MAAM,UAAU,eAAe,EAAE,QAAQ,MAAM,OAAO,CAAC;EACvD,IAAI,MAAM,YAAY,MAAM,WAAW,cACrC,QAAQ,YAAY,MAAM,QAAQ,MAAM,QAAQ;EAElD,OAAO;CACT,CAAC;CAGD,gBAAgB;EACd,IAAI,MAAM,WAAW,SAAS,QAAQ;EACtC,IAAI,MAAM,UAAU;GAClB,SAAS,YAAY,MAAM,QAAQ,MAAM,QAAQ;GACjD,SAAS,UAAU,MAAM,MAAM;EACjC,OACE,SAAc,WAAW,MAAM,MAAM,CAAC,CAAC,WAAW,SAAS,UAAU,MAAM,MAAM,CAAC;CAEtF,GAAG;EAAC,MAAM;EAAQ,MAAM;EAAU;CAAQ,CAAC;CAE3C,OAAO,cAAcA,mBAAsB,EAAE,SAAS,GAAG,MAAM,QAAQ;AACzE;AAGA,SAAgB,kBAGG;CACjB,MAAM,WAAWC,aAAW;CAC5B,MAAM,SAAS,UAAU;CACzB,OAAO,YACL,OAAO,QAAQ,YAAY;EACzB,MAAM,aAAa,UAAU,QAAQ;GAAE,QAAQ,gBAAgB;GAAQ,GAAG;EAAQ,CAAC;EACnF,OAAO,QAAQ;CACjB,GACA,CAAC,UAAU,MAAM,CACnB;AACF"}
1
+ {"version":3,"file":"client.js","names":["ReactVerbalyProvider","useVerbaly"],"sources":["../src/client.ts"],"sourcesContent":["'use client';\n\nimport { useRouter } from 'next/navigation';\nimport {\n createElement,\n useCallback,\n useEffect,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { VerbalyProvider as ReactVerbalyProvider, useVerbaly } from '@verbaly/react';\nimport { switchLocale, type SwitchLocaleOptions } from 'verbaly';\nimport { createInstance, requestOptions, sourceLocale } from 'virtual:verbaly';\n\nexport { Trans, useLocale, useT, useVerbaly } from '@verbaly/react';\n\nexport interface VerbalyProviderProps {\n locale: string;\n messages?: Record<string, string>;\n children?: ReactNode;\n}\n\nexport function VerbalyProvider(props: VerbalyProviderProps): ReactElement {\n const [instance] = useState(() => {\n const created = createInstance({ locale: props.locale });\n if (props.messages && props.locale !== sourceLocale) {\n created.addMessages(props.locale, props.messages);\n }\n return created;\n });\n\n // server changed the locale out-of-band (cookie edit + refresh): follow it\n useEffect(() => {\n if (props.locale === instance.locale) return;\n if (props.messages) {\n instance.addMessages(props.locale, props.messages);\n instance.setLocale(props.locale);\n } else {\n void instance.loadLocale(props.locale).then(() => instance.setLocale(props.locale));\n }\n }, [props.locale, props.messages, instance]);\n\n return createElement(ReactVerbalyProvider, { instance }, props.children);\n}\n\n// core switchLocale (catalog → locale → cookie + <html lang>) + RSC re-render\nexport function useSwitchLocale(): (\n locale: string,\n options?: SwitchLocaleOptions,\n) => Promise<void> {\n const instance = useVerbaly();\n const router = useRouter();\n return useCallback(\n async (locale, options) => {\n await switchLocale(instance, locale, { cookie: requestOptions?.cookie, ...options });\n router.refresh();\n },\n [instance, router],\n );\n}\n"],"mappings":";;;;;;;AAuBA,SAAgB,gBAAgB,OAA2C;CACzE,MAAM,CAAC,YAAY,eAAe;EAChC,MAAM,UAAU,eAAe,EAAE,QAAQ,MAAM,OAAO,CAAC;EACvD,IAAI,MAAM,YAAY,MAAM,WAAW,cACrC,QAAQ,YAAY,MAAM,QAAQ,MAAM,QAAQ;EAElD,OAAO;CACT,CAAC;CAGD,gBAAgB;EACd,IAAI,MAAM,WAAW,SAAS,QAAQ;EACtC,IAAI,MAAM,UAAU;GAClB,SAAS,YAAY,MAAM,QAAQ,MAAM,QAAQ;GACjD,SAAS,UAAU,MAAM,MAAM;EACjC,OACE,SAAc,WAAW,MAAM,MAAM,CAAC,CAAC,WAAW,SAAS,UAAU,MAAM,MAAM,CAAC;CAEtF,GAAG;EAAC,MAAM;EAAQ,MAAM;EAAU;CAAQ,CAAC;CAE3C,OAAO,cAAcA,mBAAsB,EAAE,SAAS,GAAG,MAAM,QAAQ;AACzE;AAGA,SAAgB,kBAGG;CACjB,MAAM,WAAWC,aAAW;CAC5B,MAAM,SAAS,UAAU;CACzB,OAAO,YACL,OAAO,QAAQ,YAAY;EACzB,MAAM,aAAa,UAAU,QAAQ;GAAE,QAAQ,gBAAgB;GAAQ,GAAG;EAAQ,CAAC;EACnF,OAAO,QAAQ;CACjB,GACA,CAAC,UAAU,MAAM,CACnB;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../src/codegen.ts","../src/watch.ts","../src/index.ts"],"sourcesContent":["import type { Catalogs, ResolvedConfig } from '@verbaly/compiler';\nimport { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// the compiler is ESM-only; the dual (CJS-consumable) root entry loads it via\n// dynamic import once and threads the module through\nexport type Compiler = typeof import('@verbaly/compiler');\n\nexport interface RequestOptions {\n cookie?: string | false;\n fallback?: string;\n}\n\nexport const GENERATED_DIR = '.verbaly';\n\nexport function generatedDir(root: string): string {\n return join(root, GENERATED_DIR);\n}\n\n// content compare — identical rewrites must not retrigger the bundler\nfunction writeIfChanged(file: string, content: string): boolean {\n try {\n if (readFileSync(file, 'utf8') === content) return false;\n } catch {\n // new file\n }\n writeFileSync(file, content);\n return true;\n}\n\n// real-file replacement for virtual:verbaly — Turbopack has no virtual modules\nexport function writeGeneratedModules(\n compiler: Compiler,\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n requestOptions: RequestOptions = {},\n): boolean {\n const dir = generatedDir(cfg.root);\n const localeDir = join(dir, 'locale');\n mkdirSync(localeDir, { recursive: true });\n\n let changed = writeIfChanged(join(dir, '.gitignore'), '*\\n');\n\n const runtime = compiler.generateRuntimeModule(cfg, {\n localeImport: (locale) => `./locale/${locale}.js`,\n extraExports: `export const requestOptions = ${JSON.stringify(requestOptions)};\\n`,\n });\n changed = writeIfChanged(join(dir, 'index.js'), runtime) || changed;\n\n const expected = new Set(cfg.locales.map((locale) => `${locale}.js`));\n for (const locale of cfg.locales) {\n changed =\n writeIfChanged(\n join(localeDir, `${locale}.js`),\n compiler.generateLocaleModule(catalogs[locale] ?? {}),\n ) || changed;\n }\n for (const file of readdirSync(localeDir)) {\n if (!expected.has(file)) {\n rmSync(join(localeDir, file));\n changed = true;\n }\n }\n return changed;\n}\n","import type { ResolvedConfig } from '@verbaly/compiler';\nimport { watch } from 'node:fs';\nimport { relative } from 'node:path';\nimport { GENERATED_DIR, writeGeneratedModules, type Compiler, type RequestOptions } from './codegen';\n\n// one watcher per project root — next.config can be evaluated more than once\nconst active = new Map<string, () => void>();\n\nexport function startWatcher(\n compiler: Compiler,\n cfg: ResolvedConfig,\n requestOptions: RequestOptions,\n): () => void {\n const existing = active.get(cfg.root);\n if (existing) return existing;\n\n const catalogDir = relative(cfg.root, cfg.dir).replaceAll('\\\\', '/');\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let queued = false;\n\n async function refresh(): Promise<void> {\n if (running) {\n queued = true;\n return;\n }\n running = true;\n try {\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n } catch (error) {\n console.warn('[verbaly] live extraction failed:', error);\n } finally {\n running = false;\n if (queued) {\n queued = false;\n schedule();\n }\n }\n }\n\n function schedule(): void {\n clearTimeout(timer);\n timer = setTimeout(() => void refresh(), 150);\n }\n\n const watcher = watch(cfg.root, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const file = filename.replaceAll('\\\\', '/');\n if (\n file.startsWith(`${GENERATED_DIR}/`) ||\n file.startsWith('.next/') ||\n file.includes('node_modules/') ||\n file.endsWith('.d.ts')\n ) {\n return;\n }\n const isCatalog = file.startsWith(`${catalogDir}/`) && file.endsWith('.json');\n if (isCatalog || compiler.SOURCE_FILE_RE.test(file)) schedule();\n });\n watcher.unref?.();\n\n const dispose = (): void => {\n clearTimeout(timer);\n watcher.close();\n active.delete(cfg.root);\n };\n active.set(cfg.root, dispose);\n return dispose;\n}\n\n// test hook\nexport function stopWatcher(root: string): void {\n active.get(root)?.();\n}\n","import type { VerbalyConfig } from '@verbaly/compiler';\nimport { join } from 'node:path';\nimport {\n GENERATED_DIR,\n generatedDir,\n writeGeneratedModules,\n type Compiler,\n type RequestOptions,\n} from './codegen';\nimport { startWatcher } from './watch';\n\nexport type { VerbalyConfig } from '@verbaly/compiler';\nexport type { RequestOptions } from './codegen';\n\nexport interface NextVerbalyOptions extends VerbalyConfig {\n // opt out of the build gate (parity with @verbaly/vite and @verbaly/unplugin)\n failOnMissing?: boolean;\n // negotiation cookie (false = Accept-Language only); defaults to core's LOCALE_STORAGE_KEY\n cookie?: string | false;\n // negotiation fallback; defaults to the source locale\n fallback?: string;\n}\n\n// structural NextConfig subset — compat asserted against next's real type in tests.\n// No index signatures: Next's real interfaces have none and a target index\n// signature would reject them.\nexport interface WebpackConfigLike {\n resolve?: { alias?: Record<string, unknown>; [key: string]: unknown };\n module?: { rules?: unknown[]; [key: string]: unknown };\n plugins?: unknown[];\n [key: string]: unknown;\n}\n\ninterface WebpackContextLike {\n webpack?: {\n NormalModuleReplacementPlugin: new (test: RegExp, resource: string) => unknown;\n };\n}\n\n// context param is `never` so Next's real webpack fn (specific context type) stays assignable\nexport type WebpackFn = (config: WebpackConfigLike, context: never) => unknown;\n\nexport interface TurbopackLike {\n resolveAlias?: Record<string, unknown>;\n rules?: Record<string, unknown>;\n}\n\nexport interface NextConfigLike {\n webpack?: WebpackFn | null;\n turbopack?: TurbopackLike;\n}\n\n// constraint is `object` (not NextConfigLike) — an all-optional target would\n// reject configs sharing no keys with it (TS weak-type rule)\nexport type NextConfigInput<C extends object> =\n | C\n | ((phase: string, context: { defaultConfig?: unknown }) => C | Promise<C>);\n\n// next/constants values — literal to keep this module import-free of next\nconst DEV_PHASE = 'phase-development-server';\nconst BUILD_PHASE = 'phase-production-build';\n\nconst LOADER = '@verbaly/next/loader';\n// compiler's SOURCE_FILE_RE (inlined: the compiler is only dynamically imported here).\n// Matching happens via `condition.path` — a bare extension glob also matches Next's\n// internal App Router entry and Turbopack panics reading it as a file.\nconst SOURCE_PATH_RE = /\\.[cm]?[jt]sx?$/;\n\nexport function withVerbaly<C extends object>(\n nextConfig?: NextConfigInput<C>,\n options: NextVerbalyOptions = {},\n): (phase: string, context?: { defaultConfig?: unknown }) => Promise<C> {\n const { failOnMissing, cookie, fallback, ...verbalyConfig } = options;\n const requestOptions: RequestOptions = { cookie, fallback };\n\n return async (phase, context = {}) => {\n const base: C =\n typeof nextConfig === 'function' ? await nextConfig(phase, context) : (nextConfig ?? ({} as C));\n const root = verbalyConfig.root ?? process.cwd();\n\n // production server / export: everything is bundled — no FS work, config only\n if (phase !== DEV_PHASE && phase !== BUILD_PHASE) {\n return composeConfig(base, root);\n }\n\n // dynamic: the compiler is ESM-only and this entry is also consumed as CJS\n const compiler: Compiler = await import('@verbaly/compiler');\n\n const cfg = await compiler.loadConfig(root, verbalyConfig);\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n\n if (phase === BUILD_PHASE) {\n if (failOnMissing !== false) compiler.runBuildGate(cfg, registry);\n } else {\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n startWatcher(compiler, cfg, requestOptions);\n }\n\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n return composeConfig(base, cfg.root);\n };\n}\n\nfunction composeConfig<C extends object>(base: C, root: string): C {\n const runtimeModule = join(generatedDir(root), 'index.js');\n const { webpack: userWebpack, turbopack } = base as NextConfigLike;\n\n const rules: Record<string, unknown> = { ...turbopack?.rules };\n const verbalyRule = {\n condition: { all: [{ not: 'foreign' }, { path: SOURCE_PATH_RE }] },\n loaders: [LOADER],\n };\n const existing = rules['*'];\n rules['*'] = existing\n ? [...(Array.isArray(existing) ? existing : [existing]), verbalyRule]\n : verbalyRule;\n\n return {\n ...base,\n turbopack: {\n ...turbopack,\n resolveAlias: {\n ...turbopack?.resolveAlias,\n 'virtual:verbaly': `./${GENERATED_DIR}/index.js`,\n },\n rules,\n },\n webpack(config: WebpackConfigLike, context: unknown) {\n // webpack 5 treats 'virtual:' as a URI scheme — resolve.alias never fires,\n // module replacement does; the alias stays as a fallback for odd setups\n const { webpack: webpackInstance } = (context ?? {}) as WebpackContextLike;\n if (webpackInstance?.NormalModuleReplacementPlugin) {\n config.plugins ??= [];\n config.plugins.push(\n new webpackInstance.NormalModuleReplacementPlugin(/^virtual:verbaly$/, runtimeModule),\n );\n }\n config.resolve ??= {};\n config.resolve.alias ??= {};\n (config.resolve.alias as Record<string, unknown>)['virtual:verbaly'] = runtimeModule;\n config.module ??= {};\n config.module.rules ??= [];\n config.module.rules.push({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /node_modules/,\n enforce: 'pre',\n use: [{ loader: LOADER }],\n });\n return userWebpack ? userWebpack(config, context as never) : config;\n },\n } as C;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/codegen.ts","../src/watch.ts","../src/index.ts"],"sourcesContent":["import type { Catalogs, ResolvedConfig } from '@verbaly/compiler';\nimport { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type Compiler = typeof import('@verbaly/compiler');\n\nexport interface RequestOptions {\n cookie?: string | false;\n fallback?: string;\n}\n\nexport const GENERATED_DIR = '.verbaly';\n\nexport function generatedDir(root: string): string {\n return join(root, GENERATED_DIR);\n}\n\n// content compare: identical rewrites must not retrigger the bundler\nfunction writeIfChanged(file: string, content: string): boolean {\n try {\n if (readFileSync(file, 'utf8') === content) return false;\n } catch {\n // new file\n }\n writeFileSync(file, content);\n return true;\n}\n\n// real-file replacement for virtual:verbaly: Turbopack has no virtual modules\nexport function writeGeneratedModules(\n compiler: Compiler,\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n requestOptions: RequestOptions = {},\n): boolean {\n const dir = generatedDir(cfg.root);\n const localeDir = join(dir, 'locale');\n mkdirSync(localeDir, { recursive: true });\n\n let changed = writeIfChanged(join(dir, '.gitignore'), '*\\n');\n\n const runtime = compiler.generateRuntimeModule(cfg, {\n localeImport: (locale) => `./locale/${locale}.js`,\n extraExports: `export const requestOptions = ${JSON.stringify(requestOptions)};\\n`,\n });\n changed = writeIfChanged(join(dir, 'index.js'), runtime) || changed;\n\n const expected = new Set(cfg.locales.map((locale) => `${locale}.js`));\n for (const locale of cfg.locales) {\n changed =\n writeIfChanged(\n join(localeDir, `${locale}.js`),\n compiler.generateLocaleModule(catalogs[locale] ?? {}),\n ) || changed;\n }\n for (const file of readdirSync(localeDir)) {\n if (!expected.has(file)) {\n rmSync(join(localeDir, file));\n changed = true;\n }\n }\n return changed;\n}\n","import type { ResolvedConfig } from '@verbaly/compiler';\nimport { watch } from 'node:fs';\nimport { relative } from 'node:path';\nimport { GENERATED_DIR, writeGeneratedModules, type Compiler, type RequestOptions } from './codegen';\n\n// one watcher per project root: next.config can be evaluated more than once\nconst active = new Map<string, () => void>();\n\nexport function startWatcher(\n compiler: Compiler,\n cfg: ResolvedConfig,\n requestOptions: RequestOptions,\n): () => void {\n const existing = active.get(cfg.root);\n if (existing) return existing;\n\n const catalogDir = relative(cfg.root, cfg.dir).replaceAll('\\\\', '/');\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let queued = false;\n\n async function refresh(): Promise<void> {\n if (running) {\n queued = true;\n return;\n }\n running = true;\n try {\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n } catch (error) {\n console.warn('[verbaly] live extraction failed:', error);\n } finally {\n running = false;\n if (queued) {\n queued = false;\n schedule();\n }\n }\n }\n\n function schedule(): void {\n clearTimeout(timer);\n timer = setTimeout(() => void refresh(), 150);\n }\n\n const watcher = watch(cfg.root, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const file = filename.replaceAll('\\\\', '/');\n if (\n file.startsWith(`${GENERATED_DIR}/`) ||\n file.startsWith('.next/') ||\n file.includes('node_modules/') ||\n file.endsWith('.d.ts')\n ) {\n return;\n }\n const isCatalog = file.startsWith(`${catalogDir}/`) && file.endsWith('.json');\n if (isCatalog || compiler.SOURCE_FILE_RE.test(file)) schedule();\n });\n watcher.unref?.();\n\n const dispose = (): void => {\n clearTimeout(timer);\n watcher.close();\n active.delete(cfg.root);\n };\n active.set(cfg.root, dispose);\n return dispose;\n}\n\n// test hook\nexport function stopWatcher(root: string): void {\n active.get(root)?.();\n}\n","import type { VerbalyConfig } from '@verbaly/compiler';\nimport { join } from 'node:path';\nimport {\n GENERATED_DIR,\n generatedDir,\n writeGeneratedModules,\n type Compiler,\n type RequestOptions,\n} from './codegen';\nimport { startWatcher } from './watch';\n\nexport type { VerbalyConfig } from '@verbaly/compiler';\nexport type { RequestOptions } from './codegen';\n\nexport interface NextVerbalyOptions extends VerbalyConfig {\n failOnMissing?: boolean;\n cookie?: string | false;\n fallback?: string;\n}\n\n// structural NextConfig subset: compat asserted against next's real type in tests.\n// No index signatures: Next's real interfaces have none and a target index\n// signature would reject them.\nexport interface WebpackConfigLike {\n resolve?: { alias?: Record<string, unknown>; [key: string]: unknown };\n module?: { rules?: unknown[]; [key: string]: unknown };\n plugins?: unknown[];\n [key: string]: unknown;\n}\n\ninterface WebpackContextLike {\n webpack?: {\n NormalModuleReplacementPlugin: new (test: RegExp, resource: string) => unknown;\n };\n}\n\n// context param is `never` so Next's real webpack fn (specific context type) stays assignable\nexport type WebpackFn = (config: WebpackConfigLike, context: never) => unknown;\n\nexport interface TurbopackLike {\n resolveAlias?: Record<string, unknown>;\n rules?: Record<string, unknown>;\n}\n\nexport interface NextConfigLike {\n webpack?: WebpackFn | null;\n turbopack?: TurbopackLike;\n}\n\n// constraint is `object` (not NextConfigLike): an all-optional target would\n// reject configs sharing no keys with it (TS weak-type rule)\nexport type NextConfigInput<C extends object> =\n | C\n | ((phase: string, context: { defaultConfig?: unknown }) => C | Promise<C>);\n\n// next/constants values: literal to keep this module import-free of next\nconst DEV_PHASE = 'phase-development-server';\nconst BUILD_PHASE = 'phase-production-build';\n\nconst LOADER = '@verbaly/next/loader';\n// compiler's SOURCE_FILE_RE (inlined: the compiler is only dynamically imported here).\n// Matching happens via `condition.path`: a bare extension glob also matches Next's\n// internal App Router entry and Turbopack panics reading it as a file.\nconst SOURCE_PATH_RE = /\\.[cm]?[jt]sx?$/;\n\nexport function withVerbaly<C extends object>(\n nextConfig?: NextConfigInput<C>,\n options: NextVerbalyOptions = {},\n): (phase: string, context?: { defaultConfig?: unknown }) => Promise<C> {\n const { failOnMissing, cookie, fallback, ...verbalyConfig } = options;\n const requestOptions: RequestOptions = { cookie, fallback };\n\n return async (phase, context = {}) => {\n const base: C =\n typeof nextConfig === 'function' ? await nextConfig(phase, context) : (nextConfig ?? ({} as C));\n const root = verbalyConfig.root ?? process.cwd();\n\n // production server / export: everything is bundled, so no FS work, config only\n if (phase !== DEV_PHASE && phase !== BUILD_PHASE) {\n return composeConfig(base, root);\n }\n\n // dynamic: the compiler is ESM-only and this entry is also consumed as CJS\n const compiler: Compiler = await import('@verbaly/compiler');\n\n const cfg = await compiler.loadConfig(root, verbalyConfig);\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n\n if (phase === BUILD_PHASE) {\n if (failOnMissing !== false) compiler.runBuildGate(cfg, registry);\n } else {\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n startWatcher(compiler, cfg, requestOptions);\n }\n\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n return composeConfig(base, cfg.root);\n };\n}\n\nfunction composeConfig<C extends object>(base: C, root: string): C {\n const runtimeModule = join(generatedDir(root), 'index.js');\n const { webpack: userWebpack, turbopack } = base as NextConfigLike;\n\n const rules: Record<string, unknown> = { ...turbopack?.rules };\n const verbalyRule = {\n condition: { all: [{ not: 'foreign' }, { path: SOURCE_PATH_RE }] },\n loaders: [LOADER],\n };\n const existing = rules['*'];\n rules['*'] = existing\n ? [...(Array.isArray(existing) ? existing : [existing]), verbalyRule]\n : verbalyRule;\n\n return {\n ...base,\n turbopack: {\n ...turbopack,\n resolveAlias: {\n ...turbopack?.resolveAlias,\n 'virtual:verbaly': `./${GENERATED_DIR}/index.js`,\n },\n rules,\n },\n webpack(config: WebpackConfigLike, context: unknown) {\n // webpack 5 treats 'virtual:' as a URI scheme: resolve.alias never fires,\n // module replacement does; the alias stays as a fallback for odd setups\n const { webpack: webpackInstance } = (context ?? {}) as WebpackContextLike;\n if (webpackInstance?.NormalModuleReplacementPlugin) {\n config.plugins ??= [];\n config.plugins.push(\n new webpackInstance.NormalModuleReplacementPlugin(/^virtual:verbaly$/, runtimeModule),\n );\n }\n config.resolve ??= {};\n config.resolve.alias ??= {};\n (config.resolve.alias as Record<string, unknown>)['virtual:verbaly'] = runtimeModule;\n config.module ??= {};\n config.module.rules ??= [];\n config.module.rules.push({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /node_modules/,\n enforce: 'pre',\n use: [{ loader: LOADER }],\n });\n return userWebpack ? userWebpack(config, context as never) : config;\n },\n } as C;\n}\n"],"mappings":"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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/codegen.ts","../src/watch.ts","../src/index.ts"],"sourcesContent":["import type { Catalogs, ResolvedConfig } from '@verbaly/compiler';\nimport { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\n// the compiler is ESM-only; the dual (CJS-consumable) root entry loads it via\n// dynamic import once and threads the module through\nexport type Compiler = typeof import('@verbaly/compiler');\n\nexport interface RequestOptions {\n cookie?: string | false;\n fallback?: string;\n}\n\nexport const GENERATED_DIR = '.verbaly';\n\nexport function generatedDir(root: string): string {\n return join(root, GENERATED_DIR);\n}\n\n// content compare — identical rewrites must not retrigger the bundler\nfunction writeIfChanged(file: string, content: string): boolean {\n try {\n if (readFileSync(file, 'utf8') === content) return false;\n } catch {\n // new file\n }\n writeFileSync(file, content);\n return true;\n}\n\n// real-file replacement for virtual:verbaly — Turbopack has no virtual modules\nexport function writeGeneratedModules(\n compiler: Compiler,\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n requestOptions: RequestOptions = {},\n): boolean {\n const dir = generatedDir(cfg.root);\n const localeDir = join(dir, 'locale');\n mkdirSync(localeDir, { recursive: true });\n\n let changed = writeIfChanged(join(dir, '.gitignore'), '*\\n');\n\n const runtime = compiler.generateRuntimeModule(cfg, {\n localeImport: (locale) => `./locale/${locale}.js`,\n extraExports: `export const requestOptions = ${JSON.stringify(requestOptions)};\\n`,\n });\n changed = writeIfChanged(join(dir, 'index.js'), runtime) || changed;\n\n const expected = new Set(cfg.locales.map((locale) => `${locale}.js`));\n for (const locale of cfg.locales) {\n changed =\n writeIfChanged(\n join(localeDir, `${locale}.js`),\n compiler.generateLocaleModule(catalogs[locale] ?? {}),\n ) || changed;\n }\n for (const file of readdirSync(localeDir)) {\n if (!expected.has(file)) {\n rmSync(join(localeDir, file));\n changed = true;\n }\n }\n return changed;\n}\n","import type { ResolvedConfig } from '@verbaly/compiler';\nimport { watch } from 'node:fs';\nimport { relative } from 'node:path';\nimport { GENERATED_DIR, writeGeneratedModules, type Compiler, type RequestOptions } from './codegen';\n\n// one watcher per project root — next.config can be evaluated more than once\nconst active = new Map<string, () => void>();\n\nexport function startWatcher(\n compiler: Compiler,\n cfg: ResolvedConfig,\n requestOptions: RequestOptions,\n): () => void {\n const existing = active.get(cfg.root);\n if (existing) return existing;\n\n const catalogDir = relative(cfg.root, cfg.dir).replaceAll('\\\\', '/');\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let queued = false;\n\n async function refresh(): Promise<void> {\n if (running) {\n queued = true;\n return;\n }\n running = true;\n try {\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n } catch (error) {\n console.warn('[verbaly] live extraction failed:', error);\n } finally {\n running = false;\n if (queued) {\n queued = false;\n schedule();\n }\n }\n }\n\n function schedule(): void {\n clearTimeout(timer);\n timer = setTimeout(() => void refresh(), 150);\n }\n\n const watcher = watch(cfg.root, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const file = filename.replaceAll('\\\\', '/');\n if (\n file.startsWith(`${GENERATED_DIR}/`) ||\n file.startsWith('.next/') ||\n file.includes('node_modules/') ||\n file.endsWith('.d.ts')\n ) {\n return;\n }\n const isCatalog = file.startsWith(`${catalogDir}/`) && file.endsWith('.json');\n if (isCatalog || compiler.SOURCE_FILE_RE.test(file)) schedule();\n });\n watcher.unref?.();\n\n const dispose = (): void => {\n clearTimeout(timer);\n watcher.close();\n active.delete(cfg.root);\n };\n active.set(cfg.root, dispose);\n return dispose;\n}\n\n// test hook\nexport function stopWatcher(root: string): void {\n active.get(root)?.();\n}\n","import type { VerbalyConfig } from '@verbaly/compiler';\nimport { join } from 'node:path';\nimport {\n GENERATED_DIR,\n generatedDir,\n writeGeneratedModules,\n type Compiler,\n type RequestOptions,\n} from './codegen';\nimport { startWatcher } from './watch';\n\nexport type { VerbalyConfig } from '@verbaly/compiler';\nexport type { RequestOptions } from './codegen';\n\nexport interface NextVerbalyOptions extends VerbalyConfig {\n // opt out of the build gate (parity with @verbaly/vite and @verbaly/unplugin)\n failOnMissing?: boolean;\n // negotiation cookie (false = Accept-Language only); defaults to core's LOCALE_STORAGE_KEY\n cookie?: string | false;\n // negotiation fallback; defaults to the source locale\n fallback?: string;\n}\n\n// structural NextConfig subset — compat asserted against next's real type in tests.\n// No index signatures: Next's real interfaces have none and a target index\n// signature would reject them.\nexport interface WebpackConfigLike {\n resolve?: { alias?: Record<string, unknown>; [key: string]: unknown };\n module?: { rules?: unknown[]; [key: string]: unknown };\n plugins?: unknown[];\n [key: string]: unknown;\n}\n\ninterface WebpackContextLike {\n webpack?: {\n NormalModuleReplacementPlugin: new (test: RegExp, resource: string) => unknown;\n };\n}\n\n// context param is `never` so Next's real webpack fn (specific context type) stays assignable\nexport type WebpackFn = (config: WebpackConfigLike, context: never) => unknown;\n\nexport interface TurbopackLike {\n resolveAlias?: Record<string, unknown>;\n rules?: Record<string, unknown>;\n}\n\nexport interface NextConfigLike {\n webpack?: WebpackFn | null;\n turbopack?: TurbopackLike;\n}\n\n// constraint is `object` (not NextConfigLike) — an all-optional target would\n// reject configs sharing no keys with it (TS weak-type rule)\nexport type NextConfigInput<C extends object> =\n | C\n | ((phase: string, context: { defaultConfig?: unknown }) => C | Promise<C>);\n\n// next/constants values — literal to keep this module import-free of next\nconst DEV_PHASE = 'phase-development-server';\nconst BUILD_PHASE = 'phase-production-build';\n\nconst LOADER = '@verbaly/next/loader';\n// compiler's SOURCE_FILE_RE (inlined: the compiler is only dynamically imported here).\n// Matching happens via `condition.path` — a bare extension glob also matches Next's\n// internal App Router entry and Turbopack panics reading it as a file.\nconst SOURCE_PATH_RE = /\\.[cm]?[jt]sx?$/;\n\nexport function withVerbaly<C extends object>(\n nextConfig?: NextConfigInput<C>,\n options: NextVerbalyOptions = {},\n): (phase: string, context?: { defaultConfig?: unknown }) => Promise<C> {\n const { failOnMissing, cookie, fallback, ...verbalyConfig } = options;\n const requestOptions: RequestOptions = { cookie, fallback };\n\n return async (phase, context = {}) => {\n const base: C =\n typeof nextConfig === 'function' ? await nextConfig(phase, context) : (nextConfig ?? ({} as C));\n const root = verbalyConfig.root ?? process.cwd();\n\n // production server / export: everything is bundled — no FS work, config only\n if (phase !== DEV_PHASE && phase !== BUILD_PHASE) {\n return composeConfig(base, root);\n }\n\n // dynamic: the compiler is ESM-only and this entry is also consumed as CJS\n const compiler: Compiler = await import('@verbaly/compiler');\n\n const cfg = await compiler.loadConfig(root, verbalyConfig);\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n\n if (phase === BUILD_PHASE) {\n if (failOnMissing !== false) compiler.runBuildGate(cfg, registry);\n } else {\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n startWatcher(compiler, cfg, requestOptions);\n }\n\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n return composeConfig(base, cfg.root);\n };\n}\n\nfunction composeConfig<C extends object>(base: C, root: string): C {\n const runtimeModule = join(generatedDir(root), 'index.js');\n const { webpack: userWebpack, turbopack } = base as NextConfigLike;\n\n const rules: Record<string, unknown> = { ...turbopack?.rules };\n const verbalyRule = {\n condition: { all: [{ not: 'foreign' }, { path: SOURCE_PATH_RE }] },\n loaders: [LOADER],\n };\n const existing = rules['*'];\n rules['*'] = existing\n ? [...(Array.isArray(existing) ? existing : [existing]), verbalyRule]\n : verbalyRule;\n\n return {\n ...base,\n turbopack: {\n ...turbopack,\n resolveAlias: {\n ...turbopack?.resolveAlias,\n 'virtual:verbaly': `./${GENERATED_DIR}/index.js`,\n },\n rules,\n },\n webpack(config: WebpackConfigLike, context: unknown) {\n // webpack 5 treats 'virtual:' as a URI scheme — resolve.alias never fires,\n // module replacement does; the alias stays as a fallback for odd setups\n const { webpack: webpackInstance } = (context ?? {}) as WebpackContextLike;\n if (webpackInstance?.NormalModuleReplacementPlugin) {\n config.plugins ??= [];\n config.plugins.push(\n new webpackInstance.NormalModuleReplacementPlugin(/^virtual:verbaly$/, runtimeModule),\n );\n }\n config.resolve ??= {};\n config.resolve.alias ??= {};\n (config.resolve.alias as Record<string, unknown>)['virtual:verbaly'] = runtimeModule;\n config.module ??= {};\n config.module.rules ??= [];\n config.module.rules.push({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /node_modules/,\n enforce: 'pre',\n use: [{ loader: LOADER }],\n });\n return userWebpack ? userWebpack(config, context as never) : config;\n },\n } as C;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/codegen.ts","../src/watch.ts","../src/index.ts"],"sourcesContent":["import type { Catalogs, ResolvedConfig } from '@verbaly/compiler';\nimport { mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport type Compiler = typeof import('@verbaly/compiler');\n\nexport interface RequestOptions {\n cookie?: string | false;\n fallback?: string;\n}\n\nexport const GENERATED_DIR = '.verbaly';\n\nexport function generatedDir(root: string): string {\n return join(root, GENERATED_DIR);\n}\n\n// content compare: identical rewrites must not retrigger the bundler\nfunction writeIfChanged(file: string, content: string): boolean {\n try {\n if (readFileSync(file, 'utf8') === content) return false;\n } catch {\n // new file\n }\n writeFileSync(file, content);\n return true;\n}\n\n// real-file replacement for virtual:verbaly: Turbopack has no virtual modules\nexport function writeGeneratedModules(\n compiler: Compiler,\n cfg: ResolvedConfig,\n catalogs: Catalogs,\n requestOptions: RequestOptions = {},\n): boolean {\n const dir = generatedDir(cfg.root);\n const localeDir = join(dir, 'locale');\n mkdirSync(localeDir, { recursive: true });\n\n let changed = writeIfChanged(join(dir, '.gitignore'), '*\\n');\n\n const runtime = compiler.generateRuntimeModule(cfg, {\n localeImport: (locale) => `./locale/${locale}.js`,\n extraExports: `export const requestOptions = ${JSON.stringify(requestOptions)};\\n`,\n });\n changed = writeIfChanged(join(dir, 'index.js'), runtime) || changed;\n\n const expected = new Set(cfg.locales.map((locale) => `${locale}.js`));\n for (const locale of cfg.locales) {\n changed =\n writeIfChanged(\n join(localeDir, `${locale}.js`),\n compiler.generateLocaleModule(catalogs[locale] ?? {}),\n ) || changed;\n }\n for (const file of readdirSync(localeDir)) {\n if (!expected.has(file)) {\n rmSync(join(localeDir, file));\n changed = true;\n }\n }\n return changed;\n}\n","import type { ResolvedConfig } from '@verbaly/compiler';\nimport { watch } from 'node:fs';\nimport { relative } from 'node:path';\nimport { GENERATED_DIR, writeGeneratedModules, type Compiler, type RequestOptions } from './codegen';\n\n// one watcher per project root: next.config can be evaluated more than once\nconst active = new Map<string, () => void>();\n\nexport function startWatcher(\n compiler: Compiler,\n cfg: ResolvedConfig,\n requestOptions: RequestOptions,\n): () => void {\n const existing = active.get(cfg.root);\n if (existing) return existing;\n\n const catalogDir = relative(cfg.root, cfg.dir).replaceAll('\\\\', '/');\n let timer: ReturnType<typeof setTimeout> | undefined;\n let running = false;\n let queued = false;\n\n async function refresh(): Promise<void> {\n if (running) {\n queued = true;\n return;\n }\n running = true;\n try {\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n } catch (error) {\n console.warn('[verbaly] live extraction failed:', error);\n } finally {\n running = false;\n if (queued) {\n queued = false;\n schedule();\n }\n }\n }\n\n function schedule(): void {\n clearTimeout(timer);\n timer = setTimeout(() => void refresh(), 150);\n }\n\n const watcher = watch(cfg.root, { recursive: true }, (_event, filename) => {\n if (!filename) return;\n const file = filename.replaceAll('\\\\', '/');\n if (\n file.startsWith(`${GENERATED_DIR}/`) ||\n file.startsWith('.next/') ||\n file.includes('node_modules/') ||\n file.endsWith('.d.ts')\n ) {\n return;\n }\n const isCatalog = file.startsWith(`${catalogDir}/`) && file.endsWith('.json');\n if (isCatalog || compiler.SOURCE_FILE_RE.test(file)) schedule();\n });\n watcher.unref?.();\n\n const dispose = (): void => {\n clearTimeout(timer);\n watcher.close();\n active.delete(cfg.root);\n };\n active.set(cfg.root, dispose);\n return dispose;\n}\n\n// test hook\nexport function stopWatcher(root: string): void {\n active.get(root)?.();\n}\n","import type { VerbalyConfig } from '@verbaly/compiler';\nimport { join } from 'node:path';\nimport {\n GENERATED_DIR,\n generatedDir,\n writeGeneratedModules,\n type Compiler,\n type RequestOptions,\n} from './codegen';\nimport { startWatcher } from './watch';\n\nexport type { VerbalyConfig } from '@verbaly/compiler';\nexport type { RequestOptions } from './codegen';\n\nexport interface NextVerbalyOptions extends VerbalyConfig {\n failOnMissing?: boolean;\n cookie?: string | false;\n fallback?: string;\n}\n\n// structural NextConfig subset: compat asserted against next's real type in tests.\n// No index signatures: Next's real interfaces have none and a target index\n// signature would reject them.\nexport interface WebpackConfigLike {\n resolve?: { alias?: Record<string, unknown>; [key: string]: unknown };\n module?: { rules?: unknown[]; [key: string]: unknown };\n plugins?: unknown[];\n [key: string]: unknown;\n}\n\ninterface WebpackContextLike {\n webpack?: {\n NormalModuleReplacementPlugin: new (test: RegExp, resource: string) => unknown;\n };\n}\n\n// context param is `never` so Next's real webpack fn (specific context type) stays assignable\nexport type WebpackFn = (config: WebpackConfigLike, context: never) => unknown;\n\nexport interface TurbopackLike {\n resolveAlias?: Record<string, unknown>;\n rules?: Record<string, unknown>;\n}\n\nexport interface NextConfigLike {\n webpack?: WebpackFn | null;\n turbopack?: TurbopackLike;\n}\n\n// constraint is `object` (not NextConfigLike): an all-optional target would\n// reject configs sharing no keys with it (TS weak-type rule)\nexport type NextConfigInput<C extends object> =\n | C\n | ((phase: string, context: { defaultConfig?: unknown }) => C | Promise<C>);\n\n// next/constants values: literal to keep this module import-free of next\nconst DEV_PHASE = 'phase-development-server';\nconst BUILD_PHASE = 'phase-production-build';\n\nconst LOADER = '@verbaly/next/loader';\n// compiler's SOURCE_FILE_RE (inlined: the compiler is only dynamically imported here).\n// Matching happens via `condition.path`: a bare extension glob also matches Next's\n// internal App Router entry and Turbopack panics reading it as a file.\nconst SOURCE_PATH_RE = /\\.[cm]?[jt]sx?$/;\n\nexport function withVerbaly<C extends object>(\n nextConfig?: NextConfigInput<C>,\n options: NextVerbalyOptions = {},\n): (phase: string, context?: { defaultConfig?: unknown }) => Promise<C> {\n const { failOnMissing, cookie, fallback, ...verbalyConfig } = options;\n const requestOptions: RequestOptions = { cookie, fallback };\n\n return async (phase, context = {}) => {\n const base: C =\n typeof nextConfig === 'function' ? await nextConfig(phase, context) : (nextConfig ?? ({} as C));\n const root = verbalyConfig.root ?? process.cwd();\n\n // production server / export: everything is bundled, so no FS work, config only\n if (phase !== DEV_PHASE && phase !== BUILD_PHASE) {\n return composeConfig(base, root);\n }\n\n // dynamic: the compiler is ESM-only and this entry is also consumed as CJS\n const compiler: Compiler = await import('@verbaly/compiler');\n\n const cfg = await compiler.loadConfig(root, verbalyConfig);\n const catalogs = compiler.loadCatalogs(cfg);\n const registry = await compiler.extractProject(cfg);\n\n if (phase === BUILD_PHASE) {\n if (failOnMissing !== false) compiler.runBuildGate(cfg, registry);\n } else {\n const { added } = compiler.syncCatalogs(cfg, catalogs, registry);\n for (const locale of Object.keys(added)) {\n compiler.writeCatalog(cfg, locale, catalogs[locale] ?? {});\n }\n compiler.writeDts(cfg, new Map(Object.entries(catalogs[cfg.sourceLocale] ?? {})));\n startWatcher(compiler, cfg, requestOptions);\n }\n\n writeGeneratedModules(compiler, cfg, catalogs, requestOptions);\n return composeConfig(base, cfg.root);\n };\n}\n\nfunction composeConfig<C extends object>(base: C, root: string): C {\n const runtimeModule = join(generatedDir(root), 'index.js');\n const { webpack: userWebpack, turbopack } = base as NextConfigLike;\n\n const rules: Record<string, unknown> = { ...turbopack?.rules };\n const verbalyRule = {\n condition: { all: [{ not: 'foreign' }, { path: SOURCE_PATH_RE }] },\n loaders: [LOADER],\n };\n const existing = rules['*'];\n rules['*'] = existing\n ? [...(Array.isArray(existing) ? existing : [existing]), verbalyRule]\n : verbalyRule;\n\n return {\n ...base,\n turbopack: {\n ...turbopack,\n resolveAlias: {\n ...turbopack?.resolveAlias,\n 'virtual:verbaly': `./${GENERATED_DIR}/index.js`,\n },\n rules,\n },\n webpack(config: WebpackConfigLike, context: unknown) {\n // webpack 5 treats 'virtual:' as a URI scheme: resolve.alias never fires,\n // module replacement does; the alias stays as a fallback for odd setups\n const { webpack: webpackInstance } = (context ?? {}) as WebpackContextLike;\n if (webpackInstance?.NormalModuleReplacementPlugin) {\n config.plugins ??= [];\n config.plugins.push(\n new webpackInstance.NormalModuleReplacementPlugin(/^virtual:verbaly$/, runtimeModule),\n );\n }\n config.resolve ??= {};\n config.resolve.alias ??= {};\n (config.resolve.alias as Record<string, unknown>)['virtual:verbaly'] = runtimeModule;\n config.module ??= {};\n config.module.rules ??= [];\n config.module.rules.push({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /node_modules/,\n enforce: 'pre',\n use: [{ loader: LOADER }],\n });\n return userWebpack ? userWebpack(config, context as never) : config;\n },\n } as C;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.cjs","names":[],"sources":["../src/loader.ts"],"sourcesContent":["// webpack/turbopack loader: rewrites t`…` / <Trans> to compiled keys.\n// Async because @verbaly/compiler is ESM-only loaded via dynamic import.\n\nexport interface LoaderContext {\n resourcePath: string;\n async(): (error: unknown, code?: string, map?: unknown) => void;\n}\n\nlet compiler: Promise<typeof import('@verbaly/compiler')> | undefined;\n\nexport default function verbalyLoader(this: LoaderContext, source: string): void {\n const callback = this.async();\n const file = this.resourcePath;\n compiler ??= import('@verbaly/compiler');\n compiler\n .then(({ isTransformTarget, transformCode }) => {\n if (!isTransformTarget(file)) {\n callback(null, source);\n return;\n }\n const result = transformCode(source, file);\n if (result) {\n // MagicString maps carry an empty source Turbopack resolves '' to the\n // module's directory and panics trying to read it as a file\n result.map.sources = [file];\n callback(null, result.code, result.map);\n } else {\n callback(null, source);\n }\n })\n .catch((error: unknown) => callback(error));\n}\n"],"mappings":";AAQA,IAAI;AAEJ,SAAwB,cAAmC,QAAsB;CAC/E,MAAM,WAAW,KAAK,MAAM;CAC5B,MAAM,OAAO,KAAK;CAClB,aAAa,OAAO;CACpB,SACG,MAAM,EAAE,mBAAmB,oBAAoB;EAC9C,IAAI,CAAC,kBAAkB,IAAI,GAAG;GAC5B,SAAS,MAAM,MAAM;GACrB;EACF;EACA,MAAM,SAAS,cAAc,QAAQ,IAAI;EACzC,IAAI,QAAQ;GAGV,OAAO,IAAI,UAAU,CAAC,IAAI;GAC1B,SAAS,MAAM,OAAO,MAAM,OAAO,GAAG;EACxC,OACE,SAAS,MAAM,MAAM;CAEzB,CAAC,CAAC,CACD,OAAO,UAAmB,SAAS,KAAK,CAAC;AAC9C"}
1
+ {"version":3,"file":"loader.cjs","names":[],"sources":["../src/loader.ts"],"sourcesContent":["// webpack/turbopack loader: rewrites t`…` / <Trans> to compiled keys.\n// Async because @verbaly/compiler is ESM-only: loaded via dynamic import.\n\nexport interface LoaderContext {\n resourcePath: string;\n async(): (error: unknown, code?: string, map?: unknown) => void;\n}\n\nlet compiler: Promise<typeof import('@verbaly/compiler')> | undefined;\n\nexport default function verbalyLoader(this: LoaderContext, source: string): void {\n const callback = this.async();\n const file = this.resourcePath;\n compiler ??= import('@verbaly/compiler');\n compiler\n .then(({ isTransformTarget, transformCode }) => {\n if (!isTransformTarget(file)) {\n callback(null, source);\n return;\n }\n const result = transformCode(source, file);\n if (result) {\n // MagicString maps carry an empty source: Turbopack resolves '' to the\n // module's directory and panics trying to read it as a file\n result.map.sources = [file];\n callback(null, result.code, result.map);\n } else {\n callback(null, source);\n }\n })\n .catch((error: unknown) => callback(error));\n}\n"],"mappings":";AAQA,IAAI;AAEJ,SAAwB,cAAmC,QAAsB;CAC/E,MAAM,WAAW,KAAK,MAAM;CAC5B,MAAM,OAAO,KAAK;CAClB,aAAa,OAAO;CACpB,SACG,MAAM,EAAE,mBAAmB,oBAAoB;EAC9C,IAAI,CAAC,kBAAkB,IAAI,GAAG;GAC5B,SAAS,MAAM,MAAM;GACrB;EACF;EACA,MAAM,SAAS,cAAc,QAAQ,IAAI;EACzC,IAAI,QAAQ;GAGV,OAAO,IAAI,UAAU,CAAC,IAAI;GAC1B,SAAS,MAAM,OAAO,MAAM,OAAO,GAAG;EACxC,OACE,SAAS,MAAM,MAAM;CAEzB,CAAC,CAAC,CACD,OAAO,UAAmB,SAAS,KAAK,CAAC;AAC9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["import { cookies, headers } from 'next/headers';\nimport * as React from 'react';\nimport {\n LOCALE_STORAGE_KEY,\n resolveRequestLocale,\n type TFunction,\n type Verbaly,\n} from 'verbaly';\nimport {\n createRequestInstance,\n loadMessages,\n locales,\n requestOptions,\n sourceLocale,\n} from 'virtual:verbaly';\n\ninterface RequestState {\n locale: string;\n instance: Verbaly;\n}\n\n// React.cache = per-request dedupe in RSC; identity fallback keeps plain-node tests runnable\nconst perRequest: <T extends () => Promise<RequestState>>(fn: T) => T =\n (React as { cache?: <T>(fn: T) => T }).cache ?? ((fn) => fn);\n\nconst getRequestState = perRequest(async (): Promise<RequestState> => {\n const cookieName = requestOptions?.cookie ?? LOCALE_STORAGE_KEY;\n const headerStore = await headers();\n const cookieValue =\n cookieName === false ? undefined : (await cookies()).get(cookieName)?.value;\n const locale = resolveRequestLocale({\n supported: locales,\n cookie: cookieValue,\n header: headerStore.get('accept-language'),\n fallback: requestOptions?.fallback ?? sourceLocale,\n });\n return { locale, instance: await createRequestInstance(locale) };\n});\n\n// request-scoped instance never the virtual:verbaly singleton (locale would leak between requests)\nexport async function getVerbaly(): Promise<Verbaly> {\n return (await getRequestState()).instance;\n}\n\nexport async function getT(): Promise<TFunction> {\n return (await getRequestState()).instance.t;\n}\n\nexport async function getRequestLocale(): Promise<string> {\n return (await getRequestState()).locale;\n}\n\nexport interface VerbalyProviderProps {\n locale: string;\n messages?: Record<string, string>;\n}\n\n// serializable props for <VerbalyProvider> messages omitted when locale is the\n// source locale (it ships inline in the client bundle already)\nexport async function getVerbalyProps(): Promise<VerbalyProviderProps> {\n const { locale } = await getRequestState();\n if (locale === sourceLocale) return { locale };\n return { locale, messages: await loadMessages(locale) };\n}\n"],"mappings":";;;;;AAyBA,MAAM,mBAFH,MAAsC,WAAW,OAAO,IAAA,CAExB,YAAmC;CACpE,MAAM,aAAa,gBAAgB,UAAU;CAC7C,MAAM,cAAc,MAAM,QAAQ;CAGlC,MAAM,SAAS,qBAAqB;EAClC,WAAW;EACX,QAHA,eAAe,QAAQ,KAAA,KAAa,MAAM,QAAQ,EAAA,CAAG,IAAI,UAAU,CAAC,EAAE;EAItE,QAAQ,YAAY,IAAI,iBAAiB;EACzC,UAAU,gBAAgB,YAAY;CACxC,CAAC;CACD,OAAO;EAAE;EAAQ,UAAU,MAAM,sBAAsB,MAAM;CAAE;AACjE,CAAC;AAGD,eAAsB,aAA+B;CACnD,QAAQ,MAAM,gBAAgB,EAAA,CAAG;AACnC;AAEA,eAAsB,OAA2B;CAC/C,QAAQ,MAAM,gBAAgB,EAAA,CAAG,SAAS;AAC5C;AAEA,eAAsB,mBAAoC;CACxD,QAAQ,MAAM,gBAAgB,EAAA,CAAG;AACnC;AASA,eAAsB,kBAAiD;CACrE,MAAM,EAAE,WAAW,MAAM,gBAAgB;CACzC,IAAI,WAAW,cAAc,OAAO,EAAE,OAAO;CAC7C,OAAO;EAAE;EAAQ,UAAU,MAAM,aAAa,MAAM;CAAE;AACxD"}
1
+ {"version":3,"file":"server.js","names":[],"sources":["../src/server.ts"],"sourcesContent":["import { cookies, headers } from 'next/headers';\nimport * as React from 'react';\nimport {\n LOCALE_STORAGE_KEY,\n resolveRequestLocale,\n type TFunction,\n type Verbaly,\n} from 'verbaly';\nimport {\n createRequestInstance,\n loadMessages,\n locales,\n requestOptions,\n sourceLocale,\n} from 'virtual:verbaly';\n\ninterface RequestState {\n locale: string;\n instance: Verbaly;\n}\n\n// React.cache = per-request dedupe in RSC; identity fallback keeps plain-node tests runnable\nconst perRequest: <T extends () => Promise<RequestState>>(fn: T) => T =\n (React as { cache?: <T>(fn: T) => T }).cache ?? ((fn) => fn);\n\nconst getRequestState = perRequest(async (): Promise<RequestState> => {\n const cookieName = requestOptions?.cookie ?? LOCALE_STORAGE_KEY;\n const headerStore = await headers();\n const cookieValue =\n cookieName === false ? undefined : (await cookies()).get(cookieName)?.value;\n const locale = resolveRequestLocale({\n supported: locales,\n cookie: cookieValue,\n header: headerStore.get('accept-language'),\n fallback: requestOptions?.fallback ?? sourceLocale,\n });\n return { locale, instance: await createRequestInstance(locale) };\n});\n\n// request-scoped instance: never the virtual:verbaly singleton (locale would leak between requests)\nexport async function getVerbaly(): Promise<Verbaly> {\n return (await getRequestState()).instance;\n}\n\nexport async function getT(): Promise<TFunction> {\n return (await getRequestState()).instance.t;\n}\n\nexport async function getRequestLocale(): Promise<string> {\n return (await getRequestState()).locale;\n}\n\nexport interface VerbalyProviderProps {\n locale: string;\n messages?: Record<string, string>;\n}\n\n// serializable props for <VerbalyProvider>: messages omitted when locale is the\n// source locale (it ships inline in the client bundle already)\nexport async function getVerbalyProps(): Promise<VerbalyProviderProps> {\n const { locale } = await getRequestState();\n if (locale === sourceLocale) return { locale };\n return { locale, messages: await loadMessages(locale) };\n}\n"],"mappings":";;;;;AAyBA,MAAM,mBAFH,MAAsC,WAAW,OAAO,IAAA,CAExB,YAAmC;CACpE,MAAM,aAAa,gBAAgB,UAAU;CAC7C,MAAM,cAAc,MAAM,QAAQ;CAGlC,MAAM,SAAS,qBAAqB;EAClC,WAAW;EACX,QAHA,eAAe,QAAQ,KAAA,KAAa,MAAM,QAAQ,EAAA,CAAG,IAAI,UAAU,CAAC,EAAE;EAItE,QAAQ,YAAY,IAAI,iBAAiB;EACzC,UAAU,gBAAgB,YAAY;CACxC,CAAC;CACD,OAAO;EAAE;EAAQ,UAAU,MAAM,sBAAsB,MAAM;CAAE;AACjE,CAAC;AAGD,eAAsB,aAA+B;CACnD,QAAQ,MAAM,gBAAgB,EAAA,CAAG;AACnC;AAEA,eAAsB,OAA2B;CAC/C,QAAQ,MAAM,gBAAgB,EAAA,CAAG,SAAS;AAC5C;AAEA,eAAsB,mBAAoC;CACxD,QAAQ,MAAM,gBAAgB,EAAA,CAAG;AACnC;AASA,eAAsB,kBAAiD;CACrE,MAAM,EAAE,WAAW,MAAM,gBAAgB;CACzC,IAAI,WAAW,cAAc,OAAO,EAAE,OAAO;CAC7C,OAAO;EAAE;EAAQ,UAAU,MAAM,aAAa,MAAM;CAAE;AACxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@verbaly/next",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "description": "Next.js integration for Verbaly — App Router/RSC with per-request locale negotiation, Turbopack and webpack support, flash-free hydration.",
5
5
  "keywords": [
6
6
  "i18n",
@@ -64,13 +64,13 @@
64
64
  "access": "public"
65
65
  },
66
66
  "dependencies": {
67
- "@verbaly/compiler": "^0.19.0"
67
+ "@verbaly/compiler": "^0.20.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "next": "^15.0.0 || ^16.0.0",
71
71
  "react": "^18.0.0 || ^19.0.0",
72
- "verbaly": "^0.19.0",
73
- "@verbaly/react": "^0.19.0"
72
+ "@verbaly/react": "^0.20.0",
73
+ "verbaly": "^0.20.0"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/react": "^19.2.17",
@@ -79,8 +79,8 @@
79
79
  "next": "^16.2.10",
80
80
  "react": "^19.2.7",
81
81
  "react-dom": "^19.2.7",
82
- "@verbaly/react": "0.19.0",
83
- "verbaly": "0.19.0"
82
+ "verbaly": "0.20.0",
83
+ "@verbaly/react": "0.20.0"
84
84
  },
85
85
  "scripts": {
86
86
  "build": "tsdown",