vinext 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/report.d.ts +117 -0
- package/dist/build/report.d.ts.map +1 -0
- package/dist/build/report.js +303 -0
- package/dist/build/report.js.map +1 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +11 -7
- package/dist/check.js.map +1 -1
- package/dist/cli.js +106 -9
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +58 -42
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +10 -0
- package/dist/cloudflare/tpr.d.ts.map +1 -1
- package/dist/cloudflare/tpr.js +36 -41
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +16 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +1 -1
- package/dist/entries/app-rsc-entry.d.ts.map +1 -1
- package/dist/entries/app-rsc-entry.js +225 -186
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts.map +1 -1
- package/dist/entries/pages-server-entry.js +192 -91
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -40
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -0
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +131 -104
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +17 -57
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.d.ts +57 -0
- package/dist/routing/route-trie.d.ts.map +1 -0
- package/dist/routing/route-trie.js +160 -0
- package/dist/routing/route-trie.js.map +1 -0
- package/dist/routing/route-validation.d.ts.map +1 -1
- package/dist/routing/route-validation.js +13 -1
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +19 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +47 -0
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts.map +1 -1
- package/dist/server/api-handler.js +28 -13
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-server.d.ts +2 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +167 -115
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/image-optimization.d.ts.map +1 -1
- package/dist/server/image-optimization.js +24 -12
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +17 -8
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts.map +1 -1
- package/dist/server/isr-cache.js +8 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-routes.js +56 -18
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +10 -0
- package/dist/server/middleware-codegen.d.ts.map +1 -1
- package/dist/server/middleware-codegen.js +76 -4
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +52 -7
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +50 -0
- package/dist/server/pages-i18n.d.ts.map +1 -0
- package/dist/server/pages-i18n.js +152 -0
- package/dist/server/pages-i18n.js.map +1 -0
- package/dist/server/prod-server.d.ts +8 -2
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +60 -20
- package/dist/server/prod-server.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +3 -0
- package/dist/shims/cache-runtime.d.ts.map +1 -1
- package/dist/shims/cache-runtime.js +22 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +3 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +21 -12
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/constants.d.ts.map +1 -1
- package/dist/shims/constants.js +0 -1
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +14 -0
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +102 -37
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.d.ts +4 -0
- package/dist/shims/head-state.d.ts.map +1 -1
- package/dist/shims/head-state.js +14 -11
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +4 -2
- package/dist/shims/head.d.ts.map +1 -1
- package/dist/shims/head.js +162 -52
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +8 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +23 -34
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +27 -0
- package/dist/shims/i18n-context.d.ts.map +1 -0
- package/dist/shims/i18n-context.js +57 -0
- package/dist/shims/i18n-context.js.map +1 -0
- package/dist/shims/i18n-state.d.ts +20 -0
- package/dist/shims/i18n-state.d.ts.map +1 -0
- package/dist/shims/i18n-state.js +53 -0
- package/dist/shims/i18n-state.js.map +1 -0
- package/dist/shims/image.d.ts +2 -0
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/image.js +14 -6
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/internal/utils.d.ts.map +1 -1
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +38 -54
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +78 -22
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +96 -28
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +14 -0
- package/dist/shims/navigation-state.d.ts.map +1 -1
- package/dist/shims/navigation-state.js +33 -15
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +2 -0
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +80 -51
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.d.ts.map +1 -1
- package/dist/shims/request-context.js +9 -0
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -0
- package/dist/shims/request-state-types.d.ts.map +1 -0
- package/dist/shims/request-state-types.js +2 -0
- package/dist/shims/request-state-types.js.map +1 -0
- package/dist/shims/router-state.d.ts +11 -0
- package/dist/shims/router-state.d.ts.map +1 -1
- package/dist/shims/router-state.js +10 -8
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +4 -0
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +130 -40
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +8 -1
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +52 -6
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +66 -0
- package/dist/shims/unified-request-context.d.ts.map +1 -0
- package/dist/shims/unified-request-context.js +116 -0
- package/dist/shims/unified-request-context.js.map +1 -0
- package/dist/shims/url-utils.d.ts +20 -6
- package/dist/shims/url-utils.d.ts.map +1 -1
- package/dist/shims/url-utils.js +79 -0
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +18 -0
- package/dist/utils/domain-locale.d.ts.map +1 -0
- package/dist/utils/domain-locale.js +64 -0
- package/dist/utils/domain-locale.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified per-request context backed by a single AsyncLocalStorage.
|
|
3
|
+
*
|
|
4
|
+
* Consolidates the 5–6 nested ALS scopes that previously wrapped every
|
|
5
|
+
* App Router request (headers, navigation, cache-state, private-cache,
|
|
6
|
+
* fetch-cache, execution-context) into one flat store.
|
|
7
|
+
*
|
|
8
|
+
* Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields
|
|
9
|
+
* from the unified store, falling back to its own standalone ALS when
|
|
10
|
+
* outside (SSR environment, Pages Router, tests).
|
|
11
|
+
*/
|
|
12
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// ALS setup — stored on globalThis via Symbol.for so all Vite environments
|
|
15
|
+
// (RSC/SSR/client) share the same instance.
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
const _ALS_KEY = Symbol.for("vinext.unifiedRequestContext.als");
|
|
18
|
+
const _REQUEST_CONTEXT_ALS_KEY = Symbol.for("vinext.requestContext.als");
|
|
19
|
+
const _g = globalThis;
|
|
20
|
+
const _als = (_g[_ALS_KEY] ??=
|
|
21
|
+
new AsyncLocalStorage());
|
|
22
|
+
function _getInheritedExecutionContext() {
|
|
23
|
+
const unifiedStore = _als.getStore();
|
|
24
|
+
if (unifiedStore)
|
|
25
|
+
return unifiedStore.executionContext;
|
|
26
|
+
const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY];
|
|
27
|
+
return executionContextAls?.getStore() ?? null;
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Public API
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Create a fresh `UnifiedRequestContext` with defaults for all fields.
|
|
34
|
+
* Pass partial overrides for the fields you need to pre-populate.
|
|
35
|
+
*/
|
|
36
|
+
export function createRequestContext(opts) {
|
|
37
|
+
return {
|
|
38
|
+
headersContext: null,
|
|
39
|
+
dynamicUsageDetected: false,
|
|
40
|
+
pendingSetCookies: [],
|
|
41
|
+
draftModeCookieHeader: null,
|
|
42
|
+
phase: "render",
|
|
43
|
+
i18nContext: null,
|
|
44
|
+
serverContext: null,
|
|
45
|
+
serverInsertedHTMLCallbacks: [],
|
|
46
|
+
requestScopedCacheLife: null,
|
|
47
|
+
_privateCache: null,
|
|
48
|
+
currentRequestTags: [],
|
|
49
|
+
executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present
|
|
50
|
+
ssrContext: null,
|
|
51
|
+
ssrHeadChildren: [],
|
|
52
|
+
...opts,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Run `fn` within a unified request context scope.
|
|
57
|
+
* All shim modules will read/write their state from `ctx` for the
|
|
58
|
+
* duration of the call, including async continuations.
|
|
59
|
+
*/
|
|
60
|
+
export function runWithRequestContext(ctx, fn) {
|
|
61
|
+
return _als.run(ctx, fn);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Run `fn` in a nested unified scope derived from the current request context.
|
|
65
|
+
* Used by legacy runWith* wrappers to reset or override one sub-state while
|
|
66
|
+
* preserving proper async isolation for continuations created inside `fn`.
|
|
67
|
+
* The child scope is a shallow clone of the parent store, so untouched fields
|
|
68
|
+
* keep sharing their existing references while overridden slices can be reset.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export function runWithUnifiedStateMutation(mutate, fn) {
|
|
73
|
+
const parentCtx = _als.getStore();
|
|
74
|
+
if (!parentCtx)
|
|
75
|
+
return fn();
|
|
76
|
+
const childCtx = { ...parentCtx };
|
|
77
|
+
// NOTE: This is a shallow clone. Array fields (pendingSetCookies,
|
|
78
|
+
// serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the
|
|
79
|
+
// _privateCache Map, and object fields (headersContext, i18nContext,
|
|
80
|
+
// serverContext, ssrContext, executionContext, requestScopedCacheLife)
|
|
81
|
+
// still share references with the parent until replaced. The mutate
|
|
82
|
+
// callback must replace those reference-typed slices (for example
|
|
83
|
+
// `ctx.currentRequestTags = []`) rather than mutating them in-place (for
|
|
84
|
+
// example `ctx.currentRequestTags.push(...)`) or the parent scope will
|
|
85
|
+
// observe those changes too. Keep this enumeration in sync with
|
|
86
|
+
// UnifiedRequestContext: when adding a new reference-typed field, add it
|
|
87
|
+
// here too and verify callers still follow the replace-not-mutate rule.
|
|
88
|
+
mutate(childCtx);
|
|
89
|
+
return _als.run(childCtx, fn);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get the current unified request context.
|
|
93
|
+
* Returns the ALS store when inside a `runWithRequestContext()` scope,
|
|
94
|
+
* or a fresh detached context otherwise. Unlike the legacy per-shim fallback
|
|
95
|
+
* singletons, this detached value is ephemeral — mutations do not persist
|
|
96
|
+
* across calls. This is intentional to prevent state leakage outside request
|
|
97
|
+
* scopes.
|
|
98
|
+
*
|
|
99
|
+
* Only direct callers observe this detached fallback. Shim `_getState()`
|
|
100
|
+
* helpers should continue to gate on `isInsideUnifiedScope()` and fall back
|
|
101
|
+
* to their standalone ALS/fallback singletons outside the unified scope.
|
|
102
|
+
* If called inside a standalone `runWithExecutionContext()` scope, the
|
|
103
|
+
* detached context still reflects that inherited `executionContext`.
|
|
104
|
+
*/
|
|
105
|
+
export function getRequestContext() {
|
|
106
|
+
return _als.getStore() ?? createRequestContext();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Check whether the current execution is inside a `runWithRequestContext()` scope.
|
|
110
|
+
* Shim modules use this to decide whether to read from the unified store
|
|
111
|
+
* or fall back to their own standalone ALS.
|
|
112
|
+
*/
|
|
113
|
+
export function isInsideUnifiedScope() {
|
|
114
|
+
return _als.getStore() != null;
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=unified-request-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unified-request-context.js","sourceRoot":"","sources":["../../src/shims/unified-request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAuCrD,8EAA8E;AAC9E,2EAA2E;AAC3E,4CAA4C;AAC5C,8EAA8E;AAE9E,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;AAChE,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;AACzE,MAAM,EAAE,GAAG,UAAqD,CAAC;AACjE,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC;IACxB,IAAI,iBAAiB,EAAyB,CAA6C,CAAC;AAE9F,SAAS,6BAA6B;IACpC,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IACrC,IAAI,YAAY;QAAE,OAAO,YAAY,CAAC,gBAAgB,CAAC;IAEvD,MAAM,mBAAmB,GAAG,EAAE,CAAC,wBAAwB,CAE1C,CAAC;IACd,OAAO,mBAAmB,EAAE,QAAQ,EAAE,IAAI,IAAI,CAAC;AACjD,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAqC;IACxE,OAAO;QACL,cAAc,EAAE,IAAI;QACpB,oBAAoB,EAAE,KAAK;QAC3B,iBAAiB,EAAE,EAAE;QACrB,qBAAqB,EAAE,IAAI;QAC3B,KAAK,EAAE,QAAQ;QACf,WAAW,EAAE,IAAI;QACjB,aAAa,EAAE,IAAI;QACnB,2BAA2B,EAAE,EAAE;QAC/B,sBAAsB,EAAE,IAAI;QAC5B,aAAa,EAAE,IAAI;QACnB,kBAAkB,EAAE,EAAE;QACtB,gBAAgB,EAAE,6BAA6B,EAAE,EAAE,0CAA0C;QAC7F,UAAU,EAAE,IAAI;QAChB,eAAe,EAAE,EAAE;QACnB,GAAG,IAAI;KACR,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAA0B,EAC1B,EAAwB;IAExB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,2BAA2B,CACzC,MAA4C,EAC5C,EAAwB;IAExB,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAClC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,EAAE,CAAC;IAE5B,MAAM,QAAQ,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IAClC,kEAAkE;IAClE,yEAAyE;IACzE,qEAAqE;IACrE,uEAAuE;IACvE,oEAAoE;IACpE,kEAAkE;IAClE,yEAAyE;IACzE,uEAAuE;IACvE,gEAAgE;IAChE,yEAAyE;IACzE,wEAAwE;IACxE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAChC,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,oBAAoB,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,IAAI,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC;AACjC,CAAC","sourcesContent":["/**\n * Unified per-request context backed by a single AsyncLocalStorage.\n *\n * Consolidates the 5–6 nested ALS scopes that previously wrapped every\n * App Router request (headers, navigation, cache-state, private-cache,\n * fetch-cache, execution-context) into one flat store.\n *\n * Each shim module checks `isInsideUnifiedScope()` and reads its sub-fields\n * from the unified store, falling back to its own standalone ALS when\n * outside (SSR environment, Pages Router, tests).\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type {\n CacheState,\n ExecutionContextLike,\n FetchCacheState,\n HeadState,\n I18nState,\n NavigationState,\n PrivateCacheState,\n RouterState,\n VinextHeadersShimState,\n} from \"./request-state-types.js\";\n\n// ---------------------------------------------------------------------------\n// Unified context shape\n// ---------------------------------------------------------------------------\n\n/**\n * Flat union of all per-request state previously spread across\n * VinextHeadersShimState, NavigationState, CacheState, PrivateCacheState,\n * FetchCacheState, and ExecutionContextLike.\n *\n * Each field group is documented with its source shim module.\n */\nexport interface UnifiedRequestContext\n extends\n VinextHeadersShimState,\n I18nState,\n NavigationState,\n CacheState,\n PrivateCacheState,\n FetchCacheState,\n RouterState,\n HeadState {\n // ── request-context.ts ─────────────────────────────────────────────\n /** Cloudflare Workers ExecutionContext, or null on Node.js dev. */\n executionContext: ExecutionContextLike | null;\n}\n\n// ---------------------------------------------------------------------------\n// ALS setup — stored on globalThis via Symbol.for so all Vite environments\n// (RSC/SSR/client) share the same instance.\n// ---------------------------------------------------------------------------\n\nconst _ALS_KEY = Symbol.for(\"vinext.unifiedRequestContext.als\");\nconst _REQUEST_CONTEXT_ALS_KEY = Symbol.for(\"vinext.requestContext.als\");\nconst _g = globalThis as unknown as Record<PropertyKey, unknown>;\nconst _als = (_g[_ALS_KEY] ??=\n new AsyncLocalStorage<UnifiedRequestContext>()) as AsyncLocalStorage<UnifiedRequestContext>;\n\nfunction _getInheritedExecutionContext(): ExecutionContextLike | null {\n const unifiedStore = _als.getStore();\n if (unifiedStore) return unifiedStore.executionContext;\n\n const executionContextAls = _g[_REQUEST_CONTEXT_ALS_KEY] as\n | AsyncLocalStorage<ExecutionContextLike | null>\n | undefined;\n return executionContextAls?.getStore() ?? null;\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a fresh `UnifiedRequestContext` with defaults for all fields.\n * Pass partial overrides for the fields you need to pre-populate.\n */\nexport function createRequestContext(opts?: Partial<UnifiedRequestContext>): UnifiedRequestContext {\n return {\n headersContext: null,\n dynamicUsageDetected: false,\n pendingSetCookies: [],\n draftModeCookieHeader: null,\n phase: \"render\",\n i18nContext: null,\n serverContext: null,\n serverInsertedHTMLCallbacks: [],\n requestScopedCacheLife: null,\n _privateCache: null,\n currentRequestTags: [],\n executionContext: _getInheritedExecutionContext(), // inherits from standalone ALS if present\n ssrContext: null,\n ssrHeadChildren: [],\n ...opts,\n };\n}\n\n/**\n * Run `fn` within a unified request context scope.\n * All shim modules will read/write their state from `ctx` for the\n * duration of the call, including async continuations.\n */\nexport function runWithRequestContext<T>(\n ctx: UnifiedRequestContext,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n return _als.run(ctx, fn);\n}\n\n/**\n * Run `fn` in a nested unified scope derived from the current request context.\n * Used by legacy runWith* wrappers to reset or override one sub-state while\n * preserving proper async isolation for continuations created inside `fn`.\n * The child scope is a shallow clone of the parent store, so untouched fields\n * keep sharing their existing references while overridden slices can be reset.\n *\n * @internal\n */\nexport function runWithUnifiedStateMutation<T>(\n mutate: (ctx: UnifiedRequestContext) => void,\n fn: () => T | Promise<T>,\n): T | Promise<T> {\n const parentCtx = _als.getStore();\n if (!parentCtx) return fn();\n\n const childCtx = { ...parentCtx };\n // NOTE: This is a shallow clone. Array fields (pendingSetCookies,\n // serverInsertedHTMLCallbacks, currentRequestTags, ssrHeadChildren), the\n // _privateCache Map, and object fields (headersContext, i18nContext,\n // serverContext, ssrContext, executionContext, requestScopedCacheLife)\n // still share references with the parent until replaced. The mutate\n // callback must replace those reference-typed slices (for example\n // `ctx.currentRequestTags = []`) rather than mutating them in-place (for\n // example `ctx.currentRequestTags.push(...)`) or the parent scope will\n // observe those changes too. Keep this enumeration in sync with\n // UnifiedRequestContext: when adding a new reference-typed field, add it\n // here too and verify callers still follow the replace-not-mutate rule.\n mutate(childCtx);\n return _als.run(childCtx, fn);\n}\n\n/**\n * Get the current unified request context.\n * Returns the ALS store when inside a `runWithRequestContext()` scope,\n * or a fresh detached context otherwise. Unlike the legacy per-shim fallback\n * singletons, this detached value is ephemeral — mutations do not persist\n * across calls. This is intentional to prevent state leakage outside request\n * scopes.\n *\n * Only direct callers observe this detached fallback. Shim `_getState()`\n * helpers should continue to gate on `isInsideUnifiedScope()` and fall back\n * to their standalone ALS/fallback singletons outside the unified scope.\n * If called inside a standalone `runWithExecutionContext()` scope, the\n * detached context still reflects that inherited `executionContext`.\n */\nexport function getRequestContext(): UnifiedRequestContext {\n return _als.getStore() ?? createRequestContext();\n}\n\n/**\n * Check whether the current execution is inside a `runWithRequestContext()` scope.\n * Shim modules use this to decide whether to read from the unified store\n * or fall back to their own standalone ALS.\n */\nexport function isInsideUnifiedScope(): boolean {\n return _als.getStore() != null;\n}\n"]}
|
|
@@ -1,13 +1,27 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared URL utilities for same-origin detection.
|
|
3
|
-
*
|
|
4
|
-
* Used by link.tsx, navigation.ts, and router.ts to normalize
|
|
5
|
-
* same-origin absolute URLs to local paths for client-side navigation.
|
|
6
|
-
*/
|
|
7
1
|
/**
|
|
8
2
|
* If `url` is an absolute same-origin URL, return the local path
|
|
9
3
|
* (pathname + search + hash). Returns null for truly external URLs
|
|
10
4
|
* or on the server (where origin is unknown).
|
|
11
5
|
*/
|
|
12
6
|
export declare function toSameOriginPath(url: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* If `url` is an absolute same-origin URL, return the app-relative path
|
|
9
|
+
* (basePath stripped from the pathname, if configured). Returns null for
|
|
10
|
+
* truly external URLs or on the server.
|
|
11
|
+
*/
|
|
12
|
+
export declare function toSameOriginAppPath(url: string, basePath: string): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Prepend basePath to a local path for browser URLs / fetches.
|
|
15
|
+
*/
|
|
16
|
+
export declare function withBasePath(path: string, basePath: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a potentially relative href against the current URL.
|
|
19
|
+
* Handles: "#hash", "?query", "?query#hash", and relative paths.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveRelativeHref(href: string, currentUrl?: string, basePath?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Convert a local navigation target into the browser URL that should be used
|
|
24
|
+
* for history entries, fetches, and onNavigate callbacks.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toBrowserNavigationHref(href: string, currentUrl?: string, basePath?: string): string;
|
|
13
27
|
//# sourceMappingURL=url-utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-utils.d.ts","sourceRoot":"","sources":["../../src/shims/url-utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"url-utils.d.ts","sourceRoot":"","sources":["../../src/shims/url-utils.ts"],"names":[],"mappings":"AAQA;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAW3D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAchF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAYnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,CA0B5F;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,MAAM,CAgBhG"}
|
package/dist/shims/url-utils.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Used by link.tsx, navigation.ts, and router.ts to normalize
|
|
5
5
|
* same-origin absolute URLs to local paths for client-side navigation.
|
|
6
6
|
*/
|
|
7
|
+
import { hasBasePath, stripBasePath } from "../utils/base-path.js";
|
|
7
8
|
/**
|
|
8
9
|
* If `url` is an absolute same-origin URL, return the local path
|
|
9
10
|
* (pathname + search + hash). Returns null for truly external URLs
|
|
@@ -23,4 +24,82 @@ export function toSameOriginPath(url) {
|
|
|
23
24
|
}
|
|
24
25
|
return null;
|
|
25
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* If `url` is an absolute same-origin URL, return the app-relative path
|
|
29
|
+
* (basePath stripped from the pathname, if configured). Returns null for
|
|
30
|
+
* truly external URLs or on the server.
|
|
31
|
+
*/
|
|
32
|
+
export function toSameOriginAppPath(url, basePath) {
|
|
33
|
+
const localPath = toSameOriginPath(url);
|
|
34
|
+
if (localPath == null || !basePath)
|
|
35
|
+
return localPath;
|
|
36
|
+
try {
|
|
37
|
+
const parsed = new URL(localPath, "http://vinext.local");
|
|
38
|
+
if (!hasBasePath(parsed.pathname, basePath)) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const pathname = stripBasePath(parsed.pathname, basePath);
|
|
42
|
+
return pathname + parsed.search + parsed.hash;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return localPath;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Prepend basePath to a local path for browser URLs / fetches.
|
|
50
|
+
*/
|
|
51
|
+
export function withBasePath(path, basePath) {
|
|
52
|
+
if (!basePath ||
|
|
53
|
+
!path.startsWith("/") ||
|
|
54
|
+
path.startsWith("http://") ||
|
|
55
|
+
path.startsWith("https://") ||
|
|
56
|
+
path.startsWith("//")) {
|
|
57
|
+
return path;
|
|
58
|
+
}
|
|
59
|
+
return basePath + path;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Resolve a potentially relative href against the current URL.
|
|
63
|
+
* Handles: "#hash", "?query", "?query#hash", and relative paths.
|
|
64
|
+
*/
|
|
65
|
+
export function resolveRelativeHref(href, currentUrl, basePath = "") {
|
|
66
|
+
const base = currentUrl ?? (typeof window !== "undefined" ? window.location.href : undefined);
|
|
67
|
+
if (!base)
|
|
68
|
+
return href;
|
|
69
|
+
if (href.startsWith("/") ||
|
|
70
|
+
href.startsWith("http://") ||
|
|
71
|
+
href.startsWith("https://") ||
|
|
72
|
+
href.startsWith("//")) {
|
|
73
|
+
return href;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const resolved = new URL(href, base);
|
|
77
|
+
const pathname = basePath && resolved.pathname === basePath
|
|
78
|
+
? ""
|
|
79
|
+
: basePath
|
|
80
|
+
? stripBasePath(resolved.pathname, basePath)
|
|
81
|
+
: resolved.pathname;
|
|
82
|
+
return pathname + resolved.search + resolved.hash;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return href;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Convert a local navigation target into the browser URL that should be used
|
|
90
|
+
* for history entries, fetches, and onNavigate callbacks.
|
|
91
|
+
*/
|
|
92
|
+
export function toBrowserNavigationHref(href, currentUrl, basePath = "") {
|
|
93
|
+
const resolved = resolveRelativeHref(href, currentUrl, basePath);
|
|
94
|
+
if (!basePath) {
|
|
95
|
+
return withBasePath(resolved, basePath);
|
|
96
|
+
}
|
|
97
|
+
if (resolved === "") {
|
|
98
|
+
return basePath;
|
|
99
|
+
}
|
|
100
|
+
if (resolved.startsWith("?") || resolved.startsWith("#")) {
|
|
101
|
+
return basePath + resolved;
|
|
102
|
+
}
|
|
103
|
+
return withBasePath(resolved, basePath);
|
|
104
|
+
}
|
|
26
105
|
//# sourceMappingURL=url-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"url-utils.js","sourceRoot":"","sources":["../../src/shims/url-utils.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"url-utils.js","sourceRoot":"","sources":["../../src/shims/url-utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared URL utilities for same-origin detection.\n *\n * Used by link.tsx, navigation.ts, and router.ts to normalize\n * same-origin absolute URLs to local paths for client-side navigation.\n */\nimport { hasBasePath, stripBasePath } from \"../utils/base-path.js\";\n\n/**\n * If `url` is an absolute same-origin URL, return the local path\n * (pathname + search + hash). Returns null for truly external URLs\n * or on the server (where origin is unknown).\n */\nexport function toSameOriginPath(url: string): string | null {\n if (typeof window === \"undefined\") return null;\n try {\n const parsed = url.startsWith(\"//\") ? new URL(url, window.location.origin) : new URL(url);\n if (parsed.origin === window.location.origin) {\n return parsed.pathname + parsed.search + parsed.hash;\n }\n } catch {\n // not a valid absolute URL — ignore\n }\n return null;\n}\n\n/**\n * If `url` is an absolute same-origin URL, return the app-relative path\n * (basePath stripped from the pathname, if configured). Returns null for\n * truly external URLs or on the server.\n */\nexport function toSameOriginAppPath(url: string, basePath: string): string | null {\n const localPath = toSameOriginPath(url);\n if (localPath == null || !basePath) return localPath;\n\n try {\n const parsed = new URL(localPath, \"http://vinext.local\");\n if (!hasBasePath(parsed.pathname, basePath)) {\n return null;\n }\n const pathname = stripBasePath(parsed.pathname, basePath);\n return pathname + parsed.search + parsed.hash;\n } catch {\n return localPath;\n }\n}\n\n/**\n * Prepend basePath to a local path for browser URLs / fetches.\n */\nexport function withBasePath(path: string, basePath: string): string {\n if (\n !basePath ||\n !path.startsWith(\"/\") ||\n path.startsWith(\"http://\") ||\n path.startsWith(\"https://\") ||\n path.startsWith(\"//\")\n ) {\n return path;\n }\n\n return basePath + path;\n}\n\n/**\n * Resolve a potentially relative href against the current URL.\n * Handles: \"#hash\", \"?query\", \"?query#hash\", and relative paths.\n */\nexport function resolveRelativeHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const base = currentUrl ?? (typeof window !== \"undefined\" ? window.location.href : undefined);\n\n if (!base) return href;\n\n if (\n href.startsWith(\"/\") ||\n href.startsWith(\"http://\") ||\n href.startsWith(\"https://\") ||\n href.startsWith(\"//\")\n ) {\n return href;\n }\n\n try {\n const resolved = new URL(href, base);\n const pathname =\n basePath && resolved.pathname === basePath\n ? \"\"\n : basePath\n ? stripBasePath(resolved.pathname, basePath)\n : resolved.pathname;\n return pathname + resolved.search + resolved.hash;\n } catch {\n return href;\n }\n}\n\n/**\n * Convert a local navigation target into the browser URL that should be used\n * for history entries, fetches, and onNavigate callbacks.\n */\nexport function toBrowserNavigationHref(href: string, currentUrl?: string, basePath = \"\"): string {\n const resolved = resolveRelativeHref(href, currentUrl, basePath);\n\n if (!basePath) {\n return withBasePath(resolved, basePath);\n }\n\n if (resolved === \"\") {\n return basePath;\n }\n\n if (resolved.startsWith(\"?\") || resolved.startsWith(\"#\")) {\n return basePath + resolved;\n }\n\n return withBasePath(resolved, basePath);\n}\n"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { NextI18nConfig } from "../config/next-config.js";
|
|
2
|
+
export type DomainLocale = NonNullable<NextI18nConfig["domains"]>[number];
|
|
3
|
+
export declare function normalizeDomainHostname(hostname: string | null | undefined): string | undefined;
|
|
4
|
+
/**
|
|
5
|
+
* Match a configured domain either by hostname or locale.
|
|
6
|
+
* When both are provided, the checks intentionally use OR semantics so the
|
|
7
|
+
* same helper can cover Next.js's hostname lookup and preferred-locale lookup.
|
|
8
|
+
* If both are passed, the first domain matching either input wins, so callers
|
|
9
|
+
* should pass hostname or detectedLocale, not both.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectDomainLocale(domainItems?: readonly DomainLocale[], hostname?: string, detectedLocale?: string): DomainLocale | undefined;
|
|
12
|
+
export declare function addLocalePrefix(path: string, locale: string, localeDefault: string): string;
|
|
13
|
+
export declare function getDomainLocaleUrl(url: string, locale: string, { basePath, currentHostname, domainItems, }: {
|
|
14
|
+
basePath?: string;
|
|
15
|
+
currentHostname?: string | null;
|
|
16
|
+
domainItems?: readonly DomainLocale[];
|
|
17
|
+
}): string | undefined;
|
|
18
|
+
//# sourceMappingURL=domain-locale.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-locale.d.ts","sourceRoot":"","sources":["../../src/utils/domain-locale.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1E,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG/F;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,EACrC,QAAQ,CAAC,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,MAAM,GACtB,YAAY,GAAG,SAAS,CAkB1B;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAc3F;AAOD,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,EACE,QAAQ,EACR,eAAe,EACf,WAAW,GACZ,EAAE;IACD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,SAAS,YAAY,EAAE,CAAC;CACvC,GACA,MAAM,GAAG,SAAS,CAqBpB"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export function normalizeDomainHostname(hostname) {
|
|
2
|
+
if (!hostname)
|
|
3
|
+
return undefined;
|
|
4
|
+
return hostname.split(",", 1)[0]?.trim().split(":", 1)[0]?.toLowerCase() || undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Match a configured domain either by hostname or locale.
|
|
8
|
+
* When both are provided, the checks intentionally use OR semantics so the
|
|
9
|
+
* same helper can cover Next.js's hostname lookup and preferred-locale lookup.
|
|
10
|
+
* If both are passed, the first domain matching either input wins, so callers
|
|
11
|
+
* should pass hostname or detectedLocale, not both.
|
|
12
|
+
*/
|
|
13
|
+
export function detectDomainLocale(domainItems, hostname, detectedLocale) {
|
|
14
|
+
if (!domainItems?.length)
|
|
15
|
+
return undefined;
|
|
16
|
+
const normalizedHostname = normalizeDomainHostname(hostname);
|
|
17
|
+
const normalizedLocale = detectedLocale?.toLowerCase();
|
|
18
|
+
for (const item of domainItems) {
|
|
19
|
+
const domainHostname = normalizeDomainHostname(item.domain);
|
|
20
|
+
if (normalizedHostname === domainHostname ||
|
|
21
|
+
normalizedLocale === item.defaultLocale.toLowerCase() ||
|
|
22
|
+
item.locales?.some((locale) => locale.toLowerCase() === normalizedLocale)) {
|
|
23
|
+
return item;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function addLocalePrefix(path, locale, localeDefault) {
|
|
29
|
+
const normalizedLocale = locale.toLowerCase();
|
|
30
|
+
if (normalizedLocale === localeDefault.toLowerCase())
|
|
31
|
+
return path;
|
|
32
|
+
const pathWithLeadingSlash = path.startsWith("/") ? path : `/${path}`;
|
|
33
|
+
const pathname = pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash;
|
|
34
|
+
const normalizedPathname = pathname.toLowerCase();
|
|
35
|
+
const localePrefix = `/${normalizedLocale}`;
|
|
36
|
+
if (normalizedPathname === localePrefix || normalizedPathname.startsWith(`${localePrefix}/`)) {
|
|
37
|
+
return path.startsWith("/") ? path : pathWithLeadingSlash;
|
|
38
|
+
}
|
|
39
|
+
return `/${locale}${pathWithLeadingSlash}`;
|
|
40
|
+
}
|
|
41
|
+
function withBasePath(path, basePath = "") {
|
|
42
|
+
if (!basePath)
|
|
43
|
+
return path;
|
|
44
|
+
return basePath + path;
|
|
45
|
+
}
|
|
46
|
+
export function getDomainLocaleUrl(url, locale, { basePath, currentHostname, domainItems, }) {
|
|
47
|
+
if (!domainItems?.length)
|
|
48
|
+
return undefined;
|
|
49
|
+
const targetDomain = detectDomainLocale(domainItems, undefined, locale);
|
|
50
|
+
if (!targetDomain)
|
|
51
|
+
return undefined;
|
|
52
|
+
const currentDomain = detectDomainLocale(domainItems, currentHostname ?? undefined);
|
|
53
|
+
const localizedPath = addLocalePrefix(url, locale, targetDomain.defaultLocale);
|
|
54
|
+
if (currentDomain &&
|
|
55
|
+
normalizeDomainHostname(currentDomain.domain) === normalizeDomainHostname(targetDomain.domain)) {
|
|
56
|
+
// Same-domain switches fall back to the caller's standard locale-prefix
|
|
57
|
+
// logic. This relies on __VINEXT_DEFAULT_LOCALE__ matching the current
|
|
58
|
+
// domain's defaultLocale, which the server entry keeps in sync.
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
const scheme = `http${targetDomain.http ? "" : "s"}://`;
|
|
62
|
+
return `${scheme}${targetDomain.domain}${withBasePath(localizedPath, basePath)}`;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=domain-locale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-locale.js","sourceRoot":"","sources":["../../src/utils/domain-locale.ts"],"names":[],"mappings":"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","sourcesContent":["import type { NextI18nConfig } from \"../config/next-config.js\";\n\nexport type DomainLocale = NonNullable<NextI18nConfig[\"domains\"]>[number];\n\nexport function normalizeDomainHostname(hostname: string | null | undefined): string | undefined {\n if (!hostname) return undefined;\n return hostname.split(\",\", 1)[0]?.trim().split(\":\", 1)[0]?.toLowerCase() || undefined;\n}\n\n/**\n * Match a configured domain either by hostname or locale.\n * When both are provided, the checks intentionally use OR semantics so the\n * same helper can cover Next.js's hostname lookup and preferred-locale lookup.\n * If both are passed, the first domain matching either input wins, so callers\n * should pass hostname or detectedLocale, not both.\n */\nexport function detectDomainLocale(\n domainItems?: readonly DomainLocale[],\n hostname?: string,\n detectedLocale?: string,\n): DomainLocale | undefined {\n if (!domainItems?.length) return undefined;\n\n const normalizedHostname = normalizeDomainHostname(hostname);\n const normalizedLocale = detectedLocale?.toLowerCase();\n\n for (const item of domainItems) {\n const domainHostname = normalizeDomainHostname(item.domain);\n if (\n normalizedHostname === domainHostname ||\n normalizedLocale === item.defaultLocale.toLowerCase() ||\n item.locales?.some((locale) => locale.toLowerCase() === normalizedLocale)\n ) {\n return item;\n }\n }\n\n return undefined;\n}\n\nexport function addLocalePrefix(path: string, locale: string, localeDefault: string): string {\n const normalizedLocale = locale.toLowerCase();\n if (normalizedLocale === localeDefault.toLowerCase()) return path;\n\n const pathWithLeadingSlash = path.startsWith(\"/\") ? path : `/${path}`;\n const pathname = pathWithLeadingSlash.split(/[?#]/, 1)[0] ?? pathWithLeadingSlash;\n const normalizedPathname = pathname.toLowerCase();\n const localePrefix = `/${normalizedLocale}`;\n\n if (normalizedPathname === localePrefix || normalizedPathname.startsWith(`${localePrefix}/`)) {\n return path.startsWith(\"/\") ? path : pathWithLeadingSlash;\n }\n\n return `/${locale}${pathWithLeadingSlash}`;\n}\n\nfunction withBasePath(path: string, basePath = \"\"): string {\n if (!basePath) return path;\n return basePath + path;\n}\n\nexport function getDomainLocaleUrl(\n url: string,\n locale: string,\n {\n basePath,\n currentHostname,\n domainItems,\n }: {\n basePath?: string;\n currentHostname?: string | null;\n domainItems?: readonly DomainLocale[];\n },\n): string | undefined {\n if (!domainItems?.length) return undefined;\n\n const targetDomain = detectDomainLocale(domainItems, undefined, locale);\n if (!targetDomain) return undefined;\n\n const currentDomain = detectDomainLocale(domainItems, currentHostname ?? undefined);\n const localizedPath = addLocalePrefix(url, locale, targetDomain.defaultLocale);\n\n if (\n currentDomain &&\n normalizeDomainHostname(currentDomain.domain) === normalizeDomainHostname(targetDomain.domain)\n ) {\n // Same-domain switches fall back to the caller's standard locale-prefix\n // logic. This relies on __VINEXT_DEFAULT_LOCALE__ matching the current\n // domain's defaultLocale, which the server entry keeps in sync.\n return undefined;\n }\n\n const scheme = `http${targetDomain.http ? \"\" : \"s\"}://`;\n return `${scheme}${targetDomain.domain}${withBasePath(localizedPath, basePath)}`;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vinext",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.30",
|
|
4
4
|
"description": "Run Next.js apps on Vite. Drop-in replacement for the next CLI.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"react": ">=19.2.0",
|
|
79
79
|
"react-dom": ">=19.2.0",
|
|
80
80
|
"react-server-dom-webpack": "^19.2.4",
|
|
81
|
-
"vite": "^7.0.0"
|
|
81
|
+
"vite": "^7.0.0 || ^8.0.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependenciesMeta": {
|
|
84
84
|
"@mdx-js/rollup": {
|