@neetru/sdk 3.2.2 → 3.2.3
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/CHANGELOG.md +16 -0
- package/dist/auth.cjs +154 -4
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.mjs +154 -4
- package/dist/auth.mjs.map +1 -1
- package/dist/db.cjs +154 -4
- package/dist/db.cjs.map +1 -1
- package/dist/db.mjs +154 -4
- package/dist/db.mjs.map +1 -1
- package/dist/index.cjs +155 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +155 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -42,6 +42,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
44
|
/** Versão do SDK — exportada explicitamente pra detecção em runtime. */
|
|
45
|
-
declare const VERSION: "3.2.
|
|
45
|
+
declare const VERSION: "3.2.3";
|
|
46
46
|
|
|
47
47
|
export { VERSION, checkCoreVersionCompat };
|
package/dist/index.d.ts
CHANGED
|
@@ -42,6 +42,6 @@ declare function checkCoreVersionCompat(coreVersion: string): void;
|
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
44
|
/** Versão do SDK — exportada explicitamente pra detecção em runtime. */
|
|
45
|
-
declare const VERSION: "3.2.
|
|
45
|
+
declare const VERSION: "3.2.3";
|
|
46
46
|
|
|
47
47
|
export { VERSION, checkCoreVersionCompat };
|
package/dist/index.mjs
CHANGED
|
@@ -275,6 +275,95 @@ var init_db_errors = __esm({
|
|
|
275
275
|
}
|
|
276
276
|
});
|
|
277
277
|
|
|
278
|
+
// src/db/sql/resilient-pool.ts
|
|
279
|
+
function isResilientPool(x) {
|
|
280
|
+
return typeof x === "object" && x !== null && x[RESILIENT_POOL_BRAND] === true;
|
|
281
|
+
}
|
|
282
|
+
function isConnectionEstablishmentError(err) {
|
|
283
|
+
const code = err && typeof err === "object" && "code" in err ? err.code : void 0;
|
|
284
|
+
if (code === "ECONNREFUSED" || code === "ETIMEDOUT" || code === "ENOTFOUND" || code === "EHOSTUNREACH" || code === "EAI_AGAIN") {
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (typeof code === "string") {
|
|
288
|
+
const upper = code.toUpperCase();
|
|
289
|
+
if (upper === "CERT_HAS_EXPIRED" || upper.startsWith("ERR_SSL") || upper.startsWith("ERR_TLS") || upper.includes("CERTIFICATE_EXPIRED")) {
|
|
290
|
+
return true;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const rawMessage = err instanceof Error ? err.message : typeof err === "string" ? err : "";
|
|
294
|
+
const message = rawMessage.toLowerCase();
|
|
295
|
+
if (message.length === 0) return false;
|
|
296
|
+
if (message.includes("certificate expired") || message.includes("certificate has expired") || message.includes("cert_has_expired") || message.includes("alert certificate expired") || message.includes("err_ssl") || message.includes("sslv3 alert") || message.includes("tlsv1 alert")) {
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
if (message.includes("econnrefused") || message.includes("etimedout") || message.includes("enotfound") || message.includes("ehostunreach") || message.includes("getaddrinfo")) {
|
|
300
|
+
return true;
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
function createResilientPool(initialInner) {
|
|
305
|
+
const state = { current: initialInner };
|
|
306
|
+
let reLease = null;
|
|
307
|
+
const controls = {
|
|
308
|
+
__neetruSwapInner(newInner) {
|
|
309
|
+
const old = state.current;
|
|
310
|
+
state.current = newInner;
|
|
311
|
+
return old;
|
|
312
|
+
},
|
|
313
|
+
__neetruGetInner() {
|
|
314
|
+
return state.current;
|
|
315
|
+
},
|
|
316
|
+
__neetruSetReLease(fn) {
|
|
317
|
+
reLease = fn;
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const invokeQuery = (pool, args) => pool.query(...args);
|
|
321
|
+
const wrappedQuery = (...args) => {
|
|
322
|
+
if (args.length > 0 && typeof args[args.length - 1] === "function") {
|
|
323
|
+
return invokeQuery(state.current, args);
|
|
324
|
+
}
|
|
325
|
+
return (async () => {
|
|
326
|
+
try {
|
|
327
|
+
return await invokeQuery(state.current, args);
|
|
328
|
+
} catch (err) {
|
|
329
|
+
const fn = reLease;
|
|
330
|
+
if (fn === null || !isConnectionEstablishmentError(err)) {
|
|
331
|
+
throw err;
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
await fn();
|
|
335
|
+
} catch {
|
|
336
|
+
throw err;
|
|
337
|
+
}
|
|
338
|
+
return await invokeQuery(state.current, args);
|
|
339
|
+
}
|
|
340
|
+
})();
|
|
341
|
+
};
|
|
342
|
+
const target = Object.create(Object.getPrototypeOf(initialInner));
|
|
343
|
+
const proxy = new Proxy(target, {
|
|
344
|
+
get(_t, prop) {
|
|
345
|
+
if (prop === RESILIENT_POOL_BRAND) return true;
|
|
346
|
+
if (prop === "__neetruSwapInner") return controls.__neetruSwapInner;
|
|
347
|
+
if (prop === "__neetruGetInner") return controls.__neetruGetInner;
|
|
348
|
+
if (prop === "__neetruSetReLease") return controls.__neetruSetReLease;
|
|
349
|
+
if (prop === "query") return wrappedQuery;
|
|
350
|
+
if (prop === "constructor") {
|
|
351
|
+
return state.current.constructor;
|
|
352
|
+
}
|
|
353
|
+
const current = state.current;
|
|
354
|
+
const value = Reflect.get(current, prop, current);
|
|
355
|
+
return typeof value === "function" ? value.bind(current) : value;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
return proxy;
|
|
359
|
+
}
|
|
360
|
+
var RESILIENT_POOL_BRAND;
|
|
361
|
+
var init_resilient_pool = __esm({
|
|
362
|
+
"src/db/sql/resilient-pool.ts"() {
|
|
363
|
+
RESILIENT_POOL_BRAND = /* @__PURE__ */ Symbol.for("neetru.sdk.resilientPool");
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
278
367
|
// src/db/sql/lease.ts
|
|
279
368
|
function hasConnectionChanged(oldLease, newLease) {
|
|
280
369
|
return oldLease.leaseId !== newLease.leaseId || oldLease.credentialVersion !== newLease.credentialVersion || oldLease.host !== newLease.host || oldLease.port !== newLease.port || oldLease.dbName !== newLease.dbName || oldLease.user !== newLease.user || oldLease.password !== newLease.password || oldLease.sslca !== newLease.sslca || oldLease.clientCert !== newLease.clientCert || oldLease.clientKey !== newLease.clientKey;
|
|
@@ -304,6 +393,7 @@ var RENEWAL_THRESHOLD, MIN_RENEWAL_DELAY_MS, SqlLeaseManager;
|
|
|
304
393
|
var init_lease = __esm({
|
|
305
394
|
"src/db/sql/lease.ts"() {
|
|
306
395
|
init_db_errors();
|
|
396
|
+
init_resilient_pool();
|
|
307
397
|
RENEWAL_THRESHOLD = 0.8;
|
|
308
398
|
MIN_RENEWAL_DELAY_MS = 3e4;
|
|
309
399
|
SqlLeaseManager = class {
|
|
@@ -312,6 +402,12 @@ var init_lease = __esm({
|
|
|
312
402
|
_orm;
|
|
313
403
|
_renewalTimer = null;
|
|
314
404
|
_closed = false;
|
|
405
|
+
/**
|
|
406
|
+
* Promessa de re-lease REATIVO em voo — coalesce chamadas concorrentes
|
|
407
|
+
* (N queries falhando ao mesmo tempo disparam UM único re-lease). Ver
|
|
408
|
+
* `_reactiveReLease`.
|
|
409
|
+
*/
|
|
410
|
+
_reLeaseInFlight = null;
|
|
315
411
|
_deps;
|
|
316
412
|
constructor(lease, pool, orm, deps) {
|
|
317
413
|
this._lease = lease;
|
|
@@ -406,6 +502,49 @@ var init_lease = __esm({
|
|
|
406
502
|
}
|
|
407
503
|
this._scheduleRenewal();
|
|
408
504
|
}
|
|
505
|
+
// ─── Re-lease REATIVO (P1.5) ───────────────────────────────────────────────
|
|
506
|
+
/**
|
|
507
|
+
* Recuperação REATIVA: chamado pelo wrapper resiliente (`resilient-pool.ts`)
|
|
508
|
+
* quando uma query plana falha num erro de ESTABELECIMENTO de conexão (cert
|
|
509
|
+
* mTLS expirado no meio de uma request, ou timer de renovação que não
|
|
510
|
+
* disparou). Emite um lease NOVO e faz o swap do pool interno do wrapper com
|
|
511
|
+
* o certificado fresco; o wrapper então re-tenta a query 1x no pool novo.
|
|
512
|
+
*
|
|
513
|
+
* Vai DIRETO ao lease novo (sem `leaseId`) — a conexão falhou porque o
|
|
514
|
+
* certificado do lease atual está ruim, então `renew` (que depende do lease
|
|
515
|
+
* antigo estar vivo) não é o caminho mais robusto. Emitir do zero é o que já
|
|
516
|
+
* cura o death-spiral no caminho proativo (ver `_doRenew`).
|
|
517
|
+
*
|
|
518
|
+
* Coalesce concorrência: N queries falhando ao mesmo tempo compartilham UM
|
|
519
|
+
* único re-lease (não N leases). Após o swap, cada query re-tenta no pool
|
|
520
|
+
* vigente.
|
|
521
|
+
*
|
|
522
|
+
* NÃO engole erro: se o re-lease falhar, propaga — o wrapper então relança o
|
|
523
|
+
* erro ORIGINAL da query pro consumer.
|
|
524
|
+
*/
|
|
525
|
+
async _reactiveReLease() {
|
|
526
|
+
if (this._closed) {
|
|
527
|
+
throw new NeetruDbError(
|
|
528
|
+
"db_unavailable",
|
|
529
|
+
"SqlLeaseManager foi fechado \u2014 re-lease reativo abortado."
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
if (this._reLeaseInFlight !== null) return this._reLeaseInFlight;
|
|
533
|
+
const run = (async () => {
|
|
534
|
+
const withDb = (o) => {
|
|
535
|
+
if (this._deps.database !== void 0) o.database = this._deps.database;
|
|
536
|
+
return o;
|
|
537
|
+
};
|
|
538
|
+
const fresh = await this._deps.fetchLease(withDb({}));
|
|
539
|
+
await this._swapPool(fresh);
|
|
540
|
+
})();
|
|
541
|
+
this._reLeaseInFlight = run;
|
|
542
|
+
try {
|
|
543
|
+
await run;
|
|
544
|
+
} finally {
|
|
545
|
+
this._reLeaseInFlight = null;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
409
548
|
/**
|
|
410
549
|
* Hot-swap do pool: cria pool novo, atualiza ponteiros, drena pool antigo.
|
|
411
550
|
*
|
|
@@ -417,6 +556,13 @@ var init_lease = __esm({
|
|
|
417
556
|
return;
|
|
418
557
|
}
|
|
419
558
|
const newPool = this._deps.createPool(newLease);
|
|
559
|
+
if (isResilientPool(this._pool)) {
|
|
560
|
+
const oldInner = this._pool.__neetruSwapInner(newPool);
|
|
561
|
+
this._lease = newLease;
|
|
562
|
+
void oldInner.end().catch(() => {
|
|
563
|
+
});
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
420
566
|
const newOrm = this._deps.createDrizzle(newPool, this._deps.schema);
|
|
421
567
|
const oldPool = this._pool;
|
|
422
568
|
this._lease = newLease;
|
|
@@ -571,23 +717,26 @@ async function createSqlClientWithDeps(deps, options) {
|
|
|
571
717
|
const msg = err instanceof Error ? err.message : String(err);
|
|
572
718
|
throw new NeetruDbError("db_unavailable", `Falha ao obter lease inicial: ${msg}`);
|
|
573
719
|
}
|
|
574
|
-
let
|
|
720
|
+
let innerPool;
|
|
575
721
|
try {
|
|
576
|
-
|
|
722
|
+
innerPool = depsWithDb.createPool(lease);
|
|
577
723
|
} catch (err) {
|
|
578
724
|
const msg = err instanceof Error ? err.message : String(err);
|
|
579
725
|
throw new NeetruDbError("db_unavailable", `Falha ao abrir pool: ${msg}`);
|
|
580
726
|
}
|
|
727
|
+
const pool = createResilientPool(innerPool);
|
|
581
728
|
let orm;
|
|
582
729
|
try {
|
|
583
730
|
orm = depsWithDb.createDrizzle(pool, depsWithDb.schema);
|
|
584
731
|
} catch (err) {
|
|
585
|
-
await
|
|
732
|
+
await innerPool.end().catch(() => {
|
|
586
733
|
});
|
|
587
734
|
const msg = err instanceof Error ? err.message : String(err);
|
|
588
735
|
throw new NeetruDbError("db_unavailable", `Falha ao criar handle Drizzle: ${msg}`);
|
|
589
736
|
}
|
|
590
|
-
|
|
737
|
+
const manager = new SqlLeaseManager(lease, pool, orm, depsWithDb);
|
|
738
|
+
pool.__neetruSetReLease(() => manager._reactiveReLease());
|
|
739
|
+
return manager;
|
|
591
740
|
}
|
|
592
741
|
async function createSqlClientFromConfig(config, schema, options) {
|
|
593
742
|
const fetchLease = createHttpLeaseFetcher(config);
|
|
@@ -646,6 +795,7 @@ var init_sql_client = __esm({
|
|
|
646
795
|
"src/db/sql/sql-client.ts"() {
|
|
647
796
|
init_db_errors();
|
|
648
797
|
init_lease();
|
|
798
|
+
init_resilient_pool();
|
|
649
799
|
LEASE_ENDPOINT = "/api/sdk/v1/db/lease";
|
|
650
800
|
LEASE_RENEW_ENDPOINT = "/api/sdk/v1/db/lease/renew";
|
|
651
801
|
}
|
|
@@ -7126,7 +7276,7 @@ function createNeetruClient(config = {}) {
|
|
|
7126
7276
|
init_errors();
|
|
7127
7277
|
init_db_errors();
|
|
7128
7278
|
init_http();
|
|
7129
|
-
var VERSION = "3.2.
|
|
7279
|
+
var VERSION = "3.2.3";
|
|
7130
7280
|
|
|
7131
7281
|
export { DEFAULT_BASE_URL, DEV_FIXTURE_USER, MockAi, MockAuth, MockCheckout, MockDb, MockEntitlements, MockNotifications, MockSupport, MockUsage, MockWebhooks, NEETRU_SENTINEL_KEY, NeetruDbError, NeetruError, VERSION, checkCoreVersionCompat, createAiNamespace, createCheckoutNamespace, createNeetruClient, createNeetruDb, createNotificationsNamespace, createWebhooksNamespace, increment, isFieldSentinel, isIncrementSentinel, isServerTimestampSentinel, serverTimestamp, verifyWebhookRequest, verifyWebhookSignature };
|
|
7132
7282
|
//# sourceMappingURL=index.mjs.map
|