@remix-run/assets 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +319 -2
  3. package/dist/assets.d.ts +3 -0
  4. package/dist/assets.d.ts.map +1 -0
  5. package/dist/assets.js +1 -0
  6. package/dist/lib/access.d.ts +10 -0
  7. package/dist/lib/access.d.ts.map +1 -0
  8. package/dist/lib/access.js +14 -0
  9. package/dist/lib/asset-server.d.ts +137 -0
  10. package/dist/lib/asset-server.d.ts.map +1 -0
  11. package/dist/lib/asset-server.js +242 -0
  12. package/dist/lib/compilation-error.d.ts +33 -0
  13. package/dist/lib/compilation-error.d.ts.map +1 -0
  14. package/dist/lib/compilation-error.js +32 -0
  15. package/dist/lib/file-matcher.d.ts +6 -0
  16. package/dist/lib/file-matcher.d.ts.map +1 -0
  17. package/dist/lib/file-matcher.js +43 -0
  18. package/dist/lib/fingerprint.d.ts +12 -0
  19. package/dist/lib/fingerprint.d.ts.map +1 -0
  20. package/dist/lib/fingerprint.js +49 -0
  21. package/dist/lib/paths.d.ts +8 -0
  22. package/dist/lib/paths.d.ts.map +1 -0
  23. package/dist/lib/paths.js +50 -0
  24. package/dist/lib/routes.d.ts +13 -0
  25. package/dist/lib/routes.d.ts.map +1 -0
  26. package/dist/lib/routes.js +94 -0
  27. package/dist/lib/scripts/cjs-check.d.ts +3 -0
  28. package/dist/lib/scripts/cjs-check.d.ts.map +1 -0
  29. package/dist/lib/scripts/cjs-check.js +398 -0
  30. package/dist/lib/scripts/compiler.d.ts +62 -0
  31. package/dist/lib/scripts/compiler.d.ts.map +1 -0
  32. package/dist/lib/scripts/compiler.js +435 -0
  33. package/dist/lib/scripts/emit.d.ts +25 -0
  34. package/dist/lib/scripts/emit.d.ts.map +1 -0
  35. package/dist/lib/scripts/emit.js +63 -0
  36. package/dist/lib/scripts/resolve.d.ts +60 -0
  37. package/dist/lib/scripts/resolve.d.ts.map +1 -0
  38. package/dist/lib/scripts/resolve.js +230 -0
  39. package/dist/lib/scripts/store.d.ts +40 -0
  40. package/dist/lib/scripts/store.d.ts.map +1 -0
  41. package/dist/lib/scripts/store.js +228 -0
  42. package/dist/lib/scripts/transform.d.ts +62 -0
  43. package/dist/lib/scripts/transform.d.ts.map +1 -0
  44. package/dist/lib/scripts/transform.js +362 -0
  45. package/dist/lib/source-maps.d.ts +4 -0
  46. package/dist/lib/source-maps.d.ts.map +1 -0
  47. package/dist/lib/source-maps.js +56 -0
  48. package/dist/lib/watch.d.ts +22 -0
  49. package/dist/lib/watch.d.ts.map +1 -0
  50. package/dist/lib/watch.js +96 -0
  51. package/package.json +50 -12
  52. package/src/assets.ts +2 -0
  53. package/src/lib/access.ts +24 -0
  54. package/src/lib/asset-server.ts +415 -0
  55. package/src/lib/compilation-error.ts +61 -0
  56. package/src/lib/file-matcher.ts +62 -0
  57. package/src/lib/fingerprint.ts +65 -0
  58. package/src/lib/paths.ts +66 -0
  59. package/src/lib/routes.ts +164 -0
  60. package/src/lib/scripts/cjs-check.ts +476 -0
  61. package/src/lib/scripts/compiler.ts +622 -0
  62. package/src/lib/scripts/emit.ts +122 -0
  63. package/src/lib/scripts/resolve.ts +422 -0
  64. package/src/lib/scripts/store.ts +327 -0
  65. package/src/lib/scripts/transform.ts +594 -0
  66. package/src/lib/source-maps.ts +68 -0
  67. package/src/lib/watch.ts +136 -0
@@ -0,0 +1,122 @@
1
+ import MagicString from 'magic-string'
2
+
3
+ import {
4
+ createAssetServerCompilationError,
5
+ isAssetServerCompilationError,
6
+ } from '../compilation-error.ts'
7
+ import { hashContent } from '../fingerprint.ts'
8
+ import type { ResolvedModule } from './resolve.ts'
9
+ import { composeSourceMaps } from '../source-maps.ts'
10
+ import type { AssetServerCompilationError } from '../compilation-error.ts'
11
+
12
+ export type EmittedAsset = {
13
+ content: string
14
+ etag: string
15
+ }
16
+
17
+ export type EmittedModule = {
18
+ code: EmittedAsset
19
+ fingerprint: string | null
20
+ importUrls: string[]
21
+ sourceMap: EmittedAsset | null
22
+ }
23
+
24
+ type EmitResult =
25
+ | {
26
+ ok: true
27
+ value: EmittedModule
28
+ }
29
+ | {
30
+ ok: false
31
+ error: AssetServerCompilationError
32
+ }
33
+
34
+ export async function emitResolvedModule(
35
+ resolvedModule: ResolvedModule,
36
+ options: {
37
+ getServedUrl(identityPath: string): Promise<string>
38
+ sourceMaps?: 'external' | 'inline'
39
+ },
40
+ ): Promise<EmitResult> {
41
+ try {
42
+ let importUrls = await Promise.all(
43
+ resolvedModule.deps.map((depPath) => options.getServedUrl(depPath)),
44
+ )
45
+ let rewriteResult = await rewriteImports(resolvedModule, options)
46
+ let finalCode = rewriteResult.code
47
+
48
+ if (rewriteResult.sourceMap) {
49
+ if (options.sourceMaps === 'inline') {
50
+ let encoded = Buffer.from(rewriteResult.sourceMap).toString('base64')
51
+ finalCode += `\n//# sourceMappingURL=data:application/json;base64,${encoded}`
52
+ } else if (options.sourceMaps === 'external') {
53
+ finalCode += `\n//# sourceMappingURL=${await options.getServedUrl(resolvedModule.identityPath)}.map`
54
+ }
55
+ }
56
+
57
+ return {
58
+ ok: true,
59
+ value: {
60
+ code: await createEmittedAsset(finalCode),
61
+ fingerprint: resolvedModule.fingerprint,
62
+ importUrls,
63
+ sourceMap: rewriteResult.sourceMap
64
+ ? await createEmittedAsset(rewriteResult.sourceMap)
65
+ : null,
66
+ },
67
+ }
68
+ } catch (error) {
69
+ return {
70
+ ok: false,
71
+ error: toEmitError(error, resolvedModule.identityPath),
72
+ }
73
+ }
74
+ }
75
+
76
+ async function rewriteImports(
77
+ resolvedModule: ResolvedModule,
78
+ options: {
79
+ getServedUrl(identityPath: string): Promise<string>
80
+ },
81
+ ): Promise<{ code: string; sourceMap: string | null }> {
82
+ let rewrittenSource = new MagicString(resolvedModule.rawCode)
83
+
84
+ for (let imported of resolvedModule.imports) {
85
+ let url = await options.getServedUrl(imported.depPath)
86
+ rewrittenSource.overwrite(
87
+ imported.start,
88
+ imported.end,
89
+ imported.quote ? `${imported.quote}${url}${imported.quote}` : url,
90
+ )
91
+ }
92
+
93
+ let code = rewrittenSource.toString()
94
+ let sourceMap =
95
+ resolvedModule.sourceMap && resolvedModule.imports.length > 0
96
+ ? composeSourceMaps(
97
+ rewrittenSource.generateMap({ hires: true }).toString(),
98
+ resolvedModule.sourceMap,
99
+ )
100
+ : resolvedModule.sourceMap
101
+
102
+ return { code, sourceMap }
103
+ }
104
+
105
+ async function createEmittedAsset(content: string): Promise<EmittedAsset> {
106
+ return {
107
+ content,
108
+ etag: `W/"${await hashContent(content)}"`,
109
+ }
110
+ }
111
+
112
+ function toEmitError(error: unknown, identityPath: string): AssetServerCompilationError {
113
+ if (isAssetServerCompilationError(error)) return error
114
+
115
+ return createAssetServerCompilationError(
116
+ `Failed to emit module ${identityPath}. ${error instanceof Error ? error.message : String(error)}`,
117
+ {
118
+ cause: error,
119
+ code: 'MODULE_EMIT_FAILED',
120
+ },
121
+ )
122
+ }
@@ -0,0 +1,422 @@
1
+ import * as fs from 'node:fs'
2
+ import * as path from 'node:path'
3
+ import type { ResolverFactory } from 'oxc-resolver'
4
+
5
+ import {
6
+ createAssetServerCompilationError,
7
+ isAssetServerCompilationError,
8
+ } from '../compilation-error.ts'
9
+ import type { AssetServerCompilationError } from '../compilation-error.ts'
10
+ import { normalizeFilePath } from '../paths.ts'
11
+ import type { CompiledRoutes } from '../routes.ts'
12
+ import type { ModuleRecord } from './store.ts'
13
+ import type { ResolveModuleResult, TransformedModule } from './transform.ts'
14
+
15
+ export const resolverExtensionAlias = {
16
+ '.js': ['.js', '.ts', '.tsx', '.jsx'],
17
+ '.jsx': ['.jsx', '.tsx'],
18
+ '.mjs': ['.mjs', '.mts'],
19
+ } satisfies Record<string, string[]>
20
+
21
+ export const resolverExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs']
22
+ export const supportedScriptExtensions = ['.ts', '.tsx', '.js', '.jsx', '.mts', '.mjs']
23
+ const supportedScriptExtensionSet = new Set<string>(supportedScriptExtensions)
24
+
25
+ type ResolvedImport = {
26
+ depPath: string
27
+ end: number
28
+ quote?: '"' | "'" | '`'
29
+ start: number
30
+ }
31
+
32
+ type RelativeImportResolution = {
33
+ candidatePaths: readonly string[]
34
+ candidatePrefixes: readonly string[]
35
+ specifier: string
36
+ }
37
+
38
+ export type TrackedResolution = RelativeImportResolution & {
39
+ resolvedIdentityPath: string | null
40
+ }
41
+
42
+ export type ResolvedModule = {
43
+ deps: string[]
44
+ fingerprint: string | null
45
+ identityPath: string
46
+ imports: ResolvedImport[]
47
+ trackedFiles: string[]
48
+ trackedResolutions: TrackedResolution[]
49
+ rawCode: string
50
+ resolvedPath: string
51
+ sourceMap: string | null
52
+ stableUrlPathname: string
53
+ }
54
+
55
+ export type ResolutionFailureState = {
56
+ trackedFiles: readonly string[]
57
+ trackedResolutions: readonly TrackedResolution[]
58
+ }
59
+
60
+ type ResolveResult =
61
+ | {
62
+ ok: true
63
+ value: ResolvedModule
64
+ }
65
+ | {
66
+ ok: false
67
+ error: AssetServerCompilationError
68
+ tracking: ResolutionFailureState
69
+ }
70
+
71
+ export type ResolveArgs = {
72
+ isAllowed(absolutePath: string): boolean
73
+ isWatchIgnored(filePath: string): boolean
74
+ resolveModulePath(absolutePath: string): ResolveModuleResult | null
75
+ resolverFactory: ResolverFactory
76
+ routes: CompiledRoutes
77
+ }
78
+
79
+ type ResolvedSpec = {
80
+ absolutePath: string | null
81
+ packageJsonPath: string | null
82
+ specifier: string
83
+ }
84
+
85
+ export async function resolveModule(
86
+ record: ModuleRecord,
87
+ transformed: TransformedModule,
88
+ args: ResolveArgs,
89
+ ): Promise<ResolveResult> {
90
+ let trackedFiles = new Set(transformed.trackedFiles)
91
+ let trackedResolutions: TrackedResolution[] = []
92
+ let resolvedImports: Map<string, ResolvedSpec>
93
+
94
+ try {
95
+ resolvedImports =
96
+ transformed.unresolvedImports.length > 0
97
+ ? await batchResolveSpecifiers(
98
+ getUniqueSpecifiers(transformed.unresolvedImports),
99
+ transformed.resolvedPath,
100
+ args.resolverFactory,
101
+ )
102
+ : new Map<string, ResolvedSpec>()
103
+ } catch (error) {
104
+ return failResolve(error, trackedFiles, trackedResolutions, transformed.resolvedPath, {
105
+ isWatchIgnored: args.isWatchIgnored,
106
+ })
107
+ }
108
+
109
+ let importsWithPaths: ResolvedImport[] = []
110
+ let deps = new Set<string>()
111
+
112
+ for (let unresolved of transformed.unresolvedImports) {
113
+ let trackedResolution = getTrackedRelativeImportResolution(
114
+ transformed.importerDir,
115
+ unresolved.specifier,
116
+ args.isWatchIgnored,
117
+ )
118
+
119
+ let resolvedSpec = resolvedImports.get(unresolved.specifier)
120
+ if (!resolvedSpec?.absolutePath) {
121
+ return failResolve(
122
+ createAssetServerCompilationError(
123
+ `Failed to resolve import "${unresolved.specifier}" in ${transformed.resolvedPath}. ` +
124
+ `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`,
125
+ {
126
+ code: 'IMPORT_RESOLUTION_FAILED',
127
+ },
128
+ ),
129
+ trackedFiles,
130
+ trackedResolutions,
131
+ transformed.resolvedPath,
132
+ { isWatchIgnored: args.isWatchIgnored, trackedResolution },
133
+ )
134
+ }
135
+
136
+ let resolvedImport = args.resolveModulePath(resolvedSpec.absolutePath)
137
+ if (!resolvedImport) {
138
+ return failResolve(
139
+ createAssetServerCompilationError(
140
+ `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is not a supported script module. ` +
141
+ `Supported extensions are ${supportedScriptExtensions.join(', ')}.`,
142
+ {
143
+ code: 'IMPORT_NOT_SUPPORTED',
144
+ },
145
+ ),
146
+ trackedFiles,
147
+ trackedResolutions,
148
+ transformed.resolvedPath,
149
+ { isWatchIgnored: args.isWatchIgnored, trackedResolution },
150
+ )
151
+ }
152
+
153
+ if (!args.isAllowed(resolvedImport.identityPath)) {
154
+ return failResolve(
155
+ createAssetServerCompilationError(
156
+ `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is not allowed by the asset server allow/deny configuration. ` +
157
+ `Add a matching allow rule, remove a conflicting deny rule, or mark this import as external.`,
158
+ {
159
+ code: 'IMPORT_NOT_ALLOWED',
160
+ },
161
+ ),
162
+ trackedFiles,
163
+ trackedResolutions,
164
+ transformed.resolvedPath,
165
+ { isWatchIgnored: args.isWatchIgnored, trackedResolution },
166
+ )
167
+ }
168
+
169
+ let stableUrlPathname = args.routes.toUrlPathname(resolvedImport.identityPath)
170
+ if (!stableUrlPathname) {
171
+ return failResolve(
172
+ createAssetServerCompilationError(
173
+ `Resolved import "${unresolved.specifier}" in ${transformed.resolvedPath} is outside all configured fileMap entries. ` +
174
+ `Add a matching fileMap entry for this file path, or mark this import as external.`,
175
+ {
176
+ code: 'IMPORT_OUTSIDE_FILE_MAP',
177
+ },
178
+ ),
179
+ trackedFiles,
180
+ trackedResolutions,
181
+ transformed.resolvedPath,
182
+ { isWatchIgnored: args.isWatchIgnored, trackedResolution },
183
+ )
184
+ }
185
+
186
+ deps.add(resolvedImport.identityPath)
187
+
188
+ if (transformed.packageSpecifiers.includes(unresolved.specifier)) {
189
+ let packageJsonPath =
190
+ resolvedSpec.packageJsonPath ?? findNearestPackageJsonPath(resolvedImport.resolvedPath)
191
+ if (packageJsonPath && !args.isWatchIgnored(packageJsonPath)) {
192
+ trackedFiles.add(packageJsonPath)
193
+ }
194
+ }
195
+
196
+ if (trackedResolution) {
197
+ trackedResolutions.push({
198
+ ...trackedResolution,
199
+ resolvedIdentityPath: resolvedImport.identityPath,
200
+ })
201
+ }
202
+
203
+ importsWithPaths.push({
204
+ depPath: resolvedImport.identityPath,
205
+ end: unresolved.end,
206
+ quote: unresolved.quote,
207
+ start: unresolved.start,
208
+ })
209
+ }
210
+
211
+ return {
212
+ ok: true,
213
+ value: {
214
+ deps: [...deps],
215
+ fingerprint: transformed.fingerprint,
216
+ identityPath: record.identityPath,
217
+ imports: importsWithPaths,
218
+ trackedFiles: [...trackedFiles],
219
+ trackedResolutions,
220
+ rawCode: transformed.rawCode,
221
+ resolvedPath: transformed.resolvedPath,
222
+ sourceMap: transformed.sourceMap,
223
+ stableUrlPathname: transformed.stableUrlPathname,
224
+ },
225
+ }
226
+ }
227
+
228
+ function findNearestPackageJsonPath(filePath: string): string | null {
229
+ let directory = path.dirname(filePath)
230
+
231
+ while (true) {
232
+ let packageJsonPath = path.join(directory, 'package.json')
233
+ if (fs.existsSync(packageJsonPath)) {
234
+ return normalizeFilePath(packageJsonPath)
235
+ }
236
+
237
+ let parentDirectory = path.dirname(directory)
238
+ if (parentDirectory === directory) return null
239
+ directory = parentDirectory
240
+ }
241
+ }
242
+
243
+ function isRelativeImportSpecifier(specifier: string): boolean {
244
+ return specifier.startsWith('./') || specifier.startsWith('../')
245
+ }
246
+
247
+ function getTrackedRelativeImportResolution(
248
+ importerDir: string,
249
+ specifier: string,
250
+ isWatchIgnored: (filePath: string) => boolean,
251
+ ): RelativeImportResolution | null {
252
+ if (!isRelativeImportSpecifier(specifier)) return null
253
+
254
+ let candidatePath = resolveCandidateBasePath(importerDir, specifier)
255
+ let candidatePrefixes = [`${candidatePath}/`].filter(
256
+ (candidatePrefix) => !isWatchIgnored(candidatePrefix.replace(/\/+$/, '') || '/'),
257
+ )
258
+ let extension = path.extname(specifier)
259
+ if (extension === '') {
260
+ let candidatePaths = [
261
+ candidatePath,
262
+ ...supportedScriptExtensions.map(
263
+ (candidateExtension) => `${candidatePath}${candidateExtension}`,
264
+ ),
265
+ ].filter((candidatePath) => !isWatchIgnored(candidatePath))
266
+
267
+ return candidatePaths.length === 0 && candidatePrefixes.length === 0
268
+ ? null
269
+ : {
270
+ candidatePaths,
271
+ candidatePrefixes,
272
+ specifier,
273
+ }
274
+ }
275
+
276
+ let candidateExtensions = resolverExtensionAlias[extension as keyof typeof resolverExtensionAlias]
277
+ if (!candidateExtensions && !supportedScriptExtensionSet.has(extension)) {
278
+ let candidatePaths = [
279
+ candidatePath,
280
+ ...supportedScriptExtensions.map(
281
+ (candidateExtension) => `${candidatePath}${candidateExtension}`,
282
+ ),
283
+ ].filter((candidatePath) => !isWatchIgnored(candidatePath))
284
+
285
+ return candidatePaths.length === 0 && candidatePrefixes.length === 0
286
+ ? null
287
+ : {
288
+ candidatePaths,
289
+ candidatePrefixes,
290
+ specifier,
291
+ }
292
+ }
293
+
294
+ if (!candidateExtensions) return null
295
+
296
+ let candidatePaths = [
297
+ candidatePath,
298
+ ...candidateExtensions.map(
299
+ (candidateExtension) =>
300
+ `${candidatePath.slice(0, candidatePath.length - extension.length)}${candidateExtension}`,
301
+ ),
302
+ ].filter((candidatePath) => !isWatchIgnored(candidatePath))
303
+
304
+ return candidatePaths.length === 0 && candidatePrefixes.length === 0
305
+ ? null
306
+ : {
307
+ candidatePaths,
308
+ candidatePrefixes,
309
+ specifier,
310
+ }
311
+ }
312
+
313
+ function resolveCandidateBasePath(importerDir: string, specifier: string): string {
314
+ return normalizeFilePath(path.resolve(importerDir, specifier))
315
+ }
316
+
317
+ async function batchResolveSpecifiers(
318
+ specifiers: string[],
319
+ importerPath: string,
320
+ resolverFactory: ResolveArgs['resolverFactory'],
321
+ ): Promise<Map<string, ResolvedSpec>> {
322
+ let resolvedBySpecifier = new Map<string, ResolvedSpec>()
323
+ if (specifiers.length === 0) return resolvedBySpecifier
324
+
325
+ try {
326
+ for (let specifier of specifiers) {
327
+ let resolutionResult = await resolverFactory.resolveFileAsync(importerPath, specifier)
328
+ if (resolutionResult.error) {
329
+ throw createAssetServerCompilationError(
330
+ `Failed to resolve import "${specifier}" in ${importerPath}. ` +
331
+ `Ensure it resolves to a file within the configured asset server fileMap, or mark it as external.`,
332
+ {
333
+ code: 'IMPORT_RESOLUTION_FAILED',
334
+ },
335
+ )
336
+ }
337
+
338
+ resolvedBySpecifier.set(specifier, {
339
+ absolutePath:
340
+ resolutionResult.path && path.isAbsolute(resolutionResult.path)
341
+ ? normalizeFilePath(resolutionResult.path)
342
+ : null,
343
+ packageJsonPath: resolutionResult.packageJsonPath
344
+ ? normalizeFilePath(resolutionResult.packageJsonPath)
345
+ : null,
346
+ specifier,
347
+ })
348
+ }
349
+ } catch (error) {
350
+ if (isAssetServerCompilationError(error) && error.code === 'IMPORT_RESOLUTION_FAILED') {
351
+ throw error
352
+ }
353
+
354
+ throw createAssetServerCompilationError(
355
+ `Failed to resolve imports in ${importerPath}. ${formatUnknownError(error)}`,
356
+ {
357
+ cause: error,
358
+ code: 'IMPORT_RESOLUTION_FAILED',
359
+ },
360
+ )
361
+ }
362
+
363
+ return resolvedBySpecifier
364
+ }
365
+
366
+ function getUniqueSpecifiers(unresolvedImports: TransformedModule['unresolvedImports']): string[] {
367
+ return [...new Set(unresolvedImports.map((unresolved) => unresolved.specifier))]
368
+ }
369
+
370
+ function formatUnknownError(error: unknown): string {
371
+ return error instanceof Error ? error.message : String(error)
372
+ }
373
+
374
+ function failResolve(
375
+ error: unknown,
376
+ trackedFiles: ReadonlySet<string>,
377
+ trackedResolutions: readonly TrackedResolution[],
378
+ importerPath: string,
379
+ options: {
380
+ isWatchIgnored?: (filePath: string) => boolean
381
+ trackedResolution?: RelativeImportResolution | null
382
+ } = {},
383
+ ): ResolveResult {
384
+ return {
385
+ ok: false,
386
+ error: toResolveError(error, importerPath),
387
+ tracking: {
388
+ trackedFiles: [...trackedFiles],
389
+ trackedResolutions: appendFailedTrackedResolution(
390
+ trackedResolutions,
391
+ options.trackedResolution,
392
+ ),
393
+ },
394
+ }
395
+ }
396
+
397
+ function appendFailedTrackedResolution(
398
+ trackedResolutions: readonly TrackedResolution[],
399
+ trackedResolution: RelativeImportResolution | null | undefined,
400
+ ): TrackedResolution[] {
401
+ if (trackedResolution == null) return [...trackedResolutions]
402
+
403
+ return [
404
+ ...trackedResolutions,
405
+ {
406
+ ...trackedResolution,
407
+ resolvedIdentityPath: null,
408
+ },
409
+ ]
410
+ }
411
+
412
+ function toResolveError(error: unknown, importerPath: string): AssetServerCompilationError {
413
+ if (isAssetServerCompilationError(error)) return error
414
+
415
+ return createAssetServerCompilationError(
416
+ `Failed to resolve imports in ${importerPath}. ${formatUnknownError(error)}`,
417
+ {
418
+ cause: error,
419
+ code: 'IMPORT_RESOLUTION_FAILED',
420
+ },
421
+ )
422
+ }