@innvoid/getmarket-sdk 0.1.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.
Files changed (40) hide show
  1. package/README.md +93 -0
  2. package/dist/cache/index.cjs +321 -0
  3. package/dist/cache/index.cjs.map +1 -0
  4. package/dist/cache/index.d.cts +82 -0
  5. package/dist/cache/index.d.ts +82 -0
  6. package/dist/cache/index.js +11 -0
  7. package/dist/cache/index.js.map +1 -0
  8. package/dist/chunk-65HACONF.js +33 -0
  9. package/dist/chunk-65HACONF.js.map +1 -0
  10. package/dist/chunk-GG7EI74E.js +169 -0
  11. package/dist/chunk-GG7EI74E.js.map +1 -0
  12. package/dist/chunk-HTHX24NK.js +106 -0
  13. package/dist/chunk-HTHX24NK.js.map +1 -0
  14. package/dist/chunk-LBFFAXER.js +293 -0
  15. package/dist/chunk-LBFFAXER.js.map +1 -0
  16. package/dist/core/index.cjs +211 -0
  17. package/dist/core/index.cjs.map +1 -0
  18. package/dist/core/index.d.cts +58 -0
  19. package/dist/core/index.d.ts +58 -0
  20. package/dist/core/index.js +19 -0
  21. package/dist/core/index.js.map +1 -0
  22. package/dist/headers/index.cjs +65 -0
  23. package/dist/headers/index.cjs.map +1 -0
  24. package/dist/headers/index.d.cts +25 -0
  25. package/dist/headers/index.d.ts +25 -0
  26. package/dist/headers/index.js +19 -0
  27. package/dist/headers/index.js.map +1 -0
  28. package/dist/index.cjs +644 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.cts +6 -0
  31. package/dist/index.d.ts +6 -0
  32. package/dist/index.js +55 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/middlewares/index.cjs +163 -0
  35. package/dist/middlewares/index.cjs.map +1 -0
  36. package/dist/middlewares/index.d.cts +18 -0
  37. package/dist/middlewares/index.d.ts +18 -0
  38. package/dist/middlewares/index.js +16 -0
  39. package/dist/middlewares/index.js.map +1 -0
  40. package/package.json +59 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,644 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var src_exports = {};
32
+ __export(src_exports, {
33
+ HEADER_AUTHORIZATION: () => HEADER_AUTHORIZATION,
34
+ HEADER_BRANCH_UID: () => HEADER_BRANCH_UID,
35
+ HEADER_COMPANY_UID: () => HEADER_COMPANY_UID,
36
+ HEADER_EMPLOYEE_UID: () => HEADER_EMPLOYEE_UID,
37
+ HEADER_INTERNAL_API_KEY: () => HEADER_INTERNAL_API_KEY,
38
+ HEADER_REQUEST_ID: () => HEADER_REQUEST_ID,
39
+ InternalHttp: () => InternalHttp,
40
+ REQUEST_ID_HEADER: () => REQUEST_ID_HEADER,
41
+ UpstreamError: () => UpstreamError,
42
+ closeCache: () => closeCache,
43
+ createHttpClient: () => createHttpClient,
44
+ getOrSet: () => getOrSet,
45
+ getRequestContextFromHeaders: () => getRequestContextFromHeaders,
46
+ getTwoLevelCache: () => getTwoLevelCache,
47
+ internalAuth: () => internalAuth,
48
+ mapAxiosToUpstreamError: () => mapAxiosToUpstreamError,
49
+ parseHeaders: () => parseHeaders,
50
+ requestId: () => requestId,
51
+ sendError: () => sendError,
52
+ sendOk: () => sendOk,
53
+ withRequestId: () => withRequestId,
54
+ withRequestIdConfig: () => withRequestIdConfig
55
+ });
56
+ module.exports = __toCommonJS(src_exports);
57
+
58
+ // src/cache/redisCacheProvider.ts
59
+ var import_redis = require("redis");
60
+ function buildRedisUrl(opts) {
61
+ if (opts.url && opts.url.trim()) return opts.url.trim();
62
+ if (!opts.host) return void 0;
63
+ const port = opts.port ?? 6379;
64
+ const db = opts.db ?? 0;
65
+ const auth = opts.password ? `:${encodeURIComponent(opts.password)}@` : "";
66
+ return `redis://${auth}${opts.host}:${port}/${db}`;
67
+ }
68
+ var RedisCacheProvider = class {
69
+ constructor(opts) {
70
+ this.opts = opts;
71
+ const url = buildRedisUrl(opts);
72
+ if (!url) {
73
+ throw new Error("[RedisCacheProvider] Missing redis config (REDIS_URL or REDIS_HOST)");
74
+ }
75
+ this.keyPrefix = opts.keyPrefix?.trim() || void 0;
76
+ this.client = (0, import_redis.createClient)({
77
+ url,
78
+ socket: {
79
+ connectTimeout: opts.connectTimeoutMs ?? 3e3,
80
+ tls: opts.tls ? true : void 0
81
+ }
82
+ });
83
+ this.client.on("error", (err) => {
84
+ const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
85
+ console.error("[redis] error", msg, err);
86
+ });
87
+ }
88
+ kind = "redis";
89
+ // ✅ tip "amplio" para evitar TS2322 por typings genéricos
90
+ client;
91
+ ready = false;
92
+ keyPrefix;
93
+ k(key) {
94
+ if (!this.keyPrefix) return key;
95
+ return `${this.keyPrefix}:${key}`;
96
+ }
97
+ async ensureConnected() {
98
+ if (this.ready) return;
99
+ await this.client.connect();
100
+ this.ready = true;
101
+ }
102
+ async get(key) {
103
+ await this.ensureConnected();
104
+ const v = await this.client.get(this.k(key));
105
+ return v ?? null;
106
+ }
107
+ async set(key, value, options) {
108
+ await this.ensureConnected();
109
+ const ttlMs = options?.ttlMs;
110
+ if (ttlMs && ttlMs > 0) {
111
+ await this.client.set(this.k(key), value, { PX: ttlMs });
112
+ return;
113
+ }
114
+ await this.client.set(this.k(key), value);
115
+ }
116
+ async del(key) {
117
+ await this.ensureConnected();
118
+ await this.client.del(this.k(key));
119
+ }
120
+ async close() {
121
+ try {
122
+ if (this.ready) await this.client.quit();
123
+ } catch {
124
+ try {
125
+ await this.client.disconnect();
126
+ } catch {
127
+ }
128
+ } finally {
129
+ this.ready = false;
130
+ }
131
+ }
132
+ };
133
+
134
+ // src/cache/cacheProvider.ts
135
+ var NoopCacheProvider = class {
136
+ kind = "noop";
137
+ async get(_key) {
138
+ return null;
139
+ }
140
+ async set(_key, _value, _options) {
141
+ return;
142
+ }
143
+ async del(_key) {
144
+ return;
145
+ }
146
+ async close() {
147
+ return;
148
+ }
149
+ };
150
+ function createCacheProvider(opts = {}) {
151
+ const envHasRedis = Boolean(process.env.REDIS_URL || process.env.REDIS_HOST);
152
+ const enabled = typeof opts.enabled === "boolean" ? opts.enabled : envHasRedis;
153
+ if (!enabled) return new NoopCacheProvider();
154
+ const redisOpts = {
155
+ url: process.env.REDIS_URL,
156
+ host: process.env.REDIS_HOST,
157
+ port: process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : void 0,
158
+ password: process.env.REDIS_PASSWORD,
159
+ db: process.env.REDIS_DB ? Number(process.env.REDIS_DB) : void 0,
160
+ tls: (process.env.REDIS_TLS || "").toLowerCase() === "true",
161
+ connectTimeoutMs: process.env.REDIS_CONNECT_TIMEOUT_MS ? Number(process.env.REDIS_CONNECT_TIMEOUT_MS) : 3e3,
162
+ keyPrefix: opts.keyPrefix || process.env.REDIS_KEY_PREFIX || void 0,
163
+ ...opts.redis || {}
164
+ };
165
+ return new RedisCacheProvider(redisOpts);
166
+ }
167
+
168
+ // src/cache/ttlCache.ts
169
+ var TtlCache = class {
170
+ constructor(defaultTtlMs) {
171
+ this.defaultTtlMs = defaultTtlMs;
172
+ }
173
+ store = /* @__PURE__ */ new Map();
174
+ get(key) {
175
+ const e = this.store.get(key);
176
+ if (!e) return null;
177
+ if (Date.now() > e.expiresAt) {
178
+ this.store.delete(key);
179
+ return null;
180
+ }
181
+ return e.value;
182
+ }
183
+ set(key, value, ttlMs) {
184
+ this.store.set(key, { value, expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs) });
185
+ }
186
+ del(key) {
187
+ this.store.delete(key);
188
+ }
189
+ };
190
+
191
+ // src/cache/twoLevelCache.ts
192
+ function safeJsonParse(raw) {
193
+ try {
194
+ return JSON.parse(raw);
195
+ } catch {
196
+ return null;
197
+ }
198
+ }
199
+ function safeJsonStringify(v) {
200
+ try {
201
+ return JSON.stringify(v);
202
+ } catch {
203
+ return null;
204
+ }
205
+ }
206
+ var TwoLevelCache = class {
207
+ constructor(l2, opts = {}) {
208
+ this.l2 = l2;
209
+ this.opts = opts;
210
+ const defaultTtl = this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
211
+ this.l1 = new TtlCache(defaultTtl);
212
+ }
213
+ l1;
214
+ inflight = /* @__PURE__ */ new Map();
215
+ key(k) {
216
+ const ns = (this.opts.namespace || "").trim();
217
+ return ns ? `${ns}:${k}` : k;
218
+ }
219
+ /**
220
+ * GET "best effort": primero L1, luego L2.
221
+ * (No llama loader)
222
+ */
223
+ async get(k) {
224
+ const key = this.key(k);
225
+ const v1 = this.l1.get(key);
226
+ if (v1 !== void 0) return v1;
227
+ const raw = await this.l2.get(key);
228
+ if (!raw) return null;
229
+ const parsed = safeJsonParse(raw);
230
+ if (parsed === null && raw !== "null") {
231
+ return null;
232
+ }
233
+ this.l1.set(key, parsed, this.opts.ttlMsL1);
234
+ return parsed;
235
+ }
236
+ async set(k, value, ttlOverride) {
237
+ const key = this.key(k);
238
+ const ttlL1 = ttlOverride?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
239
+ const ttlL2 = ttlOverride?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1e3;
240
+ this.l1.set(key, value, ttlL1);
241
+ const raw = safeJsonStringify(value);
242
+ if (raw == null) return;
243
+ await this.l2.set(key, raw, { ttlMs: ttlL2 });
244
+ }
245
+ async del(k) {
246
+ const key = this.key(k);
247
+ this.l1.del?.(key);
248
+ await this.l2.del(key);
249
+ }
250
+ /**
251
+ * Cache-aside real con L1 + L2 + loader.
252
+ *
253
+ * - Dedup de concurrencia por key (inflight)
254
+ * - Soporta negative caching (si loader retorna null)
255
+ */
256
+ async getOrSet(k, loader, options) {
257
+ const key = this.key(k);
258
+ const v1 = this.l1.get(key);
259
+ if (v1 !== void 0) return v1;
260
+ const raw = await this.l2.get(key);
261
+ if (raw) {
262
+ const parsed = safeJsonParse(raw);
263
+ if (parsed !== null || raw === "null") {
264
+ this.l1.set(key, parsed, options?.ttlMsL1 ?? this.opts.ttlMsL1);
265
+ return parsed;
266
+ }
267
+ }
268
+ if (this.inflight.has(key)) {
269
+ return this.inflight.get(key);
270
+ }
271
+ const promise = (async () => {
272
+ try {
273
+ const value = await loader();
274
+ const ttlMsL1 = options?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
275
+ const ttlMsL2 = options?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1e3;
276
+ const negL1 = options?.negativeTtlMsL1 ?? this.opts.negativeTtlMsL1 ?? 0;
277
+ const negL2 = options?.negativeTtlMsL2 ?? this.opts.negativeTtlMsL2 ?? 0;
278
+ if (value === null) {
279
+ if (negL1 > 0) this.l1.set(key, null, negL1);
280
+ if (negL2 > 0) await this.l2.set(key, "null", { ttlMs: negL2 });
281
+ return null;
282
+ }
283
+ this.l1.set(key, value, ttlMsL1);
284
+ const rawValue = safeJsonStringify(value);
285
+ if (rawValue != null) {
286
+ await this.l2.set(key, rawValue, { ttlMs: ttlMsL2 });
287
+ }
288
+ return value;
289
+ } finally {
290
+ this.inflight.delete(key);
291
+ }
292
+ })();
293
+ this.inflight.set(key, promise);
294
+ return promise;
295
+ }
296
+ };
297
+
298
+ // src/cache/index.ts
299
+ var envInt = (v, dflt = 0) => {
300
+ const n = Number(v);
301
+ return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;
302
+ };
303
+ var DEFAULT_L1_TTL_MS = envInt(process.env.CACHE_L1_DEFAULT_TTL_MS, 3e4);
304
+ var DEFAULT_L2_TTL_MS = envInt(process.env.CACHE_L2_DEFAULT_TTL_MS, 3e5);
305
+ var DEFAULT_NEG_TTL_MS = envInt(process.env.CACHE_NEGATIVE_TTL_MS, 3e4);
306
+ var l2Provider = null;
307
+ var twoLevelByNamespace = /* @__PURE__ */ new Map();
308
+ function getL2() {
309
+ if (l2Provider) return l2Provider;
310
+ l2Provider = createCacheProvider();
311
+ return l2Provider;
312
+ }
313
+ function getTwoLevelCache(namespace, opts = {}) {
314
+ const existing = twoLevelByNamespace.get(namespace);
315
+ if (existing) return existing;
316
+ const l2 = getL2();
317
+ const cacheOptions = {
318
+ // ✅ dejamos que TwoLevelCache prefije keys con namespace internamente
319
+ namespace,
320
+ ttlMsL1: opts.ttlMsL1 ?? DEFAULT_L1_TTL_MS,
321
+ ttlMsL2: opts.ttlMsL2 ?? DEFAULT_L2_TTL_MS,
322
+ // ✅ negative caching
323
+ negativeTtlMsL1: opts.negativeTtlMsL1 ?? DEFAULT_NEG_TTL_MS,
324
+ negativeTtlMsL2: opts.negativeTtlMsL2 ?? DEFAULT_NEG_TTL_MS
325
+ };
326
+ const cache = new TwoLevelCache(l2, cacheOptions);
327
+ twoLevelByNamespace.set(namespace, cache);
328
+ return cache;
329
+ }
330
+ async function getOrSet(namespace, key, loader, opts = {}) {
331
+ const cache = getTwoLevelCache(namespace, opts);
332
+ return cache.getOrSet(key, loader, opts);
333
+ }
334
+ async function closeCache() {
335
+ try {
336
+ if (l2Provider && typeof l2Provider.close === "function") {
337
+ await l2Provider.close();
338
+ }
339
+ } finally {
340
+ l2Provider = null;
341
+ twoLevelByNamespace.clear();
342
+ }
343
+ }
344
+
345
+ // src/core/errors.ts
346
+ var UpstreamError = class extends Error {
347
+ code;
348
+ status;
349
+ details;
350
+ constructor(message, code, status, details) {
351
+ super(message);
352
+ this.name = "UpstreamError";
353
+ this.code = code;
354
+ this.status = status;
355
+ this.details = details;
356
+ }
357
+ };
358
+ function mapAxiosToUpstreamError(err, svc) {
359
+ const status = err?.response?.status;
360
+ const data = err?.response?.data;
361
+ const isTimeout = err?.code === "ECONNABORTED" || String(err?.message || "").includes("timeout");
362
+ if (isTimeout) {
363
+ return new UpstreamError(`[${svc}] timeout`, "UPSTREAM_TIMEOUT", 504, { cause: err?.message });
364
+ }
365
+ if (!err?.response) {
366
+ return new UpstreamError(`[${svc}] unavailable`, "UPSTREAM_UNAVAILABLE", 503, { cause: err?.message });
367
+ }
368
+ if (status === 404) return new UpstreamError(`[${svc}] not found`, "UPSTREAM_NOT_FOUND", 404, data);
369
+ if (status === 401) return new UpstreamError(`[${svc}] unauthorized`, "UPSTREAM_UNAUTHORIZED", 401, data);
370
+ if (status === 403) return new UpstreamError(`[${svc}] forbidden`, "UPSTREAM_FORBIDDEN", 403, data);
371
+ if (status >= 400 && status < 600) {
372
+ return new UpstreamError(`[${svc}] bad response`, "UPSTREAM_BAD_RESPONSE", status, data);
373
+ }
374
+ return new UpstreamError(`[${svc}] unknown error`, "UPSTREAM_UNKNOWN", status, data);
375
+ }
376
+
377
+ // src/core/http.ts
378
+ var import_axios = __toESM(require("axios"), 1);
379
+ var REQUEST_ID_HEADER = "x-request-id";
380
+ function withRequestId(headers, requestId2) {
381
+ const h = headers && typeof headers === "object" ? { ...headers } : {};
382
+ const rid = (requestId2 || "").trim();
383
+ if (rid) h[REQUEST_ID_HEADER] = rid;
384
+ return h;
385
+ }
386
+ function withRequestIdConfig(config = {}, requestId2) {
387
+ return {
388
+ ...config,
389
+ headers: withRequestId(config.headers, requestId2)
390
+ };
391
+ }
392
+ function createHttpClient(opts) {
393
+ return import_axios.default.create({
394
+ baseURL: opts.baseURL,
395
+ timeout: opts.timeoutMs ?? 4e3,
396
+ headers: { "Content-Type": "application/json" }
397
+ });
398
+ }
399
+
400
+ // src/core/internalHttp.ts
401
+ var DEFAULT_RETRY = {
402
+ retries: 1,
403
+ baseDelayMs: 150,
404
+ retryOnStatuses: [429, 502, 503, 504],
405
+ retryOnNetworkErrors: true
406
+ };
407
+ function sleep(ms) {
408
+ return new Promise((r) => setTimeout(r, ms));
409
+ }
410
+ function safeJsonStringify2(v) {
411
+ try {
412
+ return JSON.stringify(v);
413
+ } catch {
414
+ return String(v);
415
+ }
416
+ }
417
+ function toHeaders(init) {
418
+ return new Headers(init || {});
419
+ }
420
+ function isJsonContentType(contentType) {
421
+ if (!contentType) return false;
422
+ const ct = contentType.toLowerCase();
423
+ return ct.includes("application/json") || ct.includes("+json");
424
+ }
425
+ function isAbortError(e) {
426
+ return e?.name === "AbortError";
427
+ }
428
+ function withJitter(ms) {
429
+ const jitter = ms * 0.2;
430
+ const delta = (Math.random() * 2 - 1) * jitter;
431
+ return Math.max(0, Math.floor(ms + delta));
432
+ }
433
+ var InternalHttp = class {
434
+ baseUrl;
435
+ apiKey;
436
+ timeoutMs;
437
+ retry;
438
+ constructor(opts) {
439
+ this.baseUrl = opts.baseUrl.replace(/\/+$/, "");
440
+ this.apiKey = opts.apiKey;
441
+ this.timeoutMs = opts.timeoutMs ?? 4e3;
442
+ this.retry = { ...DEFAULT_RETRY, ...opts.retry || {} };
443
+ }
444
+ async request(path, init = {}) {
445
+ const url = `${this.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
446
+ const baseHeaders = toHeaders(init.headers);
447
+ if (!baseHeaders.has("Content-Type")) baseHeaders.set("Content-Type", "application/json");
448
+ if (this.apiKey) baseHeaders.set("x-internal-api-key", this.apiKey);
449
+ if (init.requestId) baseHeaders.set("x-request-id", init.requestId);
450
+ if (init.idempotencyKey) baseHeaders.set("Idempotency-Key", init.idempotencyKey);
451
+ const { headers: _ignored, ...restInit } = init;
452
+ const doFetchOnce = async () => {
453
+ const controller = new AbortController();
454
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
455
+ try {
456
+ const res = await fetch(url, {
457
+ ...restInit,
458
+ headers: baseHeaders,
459
+ signal: controller.signal
460
+ });
461
+ if (!res.ok) {
462
+ const text2 = await res.text().catch(() => "");
463
+ const err = new Error(
464
+ `HTTP ${res.status} ${res.statusText}${text2 ? ` - ${text2}` : ""}`
465
+ );
466
+ err.status = res.status;
467
+ err.body = text2;
468
+ throw err;
469
+ }
470
+ if (res.status === 204) return void 0;
471
+ const contentType = res.headers.get("content-type");
472
+ if (isJsonContentType(contentType)) {
473
+ return await res.json();
474
+ }
475
+ const text = await res.text().catch(() => "");
476
+ return text;
477
+ } finally {
478
+ clearTimeout(timeout);
479
+ }
480
+ };
481
+ let attempt = 0;
482
+ while (true) {
483
+ try {
484
+ return await doFetchOnce();
485
+ } catch (e) {
486
+ attempt++;
487
+ const status = e?.status;
488
+ const retryableStatus = !!status && this.retry.retryOnStatuses.includes(status);
489
+ const retryableNetwork = this.retry.retryOnNetworkErrors && (isAbortError(e) || !status);
490
+ const isRetryable = retryableStatus || retryableNetwork;
491
+ if (!isRetryable || attempt > this.retry.retries) {
492
+ console.error(
493
+ `[InternalHttp] request failed: ${url} attempt=${attempt} status=${status ?? "n/a"} err=${e?.message} body=${safeJsonStringify2(e?.body)}`
494
+ );
495
+ throw e;
496
+ }
497
+ const backoff = withJitter(this.retry.baseDelayMs * attempt);
498
+ await sleep(backoff);
499
+ }
500
+ }
501
+ }
502
+ };
503
+
504
+ // src/headers/constants.ts
505
+ var HEADER_REQUEST_ID = "x-request-id";
506
+ var HEADER_COMPANY_UID = "x-company";
507
+ var HEADER_BRANCH_UID = "x-branch";
508
+ var HEADER_EMPLOYEE_UID = "x-employee-uid";
509
+ var HEADER_INTERNAL_API_KEY = "x-internal-api-key";
510
+ var HEADER_AUTHORIZATION = "authorization";
511
+
512
+ // src/headers/parse.ts
513
+ function asString(v) {
514
+ if (typeof v !== "string") return null;
515
+ const s = v.trim();
516
+ return s ? s : null;
517
+ }
518
+ function getRequestContextFromHeaders(headers) {
519
+ return {
520
+ requestId: asString(headers[HEADER_REQUEST_ID]) ?? null,
521
+ company_uid: asString(headers[HEADER_COMPANY_UID]) ?? null,
522
+ branch_uid: asString(headers[HEADER_BRANCH_UID]) ?? null,
523
+ employee_uid: asString(headers[HEADER_EMPLOYEE_UID]) ?? null
524
+ };
525
+ }
526
+
527
+ // src/middlewares/requestId.ts
528
+ var import_crypto = require("crypto");
529
+ var REQUEST_ID_HEADER2 = "x-request-id";
530
+ var REQUEST_ID_HEADER_ALT = "x-requestid";
531
+ var RESPONSE_REQUEST_ID_HEADER = "X-Request-Id";
532
+ function requestId(req, res, next) {
533
+ const headerId = req.headers[REQUEST_ID_HEADER2] || req.headers[REQUEST_ID_HEADER_ALT];
534
+ const id = headerId?.trim() || (0, import_crypto.randomUUID)();
535
+ req.requestId = id;
536
+ res.locals.requestId = id;
537
+ res.setHeader(RESPONSE_REQUEST_ID_HEADER, id);
538
+ next();
539
+ }
540
+
541
+ // src/middlewares/parseHeaders.ts
542
+ function parseHeaders(req, _res, next) {
543
+ const context = getRequestContextFromHeaders(req.headers);
544
+ req.context = context;
545
+ const auth = req.auth ?? (req.auth = {});
546
+ if (context.company_uid) auth.company_uid = context.company_uid;
547
+ if (context.branch_uid) auth.branch_uid = context.branch_uid;
548
+ if (context.employee_uid) auth.employee_uid = context.employee_uid;
549
+ next();
550
+ }
551
+
552
+ // src/middlewares/internalAuth.ts
553
+ var import_fs = __toESM(require("fs"), 1);
554
+ var import_crypto2 = __toESM(require("crypto"), 1);
555
+
556
+ // src/middlewares/respond.ts
557
+ function sendOk(_req, res, data, statusCode = 200) {
558
+ return res.status(statusCode).json({ ok: true, data, requestId: res.locals?.requestId ?? null });
559
+ }
560
+ function sendError(_req, res, statusCode, code, message, details) {
561
+ return res.status(statusCode).json({
562
+ ok: false,
563
+ error: { code, message, ...details !== void 0 ? { details } : {} },
564
+ requestId: res.locals?.requestId ?? null
565
+ });
566
+ }
567
+
568
+ // src/middlewares/internalAuth.ts
569
+ function readSecretFile(path) {
570
+ if (!path) return null;
571
+ try {
572
+ const v = import_fs.default.readFileSync(path, "utf8").trim();
573
+ return v.length ? v : null;
574
+ } catch {
575
+ return null;
576
+ }
577
+ }
578
+ function splitKeys(v) {
579
+ if (!v) return [];
580
+ return v.split(",").map((s) => s.trim()).filter(Boolean);
581
+ }
582
+ function getExpectedKeys() {
583
+ const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);
584
+ const envKey = (process.env.INTERNAL_API_KEY || "").trim();
585
+ const raw = fileKey || envKey;
586
+ return splitKeys(raw);
587
+ }
588
+ function extractToken(req) {
589
+ const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || "").trim();
590
+ return apiKey || null;
591
+ }
592
+ function safeEquals(a, b) {
593
+ const aa = Buffer.from(a);
594
+ const bb = Buffer.from(b);
595
+ if (aa.length !== bb.length) return false;
596
+ return import_crypto2.default.timingSafeEqual(aa, bb);
597
+ }
598
+ function internalAuth(req, res, next) {
599
+ const token = extractToken(req);
600
+ if (!token) {
601
+ return sendError(req, res, 401, "UNAUTHORIZED", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);
602
+ }
603
+ const expectedKeys = getExpectedKeys();
604
+ if (expectedKeys.length === 0) {
605
+ return sendError(
606
+ req,
607
+ res,
608
+ 500,
609
+ "MISCONFIGURED_INTERNAL_AUTH",
610
+ "Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)"
611
+ );
612
+ }
613
+ const ok = expectedKeys.some((k) => safeEquals(token, k));
614
+ if (!ok) {
615
+ return sendError(req, res, 403, "FORBIDDEN", "Invalid internal api key");
616
+ }
617
+ return next();
618
+ }
619
+ // Annotate the CommonJS export names for ESM import in node:
620
+ 0 && (module.exports = {
621
+ HEADER_AUTHORIZATION,
622
+ HEADER_BRANCH_UID,
623
+ HEADER_COMPANY_UID,
624
+ HEADER_EMPLOYEE_UID,
625
+ HEADER_INTERNAL_API_KEY,
626
+ HEADER_REQUEST_ID,
627
+ InternalHttp,
628
+ REQUEST_ID_HEADER,
629
+ UpstreamError,
630
+ closeCache,
631
+ createHttpClient,
632
+ getOrSet,
633
+ getRequestContextFromHeaders,
634
+ getTwoLevelCache,
635
+ internalAuth,
636
+ mapAxiosToUpstreamError,
637
+ parseHeaders,
638
+ requestId,
639
+ sendError,
640
+ sendOk,
641
+ withRequestId,
642
+ withRequestIdConfig
643
+ });
644
+ //# sourceMappingURL=index.cjs.map