@neetru/sdk 3.1.7 → 3.1.9
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/auth.cjs +65 -22
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -1
- package/dist/auth.d.ts +1 -1
- package/dist/auth.mjs +65 -22
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.d.cts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/checkout.d.cts +1 -1
- package/dist/checkout.d.ts +1 -1
- package/dist/db-react.d.cts +1 -1
- package/dist/db-react.d.ts +1 -1
- package/dist/db.cjs +55 -16
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -1
- package/dist/db.d.ts +1 -1
- package/dist/db.mjs +55 -16
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.d.cts +1 -1
- package/dist/entitlements.d.ts +1 -1
- package/dist/firestore-compat.cjs +4 -9
- package/dist/firestore-compat.cjs.map +1 -1
- package/dist/firestore-compat.d.cts +2 -2
- package/dist/firestore-compat.d.ts +2 -2
- package/dist/firestore-compat.mjs +4 -9
- package/dist/firestore-compat.mjs.map +1 -1
- package/dist/index.cjs +66 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.mjs +66 -23
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.d.cts +1 -1
- package/dist/mocks.d.ts +1 -1
- package/dist/notifications.d.cts +1 -1
- package/dist/notifications.d.ts +1 -1
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs.map +1 -1
- package/dist/support.d.cts +1 -1
- package/dist/support.d.ts +1 -1
- package/dist/telemetry.cjs +5 -1
- package/dist/telemetry.cjs.map +1 -1
- package/dist/telemetry.d.cts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.mjs +5 -1
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-BXvGHppn.d.cts → types-DDiVzgCT.d.cts} +19 -2
- package/dist/{types-CQVak2a3.d.ts → types-HWDOUmlC.d.ts} +19 -2
- package/dist/usage.cjs +2 -2
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -1
- package/dist/usage.d.ts +1 -1
- package/dist/usage.mjs +2 -2
- package/dist/usage.mjs.map +1 -1
- package/dist/webhooks.d.cts +1 -1
- package/dist/webhooks.d.ts +1 -1
- package/package.json +1 -1
package/dist/auth.d.cts
CHANGED
package/dist/auth.d.ts
CHANGED
package/dist/auth.mjs
CHANGED
|
@@ -446,7 +446,7 @@ __export(sql_client_exports, {
|
|
|
446
446
|
function mapEnvToCore(sdkEnv) {
|
|
447
447
|
if (sdkEnv === "workspace") return "staging";
|
|
448
448
|
if (sdkEnv === "prod") return "production";
|
|
449
|
-
return "dev";
|
|
449
|
+
return "dev-local";
|
|
450
450
|
}
|
|
451
451
|
function createHttpLeaseFetcher(config) {
|
|
452
452
|
return async (opts) => {
|
|
@@ -955,7 +955,11 @@ function createTelemetryNamespace(config) {
|
|
|
955
955
|
path: "/api/sdk/v1/telemetry/event",
|
|
956
956
|
body,
|
|
957
957
|
requireAuth: true,
|
|
958
|
-
retries: 1
|
|
958
|
+
retries: 1,
|
|
959
|
+
// caça-bruxas: retry sem Idempotency-Key duplicava o evento se o
|
|
960
|
+
// servidor já tinha persistido antes da falha transiente. Mesmo
|
|
961
|
+
// padrão do usage.report (key estável por chamada, reusada no retry).
|
|
962
|
+
idempotencyKey: true
|
|
959
963
|
});
|
|
960
964
|
} catch (err) {
|
|
961
965
|
if (typeof console !== "undefined") {
|
|
@@ -1159,8 +1163,8 @@ function createUsageNamespace(config) {
|
|
|
1159
1163
|
if (!resource || typeof resource !== "string") {
|
|
1160
1164
|
throw new NeetruError("validation_failed", "resource is required");
|
|
1161
1165
|
}
|
|
1162
|
-
if (!Number.isFinite(qty) || qty <= 0) {
|
|
1163
|
-
throw new NeetruError("validation_failed", "qty must be positive integer");
|
|
1166
|
+
if (!Number.isFinite(qty) || qty <= 0 || !Number.isInteger(qty)) {
|
|
1167
|
+
throw new NeetruError("validation_failed", "qty must be a positive integer");
|
|
1164
1168
|
}
|
|
1165
1169
|
const productId = options?.productId ?? config.productId;
|
|
1166
1170
|
const tenantId = options?.tenantId ?? config.tenantId;
|
|
@@ -1409,7 +1413,12 @@ function evaluateFilter(data, filter) {
|
|
|
1409
1413
|
if (!Array.isArray(value)) return true;
|
|
1410
1414
|
return !value.includes(fieldValue);
|
|
1411
1415
|
default:
|
|
1412
|
-
|
|
1416
|
+
if (op === "array-contains-any") {
|
|
1417
|
+
return Array.isArray(fieldValue) && Array.isArray(value) && value.some((v) => fieldValue.includes(v));
|
|
1418
|
+
}
|
|
1419
|
+
throw new Error(
|
|
1420
|
+
`QueryEngine: operador de filtro '${String(op)}' n\xE3o suportado em leitura offline/cache. Use um operador suportado (==, !=, <, <=, >, >=, array-contains, array-contains-any, in, not-in) ou fa\xE7a a query server-side.`
|
|
1421
|
+
);
|
|
1413
1422
|
}
|
|
1414
1423
|
}
|
|
1415
1424
|
function matchesAllFilters(data, filters) {
|
|
@@ -1939,7 +1948,7 @@ var MutationQueue = class {
|
|
|
1939
1948
|
* - `{ removed: true }` — a mutação existente deve ser deletada (add+remove)
|
|
1940
1949
|
* - `null` — não é possível coalescir
|
|
1941
1950
|
*/
|
|
1942
|
-
tryCoalesce(existing, newOp, newPayload, newBatchId) {
|
|
1951
|
+
tryCoalesce(existing, newOp, newPayload, newBatchId, newUpsert) {
|
|
1943
1952
|
if (existing.batchId !== newBatchId) return null;
|
|
1944
1953
|
if (existing.status === "inflight") return null;
|
|
1945
1954
|
const existingOp = existing.op;
|
|
@@ -1947,10 +1956,12 @@ var MutationQueue = class {
|
|
|
1947
1956
|
return { removed: true };
|
|
1948
1957
|
}
|
|
1949
1958
|
if (existingOp === "update" && newOp === "update") {
|
|
1959
|
+
const mergedUpsert = existing.upsert || newUpsert;
|
|
1950
1960
|
return {
|
|
1951
1961
|
coalesced: {
|
|
1952
1962
|
...existing,
|
|
1953
|
-
payload: { ...existing.payload ?? {}, ...newPayload ?? {} }
|
|
1963
|
+
payload: { ...existing.payload ?? {}, ...newPayload ?? {} },
|
|
1964
|
+
...mergedUpsert ? { upsert: true } : {}
|
|
1954
1965
|
}
|
|
1955
1966
|
};
|
|
1956
1967
|
}
|
|
@@ -1999,13 +2010,13 @@ var MutationQueue = class {
|
|
|
1999
2010
|
* Atômico: a persistência final é uma única operação putMutation.
|
|
2000
2011
|
*/
|
|
2001
2012
|
async enqueue(params) {
|
|
2002
|
-
const { collection, op, payload, baseVersion, batchId } = params;
|
|
2013
|
+
const { collection, op, payload, baseVersion, batchId, upsert } = params;
|
|
2003
2014
|
const docId = params.docId ?? (op === "add" ? generateUUIDv4() : "");
|
|
2004
2015
|
await this.syncSeq();
|
|
2005
2016
|
const existingMutations = await this.store.listMutations({ collection, docId });
|
|
2006
2017
|
const lastQueued = existingMutations.filter((m) => m.status === "queued").sort((a, b) => b.seq - a.seq)[0];
|
|
2007
2018
|
if (lastQueued !== void 0) {
|
|
2008
|
-
const coalesceResult = this.tryCoalesce(lastQueued, op, payload, batchId);
|
|
2019
|
+
const coalesceResult = this.tryCoalesce(lastQueued, op, payload, batchId, upsert);
|
|
2009
2020
|
if (coalesceResult !== null) {
|
|
2010
2021
|
if ("removed" in coalesceResult) {
|
|
2011
2022
|
await this.store.deleteMutation(lastQueued.mutationId);
|
|
@@ -2043,7 +2054,9 @@ var MutationQueue = class {
|
|
|
2043
2054
|
attempts: 0,
|
|
2044
2055
|
lastError: null,
|
|
2045
2056
|
status: "queued",
|
|
2046
|
-
batchId
|
|
2057
|
+
batchId,
|
|
2058
|
+
// bug_0273e4dd: só persiste o flag quando verdadeiro (mantém o doc limpo).
|
|
2059
|
+
...upsert ? { upsert: true } : {}
|
|
2047
2060
|
};
|
|
2048
2061
|
await this.store.putMutation(mutation);
|
|
2049
2062
|
return mutation;
|
|
@@ -2372,10 +2385,15 @@ var SyncEngine = class {
|
|
|
2372
2385
|
await this._applyRejected(mut, res, busChanges);
|
|
2373
2386
|
}
|
|
2374
2387
|
}
|
|
2388
|
+
const processedIds = new Set(result.results.map((r) => r.mutationId));
|
|
2389
|
+
const unprocessed = mutations.filter((m) => !processedIds.has(m.mutationId));
|
|
2390
|
+
for (const mut of unprocessed) {
|
|
2391
|
+
await this._queue.markRetry(mut.mutationId, "partial_push: muta\xE7\xE3o n\xE3o processada no lote");
|
|
2392
|
+
}
|
|
2375
2393
|
if (busChanges.length > 0) {
|
|
2376
2394
|
this._bus.emit(busChanges);
|
|
2377
2395
|
}
|
|
2378
|
-
return
|
|
2396
|
+
return unprocessed.length === 0;
|
|
2379
2397
|
}
|
|
2380
2398
|
/** Atualiza o cache após confirmação de escrita (outcome=confirmed). */
|
|
2381
2399
|
async _applySyncedDoc(collection, docId, serverVersion, serverTimestamp, mut, busChanges) {
|
|
@@ -3682,7 +3700,7 @@ var DbCollectionRefImpl = class {
|
|
|
3682
3700
|
}]);
|
|
3683
3701
|
return { ok: true };
|
|
3684
3702
|
}
|
|
3685
|
-
async update(id, data) {
|
|
3703
|
+
async update(id, data, opts) {
|
|
3686
3704
|
assertValidId(id);
|
|
3687
3705
|
const existing = await this._store.getDoc(this._collection, id);
|
|
3688
3706
|
const rawData = data;
|
|
@@ -3695,7 +3713,9 @@ var DbCollectionRefImpl = class {
|
|
|
3695
3713
|
op: "update",
|
|
3696
3714
|
payload: rawData,
|
|
3697
3715
|
baseVersion: existing?.meta.serverVersion ?? null,
|
|
3698
|
-
batchId: null
|
|
3716
|
+
batchId: null,
|
|
3717
|
+
// bug_0273e4dd: propaga merge-upsert (setDoc({merge:true}) cria-se-ausente).
|
|
3718
|
+
upsert: opts?.upsert
|
|
3699
3719
|
});
|
|
3700
3720
|
await this._store.putDoc({
|
|
3701
3721
|
collection: this._collection,
|
|
@@ -3819,7 +3839,9 @@ var DbCollectionRefImpl = class {
|
|
|
3819
3839
|
op: "update",
|
|
3820
3840
|
payload: data,
|
|
3821
3841
|
baseVersion: existing?.meta.serverVersion ?? null,
|
|
3822
|
-
batchId
|
|
3842
|
+
batchId,
|
|
3843
|
+
// bug_0273e4dd: propaga merge-upsert (writeBatch.set(merge) cria-se-ausente).
|
|
3844
|
+
upsert: op.upsert
|
|
3823
3845
|
});
|
|
3824
3846
|
await this._store.putDoc({
|
|
3825
3847
|
collection,
|
|
@@ -4081,6 +4103,10 @@ async function createOfflineDocumentsNamespace(opts) {
|
|
|
4081
4103
|
connectivity,
|
|
4082
4104
|
periodicSyncIntervalMs: opts.periodicSyncIntervalMs ?? 5 * 60 * 1e3
|
|
4083
4105
|
});
|
|
4106
|
+
connectivity.start();
|
|
4107
|
+
if (!opts.singleTab && tabCoordinatorLike instanceof TabCoordinator) {
|
|
4108
|
+
tabCoordinatorLike.start();
|
|
4109
|
+
}
|
|
4084
4110
|
return new NeetruDbDocumentsImpl({
|
|
4085
4111
|
store,
|
|
4086
4112
|
queue,
|
|
@@ -4550,11 +4576,11 @@ function createRestSyncTransport(config) {
|
|
|
4550
4576
|
let raw;
|
|
4551
4577
|
if (m.op === "add") {
|
|
4552
4578
|
raw = await httpRequest2(config, {
|
|
4553
|
-
method: "
|
|
4554
|
-
path:
|
|
4579
|
+
method: "PUT",
|
|
4580
|
+
path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),
|
|
4555
4581
|
body: { data: m.payload ?? {} },
|
|
4556
4582
|
requireAuth: true,
|
|
4557
|
-
retries:
|
|
4583
|
+
retries: 2,
|
|
4558
4584
|
headers: tenantHeaders
|
|
4559
4585
|
});
|
|
4560
4586
|
} else if (m.op === "set") {
|
|
@@ -4570,7 +4596,7 @@ function createRestSyncTransport(config) {
|
|
|
4570
4596
|
raw = await httpRequest2(config, {
|
|
4571
4597
|
method: "PATCH",
|
|
4572
4598
|
path: DATASTORE_DOC_ENDPOINT(m.collection, m.docId),
|
|
4573
|
-
body: { data: m.payload ?? {} },
|
|
4599
|
+
body: { data: m.payload ?? {}, ...m.upsert ? { upsert: true } : {} },
|
|
4574
4600
|
requireAuth: true,
|
|
4575
4601
|
retries: 2,
|
|
4576
4602
|
headers: tenantHeaders
|
|
@@ -4593,7 +4619,24 @@ function createRestSyncTransport(config) {
|
|
|
4593
4619
|
});
|
|
4594
4620
|
} catch (err) {
|
|
4595
4621
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4596
|
-
|
|
4622
|
+
const code = err?.code;
|
|
4623
|
+
const status = err?.status;
|
|
4624
|
+
const isPermanent = code === "forbidden" || code === "unauthorized" || code === "not_found" || code === "conflict" || code === "validation_failed" || typeof status === "number" && status >= 400 && status < 500 && status !== 408 && status !== 429;
|
|
4625
|
+
if (isPermanent) {
|
|
4626
|
+
const reason = code === "forbidden" || code === "unauthorized" ? "rejected_permission" : "rejected_validation";
|
|
4627
|
+
results.push({
|
|
4628
|
+
mutationId: m.mutationId,
|
|
4629
|
+
outcome: "rejected",
|
|
4630
|
+
reason,
|
|
4631
|
+
serverVersion: null,
|
|
4632
|
+
serverData: null
|
|
4633
|
+
});
|
|
4634
|
+
continue;
|
|
4635
|
+
}
|
|
4636
|
+
if (results.length === 0) {
|
|
4637
|
+
throw new NeetruDbError("db_unavailable", `pushMutations falhou: ${msg}`);
|
|
4638
|
+
}
|
|
4639
|
+
break;
|
|
4597
4640
|
}
|
|
4598
4641
|
}
|
|
4599
4642
|
return { results };
|
|
@@ -6109,15 +6152,15 @@ function createOidcAuthNamespace(config) {
|
|
|
6109
6152
|
const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
|
|
6110
6153
|
const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
|
|
6111
6154
|
const issuer = idpOrigin;
|
|
6112
|
-
const jwksUrl = `${idpOrigin}/api/v1/oauth/.well-known/jwks
|
|
6155
|
+
const jwksUrl = `${idpOrigin}/api/v1/oauth/.well-known/jwks`;
|
|
6113
6156
|
const cacheTtlMs = options?.jwksCacheTtlMs ?? DEFAULT_JWKS_TTL_MS;
|
|
6114
6157
|
const audienceFromOptions = options?.audience;
|
|
6115
6158
|
const parsedKey = tryParseApiKey(config.apiKey);
|
|
6116
|
-
const audience = audienceFromOptions ?? parsedKey?.keyId;
|
|
6159
|
+
const audience = audienceFromOptions ?? config.oidcClientId ?? parsedKey?.keyId;
|
|
6117
6160
|
if (!audience) {
|
|
6118
6161
|
throw new NeetruError(
|
|
6119
6162
|
"invalid_config",
|
|
6120
|
-
"verifyToken requires an audience: provide apiKey on the client or pass options.audience. Calling jwtVerify without an audience allows tokens issued for other OIDC clients to pass."
|
|
6163
|
+
"verifyToken requires an audience: provide oidcClientId/apiKey on the client or pass options.audience. Calling jwtVerify without an audience allows tokens issued for other OIDC clients to pass."
|
|
6121
6164
|
);
|
|
6122
6165
|
}
|
|
6123
6166
|
const jwks = _getJwks(jwksUrl, cacheTtlMs);
|