@real-router/core 0.126.4 → 0.126.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"RouterError-DCVsSNgX.js","names":["errorCodes"],"sources":["../../src/RouterError.ts"],"sourcesContent":["// packages/core/src/RouterError.ts\n\nimport { errorCodes, UNSAFE_KEY } from \"./constants\";\nimport { putField } from \"./utils/ingest\";\n\n/** Captured like the deciding seven, but this one BUILDS the guarantee (#2073). */\nconst freeze = Object.freeze;\n\nconst objectEntries = Object.entries;\nconst objectValues = Object.values;\n\n// Pre-compute Set of error code values for O(1) lookup in setCode()\n// This avoids creating array and doing linear search on every setCode() call\n// ⚑ Captured at module load, for the reason `helpers.ts` states over its own\n// three: an application can re-point `Object.hasOwn` after boot, and this one\n// gates a PUBLIC read (#1829). ⚠ The file's four other intrinsic reads are still\n// raw — #1971 owns that sweep, and a point fix here would be the N+1 it exists\n// to prevent; capturing the read this commit ADDS is not the same thing as\n// sweeping the ones it found.\nconst hasOwn = Object.hasOwn;\n\nconst errorCodeValues = new Set(objectValues(errorCodes));\n\n// Reserved built-in properties - throw error if user tries to set these\nconst reservedProperties = new Set([\"code\", \"segment\", \"path\"]);\n\n// Reserved method names - silently ignore attempts to overwrite these\nconst reservedMethods = new Set([\n \"setCode\",\n \"setErrorInstance\",\n \"setAdditionalFields\",\n \"hasField\",\n \"getField\",\n \"toJSON\",\n]);\n\n/**\n * Freeze a `RouterError` at the moment it stops being core's to change — the\n * throw (#1960).\n *\n * ⚑ At the THROW, never in the constructor. `RouterError` publishes three\n * mutators (`setCode`, `setErrorInstance`, `setAdditionalFields`) with worked\n * examples in the wiki, and `rethrowAsRouterError` copies an error and re-codes\n * the copy before throwing it. Freezing on construction was measured: it reds\n * across the tier and concentrates in this class's own suite, because it\n * withdraws published API from errors a CONSUMER builds. Freezing here\n * withdraws exactly one thing — writing to an error core threw at you — which\n * #1606 already established is corruption when the instance is one of the\n * cached, process-shared ones, and which a repository-wide sweep of every\n * `catch` binding found nobody doing.\n *\n * ⚠ Only for errors core CONSTRUCTED. A re-thrown foreign error stays untouched:\n * freezing someone else's object on the way through is the hazard, not the fix.\n */\nexport function freezeThrownError<E extends RouterError>(error: E): E {\n return freeze(error);\n}\n\nexport class RouterError extends Error {\n [key: string]: unknown;\n\n // Using public properties to ensure structural compatibility\n // with the `RouterError` interface in `types/base.ts`\n readonly segment: string | undefined;\n readonly path: string | undefined;\n\n // Note: code appears to be writable but setCode() should be used\n // to properly update both code and message together\n code: string;\n\n /**\n * Creates a new RouterError instance.\n *\n * The options object accepts built-in fields (message, segment, path)\n * and any additional custom fields, which will all be attached to the error instance.\n *\n * @param code - The error code (e.g., \"ROUTE_NOT_FOUND\", \"CANNOT_ACTIVATE\")\n * @param options - Optional configuration object\n * @param options.message - Custom error message (defaults to code if not provided)\n * @param options.segment - The route segment where the error occurred\n * @param options.path - The full path where the error occurred\n *\n * @example\n * ```typescript\n * // Basic error\n * const err1 = new RouterError(\"ROUTE_NOT_FOUND\");\n *\n * // Error with custom message\n * const err2 = new RouterError(\"ERR\", { message: \"Something went wrong\" });\n *\n * // Error with context and custom fields\n * const err3 = new RouterError(\"CANNOT_ACTIVATE\", {\n * message: \"Insufficient permissions\",\n * segment: \"admin\",\n * path: \"/admin/users\",\n * userId: \"123\" // custom field\n * });\n * ```\n */\n constructor(\n code: string,\n {\n message,\n segment,\n path,\n ...rest\n }: {\n [key: string]: unknown;\n message?: string | undefined;\n segment?: string | undefined;\n path?: string | undefined;\n } = {},\n ) {\n super(message ?? code);\n\n // Subclasses don't auto-set `name`; without this `error.name` inherits\n // \"Error\", breaking `error.name === \"RouterError\"` checks at catch sites that\n // can't `instanceof` across bundle boundaries.\n this.name = \"RouterError\";\n\n this.code = code;\n this.segment = segment;\n this.path = path;\n\n // Assign custom fields, checking reserved properties and filtering out reserved method names\n // Issue #39: Throw for reserved properties to match setAdditionalFields behavior\n for (const [key, value] of objectEntries(rest)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped for the reason the state channels give (#1852):\n // this instance is a container core hands out and `toJSON` serializes, so\n // an own `\"__proto__\"` on it is a prototype-swap primitive for whoever\n // merges or re-parses the error — measured, a guard throwing a plain\n // object put the key into `JSON.stringify(err)`.\n //\n // ⚠ Plain assignment is the alternative that looks equivalent and is\n // worse than losing the key: measured, `new RouterError(\"X\", bag)` swaps\n // the INSTANCE's prototype and `instanceof RouterError` answers `false`.\n // `putField` keeps the instance intact; the skip keeps the key off a\n // container someone will merge.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Updates the error code and conditionally updates the message.\n *\n * If the current message is one of the standard error code values\n * (e.g., \"ROUTE_NOT_FOUND\", \"SAME_STATES\"), it will be replaced with the new code.\n * This allows keeping error messages in sync with codes when using standard error codes.\n *\n * If the message is custom (not a standard error code), it will be preserved.\n *\n * @param newCode - The new error code to set\n *\n * @example\n * // Message follows code (standard error code as message)\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", { message: \"ROUTE_NOT_FOUND\" });\n * err.setCode(\"CUSTOM_ERROR\"); // message becomes \"CUSTOM_ERROR\"\n *\n * @example\n * // Custom message is preserved\n * const err = new RouterError(\"ERR\", { message: \"Custom error message\" });\n * err.setCode(\"NEW_CODE\"); // message stays \"Custom error message\"\n */\n setCode(newCode: string): void {\n this.code = newCode;\n\n // Only update message if it's a standard error code value (not a custom message)\n if (errorCodeValues.has(this.message)) {\n this.message = newCode;\n }\n }\n\n /**\n * Copies properties from another Error instance to this RouterError.\n *\n * This method updates the message, cause, and stack trace from the provided error.\n * Useful for wrapping native errors while preserving error context.\n *\n * @param err - The Error instance to copy properties from\n * @throws {TypeError} If err is null or undefined\n *\n * @example\n * ```typescript\n * const routerErr = new RouterError(\"TRANSITION_ERR\");\n * try {\n * // some operation that might fail\n * } catch (nativeErr) {\n * routerErr.setErrorInstance(nativeErr);\n * throw routerErr;\n * }\n * ```\n */\n setErrorInstance(err: Error): void {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!err) {\n throw new TypeError(\n \"[RouterError.setErrorInstance] err parameter is required and must be an Error instance\",\n );\n }\n\n this.message = err.message;\n this.cause = err.cause;\n this.stack = err.stack ?? \"\";\n }\n\n /**\n * Adds custom fields to the error object.\n *\n * This method allows attaching arbitrary data to the error for debugging or logging purposes.\n * All fields become accessible as properties on the error instance and are included in JSON serialization.\n *\n * Reserved method names (setCode, setErrorInstance, setAdditionalFields, hasField, getField, toJSON)\n * are automatically filtered out to prevent accidental overwriting of class methods.\n *\n * @param fields - Object containing custom fields to add to the error\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"CANNOT_ACTIVATE\");\n * err.setAdditionalFields({\n * userId: \"123\",\n * attemptedRoute: \"/admin\",\n * reason: \"insufficient permissions\"\n * });\n *\n * console.log(err.userId); // \"123\"\n * console.log(JSON.stringify(err)); // includes all custom fields\n * ```\n */\n setAdditionalFields(fields: Record<string, unknown>): void {\n // Assign fields, throwing for reserved properties, silently ignoring methods\n for (const [key, value] of objectEntries(fields)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError.setAdditionalFields] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped, and `putField` rather than assignment, for the\n // reasons the constructor's own field loop states (#1852). Not restated\n // here — one mechanism, one explanation.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Checks if a custom field exists on the error object.\n *\n * This method checks for both custom fields added via setAdditionalFields()\n * and built-in fields (code, message, segment, etc.).\n *\n * @param key - The field name to check\n * @returns `true` if the field exists, `false` otherwise\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\", { segment: \"users\" });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * err.hasField(\"userId\"); // true\n * err.hasField(\"segment\"); // true\n * err.hasField(\"unknown\"); // false\n * ```\n */\n hasField(key: string): boolean {\n // ⚑ `hasOwn`, not `in` (#1829). `in` walks the prototype chain, so this\n // answered `true` for `Object.prototype`'s twelve members and for the\n // class's own six methods — eighteen names for an error carrying ONE field\n // and `toString` / `constructor` are ordinary strings arriving from a config\n // key, a route param name or a serialized payload.\n //\n // ⚠ NOT `toJSON`'s `excludeKeys`, which the issue proposed. Measured against\n // the docstring above: that set excludes `code`, `segment` and `path`,\n // which this method documents as answering `true`. The two functions ask\n // different questions (what to SERIALIZE vs what the error CARRIES), so\n // agreeing on those three is the contract and diverging on `message` /\n // `stack` / `name` is not drift.\n return hasOwn(this, key);\n }\n\n /**\n * Retrieves a custom field value from the error object.\n *\n * This method can access both custom fields and built-in fields.\n * Returns `undefined` if the field doesn't exist.\n *\n * @param key - The field name to retrieve\n * @returns The field value, or `undefined` if it doesn't exist\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\");\n * err.setAdditionalFields({ userId: \"123\", role: \"admin\" });\n *\n * err.getField(\"userId\"); // \"123\"\n * err.getField(\"role\"); // \"admin\"\n * err.getField(\"code\"); // \"ERR\" (built-in field)\n * err.getField(\"unknown\"); // undefined\n * ```\n */\n getField(key: string): unknown {\n // Reachable without `hasField` — a consumer may just read — so the same gate\n // stands here rather than being implied by the predicate (#1829). Before\n // this, `getField(\"toString\")` handed back the native function.\n return hasOwn(this, key) ? this[key] : undefined;\n }\n\n /**\n * Serializes the error to a JSON-compatible object.\n *\n * This method is automatically called by JSON.stringify() and includes:\n * - Built-in fields: code, message, segment (if set), path (if set)\n * - All custom fields added via setAdditionalFields() or constructor\n * - Excludes: stack trace (for security/cleanliness)\n *\n * @returns A plain object representation of the error, suitable for JSON serialization\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * message: \"Route not found\",\n * path: \"/admin/users/123\"\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * JSON.stringify(err);\n * // {\n * // \"code\": \"ROUTE_NOT_FOUND\",\n * // \"message\": \"Route not found\",\n * // \"path\": \"/admin/users/123\",\n * // \"userId\": \"123\"\n * // }\n * ```\n */\n toJSON(): Record<string, unknown> {\n const result: Record<string, unknown> = {\n code: this.code,\n message: this.message,\n };\n\n if (this.segment !== undefined) {\n result.segment = this.segment;\n }\n if (this.path !== undefined) {\n result.path = this.path;\n }\n\n // add all public fields\n // Using Set.has() for O(1) lookup instead of Array.includes() O(n)\n // Overall complexity: O(n) instead of O(n*m)\n const excludeKeys = new Set([\n \"code\",\n \"message\",\n \"segment\",\n \"path\",\n \"stack\",\n // `name` is now an own enumerable prop (constructor sets it to\n // \"RouterError\"); it's class metadata, not a custom field — keep it out of\n // the serialized output (preserves toJSON shape).\n \"name\",\n ]);\n\n for (const key in this) {\n if (hasOwn(this, key) && !excludeKeys.has(key)) {\n // ⚑ `putField` (#1852): `result` is a fresh literal and the keys are the\n // user's own error fields. Measured, a setter under one of them made the\n // field vanish from the serialized output with no error at all.\n putField(result, key, this[key]);\n }\n }\n\n return result;\n }\n}\n"],"mappings":"wCAMM,EAAS,OAAO,OAEhB,EAAgB,OAAO,QACvB,EAAe,OAAO,OAUtB,EAAS,OAAO,OAEhB,EAAkB,IAAI,IAAI,EAAaA,EAAAA,CAAU,CAAC,EAGlD,EAAqB,IAAI,IAAI,CAAC,OAAQ,UAAW,MAAM,CAAC,EAGxD,EAAkB,IAAI,IAAI,CAC9B,UACA,mBACA,sBACA,WACA,WACA,QACF,CAAC,EAoBD,SAAgB,EAAyC,EAAa,CACpE,OAAO,EAAO,CAAK,CACrB,CAEA,IAAa,EAAb,cAAiC,KAAM,CAKrC,QACA,KAIA,KA+BA,YACE,EACA,CACE,UACA,UACA,OACA,GAAG,GAMD,CAAC,EACL,CACA,MAAM,GAAW,CAAI,EAKrB,KAAK,KAAO,cAEZ,KAAK,KAAO,EACZ,KAAK,QAAU,EACf,KAAK,KAAO,EAIZ,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAI,EAAG,CAC9C,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,+CAA+C,EAAI,EACrD,EAcE,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAA,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAuBA,QAAQ,EAAuB,CAC7B,KAAK,KAAO,EAGR,EAAgB,IAAI,KAAK,OAAO,IAClC,KAAK,QAAU,EAEnB,CAsBA,iBAAiB,EAAkB,CAEjC,GAAI,CAAC,EACH,MAAU,UACR,wFACF,EAGF,KAAK,QAAU,EAAI,QACnB,KAAK,MAAQ,EAAI,MACjB,KAAK,MAAQ,EAAI,OAAS,EAC5B,CA0BA,oBAAoB,EAAuC,CAEzD,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAM,EAAG,CAChD,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,mEAAmE,EAAI,EACzE,EAME,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAA,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAqBA,SAAS,EAAsB,CAa7B,OAAO,EAAO,KAAM,CAAG,CACzB,CAsBA,SAAS,EAAsB,CAI7B,OAAO,EAAO,KAAM,CAAG,EAAI,KAAK,GAAO,IAAA,EACzC,CA6BA,QAAkC,CAChC,IAAM,EAAkC,CACtC,KAAM,KAAK,KACX,QAAS,KAAK,OAChB,EAEI,KAAK,UAAY,IAAA,KACnB,EAAO,QAAU,KAAK,SAEpB,KAAK,OAAS,IAAA,KAChB,EAAO,KAAO,KAAK,MAMrB,IAAM,EAAc,IAAI,IAAI,CAC1B,OACA,UACA,UACA,OACA,QAIA,MACF,CAAC,EAED,IAAK,IAAM,KAAO,KACZ,EAAO,KAAM,CAAG,GAAK,CAAC,EAAY,IAAI,CAAG,GAI3C,EAAA,EAAS,EAAQ,EAAK,KAAK,EAAI,EAInC,OAAO,CACT,CACF"}
1
+ {"version":3,"file":"RouterError-DCVsSNgX.js","names":["errorCodes"],"sources":["../../src/RouterError.ts"],"sourcesContent":["// packages/core/src/RouterError.ts\n\nimport { errorCodes, UNSAFE_KEY } from \"./constants\";\nimport { putField } from \"./utils/ingest\";\n\n/** Captured like the deciding seven, but this one BUILDS the guarantee (#2073). */\nconst freeze = Object.freeze;\n\nconst objectEntries = Object.entries;\nconst objectValues = Object.values;\n\n// Pre-compute Set of error code values for O(1) lookup in setCode()\n// This avoids creating array and doing linear search on every setCode() call\n// ⚑ Captured at module load, for the reason `helpers.ts` states over its own\n// three: an application can re-point `Object.hasOwn` after boot, and this one\n// gates a PUBLIC read (#1829). ⚠ The file's four other intrinsic reads are still\n// raw — #1971 owns that sweep, and a point fix here would be the N+1 it exists\n// to prevent; capturing the read this commit ADDS is not the same thing as\n// sweeping the ones it found.\nconst hasOwn = Object.hasOwn;\n\nconst errorCodeValues = new Set(objectValues(errorCodes));\n\n// Reserved built-in properties - throw error if user tries to set these\nconst reservedProperties = new Set([\"code\", \"segment\", \"path\"]);\n\n// Reserved method names - silently ignore attempts to overwrite these\nconst reservedMethods = new Set([\n \"setCode\",\n \"setErrorInstance\",\n \"setAdditionalFields\",\n \"hasField\",\n \"getField\",\n \"toJSON\",\n]);\n\n/**\n * Freeze a `RouterError` at the moment it stops being core's to change — the\n * throw (#1960).\n *\n * ⚑ At the THROW, never in the constructor. `RouterError` publishes three\n * mutators (`setCode`, `setErrorInstance`, `setAdditionalFields`) with worked\n * examples in the wiki, and `rethrowAsRouterError` copies an error and re-codes\n * the copy before throwing it. Freezing on construction was measured: it reds\n * across the tier and concentrates in this class's own suite, because it\n * withdraws published API from errors a CONSUMER builds. Freezing here\n * withdraws exactly one thing — writing to an error core threw at you — which\n * #1606 already established is corruption when the instance is one of the\n * cached, process-shared ones, and which a repository-wide sweep of every\n * `catch` binding found nobody doing.\n *\n * ⚠ Only for errors core CONSTRUCTED. A re-thrown foreign error stays untouched:\n * freezing someone else's object on the way through is the hazard, not the fix.\n */\nexport function freezeThrownError<E extends RouterError>(error: E): E {\n return freeze(error);\n}\n\nexport class RouterError extends Error {\n [key: string]: unknown;\n\n // Using public properties to ensure structural compatibility\n // with the `RouterError` interface in `types/base.ts`\n readonly segment: string | undefined;\n readonly path: string | undefined;\n\n // Note: code appears to be writable but setCode() should be used\n // to properly update both code and message together\n code: string;\n\n /**\n * Creates a new RouterError instance.\n *\n * The options object accepts built-in fields (message, segment, path)\n * and any additional custom fields, which will all be attached to the error instance.\n *\n * @param code - The error code (e.g., \"ROUTE_NOT_FOUND\", \"CANNOT_ACTIVATE\")\n * @param options - Optional configuration object\n * @param options.message - Custom error message (defaults to code if not provided)\n * @param options.segment - The route segment where the error occurred\n * @param options.path - The full path where the error occurred\n *\n * @example\n * ```typescript\n * // Basic error\n * const err1 = new RouterError(\"ROUTE_NOT_FOUND\");\n *\n * // Error with custom message\n * const err2 = new RouterError(\"ERR\", { message: \"Something went wrong\" });\n *\n * // Error with context and custom fields\n * const err3 = new RouterError(\"CANNOT_ACTIVATE\", {\n * message: \"Insufficient permissions\",\n * segment: \"admin\",\n * path: \"/admin/users\",\n * userId: \"123\" // custom field\n * });\n * ```\n */\n constructor(\n code: string,\n {\n message,\n segment,\n path,\n ...rest\n }: {\n [key: string]: unknown;\n message?: string | undefined;\n segment?: string | undefined;\n path?: string | undefined;\n } = {},\n ) {\n super(message ?? code);\n\n // Subclasses don't auto-set `name`; without this `error.name` inherits\n // \"Error\", breaking `error.name === \"RouterError\"` checks at catch sites that\n // can't `instanceof` across bundle boundaries.\n this.name = \"RouterError\";\n\n this.code = code;\n this.segment = segment;\n this.path = path;\n\n // Assign custom fields, checking reserved properties and filtering out reserved method names\n // Issue #39: Throw for reserved properties to match setAdditionalFields behavior\n for (const [key, value] of objectEntries(rest)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped for the reason the state channels give (#1852):\n // this instance is a container core hands out and `toJSON` serializes, so\n // an own `\"__proto__\"` on it is a prototype-swap primitive for whoever\n // merges or re-parses the error — measured, a guard throwing a plain\n // object put the key into `JSON.stringify(err)`.\n //\n // ⚠ Plain assignment is the alternative that looks equivalent and is\n // worse than losing the key: measured, `new RouterError(\"X\", bag)` swaps\n // the INSTANCE's prototype and `instanceof RouterError` answers `false`.\n // `putField` keeps the instance intact; the skip keeps the key off a\n // container someone will merge.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Updates the error code and conditionally updates the message.\n *\n * If the current message is one of the standard error code values\n * (e.g., \"ROUTE_NOT_FOUND\", \"SAME_STATES\"), it will be replaced with the new code.\n * This allows keeping error messages in sync with codes when using standard error codes.\n *\n * If the message is custom (not a standard error code), it will be preserved.\n *\n * @param newCode - The new error code to set\n *\n * @example\n * // Message follows code (standard error code as message)\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", { message: \"ROUTE_NOT_FOUND\" });\n * err.setCode(\"CUSTOM_ERROR\"); // message becomes \"CUSTOM_ERROR\"\n *\n * @example\n * // Custom message is preserved\n * const err = new RouterError(\"ERR\", { message: \"Custom error message\" });\n * err.setCode(\"NEW_CODE\"); // message stays \"Custom error message\"\n */\n setCode(newCode: string): void {\n this.code = newCode;\n\n // Only update message if it's a standard error code value (not a custom message)\n if (errorCodeValues.has(this.message)) {\n this.message = newCode;\n }\n }\n\n /**\n * Copies properties from another Error instance to this RouterError.\n *\n * This method updates the message, cause, and stack trace from the provided error.\n * Useful for wrapping native errors while preserving error context.\n *\n * @param err - The Error instance to copy properties from\n * @throws {TypeError} If err is null or undefined\n *\n * @example\n * ```typescript\n * const routerErr = new RouterError(\"TRANSITION_ERR\");\n * try {\n * // some operation that might fail\n * } catch (nativeErr) {\n * routerErr.setErrorInstance(nativeErr);\n * throw routerErr;\n * }\n * ```\n */\n setErrorInstance(err: Error): void {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!err) {\n throw new TypeError(\n \"[RouterError.setErrorInstance] err parameter is required and must be an Error instance\",\n );\n }\n\n this.message = err.message;\n this.cause = err.cause;\n this.stack = err.stack ?? \"\";\n }\n\n /**\n * Adds custom fields to the error object.\n *\n * This method allows attaching arbitrary data to the error for debugging or logging purposes.\n * All fields become accessible as properties on the error instance and are included in JSON serialization.\n *\n * Reserved method names (setCode, setErrorInstance, setAdditionalFields, hasField, getField, toJSON)\n * are automatically filtered out to prevent accidental overwriting of class methods.\n *\n * @param fields - Object containing custom fields to add to the error\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"CANNOT_ACTIVATE\");\n * err.setAdditionalFields({\n * userId: \"123\",\n * attemptedRoute: \"/admin\",\n * reason: \"insufficient permissions\"\n * });\n *\n * console.log(err.userId); // \"123\"\n * console.log(JSON.stringify(err)); // includes all custom fields\n * ```\n */\n setAdditionalFields(fields: Record<string, unknown>): void {\n // Assign fields, throwing for reserved properties, silently ignoring methods\n for (const [key, value] of objectEntries(fields)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError.setAdditionalFields] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped, and `putField` rather than assignment, for the\n // reasons the constructor's own field loop states (#1852). Not restated\n // here — one mechanism, one explanation.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Checks if a custom field exists on the error object.\n *\n * This method checks for both custom fields added via setAdditionalFields()\n * and built-in fields (code, message, segment, etc.).\n *\n * @param key - The field name to check\n * @returns `true` if the field exists, `false` otherwise\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * segment: \"users\",\n * path: \"/users/7\",\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * err.hasField(\"code\"); // true\n * err.hasField(\"segment\"); // true\n * err.hasField(\"path\"); // true\n * err.hasField(\"userId\"); // true\n * err.hasField(\"unknown\"); // false\n * ```\n */\n hasField(key: string): boolean {\n // ⚑ `hasOwn`, not `in` (#1829). `in` walks the prototype chain, so this\n // answered `true` for `Object.prototype`'s twelve members and for the\n // class's own six methods — eighteen names for an error carrying ONE field\n // and `toString` / `constructor` are ordinary strings arriving from a config\n // key, a route param name or a serialized payload.\n //\n // ⚠ NOT `toJSON`'s `excludeKeys`, which the issue proposed. Measured against\n // the docstring above: that set excludes `code`, `segment` and `path`,\n // which this method documents as answering `true`. The two functions ask\n // different questions (what to SERIALIZE vs what the error CARRIES), so\n // agreeing on those three is the contract and diverging on `message` /\n // `stack` / `name` is not drift.\n return hasOwn(this, key);\n }\n\n /**\n * Retrieves a custom field value from the error object.\n *\n * This method can access both custom fields and built-in fields.\n * Returns `undefined` if the field doesn't exist.\n *\n * @param key - The field name to retrieve\n * @returns The field value, or `undefined` if it doesn't exist\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\");\n * err.setAdditionalFields({ userId: \"123\", role: \"admin\" });\n *\n * err.getField(\"userId\"); // \"123\"\n * err.getField(\"role\"); // \"admin\"\n * err.getField(\"code\"); // \"ERR\" (built-in field)\n * err.getField(\"unknown\"); // undefined\n * ```\n */\n getField(key: string): unknown {\n // Reachable without `hasField` — a consumer may just read — so the same gate\n // stands here rather than being implied by the predicate (#1829). Before\n // this, `getField(\"toString\")` handed back the native function.\n return hasOwn(this, key) ? this[key] : undefined;\n }\n\n /**\n * Serializes the error to a JSON-compatible object.\n *\n * This method is automatically called by JSON.stringify() and includes:\n * - Built-in fields: code, message, segment (if set), path (if set)\n * - All custom fields added via setAdditionalFields() or constructor\n * - Excludes: stack trace (for security/cleanliness)\n *\n * @returns A plain object representation of the error, suitable for JSON serialization\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * message: \"Route not found\",\n * path: \"/admin/users/123\"\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * JSON.stringify(err);\n * // {\n * // \"code\": \"ROUTE_NOT_FOUND\",\n * // \"message\": \"Route not found\",\n * // \"path\": \"/admin/users/123\",\n * // \"userId\": \"123\"\n * // }\n * ```\n */\n toJSON(): Record<string, unknown> {\n const result: Record<string, unknown> = {\n code: this.code,\n message: this.message,\n };\n\n if (this.segment !== undefined) {\n result.segment = this.segment;\n }\n if (this.path !== undefined) {\n result.path = this.path;\n }\n\n // add all public fields\n // Using Set.has() for O(1) lookup instead of Array.includes() O(n)\n // Overall complexity: O(n) instead of O(n*m)\n const excludeKeys = new Set([\n \"code\",\n \"message\",\n \"segment\",\n \"path\",\n \"stack\",\n // `name` is now an own enumerable prop (constructor sets it to\n // \"RouterError\"); it's class metadata, not a custom field — keep it out of\n // the serialized output (preserves toJSON shape).\n \"name\",\n ]);\n\n for (const key in this) {\n if (hasOwn(this, key) && !excludeKeys.has(key)) {\n // ⚑ `putField` (#1852): `result` is a fresh literal and the keys are the\n // user's own error fields. Measured, a setter under one of them made the\n // field vanish from the serialized output with no error at all.\n putField(result, key, this[key]);\n }\n }\n\n return result;\n }\n}\n"],"mappings":"wCAMM,EAAS,OAAO,OAEhB,EAAgB,OAAO,QACvB,EAAe,OAAO,OAUtB,EAAS,OAAO,OAEhB,EAAkB,IAAI,IAAI,EAAaA,EAAAA,CAAU,CAAC,EAGlD,EAAqB,IAAI,IAAI,CAAC,OAAQ,UAAW,MAAM,CAAC,EAGxD,EAAkB,IAAI,IAAI,CAC9B,UACA,mBACA,sBACA,WACA,WACA,QACF,CAAC,EAoBD,SAAgB,EAAyC,EAAa,CACpE,OAAO,EAAO,CAAK,CACrB,CAEA,IAAa,EAAb,cAAiC,KAAM,CAKrC,QACA,KAIA,KA+BA,YACE,EACA,CACE,UACA,UACA,OACA,GAAG,GAMD,CAAC,EACL,CACA,MAAM,GAAW,CAAI,EAKrB,KAAK,KAAO,cAEZ,KAAK,KAAO,EACZ,KAAK,QAAU,EACf,KAAK,KAAO,EAIZ,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAI,EAAG,CAC9C,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,+CAA+C,EAAI,EACrD,EAcE,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAA,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAuBA,QAAQ,EAAuB,CAC7B,KAAK,KAAO,EAGR,EAAgB,IAAI,KAAK,OAAO,IAClC,KAAK,QAAU,EAEnB,CAsBA,iBAAiB,EAAkB,CAEjC,GAAI,CAAC,EACH,MAAU,UACR,wFACF,EAGF,KAAK,QAAU,EAAI,QACnB,KAAK,MAAQ,EAAI,MACjB,KAAK,MAAQ,EAAI,OAAS,EAC5B,CA0BA,oBAAoB,EAAuC,CAEzD,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAM,EAAG,CAChD,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,mEAAmE,EAAI,EACzE,EAME,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAA,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CA0BA,SAAS,EAAsB,CAa7B,OAAO,EAAO,KAAM,CAAG,CACzB,CAsBA,SAAS,EAAsB,CAI7B,OAAO,EAAO,KAAM,CAAG,EAAI,KAAK,GAAO,IAAA,EACzC,CA6BA,QAAkC,CAChC,IAAM,EAAkC,CACtC,KAAM,KAAK,KACX,QAAS,KAAK,OAChB,EAEI,KAAK,UAAY,IAAA,KACnB,EAAO,QAAU,KAAK,SAEpB,KAAK,OAAS,IAAA,KAChB,EAAO,KAAO,KAAK,MAMrB,IAAM,EAAc,IAAI,IAAI,CAC1B,OACA,UACA,UACA,OACA,QAIA,MACF,CAAC,EAED,IAAK,IAAM,KAAO,KACZ,EAAO,KAAM,CAAG,GAAK,CAAC,EAAY,IAAI,CAAG,GAI3C,EAAA,EAAS,EAAQ,EAAK,KAAK,EAAI,EAInC,OAAO,CACT,CACF"}
@@ -137,11 +137,16 @@ declare class RouterError extends Error {
137
137
  *
138
138
  * @example
139
139
  * ```typescript
140
- * const err = new RouterError("ERR", { segment: "users" });
140
+ * const err = new RouterError("ROUTE_NOT_FOUND", {
141
+ * segment: "users",
142
+ * path: "/users/7",
143
+ * });
141
144
  * err.setAdditionalFields({ userId: "123" });
142
145
  *
143
- * err.hasField("userId"); // true
146
+ * err.hasField("code"); // true
144
147
  * err.hasField("segment"); // true
148
+ * err.hasField("path"); // true
149
+ * err.hasField("userId"); // true
145
150
  * err.hasField("unknown"); // false
146
151
  * ```
147
152
  */
@@ -1 +1 @@
1
- {"version":3,"file":"RouterError.d.ts","names":[],"sources":["../../src/RouterError.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAsDgB,kBAAkB,UAAU,aAAa,OAAO,IAAI;cAIvD,oBAAoB;GAC9B;WAIQ;WACA;EAIT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCE,YAAA,gBAEE,SACA,SACA,SACG;KAEF;IACD;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;EAoEJ,QAAQ;;;;;;;;;;;;;;;;;;;;;EA6BR,iBAAiB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtB,oBAAoB,QAAQ;;;;;;;;;;;;;;;;;;;;EA4C5B,SAAS;;;;;;;;;;;;;;;;;;;;;EAoCT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCT,UAAU"}
1
+ {"version":3,"file":"RouterError.d.ts","names":[],"sources":["../../src/RouterError.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAsDgB,kBAAkB,UAAU,aAAa,OAAO,IAAI;cAIvD,oBAAoB;GAC9B;WAIQ;WACA;EAIT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCE,YAAA,gBAEE,SACA,SACA,SACG;KAEF;IACD;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;EAoEJ,QAAQ;;;;;;;;;;;;;;;;;;;;;EA6BR,iBAAiB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtB,oBAAoB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;EAiD5B,SAAS;;;;;;;;;;;;;;;;;;;;;EAoCT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCT,UAAU"}
@@ -1 +1 @@
1
- {"version":3,"file":"RouterError-iSQqAez7.mjs","names":[],"sources":["../../src/RouterError.ts"],"sourcesContent":["// packages/core/src/RouterError.ts\n\nimport { errorCodes, UNSAFE_KEY } from \"./constants\";\nimport { putField } from \"./utils/ingest\";\n\n/** Captured like the deciding seven, but this one BUILDS the guarantee (#2073). */\nconst freeze = Object.freeze;\n\nconst objectEntries = Object.entries;\nconst objectValues = Object.values;\n\n// Pre-compute Set of error code values for O(1) lookup in setCode()\n// This avoids creating array and doing linear search on every setCode() call\n// ⚑ Captured at module load, for the reason `helpers.ts` states over its own\n// three: an application can re-point `Object.hasOwn` after boot, and this one\n// gates a PUBLIC read (#1829). ⚠ The file's four other intrinsic reads are still\n// raw — #1971 owns that sweep, and a point fix here would be the N+1 it exists\n// to prevent; capturing the read this commit ADDS is not the same thing as\n// sweeping the ones it found.\nconst hasOwn = Object.hasOwn;\n\nconst errorCodeValues = new Set(objectValues(errorCodes));\n\n// Reserved built-in properties - throw error if user tries to set these\nconst reservedProperties = new Set([\"code\", \"segment\", \"path\"]);\n\n// Reserved method names - silently ignore attempts to overwrite these\nconst reservedMethods = new Set([\n \"setCode\",\n \"setErrorInstance\",\n \"setAdditionalFields\",\n \"hasField\",\n \"getField\",\n \"toJSON\",\n]);\n\n/**\n * Freeze a `RouterError` at the moment it stops being core's to change — the\n * throw (#1960).\n *\n * ⚑ At the THROW, never in the constructor. `RouterError` publishes three\n * mutators (`setCode`, `setErrorInstance`, `setAdditionalFields`) with worked\n * examples in the wiki, and `rethrowAsRouterError` copies an error and re-codes\n * the copy before throwing it. Freezing on construction was measured: it reds\n * across the tier and concentrates in this class's own suite, because it\n * withdraws published API from errors a CONSUMER builds. Freezing here\n * withdraws exactly one thing — writing to an error core threw at you — which\n * #1606 already established is corruption when the instance is one of the\n * cached, process-shared ones, and which a repository-wide sweep of every\n * `catch` binding found nobody doing.\n *\n * ⚠ Only for errors core CONSTRUCTED. A re-thrown foreign error stays untouched:\n * freezing someone else's object on the way through is the hazard, not the fix.\n */\nexport function freezeThrownError<E extends RouterError>(error: E): E {\n return freeze(error);\n}\n\nexport class RouterError extends Error {\n [key: string]: unknown;\n\n // Using public properties to ensure structural compatibility\n // with the `RouterError` interface in `types/base.ts`\n readonly segment: string | undefined;\n readonly path: string | undefined;\n\n // Note: code appears to be writable but setCode() should be used\n // to properly update both code and message together\n code: string;\n\n /**\n * Creates a new RouterError instance.\n *\n * The options object accepts built-in fields (message, segment, path)\n * and any additional custom fields, which will all be attached to the error instance.\n *\n * @param code - The error code (e.g., \"ROUTE_NOT_FOUND\", \"CANNOT_ACTIVATE\")\n * @param options - Optional configuration object\n * @param options.message - Custom error message (defaults to code if not provided)\n * @param options.segment - The route segment where the error occurred\n * @param options.path - The full path where the error occurred\n *\n * @example\n * ```typescript\n * // Basic error\n * const err1 = new RouterError(\"ROUTE_NOT_FOUND\");\n *\n * // Error with custom message\n * const err2 = new RouterError(\"ERR\", { message: \"Something went wrong\" });\n *\n * // Error with context and custom fields\n * const err3 = new RouterError(\"CANNOT_ACTIVATE\", {\n * message: \"Insufficient permissions\",\n * segment: \"admin\",\n * path: \"/admin/users\",\n * userId: \"123\" // custom field\n * });\n * ```\n */\n constructor(\n code: string,\n {\n message,\n segment,\n path,\n ...rest\n }: {\n [key: string]: unknown;\n message?: string | undefined;\n segment?: string | undefined;\n path?: string | undefined;\n } = {},\n ) {\n super(message ?? code);\n\n // Subclasses don't auto-set `name`; without this `error.name` inherits\n // \"Error\", breaking `error.name === \"RouterError\"` checks at catch sites that\n // can't `instanceof` across bundle boundaries.\n this.name = \"RouterError\";\n\n this.code = code;\n this.segment = segment;\n this.path = path;\n\n // Assign custom fields, checking reserved properties and filtering out reserved method names\n // Issue #39: Throw for reserved properties to match setAdditionalFields behavior\n for (const [key, value] of objectEntries(rest)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped for the reason the state channels give (#1852):\n // this instance is a container core hands out and `toJSON` serializes, so\n // an own `\"__proto__\"` on it is a prototype-swap primitive for whoever\n // merges or re-parses the error — measured, a guard throwing a plain\n // object put the key into `JSON.stringify(err)`.\n //\n // ⚠ Plain assignment is the alternative that looks equivalent and is\n // worse than losing the key: measured, `new RouterError(\"X\", bag)` swaps\n // the INSTANCE's prototype and `instanceof RouterError` answers `false`.\n // `putField` keeps the instance intact; the skip keeps the key off a\n // container someone will merge.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Updates the error code and conditionally updates the message.\n *\n * If the current message is one of the standard error code values\n * (e.g., \"ROUTE_NOT_FOUND\", \"SAME_STATES\"), it will be replaced with the new code.\n * This allows keeping error messages in sync with codes when using standard error codes.\n *\n * If the message is custom (not a standard error code), it will be preserved.\n *\n * @param newCode - The new error code to set\n *\n * @example\n * // Message follows code (standard error code as message)\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", { message: \"ROUTE_NOT_FOUND\" });\n * err.setCode(\"CUSTOM_ERROR\"); // message becomes \"CUSTOM_ERROR\"\n *\n * @example\n * // Custom message is preserved\n * const err = new RouterError(\"ERR\", { message: \"Custom error message\" });\n * err.setCode(\"NEW_CODE\"); // message stays \"Custom error message\"\n */\n setCode(newCode: string): void {\n this.code = newCode;\n\n // Only update message if it's a standard error code value (not a custom message)\n if (errorCodeValues.has(this.message)) {\n this.message = newCode;\n }\n }\n\n /**\n * Copies properties from another Error instance to this RouterError.\n *\n * This method updates the message, cause, and stack trace from the provided error.\n * Useful for wrapping native errors while preserving error context.\n *\n * @param err - The Error instance to copy properties from\n * @throws {TypeError} If err is null or undefined\n *\n * @example\n * ```typescript\n * const routerErr = new RouterError(\"TRANSITION_ERR\");\n * try {\n * // some operation that might fail\n * } catch (nativeErr) {\n * routerErr.setErrorInstance(nativeErr);\n * throw routerErr;\n * }\n * ```\n */\n setErrorInstance(err: Error): void {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!err) {\n throw new TypeError(\n \"[RouterError.setErrorInstance] err parameter is required and must be an Error instance\",\n );\n }\n\n this.message = err.message;\n this.cause = err.cause;\n this.stack = err.stack ?? \"\";\n }\n\n /**\n * Adds custom fields to the error object.\n *\n * This method allows attaching arbitrary data to the error for debugging or logging purposes.\n * All fields become accessible as properties on the error instance and are included in JSON serialization.\n *\n * Reserved method names (setCode, setErrorInstance, setAdditionalFields, hasField, getField, toJSON)\n * are automatically filtered out to prevent accidental overwriting of class methods.\n *\n * @param fields - Object containing custom fields to add to the error\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"CANNOT_ACTIVATE\");\n * err.setAdditionalFields({\n * userId: \"123\",\n * attemptedRoute: \"/admin\",\n * reason: \"insufficient permissions\"\n * });\n *\n * console.log(err.userId); // \"123\"\n * console.log(JSON.stringify(err)); // includes all custom fields\n * ```\n */\n setAdditionalFields(fields: Record<string, unknown>): void {\n // Assign fields, throwing for reserved properties, silently ignoring methods\n for (const [key, value] of objectEntries(fields)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError.setAdditionalFields] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped, and `putField` rather than assignment, for the\n // reasons the constructor's own field loop states (#1852). Not restated\n // here — one mechanism, one explanation.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Checks if a custom field exists on the error object.\n *\n * This method checks for both custom fields added via setAdditionalFields()\n * and built-in fields (code, message, segment, etc.).\n *\n * @param key - The field name to check\n * @returns `true` if the field exists, `false` otherwise\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\", { segment: \"users\" });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * err.hasField(\"userId\"); // true\n * err.hasField(\"segment\"); // true\n * err.hasField(\"unknown\"); // false\n * ```\n */\n hasField(key: string): boolean {\n // ⚑ `hasOwn`, not `in` (#1829). `in` walks the prototype chain, so this\n // answered `true` for `Object.prototype`'s twelve members and for the\n // class's own six methods — eighteen names for an error carrying ONE field\n // and `toString` / `constructor` are ordinary strings arriving from a config\n // key, a route param name or a serialized payload.\n //\n // ⚠ NOT `toJSON`'s `excludeKeys`, which the issue proposed. Measured against\n // the docstring above: that set excludes `code`, `segment` and `path`,\n // which this method documents as answering `true`. The two functions ask\n // different questions (what to SERIALIZE vs what the error CARRIES), so\n // agreeing on those three is the contract and diverging on `message` /\n // `stack` / `name` is not drift.\n return hasOwn(this, key);\n }\n\n /**\n * Retrieves a custom field value from the error object.\n *\n * This method can access both custom fields and built-in fields.\n * Returns `undefined` if the field doesn't exist.\n *\n * @param key - The field name to retrieve\n * @returns The field value, or `undefined` if it doesn't exist\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\");\n * err.setAdditionalFields({ userId: \"123\", role: \"admin\" });\n *\n * err.getField(\"userId\"); // \"123\"\n * err.getField(\"role\"); // \"admin\"\n * err.getField(\"code\"); // \"ERR\" (built-in field)\n * err.getField(\"unknown\"); // undefined\n * ```\n */\n getField(key: string): unknown {\n // Reachable without `hasField` — a consumer may just read — so the same gate\n // stands here rather than being implied by the predicate (#1829). Before\n // this, `getField(\"toString\")` handed back the native function.\n return hasOwn(this, key) ? this[key] : undefined;\n }\n\n /**\n * Serializes the error to a JSON-compatible object.\n *\n * This method is automatically called by JSON.stringify() and includes:\n * - Built-in fields: code, message, segment (if set), path (if set)\n * - All custom fields added via setAdditionalFields() or constructor\n * - Excludes: stack trace (for security/cleanliness)\n *\n * @returns A plain object representation of the error, suitable for JSON serialization\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * message: \"Route not found\",\n * path: \"/admin/users/123\"\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * JSON.stringify(err);\n * // {\n * // \"code\": \"ROUTE_NOT_FOUND\",\n * // \"message\": \"Route not found\",\n * // \"path\": \"/admin/users/123\",\n * // \"userId\": \"123\"\n * // }\n * ```\n */\n toJSON(): Record<string, unknown> {\n const result: Record<string, unknown> = {\n code: this.code,\n message: this.message,\n };\n\n if (this.segment !== undefined) {\n result.segment = this.segment;\n }\n if (this.path !== undefined) {\n result.path = this.path;\n }\n\n // add all public fields\n // Using Set.has() for O(1) lookup instead of Array.includes() O(n)\n // Overall complexity: O(n) instead of O(n*m)\n const excludeKeys = new Set([\n \"code\",\n \"message\",\n \"segment\",\n \"path\",\n \"stack\",\n // `name` is now an own enumerable prop (constructor sets it to\n // \"RouterError\"); it's class metadata, not a custom field — keep it out of\n // the serialized output (preserves toJSON shape).\n \"name\",\n ]);\n\n for (const key in this) {\n if (hasOwn(this, key) && !excludeKeys.has(key)) {\n // ⚑ `putField` (#1852): `result` is a fresh literal and the keys are the\n // user's own error fields. Measured, a setter under one of them made the\n // field vanish from the serialized output with no error at all.\n putField(result, key, this[key]);\n }\n }\n\n return result;\n }\n}\n"],"mappings":"iDAMA,MAAM,EAAS,OAAO,OAEhB,EAAgB,OAAO,QACvB,EAAe,OAAO,OAUtB,EAAS,OAAO,OAEhB,EAAkB,IAAI,IAAI,EAAa,CAAU,CAAC,EAGlD,EAAqB,IAAI,IAAI,CAAC,OAAQ,UAAW,MAAM,CAAC,EAGxD,EAAkB,IAAI,IAAI,CAC9B,UACA,mBACA,sBACA,WACA,WACA,QACF,CAAC,EAoBD,SAAgB,EAAyC,EAAa,CACpE,OAAO,EAAO,CAAK,CACrB,CAEA,IAAa,EAAb,cAAiC,KAAM,CAKrC,QACA,KAIA,KA+BA,YACE,EACA,CACE,UACA,UACA,OACA,GAAG,GAMD,CAAC,EACL,CACA,MAAM,GAAW,CAAI,EAKrB,KAAK,KAAO,cAEZ,KAAK,KAAO,EACZ,KAAK,QAAU,EACf,KAAK,KAAO,EAIZ,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAI,EAAG,CAC9C,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,+CAA+C,EAAI,EACrD,EAcE,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAuBA,QAAQ,EAAuB,CAC7B,KAAK,KAAO,EAGR,EAAgB,IAAI,KAAK,OAAO,IAClC,KAAK,QAAU,EAEnB,CAsBA,iBAAiB,EAAkB,CAEjC,GAAI,CAAC,EACH,MAAU,UACR,wFACF,EAGF,KAAK,QAAU,EAAI,QACnB,KAAK,MAAQ,EAAI,MACjB,KAAK,MAAQ,EAAI,OAAS,EAC5B,CA0BA,oBAAoB,EAAuC,CAEzD,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAM,EAAG,CAChD,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,mEAAmE,EAAI,EACzE,EAME,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAqBA,SAAS,EAAsB,CAa7B,OAAO,EAAO,KAAM,CAAG,CACzB,CAsBA,SAAS,EAAsB,CAI7B,OAAO,EAAO,KAAM,CAAG,EAAI,KAAK,GAAO,IAAA,EACzC,CA6BA,QAAkC,CAChC,IAAM,EAAkC,CACtC,KAAM,KAAK,KACX,QAAS,KAAK,OAChB,EAEI,KAAK,UAAY,IAAA,KACnB,EAAO,QAAU,KAAK,SAEpB,KAAK,OAAS,IAAA,KAChB,EAAO,KAAO,KAAK,MAMrB,IAAM,EAAc,IAAI,IAAI,CAC1B,OACA,UACA,UACA,OACA,QAIA,MACF,CAAC,EAED,IAAK,IAAM,KAAO,KACZ,EAAO,KAAM,CAAG,GAAK,CAAC,EAAY,IAAI,CAAG,GAI3C,EAAS,EAAQ,EAAK,KAAK,EAAI,EAInC,OAAO,CACT,CACF"}
1
+ {"version":3,"file":"RouterError-iSQqAez7.mjs","names":[],"sources":["../../src/RouterError.ts"],"sourcesContent":["// packages/core/src/RouterError.ts\n\nimport { errorCodes, UNSAFE_KEY } from \"./constants\";\nimport { putField } from \"./utils/ingest\";\n\n/** Captured like the deciding seven, but this one BUILDS the guarantee (#2073). */\nconst freeze = Object.freeze;\n\nconst objectEntries = Object.entries;\nconst objectValues = Object.values;\n\n// Pre-compute Set of error code values for O(1) lookup in setCode()\n// This avoids creating array and doing linear search on every setCode() call\n// ⚑ Captured at module load, for the reason `helpers.ts` states over its own\n// three: an application can re-point `Object.hasOwn` after boot, and this one\n// gates a PUBLIC read (#1829). ⚠ The file's four other intrinsic reads are still\n// raw — #1971 owns that sweep, and a point fix here would be the N+1 it exists\n// to prevent; capturing the read this commit ADDS is not the same thing as\n// sweeping the ones it found.\nconst hasOwn = Object.hasOwn;\n\nconst errorCodeValues = new Set(objectValues(errorCodes));\n\n// Reserved built-in properties - throw error if user tries to set these\nconst reservedProperties = new Set([\"code\", \"segment\", \"path\"]);\n\n// Reserved method names - silently ignore attempts to overwrite these\nconst reservedMethods = new Set([\n \"setCode\",\n \"setErrorInstance\",\n \"setAdditionalFields\",\n \"hasField\",\n \"getField\",\n \"toJSON\",\n]);\n\n/**\n * Freeze a `RouterError` at the moment it stops being core's to change — the\n * throw (#1960).\n *\n * ⚑ At the THROW, never in the constructor. `RouterError` publishes three\n * mutators (`setCode`, `setErrorInstance`, `setAdditionalFields`) with worked\n * examples in the wiki, and `rethrowAsRouterError` copies an error and re-codes\n * the copy before throwing it. Freezing on construction was measured: it reds\n * across the tier and concentrates in this class's own suite, because it\n * withdraws published API from errors a CONSUMER builds. Freezing here\n * withdraws exactly one thing — writing to an error core threw at you — which\n * #1606 already established is corruption when the instance is one of the\n * cached, process-shared ones, and which a repository-wide sweep of every\n * `catch` binding found nobody doing.\n *\n * ⚠ Only for errors core CONSTRUCTED. A re-thrown foreign error stays untouched:\n * freezing someone else's object on the way through is the hazard, not the fix.\n */\nexport function freezeThrownError<E extends RouterError>(error: E): E {\n return freeze(error);\n}\n\nexport class RouterError extends Error {\n [key: string]: unknown;\n\n // Using public properties to ensure structural compatibility\n // with the `RouterError` interface in `types/base.ts`\n readonly segment: string | undefined;\n readonly path: string | undefined;\n\n // Note: code appears to be writable but setCode() should be used\n // to properly update both code and message together\n code: string;\n\n /**\n * Creates a new RouterError instance.\n *\n * The options object accepts built-in fields (message, segment, path)\n * and any additional custom fields, which will all be attached to the error instance.\n *\n * @param code - The error code (e.g., \"ROUTE_NOT_FOUND\", \"CANNOT_ACTIVATE\")\n * @param options - Optional configuration object\n * @param options.message - Custom error message (defaults to code if not provided)\n * @param options.segment - The route segment where the error occurred\n * @param options.path - The full path where the error occurred\n *\n * @example\n * ```typescript\n * // Basic error\n * const err1 = new RouterError(\"ROUTE_NOT_FOUND\");\n *\n * // Error with custom message\n * const err2 = new RouterError(\"ERR\", { message: \"Something went wrong\" });\n *\n * // Error with context and custom fields\n * const err3 = new RouterError(\"CANNOT_ACTIVATE\", {\n * message: \"Insufficient permissions\",\n * segment: \"admin\",\n * path: \"/admin/users\",\n * userId: \"123\" // custom field\n * });\n * ```\n */\n constructor(\n code: string,\n {\n message,\n segment,\n path,\n ...rest\n }: {\n [key: string]: unknown;\n message?: string | undefined;\n segment?: string | undefined;\n path?: string | undefined;\n } = {},\n ) {\n super(message ?? code);\n\n // Subclasses don't auto-set `name`; without this `error.name` inherits\n // \"Error\", breaking `error.name === \"RouterError\"` checks at catch sites that\n // can't `instanceof` across bundle boundaries.\n this.name = \"RouterError\";\n\n this.code = code;\n this.segment = segment;\n this.path = path;\n\n // Assign custom fields, checking reserved properties and filtering out reserved method names\n // Issue #39: Throw for reserved properties to match setAdditionalFields behavior\n for (const [key, value] of objectEntries(rest)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped for the reason the state channels give (#1852):\n // this instance is a container core hands out and `toJSON` serializes, so\n // an own `\"__proto__\"` on it is a prototype-swap primitive for whoever\n // merges or re-parses the error — measured, a guard throwing a plain\n // object put the key into `JSON.stringify(err)`.\n //\n // ⚠ Plain assignment is the alternative that looks equivalent and is\n // worse than losing the key: measured, `new RouterError(\"X\", bag)` swaps\n // the INSTANCE's prototype and `instanceof RouterError` answers `false`.\n // `putField` keeps the instance intact; the skip keeps the key off a\n // container someone will merge.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Updates the error code and conditionally updates the message.\n *\n * If the current message is one of the standard error code values\n * (e.g., \"ROUTE_NOT_FOUND\", \"SAME_STATES\"), it will be replaced with the new code.\n * This allows keeping error messages in sync with codes when using standard error codes.\n *\n * If the message is custom (not a standard error code), it will be preserved.\n *\n * @param newCode - The new error code to set\n *\n * @example\n * // Message follows code (standard error code as message)\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", { message: \"ROUTE_NOT_FOUND\" });\n * err.setCode(\"CUSTOM_ERROR\"); // message becomes \"CUSTOM_ERROR\"\n *\n * @example\n * // Custom message is preserved\n * const err = new RouterError(\"ERR\", { message: \"Custom error message\" });\n * err.setCode(\"NEW_CODE\"); // message stays \"Custom error message\"\n */\n setCode(newCode: string): void {\n this.code = newCode;\n\n // Only update message if it's a standard error code value (not a custom message)\n if (errorCodeValues.has(this.message)) {\n this.message = newCode;\n }\n }\n\n /**\n * Copies properties from another Error instance to this RouterError.\n *\n * This method updates the message, cause, and stack trace from the provided error.\n * Useful for wrapping native errors while preserving error context.\n *\n * @param err - The Error instance to copy properties from\n * @throws {TypeError} If err is null or undefined\n *\n * @example\n * ```typescript\n * const routerErr = new RouterError(\"TRANSITION_ERR\");\n * try {\n * // some operation that might fail\n * } catch (nativeErr) {\n * routerErr.setErrorInstance(nativeErr);\n * throw routerErr;\n * }\n * ```\n */\n setErrorInstance(err: Error): void {\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!err) {\n throw new TypeError(\n \"[RouterError.setErrorInstance] err parameter is required and must be an Error instance\",\n );\n }\n\n this.message = err.message;\n this.cause = err.cause;\n this.stack = err.stack ?? \"\";\n }\n\n /**\n * Adds custom fields to the error object.\n *\n * This method allows attaching arbitrary data to the error for debugging or logging purposes.\n * All fields become accessible as properties on the error instance and are included in JSON serialization.\n *\n * Reserved method names (setCode, setErrorInstance, setAdditionalFields, hasField, getField, toJSON)\n * are automatically filtered out to prevent accidental overwriting of class methods.\n *\n * @param fields - Object containing custom fields to add to the error\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"CANNOT_ACTIVATE\");\n * err.setAdditionalFields({\n * userId: \"123\",\n * attemptedRoute: \"/admin\",\n * reason: \"insufficient permissions\"\n * });\n *\n * console.log(err.userId); // \"123\"\n * console.log(JSON.stringify(err)); // includes all custom fields\n * ```\n */\n setAdditionalFields(fields: Record<string, unknown>): void {\n // Assign fields, throwing for reserved properties, silently ignoring methods\n for (const [key, value] of objectEntries(fields)) {\n if (reservedProperties.has(key)) {\n throw new TypeError(\n `[RouterError.setAdditionalFields] Cannot set reserved property \"${key}\"`,\n );\n }\n\n // ⚑ `UNSAFE_KEY` skipped, and `putField` rather than assignment, for the\n // reasons the constructor's own field loop states (#1852). Not restated\n // here — one mechanism, one explanation.\n if (key !== UNSAFE_KEY && !reservedMethods.has(key)) {\n // ⚑ `putField` (#1852). The target is `this`, whose chain runs\n // `RouterError.prototype → Error.prototype → Object.prototype`, and the\n // key comes from the caller's bag. `reservedProperties` / `reservedMethods`\n // above filter by NAME and therefore cannot see an ambient one: measured,\n // an accessor under a custom field name threw out of the constructor,\n // and a setter left the field non-own while reading back the hijacked\n // value.\n putField(this as unknown as Record<string, unknown>, key, value);\n }\n }\n }\n\n /**\n * Checks if a custom field exists on the error object.\n *\n * This method checks for both custom fields added via setAdditionalFields()\n * and built-in fields (code, message, segment, etc.).\n *\n * @param key - The field name to check\n * @returns `true` if the field exists, `false` otherwise\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * segment: \"users\",\n * path: \"/users/7\",\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * err.hasField(\"code\"); // true\n * err.hasField(\"segment\"); // true\n * err.hasField(\"path\"); // true\n * err.hasField(\"userId\"); // true\n * err.hasField(\"unknown\"); // false\n * ```\n */\n hasField(key: string): boolean {\n // ⚑ `hasOwn`, not `in` (#1829). `in` walks the prototype chain, so this\n // answered `true` for `Object.prototype`'s twelve members and for the\n // class's own six methods — eighteen names for an error carrying ONE field\n // and `toString` / `constructor` are ordinary strings arriving from a config\n // key, a route param name or a serialized payload.\n //\n // ⚠ NOT `toJSON`'s `excludeKeys`, which the issue proposed. Measured against\n // the docstring above: that set excludes `code`, `segment` and `path`,\n // which this method documents as answering `true`. The two functions ask\n // different questions (what to SERIALIZE vs what the error CARRIES), so\n // agreeing on those three is the contract and diverging on `message` /\n // `stack` / `name` is not drift.\n return hasOwn(this, key);\n }\n\n /**\n * Retrieves a custom field value from the error object.\n *\n * This method can access both custom fields and built-in fields.\n * Returns `undefined` if the field doesn't exist.\n *\n * @param key - The field name to retrieve\n * @returns The field value, or `undefined` if it doesn't exist\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ERR\");\n * err.setAdditionalFields({ userId: \"123\", role: \"admin\" });\n *\n * err.getField(\"userId\"); // \"123\"\n * err.getField(\"role\"); // \"admin\"\n * err.getField(\"code\"); // \"ERR\" (built-in field)\n * err.getField(\"unknown\"); // undefined\n * ```\n */\n getField(key: string): unknown {\n // Reachable without `hasField` — a consumer may just read — so the same gate\n // stands here rather than being implied by the predicate (#1829). Before\n // this, `getField(\"toString\")` handed back the native function.\n return hasOwn(this, key) ? this[key] : undefined;\n }\n\n /**\n * Serializes the error to a JSON-compatible object.\n *\n * This method is automatically called by JSON.stringify() and includes:\n * - Built-in fields: code, message, segment (if set), path (if set)\n * - All custom fields added via setAdditionalFields() or constructor\n * - Excludes: stack trace (for security/cleanliness)\n *\n * @returns A plain object representation of the error, suitable for JSON serialization\n *\n * @example\n * ```typescript\n * const err = new RouterError(\"ROUTE_NOT_FOUND\", {\n * message: \"Route not found\",\n * path: \"/admin/users/123\"\n * });\n * err.setAdditionalFields({ userId: \"123\" });\n *\n * JSON.stringify(err);\n * // {\n * // \"code\": \"ROUTE_NOT_FOUND\",\n * // \"message\": \"Route not found\",\n * // \"path\": \"/admin/users/123\",\n * // \"userId\": \"123\"\n * // }\n * ```\n */\n toJSON(): Record<string, unknown> {\n const result: Record<string, unknown> = {\n code: this.code,\n message: this.message,\n };\n\n if (this.segment !== undefined) {\n result.segment = this.segment;\n }\n if (this.path !== undefined) {\n result.path = this.path;\n }\n\n // add all public fields\n // Using Set.has() for O(1) lookup instead of Array.includes() O(n)\n // Overall complexity: O(n) instead of O(n*m)\n const excludeKeys = new Set([\n \"code\",\n \"message\",\n \"segment\",\n \"path\",\n \"stack\",\n // `name` is now an own enumerable prop (constructor sets it to\n // \"RouterError\"); it's class metadata, not a custom field — keep it out of\n // the serialized output (preserves toJSON shape).\n \"name\",\n ]);\n\n for (const key in this) {\n if (hasOwn(this, key) && !excludeKeys.has(key)) {\n // ⚑ `putField` (#1852): `result` is a fresh literal and the keys are the\n // user's own error fields. Measured, a setter under one of them made the\n // field vanish from the serialized output with no error at all.\n putField(result, key, this[key]);\n }\n }\n\n return result;\n }\n}\n"],"mappings":"iDAMA,MAAM,EAAS,OAAO,OAEhB,EAAgB,OAAO,QACvB,EAAe,OAAO,OAUtB,EAAS,OAAO,OAEhB,EAAkB,IAAI,IAAI,EAAa,CAAU,CAAC,EAGlD,EAAqB,IAAI,IAAI,CAAC,OAAQ,UAAW,MAAM,CAAC,EAGxD,EAAkB,IAAI,IAAI,CAC9B,UACA,mBACA,sBACA,WACA,WACA,QACF,CAAC,EAoBD,SAAgB,EAAyC,EAAa,CACpE,OAAO,EAAO,CAAK,CACrB,CAEA,IAAa,EAAb,cAAiC,KAAM,CAKrC,QACA,KAIA,KA+BA,YACE,EACA,CACE,UACA,UACA,OACA,GAAG,GAMD,CAAC,EACL,CACA,MAAM,GAAW,CAAI,EAKrB,KAAK,KAAO,cAEZ,KAAK,KAAO,EACZ,KAAK,QAAU,EACf,KAAK,KAAO,EAIZ,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAI,EAAG,CAC9C,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,+CAA+C,EAAI,EACrD,EAcE,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CAuBA,QAAQ,EAAuB,CAC7B,KAAK,KAAO,EAGR,EAAgB,IAAI,KAAK,OAAO,IAClC,KAAK,QAAU,EAEnB,CAsBA,iBAAiB,EAAkB,CAEjC,GAAI,CAAC,EACH,MAAU,UACR,wFACF,EAGF,KAAK,QAAU,EAAI,QACnB,KAAK,MAAQ,EAAI,MACjB,KAAK,MAAQ,EAAI,OAAS,EAC5B,CA0BA,oBAAoB,EAAuC,CAEzD,IAAK,GAAM,CAAC,EAAK,KAAU,EAAc,CAAM,EAAG,CAChD,GAAI,EAAmB,IAAI,CAAG,EAC5B,MAAU,UACR,mEAAmE,EAAI,EACzE,EAME,IAAA,aAAsB,CAAC,EAAgB,IAAI,CAAG,GAQhD,EAAS,KAA4C,EAAK,CAAK,CAEnE,CACF,CA0BA,SAAS,EAAsB,CAa7B,OAAO,EAAO,KAAM,CAAG,CACzB,CAsBA,SAAS,EAAsB,CAI7B,OAAO,EAAO,KAAM,CAAG,EAAI,KAAK,GAAO,IAAA,EACzC,CA6BA,QAAkC,CAChC,IAAM,EAAkC,CACtC,KAAM,KAAK,KACX,QAAS,KAAK,OAChB,EAEI,KAAK,UAAY,IAAA,KACnB,EAAO,QAAU,KAAK,SAEpB,KAAK,OAAS,IAAA,KAChB,EAAO,KAAO,KAAK,MAMrB,IAAM,EAAc,IAAI,IAAI,CAC1B,OACA,UACA,UACA,OACA,QAIA,MACF,CAAC,EAED,IAAK,IAAM,KAAO,KACZ,EAAO,KAAM,CAAG,GAAK,CAAC,EAAY,IAAI,CAAG,GAI3C,EAAS,EAAQ,EAAK,KAAK,EAAI,EAInC,OAAO,CACT,CACF"}
@@ -137,11 +137,16 @@ declare class RouterError extends Error {
137
137
  *
138
138
  * @example
139
139
  * ```typescript
140
- * const err = new RouterError("ERR", { segment: "users" });
140
+ * const err = new RouterError("ROUTE_NOT_FOUND", {
141
+ * segment: "users",
142
+ * path: "/users/7",
143
+ * });
141
144
  * err.setAdditionalFields({ userId: "123" });
142
145
  *
143
- * err.hasField("userId"); // true
146
+ * err.hasField("code"); // true
144
147
  * err.hasField("segment"); // true
148
+ * err.hasField("path"); // true
149
+ * err.hasField("userId"); // true
145
150
  * err.hasField("unknown"); // false
146
151
  * ```
147
152
  */
@@ -1 +1 @@
1
- {"version":3,"file":"RouterError.d.mts","names":[],"sources":["../../src/RouterError.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAsDgB,kBAAkB,UAAU,aAAa,OAAO,IAAI;cAIvD,oBAAoB;GAC9B;WAIQ;WACA;EAIT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCE,YAAA,gBAEE,SACA,SACA,SACG;KAEF;IACD;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;EAoEJ,QAAQ;;;;;;;;;;;;;;;;;;;;;EA6BR,iBAAiB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtB,oBAAoB,QAAQ;;;;;;;;;;;;;;;;;;;;EA4C5B,SAAS;;;;;;;;;;;;;;;;;;;;;EAoCT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCT,UAAU"}
1
+ {"version":3,"file":"RouterError.d.mts","names":[],"sources":["../../src/RouterError.ts"],"mappings":";;;;;;;;;;;;;;;;;;;iBAsDgB,kBAAkB,UAAU,aAAa,OAAO,IAAI;cAIvD,oBAAoB;GAC9B;WAIQ;WACA;EAIT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgCE,YAAA,gBAEE,SACA,SACA,SACG;KAEF;IACD;IACA;IACA;;;;;;;;;;;;;;;;;;;;;;;EAoEJ,QAAQ;;;;;;;;;;;;;;;;;;;;;EA6BR,iBAAiB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;EAqCtB,oBAAoB,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;EAiD5B,SAAS;;;;;;;;;;;;;;;;;;;;;EAoCT,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkCT,UAAU"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@real-router/core",
3
- "version": "0.126.4",
3
+ "version": "0.126.5",
4
4
  "type": "commonjs",
5
5
  "description": "A simple, powerful, view-agnostic, modular and extensible router",
6
6
  "main": "./dist/cjs/index.js",