From b4b3628026dd4e84071088b3c79b46f5f500b227 Mon Sep 17 00:00:00 2001
From: Ankita Sahu <71656941+SAHU-01@users.noreply.github.com>
Date: Sun, 19 Oct 2025 03:12:02 +0530
Subject: [PATCH 1/2] feat: fixing error inconsistency
---
src/lib/error-pages.ts | 395 +++++++++++++++++++++++++++++++++++++++++
src/lib/error-types.ts | 173 ++++++++++++++++++
src/sw.ts | 76 +++++++-
3 files changed, 636 insertions(+), 8 deletions(-)
create mode 100644 src/lib/error-pages.ts
create mode 100644 src/lib/error-types.ts
diff --git a/src/lib/error-pages.ts b/src/lib/error-pages.ts
new file mode 100644
index 00000000..91ca20a2
--- /dev/null
+++ b/src/lib/error-pages.ts
@@ -0,0 +1,395 @@
+/**
+ * Error page HTML generation for IPFS Service Worker Gateway
+ *
+ * This module generates user-friendly error pages with detailed information,
+ * actionable suggestions, and debugging tools.
+ *
+ * @module error-pages
+ */
+
+import type { ErrorInfo, ErrorType } from './error-types.js'
+
+/**
+ * Configuration for error page generation
+ */
+export interface ErrorPageConfig {
+ /** HTTP status code */
+ status: number
+ /** HTTP status text */
+ statusText: string
+ /** Full request URL that caused the error */
+ url: string
+ /** Extracted CID from the URL (if applicable) */
+ cid: string | null
+ /** Error type classification */
+ errorType: ErrorType | string
+ /** User-friendly error message */
+ errorMessage: string
+ /** List of actionable suggestions */
+ suggestions: string[]
+ /** Optional stack trace for debugging */
+ stack?: string
+}
+
+/**
+ * Generate complete HTML for error page
+ *
+ * @param config - Error page configuration
+ * @returns Complete HTML document as string
+ */
+export function generateErrorPageHTML(config: ErrorPageConfig): string {
+ const {
+ status,
+ statusText,
+ url,
+ cid,
+ errorType,
+ errorMessage,
+ suggestions,
+ stack
+ } = config
+
+ return `
+
+
+
+
+
+ ${status} ${statusText} - IPFS Service Worker Gateway
+ ${generateStyles()}
+
+
+
+ ${generateHeader(status, statusText, errorType)}
+
+ ${generateCIDSection(cid)}
+ ${generateErrorSection(errorMessage)}
+ ${generateSuggestionsSection(suggestions)}
+ ${generateActionsSection(cid)}
+ ${generateTechnicalDetails(config, stack)}
+
+
+
+`
+}
+
+/**
+ * Generate CSS styles for error page
+ */
+function generateStyles(): string {
+ return ``
+}
+
+/**
+ * Generate header section with status and error type
+ */
+function generateHeader(status: number, statusText: string, errorType: string): string {
+ return ``
+}
+
+/**
+ * Generate CID information section (if CID is present)
+ */
+function generateCIDSection(cid: string | null): string {
+ if (!cid) {
+ return ''
+ }
+
+ return `
+
🔗 Requested Content
+
+
CID:
+
${escapeHtml(cid)}
+
+
`
+}
+
+/**
+ * Generate error explanation section
+ */
+function generateErrorSection(errorMessage: string): string {
+ return `
+
⚠️ What Went Wrong
+
+
${escapeHtml(errorMessage)}
+
+
`
+}
+
+/**
+ * Generate suggestions section with actionable items
+ */
+function generateSuggestionsSection(suggestions: string[]): string {
+ if (!suggestions || suggestions.length === 0) {
+ return ''
+ }
+
+ const suggestionsList = suggestions
+ .map(s => `${escapeHtml(s)}`)
+ .join('')
+
+ return `
+
💡 Possible Solutions
+
+
`
+}
+
+/**
+ * Generate action buttons section
+ */
+function generateActionsSection(cid: string | null): string {
+ const publicGatewayButton = cid
+ ? `
+ 🌐 Try Public Gateway
+ `
+ : ''
+
+ return `
+
+
+ ${publicGatewayButton}
+
`
+}
+
+/**
+ * Generate technical details section (collapsible)
+ */
+function generateTechnicalDetails(config: ErrorPageConfig, stack?: string): string {
+ const technicalInfo = {
+ status: config.status,
+ statusText: config.statusText,
+ errorType: config.errorType,
+ url: config.url,
+ cid: config.cid,
+ timestamp: new Date().toISOString(),
+ userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown'
+ }
+
+ const jsonString = JSON.stringify(technicalInfo, null, 2)
+ const stackTrace = stack ? `\n\nStack Trace:\n${stack}` : ''
+
+ return `
+ 🔧 Technical Details (for debugging)
+ ${escapeHtml(jsonString + stackTrace)}
+ `
+}
+
+/**
+ * Escape HTML special characters to prevent XSS
+ */
+function escapeHtml(unsafe: string): string {
+ return unsafe
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''')
+}
+
+/**
+ * Generate error page from ErrorInfo object
+ *
+ * @param errorInfo - Error information from detectErrorType
+ * @param url - Request URL
+ * @param cid - Extracted CID (optional)
+ * @param stack - Stack trace (optional)
+ * @returns Complete HTML error page
+ */
+export function generateErrorPageFromInfo(
+ errorInfo: ErrorInfo,
+ url: string,
+ cid: string | null,
+ stack?: string
+): string {
+ return generateErrorPageHTML({
+ status: errorInfo.statusCode,
+ statusText: getStatusText(errorInfo.statusCode),
+ url,
+ cid,
+ errorType: errorInfo.errorType,
+ errorMessage: errorInfo.errorMessage,
+ suggestions: errorInfo.suggestions,
+ stack
+ })
+}
+
+/**
+ * Get HTTP status text for status code
+ */
+function getStatusText(status: number): string {
+ const statusTexts: Record = {
+ 400: 'Bad Request',
+ 404: 'Not Found',
+ 415: 'Unsupported Media Type',
+ 500: 'Internal Server Error',
+ 502: 'Bad Gateway',
+ 503: 'Service Unavailable',
+ 504: 'Gateway Timeout'
+ }
+ return statusTexts[status] || 'Error'
+}
\ No newline at end of file
diff --git a/src/lib/error-types.ts b/src/lib/error-types.ts
new file mode 100644
index 00000000..16a22d78
--- /dev/null
+++ b/src/lib/error-types.ts
@@ -0,0 +1,173 @@
+/**
+ * Error type detection and categorization for IPFS Service Worker Gateway
+ *
+ * This module analyzes errors and provides user-friendly explanations with
+ * actionable suggestions for resolution.
+ *
+ * @module error-types
+ */
+
+/**
+ * Structured error information with user-facing details
+ */
+export interface ErrorInfo {
+ /** Machine-readable error category */
+ errorType: ErrorType
+ /** User-friendly error explanation */
+ errorMessage: string
+ /** Actionable suggestions to resolve the issue */
+ suggestions: string[]
+ /** HTTP status code to return */
+ statusCode: number
+}
+
+/**
+ * Supported error categories
+ */
+export enum ErrorType {
+ HASH_VERIFICATION_FAILED = 'Hash Verification Failed',
+ NO_PROVIDERS = 'No Providers Found',
+ TIMEOUT = 'Request Timeout',
+ NETWORK_ERROR = 'Network Error',
+ INVALID_CID = 'Invalid CID',
+ UNSUPPORTED_FORMAT = 'Unsupported Content Type',
+ UNKNOWN = 'Unknown Error'
+}
+
+/**
+ * Analyze an error and return categorized information
+ *
+ * @param error - Error object or error message string
+ * @returns Structured error information with suggestions
+ *
+ */
+export function detectErrorType(error: Error | string): ErrorInfo {
+ const errorMsg = typeof error === 'string' ? error : error.message
+ const errorMsgLower = errorMsg.toLowerCase()
+
+ // Hash verification error - critical data integrity issue
+ if (errorMsgLower.includes('hash') && (errorMsgLower.includes('match') || errorMsgLower.includes('verif'))) {
+ return {
+ errorType: ErrorType.HASH_VERIFICATION_FAILED,
+ errorMessage: 'The downloaded block\'s hash did not match the requested CID. This indicates data corruption or a security issue.',
+ suggestions: [
+ 'The content may have been corrupted during transmission',
+ 'Try accessing the content from a different IPFS gateway',
+ 'Clear your browser cache and retry',
+ 'If you control this content, verify its integrity and re-pin to IPFS'
+ ],
+ statusCode: 502 // Bad Gateway - upstream returned invalid data
+ }
+ }
+
+ // No providers error - content unavailable on network
+ if (errorMsgLower.includes('no provider') || errorMsgLower.includes('no peers') || errorMsgLower.includes('could not find')) {
+ return {
+ errorType: ErrorType.NO_PROVIDERS,
+ errorMessage: 'No nodes on the IPFS network are currently hosting this content.',
+ suggestions: [
+ 'The content may have been unpinned from all hosting nodes',
+ 'Wait a few minutes and try again as nodes may come online',
+ 'Verify the CID is correct and the content was properly published',
+ 'Check if the content is available on public gateways like ipfs.io'
+ ],
+ statusCode: 404 // Not Found - content doesn't exist on network
+ }
+ }
+
+ // Timeout error - slow retrieval
+ if (errorMsgLower.includes('timeout') || errorMsgLower.includes('aborted')) {
+ return {
+ errorType: ErrorType.TIMEOUT,
+ errorMessage: 'The request took too long to complete and was aborted.',
+ suggestions: [
+ 'The content may be hosted on slow or geographically distant nodes',
+ 'Try again in a few moments',
+ 'Check your internet connection',
+ 'Try accessing via a public IPFS gateway',
+ 'Consider increasing the timeout in the config page'
+ ],
+ statusCode: 504 // Gateway Timeout
+ }
+ }
+
+ // Network error - connectivity issues
+ if (errorMsgLower.includes('network') || errorMsgLower.includes('fetch failed') || errorMsgLower.includes('connection')) {
+ return {
+ errorType: ErrorType.NETWORK_ERROR,
+ errorMessage: 'A network error occurred while fetching the content.',
+ suggestions: [
+ 'Check your internet connection',
+ 'Try refreshing the page',
+ 'The IPFS network may be experiencing temporary issues',
+ 'Try again in a few moments'
+ ],
+ statusCode: 503 // Service Unavailable
+ }
+ }
+
+ // Invalid CID - malformed identifier
+ if (errorMsgLower.includes('invalid') && errorMsgLower.includes('cid')) {
+ return {
+ errorType: ErrorType.INVALID_CID,
+ errorMessage: 'The provided CID is not valid or properly formatted.',
+ suggestions: [
+ 'Verify the CID is correctly formatted (starts with "bafy" or "Qm")',
+ 'Ensure you copied the complete CID without truncation',
+ 'Try accessing different content to verify the gateway is working',
+ 'Learn about CID formats at https://cid.ipfs.tech'
+ ],
+ statusCode: 400 // Bad Request
+ }
+ }
+
+ // Unsupported format
+ if (errorMsgLower.includes('unsupported') || errorMsgLower.includes('codec')) {
+ return {
+ errorType: ErrorType.UNSUPPORTED_FORMAT,
+ errorMessage: 'The content uses a format or codec not supported by this gateway.',
+ suggestions: [
+ 'The content may use newer IPFS features not yet supported',
+ 'Try accessing it from a different IPFS implementation',
+ 'Check the IPFS documentation for supported content types'
+ ],
+ statusCode: 415 // Unsupported Media Type
+ }
+ }
+
+ // Default/unknown error
+ return {
+ errorType: ErrorType.UNKNOWN,
+ errorMessage: errorMsg,
+ suggestions: [
+ 'Try refreshing the page',
+ 'Check the browser console for technical details',
+ 'Try accessing the content from a public IPFS gateway',
+ 'Report this issue at https://github.com/ipfs/service-worker-gateway/issues'
+ ],
+ statusCode: 500 // Internal Server Error
+ }
+}
+
+/**
+ * Extract CID from URL in subdomain or path format
+ *
+ * @param url - URL object to parse
+ * @returns Extracted CID or null if not found
+ *
+ */
+export function extractCIDFromURL(url: URL): string | null {
+ // Subdomain format: .ipfs.domain.com or .ipns.domain.com
+ const subdomainMatch = url.hostname.match(/^(.+?)\.(ipfs|ipns)\./)
+ if (subdomainMatch) {
+ return subdomainMatch[1]
+ }
+
+ // Path format: /ipfs/ or /ipns/
+ const pathMatch = url.pathname.match(/^\/(ipfs|ipns)\/([^/?#]+)/)
+ if (pathMatch) {
+ return pathMatch[2]
+ }
+
+ return null
+}
\ No newline at end of file
diff --git a/src/sw.ts b/src/sw.ts
index 496b9e0a..7095204f 100644
--- a/src/sw.ts
+++ b/src/sw.ts
@@ -11,6 +11,8 @@ import { findOriginIsolationRedirect, isPathGatewayRequest, isSubdomainGatewayRe
import { isUnregisterRequest } from './lib/unregister-request.js'
import type { ConfigDb } from './lib/config-db.js'
import type { VerifiedFetch } from '@helia/verified-fetch'
+import { detectErrorType, extractCIDFromURL } from './lib/error-types.ts'
+import { generateErrorPageHTML, generateErrorPageFromInfo } from './lib/error-pages.ts'
/**
******************************************************
@@ -614,29 +616,66 @@ async function fetchHandler ({ path, request, event }: FetchHandlerArg): Promise
} catch (err: unknown) {
log.trace('fetchHandler: error: ', err)
const errorMessages: string[] = []
+ let firstError: Error | null = null
if (isAggregateError(err)) {
log.error('fetchHandler aggregate error: ', err.message)
for (const e of err.errors) {
errorMessages.push(e.message)
log.error('fetchHandler errors: ', e)
+ if (firstError == null) {
+ firstError = e
+ }
}
} else {
- errorMessages.push(err instanceof Error ? err.message : JSON.stringify(err))
+ const error = err instanceof Error ? err : new Error(JSON.stringify(err))
+ errorMessages.push(error.message)
log.error('fetchHandler error: ', err)
+ firstError = error
}
const errorMessage = errorMessages.join('\n')
if (errorMessage.includes('aborted') || signal.aborted) {
return await get504Response(event)
}
- const response = new Response('Service Worker IPFS Gateway error: ' + errorMessage, { status: 500 })
- response.headers.set('ipfs-sw', 'true')
- return response
+
+ const errorInfo = detectErrorType(firstError ?? errorMessage)
+ const url = new URL(event.request.url)
+ const cid = extractCIDFromURL(url)
+
+ const errorHtml = generateErrorPageFromInfo(
+ errorInfo,
+ url.href,
+ cid,
+ firstError?.stack
+ )
+
+ return new Response(errorHtml, {
+ status: errorInfo.statusCode,
+ statusText: getStatusText(errorInfo.statusCode),
+ headers: {
+ 'Content-Type': 'text/html; charset=utf-8',
+ 'ipfs-sw': 'true',
+ 'Cache-Control': 'no-cache, no-store, must-revalidate'
+ }
+ })
} finally {
clearTimeout(signalAbortTimeout)
}
}
+function getStatusText(status: number): string {
+ const statusTexts: Record = {
+ 400: 'Bad Request',
+ 404: 'Not Found',
+ 415: 'Unsupported Media Type',
+ 500: 'Internal Server Error',
+ 502: 'Bad Gateway',
+ 503: 'Service Unavailable',
+ 504: 'Gateway Timeout'
+ }
+ return statusTexts[status] || 'Error'
+}
+
/**
* TODO: better styling
* TODO: more error details from @helia/verified-fetch
@@ -677,6 +716,8 @@ async function errorPageResponse (fetchResponse: Response): Promise {
const mergedHeaders = new Headers(fetchResponse.headers)
mergedHeaders.set('Content-Type', 'text/html')
mergedHeaders.set('ipfs-sw', 'true')
+ mergedHeaders.set('Cache-Control', 'no-cache, no-store, must-revalidate')
+
return new Response(`
@@ -716,13 +757,32 @@ async function errorPageResponse (fetchResponse: Response): Promise {
}
async function get504Response (event: FetchEvent): Promise {
- const response504 = await fetch(new URL('/ipfs-sw-504.html', event.request.url))
+ const url = new URL(event.request.url)
+ const cid = extractCIDFromURL(url)
+
+ const errorHtml = generateErrorPageHTML({
+ status: 504,
+ statusText: 'Gateway Timeout',
+ url: url.href,
+ cid,
+ errorType: 'Timeout',
+ errorMessage: 'The gateway timed out while trying to fetch your content from the IPFS network.',
+ suggestions: [
+ 'Wait a few moments and click the Retry button',
+ 'The content may be hosted on slow or distant nodes',
+ 'Try accessing the content from a public IPFS gateway',
+ 'Check if the content is still available on the IPFS network',
+ 'Consider increasing the timeout in the config page'
+ ]
+ })
- return new Response(response504.body, {
+ return new Response(errorHtml, {
status: 504,
+ statusText: 'Gateway Timeout',
headers: {
- 'Content-Type': 'text/html',
- 'ipfs-sw': 'true'
+ 'Content-Type': 'text/html; charset=utf-8',
+ 'ipfs-sw': 'true',
+ 'Cache-Control': 'no-cache, no-store, must-revalidate'
}
})
}
From 283be3474a1fce4cb4a574db223d886999ecda0f Mon Sep 17 00:00:00 2001
From: Ankita Sahu <71656941+SAHU-01@users.noreply.github.com>
Date: Sun, 19 Oct 2025 06:13:03 +0530
Subject: [PATCH 2/2] fix: resolve error page UX inconsistencies (#817, #816)
---
src/lib/error-pages.ts | 470 +++++++++++++----------------------------
src/lib/error-types.ts | 16 +-
src/sw.ts | 13 +-
3 files changed, 157 insertions(+), 342 deletions(-)
diff --git a/src/lib/error-pages.ts b/src/lib/error-pages.ts
index 91ca20a2..bfb3c030 100644
--- a/src/lib/error-pages.ts
+++ b/src/lib/error-pages.ts
@@ -1,10 +1,6 @@
/**
* Error page HTML generation for IPFS Service Worker Gateway
- *
- * This module generates user-friendly error pages with detailed information,
- * actionable suggestions, and debugging tools.
- *
- * @module error-pages
+ * Generates inline error pages matching the original 504.html styling
*/
import type { ErrorInfo, ErrorType } from './error-types.js'
@@ -13,336 +9,20 @@ import type { ErrorInfo, ErrorType } from './error-types.js'
* Configuration for error page generation
*/
export interface ErrorPageConfig {
- /** HTTP status code */
status: number
- /** HTTP status text */
statusText: string
- /** Full request URL that caused the error */
url: string
- /** Extracted CID from the URL (if applicable) */
cid: string | null
- /** Error type classification */
errorType: ErrorType | string
- /** User-friendly error message */
errorMessage: string
- /** List of actionable suggestions */
suggestions: string[]
- /** Optional stack trace for debugging */
stack?: string
}
-/**
- * Generate complete HTML for error page
- *
- * @param config - Error page configuration
- * @returns Complete HTML document as string
- */
-export function generateErrorPageHTML(config: ErrorPageConfig): string {
- const {
- status,
- statusText,
- url,
- cid,
- errorType,
- errorMessage,
- suggestions,
- stack
- } = config
-
- return `
-
-
-
-
-
- ${status} ${statusText} - IPFS Service Worker Gateway
- ${generateStyles()}
-
-
-
- ${generateHeader(status, statusText, errorType)}
-
- ${generateCIDSection(cid)}
- ${generateErrorSection(errorMessage)}
- ${generateSuggestionsSection(suggestions)}
- ${generateActionsSection(cid)}
- ${generateTechnicalDetails(config, stack)}
-
-
-
-`
-}
-
-/**
- * Generate CSS styles for error page
- */
-function generateStyles(): string {
- return ``
-}
-
-/**
- * Generate header section with status and error type
- */
-function generateHeader(status: number, statusText: string, errorType: string): string {
- return ``
-}
-
-/**
- * Generate CID information section (if CID is present)
- */
-function generateCIDSection(cid: string | null): string {
- if (!cid) {
- return ''
- }
-
- return `
-
🔗 Requested Content
-
-
CID:
-
${escapeHtml(cid)}
-
-
`
-}
-
-/**
- * Generate error explanation section
- */
-function generateErrorSection(errorMessage: string): string {
- return `
-
⚠️ What Went Wrong
-
-
${escapeHtml(errorMessage)}
-
-
`
-}
-
-/**
- * Generate suggestions section with actionable items
- */
-function generateSuggestionsSection(suggestions: string[]): string {
- if (!suggestions || suggestions.length === 0) {
- return ''
- }
-
- const suggestionsList = suggestions
- .map(s => `${escapeHtml(s)}`)
- .join('')
-
- return `
-
💡 Possible Solutions
-
-
`
-}
-
-/**
- * Generate action buttons section
- */
-function generateActionsSection(cid: string | null): string {
- const publicGatewayButton = cid
- ? `
- 🌐 Try Public Gateway
- `
- : ''
-
- return `
-
-
- ${publicGatewayButton}
-
`
-}
-
-/**
- * Generate technical details section (collapsible)
- */
-function generateTechnicalDetails(config: ErrorPageConfig, stack?: string): string {
- const technicalInfo = {
- status: config.status,
- statusText: config.statusText,
- errorType: config.errorType,
- url: config.url,
- cid: config.cid,
- timestamp: new Date().toISOString(),
- userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : 'unknown'
- }
-
- const jsonString = JSON.stringify(technicalInfo, null, 2)
- const stackTrace = stack ? `\n\nStack Trace:\n${stack}` : ''
-
- return `
- 🔧 Technical Details (for debugging)
- ${escapeHtml(jsonString + stackTrace)}
- `
-}
-
/**
* Escape HTML special characters to prevent XSS
*/
-function escapeHtml(unsafe: string): string {
+function escapeHtml (unsafe: string): string {
return unsafe
.replace(/&/g, '&')
.replace(/ `${escapeHtml(s)}`).join('')
+
+ return `
+
+
+
+ ${status} ${statusText}
+
+
+
+
+
+
+ ${status} ${escapeHtml(statusText)}
+
+
+ ${cid
+? `
+ Requested CID:
+ ${escapeHtml(cid)}
+ `
+: ''}
+
+
+ What went wrong:
+ ${escapeHtml(errorMessage)}
+
+
+ ${suggestions.length > 0
+? `
+ How you can proceed:
+
+ `
+: ''}
+
+ Additional resources:
+
+
+ ${cid ? `Debug retrievability of CID` : ''}
+
+
+
+
+`
+}
+
/**
* Generate error page from ErrorInfo object
- *
+ *
* @param errorInfo - Error information from detectErrorType
* @param url - Request URL
* @param cid - Extracted CID (optional)
* @param stack - Stack trace (optional)
* @returns Complete HTML error page
*/
-export function generateErrorPageFromInfo(
+export function generateErrorPageFromInfo (
errorInfo: ErrorInfo,
url: string,
cid: string | null,
@@ -381,7 +199,7 @@ export function generateErrorPageFromInfo(
/**
* Get HTTP status text for status code
*/
-function getStatusText(status: number): string {
+function getStatusText (status: number): string {
const statusTexts: Record = {
400: 'Bad Request',
404: 'Not Found',
@@ -392,4 +210,4 @@ function getStatusText(status: number): string {
504: 'Gateway Timeout'
}
return statusTexts[status] || 'Error'
-}
\ No newline at end of file
+}
diff --git a/src/lib/error-types.ts b/src/lib/error-types.ts
index 16a22d78..b9ed0fff 100644
--- a/src/lib/error-types.ts
+++ b/src/lib/error-types.ts
@@ -1,9 +1,9 @@
/**
* Error type detection and categorization for IPFS Service Worker Gateway
- *
+ *
* This module analyzes errors and provides user-friendly explanations with
* actionable suggestions for resolution.
- *
+ *
* @module error-types
*/
@@ -36,12 +36,11 @@ export enum ErrorType {
/**
* Analyze an error and return categorized information
- *
+ *
* @param error - Error object or error message string
* @returns Structured error information with suggestions
- *
*/
-export function detectErrorType(error: Error | string): ErrorInfo {
+export function detectErrorType (error: Error | string): ErrorInfo {
const errorMsg = typeof error === 'string' ? error : error.message
const errorMsgLower = errorMsg.toLowerCase()
@@ -151,12 +150,11 @@ export function detectErrorType(error: Error | string): ErrorInfo {
/**
* Extract CID from URL in subdomain or path format
- *
+ *
* @param url - URL object to parse
* @returns Extracted CID or null if not found
- *
*/
-export function extractCIDFromURL(url: URL): string | null {
+export function extractCIDFromURL (url: URL): string | null {
// Subdomain format: .ipfs.domain.com or .ipns.domain.com
const subdomainMatch = url.hostname.match(/^(.+?)\.(ipfs|ipns)\./)
if (subdomainMatch) {
@@ -170,4 +168,4 @@ export function extractCIDFromURL(url: URL): string | null {
}
return null
-}
\ No newline at end of file
+}
diff --git a/src/sw.ts b/src/sw.ts
index 7095204f..6a846fa7 100644
--- a/src/sw.ts
+++ b/src/sw.ts
@@ -1,5 +1,7 @@
import { getConfig } from './lib/config-db.js'
import { HASH_FRAGMENTS, QUERY_PARAMS } from './lib/constants.js'
+import { generateErrorPageHTML, generateErrorPageFromInfo } from './lib/error-pages.ts'
+import { detectErrorType, extractCIDFromURL } from './lib/error-types.ts'
import { getHeliaSwRedirectUrl } from './lib/first-hit-helpers.js'
import { GenericIDB } from './lib/generic-db.js'
import { getSubdomainParts } from './lib/get-subdomain-parts.js'
@@ -11,8 +13,6 @@ import { findOriginIsolationRedirect, isPathGatewayRequest, isSubdomainGatewayRe
import { isUnregisterRequest } from './lib/unregister-request.js'
import type { ConfigDb } from './lib/config-db.js'
import type { VerifiedFetch } from '@helia/verified-fetch'
-import { detectErrorType, extractCIDFromURL } from './lib/error-types.ts'
-import { generateErrorPageHTML, generateErrorPageFromInfo } from './lib/error-pages.ts'
/**
******************************************************
@@ -642,13 +642,13 @@ async function fetchHandler ({ path, request, event }: FetchHandlerArg): Promise
const url = new URL(event.request.url)
const cid = extractCIDFromURL(url)
- const errorHtml = generateErrorPageFromInfo(
+ const errorHtml = generateErrorPageFromInfo(
errorInfo,
url.href,
cid,
firstError?.stack
)
-
+
return new Response(errorHtml, {
status: errorInfo.statusCode,
statusText: getStatusText(errorInfo.statusCode),
@@ -663,7 +663,7 @@ async function fetchHandler ({ path, request, event }: FetchHandlerArg): Promise
}
}
-function getStatusText(status: number): string {
+function getStatusText (status: number): string {
const statusTexts: Record = {
400: 'Bad Request',
404: 'Not Found',
@@ -718,7 +718,6 @@ async function errorPageResponse (fetchResponse: Response): Promise {
mergedHeaders.set('ipfs-sw', 'true')
mergedHeaders.set('Cache-Control', 'no-cache, no-store, must-revalidate')
-
return new Response(`
@@ -759,7 +758,7 @@ async function errorPageResponse (fetchResponse: Response): Promise {
async function get504Response (event: FetchEvent): Promise {
const url = new URL(event.request.url)
const cid = extractCIDFromURL(url)
-
+
const errorHtml = generateErrorPageHTML({
status: 504,
statusText: 'Gateway Timeout',