Turbopack: add edge support for pages apis (#54449)
### What? * add support for middleware manifest and edge adapter for pages API routes * improve the error reporting a tiny bit ### Why? ### How? Closes WEB-1428
This commit is contained in:
parent
dbac7552eb
commit
4d6febf426
7 changed files with 253 additions and 731 deletions
|
@ -9,7 +9,11 @@ use next_core::{
|
|||
get_client_runtime_entries, ClientContextType, RuntimeEntries,
|
||||
},
|
||||
next_dynamic::NextDynamicTransition,
|
||||
next_manifests::{BuildManifest, PagesManifest},
|
||||
next_edge::route_regex::get_named_middleware_regex,
|
||||
next_manifests::{
|
||||
BuildManifest, EdgeFunctionDefinition, MiddlewareMatcher, MiddlewaresManifestV2,
|
||||
PagesManifest,
|
||||
},
|
||||
next_pages::create_page_ssr_entry_module,
|
||||
next_server::{
|
||||
get_server_module_options_context, get_server_resolve_options_context,
|
||||
|
@ -22,9 +26,13 @@ use next_core::{
|
|||
PageLoaderAsset,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use turbo_tasks::{trace::TraceRawVcs, Completion, TaskInput, TryJoinIterExt, Value, Vc};
|
||||
use turbo_tasks::{
|
||||
trace::TraceRawVcs, Completion, TaskInput, TryFlatJoinIterExt, TryJoinIterExt, Value, Vc,
|
||||
};
|
||||
use turbopack_binding::{
|
||||
turbo::tasks_fs::{File, FileSystem, FileSystemPath, FileSystemPathOption, VirtualFileSystem},
|
||||
turbo::tasks_fs::{
|
||||
File, FileContent, FileSystem, FileSystemPath, FileSystemPathOption, VirtualFileSystem,
|
||||
},
|
||||
turbopack::{
|
||||
build::BuildChunkingContext,
|
||||
core::{
|
||||
|
@ -601,11 +609,18 @@ impl PageEndpoint {
|
|||
Vc::upcast(edge_module_context),
|
||||
self.source(),
|
||||
this.original_name,
|
||||
config.runtime,
|
||||
);
|
||||
|
||||
let mut evaluatable_assets = edge_runtime_entries.await?.clone_value();
|
||||
let Some(evaluatable) = Vc::try_resolve_sidecast(ssr_module).await? else {
|
||||
bail!("Entry module must be evaluatable");
|
||||
};
|
||||
evaluatable_assets.push(evaluatable);
|
||||
|
||||
let edge_files = edge_chunking_context.evaluated_chunk_group(
|
||||
ssr_module.as_root_chunk(Vc::upcast(edge_chunking_context)),
|
||||
edge_runtime_entries,
|
||||
Vc::cell(evaluatable_assets),
|
||||
);
|
||||
|
||||
Ok(SsrChunk::Edge { files: edge_files }.cell())
|
||||
|
@ -617,6 +632,7 @@ impl PageEndpoint {
|
|||
Vc::upcast(module_context),
|
||||
self.source(),
|
||||
this.original_name,
|
||||
config.runtime,
|
||||
);
|
||||
|
||||
let asset_path = get_asset_path_from_pathname(&this.pathname.await?, ".js");
|
||||
|
@ -801,7 +817,64 @@ impl PageEndpoint {
|
|||
}
|
||||
}
|
||||
SsrChunk::Edge { files } => {
|
||||
server_assets.extend(files.await?.iter().copied());
|
||||
let node_root = this.pages_project.project().node_root();
|
||||
let files_value = files.await?;
|
||||
if let Some(&file) = files_value.first() {
|
||||
let pages_manifest = self.pages_manifest(file);
|
||||
server_assets.push(pages_manifest);
|
||||
}
|
||||
server_assets.extend(files_value.iter().copied());
|
||||
|
||||
let node_root_value = node_root.await?;
|
||||
let files_paths_from_root: Vec<String> = files_value
|
||||
.iter()
|
||||
.map(move |&file| {
|
||||
let node_root_value = node_root_value.clone();
|
||||
async move {
|
||||
Ok(node_root_value
|
||||
.get_path_to(&*file.ident().path().await?)
|
||||
.map(|path| path.to_string()))
|
||||
}
|
||||
})
|
||||
.try_flat_join()
|
||||
.await?;
|
||||
|
||||
let pathname = this.pathname.await?;
|
||||
let named_regex = get_named_middleware_regex(&pathname);
|
||||
let matchers = MiddlewareMatcher {
|
||||
regexp: named_regex,
|
||||
original_source: pathname.to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
let original_name = this.original_name.await?;
|
||||
let edge_function_definition = EdgeFunctionDefinition {
|
||||
files: files_paths_from_root,
|
||||
name: original_name.to_string(),
|
||||
page: original_name.to_string(),
|
||||
regions: None,
|
||||
matchers: vec![matchers],
|
||||
..Default::default()
|
||||
};
|
||||
let middleware_manifest_v2 = MiddlewaresManifestV2 {
|
||||
sorted_middleware: vec![original_name.to_string()],
|
||||
middleware: Default::default(),
|
||||
functions: [(original_name.to_string(), edge_function_definition)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
};
|
||||
let middleware_manifest_v2 = Vc::upcast(VirtualOutputAsset::new(
|
||||
node_root.join(format!(
|
||||
"server/pages{original_name}/middleware-manifest.json"
|
||||
)),
|
||||
AssetContent::file(
|
||||
FileContent::Content(File::from(serde_json::to_string_pretty(
|
||||
&middleware_manifest_v2,
|
||||
)?))
|
||||
.cell(),
|
||||
),
|
||||
));
|
||||
server_assets.push(middleware_manifest_v2);
|
||||
|
||||
PageEndpointOutput::Edge {
|
||||
files,
|
||||
server_assets: Vc::cell(server_assets),
|
||||
|
|
|
@ -17,7 +17,9 @@ use next_core::{
|
|||
pages_structure::{
|
||||
find_pages_structure, PagesDirectoryStructure, PagesStructure, PagesStructureItem,
|
||||
},
|
||||
pathname_for_path, PathType,
|
||||
pathname_for_path,
|
||||
util::NextRuntime,
|
||||
PathType,
|
||||
};
|
||||
use turbo_tasks::Vc;
|
||||
use turbopack_binding::{
|
||||
|
@ -343,6 +345,7 @@ async fn get_page_entry_for_file(
|
|||
ssr_module_context,
|
||||
source,
|
||||
Vc::cell(original_name),
|
||||
NextRuntime::NodeJs,
|
||||
);
|
||||
|
||||
let client_module = create_page_loader_entry_module(client_module_context, source, pathname);
|
||||
|
|
|
@ -2,6 +2,7 @@ use std::io::Write;
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
use indexmap::indexmap;
|
||||
use indoc::writedoc;
|
||||
use turbo_tasks::Vc;
|
||||
use turbo_tasks_fs::{rope::Rope, FileSystemPath};
|
||||
use turbopack_binding::{
|
||||
|
@ -13,6 +14,7 @@ use turbopack_binding::{
|
|||
core::{
|
||||
asset::AssetContent,
|
||||
context::AssetContext,
|
||||
module::Module,
|
||||
reference_type::{EntryReferenceSubType, ReferenceType},
|
||||
source::Source,
|
||||
virtual_source::VirtualSource,
|
||||
|
@ -21,7 +23,7 @@ use turbopack_binding::{
|
|||
},
|
||||
};
|
||||
|
||||
use crate::util::{load_next_js_template, virtual_next_js_template_path};
|
||||
use crate::util::{load_next_js_template, virtual_next_js_template_path, NextRuntime};
|
||||
|
||||
#[turbo_tasks::function]
|
||||
pub async fn create_page_ssr_entry_module(
|
||||
|
@ -31,6 +33,7 @@ pub async fn create_page_ssr_entry_module(
|
|||
ssr_module_context: Vc<Box<dyn AssetContext>>,
|
||||
source: Vc<Box<dyn Source>>,
|
||||
next_original_name: Vc<String>,
|
||||
runtime: NextRuntime,
|
||||
) -> Result<Vc<Box<dyn EcmascriptChunkPlaceable>>> {
|
||||
let definition_page = next_original_name.await?;
|
||||
let definition_pathname = pathname.await?;
|
||||
|
@ -39,15 +42,19 @@ pub async fn create_page_ssr_entry_module(
|
|||
|
||||
let reference_type = reference_type.into_value();
|
||||
|
||||
let template_file = match reference_type {
|
||||
ReferenceType::Entry(EntryReferenceSubType::Page) => {
|
||||
let template_file = match (&reference_type, runtime) {
|
||||
(ReferenceType::Entry(EntryReferenceSubType::Page), _) => {
|
||||
// Load the Page entry file.
|
||||
"build/webpack/loaders/next-route-loader/templates/pages.js"
|
||||
}
|
||||
ReferenceType::Entry(EntryReferenceSubType::PagesApi) => {
|
||||
(ReferenceType::Entry(EntryReferenceSubType::PagesApi), NextRuntime::NodeJs) => {
|
||||
// Load the Pages API entry file.
|
||||
"build/webpack/loaders/next-route-loader/templates/pages-api.js"
|
||||
}
|
||||
(ReferenceType::Entry(EntryReferenceSubType::PagesApi), NextRuntime::Edge) => {
|
||||
// Load the Pages API entry file.
|
||||
"build/webpack/loaders/next-route-loader/templates/pages-edge-api.js"
|
||||
}
|
||||
_ => bail!("Invalid path type"),
|
||||
};
|
||||
|
||||
|
@ -106,13 +113,22 @@ pub async fn create_page_ssr_entry_module(
|
|||
|
||||
let source = VirtualSource::new(template_path, AssetContent::file(file.into()));
|
||||
|
||||
let ssr_module = ssr_module_context.process(
|
||||
let mut ssr_module = ssr_module_context.process(
|
||||
Vc::upcast(source),
|
||||
Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
|
||||
"VAR_USERLAND".to_string() => ssr_module,
|
||||
}))),
|
||||
);
|
||||
|
||||
if matches!(runtime, NextRuntime::Edge) {
|
||||
ssr_module = wrap_edge_entry(
|
||||
ssr_module_context,
|
||||
project_root,
|
||||
ssr_module,
|
||||
definition_page.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
let Some(ssr_module) =
|
||||
Vc::try_resolve_downcast::<Box<dyn EcmascriptChunkPlaceable>>(ssr_module).await?
|
||||
else {
|
||||
|
@ -121,3 +137,37 @@ pub async fn create_page_ssr_entry_module(
|
|||
|
||||
Ok(ssr_module)
|
||||
}
|
||||
|
||||
#[turbo_tasks::function]
|
||||
pub async fn wrap_edge_entry(
|
||||
context: Vc<Box<dyn AssetContext>>,
|
||||
project_root: Vc<FileSystemPath>,
|
||||
entry: Vc<Box<dyn Module>>,
|
||||
original_name: String,
|
||||
) -> Result<Vc<Box<dyn Module>>> {
|
||||
let mut source = RopeBuilder::default();
|
||||
writedoc!(
|
||||
source,
|
||||
r#"
|
||||
import * as module from "MODULE"
|
||||
|
||||
self._ENTRIES ||= {{}}
|
||||
self._ENTRIES[{}] = module
|
||||
"#,
|
||||
StringifyJs(&format_args!("middleware_{}", original_name))
|
||||
)?;
|
||||
let file = File::from(source.build());
|
||||
// TODO(alexkirsz) Figure out how to name this virtual asset.
|
||||
let virtual_source = VirtualSource::new(
|
||||
project_root.join("edge-wrapper.js".to_string()),
|
||||
AssetContent::file(file.into()),
|
||||
);
|
||||
let inner_assets = indexmap! {
|
||||
"MODULE".to_string() => entry
|
||||
};
|
||||
|
||||
Ok(context.process(
|
||||
Vc::upcast(virtual_source),
|
||||
Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
|
||||
))
|
||||
}
|
||||
|
|
|
@ -113,6 +113,7 @@ pub async fn foreign_code_context_condition(
|
|||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
TaskInput,
|
||||
)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum NextRuntime {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import '../../../../../server/web/globals'
|
||||
import type { AdapterOptions } from '../../../../../server/web/adapter'
|
||||
import { adapter } from '../../../../../server/web/adapter'
|
||||
import { IncrementalCache } from '../../../../..//server/lib/incremental-cache'
|
||||
|
||||
// Import the userland code.
|
||||
// @ts-expect-error - replaced by webpack/turbopack loader
|
||||
import handler from 'VAR_USERLAND'
|
||||
|
||||
const page = 'VAR_DEFINITION_PAGE'
|
||||
|
||||
if (typeof handler !== 'function') {
|
||||
throw new Error(
|
||||
`The Edge Function "pages${page}" must export a \`default\` function`
|
||||
)
|
||||
}
|
||||
|
||||
export default function (
|
||||
opts: Omit<AdapterOptions, 'IncrementalCache' | 'page' | 'handler'>
|
||||
) {
|
||||
return adapter({
|
||||
...opts,
|
||||
IncrementalCache,
|
||||
page: 'VAR_DEFINITION_PATHNAME',
|
||||
handler,
|
||||
})
|
||||
}
|
|
@ -216,6 +216,8 @@ async function startWatcher(opts: SetupOpts) {
|
|||
const appPathsManifests = new Map<string, PagesManifest>()
|
||||
const middlewareManifests = new Map<string, MiddlewareManifest>()
|
||||
|
||||
const issues = new Map<string, Set<string>>()
|
||||
|
||||
function mergeBuildManifests(manifests: Iterable<BuildManifest>) {
|
||||
const manifest: Partial<BuildManifest> & Pick<BuildManifest, 'pages'> = {
|
||||
pages: {
|
||||
|
@ -273,6 +275,7 @@ async function startWatcher(opts: SetupOpts) {
|
|||
}
|
||||
|
||||
async function processResult(
|
||||
key: string,
|
||||
result: TurbopackResult<WrittenEndpoint> | undefined
|
||||
): Promise<TurbopackResult<WrittenEndpoint> | undefined> {
|
||||
if (result) {
|
||||
|
@ -291,13 +294,32 @@ async function startWatcher(opts: SetupOpts) {
|
|||
])
|
||||
)
|
||||
|
||||
const oldSet = issues.get(key) ?? new Set()
|
||||
const newSet = new Set<string>()
|
||||
|
||||
for (const issue of result.issues) {
|
||||
// TODO better formatting
|
||||
if (issue.severity !== 'error' && issue.severity !== 'fatal') continue
|
||||
console.error(
|
||||
`⚠ ${issue.severity} - ${issue.filePath}\n${issue.title}\n${issue.description}\n\n`
|
||||
)
|
||||
const issueKey = `${issue.severity} - ${issue.filePath} - ${issue.title}\n${issue.description}\n\n`
|
||||
if (!oldSet.has(issueKey)) {
|
||||
console.error(
|
||||
` ⚠ ${key} ${issue.severity} - ${
|
||||
issue.filePath
|
||||
}\n ${issue.title.replace(
|
||||
/\n/g,
|
||||
'\n '
|
||||
)}\n ${issue.description.replace(/\n/g, '\n ')}\n\n`
|
||||
)
|
||||
}
|
||||
newSet.add(issueKey)
|
||||
}
|
||||
for (const issue of oldSet) {
|
||||
if (!newSet.has(issue)) {
|
||||
console.error(`✅ ${key} fixed ${issue}`)
|
||||
}
|
||||
}
|
||||
|
||||
issues.set(key, newSet)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -537,14 +559,23 @@ async function startWatcher(opts: SetupOpts) {
|
|||
}
|
||||
|
||||
if (page === '/_error') {
|
||||
await processResult(await globalEntries.app?.writeToDisk())
|
||||
await processResult(
|
||||
'_app',
|
||||
await globalEntries.app?.writeToDisk()
|
||||
)
|
||||
await loadBuildManifest('_app')
|
||||
await loadPagesManifest('_app')
|
||||
|
||||
await processResult(await globalEntries.document?.writeToDisk())
|
||||
await processResult(
|
||||
'_document',
|
||||
await globalEntries.document?.writeToDisk()
|
||||
)
|
||||
await loadPagesManifest('_document')
|
||||
|
||||
await processResult(await globalEntries.error?.writeToDisk())
|
||||
await processResult(
|
||||
page,
|
||||
await globalEntries.error?.writeToDisk()
|
||||
)
|
||||
await loadBuildManifest('_error')
|
||||
await loadPagesManifest('_error')
|
||||
|
||||
|
@ -567,7 +598,44 @@ async function startWatcher(opts: SetupOpts) {
|
|||
}
|
||||
|
||||
switch (route.type) {
|
||||
case 'page':
|
||||
case 'page': {
|
||||
if (ensureOpts.isApp) {
|
||||
throw new Error(
|
||||
`mis-matched route type: isApp && page for ${page}`
|
||||
)
|
||||
}
|
||||
|
||||
await processResult(
|
||||
'_app',
|
||||
await globalEntries.app?.writeToDisk()
|
||||
)
|
||||
await loadBuildManifest('_app')
|
||||
await loadPagesManifest('_app')
|
||||
|
||||
await processResult(
|
||||
'_document',
|
||||
await globalEntries.document?.writeToDisk()
|
||||
)
|
||||
await loadPagesManifest('_document')
|
||||
|
||||
const writtenEndpoint = await processResult(
|
||||
page,
|
||||
await route.htmlEndpoint.writeToDisk()
|
||||
)
|
||||
|
||||
const type = writtenEndpoint?.type
|
||||
|
||||
await loadBuildManifest(page)
|
||||
await loadPagesManifest(page)
|
||||
if (type === 'edge') await loadMiddlewareManifest(page, false)
|
||||
|
||||
await writeBuildManifest()
|
||||
await writePagesManifest()
|
||||
if (type === 'edge') await writeMiddlewareManifest()
|
||||
await writeOtherManifests()
|
||||
|
||||
break
|
||||
}
|
||||
case 'page-api': {
|
||||
if (ensureOpts.isApp) {
|
||||
throw new Error(
|
||||
|
@ -575,48 +643,27 @@ async function startWatcher(opts: SetupOpts) {
|
|||
)
|
||||
}
|
||||
|
||||
await processResult(await globalEntries.app?.writeToDisk())
|
||||
await loadBuildManifest('_app')
|
||||
await loadPagesManifest('_app')
|
||||
const writtenEndpoint = await processResult(
|
||||
page,
|
||||
await route.endpoint.writeToDisk()
|
||||
)
|
||||
|
||||
await processResult(await globalEntries.document?.writeToDisk())
|
||||
await loadPagesManifest('_document')
|
||||
const type = writtenEndpoint?.type
|
||||
|
||||
const writtenEndpoint =
|
||||
route.type === 'page-api'
|
||||
? await processResult(await route.endpoint.writeToDisk())
|
||||
: await processResult(
|
||||
await route.htmlEndpoint.writeToDisk()
|
||||
)
|
||||
|
||||
if (route.type === 'page') {
|
||||
await loadBuildManifest(page)
|
||||
}
|
||||
await loadPagesManifest(page)
|
||||
if (type === 'edge') await loadMiddlewareManifest(page, false)
|
||||
|
||||
switch (writtenEndpoint!.type) {
|
||||
case 'nodejs': {
|
||||
break
|
||||
}
|
||||
case 'edge': {
|
||||
throw new Error('edge is not implemented yet')
|
||||
}
|
||||
default: {
|
||||
throw new Error(
|
||||
`unknown endpoint type ${(writtenEndpoint as any).type}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await writeBuildManifest()
|
||||
await writePagesManifest()
|
||||
await writeMiddlewareManifest()
|
||||
if (type === 'edge') await writeMiddlewareManifest()
|
||||
await writeOtherManifests()
|
||||
|
||||
break
|
||||
}
|
||||
case 'app-page': {
|
||||
await processResult(await route.htmlEndpoint.writeToDisk())
|
||||
await processResult(
|
||||
page,
|
||||
await route.htmlEndpoint.writeToDisk()
|
||||
)
|
||||
|
||||
await loadAppBuildManifest(page)
|
||||
await loadBuildManifest(page, true)
|
||||
|
@ -632,7 +679,7 @@ async function startWatcher(opts: SetupOpts) {
|
|||
}
|
||||
case 'app-route': {
|
||||
const type = (
|
||||
await processResult(await route.endpoint.writeToDisk())
|
||||
await processResult(page, await route.endpoint.writeToDisk())
|
||||
)?.type
|
||||
|
||||
await loadAppPathManifest(page, true)
|
||||
|
|
|
@ -30,686 +30,7 @@ exports[`next.rs api should allow to write pages Node.js page to disk: issues 1`
|
|||
|
||||
exports[`next.rs api should allow to write pages edge api to disk: diagnostics 1`] = `Array []`;
|
||||
|
||||
exports[`next.rs api should allow to write pages edge api to disk: issues 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"buffer\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"buffer\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 945,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 928,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"buffer\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"buffer\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 945,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 928,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"crypto\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"crypto\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 995,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 978,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"crypto\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"crypto\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 995,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 978,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 1114,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 1097,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 1114,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 1097,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"util\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"util\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 1162,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 1147,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"util\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"util\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 1162,
|
||||
"line": 10,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/jsonwebtoken/index.js",
|
||||
"start": Object {
|
||||
"column": 1147,
|
||||
"line": 10,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"buffer\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"buffer\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 504,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 487,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"buffer\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"buffer\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 504,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 487,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"events\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"events\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 554,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 537,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"events\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"events\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 554,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 537,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"path\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"path\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 669,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 654,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"path\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"path\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 669,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 654,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 719,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 702,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 719,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 702,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"string_decoder\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"string_decoder\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 777,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 752,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"string_decoder\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"string_decoder\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 777,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 752,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"util\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"util\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 825,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 810,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"util\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"util\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/compiled/raw-body/index.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 825,
|
||||
"line": 50,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/compiled/raw-body/index.js",
|
||||
"start": Object {
|
||||
"column": 810,
|
||||
"line": 50,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"querystring\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"querystring\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/api-utils/node.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 42,
|
||||
"line": 154,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"start": Object {
|
||||
"column": 20,
|
||||
"line": 154,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"querystring\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"querystring\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/api-utils/node.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 42,
|
||||
"line": 154,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"start": Object {
|
||||
"column": 20,
|
||||
"line": 154,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/api-utils/node.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 34,
|
||||
"line": 30,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"start": Object {
|
||||
"column": 17,
|
||||
"line": 30,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"stream\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"stream\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/api-utils/node.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 34,
|
||||
"line": 30,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/api-utils/node.js",
|
||||
"start": Object {
|
||||
"column": 17,
|
||||
"line": 30,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"crypto\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"crypto\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/crypto-utils.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/crypto-utils.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 73,
|
||||
"line": 22,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/crypto-utils.js",
|
||||
"start": Object {
|
||||
"column": 56,
|
||||
"line": 22,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
Object {
|
||||
"category": "resolve",
|
||||
"description": "unable to resolve module \\"crypto\\"",
|
||||
"detail": "It was not possible to find the requested file.
|
||||
Parsed request as written in source code: module \\"crypto\\"
|
||||
Path where resolving has started: [project]/.../node_modules/next/dist/server/crypto-utils.js
|
||||
Type of request: commonjs request
|
||||
Import map: No import map entry
|
||||
",
|
||||
"documentationLink": "",
|
||||
"filePath": "[project]/.../node_modules/next/dist/server/crypto-utils.js",
|
||||
"severity": "error",
|
||||
"source": Object {
|
||||
"end": Object {
|
||||
"column": 73,
|
||||
"line": 22,
|
||||
},
|
||||
"source": "[project]/.../node_modules/next/dist/server/crypto-utils.js",
|
||||
"start": Object {
|
||||
"column": 56,
|
||||
"line": 22,
|
||||
},
|
||||
},
|
||||
"subIssues": Array [],
|
||||
"title": "Error resolving commonjs request",
|
||||
},
|
||||
]
|
||||
`;
|
||||
exports[`next.rs api should allow to write pages edge api to disk: issues 1`] = `Array []`;
|
||||
|
||||
exports[`next.rs api should allow to write pages edge page to disk: data diagnostics 1`] = `Array []`;
|
||||
|
||||
|
|
Loading…
Reference in a new issue