@h3ravel/url 1.0.0 → 1.0.1

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.
package/dist/index.cjs CHANGED
@@ -246,8 +246,7 @@ var Url = class Url {
246
246
  const url$1 = this.toString();
247
247
  const queryParams = { ...this._query };
248
248
  if (expiration) queryParams.expires = Math.floor(expiration / 1e3);
249
- const payload = expiration ? `${url$1}?expires=${queryParams.expires}` : url$1;
250
- queryParams.signature = (0, __h3ravel_support.hmac)(payload, key);
249
+ queryParams.signature = (0, __h3ravel_support.hmac)(expiration ? `${url$1}?expires=${queryParams.expires}` : url$1, key);
251
250
  return this.withQuery(queryParams);
252
251
  }
253
252
  /**
@@ -270,8 +269,7 @@ var Url = class Url {
270
269
  try {
271
270
  key = config("app.key", "default-key");
272
271
  } catch {}
273
- const expectedSignature = (0, __h3ravel_support.hmac)(payload, key);
274
- return signature === expectedSignature;
272
+ return signature === (0, __h3ravel_support.hmac)(payload, key);
275
273
  }
276
274
  /**
277
275
  * Convert the URL to its string representation
@@ -400,6 +398,7 @@ function createUrlHelpers(app) {
400
398
  * Service provider for URL utilities
401
399
  */
402
400
  var UrlServiceProvider = class extends __h3ravel_core.ServiceProvider {
401
+ static priority = 897;
403
402
  /**
404
403
  * Register URL services in the container
405
404
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["app: Application","path","url","query: Record<string, unknown>","routes: RouteDefinition[]","route","ConfigException","queryParams: Record<string, unknown>","path","ServiceProvider"],"sources":["../src/RequestAwareHelpers.ts","../src/Url.ts","../src/Helpers.ts","../src/Providers/UrlServiceProvider.ts"],"sourcesContent":["import type { Application } from '@h3ravel/core'\nimport type { IRequest } from '@h3ravel/shared'\nimport { RouteParams } from './Contracts/UrlContract'\n\n/**\n * Request-aware URL helper class\n */\nexport class RequestAwareHelpers {\n private readonly baseUrl: string = ''\n\n constructor(private app: Application) {\n try {\n this.baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n }\n\n /**\n * Get the current request instance\n */\n private getCurrentRequest (): IRequest {\n const request = this.app.make('http.request')\n if (!request) {\n throw new Error('Request instance not available in current context')\n }\n return request\n }\n\n /**\n * Get the current request URL (path only, no query string)\n */\n current (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the path from the request\n const raw = event.req.url ?? '/'\n const url = new URL(raw, 'http://localhost')\n return url.pathname\n }\n\n /**\n * Get the full current URL with query string\n */\n full (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the full URL including query string\n const requestUrl = event.req.url ?? '/'\n\n // If requestUrl is already absolute, use it directly, otherwise combine with baseUrl\n if (requestUrl.startsWith('http')) {\n return requestUrl\n }\n\n const fullUrl = new URL(requestUrl, this.baseUrl)\n return fullUrl.toString()\n }\n\n /**\n * Get the previous request URL from session or referrer\n */\n previous (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Try to get from session first (if session is available)\n // For now, fallback to HTTP referrer header\n const headers = (event as any)?.node?.req?.headers as Record<string, string | string[] | undefined> | undefined\n // console.log(headers)\n let referrer = headers?.referer ?? headers?.referrer\n if (Array.isArray(referrer)) referrer = referrer[0]\n if (referrer) return referrer\n\n // Fallback to current URL if no referrer\n return this.current()\n }\n\n /**\n * Get the previous request path (without query string)\n */\n previousPath (): string {\n const previousUrl = this.previous()\n\n try {\n const url = new URL(previousUrl)\n return url.pathname\n } catch {\n // If previous URL is not a valid URL, return as-is\n return previousUrl\n }\n }\n\n /**\n * Get the current query parameters\n */\n query (): RouteParams {\n const request = this.getCurrentRequest()\n return request.query || {}\n }\n}\n\n/**\n * Global helper function factory\n */\nexport function createUrlHelper (app: Application): () => RequestAwareHelpers {\n return () => new RequestAwareHelpers(app)\n}\n","import { ConfigException, type Application } from '@h3ravel/core'\nimport { RouteParams } from './Contracts/UrlContract'\nimport { hmac } from '@h3ravel/support'\nimport { RouteDefinition, ExtractControllerMethods } from '@h3ravel/shared'\nimport path from 'node:path'\n\n/**\n * URL builder class with fluent API and request-aware helpers\n */\nexport class Url {\n private readonly _scheme?: string\n private readonly _host?: string\n private readonly _port?: number\n private readonly _path: string\n private readonly _query: Record<string, unknown>\n private readonly _fragment?: string\n private readonly app?: Application\n\n private constructor(\n app?: Application,\n scheme?: string,\n host?: string,\n port?: number,\n path: string = '/',\n query: Record<string, unknown> = {},\n fragment?: string\n ) {\n this.app = app\n this._scheme = scheme\n this._host = host\n this._port = port\n this._path = path.startsWith('/') ? path : `/${path}`\n this._query = { ...query }\n this._fragment = fragment\n }\n\n /**\n * Create a URL from a full URL string\n */\n static of (url: string, app?: Application): Url {\n try {\n const parsed = new URL(url)\n const query: Record<string, unknown> = {}\n\n // Parse query parameters\n parsed.searchParams.forEach((value, key) => {\n query[key] = value\n })\n\n return new Url(\n app,\n parsed.protocol.replace(':', ''),\n parsed.hostname,\n parsed.port ? parseInt(parsed.port) : undefined,\n parsed.pathname || '/',\n query,\n parsed.hash ? parsed.hash.substring(1) : undefined\n )\n } catch {\n throw new Error(`Invalid URL: ${url}`)\n }\n }\n\n /**\n * Create a URL from a path relative to the app URL\n */\n static to (path: string, app?: Application): Url {\n let baseUrl = ''\n try {\n baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n\n const fullUrl = new URL(path, baseUrl).toString()\n\n return Url.of(fullUrl, app)\n }\n\n /**\n * Create a URL from a named route\n */\n // Route parameter map (declaration-mergeable by consumers)\n static route<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n if (!app) {\n throw new Error('Application instance required for route generation')\n }\n\n // Use (app as any).make to avoid TS error if make is not typed on Application\n const router = app.make('router')\n if (!router || typeof router.route !== 'function') {\n throw new Error('Router not available or does not support route generation')\n }\n\n if (typeof router.route !== 'function') {\n throw new Error('Router does not support route generation')\n }\n\n const routeUrl = router.route(name, params)\n if (!routeUrl) {\n throw new Error(`Route \"${name}\" not found`)\n }\n\n return Url.to(routeUrl, app)\n }\n\n /**\n * Create a signed URL from a named route\n */\n static signedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app)\n }\n\n /**\n * Create a temporary signed URL from a named route\n */\n static temporarySignedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n expiration: number,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app, expiration)\n }\n\n /**\n * Create a URL from a controller action\n */\n static action<C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>,\n app?: Application\n ): Url {\n if (!app) throw new Error('Application instance required for action URL generation')\n\n const [controllerName, methodName = 'index'] = typeof controller === 'string'\n ? controller.split('@')\n : controller\n\n const cname = typeof controllerName === 'string' ? controllerName : controllerName.name\n\n const routes: RouteDefinition[] = app.make('app.routes')\n\n if (!Array.isArray(routes)) {\n // Backward-compatible message expected by existing tests\n throw new Error('Action URL generation requires router integration - not yet implemented')\n }\n\n if (routes.length < 1) throw new Error(`No routes available to resolve action: ${controller}`)\n\n // Search for for the \n const found = routes.find(route => {\n return route.signature?.[0] === cname && (route.signature?.[1] || 'index') === methodName\n })\n\n if (!found) throw new Error(`No route found for ${cname}`)\n\n // Build the route parameters\n const _params = Object.values(params ?? {}).join('/')\n\n if (_params) {\n return Url.to(path.join(found.path, _params))\n }\n\n return Url.to(found.path, app)\n }\n\n /**\n * Set the scheme (protocol) of the URL\n */\n withScheme (scheme: string): Url {\n return new Url(\n this.app,\n scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the host of the URL\n */\n withHost (host: string): Url {\n return new Url(\n this.app,\n this._scheme,\n host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the port of the URL\n */\n withPort (port: number): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the path of the URL\n */\n withPath (path: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the query parameters of the URL\n */\n withQuery (query: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...query },\n this._fragment\n )\n }\n\n /**\n * Merge additional query parameters\n */\n withQueryParams (params: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...this._query, ...params },\n this._fragment\n )\n }\n\n /**\n * Set the fragment (hash) of the URL\n */\n withFragment (fragment: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n fragment\n )\n }\n\n /**\n * Add a signature to the URL for security\n */\n withSignature (app?: Application, expiration?: number): Url {\n const appInstance = app || this.app\n if (!appInstance) {\n throw new Error('Application instance required for URL signing')\n }\n\n let key = ''\n try {\n key = config('app.key')\n } catch {/** */ }\n\n if (!key) {\n throw new ConfigException('APP_KEY and app.key', 'any', this)\n }\n const url = this.toString()\n const queryParams: Record<string, unknown> = { ...this._query }\n\n if (expiration) {\n queryParams.expires = Math.floor(expiration / 1000)\n }\n\n // Create signature payload\n const payload = expiration\n ? `${url}?expires=${queryParams.expires}`\n : url\n\n const signature = hmac(payload, key)\n queryParams.signature = signature\n\n return this.withQuery(queryParams)\n }\n\n /**\n * Verify if a URL signature is valid\n */\n hasValidSignature (app?: Application): boolean {\n const appInstance = app || this.app\n if (!appInstance) {\n return false\n }\n\n const signature = this._query.signature\n if (!signature) {\n return false\n }\n\n // Check expiration if present\n if (this._query.expires !== undefined && this._query.expires !== null) {\n const expiresStr = String(this._query.expires)\n const expirationTime = parseInt(expiresStr, 10) * 1000\n if (isNaN(expirationTime) || Date.now() > expirationTime) {\n return false\n }\n }\n\n // Recreate URL without signature for verification\n const queryWithoutSignature = { ...this._query }\n delete queryWithoutSignature.signature\n\n const urlWithoutSignature = new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n queryWithoutSignature,\n this._fragment\n ).toString()\n\n const payload = this._query.expires\n ? `${urlWithoutSignature}?expires=${this._query.expires}`\n : urlWithoutSignature\n\n let key = ''\n try {\n key = config('app.key', 'default-key')\n } catch {/** */ }\n const expectedSignature = hmac(payload, key)\n\n return signature === expectedSignature\n }\n\n /**\n * Convert the URL to its string representation\n */\n toString (): string {\n let url = ''\n\n // Add scheme and host\n if (this._scheme && this._host) {\n url += `${this._scheme}://${this._host}`\n\n // Add port if specified and not default\n if (this._port &&\n !((this._scheme === 'http' && this._port === 80) ||\n (this._scheme === 'https' && this._port === 443))) {\n url += `:${this._port}`\n }\n }\n\n // Add path\n if (this._path) {\n if (!this._path.startsWith('/')) {\n url += '/'\n }\n url += this._path\n }\n\n // Add query parameters\n const queryEntries = Object.entries(this._query)\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(v => `${encodeURIComponent(key)}%5B%5D=${encodeURIComponent(v)}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n url += `?${queryString}`\n }\n\n // Add fragment\n if (this._fragment) {\n url += `#${this._fragment}`\n }\n\n return url\n }\n\n /**\n * Get the scheme\n */\n getScheme (): string | undefined {\n return this._scheme\n }\n\n /**\n * Get the host\n */\n getHost (): string | undefined {\n return this._host\n }\n\n /**\n * Get the port\n */\n getPort (): number | undefined {\n return this._port\n }\n\n /**\n * Get the path\n */\n getPath (): string {\n return this._path\n }\n\n /**\n * Get the query parameters\n */\n getQuery (): Record<string, unknown> {\n return { ...this._query }\n }\n\n /**\n * Get the fragment\n */\n getFragment (): string | undefined {\n return this._fragment\n }\n}\n","import { Application } from '@h3ravel/core'\nimport { HelpersContract } from './Contracts/UrlContract'\nimport { RequestAwareHelpers } from './RequestAwareHelpers'\nimport { Url } from './Url'\nimport { ExtractControllerMethods } from '@h3ravel/shared'\n\n/**\n * Global helper functions for URL manipulation\n */\n\n/**\n * Create a URL from a path relative to the app URL\n */\nexport function to (\n path: string,\n app?: Application\n): Url {\n return Url.to(path, app)\n}\n\n/**\n * Create a URL from a named route\n */\nexport function route<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.route<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a signed URL from a named route\n */\nexport function signedRoute<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.signedRoute<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a temporary signed URL from a named route\n */\nexport function temporarySignedRoute (\n name: string,\n params: Record<string, string> = {},\n expiration: number,\n app?: Application\n): Url {\n return Url.temporarySignedRoute(name, params, expiration, app)\n}\n\n/**\n * Create a URL from a controller action\n */\nexport function action (\n controller: string,\n app?: Application\n): Url {\n return Url.action(controller, app)\n}\n\n/**\n * Get request-aware URL helpers\n */\nexport function url (app?: Application): RequestAwareHelpers {\n if (!app) throw new Error('Application instance required for request-aware URL helpers')\n return new RequestAwareHelpers(app)\n}\n\n/**\n * Create URL helpers that are bound to an application instance\n */\nexport function createUrlHelpers (app: Application): HelpersContract {\n return {\n /**\n * Create a URL from a path relative to the app URL\n */\n to: (path: string) => Url.to(path, app),\n\n /**\n * Create a URL from a named route\n */\n route: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.route(name, params, app).toString(),\n\n /**\n * Create a signed URL from a named route\n */\n signedRoute: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.signedRoute(name, params, app),\n\n /**\n * Create a temporary signed URL from a named route\n */\n temporarySignedRoute: (\n name: string,\n params: Record<string, any> = {},\n expiration: number\n ) => Url.temporarySignedRoute(name, params, expiration, app),\n\n /**\n * Create a URL from a controller action\n */\n action: <C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>\n ) => Url.action(controller, params, app).toString(),\n\n /**\n * Get request-aware URL helpers\n */\n url: (path?: string) => {\n if (path) {\n return Url.to(path).toString() as never\n }\n return new RequestAwareHelpers(app) as never\n }\n }\n}\n","/// <reference path=\"../app.globals.d.ts\" />\nimport { ServiceProvider } from '@h3ravel/core'\nimport { Url } from '../Url'\nimport { createUrlHelper } from '../RequestAwareHelpers'\nimport { createUrlHelpers } from '../Helpers'\n\n/**\n * Service provider for URL utilities\n */\nexport class UrlServiceProvider extends ServiceProvider {\n /**\n * Register URL services in the container\n */\n register (): void {\n // Register the Url class\n this.app.singleton('app.url', () => Url)\n // Register the url() helper function\n this.app.singleton('app.url.helper', () => createUrlHelper(this.app))\n\n // Register bound URL helpers\n this.app.singleton('app.url.helpers', () => createUrlHelpers(this.app))\n\n // Make url() globally available\n if (typeof globalThis !== 'undefined') {\n const helpers = createUrlHelpers(this.app)\n\n Object.assign(globalThis, {\n url: helpers.url,\n route: helpers.route,\n action: helpers.action,\n })\n }\n }\n\n /**\n * Boot URL services\n */\n boot (): void {\n // Any additional setup can be done here\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["app: Application","path","url","query: Record<string, unknown>","routes: RouteDefinition[]","route","ConfigException","queryParams: Record<string, unknown>","path","ServiceProvider"],"sources":["../src/RequestAwareHelpers.ts","../src/Url.ts","../src/Helpers.ts","../src/Providers/UrlServiceProvider.ts"],"sourcesContent":["import type { Application } from '@h3ravel/core'\nimport type { IRequest } from '@h3ravel/shared'\nimport { RouteParams } from './Contracts/UrlContract'\n\n/**\n * Request-aware URL helper class\n */\nexport class RequestAwareHelpers {\n private readonly baseUrl: string = ''\n\n constructor(private app: Application) {\n try {\n this.baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n }\n\n /**\n * Get the current request instance\n */\n private getCurrentRequest (): IRequest {\n const request = this.app.make('http.request')\n if (!request) {\n throw new Error('Request instance not available in current context')\n }\n return request\n }\n\n /**\n * Get the current request URL (path only, no query string)\n */\n current (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the path from the request\n const raw = event.req.url ?? '/'\n const url = new URL(raw, 'http://localhost')\n return url.pathname\n }\n\n /**\n * Get the full current URL with query string\n */\n full (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the full URL including query string\n const requestUrl = event.req.url ?? '/'\n\n // If requestUrl is already absolute, use it directly, otherwise combine with baseUrl\n if (requestUrl.startsWith('http')) {\n return requestUrl\n }\n\n const fullUrl = new URL(requestUrl, this.baseUrl)\n return fullUrl.toString()\n }\n\n /**\n * Get the previous request URL from session or referrer\n */\n previous (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Try to get from session first (if session is available)\n // For now, fallback to HTTP referrer header\n const headers = (event as any)?.node?.req?.headers as Record<string, string | string[] | undefined> | undefined\n // console.log(headers)\n let referrer = headers?.referer ?? headers?.referrer\n if (Array.isArray(referrer)) referrer = referrer[0]\n if (referrer) return referrer\n\n // Fallback to current URL if no referrer\n return this.current()\n }\n\n /**\n * Get the previous request path (without query string)\n */\n previousPath (): string {\n const previousUrl = this.previous()\n\n try {\n const url = new URL(previousUrl)\n return url.pathname\n } catch {\n // If previous URL is not a valid URL, return as-is\n return previousUrl\n }\n }\n\n /**\n * Get the current query parameters\n */\n query (): RouteParams {\n const request = this.getCurrentRequest()\n return request.query || {}\n }\n}\n\n/**\n * Global helper function factory\n */\nexport function createUrlHelper (app: Application): () => RequestAwareHelpers {\n return () => new RequestAwareHelpers(app)\n}\n","import { ConfigException, type Application } from '@h3ravel/core'\nimport { RouteParams } from './Contracts/UrlContract'\nimport { hmac } from '@h3ravel/support'\nimport { RouteDefinition, ExtractControllerMethods } from '@h3ravel/shared'\nimport path from 'node:path'\n\n/**\n * URL builder class with fluent API and request-aware helpers\n */\nexport class Url {\n private readonly _scheme?: string\n private readonly _host?: string\n private readonly _port?: number\n private readonly _path: string\n private readonly _query: Record<string, unknown>\n private readonly _fragment?: string\n private readonly app?: Application\n\n private constructor(\n app?: Application,\n scheme?: string,\n host?: string,\n port?: number,\n path: string = '/',\n query: Record<string, unknown> = {},\n fragment?: string\n ) {\n this.app = app\n this._scheme = scheme\n this._host = host\n this._port = port\n this._path = path.startsWith('/') ? path : `/${path}`\n this._query = { ...query }\n this._fragment = fragment\n }\n\n /**\n * Create a URL from a full URL string\n */\n static of (url: string, app?: Application): Url {\n try {\n const parsed = new URL(url)\n const query: Record<string, unknown> = {}\n\n // Parse query parameters\n parsed.searchParams.forEach((value, key) => {\n query[key] = value\n })\n\n return new Url(\n app,\n parsed.protocol.replace(':', ''),\n parsed.hostname,\n parsed.port ? parseInt(parsed.port) : undefined,\n parsed.pathname || '/',\n query,\n parsed.hash ? parsed.hash.substring(1) : undefined\n )\n } catch {\n throw new Error(`Invalid URL: ${url}`)\n }\n }\n\n /**\n * Create a URL from a path relative to the app URL\n */\n static to (path: string, app?: Application): Url {\n let baseUrl = ''\n try {\n baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n\n const fullUrl = new URL(path, baseUrl).toString()\n\n return Url.of(fullUrl, app)\n }\n\n /**\n * Create a URL from a named route\n */\n // Route parameter map (declaration-mergeable by consumers)\n static route<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n if (!app) {\n throw new Error('Application instance required for route generation')\n }\n\n // Use (app as any).make to avoid TS error if make is not typed on Application\n const router = app.make('router')\n if (!router || typeof router.route !== 'function') {\n throw new Error('Router not available or does not support route generation')\n }\n\n if (typeof router.route !== 'function') {\n throw new Error('Router does not support route generation')\n }\n\n const routeUrl = router.route(name, params)\n if (!routeUrl) {\n throw new Error(`Route \"${name}\" not found`)\n }\n\n return Url.to(routeUrl, app)\n }\n\n /**\n * Create a signed URL from a named route\n */\n static signedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app)\n }\n\n /**\n * Create a temporary signed URL from a named route\n */\n static temporarySignedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n expiration: number,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app, expiration)\n }\n\n /**\n * Create a URL from a controller action\n */\n static action<C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>,\n app?: Application\n ): Url {\n if (!app) throw new Error('Application instance required for action URL generation')\n\n const [controllerName, methodName = 'index'] = typeof controller === 'string'\n ? controller.split('@')\n : controller\n\n const cname = typeof controllerName === 'string' ? controllerName : controllerName.name\n\n const routes: RouteDefinition[] = app.make('app.routes')\n\n if (!Array.isArray(routes)) {\n // Backward-compatible message expected by existing tests\n throw new Error('Action URL generation requires router integration - not yet implemented')\n }\n\n if (routes.length < 1) throw new Error(`No routes available to resolve action: ${controller}`)\n\n // Search for for the \n const found = routes.find(route => {\n return route.signature?.[0] === cname && (route.signature?.[1] || 'index') === methodName\n })\n\n if (!found) throw new Error(`No route found for ${cname}`)\n\n // Build the route parameters\n const _params = Object.values(params ?? {}).join('/')\n\n if (_params) {\n return Url.to(path.join(found.path, _params))\n }\n\n return Url.to(found.path, app)\n }\n\n /**\n * Set the scheme (protocol) of the URL\n */\n withScheme (scheme: string): Url {\n return new Url(\n this.app,\n scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the host of the URL\n */\n withHost (host: string): Url {\n return new Url(\n this.app,\n this._scheme,\n host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the port of the URL\n */\n withPort (port: number): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the path of the URL\n */\n withPath (path: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the query parameters of the URL\n */\n withQuery (query: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...query },\n this._fragment\n )\n }\n\n /**\n * Merge additional query parameters\n */\n withQueryParams (params: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...this._query, ...params },\n this._fragment\n )\n }\n\n /**\n * Set the fragment (hash) of the URL\n */\n withFragment (fragment: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n fragment\n )\n }\n\n /**\n * Add a signature to the URL for security\n */\n withSignature (app?: Application, expiration?: number): Url {\n const appInstance = app || this.app\n if (!appInstance) {\n throw new Error('Application instance required for URL signing')\n }\n\n let key = ''\n try {\n key = config('app.key')\n } catch {/** */ }\n\n if (!key) {\n throw new ConfigException('APP_KEY and app.key', 'any', this)\n }\n const url = this.toString()\n const queryParams: Record<string, unknown> = { ...this._query }\n\n if (expiration) {\n queryParams.expires = Math.floor(expiration / 1000)\n }\n\n // Create signature payload\n const payload = expiration\n ? `${url}?expires=${queryParams.expires}`\n : url\n\n const signature = hmac(payload, key)\n queryParams.signature = signature\n\n return this.withQuery(queryParams)\n }\n\n /**\n * Verify if a URL signature is valid\n */\n hasValidSignature (app?: Application): boolean {\n const appInstance = app || this.app\n if (!appInstance) {\n return false\n }\n\n const signature = this._query.signature\n if (!signature) {\n return false\n }\n\n // Check expiration if present\n if (this._query.expires !== undefined && this._query.expires !== null) {\n const expiresStr = String(this._query.expires)\n const expirationTime = parseInt(expiresStr, 10) * 1000\n if (isNaN(expirationTime) || Date.now() > expirationTime) {\n return false\n }\n }\n\n // Recreate URL without signature for verification\n const queryWithoutSignature = { ...this._query }\n delete queryWithoutSignature.signature\n\n const urlWithoutSignature = new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n queryWithoutSignature,\n this._fragment\n ).toString()\n\n const payload = this._query.expires\n ? `${urlWithoutSignature}?expires=${this._query.expires}`\n : urlWithoutSignature\n\n let key = ''\n try {\n key = config('app.key', 'default-key')\n } catch {/** */ }\n const expectedSignature = hmac(payload, key)\n\n return signature === expectedSignature\n }\n\n /**\n * Convert the URL to its string representation\n */\n toString (): string {\n let url = ''\n\n // Add scheme and host\n if (this._scheme && this._host) {\n url += `${this._scheme}://${this._host}`\n\n // Add port if specified and not default\n if (this._port &&\n !((this._scheme === 'http' && this._port === 80) ||\n (this._scheme === 'https' && this._port === 443))) {\n url += `:${this._port}`\n }\n }\n\n // Add path\n if (this._path) {\n if (!this._path.startsWith('/')) {\n url += '/'\n }\n url += this._path\n }\n\n // Add query parameters\n const queryEntries = Object.entries(this._query)\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(v => `${encodeURIComponent(key)}%5B%5D=${encodeURIComponent(v)}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n url += `?${queryString}`\n }\n\n // Add fragment\n if (this._fragment) {\n url += `#${this._fragment}`\n }\n\n return url\n }\n\n /**\n * Get the scheme\n */\n getScheme (): string | undefined {\n return this._scheme\n }\n\n /**\n * Get the host\n */\n getHost (): string | undefined {\n return this._host\n }\n\n /**\n * Get the port\n */\n getPort (): number | undefined {\n return this._port\n }\n\n /**\n * Get the path\n */\n getPath (): string {\n return this._path\n }\n\n /**\n * Get the query parameters\n */\n getQuery (): Record<string, unknown> {\n return { ...this._query }\n }\n\n /**\n * Get the fragment\n */\n getFragment (): string | undefined {\n return this._fragment\n }\n}\n","import { Application } from '@h3ravel/core'\nimport { HelpersContract } from './Contracts/UrlContract'\nimport { RequestAwareHelpers } from './RequestAwareHelpers'\nimport { Url } from './Url'\nimport { ExtractControllerMethods } from '@h3ravel/shared'\n\n/**\n * Global helper functions for URL manipulation\n */\n\n/**\n * Create a URL from a path relative to the app URL\n */\nexport function to (\n path: string,\n app?: Application\n): Url {\n return Url.to(path, app)\n}\n\n/**\n * Create a URL from a named route\n */\nexport function route<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.route<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a signed URL from a named route\n */\nexport function signedRoute<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.signedRoute<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a temporary signed URL from a named route\n */\nexport function temporarySignedRoute (\n name: string,\n params: Record<string, string> = {},\n expiration: number,\n app?: Application\n): Url {\n return Url.temporarySignedRoute(name, params, expiration, app)\n}\n\n/**\n * Create a URL from a controller action\n */\nexport function action (\n controller: string,\n app?: Application\n): Url {\n return Url.action(controller, app)\n}\n\n/**\n * Get request-aware URL helpers\n */\nexport function url (app?: Application): RequestAwareHelpers {\n if (!app) throw new Error('Application instance required for request-aware URL helpers')\n return new RequestAwareHelpers(app)\n}\n\n/**\n * Create URL helpers that are bound to an application instance\n */\nexport function createUrlHelpers (app: Application): HelpersContract {\n return {\n /**\n * Create a URL from a path relative to the app URL\n */\n to: (path: string) => Url.to(path, app),\n\n /**\n * Create a URL from a named route\n */\n route: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.route(name, params, app).toString(),\n\n /**\n * Create a signed URL from a named route\n */\n signedRoute: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.signedRoute(name, params, app),\n\n /**\n * Create a temporary signed URL from a named route\n */\n temporarySignedRoute: (\n name: string,\n params: Record<string, any> = {},\n expiration: number\n ) => Url.temporarySignedRoute(name, params, expiration, app),\n\n /**\n * Create a URL from a controller action\n */\n action: <C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>\n ) => Url.action(controller, params, app).toString(),\n\n /**\n * Get request-aware URL helpers\n */\n url: (path?: string) => {\n if (path) {\n return Url.to(path).toString() as never\n }\n return new RequestAwareHelpers(app) as never\n }\n }\n}\n","/// <reference path=\"../app.globals.d.ts\" />\nimport { ServiceProvider } from '@h3ravel/core'\nimport { Url } from '../Url'\nimport { createUrlHelper } from '../RequestAwareHelpers'\nimport { createUrlHelpers } from '../Helpers'\n\n/**\n * Service provider for URL utilities\n */\nexport class UrlServiceProvider extends ServiceProvider {\n public static priority = 897\n\n /**\n * Register URL services in the container\n */\n register (): void {\n // Register the Url class\n this.app.singleton('app.url', () => Url)\n // Register the url() helper function\n this.app.singleton('app.url.helper', () => createUrlHelper(this.app))\n\n // Register bound URL helpers\n this.app.singleton('app.url.helpers', () => createUrlHelpers(this.app))\n\n // Make url() globally available\n if (typeof globalThis !== 'undefined') {\n const helpers = createUrlHelpers(this.app)\n\n Object.assign(globalThis, {\n url: helpers.url,\n route: helpers.route,\n action: helpers.action,\n })\n }\n }\n\n /**\n * Boot URL services\n */\n boot (): void {\n // Any additional setup can be done here\n }\n}\n"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -284,6 +284,7 @@ declare function createUrlHelpers(app: Application): HelpersContract;
284
284
  * Service provider for URL utilities
285
285
  */
286
286
  declare class UrlServiceProvider extends ServiceProvider {
287
+ static priority: number;
287
288
  /**
288
289
  * Register URL services in the container
289
290
  */
package/dist/index.d.ts CHANGED
@@ -284,6 +284,7 @@ declare function createUrlHelpers(app: Application): HelpersContract;
284
284
  * Service provider for URL utilities
285
285
  */
286
286
  declare class UrlServiceProvider extends ServiceProvider {
287
+ static priority: number;
287
288
  /**
288
289
  * Register URL services in the container
289
290
  */
package/dist/index.js CHANGED
@@ -220,8 +220,7 @@ var Url = class Url {
220
220
  const url$1 = this.toString();
221
221
  const queryParams = { ...this._query };
222
222
  if (expiration) queryParams.expires = Math.floor(expiration / 1e3);
223
- const payload = expiration ? `${url$1}?expires=${queryParams.expires}` : url$1;
224
- queryParams.signature = hmac(payload, key);
223
+ queryParams.signature = hmac(expiration ? `${url$1}?expires=${queryParams.expires}` : url$1, key);
225
224
  return this.withQuery(queryParams);
226
225
  }
227
226
  /**
@@ -244,8 +243,7 @@ var Url = class Url {
244
243
  try {
245
244
  key = config("app.key", "default-key");
246
245
  } catch {}
247
- const expectedSignature = hmac(payload, key);
248
- return signature === expectedSignature;
246
+ return signature === hmac(payload, key);
249
247
  }
250
248
  /**
251
249
  * Convert the URL to its string representation
@@ -374,6 +372,7 @@ function createUrlHelpers(app) {
374
372
  * Service provider for URL utilities
375
373
  */
376
374
  var UrlServiceProvider = class extends ServiceProvider {
375
+ static priority = 897;
377
376
  /**
378
377
  * Register URL services in the container
379
378
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["app: Application","path","url","query: Record<string, unknown>","routes: RouteDefinition[]","route","queryParams: Record<string, unknown>","path"],"sources":["../src/RequestAwareHelpers.ts","../src/Url.ts","../src/Helpers.ts","../src/Providers/UrlServiceProvider.ts"],"sourcesContent":["import type { Application } from '@h3ravel/core'\nimport type { IRequest } from '@h3ravel/shared'\nimport { RouteParams } from './Contracts/UrlContract'\n\n/**\n * Request-aware URL helper class\n */\nexport class RequestAwareHelpers {\n private readonly baseUrl: string = ''\n\n constructor(private app: Application) {\n try {\n this.baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n }\n\n /**\n * Get the current request instance\n */\n private getCurrentRequest (): IRequest {\n const request = this.app.make('http.request')\n if (!request) {\n throw new Error('Request instance not available in current context')\n }\n return request\n }\n\n /**\n * Get the current request URL (path only, no query string)\n */\n current (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the path from the request\n const raw = event.req.url ?? '/'\n const url = new URL(raw, 'http://localhost')\n return url.pathname\n }\n\n /**\n * Get the full current URL with query string\n */\n full (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the full URL including query string\n const requestUrl = event.req.url ?? '/'\n\n // If requestUrl is already absolute, use it directly, otherwise combine with baseUrl\n if (requestUrl.startsWith('http')) {\n return requestUrl\n }\n\n const fullUrl = new URL(requestUrl, this.baseUrl)\n return fullUrl.toString()\n }\n\n /**\n * Get the previous request URL from session or referrer\n */\n previous (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Try to get from session first (if session is available)\n // For now, fallback to HTTP referrer header\n const headers = (event as any)?.node?.req?.headers as Record<string, string | string[] | undefined> | undefined\n // console.log(headers)\n let referrer = headers?.referer ?? headers?.referrer\n if (Array.isArray(referrer)) referrer = referrer[0]\n if (referrer) return referrer\n\n // Fallback to current URL if no referrer\n return this.current()\n }\n\n /**\n * Get the previous request path (without query string)\n */\n previousPath (): string {\n const previousUrl = this.previous()\n\n try {\n const url = new URL(previousUrl)\n return url.pathname\n } catch {\n // If previous URL is not a valid URL, return as-is\n return previousUrl\n }\n }\n\n /**\n * Get the current query parameters\n */\n query (): RouteParams {\n const request = this.getCurrentRequest()\n return request.query || {}\n }\n}\n\n/**\n * Global helper function factory\n */\nexport function createUrlHelper (app: Application): () => RequestAwareHelpers {\n return () => new RequestAwareHelpers(app)\n}\n","import { ConfigException, type Application } from '@h3ravel/core'\nimport { RouteParams } from './Contracts/UrlContract'\nimport { hmac } from '@h3ravel/support'\nimport { RouteDefinition, ExtractControllerMethods } from '@h3ravel/shared'\nimport path from 'node:path'\n\n/**\n * URL builder class with fluent API and request-aware helpers\n */\nexport class Url {\n private readonly _scheme?: string\n private readonly _host?: string\n private readonly _port?: number\n private readonly _path: string\n private readonly _query: Record<string, unknown>\n private readonly _fragment?: string\n private readonly app?: Application\n\n private constructor(\n app?: Application,\n scheme?: string,\n host?: string,\n port?: number,\n path: string = '/',\n query: Record<string, unknown> = {},\n fragment?: string\n ) {\n this.app = app\n this._scheme = scheme\n this._host = host\n this._port = port\n this._path = path.startsWith('/') ? path : `/${path}`\n this._query = { ...query }\n this._fragment = fragment\n }\n\n /**\n * Create a URL from a full URL string\n */\n static of (url: string, app?: Application): Url {\n try {\n const parsed = new URL(url)\n const query: Record<string, unknown> = {}\n\n // Parse query parameters\n parsed.searchParams.forEach((value, key) => {\n query[key] = value\n })\n\n return new Url(\n app,\n parsed.protocol.replace(':', ''),\n parsed.hostname,\n parsed.port ? parseInt(parsed.port) : undefined,\n parsed.pathname || '/',\n query,\n parsed.hash ? parsed.hash.substring(1) : undefined\n )\n } catch {\n throw new Error(`Invalid URL: ${url}`)\n }\n }\n\n /**\n * Create a URL from a path relative to the app URL\n */\n static to (path: string, app?: Application): Url {\n let baseUrl = ''\n try {\n baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n\n const fullUrl = new URL(path, baseUrl).toString()\n\n return Url.of(fullUrl, app)\n }\n\n /**\n * Create a URL from a named route\n */\n // Route parameter map (declaration-mergeable by consumers)\n static route<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n if (!app) {\n throw new Error('Application instance required for route generation')\n }\n\n // Use (app as any).make to avoid TS error if make is not typed on Application\n const router = app.make('router')\n if (!router || typeof router.route !== 'function') {\n throw new Error('Router not available or does not support route generation')\n }\n\n if (typeof router.route !== 'function') {\n throw new Error('Router does not support route generation')\n }\n\n const routeUrl = router.route(name, params)\n if (!routeUrl) {\n throw new Error(`Route \"${name}\" not found`)\n }\n\n return Url.to(routeUrl, app)\n }\n\n /**\n * Create a signed URL from a named route\n */\n static signedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app)\n }\n\n /**\n * Create a temporary signed URL from a named route\n */\n static temporarySignedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n expiration: number,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app, expiration)\n }\n\n /**\n * Create a URL from a controller action\n */\n static action<C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>,\n app?: Application\n ): Url {\n if (!app) throw new Error('Application instance required for action URL generation')\n\n const [controllerName, methodName = 'index'] = typeof controller === 'string'\n ? controller.split('@')\n : controller\n\n const cname = typeof controllerName === 'string' ? controllerName : controllerName.name\n\n const routes: RouteDefinition[] = app.make('app.routes')\n\n if (!Array.isArray(routes)) {\n // Backward-compatible message expected by existing tests\n throw new Error('Action URL generation requires router integration - not yet implemented')\n }\n\n if (routes.length < 1) throw new Error(`No routes available to resolve action: ${controller}`)\n\n // Search for for the \n const found = routes.find(route => {\n return route.signature?.[0] === cname && (route.signature?.[1] || 'index') === methodName\n })\n\n if (!found) throw new Error(`No route found for ${cname}`)\n\n // Build the route parameters\n const _params = Object.values(params ?? {}).join('/')\n\n if (_params) {\n return Url.to(path.join(found.path, _params))\n }\n\n return Url.to(found.path, app)\n }\n\n /**\n * Set the scheme (protocol) of the URL\n */\n withScheme (scheme: string): Url {\n return new Url(\n this.app,\n scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the host of the URL\n */\n withHost (host: string): Url {\n return new Url(\n this.app,\n this._scheme,\n host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the port of the URL\n */\n withPort (port: number): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the path of the URL\n */\n withPath (path: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the query parameters of the URL\n */\n withQuery (query: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...query },\n this._fragment\n )\n }\n\n /**\n * Merge additional query parameters\n */\n withQueryParams (params: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...this._query, ...params },\n this._fragment\n )\n }\n\n /**\n * Set the fragment (hash) of the URL\n */\n withFragment (fragment: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n fragment\n )\n }\n\n /**\n * Add a signature to the URL for security\n */\n withSignature (app?: Application, expiration?: number): Url {\n const appInstance = app || this.app\n if (!appInstance) {\n throw new Error('Application instance required for URL signing')\n }\n\n let key = ''\n try {\n key = config('app.key')\n } catch {/** */ }\n\n if (!key) {\n throw new ConfigException('APP_KEY and app.key', 'any', this)\n }\n const url = this.toString()\n const queryParams: Record<string, unknown> = { ...this._query }\n\n if (expiration) {\n queryParams.expires = Math.floor(expiration / 1000)\n }\n\n // Create signature payload\n const payload = expiration\n ? `${url}?expires=${queryParams.expires}`\n : url\n\n const signature = hmac(payload, key)\n queryParams.signature = signature\n\n return this.withQuery(queryParams)\n }\n\n /**\n * Verify if a URL signature is valid\n */\n hasValidSignature (app?: Application): boolean {\n const appInstance = app || this.app\n if (!appInstance) {\n return false\n }\n\n const signature = this._query.signature\n if (!signature) {\n return false\n }\n\n // Check expiration if present\n if (this._query.expires !== undefined && this._query.expires !== null) {\n const expiresStr = String(this._query.expires)\n const expirationTime = parseInt(expiresStr, 10) * 1000\n if (isNaN(expirationTime) || Date.now() > expirationTime) {\n return false\n }\n }\n\n // Recreate URL without signature for verification\n const queryWithoutSignature = { ...this._query }\n delete queryWithoutSignature.signature\n\n const urlWithoutSignature = new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n queryWithoutSignature,\n this._fragment\n ).toString()\n\n const payload = this._query.expires\n ? `${urlWithoutSignature}?expires=${this._query.expires}`\n : urlWithoutSignature\n\n let key = ''\n try {\n key = config('app.key', 'default-key')\n } catch {/** */ }\n const expectedSignature = hmac(payload, key)\n\n return signature === expectedSignature\n }\n\n /**\n * Convert the URL to its string representation\n */\n toString (): string {\n let url = ''\n\n // Add scheme and host\n if (this._scheme && this._host) {\n url += `${this._scheme}://${this._host}`\n\n // Add port if specified and not default\n if (this._port &&\n !((this._scheme === 'http' && this._port === 80) ||\n (this._scheme === 'https' && this._port === 443))) {\n url += `:${this._port}`\n }\n }\n\n // Add path\n if (this._path) {\n if (!this._path.startsWith('/')) {\n url += '/'\n }\n url += this._path\n }\n\n // Add query parameters\n const queryEntries = Object.entries(this._query)\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(v => `${encodeURIComponent(key)}%5B%5D=${encodeURIComponent(v)}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n url += `?${queryString}`\n }\n\n // Add fragment\n if (this._fragment) {\n url += `#${this._fragment}`\n }\n\n return url\n }\n\n /**\n * Get the scheme\n */\n getScheme (): string | undefined {\n return this._scheme\n }\n\n /**\n * Get the host\n */\n getHost (): string | undefined {\n return this._host\n }\n\n /**\n * Get the port\n */\n getPort (): number | undefined {\n return this._port\n }\n\n /**\n * Get the path\n */\n getPath (): string {\n return this._path\n }\n\n /**\n * Get the query parameters\n */\n getQuery (): Record<string, unknown> {\n return { ...this._query }\n }\n\n /**\n * Get the fragment\n */\n getFragment (): string | undefined {\n return this._fragment\n }\n}\n","import { Application } from '@h3ravel/core'\nimport { HelpersContract } from './Contracts/UrlContract'\nimport { RequestAwareHelpers } from './RequestAwareHelpers'\nimport { Url } from './Url'\nimport { ExtractControllerMethods } from '@h3ravel/shared'\n\n/**\n * Global helper functions for URL manipulation\n */\n\n/**\n * Create a URL from a path relative to the app URL\n */\nexport function to (\n path: string,\n app?: Application\n): Url {\n return Url.to(path, app)\n}\n\n/**\n * Create a URL from a named route\n */\nexport function route<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.route<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a signed URL from a named route\n */\nexport function signedRoute<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.signedRoute<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a temporary signed URL from a named route\n */\nexport function temporarySignedRoute (\n name: string,\n params: Record<string, string> = {},\n expiration: number,\n app?: Application\n): Url {\n return Url.temporarySignedRoute(name, params, expiration, app)\n}\n\n/**\n * Create a URL from a controller action\n */\nexport function action (\n controller: string,\n app?: Application\n): Url {\n return Url.action(controller, app)\n}\n\n/**\n * Get request-aware URL helpers\n */\nexport function url (app?: Application): RequestAwareHelpers {\n if (!app) throw new Error('Application instance required for request-aware URL helpers')\n return new RequestAwareHelpers(app)\n}\n\n/**\n * Create URL helpers that are bound to an application instance\n */\nexport function createUrlHelpers (app: Application): HelpersContract {\n return {\n /**\n * Create a URL from a path relative to the app URL\n */\n to: (path: string) => Url.to(path, app),\n\n /**\n * Create a URL from a named route\n */\n route: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.route(name, params, app).toString(),\n\n /**\n * Create a signed URL from a named route\n */\n signedRoute: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.signedRoute(name, params, app),\n\n /**\n * Create a temporary signed URL from a named route\n */\n temporarySignedRoute: (\n name: string,\n params: Record<string, any> = {},\n expiration: number\n ) => Url.temporarySignedRoute(name, params, expiration, app),\n\n /**\n * Create a URL from a controller action\n */\n action: <C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>\n ) => Url.action(controller, params, app).toString(),\n\n /**\n * Get request-aware URL helpers\n */\n url: (path?: string) => {\n if (path) {\n return Url.to(path).toString() as never\n }\n return new RequestAwareHelpers(app) as never\n }\n }\n}\n","/// <reference path=\"../app.globals.d.ts\" />\nimport { ServiceProvider } from '@h3ravel/core'\nimport { Url } from '../Url'\nimport { createUrlHelper } from '../RequestAwareHelpers'\nimport { createUrlHelpers } from '../Helpers'\n\n/**\n * Service provider for URL utilities\n */\nexport class UrlServiceProvider extends ServiceProvider {\n /**\n * Register URL services in the container\n */\n register (): void {\n // Register the Url class\n this.app.singleton('app.url', () => Url)\n // Register the url() helper function\n this.app.singleton('app.url.helper', () => createUrlHelper(this.app))\n\n // Register bound URL helpers\n this.app.singleton('app.url.helpers', () => createUrlHelpers(this.app))\n\n // Make url() globally available\n if (typeof globalThis !== 'undefined') {\n const helpers = createUrlHelpers(this.app)\n\n Object.assign(globalThis, {\n url: helpers.url,\n route: helpers.route,\n action: helpers.action,\n })\n }\n }\n\n /**\n * Boot URL services\n */\n boot (): void {\n // Any additional setup can be done here\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["app: Application","path","url","query: Record<string, unknown>","routes: RouteDefinition[]","route","queryParams: Record<string, unknown>","path"],"sources":["../src/RequestAwareHelpers.ts","../src/Url.ts","../src/Helpers.ts","../src/Providers/UrlServiceProvider.ts"],"sourcesContent":["import type { Application } from '@h3ravel/core'\nimport type { IRequest } from '@h3ravel/shared'\nimport { RouteParams } from './Contracts/UrlContract'\n\n/**\n * Request-aware URL helper class\n */\nexport class RequestAwareHelpers {\n private readonly baseUrl: string = ''\n\n constructor(private app: Application) {\n try {\n this.baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n }\n\n /**\n * Get the current request instance\n */\n private getCurrentRequest (): IRequest {\n const request = this.app.make('http.request')\n if (!request) {\n throw new Error('Request instance not available in current context')\n }\n return request\n }\n\n /**\n * Get the current request URL (path only, no query string)\n */\n current (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the path from the request\n const raw = event.req.url ?? '/'\n const url = new URL(raw, 'http://localhost')\n return url.pathname\n }\n\n /**\n * Get the full current URL with query string\n */\n full (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Get the full URL including query string\n const requestUrl = event.req.url ?? '/'\n\n // If requestUrl is already absolute, use it directly, otherwise combine with baseUrl\n if (requestUrl.startsWith('http')) {\n return requestUrl\n }\n\n const fullUrl = new URL(requestUrl, this.baseUrl)\n return fullUrl.toString()\n }\n\n /**\n * Get the previous request URL from session or referrer\n */\n previous (): string {\n const request = this.getCurrentRequest()\n const event = request.getEvent()\n\n // Try to get from session first (if session is available)\n // For now, fallback to HTTP referrer header\n const headers = (event as any)?.node?.req?.headers as Record<string, string | string[] | undefined> | undefined\n // console.log(headers)\n let referrer = headers?.referer ?? headers?.referrer\n if (Array.isArray(referrer)) referrer = referrer[0]\n if (referrer) return referrer\n\n // Fallback to current URL if no referrer\n return this.current()\n }\n\n /**\n * Get the previous request path (without query string)\n */\n previousPath (): string {\n const previousUrl = this.previous()\n\n try {\n const url = new URL(previousUrl)\n return url.pathname\n } catch {\n // If previous URL is not a valid URL, return as-is\n return previousUrl\n }\n }\n\n /**\n * Get the current query parameters\n */\n query (): RouteParams {\n const request = this.getCurrentRequest()\n return request.query || {}\n }\n}\n\n/**\n * Global helper function factory\n */\nexport function createUrlHelper (app: Application): () => RequestAwareHelpers {\n return () => new RequestAwareHelpers(app)\n}\n","import { ConfigException, type Application } from '@h3ravel/core'\nimport { RouteParams } from './Contracts/UrlContract'\nimport { hmac } from '@h3ravel/support'\nimport { RouteDefinition, ExtractControllerMethods } from '@h3ravel/shared'\nimport path from 'node:path'\n\n/**\n * URL builder class with fluent API and request-aware helpers\n */\nexport class Url {\n private readonly _scheme?: string\n private readonly _host?: string\n private readonly _port?: number\n private readonly _path: string\n private readonly _query: Record<string, unknown>\n private readonly _fragment?: string\n private readonly app?: Application\n\n private constructor(\n app?: Application,\n scheme?: string,\n host?: string,\n port?: number,\n path: string = '/',\n query: Record<string, unknown> = {},\n fragment?: string\n ) {\n this.app = app\n this._scheme = scheme\n this._host = host\n this._port = port\n this._path = path.startsWith('/') ? path : `/${path}`\n this._query = { ...query }\n this._fragment = fragment\n }\n\n /**\n * Create a URL from a full URL string\n */\n static of (url: string, app?: Application): Url {\n try {\n const parsed = new URL(url)\n const query: Record<string, unknown> = {}\n\n // Parse query parameters\n parsed.searchParams.forEach((value, key) => {\n query[key] = value\n })\n\n return new Url(\n app,\n parsed.protocol.replace(':', ''),\n parsed.hostname,\n parsed.port ? parseInt(parsed.port) : undefined,\n parsed.pathname || '/',\n query,\n parsed.hash ? parsed.hash.substring(1) : undefined\n )\n } catch {\n throw new Error(`Invalid URL: ${url}`)\n }\n }\n\n /**\n * Create a URL from a path relative to the app URL\n */\n static to (path: string, app?: Application): Url {\n let baseUrl = ''\n try {\n baseUrl = config('app.url', 'http://localhost:3000')\n } catch {/** */ }\n\n const fullUrl = new URL(path, baseUrl).toString()\n\n return Url.of(fullUrl, app)\n }\n\n /**\n * Create a URL from a named route\n */\n // Route parameter map (declaration-mergeable by consumers)\n static route<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n if (!app) {\n throw new Error('Application instance required for route generation')\n }\n\n // Use (app as any).make to avoid TS error if make is not typed on Application\n const router = app.make('router')\n if (!router || typeof router.route !== 'function') {\n throw new Error('Router not available or does not support route generation')\n }\n\n if (typeof router.route !== 'function') {\n throw new Error('Router does not support route generation')\n }\n\n const routeUrl = router.route(name, params)\n if (!routeUrl) {\n throw new Error(`Route \"${name}\" not found`)\n }\n\n return Url.to(routeUrl, app)\n }\n\n /**\n * Create a signed URL from a named route\n */\n static signedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app)\n }\n\n /**\n * Create a temporary signed URL from a named route\n */\n static temporarySignedRoute<TName extends string = string, TParams extends RouteParams = RouteParams> (\n name: TName,\n params: TParams = {} as TParams,\n expiration: number,\n app?: Application\n ): Url {\n const url = Url.route<TName, TParams>(name, params, app)\n return url.withSignature(app, expiration)\n }\n\n /**\n * Create a URL from a controller action\n */\n static action<C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>,\n app?: Application\n ): Url {\n if (!app) throw new Error('Application instance required for action URL generation')\n\n const [controllerName, methodName = 'index'] = typeof controller === 'string'\n ? controller.split('@')\n : controller\n\n const cname = typeof controllerName === 'string' ? controllerName : controllerName.name\n\n const routes: RouteDefinition[] = app.make('app.routes')\n\n if (!Array.isArray(routes)) {\n // Backward-compatible message expected by existing tests\n throw new Error('Action URL generation requires router integration - not yet implemented')\n }\n\n if (routes.length < 1) throw new Error(`No routes available to resolve action: ${controller}`)\n\n // Search for for the \n const found = routes.find(route => {\n return route.signature?.[0] === cname && (route.signature?.[1] || 'index') === methodName\n })\n\n if (!found) throw new Error(`No route found for ${cname}`)\n\n // Build the route parameters\n const _params = Object.values(params ?? {}).join('/')\n\n if (_params) {\n return Url.to(path.join(found.path, _params))\n }\n\n return Url.to(found.path, app)\n }\n\n /**\n * Set the scheme (protocol) of the URL\n */\n withScheme (scheme: string): Url {\n return new Url(\n this.app,\n scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the host of the URL\n */\n withHost (host: string): Url {\n return new Url(\n this.app,\n this._scheme,\n host,\n this._port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the port of the URL\n */\n withPort (port: number): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n port,\n this._path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the path of the URL\n */\n withPath (path: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n path,\n this._query,\n this._fragment\n )\n }\n\n /**\n * Set the query parameters of the URL\n */\n withQuery (query: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...query },\n this._fragment\n )\n }\n\n /**\n * Merge additional query parameters\n */\n withQueryParams (params: Record<string, unknown>): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n { ...this._query, ...params },\n this._fragment\n )\n }\n\n /**\n * Set the fragment (hash) of the URL\n */\n withFragment (fragment: string): Url {\n return new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n this._query,\n fragment\n )\n }\n\n /**\n * Add a signature to the URL for security\n */\n withSignature (app?: Application, expiration?: number): Url {\n const appInstance = app || this.app\n if (!appInstance) {\n throw new Error('Application instance required for URL signing')\n }\n\n let key = ''\n try {\n key = config('app.key')\n } catch {/** */ }\n\n if (!key) {\n throw new ConfigException('APP_KEY and app.key', 'any', this)\n }\n const url = this.toString()\n const queryParams: Record<string, unknown> = { ...this._query }\n\n if (expiration) {\n queryParams.expires = Math.floor(expiration / 1000)\n }\n\n // Create signature payload\n const payload = expiration\n ? `${url}?expires=${queryParams.expires}`\n : url\n\n const signature = hmac(payload, key)\n queryParams.signature = signature\n\n return this.withQuery(queryParams)\n }\n\n /**\n * Verify if a URL signature is valid\n */\n hasValidSignature (app?: Application): boolean {\n const appInstance = app || this.app\n if (!appInstance) {\n return false\n }\n\n const signature = this._query.signature\n if (!signature) {\n return false\n }\n\n // Check expiration if present\n if (this._query.expires !== undefined && this._query.expires !== null) {\n const expiresStr = String(this._query.expires)\n const expirationTime = parseInt(expiresStr, 10) * 1000\n if (isNaN(expirationTime) || Date.now() > expirationTime) {\n return false\n }\n }\n\n // Recreate URL without signature for verification\n const queryWithoutSignature = { ...this._query }\n delete queryWithoutSignature.signature\n\n const urlWithoutSignature = new Url(\n this.app,\n this._scheme,\n this._host,\n this._port,\n this._path,\n queryWithoutSignature,\n this._fragment\n ).toString()\n\n const payload = this._query.expires\n ? `${urlWithoutSignature}?expires=${this._query.expires}`\n : urlWithoutSignature\n\n let key = ''\n try {\n key = config('app.key', 'default-key')\n } catch {/** */ }\n const expectedSignature = hmac(payload, key)\n\n return signature === expectedSignature\n }\n\n /**\n * Convert the URL to its string representation\n */\n toString (): string {\n let url = ''\n\n // Add scheme and host\n if (this._scheme && this._host) {\n url += `${this._scheme}://${this._host}`\n\n // Add port if specified and not default\n if (this._port &&\n !((this._scheme === 'http' && this._port === 80) ||\n (this._scheme === 'https' && this._port === 443))) {\n url += `:${this._port}`\n }\n }\n\n // Add path\n if (this._path) {\n if (!this._path.startsWith('/')) {\n url += '/'\n }\n url += this._path\n }\n\n // Add query parameters\n const queryEntries = Object.entries(this._query)\n if (queryEntries.length > 0) {\n const queryString = queryEntries\n .map(([key, value]) => {\n if (Array.isArray(value)) {\n return value.map(v => `${encodeURIComponent(key)}%5B%5D=${encodeURIComponent(v)}`).join('&')\n }\n return `${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`\n })\n .join('&')\n url += `?${queryString}`\n }\n\n // Add fragment\n if (this._fragment) {\n url += `#${this._fragment}`\n }\n\n return url\n }\n\n /**\n * Get the scheme\n */\n getScheme (): string | undefined {\n return this._scheme\n }\n\n /**\n * Get the host\n */\n getHost (): string | undefined {\n return this._host\n }\n\n /**\n * Get the port\n */\n getPort (): number | undefined {\n return this._port\n }\n\n /**\n * Get the path\n */\n getPath (): string {\n return this._path\n }\n\n /**\n * Get the query parameters\n */\n getQuery (): Record<string, unknown> {\n return { ...this._query }\n }\n\n /**\n * Get the fragment\n */\n getFragment (): string | undefined {\n return this._fragment\n }\n}\n","import { Application } from '@h3ravel/core'\nimport { HelpersContract } from './Contracts/UrlContract'\nimport { RequestAwareHelpers } from './RequestAwareHelpers'\nimport { Url } from './Url'\nimport { ExtractControllerMethods } from '@h3ravel/shared'\n\n/**\n * Global helper functions for URL manipulation\n */\n\n/**\n * Create a URL from a path relative to the app URL\n */\nexport function to (\n path: string,\n app?: Application\n): Url {\n return Url.to(path, app)\n}\n\n/**\n * Create a URL from a named route\n */\nexport function route<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.route<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a signed URL from a named route\n */\nexport function signedRoute<TName extends string, TParams extends Record<string, string> = Record<string, string>> (\n name: TName,\n params: TParams = {} as TParams,\n app?: Application\n): Url {\n return Url.signedRoute<TName, TParams>(name, params, app)\n}\n\n/**\n * Create a temporary signed URL from a named route\n */\nexport function temporarySignedRoute (\n name: string,\n params: Record<string, string> = {},\n expiration: number,\n app?: Application\n): Url {\n return Url.temporarySignedRoute(name, params, expiration, app)\n}\n\n/**\n * Create a URL from a controller action\n */\nexport function action (\n controller: string,\n app?: Application\n): Url {\n return Url.action(controller, app)\n}\n\n/**\n * Get request-aware URL helpers\n */\nexport function url (app?: Application): RequestAwareHelpers {\n if (!app) throw new Error('Application instance required for request-aware URL helpers')\n return new RequestAwareHelpers(app)\n}\n\n/**\n * Create URL helpers that are bound to an application instance\n */\nexport function createUrlHelpers (app: Application): HelpersContract {\n return {\n /**\n * Create a URL from a path relative to the app URL\n */\n to: (path: string) => Url.to(path, app),\n\n /**\n * Create a URL from a named route\n */\n route: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.route(name, params, app).toString(),\n\n /**\n * Create a signed URL from a named route\n */\n signedRoute: (\n name: string,\n params: Record<string, any> = {}\n ) => Url.signedRoute(name, params, app),\n\n /**\n * Create a temporary signed URL from a named route\n */\n temporarySignedRoute: (\n name: string,\n params: Record<string, any> = {},\n expiration: number\n ) => Url.temporarySignedRoute(name, params, expiration, app),\n\n /**\n * Create a URL from a controller action\n */\n action: <C extends new (...args: any) => any> (\n controller: string | [C, methodName: ExtractControllerMethods<InstanceType<C>>],\n params?: Record<string, any>\n ) => Url.action(controller, params, app).toString(),\n\n /**\n * Get request-aware URL helpers\n */\n url: (path?: string) => {\n if (path) {\n return Url.to(path).toString() as never\n }\n return new RequestAwareHelpers(app) as never\n }\n }\n}\n","/// <reference path=\"../app.globals.d.ts\" />\nimport { ServiceProvider } from '@h3ravel/core'\nimport { Url } from '../Url'\nimport { createUrlHelper } from '../RequestAwareHelpers'\nimport { createUrlHelpers } from '../Helpers'\n\n/**\n * Service provider for URL utilities\n */\nexport class UrlServiceProvider extends ServiceProvider {\n public static priority = 897\n\n /**\n * Register URL services in the container\n */\n register (): void {\n // Register the Url class\n this.app.singleton('app.url', () => Url)\n // Register the url() helper function\n this.app.singleton('app.url.helper', () => createUrlHelper(this.app))\n\n // Register bound URL helpers\n this.app.singleton('app.url.helpers', () => createUrlHelpers(this.app))\n\n // Make url() globally available\n if (typeof globalThis !== 'undefined') {\n const helpers = createUrlHelpers(this.app)\n\n Object.assign(globalThis, {\n url: helpers.url,\n route: helpers.route,\n action: helpers.action,\n })\n }\n }\n\n /**\n * Boot URL services\n */\n boot (): void {\n // Any additional setup can be done here\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h3ravel/url",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Request-aware URI builder and URL manipulation utilities for H3ravel.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,12 +39,12 @@
39
39
  "builder"
40
40
  ],
41
41
  "dependencies": {
42
- "@h3ravel/support": "^0.13.0",
43
- "@h3ravel/shared": "^0.21.0"
42
+ "@h3ravel/support": "^0.14.0",
43
+ "@h3ravel/shared": "^0.22.1"
44
44
  },
45
45
  "peerDependencies": {
46
- "@h3ravel/core": "^1.13.0",
47
- "@h3ravel/http": "^11.3.2"
46
+ "@h3ravel/core": "^1.15.0",
47
+ "@h3ravel/http": "^11.3.3"
48
48
  },
49
49
  "devDependencies": {
50
50
  "typescript": "^5.4.0"