@innvoid/getmarket-sdk 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/cache/redisCacheProvider.ts","../src/cache/cacheProvider.ts","../src/cache/ttlCache.ts","../src/cache/twoLevelCache.ts","../src/cache/index.ts","../src/core/errors.ts","../src/core/http.ts","../src/core/internalHttp.ts","../src/headers/constants.ts","../src/headers/parse.ts","../src/middlewares/requestId.ts","../src/middlewares/parseHeaders.ts","../src/middlewares/internalAuth.ts","../src/middlewares/respond.ts"],"sourcesContent":["// src/index.ts\nexport * from \"./cache\";\nexport * from \"./core\";\nexport * from \"./headers\";\nexport * from \"./middlewares\";\n","// clients/cache/redisCacheProvider.ts\nimport {createClient, type RedisClientType} from \"redis\";\nimport type {CacheProvider, CacheSetOptions, CacheValue} from \"./cacheProvider\";\n\nexport type RedisCacheProviderOptions = {\n url?: string;\n\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n\n tls?: boolean;\n\n connectTimeoutMs?: number;\n\n keyPrefix?: string;\n};\n\nfunction buildRedisUrl(opts: RedisCacheProviderOptions): string | undefined {\n if (opts.url && opts.url.trim()) return opts.url.trim();\n\n if (!opts.host) return undefined;\n const port = opts.port ?? 6379;\n const db = opts.db ?? 0;\n\n const auth = opts.password ? `:${encodeURIComponent(opts.password)}@` : \"\";\n return `redis://${auth}${opts.host}:${port}/${db}`;\n}\n\nexport class RedisCacheProvider implements CacheProvider {\n readonly kind = \"redis\" as const;\n\n // ✅ tip \"amplio\" para evitar TS2322 por typings genéricos\n private client: RedisClientType<any, any, any>;\n private ready = false;\n private readonly keyPrefix?: string;\n\n constructor(private readonly opts: RedisCacheProviderOptions) {\n const url = buildRedisUrl(opts);\n if (!url) {\n throw new Error(\"[RedisCacheProvider] Missing redis config (REDIS_URL or REDIS_HOST)\");\n }\n\n this.keyPrefix = opts.keyPrefix?.trim() || undefined;\n\n this.client = createClient({\n url,\n socket: {\n connectTimeout: opts.connectTimeoutMs ?? 3000,\n tls: opts.tls ? true : undefined,\n },\n }) as RedisClientType<any, any, any>;\n\n this.client.on(\"error\", (err: unknown) => {\n const msg =\n err instanceof Error\n ? err.message\n : typeof err === \"object\" && err !== null && \"message\" in err\n ? String((err as any).message)\n : String(err);\n\n console.error(\"[redis] error\", msg, err);\n });\n }\n\n private k(key: string): string {\n if (!this.keyPrefix) return key;\n return `${this.keyPrefix}:${key}`;\n }\n\n private async ensureConnected() {\n if (this.ready) return;\n await this.client.connect();\n this.ready = true;\n }\n\n async get(key: string): Promise<CacheValue | null> {\n await this.ensureConnected();\n const v = (await this.client.get(this.k(key))) as string | null;\n return v ?? null;\n }\n\n async set(key: string, value: CacheValue, options?: CacheSetOptions): Promise<void> {\n await this.ensureConnected();\n\n const ttlMs = options?.ttlMs;\n if (ttlMs && ttlMs > 0) {\n await this.client.set(this.k(key), value, {PX: ttlMs});\n return;\n }\n\n await this.client.set(this.k(key), value);\n }\n\n async del(key: string): Promise<void> {\n await this.ensureConnected();\n await this.client.del(this.k(key));\n }\n\n async close(): Promise<void> {\n try {\n if (this.ready) await this.client.quit();\n } catch {\n try {\n await this.client.disconnect();\n } catch {\n }\n } finally {\n this.ready = false;\n }\n }\n}\n","// clients/cache/cacheProvider.ts\nimport type {RedisCacheProviderOptions} from \"./redisCacheProvider\";\nimport {RedisCacheProvider} from \"./redisCacheProvider\";\n\nexport type CacheValue = string;\n\nexport type CacheSetOptions = {\n ttlMs?: number; // TTL en milisegundos (PX)\n};\n\nexport interface CacheProvider {\n readonly kind: \"redis\" | \"noop\";\n\n get(key: string): Promise<CacheValue | null>;\n\n set(key: string, value: CacheValue, options?: CacheSetOptions): Promise<void>;\n\n del(key: string): Promise<void>;\n\n /**\n * Cierra conexiones si aplica.\n */\n close(): Promise<void>;\n}\n\nexport class NoopCacheProvider implements CacheProvider {\n readonly kind = \"noop\" as const;\n\n async get(_key: string): Promise<CacheValue | null> {\n return null;\n }\n\n async set(_key: string, _value: CacheValue, _options?: CacheSetOptions): Promise<void> {\n return;\n }\n\n async del(_key: string): Promise<void> {\n return;\n }\n\n async close(): Promise<void> {\n return;\n }\n}\n\nexport type CacheProviderFactoryOptions = {\n /**\n * Si false, devuelve Noop (útil en local si no quieres Redis).\n * Default: true si hay REDIS_URL o REDIS_HOST.\n */\n enabled?: boolean;\n\n /**\n * Prefijo global opcional para keys.\n * Ej: \"getmarket:erp\"\n */\n keyPrefix?: string;\n\n /**\n * Redis options\n */\n redis?: Partial<RedisCacheProviderOptions>;\n};\n\n/**\n * Factory simple para L2 (Redis).\n * - Si no está habilitado / no hay config => Noop\n * - Si hay config => RedisCacheProvider\n */\nexport function createCacheProvider(opts: CacheProviderFactoryOptions = {}): CacheProvider {\n const envHasRedis = Boolean(process.env.REDIS_URL || process.env.REDIS_HOST);\n\n const enabled =\n typeof opts.enabled === \"boolean\" ? opts.enabled : envHasRedis;\n\n if (!enabled) return new NoopCacheProvider();\n\n // Construye options redis desde env + overrides\n const redisOpts: RedisCacheProviderOptions = {\n url: process.env.REDIS_URL,\n host: process.env.REDIS_HOST,\n port: process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : undefined,\n password: process.env.REDIS_PASSWORD,\n db: process.env.REDIS_DB ? Number(process.env.REDIS_DB) : undefined,\n tls: (process.env.REDIS_TLS || \"\").toLowerCase() === \"true\",\n connectTimeoutMs: process.env.REDIS_CONNECT_TIMEOUT_MS\n ? Number(process.env.REDIS_CONNECT_TIMEOUT_MS)\n : 3000,\n keyPrefix: opts.keyPrefix || process.env.REDIS_KEY_PREFIX || undefined,\n ...(opts.redis || {}),\n };\n\n return new RedisCacheProvider(redisOpts);\n}\n","// clients/cache/ttlCache.ts\ntype CacheEntry<T> = { value: T; expiresAt: number };\n\nexport class TtlCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n constructor(private defaultTtlMs: number) {\n }\n\n get(key: string): T | null {\n const e = this.store.get(key);\n if (!e) return null;\n if (Date.now() > e.expiresAt) {\n this.store.delete(key);\n return null;\n }\n return e.value;\n }\n\n set(key: string, value: T, ttlMs?: number): void {\n this.store.set(key, {value, expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs)});\n }\n\n del(key: string): void {\n this.store.delete(key);\n }\n}\n","// clients/cache/twoLevelCache.ts\nimport type {CacheProvider} from \"./cacheProvider\";\nimport {TtlCache} from \"./ttlCache\";\n\nexport type TwoLevelCacheOptions = {\n /**\n * TTL para L1 (in-memory).\n * Default: 2 min\n */\n ttlMsL1?: number;\n\n /**\n * TTL para L2 (redis).\n * Default: 10 min\n */\n ttlMsL2?: number;\n\n /**\n * Si quieres cachear \"no encontrado\" (null) por un TTL corto,\n * para evitar golpear upstream repetidamente.\n * Default: 0 (deshabilitado)\n */\n negativeTtlMsL1?: number;\n negativeTtlMsL2?: number;\n\n /**\n * Prefijo lógico extra por instancia (además del keyPrefix del provider).\n * Ej: \"res:variety\"\n */\n namespace?: string;\n};\n\ntype Loader<T> = () => Promise<T>;\n\nfunction safeJsonParse<T>(raw: string): T | null {\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nfunction safeJsonStringify(v: any): string | null {\n try {\n return JSON.stringify(v);\n } catch {\n return null;\n }\n}\n\nexport class TwoLevelCache<T> {\n private readonly l1: TtlCache<T | null>;\n private readonly inflight = new Map<string, Promise<T>>();\n\n constructor(\n private readonly l2: CacheProvider,\n private readonly opts: TwoLevelCacheOptions = {}\n ) {\n // El TTL real lo controla set(key, ttl), pero TTLCache necesita \"default ttl\"\n const defaultTtl = this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n this.l1 = new TtlCache<T | null>(defaultTtl);\n }\n\n private key(k: string): string {\n const ns = (this.opts.namespace || \"\").trim();\n return ns ? `${ns}:${k}` : k;\n }\n\n /**\n * GET \"best effort\": primero L1, luego L2.\n * (No llama loader)\n */\n async get(k: string): Promise<T | null> {\n const key = this.key(k);\n\n const v1 = this.l1.get(key);\n if (v1 !== undefined) return v1; // Ojo: TTLCache puede devolver null también\n\n const raw = await this.l2.get(key);\n if (!raw) return null;\n\n const parsed = safeJsonParse<T | null>(raw);\n if (parsed === null && raw !== \"null\") {\n // payload corrupto\n return null;\n }\n\n // Rehidrata L1 con ttl L1\n this.l1.set(key, parsed, this.opts.ttlMsL1);\n return parsed;\n }\n\n async set(k: string, value: T | null, ttlOverride?: { ttlMsL1?: number; ttlMsL2?: number }) {\n const key = this.key(k);\n\n const ttlL1 = ttlOverride?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n const ttlL2 = ttlOverride?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1000;\n\n this.l1.set(key, value, ttlL1);\n\n const raw = safeJsonStringify(value);\n if (raw == null) return;\n\n await this.l2.set(key, raw, {ttlMs: ttlL2});\n }\n\n async del(k: string) {\n const key = this.key(k);\n this.l1.del?.(key as any); // si tu TtlCache no tiene del(), ignora (ver comentario abajo)\n await this.l2.del(key);\n }\n\n /**\n * Cache-aside real con L1 + L2 + loader.\n *\n * - Dedup de concurrencia por key (inflight)\n * - Soporta negative caching (si loader retorna null)\n */\n async getOrSet(\n k: string,\n loader: Loader<T | null>,\n options?: TwoLevelCacheOptions\n ): Promise<T | null> {\n const key = this.key(k);\n\n // 1) L1\n const v1 = this.l1.get(key);\n if (v1 !== undefined) return v1;\n\n // 2) L2\n const raw = await this.l2.get(key);\n if (raw) {\n const parsed = safeJsonParse<T | null>(raw);\n if (parsed !== null || raw === \"null\") {\n this.l1.set(key, parsed, options?.ttlMsL1 ?? this.opts.ttlMsL1);\n return parsed;\n }\n }\n\n // 3) Dedup inflight (anti stampede)\n if (this.inflight.has(key)) {\n return this.inflight.get(key)! as any;\n }\n\n const promise = (async () => {\n try {\n const value = await loader();\n\n const ttlMsL1 = options?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n const ttlMsL2 = options?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1000;\n\n // negative caching\n const negL1 = options?.negativeTtlMsL1 ?? this.opts.negativeTtlMsL1 ?? 0;\n const negL2 = options?.negativeTtlMsL2 ?? this.opts.negativeTtlMsL2 ?? 0;\n\n if (value === null) {\n if (negL1 > 0) this.l1.set(key, null, negL1);\n if (negL2 > 0) await this.l2.set(key, \"null\", {ttlMs: negL2});\n return null;\n }\n\n // normal set\n this.l1.set(key, value, ttlMsL1);\n\n const rawValue = safeJsonStringify(value);\n if (rawValue != null) {\n await this.l2.set(key, rawValue, {ttlMs: ttlMsL2});\n }\n\n return value;\n } finally {\n this.inflight.delete(key);\n }\n })();\n\n this.inflight.set(key, promise as any);\n return promise;\n }\n}\n","// packages/sdk/src/cache/index.ts\nimport {createCacheProvider, type CacheProvider} from \"./cacheProvider\";\nimport {TwoLevelCache, type TwoLevelCacheOptions} from \"./twoLevelCache\";\n\nconst envInt = (v?: string, dflt: number = 0) => {\n const n = Number(v);\n return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;\n};\n\nconst DEFAULT_L1_TTL_MS = envInt(process.env.CACHE_L1_DEFAULT_TTL_MS, 30_000);\nconst DEFAULT_L2_TTL_MS = envInt(process.env.CACHE_L2_DEFAULT_TTL_MS, 300_000);\nconst DEFAULT_NEG_TTL_MS = envInt(process.env.CACHE_NEGATIVE_TTL_MS, 30_000);\n\nlet l2Provider: CacheProvider | null = null;\nconst twoLevelByNamespace = new Map<string, TwoLevelCache<any>>();\n\nfunction getL2(): CacheProvider {\n if (l2Provider) return l2Provider;\n l2Provider = createCacheProvider();\n return l2Provider;\n}\n\n/**\n * Retorna (o crea) un TwoLevelCache por namespace.\n * Namespace recomendado: auth:employee | md:country | platform:tenant-resolve ...\n */\nexport function getTwoLevelCache<T = any>(\n namespace: string,\n opts: Partial<TwoLevelCacheOptions> = {}\n): TwoLevelCache<T> {\n const existing = twoLevelByNamespace.get(namespace);\n if (existing) return existing as TwoLevelCache<T>;\n\n const l2 = getL2();\n\n const cacheOptions: TwoLevelCacheOptions = {\n // ✅ TwoLevelCache prefija keys con namespace internamente\n namespace,\n\n ttlMsL1: opts.ttlMsL1 ?? DEFAULT_L1_TTL_MS,\n ttlMsL2: opts.ttlMsL2 ?? DEFAULT_L2_TTL_MS,\n\n // ✅ negative caching\n negativeTtlMsL1: opts.negativeTtlMsL1 ?? DEFAULT_NEG_TTL_MS,\n negativeTtlMsL2: opts.negativeTtlMsL2 ?? DEFAULT_NEG_TTL_MS,\n };\n\n const cache = new TwoLevelCache<T>(l2, cacheOptions);\n twoLevelByNamespace.set(namespace, cache as TwoLevelCache<any>);\n return cache;\n}\n\n/**\n * Helper: cache.getOrSet\n *\n * IMPORTANT:\n * - No prefijar manualmente la key.\n * - TwoLevelCache ya usa opts.namespace.\n */\nexport async function getOrSet<T>(\n namespace: string,\n key: string,\n loader: () => Promise<T | null>,\n opts: Partial<TwoLevelCacheOptions> = {}\n): Promise<T | null> {\n const cache = getTwoLevelCache<T>(namespace, opts);\n return cache.getOrSet(key, loader, opts);\n}\n\nexport async function closeCache(): Promise<void> {\n try {\n if (l2Provider && typeof (l2Provider as any).close === \"function\") {\n await (l2Provider as any).close();\n }\n } finally {\n l2Provider = null;\n twoLevelByNamespace.clear();\n }\n}\n\n/**\n * ✅ Re-exports públicos para consumo desde:\n * import type {TwoLevelCacheOptions} from \"@innvoid/getmarket-sdk/cache\";\n */\nexport type {TwoLevelCacheOptions, CacheProvider};\nexport {TwoLevelCache};\n","export type ClientErrorCode =\n | \"UPSTREAM_TIMEOUT\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"UPSTREAM_BAD_RESPONSE\"\n | \"UPSTREAM_NOT_FOUND\"\n | \"UPSTREAM_UNAUTHORIZED\"\n | \"UPSTREAM_FORBIDDEN\"\n | \"UPSTREAM_UNKNOWN\";\n\nexport class UpstreamError extends Error {\n public code: ClientErrorCode;\n public status?: number;\n public details?: any;\n\n constructor(message: string, code: ClientErrorCode, status?: number, details?: any) {\n super(message);\n this.name = \"UpstreamError\";\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport function mapAxiosToUpstreamError(err: any, svc: string): UpstreamError {\n const status = err?.response?.status;\n const data = err?.response?.data;\n const isTimeout = err?.code === \"ECONNABORTED\" || String(err?.message || \"\").includes(\"timeout\");\n\n if (isTimeout) {\n return new UpstreamError(`[${svc}] timeout`, \"UPSTREAM_TIMEOUT\", 504, {cause: err?.message});\n }\n if (!err?.response) {\n return new UpstreamError(`[${svc}] unavailable`, \"UPSTREAM_UNAVAILABLE\", 503, {cause: err?.message});\n }\n if (status === 404) return new UpstreamError(`[${svc}] not found`, \"UPSTREAM_NOT_FOUND\", 404, data);\n if (status === 401) return new UpstreamError(`[${svc}] unauthorized`, \"UPSTREAM_UNAUTHORIZED\", 401, data);\n if (status === 403) return new UpstreamError(`[${svc}] forbidden`, \"UPSTREAM_FORBIDDEN\", 403, data);\n if (status >= 400 && status < 600) {\n return new UpstreamError(`[${svc}] bad response`, \"UPSTREAM_BAD_RESPONSE\", status, data);\n }\n return new UpstreamError(`[${svc}] unknown error`, \"UPSTREAM_UNKNOWN\", status, data);\n}\n","// clients/core/http.ts\nimport axios, {AxiosInstance, AxiosRequestConfig} from \"axios\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\n\nexport type HttpClientOpts = {\n baseURL: string;\n timeoutMs?: number;\n};\n\n/**\n * Headers compatibles con múltiples versiones de axios.\n * En axios antiguo, `headers` suele ser `any`, así que mantenemos tolerancia.\n */\nexport type AnyHeaders = NonNullable<AxiosRequestConfig[\"headers\"]> | Record<string, string>;\n\n/**\n * Agrega x-request-id a headers (sin pisar otros headers).\n */\nexport function withRequestId(headers: AnyHeaders | undefined, requestId?: string | null): AnyHeaders {\n const h: Record<string, any> =\n headers && typeof headers === \"object\"\n ? {...(headers as any)}\n : {};\n\n const rid = (requestId || \"\").trim();\n if (rid) h[REQUEST_ID_HEADER] = rid;\n\n return h as AnyHeaders;\n}\n\n/**\n * Helper para construir config de axios con requestId\n * (SIN genéricos para compat con axios typings antiguos).\n */\nexport function withRequestIdConfig(\n config: AxiosRequestConfig = {},\n requestId?: string | null\n): AxiosRequestConfig {\n return {\n ...config,\n headers: withRequestId((config as any).headers, requestId) as any,\n };\n}\n\nexport function createHttpClient(opts: HttpClientOpts): AxiosInstance {\n return axios.create({\n baseURL: opts.baseURL,\n timeout: opts.timeoutMs ?? 4000,\n headers: {\"Content-Type\": \"application/json\"},\n });\n}\n","// clients/internalHttp.ts\n\ntype RetryPolicy = {\n retries: number;\n baseDelayMs: number;\n retryOnStatuses: number[];\n retryOnNetworkErrors: boolean;\n};\n\ntype InternalHttpOptions = {\n baseUrl: string;\n apiKey?: string; // x-internal-api-key\n timeoutMs?: number;\n retry?: Partial<RetryPolicy>;\n};\n\nconst DEFAULT_RETRY: RetryPolicy = {\n retries: 1,\n baseDelayMs: 150,\n retryOnStatuses: [429, 502, 503, 504],\n retryOnNetworkErrors: true,\n};\n\nfunction sleep(ms: number) {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction safeJsonStringify(v: any) {\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\nfunction toHeaders(init?: HeadersInit): Headers {\n return new Headers(init || {});\n}\n\nfunction isJsonContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n const ct = contentType.toLowerCase();\n return ct.includes(\"application/json\") || ct.includes(\"+json\");\n}\n\nfunction isAbortError(e: any): boolean {\n return e?.name === \"AbortError\";\n}\n\nfunction withJitter(ms: number): number {\n // jitter +-20%\n const jitter = ms * 0.2;\n const delta = (Math.random() * 2 - 1) * jitter;\n return Math.max(0, Math.floor(ms + delta));\n}\n\nexport class InternalHttp {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly timeoutMs: number;\n private retry: RetryPolicy;\n\n constructor(opts: InternalHttpOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n\n // ✅ Default más seguro para internas (evita cascadas)\n this.timeoutMs = opts.timeoutMs ?? 4000;\n\n this.retry = {...DEFAULT_RETRY, ...(opts.retry || {})};\n }\n\n async request<T>(\n path: string,\n init: RequestInit & {\n requestId?: string;\n idempotencyKey?: string;\n headers?: HeadersInit;\n } = {}\n ): Promise<T> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n\n const baseHeaders = toHeaders(init.headers);\n\n if (!baseHeaders.has(\"Content-Type\")) baseHeaders.set(\"Content-Type\", \"application/json\");\n if (this.apiKey) baseHeaders.set(\"x-internal-api-key\", this.apiKey);\n\n if (init.requestId) baseHeaders.set(\"x-request-id\", init.requestId);\n if (init.idempotencyKey) baseHeaders.set(\"Idempotency-Key\", init.idempotencyKey);\n\n const {headers: _ignored, ...restInit} = init;\n\n const doFetchOnce = async () => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const res = await fetch(url, {\n ...restInit,\n headers: baseHeaders,\n signal: controller.signal,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n const err: any = new Error(\n `HTTP ${res.status} ${res.statusText}${text ? ` - ${text}` : \"\"}`\n );\n err.status = res.status;\n err.body = text;\n throw err;\n }\n\n if (res.status === 204) return undefined as unknown as T;\n\n const contentType = res.headers.get(\"content-type\");\n if (isJsonContentType(contentType)) {\n return (await res.json()) as T;\n }\n\n const text = await res.text().catch(() => \"\");\n return text as unknown as T;\n } finally {\n clearTimeout(timeout);\n }\n };\n\n let attempt = 0;\n\n while (true) {\n try {\n return await doFetchOnce();\n } catch (e: any) {\n attempt++;\n\n const status = e?.status;\n const retryableStatus = !!status && this.retry.retryOnStatuses.includes(status);\n\n const retryableNetwork =\n this.retry.retryOnNetworkErrors &&\n (isAbortError(e) || !status); // sin status suele ser red/dns/timeout\n\n const isRetryable = retryableStatus || retryableNetwork;\n\n if (!isRetryable || attempt > this.retry.retries) {\n console.error(\n `[InternalHttp] request failed: ${url} attempt=${attempt} status=${status ?? \"n/a\"} err=${e?.message\n } body=${safeJsonStringify(e?.body)}`\n );\n throw e;\n }\n\n const backoff = withJitter(this.retry.baseDelayMs * attempt);\n await sleep(backoff);\n }\n }\n }\n}\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction asString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n return s ? s : null;\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional)\n * - x-request-id: string (opcional)\n *\n * 🚫 No JSON, no _id, no objetos.\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,\n company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,\n branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,\n employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null,\n };\n}\n","// middlewares/requestId.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {randomUUID, randomBytes} from \"crypto\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\nexport const REQUEST_ID_HEADER_ALT = \"x-requestid\";\nexport const RESPONSE_REQUEST_ID_HEADER = \"X-Request-Id\";\n\n// Si quieres IDs más cortos (opcional). Por defecto usamos UUID.\nfunction nanoidLike(len = 21) {\n return randomBytes(16).toString(\"base64url\").slice(0, len);\n}\n\nexport default function requestId(req: Request, res: Response, next: NextFunction) {\n const headerId = (req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT]) as\n | string\n | undefined;\n\n // ✅ estándar único: usa UUID (o cambia a nanoidLike() si prefieres corto)\n const id = headerId?.trim() || randomUUID();\n\n // ✅ estándar único (no legacy)\n (req as any).requestId = id;\n res.locals.requestId = id;\n\n // ✅ respuesta\n res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY:\n * - solo setea UIDs\n * - no crea objetos company/branch\n * - no copia provider\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n const context = getRequestContextFromHeaders(req.headers as any);\n\n (req as any).context = context;\n\n const auth: any = (req as any).auth ?? ((req as any).auth = {});\n if (context.company_uid) auth.company_uid = context.company_uid;\n if (context.branch_uid) auth.branch_uid = context.branch_uid;\n if (context.employee_uid) auth.employee_uid = context.employee_uid;\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n"],"mappings":"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","names":["requestId","axios","safeJsonStringify","text","REQUEST_ID_HEADER","REQUEST_ID_HEADER","import_crypto","fs","crypto"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/cache/redisCacheProvider.ts","../src/cache/cacheProvider.ts","../src/cache/ttlCache.ts","../src/cache/twoLevelCache.ts","../src/cache/index.ts","../src/core/errors.ts","../src/core/http.ts","../src/core/internalHttp.ts","../src/headers/constants.ts","../src/headers/parse.ts","../src/middlewares/requestId.ts","../src/middlewares/parseHeaders.ts","../src/middlewares/internalAuth.ts","../src/middlewares/respond.ts","../src/middlewares/autorization.ts","../src/auth/index.ts","../src/auth/jwt.ts","../src/auth/middleware.ts"],"sourcesContent":["// src/index.ts\nexport * from \"./cache\";\nexport * from \"./core\";\nexport * from \"./headers\";\nexport * from \"./middlewares\";\nexport * as auth from \"./auth\";\nexport * from \"./auth\";\n","// clients/cache/redisCacheProvider.ts\nimport {createClient, type RedisClientType} from \"redis\";\nimport type {CacheProvider, CacheSetOptions, CacheValue} from \"./cacheProvider\";\n\nexport type RedisCacheProviderOptions = {\n url?: string;\n\n host?: string;\n port?: number;\n password?: string;\n db?: number;\n\n tls?: boolean;\n\n connectTimeoutMs?: number;\n\n keyPrefix?: string;\n};\n\nfunction buildRedisUrl(opts: RedisCacheProviderOptions): string | undefined {\n if (opts.url && opts.url.trim()) return opts.url.trim();\n\n if (!opts.host) return undefined;\n const port = opts.port ?? 6379;\n const db = opts.db ?? 0;\n\n const auth = opts.password ? `:${encodeURIComponent(opts.password)}@` : \"\";\n return `redis://${auth}${opts.host}:${port}/${db}`;\n}\n\nexport class RedisCacheProvider implements CacheProvider {\n readonly kind = \"redis\" as const;\n\n // ✅ tip \"amplio\" para evitar TS2322 por typings genéricos\n private client: RedisClientType<any, any, any>;\n private ready = false;\n private readonly keyPrefix?: string;\n\n constructor(private readonly opts: RedisCacheProviderOptions) {\n const url = buildRedisUrl(opts);\n if (!url) {\n throw new Error(\"[RedisCacheProvider] Missing redis config (REDIS_URL or REDIS_HOST)\");\n }\n\n this.keyPrefix = opts.keyPrefix?.trim() || undefined;\n\n this.client = createClient({\n url,\n socket: {\n connectTimeout: opts.connectTimeoutMs ?? 3000,\n tls: opts.tls ? true : undefined,\n },\n }) as RedisClientType<any, any, any>;\n\n this.client.on(\"error\", (err: unknown) => {\n const msg =\n err instanceof Error\n ? err.message\n : typeof err === \"object\" && err !== null && \"message\" in err\n ? String((err as any).message)\n : String(err);\n\n console.error(\"[redis] error\", msg, err);\n });\n }\n\n private k(key: string): string {\n if (!this.keyPrefix) return key;\n return `${this.keyPrefix}:${key}`;\n }\n\n private async ensureConnected() {\n if (this.ready) return;\n await this.client.connect();\n this.ready = true;\n }\n\n async get(key: string): Promise<CacheValue | null> {\n await this.ensureConnected();\n const v = (await this.client.get(this.k(key))) as string | null;\n return v ?? null;\n }\n\n async set(key: string, value: CacheValue, options?: CacheSetOptions): Promise<void> {\n await this.ensureConnected();\n\n const ttlMs = options?.ttlMs;\n if (ttlMs && ttlMs > 0) {\n await this.client.set(this.k(key), value, {PX: ttlMs});\n return;\n }\n\n await this.client.set(this.k(key), value);\n }\n\n async del(key: string): Promise<void> {\n await this.ensureConnected();\n await this.client.del(this.k(key));\n }\n\n async close(): Promise<void> {\n try {\n if (this.ready) await this.client.quit();\n } catch {\n try {\n await this.client.disconnect();\n } catch {\n }\n } finally {\n this.ready = false;\n }\n }\n}\n","// clients/cache/cacheProvider.ts\nimport type {RedisCacheProviderOptions} from \"./redisCacheProvider\";\nimport {RedisCacheProvider} from \"./redisCacheProvider\";\n\nexport type CacheValue = string;\n\nexport type CacheSetOptions = {\n ttlMs?: number; // TTL en milisegundos (PX)\n};\n\nexport interface CacheProvider {\n readonly kind: \"redis\" | \"noop\";\n\n get(key: string): Promise<CacheValue | null>;\n\n set(key: string, value: CacheValue, options?: CacheSetOptions): Promise<void>;\n\n del(key: string): Promise<void>;\n\n /**\n * Cierra conexiones si aplica.\n */\n close(): Promise<void>;\n}\n\nexport class NoopCacheProvider implements CacheProvider {\n readonly kind = \"noop\" as const;\n\n async get(_key: string): Promise<CacheValue | null> {\n return null;\n }\n\n async set(_key: string, _value: CacheValue, _options?: CacheSetOptions): Promise<void> {\n return;\n }\n\n async del(_key: string): Promise<void> {\n return;\n }\n\n async close(): Promise<void> {\n return;\n }\n}\n\nexport type CacheProviderFactoryOptions = {\n /**\n * Si false, devuelve Noop (útil en local si no quieres Redis).\n * Default: true si hay REDIS_URL o REDIS_HOST.\n */\n enabled?: boolean;\n\n /**\n * Prefijo global opcional para keys.\n * Ej: \"getmarket:erp\"\n */\n keyPrefix?: string;\n\n /**\n * Redis options\n */\n redis?: Partial<RedisCacheProviderOptions>;\n};\n\n/**\n * Factory simple para L2 (Redis).\n * - Si no está habilitado / no hay config => Noop\n * - Si hay config => RedisCacheProvider\n */\nexport function createCacheProvider(opts: CacheProviderFactoryOptions = {}): CacheProvider {\n const envHasRedis = Boolean(process.env.REDIS_URL || process.env.REDIS_HOST);\n\n const enabled =\n typeof opts.enabled === \"boolean\" ? opts.enabled : envHasRedis;\n\n if (!enabled) return new NoopCacheProvider();\n\n // Construye options redis desde env + overrides\n const redisOpts: RedisCacheProviderOptions = {\n url: process.env.REDIS_URL,\n host: process.env.REDIS_HOST,\n port: process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : undefined,\n password: process.env.REDIS_PASSWORD,\n db: process.env.REDIS_DB ? Number(process.env.REDIS_DB) : undefined,\n tls: (process.env.REDIS_TLS || \"\").toLowerCase() === \"true\",\n connectTimeoutMs: process.env.REDIS_CONNECT_TIMEOUT_MS\n ? Number(process.env.REDIS_CONNECT_TIMEOUT_MS)\n : 3000,\n keyPrefix: opts.keyPrefix || process.env.REDIS_KEY_PREFIX || undefined,\n ...(opts.redis || {}),\n };\n\n return new RedisCacheProvider(redisOpts);\n}\n","// clients/cache/ttlCache.ts\ntype CacheEntry<T> = { value: T; expiresAt: number };\n\nexport class TtlCache<T> {\n private store = new Map<string, CacheEntry<T>>();\n\n constructor(private defaultTtlMs: number) {\n }\n\n get(key: string): T | null {\n const e = this.store.get(key);\n if (!e) return null;\n if (Date.now() > e.expiresAt) {\n this.store.delete(key);\n return null;\n }\n return e.value;\n }\n\n set(key: string, value: T, ttlMs?: number): void {\n this.store.set(key, {value, expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs)});\n }\n\n del(key: string): void {\n this.store.delete(key);\n }\n}\n","// clients/cache/twoLevelCache.ts\nimport type {CacheProvider} from \"./cacheProvider\";\nimport {TtlCache} from \"./ttlCache\";\n\nexport type TwoLevelCacheOptions = {\n /**\n * TTL para L1 (in-memory).\n * Default: 2 min\n */\n ttlMsL1?: number;\n\n /**\n * TTL para L2 (redis).\n * Default: 10 min\n */\n ttlMsL2?: number;\n\n /**\n * Si quieres cachear \"no encontrado\" (null) por un TTL corto,\n * para evitar golpear upstream repetidamente.\n * Default: 0 (deshabilitado)\n */\n negativeTtlMsL1?: number;\n negativeTtlMsL2?: number;\n\n /**\n * Prefijo lógico extra por instancia (además del keyPrefix del provider).\n * Ej: \"res:variety\"\n */\n namespace?: string;\n};\n\ntype Loader<T> = () => Promise<T>;\n\nfunction safeJsonParse<T>(raw: string): T | null {\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nfunction safeJsonStringify(v: any): string | null {\n try {\n return JSON.stringify(v);\n } catch {\n return null;\n }\n}\n\nexport class TwoLevelCache<T> {\n private readonly l1: TtlCache<T | null>;\n private readonly inflight = new Map<string, Promise<T>>();\n\n constructor(\n private readonly l2: CacheProvider,\n private readonly opts: TwoLevelCacheOptions = {}\n ) {\n // El TTL real lo controla set(key, ttl), pero TTLCache necesita \"default ttl\"\n const defaultTtl = this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n this.l1 = new TtlCache<T | null>(defaultTtl);\n }\n\n private key(k: string): string {\n const ns = (this.opts.namespace || \"\").trim();\n return ns ? `${ns}:${k}` : k;\n }\n\n /**\n * GET \"best effort\": primero L1, luego L2.\n * (No llama loader)\n */\n async get(k: string): Promise<T | null> {\n const key = this.key(k);\n\n const v1 = this.l1.get(key);\n if (v1 !== undefined) return v1; // Ojo: TTLCache puede devolver null también\n\n const raw = await this.l2.get(key);\n if (!raw) return null;\n\n const parsed = safeJsonParse<T | null>(raw);\n if (parsed === null && raw !== \"null\") {\n // payload corrupto\n return null;\n }\n\n // Rehidrata L1 con ttl L1\n this.l1.set(key, parsed, this.opts.ttlMsL1);\n return parsed;\n }\n\n async set(k: string, value: T | null, ttlOverride?: { ttlMsL1?: number; ttlMsL2?: number }) {\n const key = this.key(k);\n\n const ttlL1 = ttlOverride?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n const ttlL2 = ttlOverride?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1000;\n\n this.l1.set(key, value, ttlL1);\n\n const raw = safeJsonStringify(value);\n if (raw == null) return;\n\n await this.l2.set(key, raw, {ttlMs: ttlL2});\n }\n\n async del(k: string) {\n const key = this.key(k);\n this.l1.del?.(key as any); // si tu TtlCache no tiene del(), ignora (ver comentario abajo)\n await this.l2.del(key);\n }\n\n /**\n * Cache-aside real con L1 + L2 + loader.\n *\n * - Dedup de concurrencia por key (inflight)\n * - Soporta negative caching (si loader retorna null)\n */\n async getOrSet(\n k: string,\n loader: Loader<T | null>,\n options?: TwoLevelCacheOptions\n ): Promise<T | null> {\n const key = this.key(k);\n\n // 1) L1\n const v1 = this.l1.get(key);\n if (v1 !== undefined) return v1;\n\n // 2) L2\n const raw = await this.l2.get(key);\n if (raw) {\n const parsed = safeJsonParse<T | null>(raw);\n if (parsed !== null || raw === \"null\") {\n this.l1.set(key, parsed, options?.ttlMsL1 ?? this.opts.ttlMsL1);\n return parsed;\n }\n }\n\n // 3) Dedup inflight (anti stampede)\n if (this.inflight.has(key)) {\n return this.inflight.get(key)! as any;\n }\n\n const promise = (async () => {\n try {\n const value = await loader();\n\n const ttlMsL1 = options?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1000;\n const ttlMsL2 = options?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1000;\n\n // negative caching\n const negL1 = options?.negativeTtlMsL1 ?? this.opts.negativeTtlMsL1 ?? 0;\n const negL2 = options?.negativeTtlMsL2 ?? this.opts.negativeTtlMsL2 ?? 0;\n\n if (value === null) {\n if (negL1 > 0) this.l1.set(key, null, negL1);\n if (negL2 > 0) await this.l2.set(key, \"null\", {ttlMs: negL2});\n return null;\n }\n\n // normal set\n this.l1.set(key, value, ttlMsL1);\n\n const rawValue = safeJsonStringify(value);\n if (rawValue != null) {\n await this.l2.set(key, rawValue, {ttlMs: ttlMsL2});\n }\n\n return value;\n } finally {\n this.inflight.delete(key);\n }\n })();\n\n this.inflight.set(key, promise as any);\n return promise;\n }\n}\n","// packages/sdk/src/cache/index.ts\nimport {createCacheProvider, type CacheProvider} from \"./cacheProvider\";\nimport {TwoLevelCache, type TwoLevelCacheOptions} from \"./twoLevelCache\";\n\nconst envInt = (v?: string, dflt: number = 0) => {\n const n = Number(v);\n return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;\n};\n\nconst DEFAULT_L1_TTL_MS = envInt(process.env.CACHE_L1_DEFAULT_TTL_MS, 30_000);\nconst DEFAULT_L2_TTL_MS = envInt(process.env.CACHE_L2_DEFAULT_TTL_MS, 300_000);\nconst DEFAULT_NEG_TTL_MS = envInt(process.env.CACHE_NEGATIVE_TTL_MS, 30_000);\n\nlet l2Provider: CacheProvider | null = null;\nconst twoLevelByNamespace = new Map<string, TwoLevelCache<any>>();\n\nfunction getL2(): CacheProvider {\n if (l2Provider) return l2Provider;\n l2Provider = createCacheProvider();\n return l2Provider;\n}\n\n/**\n * Retorna (o crea) un TwoLevelCache por namespace.\n * Namespace recomendado: auth:employee | md:country | platform:tenant-resolve ...\n */\nexport function getTwoLevelCache<T = any>(\n namespace: string,\n opts: Partial<TwoLevelCacheOptions> = {}\n): TwoLevelCache<T> {\n const existing = twoLevelByNamespace.get(namespace);\n if (existing) return existing as TwoLevelCache<T>;\n\n const l2 = getL2();\n\n const cacheOptions: TwoLevelCacheOptions = {\n // ✅ TwoLevelCache prefija keys con namespace internamente\n namespace,\n\n ttlMsL1: opts.ttlMsL1 ?? DEFAULT_L1_TTL_MS,\n ttlMsL2: opts.ttlMsL2 ?? DEFAULT_L2_TTL_MS,\n\n // ✅ negative caching\n negativeTtlMsL1: opts.negativeTtlMsL1 ?? DEFAULT_NEG_TTL_MS,\n negativeTtlMsL2: opts.negativeTtlMsL2 ?? DEFAULT_NEG_TTL_MS,\n };\n\n const cache = new TwoLevelCache<T>(l2, cacheOptions);\n twoLevelByNamespace.set(namespace, cache as TwoLevelCache<any>);\n return cache;\n}\n\n/**\n * Helper: cache.getOrSet\n *\n * IMPORTANT:\n * - No prefijar manualmente la key.\n * - TwoLevelCache ya usa opts.namespace.\n */\nexport async function getOrSet<T>(\n namespace: string,\n key: string,\n loader: () => Promise<T | null>,\n opts: Partial<TwoLevelCacheOptions> = {}\n): Promise<T | null> {\n const cache = getTwoLevelCache<T>(namespace, opts);\n return cache.getOrSet(key, loader, opts);\n}\n\nexport async function closeCache(): Promise<void> {\n try {\n if (l2Provider && typeof (l2Provider as any).close === \"function\") {\n await (l2Provider as any).close();\n }\n } finally {\n l2Provider = null;\n twoLevelByNamespace.clear();\n }\n}\n\n/**\n * ✅ Re-exports públicos para consumo desde:\n * import type {TwoLevelCacheOptions} from \"@innvoid/getmarket-sdk/cache\";\n */\nexport type {TwoLevelCacheOptions, CacheProvider};\nexport {TwoLevelCache};\n","export type ClientErrorCode =\n | \"UPSTREAM_TIMEOUT\"\n | \"UPSTREAM_UNAVAILABLE\"\n | \"UPSTREAM_BAD_RESPONSE\"\n | \"UPSTREAM_NOT_FOUND\"\n | \"UPSTREAM_UNAUTHORIZED\"\n | \"UPSTREAM_FORBIDDEN\"\n | \"UPSTREAM_UNKNOWN\";\n\nexport class UpstreamError extends Error {\n public code: ClientErrorCode;\n public status?: number;\n public details?: any;\n\n constructor(message: string, code: ClientErrorCode, status?: number, details?: any) {\n super(message);\n this.name = \"UpstreamError\";\n this.code = code;\n this.status = status;\n this.details = details;\n }\n}\n\nexport function mapAxiosToUpstreamError(err: any, svc: string): UpstreamError {\n const status = err?.response?.status;\n const data = err?.response?.data;\n const isTimeout = err?.code === \"ECONNABORTED\" || String(err?.message || \"\").includes(\"timeout\");\n\n if (isTimeout) {\n return new UpstreamError(`[${svc}] timeout`, \"UPSTREAM_TIMEOUT\", 504, {cause: err?.message});\n }\n if (!err?.response) {\n return new UpstreamError(`[${svc}] unavailable`, \"UPSTREAM_UNAVAILABLE\", 503, {cause: err?.message});\n }\n if (status === 404) return new UpstreamError(`[${svc}] not found`, \"UPSTREAM_NOT_FOUND\", 404, data);\n if (status === 401) return new UpstreamError(`[${svc}] unauthorized`, \"UPSTREAM_UNAUTHORIZED\", 401, data);\n if (status === 403) return new UpstreamError(`[${svc}] forbidden`, \"UPSTREAM_FORBIDDEN\", 403, data);\n if (status >= 400 && status < 600) {\n return new UpstreamError(`[${svc}] bad response`, \"UPSTREAM_BAD_RESPONSE\", status, data);\n }\n return new UpstreamError(`[${svc}] unknown error`, \"UPSTREAM_UNKNOWN\", status, data);\n}\n","// clients/core/http.ts\nimport axios, {AxiosInstance, AxiosRequestConfig} from \"axios\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\n\nexport type HttpClientOpts = {\n baseURL: string;\n timeoutMs?: number;\n};\n\n/**\n * Headers compatibles con múltiples versiones de axios.\n * En axios antiguo, `headers` suele ser `any`, así que mantenemos tolerancia.\n */\nexport type AnyHeaders = NonNullable<AxiosRequestConfig[\"headers\"]> | Record<string, string>;\n\n/**\n * Agrega x-request-id a headers (sin pisar otros headers).\n */\nexport function withRequestId(headers: AnyHeaders | undefined, requestId?: string | null): AnyHeaders {\n const h: Record<string, any> =\n headers && typeof headers === \"object\"\n ? {...(headers as any)}\n : {};\n\n const rid = (requestId || \"\").trim();\n if (rid) h[REQUEST_ID_HEADER] = rid;\n\n return h as AnyHeaders;\n}\n\n/**\n * Helper para construir config de axios con requestId\n * (SIN genéricos para compat con axios typings antiguos).\n */\nexport function withRequestIdConfig(\n config: AxiosRequestConfig = {},\n requestId?: string | null\n): AxiosRequestConfig {\n return {\n ...config,\n headers: withRequestId((config as any).headers, requestId) as any,\n };\n}\n\nexport function createHttpClient(opts: HttpClientOpts): AxiosInstance {\n return axios.create({\n baseURL: opts.baseURL,\n timeout: opts.timeoutMs ?? 4000,\n headers: {\"Content-Type\": \"application/json\"},\n });\n}\n","// clients/internalHttp.ts\n\ntype RetryPolicy = {\n retries: number;\n baseDelayMs: number;\n retryOnStatuses: number[];\n retryOnNetworkErrors: boolean;\n};\n\ntype InternalHttpOptions = {\n baseUrl: string;\n apiKey?: string; // x-internal-api-key\n timeoutMs?: number;\n retry?: Partial<RetryPolicy>;\n};\n\nconst DEFAULT_RETRY: RetryPolicy = {\n retries: 1,\n baseDelayMs: 150,\n retryOnStatuses: [429, 502, 503, 504],\n retryOnNetworkErrors: true,\n};\n\nfunction sleep(ms: number) {\n return new Promise((r) => setTimeout(r, ms));\n}\n\nfunction safeJsonStringify(v: any) {\n try {\n return JSON.stringify(v);\n } catch {\n return String(v);\n }\n}\n\nfunction toHeaders(init?: HeadersInit): Headers {\n return new Headers(init || {});\n}\n\nfunction isJsonContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n const ct = contentType.toLowerCase();\n return ct.includes(\"application/json\") || ct.includes(\"+json\");\n}\n\nfunction isAbortError(e: any): boolean {\n return e?.name === \"AbortError\";\n}\n\nfunction withJitter(ms: number): number {\n // jitter +-20%\n const jitter = ms * 0.2;\n const delta = (Math.random() * 2 - 1) * jitter;\n return Math.max(0, Math.floor(ms + delta));\n}\n\nexport class InternalHttp {\n private readonly baseUrl: string;\n private readonly apiKey: string | undefined;\n private readonly timeoutMs: number;\n private retry: RetryPolicy;\n\n constructor(opts: InternalHttpOptions) {\n this.baseUrl = opts.baseUrl.replace(/\\/+$/, \"\");\n this.apiKey = opts.apiKey;\n\n // ✅ Default más seguro para internas (evita cascadas)\n this.timeoutMs = opts.timeoutMs ?? 4000;\n\n this.retry = {...DEFAULT_RETRY, ...(opts.retry || {})};\n }\n\n async request<T>(\n path: string,\n init: RequestInit & {\n requestId?: string;\n idempotencyKey?: string;\n headers?: HeadersInit;\n } = {}\n ): Promise<T> {\n const url = `${this.baseUrl}${path.startsWith(\"/\") ? \"\" : \"/\"}${path}`;\n\n const baseHeaders = toHeaders(init.headers);\n\n if (!baseHeaders.has(\"Content-Type\")) baseHeaders.set(\"Content-Type\", \"application/json\");\n if (this.apiKey) baseHeaders.set(\"x-internal-api-key\", this.apiKey);\n\n if (init.requestId) baseHeaders.set(\"x-request-id\", init.requestId);\n if (init.idempotencyKey) baseHeaders.set(\"Idempotency-Key\", init.idempotencyKey);\n\n const {headers: _ignored, ...restInit} = init;\n\n const doFetchOnce = async () => {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const res = await fetch(url, {\n ...restInit,\n headers: baseHeaders,\n signal: controller.signal,\n });\n\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n const err: any = new Error(\n `HTTP ${res.status} ${res.statusText}${text ? ` - ${text}` : \"\"}`\n );\n err.status = res.status;\n err.body = text;\n throw err;\n }\n\n if (res.status === 204) return undefined as unknown as T;\n\n const contentType = res.headers.get(\"content-type\");\n if (isJsonContentType(contentType)) {\n return (await res.json()) as T;\n }\n\n const text = await res.text().catch(() => \"\");\n return text as unknown as T;\n } finally {\n clearTimeout(timeout);\n }\n };\n\n let attempt = 0;\n\n while (true) {\n try {\n return await doFetchOnce();\n } catch (e: any) {\n attempt++;\n\n const status = e?.status;\n const retryableStatus = !!status && this.retry.retryOnStatuses.includes(status);\n\n const retryableNetwork =\n this.retry.retryOnNetworkErrors &&\n (isAbortError(e) || !status); // sin status suele ser red/dns/timeout\n\n const isRetryable = retryableStatus || retryableNetwork;\n\n if (!isRetryable || attempt > this.retry.retries) {\n console.error(\n `[InternalHttp] request failed: ${url} attempt=${attempt} status=${status ?? \"n/a\"} err=${e?.message\n } body=${safeJsonStringify(e?.body)}`\n );\n throw e;\n }\n\n const backoff = withJitter(this.retry.baseDelayMs * attempt);\n await sleep(backoff);\n }\n }\n }\n}\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction asString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n return s ? s : null;\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional)\n * - x-request-id: string (opcional)\n *\n * 🚫 No JSON, no _id, no objetos.\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,\n company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,\n branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,\n employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null,\n };\n}\n","// middlewares/requestId.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {randomUUID, randomBytes} from \"crypto\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\nexport const REQUEST_ID_HEADER_ALT = \"x-requestid\";\nexport const RESPONSE_REQUEST_ID_HEADER = \"X-Request-Id\";\n\n// Si quieres IDs más cortos (opcional). Por defecto usamos UUID.\nfunction nanoidLike(len = 21) {\n return randomBytes(16).toString(\"base64url\").slice(0, len);\n}\n\nexport default function requestId(req: Request, res: Response, next: NextFunction) {\n const headerId = (req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT]) as\n | string\n | undefined;\n\n // ✅ estándar único: usa UUID (o cambia a nanoidLike() si prefieres corto)\n const id = headerId?.trim() || randomUUID();\n\n // ✅ estándar único (no legacy)\n (req as any).requestId = id;\n res.locals.requestId = id;\n\n // ✅ respuesta\n res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY:\n * - solo setea UIDs\n * - no crea objetos company/branch\n * - no copia provider\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n const context = getRequestContextFromHeaders(req.headers as any);\n\n (req as any).context = context;\n\n const auth: any = (req as any).auth ?? ((req as any).auth = {});\n if (context.company_uid) auth.company_uid = context.company_uid;\n if (context.branch_uid) auth.branch_uid = context.branch_uid;\n if (context.employee_uid) auth.employee_uid = context.employee_uid;\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n","// packages/sdk/src/middlewares/authorization.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {sendError} from \"./respond\";\n\ntype AuthShape = {\n roles?: string[];\n permissions?: string[];\n denied_permissions?: string[];\n};\n\nfunction getAuth(req: Request): AuthShape {\n return ((req as any).auth ?? {}) as AuthShape;\n}\n\n/**\n * 401 si no existe req.auth (contexto auth).\n * Útil para proteger rutas internas donde SIEMPRE debe existir auth.\n */\nexport function requireAuthContext() {\n return (req: Request, res: Response, next: NextFunction) => {\n if (!(req as any).auth) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", \"Missing auth context\");\n }\n return next();\n };\n}\n\n/**\n * Requiere TODOS los permisos indicados.\n * Regla: denied_permissions siempre gana sobre permissions.\n */\nexport function requirePermissions(...perms: string[]) {\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n const allow = new Set<string>(auth.permissions ?? []);\n const deny = new Set<string>(auth.denied_permissions ?? []);\n\n // deny gana siempre\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied: ${p}`);\n }\n }\n\n const missing = perms.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions\", {missing});\n }\n\n return next();\n };\n}\n\n/**\n * Requiere al menos 1 de los roles indicados.\n */\nexport function requireRoles(...roles: string[]) {\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n const have = new Set<string>(auth.roles ?? []);\n\n if (!roles.some((r) => have.has(r))) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {required: roles});\n }\n\n return next();\n };\n}\n","export * from \"./types\";\nexport * from \"./jwt\";\nexport * from \"./middleware\";\n","import fs from \"fs\";\nimport jwt, {JwtPayload} from \"jsonwebtoken\";\n\nfunction readFileIfExists(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\n/**\n * ✅ Keys viven en getmarket-stack:\n * - JWT_PUBLIC_KEY_PATH=/run/secrets/jwtRS256.key.pub (recomendado)\n * - fallback env AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY\n */\nexport function readRs256PublicKey(): string {\n const fromFile = readFileIfExists(process.env.JWT_PUBLIC_KEY_PATH);\n if (fromFile) return fromFile;\n\n const fromEnv = String(process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || \"\")\n .replace(/\\\\n/g, \"\\n\")\n .trim();\n\n if (fromEnv) return fromEnv;\n\n throw new Error(\"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)\");\n}\n\nexport function verifyBackendJwtRS256(raw: string): JwtPayload {\n const publicKey = readRs256PublicKey();\n\n const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || \"getmarket.api\";\n const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || \"getmarket-auth\";\n\n // ✅ SOLO RS256\n return jwt.verify(raw, publicKey, {\n algorithms: [\"RS256\"],\n audience,\n issuer,\n }) as JwtPayload;\n}\n","import type {NextFunction, Response} from \"express\";\nimport {verifyBackendJwtRS256} from \"./jwt\";\nimport type {AuthContext, AuthMiddlewareOptions} from \"./types\";\n\nfunction getBearerToken(req: any): string | null {\n const auth = String(req.headers?.authorization || \"\");\n if (!auth.startsWith(\"Bearer \")) return null;\n const token = auth.slice(7).trim();\n return token.length ? token : null;\n}\n\nfunction normalizeUid(v: any): string | null {\n const s = String(v ?? \"\").trim();\n return s.length ? s : null;\n}\n\n/**\n * ✅ Middleware estándar:\n * - Solo Authorization: Bearer\n * - Solo RS256\n * - Cero legacy\n * - Hidrata vía hook (OBLIGATORIO) para que cada micro no replique lógica\n */\nexport function createAuthMiddleware(opts: AuthMiddlewareOptions) {\n const {\n subject,\n allowFirebaseIdToken = false,\n requireSubject = true,\n hydrate,\n } = opts;\n\n return async (req: any, res: Response, next: NextFunction) => {\n const token = getBearerToken(req);\n if (!token) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_MISSING_TOKEN\",\n message: \"Missing Authorization Bearer token\",\n });\n }\n\n // Contexto desde parseHeaders (SDK) -> req.context\n const headerCtx = (req as any).context || {};\n const company_uid = normalizeUid(headerCtx.company_uid);\n const branch_uid = normalizeUid(headerCtx.branch_uid);\n\n // 1) RS256 backend JWT\n try {\n const decoded: any = verifyBackendJwtRS256(token);\n\n const baseCtx: AuthContext = {\n tokenType: \"backend\",\n subject,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n roles: Array.isArray(decoded?.roles) ? decoded.roles : [],\n permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],\n denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],\n session: {\n jti: decoded?.jti,\n device_id: decoded?.device_id,\n expires_at: decoded?.exp,\n },\n };\n\n // ✅ hydrate obligatorio (cero legacy)\n const hydrated = await hydrate({decoded, req, subject, company_uid, branch_uid});\n Object.assign(baseCtx, hydrated);\n\n if (requireSubject) {\n if (subject === \"employee\" && !baseCtx.employee) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not resolved by hydrator\",\n });\n }\n if (subject === \"customer\" && !baseCtx.customer) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not resolved by hydrator\",\n });\n }\n }\n\n req.auth = baseCtx;\n return next();\n } catch (errJwt) {\n // 2) Firebase opcional (si está habilitado explícitamente)\n if (!allowFirebaseIdToken) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n\n try {\n // Import dinámico (pero firebase-admin está en deps del SDK)\n const {default: admin} = await import(\"firebase-admin\");\n const firebaseDecoded = await admin.auth().verifyIdToken(token);\n\n if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMAIL_NOT_VERIFIED\",\n message: \"Email not verified\",\n });\n }\n\n req.auth = {\n tokenType: \"backend\",\n subject,\n firebase: firebaseDecoded,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n companies: [],\n roles: [],\n permissions: [],\n denied_permissions: [],\n };\n\n return next();\n } catch {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n }\n };\n}\n"],"mappings":"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","names":["requestId","axios","safeJsonStringify","text","REQUEST_ID_HEADER","REQUEST_ID_HEADER","import_crypto","fs","crypto","import_fs","fs","jwt"]}
package/dist/index.d.cts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { CacheProvider, TwoLevelCache, TwoLevelCacheOptions, closeCache, getOrSet, getTwoLevelCache } from './cache/index.cjs';
2
2
  export { AnyHeaders, ClientErrorCode, HttpClientOpts, InternalHttp, REQUEST_ID_HEADER, UpstreamError, createHttpClient, mapAxiosToUpstreamError, withRequestId, withRequestIdConfig } from './core/index.cjs';
3
3
  export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, RequestContext, getRequestContextFromHeaders } from './headers/index.cjs';
4
- export { internalAuth, parseHeaders, requestId, sendError, sendOk } from './middlewares/index.cjs';
4
+ export { internalAuth, parseHeaders, requestId, requireAuthContext, requirePermissions, requireRoles, sendError, sendOk } from './middlewares/index.cjs';
5
+ export { A as AuthContext, a as AuthMiddlewareOptions, b as AuthSession, c as AuthSubject, H as HydrateInput, d as HydrateResult, e as Hydrator, T as TokenType, i as auth, f as createAuthMiddleware, r as readRs256PublicKey, v as verifyBackendJwtRS256 } from './index-WbfzvmOt.cjs';
5
6
  import 'axios';
6
7
  import 'express';
8
+ import 'jsonwebtoken';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  export { CacheProvider, TwoLevelCache, TwoLevelCacheOptions, closeCache, getOrSet, getTwoLevelCache } from './cache/index.js';
2
2
  export { AnyHeaders, ClientErrorCode, HttpClientOpts, InternalHttp, REQUEST_ID_HEADER, UpstreamError, createHttpClient, mapAxiosToUpstreamError, withRequestId, withRequestIdConfig } from './core/index.js';
3
3
  export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, RequestContext, getRequestContextFromHeaders } from './headers/index.js';
4
- export { internalAuth, parseHeaders, requestId, sendError, sendOk } from './middlewares/index.js';
4
+ export { internalAuth, parseHeaders, requestId, requireAuthContext, requirePermissions, requireRoles, sendError, sendOk } from './middlewares/index.js';
5
+ export { A as AuthContext, a as AuthMiddlewareOptions, b as AuthSession, c as AuthSubject, H as HydrateInput, d as HydrateResult, e as Hydrator, T as TokenType, i as auth, f as createAuthMiddleware, r as readRs256PublicKey, v as verifyBackendJwtRS256 } from './index-WbfzvmOt.js';
5
6
  import 'axios';
6
7
  import 'express';
8
+ import 'jsonwebtoken';
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ auth_exports,
3
+ createAuthMiddleware,
4
+ readRs256PublicKey,
5
+ verifyBackendJwtRS256
6
+ } from "./chunk-W23UYULS.js";
1
7
  import {
2
8
  TwoLevelCache,
3
9
  closeCache,
@@ -17,9 +23,12 @@ import {
17
23
  internalAuth,
18
24
  parseHeaders,
19
25
  requestId,
26
+ requireAuthContext,
27
+ requirePermissions,
28
+ requireRoles,
20
29
  sendError,
21
30
  sendOk
22
- } from "./chunk-HTHX24NK.js";
31
+ } from "./chunk-Y2JJLHAY.js";
23
32
  import {
24
33
  HEADER_AUTHORIZATION,
25
34
  HEADER_BRANCH_UID,
@@ -29,6 +38,7 @@ import {
29
38
  HEADER_REQUEST_ID,
30
39
  getRequestContextFromHeaders
31
40
  } from "./chunk-65HACONF.js";
41
+ import "./chunk-PZ5AY32C.js";
32
42
  export {
33
43
  HEADER_AUTHORIZATION,
34
44
  HEADER_BRANCH_UID,
@@ -40,7 +50,9 @@ export {
40
50
  REQUEST_ID_HEADER,
41
51
  TwoLevelCache,
42
52
  UpstreamError,
53
+ auth_exports as auth,
43
54
  closeCache,
55
+ createAuthMiddleware,
44
56
  createHttpClient,
45
57
  getOrSet,
46
58
  getRequestContextFromHeaders,
@@ -48,9 +60,14 @@ export {
48
60
  internalAuth,
49
61
  mapAxiosToUpstreamError,
50
62
  parseHeaders,
63
+ readRs256PublicKey,
51
64
  requestId,
65
+ requireAuthContext,
66
+ requirePermissions,
67
+ requireRoles,
52
68
  sendError,
53
69
  sendOk,
70
+ verifyBackendJwtRS256,
54
71
  withRequestId,
55
72
  withRequestIdConfig
56
73
  };
@@ -33,6 +33,9 @@ __export(middlewares_exports, {
33
33
  internalAuth: () => internalAuth,
34
34
  parseHeaders: () => parseHeaders,
35
35
  requestId: () => requestId,
36
+ requireAuthContext: () => requireAuthContext,
37
+ requirePermissions: () => requirePermissions,
38
+ requireRoles: () => requireRoles,
36
39
  sendError: () => sendError,
37
40
  sendOk: () => sendOk
38
41
  });
@@ -152,11 +155,54 @@ function internalAuth(req, res, next) {
152
155
  }
153
156
  return next();
154
157
  }
158
+
159
+ // src/middlewares/autorization.ts
160
+ function getAuth(req) {
161
+ return req.auth ?? {};
162
+ }
163
+ function requireAuthContext() {
164
+ return (req, res, next) => {
165
+ if (!req.auth) {
166
+ return sendError(req, res, 401, "UNAUTHORIZED", "Missing auth context");
167
+ }
168
+ return next();
169
+ };
170
+ }
171
+ function requirePermissions(...perms) {
172
+ return (req, res, next) => {
173
+ const auth = getAuth(req);
174
+ const allow = new Set(auth.permissions ?? []);
175
+ const deny = new Set(auth.denied_permissions ?? []);
176
+ for (const p of perms) {
177
+ if (deny.has(p)) {
178
+ return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`);
179
+ }
180
+ }
181
+ const missing = perms.filter((p) => !allow.has(p));
182
+ if (missing.length) {
183
+ return sendError(req, res, 403, "FORBIDDEN", "Missing permissions", { missing });
184
+ }
185
+ return next();
186
+ };
187
+ }
188
+ function requireRoles(...roles) {
189
+ return (req, res, next) => {
190
+ const auth = getAuth(req);
191
+ const have = new Set(auth.roles ?? []);
192
+ if (!roles.some((r) => have.has(r))) {
193
+ return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required: roles });
194
+ }
195
+ return next();
196
+ };
197
+ }
155
198
  // Annotate the CommonJS export names for ESM import in node:
156
199
  0 && (module.exports = {
157
200
  internalAuth,
158
201
  parseHeaders,
159
202
  requestId,
203
+ requireAuthContext,
204
+ requirePermissions,
205
+ requireRoles,
160
206
  sendError,
161
207
  sendOk
162
208
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/middlewares/index.ts","../../src/middlewares/requestId.ts","../../src/headers/constants.ts","../../src/headers/parse.ts","../../src/middlewares/parseHeaders.ts","../../src/middlewares/internalAuth.ts","../../src/middlewares/respond.ts"],"sourcesContent":["export {default as requestId} from \"./requestId\";\nexport {default as parseHeaders} from \"./parseHeaders\";\nexport {default as internalAuth} from \"./internalAuth\";\nexport * from \"./respond\";\n","// middlewares/requestId.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {randomUUID, randomBytes} from \"crypto\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\nexport const REQUEST_ID_HEADER_ALT = \"x-requestid\";\nexport const RESPONSE_REQUEST_ID_HEADER = \"X-Request-Id\";\n\n// Si quieres IDs más cortos (opcional). Por defecto usamos UUID.\nfunction nanoidLike(len = 21) {\n return randomBytes(16).toString(\"base64url\").slice(0, len);\n}\n\nexport default function requestId(req: Request, res: Response, next: NextFunction) {\n const headerId = (req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT]) as\n | string\n | undefined;\n\n // ✅ estándar único: usa UUID (o cambia a nanoidLike() si prefieres corto)\n const id = headerId?.trim() || randomUUID();\n\n // ✅ estándar único (no legacy)\n (req as any).requestId = id;\n res.locals.requestId = id;\n\n // ✅ respuesta\n res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);\n\n next();\n}\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction asString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n return s ? s : null;\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional)\n * - x-request-id: string (opcional)\n *\n * 🚫 No JSON, no _id, no objetos.\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,\n company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,\n branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,\n employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null,\n };\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY:\n * - solo setea UIDs\n * - no crea objetos company/branch\n * - no copia provider\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n const context = getRequestContextFromHeaders(req.headers as any);\n\n (req as any).context = context;\n\n const auth: any = (req as any).auth ?? ((req as any).auth = {});\n if (context.company_uid) auth.company_uid = context.company_uid;\n if (context.branch_uid) auth.branch_uid = context.branch_uid;\n if (context.employee_uid) auth.employee_uid = context.employee_uid;\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n"],"mappings":"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","names":["import_crypto","fs","crypto"]}
1
+ {"version":3,"sources":["../../src/middlewares/index.ts","../../src/middlewares/requestId.ts","../../src/headers/constants.ts","../../src/headers/parse.ts","../../src/middlewares/parseHeaders.ts","../../src/middlewares/internalAuth.ts","../../src/middlewares/respond.ts","../../src/middlewares/autorization.ts"],"sourcesContent":["export {default as requestId} from \"./requestId\";\nexport {default as parseHeaders} from \"./parseHeaders\";\nexport {default as internalAuth} from \"./internalAuth\";\nexport * from \"./autorization\";\nexport * from \"./respond\";\n","// middlewares/requestId.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {randomUUID, randomBytes} from \"crypto\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\nexport const REQUEST_ID_HEADER_ALT = \"x-requestid\";\nexport const RESPONSE_REQUEST_ID_HEADER = \"X-Request-Id\";\n\n// Si quieres IDs más cortos (opcional). Por defecto usamos UUID.\nfunction nanoidLike(len = 21) {\n return randomBytes(16).toString(\"base64url\").slice(0, len);\n}\n\nexport default function requestId(req: Request, res: Response, next: NextFunction) {\n const headerId = (req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT]) as\n | string\n | undefined;\n\n // ✅ estándar único: usa UUID (o cambia a nanoidLike() si prefieres corto)\n const id = headerId?.trim() || randomUUID();\n\n // ✅ estándar único (no legacy)\n (req as any).requestId = id;\n res.locals.requestId = id;\n\n // ✅ respuesta\n res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);\n\n next();\n}\n","export const HEADER_REQUEST_ID = \"x-request-id\";\n\nexport const HEADER_COMPANY_UID = \"x-company\";\nexport const HEADER_BRANCH_UID = \"x-branch\";\nexport const HEADER_EMPLOYEE_UID = \"x-employee-uid\";\n\nexport const HEADER_INTERNAL_API_KEY = \"x-internal-api-key\";\nexport const HEADER_AUTHORIZATION = \"authorization\";\n","import {\n HEADER_BRANCH_UID,\n HEADER_COMPANY_UID,\n HEADER_EMPLOYEE_UID,\n HEADER_REQUEST_ID,\n} from \"./constants\";\n\nexport type RequestContext = {\n requestId?: string | null;\n\n company_uid?: string | null;\n branch_uid?: string | null;\n employee_uid?: string | null;\n};\n\nfunction asString(v: unknown): string | null {\n if (typeof v !== \"string\") return null;\n const s = v.trim();\n return s ? s : null;\n}\n\n/**\n * ✅ NO-LEGACY:\n * - x-company: <UID>\n * - x-branch: <UID>\n * - x-employee-uid: <UID> (opcional)\n * - x-request-id: string (opcional)\n *\n * 🚫 No JSON, no _id, no objetos.\n */\nexport function getRequestContextFromHeaders(headers: Record<string, any>): RequestContext {\n return {\n requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,\n company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,\n branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,\n employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null,\n };\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY:\n * - solo setea UIDs\n * - no crea objetos company/branch\n * - no copia provider\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n const context = getRequestContextFromHeaders(req.headers as any);\n\n (req as any).context = context;\n\n const auth: any = (req as any).auth ?? ((req as any).auth = {});\n if (context.company_uid) auth.company_uid = context.company_uid;\n if (context.branch_uid) auth.branch_uid = context.branch_uid;\n if (context.employee_uid) auth.employee_uid = context.employee_uid;\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n","// packages/sdk/src/middlewares/authorization.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {sendError} from \"./respond\";\n\ntype AuthShape = {\n roles?: string[];\n permissions?: string[];\n denied_permissions?: string[];\n};\n\nfunction getAuth(req: Request): AuthShape {\n return ((req as any).auth ?? {}) as AuthShape;\n}\n\n/**\n * 401 si no existe req.auth (contexto auth).\n * Útil para proteger rutas internas donde SIEMPRE debe existir auth.\n */\nexport function requireAuthContext() {\n return (req: Request, res: Response, next: NextFunction) => {\n if (!(req as any).auth) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", \"Missing auth context\");\n }\n return next();\n };\n}\n\n/**\n * Requiere TODOS los permisos indicados.\n * Regla: denied_permissions siempre gana sobre permissions.\n */\nexport function requirePermissions(...perms: string[]) {\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n const allow = new Set<string>(auth.permissions ?? []);\n const deny = new Set<string>(auth.denied_permissions ?? []);\n\n // deny gana siempre\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied: ${p}`);\n }\n }\n\n const missing = perms.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions\", {missing});\n }\n\n return next();\n };\n}\n\n/**\n * Requiere al menos 1 de los roles indicados.\n */\nexport function requireRoles(...roles: string[]) {\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n const have = new Set<string>(auth.roles ?? []);\n\n if (!roles.some((r) => have.has(r))) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {required: roles});\n }\n\n return next();\n };\n}\n"],"mappings":"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","names":["import_crypto","fs","crypto"]}
@@ -12,7 +12,22 @@ declare function parseHeaders(req: Request, _res: Response, next: NextFunction):
12
12
 
13
13
  declare function internalAuth(req: Request, res: Response, next: NextFunction): void | Response<any, Record<string, any>>;
14
14
 
15
+ /**
16
+ * 401 si no existe req.auth (contexto auth).
17
+ * Útil para proteger rutas internas donde SIEMPRE debe existir auth.
18
+ */
19
+ declare function requireAuthContext(): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
20
+ /**
21
+ * Requiere TODOS los permisos indicados.
22
+ * Regla: denied_permissions siempre gana sobre permissions.
23
+ */
24
+ declare function requirePermissions(...perms: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
25
+ /**
26
+ * Requiere al menos 1 de los roles indicados.
27
+ */
28
+ declare function requireRoles(...roles: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
29
+
15
30
  declare function sendOk<T>(_req: Request, res: Response, data: T, statusCode?: number): Response<any, Record<string, any>>;
16
31
  declare function sendError(_req: Request, res: Response, statusCode: number, code: string, message: string, details?: any): Response<any, Record<string, any>>;
17
32
 
18
- export { internalAuth, parseHeaders, requestId, sendError, sendOk };
33
+ export { internalAuth, parseHeaders, requestId, requireAuthContext, requirePermissions, requireRoles, sendError, sendOk };
@@ -12,7 +12,22 @@ declare function parseHeaders(req: Request, _res: Response, next: NextFunction):
12
12
 
13
13
  declare function internalAuth(req: Request, res: Response, next: NextFunction): void | Response<any, Record<string, any>>;
14
14
 
15
+ /**
16
+ * 401 si no existe req.auth (contexto auth).
17
+ * Útil para proteger rutas internas donde SIEMPRE debe existir auth.
18
+ */
19
+ declare function requireAuthContext(): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
20
+ /**
21
+ * Requiere TODOS los permisos indicados.
22
+ * Regla: denied_permissions siempre gana sobre permissions.
23
+ */
24
+ declare function requirePermissions(...perms: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
25
+ /**
26
+ * Requiere al menos 1 de los roles indicados.
27
+ */
28
+ declare function requireRoles(...roles: string[]): (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
29
+
15
30
  declare function sendOk<T>(_req: Request, res: Response, data: T, statusCode?: number): Response<any, Record<string, any>>;
16
31
  declare function sendError(_req: Request, res: Response, statusCode: number, code: string, message: string, details?: any): Response<any, Record<string, any>>;
17
32
 
18
- export { internalAuth, parseHeaders, requestId, sendError, sendOk };
33
+ export { internalAuth, parseHeaders, requestId, requireAuthContext, requirePermissions, requireRoles, sendError, sendOk };
@@ -2,14 +2,21 @@ import {
2
2
  internalAuth,
3
3
  parseHeaders,
4
4
  requestId,
5
+ requireAuthContext,
6
+ requirePermissions,
7
+ requireRoles,
5
8
  sendError,
6
9
  sendOk
7
- } from "../chunk-HTHX24NK.js";
10
+ } from "../chunk-Y2JJLHAY.js";
8
11
  import "../chunk-65HACONF.js";
12
+ import "../chunk-PZ5AY32C.js";
9
13
  export {
10
14
  internalAuth,
11
15
  parseHeaders,
12
16
  requestId,
17
+ requireAuthContext,
18
+ requirePermissions,
19
+ requireRoles,
13
20
  sendError,
14
21
  sendOk
15
22
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innvoid/getmarket-sdk",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -12,6 +12,11 @@
12
12
  "import": "./dist/index.js",
13
13
  "require": "./dist/index.cjs"
14
14
  },
15
+ "./auth": {
16
+ "types": "./dist/auth/index.d.ts",
17
+ "import": "./dist/auth/index.js",
18
+ "require": "./dist/auth/index.cjs"
19
+ },
15
20
  "./cache": {
16
21
  "types": "./dist/cache/index.d.ts",
17
22
  "import": "./dist/cache/index.js",
@@ -35,6 +40,9 @@
35
40
  },
36
41
  "typesVersions": {
37
42
  "*": {
43
+ "auth": [
44
+ "dist/auth/index.d.ts"
45
+ ],
38
46
  "cache": [
39
47
  "dist/cache/index.d.ts"
40
48
  ],
@@ -61,6 +69,8 @@
61
69
  "dependencies": {
62
70
  "@innvoid/getmarket-contracts": "^0.1.1",
63
71
  "axios": "^1.13.5",
72
+ "firebase-admin": "^13.6.1",
73
+ "jsonwebtoken": "^9.0.2",
64
74
  "redis": "^5.11.0"
65
75
  },
66
76
  "peerDependencies": {
@@ -68,6 +78,7 @@
68
78
  },
69
79
  "devDependencies": {
70
80
  "@types/express": "^5.0.6",
81
+ "@types/jsonwebtoken": "^9.0.6",
71
82
  "@types/node": "^22.0.0",
72
83
  "tsup": "^8.0.0",
73
84
  "typescript": "^5.5.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/middlewares/requestId.ts","../src/middlewares/parseHeaders.ts","../src/middlewares/internalAuth.ts","../src/middlewares/respond.ts"],"sourcesContent":["// middlewares/requestId.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {randomUUID, randomBytes} from \"crypto\";\n\nexport const REQUEST_ID_HEADER = \"x-request-id\";\nexport const REQUEST_ID_HEADER_ALT = \"x-requestid\";\nexport const RESPONSE_REQUEST_ID_HEADER = \"X-Request-Id\";\n\n// Si quieres IDs más cortos (opcional). Por defecto usamos UUID.\nfunction nanoidLike(len = 21) {\n return randomBytes(16).toString(\"base64url\").slice(0, len);\n}\n\nexport default function requestId(req: Request, res: Response, next: NextFunction) {\n const headerId = (req.headers[REQUEST_ID_HEADER] || req.headers[REQUEST_ID_HEADER_ALT]) as\n | string\n | undefined;\n\n // ✅ estándar único: usa UUID (o cambia a nanoidLike() si prefieres corto)\n const id = headerId?.trim() || randomUUID();\n\n // ✅ estándar único (no legacy)\n (req as any).requestId = id;\n res.locals.requestId = id;\n\n // ✅ respuesta\n res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY:\n * - solo setea UIDs\n * - no crea objetos company/branch\n * - no copia provider\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n const context = getRequestContextFromHeaders(req.headers as any);\n\n (req as any).context = context;\n\n const auth: any = (req as any).auth ?? ((req as any).auth = {});\n if (context.company_uid) auth.company_uid = context.company_uid;\n if (context.branch_uid) auth.branch_uid = context.branch_uid;\n if (context.employee_uid) auth.employee_uid = context.employee_uid;\n\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n"],"mappings":"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","names":[]}