@innvoid/getmarket-sdk 0.2.2 → 0.2.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.
- package/dist/cache/index.js +1 -1
- package/dist/{chunk-OSYBK5AN.js → chunk-5S2JP7PR.js} +4 -22
- package/dist/chunk-5S2JP7PR.js.map +1 -0
- package/dist/{chunk-IYFWQDHD.js → chunk-QVPPDOXY.js} +2 -1
- package/dist/chunk-UK6LHHJQ.js +413 -0
- package/dist/chunk-UK6LHHJQ.js.map +1 -0
- package/dist/{chunk-S44JVJZS.js → chunk-WM2QICZQ.js} +16 -1
- package/dist/{chunk-S44JVJZS.js.map → chunk-WM2QICZQ.js.map} +1 -1
- package/dist/clients/index.cjs +699 -0
- package/dist/clients/index.cjs.map +1 -0
- package/dist/clients/index.d.cts +75 -0
- package/dist/clients/index.d.ts +75 -0
- package/dist/clients/index.js +23 -0
- package/dist/clients/index.js.map +1 -0
- package/dist/core/index.cjs +5 -26
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +5 -17
- package/dist/core/index.d.ts +5 -17
- package/dist/core/index.js +3 -8
- package/dist/headers/index.d.cts +3 -16
- package/dist/headers/index.d.ts +3 -16
- package/dist/index.cjs +428 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -3
- package/dist/index.d.ts +52 -3
- package/dist/index.js +34 -16
- package/dist/middlewares/index.cjs +4 -7
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.js +2 -4
- package/dist/parse-C4vk-fmH.d.cts +16 -0
- package/dist/parse-C4vk-fmH.d.ts +16 -0
- package/package.json +11 -3
- package/dist/chunk-KJ64O2EG.js +0 -19
- package/dist/chunk-KJ64O2EG.js.map +0 -1
- package/dist/chunk-OSYBK5AN.js.map +0 -1
- /package/dist/{chunk-IYFWQDHD.js.map → chunk-QVPPDOXY.js.map} +0 -0
|
@@ -0,0 +1,699 @@
|
|
|
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/clients/index.ts
|
|
31
|
+
var clients_exports = {};
|
|
32
|
+
__export(clients_exports, {
|
|
33
|
+
createBulkRefsClient: () => createBulkRefsClient,
|
|
34
|
+
createFisClient: () => createFisClient,
|
|
35
|
+
createMdClient: () => createMdClient,
|
|
36
|
+
createMediaClient: () => createMediaClient,
|
|
37
|
+
createMkpClient: () => createMkpClient,
|
|
38
|
+
createPlatformClient: () => createPlatformClient,
|
|
39
|
+
createResClient: () => createResClient,
|
|
40
|
+
readServiceEnv: () => readServiceEnv
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(clients_exports);
|
|
43
|
+
|
|
44
|
+
// src/clients/env.ts
|
|
45
|
+
function must(v, name) {
|
|
46
|
+
const s = (v || "").trim();
|
|
47
|
+
if (!s) throw new Error(`Missing env var: ${name}`);
|
|
48
|
+
return s;
|
|
49
|
+
}
|
|
50
|
+
function readServiceEnv(prefix, defaults) {
|
|
51
|
+
const baseURL = (process.env[`${prefix}_BASE_URL`] || defaults?.baseURL || "").trim();
|
|
52
|
+
const apiPrefix = (process.env[`${prefix}_API_PREFIX`] || defaults?.apiPrefix || "/internal/v1").trim();
|
|
53
|
+
return {
|
|
54
|
+
baseURL: must(baseURL, `${prefix}_BASE_URL`),
|
|
55
|
+
apiPrefix
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/internalHttpClient.ts
|
|
60
|
+
var import_fs = __toESM(require("fs"), 1);
|
|
61
|
+
|
|
62
|
+
// src/headers/constants.ts
|
|
63
|
+
var HEADER_REQUEST_ID = "x-request-id";
|
|
64
|
+
var HEADER_COMPANY_UID = "x-company";
|
|
65
|
+
var HEADER_BRANCH_UID = "x-branch";
|
|
66
|
+
var HEADER_EMPLOYEE_UID = "x-employee-uid";
|
|
67
|
+
var HEADER_INTERNAL_API_KEY = "x-internal-api-key";
|
|
68
|
+
|
|
69
|
+
// src/internalHttpClient.ts
|
|
70
|
+
var InternalHttpError = class extends Error {
|
|
71
|
+
status;
|
|
72
|
+
code;
|
|
73
|
+
details;
|
|
74
|
+
constructor(status, code, message, details) {
|
|
75
|
+
super(message);
|
|
76
|
+
this.status = status;
|
|
77
|
+
this.code = code;
|
|
78
|
+
this.details = details ?? null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
function readSecretFile(path) {
|
|
82
|
+
if (!path) return null;
|
|
83
|
+
try {
|
|
84
|
+
const v = import_fs.default.readFileSync(path, "utf8").trim();
|
|
85
|
+
return v.length ? v : null;
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function splitKeys(v) {
|
|
91
|
+
if (!v) return [];
|
|
92
|
+
return v.split(",").map((s) => s.trim()).filter(Boolean);
|
|
93
|
+
}
|
|
94
|
+
function getInternalApiKey(override) {
|
|
95
|
+
if (override && override.trim()) return override.trim();
|
|
96
|
+
const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);
|
|
97
|
+
const envKey = (process.env.INTERNAL_API_KEY || "").trim();
|
|
98
|
+
const raw = fileKey || envKey;
|
|
99
|
+
const keys = splitKeys(raw);
|
|
100
|
+
return keys[0] || null;
|
|
101
|
+
}
|
|
102
|
+
function normalizeBaseURL(baseURL) {
|
|
103
|
+
const b = (baseURL || "").trim();
|
|
104
|
+
if (!b) throw new Error("InternalHttpClient: baseURL is required");
|
|
105
|
+
return b.replace(/\/+$/g, "");
|
|
106
|
+
}
|
|
107
|
+
function normalizePrefix(prefix) {
|
|
108
|
+
const p = (prefix || "").trim();
|
|
109
|
+
if (!p) return "";
|
|
110
|
+
const withSlash = p.startsWith("/") ? p : `/${p}`;
|
|
111
|
+
return withSlash.replace(/\/+$/g, "");
|
|
112
|
+
}
|
|
113
|
+
function buildQuery(query) {
|
|
114
|
+
if (!query) return "";
|
|
115
|
+
const params = new URLSearchParams();
|
|
116
|
+
for (const [k, v] of Object.entries(query)) {
|
|
117
|
+
if (v === null || v === void 0) continue;
|
|
118
|
+
params.set(k, String(v));
|
|
119
|
+
}
|
|
120
|
+
const s = params.toString();
|
|
121
|
+
return s ? `?${s}` : "";
|
|
122
|
+
}
|
|
123
|
+
function buildInternalHeaders(ctx, extra, idempotencyKey) {
|
|
124
|
+
const h = {
|
|
125
|
+
"Content-Type": "application/json"
|
|
126
|
+
};
|
|
127
|
+
if (ctx?.requestId) h[HEADER_REQUEST_ID] = String(ctx.requestId);
|
|
128
|
+
if (ctx?.company_uid) h[HEADER_COMPANY_UID] = String(ctx.company_uid);
|
|
129
|
+
if (ctx?.branch_uid) h[HEADER_BRANCH_UID] = String(ctx.branch_uid);
|
|
130
|
+
if (ctx?.employee_uid) h[HEADER_EMPLOYEE_UID] = String(ctx.employee_uid);
|
|
131
|
+
if (idempotencyKey && idempotencyKey.trim()) {
|
|
132
|
+
h["Idempotency-Key"] = idempotencyKey.trim();
|
|
133
|
+
}
|
|
134
|
+
for (const [k, v] of Object.entries(extra || {})) {
|
|
135
|
+
if (v === void 0) continue;
|
|
136
|
+
const vv = String(v).trim();
|
|
137
|
+
if (!vv) continue;
|
|
138
|
+
h[k] = vv;
|
|
139
|
+
}
|
|
140
|
+
return h;
|
|
141
|
+
}
|
|
142
|
+
async function sleep(ms) {
|
|
143
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
144
|
+
}
|
|
145
|
+
function shouldRetry(status, err) {
|
|
146
|
+
if (err?.name === "AbortError") return true;
|
|
147
|
+
if (!status) return true;
|
|
148
|
+
if (status >= 500) return true;
|
|
149
|
+
if (status === 429) return true;
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
async function safeReadJson(res) {
|
|
153
|
+
const text = await res.text();
|
|
154
|
+
if (!text) return null;
|
|
155
|
+
try {
|
|
156
|
+
return JSON.parse(text);
|
|
157
|
+
} catch {
|
|
158
|
+
return { raw: text };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function createInternalHttpClient(opts) {
|
|
162
|
+
const baseURL = normalizeBaseURL(opts.baseURL);
|
|
163
|
+
const apiPrefix = normalizePrefix(opts.apiPrefix);
|
|
164
|
+
const timeoutMs = typeof opts.timeoutMs === "number" ? opts.timeoutMs : 15e3;
|
|
165
|
+
const retries = typeof opts.retries === "number" ? opts.retries : 2;
|
|
166
|
+
const retryDelayMs = typeof opts.retryDelayMs === "number" ? opts.retryDelayMs : 250;
|
|
167
|
+
const apiKey = getInternalApiKey(opts.apiKey ?? null);
|
|
168
|
+
if (!apiKey) {
|
|
169
|
+
throw new Error(
|
|
170
|
+
"InternalHttpClient: INTERNAL_API_KEY or INTERNAL_API_KEY_FILE is required to call internal endpoints."
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
async function request(r) {
|
|
174
|
+
const path = (r.path || "").trim();
|
|
175
|
+
if (!path.startsWith("/")) {
|
|
176
|
+
throw new Error(`InternalHttpClient: path must start with '/': ${path}`);
|
|
177
|
+
}
|
|
178
|
+
const url = `${baseURL}${apiPrefix}${path}${buildQuery(r.query)}`;
|
|
179
|
+
const headers = buildInternalHeaders(r.ctx ?? null, r.headers, r.idempotencyKey ?? null);
|
|
180
|
+
if (apiKey != null) {
|
|
181
|
+
headers[HEADER_INTERNAL_API_KEY] = apiKey;
|
|
182
|
+
}
|
|
183
|
+
const method = r.method;
|
|
184
|
+
const expectJson = r.expectJson !== false;
|
|
185
|
+
const body = method === "GET" || method === "DELETE" ? void 0 : r.body !== void 0 ? JSON.stringify(r.body) : void 0;
|
|
186
|
+
let attempt = 0;
|
|
187
|
+
let lastErr = null;
|
|
188
|
+
while (attempt <= retries) {
|
|
189
|
+
attempt++;
|
|
190
|
+
const ac = new AbortController();
|
|
191
|
+
const to = setTimeout(() => ac.abort(), timeoutMs);
|
|
192
|
+
try {
|
|
193
|
+
const res = await fetch(url, {
|
|
194
|
+
method,
|
|
195
|
+
headers,
|
|
196
|
+
body,
|
|
197
|
+
signal: ac.signal
|
|
198
|
+
});
|
|
199
|
+
clearTimeout(to);
|
|
200
|
+
if (res.ok) {
|
|
201
|
+
if (!expectJson) return void 0;
|
|
202
|
+
const data = await safeReadJson(res);
|
|
203
|
+
return data;
|
|
204
|
+
}
|
|
205
|
+
const errBody = await safeReadJson(res);
|
|
206
|
+
const status = res.status;
|
|
207
|
+
if (attempt <= retries && shouldRetry(status, null)) {
|
|
208
|
+
lastErr = new InternalHttpError(
|
|
209
|
+
status,
|
|
210
|
+
"INTERNAL_HTTP_RETRY",
|
|
211
|
+
`Retryable internal HTTP error (${status})`,
|
|
212
|
+
{ url, status, response: errBody, attempt }
|
|
213
|
+
);
|
|
214
|
+
await sleep(retryDelayMs * attempt);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
throw new InternalHttpError(
|
|
218
|
+
status,
|
|
219
|
+
"INTERNAL_HTTP_ERROR",
|
|
220
|
+
`Internal HTTP error (${status})`,
|
|
221
|
+
{ url, status, response: errBody }
|
|
222
|
+
);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
clearTimeout(to);
|
|
225
|
+
if (attempt <= retries && shouldRetry(null, e)) {
|
|
226
|
+
lastErr = e;
|
|
227
|
+
await sleep(retryDelayMs * attempt);
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (e instanceof InternalHttpError) throw e;
|
|
231
|
+
throw new InternalHttpError(
|
|
232
|
+
0,
|
|
233
|
+
"INTERNAL_HTTP_NETWORK_ERROR",
|
|
234
|
+
e?.message || "Internal HTTP network error",
|
|
235
|
+
{ url, attempt, error: String(e) }
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
throw lastErr || new InternalHttpError(0, "INTERNAL_HTTP_FAILED", "Internal request failed");
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
request,
|
|
243
|
+
get: (path, o) => request({ ...o || {}, method: "GET", path }),
|
|
244
|
+
post: (path, body, o) => request({ ...o || {}, method: "POST", path, body }),
|
|
245
|
+
put: (path, body, o) => request({ ...o || {}, method: "PUT", path, body }),
|
|
246
|
+
patch: (path, body, o) => request({ ...o || {}, method: "PATCH", path, body }),
|
|
247
|
+
del: (path, o) => request({ ...o || {}, method: "DELETE", path })
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/cache/redisCacheProvider.ts
|
|
252
|
+
var import_redis = require("redis");
|
|
253
|
+
function buildRedisUrl(opts) {
|
|
254
|
+
if (opts.url && opts.url.trim()) return opts.url.trim();
|
|
255
|
+
if (!opts.host) return void 0;
|
|
256
|
+
const port = opts.port ?? 6379;
|
|
257
|
+
const db = opts.db ?? 0;
|
|
258
|
+
const auth = opts.password ? `:${encodeURIComponent(opts.password)}@` : "";
|
|
259
|
+
return `redis://${auth}${opts.host}:${port}/${db}`;
|
|
260
|
+
}
|
|
261
|
+
var RedisCacheProvider = class {
|
|
262
|
+
constructor(opts) {
|
|
263
|
+
this.opts = opts;
|
|
264
|
+
const url = buildRedisUrl(opts);
|
|
265
|
+
if (!url) {
|
|
266
|
+
throw new Error("[RedisCacheProvider] Missing redis config (REDIS_URL or REDIS_HOST)");
|
|
267
|
+
}
|
|
268
|
+
this.keyPrefix = opts.keyPrefix?.trim() || void 0;
|
|
269
|
+
this.client = (0, import_redis.createClient)({
|
|
270
|
+
url,
|
|
271
|
+
socket: {
|
|
272
|
+
connectTimeout: opts.connectTimeoutMs ?? 3e3,
|
|
273
|
+
tls: opts.tls ? true : void 0
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
this.client.on("error", (err) => {
|
|
277
|
+
const msg = err instanceof Error ? err.message : typeof err === "object" && err !== null && "message" in err ? String(err.message) : String(err);
|
|
278
|
+
console.error("[redis] error", msg, err);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
kind = "redis";
|
|
282
|
+
// ✅ tip "amplio" para evitar TS2322 por typings genéricos
|
|
283
|
+
client;
|
|
284
|
+
ready = false;
|
|
285
|
+
keyPrefix;
|
|
286
|
+
k(key) {
|
|
287
|
+
if (!this.keyPrefix) return key;
|
|
288
|
+
return `${this.keyPrefix}:${key}`;
|
|
289
|
+
}
|
|
290
|
+
async ensureConnected() {
|
|
291
|
+
if (this.ready) return;
|
|
292
|
+
await this.client.connect();
|
|
293
|
+
this.ready = true;
|
|
294
|
+
}
|
|
295
|
+
async get(key) {
|
|
296
|
+
await this.ensureConnected();
|
|
297
|
+
const v = await this.client.get(this.k(key));
|
|
298
|
+
return v ?? null;
|
|
299
|
+
}
|
|
300
|
+
async set(key, value, options) {
|
|
301
|
+
await this.ensureConnected();
|
|
302
|
+
const ttlMs = options?.ttlMs;
|
|
303
|
+
if (ttlMs && ttlMs > 0) {
|
|
304
|
+
await this.client.set(this.k(key), value, { PX: ttlMs });
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
await this.client.set(this.k(key), value);
|
|
308
|
+
}
|
|
309
|
+
async del(key) {
|
|
310
|
+
await this.ensureConnected();
|
|
311
|
+
await this.client.del(this.k(key));
|
|
312
|
+
}
|
|
313
|
+
async close() {
|
|
314
|
+
try {
|
|
315
|
+
if (this.ready) await this.client.quit();
|
|
316
|
+
} catch {
|
|
317
|
+
try {
|
|
318
|
+
await this.client.disconnect();
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
} finally {
|
|
322
|
+
this.ready = false;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// src/cache/cacheProvider.ts
|
|
328
|
+
var NoopCacheProvider = class {
|
|
329
|
+
kind = "noop";
|
|
330
|
+
async get(_key) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
async set(_key, _value, _options) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
async del(_key) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
async close() {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
function createCacheProvider(opts = {}) {
|
|
344
|
+
const envHasRedis = Boolean(process.env.REDIS_URL || process.env.REDIS_HOST);
|
|
345
|
+
const enabled = typeof opts.enabled === "boolean" ? opts.enabled : envHasRedis;
|
|
346
|
+
if (!enabled) return new NoopCacheProvider();
|
|
347
|
+
const redisOpts = {
|
|
348
|
+
url: process.env.REDIS_URL,
|
|
349
|
+
host: process.env.REDIS_HOST,
|
|
350
|
+
port: process.env.REDIS_PORT ? Number(process.env.REDIS_PORT) : void 0,
|
|
351
|
+
password: process.env.REDIS_PASSWORD,
|
|
352
|
+
db: process.env.REDIS_DB ? Number(process.env.REDIS_DB) : void 0,
|
|
353
|
+
tls: (process.env.REDIS_TLS || "").toLowerCase() === "true",
|
|
354
|
+
connectTimeoutMs: process.env.REDIS_CONNECT_TIMEOUT_MS ? Number(process.env.REDIS_CONNECT_TIMEOUT_MS) : 3e3,
|
|
355
|
+
keyPrefix: opts.keyPrefix || process.env.REDIS_KEY_PREFIX || void 0,
|
|
356
|
+
...opts.redis || {}
|
|
357
|
+
};
|
|
358
|
+
return new RedisCacheProvider(redisOpts);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// src/cache/ttlCache.ts
|
|
362
|
+
var TtlCache = class {
|
|
363
|
+
constructor(defaultTtlMs) {
|
|
364
|
+
this.defaultTtlMs = defaultTtlMs;
|
|
365
|
+
}
|
|
366
|
+
store = /* @__PURE__ */ new Map();
|
|
367
|
+
get(key) {
|
|
368
|
+
const e = this.store.get(key);
|
|
369
|
+
if (!e) return null;
|
|
370
|
+
if (Date.now() > e.expiresAt) {
|
|
371
|
+
this.store.delete(key);
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
return e.value;
|
|
375
|
+
}
|
|
376
|
+
set(key, value, ttlMs) {
|
|
377
|
+
this.store.set(key, { value, expiresAt: Date.now() + (ttlMs ?? this.defaultTtlMs) });
|
|
378
|
+
}
|
|
379
|
+
del(key) {
|
|
380
|
+
this.store.delete(key);
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// src/cache/twoLevelCache.ts
|
|
385
|
+
function safeJsonParse(raw) {
|
|
386
|
+
try {
|
|
387
|
+
return JSON.parse(raw);
|
|
388
|
+
} catch {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function safeJsonStringify(v) {
|
|
393
|
+
try {
|
|
394
|
+
return JSON.stringify(v);
|
|
395
|
+
} catch {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
var TwoLevelCache = class {
|
|
400
|
+
constructor(l2, opts = {}) {
|
|
401
|
+
this.l2 = l2;
|
|
402
|
+
this.opts = opts;
|
|
403
|
+
const defaultTtl = this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
|
|
404
|
+
this.l1 = new TtlCache(defaultTtl);
|
|
405
|
+
}
|
|
406
|
+
l1;
|
|
407
|
+
inflight = /* @__PURE__ */ new Map();
|
|
408
|
+
key(k) {
|
|
409
|
+
const ns = (this.opts.namespace || "").trim();
|
|
410
|
+
return ns ? `${ns}:${k}` : k;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* GET "best effort": primero L1, luego L2.
|
|
414
|
+
* (No llama loader)
|
|
415
|
+
*/
|
|
416
|
+
async get(k) {
|
|
417
|
+
const key = this.key(k);
|
|
418
|
+
const v1 = this.l1.get(key);
|
|
419
|
+
if (v1 !== void 0) return v1;
|
|
420
|
+
const raw = await this.l2.get(key);
|
|
421
|
+
if (!raw) return null;
|
|
422
|
+
const parsed = safeJsonParse(raw);
|
|
423
|
+
if (parsed === null && raw !== "null") {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
426
|
+
this.l1.set(key, parsed, this.opts.ttlMsL1);
|
|
427
|
+
return parsed;
|
|
428
|
+
}
|
|
429
|
+
async set(k, value, ttlOverride) {
|
|
430
|
+
const key = this.key(k);
|
|
431
|
+
const ttlL1 = ttlOverride?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
|
|
432
|
+
const ttlL2 = ttlOverride?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1e3;
|
|
433
|
+
this.l1.set(key, value, ttlL1);
|
|
434
|
+
const raw = safeJsonStringify(value);
|
|
435
|
+
if (raw == null) return;
|
|
436
|
+
await this.l2.set(key, raw, { ttlMs: ttlL2 });
|
|
437
|
+
}
|
|
438
|
+
async del(k) {
|
|
439
|
+
const key = this.key(k);
|
|
440
|
+
this.l1.del?.(key);
|
|
441
|
+
await this.l2.del(key);
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Cache-aside real con L1 + L2 + loader.
|
|
445
|
+
*
|
|
446
|
+
* - Dedup de concurrencia por key (inflight)
|
|
447
|
+
* - Soporta negative caching (si loader retorna null)
|
|
448
|
+
*/
|
|
449
|
+
async getOrSet(k, loader, options) {
|
|
450
|
+
const key = this.key(k);
|
|
451
|
+
const v1 = this.l1.get(key);
|
|
452
|
+
if (v1 !== void 0) return v1;
|
|
453
|
+
const raw = await this.l2.get(key);
|
|
454
|
+
if (raw) {
|
|
455
|
+
const parsed = safeJsonParse(raw);
|
|
456
|
+
if (parsed !== null || raw === "null") {
|
|
457
|
+
this.l1.set(key, parsed, options?.ttlMsL1 ?? this.opts.ttlMsL1);
|
|
458
|
+
return parsed;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (this.inflight.has(key)) {
|
|
462
|
+
return this.inflight.get(key);
|
|
463
|
+
}
|
|
464
|
+
const promise = (async () => {
|
|
465
|
+
try {
|
|
466
|
+
const value = await loader();
|
|
467
|
+
const ttlMsL1 = options?.ttlMsL1 ?? this.opts.ttlMsL1 ?? 2 * 60 * 1e3;
|
|
468
|
+
const ttlMsL2 = options?.ttlMsL2 ?? this.opts.ttlMsL2 ?? 10 * 60 * 1e3;
|
|
469
|
+
const negL1 = options?.negativeTtlMsL1 ?? this.opts.negativeTtlMsL1 ?? 0;
|
|
470
|
+
const negL2 = options?.negativeTtlMsL2 ?? this.opts.negativeTtlMsL2 ?? 0;
|
|
471
|
+
if (value === null) {
|
|
472
|
+
if (negL1 > 0) this.l1.set(key, null, negL1);
|
|
473
|
+
if (negL2 > 0) await this.l2.set(key, "null", { ttlMs: negL2 });
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
476
|
+
this.l1.set(key, value, ttlMsL1);
|
|
477
|
+
const rawValue = safeJsonStringify(value);
|
|
478
|
+
if (rawValue != null) {
|
|
479
|
+
await this.l2.set(key, rawValue, { ttlMs: ttlMsL2 });
|
|
480
|
+
}
|
|
481
|
+
return value;
|
|
482
|
+
} finally {
|
|
483
|
+
this.inflight.delete(key);
|
|
484
|
+
}
|
|
485
|
+
})();
|
|
486
|
+
this.inflight.set(key, promise);
|
|
487
|
+
return promise;
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
// src/cache/index.ts
|
|
492
|
+
var envInt = (v, dflt = 0) => {
|
|
493
|
+
const n = Number(v);
|
|
494
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(n) : dflt;
|
|
495
|
+
};
|
|
496
|
+
var DEFAULT_L1_TTL_MS = envInt(process.env.CACHE_L1_DEFAULT_TTL_MS, 3e4);
|
|
497
|
+
var DEFAULT_L2_TTL_MS = envInt(process.env.CACHE_L2_DEFAULT_TTL_MS, 3e5);
|
|
498
|
+
var DEFAULT_NEG_TTL_MS = envInt(process.env.CACHE_NEGATIVE_TTL_MS, 3e4);
|
|
499
|
+
|
|
500
|
+
// src/clients/cacheFactory.ts
|
|
501
|
+
function makeRefsCache(namespace) {
|
|
502
|
+
const l2 = createCacheProvider();
|
|
503
|
+
return new TwoLevelCache(l2, {
|
|
504
|
+
namespace,
|
|
505
|
+
ttlMsL1: 3e4,
|
|
506
|
+
ttlMsL2: 3e5,
|
|
507
|
+
negativeTtlMsL1: 3e4,
|
|
508
|
+
negativeTtlMsL2: 3e4
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/clients/bulkRefsClient.ts
|
|
513
|
+
function uniq(arr) {
|
|
514
|
+
return Array.from(new Set(arr.filter(Boolean)));
|
|
515
|
+
}
|
|
516
|
+
function createBulkRefsClient(args) {
|
|
517
|
+
const http = createInternalHttpClient({
|
|
518
|
+
baseURL: args.baseURL,
|
|
519
|
+
apiPrefix: args.apiPrefix
|
|
520
|
+
});
|
|
521
|
+
const cache = makeRefsCache(args.namespace);
|
|
522
|
+
async function bulkRefs(uids, opts) {
|
|
523
|
+
const list = uniq(uids);
|
|
524
|
+
if (list.length === 0) {
|
|
525
|
+
return { ok: true, refs: [], meta: { requested: 0, returned: 0, missing: [] } };
|
|
526
|
+
}
|
|
527
|
+
const hits = [];
|
|
528
|
+
const missing = [];
|
|
529
|
+
for (const uid of list) {
|
|
530
|
+
const v = await cache.get(uid);
|
|
531
|
+
if (v) hits.push(v);
|
|
532
|
+
else missing.push(uid);
|
|
533
|
+
}
|
|
534
|
+
let fetched = [];
|
|
535
|
+
if (missing.length) {
|
|
536
|
+
const resp = await http.post(
|
|
537
|
+
args.path,
|
|
538
|
+
{ uids: missing },
|
|
539
|
+
{
|
|
540
|
+
ctx: opts?.ctx ?? null
|
|
541
|
+
}
|
|
542
|
+
);
|
|
543
|
+
const refs = resp.refs ?? resp.items ?? [];
|
|
544
|
+
fetched = refs;
|
|
545
|
+
const ttlMsL1 = opts?.ttlMsL1 ?? args.defaultTtlMsL1;
|
|
546
|
+
const ttlMsL2 = opts?.ttlMsL2 ?? args.defaultTtlMsL2;
|
|
547
|
+
for (const ref of refs) {
|
|
548
|
+
const uid = String(ref?.uid || "").trim();
|
|
549
|
+
if (!uid) continue;
|
|
550
|
+
await cache.set(uid, ref, {
|
|
551
|
+
ttlMsL1,
|
|
552
|
+
ttlMsL2
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
const all = [...hits, ...fetched];
|
|
557
|
+
const returnedSet = new Set(all.map((r) => String(r?.uid || "")));
|
|
558
|
+
const missingFinal = list.filter((u) => !returnedSet.has(u));
|
|
559
|
+
return {
|
|
560
|
+
ok: true,
|
|
561
|
+
refs: all,
|
|
562
|
+
meta: {
|
|
563
|
+
requested: list.length,
|
|
564
|
+
returned: all.length,
|
|
565
|
+
missing: missingFinal
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
return { bulkRefs };
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// src/clients/platformClient.ts
|
|
573
|
+
function createPlatformClient(env) {
|
|
574
|
+
const http = createInternalHttpClient(env);
|
|
575
|
+
const cache = makeRefsCache("platform:tenant");
|
|
576
|
+
async function resolveTenant(input, ctx) {
|
|
577
|
+
const key = `${input.company_uid}:${input.service}`;
|
|
578
|
+
const cached = await cache.get(key);
|
|
579
|
+
if (cached) return cached;
|
|
580
|
+
const resp = await http.post(
|
|
581
|
+
"/tenants/resolve",
|
|
582
|
+
input,
|
|
583
|
+
{ ctx: ctx ?? null }
|
|
584
|
+
);
|
|
585
|
+
await cache.set(key, resp);
|
|
586
|
+
return resp;
|
|
587
|
+
}
|
|
588
|
+
return { resolveTenant };
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
// src/clients/resClient.ts
|
|
592
|
+
function createResClient() {
|
|
593
|
+
const env = readServiceEnv("RES", { apiPrefix: "/internal/v1" });
|
|
594
|
+
const varieties = createBulkRefsClient({
|
|
595
|
+
namespace: "res:variety",
|
|
596
|
+
baseURL: env.baseURL,
|
|
597
|
+
apiPrefix: env.apiPrefix,
|
|
598
|
+
path: "/refs/varieties"
|
|
599
|
+
});
|
|
600
|
+
return {
|
|
601
|
+
varietiesRefs: (uids, opts) => varieties.bulkRefs(uids, opts)
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// src/clients/mdClient.ts
|
|
606
|
+
function createMdClient() {
|
|
607
|
+
const env = readServiceEnv("MD", { apiPrefix: "/internal/v1" });
|
|
608
|
+
const measures = createBulkRefsClient({
|
|
609
|
+
namespace: "md:measure",
|
|
610
|
+
baseURL: env.baseURL,
|
|
611
|
+
apiPrefix: env.apiPrefix,
|
|
612
|
+
path: "/refs/measures"
|
|
613
|
+
});
|
|
614
|
+
const measureTypes = createBulkRefsClient({
|
|
615
|
+
namespace: "md:measure_type",
|
|
616
|
+
baseURL: env.baseURL,
|
|
617
|
+
apiPrefix: env.apiPrefix,
|
|
618
|
+
path: "/refs/measure-types"
|
|
619
|
+
});
|
|
620
|
+
const countries = createBulkRefsClient({
|
|
621
|
+
namespace: "md:country",
|
|
622
|
+
baseURL: env.baseURL,
|
|
623
|
+
apiPrefix: env.apiPrefix,
|
|
624
|
+
path: "/refs/countries"
|
|
625
|
+
});
|
|
626
|
+
return {
|
|
627
|
+
measuresRefs: (uids, opts) => measures.bulkRefs(uids, opts),
|
|
628
|
+
measureTypesRefs: (uids, opts) => measureTypes.bulkRefs(uids, opts),
|
|
629
|
+
countriesRefs: (uids, opts) => countries.bulkRefs(uids, opts)
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// src/clients/fisClient.ts
|
|
634
|
+
function createFisClient() {
|
|
635
|
+
const env = readServiceEnv("FIS", { apiPrefix: "/internal/v1" });
|
|
636
|
+
const taxes = createBulkRefsClient({
|
|
637
|
+
namespace: "fis:tax",
|
|
638
|
+
baseURL: env.baseURL,
|
|
639
|
+
apiPrefix: env.apiPrefix,
|
|
640
|
+
path: "/refs/taxes"
|
|
641
|
+
});
|
|
642
|
+
return {
|
|
643
|
+
taxesRefs: (uids, opts) => taxes.bulkRefs(uids, opts)
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// src/clients/mediaClient.ts
|
|
648
|
+
function createMediaClient() {
|
|
649
|
+
const env = readServiceEnv("MEDIA", { apiPrefix: "/internal/v1" });
|
|
650
|
+
const files = createBulkRefsClient({
|
|
651
|
+
namespace: "media:file",
|
|
652
|
+
baseURL: env.baseURL,
|
|
653
|
+
apiPrefix: env.apiPrefix,
|
|
654
|
+
path: "/refs/files"
|
|
655
|
+
});
|
|
656
|
+
return {
|
|
657
|
+
filesRefs: (uids, opts) => files.bulkRefs(uids, opts)
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// src/clients/mkpClient.ts
|
|
662
|
+
function createMkpClient() {
|
|
663
|
+
const env = readServiceEnv("MKP", { apiPrefix: "/internal/v1" });
|
|
664
|
+
const publications = createBulkRefsClient({
|
|
665
|
+
namespace: "mkp:publication",
|
|
666
|
+
baseURL: env.baseURL,
|
|
667
|
+
apiPrefix: env.apiPrefix,
|
|
668
|
+
path: "/refs/publications"
|
|
669
|
+
});
|
|
670
|
+
const events = createBulkRefsClient({
|
|
671
|
+
namespace: "mkp:event",
|
|
672
|
+
baseURL: env.baseURL,
|
|
673
|
+
apiPrefix: env.apiPrefix,
|
|
674
|
+
path: "/refs/events"
|
|
675
|
+
});
|
|
676
|
+
const promotions = createBulkRefsClient({
|
|
677
|
+
namespace: "mkp:promotion",
|
|
678
|
+
baseURL: env.baseURL,
|
|
679
|
+
apiPrefix: env.apiPrefix,
|
|
680
|
+
path: "/refs/promotions"
|
|
681
|
+
});
|
|
682
|
+
return {
|
|
683
|
+
publicationsRefs: (uids, opts) => publications.bulkRefs(uids, opts),
|
|
684
|
+
eventsRefs: (uids, opts) => events.bulkRefs(uids, opts),
|
|
685
|
+
promotionsRefs: (uids, opts) => promotions.bulkRefs(uids, opts)
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
689
|
+
0 && (module.exports = {
|
|
690
|
+
createBulkRefsClient,
|
|
691
|
+
createFisClient,
|
|
692
|
+
createMdClient,
|
|
693
|
+
createMediaClient,
|
|
694
|
+
createMkpClient,
|
|
695
|
+
createPlatformClient,
|
|
696
|
+
createResClient,
|
|
697
|
+
readServiceEnv
|
|
698
|
+
});
|
|
699
|
+
//# sourceMappingURL=index.cjs.map
|