@neetru/sdk 3.0.2 → 3.1.1
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 +554 -530
- package/dist/auth.cjs +219 -54
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +1 -2
- package/dist/auth.d.ts +1 -2
- package/dist/auth.mjs +219 -54
- package/dist/auth.mjs.map +1 -1
- package/dist/catalog.cjs +50 -2
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +1 -2
- package/dist/catalog.d.ts +1 -2
- package/dist/catalog.mjs +50 -2
- package/dist/catalog.mjs.map +1 -1
- package/dist/checkout.cjs +52 -3
- package/dist/checkout.cjs.map +1 -1
- package/dist/checkout.d.cts +1 -2
- package/dist/checkout.d.ts +1 -2
- package/dist/checkout.mjs +52 -3
- package/dist/checkout.mjs.map +1 -1
- package/dist/db-react.cjs +18 -6
- package/dist/db-react.cjs.map +1 -1
- package/dist/db-react.d.cts +35 -13
- package/dist/db-react.d.ts +35 -13
- package/dist/db-react.mjs +18 -6
- package/dist/db-react.mjs.map +1 -1
- package/dist/db.cjs +164 -56
- package/dist/db.cjs.map +1 -1
- package/dist/db.d.cts +1 -2
- package/dist/db.d.ts +1 -2
- package/dist/db.mjs +164 -56
- package/dist/db.mjs.map +1 -1
- package/dist/entitlements.cjs +50 -2
- package/dist/entitlements.cjs.map +1 -1
- package/dist/entitlements.d.cts +1 -2
- package/dist/entitlements.d.ts +1 -2
- package/dist/entitlements.mjs +50 -2
- package/dist/entitlements.mjs.map +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +3 -1
- package/dist/errors.d.ts +3 -1
- package/dist/errors.mjs.map +1 -1
- package/dist/firestore-compat.cjs +411 -0
- package/dist/firestore-compat.cjs.map +1 -0
- package/dist/firestore-compat.d.cts +319 -0
- package/dist/firestore-compat.d.ts +319 -0
- package/dist/firestore-compat.mjs +383 -0
- package/dist/firestore-compat.mjs.map +1 -0
- package/dist/index.cjs +266 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.mjs +265 -67
- package/dist/index.mjs.map +1 -1
- package/dist/mocks.cjs.map +1 -1
- package/dist/mocks.d.cts +1 -2
- package/dist/mocks.d.ts +1 -2
- package/dist/mocks.mjs.map +1 -1
- package/dist/notifications.cjs +50 -2
- package/dist/notifications.cjs.map +1 -1
- package/dist/notifications.d.cts +1 -2
- package/dist/notifications.d.ts +1 -2
- package/dist/notifications.mjs +50 -2
- package/dist/notifications.mjs.map +1 -1
- package/dist/react.cjs +268 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +135 -3
- package/dist/react.d.ts +135 -3
- package/dist/react.mjs +266 -3
- package/dist/react.mjs.map +1 -1
- package/dist/support.cjs +50 -2
- package/dist/support.cjs.map +1 -1
- package/dist/support.d.cts +1 -2
- package/dist/support.d.ts +1 -2
- package/dist/support.mjs +50 -2
- package/dist/support.mjs.map +1 -1
- package/dist/telemetry.cjs +65 -4
- package/dist/telemetry.cjs.map +1 -1
- package/dist/telemetry.d.cts +1 -2
- package/dist/telemetry.d.ts +1 -2
- package/dist/telemetry.mjs +65 -4
- package/dist/telemetry.mjs.map +1 -1
- package/dist/{types-D7zVkO3n.d.ts → types-B3XFHD4A.d.ts} +640 -2
- package/dist/{types-Dc4bjrrt.d.cts → types-DePdSU3P.d.cts} +640 -2
- package/dist/usage.cjs +50 -2
- package/dist/usage.cjs.map +1 -1
- package/dist/usage.d.cts +1 -2
- package/dist/usage.d.ts +1 -2
- package/dist/usage.mjs +50 -2
- package/dist/usage.mjs.map +1 -1
- package/dist/webhooks.cjs +83 -2
- package/dist/webhooks.cjs.map +1 -1
- package/dist/webhooks.d.cts +1 -2
- package/dist/webhooks.d.ts +1 -2
- package/dist/webhooks.mjs +83 -3
- package/dist/webhooks.mjs.map +1 -1
- package/package.json +156 -151
- package/dist/collection-ref-BDdfD87k.d.cts +0 -581
- package/dist/collection-ref-BDdfD87k.d.ts +0 -581
package/dist/auth.cjs
CHANGED
|
@@ -53,8 +53,47 @@ var init_idempotency = __esm({
|
|
|
53
53
|
// src/http.ts
|
|
54
54
|
var http_exports = {};
|
|
55
55
|
__export(http_exports, {
|
|
56
|
+
checkCoreVersionCompat: () => checkCoreVersionCompat,
|
|
56
57
|
httpRequest: () => httpRequest
|
|
57
58
|
});
|
|
59
|
+
function stripRevision(v) {
|
|
60
|
+
return v.split("+")[0] ?? v;
|
|
61
|
+
}
|
|
62
|
+
function compareCalVer(a, b) {
|
|
63
|
+
const partsA = stripRevision(a).split(".").map(Number);
|
|
64
|
+
const partsB = stripRevision(b).split(".").map(Number);
|
|
65
|
+
const len = Math.max(partsA.length, partsB.length);
|
|
66
|
+
for (let i = 0; i < len; i++) {
|
|
67
|
+
const pa = partsA[i] ?? 0;
|
|
68
|
+
const pb = partsB[i] ?? 0;
|
|
69
|
+
if (pa !== pb) return pa - pb;
|
|
70
|
+
}
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
function getSdkMajor() {
|
|
74
|
+
try {
|
|
75
|
+
const ver = globalThis.__NEETRU_SDK_VERSION__;
|
|
76
|
+
if (ver) return parseInt(ver.split(".")[0] ?? "3", 10);
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
return 3;
|
|
80
|
+
}
|
|
81
|
+
function checkCoreVersionCompat(coreVersion) {
|
|
82
|
+
if (!coreVersion) return;
|
|
83
|
+
const sdkMajor = getSdkMajor();
|
|
84
|
+
const minCore = COMPAT_MATRIX[sdkMajor];
|
|
85
|
+
if (!minCore) return;
|
|
86
|
+
const stripped = stripRevision(coreVersion);
|
|
87
|
+
if (compareCalVer(stripped, minCore) < 0) {
|
|
88
|
+
const key = `${sdkMajor}:${stripped}`;
|
|
89
|
+
if (!_warnedCoreTooOld.has(key)) {
|
|
90
|
+
_warnedCoreTooOld.add(key);
|
|
91
|
+
console.warn(
|
|
92
|
+
`[Neetru SDK] Aten\xE7\xE3o: Core vers\xE3o "${coreVersion}" \xE9 anterior ao m\xEDnimo recomendado "${minCore}" para SDK major ${sdkMajor}. Alguns recursos podem n\xE3o funcionar corretamente. Atualize o Core para a vers\xE3o mais recente.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
58
97
|
function backoffMs(attempt) {
|
|
59
98
|
const base = 200 * Math.pow(4, attempt);
|
|
60
99
|
const jitter = base * 0.2 * (Math.random() * 2 - 1);
|
|
@@ -63,11 +102,11 @@ function backoffMs(attempt) {
|
|
|
63
102
|
function parseRetryAfter(value) {
|
|
64
103
|
if (!value) return null;
|
|
65
104
|
const secs = Number(value);
|
|
66
|
-
if (Number.isFinite(secs) && secs >= 0) return Math.round(secs * 1e3);
|
|
105
|
+
if (Number.isFinite(secs) && secs >= 0) return Math.min(Math.round(secs * 1e3), MAX_RETRY_AFTER_MS);
|
|
67
106
|
const dateMs = Date.parse(value);
|
|
68
107
|
if (Number.isFinite(dateMs)) {
|
|
69
108
|
const delta = dateMs - Date.now();
|
|
70
|
-
if (delta > 0) return delta;
|
|
109
|
+
if (delta > 0) return Math.min(delta, MAX_RETRY_AFTER_MS);
|
|
71
110
|
}
|
|
72
111
|
return null;
|
|
73
112
|
}
|
|
@@ -78,6 +117,7 @@ function statusToCode(status) {
|
|
|
78
117
|
if (status === 401) return "unauthorized";
|
|
79
118
|
if (status === 403) return "forbidden";
|
|
80
119
|
if (status === 404) return "not_found";
|
|
120
|
+
if (status === 409) return "conflict";
|
|
81
121
|
if (status === 422 || status === 400) return "validation_failed";
|
|
82
122
|
if (status === 429) return "rate_limited";
|
|
83
123
|
if (status >= 500) return "server_error";
|
|
@@ -149,6 +189,8 @@ async function httpRequest(config, opts) {
|
|
|
149
189
|
}
|
|
150
190
|
const requestId = res.headers.get("x-request-id") ?? res.headers.get("x-correlation-id") ?? void 0;
|
|
151
191
|
if (res.ok) {
|
|
192
|
+
const coreVersion = res.headers.get("x-neetru-version");
|
|
193
|
+
if (coreVersion) checkCoreVersionCompat(coreVersion);
|
|
152
194
|
const parsed = await safeJson(res);
|
|
153
195
|
return parsed;
|
|
154
196
|
}
|
|
@@ -177,11 +219,17 @@ async function httpRequest(config, opts) {
|
|
|
177
219
|
}
|
|
178
220
|
throw lastError ?? new NeetruError("unknown", "unexpected httpRequest exit");
|
|
179
221
|
}
|
|
180
|
-
var DEFAULT_RETRIES_READ, DEFAULT_RETRIES_WRITE, READ_METHODS, RETRYABLE_CODES;
|
|
222
|
+
var COMPAT_MATRIX, _warnedCoreTooOld, DEFAULT_RETRIES_READ, DEFAULT_RETRIES_WRITE, READ_METHODS, RETRYABLE_CODES, MAX_RETRY_AFTER_MS;
|
|
181
223
|
var init_http = __esm({
|
|
182
224
|
"src/http.ts"() {
|
|
183
225
|
init_errors();
|
|
184
226
|
init_idempotency();
|
|
227
|
+
COMPAT_MATRIX = {
|
|
228
|
+
// SDK major 3.x requer Core ≥ 2026.05.1 (suporte a X-Neetru-Version header,
|
|
229
|
+
// runTransaction write-after-read, verifyWebhookRequest, webhooks 3.0+)
|
|
230
|
+
3: "2026.05.1"
|
|
231
|
+
};
|
|
232
|
+
_warnedCoreTooOld = /* @__PURE__ */ new Set();
|
|
185
233
|
DEFAULT_RETRIES_READ = 2;
|
|
186
234
|
DEFAULT_RETRIES_WRITE = 0;
|
|
187
235
|
READ_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
@@ -190,6 +238,7 @@ var init_http = __esm({
|
|
|
190
238
|
"server_error",
|
|
191
239
|
"network_error"
|
|
192
240
|
]);
|
|
241
|
+
MAX_RETRY_AFTER_MS = 6e4;
|
|
193
242
|
}
|
|
194
243
|
});
|
|
195
244
|
|
|
@@ -891,11 +940,11 @@ var TRACK_MAX_QUEUE = 50;
|
|
|
891
940
|
function createTelemetryNamespace(config) {
|
|
892
941
|
const queue = [];
|
|
893
942
|
let flushTimer = null;
|
|
943
|
+
let _inflightDrain = null;
|
|
894
944
|
async function drainQueue() {
|
|
895
945
|
if (queue.length === 0) return;
|
|
896
946
|
const batch = queue.splice(0, queue.length);
|
|
897
|
-
|
|
898
|
-
await Promise.allSettled(
|
|
947
|
+
const work = Promise.allSettled(
|
|
899
948
|
batch.map(async (ev) => {
|
|
900
949
|
try {
|
|
901
950
|
const body = { name: ev.name };
|
|
@@ -917,6 +966,14 @@ function createTelemetryNamespace(config) {
|
|
|
917
966
|
}
|
|
918
967
|
})
|
|
919
968
|
);
|
|
969
|
+
_inflightDrain = work.then(() => {
|
|
970
|
+
_inflightDrain = null;
|
|
971
|
+
});
|
|
972
|
+
await work;
|
|
973
|
+
flushTimer = null;
|
|
974
|
+
if (queue.length > 0) {
|
|
975
|
+
scheduleFlush();
|
|
976
|
+
}
|
|
920
977
|
}
|
|
921
978
|
function scheduleFlush() {
|
|
922
979
|
if (flushTimer) return;
|
|
@@ -979,6 +1036,10 @@ function createTelemetryNamespace(config) {
|
|
|
979
1036
|
if (input.name.length > 128) return;
|
|
980
1037
|
queue.push(input);
|
|
981
1038
|
if (queue.length >= TRACK_MAX_QUEUE) {
|
|
1039
|
+
if (flushTimer) {
|
|
1040
|
+
clearTimeout(flushTimer);
|
|
1041
|
+
flushTimer = null;
|
|
1042
|
+
}
|
|
982
1043
|
void drainQueue();
|
|
983
1044
|
} else {
|
|
984
1045
|
scheduleFlush();
|
|
@@ -993,6 +1054,7 @@ function createTelemetryNamespace(config) {
|
|
|
993
1054
|
clearTimeout(flushTimer);
|
|
994
1055
|
flushTimer = null;
|
|
995
1056
|
}
|
|
1057
|
+
if (_inflightDrain) await _inflightDrain;
|
|
996
1058
|
await drainQueue();
|
|
997
1059
|
},
|
|
998
1060
|
/**
|
|
@@ -1481,6 +1543,31 @@ var LocalStore = class {
|
|
|
1481
1543
|
this.db?.close();
|
|
1482
1544
|
this.db = null;
|
|
1483
1545
|
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Apaga completamente o banco IndexedDB e o recria do zero.
|
|
1548
|
+
*
|
|
1549
|
+
* Ao contrário de `close()` + `open()` (que reabre o banco existente sem
|
|
1550
|
+
* apagar dados), `clearAll()` chama `indexedDB.deleteDatabase(dbName)` e
|
|
1551
|
+
* só então chama `open()` — garantindo que nenhum documento, mutação ou
|
|
1552
|
+
* metadado sobrevive.
|
|
1553
|
+
*
|
|
1554
|
+
* BUG fix: `clearCache()` em `NeetruDbDocumentsImpl` chamava close+open,
|
|
1555
|
+
* que reabre o mesmo banco. `clearAll()` é o método correto.
|
|
1556
|
+
*/
|
|
1557
|
+
async clearAll() {
|
|
1558
|
+
if (this.db !== null) {
|
|
1559
|
+
this.db.close();
|
|
1560
|
+
this.db = null;
|
|
1561
|
+
}
|
|
1562
|
+
await new Promise((resolve, reject) => {
|
|
1563
|
+
const req = indexedDB.deleteDatabase(this.dbName);
|
|
1564
|
+
req.onsuccess = () => resolve();
|
|
1565
|
+
req.onerror = () => reject(req.error);
|
|
1566
|
+
req.onblocked = () => {
|
|
1567
|
+
};
|
|
1568
|
+
});
|
|
1569
|
+
await this.open();
|
|
1570
|
+
}
|
|
1484
1571
|
assertOpen() {
|
|
1485
1572
|
if (this.db === null) {
|
|
1486
1573
|
throw new Error("LocalStore: banco n\xE3o est\xE1 aberto. Chame open() primeiro.");
|
|
@@ -1688,6 +1775,12 @@ var MemoryStore = class {
|
|
|
1688
1775
|
async open() {
|
|
1689
1776
|
}
|
|
1690
1777
|
async close() {
|
|
1778
|
+
}
|
|
1779
|
+
/**
|
|
1780
|
+
* Apaga todos os dados em memória — equivalente ao `indexedDB.deleteDatabase`
|
|
1781
|
+
* que `LocalStore.clearAll()` executa em ambientes com IndexedDB.
|
|
1782
|
+
*/
|
|
1783
|
+
async clearAll() {
|
|
1691
1784
|
this._docs.clear();
|
|
1692
1785
|
this._mutations.clear();
|
|
1693
1786
|
this._meta.clear();
|
|
@@ -2043,7 +2136,60 @@ var MutationQueue = class {
|
|
|
2043
2136
|
}
|
|
2044
2137
|
};
|
|
2045
2138
|
|
|
2139
|
+
// src/db/field-value.ts
|
|
2140
|
+
var NEETRU_SENTINEL_KEY = "__neetru__";
|
|
2141
|
+
function isFieldSentinel(v) {
|
|
2142
|
+
return typeof v === "object" && v !== null && NEETRU_SENTINEL_KEY in v && typeof v[NEETRU_SENTINEL_KEY] === "string";
|
|
2143
|
+
}
|
|
2144
|
+
function isServerTimestampSentinel(v) {
|
|
2145
|
+
return isFieldSentinel(v) && v.__neetru__ === "serverTimestamp";
|
|
2146
|
+
}
|
|
2147
|
+
function isIncrementSentinel(v) {
|
|
2148
|
+
return isFieldSentinel(v) && v.__neetru__ === "increment" && typeof v.operand === "number" && Number.isFinite(v.operand);
|
|
2149
|
+
}
|
|
2150
|
+
function resolveSentinelLocally(value, baseValue) {
|
|
2151
|
+
if (isServerTimestampSentinel(value)) {
|
|
2152
|
+
return Date.now();
|
|
2153
|
+
}
|
|
2154
|
+
if (isIncrementSentinel(value)) {
|
|
2155
|
+
const base = typeof baseValue === "number" && Number.isFinite(baseValue) ? baseValue : 0;
|
|
2156
|
+
return base + value.operand;
|
|
2157
|
+
}
|
|
2158
|
+
return value;
|
|
2159
|
+
}
|
|
2160
|
+
function resolveSentinelsLocally(data, existing) {
|
|
2161
|
+
let touched = false;
|
|
2162
|
+
const out = {};
|
|
2163
|
+
for (const [k, v] of Object.entries(data)) {
|
|
2164
|
+
if (isFieldSentinel(v)) {
|
|
2165
|
+
touched = true;
|
|
2166
|
+
out[k] = resolveSentinelLocally(v, existing?.[k]);
|
|
2167
|
+
} else {
|
|
2168
|
+
out[k] = v;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
return touched ? out : data;
|
|
2172
|
+
}
|
|
2173
|
+
function hasFieldSentinel(data) {
|
|
2174
|
+
for (const v of Object.values(data)) {
|
|
2175
|
+
if (isFieldSentinel(v)) return true;
|
|
2176
|
+
}
|
|
2177
|
+
return false;
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2046
2180
|
// src/db/offline/sync-engine.ts
|
|
2181
|
+
function hasSentinels(payload) {
|
|
2182
|
+
return payload !== null && hasFieldSentinel(payload);
|
|
2183
|
+
}
|
|
2184
|
+
function sanitizeSentinelPayload(payload) {
|
|
2185
|
+
if (payload === null) return null;
|
|
2186
|
+
if (!hasFieldSentinel(payload)) return payload;
|
|
2187
|
+
const out = {};
|
|
2188
|
+
for (const [k, v] of Object.entries(payload)) {
|
|
2189
|
+
if (!isFieldSentinel(v)) out[k] = v;
|
|
2190
|
+
}
|
|
2191
|
+
return out;
|
|
2192
|
+
}
|
|
2047
2193
|
var SyncEngine = class {
|
|
2048
2194
|
_store;
|
|
2049
2195
|
_queue;
|
|
@@ -2149,6 +2295,8 @@ var SyncEngine = class {
|
|
|
2149
2295
|
const phase1Ok = await this._phase1Push();
|
|
2150
2296
|
if (!phase1Ok) {
|
|
2151
2297
|
this._updateState({ status: "idle" });
|
|
2298
|
+
this._refreshPendingWrites().catch(() => {
|
|
2299
|
+
});
|
|
2152
2300
|
this._syncing = false;
|
|
2153
2301
|
return;
|
|
2154
2302
|
}
|
|
@@ -2251,11 +2399,16 @@ var SyncEngine = class {
|
|
|
2251
2399
|
}
|
|
2252
2400
|
return;
|
|
2253
2401
|
}
|
|
2254
|
-
const
|
|
2402
|
+
const literalPayload = sanitizeSentinelPayload(mut.payload);
|
|
2403
|
+
const newData = literalPayload ?? (existing?.data ?? {});
|
|
2255
2404
|
const updatedDoc = {
|
|
2256
2405
|
collection,
|
|
2257
2406
|
id: docId,
|
|
2258
|
-
data: mut.op === "update" ? { ...existing?.data ?? {}, ...newData } :
|
|
2407
|
+
data: mut.op === "update" ? { ...existing?.data ?? {}, ...newData } : (
|
|
2408
|
+
// add/set: se o payload tinha sentinels, o cache otimista (existing.data)
|
|
2409
|
+
// é a fonte de verdade até o pull; senão usa o payload literal.
|
|
2410
|
+
hasSentinels(mut.payload) ? { ...existing?.data ?? {}, ...newData } : newData
|
|
2411
|
+
),
|
|
2259
2412
|
meta: {
|
|
2260
2413
|
serverVersion,
|
|
2261
2414
|
updatedAtServer: serverTimestamp,
|
|
@@ -2530,7 +2683,7 @@ var SyncEngine = class {
|
|
|
2530
2683
|
ownerId: localDoc.meta.ownerId
|
|
2531
2684
|
}
|
|
2532
2685
|
};
|
|
2533
|
-
const pendingMuts = await this._queue.
|
|
2686
|
+
const pendingMuts = await this._queue.listAll();
|
|
2534
2687
|
const docMut = pendingMuts.find(
|
|
2535
2688
|
(m) => m.collection === serverDoc.collection && m.docId === serverDoc.id
|
|
2536
2689
|
);
|
|
@@ -3337,43 +3490,6 @@ var TabCoordinator = class {
|
|
|
3337
3490
|
|
|
3338
3491
|
// src/db/collection-ref.ts
|
|
3339
3492
|
init_db_errors();
|
|
3340
|
-
|
|
3341
|
-
// src/db/field-value.ts
|
|
3342
|
-
var NEETRU_SENTINEL_KEY = "__neetru__";
|
|
3343
|
-
function isFieldSentinel(v) {
|
|
3344
|
-
return typeof v === "object" && v !== null && NEETRU_SENTINEL_KEY in v && typeof v[NEETRU_SENTINEL_KEY] === "string";
|
|
3345
|
-
}
|
|
3346
|
-
function isServerTimestampSentinel(v) {
|
|
3347
|
-
return isFieldSentinel(v) && v.__neetru__ === "serverTimestamp";
|
|
3348
|
-
}
|
|
3349
|
-
function isIncrementSentinel(v) {
|
|
3350
|
-
return isFieldSentinel(v) && v.__neetru__ === "increment" && typeof v.operand === "number" && Number.isFinite(v.operand);
|
|
3351
|
-
}
|
|
3352
|
-
function resolveSentinelLocally(value, baseValue) {
|
|
3353
|
-
if (isServerTimestampSentinel(value)) {
|
|
3354
|
-
return Date.now();
|
|
3355
|
-
}
|
|
3356
|
-
if (isIncrementSentinel(value)) {
|
|
3357
|
-
const base = typeof baseValue === "number" && Number.isFinite(baseValue) ? baseValue : 0;
|
|
3358
|
-
return base + value.operand;
|
|
3359
|
-
}
|
|
3360
|
-
return value;
|
|
3361
|
-
}
|
|
3362
|
-
function resolveSentinelsLocally(data, existing) {
|
|
3363
|
-
let touched = false;
|
|
3364
|
-
const out = {};
|
|
3365
|
-
for (const [k, v] of Object.entries(data)) {
|
|
3366
|
-
if (isFieldSentinel(v)) {
|
|
3367
|
-
touched = true;
|
|
3368
|
-
out[k] = resolveSentinelLocally(v, existing?.[k]);
|
|
3369
|
-
} else {
|
|
3370
|
-
out[k] = v;
|
|
3371
|
-
}
|
|
3372
|
-
}
|
|
3373
|
-
return touched ? out : data;
|
|
3374
|
-
}
|
|
3375
|
-
|
|
3376
|
-
// src/db/collection-ref.ts
|
|
3377
3493
|
function isIndexedDBUnavailable() {
|
|
3378
3494
|
return typeof indexedDB === "undefined" || typeof window === "undefined";
|
|
3379
3495
|
}
|
|
@@ -3921,8 +4037,13 @@ var NeetruDbDocumentsImpl = class {
|
|
|
3921
4037
|
return this._engine.flush();
|
|
3922
4038
|
}
|
|
3923
4039
|
async clearCache() {
|
|
3924
|
-
|
|
3925
|
-
|
|
4040
|
+
const storeWithClear = this._store;
|
|
4041
|
+
if (typeof storeWithClear.clearAll === "function") {
|
|
4042
|
+
await storeWithClear.clearAll();
|
|
4043
|
+
} else {
|
|
4044
|
+
await this._store.close();
|
|
4045
|
+
await this._store.open();
|
|
4046
|
+
}
|
|
3926
4047
|
}
|
|
3927
4048
|
async getConflicts() {
|
|
3928
4049
|
return this._store.listConflicts();
|
|
@@ -4809,7 +4930,8 @@ function createHttpCheckoutNamespace(config) {
|
|
|
4809
4930
|
method: "POST",
|
|
4810
4931
|
path: "/api/v1/checkout/intents",
|
|
4811
4932
|
body,
|
|
4812
|
-
requireAuth: true
|
|
4933
|
+
requireAuth: true,
|
|
4934
|
+
idempotencyKey: true
|
|
4813
4935
|
});
|
|
4814
4936
|
const result = parseStartResponse(raw);
|
|
4815
4937
|
const shouldRedirect = input.autoRedirect !== false;
|
|
@@ -5564,6 +5686,7 @@ function createOidcAuthNamespace(config) {
|
|
|
5564
5686
|
const STORAGE_KEY = "neetru_id_token";
|
|
5565
5687
|
const listeners = /* @__PURE__ */ new Set();
|
|
5566
5688
|
let cachedUser = null;
|
|
5689
|
+
let _expiryTimerId = null;
|
|
5567
5690
|
function getStorage() {
|
|
5568
5691
|
try {
|
|
5569
5692
|
return typeof globalThis.localStorage !== "undefined" ? globalThis.localStorage : null;
|
|
@@ -5586,6 +5709,9 @@ function createOidcAuthNamespace(config) {
|
|
|
5586
5709
|
function tokenToUser(token) {
|
|
5587
5710
|
const payload = decodeJwtPayload(token);
|
|
5588
5711
|
if (!payload || typeof payload.sub !== "string") return null;
|
|
5712
|
+
if (typeof payload.exp === "number" && payload.exp * 1e3 < Date.now()) {
|
|
5713
|
+
return null;
|
|
5714
|
+
}
|
|
5589
5715
|
return {
|
|
5590
5716
|
uid: payload.sub,
|
|
5591
5717
|
email: typeof payload.email === "string" ? payload.email : "",
|
|
@@ -5599,12 +5725,28 @@ function createOidcAuthNamespace(config) {
|
|
|
5599
5725
|
};
|
|
5600
5726
|
}
|
|
5601
5727
|
function loadCachedUser() {
|
|
5602
|
-
if (cachedUser)
|
|
5728
|
+
if (cachedUser) {
|
|
5729
|
+
const exp = cachedUser.exp;
|
|
5730
|
+
if (typeof exp === "number" && exp * 1e3 < Date.now()) {
|
|
5731
|
+
cachedUser = null;
|
|
5732
|
+
const storage2 = getStorage();
|
|
5733
|
+
storage2?.removeItem(STORAGE_KEY);
|
|
5734
|
+
notify();
|
|
5735
|
+
return null;
|
|
5736
|
+
}
|
|
5737
|
+
return cachedUser;
|
|
5738
|
+
}
|
|
5603
5739
|
const storage = getStorage();
|
|
5604
5740
|
if (!storage) return null;
|
|
5605
5741
|
const token = storage.getItem(STORAGE_KEY);
|
|
5606
5742
|
if (!token) return null;
|
|
5607
|
-
|
|
5743
|
+
const user = tokenToUser(token);
|
|
5744
|
+
if (!user) {
|
|
5745
|
+
storage.removeItem(STORAGE_KEY);
|
|
5746
|
+
return null;
|
|
5747
|
+
}
|
|
5748
|
+
cachedUser = user;
|
|
5749
|
+
scheduleExpiryTimer(user);
|
|
5608
5750
|
return cachedUser;
|
|
5609
5751
|
}
|
|
5610
5752
|
function notify() {
|
|
@@ -5615,6 +5757,23 @@ function createOidcAuthNamespace(config) {
|
|
|
5615
5757
|
}
|
|
5616
5758
|
}
|
|
5617
5759
|
}
|
|
5760
|
+
function cancelExpiryTimer() {
|
|
5761
|
+
if (_expiryTimerId !== null) {
|
|
5762
|
+
clearTimeout(_expiryTimerId);
|
|
5763
|
+
_expiryTimerId = null;
|
|
5764
|
+
}
|
|
5765
|
+
}
|
|
5766
|
+
function scheduleExpiryTimer(user) {
|
|
5767
|
+
cancelExpiryTimer();
|
|
5768
|
+
const exp = user.exp;
|
|
5769
|
+
if (typeof exp !== "number") return;
|
|
5770
|
+
const msUntilExpiry = exp * 1e3 - Date.now();
|
|
5771
|
+
if (msUntilExpiry <= 0) return;
|
|
5772
|
+
_expiryTimerId = setTimeout(() => {
|
|
5773
|
+
_expiryTimerId = null;
|
|
5774
|
+
loadCachedUser();
|
|
5775
|
+
}, msUntilExpiry + 1);
|
|
5776
|
+
}
|
|
5618
5777
|
return {
|
|
5619
5778
|
async signIn(options) {
|
|
5620
5779
|
if (typeof globalThis.location !== "undefined" && typeof globalThis.location.assign === "function") {
|
|
@@ -5642,18 +5801,24 @@ function createOidcAuthNamespace(config) {
|
|
|
5642
5801
|
},
|
|
5643
5802
|
async signOut() {
|
|
5644
5803
|
const storage = getStorage();
|
|
5804
|
+
const storedToken = storage?.getItem(STORAGE_KEY) ?? null;
|
|
5645
5805
|
if (storage) storage.removeItem(STORAGE_KEY);
|
|
5806
|
+
cancelExpiryTimer();
|
|
5646
5807
|
cachedUser = null;
|
|
5647
5808
|
const overrideAuthUrl = typeof globalThis.NEETRU_AUTH_URL === "string" ? globalThis.NEETRU_AUTH_URL : null;
|
|
5648
5809
|
const idpOrigin = overrideAuthUrl ?? config.baseUrl.replace(/^https?:\/\/api\./, "https://auth.");
|
|
5649
5810
|
const revokeUrl = `${idpOrigin}/api/v1/oauth/revoke`;
|
|
5811
|
+
const revokeBody = storedToken ? JSON.stringify({ token: storedToken }) : null;
|
|
5650
5812
|
let revokeError = null;
|
|
5651
5813
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
5652
5814
|
try {
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5815
|
+
if (revokeBody) {
|
|
5816
|
+
await config.fetch(revokeUrl, {
|
|
5817
|
+
method: "POST",
|
|
5818
|
+
headers: { "content-type": "application/json" },
|
|
5819
|
+
body: revokeBody
|
|
5820
|
+
});
|
|
5821
|
+
}
|
|
5657
5822
|
revokeError = null;
|
|
5658
5823
|
break;
|
|
5659
5824
|
} catch (err) {
|