@thomas.f/prnext 0.1.0-alpha.1
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 +54 -0
- package/build/action-exports.mjs +107 -0
- package/build/actions.mjs +214 -0
- package/build/app-config.mjs +138 -0
- package/build/app-routing.mjs +119 -0
- package/build/app-static.mjs +158 -0
- package/build/app.mjs +536 -0
- package/build/cache-components.mjs +91 -0
- package/build/cache-handlers.mjs +54 -0
- package/build/check.mjs +40 -0
- package/build/compiler.mjs +222 -0
- package/build/config.mjs +193 -0
- package/build/css-modules.mjs +114 -0
- package/build/custom-routes.mjs +363 -0
- package/build/dev-worker.mjs +18 -0
- package/build/dev.mjs +76 -0
- package/build/directory-cache.mjs +29 -0
- package/build/dynamic.mjs +125 -0
- package/build/edge.mjs +141 -0
- package/build/font-data.LICENSE.txt +25 -0
- package/build/font-data.json +1 -0
- package/build/font-files.mjs +221 -0
- package/build/fonts.mjs +131 -0
- package/build/framework-imports.mjs +17 -0
- package/build/i18n.mjs +39 -0
- package/build/images-config.mjs +62 -0
- package/build/images.mjs +86 -0
- package/build/incremental.mjs +76 -0
- package/build/index.mjs +356 -0
- package/build/loader-cache.mjs +69 -0
- package/build/metadata-images.mjs +72 -0
- package/build/metadata-routes.mjs +77 -0
- package/build/middleware.mjs +231 -0
- package/build/migrate.mjs +289 -0
- package/build/module-resolution.mjs +78 -0
- package/build/native-discovery.mjs +134 -0
- package/build/native-packages.mjs +105 -0
- package/build/npm-packages.mjs +110 -0
- package/build/og.mjs +14 -0
- package/build/page-extensions.mjs +12 -0
- package/build/passthrough-loader.cjs +4 -0
- package/build/precompress.mjs +122 -0
- package/build/scan.mjs +178 -0
- package/build/script-workers.mjs +25 -0
- package/build/server-actions-config.mjs +27 -0
- package/build/source-maps.mjs +34 -0
- package/build/standalone-config.mjs +19 -0
- package/build/standalone-runner.mjs +21 -0
- package/build/standalone-worker.mjs +5 -0
- package/build/standalone.mjs +240 -0
- package/build/static-export.mjs +93 -0
- package/build/styles.mjs +174 -0
- package/build/transform-cache.mjs +50 -0
- package/build/transform.mjs +155 -0
- package/build/turbopack-conditions.mjs +59 -0
- package/build/webpack-bridge.cjs +3 -0
- package/build/webpack-graph.mjs +256 -0
- package/build/webpack-loader.cjs +9 -0
- package/cli.mjs +210 -0
- package/compat/app-client-page.cjs +32 -0
- package/compat/app-context.cjs +40 -0
- package/compat/app-context.d.cts +20 -0
- package/compat/app-dynamic.cjs +34 -0
- package/compat/app-error-boundary.cjs +53 -0
- package/compat/app-global-error-boundary.cjs +34 -0
- package/compat/app-layout-context.cjs +27 -0
- package/compat/app-navigation-boundary.cjs +47 -0
- package/compat/app.cjs +33 -0
- package/compat/app.d.cts +9 -0
- package/compat/cache-handlers.cjs +223 -0
- package/compat/cache-life.cjs +34 -0
- package/compat/cache.cjs +99 -0
- package/compat/cache.d.cts +36 -0
- package/compat/compat/router.d.cts +2 -0
- package/compat/compat-router.cjs +7 -0
- package/compat/constants.cjs +8 -0
- package/compat/constants.d.cts +7 -0
- package/compat/cookies.cjs +129 -0
- package/compat/data-cache.cjs +389 -0
- package/compat/dist/shared/lib/app-router-context.shared-runtime.d.cts +3 -0
- package/compat/dist/shared/lib/router-context.d.cts +1 -0
- package/compat/dist/shared/lib/router-context.shared-runtime.d.cts +3 -0
- package/compat/document.cjs +73 -0
- package/compat/document.d.cts +41 -0
- package/compat/draft.cjs +28 -0
- package/compat/dynamic-bailout.cjs +13 -0
- package/compat/dynamic.cjs +119 -0
- package/compat/dynamic.d.cts +32 -0
- package/compat/error.cjs +36 -0
- package/compat/error.d.cts +15 -0
- package/compat/fetch.d.cts +10 -0
- package/compat/font/google.d.cts +1 -0
- package/compat/font/local.d.cts +2 -0
- package/compat/font-google.cjs +2 -0
- package/compat/font-google.d.cts +1944 -0
- package/compat/font-local.cjs +5 -0
- package/compat/font-local.d.cts +3 -0
- package/compat/font-types.d.cts +25 -0
- package/compat/head.cjs +180 -0
- package/compat/head.d.cts +3 -0
- package/compat/headers.cjs +89 -0
- package/compat/headers.d.cts +26 -0
- package/compat/image-config.cjs +3 -0
- package/compat/image-imports.d.ts +12 -0
- package/compat/image-shared.cjs +62 -0
- package/compat/image.cjs +64 -0
- package/compat/image.d.cts +35 -0
- package/compat/incremental-cache.cjs +186 -0
- package/compat/index.d.ts +159 -0
- package/compat/instant-samples.cjs +39 -0
- package/compat/instant.cjs +13 -0
- package/compat/link.cjs +68 -0
- package/compat/link.d.cts +17 -0
- package/compat/locale.cjs +30 -0
- package/compat/metadata.d.cts +77 -0
- package/compat/navigation-controls.cjs +27 -0
- package/compat/navigation-server.cjs +25 -0
- package/compat/navigation.cjs +52 -0
- package/compat/navigation.d.cts +28 -0
- package/compat/next-app-router-context.cjs +6 -0
- package/compat/next-router-context.cjs +3 -0
- package/compat/og.cjs +32 -0
- package/compat/og.d.cts +1 -0
- package/compat/paths.cjs +33 -0
- package/compat/preview.cjs +41 -0
- package/compat/rewrite.cjs +41 -0
- package/compat/route-request.cjs +64 -0
- package/compat/router.cjs +137 -0
- package/compat/router.d.cts +58 -0
- package/compat/script-context.cjs +5 -0
- package/compat/script-loader.cjs +135 -0
- package/compat/script.cjs +69 -0
- package/compat/script.d.cts +17 -0
- package/compat/server-primitives.cjs +109 -0
- package/compat/server.cjs +13 -0
- package/compat/server.d.cts +37 -0
- package/compat/static-generation.cjs +108 -0
- package/compat/use-cache.cjs +129 -0
- package/index.mjs +1 -0
- package/native/platforms.json +6 -0
- package/native/resolve.mjs +81 -0
- package/package.json +127 -0
- package/release/verify.mjs +59 -0
- package/runtime/action-client.mjs +19 -0
- package/runtime/action-crypto.mjs +138 -0
- package/runtime/action-reference.mjs +2 -0
- package/runtime/action-server.mjs +161 -0
- package/runtime/action-ssr.mjs +5 -0
- package/runtime/api.mjs +326 -0
- package/runtime/app-client.mjs +539 -0
- package/runtime/app-content.mjs +8 -0
- package/runtime/app-errors.mjs +12 -0
- package/runtime/app-instant.mjs +30 -0
- package/runtime/app-metadata.mjs +410 -0
- package/runtime/app-partial-model.mjs +228 -0
- package/runtime/app-partial.mjs +130 -0
- package/runtime/app-prefetch.mjs +34 -0
- package/runtime/app-recovery.mjs +87 -0
- package/runtime/app-render.mjs +544 -0
- package/runtime/app-routing-access.mjs +143 -0
- package/runtime/app-routing-context.mjs +35 -0
- package/runtime/app-routing-state.mjs +61 -0
- package/runtime/app-routing.mjs +323 -0
- package/runtime/app-segments.mjs +22 -0
- package/runtime/app-static-params.mjs +120 -0
- package/runtime/app-static.mjs +86 -0
- package/runtime/app-stream-channel.mjs +92 -0
- package/runtime/app-stream-html.mjs +279 -0
- package/runtime/build-directory.mjs +48 -0
- package/runtime/cache-arguments.mjs +33 -0
- package/runtime/cache-components-rsc.mjs +64 -0
- package/runtime/cache-request.mjs +23 -0
- package/runtime/client-navigation.mjs +40 -0
- package/runtime/dev-client.mjs +129 -0
- package/runtime/dev-file-changes.mjs +110 -0
- package/runtime/document.mjs +96 -0
- package/runtime/edge.mjs +105 -0
- package/runtime/env.mjs +68 -0
- package/runtime/fetch-cache.mjs +379 -0
- package/runtime/font-preload.mjs +4 -0
- package/runtime/http.mjs +190 -0
- package/runtime/incremental-cache.mjs +83 -0
- package/runtime/metadata-route.mjs +83 -0
- package/runtime/middleware.mjs +186 -0
- package/runtime/module-loader.mjs +21 -0
- package/runtime/navigation.mjs +16 -0
- package/runtime/og-loader.mjs +17 -0
- package/runtime/pages-client.mjs +197 -0
- package/runtime/pages-error-props.mjs +6 -0
- package/runtime/pages-errors.mjs +85 -0
- package/runtime/pages-initial-props.mjs +43 -0
- package/runtime/pages-navigation.mjs +565 -0
- package/runtime/pages-paths.mjs +80 -0
- package/runtime/pages-revalidate.mjs +33 -0
- package/runtime/partial-artifact-cache.mjs +37 -0
- package/runtime/partial-template.mjs +174 -0
- package/runtime/profile.mjs +9 -0
- package/runtime/profiles.json +47 -0
- package/runtime/render.mjs +304 -0
- package/runtime/request-transport.mjs +41 -0
- package/runtime/request-work.mjs +7 -0
- package/runtime/route-static.mjs +117 -0
- package/runtime/rsc-worker.mjs +426 -0
- package/runtime/script-html.mjs +61 -0
- package/runtime/stream-select.mjs +25 -0
- package/runtime/stream-utils.mjs +127 -0
- package/runtime/transport.mjs +108 -0
- package/runtime/watch-project.mjs +130 -0
- package/runtime/worker-artifacts.mjs +22 -0
- package/runtime/worker-metadata.mjs +31 -0
- package/runtime/worker.mjs +197 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const { pathToFileURL } = require('node:url');
|
|
5
|
+
const { softTags } = require('./cache-handlers.cjs');
|
|
6
|
+
const { trackStaticDependency } = require('./static-generation.cjs');
|
|
7
|
+
const MAX_BYTES = 2 * 1024 * 1024;
|
|
8
|
+
const modules = new Map();
|
|
9
|
+
const instances = new WeakMap();
|
|
10
|
+
let ownersCount = 0;
|
|
11
|
+
|
|
12
|
+
function configured(context) { return context?.cacheHandler || context?.manifest?.config?.cacheHandler; }
|
|
13
|
+
function outside(callback) { return require('./headers.cjs').runWithoutRequestContext(callback); }
|
|
14
|
+
function wait(promise, signal, milliseconds = 5000) {
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const timer = setTimeout(() => finish(reject, new Error('Incremental cache handler timed out')), milliseconds);
|
|
17
|
+
timer.unref();
|
|
18
|
+
const abort = () => finish(reject, signal.reason);
|
|
19
|
+
function finish(callback, value) { clearTimeout(timer); signal?.removeEventListener('abort', abort); callback(value); }
|
|
20
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
21
|
+
if (signal?.aborted) abort();
|
|
22
|
+
Promise.resolve(promise).then(value => finish(resolve, value), error => finish(reject, error));
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function invoke(handler, method, args, context) {
|
|
26
|
+
return wait(outside(() => Promise.resolve().then(() => handler[method](...args))), context?.signal);
|
|
27
|
+
}
|
|
28
|
+
async function load(context) {
|
|
29
|
+
const source = configured(context);
|
|
30
|
+
if (!source) return undefined;
|
|
31
|
+
let pending = instances.get(context);
|
|
32
|
+
if (pending) return pending;
|
|
33
|
+
const root = path.resolve(context.distDir || '');
|
|
34
|
+
const filename = path.resolve(root, source);
|
|
35
|
+
if (!context.distDir || !source.startsWith('server/') || !filename.startsWith(root + path.sep)) throw new Error('Invalid incremental cache handler path');
|
|
36
|
+
let record = modules.get(filename);
|
|
37
|
+
if (!record) {
|
|
38
|
+
record = { module: outside(() => import(pathToFileURL(filename).href)), revision: 0, owners: new Map() };
|
|
39
|
+
if (modules.size >= 32) modules.delete(modules.keys().next().value);
|
|
40
|
+
modules.set(filename, record);
|
|
41
|
+
}
|
|
42
|
+
pending = (async () => {
|
|
43
|
+
const imported = await wait(record.module, context.signal);
|
|
44
|
+
const Constructor = imported.default;
|
|
45
|
+
if (typeof Constructor !== 'function') throw new TypeError('cacheHandler must export a constructor');
|
|
46
|
+
const handler = outside(() => new Constructor({
|
|
47
|
+
dev: context.production === false, fs: { ...fs.promises, readFileSync: fs.readFileSync, existsSync: fs.existsSync },
|
|
48
|
+
flushToDisk: true, serverDistDir: path.join(root, 'server'), revalidatedTags: [],
|
|
49
|
+
maxMemoryCacheSize: context.cacheMaxMemorySize ?? context.manifest?.config?.cacheMaxMemorySize,
|
|
50
|
+
_requestHeaders: Object.fromEntries(new Headers(context.headers || {})), fetchCacheKeyPrefix: '',
|
|
51
|
+
}));
|
|
52
|
+
if (['get', 'set', 'revalidateTag'].some(name => typeof handler[name] !== 'function')) throw new TypeError('cacheHandler must implement get, set and revalidateTag');
|
|
53
|
+
if (handler.resetRequestCache !== undefined) {
|
|
54
|
+
if (typeof handler.resetRequestCache !== 'function') throw new TypeError('cacheHandler.resetRequestCache must be a function');
|
|
55
|
+
await invoke(handler, 'resetRequestCache', [], context);
|
|
56
|
+
}
|
|
57
|
+
return { handler, record };
|
|
58
|
+
})();
|
|
59
|
+
instances.set(context, pending);
|
|
60
|
+
return pending;
|
|
61
|
+
}
|
|
62
|
+
async function getEntry(key, kind, context, options = {}) {
|
|
63
|
+
const { handler } = await load(context);
|
|
64
|
+
return invoke(handler, 'get', [key, { kind, ...options }], context);
|
|
65
|
+
}
|
|
66
|
+
async function setEntry(key, value, context, options = {}) {
|
|
67
|
+
const { handler } = await load(context);
|
|
68
|
+
return invoke(handler, 'set', [key, value, { ...options }], context);
|
|
69
|
+
}
|
|
70
|
+
async function invalidate(context, operation) {
|
|
71
|
+
const { handler, record } = await load(context);
|
|
72
|
+
record.revision++;
|
|
73
|
+
const tags = [...(operation.tags || []), ...(operation.paths || []).map(value => {
|
|
74
|
+
const separator = value.indexOf(':');
|
|
75
|
+
return '_N_T_' + value.slice(separator + 1).replace(/\/$/, '') + '/' + value.slice(0, separator);
|
|
76
|
+
})];
|
|
77
|
+
const durations = operation.mode === 'expire' ? { expire: 0 } : operation.expire === undefined ? undefined : { expire: operation.expire };
|
|
78
|
+
await invoke(handler, 'revalidateTag', [[...new Set(tags)], durations], context);
|
|
79
|
+
}
|
|
80
|
+
function fresh(entry, revalidate) {
|
|
81
|
+
const timestamp = entry?.lastModified;
|
|
82
|
+
if (!Number.isFinite(timestamp) || timestamp < 0 || timestamp > Date.now() + 60_000) return false;
|
|
83
|
+
const stored = entry.value?.revalidate;
|
|
84
|
+
const storedTtl = typeof stored === 'number' && Number.isFinite(stored) && stored >= 0 ? stored : Infinity;
|
|
85
|
+
const ttl = Math.min(revalidate === false ? Infinity : revalidate, storedTtl);
|
|
86
|
+
return Date.now() - timestamp < ttl * 1000;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Keep streaming fetch responses live while only bounded captured bytes enter storage. */
|
|
90
|
+
async function cachedIncrementalValue(key, producer, options) {
|
|
91
|
+
const cache = require('./data-cache.cjs');
|
|
92
|
+
const { context, incremental } = options;
|
|
93
|
+
const signal = options.signal || context.signal;
|
|
94
|
+
const state = cache.cacheState(context);
|
|
95
|
+
await state.invalidations;
|
|
96
|
+
signal?.throwIfAborted();
|
|
97
|
+
const { handler, record } = await load(context);
|
|
98
|
+
const tags = cache.validateTags(options.tags);
|
|
99
|
+
const implicit = softTags(context);
|
|
100
|
+
const revalidate = options.revalidate == null ? false : options.revalidate;
|
|
101
|
+
const getContext = { kind: 'FETCH', fetchCache: true, tags, softTags: implicit,
|
|
102
|
+
revalidate, fetchUrl: incremental.url || '', fetchIdx: 0 };
|
|
103
|
+
// PPR artifacts cannot hide invalidations maintained by an external backend.
|
|
104
|
+
if (context.cacheComponents) trackStaticDependency({ externalCache: true }, context);
|
|
105
|
+
let entry, bytes;
|
|
106
|
+
try {
|
|
107
|
+
entry = await invoke(handler, 'get', [key, getContext], context);
|
|
108
|
+
if (entry?.value?.kind === 'FETCH' && typeof entry.lastModified === 'number' && Number.isFinite(entry.lastModified)) {
|
|
109
|
+
bytes = incremental.decode(entry.value);
|
|
110
|
+
if (!Buffer.isBuffer(bytes) || bytes.length > MAX_BYTES) bytes = undefined;
|
|
111
|
+
}
|
|
112
|
+
} catch { signal?.throwIfAborted(); }
|
|
113
|
+
const stale = bytes && !fresh(entry, revalidate);
|
|
114
|
+
if (bytes && !stale) return bytes;
|
|
115
|
+
const existing = record.owners.get(key);
|
|
116
|
+
if (options.join !== false && (!bytes || options.forceFresh || context.staticState) && existing?.revision === record.revision) {
|
|
117
|
+
// Read the backend again after joining: it owns cross-instance invalidation.
|
|
118
|
+
await wait(existing.done, signal, 25_000);
|
|
119
|
+
if (options.join !== false) return cachedIncrementalValue(key, producer, { ...options, join: false });
|
|
120
|
+
}
|
|
121
|
+
if (stale && !options.forceFresh && !context.staticState && existing?.revision === record.revision) return bytes;
|
|
122
|
+
const background = Boolean(stale && !options.forceFresh && !context.staticState);
|
|
123
|
+
const revision = record.revision;
|
|
124
|
+
let complete;
|
|
125
|
+
const owner = { revision, done: new Promise(resolve => { complete = resolve; }) };
|
|
126
|
+
if (ownersCount < 64) { record.owners.set(key, owner); ownersCount++; }
|
|
127
|
+
let lease;
|
|
128
|
+
const cleanup = async () => {
|
|
129
|
+
if (owner.finished) return;
|
|
130
|
+
owner.finished = true;
|
|
131
|
+
try { await lease?.release(); } finally {
|
|
132
|
+
if (record.owners.get(key) === owner) record.owners.delete(key);
|
|
133
|
+
if (owner.tracked) ownersCount--;
|
|
134
|
+
complete();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
owner.tracked = record.owners.get(key) === owner;
|
|
138
|
+
const store = async value => {
|
|
139
|
+
if (value == null || revision !== record.revision) return;
|
|
140
|
+
if (!(value instanceof Uint8Array) || value.byteLength > MAX_BYTES) return;
|
|
141
|
+
if (lease && !await lease.valid()) return;
|
|
142
|
+
const data = incremental.encode(Buffer.from(value));
|
|
143
|
+
const setContext = { ...getContext, tags: [...new Set([...tags, ...implicit])], cacheControl: { revalidate } };
|
|
144
|
+
try {
|
|
145
|
+
await invoke(handler, 'set', [key, { kind: 'FETCH', data, revalidate: revalidate === false ? 31536000 : revalidate }, setContext], context);
|
|
146
|
+
// A mutation in any local worker can revoke the native lease while the
|
|
147
|
+
// asynchronous backend write is finishing. Remove a possibly old entry.
|
|
148
|
+
if (revision !== record.revision || (lease && !await lease.valid())) await invoke(handler, 'set', [key, null, setContext], context);
|
|
149
|
+
}
|
|
150
|
+
catch { signal?.throwIfAborted(); }
|
|
151
|
+
};
|
|
152
|
+
const work = (async () => {
|
|
153
|
+
try {
|
|
154
|
+
lease = await cache.acquireExternalCacheLease(key, signal);
|
|
155
|
+
if (lease) {
|
|
156
|
+
// Even an immediately granted lease may follow a producer that finished
|
|
157
|
+
// between our first backend read and this native admission.
|
|
158
|
+
let shared;
|
|
159
|
+
try {
|
|
160
|
+
const latest = await invoke(handler, 'get', [key, getContext], context);
|
|
161
|
+
if (latest?.value?.kind === 'FETCH' && fresh(latest, revalidate)) {
|
|
162
|
+
shared = incremental.decode(latest.value);
|
|
163
|
+
if (!Buffer.isBuffer(shared) || shared.length > MAX_BYTES) shared = undefined;
|
|
164
|
+
}
|
|
165
|
+
} catch { signal?.throwIfAborted(); }
|
|
166
|
+
if (shared) { await cleanup(); return shared; }
|
|
167
|
+
}
|
|
168
|
+
const result = await wait(Promise.resolve().then(() => producer({ background, signal })), signal, 25_000);
|
|
169
|
+
if (result?.[cache.DEFERRED_VALUE]) {
|
|
170
|
+
const fill = (async () => {
|
|
171
|
+
try { await store(await wait(result.cacheValue, signal, 25_000)); }
|
|
172
|
+
finally { try { if (background) await wait(result.dispose?.(), signal, 1000); } finally { await cleanup(); } }
|
|
173
|
+
})();
|
|
174
|
+
const observed = fill.catch(() => {});
|
|
175
|
+
state.pending.add(observed); void observed.finally(() => state.pending.delete(observed));
|
|
176
|
+
return result.value;
|
|
177
|
+
}
|
|
178
|
+
try { await store(result); return result; } finally { await cleanup(); }
|
|
179
|
+
} catch (error) { await cleanup(); throw error; }
|
|
180
|
+
})();
|
|
181
|
+
if (!background) return work;
|
|
182
|
+
const observed = work.catch(async error => { try { await error?.dispose?.(); } catch {} });
|
|
183
|
+
state.pending.add(observed); void observed.finally(() => state.pending.delete(observed));
|
|
184
|
+
return bytes;
|
|
185
|
+
}
|
|
186
|
+
module.exports = { configured, load, invoke, wait, getEntry, setEntry, invalidate, cachedIncrementalValue };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/// <reference path="./fetch.d.cts" />
|
|
2
|
+
import type { ComponentType } from 'react';
|
|
3
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
4
|
+
export type { Metadata, Viewport, ResolvingMetadata, ResolvingViewport, MetadataRoute } from './metadata.cjs';
|
|
5
|
+
|
|
6
|
+
export interface InstantSample {
|
|
7
|
+
cookies?: Array<{name: string; value: string | null}>;
|
|
8
|
+
headers?: Array<[string, string | null]>;
|
|
9
|
+
params?: Record<string, string | string[]>;
|
|
10
|
+
searchParams?: Record<string, string | string[] | null>;
|
|
11
|
+
}
|
|
12
|
+
export type InstantConfig = boolean | { level?: 'warning' | 'experimental-error'; unstable_samples?: InstantSample[]; unstable_disableValidation?: true; unstable_disableDevValidation?: true; unstable_disableBuildValidation?: true };
|
|
13
|
+
|
|
14
|
+
export type TurbopackCondition = 'browser' | 'foreign' | 'development' | 'production' | 'node' | 'edge-light'
|
|
15
|
+
| {all: TurbopackCondition[]} | {any: TurbopackCondition[]} | {not: TurbopackCondition}
|
|
16
|
+
| {path: string | RegExp; content?: RegExp} | {path?: string | RegExp; content: RegExp};
|
|
17
|
+
export interface TurbopackRule {
|
|
18
|
+
loaders: Array<string | {loader: string; options?: Record<string, unknown>}>;
|
|
19
|
+
as?: '*.js' | '*.jsx';
|
|
20
|
+
condition?: TurbopackCondition;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type PreviewData = string | false | object | undefined;
|
|
24
|
+
export type ParsedUrlQuery = Record<string, string | string[] | undefined>;
|
|
25
|
+
export type Redirect = ({ destination: string; permanent: boolean; statusCode?: never } | { destination: string; statusCode: 301 | 302 | 303 | 307 | 308; permanent?: never }) & { basePath?: false };
|
|
26
|
+
export type DataResult<Props> = { props: Props | Promise<Props> } | { notFound: true } | { redirect: Redirect };
|
|
27
|
+
export interface LocaleInfo { locale?: string; locales?: string[]; defaultLocale?: string; }
|
|
28
|
+
export interface GetServerSidePropsContext<Params extends ParsedUrlQuery = ParsedUrlQuery> extends LocaleInfo {
|
|
29
|
+
req: IncomingMessage & { cookies: Record<string, string>; query: ParsedUrlQuery };
|
|
30
|
+
res: ServerResponse;
|
|
31
|
+
params?: Params;
|
|
32
|
+
query: ParsedUrlQuery;
|
|
33
|
+
resolvedUrl: string;
|
|
34
|
+
preview: boolean;
|
|
35
|
+
previewData?: PreviewData;
|
|
36
|
+
draftMode: boolean;
|
|
37
|
+
}
|
|
38
|
+
export type GetServerSideProps<Props extends Record<string, unknown> = Record<string, unknown>, Params extends ParsedUrlQuery = ParsedUrlQuery> = (context: GetServerSidePropsContext<Params>) => Promise<DataResult<Props>> | DataResult<Props>;
|
|
39
|
+
export interface GetStaticPropsContext<Params extends ParsedUrlQuery = ParsedUrlQuery> extends LocaleInfo {
|
|
40
|
+
params?: Params;
|
|
41
|
+
preview: boolean;
|
|
42
|
+
previewData?: PreviewData;
|
|
43
|
+
draftMode: boolean;
|
|
44
|
+
revalidateReason: 'build' | 'stale' | 'on-demand';
|
|
45
|
+
}
|
|
46
|
+
export type GetStaticProps<Props extends Record<string, unknown> = Record<string, unknown>, Params extends ParsedUrlQuery = ParsedUrlQuery> = (context: GetStaticPropsContext<Params>) => Promise<DataResult<Props> & { revalidate?: number | false }> | (DataResult<Props> & { revalidate?: number | false });
|
|
47
|
+
export type GetStaticPaths<Params extends ParsedUrlQuery = ParsedUrlQuery> = (context: {locales?: string[]; defaultLocale?: string}) => Promise<{ paths: Array<string | { params: Params; locale?: string }>; fallback: boolean | 'blocking' }> | { paths: Array<string | { params: Params; locale?: string }>; fallback: boolean | 'blocking' };
|
|
48
|
+
export type InferGetServerSidePropsType<T extends (...args: any[]) => any> = Awaited<Extract<Awaited<ReturnType<T>>, { props: any }>['props']>;
|
|
49
|
+
export type InferGetStaticPropsType<T extends (...args: any[]) => any> = InferGetServerSidePropsType<T>;
|
|
50
|
+
export interface NextApiRequest extends IncomingMessage {
|
|
51
|
+
query: ParsedUrlQuery;
|
|
52
|
+
cookies: Record<string, string>;
|
|
53
|
+
body: any;
|
|
54
|
+
draftMode: boolean;
|
|
55
|
+
preview: boolean;
|
|
56
|
+
previewData?: PreviewData;
|
|
57
|
+
}
|
|
58
|
+
/** Pages API responses can stream; socket upgrades are not implemented. */
|
|
59
|
+
export type NextApiResponse<T = any> = Pick<ServerResponse, 'statusCode' | 'statusMessage' | 'headersSent' | 'getHeader' | 'getHeaders' | 'getHeaderNames' | 'hasHeader' | 'removeHeader' | 'write' | 'end' | 'on' | 'once' | 'writableEnded'> & {
|
|
60
|
+
setHeader(name: string, value: number | string | readonly string[]): NextApiResponse<T>;
|
|
61
|
+
appendHeader(name: string, value: string | readonly string[]): NextApiResponse<T>;
|
|
62
|
+
writeHead(statusCode: number, headers?: import('node:http').OutgoingHttpHeaders): NextApiResponse<T>;
|
|
63
|
+
writeHead(statusCode: number, statusMessage?: string, headers?: import('node:http').OutgoingHttpHeaders): NextApiResponse<T>;
|
|
64
|
+
status(statusCode: number): NextApiResponse<T>;
|
|
65
|
+
json(body: T): void;
|
|
66
|
+
send(body: T | string | Buffer | Uint8Array): void;
|
|
67
|
+
redirect(destination: string): void;
|
|
68
|
+
redirect(statusCode: number, destination: string): void;
|
|
69
|
+
revalidate(path: string, options?: { unstable_onlyGenerated?: boolean }): Promise<void>;
|
|
70
|
+
setPreviewData(data: PreviewData, options?: { maxAge?: number; path?: string }): NextApiResponse<T>;
|
|
71
|
+
setDraftMode(options: { enable: boolean }): NextApiResponse<T>;
|
|
72
|
+
clearPreviewData(options?: { path?: string }): NextApiResponse<T>;
|
|
73
|
+
};
|
|
74
|
+
export type NextApiHandler<T = any> = (req: NextApiRequest, res: NextApiResponse<T>) => void | Promise<void>;
|
|
75
|
+
export interface NextPageContext extends LocaleInfo {
|
|
76
|
+
err?: (Error & { statusCode?: number }) | null;
|
|
77
|
+
req?: IncomingMessage;
|
|
78
|
+
res?: ServerResponse;
|
|
79
|
+
pathname: string;
|
|
80
|
+
query: ParsedUrlQuery;
|
|
81
|
+
asPath?: string;
|
|
82
|
+
AppTree: ComponentType<AppInitialProps & Record<string, any>>;
|
|
83
|
+
}
|
|
84
|
+
export type NextPage<Props = Record<string, never>, InitialProps = Props> = ComponentType<Props> & {
|
|
85
|
+
getInitialProps?(context: NextPageContext): InitialProps | Promise<InitialProps>;
|
|
86
|
+
};
|
|
87
|
+
export interface AppProps<Props = Record<string, unknown>> {
|
|
88
|
+
Component: NextPage<Props, any>;
|
|
89
|
+
pageProps: Props;
|
|
90
|
+
router: import('./router.cjs').PRNextRouter;
|
|
91
|
+
}
|
|
92
|
+
export interface AppInitialProps<Props = any> { pageProps: Props }
|
|
93
|
+
export interface AppContext {
|
|
94
|
+
Component: NextPage<any, any>;
|
|
95
|
+
router: import('./router.cjs').PRNextRouter;
|
|
96
|
+
ctx: NextPageContext;
|
|
97
|
+
AppTree: ComponentType<any>;
|
|
98
|
+
}
|
|
99
|
+
export type AppType<Props = {}> = ComponentType<AppProps<any> & Props> & {
|
|
100
|
+
getInitialProps?(context: AppContext): AppInitialProps & Props | Promise<AppInitialProps & Props>;
|
|
101
|
+
};
|
|
102
|
+
export type RouteCondition = { type: 'header' | 'cookie' | 'query'; key: string; value?: string } | { type: 'host'; value: string; key?: never };
|
|
103
|
+
export interface CustomRoute {
|
|
104
|
+
source: string;
|
|
105
|
+
has?: RouteCondition[];
|
|
106
|
+
missing?: RouteCondition[];
|
|
107
|
+
basePath?: false;
|
|
108
|
+
locale?: false;
|
|
109
|
+
}
|
|
110
|
+
export interface Header extends CustomRoute { headers: Array<{ key: string; value: string }> }
|
|
111
|
+
export interface Rewrite extends CustomRoute { destination: string }
|
|
112
|
+
export type ConfigRedirect = CustomRoute & Redirect;
|
|
113
|
+
/** Implemented project options. Unsupported behavior-changing options fail the build. */
|
|
114
|
+
export interface NextConfig {
|
|
115
|
+
/** Next dev page-retention hints; PRNext builds all routes without that eviction queue. */
|
|
116
|
+
onDemandEntries?: { maxInactiveAge?: number; pagesBufferLength?: number };
|
|
117
|
+
i18n?: { locales: string[]; defaultLocale: string; localeDetection?: boolean; domains?: Array<{domain: string; defaultLocale: string; locales?: string[]; http?: boolean}> };
|
|
118
|
+
webpack?: (config: import('webpack').Configuration, context: { buildId: string; dev: boolean; isServer: boolean; nextRuntime?: 'nodejs' | 'edge'; webpack: typeof import('webpack'); defaultLoaders: {babel: {loader: string}} }) => import('webpack').Configuration | Promise<import('webpack').Configuration>;
|
|
119
|
+
turbopack?: { root?: string; rules?: Record<string, TurbopackRule | TurbopackRule[]>; resolveAlias?: Record<string, string | { browser: string }>; resolveExtensions?: string[] };
|
|
120
|
+
images?: import('./image.cjs').ImageConfig;
|
|
121
|
+
pageExtensions?: string[];
|
|
122
|
+
reactStrictMode?: boolean;
|
|
123
|
+
cacheComponents?: boolean;
|
|
124
|
+
cacheLife?: Record<string, import('./cache.cjs').CacheLife>;
|
|
125
|
+
transpilePackages?: string[];
|
|
126
|
+
serverExternalPackages?: string[];
|
|
127
|
+
sassOptions?: {
|
|
128
|
+
additionalData?: string | ((source: string, context: { resourcePath: string; rootContext: string }) => string | Promise<string>);
|
|
129
|
+
includePaths?: string[];
|
|
130
|
+
loadPaths?: string[];
|
|
131
|
+
implementation?: 'sass' | 'sass-embedded';
|
|
132
|
+
[option: string]: unknown;
|
|
133
|
+
};
|
|
134
|
+
experimental?: { nextScriptWorkers?: boolean; serverActions?: true | { allowedOrigins?: string[]; bodySizeLimit?: number | string } };
|
|
135
|
+
trailingSlash?: boolean;
|
|
136
|
+
skipTrailingSlashRedirect?: boolean;
|
|
137
|
+
skipMiddlewareUrlNormalize?: boolean;
|
|
138
|
+
skipProxyUrlNormalize?: boolean;
|
|
139
|
+
cacheHandlers?: Record<string, string | undefined>;
|
|
140
|
+
cacheHandler?: string;
|
|
141
|
+
cacheMaxMemorySize?: number;
|
|
142
|
+
distDir?: string;
|
|
143
|
+
output?: 'standalone' | 'export';
|
|
144
|
+
outputFileTracingRoot?: string;
|
|
145
|
+
outputFileTracingIncludes?: Record<string, string[]>;
|
|
146
|
+
outputFileTracingExcludes?: Record<string, string[]>;
|
|
147
|
+
basePath?: string;
|
|
148
|
+
assetPrefix?: string;
|
|
149
|
+
env?: Record<string, string | undefined>;
|
|
150
|
+
compress?: boolean;
|
|
151
|
+
poweredByHeader?: boolean;
|
|
152
|
+
productionBrowserSourceMaps?: boolean;
|
|
153
|
+
generateBuildId?: () => string | null | Promise<string | null>;
|
|
154
|
+
headers?: () => Header[] | Promise<Header[]>;
|
|
155
|
+
redirects?: () => ConfigRedirect[] | Promise<ConfigRedirect[]>;
|
|
156
|
+
rewrites?: () => Rewrite[] | { beforeFiles?: Rewrite[]; afterFiles?: Rewrite[]; fallback?: Rewrite[] } | Promise<Rewrite[] | { beforeFiles?: Rewrite[]; afterFiles?: Rewrite[]; fallback?: Rewrite[] }>;
|
|
157
|
+
}
|
|
158
|
+
export type PRNextConfig = NextConfig;
|
|
159
|
+
export type { DocumentContext, DocumentInitialProps, DocumentProps } from './document.cjs';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const record = value => value && typeof value === 'object' && !Array.isArray(value);
|
|
3
|
+
const text = value => typeof value === 'string' && value.length <= 8192;
|
|
4
|
+
const values = value => text(value) || Array.isArray(value) && value.length <= 128 && value.every(text);
|
|
5
|
+
function validSamples(samples) {
|
|
6
|
+
return Array.isArray(samples) && samples.length > 0 && samples.length <= 32 && Buffer.byteLength(JSON.stringify(samples)) <= 128 * 1024 && samples.every(sample => record(sample) && Object.entries(sample).every(([name,value]) => {
|
|
7
|
+
if (name === 'cookies') return Array.isArray(value) && value.length <= 128 && value.every(item => record(item) && Object.keys(item).every(key=>['name','value'].includes(key)) && text(item.name) && /^[!#$%&'*+.^_`|~\w-]+$/.test(item.name) && (item.value === null || text(item.value)));
|
|
8
|
+
if (name === 'headers') return Array.isArray(value) && value.length <= 128 && value.every(item => Array.isArray(item) && item.length === 2 && text(item[0]) && /^[!#$%&'*+.^_`|~\w-]+$/.test(item[0]) && (item[1] === null || text(item[1]) && !/[\r\n\0]/.test(item[1])));
|
|
9
|
+
if (name === 'params' || name === 'searchParams') return record(value) && Object.keys(value).length <= 128 && Object.entries(value).every(([key,value])=>text(key) && (values(value) || name === 'searchParams' && value === null));
|
|
10
|
+
return false;
|
|
11
|
+
}));
|
|
12
|
+
}
|
|
13
|
+
function missing(request, kind, name) {
|
|
14
|
+
const error = Object.assign(new Error(`Route ${request.routePattern}: instant.unstable_samples does not declare ${kind} ${JSON.stringify(name)}. Supply a value${kind === 'params' ? '' : ' or null for absence'}.`),{code:'PRNEXT_INSTANT_SAMPLE'});
|
|
15
|
+
if(request.staticState) request.staticState.error ||= error;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
function sampleMethods(request,kind,target) {
|
|
19
|
+
const sample = request.instantSample;
|
|
20
|
+
const names = new Set((sample[kind] || []).map(item=>kind === 'cookies' ? item.name : item[0].toLowerCase()));
|
|
21
|
+
if(kind === 'headers' && sample.cookies)names.add('cookie');
|
|
22
|
+
return new Proxy(target,{get(value,key){
|
|
23
|
+
const method=Reflect.get(value,key,value);
|
|
24
|
+
if(['get','has','getAll'].includes(key))return argument=>{
|
|
25
|
+
const name=typeof argument === 'object' ? argument.name : argument;
|
|
26
|
+
if(name !== undefined && !names.has(kind === 'headers' ? String(name).toLowerCase() : name))missing(request,kind,name);
|
|
27
|
+
return method.call(value,argument);
|
|
28
|
+
};
|
|
29
|
+
return typeof method === 'function' ? method.bind(value) : method;
|
|
30
|
+
}});
|
|
31
|
+
}
|
|
32
|
+
function sampleObject(request,kind,values) {
|
|
33
|
+
const declared=request.instantSample[kind] || {};
|
|
34
|
+
return new Proxy(values,{get(target,key,receiver){
|
|
35
|
+
if(typeof key === 'string' && !['then','toJSON'].includes(key) && !Object.hasOwn(declared,key))missing(request,kind,key);
|
|
36
|
+
return Reflect.get(target,key,receiver);
|
|
37
|
+
},has(target,key){if(typeof key==='string'&&!Object.hasOwn(declared,key))missing(request,kind,key);return Reflect.has(target,key);}});
|
|
38
|
+
}
|
|
39
|
+
module.exports={validSamples,sampleMethods,sampleObject};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Shell validation is separate: these options only control navigation probes.
|
|
4
|
+
function instantEnabled(config, production) {
|
|
5
|
+
if (config === false) return false;
|
|
6
|
+
if (config && typeof config === 'object') {
|
|
7
|
+
if (config.unstable_disableValidation || (production ? config.unstable_disableBuildValidation : config.unstable_disableDevValidation)) return false;
|
|
8
|
+
return !production || config.level === 'experimental-error';
|
|
9
|
+
}
|
|
10
|
+
return !production;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
module.exports = { instantEnabled };
|
package/compat/link.cjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
'use strict';
|
|
3
|
+
const React = require('react');
|
|
4
|
+
const { formatUrl, RouterContext } = require('./router.cjs');
|
|
5
|
+
const { AppRouterContext } = require('./app-context.cjs');
|
|
6
|
+
const { addBasePath, hasBasePath, normalizeTrailingSlash } = require('./paths.cjs');
|
|
7
|
+
const { localizedHref } = require('./locale.cjs');
|
|
8
|
+
|
|
9
|
+
const Link = React.forwardRef(function Link({ href, as, children, replace, scroll, shallow, prefetch,
|
|
10
|
+
locale, legacyBehavior, passHref, onClick, onNavigate, onMouseEnter, onTouchStart, ...props }, ref) {
|
|
11
|
+
const app = React.useContext(AppRouterContext);
|
|
12
|
+
const pages = React.useContext(RouterContext);
|
|
13
|
+
const anchorRef = React.useRef(null);
|
|
14
|
+
const setRef = React.useCallback(node => { anchorRef.current = node; if (typeof ref === 'function') ref(node); else if (ref) ref.current = node; }, [ref]);
|
|
15
|
+
const target = localizedHref(formatUrl(as || href), pages, locale);
|
|
16
|
+
const basePath = app?.basePath || pages?.basePath || '';
|
|
17
|
+
const policy = app || pages || {};
|
|
18
|
+
const mounted = basePath && /^\/(?:[?#]|$)/.test(target) && !policy.trailingSlash && !policy.skipTrailingSlashRedirect ? `${basePath}${target.slice(1)}`
|
|
19
|
+
: target.startsWith('//') ? target : addBasePath(target, basePath);
|
|
20
|
+
const publicTarget = normalizeTrailingSlash(mounted, policy);
|
|
21
|
+
const source = formatUrl(href);
|
|
22
|
+
const requestPrefetch = React.useCallback(() => {
|
|
23
|
+
if (app?.router.partialPrefetch && prefetch !== false && process.env.NODE_ENV === 'production') app.router.prefetch(target);
|
|
24
|
+
if (!app && pages && process.env.NODE_ENV === 'production') void pages.prefetch(source, as ? target : undefined, {locale}).catch(() => {});
|
|
25
|
+
}, [app, pages, source, target, as, prefetch]);
|
|
26
|
+
React.useEffect(() => {
|
|
27
|
+
if ((app ? !app.router.partialPrefetch : !pages) || prefetch === false || process.env.NODE_ENV !== 'production' || typeof IntersectionObserver === 'undefined' || !anchorRef.current) return;
|
|
28
|
+
const observer = new IntersectionObserver(entries => {
|
|
29
|
+
if (entries.some(entry => entry.isIntersecting)) { observer.disconnect(); requestPrefetch(); }
|
|
30
|
+
}, { rootMargin: '200px' });
|
|
31
|
+
observer.observe(anchorRef.current);
|
|
32
|
+
return () => observer.disconnect();
|
|
33
|
+
}, [app, pages, prefetch, requestPrefetch]);
|
|
34
|
+
if (/^[\s\u0000-\u001f]*javascript:/i.test(target.replace(/[\r\n\t]/g, ''))) {
|
|
35
|
+
throw new Error('Link does not permit javascript: URLs');
|
|
36
|
+
}
|
|
37
|
+
function click(event) {
|
|
38
|
+
onClick?.(event);
|
|
39
|
+
const anchor = event.currentTarget;
|
|
40
|
+
const anchorTarget = anchor?.getAttribute('target') || props.target;
|
|
41
|
+
if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey ||
|
|
42
|
+
(anchorTarget && anchorTarget.toLowerCase() !== '_self') || anchor?.hasAttribute('download') || props.download !== undefined) return;
|
|
43
|
+
const destination = new URL(publicTarget, window.location.href);
|
|
44
|
+
if (destination.origin !== window.location.origin || !hasBasePath(destination.pathname, basePath) || !['http:', 'https:'].includes(destination.protocol)) return;
|
|
45
|
+
let prevented = false;
|
|
46
|
+
onNavigate?.({ preventDefault() { prevented = true; event.preventDefault(); } });
|
|
47
|
+
if (prevented) return;
|
|
48
|
+
if (app) {
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
app.router[replace ? 'replace' : 'push'](target, { scroll });
|
|
51
|
+
} else if (pages) {
|
|
52
|
+
event.preventDefault();
|
|
53
|
+
void pages[replace ? 'replace' : 'push'](href, as, { scroll, shallow, locale }).catch(error => console.error(error));
|
|
54
|
+
} else if (replace) { event.preventDefault(); window.location.replace(publicTarget); }
|
|
55
|
+
}
|
|
56
|
+
function hover(event) { onMouseEnter?.(event); requestPrefetch(); }
|
|
57
|
+
function touch(event) { onTouchStart?.(event); requestPrefetch(); }
|
|
58
|
+
if (legacyBehavior) {
|
|
59
|
+
const child = React.Children.only(children);
|
|
60
|
+
return React.cloneElement(child, { ...props, href: publicTarget, ref: setRef,
|
|
61
|
+
onMouseEnter(event) { child.props.onMouseEnter?.(event); hover(event); },
|
|
62
|
+
onTouchStart(event) { child.props.onTouchStart?.(event); touch(event); },
|
|
63
|
+
onClick(event) { child.props.onClick?.(event); if (!event.defaultPrevented) click(event); } });
|
|
64
|
+
}
|
|
65
|
+
return React.createElement('a', { ...props, href: publicTarget, ref: setRef, onClick: click, onMouseEnter: hover, onTouchStart: touch }, children);
|
|
66
|
+
});
|
|
67
|
+
module.exports = Link;
|
|
68
|
+
module.exports.default = Link;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AnchorHTMLAttributes, ForwardRefExoticComponent, ReactNode, RefAttributes } from 'react';
|
|
2
|
+
import type { UrlObject } from './router.cjs';
|
|
3
|
+
export interface LinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'href'> {
|
|
4
|
+
href: string | UrlObject;
|
|
5
|
+
as?: string | UrlObject;
|
|
6
|
+
replace?: boolean;
|
|
7
|
+
scroll?: boolean;
|
|
8
|
+
shallow?: boolean;
|
|
9
|
+
prefetch?: boolean | null;
|
|
10
|
+
locale?: string | false;
|
|
11
|
+
legacyBehavior?: boolean;
|
|
12
|
+
passHref?: boolean;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
onNavigate?: (event: { preventDefault(): void }) => void;
|
|
15
|
+
}
|
|
16
|
+
declare const Link: ForwardRefExoticComponent<LinkProps & RefAttributes<HTMLAnchorElement>>;
|
|
17
|
+
export default Link;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
function localePath(pathname, i18n) {
|
|
3
|
+
if (!i18n) return { pathname, locale: undefined };
|
|
4
|
+
const first = pathname.split(/[/?#]/)[1];
|
|
5
|
+
const locale = i18n.locales.find(value => value.toLowerCase() === first?.toLowerCase());
|
|
6
|
+
const rest = locale ? pathname.slice(first.length + 1) : pathname;
|
|
7
|
+
return { pathname: rest.startsWith('/') ? rest : '/' + rest, locale: locale || i18n.defaultLocale };
|
|
8
|
+
}
|
|
9
|
+
function withLocale(pathname, locale, defaultLocale) {
|
|
10
|
+
return !locale || locale === defaultLocale ? pathname : '/' + locale + (pathname === '/' ? '' : pathname);
|
|
11
|
+
}
|
|
12
|
+
function localizedHref(href, router, selected) {
|
|
13
|
+
if (!router?.i18n || selected === false || !href.startsWith('/') || href.startsWith('//')) return href;
|
|
14
|
+
const i18n = router.i18n;
|
|
15
|
+
const locale = selected || router.locale || i18n.defaultLocale;
|
|
16
|
+
if (!i18n.locales.includes(locale)) throw new Error(`Unknown locale: ${locale}`);
|
|
17
|
+
const url = new URL(href, 'http://prnext.local');
|
|
18
|
+
const base = router.basePath || '';
|
|
19
|
+
if (base && (url.pathname === base || url.pathname.startsWith(base + '/'))) url.pathname = url.pathname.slice(base.length) || '/';
|
|
20
|
+
const parsed = localePath(url.pathname, i18n);
|
|
21
|
+
const explicit = parsed.pathname !== url.pathname;
|
|
22
|
+
const chosen = selected || (explicit ? parsed.locale : locale);
|
|
23
|
+
const domain = i18n.domains?.find(value => value.defaultLocale === chosen || value.locales?.includes(chosen));
|
|
24
|
+
const host = router.domain;
|
|
25
|
+
const current = i18n.domains?.find(value => value.domain.toLowerCase() === host?.toLowerCase());
|
|
26
|
+
const prefix = domain && current && domain.domain !== current.domain ? `${domain.http ? 'http' : 'https'}://${domain.domain}` : '';
|
|
27
|
+
const defaultLocale = (prefix ? domain?.defaultLocale : current?.defaultLocale) || router.defaultLocale || i18n.defaultLocale;
|
|
28
|
+
return prefix + base + withLocale(parsed.pathname, chosen, defaultLocale) + url.search + url.hash;
|
|
29
|
+
}
|
|
30
|
+
module.exports = { localePath, withLocale, localizedHref };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
type OneOrMany<T> = T | T[];
|
|
2
|
+
type Url = string | URL;
|
|
3
|
+
type Title = string | { default: string; template: string; absolute?: string } | { absolute: string; template?: string };
|
|
4
|
+
type UrlDescriptor = { url: Url; title?: string };
|
|
5
|
+
type Image = Url | { url: Url; secureUrl?: Url; width?: string | number; height?: string | number; alt?: string; type?: string };
|
|
6
|
+
type Robots = { index?: boolean; follow?: boolean; noarchive?: boolean; nosnippet?: boolean; noimageindex?: boolean; nocache?: boolean; notranslate?: boolean; indexifembedded?: boolean; nositelinkssearchbox?: boolean; unavailable_after?: string; 'max-video-preview'?: number; 'max-image-preview'?: 'none' | 'standard' | 'large'; 'max-snippet'?: number };
|
|
7
|
+
type Icon = Url | { url: Url; rel?: string; sizes?: string; type?: string; media?: string; color?: string; fetchPriority?: 'high' | 'low' | 'auto' };
|
|
8
|
+
type Social = { title?: Title; description?: string; images?: OneOrMany<Image> };
|
|
9
|
+
type OpenGraph = Social & {
|
|
10
|
+
type?: 'website' | 'article' | 'book' | 'profile' | 'music.song' | 'music.album' | 'music.playlist' | 'music.radio_station' | 'video.movie' | 'video.episode' | 'video.tv_show' | 'video.other';
|
|
11
|
+
url?: Url; siteName?: string; locale?: string; countryName?: string; determiner?: string; ttl?: number;
|
|
12
|
+
emails?: OneOrMany<string>; phoneNumbers?: OneOrMany<string>; faxNumbers?: OneOrMany<string>; alternateLocale?: OneOrMany<string>;
|
|
13
|
+
audio?: OneOrMany<Url | { url: Url; secureUrl?: Url; type?: string }>; videos?: OneOrMany<Image>;
|
|
14
|
+
publishedTime?: string; modifiedTime?: string; expirationTime?: string; authors?: OneOrMany<string>; section?: string; tags?: OneOrMany<string>;
|
|
15
|
+
isbn?: string; releaseDate?: string; firstName?: string; lastName?: string; username?: string; gender?: string;
|
|
16
|
+
duration?: number; albums?: OneOrMany<Url | { url: Url; disc?: number; track?: number }>; songs?: OneOrMany<Url | { url: Url; disc?: number; track?: number }>;
|
|
17
|
+
musicians?: OneOrMany<string>; creators?: OneOrMany<string>; actors?: OneOrMany<Url | { url: Url; role?: string }>; directors?: OneOrMany<string>; writers?: OneOrMany<string>; series?: Url;
|
|
18
|
+
};
|
|
19
|
+
type Twitter = Social & {
|
|
20
|
+
card?: 'summary' | 'summary_large_image' | 'player' | 'app'; site?: string; siteId?: string; creator?: string; creatorId?: string;
|
|
21
|
+
players?: OneOrMany<{ playerUrl: string; streamUrl: string; width: number; height: number }>;
|
|
22
|
+
app?: { name?: string; id: { iphone?: string | number; ipad?: string | number; googleplay?: string }; url?: { iphone?: string; ipad?: string; googleplay?: string } };
|
|
23
|
+
};
|
|
24
|
+
export interface Viewport {
|
|
25
|
+
width?: string | number; height?: string | number; initialScale?: number; minimumScale?: number; maximumScale?: number; userScalable?: boolean;
|
|
26
|
+
viewportFit?: 'auto' | 'cover' | 'contain'; interactiveWidget?: 'resizes-visual' | 'resizes-content' | 'overlays-content';
|
|
27
|
+
themeColor?: string | Array<{ color: string; media?: string }> | null;
|
|
28
|
+
colorScheme?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export interface Metadata {
|
|
31
|
+
metadataBase?: URL | null; title?: Title | null; description?: string | null; applicationName?: string | null; generator?: string | null;
|
|
32
|
+
referrer?: string | null; keywords?: OneOrMany<string> | null; authors?: OneOrMany<{ name?: string; url?: Url }> | null;
|
|
33
|
+
creator?: string | null; publisher?: string | null; category?: string | null; abstract?: string | null; classification?: string | null;
|
|
34
|
+
manifest?: Url | null; robots?: string | (Robots & { googleBot?: string | Robots }) | null;
|
|
35
|
+
alternates?: { canonical?: Url | UrlDescriptor | null; languages?: Record<string, Url | UrlDescriptor[]> | null; media?: Record<string, Url | UrlDescriptor[]> | null; types?: Record<string, Url | UrlDescriptor[]> | null } | null;
|
|
36
|
+
icons?: OneOrMany<Icon> | { icon?: OneOrMany<Icon>; shortcut?: OneOrMany<Icon>; apple?: OneOrMany<Icon>; other?: OneOrMany<Icon> } | null;
|
|
37
|
+
openGraph?: OpenGraph | null; twitter?: Twitter | null;
|
|
38
|
+
verification?: { google?: OneOrMany<string | number>; yahoo?: OneOrMany<string | number>; yandex?: OneOrMany<string | number>; me?: OneOrMany<string | number>; other?: Record<string, OneOrMany<string | number>> };
|
|
39
|
+
appleWebApp?: boolean | { capable?: boolean; title?: string; statusBarStyle?: 'default' | 'black' | 'black-translucent'; startupImage?: OneOrMany<Url | { url: Url; media?: string }> } | null;
|
|
40
|
+
formatDetection?: { telephone?: boolean; date?: boolean; address?: boolean; email?: boolean; url?: boolean } | null;
|
|
41
|
+
itunes?: { appId: string; appArgument?: string } | null;
|
|
42
|
+
facebook?: { appId?: string; admins?: OneOrMany<string> } | null; pinterest?: { richPin: boolean };
|
|
43
|
+
archives?: OneOrMany<string> | null; assets?: OneOrMany<string> | null; bookmarks?: OneOrMany<string> | null; pagination?: { previous?: Url | null; next?: Url | null };
|
|
44
|
+
appLinks?: {
|
|
45
|
+
ios?: OneOrMany<{ url: Url; app_store_id?: string | number; app_name?: string }>; iphone?: OneOrMany<{ url: Url; app_store_id?: string | number; app_name?: string }>; ipad?: OneOrMany<{ url: Url; app_store_id?: string | number; app_name?: string }>;
|
|
46
|
+
android?: OneOrMany<{ package: string; url?: Url; class?: string; app_name?: string }>;
|
|
47
|
+
windows_phone?: OneOrMany<{ url: Url; app_id?: string; app_name?: string }>; windows?: OneOrMany<{ url: Url; app_id?: string; app_name?: string }>; windows_universal?: OneOrMany<{ url: Url; app_id?: string; app_name?: string }>;
|
|
48
|
+
web?: OneOrMany<{ url: Url; should_fallback?: boolean }>;
|
|
49
|
+
} | null;
|
|
50
|
+
other?: Record<string, OneOrMany<string | number>>;
|
|
51
|
+
}
|
|
52
|
+
export type ResolvingMetadata = Promise<Omit<Metadata, 'title' | 'openGraph' | 'twitter' | 'metadataBase'> & {
|
|
53
|
+
title: { absolute: string; template: string | null } | null;
|
|
54
|
+
metadataBase?: string | null;
|
|
55
|
+
openGraph?: Omit<OpenGraph, 'images' | 'title'> & { images?: Exclude<Image, Url>[]; title?: { absolute: string; template: string | null } } | null;
|
|
56
|
+
twitter?: Omit<Twitter, 'images' | 'title'> & { images?: Exclude<Image, Url>[]; title?: { absolute: string; template: string | null } } | null;
|
|
57
|
+
}>;
|
|
58
|
+
export type ResolvingViewport = Promise<Viewport>;
|
|
59
|
+
export namespace MetadataRoute {
|
|
60
|
+
type Robots = {
|
|
61
|
+
rules: OneOrMany<{ userAgent?: OneOrMany<string>; allow?: OneOrMany<string>; disallow?: OneOrMany<string>; crawlDelay?: number; other?: Record<string, OneOrMany<string> | null> }>;
|
|
62
|
+
sitemap?: OneOrMany<string>; host?: string;
|
|
63
|
+
};
|
|
64
|
+
type Sitemap = Array<{
|
|
65
|
+
url: string; lastModified?: string | Date; changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'; priority?: number;
|
|
66
|
+
alternates?: { languages?: Record<string, string> }; images?: string[];
|
|
67
|
+
videos?: Array<{ title: string; thumbnail_loc: string; description: string; content_loc?: string; player_loc?: string; duration?: number; view_count?: number; tag?: string; rating?: number; expiration_date?: string; publication_date?: string; family_friendly?: 'yes' | 'no'; requires_subscription?: 'yes' | 'no'; live?: 'yes' | 'no'; restriction?: { relationship: 'allow' | 'deny'; content: string }; platform?: { relationship: 'allow' | 'deny'; content: string }; uploader?: { content: string; info?: string } }>;
|
|
68
|
+
}>;
|
|
69
|
+
interface Manifest {
|
|
70
|
+
name?: string; short_name?: string; description?: string; id?: string; start_url?: string; scope?: string; lang?: string; dir?: 'auto' | 'ltr' | 'rtl';
|
|
71
|
+
display?: 'fullscreen' | 'standalone' | 'minimal-ui' | 'browser'; display_override?: string[]; orientation?: string; background_color?: string; theme_color?: string; categories?: string[];
|
|
72
|
+
icons?: Array<{ src: string; sizes?: string; type?: string; purpose?: string }>; screenshots?: Array<{ src: string; sizes?: string; type?: string; form_factor?: string; label?: string }>;
|
|
73
|
+
shortcuts?: Array<{ name: string; short_name?: string; description?: string; url: string; icons?: Manifest['icons'] }>;
|
|
74
|
+
related_applications?: Array<{ platform: string; url?: string; id?: string }>; prefer_related_applications?: boolean;
|
|
75
|
+
[extension: string]: unknown;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const RedirectType = Object.freeze({ push: 'push', replace: 'replace' });
|
|
4
|
+
function redirectError(url, type, status) {
|
|
5
|
+
if (typeof url !== 'string' || /[\r\n]/.test(url)) throw new TypeError('Invalid redirect destination');
|
|
6
|
+
if (type !== 'push' && type !== 'replace') throw new TypeError('Invalid redirect type');
|
|
7
|
+
const error = new Error('NEXT_REDIRECT');
|
|
8
|
+
error.digest = `NEXT_REDIRECT;${type};${url};${status};`;
|
|
9
|
+
return error;
|
|
10
|
+
}
|
|
11
|
+
function redirect(url, type = RedirectType.replace) { throw redirectError(url, type, 307); }
|
|
12
|
+
function permanentRedirect(url, type = RedirectType.replace) { throw redirectError(url, type, 308); }
|
|
13
|
+
function notFound() {
|
|
14
|
+
const error = new Error('NEXT_HTTP_ERROR_FALLBACK;404');
|
|
15
|
+
error.digest = 'NEXT_HTTP_ERROR_FALLBACK;404';
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
function unstable_rethrow(error) {
|
|
19
|
+
if (typeof error?.digest === 'string' &&
|
|
20
|
+
(error.digest.startsWith('NEXT_REDIRECT;') || error.digest.startsWith('NEXT_HTTP_ERROR_FALLBACK;'))) throw error;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports.redirect = redirect;
|
|
24
|
+
module.exports.permanentRedirect = permanentRedirect;
|
|
25
|
+
module.exports.notFound = notFound;
|
|
26
|
+
module.exports.RedirectType = RedirectType;
|
|
27
|
+
module.exports.unstable_rethrow = unstable_rethrow;
|