From d5a88ba4eb50fa9fcc2c06a68da54783d615b017 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:26:59 -0800 Subject: [PATCH 1/3] tweak LRU sentinel cache key (#89123) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We originally prefixed the TTL sentinel with the null-byte separator to avoid collisions with real invocation IDs, but that makes `extractInvocationID` return "ttl" instead of undefined for TTL-mode keys. This switches to a reserved magic string sentinel so TTL-mode entries are correctly treated as “no invocation ID”. --- packages/next/src/server/response-cache/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/next/src/server/response-cache/index.ts b/packages/next/src/server/response-cache/index.ts index e40ef2f00596a..4981741e6c31f 100644 --- a/packages/next/src/server/response-cache/index.ts +++ b/packages/next/src/server/response-cache/index.ts @@ -63,10 +63,9 @@ const KEY_SEPARATOR = '\0' /** * Sentinel value used for TTL-based cache entries (when invocationID is undefined). - * Uses KEY_SEPARATOR prefix to guarantee uniqueness since null bytes cannot appear - * in HTTP headers (RFC 7230), making collision with real invocation IDs impossible. + * Chosen to be a clearly reserved marker for internal cache keys. */ -const TTL_SENTINEL = `${KEY_SEPARATOR}ttl` +const TTL_SENTINEL = '__ttl_sentinel__' /** * Entry stored in the LRU cache. From 03899db53a83d7ca665c3f56273595f3dca195a6 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Tue, 27 Jan 2026 23:45:01 +0100 Subject: [PATCH 2/3] Turbopack: allow key block without hash in SST files (#88938) ### What? Change the SST format to allow a variable hash len. For short keys avoid storing the hashes and recompute them on demand instead. For short keys use bit rotation instead of a real hash. This avoid wasting storage for hashes which can be cheaply recomputed --- turbopack/crates/turbo-persistence/README.md | 21 +++-- .../src/static_sorted_file.rs | 85 +++++++++++++++---- .../src/static_sorted_file_builder.rs | 53 +++++++++--- 3 files changed, 124 insertions(+), 35 deletions(-) diff --git a/turbopack/crates/turbo-persistence/README.md b/turbopack/crates/turbo-persistence/README.md index 4ca9331dfefb1..e5ccef6bb6c74 100644 --- a/turbopack/crates/turbo-persistence/README.md +++ b/turbopack/crates/turbo-persistence/README.md @@ -85,7 +85,7 @@ The hashes are sorted. #### Key Block -- 1 byte block type (1: key block) +- 1 byte block type (1: key block with hash, 2: key block without hash) - 3 bytes entry count - foreach entry - 1 byte type @@ -94,23 +94,30 @@ The hashes are sorted. A Key block contains n keys, which specify n key value pairs. +The block type determines whether the key hash is stored per entry: + +- Block type 1 (with hash): Full 8-byte hash stored per entry +- Block type 2 (no hash): No hash stored (for keys ≤ 32 bytes) + +During lookup, if block type is 2, the full hash is recomputed from the key data. + Depending on the `type` field entry has a different format: - 0: normal key (small value) - - 8 bytes key hash + - 8 bytes key hash (if block type 1) - key data - 2 byte block index - 2 bytes size - 4 bytes position in block - 1: blob reference - - 8 bytes key hash + - 8 bytes key hash (if block type 1) - key data - 4 bytes sequence number - 2: deleted key / tombstone (no data) - - 8 bytes key hash + - 8 bytes key hash (if block type 1) - key data - 3: normal key (medium sized value) - - 8 bytes key hash + - 8 bytes key hash (if block type 1) - key data - 2 byte block index - 7: merge key (future) @@ -119,14 +126,12 @@ Depending on the `type` field entry has a different format: - 3 bytes size - 4 bytes position in block - 8..255: inlined key (future) - - 8 bytes key hash + - 8 bytes key hash (if block type 1) - key data - type - 8 bytes value data The entries are sorted by key hash and key. -TODO: 8 bytes key hash is a bit inefficient for small keys. - #### Value Block - no header, all bytes are data referenced by other blocks diff --git a/turbopack/crates/turbo-persistence/src/static_sorted_file.rs b/turbopack/crates/turbo-persistence/src/static_sorted_file.rs index 2233880f397d7..0767d85085870 100644 --- a/turbopack/crates/turbo-persistence/src/static_sorted_file.rs +++ b/turbopack/crates/turbo-persistence/src/static_sorted_file.rs @@ -21,8 +21,10 @@ use crate::{ /// The block header for an index block. pub const BLOCK_TYPE_INDEX: u8 = 0; -/// The block header for a key block. -pub const BLOCK_TYPE_KEY: u8 = 1; +/// The block header for a key block with 8-byte hash per entry. +pub const BLOCK_TYPE_KEY_WITH_HASH: u8 = 1; +/// The block header for a key block without hash. +pub const BLOCK_TYPE_KEY_NO_HASH: u8 = 2; /// The tag for a small-sized value. pub const KEY_BLOCK_ENTRY_TYPE_SMALL: u8 = 0; @@ -152,8 +154,15 @@ impl StaticSortedFile { BLOCK_TYPE_INDEX => { current_block = self.lookup_index_block(block, key_hash)?; } - BLOCK_TYPE_KEY => { - return self.lookup_key_block(block, key_hash, key, value_block_cache); + BLOCK_TYPE_KEY_WITH_HASH | BLOCK_TYPE_KEY_NO_HASH => { + let has_hash = block_type == BLOCK_TYPE_KEY_WITH_HASH; + return self.lookup_key_block( + block, + key_hash, + key, + has_hash, + value_block_cache, + ); } _ => { bail!("Invalid block type"); @@ -214,8 +223,10 @@ impl StaticSortedFile { mut block: &[u8], key_hash: u64, key: &K, + has_hash: bool, value_block_cache: &BlockCache, ) -> Result { + let hash_len: u8 = if has_hash { 8 } else { 0 }; let entry_count = block.read_u24::()? as usize; let offsets = &block[..entry_count * 4]; let entries = &block[entry_count * 4..]; @@ -230,8 +241,11 @@ impl StaticSortedFile { key: mid_key, ty, val: mid_val, - } = get_key_entry(offsets, entries, entry_count, m)?; - match key_hash.cmp(&mid_hash).then_with(|| key.cmp(mid_key)) { + } = get_key_entry(offsets, entries, entry_count, m, hash_len)?; + + let comparison = compare_hash_key(mid_hash, mid_key, key_hash, key); + + match comparison { Ordering::Less => { r = m; } @@ -429,6 +443,7 @@ struct CurrentKeyBlock { entries: ArcSlice, entry_count: usize, index: usize, + hash_len: u8, } struct CurrentIndexBlock { @@ -461,7 +476,9 @@ impl<'l> StaticSortedFileIter<'l> { index: 0, }); } - BLOCK_TYPE_KEY => { + BLOCK_TYPE_KEY_WITH_HASH | BLOCK_TYPE_KEY_NO_HASH => { + let has_hash = block_type == BLOCK_TYPE_KEY_WITH_HASH; + let hash_len = if has_hash { 8 } else { 0 }; let entry_count = block.read_u24::()? as usize; let offsets_range = 4..4 + entry_count * 4; let entries_range = 4 + entry_count * 4..block_arc.len(); @@ -472,6 +489,7 @@ impl<'l> StaticSortedFileIter<'l> { entries, entry_count, index: 0, + hash_len, }); } _ => { @@ -489,10 +507,17 @@ impl<'l> StaticSortedFileIter<'l> { entries, entry_count, index, + hash_len, }) = self.current_key_block.take() { let GetKeyEntryResult { hash, key, ty, val } = - get_key_entry(&offsets, &entries, entry_count, index)?; + get_key_entry(&offsets, &entries, entry_count, index, hash_len)?; + // Convert hash slice to u64, computing from key if no hash stored + let full_hash = if hash.is_empty() { + crate::key::hash_key(&key) + } else { + u64::from_be_bytes(hash.try_into().unwrap()) + }; let value = if ty == KEY_BLOCK_ENTRY_TYPE_MEDIUM { let mut val = val; let block = val.read_u16::()?; @@ -508,7 +533,7 @@ impl<'l> StaticSortedFileIter<'l> { LazyLookupValue::Eager(value) }; let entry = LookupEntry { - hash, + hash: full_hash, // Safety: The key is a valid slice of the entries. key: unsafe { ArcSlice::new_unchecked(key, ArcSlice::full_arc(&entries)) }, value, @@ -519,6 +544,7 @@ impl<'l> StaticSortedFileIter<'l> { entries, entry_count, index: index + 1, + hash_len, }); } return Ok(Some(entry)); @@ -546,19 +572,47 @@ impl<'l> StaticSortedFileIter<'l> { } struct GetKeyEntryResult<'l> { - hash: u64, + hash: &'l [u8], key: &'l [u8], ty: u8, val: &'l [u8], } +/// Compares a query (full_hash + query_key) against an entry (entry_hash + entry_key). +/// Returns the ordering of query relative to entry. +/// When entry_hash is empty, computes full hash from entry_key. +fn compare_hash_key( + entry_hash: &[u8], + entry_key: &[u8], + full_hash: u64, + query_key: &K, +) -> Ordering { + if entry_hash.is_empty() { + // No hash stored - compute full hash from entry key + let entry_full_hash = crate::key::hash_key(&entry_key); + match full_hash.cmp(&entry_full_hash) { + Ordering::Equal => query_key.cmp(entry_key), + ord => ord, + } + } else { + // Full 8-byte hash stored - compare hashes first + let full_hash_bytes = full_hash.to_be_bytes(); + match full_hash_bytes[..].cmp(entry_hash) { + Ordering::Equal => query_key.cmp(entry_key), + ord => ord, + } + } +} + /// Reads a key entry from a key block. fn get_key_entry<'l>( offsets: &[u8], entries: &'l [u8], entry_count: usize, index: usize, + hash_len: u8, ) -> Result> { + let hash_len_usize = hash_len as usize; let mut offset = &offsets[index * 4..]; let ty = offset.read_u8()?; let start = offset.read_u24::()? as usize; @@ -567,29 +621,30 @@ fn get_key_entry<'l>( } else { (&offsets[(index + 1) * 4 + 1..]).read_u24::()? as usize }; - let hash = (&entries[start..start + 8]).read_u64::()?; + // Return the raw hash bytes slice (0-8 bytes depending on hash_len) + let hash = &entries[start..start + hash_len_usize]; Ok(match ty { KEY_BLOCK_ENTRY_TYPE_SMALL => GetKeyEntryResult { hash, - key: &entries[start + 8..end - 8], + key: &entries[start + hash_len_usize..end - 8], ty, val: &entries[end - 8..end], }, KEY_BLOCK_ENTRY_TYPE_MEDIUM => GetKeyEntryResult { hash, - key: &entries[start + 8..end - 2], + key: &entries[start + hash_len_usize..end - 2], ty, val: &entries[end - 2..end], }, KEY_BLOCK_ENTRY_TYPE_BLOB => GetKeyEntryResult { hash, - key: &entries[start + 8..end - 4], + key: &entries[start + hash_len_usize..end - 4], ty, val: &entries[end - 4..end], }, KEY_BLOCK_ENTRY_TYPE_DELETED => GetKeyEntryResult { hash, - key: &entries[start + 8..end], + key: &entries[start + hash_len_usize..end], ty, val: &[], }, diff --git a/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs b/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs index c105c8484c325..29ac7fa4e7dfd 100644 --- a/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs +++ b/turbopack/crates/turbo-persistence/src/static_sorted_file_builder.rs @@ -14,8 +14,9 @@ use crate::{ compression::compress_into_buffer, meta_file::{AmqfBincodeWrapper, MetaEntryFlags}, static_sorted_file::{ - BLOCK_TYPE_INDEX, BLOCK_TYPE_KEY, KEY_BLOCK_ENTRY_TYPE_BLOB, KEY_BLOCK_ENTRY_TYPE_DELETED, - KEY_BLOCK_ENTRY_TYPE_MEDIUM, KEY_BLOCK_ENTRY_TYPE_SMALL, + BLOCK_TYPE_INDEX, BLOCK_TYPE_KEY_NO_HASH, BLOCK_TYPE_KEY_WITH_HASH, + KEY_BLOCK_ENTRY_TYPE_BLOB, KEY_BLOCK_ENTRY_TYPE_DELETED, KEY_BLOCK_ENTRY_TYPE_MEDIUM, + KEY_BLOCK_ENTRY_TYPE_SMALL, }, }; @@ -45,6 +46,11 @@ const COMPRESSION_DICTIONARY_SAMPLE_PER_ENTRY: usize = 100; /// The minimum bytes that are used per key entry for a sample. const MIN_COMPRESSION_DICTIONARY_SAMPLE_PER_ENTRY: usize = 16; +/// Determines whether to store the hash per entry based on max key length. +fn use_hash(max_key_len: usize) -> bool { + max_key_len > 32 +} + /// Trait for entries from that SST files can be created pub trait Entry { /// Returns the hash of the key @@ -431,9 +437,11 @@ fn write_key_blocks_and_compute_amqf( } let mut current_block_start = 0; let mut current_block_size = 0; + let mut current_block_max_key_len = 0; let mut last_hash = 0; for (i, entry) in entries.iter().enumerate() { let key_hash = entry.key_hash(); + let key_len = entry.key_len(); // Add to AMQF filter @@ -443,13 +451,15 @@ fn write_key_blocks_and_compute_amqf( // Accumulate until the block is full if current_block_size > 0 - && (current_block_size + entry.key_len() + KEY_BLOCK_ENTRY_META_OVERHEAD + && (current_block_size + key_len + KEY_BLOCK_ENTRY_META_OVERHEAD > MAX_KEY_BLOCK_SIZE || i - current_block_start >= MAX_KEY_BLOCK_ENTRIES) && // avoid breaking the block in the middle of a hash conflict last_hash != key_hash { - let mut block = KeyBlockBuilder::new(buffer, (i - current_block_start) as u32); + let entry_count = i - current_block_start; + let has_hash = use_hash(current_block_max_key_len); + let mut block = KeyBlockBuilder::new(buffer, entry_count as u32, has_hash); for j in current_block_start..i { let entry = &entries[j]; let value_location = &value_locations[j]; @@ -463,15 +473,19 @@ fn write_key_blocks_and_compute_amqf( writer.write_key_block(buffer, key_compression_dictionary)?; buffer.clear(); current_block_size = 0; + current_block_max_key_len = 0; current_block_start = i; } current_block_size += entry.key_len() + KEY_BLOCK_ENTRY_META_OVERHEAD; + current_block_max_key_len = current_block_max_key_len.max(key_len); last_hash = key_hash; } // Finish the last block if current_block_size > 0 { - let mut block = KeyBlockBuilder::new(buffer, (entries.len() - current_block_start) as u32); + let entry_count = entries.len() - current_block_start; + let has_hash = use_hash(current_block_max_key_len); + let mut block = KeyBlockBuilder::new(buffer, entry_count as u32, has_hash); for j in current_block_start..entries.len() { let entry = &entries[j]; let value_location = &value_locations[j]; @@ -510,20 +524,26 @@ fn write_key_blocks_and_compute_amqf( pub struct KeyBlockBuilder<'l> { current_entry: usize, header_size: usize, + has_hash: bool, buffer: &'l mut Vec, } -/// The size of the key block header. +/// The size of the key block header (block type + entry count). const KEY_BLOCK_HEADER_SIZE: usize = 4; impl<'l> KeyBlockBuilder<'l> { /// Creates a new key block builder for the number of entries. - pub fn new(buffer: &'l mut Vec, entry_count: u32) -> Self { + pub fn new(buffer: &'l mut Vec, entry_count: u32, has_hash: bool) -> Self { debug_assert!(entry_count < (1 << 24)); const ESTIMATED_KEY_SIZE: usize = 16; buffer.reserve(entry_count as usize * ESTIMATED_KEY_SIZE); - buffer.write_u8(BLOCK_TYPE_KEY).unwrap(); + let block_type = if has_hash { + BLOCK_TYPE_KEY_WITH_HASH + } else { + BLOCK_TYPE_KEY_NO_HASH + }; + buffer.write_u8(block_type).unwrap(); buffer.write_u24::(entry_count).unwrap(); for _ in 0..entry_count { buffer.write_u32::(0).unwrap(); @@ -531,10 +551,19 @@ impl<'l> KeyBlockBuilder<'l> { Self { current_entry: 0, header_size: buffer.len(), + has_hash, buffer, } } + /// Writes the 8-byte hash if `has_hash` is true. + fn write_hash(&mut self, entry: &E) { + if self.has_hash { + let hash_bytes = entry.key_hash().to_be_bytes(); + self.buffer.extend_from_slice(&hash_bytes); + } + } + /// Writes a small-sized value to the buffer. pub fn put_small( &mut self, @@ -548,7 +577,7 @@ impl<'l> KeyBlockBuilder<'l> { let header = (pos as u32) | ((KEY_BLOCK_ENTRY_TYPE_SMALL as u32) << 24); BE::write_u32(&mut self.buffer[header_offset..header_offset + 4], header); - self.buffer.write_u64::(entry.key_hash()).unwrap(); + self.write_hash(entry); entry.write_key_to(self.buffer); self.buffer.write_u16::(value_block).unwrap(); self.buffer.write_u16::(value_size).unwrap(); @@ -564,7 +593,7 @@ impl<'l> KeyBlockBuilder<'l> { let header = (pos as u32) | ((KEY_BLOCK_ENTRY_TYPE_MEDIUM as u32) << 24); BE::write_u32(&mut self.buffer[header_offset..header_offset + 4], header); - self.buffer.write_u64::(entry.key_hash()).unwrap(); + self.write_hash(entry); entry.write_key_to(self.buffer); self.buffer.write_u16::(value_block).unwrap(); @@ -578,7 +607,7 @@ impl<'l> KeyBlockBuilder<'l> { let header = (pos as u32) | ((KEY_BLOCK_ENTRY_TYPE_DELETED as u32) << 24); BE::write_u32(&mut self.buffer[header_offset..header_offset + 4], header); - self.buffer.write_u64::(entry.key_hash()).unwrap(); + self.write_hash(entry); entry.write_key_to(self.buffer); self.current_entry += 1; @@ -591,7 +620,7 @@ impl<'l> KeyBlockBuilder<'l> { let header = (pos as u32) | ((KEY_BLOCK_ENTRY_TYPE_BLOB as u32) << 24); BE::write_u32(&mut self.buffer[header_offset..header_offset + 4], header); - self.buffer.write_u64::(entry.key_hash()).unwrap(); + self.write_hash(entry); entry.write_key_to(self.buffer); self.buffer.write_u32::(blob).unwrap(); From 02d8ff2cf3b3cdb0101981321ee7a31730d6a843 Mon Sep 17 00:00:00 2001 From: nextjs-bot Date: Tue, 27 Jan 2026 23:24:59 +0000 Subject: [PATCH 3/3] v16.2.0-canary.14 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-internal/package.json | 2 +- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-routing/package.json | 2 +- packages/next-rspack/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 20 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lerna.json b/lerna.json index 24259ca9430d5..c8e28cefa605b 100644 --- a/lerna.json +++ b/lerna.json @@ -15,5 +15,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "16.2.0-canary.13" + "version": "16.2.0-canary.14" } \ No newline at end of file diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 1d99b321e8f40..c7eebf52989a9 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 5555374e1cd93..eeb461b40465c 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "ESLint configuration used by Next.js.", "license": "MIT", "repository": { @@ -12,7 +12,7 @@ "dist" ], "dependencies": { - "@next/eslint-plugin-next": "16.2.0-canary.13", + "@next/eslint-plugin-next": "16.2.0-canary.14", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index bc57bd0870782..c58b4d5ead9a4 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,7 +1,7 @@ { "name": "@next/eslint-plugin-internal", "private": true, - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "ESLint plugin for working on Next.js.", "exports": { ".": "./src/eslint-plugin-internal.js" diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 0057d58b21f8b..92f15a34bd526 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/font/package.json b/packages/font/package.json index 5f3fbfeab44cb..68f5dedbaf2c7 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,7 +1,7 @@ { "name": "@next/font", "private": true, - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 3607e6638150c..263bba29282c1 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index a0fb0110f88bd..ae2b910e206bb 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index d983e78a37ec3..39e09229a4ecd 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 9aa5531cc2c55..63884ffbd3aab 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index a5f129f7f17c8..617467743b9f4 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index 9b9b4f54eee85..5290b6dd1b065 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 80db40653b48d..2c5cd52fcd293 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-routing/package.json b/packages/next-routing/package.json index 2307040435835..7fe9d25aaf9a8 100644 --- a/packages/next-routing/package.json +++ b/packages/next-routing/package.json @@ -1,6 +1,6 @@ { "name": "@next/routing", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "keywords": [ "react", "next", diff --git a/packages/next-rspack/package.json b/packages/next-rspack/package.json index 254254644601d..097aa54b90210 100644 --- a/packages/next-rspack/package.json +++ b/packages/next-rspack/package.json @@ -1,6 +1,6 @@ { "name": "next-rspack", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "repository": { "url": "vercel/next.js", "directory": "packages/next-rspack" diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index ce31ea5d59fd9..4691ce391d705 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "private": true, "files": [ "native/" diff --git a/packages/next/package.json b/packages/next/package.json index b400d6fbe85f3..860fac9c5fe30 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -97,7 +97,7 @@ ] }, "dependencies": { - "@next/env": "16.2.0-canary.13", + "@next/env": "16.2.0-canary.14", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.8.3", "caniuse-lite": "^1.0.30001579", @@ -162,11 +162,11 @@ "@modelcontextprotocol/sdk": "1.18.1", "@mswjs/interceptors": "0.23.0", "@napi-rs/triples": "1.2.0", - "@next/font": "16.2.0-canary.13", - "@next/polyfill-module": "16.2.0-canary.13", - "@next/polyfill-nomodule": "16.2.0-canary.13", - "@next/react-refresh-utils": "16.2.0-canary.13", - "@next/swc": "16.2.0-canary.13", + "@next/font": "16.2.0-canary.14", + "@next/polyfill-module": "16.2.0-canary.14", + "@next/polyfill-nomodule": "16.2.0-canary.14", + "@next/react-refresh-utils": "16.2.0-canary.14", + "@next/swc": "16.2.0-canary.14", "@opentelemetry/api": "1.6.0", "@playwright/test": "1.51.1", "@rspack/core": "1.6.7", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 6cd91400d551d..51657173986a5 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json index 26ba3549a0531..a1fc3c8be56fa 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "16.2.0-canary.13", + "version": "16.2.0-canary.14", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -26,7 +26,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "16.2.0-canary.13", + "next": "16.2.0-canary.14", "outdent": "0.8.0", "prettier": "2.5.1", "typescript": "5.9.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e4b1c32c5830..e670db8c0f1f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1008,7 +1008,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../eslint-plugin-next eslint: specifier: '>=9.0.0' @@ -1085,7 +1085,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../next-env '@swc/helpers': specifier: 0.5.15 @@ -1213,19 +1213,19 @@ importers: specifier: 1.2.0 version: 1.2.0 '@next/font': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../font '@next/polyfill-module': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../next-polyfill-nomodule '@next/react-refresh-utils': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../react-refresh-utils '@next/swc': - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1943,7 +1943,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 16.2.0-canary.13 + specifier: 16.2.0-canary.14 version: link:../next outdent: specifier: 0.8.0