@danceroutine/tango-core 1.11.15 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/errors-DpI5Dxmr.js.map +1 -1
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.js +1 -1
- package/dist/{http-BJPRtBGV.js → http-DP2xzidS.js} +50 -21
- package/dist/http-DP2xzidS.js.map +1 -0
- package/dist/{index-Ds43ITu5.d.ts → index-hxHvR7TR.d.ts} +35 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/sql-CIPnuTYO.js.map +1 -1
- package/package.json +2 -2
- package/dist/http-BJPRtBGV.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors-DpI5Dxmr.js","names":[],"sources":["../src/errors/factories/HttpErrorFactory.ts","../src/errors/factories/index.ts","../src/errors/ConflictError.ts","../src/errors/ValidationError.ts","../src/errors/MultipleObjectsReturned.ts","../src/errors/NotFoundError.ts","../src/errors/PermissionDenied.ts","../src/errors/AuthenticationError.ts","../src/errors/index.ts"],"sourcesContent":["import { TangoError } from '../TangoError';\nimport type { HttpError } from '../HttpError';\nimport { isError, isObject } from '../../runtime/index';\n\nexport interface HttpErrorFactoryConfig {\n /**\n * When true, raw error messages are included in HTTP responses.\n * When false, generic messages are returned for non-TangoError exceptions.\n * Defaults to true (dev-friendly). Set to false in production.\n */\n exposeErrors?: boolean;\n}\n\ntype ZodLikeIssue = {\n path?: unknown[];\n message?: unknown;\n};\n\ntype ZodLikeError = Error & {\n issues: ZodLikeIssue[];\n};\n\n/**\n * Converts errors into structured HTTP error responses.\n * Supports TangoError subclasses out of the box, and custom error handlers\n * can be registered for third-party or application-specific error types.\n *\n * @example\n * ```typescript\n * // Development (default) — exposes real error messages\n * const devFactory = new HttpErrorFactory();\n *\n * // Production — hides internal error details\n * const prodFactory = new HttpErrorFactory({ exposeErrors: false });\n *\n * // Register a custom handler for a third-party error\n * prodFactory.registerHandler(ZodError, (err) => ({\n * status: 400,\n * body: { error: 'Validation failed', details: err.flatten().fieldErrors },\n * }));\n *\n * // Quick one-shot conversion with dev defaults\n * const httpError = HttpErrorFactory.toHttpError(new NotFoundError('missing'));\n * ```\n */\nexport class HttpErrorFactory {\n static readonly BRAND = 'tango.error_factory.http' as const;\n readonly __tangoBrand: typeof HttpErrorFactory.BRAND = HttpErrorFactory.BRAND;\n\n // oxlint-disable-next-line typescript/no-explicit-any\n private handlers = new Map<new (...args: any[]) => Error, (error: Error) => HttpError>();\n private exposeErrors: boolean;\n\n constructor(config: HttpErrorFactoryConfig = {}) {\n this.exposeErrors = config.exposeErrors ?? true;\n }\n\n /**\n * Narrow an unknown value to `HttpErrorFactory`.\n */\n static isHttpErrorFactory(value: unknown): value is HttpErrorFactory {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === HttpErrorFactory.BRAND\n );\n }\n\n /**\n * Convert an unknown error into an `HttpError` using dev-friendly defaults.\n * Shorthand for `new HttpErrorFactory().create(error)`.\n */\n static toHttpError(error: unknown): HttpError {\n return new HttpErrorFactory().create(error);\n }\n\n private static isZodLikeValidationError(error: unknown): error is ZodLikeError {\n return (\n isError(error) &&\n isObject(error) &&\n Array.isArray((error as { issues?: unknown }).issues) &&\n (error as { name?: unknown }).name === 'ZodError'\n );\n }\n\n private static zodLikeErrorDetails(error: ZodLikeError): Record<string, string[]> {\n const details: Record<string, string[]> = {};\n\n for (const issue of error.issues) {\n const key = Array.isArray(issue.path) && issue.path.length > 0 ? String(issue.path.join('.')) : '_schema';\n const message = typeof issue.message === 'string' ? issue.message : 'Invalid value';\n\n const existing = details[key];\n if (existing) {\n existing.push(message);\n } else {\n details[key] = [message];\n }\n }\n\n return details;\n }\n\n /**\n * Register a custom mapper for an application or third-party error type.\n */\n\n // oxlint-disable-next-line typescript/no-explicit-any\n registerHandler<T extends Error>(errorClass: new (...args: any[]) => T, handler: (error: T) => HttpError): this {\n this.handlers.set(errorClass, handler as (error: Error) => HttpError);\n return this;\n }\n\n /**\n * Convert an unknown error into the normalized HTTP error shape Tango uses.\n */\n create(error: unknown): HttpError {\n if (TangoError.isTangoError(error)) {\n return error.toHttpError();\n }\n\n if (HttpErrorFactory.isZodLikeValidationError(error)) {\n return {\n status: 400,\n body: {\n error: error.message || 'Validation failed',\n details: HttpErrorFactory.zodLikeErrorDetails(error),\n },\n };\n }\n\n for (const [ErrorClass, handler] of this.handlers) {\n if (this.isErrorClassInstance(error, ErrorClass)) {\n return handler(error);\n }\n }\n\n if (isError(error)) {\n return {\n status: 500,\n body: {\n error: this.exposeErrors ? error.message : 'Internal Server Error',\n details: null,\n },\n };\n }\n\n return {\n status: 500,\n body: {\n error: 'Unknown error occurred',\n details: null,\n },\n };\n }\n\n // oxlint-disable-next-line typescript/no-explicit-any\n private isErrorClassInstance(error: unknown, ErrorClass: new (...args: any[]) => Error): error is Error {\n if (!isError(error)) {\n return false;\n }\n\n const expectedBrand = (ErrorClass as { BRAND?: unknown }).BRAND;\n if (\n typeof expectedBrand === 'string' &&\n isObject(error) &&\n (error as { __tangoBrand?: unknown }).__tangoBrand === expectedBrand\n ) {\n return true;\n }\n\n const constructorName = (error as { constructor?: { name?: unknown } }).constructor?.name;\n if (typeof constructorName === 'string' && constructorName === ErrorClass.name) {\n return true;\n }\n\n const errorName = (error as { name?: unknown }).name;\n if (typeof errorName === 'string' && errorName === ErrorClass.name) {\n return true;\n }\n\n return false;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { HttpErrorFactory, type HttpErrorFactoryConfig } from './HttpErrorFactory';\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for conflicting resource state (HTTP 409). */\nexport class ConflictError extends TangoError {\n static readonly BRAND = 'tango.error.conflict' as const;\n readonly __tangoBrand: typeof ConflictError.BRAND = ConflictError.BRAND;\n status = 409;\n\n /** Create a conflict error with optional custom message. */\n constructor(message: string = 'Resource conflict') {\n super(message);\n this.name = 'ConflictError';\n Object.setPrototypeOf(this, ConflictError.prototype);\n }\n\n /**\n * Narrow an unknown value to `ConflictError`.\n */\n static isConflictError(value: unknown): value is ConflictError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === ConflictError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'conflict';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for request validation failures (HTTP 400). */\nexport class ValidationError extends TangoError {\n readonly __tangoValidationErrorBrand = 'tango.error.validation' as const;\n status = 400;\n\n constructor(\n message: string,\n public details?: ErrorDetails\n ) {\n super(message);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n\n /**\n * Narrow an unknown value to `ValidationError`, including common legacy shapes.\n */\n static isValidationError(err: unknown): err is ValidationError {\n return (\n (!!err &&\n typeof err === 'object' &&\n (err as { __tangoValidationErrorBrand?: string }).__tangoValidationErrorBrand ===\n 'tango.error.validation') ||\n (typeof err === 'object' &&\n err !== null &&\n 'fields' in err &&\n typeof (err as { fields: unknown }).fields === 'object')\n );\n }\n\n protected override getErrorName(): string {\n return 'ValidationError';\n }\n\n protected override getDetails(): ErrorDetails {\n return this.details;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error when a queryset lookup returns more than one row (HTTP 409). */\nexport class MultipleObjectsReturned extends TangoError {\n static readonly BRAND = 'tango.error.multiple_objects_returned' as const;\n readonly __tangoBrand: typeof MultipleObjectsReturned.BRAND = MultipleObjectsReturned.BRAND;\n status = 409;\n\n constructor(message: string = 'Multiple objects returned') {\n super(message);\n this.name = 'MultipleObjectsReturned';\n Object.setPrototypeOf(this, MultipleObjectsReturned.prototype);\n }\n\n static isMultipleObjectsReturned(value: unknown): value is MultipleObjectsReturned {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === MultipleObjectsReturned.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'multiple_objects_returned';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for missing resources (HTTP 404). */\nexport class NotFoundError extends TangoError {\n static readonly BRAND = 'tango.error.not_found' as const;\n readonly __tangoBrand: typeof NotFoundError.BRAND = NotFoundError.BRAND;\n status = 404;\n\n /** Create a not-found error with optional custom message. */\n constructor(message: string = 'Resource not found') {\n super(message);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n\n /**\n * Narrow an unknown value to `NotFoundError`.\n */\n static isNotFoundError(value: unknown): value is NotFoundError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === NotFoundError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'not_found';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for authorization failures (HTTP 403). */\nexport class PermissionDenied extends TangoError {\n static readonly BRAND = 'tango.error.permission_denied' as const;\n readonly __tangoBrand: typeof PermissionDenied.BRAND = PermissionDenied.BRAND;\n status = 403;\n\n /** Create a permission-denied error with optional custom message. */\n constructor(message: string = 'Permission denied') {\n super(message);\n this.name = 'PermissionDenied';\n Object.setPrototypeOf(this, PermissionDenied.prototype);\n }\n\n /**\n * Narrow an unknown value to `PermissionDenied`.\n */\n static isPermissionDenied(value: unknown): value is PermissionDenied {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PermissionDenied.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'permission_denied';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for missing/invalid authentication (HTTP 401). */\nexport class AuthenticationError extends TangoError {\n static readonly BRAND = 'tango.error.authentication' as const;\n readonly __tangoBrand: typeof AuthenticationError.BRAND = AuthenticationError.BRAND;\n status = 401;\n\n /** Create an authentication error with optional custom message. */\n constructor(message: string = 'Authentication required') {\n super(message);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n\n /**\n * Narrow an unknown value to `AuthenticationError`.\n */\n static isAuthenticationError(value: unknown): value is AuthenticationError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === AuthenticationError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'authentication_error';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nimport type { HttpError } from './HttpError';\nimport * as factories from './factories/index';\nimport { TangoError, type ErrorDetails, type ErrorEnvelope, type ProblemDetails } from './TangoError';\nimport { ConflictError } from './ConflictError';\nimport { ValidationError } from './ValidationError';\nimport { MultipleObjectsReturned } from './MultipleObjectsReturned';\nimport { NotFoundError } from './NotFoundError';\nimport { PermissionDenied } from './PermissionDenied';\nimport { AuthenticationError } from './AuthenticationError';\nimport { HttpErrorFactory, type HttpErrorFactoryConfig } from './factories/HttpErrorFactory';\n\nexport {\n AuthenticationError,\n ConflictError,\n HttpErrorFactory,\n MultipleObjectsReturned,\n NotFoundError,\n PermissionDenied,\n TangoError,\n ValidationError,\n factories,\n};\n\nexport type { ErrorDetails, ErrorEnvelope, HttpError, HttpErrorFactoryConfig, ProblemDetails };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"errors-DpI5Dxmr.js","names":[],"sources":["../src/errors/factories/HttpErrorFactory.ts","../src/errors/factories/index.ts","../src/errors/ConflictError.ts","../src/errors/ValidationError.ts","../src/errors/MultipleObjectsReturned.ts","../src/errors/NotFoundError.ts","../src/errors/PermissionDenied.ts","../src/errors/AuthenticationError.ts","../src/errors/index.ts"],"sourcesContent":["import { TangoError } from '../TangoError';\nimport type { HttpError } from '../HttpError';\nimport { isError, isObject } from '../../runtime/index';\n\nexport interface HttpErrorFactoryConfig {\n /**\n * When true, raw error messages are included in HTTP responses.\n * When false, generic messages are returned for non-TangoError exceptions.\n * Defaults to true (dev-friendly). Set to false in production.\n */\n exposeErrors?: boolean;\n}\n\ntype ZodLikeIssue = {\n path?: unknown[];\n message?: unknown;\n};\n\ntype ZodLikeError = Error & {\n issues: ZodLikeIssue[];\n};\n\n/**\n * Converts errors into structured HTTP error responses.\n * Supports TangoError subclasses out of the box, and custom error handlers\n * can be registered for third-party or application-specific error types.\n *\n * @example\n * ```typescript\n * // Development (default) — exposes real error messages\n * const devFactory = new HttpErrorFactory();\n *\n * // Production — hides internal error details\n * const prodFactory = new HttpErrorFactory({ exposeErrors: false });\n *\n * // Register a custom handler for a third-party error\n * prodFactory.registerHandler(ZodError, (err) => ({\n * status: 400,\n * body: { error: 'Validation failed', details: err.flatten().fieldErrors },\n * }));\n *\n * // Quick one-shot conversion with dev defaults\n * const httpError = HttpErrorFactory.toHttpError(new NotFoundError('missing'));\n * ```\n */\nexport class HttpErrorFactory {\n static readonly BRAND = 'tango.error_factory.http' as const;\n readonly __tangoBrand: typeof HttpErrorFactory.BRAND = HttpErrorFactory.BRAND;\n\n // oxlint-disable-next-line typescript/no-explicit-any\n private handlers = new Map<new (...args: any[]) => Error, (error: Error) => HttpError>();\n private exposeErrors: boolean;\n\n constructor(config: HttpErrorFactoryConfig = {}) {\n this.exposeErrors = config.exposeErrors ?? true;\n }\n\n /**\n * Narrow an unknown value to `HttpErrorFactory`.\n */\n static isHttpErrorFactory(value: unknown): value is HttpErrorFactory {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === HttpErrorFactory.BRAND\n );\n }\n\n /**\n * Convert an unknown error into an `HttpError` using dev-friendly defaults.\n * Shorthand for `new HttpErrorFactory().create(error)`.\n */\n static toHttpError(error: unknown): HttpError {\n return new HttpErrorFactory().create(error);\n }\n\n private static isZodLikeValidationError(error: unknown): error is ZodLikeError {\n return (\n isError(error) &&\n isObject(error) &&\n Array.isArray((error as { issues?: unknown }).issues) &&\n (error as { name?: unknown }).name === 'ZodError'\n );\n }\n\n private static zodLikeErrorDetails(error: ZodLikeError): Record<string, string[]> {\n const details: Record<string, string[]> = {};\n\n for (const issue of error.issues) {\n const key = Array.isArray(issue.path) && issue.path.length > 0 ? String(issue.path.join('.')) : '_schema';\n const message = typeof issue.message === 'string' ? issue.message : 'Invalid value';\n\n const existing = details[key];\n if (existing) {\n existing.push(message);\n } else {\n details[key] = [message];\n }\n }\n\n return details;\n }\n\n /**\n * Register a custom mapper for an application or third-party error type.\n */\n\n // oxlint-disable-next-line typescript/no-explicit-any\n registerHandler<T extends Error>(errorClass: new (...args: any[]) => T, handler: (error: T) => HttpError): this {\n this.handlers.set(errorClass, handler as (error: Error) => HttpError);\n return this;\n }\n\n /**\n * Convert an unknown error into the normalized HTTP error shape Tango uses.\n */\n create(error: unknown): HttpError {\n if (TangoError.isTangoError(error)) {\n return error.toHttpError();\n }\n\n if (HttpErrorFactory.isZodLikeValidationError(error)) {\n return {\n status: 400,\n body: {\n error: error.message || 'Validation failed',\n details: HttpErrorFactory.zodLikeErrorDetails(error),\n },\n };\n }\n\n for (const [ErrorClass, handler] of this.handlers) {\n if (this.isErrorClassInstance(error, ErrorClass)) {\n return handler(error);\n }\n }\n\n if (isError(error)) {\n return {\n status: 500,\n body: {\n error: this.exposeErrors ? error.message : 'Internal Server Error',\n details: null,\n },\n };\n }\n\n return {\n status: 500,\n body: {\n error: 'Unknown error occurred',\n details: null,\n },\n };\n }\n\n // oxlint-disable-next-line typescript/no-explicit-any\n private isErrorClassInstance(error: unknown, ErrorClass: new (...args: any[]) => Error): error is Error {\n if (!isError(error)) {\n return false;\n }\n\n const expectedBrand = (ErrorClass as { BRAND?: unknown }).BRAND;\n if (\n typeof expectedBrand === 'string' &&\n isObject(error) &&\n (error as { __tangoBrand?: unknown }).__tangoBrand === expectedBrand\n ) {\n return true;\n }\n\n const constructorName = (error as { constructor?: { name?: unknown } }).constructor?.name;\n if (typeof constructorName === 'string' && constructorName === ErrorClass.name) {\n return true;\n }\n\n const errorName = (error as { name?: unknown }).name;\n if (typeof errorName === 'string' && errorName === ErrorClass.name) {\n return true;\n }\n\n return false;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nexport { HttpErrorFactory, type HttpErrorFactoryConfig } from './HttpErrorFactory';\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for conflicting resource state (HTTP 409). */\nexport class ConflictError extends TangoError {\n static readonly BRAND = 'tango.error.conflict' as const;\n readonly __tangoBrand: typeof ConflictError.BRAND = ConflictError.BRAND;\n status = 409;\n\n /** Create a conflict error with optional custom message. */\n constructor(message: string = 'Resource conflict') {\n super(message);\n this.name = 'ConflictError';\n Object.setPrototypeOf(this, ConflictError.prototype);\n }\n\n /**\n * Narrow an unknown value to `ConflictError`.\n */\n static isConflictError(value: unknown): value is ConflictError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === ConflictError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'conflict';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for request validation failures (HTTP 400). */\nexport class ValidationError extends TangoError {\n readonly __tangoValidationErrorBrand = 'tango.error.validation' as const;\n status = 400;\n\n constructor(\n message: string,\n public details?: ErrorDetails\n ) {\n super(message);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n\n /**\n * Narrow an unknown value to `ValidationError`, including common legacy shapes.\n */\n static isValidationError(err: unknown): err is ValidationError {\n return (\n (!!err &&\n typeof err === 'object' &&\n (err as { __tangoValidationErrorBrand?: string }).__tangoValidationErrorBrand ===\n 'tango.error.validation') ||\n (typeof err === 'object' &&\n err !== null &&\n 'fields' in err &&\n typeof (err as { fields: unknown }).fields === 'object')\n );\n }\n\n protected override getErrorName(): string {\n return 'ValidationError';\n }\n\n protected override getDetails(): ErrorDetails {\n return this.details;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error when a queryset lookup returns more than one row (HTTP 409). */\nexport class MultipleObjectsReturned extends TangoError {\n static readonly BRAND = 'tango.error.multiple_objects_returned' as const;\n readonly __tangoBrand: typeof MultipleObjectsReturned.BRAND = MultipleObjectsReturned.BRAND;\n status = 409;\n\n constructor(message: string = 'Multiple objects returned') {\n super(message);\n this.name = 'MultipleObjectsReturned';\n Object.setPrototypeOf(this, MultipleObjectsReturned.prototype);\n }\n\n static isMultipleObjectsReturned(value: unknown): value is MultipleObjectsReturned {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === MultipleObjectsReturned.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'multiple_objects_returned';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for missing resources (HTTP 404). */\nexport class NotFoundError extends TangoError {\n static readonly BRAND = 'tango.error.not_found' as const;\n readonly __tangoBrand: typeof NotFoundError.BRAND = NotFoundError.BRAND;\n status = 404;\n\n /** Create a not-found error with optional custom message. */\n constructor(message: string = 'Resource not found') {\n super(message);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n\n /**\n * Narrow an unknown value to `NotFoundError`.\n */\n static isNotFoundError(value: unknown): value is NotFoundError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === NotFoundError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'not_found';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for authorization failures (HTTP 403). */\nexport class PermissionDenied extends TangoError {\n static readonly BRAND = 'tango.error.permission_denied' as const;\n readonly __tangoBrand: typeof PermissionDenied.BRAND = PermissionDenied.BRAND;\n status = 403;\n\n /** Create a permission-denied error with optional custom message. */\n constructor(message: string = 'Permission denied') {\n super(message);\n this.name = 'PermissionDenied';\n Object.setPrototypeOf(this, PermissionDenied.prototype);\n }\n\n /**\n * Narrow an unknown value to `PermissionDenied`.\n */\n static isPermissionDenied(value: unknown): value is PermissionDenied {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === PermissionDenied.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'permission_denied';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","import { TangoError, type ErrorDetails } from './TangoError';\n\n/** Error for missing/invalid authentication (HTTP 401). */\nexport class AuthenticationError extends TangoError {\n static readonly BRAND = 'tango.error.authentication' as const;\n readonly __tangoBrand: typeof AuthenticationError.BRAND = AuthenticationError.BRAND;\n status = 401;\n\n /** Create an authentication error with optional custom message. */\n constructor(message: string = 'Authentication required') {\n super(message);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n\n /**\n * Narrow an unknown value to `AuthenticationError`.\n */\n static isAuthenticationError(value: unknown): value is AuthenticationError {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === AuthenticationError.BRAND\n );\n }\n\n protected override getErrorName(): string {\n return 'authentication_error';\n }\n\n protected override getDetails(): ErrorDetails {\n return undefined;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nimport type { HttpError } from './HttpError';\nimport * as factories from './factories/index';\nimport { TangoError, type ErrorDetails, type ErrorEnvelope, type ProblemDetails } from './TangoError';\nimport { ConflictError } from './ConflictError';\nimport { ValidationError } from './ValidationError';\nimport { MultipleObjectsReturned } from './MultipleObjectsReturned';\nimport { NotFoundError } from './NotFoundError';\nimport { PermissionDenied } from './PermissionDenied';\nimport { AuthenticationError } from './AuthenticationError';\nimport { HttpErrorFactory, type HttpErrorFactoryConfig } from './factories/HttpErrorFactory';\n\nexport {\n AuthenticationError,\n ConflictError,\n HttpErrorFactory,\n MultipleObjectsReturned,\n NotFoundError,\n PermissionDenied,\n TangoError,\n ValidationError,\n factories,\n};\n\nexport type { ErrorDetails, ErrorEnvelope, HttpError, HttpErrorFactoryConfig, ProblemDetails };\n"],"mappings":"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"}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as TangoHeaders, i as TangoRequest, n as TangoResponse, o as JsonValue, r as TangoQueryParams, s as TangoBody } from "../index-
|
|
1
|
+
import { a as TangoHeaders, i as TangoRequest, n as TangoResponse, o as JsonValue, r as TangoQueryParams, s as TangoBody } from "../index-hxHvR7TR.js";
|
|
2
2
|
export { type JsonValue, TangoBody, TangoHeaders, TangoQueryParams, TangoRequest, TangoResponse };
|
package/dist/http/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as TangoHeaders, i as TangoQueryParams, n as TangoResponse, o as TangoBody, r as TangoRequest } from "../http-
|
|
1
|
+
import { a as TangoHeaders, i as TangoQueryParams, n as TangoResponse, o as TangoBody, r as TangoRequest } from "../http-DP2xzidS.js";
|
|
2
2
|
export { TangoBody, TangoHeaders, TangoQueryParams, TangoRequest, TangoResponse };
|
|
@@ -485,14 +485,14 @@ var TangoHeaders = class TangoHeaders extends Headers {
|
|
|
485
485
|
this.set("Content-Type", mime);
|
|
486
486
|
}
|
|
487
487
|
/**
|
|
488
|
-
* Attempt to guess and set the Content-Type header from
|
|
488
|
+
* Attempt to guess and set the Content-Type header from response body bytes and an optional filename.
|
|
489
489
|
*
|
|
490
|
-
* @param
|
|
491
|
-
* @param filename Optional filename to
|
|
490
|
+
* @param body Response body bytes (for example a Blob or Uint8Array)
|
|
491
|
+
* @param filename Optional filename used to guess mime type by extension
|
|
492
492
|
*/
|
|
493
|
-
|
|
493
|
+
setContentTypeForBody(body, filename) {
|
|
494
494
|
if (this.has("Content-Type")) return;
|
|
495
|
-
if (
|
|
495
|
+
if (filename) {
|
|
496
496
|
const dotIndex = filename.lastIndexOf(".");
|
|
497
497
|
const mime = {
|
|
498
498
|
txt: "text/plain",
|
|
@@ -511,18 +511,25 @@ var TangoHeaders = class TangoHeaders extends Headers {
|
|
|
511
511
|
ico: "image/x-icon",
|
|
512
512
|
md: "text/markdown"
|
|
513
513
|
}[dotIndex >= 0 ? filename.slice(dotIndex + 1).toLowerCase() : ""];
|
|
514
|
-
if (mime)
|
|
515
|
-
|
|
516
|
-
|
|
514
|
+
if (mime) {
|
|
515
|
+
this.set("Content-Type", mime);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
517
518
|
}
|
|
518
|
-
if (isBlob(
|
|
519
|
-
if (
|
|
519
|
+
if (isBlob(body)) {
|
|
520
|
+
if (body.type && body.type !== "") this.set("Content-Type", body.type);
|
|
520
521
|
else this.set("Content-Type", "application/octet-stream");
|
|
521
522
|
return;
|
|
522
523
|
}
|
|
523
524
|
this.set("Content-Type", "application/octet-stream");
|
|
524
525
|
}
|
|
525
526
|
/**
|
|
527
|
+
* @deprecated Use {@link TangoHeaders.setContentTypeForBody} instead.
|
|
528
|
+
*/
|
|
529
|
+
setContentTypeByFile(body, filename) {
|
|
530
|
+
this.setContentTypeForBody(body, filename);
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
526
533
|
* Sets the Content-Length header, inferring it from the body if not explicitly provided.
|
|
527
534
|
* If the body is a string, ArrayBuffer, Uint8Array, Blob/Buffer (or has a .size or .length property),
|
|
528
535
|
* the length is computed. For unsupported types, does nothing.
|
|
@@ -1367,33 +1374,55 @@ var TangoResponse = class TangoResponse {
|
|
|
1367
1374
|
});
|
|
1368
1375
|
}
|
|
1369
1376
|
/**
|
|
1370
|
-
*
|
|
1377
|
+
* Create a response with inline Content-Disposition for file-like body content.
|
|
1378
|
+
*
|
|
1379
|
+
* The first argument is response body bytes, not a filesystem path. To serve bytes
|
|
1380
|
+
* from disk, read the file first and pass the result here.
|
|
1381
|
+
*
|
|
1382
|
+
* @example
|
|
1383
|
+
* ```ts
|
|
1384
|
+
* import { readFile } from 'node:fs/promises';
|
|
1385
|
+
*
|
|
1386
|
+
* const bytes = await readFile('/data/report.pdf');
|
|
1387
|
+
* return TangoResponse.file(bytes, { filename: 'report.pdf' });
|
|
1388
|
+
* ```
|
|
1371
1389
|
*/
|
|
1372
|
-
static file(
|
|
1390
|
+
static file(body, opts) {
|
|
1373
1391
|
const headers = new TangoHeaders(opts?.init?.headers ?? {});
|
|
1374
1392
|
if (opts?.filename) headers.setContentDispositionInline(opts.filename);
|
|
1375
1393
|
if (opts?.contentType && !headers.has("Content-Type")) headers.set("Content-Type", opts.contentType);
|
|
1376
|
-
else if (!headers.has("Content-Type")) headers.
|
|
1377
|
-
if (!headers.has("Content-Length")) headers.setContentLengthFromBody(
|
|
1394
|
+
else if (!headers.has("Content-Type")) headers.setContentTypeForBody(body, opts?.filename);
|
|
1395
|
+
if (!headers.has("Content-Length")) headers.setContentLengthFromBody(body);
|
|
1378
1396
|
return new TangoResponse({
|
|
1379
1397
|
...opts?.init,
|
|
1380
|
-
body
|
|
1398
|
+
body,
|
|
1381
1399
|
headers
|
|
1382
1400
|
});
|
|
1383
1401
|
}
|
|
1384
1402
|
/**
|
|
1385
|
-
*
|
|
1403
|
+
* Create a response with attachment Content-Disposition for file-like body content.
|
|
1404
|
+
*
|
|
1405
|
+
* The first argument must be the response body bytes, not a filesystem path. To serve bytes
|
|
1406
|
+
* from disk, read the file first and pass the result here.
|
|
1407
|
+
*
|
|
1408
|
+
* @example
|
|
1409
|
+
* ```ts
|
|
1410
|
+
* import { readFile } from 'node:fs/promises';
|
|
1411
|
+
*
|
|
1412
|
+
* const bytes = await readFile('/data/report.pdf');
|
|
1413
|
+
* return TangoResponse.download(bytes, { filename: 'report.pdf' });
|
|
1414
|
+
* ```
|
|
1386
1415
|
*/
|
|
1387
|
-
static download(
|
|
1416
|
+
static download(body, opts) {
|
|
1388
1417
|
const headers = new TangoHeaders(opts?.init?.headers ?? {});
|
|
1389
1418
|
if (opts?.filename) headers.setContentDispositionAttachment(opts.filename);
|
|
1390
1419
|
else headers.set("Content-Disposition", "attachment");
|
|
1391
1420
|
if (opts?.contentType && !headers.has("Content-Type")) headers.set("Content-Type", opts.contentType);
|
|
1392
|
-
else if (!headers.has("Content-Type")) headers.
|
|
1393
|
-
if (!headers.has("Content-Length")) headers.setContentLengthFromBody(
|
|
1421
|
+
else if (!headers.has("Content-Type")) headers.setContentTypeForBody(body, opts?.filename);
|
|
1422
|
+
if (!headers.has("Content-Length")) headers.setContentLengthFromBody(body);
|
|
1394
1423
|
return new TangoResponse({
|
|
1395
1424
|
...opts?.init,
|
|
1396
|
-
body
|
|
1425
|
+
body,
|
|
1397
1426
|
headers
|
|
1398
1427
|
});
|
|
1399
1428
|
}
|
|
@@ -1657,4 +1686,4 @@ var http_exports = /* @__PURE__ */ __exportAll({
|
|
|
1657
1686
|
//#endregion
|
|
1658
1687
|
export { TangoHeaders as a, TangoQueryParams as i, TangoResponse as n, TangoBody as o, TangoRequest as r, http_exports as t };
|
|
1659
1688
|
|
|
1660
|
-
//# sourceMappingURL=http-
|
|
1689
|
+
//# sourceMappingURL=http-DP2xzidS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-DP2xzidS.js","names":[],"sources":["../src/http/TangoBody.ts","../src/http/TangoHeaders.ts","../src/http/TangoQueryParams.ts","../src/http/TangoRequest.ts","../src/http/TangoResponse.ts","../src/http/index.ts"],"sourcesContent":["import {\n isArrayBuffer,\n isBlob,\n isFile,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\n\n/**\n * The full type of body that TangoResponse/TangoBody supports.\n * Unlike the fetch spec BodyInit, this can be directly:\n * - a string, ArrayBuffer, Uint8Array, Blob, FormData, ReadableStream, or JSON-like object, or null/undefined.\n */\n\ntype HeadersLike = { get?: (arg: string) => string | null };\n\ntype TangoBodySource = BodyInit | JsonValue | null;\n\n/** Recursive JSON value contract used by Tango HTTP helpers. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\n/**\n * Unified body reader/clone utility for Tango request/response wrappers.\n */\nexport class TangoBody {\n static readonly BRAND = 'tango.http.body' as const;\n readonly __tangoBrand: typeof TangoBody.BRAND = TangoBody.BRAND;\n private bodySourceInternal: TangoBodySource;\n private bodyUsedInternal: boolean;\n private headers?: HeadersLike;\n\n constructor(bodySource: TangoBodySource, headers?: HeadersLike) {\n this.bodySourceInternal = bodySource;\n this.bodyUsedInternal = false;\n this.headers = headers;\n }\n\n /**\n * Narrow an unknown value to `TangoBody`.\n */\n static isTangoBody(value: unknown): value is TangoBody {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoBody.BRAND\n );\n }\n\n /**\n * Expose the original body source for cloning and adapter integration.\n */\n public get bodySource(): TangoBodySource {\n return this.bodySourceInternal;\n }\n\n /**\n * Report whether a reader method has already consumed this body.\n */\n get bodyUsed(): boolean {\n return this.bodyUsedInternal;\n }\n\n /**\n * Describe the current body shape in a way that is useful for diagnostics.\n */\n get bodyType(): string {\n const body = this.bodySourceInternal;\n if (isNil(body)) return 'null';\n if (typeof body === 'string') return 'string';\n if (isArrayBuffer(body)) return 'ArrayBuffer';\n if (isUint8Array(body)) return 'Uint8Array';\n if (isBlob(body)) return 'Blob';\n if (isFormData(body)) return 'FormData';\n if (isURLSearchParams(body)) return 'URLSearchParams';\n if (isReadableStream(body)) return 'ReadableStream';\n if (TangoBody.isJsonValue(body)) return 'JsonValue';\n return typeof body;\n }\n\n /**\n * Returns true if value is a valid JSON value (recursively).\n */\n public static isJsonValue(v: unknown): v is JsonValue {\n if (v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n return true;\n }\n if (Array.isArray(v)) {\n return v.every(TangoBody.isJsonValue);\n }\n if (typeof v === 'object' && v !== null && Object.prototype.toString.call(v) === '[object Object]') {\n return Object.values(v).every(TangoBody.isJsonValue);\n }\n return false;\n }\n\n /**\n * Deep clone utility for body values. Preserves types and values as in the legacy implementation.\n * If the source is a stream, the stream will be cloned if readable, otherwise throws.\n */\n static deepCloneBody(body: TangoBodySource): TangoBodySource {\n if (isNil(body)) {\n return null;\n }\n if (typeof body === 'string') {\n return body;\n }\n if (isArrayBuffer(body)) {\n return body.slice(0);\n }\n if (isUint8Array(body)) {\n return new Uint8Array(body);\n }\n if (isBlob(body)) {\n return body.slice(0, body.size, body.type);\n }\n if (isFormData(body)) {\n // Deep clone FormData: only text fields (files not handled)\n // This is the best we can do in cross-platform without File support.\n const cloned = new FormData();\n for (const [k, v] of body) {\n // If value is File, attempt to clone (not fully implemented)\n if (isFile(v)) {\n // Note: Cloning File loses prototype, but rarely needed\n const file = new File([v], v.name, { type: v.type, lastModified: v.lastModified });\n cloned.append(k, file);\n } else {\n cloned.append(k, v as string);\n }\n }\n return cloned;\n }\n if (isReadableStream(body)) {\n throw new TypeError('Cannot deep clone a ReadableStream directly; use TangoBody.clone()');\n }\n if (TangoBody.isJsonValue(body)) {\n return JSON.parse(JSON.stringify(body));\n }\n return null;\n }\n\n /**\n * Read a `ReadableStream` into an `ArrayBuffer`.\n */\n static async readStreamToArrayBuffer(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer> {\n const chunks: Uint8Array[] = [];\n const reader = stream.getReader();\n let total = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n total += value.length;\n }\n const joined = new Uint8Array(total);\n let off = 0;\n for (const chunk of chunks) {\n joined.set(chunk, off);\n off += chunk.length;\n }\n return joined.buffer.slice(0, joined.byteLength) as ArrayBuffer;\n }\n\n /**\n * Read a `ReadableStream` into a `Uint8Array`.\n */\n static async readStreamToUint8Array(stream: ReadableStream<Uint8Array>): Promise<Uint8Array<ArrayBuffer>> {\n const buf = await TangoBody.readStreamToArrayBuffer(stream);\n return new Uint8Array(buf) as Uint8Array<ArrayBuffer>;\n }\n\n /**\n * Read a `ReadableStream` into UTF-8 text.\n */\n static async readStreamToText(stream: ReadableStream<Uint8Array>): Promise<string> {\n const arr = await TangoBody.readStreamToUint8Array(stream);\n return new TextDecoder().decode(arr);\n }\n\n /**\n * Determine the content type for this body, if possible.\n * Respects an explicitly passed header, otherwise infers from value type.\n */\n static detectContentType(body: TangoBodySource, providedType?: string): string | undefined {\n if (providedType) return providedType;\n if (isNil(body)) return undefined;\n if (typeof body === 'string') return 'text/plain; charset=utf-8';\n if (isArrayBuffer(body) || isUint8Array(body)) return 'application/octet-stream';\n if (isBlob(body)) {\n if (body.type) return body.type;\n return 'application/octet-stream';\n }\n if (isFormData(body)) return undefined;\n if (typeof body === 'object' && TangoBody.isJsonValue(body)) return 'application/json; charset=utf-8';\n if (isReadableStream(body)) return undefined;\n return undefined;\n }\n\n /**\n * Attempt to determine the content length, in bytes, for this body.\n * Only available for certain body types, otherwise returns undefined.\n */\n static async getContentLength(body: TangoBodySource): Promise<number | undefined> {\n if (isNil(body)) return 0;\n if (typeof body === 'string') return new TextEncoder().encode(body).length;\n if (isUint8Array(body)) return body.byteLength;\n if (isArrayBuffer(body)) return body.byteLength;\n if (isBlob(body)) return body.size;\n if (TangoBody.isJsonValue(body)) return new TextEncoder().encode(JSON.stringify(body)).length;\n return undefined;\n }\n\n /**\n * Reads the body as an ArrayBuffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.consumeBody(async (input) => {\n if (isArrayBuffer(input)) return input;\n if (isUint8Array(input)) {\n const copy = new Uint8Array(input.byteLength);\n copy.set(input);\n return copy.buffer;\n }\n if (typeof input === 'string') return new TextEncoder().encode(input).buffer as ArrayBuffer;\n if (isBlob(input)) return input.arrayBuffer();\n if (isReadableStream(input)) {\n return TangoBody.readStreamToArrayBuffer(input);\n }\n if (TangoBody.isJsonValue(input)) {\n // If body is object/array, encode as JSON and return buffer\n return new TextEncoder().encode(JSON.stringify(input)).buffer as ArrayBuffer;\n }\n throw new TypeError('Body is not an ArrayBuffer, Blob, string, stream, or JSON serializable object');\n });\n }\n\n /**\n * Reads the body as a Blob (browser only).\n */\n async blob(): Promise<Blob> {\n return this.consumeBody(async (input) => {\n if (isBlob(input)) return input;\n if (typeof input === 'string') return new Blob([input]);\n if (isArrayBuffer(input)) return new Blob([input]);\n if (isUint8Array(input)) return new Blob([new Uint8Array(input)]);\n if (isReadableStream(input)) {\n const buf = await TangoBody.readStreamToArrayBuffer(input);\n return new Blob([buf]);\n }\n if (TangoBody.isJsonValue(input)) {\n return new Blob([JSON.stringify(input)], { type: 'application/json' });\n }\n throw new TypeError(\n 'Body is not a Blob, string, ArrayBuffer, Uint8Array, stream, or JSON serializable object'\n );\n });\n }\n\n /**\n * Reads the body as a Uint8Array.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n return this.consumeBody(async (input) => {\n if (isUint8Array(input)) return new Uint8Array(input);\n if (isArrayBuffer(input)) return new Uint8Array(input);\n if (typeof input === 'string') return new TextEncoder().encode(input);\n if (isBlob(input)) return new Uint8Array(await input.arrayBuffer());\n if (isReadableStream(input)) {\n return TangoBody.readStreamToUint8Array(input);\n }\n if (TangoBody.isJsonValue(input)) {\n return new TextEncoder().encode(JSON.stringify(input));\n }\n throw new TypeError('Body is not bytes, ArrayBuffer, Blob, string, stream, or JSON serializable object');\n });\n }\n\n /**\n * Reads the body as FormData.\n * Accepts FormData, or if type is urlencoded or multipart parses a string/bytes.\n */\n async formData(): Promise<FormData> {\n return this.consumeBody(async (input) => {\n if (isFormData(input)) return input;\n\n let contentType: string | undefined = undefined;\n if (this.headers && typeof this.headers.get === 'function') {\n const raw = this.headers.get('Content-Type');\n if (typeof raw === 'string') contentType = raw.toLowerCase();\n }\n\n let raw: string;\n if (typeof input === 'string') {\n raw = input;\n } else if (isArrayBuffer(input)) {\n raw = new TextDecoder().decode(input);\n } else if (isUint8Array(input)) {\n raw = new TextDecoder().decode(input);\n } else {\n throw new TypeError('Body is not valid for FormData');\n }\n\n // application/x-www-form-urlencoded\n if (contentType && contentType.includes('application/x-www-form-urlencoded')) {\n const form = new FormData();\n const params = new URLSearchParams(raw);\n params.forEach((value, key) => form.append(key, value));\n return form;\n }\n // multipart/form-data\n if (contentType && contentType.startsWith('multipart/form-data')) {\n const boundaryMatch = /boundary=([^\\s;]+)/i.exec(contentType);\n if (!boundaryMatch) throw new TypeError('Missing boundary in multipart/form-data');\n const boundary = boundaryMatch[1];\n\n // Warning: minimal multipart parsing, no file support\n const parts = raw.split(`--${boundary}`);\n const form = new FormData();\n for (const part of parts) {\n const trimmed = part.trim();\n if (!trimmed || trimmed === '--' || trimmed === '') continue;\n\n const [rawHeaders = '', ...rawBodyParts] = trimmed.split(/\\r?\\n\\r?\\n/);\n const body = rawBodyParts.join('\\n\\n').replace(/\\r?\\n$/, '');\n const dispositionMatch = /Content-Disposition:\\s*form-data;\\s*name=\"([^\"]+)\"/i.exec(rawHeaders);\n if (!dispositionMatch) continue;\n const name = dispositionMatch[1]!;\n form.append(name, body);\n }\n return form;\n }\n throw new TypeError('Body is not FormData, nor a supported form encoding');\n });\n }\n\n /**\n * Reads and parses the body as JSON (if possible).\n */\n async json<T = unknown>(): Promise<T> {\n return this.consumeBody(async (input) => {\n if (typeof input === 'string') return JSON.parse(input) as T;\n if (TangoBody.isJsonValue(input)) return input as T;\n if (isArrayBuffer(input) || isUint8Array(input)) {\n const text = new TextDecoder().decode(isUint8Array(input) ? input : new Uint8Array(input));\n return JSON.parse(text) as T;\n }\n if (isReadableStream(input)) {\n const text = await TangoBody.readStreamToText(input);\n return JSON.parse(text) as T;\n }\n throw new TypeError('Body is not valid JSON');\n });\n }\n\n /**\n * Reads the body as UTF-8 string.\n */\n async text(): Promise<string> {\n return this.consumeBody(async (input) => {\n if (typeof input === 'string') return input;\n if (isArrayBuffer(input)) return new TextDecoder().decode(input);\n if (isUint8Array(input)) return new TextDecoder().decode(input);\n if (isBlob(input)) return await input.text();\n if (isReadableStream(input)) return await TangoBody.readStreamToText(input);\n if (TangoBody.isJsonValue(input)) return JSON.stringify(input);\n throw new TypeError('Body is not text, ArrayBuffer, Uint8Array, Blob, stream, or JSON serializable object');\n });\n }\n\n /**\n * Returns the original body value (may be used for streaming or clone).\n */\n getRawBodyInit(): TangoBodySource {\n return this.bodySourceInternal;\n }\n\n /**\n * Clone the body instance and stream if possible.\n * If the source is a stream, the stream will be cloned if readable, otherwise throws.\n */\n clone(): TangoBody {\n if (this.bodyUsedInternal) throw new TypeError('Body has already been used.');\n if (isReadableStream(this.bodySourceInternal)) {\n if (typeof this.bodySourceInternal.tee !== 'function') {\n throw new TypeError('Cannot clone: body is a ReadableStream and tee() is not available');\n }\n const [streamForOriginal, streamForClone] = this.bodySourceInternal.tee();\n this.bodySourceInternal = streamForOriginal;\n return new TangoBody(streamForClone, this.headers);\n }\n const cloneSource = TangoBody.deepCloneBody(this.bodySourceInternal);\n return new TangoBody(cloneSource, this.headers);\n }\n\n /**\n * Helper for all readers. Only allows reading once.\n */\n private async consumeBody<T>(parser: (input: TangoBodySource) => Promise<T>): Promise<T> {\n if (this.bodyUsedInternal) {\n throw new TypeError('Body has already been consumed.');\n }\n this.bodyUsedInternal = true;\n return parser(this.bodySourceInternal);\n }\n}\n","import { isArrayBuffer, isBlob, isUint8Array } from '../runtime/index';\n\n/**\n * TangoHeaders extends the Web Headers class, adding ergonomic helpers\n * for common HTTP header patterns, convenience features, and a consistent API for\n * setting, appending, and deleting headers and cookies. This is designed to be\n * used by TangoResponse and other Tango HTTP utilities.\n * Additionally, provides helpers for safely setting Content-Length based on a known body,\n * and setting Content-Disposition for inline or attachment filenames.\n *\n * Includes helpers for request tracing and correlation headers:\n * - X-Request-Id\n * - traceparent (W3C Trace Context)\n * - Server-Timing\n * - X-Response-Time\n */\nexport class TangoHeaders extends Headers {\n static readonly BRAND = 'tango.http.headers' as const;\n readonly __tangoBrand: typeof TangoHeaders.BRAND = TangoHeaders.BRAND;\n\n /**\n * Narrow an unknown value to `TangoHeaders`.\n */\n static isTangoHeaders(value: unknown): value is TangoHeaders {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoHeaders.BRAND\n );\n }\n\n /**\n * Serialize a cookie for the Set-Cookie header line.\n */\n private static serializeCookie(\n name: string,\n value: string,\n options: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n } = {}\n ): string {\n let cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value ?? '');\n if (options.domain) cookie += `; Domain=${options.domain}`;\n if (options.path) cookie += `; Path=${options.path}`;\n else cookie += '; Path=/';\n if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;\n if (typeof options.maxAge === 'number') cookie += `; Max-Age=${options.maxAge}`;\n if (options.secure) cookie += '; Secure';\n if (options.httpOnly) cookie += '; HttpOnly';\n if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;\n if (options.priority) cookie += `; Priority=${options.priority}`;\n if (options.partitioned) cookie += '; Partitioned';\n return cookie;\n }\n\n private static hasNumberSize(value: unknown): value is { size: number } {\n return typeof value === 'object' && value !== null && typeof (value as { size?: unknown }).size === 'number';\n }\n\n private static hasNumberLength(value: unknown): value is { length: number } {\n return (\n typeof value === 'object' && value !== null && typeof (value as { length?: unknown }).length === 'number'\n );\n }\n\n private static isNodeBuffer(value: unknown): value is { length: number } {\n const maybeBuffer = Buffer as unknown as { isBuffer?: (input: unknown) => boolean };\n return (\n typeof Buffer !== 'undefined' && typeof maybeBuffer.isBuffer === 'function' && maybeBuffer.isBuffer(value)\n );\n }\n\n /**\n * Sets the Content-Disposition header with type \"inline\" and the specified filename.\n * This is useful to indicate that the content should be displayed inline in the browser,\n * but with a suggested filename for saving.\n *\n * @param filename The filename to include in the Content-Disposition header.\n */\n setContentDispositionInline(filename: string): void {\n const encoded = encodeURIComponent(filename);\n this.set('Content-Disposition', `inline; filename=\"${encoded}\"; filename*=UTF-8''${encoded}`);\n }\n\n /**\n * Sets the Content-Disposition header with type \"attachment\" and the specified filename.\n * This is useful to indicate that the response should be downloaded as a file.\n *\n * @param filename The filename to include in the Content-Disposition header.\n */\n setContentDispositionAttachment(filename: string): void {\n const encoded = encodeURIComponent(filename);\n this.set('Content-Disposition', `attachment; filename=\"${encoded}\"; filename*=UTF-8''${encoded}`);\n }\n\n /**\n * Create a copy that preserves all header names and values.\n */\n clone(): TangoHeaders {\n const copy = new TangoHeaders();\n for (const [name, value] of this.entries()) {\n copy.append(name, value);\n }\n return copy;\n }\n\n /**\n * Set a header, replacing the existing value.\n */\n setHeader(name: string, value: string): void {\n this.set(name, value);\n }\n\n /**\n * Append a header, adding to existing value(s) for the name.\n */\n appendHeader(name: string, value: string): void {\n this.append(name, value);\n }\n\n /**\n * Get a header value (first value if header is repeated).\n */\n getHeader(name: string): string | null {\n return this.get(name);\n }\n\n /**\n * Check if a header exists.\n */\n hasHeader(name: string): boolean {\n return this.has(name);\n }\n\n /**\n * Delete a header.\n */\n deleteHeader(name: string): void {\n this.delete(name);\n }\n\n /**\n * Ensure a header is present only once and fully replaces the old value.\n */\n ensureUnique(name: string, value: string): void {\n this.delete(name);\n this.set(name, value);\n }\n\n /**\n * Add a field (or fields) to the Vary header, merging with existing values.\n */\n vary(...fields: string[]): void {\n if (fields.length === 0) return;\n const key = 'Vary';\n const prev = this.get(key);\n const nextSet = new Set<string>();\n if (prev) {\n for (const v of prev.split(',')) {\n if (v.trim()) nextSet.add(v.trim());\n }\n }\n for (const f of fields) {\n if (f.trim()) nextSet.add(f.trim());\n }\n this.set(key, Array.from(nextSet).join(', '));\n }\n\n /**\n * Set a cookie header (for Set-Cookie).\n * @param name\n * @param value\n * @param options\n */\n setCookie(\n name: string,\n value: string,\n options?: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.append('Set-Cookie', TangoHeaders.serializeCookie(name, value, options));\n }\n\n /**\n * Append (additionally) a new cookie.\n */\n appendCookie(\n name: string,\n value: string,\n options?: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.append('Set-Cookie', TangoHeaders.serializeCookie(name, value, options));\n }\n\n /**\n * Delete a cookie (\"unset\" it via expired date).\n */\n deleteCookie(\n name: string,\n options?: {\n domain?: string;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.setCookie(name, '', {\n ...options,\n expires: new Date(0),\n maxAge: 0,\n });\n }\n\n /**\n * Add or override Cache-Control header with helpers for common policies.\n */\n cacheControl(control: string | Record<string, string | number | boolean | undefined>): void {\n if (typeof control === 'string') {\n this.set('Cache-Control', control);\n return;\n }\n // Compose Cache-Control from object\n const parts: string[] = [];\n for (const [k, v] of Object.entries(control)) {\n if (typeof v === 'boolean') {\n if (v) parts.push(k.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase()));\n } else if (typeof v === 'number' || (typeof v === 'string' && v.length > 0)) {\n parts.push(`${k.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase())}=${v}`);\n }\n }\n if (parts.length) {\n this.set('Cache-Control', parts.join(', '));\n }\n }\n\n /**\n * Set the Location header.\n */\n location(url: string): void {\n this.set('Location', url);\n }\n\n /**\n * Set the Content-Type header.\n */\n contentType(mime: string): void {\n this.set('Content-Type', mime);\n }\n\n /**\n * Attempt to guess and set the Content-Type header from response body bytes and an optional filename.\n *\n * @param body Response body bytes (for example a Blob or Uint8Array)\n * @param filename Optional filename used to guess mime type by extension\n */\n setContentTypeForBody(body: unknown, filename?: string): void {\n if (this.has('Content-Type')) return;\n\n if (filename) {\n const dotIndex = filename.lastIndexOf('.');\n const ext = dotIndex >= 0 ? filename.slice(dotIndex + 1).toLowerCase() : '';\n const map: Record<string, string> = {\n txt: 'text/plain',\n text: 'text/plain',\n html: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n json: 'application/json',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n pdf: 'application/pdf',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n md: 'text/markdown',\n };\n const mime = map[ext];\n if (mime) {\n this.set('Content-Type', mime);\n return;\n }\n }\n\n if (isBlob(body)) {\n if (body.type && body.type !== '') {\n this.set('Content-Type', body.type);\n } else {\n this.set('Content-Type', 'application/octet-stream');\n }\n return;\n }\n\n this.set('Content-Type', 'application/octet-stream');\n }\n\n /**\n * @deprecated Use {@link TangoHeaders.setContentTypeForBody} instead.\n */\n setContentTypeByFile(body: unknown, filename?: string): void {\n this.setContentTypeForBody(body, filename);\n }\n\n /**\n * Sets the Content-Length header, inferring it from the body if not explicitly provided.\n * If the body is a string, ArrayBuffer, Uint8Array, Blob/Buffer (or has a .size or .length property),\n * the length is computed. For unsupported types, does nothing.\n * Mirrors logic from TangoResponse.ts, but generalized for use anywhere.\n */\n setContentLengthFromBody(body: unknown): void {\n if (this.has('Content-Length') || body === null || body === undefined) {\n return;\n }\n\n let len: number | undefined;\n\n if (typeof body === 'string') {\n len = new TextEncoder().encode(body).length;\n } else if (isArrayBuffer(body)) {\n len = body.byteLength;\n }\n // Node.js Buffer support (Buffer.isBuffer and .length)\n else if (TangoHeaders.isNodeBuffer(body)) {\n len = (body as { length: number }).length;\n } else if (isUint8Array(body)) {\n len = body.byteLength;\n } else if (isBlob(body)) {\n len = body.size;\n }\n // Generic \"size\" (number) property\n else if (TangoHeaders.hasNumberSize(body)) {\n len = (body as { size: number }).size;\n }\n // Generic \"length\" (number) property but not string/ArrayBuffer/Uint8Array/etc\n else if (\n TangoHeaders.hasNumberLength(body) &&\n typeof body !== 'string' &&\n !isArrayBuffer(body) &&\n !isUint8Array(body)\n ) {\n len = (body as { length: number }).length;\n }\n\n if (typeof len === 'number') {\n this.set('Content-Length', len.toString());\n }\n }\n\n /**\n * Set or update the X-Request-Id header. Used for associating a request/response with a unique id.\n * @param id The request id value to set.\n */\n withRequestId(id: string): this {\n this.set('X-Request-Id', id);\n return this;\n }\n\n /**\n * Set or update the traceparent header. Used for distributed trace context propagation (W3C Trace Context).\n * @param value The traceparent value (should be a valid traceparent header value).\n */\n withTraceParent(value: string): this {\n this.set('traceparent', value);\n return this;\n }\n\n /**\n * Set or append a value to the Server-Timing header.\n * For a single metric, supply name, and optionally dur and desc.\n * For advanced usage (many metrics), set the value directly or use appendServerTimingRaw.\n *\n * @param name Name of the server-timing metric (e.g., 'total', 'db').\n * @param dur Optional duration in ms.\n * @param desc Optional string description.\n */\n withServerTiming(name: string, dur?: number, desc?: string): this {\n // Build the metric string per spec: <metric>=<value>;dur=<duration>;desc=\"<description>\"\n let metric = name;\n if (typeof dur === 'number') {\n metric += `;dur=${dur}`;\n }\n if (desc) {\n metric += `;desc=\"${desc.replace(/\"/g, '\\\\\"')}\"`;\n }\n\n // Set or append. If header exists, append, separated by comma.\n const prev = this.get('Server-Timing');\n if (prev && prev.length > 0) {\n this.set('Server-Timing', prev + ', ' + metric);\n } else {\n this.set('Server-Timing', metric);\n }\n return this;\n }\n\n /**\n * Directly append a raw Server-Timing metric value.\n * This is useful for advanced cases where you have multiple metrics assembled.\n * @param value The server-timing value chunk to append.\n */\n appendServerTimingRaw(value: string): this {\n const prev = this.get('Server-Timing');\n if (prev && prev.length > 0) {\n this.set('Server-Timing', prev + ', ' + value);\n } else {\n this.set('Server-Timing', value);\n }\n return this;\n }\n\n /**\n * Set or update X-Response-Time header.\n * @param ms Elapsed time in milliseconds (number or string for flexibility).\n */\n withResponseTime(ms: number | string): this {\n this.set('X-Response-Time', typeof ms === 'number' ? `${ms}ms` : ms);\n return this;\n }\n\n /**\n * Return the current value of X-Request-Id.\n */\n getRequestId(): string | null {\n return this.get('X-Request-Id');\n }\n\n /**\n * Return the current value of traceparent header.\n */\n getTraceParent(): string | null {\n return this.get('traceparent');\n }\n\n /**\n * Return the current Server-Timing string, if set.\n */\n getServerTiming(): string | null {\n return this.get('Server-Timing');\n }\n\n /**\n * Return the current X-Response-Time string, if set.\n */\n getResponseTime(): string | null {\n return this.get('X-Response-Time');\n }\n}\n","import type { TangoRequest } from './TangoRequest';\n\ntype QueryParamRecord = Record<string, string | string[] | undefined>;\ntype QueryParamMutationValue = string | number | readonly (string | number)[] | null | undefined;\ntype QueryParamMutationRecord = Record<string, QueryParamMutationValue>;\n\n/**\n * Immutable query parameter helper that normalizes framework-specific shapes\n * into one Tango-owned API.\n */\nexport class TangoQueryParams {\n static readonly BRAND = 'tango.http.query_params' as const;\n readonly __tangoBrand: typeof TangoQueryParams.BRAND = TangoQueryParams.BRAND;\n private readonly values: Map<string, readonly string[]>;\n\n private constructor(values: Map<string, readonly string[]>) {\n this.values = values;\n }\n\n /**\n * Narrow an unknown value to `TangoQueryParams`.\n */\n static isTangoQueryParams(value: unknown): value is TangoQueryParams {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoQueryParams.BRAND\n );\n }\n\n /**\n * Build query params from a `URLSearchParams` instance.\n */\n static fromURLSearchParams(params: URLSearchParams): TangoQueryParams {\n const values = new Map<string, string[]>();\n\n for (const [key, value] of params.entries()) {\n const current = values.get(key);\n if (current) {\n current.push(value);\n continue;\n }\n values.set(key, [value]);\n }\n\n return new TangoQueryParams(values);\n }\n\n /**\n * Build query params from framework record-style search params.\n */\n static fromRecord(params: QueryParamRecord): TangoQueryParams {\n const values = new Map<string, string[]>();\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n const normalized = value.filter((entry) => typeof entry === 'string');\n if (normalized.length > 0) {\n values.set(key, normalized);\n }\n continue;\n }\n\n if (typeof value === 'string') {\n values.set(key, [value]);\n }\n }\n\n return new TangoQueryParams(values);\n }\n\n /**\n * Build query params from a full URL string or URL object.\n */\n static fromURL(input: string | URL): TangoQueryParams {\n const url = typeof input === 'string' ? new URL(input) : input;\n return TangoQueryParams.fromURLSearchParams(url.searchParams);\n }\n\n /**\n * Build query params from a request-like object with a URL.\n */\n static fromRequest(request: Request | TangoRequest): TangoQueryParams {\n return TangoQueryParams.fromURL(request.url);\n }\n\n /**\n * Get the first value for a query param.\n */\n get(name: string): string | undefined {\n return this.values.get(name)?.[0];\n }\n\n /**\n * Get all values for a query param.\n */\n getAll(name: string): string[] {\n return [...(this.values.get(name) ?? [])];\n }\n\n /**\n * Check whether a query param exists.\n */\n has(name: string): boolean {\n return (this.values.get(name)?.length ?? 0) > 0;\n }\n\n /**\n * Iterate key -> values entries.\n */\n *entries(): IterableIterator<[string, string[]]> {\n for (const [key, values] of this.values.entries()) {\n yield [key, [...values]];\n }\n }\n\n /**\n * Iterate keys present in the query params.\n */\n *keys(): IterableIterator<string> {\n yield* this.values.keys();\n }\n\n /**\n * Convert back to a native `URLSearchParams` object.\n */\n toURLSearchParams(): URLSearchParams {\n const params = new URLSearchParams();\n\n for (const [key, values] of this.values.entries()) {\n for (const value of values) {\n params.append(key, value);\n }\n }\n\n return params;\n }\n\n /**\n * Return a new query param set with selected keys replaced or removed.\n *\n * `undefined`, `null`, and empty arrays remove the key entirely.\n */\n withValues(updates: QueryParamMutationRecord): TangoQueryParams {\n const next = new Map<string, string[]>();\n\n for (const [key, values] of this.values.entries()) {\n next.set(key, [...values]);\n }\n\n for (const [key, value] of Object.entries(updates)) {\n if (value === undefined || value === null) {\n next.delete(key);\n continue;\n }\n\n const normalized = Array.isArray(value) ? value.map((entry) => String(entry)) : [String(value)];\n if (normalized.length === 0) {\n next.delete(key);\n continue;\n }\n\n next.set(key, normalized);\n }\n\n return new TangoQueryParams(next);\n }\n\n /**\n * Convert to a relative query string suitable for links.\n */\n toRelativeURL(): string {\n const query = this.toURLSearchParams().toString();\n return query.length > 0 ? `?${query}` : '';\n }\n\n /**\n * Get a trimmed value, omitting blank strings.\n */\n getTrimmed(name: string): string | undefined {\n const value = this.get(name)?.trim();\n return value ? value : undefined;\n }\n\n /**\n * Get the free-text search param using Tango's default key.\n */\n getSearch(key: string = 'search'): string | undefined {\n return this.getTrimmed(key);\n }\n\n /**\n * Get the ordering param as trimmed field tokens.\n */\n getOrdering(key: string = 'ordering'): string[] {\n const value = this.get(key);\n if (!value) {\n return [];\n }\n\n return value\n .split(',')\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n }\n}\n","import type { JsonValue } from './TangoBody';\nimport { TangoQueryParams } from './TangoQueryParams';\nimport {\n isArrayBuffer,\n isBlob,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\n\ntype TangoRequestInit = {\n method?: string;\n headers?: HeadersInit;\n body?: BodyInit | JsonValue | null;\n redirect?: RequestRedirect;\n cache?: RequestCache;\n credentials?: RequestCredentials;\n integrity?: string;\n keepalive?: boolean;\n mode?: RequestMode;\n referrer?: string;\n referrerPolicy?: ReferrerPolicy;\n signal?: AbortSignal;\n};\n\n/**\n * Framework request wrapper that normalizes JSON-like bodies and preserves\n * fetch `Request` compatibility for downstream handlers.\n */\nexport class TangoRequest implements Request {\n static readonly BRAND = 'tango.http.request' as const;\n readonly __tangoBrand: typeof TangoRequest.BRAND = TangoRequest.BRAND;\n private request: Request;\n private bodySourceValue: BodyInit | JsonValue | null;\n private queryParamsValue?: TangoQueryParams;\n\n constructor(input: string | Request, init: TangoRequestInit = {}) {\n const sourceRequest = typeof input === 'string' ? undefined : input;\n const method = (init.method ?? sourceRequest?.method ?? 'GET').toUpperCase();\n const headers = new Headers(init.headers ?? sourceRequest?.headers);\n const normalizedBody = this.normalizeBody(init.body, headers, method);\n\n const requestInit: RequestInit & { duplex?: 'half' } = {\n method,\n headers,\n redirect: init.redirect ?? sourceRequest?.redirect,\n cache: init.cache ?? sourceRequest?.cache,\n credentials: init.credentials ?? sourceRequest?.credentials,\n integrity: init.integrity ?? sourceRequest?.integrity,\n keepalive: init.keepalive ?? sourceRequest?.keepalive,\n mode: init.mode ?? sourceRequest?.mode,\n referrer: init.referrer ?? sourceRequest?.referrer,\n referrerPolicy: init.referrerPolicy ?? sourceRequest?.referrerPolicy,\n signal: init.signal ?? sourceRequest?.signal,\n };\n\n if (normalizedBody !== undefined) {\n requestInit.body = normalizedBody;\n if (isReadableStream(normalizedBody)) {\n requestInit.duplex = 'half';\n }\n }\n\n this.request = new Request(input, requestInit);\n this.bodySourceValue = normalizedBody ?? null;\n }\n\n /**\n * Narrow an unknown value to `TangoRequest`.\n */\n static isTangoRequest(value: unknown): value is TangoRequest {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoRequest.BRAND\n );\n }\n\n /**\n * Expose the request cache mode from the underlying fetch request.\n */\n get cache(): RequestCache {\n return this.request.cache;\n }\n\n /**\n * Expose the request credentials mode from the underlying fetch request.\n */\n get credentials(): RequestCredentials {\n return this.request.credentials;\n }\n\n /**\n * Expose the request destination from the underlying fetch request.\n */\n get destination(): RequestDestination {\n return this.request.destination;\n }\n\n /**\n * Expose the request headers from the underlying fetch request.\n */\n get headers(): Headers {\n return this.request.headers;\n }\n\n /**\n * Expose the request integrity value from the underlying fetch request.\n */\n get integrity(): string {\n return this.request.integrity;\n }\n\n /**\n * Expose the request keepalive flag from the underlying fetch request.\n */\n get keepalive(): boolean {\n return this.request.keepalive;\n }\n\n /**\n * Expose the normalized HTTP method.\n */\n get method(): string {\n return this.request.method;\n }\n\n /**\n * Expose the request mode from the underlying fetch request.\n */\n get mode(): RequestMode {\n return this.request.mode;\n }\n\n /**\n * Expose the redirect policy from the underlying fetch request.\n */\n get redirect(): RequestRedirect {\n return this.request.redirect;\n }\n\n /**\n * Expose the referrer from the underlying fetch request.\n */\n get referrer(): string {\n return this.request.referrer;\n }\n\n /**\n * Expose the referrer policy from the underlying fetch request.\n */\n get referrerPolicy(): ReferrerPolicy {\n return this.request.referrerPolicy;\n }\n\n /**\n * Expose the abort signal from the underlying fetch request.\n */\n get signal(): AbortSignal {\n return this.request.signal;\n }\n\n /**\n * Expose the absolute request URL.\n */\n get url(): string {\n return this.request.url;\n }\n\n /**\n * Expose the readable request body stream when one exists.\n */\n get body(): Request['body'] {\n return this.request.body;\n }\n\n /**\n * Report whether the body has been consumed.\n */\n get bodyUsed(): boolean {\n return this.request.bodyUsed;\n }\n\n /**\n * Expose the pre-normalized body value used to build the request.\n */\n get bodySource(): BodyInit | JsonValue | null {\n return this.bodySourceValue;\n }\n\n /**\n * Expose normalized query parameters derived from the request URL.\n */\n get queryParams(): TangoQueryParams {\n this.queryParamsValue ??= TangoQueryParams.fromURL(this.request.url);\n return this.queryParamsValue;\n }\n\n /**\n * Read the request body as an array buffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.request.arrayBuffer();\n }\n\n /**\n * Read the request body as a blob.\n */\n async blob(): Promise<Blob> {\n return this.request.blob();\n }\n\n /**\n * Read the request body as bytes, including runtimes without `Request.bytes()`.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n const requestWithBytes = this.request as Request & { bytes?: () => Promise<Uint8Array<ArrayBuffer>> };\n if (typeof requestWithBytes.bytes === 'function') {\n return requestWithBytes.bytes();\n }\n const buffer = await this.request.arrayBuffer();\n return new Uint8Array(buffer);\n }\n\n /**\n * Read the request body as form data.\n */\n async formData(): Promise<FormData> {\n return this.request.formData();\n }\n\n /**\n * Parse the request body as JSON.\n */\n async json<T = unknown>(): Promise<T> {\n return this.request.json() as Promise<T>;\n }\n\n /**\n * Read the request body as text.\n */\n async text(): Promise<string> {\n return this.request.text();\n }\n\n /**\n * Clone the request so downstream code can consume it independently.\n */\n clone(): TangoRequest {\n return new TangoRequest(this.request.clone());\n }\n\n private normalizeBody(\n body: BodyInit | JsonValue | null | undefined,\n headers: Headers,\n method: string\n ): BodyInit | undefined {\n if (method === 'GET' || method === 'HEAD') {\n return undefined;\n }\n if (isNil(body)) {\n return undefined;\n }\n if (typeof body === 'string') {\n return body;\n }\n if (isArrayBuffer(body) || isUint8Array(body) || isBlob(body)) {\n return body;\n }\n if (isURLSearchParams(body) || isFormData(body) || isReadableStream(body)) {\n return body as BodyInit;\n }\n\n const serialized = JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json; charset=utf-8');\n }\n return serialized;\n }\n}\n","import { TangoError, type ErrorEnvelope, type ErrorDetails, type ProblemDetails } from '../errors/TangoError';\nimport {\n isArrayBuffer,\n isBlob,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\nimport { TangoHeaders } from '../http/TangoHeaders';\nimport { TangoBody, type JsonValue } from './TangoBody';\n\ntype TangoResponseInit = {\n body?: BodyInit | JsonValue | null;\n headers?: HeadersInit;\n ok?: boolean;\n redirected?: boolean;\n status?: number;\n statusText?: string;\n type?: ResponseType;\n url?: string;\n};\n\n/**\n * Framework response wrapper with fetch-compatible surface plus ergonomic helpers.\n */\nexport class TangoResponse implements Response {\n static readonly BRAND = 'tango.http.response' as const;\n readonly __tangoBrand: typeof TangoResponse.BRAND = TangoResponse.BRAND;\n readonly headers: TangoHeaders;\n readonly redirected: boolean;\n readonly status: number;\n readonly statusText: string;\n readonly type: ResponseType;\n readonly url: string;\n readonly body: Response['body'];\n private tangoBody: TangoBody;\n private okValue: boolean | undefined;\n\n constructor(init: TangoResponseInit = {}) {\n this.headers = new TangoHeaders(init.headers);\n this.redirected = Boolean(init.redirected);\n this.status = typeof init.status === 'number' ? init.status : 200;\n this.statusText = init.statusText || '';\n this.type = init.type || 'default';\n this.url = init.url || '';\n this.okValue = typeof init.ok === 'boolean' ? init.ok : undefined;\n\n this.tangoBody = new TangoBody(init.body ?? null, this.headers);\n this.body = isReadableStream(this.tangoBody.bodySource) ? this.tangoBody.bodySource : null;\n }\n\n /**\n * Narrow an unknown value to `TangoResponse`.\n */\n static isTangoResponse(value: unknown): value is TangoResponse {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoResponse.BRAND\n );\n }\n\n /**\n * Create a JSON response with sensible content headers.\n */\n static json(\n data: JsonValue,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json; charset=utf-8');\n }\n const body = JSON.stringify(data);\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(body).length.toString());\n }\n return new TangoResponse({\n ...init,\n body,\n headers,\n });\n }\n\n /**\n * Create a plain-text response with sensible content headers.\n */\n static text(\n text: string,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'text/plain; charset=utf-8');\n }\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(text).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: text,\n headers,\n });\n }\n\n /**\n * Create an HTML response with sensible content headers.\n */\n static html(\n html: string,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'text/html; charset=utf-8');\n }\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(html).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: html,\n headers,\n });\n }\n\n /**\n * Create a streaming response without buffering the payload in memory.\n */\n static stream(\n stream: ReadableStream<Uint8Array>,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n return new TangoResponse({\n ...init,\n body: stream,\n headers: new TangoHeaders(init?.headers),\n });\n }\n\n /**\n * Create a redirect response and set the `Location` header.\n */\n static redirect(\n url: string,\n status: number = 302,\n init?: Omit<TangoResponseInit, 'body' | 'headers' | 'status'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n headers.set('Location', url);\n return new TangoResponse({\n ...init,\n body: undefined,\n status,\n headers,\n redirected: true,\n url,\n });\n }\n\n /**\n * Create an empty `204 No Content` response.\n */\n static noContent(\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n return new TangoResponse({\n ...init,\n body: undefined,\n status: 204,\n headers,\n });\n }\n\n /**\n * Create a `201 Created` response and optionally attach a location or body.\n */\n static created(\n location?: string,\n body?: JsonValue,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (location) {\n headers.set('Location', location);\n }\n let respBody: BodyInit | undefined;\n if (body !== undefined) {\n respBody = JSON.stringify(body);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json; charset=utf-8');\n }\n }\n if (typeof respBody === 'string' && !headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(respBody).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: respBody,\n status: 201,\n headers,\n });\n }\n\n /**\n * Create a `405 Method Not Allowed` response and optionally populate `Allow`.\n */\n static methodNotAllowed<TDetails extends ErrorDetails = null>(\n allow?: readonly string[],\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (allow && allow.length > 0) {\n headers.set('Allow', allow.join(', '));\n }\n\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 405, headers });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'method_not_allowed',\n message: detail,\n },\n { ...init, status: 405, headers }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'method_not_allowed',\n message: 'Method not allowed.',\n },\n { ...init, status: 405, headers }\n );\n }\n\n /**\n * Normalize a Tango error or problem-details object into an error response.\n */\n static error<TDetails extends ErrorDetails = null>(\n error: TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n let code: string;\n let message: string;\n let details: ErrorDetails;\n let fields: Record<string, string[]> | undefined;\n let status = init?.status ?? 500;\n\n if (TangoError.isTangoError(error)) {\n const envelope = error.toErrorEnvelope();\n code = envelope.error.code;\n message = envelope.error.message;\n details = envelope.error.details;\n fields = envelope.error.fields;\n status = error.status;\n } else {\n code = error.code;\n message = error.message;\n details = error.details;\n fields = error.fields;\n }\n\n return TangoResponse.problem(\n {\n code,\n message,\n details,\n fields,\n },\n {\n ...init,\n status,\n }\n );\n }\n\n /**\n * Create a `400 Bad Request` response from a string or structured error.\n */\n static badRequest<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 400 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'bad_request',\n message: detail,\n },\n { ...init, status: 400 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'bad_request',\n message: 'Bad Request',\n },\n { ...init, status: 400 }\n );\n }\n\n /**\n * Create a `401 Unauthorized` response from a string or structured error.\n */\n static unauthorized<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 401 });\n }\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'unauthorized',\n message: detail,\n },\n { ...init, status: 401 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'unauthorized',\n message: 'Unauthorized',\n },\n { ...init, status: 401 }\n );\n }\n\n /**\n * Create a `403 Forbidden` response from a string or structured error.\n */\n static forbidden<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 403 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'forbidden',\n message: detail,\n },\n { ...init, status: 403 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'forbidden',\n message: 'Forbidden',\n },\n { ...init, status: 403 }\n );\n }\n\n /**\n * Create a `404 Not Found` response from a string or structured error.\n */\n static notFound<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 404 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'not_found',\n message: detail,\n },\n { ...init, status: 404 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'not_found',\n message: 'Not Found',\n },\n { ...init, status: 404 }\n );\n }\n\n /**\n * Create a `409 Conflict` response from a string or structured error.\n */\n static conflict<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 409 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'conflict',\n message: detail,\n },\n { ...init, status: 409 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'conflict',\n message: 'Conflict',\n },\n { ...init, status: 409 }\n );\n }\n\n /**\n * Create a `422 Unprocessable Entity` response from a string or structured error.\n */\n static unprocessableEntity<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 422 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'unprocessable_entity',\n message: detail,\n },\n { ...init, status: 422 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'unprocessable_entity',\n message: 'Unprocessable Entity',\n },\n { ...init, status: 422 }\n );\n }\n\n /**\n * Create a `429 Too Many Requests` response from a string or structured error.\n */\n static tooManyRequests<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 429 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'too_many_requests',\n message: detail,\n },\n { ...init, status: 429 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'too_many_requests',\n message: 'Too Many Requests',\n },\n { ...init, status: 429 }\n );\n }\n\n /**\n * Create a problem-details style error response with Tango's envelope shape.\n */\n static problem<TDetails extends ErrorDetails = null>(\n problem?: string | TangoError | ProblemDetails<TDetails> | unknown,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & {\n headers?: HeadersInit;\n status?: number;\n }\n ): TangoResponse {\n let status = init?.status ?? 500;\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/problem+json; charset=utf-8');\n }\n\n let code = 'error';\n let message = 'An error occurred';\n let details: ErrorDetails = undefined;\n let fields: Record<string, string[]> | undefined;\n\n if (TangoError.isTangoError(problem)) {\n const envelope = problem.toErrorEnvelope();\n status = problem.status;\n code = envelope.error.code;\n message = envelope.error.message;\n details = envelope.error.details;\n fields = envelope.error.fields;\n } else if (TangoError.isProblemDetails(problem)) {\n code = problem.code;\n message = problem.message;\n details = problem.details;\n fields = problem.fields;\n } else if (typeof problem === 'string') {\n message = problem;\n } else if (problem && typeof problem === 'object') {\n const extracted = problem as {\n details?: ErrorDetails;\n fields?: Record<string, string[]>;\n };\n details = extracted.details;\n fields = extracted.fields;\n }\n\n const envelope: ErrorEnvelope<ErrorDetails> = {\n error: {\n code,\n message,\n ...(details === undefined ? {} : { details }),\n ...(fields ? { fields } : {}),\n },\n };\n\n const body = JSON.stringify(envelope);\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(body).length.toString());\n }\n return new TangoResponse({\n ...init,\n headers,\n status,\n body,\n });\n }\n\n /**\n * Create a response with inline Content-Disposition for file-like body content.\n *\n * The first argument is response body bytes, not a filesystem path. To serve bytes\n * from disk, read the file first and pass the result here.\n *\n * @example\n * ```ts\n * import { readFile } from 'node:fs/promises';\n *\n * const bytes = await readFile('/data/report.pdf');\n * return TangoResponse.file(bytes, { filename: 'report.pdf' });\n * ```\n */\n static file(\n body: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>,\n opts?: {\n filename?: string;\n contentType?: string;\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit };\n }\n ): TangoResponse {\n const headers = new TangoHeaders(opts?.init?.headers ?? {});\n if (opts?.filename) {\n headers.setContentDispositionInline(opts.filename);\n }\n if (opts?.contentType && !headers.has('Content-Type')) {\n headers.set('Content-Type', opts.contentType);\n } else if (!headers.has('Content-Type')) {\n headers.setContentTypeForBody(body, opts?.filename);\n }\n if (!headers.has('Content-Length')) {\n headers.setContentLengthFromBody(body);\n }\n return new TangoResponse({\n ...opts?.init,\n body: body as BodyInit,\n headers,\n });\n }\n\n /**\n * Create a response with attachment Content-Disposition for file-like body content.\n *\n * The first argument must be the response body bytes, not a filesystem path. To serve bytes\n * from disk, read the file first and pass the result here.\n *\n * @example\n * ```ts\n * import { readFile } from 'node:fs/promises';\n *\n * const bytes = await readFile('/data/report.pdf');\n * return TangoResponse.download(bytes, { filename: 'report.pdf' });\n * ```\n */\n static download(\n body: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>,\n opts?: {\n filename?: string;\n contentType?: string;\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit };\n }\n ): TangoResponse {\n const headers = new TangoHeaders(opts?.init?.headers ?? {});\n if (opts?.filename) {\n headers.setContentDispositionAttachment(opts.filename);\n } else {\n headers.set('Content-Disposition', 'attachment');\n }\n if (opts?.contentType && !headers.has('Content-Type')) {\n headers.set('Content-Type', opts.contentType);\n } else if (!headers.has('Content-Type')) {\n headers.setContentTypeForBody(body, opts?.filename);\n }\n if (!headers.has('Content-Length')) {\n headers.setContentLengthFromBody(body);\n }\n return new TangoResponse({\n ...opts?.init,\n body: body as BodyInit,\n headers,\n });\n }\n\n private static normalizeWebBody(body: BodyInit | JsonValue | null): BodyInit | null {\n if (\n isNil(body) ||\n typeof body === 'string' ||\n isBlob(body) ||\n isFormData(body) ||\n isArrayBuffer(body) ||\n isUint8Array(body) ||\n isURLSearchParams(body) ||\n isReadableStream(body)\n ) {\n return body;\n }\n\n return JSON.stringify(body);\n }\n\n /**\n * Expose the original body source for cloning and adapter integration.\n */\n get bodySource(): BodyInit | JsonValue | null {\n return this.tangoBody.bodySource;\n }\n\n /**\n * Report whether the status code falls inside the 2xx range.\n */\n get ok(): boolean {\n if (typeof this.okValue === 'boolean') return this.okValue;\n return this.status >= 200 && this.status < 300;\n }\n\n /**\n * Report whether the body has been consumed.\n */\n get bodyUsed(): boolean {\n return this.tangoBody.bodyUsed;\n }\n\n /**\n * Replace a header value on the response.\n */\n setHeader(name: string, value: string): void {\n this.headers.set(name, value);\n }\n /**\n * Append another value for a repeated response header.\n */\n appendHeader(name: string, value: string): void {\n this.headers.append(name, value);\n }\n /**\n * Read a response header value.\n */\n getHeader(name: string): string | null {\n return this.headers.get(name);\n }\n /**\n * Check whether a response header is present.\n */\n hasHeader(name: string): boolean {\n return this.headers.has(name);\n }\n /**\n * Remove a response header.\n */\n deleteHeader(name: string): void {\n this.headers.delete(name);\n }\n /**\n * Merge one or more values into the `Vary` header.\n */\n vary(...fields: string[]): void {\n this.headers.vary(...fields);\n }\n\n /**\n * Add a `Set-Cookie` header that replaces prior application intent.\n */\n setCookie(name: string, value: string, options?: Parameters<TangoHeaders['setCookie']>[2]): void {\n this.headers.setCookie(name, value, options);\n }\n /**\n * Append another `Set-Cookie` header.\n */\n appendCookie(name: string, value: string, options?: Parameters<TangoHeaders['appendCookie']>[2]): void {\n this.headers.appendCookie(name, value, options);\n }\n /**\n * Expire a cookie by issuing a matching deletion cookie header.\n */\n deleteCookie(name: string, options?: Parameters<TangoHeaders['deleteCookie']>[1]): void {\n this.headers.deleteCookie(name, options);\n }\n\n /**\n * Set the `Cache-Control` header through Tango's higher-level helper.\n */\n cacheControl(control: Parameters<TangoHeaders['cacheControl']>[0]): void {\n this.headers.cacheControl(control);\n }\n\n /**\n * Set the `Location` header on the response.\n */\n location(url: string): void {\n this.headers.location(url);\n }\n\n /**\n * Set the response content type.\n */\n contentType(mime: string): void {\n this.headers.contentType(mime);\n }\n\n // ---- Trace & Correlation helper methods ----\n\n /**\n * Set the X-Request-Id header (request correlation).\n * Returns this for fluent chaining.\n */\n withRequestId(requestId: string | undefined | null): this {\n if (!isNil(requestId) && typeof requestId === 'string' && requestId !== '') {\n this.headers.set('X-Request-Id', requestId);\n }\n return this;\n }\n\n /**\n * Set the traceparent header (W3C Trace Context propagation).\n * Returns this for fluent chaining.\n */\n withTraceparent(traceparent: string | undefined | null): this {\n if (!isNil(traceparent) && typeof traceparent === 'string' && traceparent !== '') {\n this.headers.set('traceparent', traceparent);\n }\n return this;\n }\n\n /**\n * Set the Server-Timing header.\n * Accepts a string or array of timing metrics.\n * Returns this for fluent chaining.\n */\n withServerTiming(timing: string | string[]): this {\n if (Array.isArray(timing)) {\n this.headers.set('Server-Timing', timing.join(', '));\n } else if (typeof timing === 'string') {\n this.headers.set('Server-Timing', timing);\n }\n return this;\n }\n\n /**\n * Set the X-Response-Time header (in ms).\n * Numeric or formatted string (e.g. \"76ms\").\n * Returns this for fluent chaining.\n */\n withResponseTime(time: number | string): this {\n if (typeof time === 'number') {\n this.headers.set('X-Response-Time', `${time}ms`);\n } else if (typeof time === 'string') {\n this.headers.set('X-Response-Time', time);\n }\n return this;\n }\n\n /**\n * Propagate common tracing/correlation headers from provided Headers, TangoHeaders, or plain object.\n * Known headers: x-request-id, traceparent, server-timing\n * Returns this for fluent chaining.\n */\n propagateTraceHeaders(input: HeadersInit): this {\n const incoming = new TangoHeaders(input);\n const traceHeaderNames = [\n 'x-request-id',\n 'traceparent',\n 'server-timing',\n // If you want to propagate response time, add 'x-response-time',\n ];\n for (const name of traceHeaderNames) {\n const value = incoming.get(name);\n if (!isNil(value)) this.headers.set(name, value);\n }\n return this;\n }\n\n /**\n * Clone the response so its body can be consumed independently.\n */\n clone(): TangoResponse {\n if (this.bodyUsed) {\n throw new TypeError('Body has already been used');\n }\n const clonedBody = this.tangoBody.clone();\n return new TangoResponse({\n body: clonedBody.bodySource,\n headers: this.headers.clone(),\n ok: this.okValue,\n redirected: this.redirected,\n status: this.status,\n statusText: this.statusText,\n type: this.type,\n url: this.url,\n });\n }\n\n /**\n * Convert this Tango-owned response into a native web `Response`.\n *\n * Adapters use this at the host-framework boundary so Tango can standardize\n * on `TangoResponse` internally while Next.js and other hosts still receive\n * a platform-native response object.\n */\n toWebResponse(): Response {\n const responseForTransfer = !this.bodyUsed && isReadableStream(this.bodySource) ? this.clone() : this;\n const body = TangoResponse.normalizeWebBody(responseForTransfer.bodySource);\n\n return new Response(body, {\n headers: new Headers(responseForTransfer.headers),\n status: responseForTransfer.status,\n statusText: responseForTransfer.statusText,\n });\n }\n\n //---- Spec Response interface fields and methods ----\n\n /**\n * Read the response body as an array buffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.tangoBody.arrayBuffer();\n }\n /**\n * Read the response body as a blob.\n */\n async blob(): Promise<Blob> {\n return this.tangoBody.blob();\n }\n /**\n * Read the response body as bytes.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n return this.tangoBody.bytes();\n }\n /**\n * Read the response body as form data.\n */\n async formData(): Promise<FormData> {\n return this.tangoBody.formData();\n }\n /**\n * Parse the response body as JSON.\n */\n async json<T = unknown>(): Promise<T> {\n return this.tangoBody.json<T>();\n }\n /**\n * Read the response body as text.\n */\n async text(): Promise<string> {\n return this.tangoBody.text();\n }\n\n /**\n * Returns a plain object debug representation of this response: { status, headers: { ... }, bodyType: ... }.\n * Intended for testing and debug tooling.\n */\n toJSON(): { status: number; headers: Record<string, string>; bodyType: string } {\n return {\n status: this.status,\n headers: Object.fromEntries(this.headers.entries()),\n bodyType: this.tangoBody.bodyType,\n };\n }\n\n /**\n * Returns the original body for test/debug purposes *without* consuming the stream.\n *\n * @throws {Error} if called in a production environment. Provided only for test or debug.\n * @remarks\n * This method gives direct access to the original body as provided to the constructor,\n * before consumption. It is primarily intended for use in test code, introspection, or\n * advanced debug tools. **Do not rely on this in production.**\n * In production (`process.env.NODE_ENV === 'production'`), using this method will throw.\n *\n * This method is _not_ part of the web Response interface, and is intentionally private/internal.\n */\n\n public __peekBodyForTestOnly(): BodyInit | JsonValue | null {\n const nodeEnv = typeof process !== 'undefined' ? (process.env?.NODE_ENV as string | undefined) : undefined;\n\n // Strong guard against accidental shipping in production\n if (nodeEnv === 'production' || nodeEnv === 'prod') {\n throw new Error('peekBody() is not available in production builds. For test/debug use only.');\n }\n return this.tangoBody.bodySource;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nimport { TangoBody, type JsonValue } from './TangoBody';\nimport { TangoHeaders } from './TangoHeaders';\nimport { TangoQueryParams } from './TangoQueryParams';\nimport { TangoRequest } from './TangoRequest';\nimport { TangoResponse } from './TangoResponse';\n\nexport { TangoBody, TangoHeaders, TangoQueryParams, TangoRequest, TangoResponse };\nexport type { JsonValue };\n"],"mappings":"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"}
|
|
@@ -242,12 +242,16 @@ declare class TangoHeaders extends Headers {
|
|
|
242
242
|
*/
|
|
243
243
|
contentType(mime: string): void;
|
|
244
244
|
/**
|
|
245
|
-
* Attempt to guess and set the Content-Type header from
|
|
245
|
+
* Attempt to guess and set the Content-Type header from response body bytes and an optional filename.
|
|
246
246
|
*
|
|
247
|
-
* @param
|
|
248
|
-
* @param filename Optional filename to
|
|
247
|
+
* @param body Response body bytes (for example a Blob or Uint8Array)
|
|
248
|
+
* @param filename Optional filename used to guess mime type by extension
|
|
249
249
|
*/
|
|
250
|
-
|
|
250
|
+
setContentTypeForBody(body: unknown, filename?: string): void;
|
|
251
|
+
/**
|
|
252
|
+
* @deprecated Use {@link TangoHeaders.setContentTypeForBody} instead.
|
|
253
|
+
*/
|
|
254
|
+
setContentTypeByFile(body: unknown, filename?: string): void;
|
|
251
255
|
/**
|
|
252
256
|
* Sets the Content-Length header, inferring it from the body if not explicitly provided.
|
|
253
257
|
* If the body is a string, ArrayBuffer, Uint8Array, Blob/Buffer (or has a .size or .length property),
|
|
@@ -649,9 +653,20 @@ declare class TangoResponse implements Response {
|
|
|
649
653
|
status?: number;
|
|
650
654
|
}): TangoResponse;
|
|
651
655
|
/**
|
|
652
|
-
*
|
|
656
|
+
* Create a response with inline Content-Disposition for file-like body content.
|
|
657
|
+
*
|
|
658
|
+
* The first argument is response body bytes, not a filesystem path. To serve bytes
|
|
659
|
+
* from disk, read the file first and pass the result here.
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```ts
|
|
663
|
+
* import { readFile } from 'node:fs/promises';
|
|
664
|
+
*
|
|
665
|
+
* const bytes = await readFile('/data/report.pdf');
|
|
666
|
+
* return TangoResponse.file(bytes, { filename: 'report.pdf' });
|
|
667
|
+
* ```
|
|
653
668
|
*/
|
|
654
|
-
static file(
|
|
669
|
+
static file(body: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>, opts?: {
|
|
655
670
|
filename?: string;
|
|
656
671
|
contentType?: string;
|
|
657
672
|
init?: Omit<TangoResponseInit, 'body' | 'headers'> & {
|
|
@@ -659,9 +674,20 @@ declare class TangoResponse implements Response {
|
|
|
659
674
|
};
|
|
660
675
|
}): TangoResponse;
|
|
661
676
|
/**
|
|
662
|
-
*
|
|
677
|
+
* Create a response with attachment Content-Disposition for file-like body content.
|
|
678
|
+
*
|
|
679
|
+
* The first argument must be the response body bytes, not a filesystem path. To serve bytes
|
|
680
|
+
* from disk, read the file first and pass the result here.
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* ```ts
|
|
684
|
+
* import { readFile } from 'node:fs/promises';
|
|
685
|
+
*
|
|
686
|
+
* const bytes = await readFile('/data/report.pdf');
|
|
687
|
+
* return TangoResponse.download(bytes, { filename: 'report.pdf' });
|
|
688
|
+
* ```
|
|
663
689
|
*/
|
|
664
|
-
static download(
|
|
690
|
+
static download(body: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>, opts?: {
|
|
665
691
|
filename?: string;
|
|
666
692
|
contentType?: string;
|
|
667
693
|
init?: Omit<TangoResponseInit, 'body' | 'headers'> & {
|
|
@@ -821,4 +847,4 @@ declare namespace index_d_exports {
|
|
|
821
847
|
}
|
|
822
848
|
//#endregion
|
|
823
849
|
export { TangoHeaders as a, TangoRequest as i, TangoResponse as n, JsonValue as o, TangoQueryParams as r, TangoBody as s, index_d_exports as t };
|
|
824
|
-
//# sourceMappingURL=index-
|
|
850
|
+
//# sourceMappingURL=index-hxHvR7TR.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as HttpError, i as TangoError, n as ErrorEnvelope, r as ProblemDetails, t as ErrorDetails } from "./TangoError-ptR2iApz.js";
|
|
2
2
|
import { a as MultipleObjectsReturned, i as NotFoundError, l as HttpErrorFactory, n as AuthenticationError, o as ValidationError, r as PermissionDenied, s as ConflictError, t as index_d_exports, u as HttpErrorFactoryConfig } from "./index-DFWodYLS.js";
|
|
3
|
-
import { a as TangoHeaders, i as TangoRequest, n as TangoResponse, o as JsonValue, r as TangoQueryParams, s as TangoBody, t as index_d_exports$1 } from "./index-
|
|
3
|
+
import { a as TangoHeaders, i as TangoRequest, n as TangoResponse, o as JsonValue, r as TangoQueryParams, s as TangoBody, t as index_d_exports$1 } from "./index-hxHvR7TR.js";
|
|
4
4
|
import { a as ConsoleLogger, i as setLoggerFactory, n as getLogger, o as Logger, r as resetLoggerFactory, t as index_d_exports$2 } from "./index-MZzjIxgD.js";
|
|
5
5
|
import { _ as isArrayBuffer, a as isError, c as isObject, d as isReadableStream, f as isURLSearchParams, g as isUint8Array, h as isBlob, p as isFormData, r as isDate, t as index_d_exports$3, u as isFile } from "./index-B5PoK4LH.js";
|
|
6
6
|
import { a as trustedSql, c as SqlRawFragmentRequest, d as ValidatedSqlLookupToken, f as ValidatedSqlSafetyResult, g as SqlDialect, h as SqlIdentifierRole, i as isTrustedSqlFragment, l as SqlSafetyEngine, m as TrustedSqlFragment, n as quoteSqlIdentifier, o as SqlIdentifierRequest, p as ValidatedSqlIdentifier, r as validateSqlIdentifier, s as SqlLookupTokenRequest, t as index_d_exports$4, u as SqlSafetyRequest } from "./index-DPABSINz.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { t as TangoError } from "./TangoError-Cvgnm026.js";
|
|
2
2
|
import { a as isError, d as isURLSearchParams, f as isFormData, g as isArrayBuffer, h as isUint8Array, l as isFile, m as isBlob, r as isDate, s as isObject, t as runtime_exports, u as isReadableStream } from "./runtime-BAG_EKuM.js";
|
|
3
3
|
import { a as MultipleObjectsReturned, i as NotFoundError, l as HttpErrorFactory, n as AuthenticationError, o as ValidationError, r as PermissionDenied, s as ConflictError, t as errors_exports } from "./errors-DpI5Dxmr.js";
|
|
4
|
-
import { a as TangoHeaders, i as TangoQueryParams, n as TangoResponse, o as TangoBody, r as TangoRequest, t as http_exports } from "./http-
|
|
4
|
+
import { a as TangoHeaders, i as TangoQueryParams, n as TangoResponse, o as TangoBody, r as TangoRequest, t as http_exports } from "./http-DP2xzidS.js";
|
|
5
5
|
import { a as ConsoleLogger, i as setLoggerFactory, n as getLogger, r as resetLoggerFactory, t as logging_exports } from "./logging-UC5uXHET.js";
|
|
6
6
|
import { a as validateSqlIdentifier, i as SqlSafetyEngine, n as quoteSqlIdentifier, o as isTrustedSqlFragment, r as trustedSql, t as sql_exports } from "./sql-CIPnuTYO.js";
|
|
7
7
|
//#region src/index.ts
|
package/dist/sql-CIPnuTYO.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sql-CIPnuTYO.js","names":[],"sources":["../src/sql/TrustedSqlFragment.ts","../src/sql/isTrustedSqlFragment.ts","../src/sql/ValidatedSqlIdentifier.ts","../src/sql/SqlIdentifierRole.ts","../src/sql/validateSqlIdentifier.ts","../src/sql/SqlSafetyEngine.ts","../src/sql/trustedSql.ts","../src/sql/quoteSqlIdentifier.ts","../src/sql/index.ts"],"sourcesContent":["export const TRUSTED_SQL_FRAGMENT_BRAND = 'tango.core.trusted_sql_fragment' as const;\n\nexport type TrustedSqlFragment = {\n readonly __tangoBrand: typeof TRUSTED_SQL_FRAGMENT_BRAND;\n readonly sql: string;\n};\n","import { TRUSTED_SQL_FRAGMENT_BRAND, type TrustedSqlFragment } from './TrustedSqlFragment';\n\n/**\n * Narrow an unknown value to a trusted raw SQL fragment.\n */\nexport function isTrustedSqlFragment(value: unknown): value is TrustedSqlFragment {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TRUSTED_SQL_FRAGMENT_BRAND &&\n typeof (value as { sql?: unknown }).sql === 'string'\n );\n}\n","import type { SqlIdentifierRole } from './SqlIdentifierRole';\n\nexport const VALIDATED_SQL_IDENTIFIER_BRAND = 'tango.core.validated_sql_identifier' as const;\n\nexport type ValidatedSqlIdentifier = {\n readonly __tangoBrand: typeof VALIDATED_SQL_IDENTIFIER_BRAND;\n readonly role: SqlIdentifierRole;\n readonly value: string;\n};\n","export const InternalSqlIdentifierRole = {\n TABLE: 'table',\n COLUMN: 'column',\n PRIMARY_KEY: 'primaryKey',\n INDEX: 'index',\n ALIAS: 'alias',\n CONSTRAINT: 'constraint',\n SCHEMA: 'schema',\n RELATION_TABLE: 'relationTable',\n RELATION_FOREIGN_KEY: 'relationForeignKey',\n RELATION_TARGET_PRIMARY_KEY: 'relationTargetPrimaryKey',\n} as const;\n\nexport type SqlIdentifierRole = (typeof InternalSqlIdentifierRole)[keyof typeof InternalSqlIdentifierRole];\n","import { VALIDATED_SQL_IDENTIFIER_BRAND, type ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\nimport { InternalSqlIdentifierRole, type SqlIdentifierRole } from './SqlIdentifierRole';\n\nconst SQL_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nconst ROLE_LABELS: Record<SqlIdentifierRole, string> = {\n [InternalSqlIdentifierRole.TABLE]: 'table name',\n [InternalSqlIdentifierRole.COLUMN]: 'column',\n [InternalSqlIdentifierRole.PRIMARY_KEY]: 'primary key',\n [InternalSqlIdentifierRole.INDEX]: 'index',\n [InternalSqlIdentifierRole.ALIAS]: 'alias',\n [InternalSqlIdentifierRole.CONSTRAINT]: 'constraint',\n [InternalSqlIdentifierRole.SCHEMA]: 'schema',\n [InternalSqlIdentifierRole.RELATION_TABLE]: 'relation table',\n [InternalSqlIdentifierRole.RELATION_FOREIGN_KEY]: 'relation foreign key',\n [InternalSqlIdentifierRole.RELATION_TARGET_PRIMARY_KEY]: 'relation target primary key',\n};\n\n/**\n * Validate an identifier against Tango's SQL safety policy.\n */\nexport function validateSqlIdentifier(\n value: string,\n role: SqlIdentifierRole,\n allowlist?: readonly string[]\n): ValidatedSqlIdentifier {\n const label = ROLE_LABELS[role];\n\n if (!SQL_IDENTIFIER_PATTERN.test(value)) {\n throw new Error(`Invalid SQL ${label}: '${value}'.`);\n }\n\n if (allowlist && !allowlist.includes(value)) {\n throw new Error(`Unknown SQL ${label}: '${value}'.`);\n }\n\n return {\n __tangoBrand: VALIDATED_SQL_IDENTIFIER_BRAND,\n role,\n value,\n };\n}\n","import type { SqlDialect } from './SqlDialect';\nimport type { SqlIdentifierRole } from './SqlIdentifierRole';\nimport { isTrustedSqlFragment } from './isTrustedSqlFragment';\nimport type { TrustedSqlFragment } from './TrustedSqlFragment';\nimport { validateSqlIdentifier } from './validateSqlIdentifier';\nimport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\n\nexport type SqlIdentifierRequest = {\n key: string;\n role: SqlIdentifierRole;\n value: string;\n allowlist?: readonly string[];\n};\n\nexport type SqlLookupTokenRequest = {\n key: string;\n lookup: string;\n allowed: readonly string[];\n};\n\nexport type SqlRawFragmentRequest = {\n key: string;\n value: TrustedSqlFragment;\n};\n\nexport type SqlSafetyRequest = {\n dialect?: SqlDialect;\n identifiers?: readonly SqlIdentifierRequest[];\n lookupTokens?: readonly SqlLookupTokenRequest[];\n rawFragments?: readonly SqlRawFragmentRequest[];\n};\n\nexport type ValidatedSqlLookupToken = {\n lookup: string;\n};\n\nexport type ValidatedSqlSafetyResult = {\n identifiers: Record<string, ValidatedSqlIdentifier>;\n lookupTokens: Record<string, ValidatedSqlLookupToken>;\n rawFragments: Record<string, TrustedSqlFragment>;\n};\n\n/**\n * Canonical SQL safety policy engine shared across Tango packages.\n */\nexport class SqlSafetyEngine {\n static readonly BRAND = 'tango.core.sql_safety_engine' as const;\n readonly __tangoBrand: typeof SqlSafetyEngine.BRAND = SqlSafetyEngine.BRAND;\n\n /**\n * Narrow an unknown value to `SqlSafetyEngine`.\n */\n static isSqlSafetyEngine(value: unknown): value is SqlSafetyEngine {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqlSafetyEngine.BRAND\n );\n }\n\n /**\n * Validate a canonical SQL safety request and return trusted tokens.\n */\n validate(request: SqlSafetyRequest): ValidatedSqlSafetyResult {\n return {\n identifiers: Object.fromEntries(\n (request.identifiers ?? []).map((entry) => [\n entry.key,\n validateSqlIdentifier(entry.value, entry.role, entry.allowlist),\n ])\n ),\n lookupTokens: Object.fromEntries(\n (request.lookupTokens ?? []).map((entry) => [entry.key, this.validateLookupToken(entry)])\n ),\n rawFragments: Object.fromEntries(\n (request.rawFragments ?? []).map((entry) => [entry.key, this.validateRawFragment(entry)])\n ),\n };\n }\n\n private validateLookupToken(entry: SqlLookupTokenRequest): ValidatedSqlLookupToken {\n if (!entry.allowed.includes(entry.lookup)) {\n throw new Error(`Unknown lookup: ${entry.lookup}`);\n }\n\n return {\n lookup: entry.lookup,\n };\n }\n\n private validateRawFragment(entry: SqlRawFragmentRequest): TrustedSqlFragment {\n if (!isTrustedSqlFragment(entry.value)) {\n throw new Error(`Untrusted raw SQL fragment for '${entry.key}'.`);\n }\n\n return entry.value;\n }\n}\n","import { TRUSTED_SQL_FRAGMENT_BRAND, type TrustedSqlFragment } from './TrustedSqlFragment';\n\n/**\n * Explicitly opt into embedding a reviewed raw SQL fragment.\n */\nexport function trustedSql(sql: string): TrustedSqlFragment {\n return {\n __tangoBrand: TRUSTED_SQL_FRAGMENT_BRAND,\n sql,\n };\n}\n","import type { SqlDialect } from './SqlDialect';\nimport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\n\n/**\n * Quote a validated identifier for the target SQL dialect.\n */\nexport function quoteSqlIdentifier(identifier: ValidatedSqlIdentifier, _dialect: SqlDialect): string {\n return `\"${identifier.value.replaceAll('\"', '\"\"')}\"`;\n}\n","/**\n * Domain boundary barrel: centralizes SQL safety primitives and policy helpers.\n */\n\nexport type { SqlDialect } from './SqlDialect';\nexport type { SqlIdentifierRole } from './SqlIdentifierRole';\nexport type { TrustedSqlFragment } from './TrustedSqlFragment';\nexport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\nexport { SqlSafetyEngine } from './SqlSafetyEngine';\nexport type {\n SqlIdentifierRequest,\n SqlLookupTokenRequest,\n SqlRawFragmentRequest,\n SqlSafetyRequest,\n ValidatedSqlLookupToken,\n ValidatedSqlSafetyResult,\n} from './SqlSafetyEngine';\nexport { trustedSql } from './trustedSql';\nexport { isTrustedSqlFragment } from './isTrustedSqlFragment';\nexport { validateSqlIdentifier } from './validateSqlIdentifier';\nexport { quoteSqlIdentifier } from './quoteSqlIdentifier';\n"],"mappings":";;AAAA,MAAa,6BAA6B;;;;;;ACK1C,SAAgB,qBAAqB,OAA6C;CAC9E,OACI,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAA,qCACtC,OAAQ,MAA4B,QAAQ;AAEpD;;;ACVA,MAAa,iCAAiC;;;ACF9C,MAAa,4BAA4B;CACrC,OAAO;CACP,QAAQ;CACR,aAAa;CACb,OAAO;CACP,OAAO;CACP,YAAY;CACZ,QAAQ;CACR,gBAAgB;CAChB,sBAAsB;CACtB,6BAA6B;AACjC;;;ACRA,MAAM,yBAAyB;AAE/B,MAAM,cAAiD;EAClD,0BAA0B,QAAQ;EAClC,0BAA0B,SAAS;EACnC,0BAA0B,cAAc;EACxC,0BAA0B,QAAQ;EAClC,0BAA0B,QAAQ;EAClC,0BAA0B,aAAa;EACvC,0BAA0B,SAAS;EACnC,0BAA0B,iBAAiB;EAC3C,0BAA0B,uBAAuB;EACjD,0BAA0B,8BAA8B;AAC7D;;;;AAKA,SAAgB,sBACZ,OACA,MACA,WACsB;CACtB,MAAM,QAAQ,YAAY;CAE1B,IAAI,CAAC,uBAAuB,KAAK,KAAK,GAClC,MAAM,IAAI,MAAM,eAAe,MAAM,KAAK,MAAM,GAAG;CAGvD,IAAI,aAAa,CAAC,UAAU,SAAS,KAAK,GACtC,MAAM,IAAI,MAAM,eAAe,MAAM,KAAK,MAAM,GAAG;CAGvD,OAAO;EACH,cAAc;EACd;EACA;CACJ;AACJ;;;;;;ACIA,IAAa,kBAAb,MAAa,gBAAgB;CACzB,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;;;;CAKtE,OAAO,kBAAkB,OAA0C;EAC/D,OACI,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE/E;;;;CAKA,SAAS,SAAqD;EAC1D,OAAO;GACH,aAAa,OAAO,aACf,QAAQ,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"sql-CIPnuTYO.js","names":[],"sources":["../src/sql/TrustedSqlFragment.ts","../src/sql/isTrustedSqlFragment.ts","../src/sql/ValidatedSqlIdentifier.ts","../src/sql/SqlIdentifierRole.ts","../src/sql/validateSqlIdentifier.ts","../src/sql/SqlSafetyEngine.ts","../src/sql/trustedSql.ts","../src/sql/quoteSqlIdentifier.ts","../src/sql/index.ts"],"sourcesContent":["export const TRUSTED_SQL_FRAGMENT_BRAND = 'tango.core.trusted_sql_fragment' as const;\n\nexport type TrustedSqlFragment = {\n readonly __tangoBrand: typeof TRUSTED_SQL_FRAGMENT_BRAND;\n readonly sql: string;\n};\n","import { TRUSTED_SQL_FRAGMENT_BRAND, type TrustedSqlFragment } from './TrustedSqlFragment';\n\n/**\n * Narrow an unknown value to a trusted raw SQL fragment.\n */\nexport function isTrustedSqlFragment(value: unknown): value is TrustedSqlFragment {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TRUSTED_SQL_FRAGMENT_BRAND &&\n typeof (value as { sql?: unknown }).sql === 'string'\n );\n}\n","import type { SqlIdentifierRole } from './SqlIdentifierRole';\n\nexport const VALIDATED_SQL_IDENTIFIER_BRAND = 'tango.core.validated_sql_identifier' as const;\n\nexport type ValidatedSqlIdentifier = {\n readonly __tangoBrand: typeof VALIDATED_SQL_IDENTIFIER_BRAND;\n readonly role: SqlIdentifierRole;\n readonly value: string;\n};\n","export const InternalSqlIdentifierRole = {\n TABLE: 'table',\n COLUMN: 'column',\n PRIMARY_KEY: 'primaryKey',\n INDEX: 'index',\n ALIAS: 'alias',\n CONSTRAINT: 'constraint',\n SCHEMA: 'schema',\n RELATION_TABLE: 'relationTable',\n RELATION_FOREIGN_KEY: 'relationForeignKey',\n RELATION_TARGET_PRIMARY_KEY: 'relationTargetPrimaryKey',\n} as const;\n\nexport type SqlIdentifierRole = (typeof InternalSqlIdentifierRole)[keyof typeof InternalSqlIdentifierRole];\n","import { VALIDATED_SQL_IDENTIFIER_BRAND, type ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\nimport { InternalSqlIdentifierRole, type SqlIdentifierRole } from './SqlIdentifierRole';\n\nconst SQL_IDENTIFIER_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;\n\nconst ROLE_LABELS: Record<SqlIdentifierRole, string> = {\n [InternalSqlIdentifierRole.TABLE]: 'table name',\n [InternalSqlIdentifierRole.COLUMN]: 'column',\n [InternalSqlIdentifierRole.PRIMARY_KEY]: 'primary key',\n [InternalSqlIdentifierRole.INDEX]: 'index',\n [InternalSqlIdentifierRole.ALIAS]: 'alias',\n [InternalSqlIdentifierRole.CONSTRAINT]: 'constraint',\n [InternalSqlIdentifierRole.SCHEMA]: 'schema',\n [InternalSqlIdentifierRole.RELATION_TABLE]: 'relation table',\n [InternalSqlIdentifierRole.RELATION_FOREIGN_KEY]: 'relation foreign key',\n [InternalSqlIdentifierRole.RELATION_TARGET_PRIMARY_KEY]: 'relation target primary key',\n};\n\n/**\n * Validate an identifier against Tango's SQL safety policy.\n */\nexport function validateSqlIdentifier(\n value: string,\n role: SqlIdentifierRole,\n allowlist?: readonly string[]\n): ValidatedSqlIdentifier {\n const label = ROLE_LABELS[role];\n\n if (!SQL_IDENTIFIER_PATTERN.test(value)) {\n throw new Error(`Invalid SQL ${label}: '${value}'.`);\n }\n\n if (allowlist && !allowlist.includes(value)) {\n throw new Error(`Unknown SQL ${label}: '${value}'.`);\n }\n\n return {\n __tangoBrand: VALIDATED_SQL_IDENTIFIER_BRAND,\n role,\n value,\n };\n}\n","import type { SqlDialect } from './SqlDialect';\nimport type { SqlIdentifierRole } from './SqlIdentifierRole';\nimport { isTrustedSqlFragment } from './isTrustedSqlFragment';\nimport type { TrustedSqlFragment } from './TrustedSqlFragment';\nimport { validateSqlIdentifier } from './validateSqlIdentifier';\nimport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\n\nexport type SqlIdentifierRequest = {\n key: string;\n role: SqlIdentifierRole;\n value: string;\n allowlist?: readonly string[];\n};\n\nexport type SqlLookupTokenRequest = {\n key: string;\n lookup: string;\n allowed: readonly string[];\n};\n\nexport type SqlRawFragmentRequest = {\n key: string;\n value: TrustedSqlFragment;\n};\n\nexport type SqlSafetyRequest = {\n dialect?: SqlDialect;\n identifiers?: readonly SqlIdentifierRequest[];\n lookupTokens?: readonly SqlLookupTokenRequest[];\n rawFragments?: readonly SqlRawFragmentRequest[];\n};\n\nexport type ValidatedSqlLookupToken = {\n lookup: string;\n};\n\nexport type ValidatedSqlSafetyResult = {\n identifiers: Record<string, ValidatedSqlIdentifier>;\n lookupTokens: Record<string, ValidatedSqlLookupToken>;\n rawFragments: Record<string, TrustedSqlFragment>;\n};\n\n/**\n * Canonical SQL safety policy engine shared across Tango packages.\n */\nexport class SqlSafetyEngine {\n static readonly BRAND = 'tango.core.sql_safety_engine' as const;\n readonly __tangoBrand: typeof SqlSafetyEngine.BRAND = SqlSafetyEngine.BRAND;\n\n /**\n * Narrow an unknown value to `SqlSafetyEngine`.\n */\n static isSqlSafetyEngine(value: unknown): value is SqlSafetyEngine {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === SqlSafetyEngine.BRAND\n );\n }\n\n /**\n * Validate a canonical SQL safety request and return trusted tokens.\n */\n validate(request: SqlSafetyRequest): ValidatedSqlSafetyResult {\n return {\n identifiers: Object.fromEntries(\n (request.identifiers ?? []).map((entry) => [\n entry.key,\n validateSqlIdentifier(entry.value, entry.role, entry.allowlist),\n ])\n ),\n lookupTokens: Object.fromEntries(\n (request.lookupTokens ?? []).map((entry) => [entry.key, this.validateLookupToken(entry)])\n ),\n rawFragments: Object.fromEntries(\n (request.rawFragments ?? []).map((entry) => [entry.key, this.validateRawFragment(entry)])\n ),\n };\n }\n\n private validateLookupToken(entry: SqlLookupTokenRequest): ValidatedSqlLookupToken {\n if (!entry.allowed.includes(entry.lookup)) {\n throw new Error(`Unknown lookup: ${entry.lookup}`);\n }\n\n return {\n lookup: entry.lookup,\n };\n }\n\n private validateRawFragment(entry: SqlRawFragmentRequest): TrustedSqlFragment {\n if (!isTrustedSqlFragment(entry.value)) {\n throw new Error(`Untrusted raw SQL fragment for '${entry.key}'.`);\n }\n\n return entry.value;\n }\n}\n","import { TRUSTED_SQL_FRAGMENT_BRAND, type TrustedSqlFragment } from './TrustedSqlFragment';\n\n/**\n * Explicitly opt into embedding a reviewed raw SQL fragment.\n */\nexport function trustedSql(sql: string): TrustedSqlFragment {\n return {\n __tangoBrand: TRUSTED_SQL_FRAGMENT_BRAND,\n sql,\n };\n}\n","import type { SqlDialect } from './SqlDialect';\nimport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\n\n/**\n * Quote a validated identifier for the target SQL dialect.\n */\nexport function quoteSqlIdentifier(identifier: ValidatedSqlIdentifier, _dialect: SqlDialect): string {\n return `\"${identifier.value.replaceAll('\"', '\"\"')}\"`;\n}\n","/**\n * Domain boundary barrel: centralizes SQL safety primitives and policy helpers.\n */\n\nexport type { SqlDialect } from './SqlDialect';\nexport type { SqlIdentifierRole } from './SqlIdentifierRole';\nexport type { TrustedSqlFragment } from './TrustedSqlFragment';\nexport type { ValidatedSqlIdentifier } from './ValidatedSqlIdentifier';\nexport { SqlSafetyEngine } from './SqlSafetyEngine';\nexport type {\n SqlIdentifierRequest,\n SqlLookupTokenRequest,\n SqlRawFragmentRequest,\n SqlSafetyRequest,\n ValidatedSqlLookupToken,\n ValidatedSqlSafetyResult,\n} from './SqlSafetyEngine';\nexport { trustedSql } from './trustedSql';\nexport { isTrustedSqlFragment } from './isTrustedSqlFragment';\nexport { validateSqlIdentifier } from './validateSqlIdentifier';\nexport { quoteSqlIdentifier } from './quoteSqlIdentifier';\n"],"mappings":";;AAAA,MAAa,6BAA6B;;;;;;ACK1C,SAAgB,qBAAqB,OAA6C;CAC9E,OACI,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAA,qCACtC,OAAQ,MAA4B,QAAQ;AAEpD;;;ACVA,MAAa,iCAAiC;;;ACF9C,MAAa,4BAA4B;CACrC,OAAO;CACP,QAAQ;CACR,aAAa;CACb,OAAO;CACP,OAAO;CACP,YAAY;CACZ,QAAQ;CACR,gBAAgB;CAChB,sBAAsB;CACtB,6BAA6B;AACjC;;;ACRA,MAAM,yBAAyB;AAE/B,MAAM,cAAiD;EAClD,0BAA0B,QAAQ;EAClC,0BAA0B,SAAS;EACnC,0BAA0B,cAAc;EACxC,0BAA0B,QAAQ;EAClC,0BAA0B,QAAQ;EAClC,0BAA0B,aAAa;EACvC,0BAA0B,SAAS;EACnC,0BAA0B,iBAAiB;EAC3C,0BAA0B,uBAAuB;EACjD,0BAA0B,8BAA8B;AAC7D;;;;AAKA,SAAgB,sBACZ,OACA,MACA,WACsB;CACtB,MAAM,QAAQ,YAAY;CAE1B,IAAI,CAAC,uBAAuB,KAAK,KAAK,GAClC,MAAM,IAAI,MAAM,eAAe,MAAM,KAAK,MAAM,GAAG;CAGvD,IAAI,aAAa,CAAC,UAAU,SAAS,KAAK,GACtC,MAAM,IAAI,MAAM,eAAe,MAAM,KAAK,MAAM,GAAG;CAGvD,OAAO;EACH,cAAc;EACd;EACA;CACJ;AACJ;;;;;;ACIA,IAAa,kBAAb,MAAa,gBAAgB;CACzB,OAAgB,QAAQ;CACxB,eAAsD,gBAAgB;;;;CAKtE,OAAO,kBAAkB,OAA0C;EAC/D,OACI,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB,gBAAgB;CAE/E;;;;CAKA,SAAS,SAAqD;EAC1D,OAAO;GACH,aAAa,OAAO,aACf,QAAQ,eAAe,CAAC,EAAA,CAAG,KAAK,UAAU,CACvC,MAAM,KACN,sBAAsB,MAAM,OAAO,MAAM,MAAM,MAAM,SAAS,CAClE,CAAC,CACL;GACA,cAAc,OAAO,aAChB,QAAQ,gBAAgB,CAAC,EAAA,CAAG,KAAK,UAAU,CAAC,MAAM,KAAK,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAC5F;GACA,cAAc,OAAO,aAChB,QAAQ,gBAAgB,CAAC,EAAA,CAAG,KAAK,UAAU,CAAC,MAAM,KAAK,KAAK,oBAAoB,KAAK,CAAC,CAAC,CAC5F;EACJ;CACJ;CAEA,oBAA4B,OAAuD;EAC/E,IAAI,CAAC,MAAM,QAAQ,SAAS,MAAM,MAAM,GACpC,MAAM,IAAI,MAAM,mBAAmB,MAAM,QAAQ;EAGrD,OAAO,EACH,QAAQ,MAAM,OAClB;CACJ;CAEA,oBAA4B,OAAkD;EAC1E,IAAI,CAAC,qBAAqB,MAAM,KAAK,GACjC,MAAM,IAAI,MAAM,mCAAmC,MAAM,IAAI,GAAG;EAGpE,OAAO,MAAM;CACjB;AACJ;;;;;;AC5FA,SAAgB,WAAW,KAAiC;CACxD,OAAO;EACH,cAAc;EACd;CACJ;AACJ;;;;;;ACJA,SAAgB,mBAAmB,YAAoC,UAA8B;CACjG,OAAO,IAAI,WAAW,MAAM,WAAW,MAAK,MAAI,EAAE;AACtD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danceroutine/tango-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "Core types, errors, and result utilities for Tango",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/node": "^25.9.1",
|
|
57
|
-
"tsdown": "^0.22.
|
|
57
|
+
"tsdown": "^0.22.2",
|
|
58
58
|
"typescript": "^6.0.3",
|
|
59
59
|
"vitest": "^4.1.8",
|
|
60
60
|
"zod": "^4.0.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http-BJPRtBGV.js","names":[],"sources":["../src/http/TangoBody.ts","../src/http/TangoHeaders.ts","../src/http/TangoQueryParams.ts","../src/http/TangoRequest.ts","../src/http/TangoResponse.ts","../src/http/index.ts"],"sourcesContent":["import {\n isArrayBuffer,\n isBlob,\n isFile,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\n\n/**\n * The full type of body that TangoResponse/TangoBody supports.\n * Unlike the fetch spec BodyInit, this can be directly:\n * - a string, ArrayBuffer, Uint8Array, Blob, FormData, ReadableStream, or JSON-like object, or null/undefined.\n */\n\ntype HeadersLike = { get?: (arg: string) => string | null };\n\ntype TangoBodySource = BodyInit | JsonValue | null;\n\n/** Recursive JSON value contract used by Tango HTTP helpers. */\nexport type JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\n/**\n * Unified body reader/clone utility for Tango request/response wrappers.\n */\nexport class TangoBody {\n static readonly BRAND = 'tango.http.body' as const;\n readonly __tangoBrand: typeof TangoBody.BRAND = TangoBody.BRAND;\n private bodySourceInternal: TangoBodySource;\n private bodyUsedInternal: boolean;\n private headers?: HeadersLike;\n\n constructor(bodySource: TangoBodySource, headers?: HeadersLike) {\n this.bodySourceInternal = bodySource;\n this.bodyUsedInternal = false;\n this.headers = headers;\n }\n\n /**\n * Narrow an unknown value to `TangoBody`.\n */\n static isTangoBody(value: unknown): value is TangoBody {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoBody.BRAND\n );\n }\n\n /**\n * Expose the original body source for cloning and adapter integration.\n */\n public get bodySource(): TangoBodySource {\n return this.bodySourceInternal;\n }\n\n /**\n * Report whether a reader method has already consumed this body.\n */\n get bodyUsed(): boolean {\n return this.bodyUsedInternal;\n }\n\n /**\n * Describe the current body shape in a way that is useful for diagnostics.\n */\n get bodyType(): string {\n const body = this.bodySourceInternal;\n if (isNil(body)) return 'null';\n if (typeof body === 'string') return 'string';\n if (isArrayBuffer(body)) return 'ArrayBuffer';\n if (isUint8Array(body)) return 'Uint8Array';\n if (isBlob(body)) return 'Blob';\n if (isFormData(body)) return 'FormData';\n if (isURLSearchParams(body)) return 'URLSearchParams';\n if (isReadableStream(body)) return 'ReadableStream';\n if (TangoBody.isJsonValue(body)) return 'JsonValue';\n return typeof body;\n }\n\n /**\n * Returns true if value is a valid JSON value (recursively).\n */\n public static isJsonValue(v: unknown): v is JsonValue {\n if (v === null || typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {\n return true;\n }\n if (Array.isArray(v)) {\n return v.every(TangoBody.isJsonValue);\n }\n if (typeof v === 'object' && v !== null && Object.prototype.toString.call(v) === '[object Object]') {\n return Object.values(v).every(TangoBody.isJsonValue);\n }\n return false;\n }\n\n /**\n * Deep clone utility for body values. Preserves types and values as in the legacy implementation.\n * If the source is a stream, the stream will be cloned if readable, otherwise throws.\n */\n static deepCloneBody(body: TangoBodySource): TangoBodySource {\n if (isNil(body)) {\n return null;\n }\n if (typeof body === 'string') {\n return body;\n }\n if (isArrayBuffer(body)) {\n return body.slice(0);\n }\n if (isUint8Array(body)) {\n return new Uint8Array(body);\n }\n if (isBlob(body)) {\n return body.slice(0, body.size, body.type);\n }\n if (isFormData(body)) {\n // Deep clone FormData: only text fields (files not handled)\n // This is the best we can do in cross-platform without File support.\n const cloned = new FormData();\n for (const [k, v] of body) {\n // If value is File, attempt to clone (not fully implemented)\n if (isFile(v)) {\n // Note: Cloning File loses prototype, but rarely needed\n const file = new File([v], v.name, { type: v.type, lastModified: v.lastModified });\n cloned.append(k, file);\n } else {\n cloned.append(k, v as string);\n }\n }\n return cloned;\n }\n if (isReadableStream(body)) {\n throw new TypeError('Cannot deep clone a ReadableStream directly; use TangoBody.clone()');\n }\n if (TangoBody.isJsonValue(body)) {\n return JSON.parse(JSON.stringify(body));\n }\n return null;\n }\n\n /**\n * Read a `ReadableStream` into an `ArrayBuffer`.\n */\n static async readStreamToArrayBuffer(stream: ReadableStream<Uint8Array>): Promise<ArrayBuffer> {\n const chunks: Uint8Array[] = [];\n const reader = stream.getReader();\n let total = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n chunks.push(value);\n total += value.length;\n }\n const joined = new Uint8Array(total);\n let off = 0;\n for (const chunk of chunks) {\n joined.set(chunk, off);\n off += chunk.length;\n }\n return joined.buffer.slice(0, joined.byteLength) as ArrayBuffer;\n }\n\n /**\n * Read a `ReadableStream` into a `Uint8Array`.\n */\n static async readStreamToUint8Array(stream: ReadableStream<Uint8Array>): Promise<Uint8Array<ArrayBuffer>> {\n const buf = await TangoBody.readStreamToArrayBuffer(stream);\n return new Uint8Array(buf) as Uint8Array<ArrayBuffer>;\n }\n\n /**\n * Read a `ReadableStream` into UTF-8 text.\n */\n static async readStreamToText(stream: ReadableStream<Uint8Array>): Promise<string> {\n const arr = await TangoBody.readStreamToUint8Array(stream);\n return new TextDecoder().decode(arr);\n }\n\n /**\n * Determine the content type for this body, if possible.\n * Respects an explicitly passed header, otherwise infers from value type.\n */\n static detectContentType(body: TangoBodySource, providedType?: string): string | undefined {\n if (providedType) return providedType;\n if (isNil(body)) return undefined;\n if (typeof body === 'string') return 'text/plain; charset=utf-8';\n if (isArrayBuffer(body) || isUint8Array(body)) return 'application/octet-stream';\n if (isBlob(body)) {\n if (body.type) return body.type;\n return 'application/octet-stream';\n }\n if (isFormData(body)) return undefined;\n if (typeof body === 'object' && TangoBody.isJsonValue(body)) return 'application/json; charset=utf-8';\n if (isReadableStream(body)) return undefined;\n return undefined;\n }\n\n /**\n * Attempt to determine the content length, in bytes, for this body.\n * Only available for certain body types, otherwise returns undefined.\n */\n static async getContentLength(body: TangoBodySource): Promise<number | undefined> {\n if (isNil(body)) return 0;\n if (typeof body === 'string') return new TextEncoder().encode(body).length;\n if (isUint8Array(body)) return body.byteLength;\n if (isArrayBuffer(body)) return body.byteLength;\n if (isBlob(body)) return body.size;\n if (TangoBody.isJsonValue(body)) return new TextEncoder().encode(JSON.stringify(body)).length;\n return undefined;\n }\n\n /**\n * Reads the body as an ArrayBuffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.consumeBody(async (input) => {\n if (isArrayBuffer(input)) return input;\n if (isUint8Array(input)) {\n const copy = new Uint8Array(input.byteLength);\n copy.set(input);\n return copy.buffer;\n }\n if (typeof input === 'string') return new TextEncoder().encode(input).buffer as ArrayBuffer;\n if (isBlob(input)) return input.arrayBuffer();\n if (isReadableStream(input)) {\n return TangoBody.readStreamToArrayBuffer(input);\n }\n if (TangoBody.isJsonValue(input)) {\n // If body is object/array, encode as JSON and return buffer\n return new TextEncoder().encode(JSON.stringify(input)).buffer as ArrayBuffer;\n }\n throw new TypeError('Body is not an ArrayBuffer, Blob, string, stream, or JSON serializable object');\n });\n }\n\n /**\n * Reads the body as a Blob (browser only).\n */\n async blob(): Promise<Blob> {\n return this.consumeBody(async (input) => {\n if (isBlob(input)) return input;\n if (typeof input === 'string') return new Blob([input]);\n if (isArrayBuffer(input)) return new Blob([input]);\n if (isUint8Array(input)) return new Blob([new Uint8Array(input)]);\n if (isReadableStream(input)) {\n const buf = await TangoBody.readStreamToArrayBuffer(input);\n return new Blob([buf]);\n }\n if (TangoBody.isJsonValue(input)) {\n return new Blob([JSON.stringify(input)], { type: 'application/json' });\n }\n throw new TypeError(\n 'Body is not a Blob, string, ArrayBuffer, Uint8Array, stream, or JSON serializable object'\n );\n });\n }\n\n /**\n * Reads the body as a Uint8Array.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n return this.consumeBody(async (input) => {\n if (isUint8Array(input)) return new Uint8Array(input);\n if (isArrayBuffer(input)) return new Uint8Array(input);\n if (typeof input === 'string') return new TextEncoder().encode(input);\n if (isBlob(input)) return new Uint8Array(await input.arrayBuffer());\n if (isReadableStream(input)) {\n return TangoBody.readStreamToUint8Array(input);\n }\n if (TangoBody.isJsonValue(input)) {\n return new TextEncoder().encode(JSON.stringify(input));\n }\n throw new TypeError('Body is not bytes, ArrayBuffer, Blob, string, stream, or JSON serializable object');\n });\n }\n\n /**\n * Reads the body as FormData.\n * Accepts FormData, or if type is urlencoded or multipart parses a string/bytes.\n */\n async formData(): Promise<FormData> {\n return this.consumeBody(async (input) => {\n if (isFormData(input)) return input;\n\n let contentType: string | undefined = undefined;\n if (this.headers && typeof this.headers.get === 'function') {\n const raw = this.headers.get('Content-Type');\n if (typeof raw === 'string') contentType = raw.toLowerCase();\n }\n\n let raw: string;\n if (typeof input === 'string') {\n raw = input;\n } else if (isArrayBuffer(input)) {\n raw = new TextDecoder().decode(input);\n } else if (isUint8Array(input)) {\n raw = new TextDecoder().decode(input);\n } else {\n throw new TypeError('Body is not valid for FormData');\n }\n\n // application/x-www-form-urlencoded\n if (contentType && contentType.includes('application/x-www-form-urlencoded')) {\n const form = new FormData();\n const params = new URLSearchParams(raw);\n params.forEach((value, key) => form.append(key, value));\n return form;\n }\n // multipart/form-data\n if (contentType && contentType.startsWith('multipart/form-data')) {\n const boundaryMatch = /boundary=([^\\s;]+)/i.exec(contentType);\n if (!boundaryMatch) throw new TypeError('Missing boundary in multipart/form-data');\n const boundary = boundaryMatch[1];\n\n // Warning: minimal multipart parsing, no file support\n const parts = raw.split(`--${boundary}`);\n const form = new FormData();\n for (const part of parts) {\n const trimmed = part.trim();\n if (!trimmed || trimmed === '--' || trimmed === '') continue;\n\n const [rawHeaders = '', ...rawBodyParts] = trimmed.split(/\\r?\\n\\r?\\n/);\n const body = rawBodyParts.join('\\n\\n').replace(/\\r?\\n$/, '');\n const dispositionMatch = /Content-Disposition:\\s*form-data;\\s*name=\"([^\"]+)\"/i.exec(rawHeaders);\n if (!dispositionMatch) continue;\n const name = dispositionMatch[1]!;\n form.append(name, body);\n }\n return form;\n }\n throw new TypeError('Body is not FormData, nor a supported form encoding');\n });\n }\n\n /**\n * Reads and parses the body as JSON (if possible).\n */\n async json<T = unknown>(): Promise<T> {\n return this.consumeBody(async (input) => {\n if (typeof input === 'string') return JSON.parse(input) as T;\n if (TangoBody.isJsonValue(input)) return input as T;\n if (isArrayBuffer(input) || isUint8Array(input)) {\n const text = new TextDecoder().decode(isUint8Array(input) ? input : new Uint8Array(input));\n return JSON.parse(text) as T;\n }\n if (isReadableStream(input)) {\n const text = await TangoBody.readStreamToText(input);\n return JSON.parse(text) as T;\n }\n throw new TypeError('Body is not valid JSON');\n });\n }\n\n /**\n * Reads the body as UTF-8 string.\n */\n async text(): Promise<string> {\n return this.consumeBody(async (input) => {\n if (typeof input === 'string') return input;\n if (isArrayBuffer(input)) return new TextDecoder().decode(input);\n if (isUint8Array(input)) return new TextDecoder().decode(input);\n if (isBlob(input)) return await input.text();\n if (isReadableStream(input)) return await TangoBody.readStreamToText(input);\n if (TangoBody.isJsonValue(input)) return JSON.stringify(input);\n throw new TypeError('Body is not text, ArrayBuffer, Uint8Array, Blob, stream, or JSON serializable object');\n });\n }\n\n /**\n * Returns the original body value (may be used for streaming or clone).\n */\n getRawBodyInit(): TangoBodySource {\n return this.bodySourceInternal;\n }\n\n /**\n * Clone the body instance and stream if possible.\n * If the source is a stream, the stream will be cloned if readable, otherwise throws.\n */\n clone(): TangoBody {\n if (this.bodyUsedInternal) throw new TypeError('Body has already been used.');\n if (isReadableStream(this.bodySourceInternal)) {\n if (typeof this.bodySourceInternal.tee !== 'function') {\n throw new TypeError('Cannot clone: body is a ReadableStream and tee() is not available');\n }\n const [streamForOriginal, streamForClone] = this.bodySourceInternal.tee();\n this.bodySourceInternal = streamForOriginal;\n return new TangoBody(streamForClone, this.headers);\n }\n const cloneSource = TangoBody.deepCloneBody(this.bodySourceInternal);\n return new TangoBody(cloneSource, this.headers);\n }\n\n /**\n * Helper for all readers. Only allows reading once.\n */\n private async consumeBody<T>(parser: (input: TangoBodySource) => Promise<T>): Promise<T> {\n if (this.bodyUsedInternal) {\n throw new TypeError('Body has already been consumed.');\n }\n this.bodyUsedInternal = true;\n return parser(this.bodySourceInternal);\n }\n}\n","import { isArrayBuffer, isBlob, isUint8Array } from '../runtime/index';\n\n/**\n * TangoHeaders extends the Web Headers class, adding ergonomic helpers\n * for common HTTP header patterns, convenience features, and a consistent API for\n * setting, appending, and deleting headers and cookies. This is designed to be\n * used by TangoResponse and other Tango HTTP utilities.\n * Additionally, provides helpers for safely setting Content-Length based on a known body,\n * and setting Content-Disposition for inline or attachment filenames.\n *\n * Includes helpers for request tracing and correlation headers:\n * - X-Request-Id\n * - traceparent (W3C Trace Context)\n * - Server-Timing\n * - X-Response-Time\n */\nexport class TangoHeaders extends Headers {\n static readonly BRAND = 'tango.http.headers' as const;\n readonly __tangoBrand: typeof TangoHeaders.BRAND = TangoHeaders.BRAND;\n\n /**\n * Narrow an unknown value to `TangoHeaders`.\n */\n static isTangoHeaders(value: unknown): value is TangoHeaders {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoHeaders.BRAND\n );\n }\n\n /**\n * Serialize a cookie for the Set-Cookie header line.\n */\n private static serializeCookie(\n name: string,\n value: string,\n options: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n } = {}\n ): string {\n let cookie = encodeURIComponent(name) + '=' + encodeURIComponent(value ?? '');\n if (options.domain) cookie += `; Domain=${options.domain}`;\n if (options.path) cookie += `; Path=${options.path}`;\n else cookie += '; Path=/';\n if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;\n if (typeof options.maxAge === 'number') cookie += `; Max-Age=${options.maxAge}`;\n if (options.secure) cookie += '; Secure';\n if (options.httpOnly) cookie += '; HttpOnly';\n if (options.sameSite) cookie += `; SameSite=${options.sameSite}`;\n if (options.priority) cookie += `; Priority=${options.priority}`;\n if (options.partitioned) cookie += '; Partitioned';\n return cookie;\n }\n\n private static hasNumberSize(value: unknown): value is { size: number } {\n return typeof value === 'object' && value !== null && typeof (value as { size?: unknown }).size === 'number';\n }\n\n private static hasNumberLength(value: unknown): value is { length: number } {\n return (\n typeof value === 'object' && value !== null && typeof (value as { length?: unknown }).length === 'number'\n );\n }\n\n private static isNodeBuffer(value: unknown): value is { length: number } {\n const maybeBuffer = Buffer as unknown as { isBuffer?: (input: unknown) => boolean };\n return (\n typeof Buffer !== 'undefined' && typeof maybeBuffer.isBuffer === 'function' && maybeBuffer.isBuffer(value)\n );\n }\n\n /**\n * Sets the Content-Disposition header with type \"inline\" and the specified filename.\n * This is useful to indicate that the content should be displayed inline in the browser,\n * but with a suggested filename for saving.\n *\n * @param filename The filename to include in the Content-Disposition header.\n */\n setContentDispositionInline(filename: string): void {\n const encoded = encodeURIComponent(filename);\n this.set('Content-Disposition', `inline; filename=\"${encoded}\"; filename*=UTF-8''${encoded}`);\n }\n\n /**\n * Sets the Content-Disposition header with type \"attachment\" and the specified filename.\n * This is useful to indicate that the response should be downloaded as a file.\n *\n * @param filename The filename to include in the Content-Disposition header.\n */\n setContentDispositionAttachment(filename: string): void {\n const encoded = encodeURIComponent(filename);\n this.set('Content-Disposition', `attachment; filename=\"${encoded}\"; filename*=UTF-8''${encoded}`);\n }\n\n /**\n * Create a copy that preserves all header names and values.\n */\n clone(): TangoHeaders {\n const copy = new TangoHeaders();\n for (const [name, value] of this.entries()) {\n copy.append(name, value);\n }\n return copy;\n }\n\n /**\n * Set a header, replacing the existing value.\n */\n setHeader(name: string, value: string): void {\n this.set(name, value);\n }\n\n /**\n * Append a header, adding to existing value(s) for the name.\n */\n appendHeader(name: string, value: string): void {\n this.append(name, value);\n }\n\n /**\n * Get a header value (first value if header is repeated).\n */\n getHeader(name: string): string | null {\n return this.get(name);\n }\n\n /**\n * Check if a header exists.\n */\n hasHeader(name: string): boolean {\n return this.has(name);\n }\n\n /**\n * Delete a header.\n */\n deleteHeader(name: string): void {\n this.delete(name);\n }\n\n /**\n * Ensure a header is present only once and fully replaces the old value.\n */\n ensureUnique(name: string, value: string): void {\n this.delete(name);\n this.set(name, value);\n }\n\n /**\n * Add a field (or fields) to the Vary header, merging with existing values.\n */\n vary(...fields: string[]): void {\n if (fields.length === 0) return;\n const key = 'Vary';\n const prev = this.get(key);\n const nextSet = new Set<string>();\n if (prev) {\n for (const v of prev.split(',')) {\n if (v.trim()) nextSet.add(v.trim());\n }\n }\n for (const f of fields) {\n if (f.trim()) nextSet.add(f.trim());\n }\n this.set(key, Array.from(nextSet).join(', '));\n }\n\n /**\n * Set a cookie header (for Set-Cookie).\n * @param name\n * @param value\n * @param options\n */\n setCookie(\n name: string,\n value: string,\n options?: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.append('Set-Cookie', TangoHeaders.serializeCookie(name, value, options));\n }\n\n /**\n * Append (additionally) a new cookie.\n */\n appendCookie(\n name: string,\n value: string,\n options?: {\n domain?: string;\n expires?: Date;\n httpOnly?: boolean;\n maxAge?: number;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.append('Set-Cookie', TangoHeaders.serializeCookie(name, value, options));\n }\n\n /**\n * Delete a cookie (\"unset\" it via expired date).\n */\n deleteCookie(\n name: string,\n options?: {\n domain?: string;\n path?: string;\n sameSite?: 'Strict' | 'Lax' | 'None';\n secure?: boolean;\n priority?: 'Low' | 'Medium' | 'High';\n partitioned?: boolean;\n }\n ): void {\n this.setCookie(name, '', {\n ...options,\n expires: new Date(0),\n maxAge: 0,\n });\n }\n\n /**\n * Add or override Cache-Control header with helpers for common policies.\n */\n cacheControl(control: string | Record<string, string | number | boolean | undefined>): void {\n if (typeof control === 'string') {\n this.set('Cache-Control', control);\n return;\n }\n // Compose Cache-Control from object\n const parts: string[] = [];\n for (const [k, v] of Object.entries(control)) {\n if (typeof v === 'boolean') {\n if (v) parts.push(k.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase()));\n } else if (typeof v === 'number' || (typeof v === 'string' && v.length > 0)) {\n parts.push(`${k.replace(/[A-Z]/g, (c) => '-' + c.toLowerCase())}=${v}`);\n }\n }\n if (parts.length) {\n this.set('Cache-Control', parts.join(', '));\n }\n }\n\n /**\n * Set the Location header.\n */\n location(url: string): void {\n this.set('Location', url);\n }\n\n /**\n * Set the Content-Type header.\n */\n contentType(mime: string): void {\n this.set('Content-Type', mime);\n }\n\n /**\n * Attempt to guess and set the Content-Type header from a file (string or Blob) and optional filename.\n *\n * @param file File-like input (string or Blob)\n * @param filename Optional filename to help guess mime type by extension\n */\n setContentTypeByFile(file: unknown, filename?: string): void {\n // do not overwrite explicit content-type\n if (this.has('Content-Type')) return;\n\n // If file is a string and a filename is provided or can be guessed from file path\n if (typeof file === 'string' && filename) {\n // Guess type by extension\n const dotIndex = filename.lastIndexOf('.');\n const ext = dotIndex >= 0 ? filename.slice(dotIndex + 1).toLowerCase() : '';\n const map: Record<string, string> = {\n txt: 'text/plain',\n text: 'text/plain',\n html: 'text/html',\n css: 'text/css',\n js: 'application/javascript',\n json: 'application/json',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n pdf: 'application/pdf',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n md: 'text/markdown',\n };\n const mime = map[ext];\n if (mime) {\n this.set('Content-Type', mime);\n } else {\n this.set('Content-Type', 'application/octet-stream');\n }\n return;\n }\n\n // If it's a Blob, use its type, or fallback\n if (isBlob(file)) {\n if (file.type && file.type !== '') {\n this.set('Content-Type', file.type);\n } else {\n this.set('Content-Type', 'application/octet-stream');\n }\n return;\n }\n\n // Fallback\n this.set('Content-Type', 'application/octet-stream');\n }\n\n /**\n * Sets the Content-Length header, inferring it from the body if not explicitly provided.\n * If the body is a string, ArrayBuffer, Uint8Array, Blob/Buffer (or has a .size or .length property),\n * the length is computed. For unsupported types, does nothing.\n * Mirrors logic from TangoResponse.ts, but generalized for use anywhere.\n */\n setContentLengthFromBody(body: unknown): void {\n if (this.has('Content-Length') || body === null || body === undefined) {\n return;\n }\n\n let len: number | undefined;\n\n if (typeof body === 'string') {\n len = new TextEncoder().encode(body).length;\n } else if (isArrayBuffer(body)) {\n len = body.byteLength;\n }\n // Node.js Buffer support (Buffer.isBuffer and .length)\n else if (TangoHeaders.isNodeBuffer(body)) {\n len = (body as { length: number }).length;\n } else if (isUint8Array(body)) {\n len = body.byteLength;\n } else if (isBlob(body)) {\n len = body.size;\n }\n // Generic \"size\" (number) property\n else if (TangoHeaders.hasNumberSize(body)) {\n len = (body as { size: number }).size;\n }\n // Generic \"length\" (number) property but not string/ArrayBuffer/Uint8Array/etc\n else if (\n TangoHeaders.hasNumberLength(body) &&\n typeof body !== 'string' &&\n !isArrayBuffer(body) &&\n !isUint8Array(body)\n ) {\n len = (body as { length: number }).length;\n }\n\n if (typeof len === 'number') {\n this.set('Content-Length', len.toString());\n }\n }\n\n /**\n * Set or update the X-Request-Id header. Used for associating a request/response with a unique id.\n * @param id The request id value to set.\n */\n withRequestId(id: string): this {\n this.set('X-Request-Id', id);\n return this;\n }\n\n /**\n * Set or update the traceparent header. Used for distributed trace context propagation (W3C Trace Context).\n * @param value The traceparent value (should be a valid traceparent header value).\n */\n withTraceParent(value: string): this {\n this.set('traceparent', value);\n return this;\n }\n\n /**\n * Set or append a value to the Server-Timing header.\n * For a single metric, supply name, and optionally dur and desc.\n * For advanced usage (many metrics), set the value directly or use appendServerTimingRaw.\n *\n * @param name Name of the server-timing metric (e.g., 'total', 'db').\n * @param dur Optional duration in ms.\n * @param desc Optional string description.\n */\n withServerTiming(name: string, dur?: number, desc?: string): this {\n // Build the metric string per spec: <metric>=<value>;dur=<duration>;desc=\"<description>\"\n let metric = name;\n if (typeof dur === 'number') {\n metric += `;dur=${dur}`;\n }\n if (desc) {\n metric += `;desc=\"${desc.replace(/\"/g, '\\\\\"')}\"`;\n }\n\n // Set or append. If header exists, append, separated by comma.\n const prev = this.get('Server-Timing');\n if (prev && prev.length > 0) {\n this.set('Server-Timing', prev + ', ' + metric);\n } else {\n this.set('Server-Timing', metric);\n }\n return this;\n }\n\n /**\n * Directly append a raw Server-Timing metric value.\n * This is useful for advanced cases where you have multiple metrics assembled.\n * @param value The server-timing value chunk to append.\n */\n appendServerTimingRaw(value: string): this {\n const prev = this.get('Server-Timing');\n if (prev && prev.length > 0) {\n this.set('Server-Timing', prev + ', ' + value);\n } else {\n this.set('Server-Timing', value);\n }\n return this;\n }\n\n /**\n * Set or update X-Response-Time header.\n * @param ms Elapsed time in milliseconds (number or string for flexibility).\n */\n withResponseTime(ms: number | string): this {\n this.set('X-Response-Time', typeof ms === 'number' ? `${ms}ms` : ms);\n return this;\n }\n\n /**\n * Return the current value of X-Request-Id.\n */\n getRequestId(): string | null {\n return this.get('X-Request-Id');\n }\n\n /**\n * Return the current value of traceparent header.\n */\n getTraceParent(): string | null {\n return this.get('traceparent');\n }\n\n /**\n * Return the current Server-Timing string, if set.\n */\n getServerTiming(): string | null {\n return this.get('Server-Timing');\n }\n\n /**\n * Return the current X-Response-Time string, if set.\n */\n getResponseTime(): string | null {\n return this.get('X-Response-Time');\n }\n}\n","import type { TangoRequest } from './TangoRequest';\n\ntype QueryParamRecord = Record<string, string | string[] | undefined>;\ntype QueryParamMutationValue = string | number | readonly (string | number)[] | null | undefined;\ntype QueryParamMutationRecord = Record<string, QueryParamMutationValue>;\n\n/**\n * Immutable query parameter helper that normalizes framework-specific shapes\n * into one Tango-owned API.\n */\nexport class TangoQueryParams {\n static readonly BRAND = 'tango.http.query_params' as const;\n readonly __tangoBrand: typeof TangoQueryParams.BRAND = TangoQueryParams.BRAND;\n private readonly values: Map<string, readonly string[]>;\n\n private constructor(values: Map<string, readonly string[]>) {\n this.values = values;\n }\n\n /**\n * Narrow an unknown value to `TangoQueryParams`.\n */\n static isTangoQueryParams(value: unknown): value is TangoQueryParams {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoQueryParams.BRAND\n );\n }\n\n /**\n * Build query params from a `URLSearchParams` instance.\n */\n static fromURLSearchParams(params: URLSearchParams): TangoQueryParams {\n const values = new Map<string, string[]>();\n\n for (const [key, value] of params.entries()) {\n const current = values.get(key);\n if (current) {\n current.push(value);\n continue;\n }\n values.set(key, [value]);\n }\n\n return new TangoQueryParams(values);\n }\n\n /**\n * Build query params from framework record-style search params.\n */\n static fromRecord(params: QueryParamRecord): TangoQueryParams {\n const values = new Map<string, string[]>();\n\n for (const [key, value] of Object.entries(params)) {\n if (Array.isArray(value)) {\n const normalized = value.filter((entry) => typeof entry === 'string');\n if (normalized.length > 0) {\n values.set(key, normalized);\n }\n continue;\n }\n\n if (typeof value === 'string') {\n values.set(key, [value]);\n }\n }\n\n return new TangoQueryParams(values);\n }\n\n /**\n * Build query params from a full URL string or URL object.\n */\n static fromURL(input: string | URL): TangoQueryParams {\n const url = typeof input === 'string' ? new URL(input) : input;\n return TangoQueryParams.fromURLSearchParams(url.searchParams);\n }\n\n /**\n * Build query params from a request-like object with a URL.\n */\n static fromRequest(request: Request | TangoRequest): TangoQueryParams {\n return TangoQueryParams.fromURL(request.url);\n }\n\n /**\n * Get the first value for a query param.\n */\n get(name: string): string | undefined {\n return this.values.get(name)?.[0];\n }\n\n /**\n * Get all values for a query param.\n */\n getAll(name: string): string[] {\n return [...(this.values.get(name) ?? [])];\n }\n\n /**\n * Check whether a query param exists.\n */\n has(name: string): boolean {\n return (this.values.get(name)?.length ?? 0) > 0;\n }\n\n /**\n * Iterate key -> values entries.\n */\n *entries(): IterableIterator<[string, string[]]> {\n for (const [key, values] of this.values.entries()) {\n yield [key, [...values]];\n }\n }\n\n /**\n * Iterate keys present in the query params.\n */\n *keys(): IterableIterator<string> {\n yield* this.values.keys();\n }\n\n /**\n * Convert back to a native `URLSearchParams` object.\n */\n toURLSearchParams(): URLSearchParams {\n const params = new URLSearchParams();\n\n for (const [key, values] of this.values.entries()) {\n for (const value of values) {\n params.append(key, value);\n }\n }\n\n return params;\n }\n\n /**\n * Return a new query param set with selected keys replaced or removed.\n *\n * `undefined`, `null`, and empty arrays remove the key entirely.\n */\n withValues(updates: QueryParamMutationRecord): TangoQueryParams {\n const next = new Map<string, string[]>();\n\n for (const [key, values] of this.values.entries()) {\n next.set(key, [...values]);\n }\n\n for (const [key, value] of Object.entries(updates)) {\n if (value === undefined || value === null) {\n next.delete(key);\n continue;\n }\n\n const normalized = Array.isArray(value) ? value.map((entry) => String(entry)) : [String(value)];\n if (normalized.length === 0) {\n next.delete(key);\n continue;\n }\n\n next.set(key, normalized);\n }\n\n return new TangoQueryParams(next);\n }\n\n /**\n * Convert to a relative query string suitable for links.\n */\n toRelativeURL(): string {\n const query = this.toURLSearchParams().toString();\n return query.length > 0 ? `?${query}` : '';\n }\n\n /**\n * Get a trimmed value, omitting blank strings.\n */\n getTrimmed(name: string): string | undefined {\n const value = this.get(name)?.trim();\n return value ? value : undefined;\n }\n\n /**\n * Get the free-text search param using Tango's default key.\n */\n getSearch(key: string = 'search'): string | undefined {\n return this.getTrimmed(key);\n }\n\n /**\n * Get the ordering param as trimmed field tokens.\n */\n getOrdering(key: string = 'ordering'): string[] {\n const value = this.get(key);\n if (!value) {\n return [];\n }\n\n return value\n .split(',')\n .map((token) => token.trim())\n .filter((token) => token.length > 0);\n }\n}\n","import type { JsonValue } from './TangoBody';\nimport { TangoQueryParams } from './TangoQueryParams';\nimport {\n isArrayBuffer,\n isBlob,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\n\ntype TangoRequestInit = {\n method?: string;\n headers?: HeadersInit;\n body?: BodyInit | JsonValue | null;\n redirect?: RequestRedirect;\n cache?: RequestCache;\n credentials?: RequestCredentials;\n integrity?: string;\n keepalive?: boolean;\n mode?: RequestMode;\n referrer?: string;\n referrerPolicy?: ReferrerPolicy;\n signal?: AbortSignal;\n};\n\n/**\n * Framework request wrapper that normalizes JSON-like bodies and preserves\n * fetch `Request` compatibility for downstream handlers.\n */\nexport class TangoRequest implements Request {\n static readonly BRAND = 'tango.http.request' as const;\n readonly __tangoBrand: typeof TangoRequest.BRAND = TangoRequest.BRAND;\n private request: Request;\n private bodySourceValue: BodyInit | JsonValue | null;\n private queryParamsValue?: TangoQueryParams;\n\n constructor(input: string | Request, init: TangoRequestInit = {}) {\n const sourceRequest = typeof input === 'string' ? undefined : input;\n const method = (init.method ?? sourceRequest?.method ?? 'GET').toUpperCase();\n const headers = new Headers(init.headers ?? sourceRequest?.headers);\n const normalizedBody = this.normalizeBody(init.body, headers, method);\n\n const requestInit: RequestInit & { duplex?: 'half' } = {\n method,\n headers,\n redirect: init.redirect ?? sourceRequest?.redirect,\n cache: init.cache ?? sourceRequest?.cache,\n credentials: init.credentials ?? sourceRequest?.credentials,\n integrity: init.integrity ?? sourceRequest?.integrity,\n keepalive: init.keepalive ?? sourceRequest?.keepalive,\n mode: init.mode ?? sourceRequest?.mode,\n referrer: init.referrer ?? sourceRequest?.referrer,\n referrerPolicy: init.referrerPolicy ?? sourceRequest?.referrerPolicy,\n signal: init.signal ?? sourceRequest?.signal,\n };\n\n if (normalizedBody !== undefined) {\n requestInit.body = normalizedBody;\n if (isReadableStream(normalizedBody)) {\n requestInit.duplex = 'half';\n }\n }\n\n this.request = new Request(input, requestInit);\n this.bodySourceValue = normalizedBody ?? null;\n }\n\n /**\n * Narrow an unknown value to `TangoRequest`.\n */\n static isTangoRequest(value: unknown): value is TangoRequest {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoRequest.BRAND\n );\n }\n\n /**\n * Expose the request cache mode from the underlying fetch request.\n */\n get cache(): RequestCache {\n return this.request.cache;\n }\n\n /**\n * Expose the request credentials mode from the underlying fetch request.\n */\n get credentials(): RequestCredentials {\n return this.request.credentials;\n }\n\n /**\n * Expose the request destination from the underlying fetch request.\n */\n get destination(): RequestDestination {\n return this.request.destination;\n }\n\n /**\n * Expose the request headers from the underlying fetch request.\n */\n get headers(): Headers {\n return this.request.headers;\n }\n\n /**\n * Expose the request integrity value from the underlying fetch request.\n */\n get integrity(): string {\n return this.request.integrity;\n }\n\n /**\n * Expose the request keepalive flag from the underlying fetch request.\n */\n get keepalive(): boolean {\n return this.request.keepalive;\n }\n\n /**\n * Expose the normalized HTTP method.\n */\n get method(): string {\n return this.request.method;\n }\n\n /**\n * Expose the request mode from the underlying fetch request.\n */\n get mode(): RequestMode {\n return this.request.mode;\n }\n\n /**\n * Expose the redirect policy from the underlying fetch request.\n */\n get redirect(): RequestRedirect {\n return this.request.redirect;\n }\n\n /**\n * Expose the referrer from the underlying fetch request.\n */\n get referrer(): string {\n return this.request.referrer;\n }\n\n /**\n * Expose the referrer policy from the underlying fetch request.\n */\n get referrerPolicy(): ReferrerPolicy {\n return this.request.referrerPolicy;\n }\n\n /**\n * Expose the abort signal from the underlying fetch request.\n */\n get signal(): AbortSignal {\n return this.request.signal;\n }\n\n /**\n * Expose the absolute request URL.\n */\n get url(): string {\n return this.request.url;\n }\n\n /**\n * Expose the readable request body stream when one exists.\n */\n get body(): Request['body'] {\n return this.request.body;\n }\n\n /**\n * Report whether the body has been consumed.\n */\n get bodyUsed(): boolean {\n return this.request.bodyUsed;\n }\n\n /**\n * Expose the pre-normalized body value used to build the request.\n */\n get bodySource(): BodyInit | JsonValue | null {\n return this.bodySourceValue;\n }\n\n /**\n * Expose normalized query parameters derived from the request URL.\n */\n get queryParams(): TangoQueryParams {\n this.queryParamsValue ??= TangoQueryParams.fromURL(this.request.url);\n return this.queryParamsValue;\n }\n\n /**\n * Read the request body as an array buffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.request.arrayBuffer();\n }\n\n /**\n * Read the request body as a blob.\n */\n async blob(): Promise<Blob> {\n return this.request.blob();\n }\n\n /**\n * Read the request body as bytes, including runtimes without `Request.bytes()`.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n const requestWithBytes = this.request as Request & { bytes?: () => Promise<Uint8Array<ArrayBuffer>> };\n if (typeof requestWithBytes.bytes === 'function') {\n return requestWithBytes.bytes();\n }\n const buffer = await this.request.arrayBuffer();\n return new Uint8Array(buffer);\n }\n\n /**\n * Read the request body as form data.\n */\n async formData(): Promise<FormData> {\n return this.request.formData();\n }\n\n /**\n * Parse the request body as JSON.\n */\n async json<T = unknown>(): Promise<T> {\n return this.request.json() as Promise<T>;\n }\n\n /**\n * Read the request body as text.\n */\n async text(): Promise<string> {\n return this.request.text();\n }\n\n /**\n * Clone the request so downstream code can consume it independently.\n */\n clone(): TangoRequest {\n return new TangoRequest(this.request.clone());\n }\n\n private normalizeBody(\n body: BodyInit | JsonValue | null | undefined,\n headers: Headers,\n method: string\n ): BodyInit | undefined {\n if (method === 'GET' || method === 'HEAD') {\n return undefined;\n }\n if (isNil(body)) {\n return undefined;\n }\n if (typeof body === 'string') {\n return body;\n }\n if (isArrayBuffer(body) || isUint8Array(body) || isBlob(body)) {\n return body;\n }\n if (isURLSearchParams(body) || isFormData(body) || isReadableStream(body)) {\n return body as BodyInit;\n }\n\n const serialized = JSON.stringify(body);\n if (!headers.has('content-type')) {\n headers.set('content-type', 'application/json; charset=utf-8');\n }\n return serialized;\n }\n}\n","import { TangoError, type ErrorEnvelope, type ErrorDetails, type ProblemDetails } from '../errors/TangoError';\nimport {\n isArrayBuffer,\n isBlob,\n isFormData,\n isNil,\n isReadableStream,\n isUint8Array,\n isURLSearchParams,\n} from '../runtime/index';\nimport { TangoHeaders } from '../http/TangoHeaders';\nimport { TangoBody, type JsonValue } from './TangoBody';\n\ntype TangoResponseInit = {\n body?: BodyInit | JsonValue | null;\n headers?: HeadersInit;\n ok?: boolean;\n redirected?: boolean;\n status?: number;\n statusText?: string;\n type?: ResponseType;\n url?: string;\n};\n\n/**\n * Framework response wrapper with fetch-compatible surface plus ergonomic helpers.\n */\nexport class TangoResponse implements Response {\n static readonly BRAND = 'tango.http.response' as const;\n readonly __tangoBrand: typeof TangoResponse.BRAND = TangoResponse.BRAND;\n readonly headers: TangoHeaders;\n readonly redirected: boolean;\n readonly status: number;\n readonly statusText: string;\n readonly type: ResponseType;\n readonly url: string;\n readonly body: Response['body'];\n private tangoBody: TangoBody;\n private okValue: boolean | undefined;\n\n constructor(init: TangoResponseInit = {}) {\n this.headers = new TangoHeaders(init.headers);\n this.redirected = Boolean(init.redirected);\n this.status = typeof init.status === 'number' ? init.status : 200;\n this.statusText = init.statusText || '';\n this.type = init.type || 'default';\n this.url = init.url || '';\n this.okValue = typeof init.ok === 'boolean' ? init.ok : undefined;\n\n this.tangoBody = new TangoBody(init.body ?? null, this.headers);\n this.body = isReadableStream(this.tangoBody.bodySource) ? this.tangoBody.bodySource : null;\n }\n\n /**\n * Narrow an unknown value to `TangoResponse`.\n */\n static isTangoResponse(value: unknown): value is TangoResponse {\n return (\n typeof value === 'object' &&\n value !== null &&\n (value as { __tangoBrand?: unknown }).__tangoBrand === TangoResponse.BRAND\n );\n }\n\n /**\n * Create a JSON response with sensible content headers.\n */\n static json(\n data: JsonValue,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json; charset=utf-8');\n }\n const body = JSON.stringify(data);\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(body).length.toString());\n }\n return new TangoResponse({\n ...init,\n body,\n headers,\n });\n }\n\n /**\n * Create a plain-text response with sensible content headers.\n */\n static text(\n text: string,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'text/plain; charset=utf-8');\n }\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(text).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: text,\n headers,\n });\n }\n\n /**\n * Create an HTML response with sensible content headers.\n */\n static html(\n html: string,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'text/html; charset=utf-8');\n }\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(html).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: html,\n headers,\n });\n }\n\n /**\n * Create a streaming response without buffering the payload in memory.\n */\n static stream(\n stream: ReadableStream<Uint8Array>,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n return new TangoResponse({\n ...init,\n body: stream,\n headers: new TangoHeaders(init?.headers),\n });\n }\n\n /**\n * Create a redirect response and set the `Location` header.\n */\n static redirect(\n url: string,\n status: number = 302,\n init?: Omit<TangoResponseInit, 'body' | 'headers' | 'status'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n headers.set('Location', url);\n return new TangoResponse({\n ...init,\n body: undefined,\n status,\n headers,\n redirected: true,\n url,\n });\n }\n\n /**\n * Create an empty `204 No Content` response.\n */\n static noContent(\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n return new TangoResponse({\n ...init,\n body: undefined,\n status: 204,\n headers,\n });\n }\n\n /**\n * Create a `201 Created` response and optionally attach a location or body.\n */\n static created(\n location?: string,\n body?: JsonValue,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (location) {\n headers.set('Location', location);\n }\n let respBody: BodyInit | undefined;\n if (body !== undefined) {\n respBody = JSON.stringify(body);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/json; charset=utf-8');\n }\n }\n if (typeof respBody === 'string' && !headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(respBody).length.toString());\n }\n return new TangoResponse({\n ...init,\n body: respBody,\n status: 201,\n headers,\n });\n }\n\n /**\n * Create a `405 Method Not Allowed` response and optionally populate `Allow`.\n */\n static methodNotAllowed<TDetails extends ErrorDetails = null>(\n allow?: readonly string[],\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n const headers = new TangoHeaders(init?.headers);\n if (allow && allow.length > 0) {\n headers.set('Allow', allow.join(', '));\n }\n\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 405, headers });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'method_not_allowed',\n message: detail,\n },\n { ...init, status: 405, headers }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'method_not_allowed',\n message: 'Method not allowed.',\n },\n { ...init, status: 405, headers }\n );\n }\n\n /**\n * Normalize a Tango error or problem-details object into an error response.\n */\n static error<TDetails extends ErrorDetails = null>(\n error: TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit }\n ): TangoResponse {\n let code: string;\n let message: string;\n let details: ErrorDetails;\n let fields: Record<string, string[]> | undefined;\n let status = init?.status ?? 500;\n\n if (TangoError.isTangoError(error)) {\n const envelope = error.toErrorEnvelope();\n code = envelope.error.code;\n message = envelope.error.message;\n details = envelope.error.details;\n fields = envelope.error.fields;\n status = error.status;\n } else {\n code = error.code;\n message = error.message;\n details = error.details;\n fields = error.fields;\n }\n\n return TangoResponse.problem(\n {\n code,\n message,\n details,\n fields,\n },\n {\n ...init,\n status,\n }\n );\n }\n\n /**\n * Create a `400 Bad Request` response from a string or structured error.\n */\n static badRequest<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 400 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'bad_request',\n message: detail,\n },\n { ...init, status: 400 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'bad_request',\n message: 'Bad Request',\n },\n { ...init, status: 400 }\n );\n }\n\n /**\n * Create a `401 Unauthorized` response from a string or structured error.\n */\n static unauthorized<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 401 });\n }\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'unauthorized',\n message: detail,\n },\n { ...init, status: 401 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'unauthorized',\n message: 'Unauthorized',\n },\n { ...init, status: 401 }\n );\n }\n\n /**\n * Create a `403 Forbidden` response from a string or structured error.\n */\n static forbidden<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 403 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'forbidden',\n message: detail,\n },\n { ...init, status: 403 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'forbidden',\n message: 'Forbidden',\n },\n { ...init, status: 403 }\n );\n }\n\n /**\n * Create a `404 Not Found` response from a string or structured error.\n */\n static notFound<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 404 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'not_found',\n message: detail,\n },\n { ...init, status: 404 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'not_found',\n message: 'Not Found',\n },\n { ...init, status: 404 }\n );\n }\n\n /**\n * Create a `409 Conflict` response from a string or structured error.\n */\n static conflict<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 409 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'conflict',\n message: detail,\n },\n { ...init, status: 409 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'conflict',\n message: 'Conflict',\n },\n { ...init, status: 409 }\n );\n }\n\n /**\n * Create a `422 Unprocessable Entity` response from a string or structured error.\n */\n static unprocessableEntity<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 422 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'unprocessable_entity',\n message: detail,\n },\n { ...init, status: 422 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'unprocessable_entity',\n message: 'Unprocessable Entity',\n },\n { ...init, status: 422 }\n );\n }\n\n /**\n * Create a `429 Too Many Requests` response from a string or structured error.\n */\n static tooManyRequests<TDetails extends ErrorDetails = null>(\n detail?: string | TangoError | ProblemDetails<TDetails>,\n init?: Omit<TangoResponseInit, 'body' | 'status' | 'headers'> & {\n headers?: HeadersInit;\n }\n ): TangoResponse {\n if (TangoError.isTangoError(detail) || TangoError.isProblemDetails(detail)) {\n return TangoResponse.error(detail, { ...init, status: 429 });\n }\n\n if (typeof detail === 'string') {\n return TangoResponse.error(\n {\n code: 'too_many_requests',\n message: detail,\n },\n { ...init, status: 429 }\n );\n }\n\n return TangoResponse.error(\n {\n code: 'too_many_requests',\n message: 'Too Many Requests',\n },\n { ...init, status: 429 }\n );\n }\n\n /**\n * Create a problem-details style error response with Tango's envelope shape.\n */\n static problem<TDetails extends ErrorDetails = null>(\n problem?: string | TangoError | ProblemDetails<TDetails> | unknown,\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & {\n headers?: HeadersInit;\n status?: number;\n }\n ): TangoResponse {\n let status = init?.status ?? 500;\n const headers = new TangoHeaders(init?.headers);\n if (!headers.has('Content-Type')) {\n headers.set('Content-Type', 'application/problem+json; charset=utf-8');\n }\n\n let code = 'error';\n let message = 'An error occurred';\n let details: ErrorDetails = undefined;\n let fields: Record<string, string[]> | undefined;\n\n if (TangoError.isTangoError(problem)) {\n const envelope = problem.toErrorEnvelope();\n status = problem.status;\n code = envelope.error.code;\n message = envelope.error.message;\n details = envelope.error.details;\n fields = envelope.error.fields;\n } else if (TangoError.isProblemDetails(problem)) {\n code = problem.code;\n message = problem.message;\n details = problem.details;\n fields = problem.fields;\n } else if (typeof problem === 'string') {\n message = problem;\n } else if (problem && typeof problem === 'object') {\n const extracted = problem as {\n details?: ErrorDetails;\n fields?: Record<string, string[]>;\n };\n details = extracted.details;\n fields = extracted.fields;\n }\n\n const envelope: ErrorEnvelope<ErrorDetails> = {\n error: {\n code,\n message,\n ...(details === undefined ? {} : { details }),\n ...(fields ? { fields } : {}),\n },\n };\n\n const body = JSON.stringify(envelope);\n if (!headers.has('Content-Length')) {\n headers.set('Content-Length', new TextEncoder().encode(body).length.toString());\n }\n return new TangoResponse({\n ...init,\n headers,\n status,\n body,\n });\n }\n\n /**\n * Returns a response for serving a file.\n */\n static file(\n file: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | string,\n opts?: {\n filename?: string;\n contentType?: string;\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit };\n }\n ): TangoResponse {\n const headers = new TangoHeaders(opts?.init?.headers ?? {});\n if (opts?.filename) {\n // Serve as an attachment by default, but not 'download'\n headers.setContentDispositionInline(opts.filename);\n }\n if (opts?.contentType && !headers.has('Content-Type')) {\n headers.set('Content-Type', opts.contentType);\n } else if (!headers.has('Content-Type')) {\n headers.setContentTypeByFile(file, opts?.filename);\n }\n if (!headers.has('Content-Length')) {\n headers.setContentLengthFromBody(file);\n }\n return new TangoResponse({\n ...opts?.init,\n body: file as BodyInit,\n headers,\n });\n }\n\n /**\n * Returns a response that prompts the user to download the file.\n */\n static download(\n file: Blob | Uint8Array | ArrayBuffer | ReadableStream<Uint8Array> | string,\n opts?: {\n filename?: string;\n contentType?: string;\n init?: Omit<TangoResponseInit, 'body' | 'headers'> & { headers?: HeadersInit };\n }\n ): TangoResponse {\n const headers = new TangoHeaders(opts?.init?.headers ?? {});\n if (opts?.filename) {\n headers.setContentDispositionAttachment(opts.filename);\n } else {\n headers.set('Content-Disposition', 'attachment');\n }\n if (opts?.contentType && !headers.has('Content-Type')) {\n headers.set('Content-Type', opts.contentType);\n } else if (!headers.has('Content-Type')) {\n headers.setContentTypeByFile(file, opts?.filename);\n }\n if (!headers.has('Content-Length')) {\n headers.setContentLengthFromBody(file);\n }\n return new TangoResponse({\n ...opts?.init,\n body: file as BodyInit,\n headers,\n });\n }\n\n private static normalizeWebBody(body: BodyInit | JsonValue | null): BodyInit | null {\n if (\n isNil(body) ||\n typeof body === 'string' ||\n isBlob(body) ||\n isFormData(body) ||\n isArrayBuffer(body) ||\n isUint8Array(body) ||\n isURLSearchParams(body) ||\n isReadableStream(body)\n ) {\n return body;\n }\n\n return JSON.stringify(body);\n }\n\n /**\n * Expose the original body source for cloning and adapter integration.\n */\n get bodySource(): BodyInit | JsonValue | null {\n return this.tangoBody.bodySource;\n }\n\n /**\n * Report whether the status code falls inside the 2xx range.\n */\n get ok(): boolean {\n if (typeof this.okValue === 'boolean') return this.okValue;\n return this.status >= 200 && this.status < 300;\n }\n\n /**\n * Report whether the body has been consumed.\n */\n get bodyUsed(): boolean {\n return this.tangoBody.bodyUsed;\n }\n\n /**\n * Replace a header value on the response.\n */\n setHeader(name: string, value: string): void {\n this.headers.set(name, value);\n }\n /**\n * Append another value for a repeated response header.\n */\n appendHeader(name: string, value: string): void {\n this.headers.append(name, value);\n }\n /**\n * Read a response header value.\n */\n getHeader(name: string): string | null {\n return this.headers.get(name);\n }\n /**\n * Check whether a response header is present.\n */\n hasHeader(name: string): boolean {\n return this.headers.has(name);\n }\n /**\n * Remove a response header.\n */\n deleteHeader(name: string): void {\n this.headers.delete(name);\n }\n /**\n * Merge one or more values into the `Vary` header.\n */\n vary(...fields: string[]): void {\n this.headers.vary(...fields);\n }\n\n /**\n * Add a `Set-Cookie` header that replaces prior application intent.\n */\n setCookie(name: string, value: string, options?: Parameters<TangoHeaders['setCookie']>[2]): void {\n this.headers.setCookie(name, value, options);\n }\n /**\n * Append another `Set-Cookie` header.\n */\n appendCookie(name: string, value: string, options?: Parameters<TangoHeaders['appendCookie']>[2]): void {\n this.headers.appendCookie(name, value, options);\n }\n /**\n * Expire a cookie by issuing a matching deletion cookie header.\n */\n deleteCookie(name: string, options?: Parameters<TangoHeaders['deleteCookie']>[1]): void {\n this.headers.deleteCookie(name, options);\n }\n\n /**\n * Set the `Cache-Control` header through Tango's higher-level helper.\n */\n cacheControl(control: Parameters<TangoHeaders['cacheControl']>[0]): void {\n this.headers.cacheControl(control);\n }\n\n /**\n * Set the `Location` header on the response.\n */\n location(url: string): void {\n this.headers.location(url);\n }\n\n /**\n * Set the response content type.\n */\n contentType(mime: string): void {\n this.headers.contentType(mime);\n }\n\n // ---- Trace & Correlation helper methods ----\n\n /**\n * Set the X-Request-Id header (request correlation).\n * Returns this for fluent chaining.\n */\n withRequestId(requestId: string | undefined | null): this {\n if (!isNil(requestId) && typeof requestId === 'string' && requestId !== '') {\n this.headers.set('X-Request-Id', requestId);\n }\n return this;\n }\n\n /**\n * Set the traceparent header (W3C Trace Context propagation).\n * Returns this for fluent chaining.\n */\n withTraceparent(traceparent: string | undefined | null): this {\n if (!isNil(traceparent) && typeof traceparent === 'string' && traceparent !== '') {\n this.headers.set('traceparent', traceparent);\n }\n return this;\n }\n\n /**\n * Set the Server-Timing header.\n * Accepts a string or array of timing metrics.\n * Returns this for fluent chaining.\n */\n withServerTiming(timing: string | string[]): this {\n if (Array.isArray(timing)) {\n this.headers.set('Server-Timing', timing.join(', '));\n } else if (typeof timing === 'string') {\n this.headers.set('Server-Timing', timing);\n }\n return this;\n }\n\n /**\n * Set the X-Response-Time header (in ms).\n * Numeric or formatted string (e.g. \"76ms\").\n * Returns this for fluent chaining.\n */\n withResponseTime(time: number | string): this {\n if (typeof time === 'number') {\n this.headers.set('X-Response-Time', `${time}ms`);\n } else if (typeof time === 'string') {\n this.headers.set('X-Response-Time', time);\n }\n return this;\n }\n\n /**\n * Propagate common tracing/correlation headers from provided Headers, TangoHeaders, or plain object.\n * Known headers: x-request-id, traceparent, server-timing\n * Returns this for fluent chaining.\n */\n propagateTraceHeaders(input: HeadersInit): this {\n const incoming = new TangoHeaders(input);\n const traceHeaderNames = [\n 'x-request-id',\n 'traceparent',\n 'server-timing',\n // If you want to propagate response time, add 'x-response-time',\n ];\n for (const name of traceHeaderNames) {\n const value = incoming.get(name);\n if (!isNil(value)) this.headers.set(name, value);\n }\n return this;\n }\n\n /**\n * Clone the response so its body can be consumed independently.\n */\n clone(): TangoResponse {\n if (this.bodyUsed) {\n throw new TypeError('Body has already been used');\n }\n const clonedBody = this.tangoBody.clone();\n return new TangoResponse({\n body: clonedBody.bodySource,\n headers: this.headers.clone(),\n ok: this.okValue,\n redirected: this.redirected,\n status: this.status,\n statusText: this.statusText,\n type: this.type,\n url: this.url,\n });\n }\n\n /**\n * Convert this Tango-owned response into a native web `Response`.\n *\n * Adapters use this at the host-framework boundary so Tango can standardize\n * on `TangoResponse` internally while Next.js and other hosts still receive\n * a platform-native response object.\n */\n toWebResponse(): Response {\n const responseForTransfer = !this.bodyUsed && isReadableStream(this.bodySource) ? this.clone() : this;\n const body = TangoResponse.normalizeWebBody(responseForTransfer.bodySource);\n\n return new Response(body, {\n headers: new Headers(responseForTransfer.headers),\n status: responseForTransfer.status,\n statusText: responseForTransfer.statusText,\n });\n }\n\n //---- Spec Response interface fields and methods ----\n\n /**\n * Read the response body as an array buffer.\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.tangoBody.arrayBuffer();\n }\n /**\n * Read the response body as a blob.\n */\n async blob(): Promise<Blob> {\n return this.tangoBody.blob();\n }\n /**\n * Read the response body as bytes.\n */\n async bytes(): Promise<Uint8Array<ArrayBuffer>> {\n return this.tangoBody.bytes();\n }\n /**\n * Read the response body as form data.\n */\n async formData(): Promise<FormData> {\n return this.tangoBody.formData();\n }\n /**\n * Parse the response body as JSON.\n */\n async json<T = unknown>(): Promise<T> {\n return this.tangoBody.json<T>();\n }\n /**\n * Read the response body as text.\n */\n async text(): Promise<string> {\n return this.tangoBody.text();\n }\n\n /**\n * Returns a plain object debug representation of this response: { status, headers: { ... }, bodyType: ... }.\n * Intended for testing and debug tooling.\n */\n toJSON(): { status: number; headers: Record<string, string>; bodyType: string } {\n return {\n status: this.status,\n headers: Object.fromEntries(this.headers.entries()),\n bodyType: this.tangoBody.bodyType,\n };\n }\n\n /**\n * Returns the original body for test/debug purposes *without* consuming the stream.\n *\n * @throws {Error} if called in a production environment. Provided only for test or debug.\n * @remarks\n * This method gives direct access to the original body as provided to the constructor,\n * before consumption. It is primarily intended for use in test code, introspection, or\n * advanced debug tools. **Do not rely on this in production.**\n * In production (`process.env.NODE_ENV === 'production'`), using this method will throw.\n *\n * This method is _not_ part of the web Response interface, and is intentionally private/internal.\n */\n\n public __peekBodyForTestOnly(): BodyInit | JsonValue | null {\n const nodeEnv = typeof process !== 'undefined' ? (process.env?.NODE_ENV as string | undefined) : undefined;\n\n // Strong guard against accidental shipping in production\n if (nodeEnv === 'production' || nodeEnv === 'prod') {\n throw new Error('peekBody() is not available in production builds. For test/debug use only.');\n }\n return this.tangoBody.bodySource;\n }\n}\n","/**\n * Domain boundary barrel: centralizes this subdomain's public contract.\n */\n\nimport { TangoBody, type JsonValue } from './TangoBody';\nimport { TangoHeaders } from './TangoHeaders';\nimport { TangoQueryParams } from './TangoQueryParams';\nimport { TangoRequest } from './TangoRequest';\nimport { TangoResponse } from './TangoResponse';\n\nexport { TangoBody, TangoHeaders, TangoQueryParams, TangoRequest, TangoResponse };\nexport type { JsonValue };\n"],"mappings":"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"}
|