@strav/http 0.2.7 → 0.2.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strav/http",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "type": "module",
5
5
  "description": "HTTP layer for the Strav framework — router, server, middleware, authentication, sessions, validation, and views",
6
6
  "license": "MIT",
@@ -36,8 +36,8 @@
36
36
  "./providers/*": "./src/providers/*.ts"
37
37
  },
38
38
  "peerDependencies": {
39
- "@strav/kernel": "0.2.6",
40
- "@strav/database": "0.2.6"
39
+ "@strav/kernel": "0.2.8",
40
+ "@strav/database": "0.2.8"
41
41
  },
42
42
  "dependencies": {
43
43
  "@vue/compiler-sfc": "^3.5.28",
@@ -67,6 +67,22 @@ export default class Context {
67
67
  return this._subdomain
68
68
  }
69
69
 
70
+ /**
71
+ * Get the full origin (protocol + host) of the current request.
72
+ * Uses the X-Forwarded-Proto header if present (common behind proxies),
73
+ * otherwise determines from the request URL.
74
+ */
75
+ getOrigin(): string {
76
+ // Check for forwarded protocol (when behind proxy/load balancer)
77
+ const forwardedProto = this.headers.get('x-forwarded-proto')
78
+ const protocol = forwardedProto ? `${forwardedProto}:` : this.url.protocol
79
+
80
+ // Get host from header (includes port if non-standard)
81
+ const host = this.headers.get('host') || this.url.host
82
+
83
+ return `${protocol}//${host}`
84
+ }
85
+
70
86
  /** Shorthand for reading a single request header. */
71
87
  header(name: string): string | null {
72
88
  return this.headers.get(name)
package/src/http/index.ts CHANGED
@@ -8,7 +8,7 @@ export { compose } from './middleware.ts'
8
8
  export { serializeCookie, parseCookies, withCookie, clearCookie } from './cookie.ts'
9
9
  export { rateLimit, MemoryStore } from './rate_limit.ts'
10
10
  export { Resource } from './resource.ts'
11
- export { route, routeUrl } from './route_helper.ts'
11
+ export { route, routeUrl, routeFullUrl } from './route_helper.ts'
12
12
  export type { Handler, Middleware, Next } from './middleware.ts'
13
13
  export type { GroupOptions, WebSocketHandlers, WebSocketData, RouteDefinition } from './router.ts'
14
14
  export type { CookieOptions } from './cookie.ts'
@@ -1,5 +1,7 @@
1
1
  import { router } from './index.ts'
2
2
  import type { RouteDefinition } from './router.ts'
3
+ import { app } from '@strav/kernel/core/application'
4
+ import Configuration from '@strav/kernel/config/configuration'
3
5
 
4
6
  export interface RouteOptions extends Omit<RequestInit, 'body'> {
5
7
  params?: Record<string, any>
@@ -131,4 +133,62 @@ export async function route(
131
133
  */
132
134
  export function routeUrl(name: string, params?: Record<string, any>): string {
133
135
  return router.generateUrl(name, params)
136
+ }
137
+
138
+ /**
139
+ * Generate a full URL (with protocol and domain) for a named route.
140
+ *
141
+ * Uses the APP_URL from configuration if set, otherwise constructs from
142
+ * the current request context (requires passing the context).
143
+ *
144
+ * @example
145
+ * // With APP_URL configured
146
+ * const resetUrl = routeFullUrl('auth.password.reset', { token: 'abc123' })
147
+ * // Returns 'https://example.com/auth/password-reset?token=abc123'
148
+ *
149
+ * // With request context
150
+ * const profileUrl = routeFullUrl('users.profile', { id: 456 }, ctx)
151
+ * // Returns 'https://example.com/users/456'
152
+ *
153
+ * // Override the base URL
154
+ * const apiUrl = routeFullUrl('api.users', {}, null, 'https://api.example.com')
155
+ * // Returns 'https://api.example.com/api/users'
156
+ */
157
+ export function routeFullUrl(
158
+ name: string,
159
+ params?: Record<string, any>,
160
+ context?: { getOrigin(): string } | null,
161
+ baseUrl?: string
162
+ ): string {
163
+ const path = routeUrl(name, params)
164
+
165
+ // Use provided base URL if given
166
+ if (baseUrl) {
167
+ return baseUrl.replace(/\/$/, '') + path
168
+ }
169
+
170
+ // Try to get app_url from config
171
+ const config = app.resolve(Configuration)
172
+ const appUrl = config.get('http.app_url') as string | undefined
173
+
174
+ if (appUrl) {
175
+ return appUrl.replace(/\/$/, '') + path
176
+ }
177
+
178
+ // Fall back to context origin
179
+ if (context) {
180
+ return context.getOrigin() + path
181
+ }
182
+
183
+ // If no context and no config, construct from http config
184
+ const protocol = config.get('http.secure', false) ? 'https' : 'http'
185
+ const domain = config.get('http.domain', 'localhost') as string
186
+ const port = config.get('http.port', 3000) as number
187
+
188
+ // Only include port if non-standard
189
+ const includePort = (protocol === 'http' && port !== 80) ||
190
+ (protocol === 'https' && port !== 443)
191
+ const host = includePort ? `${domain}:${port}` : domain
192
+
193
+ return `${protocol}://${host}${path}`
134
194
  }
package/src/index.ts CHANGED
@@ -6,4 +6,9 @@ export * from './auth/index.ts'
6
6
  export * from './providers/index.ts'
7
7
 
8
8
  // Route helpers for named route invocation
9
- export { route, routeUrl } from './http/route_helper.ts'
9
+ export { route, routeUrl, routeFullUrl } from './http/route_helper.ts'
10
+
11
+ // Middleware exports for cross-package functionality
12
+ export { httpCache } from './middleware/http_cache.ts'
13
+ export { i18n } from './middleware/i18n.ts'
14
+ export { requestLogger } from './middleware/request_logger.ts'