@inlang/paraglide-js 2.26.0 → 2.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -1
- package/dist/bundler-plugins/per-locale-build/index.js +14 -7
- package/dist/bundler-plugins/per-locale-build/index.js.map +1 -1
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js +237 -4
- package/dist/bundler-plugins/per-locale-build/vite-environments.test.js.map +1 -1
- package/dist/bundler-plugins/unplugin.d.ts +1 -1
- package/dist/bundler-plugins/unplugin.js +79 -10
- package/dist/bundler-plugins/unplugin.js.map +1 -1
- package/dist/bundler-plugins/unplugin.test.js +334 -1
- package/dist/bundler-plugins/unplugin.test.js.map +1 -1
- package/dist/bundler-plugins/vite.js +2 -1
- package/dist/bundler-plugins/vite.js.map +1 -1
- package/dist/bundler-plugins/vite.test.js +1 -1
- package/dist/bundler-plugins/vite.test.js.map +1 -1
- package/dist/cli/commands/compile/command.js +13 -0
- package/dist/cli/commands/compile/command.js.map +1 -1
- package/dist/cli/commands/compile/command.test.js +87 -3
- package/dist/cli/commands/compile/command.test.js.map +1 -1
- package/dist/cli/commands/init/command.d.ts +5 -0
- package/dist/cli/commands/init/command.js +216 -44
- package/dist/cli/commands/init/command.js.map +1 -1
- package/dist/cli/commands/init/command.test.d.ts +1 -0
- package/dist/cli/commands/init/command.test.js +123 -0
- package/dist/cli/commands/init/command.test.js.map +1 -0
- package/dist/cli/defaults.js +2 -2
- package/dist/cli/defaults.js.map +1 -1
- package/dist/cli/init-options.d.ts +11 -0
- package/dist/cli/init-options.js +2 -0
- package/dist/cli/init-options.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.d.ts +19 -0
- package/dist/cli/steps/add-inlang-check.js +60 -0
- package/dist/cli/steps/add-inlang-check.js.map +1 -0
- package/dist/cli/steps/add-inlang-check.test.d.ts +1 -0
- package/dist/cli/steps/add-inlang-check.test.js +88 -0
- package/dist/cli/steps/add-inlang-check.test.js.map +1 -0
- package/dist/cli/steps/add-message-lint.d.ts +34 -0
- package/dist/cli/steps/add-message-lint.js +105 -0
- package/dist/cli/steps/add-message-lint.js.map +1 -0
- package/dist/cli/steps/add-message-lint.test.d.ts +1 -0
- package/dist/cli/steps/add-message-lint.test.js +74 -0
- package/dist/cli/steps/add-message-lint.test.js.map +1 -0
- package/dist/cli/steps/add-vite-plugin.d.ts +18 -0
- package/dist/cli/steps/add-vite-plugin.js +34 -6
- package/dist/cli/steps/add-vite-plugin.js.map +1 -1
- package/dist/cli/steps/add-vite-plugin.test.js +25 -9
- package/dist/cli/steps/add-vite-plugin.test.js.map +1 -1
- package/dist/cli/steps/agents-md-suggestion.d.ts +11 -0
- package/dist/cli/steps/agents-md-suggestion.js +19 -0
- package/dist/cli/steps/agents-md-suggestion.js.map +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.d.ts +1 -0
- package/dist/cli/steps/agents-md-suggestion.test.js +36 -0
- package/dist/cli/steps/agents-md-suggestion.test.js.map +1 -0
- package/dist/cli/steps/check-for-uncomitted-changes.d.ts +3 -0
- package/dist/cli/steps/check-for-uncomitted-changes.js +15 -3
- package/dist/cli/steps/check-for-uncomitted-changes.js.map +1 -1
- package/dist/cli/steps/detect-bundler.d.ts +1 -0
- package/dist/cli/steps/detect-bundler.js +7 -1
- package/dist/cli/steps/detect-bundler.js.map +1 -1
- package/dist/cli/steps/initialize-inlang-project.d.ts +4 -3
- package/dist/cli/steps/initialize-inlang-project.js +60 -157
- package/dist/cli/steps/initialize-inlang-project.js.map +1 -1
- package/dist/cli/steps/maybe-add-machine-translation.d.ts +4 -0
- package/dist/cli/steps/maybe-add-machine-translation.js +14 -8
- package/dist/cli/steps/maybe-add-machine-translation.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.d.ts +2 -0
- package/dist/cli/steps/maybe-add-sherlock.js +13 -7
- package/dist/cli/steps/maybe-add-sherlock.js.map +1 -1
- package/dist/cli/steps/maybe-add-sherlock.test.d.ts +1 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js +44 -0
- package/dist/cli/steps/maybe-add-sherlock.test.js.map +1 -0
- package/dist/cli/steps/prompt-for-outdir.d.ts +2 -0
- package/dist/cli/steps/prompt-for-outdir.js +4 -0
- package/dist/cli/steps/prompt-for-outdir.js.map +1 -1
- package/dist/cli/steps/update-package-json.js +8 -13
- package/dist/cli/steps/update-package-json.js.map +1 -1
- package/dist/cli/steps/update-ts-config.d.ts +6 -0
- package/dist/cli/steps/update-ts-config.js +27 -4
- package/dist/cli/steps/update-ts-config.js.map +1 -1
- package/dist/cli/utils.d.ts +11 -0
- package/dist/cli/utils.js +21 -0
- package/dist/cli/utils.js.map +1 -1
- package/dist/cli/utils.test.d.ts +1 -0
- package/dist/cli/utils.test.js +16 -0
- package/dist/cli/utils.test.js.map +1 -0
- package/dist/compiler/compile-annotation.d.ts +48 -1
- package/dist/compiler/compile-annotation.js +243 -10
- package/dist/compiler/compile-annotation.js.map +1 -1
- package/dist/compiler/compile-bundle.d.ts +7 -2
- package/dist/compiler/compile-bundle.js +97 -3
- package/dist/compiler/compile-bundle.js.map +1 -1
- package/dist/compiler/compile-bundle.test.js +232 -19
- package/dist/compiler/compile-bundle.test.js.map +1 -1
- package/dist/compiler/compile-lifecycle.test.d.ts +1 -0
- package/dist/compiler/compile-lifecycle.test.js +69 -0
- package/dist/compiler/compile-lifecycle.test.js.map +1 -0
- package/dist/compiler/compile-local-variable.d.ts +3 -0
- package/dist/compiler/compile-local-variable.js +5 -2
- package/dist/compiler/compile-local-variable.js.map +1 -1
- package/dist/compiler/compile-local-variable.test.js +55 -15
- package/dist/compiler/compile-local-variable.test.js.map +1 -1
- package/dist/compiler/compile-message.d.ts +29 -1
- package/dist/compiler/compile-message.exact-number.test.d.ts +1 -0
- package/dist/compiler/compile-message.exact-number.test.js +786 -0
- package/dist/compiler/compile-message.exact-number.test.js.map +1 -0
- package/dist/compiler/compile-message.js +162 -66
- package/dist/compiler/compile-message.js.map +1 -1
- package/dist/compiler/compile-message.locals.test.d.ts +1 -0
- package/dist/compiler/compile-message.locals.test.js +498 -0
- package/dist/compiler/compile-message.locals.test.js.map +1 -0
- package/dist/compiler/compile-message.test.js +113 -22
- package/dist/compiler/compile-message.test.js.map +1 -1
- package/dist/compiler/compile-pattern.d.ts +5 -0
- package/dist/compiler/compile-pattern.js +6 -18
- package/dist/compiler/compile-pattern.js.map +1 -1
- package/dist/compiler/compile-pattern.test.js +169 -5
- package/dist/compiler/compile-pattern.test.js.map +1 -1
- package/dist/compiler/compile-project.js +5 -1
- package/dist/compiler/compile-project.js.map +1 -1
- package/dist/compiler/compile-project.test.js +1260 -185
- package/dist/compiler/compile-project.test.js.map +1 -1
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/compile.test.js +71 -1
- package/dist/compiler/compile.test.js.map +1 -1
- package/dist/compiler/compiler-options.d.ts +41 -0
- package/dist/compiler/compiler-options.js.map +1 -1
- package/dist/compiler/create-readme.d.ts +4 -1
- package/dist/compiler/create-readme.js +33 -125
- package/dist/compiler/create-readme.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.interop.test.js +2 -2
- package/dist/compiler/emit-ts-declarations.interop.test.js.map +1 -1
- package/dist/compiler/emit-ts-declarations.test.js +4 -4
- package/dist/compiler/emit-ts-declarations.test.js.map +1 -1
- package/dist/compiler/index.d.ts +1 -1
- package/dist/compiler/index.js +1 -1
- package/dist/compiler/index.js.map +1 -1
- package/dist/compiler/input-alias.d.ts +21 -0
- package/dist/compiler/input-alias.js +42 -0
- package/dist/compiler/input-alias.js.map +1 -0
- package/dist/compiler/input-alias.test.d.ts +1 -0
- package/dist/compiler/input-alias.test.js +58 -0
- package/dist/compiler/input-alias.test.js.map +1 -0
- package/dist/compiler/message-locals.d.ts +46 -0
- package/dist/compiler/message-locals.js +129 -0
- package/dist/compiler/message-locals.js.map +1 -0
- package/dist/compiler/output-structure/locale-modules.js +7 -1
- package/dist/compiler/output-structure/locale-modules.js.map +1 -1
- package/dist/compiler/output-structure/locale-modules.test.js +35 -0
- package/dist/compiler/output-structure/locale-modules.test.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.js +6 -4
- package/dist/compiler/output-structure/message-modules.js.map +1 -1
- package/dist/compiler/output-structure/message-modules.test.js +35 -0
- package/dist/compiler/output-structure/message-modules.test.js.map +1 -1
- package/dist/compiler/registry.d.ts +12 -0
- package/dist/compiler/registry.js +158 -31
- package/dist/compiler/registry.js.map +1 -1
- package/dist/compiler/registry.test.d.ts +1 -0
- package/dist/compiler/registry.test.js +291 -0
- package/dist/compiler/registry.test.js.map +1 -0
- package/dist/compiler/runtime/create-runtime.d.ts +2 -0
- package/dist/compiler/runtime/create-runtime.js +9 -0
- package/dist/compiler/runtime/create-runtime.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js +8 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js +26 -0
- package/dist/compiler/runtime/extract-locale-from-cookie.test.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.js +47 -5
- package/dist/compiler/runtime/extract-locale-from-header.js.map +1 -1
- package/dist/compiler/runtime/extract-locale-from-header.test.js +58 -0
- package/dist/compiler/runtime/extract-locale-from-header.test.js.map +1 -1
- package/dist/compiler/runtime/get-locale.js +7 -1
- package/dist/compiler/runtime/get-locale.js.map +1 -1
- package/dist/compiler/runtime/get-locale.test.js +95 -0
- package/dist/compiler/runtime/get-locale.test.js.map +1 -1
- package/dist/compiler/runtime/localize-href.d.ts +8 -0
- package/dist/compiler/runtime/localize-href.js +60 -0
- package/dist/compiler/runtime/localize-href.js.map +1 -1
- package/dist/compiler/runtime/localize-href.test.js +227 -1
- package/dist/compiler/runtime/localize-href.test.js.map +1 -1
- package/dist/compiler/runtime/set-locale.js +24 -6
- package/dist/compiler/runtime/set-locale.js.map +1 -1
- package/dist/compiler/runtime/set-locale.test.js +182 -0
- package/dist/compiler/runtime/set-locale.test.js.map +1 -1
- package/dist/compiler/runtime/type.d.ts +2 -0
- package/dist/compiler/runtime/type.js.map +1 -1
- package/dist/compiler/runtime/type.test.js +34 -0
- package/dist/compiler/runtime/type.test.js.map +1 -1
- package/dist/compiler/runtime/variables.d.ts +2 -0
- package/dist/compiler/runtime/variables.js +7 -0
- package/dist/compiler/runtime/variables.js.map +1 -1
- package/dist/compiler/server/create-server-file.js +24 -0
- package/dist/compiler/server/create-server-file.js.map +1 -1
- package/dist/compiler/server/create-server-file.test.js +8 -2
- package/dist/compiler/server/create-server-file.test.js.map +1 -1
- package/dist/compiler/server/middleware.d.ts +8 -2
- package/dist/compiler/server/middleware.js +204 -11
- package/dist/compiler/server/middleware.js.map +1 -1
- package/dist/compiler/server/middleware.test.js +750 -3
- package/dist/compiler/server/middleware.test.js.map +1 -1
- package/dist/eslint/index.d.ts +4 -0
- package/dist/eslint/index.js +8 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.d.ts +3 -0
- package/dist/eslint/no-dynamic-message-access.js +150 -0
- package/dist/eslint/no-dynamic-message-access.js.map +1 -0
- package/dist/eslint/no-dynamic-message-access.test.d.ts +1 -0
- package/dist/eslint/no-dynamic-message-access.test.js +126 -0
- package/dist/eslint/no-dynamic-message-access.test.js.map +1 -0
- package/dist/eslint/oxlint.test.d.ts +1 -0
- package/dist/eslint/oxlint.test.js +64 -0
- package/dist/eslint/oxlint.test.js.map +1 -0
- package/dist/services/config/config-schema.d.ts +2 -0
- package/dist/services/config/config-schema.js +2 -0
- package/dist/services/config/config-schema.js.map +1 -1
- package/dist/services/config/load-paraglide-config.test.js +12 -0
- package/dist/services/config/load-paraglide-config.test.js.map +1 -1
- package/dist/services/env-variables/index.js +1 -1
- package/dist/services/env-variables/index.js.map +1 -1
- package/dist/services/file-handling/write-output.bench.js +51 -11
- package/dist/services/file-handling/write-output.bench.js.map +1 -1
- package/dist/services/file-handling/write-output.js +60 -20
- package/dist/services/file-handling/write-output.js.map +1 -1
- package/dist/services/file-handling/write-output.test.js +175 -0
- package/dist/services/file-handling/write-output.test.js.map +1 -1
- package/package.json +15 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-server-file.test.js","sourceRoot":"","sources":["../../../src/compiler/server/create-server-file.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { afterEach, expect, test } from \"vitest\";\nimport type { CompiledBundleWithMessages } from \"../compile-bundle.js\";\nimport { toSafeModuleId } from \"../safe-module-id.js\";\nimport { createServerFile } from \"./create-server-file.js\";\n\nconst temporaryDirectories: string[] = [];\n\nafterEach(async () => {\n\tawait Promise.all(\n\t\ttemporaryDirectories\n\t\t\t.splice(0)\n\t\t\t.map((directory) => rm(directory, { recursive: true, force: true }))\n\t);\n});\n\ntest(\"uses the initialized AsyncLocalStorage when an import interceptor snapshots the initial export\", async () => {\n\tconst directory = await mkdtemp(join(tmpdir(), \"paraglide-server-\"));\n\ttemporaryDirectories.push(directory);\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles: [],\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: false,\n\t\t},\n\t}).replace('\"./runtime.js\"', '\"./runtime-wrapper.mjs\"');\n\n\tawait writeFile(join(directory, \"server.mjs\"), serverCode);\n\tawait writeFile(\n\t\tjoin(directory, \"runtime-real.mjs\"),\n\t\t`export let serverAsyncLocalStorage;\nexport const disableAsyncLocalStorage = false;\nexport function overwriteServerAsyncLocalStorage(value) {\n serverAsyncLocalStorage = value;\n}\nexport function getServerAsyncLocalStorage() {\n return serverAsyncLocalStorage;\n}\nexport const baseLocale = \"en\";\nexport function isExcludedByRouteStrategy() {\n return true;\n}`\n\t);\n\tawait writeFile(\n\t\tjoin(directory, \"runtime-wrapper.mjs\"),\n\t\t`import * as runtime from \"./runtime-real.mjs\";\nexport const serverAsyncLocalStorage = runtime.serverAsyncLocalStorage;\nexport const disableAsyncLocalStorage = runtime.disableAsyncLocalStorage;\nexport const overwriteServerAsyncLocalStorage = runtime.overwriteServerAsyncLocalStorage;\nexport const getServerAsyncLocalStorage = runtime.getServerAsyncLocalStorage;\nexport const baseLocale = runtime.baseLocale;\nexport const isExcludedByRouteStrategy = runtime.isExcludedByRouteStrategy;`\n\t);\n\n\tconst server = await import(\n\t\tpathToFileURL(join(directory, \"server.mjs\")).href\n\t);\n\tconst response = await server.paraglideMiddleware(\n\t\tnew Request(\"https://example.com/api/ready\"),\n\t\t() => new Response(\"ready\")\n\t);\n\n\texpect(response.status).toBe(200);\n\texpect(await response.text()).toBe(\"ready\");\n});\n\ntest(\"import statements in JSDoc examples survive in the generated server file\", () => {\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles: [],\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: false,\n\t\t},\n\t});\n\n\texpect(serverCode).toContain(\n\t\t` * import { paraglideMiddleware } from './paraglide/server.js'\\n * import handler from '@tanstack/react-start/server-entry'\\n *\\n * export default {`\n\t);\n\t// only the `import * as runtime` line that createServerFile itself prepends\n\texpect(serverCode.match(/^\\s*import\\s/gm)).toHaveLength(1);\n});\n\ntest(\"keys compiledBundles by the safe module id, not the raw bundle id (experimentalMiddlewareLocaleSplitting)\", () => {\n\t// A bundle id that changes under toSafeModuleId (case-folded + a numeric\n\t// suffix appended for the uppercase letters). trackMessageCall(), the\n\t// client's SSR message guard, and middleware.js all look up\n\t// compiledBundles by this safe id - only createCompiledMessagesObject\n\t// (inside createServerFile) used the raw id instead.\n\tconst bundleId = \"GREETING\";\n\tconst safeModuleId = toSafeModuleId(bundleId);\n\texpect(safeModuleId).not.toBe(bundleId);\n\n\tconst compiledBundles = [\n\t\t{\n\t\t\tbundle: { node: { id: bundleId } },\n\t\t\tmessages: {\n\t\t\t\ten: { code: `export const ${safeModuleId} = () => \"hello\";` },\n\t\t\t},\n\t\t},\n\t] as unknown as CompiledBundleWithMessages[];\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles,\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: true,\n\t\t},\n\t});\n\n\texpect(serverCode).toContain(`\"${safeModuleId}\":{\"en\":`);\n\texpect(serverCode).not.toContain(`\"${bundleId}\":{\"en\":`);\n});\n\ntest(\"a literal '$' in a compiled message does not corrupt the generated file (experimentalMiddlewareLocaleSplitting)\", async () => {\n\tconst directory = await mkdtemp(join(tmpdir(), \"paraglide-server-dollar-\"));\n\ttemporaryDirectories.push(directory);\n\n\t// The compiled message source for locale \"en\" evaluates to the literal\n\t// text \"$\", wrapped in a template literal by the compiler (i.e. it\n\t// contains a backtick immediately followed by a `$` immediately followed\n\t// by another backtick). Passed as a *string* to `code.replace()`, `` $` ``\n\t// is a special replacement pattern (\"insert everything before the\n\t// match\"), which splices the file's own header into the string being\n\t// built and corrupts the generated server file.\n\tconst compiledBundles = [\n\t\t{\n\t\t\tbundle: { node: { id: \"price_symbol\" } },\n\t\t\tmessages: {\n\t\t\t\ten: { code: \"export const price_symbol = () => `$`;\" },\n\t\t\t},\n\t\t},\n\t] as unknown as CompiledBundleWithMessages[];\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles,\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: true,\n\t\t},\n\t});\n\n\t// The message value must survive JSON serialization untouched.\n\texpect(serverCode).toContain('\"price_symbol\":{\"en\":\"() => `$`\"}');\n\n\t// The generated file must still be syntactically valid and importable\n\t// (the bug produces an unterminated string / invalid JS).\n\tawait writeFile(\n\t\tjoin(directory, \"runtime.js\"),\n\t\t`export const serverAsyncLocalStorage = undefined;\nexport const disableAsyncLocalStorage = false;\nexport const experimentalMiddlewareLocaleSplitting = true;\nexport const baseLocale = \"en\";\nexport function isExcludedByRouteStrategy() {\n return true;\n}\nexport function getStrategyForUrl() {\n return [];\n}\nexport async function shouldRedirect() {\n return { locale: \"en\", shouldRedirect: false };\n}\nexport function deLocalizeUrl(url) {\n return url;\n}`\n\t);\n\tawait writeFile(join(directory, \"server.mjs\"), serverCode);\n\n\tawait expect(\n\t\timport(pathToFileURL(join(directory, \"server.mjs\")).href)\n\t).resolves.toBeDefined();\n});\n"]}
|
|
1
|
+
{"version":3,"file":"create-server-file.test.js","sourceRoot":"","sources":["../../../src/compiler/server/create-server-file.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdtemp, rm, writeFile } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { afterEach, expect, test } from \"vitest\";\nimport type { CompiledBundleWithMessages } from \"../compile-bundle.js\";\nimport { toSafeModuleId } from \"../safe-module-id.js\";\nimport { createServerFile } from \"./create-server-file.js\";\n\nconst temporaryDirectories: string[] = [];\n\nafterEach(async () => {\n\tawait Promise.all(\n\t\ttemporaryDirectories\n\t\t\t.splice(0)\n\t\t\t.map((directory) => rm(directory, { recursive: true, force: true }))\n\t);\n});\n\ntest(\"uses the initialized AsyncLocalStorage when an import interceptor snapshots the initial export\", async () => {\n\tconst directory = await mkdtemp(join(tmpdir(), \"paraglide-server-\"));\n\ttemporaryDirectories.push(directory);\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles: [],\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: false,\n\t\t},\n\t}).replace('\"./runtime.js\"', '\"./runtime-wrapper.mjs\"');\n\n\tawait writeFile(join(directory, \"server.mjs\"), serverCode);\n\tawait writeFile(\n\t\tjoin(directory, \"runtime-real.mjs\"),\n\t\t`export let serverAsyncLocalStorage;\nexport const disableAsyncLocalStorage = false;\nexport function overwriteServerAsyncLocalStorage(value) {\n serverAsyncLocalStorage = value;\n}\nexport function getServerAsyncLocalStorage() {\n return serverAsyncLocalStorage;\n}\nexport const baseLocale = \"en\";\nexport function isExcludedByRouteStrategy() {\n return true;\n}`\n\t);\n\tawait writeFile(\n\t\tjoin(directory, \"runtime-wrapper.mjs\"),\n\t\t`import * as runtime from \"./runtime-real.mjs\";\nexport const serverAsyncLocalStorage = runtime.serverAsyncLocalStorage;\nexport const disableAsyncLocalStorage = runtime.disableAsyncLocalStorage;\nexport const overwriteServerAsyncLocalStorage = runtime.overwriteServerAsyncLocalStorage;\nexport const getServerAsyncLocalStorage = runtime.getServerAsyncLocalStorage;\nexport const baseLocale = runtime.baseLocale;\nexport const isExcludedByRouteStrategy = runtime.isExcludedByRouteStrategy;`\n\t);\n\n\tconst server = await import(\n\t\tpathToFileURL(join(directory, \"server.mjs\")).href\n\t);\n\tconst response = await server.paraglideMiddleware(\n\t\tnew Request(\"https://example.com/api/ready\"),\n\t\t() => new Response(\"ready\")\n\t);\n\n\texpect(response.status).toBe(200);\n\texpect(await response.text()).toBe(\"ready\");\n});\n\ntest(\"import statements in JSDoc examples survive in the generated server file\", () => {\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles: [],\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: false,\n\t\t},\n\t});\n\n\texpect(serverCode).toContain(\n\t\t` * import { paraglideMiddleware } from './paraglide/server.js'\\n * import handler from '@tanstack/react-start/server-entry'\\n *\\n * export default {`\n\t);\n\t// only the `import * as runtime` line that createServerFile itself prepends\n\texpect(serverCode.match(/^\\s*import\\s/gm)).toHaveLength(1);\n});\n\ntest(\"keys compiledBundles by the safe module id, not the raw bundle id (experimentalMiddlewareLocaleSplitting)\", () => {\n\t// A bundle id that changes under toSafeModuleId (case-folded + a numeric\n\t// suffix appended for the uppercase letters). trackMessageCall(), the\n\t// client's SSR message guard, and middleware.js all look up\n\t// compiledBundles by this safe id - only createCompiledMessagesObject\n\t// (inside createServerFile) used the raw id instead.\n\tconst bundleId = \"GREETING\";\n\tconst safeModuleId = toSafeModuleId(bundleId);\n\texpect(safeModuleId).not.toBe(bundleId);\n\n\tconst compiledBundles = [\n\t\t{\n\t\t\tbundle: { node: { id: bundleId } },\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: `export const ${safeModuleId} = () => \"hello\";`,\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t] as unknown as CompiledBundleWithMessages[];\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles,\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: true,\n\t\t},\n\t});\n\n\texpect(serverCode).toContain(`\"${safeModuleId}\":{\"en\":`);\n\texpect(serverCode).not.toContain(`\"${bundleId}\":{\"en\":`);\n});\n\ntest(\"a literal '$' in a compiled message does not corrupt the generated file (experimentalMiddlewareLocaleSplitting)\", async () => {\n\tconst directory = await mkdtemp(join(tmpdir(), \"paraglide-server-dollar-\"));\n\ttemporaryDirectories.push(directory);\n\n\t// The compiled message source for locale \"en\" evaluates to the literal\n\t// text \"$\", wrapped in a template literal by the compiler (i.e. it\n\t// contains a backtick immediately followed by a `$` immediately followed\n\t// by another backtick). Passed as a *string* to `code.replace()`, `` $` ``\n\t// is a special replacement pattern (\"insert everything before the\n\t// match\"), which splices the file's own header into the string being\n\t// built and corrupts the generated server file.\n\tconst compiledBundles = [\n\t\t{\n\t\t\tbundle: { node: { id: \"price_symbol\" } },\n\t\t\tmessages: {\n\t\t\t\ten: {\n\t\t\t\t\tcode: \"export const price_symbol = () => `$`;\",\n\t\t\t\t\tregistryFunctions: [],\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t] as unknown as CompiledBundleWithMessages[];\n\n\tconst serverCode = createServerFile({\n\t\tcompiledBundles,\n\t\tcompilerOptions: {\n\t\t\tdisableAsyncLocalStorage: false,\n\t\t\texperimentalMiddlewareLocaleSplitting: true,\n\t\t},\n\t});\n\n\t// The message value must survive JSON serialization untouched.\n\texpect(serverCode).toContain('\"price_symbol\":{\"en\":\"() => `$`\"}');\n\n\t// The generated file must still be syntactically valid and importable\n\t// (the bug produces an unterminated string / invalid JS).\n\tawait writeFile(\n\t\tjoin(directory, \"runtime.js\"),\n\t\t`export const serverAsyncLocalStorage = undefined;\nexport const disableAsyncLocalStorage = false;\nexport const experimentalMiddlewareLocaleSplitting = true;\nexport const baseLocale = \"en\";\nexport function isExcludedByRouteStrategy() {\n return true;\n}\nexport function getStrategyForUrl() {\n return [];\n}\nexport async function shouldRedirect() {\n return { locale: \"en\", shouldRedirect: false };\n}\nexport function deLocalizeUrl(url) {\n return url;\n}`\n\t);\n\tawait writeFile(join(directory, \"server.mjs\"), serverCode);\n\n\tawait expect(\n\t\timport(pathToFileURL(join(directory, \"server.mjs\")).href)\n\t).resolves.toBeDefined();\n});\n"]}
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
* This middleware performs several key functions:
|
|
11
11
|
*
|
|
12
12
|
* 1. Determines the locale for the incoming request using configured strategies
|
|
13
|
-
* 2. Handles URL localization and redirects (only for document requests)
|
|
13
|
+
* 2. Handles URL localization and redirects (only for document requests by default)
|
|
14
14
|
* 3. Maintains locale state using AsyncLocalStorage to prevent request interference
|
|
15
15
|
*
|
|
16
16
|
* When URL strategy is used:
|
|
17
17
|
*
|
|
18
18
|
* - The locale is extracted from the URL for all request types
|
|
19
|
-
* - If URL doesn't match the determined locale, redirects to localized URL (only for document requests)
|
|
19
|
+
* - If URL doesn't match the determined locale, redirects to localized URL (only for document requests by default)
|
|
20
20
|
* - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)
|
|
21
21
|
*
|
|
22
22
|
* @see https://paraglidejs.com/middleware
|
|
@@ -31,8 +31,13 @@
|
|
|
31
31
|
* - `locale`: The determined locale for this request.
|
|
32
32
|
* @param {{
|
|
33
33
|
* effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),
|
|
34
|
+
* redirect?: "document" | "navigation",
|
|
34
35
|
* onRedirect?: (response: Response) => void
|
|
35
36
|
* }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.
|
|
37
|
+
* `redirect` defaults to `"document"`, which requires `Sec-Fetch-Dest: document`.
|
|
38
|
+
* Unrecognized values keep that default behavior.
|
|
39
|
+
* `"navigation"` only redirects GET/HEAD requests, accepting either that destination
|
|
40
|
+
* or an absent destination with an explicit `Accept` header that allows `text/html`.
|
|
36
41
|
* @returns {Promise<Response>}
|
|
37
42
|
*
|
|
38
43
|
* @example
|
|
@@ -94,5 +99,6 @@ export declare function paraglideMiddleware<T>(request: Request, resolve: (args:
|
|
|
94
99
|
locale: import("./runtime.js").Locale;
|
|
95
100
|
}) => T | Promise<T>, options?: {
|
|
96
101
|
effectiveRequestUrl?: string | URL | ((request: Request) => string | URL);
|
|
102
|
+
redirect?: "document" | "navigation";
|
|
97
103
|
onRedirect?: (response: Response) => void;
|
|
98
104
|
}): Promise<Response>;
|
|
@@ -11,13 +11,13 @@ import * as runtime from "./runtime.js";
|
|
|
11
11
|
* This middleware performs several key functions:
|
|
12
12
|
*
|
|
13
13
|
* 1. Determines the locale for the incoming request using configured strategies
|
|
14
|
-
* 2. Handles URL localization and redirects (only for document requests)
|
|
14
|
+
* 2. Handles URL localization and redirects (only for document requests by default)
|
|
15
15
|
* 3. Maintains locale state using AsyncLocalStorage to prevent request interference
|
|
16
16
|
*
|
|
17
17
|
* When URL strategy is used:
|
|
18
18
|
*
|
|
19
19
|
* - The locale is extracted from the URL for all request types
|
|
20
|
-
* - If URL doesn't match the determined locale, redirects to localized URL (only for document requests)
|
|
20
|
+
* - If URL doesn't match the determined locale, redirects to localized URL (only for document requests by default)
|
|
21
21
|
* - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)
|
|
22
22
|
*
|
|
23
23
|
* @see https://paraglidejs.com/middleware
|
|
@@ -32,8 +32,13 @@ import * as runtime from "./runtime.js";
|
|
|
32
32
|
* - `locale`: The determined locale for this request.
|
|
33
33
|
* @param {{
|
|
34
34
|
* effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),
|
|
35
|
+
* redirect?: "document" | "navigation",
|
|
35
36
|
* onRedirect?: (response: Response) => void
|
|
36
37
|
* }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.
|
|
38
|
+
* `redirect` defaults to `"document"`, which requires `Sec-Fetch-Dest: document`.
|
|
39
|
+
* Unrecognized values keep that default behavior.
|
|
40
|
+
* `"navigation"` only redirects GET/HEAD requests, accepting either that destination
|
|
41
|
+
* or an absent destination with an explicit `Accept` header that allows `text/html`.
|
|
37
42
|
* @returns {Promise<Response>}
|
|
38
43
|
*
|
|
39
44
|
* @example
|
|
@@ -103,21 +108,29 @@ export async function paraglideMiddleware(request, resolve, options) {
|
|
|
103
108
|
return /** @type {Response} */ (await requestAsyncLocalStorage?.run({ locale, origin, messageCalls }, () => resolve({ locale, request: newRequest })));
|
|
104
109
|
}
|
|
105
110
|
const strategy = runtime.getStrategyForUrl(url.href);
|
|
111
|
+
const vary = getVaryFields(strategy);
|
|
106
112
|
const decision = await runtime.shouldRedirect({
|
|
107
113
|
request,
|
|
108
114
|
effectiveRequestUrl: url,
|
|
109
115
|
});
|
|
110
116
|
const locale = decision.locale;
|
|
117
|
+
// Custom server strategies run before built-in strategies, regardless of order.
|
|
118
|
+
const hasCustomStrategy = strategy.some((strat) => strat.startsWith("custom-"));
|
|
119
|
+
const urlDecidesLocale = options?.redirect === "navigation" &&
|
|
120
|
+
strategy[0] === "url" &&
|
|
121
|
+
!hasCustomStrategy &&
|
|
122
|
+
runtime.extractLocaleFromUrl(url) !== undefined;
|
|
123
|
+
const navigationVary = options?.redirect === "navigation" ? ["Accept", "Sec-Fetch-Dest"] : [];
|
|
111
124
|
// if the client makes a request to a URL that doesn't match
|
|
112
125
|
// the localizedUrl, redirect the client to the localized URL
|
|
113
|
-
if (request
|
|
126
|
+
if (shouldRedirectRequest(request, options?.redirect) &&
|
|
114
127
|
decision.shouldRedirect &&
|
|
115
128
|
decision.redirectUrl) {
|
|
116
|
-
// Create headers object with Vary header if preferredLanguage strategy is used
|
|
117
129
|
/** @type {Record<string, string>} */
|
|
118
130
|
const headers = {};
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
const redirectVary = [...(urlDecidesLocale ? [] : vary), ...navigationVary];
|
|
132
|
+
if (redirectVary.length > 0) {
|
|
133
|
+
headers["Vary"] = redirectVary.join(", ");
|
|
121
134
|
}
|
|
122
135
|
const response = new Response(null, {
|
|
123
136
|
status: 307,
|
|
@@ -145,29 +158,58 @@ export async function paraglideMiddleware(request, resolve, options) {
|
|
|
145
158
|
// the message functions that have been called in this request
|
|
146
159
|
/** @type {Set<string>} */
|
|
147
160
|
const messageCalls = new Set();
|
|
148
|
-
|
|
161
|
+
let response = await requestAsyncLocalStorage?.run({ locale, origin, messageCalls }, () => resolve({ locale, request: newRequest }));
|
|
162
|
+
if (response instanceof Response) {
|
|
163
|
+
const urlIndex = strategy.indexOf("url");
|
|
164
|
+
const responseVary = urlIndex !== -1 && !hasCustomStrategy && runtime.extractLocaleFromUrl(url)
|
|
165
|
+
? getVaryFields(strategy.slice(0, urlIndex))
|
|
166
|
+
: [...vary];
|
|
167
|
+
// Classifying navigations can change a cached 200 into a redirect.
|
|
168
|
+
if ((request.method === "GET" || request.method === "HEAD") &&
|
|
169
|
+
urlIndex !== -1 &&
|
|
170
|
+
(!urlDecidesLocale || decision.shouldRedirect)) {
|
|
171
|
+
responseVary.push(...navigationVary);
|
|
172
|
+
}
|
|
173
|
+
response = withVary(response, responseVary);
|
|
174
|
+
}
|
|
149
175
|
// Only modify HTML responses
|
|
150
176
|
if (runtime.experimentalMiddlewareLocaleSplitting &&
|
|
177
|
+
typeof response?.headers?.get === "function" &&
|
|
178
|
+
typeof response.text === "function" &&
|
|
179
|
+
!response.bodyUsed &&
|
|
180
|
+
!response.body?.locked &&
|
|
151
181
|
response.headers.get("Content-Type")?.includes("html")) {
|
|
152
182
|
const body = await response.text();
|
|
153
183
|
const messages = [];
|
|
184
|
+
/** @type {Set<string>} */
|
|
185
|
+
const registryFunctionNames = new Set();
|
|
154
186
|
// using .values() to avoid polyfilling in older projects. else the following error is thrown
|
|
155
187
|
// Type 'Set<string>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.
|
|
156
188
|
for (const messageCall of Array.from(messageCalls)) {
|
|
157
189
|
const [id, locale] =
|
|
158
190
|
/** @type {[string, import("./runtime.js").Locale]} */ (messageCall.split(":"));
|
|
159
191
|
messages.push(`${id}: ${compiledBundles[id]?.[locale]}`);
|
|
192
|
+
for (const name of compiledRegistry.messages[id]?.[locale] ?? []) {
|
|
193
|
+
registryFunctionNames.add(name);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// The injected messages run without registry.js. Declare the registry
|
|
197
|
+
// functions they call (including the ones those call) in a closure.
|
|
198
|
+
let ssr = `{ ${messages.join(",")} }`;
|
|
199
|
+
if (registryFunctionNames.size > 0) {
|
|
200
|
+
const names = Array.from(registryFunctionNames);
|
|
201
|
+
ssr = `(() => { ${names
|
|
202
|
+
.map((name) => compiledRegistry.functions[name])
|
|
203
|
+
.join("\n")}\nconst registry = { ${names.join(", ")} };\nreturn ${ssr} })()`;
|
|
160
204
|
}
|
|
161
205
|
// Prevent translated content from terminating the inline script tag.
|
|
162
|
-
const
|
|
163
|
-
.join(",")
|
|
164
|
-
.replace(/<\/(script)/gi, "<\\/$1");
|
|
206
|
+
const escapedSsr = ssr.replace(/<\/(script)/gi, "<\\/$1");
|
|
165
207
|
// Reuse the request's CSP nonce (if any) so the injected script is allowed under a strict CSP
|
|
166
208
|
const nonce = response.headers
|
|
167
209
|
.get("Content-Security-Policy")
|
|
168
210
|
?.match(/'nonce-([\w+/=-]+)'/)?.[1];
|
|
169
211
|
const nonceAttr = nonce ? `nonce="${nonce}"` : "";
|
|
170
|
-
const script = `<script ${nonceAttr}>globalThis.__paraglide = globalThis.__paraglide ?? {}; globalThis.__paraglide.ssr =
|
|
212
|
+
const script = `<script ${nonceAttr}>globalThis.__paraglide = globalThis.__paraglide ?? {}; globalThis.__paraglide.ssr = ${escapedSsr}</script>`;
|
|
171
213
|
// Insert the script before the closing head tag
|
|
172
214
|
const newBody = body.replace("</head>", `${script}</head>`);
|
|
173
215
|
// Create a new response with the modified body
|
|
@@ -182,6 +224,144 @@ export async function paraglideMiddleware(request, resolve, options) {
|
|
|
182
224
|
}
|
|
183
225
|
return response;
|
|
184
226
|
}
|
|
227
|
+
/**
|
|
228
|
+
* @param {string[]} strategy
|
|
229
|
+
* @returns {string[]}
|
|
230
|
+
*/
|
|
231
|
+
function getVaryFields(strategy) {
|
|
232
|
+
/** @type {string[]} */
|
|
233
|
+
const vary = [];
|
|
234
|
+
if (strategy.includes("cookie"))
|
|
235
|
+
vary.push("Cookie");
|
|
236
|
+
if (strategy.includes("preferredLanguage"))
|
|
237
|
+
vary.push("Accept-Language");
|
|
238
|
+
return vary;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* @param {Response} response
|
|
242
|
+
* @param {string[]} vary
|
|
243
|
+
* @returns {Response}
|
|
244
|
+
*/
|
|
245
|
+
function withVary(response, vary) {
|
|
246
|
+
// Network errors and protocol upgrades are not ordinary HTTP responses.
|
|
247
|
+
if (response.status < 200 || response.status > 599)
|
|
248
|
+
return response;
|
|
249
|
+
const existing = response.headers.get("Vary");
|
|
250
|
+
const fields = existing?.split(",").map((field) => field.trim().toLowerCase()) ?? [];
|
|
251
|
+
if (fields.includes("*"))
|
|
252
|
+
return response;
|
|
253
|
+
const missing = vary.filter((field) => !fields.includes(field.toLowerCase()));
|
|
254
|
+
if (missing.length === 0)
|
|
255
|
+
return response;
|
|
256
|
+
const value = [existing, ...missing].filter(Boolean).join(", ");
|
|
257
|
+
try {
|
|
258
|
+
response.headers.set("Vary", value);
|
|
259
|
+
return response;
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (!(error instanceof TypeError))
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
// Responses from fetch() or Response.redirect() can have immutable headers.
|
|
266
|
+
try {
|
|
267
|
+
// Preserve runtime-specific response state, including Workers body encoding.
|
|
268
|
+
const copy = new Response(response.body, response);
|
|
269
|
+
copy.headers.set("Vary", value);
|
|
270
|
+
return copyResponseMetadata(copy, response);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// Keep callback responses whose body cannot be reused.
|
|
274
|
+
return response;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* @param {Response} target
|
|
279
|
+
* @param {Response} source
|
|
280
|
+
* @returns {Response}
|
|
281
|
+
*/
|
|
282
|
+
function copyResponseMetadata(target, source) {
|
|
283
|
+
// ResponseInit omits fetch metadata, so clones need to retain it as well.
|
|
284
|
+
return Object.defineProperties(target, {
|
|
285
|
+
url: { value: source.url, configurable: true },
|
|
286
|
+
redirected: { value: source.redirected, configurable: true },
|
|
287
|
+
type: { value: source.type, configurable: true },
|
|
288
|
+
clone: {
|
|
289
|
+
configurable: true,
|
|
290
|
+
writable: true,
|
|
291
|
+
/** @this {Response} */
|
|
292
|
+
value() {
|
|
293
|
+
return copyResponseMetadata(Response.prototype.clone.call(this), this);
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* @param {Request} request
|
|
300
|
+
* @param {"document" | "navigation"} [redirect]
|
|
301
|
+
* @returns {boolean}
|
|
302
|
+
*/
|
|
303
|
+
function shouldRedirectRequest(request, redirect) {
|
|
304
|
+
const destination = request.headers.get("Sec-Fetch-Dest");
|
|
305
|
+
if (redirect !== "navigation")
|
|
306
|
+
return destination === "document";
|
|
307
|
+
if (request.method !== "GET" && request.method !== "HEAD")
|
|
308
|
+
return false;
|
|
309
|
+
if (destination !== null)
|
|
310
|
+
return destination === "document";
|
|
311
|
+
let specificity = -1;
|
|
312
|
+
let quality = 0;
|
|
313
|
+
for (const range of splitHeaderValue(request.headers.get("Accept") ?? "", ",")) {
|
|
314
|
+
const [type, ...parameters] = splitHeaderValue(range, ";").map((part) => part.trim().toLowerCase());
|
|
315
|
+
const rangeSpecificity = type === "text/html"
|
|
316
|
+
? 2
|
|
317
|
+
: type === "text/*"
|
|
318
|
+
? 1
|
|
319
|
+
: type === "*/*"
|
|
320
|
+
? 0
|
|
321
|
+
: -1;
|
|
322
|
+
if (rangeSpecificity < 0 || rangeSpecificity < specificity)
|
|
323
|
+
continue;
|
|
324
|
+
const weight = parameters.find((parameter) => /^q\s*=/.test(parameter));
|
|
325
|
+
const value = weight ? weight.slice(weight.indexOf("=") + 1).trim() : "1";
|
|
326
|
+
const rangeQuality = /^(?:0(?:\.\d{0,3})?|1(?:\.0{0,3})?)$/.test(value)
|
|
327
|
+
? Number(value)
|
|
328
|
+
: 0;
|
|
329
|
+
// A specific q=0 exclusion takes precedence over an acceptable wildcard.
|
|
330
|
+
quality =
|
|
331
|
+
rangeSpecificity > specificity
|
|
332
|
+
? rangeQuality
|
|
333
|
+
: Math.max(quality, rangeQuality);
|
|
334
|
+
specificity = rangeSpecificity;
|
|
335
|
+
}
|
|
336
|
+
return quality > 0;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* @param {string} value
|
|
340
|
+
* @param {string} separator
|
|
341
|
+
* @returns {string[]}
|
|
342
|
+
*/
|
|
343
|
+
function splitHeaderValue(value, separator) {
|
|
344
|
+
const parts = [];
|
|
345
|
+
let start = 0;
|
|
346
|
+
let quoted = false;
|
|
347
|
+
for (let index = 0; index < value.length; index++) {
|
|
348
|
+
const character = value[index];
|
|
349
|
+
if (quoted && character === "\\") {
|
|
350
|
+
index++;
|
|
351
|
+
}
|
|
352
|
+
else if (character === '"') {
|
|
353
|
+
quoted = !quoted;
|
|
354
|
+
}
|
|
355
|
+
else if (!quoted && character === separator) {
|
|
356
|
+
parts.push(value.slice(start, index));
|
|
357
|
+
start = index + 1;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
if (quoted)
|
|
361
|
+
return [];
|
|
362
|
+
parts.push(value.slice(start));
|
|
363
|
+
return parts;
|
|
364
|
+
}
|
|
185
365
|
/**
|
|
186
366
|
* @param {Request} request
|
|
187
367
|
* @param {string | URL | ((request: Request) => string | URL) | undefined} effectiveRequestUrl
|
|
@@ -279,4 +459,17 @@ void createMockAsyncLocalStorage;
|
|
|
279
459
|
* @type {Record<string, Record<import("./runtime.js").Locale, string>>}
|
|
280
460
|
*/
|
|
281
461
|
const compiledBundles = {};
|
|
462
|
+
/**
|
|
463
|
+
* The registry functions the compiled messages call, for the injected
|
|
464
|
+
* messages that run without registry.js.
|
|
465
|
+
*
|
|
466
|
+
* `messages[id][locale]` lists the registry functions a message calls,
|
|
467
|
+
* including the ones those call. `functions[name]` is the code of a registry
|
|
468
|
+
* function.
|
|
469
|
+
*
|
|
470
|
+
* Only populated if `enableMiddlewareOptimizations` is set to `true`.
|
|
471
|
+
*
|
|
472
|
+
* @type {{ functions: Record<string, string>, messages: Record<string, Record<string, string[]>> }}
|
|
473
|
+
*/
|
|
474
|
+
const compiledRegistry = { functions: {}, messages: {} };
|
|
282
475
|
//# sourceMappingURL=middleware.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/compiler/server/middleware.js"],"names":[],"mappings":"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","sourcesContent":["import * as runtime from \"./runtime.js\";\n\n/**\n * Server middleware that handles locale-based routing and request processing.\n *\n * Configure `disableAsyncLocalStorage` when generating Paraglide with\n * `paraglideVitePlugin()` or `compile()`, not when calling\n * `paraglideMiddleware()`. Keep AsyncLocalStorage enabled by default and\n * only disable it for runtimes that lack `AsyncLocalStorage` support and\n * guarantee request isolation.\n *\n * This middleware performs several key functions:\n *\n * 1. Determines the locale for the incoming request using configured strategies\n * 2. Handles URL localization and redirects (only for document requests)\n * 3. Maintains locale state using AsyncLocalStorage to prevent request interference\n *\n * When URL strategy is used:\n *\n * - The locale is extracted from the URL for all request types\n * - If URL doesn't match the determined locale, redirects to localized URL (only for document requests)\n * - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)\n *\n * @see https://paraglidejs.com/middleware\n *\n * @template T - The return type of the resolve function\n *\n * @param {Request} request - The incoming request object\n * @param {(args: { request: Request, locale: import(\"./runtime.js\").Locale }) => T | Promise<T>} resolve - Function to handle the request. The callback receives:\n * - `request`: A modified request with a delocalized URL when the URL strategy is used (e.g., `/fr/about` → `/about`).\n * If your framework handles URL localization itself (e.g., TanStack Router's `rewrite` option), use the original\n * request instead to avoid redirect loops.\n * - `locale`: The determined locale for this request.\n * @param {{\n * effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),\n * onRedirect?: (response: Response) => void\n * }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.\n * @returns {Promise<Response>}\n *\n * @example\n * ```typescript\n * // Basic usage in metaframeworks like NextJS, SvelteKit, Astro, Nuxt, etc.\n * export const handle = async ({ event, resolve }) => {\n * return paraglideMiddleware(event.request, ({ request, locale }) => {\n * // let the framework further resolve the request\n * return resolve(request);\n * });\n * };\n * ```\n *\n * @example\n * ```typescript\n * // Usage in a framework like Express JS or Hono\n * app.use(async (req, res, next) => {\n * const result = await paraglideMiddleware(req, ({ request, locale }) => {\n * // If a redirect happens this won't be called\n * return next(request);\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Usage with frameworks that handle URL localization/delocalization themselves\n * //\n * // Some frameworks like TanStack Router handle URL localization and delocalization\n * // themselves via their own rewrite APIs (e.g., `rewrite.input`/`rewrite.output`).\n * //\n * // When the framework handles this, the middleware's URL delocalization is not needed.\n * // Using the modified `request` from the callback would cause a redirect loop because\n * // both the middleware and the framework would attempt to delocalize the URL.\n * //\n * // Solution: Pass the original request to the handler instead of the modified one.\n * // The middleware still handles locale detection, cookies, and AsyncLocalStorage context.\n * //\n * // ❌ WRONG - causes redirect loop when framework handles URL rewriting:\n * // paraglideMiddleware(req, ({ request }) => handler.fetch(request))\n * //\n * // ✅ CORRECT - use original request when framework handles URL localization:\n * // paraglideMiddleware(req, () => handler.fetch(req))\n *\n * import { paraglideMiddleware } from './paraglide/server.js'\n * import handler from '@tanstack/react-start/server-entry'\n *\n * export default {\n * fetch(req: Request): Promise<Response> {\n * // TanStack Router handles URL rewriting via deLocalizeUrl/localizeUrl\n * // so we pass the original `req` instead of the modified `request`\n * return paraglideMiddleware(req, () => handler.fetch(req))\n * },\n * }\n * ```\n */\nexport async function paraglideMiddleware(request, resolve, options) {\n\tlet requestAsyncLocalStorage = runtime.serverAsyncLocalStorage;\n\t// %async-local-storage\n\tconst url = resolveMiddlewareUrl(request, options?.effectiveRequestUrl);\n\tconst origin = url.origin;\n\n\tif (runtime.isExcludedByRouteStrategy(url.href)) {\n\t\tconst locale = runtime.baseLocale;\n\t\tconst newRequest = cloneRequestWithFallback(request, url);\n\t\t/** @type {Set<string>} */\n\t\tconst messageCalls = new Set();\n\t\treturn /** @type {Response} */ (\n\t\t\tawait requestAsyncLocalStorage?.run(\n\t\t\t\t{ locale, origin, messageCalls },\n\t\t\t\t() => resolve({ locale, request: newRequest })\n\t\t\t)\n\t\t);\n\t}\n\n\tconst strategy = runtime.getStrategyForUrl(url.href);\n\tconst decision = await runtime.shouldRedirect({\n\t\trequest,\n\t\teffectiveRequestUrl: url,\n\t});\n\tconst locale = decision.locale;\n\n\t// if the client makes a request to a URL that doesn't match\n\t// the localizedUrl, redirect the client to the localized URL\n\tif (\n\t\trequest.headers.get(\"Sec-Fetch-Dest\") === \"document\" &&\n\t\tdecision.shouldRedirect &&\n\t\tdecision.redirectUrl\n\t) {\n\t\t// Create headers object with Vary header if preferredLanguage strategy is used\n\t\t/** @type {Record<string, string>} */\n\t\tconst headers = {};\n\t\tif (strategy.includes(\"preferredLanguage\")) {\n\t\t\theaders[\"Vary\"] = \"Accept-Language\";\n\t\t}\n\n\t\tconst response = new Response(null, {\n\t\t\tstatus: 307,\n\t\t\theaders: {\n\t\t\t\tLocation: decision.redirectUrl.href,\n\t\t\t\t...headers,\n\t\t\t},\n\t\t});\n\n\t\toptions?.onRedirect?.(response);\n\t\treturn response;\n\t}\n\n\t// If the strategy includes \"url\", we need to de-localize the URL\n\t// before passing it to the server middleware.\n\t//\n\t// The middleware is responsible for mapping a localized URL to the\n\t// de-localized URL e.g. `/en/about` to `/about`. Otherwise,\n\t// the server can't render the correct page.\n\tlet newRequest;\n\tif (strategy.includes(\"url\")) {\n\t\tnewRequest = cloneRequestWithFallback(request, runtime.deLocalizeUrl(url));\n\t} else {\n\t\tnewRequest = cloneRequestWithFallback(request, url);\n\t}\n\n\t// the message functions that have been called in this request\n\t/** @type {Set<string>} */\n\tconst messageCalls = new Set();\n\n\tconst response = await requestAsyncLocalStorage?.run(\n\t\t{ locale, origin, messageCalls },\n\t\t() => resolve({ locale, request: newRequest })\n\t);\n\n\t// Only modify HTML responses\n\tif (\n\t\truntime.experimentalMiddlewareLocaleSplitting &&\n\t\tresponse.headers.get(\"Content-Type\")?.includes(\"html\")\n\t) {\n\t\tconst body = await response.text();\n\n\t\tconst messages = [];\n\n\t\t// using .values() to avoid polyfilling in older projects. else the following error is thrown\n\t\t// Type 'Set<string>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.\n\t\tfor (const messageCall of Array.from(messageCalls)) {\n\t\t\tconst [id, locale] =\n\t\t\t\t/** @type {[string, import(\"./runtime.js\").Locale]} */ (\n\t\t\t\t\tmessageCall.split(\":\")\n\t\t\t\t);\n\t\t\tmessages.push(`${id}: ${compiledBundles[id]?.[locale]}`);\n\t\t}\n\n\t\t// Prevent translated content from terminating the inline script tag.\n\t\tconst escapedMessages = messages\n\t\t\t.join(\",\")\n\t\t\t.replace(/<\\/(script)/gi, \"<\\\\/$1\");\n\t\t// Reuse the request's CSP nonce (if any) so the injected script is allowed under a strict CSP\n\t\tconst nonce = response.headers\n\t\t\t.get(\"Content-Security-Policy\")\n\t\t\t?.match(/'nonce-([\\w+/=-]+)'/)?.[1];\n\t\tconst nonceAttr = nonce ? `nonce=\"${nonce}\"` : \"\";\n\t\tconst script = `<script ${nonceAttr}>globalThis.__paraglide = globalThis.__paraglide ?? {}; globalThis.__paraglide.ssr = { ${escapedMessages} }</script>`;\n\n\t\t// Insert the script before the closing head tag\n\t\tconst newBody = body.replace(\"</head>\", `${script}</head>`);\n\n\t\t// Create a new response with the modified body\n\t\t// Clone all headers except Content-Length which will be set automatically\n\t\tconst newHeaders = new Headers(response.headers);\n\t\tnewHeaders.delete(\"Content-Length\"); // Let the browser calculate the correct length\n\n\t\treturn new Response(newBody, {\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: newHeaders,\n\t\t});\n\t}\n\n\treturn response;\n}\n\n/**\n * @param {Request} request\n * @param {string | URL | ((request: Request) => string | URL) | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveMiddlewareUrl(request, effectiveRequestUrl) {\n\tif (typeof effectiveRequestUrl === \"function\") {\n\t\treturn new URL(effectiveRequestUrl(request), request.url);\n\t}\n\n\tif (\n\t\ttypeof effectiveRequestUrl === \"string\" ||\n\t\teffectiveRequestUrl instanceof URL\n\t) {\n\t\treturn new URL(effectiveRequestUrl, request.url);\n\t}\n\n\treturn new URL(request.url);\n}\n\n/**\n * Some metaframeworks (NextJS) require a new Request object.\n * https://github.com/opral/inlang-paraglide-js/issues/411\n *\n * However, some frameworks (TanStack Start 1.143+) use custom Request\n * implementations that cannot be cloned with `new Request(request)`.\n * https://github.com/opral/paraglide-js/issues/573\n *\n * Effective request URL overrides behind proxies:\n * https://github.com/opral/paraglide-js/issues/652\n *\n * @param {Request} request\n * @param {string | URL} [url]\n * @returns {Request}\n */\nfunction cloneRequestWithFallback(request, url = request.url) {\n\tconst targetUrl = typeof url === \"string\" ? url : url.href;\n\tif (targetUrl === request.url) {\n\t\ttry {\n\t\t\t// Clone first so building a new Request does not consume the original body stream.\n\t\t\treturn new Request(request.clone());\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\treturn new Request(request);\n\t\t\t} catch {\n\t\t\t\treturn request;\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\t// Clone first so building a new Request does not consume the original body stream.\n\t\treturn new Request(targetUrl, request.clone());\n\t} catch {\n\t\ttry {\n\t\t\treturn new Request(targetUrl, request);\n\t\t} catch {\n\t\t\treturn request;\n\t\t}\n\t}\n}\n\n/**\n * Creates a mock AsyncLocalStorage implementation for environments where\n * native AsyncLocalStorage is not available or disabled.\n *\n * This mock implementation mimics the behavior of the native AsyncLocalStorage\n * but doesn't require the async_hooks module. It's used as a fallback when\n * the runtime does not expose AsyncLocalStorage or when it has been disabled.\n *\n * @returns {import(\"./runtime.js\").ParaglideAsyncLocalStorage}\n */\nfunction createMockAsyncLocalStorage() {\n\t/** @type {any} */\n\tlet currentStore = undefined;\n\treturn {\n\t\tgetStore() {\n\t\t\treturn currentStore;\n\t\t},\n\t\tasync run(store, callback) {\n\t\t\tcurrentStore = store;\n\t\t\ttry {\n\t\t\t\treturn await callback();\n\t\t\t} finally {\n\t\t\t\tcurrentStore = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n\n// Used in generated server.js when async local storage is disabled.\nvoid createMockAsyncLocalStorage;\n\n/**\n * The compiled messages for the server middleware.\n *\n * Only populated if `enableMiddlewareOptimizations` is set to `true`.\n *\n * @type {Record<string, Record<import(\"./runtime.js\").Locale, string>>}\n */\nconst compiledBundles = {};\n"]}
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/compiler/server/middleware.js"],"names":[],"mappings":"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","sourcesContent":["import * as runtime from \"./runtime.js\";\n\n/**\n * Server middleware that handles locale-based routing and request processing.\n *\n * Configure `disableAsyncLocalStorage` when generating Paraglide with\n * `paraglideVitePlugin()` or `compile()`, not when calling\n * `paraglideMiddleware()`. Keep AsyncLocalStorage enabled by default and\n * only disable it for runtimes that lack `AsyncLocalStorage` support and\n * guarantee request isolation.\n *\n * This middleware performs several key functions:\n *\n * 1. Determines the locale for the incoming request using configured strategies\n * 2. Handles URL localization and redirects (only for document requests by default)\n * 3. Maintains locale state using AsyncLocalStorage to prevent request interference\n *\n * When URL strategy is used:\n *\n * - The locale is extracted from the URL for all request types\n * - If URL doesn't match the determined locale, redirects to localized URL (only for document requests by default)\n * - De-localizes URLs before passing to server (e.g., `/fr/about` → `/about`)\n *\n * @see https://paraglidejs.com/middleware\n *\n * @template T - The return type of the resolve function\n *\n * @param {Request} request - The incoming request object\n * @param {(args: { request: Request, locale: import(\"./runtime.js\").Locale }) => T | Promise<T>} resolve - Function to handle the request. The callback receives:\n * - `request`: A modified request with a delocalized URL when the URL strategy is used (e.g., `/fr/about` → `/about`).\n * If your framework handles URL localization itself (e.g., TanStack Router's `rewrite` option), use the original\n * request instead to avoid redirect loops.\n * - `locale`: The determined locale for this request.\n * @param {{\n * effectiveRequestUrl?: string | URL | ((request: Request) => string | URL),\n * redirect?: \"document\" | \"navigation\",\n * onRedirect?: (response: Response) => void\n * }} [options] - Options to control middleware behavior. `effectiveRequestUrl` sets the effective request URL used for route matching, URL-based locale detection, redirects, and `getUrlOrigin()`.\n * `redirect` defaults to `\"document\"`, which requires `Sec-Fetch-Dest: document`.\n * Unrecognized values keep that default behavior.\n * `\"navigation\"` only redirects GET/HEAD requests, accepting either that destination\n * or an absent destination with an explicit `Accept` header that allows `text/html`.\n * @returns {Promise<Response>}\n *\n * @example\n * ```typescript\n * // Basic usage in metaframeworks like NextJS, SvelteKit, Astro, Nuxt, etc.\n * export const handle = async ({ event, resolve }) => {\n * return paraglideMiddleware(event.request, ({ request, locale }) => {\n * // let the framework further resolve the request\n * return resolve(request);\n * });\n * };\n * ```\n *\n * @example\n * ```typescript\n * // Usage in a framework like Express JS or Hono\n * app.use(async (req, res, next) => {\n * const result = await paraglideMiddleware(req, ({ request, locale }) => {\n * // If a redirect happens this won't be called\n * return next(request);\n * });\n * });\n * ```\n *\n * @example\n * ```typescript\n * // Usage with frameworks that handle URL localization/delocalization themselves\n * //\n * // Some frameworks like TanStack Router handle URL localization and delocalization\n * // themselves via their own rewrite APIs (e.g., `rewrite.input`/`rewrite.output`).\n * //\n * // When the framework handles this, the middleware's URL delocalization is not needed.\n * // Using the modified `request` from the callback would cause a redirect loop because\n * // both the middleware and the framework would attempt to delocalize the URL.\n * //\n * // Solution: Pass the original request to the handler instead of the modified one.\n * // The middleware still handles locale detection, cookies, and AsyncLocalStorage context.\n * //\n * // ❌ WRONG - causes redirect loop when framework handles URL rewriting:\n * // paraglideMiddleware(req, ({ request }) => handler.fetch(request))\n * //\n * // ✅ CORRECT - use original request when framework handles URL localization:\n * // paraglideMiddleware(req, () => handler.fetch(req))\n *\n * import { paraglideMiddleware } from './paraglide/server.js'\n * import handler from '@tanstack/react-start/server-entry'\n *\n * export default {\n * fetch(req: Request): Promise<Response> {\n * // TanStack Router handles URL rewriting via deLocalizeUrl/localizeUrl\n * // so we pass the original `req` instead of the modified `request`\n * return paraglideMiddleware(req, () => handler.fetch(req))\n * },\n * }\n * ```\n */\nexport async function paraglideMiddleware(request, resolve, options) {\n\tlet requestAsyncLocalStorage = runtime.serverAsyncLocalStorage;\n\t// %async-local-storage\n\tconst url = resolveMiddlewareUrl(request, options?.effectiveRequestUrl);\n\tconst origin = url.origin;\n\n\tif (runtime.isExcludedByRouteStrategy(url.href)) {\n\t\tconst locale = runtime.baseLocale;\n\t\tconst newRequest = cloneRequestWithFallback(request, url);\n\t\t/** @type {Set<string>} */\n\t\tconst messageCalls = new Set();\n\t\treturn /** @type {Response} */ (\n\t\t\tawait requestAsyncLocalStorage?.run(\n\t\t\t\t{ locale, origin, messageCalls },\n\t\t\t\t() => resolve({ locale, request: newRequest })\n\t\t\t)\n\t\t);\n\t}\n\n\tconst strategy = runtime.getStrategyForUrl(url.href);\n\tconst vary = getVaryFields(strategy);\n\tconst decision = await runtime.shouldRedirect({\n\t\trequest,\n\t\teffectiveRequestUrl: url,\n\t});\n\tconst locale = decision.locale;\n\t// Custom server strategies run before built-in strategies, regardless of order.\n\tconst hasCustomStrategy = strategy.some((strat) =>\n\t\tstrat.startsWith(\"custom-\")\n\t);\n\tconst urlDecidesLocale =\n\t\toptions?.redirect === \"navigation\" &&\n\t\tstrategy[0] === \"url\" &&\n\t\t!hasCustomStrategy &&\n\t\truntime.extractLocaleFromUrl(url) !== undefined;\n\tconst navigationVary =\n\t\toptions?.redirect === \"navigation\" ? [\"Accept\", \"Sec-Fetch-Dest\"] : [];\n\n\t// if the client makes a request to a URL that doesn't match\n\t// the localizedUrl, redirect the client to the localized URL\n\tif (\n\t\tshouldRedirectRequest(request, options?.redirect) &&\n\t\tdecision.shouldRedirect &&\n\t\tdecision.redirectUrl\n\t) {\n\t\t/** @type {Record<string, string>} */\n\t\tconst headers = {};\n\t\tconst redirectVary = [...(urlDecidesLocale ? [] : vary), ...navigationVary];\n\t\tif (redirectVary.length > 0) {\n\t\t\theaders[\"Vary\"] = redirectVary.join(\", \");\n\t\t}\n\n\t\tconst response = new Response(null, {\n\t\t\tstatus: 307,\n\t\t\theaders: {\n\t\t\t\tLocation: decision.redirectUrl.href,\n\t\t\t\t...headers,\n\t\t\t},\n\t\t});\n\n\t\toptions?.onRedirect?.(response);\n\t\treturn response;\n\t}\n\n\t// If the strategy includes \"url\", we need to de-localize the URL\n\t// before passing it to the server middleware.\n\t//\n\t// The middleware is responsible for mapping a localized URL to the\n\t// de-localized URL e.g. `/en/about` to `/about`. Otherwise,\n\t// the server can't render the correct page.\n\tlet newRequest;\n\tif (strategy.includes(\"url\")) {\n\t\tnewRequest = cloneRequestWithFallback(request, runtime.deLocalizeUrl(url));\n\t} else {\n\t\tnewRequest = cloneRequestWithFallback(request, url);\n\t}\n\n\t// the message functions that have been called in this request\n\t/** @type {Set<string>} */\n\tconst messageCalls = new Set();\n\n\tlet response = await requestAsyncLocalStorage?.run(\n\t\t{ locale, origin, messageCalls },\n\t\t() => resolve({ locale, request: newRequest })\n\t);\n\n\tif (response instanceof Response) {\n\t\tconst urlIndex = strategy.indexOf(\"url\");\n\t\tconst responseVary =\n\t\t\turlIndex !== -1 && !hasCustomStrategy && runtime.extractLocaleFromUrl(url)\n\t\t\t\t? getVaryFields(strategy.slice(0, urlIndex))\n\t\t\t\t: [...vary];\n\t\t// Classifying navigations can change a cached 200 into a redirect.\n\t\tif (\n\t\t\t(request.method === \"GET\" || request.method === \"HEAD\") &&\n\t\t\turlIndex !== -1 &&\n\t\t\t(!urlDecidesLocale || decision.shouldRedirect)\n\t\t) {\n\t\t\tresponseVary.push(...navigationVary);\n\t\t}\n\t\tresponse = withVary(response, responseVary);\n\t}\n\n\t// Only modify HTML responses\n\tif (\n\t\truntime.experimentalMiddlewareLocaleSplitting &&\n\t\ttypeof response?.headers?.get === \"function\" &&\n\t\ttypeof response.text === \"function\" &&\n\t\t!response.bodyUsed &&\n\t\t!response.body?.locked &&\n\t\tresponse.headers.get(\"Content-Type\")?.includes(\"html\")\n\t) {\n\t\tconst body = await response.text();\n\n\t\tconst messages = [];\n\t\t/** @type {Set<string>} */\n\t\tconst registryFunctionNames = new Set();\n\n\t\t// using .values() to avoid polyfilling in older projects. else the following error is thrown\n\t\t// Type 'Set<string>' can only be iterated through when using the '--downlevelIteration' flag or with a '--target' of 'es2015' or higher.\n\t\tfor (const messageCall of Array.from(messageCalls)) {\n\t\t\tconst [id, locale] =\n\t\t\t\t/** @type {[string, import(\"./runtime.js\").Locale]} */ (\n\t\t\t\t\tmessageCall.split(\":\")\n\t\t\t\t);\n\t\t\tmessages.push(`${id}: ${compiledBundles[id]?.[locale]}`);\n\t\t\tfor (const name of compiledRegistry.messages[id]?.[locale] ?? []) {\n\t\t\t\tregistryFunctionNames.add(name);\n\t\t\t}\n\t\t}\n\n\t\t// The injected messages run without registry.js. Declare the registry\n\t\t// functions they call (including the ones those call) in a closure.\n\t\tlet ssr = `{ ${messages.join(\",\")} }`;\n\t\tif (registryFunctionNames.size > 0) {\n\t\t\tconst names = Array.from(registryFunctionNames);\n\t\t\tssr = `(() => { ${names\n\t\t\t\t.map((name) => compiledRegistry.functions[name])\n\t\t\t\t.join(\n\t\t\t\t\t\"\\n\"\n\t\t\t\t)}\\nconst registry = { ${names.join(\", \")} };\\nreturn ${ssr} })()`;\n\t\t}\n\n\t\t// Prevent translated content from terminating the inline script tag.\n\t\tconst escapedSsr = ssr.replace(/<\\/(script)/gi, \"<\\\\/$1\");\n\t\t// Reuse the request's CSP nonce (if any) so the injected script is allowed under a strict CSP\n\t\tconst nonce = response.headers\n\t\t\t.get(\"Content-Security-Policy\")\n\t\t\t?.match(/'nonce-([\\w+/=-]+)'/)?.[1];\n\t\tconst nonceAttr = nonce ? `nonce=\"${nonce}\"` : \"\";\n\t\tconst script = `<script ${nonceAttr}>globalThis.__paraglide = globalThis.__paraglide ?? {}; globalThis.__paraglide.ssr = ${escapedSsr}</script>`;\n\n\t\t// Insert the script before the closing head tag\n\t\tconst newBody = body.replace(\"</head>\", `${script}</head>`);\n\n\t\t// Create a new response with the modified body\n\t\t// Clone all headers except Content-Length which will be set automatically\n\t\tconst newHeaders = new Headers(response.headers);\n\t\tnewHeaders.delete(\"Content-Length\"); // Let the browser calculate the correct length\n\n\t\treturn new Response(newBody, {\n\t\t\tstatus: response.status,\n\t\t\tstatusText: response.statusText,\n\t\t\theaders: newHeaders,\n\t\t});\n\t}\n\n\treturn response;\n}\n\n/**\n * @param {string[]} strategy\n * @returns {string[]}\n */\nfunction getVaryFields(strategy) {\n\t/** @type {string[]} */\n\tconst vary = [];\n\tif (strategy.includes(\"cookie\")) vary.push(\"Cookie\");\n\tif (strategy.includes(\"preferredLanguage\")) vary.push(\"Accept-Language\");\n\treturn vary;\n}\n\n/**\n * @param {Response} response\n * @param {string[]} vary\n * @returns {Response}\n */\nfunction withVary(response, vary) {\n\t// Network errors and protocol upgrades are not ordinary HTTP responses.\n\tif (response.status < 200 || response.status > 599) return response;\n\tconst existing = response.headers.get(\"Vary\");\n\tconst fields =\n\t\texisting?.split(\",\").map((field) => field.trim().toLowerCase()) ?? [];\n\tif (fields.includes(\"*\")) return response;\n\tconst missing = vary.filter((field) => !fields.includes(field.toLowerCase()));\n\tif (missing.length === 0) return response;\n\tconst value = [existing, ...missing].filter(Boolean).join(\", \");\n\n\ttry {\n\t\tresponse.headers.set(\"Vary\", value);\n\t\treturn response;\n\t} catch (error) {\n\t\tif (!(error instanceof TypeError)) throw error;\n\t}\n\n\t// Responses from fetch() or Response.redirect() can have immutable headers.\n\ttry {\n\t\t// Preserve runtime-specific response state, including Workers body encoding.\n\t\tconst copy = new Response(response.body, response);\n\t\tcopy.headers.set(\"Vary\", value);\n\t\treturn copyResponseMetadata(copy, response);\n\t} catch {\n\t\t// Keep callback responses whose body cannot be reused.\n\t\treturn response;\n\t}\n}\n\n/**\n * @param {Response} target\n * @param {Response} source\n * @returns {Response}\n */\nfunction copyResponseMetadata(target, source) {\n\t// ResponseInit omits fetch metadata, so clones need to retain it as well.\n\treturn Object.defineProperties(target, {\n\t\turl: { value: source.url, configurable: true },\n\t\tredirected: { value: source.redirected, configurable: true },\n\t\ttype: { value: source.type, configurable: true },\n\t\tclone: {\n\t\t\tconfigurable: true,\n\t\t\twritable: true,\n\t\t\t/** @this {Response} */\n\t\t\tvalue() {\n\t\t\t\treturn copyResponseMetadata(Response.prototype.clone.call(this), this);\n\t\t\t},\n\t\t},\n\t});\n}\n\n/**\n * @param {Request} request\n * @param {\"document\" | \"navigation\"} [redirect]\n * @returns {boolean}\n */\nfunction shouldRedirectRequest(request, redirect) {\n\tconst destination = request.headers.get(\"Sec-Fetch-Dest\");\n\tif (redirect !== \"navigation\") return destination === \"document\";\n\tif (request.method !== \"GET\" && request.method !== \"HEAD\") return false;\n\tif (destination !== null) return destination === \"document\";\n\n\tlet specificity = -1;\n\tlet quality = 0;\n\tfor (const range of splitHeaderValue(\n\t\trequest.headers.get(\"Accept\") ?? \"\",\n\t\t\",\"\n\t)) {\n\t\tconst [type, ...parameters] = splitHeaderValue(range, \";\").map((part) =>\n\t\t\tpart.trim().toLowerCase()\n\t\t);\n\t\tconst rangeSpecificity =\n\t\t\ttype === \"text/html\"\n\t\t\t\t? 2\n\t\t\t\t: type === \"text/*\"\n\t\t\t\t\t? 1\n\t\t\t\t\t: type === \"*/*\"\n\t\t\t\t\t\t? 0\n\t\t\t\t\t\t: -1;\n\t\tif (rangeSpecificity < 0 || rangeSpecificity < specificity) continue;\n\n\t\tconst weight = parameters.find((parameter) => /^q\\s*=/.test(parameter));\n\t\tconst value = weight ? weight.slice(weight.indexOf(\"=\") + 1).trim() : \"1\";\n\t\tconst rangeQuality = /^(?:0(?:\\.\\d{0,3})?|1(?:\\.0{0,3})?)$/.test(value)\n\t\t\t? Number(value)\n\t\t\t: 0;\n\t\t// A specific q=0 exclusion takes precedence over an acceptable wildcard.\n\t\tquality =\n\t\t\trangeSpecificity > specificity\n\t\t\t\t? rangeQuality\n\t\t\t\t: Math.max(quality, rangeQuality);\n\t\tspecificity = rangeSpecificity;\n\t}\n\treturn quality > 0;\n}\n\n/**\n * @param {string} value\n * @param {string} separator\n * @returns {string[]}\n */\nfunction splitHeaderValue(value, separator) {\n\tconst parts = [];\n\tlet start = 0;\n\tlet quoted = false;\n\tfor (let index = 0; index < value.length; index++) {\n\t\tconst character = value[index];\n\t\tif (quoted && character === \"\\\\\") {\n\t\t\tindex++;\n\t\t} else if (character === '\"') {\n\t\t\tquoted = !quoted;\n\t\t} else if (!quoted && character === separator) {\n\t\t\tparts.push(value.slice(start, index));\n\t\t\tstart = index + 1;\n\t\t}\n\t}\n\tif (quoted) return [];\n\tparts.push(value.slice(start));\n\treturn parts;\n}\n\n/**\n * @param {Request} request\n * @param {string | URL | ((request: Request) => string | URL) | undefined} effectiveRequestUrl\n * @returns {URL}\n */\nfunction resolveMiddlewareUrl(request, effectiveRequestUrl) {\n\tif (typeof effectiveRequestUrl === \"function\") {\n\t\treturn new URL(effectiveRequestUrl(request), request.url);\n\t}\n\n\tif (\n\t\ttypeof effectiveRequestUrl === \"string\" ||\n\t\teffectiveRequestUrl instanceof URL\n\t) {\n\t\treturn new URL(effectiveRequestUrl, request.url);\n\t}\n\n\treturn new URL(request.url);\n}\n\n/**\n * Some metaframeworks (NextJS) require a new Request object.\n * https://github.com/opral/inlang-paraglide-js/issues/411\n *\n * However, some frameworks (TanStack Start 1.143+) use custom Request\n * implementations that cannot be cloned with `new Request(request)`.\n * https://github.com/opral/paraglide-js/issues/573\n *\n * Effective request URL overrides behind proxies:\n * https://github.com/opral/paraglide-js/issues/652\n *\n * @param {Request} request\n * @param {string | URL} [url]\n * @returns {Request}\n */\nfunction cloneRequestWithFallback(request, url = request.url) {\n\tconst targetUrl = typeof url === \"string\" ? url : url.href;\n\tif (targetUrl === request.url) {\n\t\ttry {\n\t\t\t// Clone first so building a new Request does not consume the original body stream.\n\t\t\treturn new Request(request.clone());\n\t\t} catch {\n\t\t\ttry {\n\t\t\t\treturn new Request(request);\n\t\t\t} catch {\n\t\t\t\treturn request;\n\t\t\t}\n\t\t}\n\t}\n\n\ttry {\n\t\t// Clone first so building a new Request does not consume the original body stream.\n\t\treturn new Request(targetUrl, request.clone());\n\t} catch {\n\t\ttry {\n\t\t\treturn new Request(targetUrl, request);\n\t\t} catch {\n\t\t\treturn request;\n\t\t}\n\t}\n}\n\n/**\n * Creates a mock AsyncLocalStorage implementation for environments where\n * native AsyncLocalStorage is not available or disabled.\n *\n * This mock implementation mimics the behavior of the native AsyncLocalStorage\n * but doesn't require the async_hooks module. It's used as a fallback when\n * the runtime does not expose AsyncLocalStorage or when it has been disabled.\n *\n * @returns {import(\"./runtime.js\").ParaglideAsyncLocalStorage}\n */\nfunction createMockAsyncLocalStorage() {\n\t/** @type {any} */\n\tlet currentStore = undefined;\n\treturn {\n\t\tgetStore() {\n\t\t\treturn currentStore;\n\t\t},\n\t\tasync run(store, callback) {\n\t\t\tcurrentStore = store;\n\t\t\ttry {\n\t\t\t\treturn await callback();\n\t\t\t} finally {\n\t\t\t\tcurrentStore = undefined;\n\t\t\t}\n\t\t},\n\t};\n}\n\n// Used in generated server.js when async local storage is disabled.\nvoid createMockAsyncLocalStorage;\n\n/**\n * The compiled messages for the server middleware.\n *\n * Only populated if `enableMiddlewareOptimizations` is set to `true`.\n *\n * @type {Record<string, Record<import(\"./runtime.js\").Locale, string>>}\n */\nconst compiledBundles = {};\n\n/**\n * The registry functions the compiled messages call, for the injected\n * messages that run without registry.js.\n *\n * `messages[id][locale]` lists the registry functions a message calls,\n * including the ones those call. `functions[name]` is the code of a registry\n * function.\n *\n * Only populated if `enableMiddlewareOptimizations` is set to `true`.\n *\n * @type {{ functions: Record<string, string>, messages: Record<string, Record<string, string[]>> }}\n */\nconst compiledRegistry = { functions: {}, messages: {} };\n"]}
|