@katlux/providers 0.1.1-alpha.105 → 0.1.1-alpha.106
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/index.cjs +482 -124
- package/dist/index.d.cts +136 -7
- package/dist/index.d.mts +136 -7
- package/dist/index.d.ts +136 -7
- package/dist/index.mjs +473 -125
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -304,6 +304,18 @@ class ADataProvider {
|
|
|
304
304
|
set sortList(s) {
|
|
305
305
|
this.setSortList(s);
|
|
306
306
|
}
|
|
307
|
+
get hasMore() {
|
|
308
|
+
if (this._rowCount <= 0) return false;
|
|
309
|
+
return this._currentPage * this._pageSize < this._rowCount;
|
|
310
|
+
}
|
|
311
|
+
async nextPage() {
|
|
312
|
+
if (this.hasMore && !this._loading) {
|
|
313
|
+
await this.setCurrentPage(this._currentPage + 1);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async loadMore() {
|
|
317
|
+
await this.nextPage();
|
|
318
|
+
}
|
|
307
319
|
_listeners = /* @__PURE__ */ new Set();
|
|
308
320
|
_stateListeners = /* @__PURE__ */ new Set();
|
|
309
321
|
_pendingChangedKeys = /* @__PURE__ */ new Set();
|
|
@@ -584,11 +596,13 @@ class ADataProvider {
|
|
|
584
596
|
}
|
|
585
597
|
this.notify();
|
|
586
598
|
}
|
|
587
|
-
setPageSize(pageSize) {
|
|
599
|
+
setPageSize(pageSize, resetPage = true) {
|
|
588
600
|
this._pageSize = pageSize;
|
|
589
|
-
|
|
601
|
+
if (resetPage) {
|
|
602
|
+
this._currentPage = 1;
|
|
603
|
+
this._pendingChangedKeys.add("currentPage");
|
|
604
|
+
}
|
|
590
605
|
this._pendingChangedKeys.add("pageSize");
|
|
591
|
-
this._pendingChangedKeys.add("currentPage");
|
|
592
606
|
this.loadPageData();
|
|
593
607
|
this.notify();
|
|
594
608
|
}
|
|
@@ -2024,9 +2038,6 @@ class RequestQueue {
|
|
|
2024
2038
|
Object.assign(headers, existingHeaders);
|
|
2025
2039
|
}
|
|
2026
2040
|
}
|
|
2027
|
-
if (typeof document !== "undefined" && document.cookie && !headers["cookie"] && !headers["Cookie"]) {
|
|
2028
|
-
headers["cookie"] = document.cookie;
|
|
2029
|
-
}
|
|
2030
2041
|
if (this._headerProvider) {
|
|
2031
2042
|
try {
|
|
2032
2043
|
const dynamicHeaders = await this._headerProvider();
|
|
@@ -2037,6 +2048,9 @@ class RequestQueue {
|
|
|
2037
2048
|
console.error("[RequestQueue] Header provider failed:", err);
|
|
2038
2049
|
}
|
|
2039
2050
|
}
|
|
2051
|
+
if (typeof document !== "undefined" && document.cookie && !headers["cookie"] && !headers["Cookie"]) {
|
|
2052
|
+
headers["cookie"] = document.cookie;
|
|
2053
|
+
}
|
|
2040
2054
|
return headers;
|
|
2041
2055
|
}
|
|
2042
2056
|
static async executeRequest(item) {
|
|
@@ -2060,6 +2074,8 @@ class RequestQueue {
|
|
|
2060
2074
|
};
|
|
2061
2075
|
this.queue = this.queue.filter((i) => i.id !== item.id);
|
|
2062
2076
|
if (this.deadLetterQueue.length >= this.MAX_DEAD_LETTER_SIZE) {
|
|
2077
|
+
const evicted = this.deadLetterQueue[0];
|
|
2078
|
+
console.warn(`[RequestQueue] Dead-letter queue reached capacity (${this.MAX_DEAD_LETTER_SIZE}). Evicting oldest item: ${evicted?.id}`);
|
|
2063
2079
|
this.deadLetterQueue = this.deadLetterQueue.slice(1);
|
|
2064
2080
|
}
|
|
2065
2081
|
this.deadLetterQueue = [...this.deadLetterQueue, deadItem];
|
|
@@ -2143,24 +2159,39 @@ function toBase64(buffer) {
|
|
|
2143
2159
|
}
|
|
2144
2160
|
let objKeyCounter = 0;
|
|
2145
2161
|
const objKeyMap = /* @__PURE__ */ new WeakMap();
|
|
2146
|
-
function
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2162
|
+
function fastKeyHash(str) {
|
|
2163
|
+
let h1 = 3735928559 ^ 0;
|
|
2164
|
+
let h2 = 1103547991 ^ 0;
|
|
2165
|
+
for (let i = 0; i < str.length; i++) {
|
|
2166
|
+
const ch = str.charCodeAt(i);
|
|
2167
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
2168
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
2169
|
+
}
|
|
2170
|
+
h1 = Math.imul(h1 ^ h1 >>> 16, 2246822507) ^ Math.imul(h2 ^ h2 >>> 13, 3266489909);
|
|
2171
|
+
h2 = Math.imul(h2 ^ h2 >>> 16, 2246822507) ^ Math.imul(h1 ^ h1 >>> 13, 3266489909);
|
|
2172
|
+
return (4294967296 * (2097151 & h2) + (h1 >>> 0)).toString(16);
|
|
2173
|
+
}
|
|
2174
|
+
function getSafeKeyIdentifier(rawKey) {
|
|
2175
|
+
if (typeof rawKey === "string") {
|
|
2176
|
+
return `h_${fastKeyHash(rawKey)}`;
|
|
2150
2177
|
}
|
|
2151
|
-
if (
|
|
2152
|
-
return toBase64(
|
|
2178
|
+
if (rawKey instanceof Uint8Array || rawKey instanceof ArrayBuffer) {
|
|
2179
|
+
return `b_${fastKeyHash(toBase64(rawKey))}`;
|
|
2153
2180
|
}
|
|
2154
|
-
if (typeof
|
|
2155
|
-
let id = objKeyMap.get(
|
|
2181
|
+
if ((typeof rawKey === "object" || typeof rawKey === "function") && rawKey !== null) {
|
|
2182
|
+
let id = objKeyMap.get(rawKey);
|
|
2156
2183
|
if (!id) {
|
|
2157
|
-
id = `
|
|
2158
|
-
objKeyMap.set(
|
|
2184
|
+
id = `__key_${++objKeyCounter}__`;
|
|
2185
|
+
objKeyMap.set(rawKey, id);
|
|
2159
2186
|
}
|
|
2160
2187
|
return id;
|
|
2161
2188
|
}
|
|
2162
2189
|
return "__default__";
|
|
2163
2190
|
}
|
|
2191
|
+
function getKeyIdentifier(keyProvider, defaultKey) {
|
|
2192
|
+
const target = keyProvider ?? defaultKey;
|
|
2193
|
+
return getSafeKeyIdentifier(target);
|
|
2194
|
+
}
|
|
2164
2195
|
|
|
2165
2196
|
class AEncryptionProvider {
|
|
2166
2197
|
defaultKey;
|
|
@@ -2412,6 +2443,11 @@ class CKeyManager {
|
|
|
2412
2443
|
// ── Symmetric Key Management ─────────────────────────────────────────────
|
|
2413
2444
|
/**
|
|
2414
2445
|
* Generates a random AES CryptoKey suitable for AES-GCM or AES-CBC.
|
|
2446
|
+
*
|
|
2447
|
+
* E2EE Threat Model Note: Focuses on protecting GDPR/tenant data against database and
|
|
2448
|
+
* server-side leaks. Keys remain extractable by default to enable role-based key sharing,
|
|
2449
|
+
* wrapping, and transfer between authorized client sessions in multi-user SaaS apps.
|
|
2450
|
+
* Client-side malware/trojan protection is out of scope.
|
|
2415
2451
|
*/
|
|
2416
2452
|
static async generateAESKey(length = 256, algorithm = "AES-GCM", extractable = true) {
|
|
2417
2453
|
const subtle = getSubtleCrypto();
|
|
@@ -2871,6 +2907,8 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2871
2907
|
_cachedKdf;
|
|
2872
2908
|
_cachedIter;
|
|
2873
2909
|
_cachedHash;
|
|
2910
|
+
_cachedKeyId;
|
|
2911
|
+
_configuredKid;
|
|
2874
2912
|
_decryptSaltCache = /* @__PURE__ */ new Map();
|
|
2875
2913
|
setDefaultKey(key) {
|
|
2876
2914
|
super.setDefaultKey(key);
|
|
@@ -2879,6 +2917,7 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2879
2917
|
this._cachedKdf = void 0;
|
|
2880
2918
|
this._cachedIter = void 0;
|
|
2881
2919
|
this._cachedHash = void 0;
|
|
2920
|
+
this._cachedKeyId = void 0;
|
|
2882
2921
|
this._decryptSaltCache.clear();
|
|
2883
2922
|
}
|
|
2884
2923
|
clearKeys() {
|
|
@@ -2888,11 +2927,15 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2888
2927
|
this._cachedKdf = void 0;
|
|
2889
2928
|
this._cachedIter = void 0;
|
|
2890
2929
|
this._cachedHash = void 0;
|
|
2930
|
+
this._cachedKeyId = void 0;
|
|
2891
2931
|
this._decryptSaltCache.clear();
|
|
2892
2932
|
}
|
|
2893
2933
|
constructor(key, options) {
|
|
2894
2934
|
super(key);
|
|
2895
2935
|
if (options) {
|
|
2936
|
+
if (options.kid || options.keyId) {
|
|
2937
|
+
this._configuredKid = options.kid || options.keyId;
|
|
2938
|
+
}
|
|
2896
2939
|
this._defaultKdf = options.kdf || "pbkdf2";
|
|
2897
2940
|
if (options.kdf && options.kdf !== "none") {
|
|
2898
2941
|
this._kdfOptions = {
|
|
@@ -2909,6 +2952,9 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2909
2952
|
* Derives or returns a CryptoKey for encryption/decryption based on KDF settings.
|
|
2910
2953
|
*/
|
|
2911
2954
|
async resolveCryptoKey(keyProvider, kdfOverride, saltOverride, options, iterationsOverride) {
|
|
2955
|
+
if (options?._warmedKey) {
|
|
2956
|
+
return options._warmedKey;
|
|
2957
|
+
}
|
|
2912
2958
|
if (saltOverride) {
|
|
2913
2959
|
const saltKey = typeof saltOverride === "string" ? saltOverride : CKeyManager.toBase64(saltOverride);
|
|
2914
2960
|
const keyId = getKeyIdentifier(keyProvider, this.defaultKey);
|
|
@@ -2972,13 +3018,16 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2972
3018
|
const matchesHash = !targetHash || this._cachedHash !== void 0 && targetHash.toLowerCase() === this._cachedHash.toLowerCase();
|
|
2973
3019
|
const matchesKdf = this._cachedKdf !== void 0 && kdf === this._cachedKdf.toLowerCase();
|
|
2974
3020
|
const matchesSalt = !saltOverride || this._cachedSalt !== void 0 && saltOverride === this._cachedSalt;
|
|
2975
|
-
|
|
2976
|
-
|
|
3021
|
+
const currentKeyId = getKeyIdentifier(keyProvider, this.defaultKey);
|
|
3022
|
+
if (this._cachedKey && matchesSalt && !options?.kdfSalt && matchesKdf && matchesIter && matchesHash) {
|
|
3023
|
+
if (!this._cachedKeyId || this._cachedKeyId === currentKeyId) {
|
|
3024
|
+
return { cryptoKey: this._cachedKey, salt: this._cachedSalt, kdf: this._cachedKdf, iter: this._cachedIter };
|
|
3025
|
+
}
|
|
2977
3026
|
}
|
|
2978
3027
|
if (kdf === "pbkdf2") {
|
|
2979
3028
|
const salt = saltOverride || options?.kdfSalt || this._kdfOptions?.salt;
|
|
2980
3029
|
const rawIterations = iterationsOverride || options?.kdfIterations || this._kdfOptions?.iterations || 31e4;
|
|
2981
|
-
const iterations = Math.min(Math.max(rawIterations, 1e3),
|
|
3030
|
+
const iterations = Math.min(Math.max(rawIterations, 1e3), 6e5);
|
|
2982
3031
|
const hash = options?.kdfHash || this._kdfOptions?.hash || "SHA-256";
|
|
2983
3032
|
const derived = await CKeyManager.deriveKey(passphrase, {
|
|
2984
3033
|
kdf: "pbkdf2",
|
|
@@ -2986,16 +3035,22 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
2986
3035
|
iterations,
|
|
2987
3036
|
hash
|
|
2988
3037
|
});
|
|
2989
|
-
if (!
|
|
3038
|
+
if (!saltOverride && !options?.kdfSalt) {
|
|
2990
3039
|
this._cachedKey = derived.key;
|
|
2991
3040
|
this._cachedSalt = derived.salt;
|
|
2992
3041
|
this._cachedKdf = "PBKDF2";
|
|
2993
3042
|
this._cachedIter = iterations;
|
|
2994
3043
|
this._cachedHash = hash;
|
|
3044
|
+
this._cachedKeyId = currentKeyId;
|
|
2995
3045
|
}
|
|
2996
3046
|
return { cryptoKey: derived.key, salt: derived.salt, kdf: "PBKDF2", iter: iterations };
|
|
2997
3047
|
}
|
|
2998
3048
|
if (kdf === "hkdf") {
|
|
3049
|
+
if (typeof rawKey === "string") {
|
|
3050
|
+
console.warn(
|
|
3051
|
+
'[CWebCryptoEncryptionProvider] ADVISORY: HKDF is designed for high-entropy input key material (IKM), not low-entropy human passphrases. Use "pbkdf2" for password-derived encryption.'
|
|
3052
|
+
);
|
|
3053
|
+
}
|
|
2999
3054
|
const salt = saltOverride || options?.kdfSalt || this._kdfOptions?.salt;
|
|
3000
3055
|
const hash = options?.kdfHash || this._kdfOptions?.hash || "SHA-256";
|
|
3001
3056
|
const info = options?.info || this._kdfOptions?.info;
|
|
@@ -3005,18 +3060,21 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
3005
3060
|
hash,
|
|
3006
3061
|
info
|
|
3007
3062
|
});
|
|
3008
|
-
if (!
|
|
3063
|
+
if (!saltOverride && !options?.kdfSalt) {
|
|
3009
3064
|
this._cachedKey = derived.key;
|
|
3010
3065
|
this._cachedSalt = derived.salt;
|
|
3011
3066
|
this._cachedKdf = "HKDF";
|
|
3012
3067
|
this._cachedHash = hash;
|
|
3068
|
+
this._cachedKeyId = currentKeyId;
|
|
3013
3069
|
}
|
|
3014
3070
|
return { cryptoKey: derived.key, salt: derived.salt, kdf: "HKDF" };
|
|
3015
3071
|
}
|
|
3016
3072
|
if (kdf === "none") {
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3073
|
+
if (saltOverride) {
|
|
3074
|
+
console.warn(
|
|
3075
|
+
"[CWebCryptoEncryptionProvider] WARNING: Decrypting a legacy envelope with no KDF (raw SHA-256 key derivation). This is cryptographically weak. Migrate to pbkdf2 or hkdf."
|
|
3076
|
+
);
|
|
3077
|
+
}
|
|
3020
3078
|
}
|
|
3021
3079
|
if (!keyProvider && this._cachedKey && this._cachedKdf === "none") {
|
|
3022
3080
|
return { cryptoKey: this._cachedKey, kdf: "none" };
|
|
@@ -3056,12 +3114,14 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
3056
3114
|
}
|
|
3057
3115
|
async warmupKey(options) {
|
|
3058
3116
|
const res = await this.resolveCryptoKey(options?.key, void 0, void 0, options);
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3117
|
+
this._cachedKey = res.cryptoKey;
|
|
3118
|
+
this._cachedSalt = res.salt;
|
|
3119
|
+
this._cachedKdf = res.kdf;
|
|
3120
|
+
this._cachedIter = res.iter;
|
|
3121
|
+
this._cachedHash = options?.kdfHash || this._kdfOptions?.hash || "SHA-256";
|
|
3122
|
+
this._cachedKeyId = getKeyIdentifier(options?.key, this.defaultKey);
|
|
3123
|
+
if (options) {
|
|
3124
|
+
options._warmedKey = res;
|
|
3065
3125
|
}
|
|
3066
3126
|
}
|
|
3067
3127
|
/**
|
|
@@ -3077,11 +3137,25 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
3077
3137
|
const subtle = getSubtleCrypto();
|
|
3078
3138
|
const jsonString = JSON.stringify(data);
|
|
3079
3139
|
const iv = CKeyManager.randomBytes(12);
|
|
3140
|
+
const encryptParams = {
|
|
3141
|
+
name: "AES-GCM",
|
|
3142
|
+
iv
|
|
3143
|
+
};
|
|
3144
|
+
const aad = options?.aad;
|
|
3145
|
+
let hasAad = false;
|
|
3146
|
+
if (aad) {
|
|
3147
|
+
const aadBytes = typeof aad === "string" ? textEncoder.encode(aad) : aad instanceof Uint8Array ? aad : new Uint8Array(aad);
|
|
3148
|
+
if (aadBytes.byteLength > 0) {
|
|
3149
|
+
encryptParams.additionalData = aadBytes;
|
|
3150
|
+
hasAad = true;
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3080
3153
|
const ciphertextBuffer = await subtle.encrypt(
|
|
3081
|
-
|
|
3154
|
+
encryptParams,
|
|
3082
3155
|
cryptoKey,
|
|
3083
3156
|
textEncoder.encode(jsonString)
|
|
3084
3157
|
);
|
|
3158
|
+
const kid = options?.kid || options?.keyId || this._configuredKid;
|
|
3085
3159
|
return {
|
|
3086
3160
|
__encrypted: true,
|
|
3087
3161
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
@@ -3089,7 +3163,9 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
3089
3163
|
alg: "AES-GCM",
|
|
3090
3164
|
...salt ? { salt } : {},
|
|
3091
3165
|
...kdf && kdf !== "none" && kdf !== "raw" && kdf !== "direct" ? { kdf } : {},
|
|
3092
|
-
...iter ? { iter } : {}
|
|
3166
|
+
...iter ? { iter } : {},
|
|
3167
|
+
...kid ? { kid } : {},
|
|
3168
|
+
...hasAad ? { aad: true } : {}
|
|
3093
3169
|
};
|
|
3094
3170
|
}
|
|
3095
3171
|
/**
|
|
@@ -3115,13 +3191,31 @@ class CWebCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
3115
3191
|
let ciphertextBytes = CKeyManager.fromBase64(payload.ciphertext);
|
|
3116
3192
|
if (payload.tag) {
|
|
3117
3193
|
const tagBytes = CKeyManager.fromBase64(payload.tag);
|
|
3194
|
+
if (tagBytes.length !== 16) {
|
|
3195
|
+
throw new Error("[CWebCryptoEncryptionProvider] Authentication tag must be exactly 16 bytes for AES-256-GCM");
|
|
3196
|
+
}
|
|
3118
3197
|
const combined = new Uint8Array(ciphertextBytes.length + tagBytes.length);
|
|
3119
3198
|
combined.set(ciphertextBytes, 0);
|
|
3120
3199
|
combined.set(tagBytes, ciphertextBytes.length);
|
|
3121
3200
|
ciphertextBytes = combined;
|
|
3122
3201
|
}
|
|
3202
|
+
const decryptParams = {
|
|
3203
|
+
name: "AES-GCM",
|
|
3204
|
+
iv
|
|
3205
|
+
};
|
|
3206
|
+
const aad = options?.aad;
|
|
3207
|
+
if (payload.aad || aad) {
|
|
3208
|
+
if (aad) {
|
|
3209
|
+
const aadBytes = typeof aad === "string" ? textEncoder.encode(aad) : aad instanceof Uint8Array ? aad : new Uint8Array(aad);
|
|
3210
|
+
if (aadBytes.byteLength > 0) {
|
|
3211
|
+
decryptParams.additionalData = aadBytes;
|
|
3212
|
+
}
|
|
3213
|
+
} else if (payload.aad) {
|
|
3214
|
+
throw new Error("[CWebCryptoEncryptionProvider] Payload requires Authenticated Additional Data (AAD) for decryption, but none was provided.");
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3123
3217
|
const decryptedBuffer = await subtle.decrypt(
|
|
3124
|
-
|
|
3218
|
+
decryptParams,
|
|
3125
3219
|
cryptoKey,
|
|
3126
3220
|
ciphertextBytes
|
|
3127
3221
|
);
|
|
@@ -3146,11 +3240,15 @@ class CWebCryptoAESCBCProvider extends AEncryptionProvider {
|
|
|
3146
3240
|
_cachedKdf;
|
|
3147
3241
|
_cachedIter;
|
|
3148
3242
|
_cachedHash;
|
|
3243
|
+
_configuredKid;
|
|
3149
3244
|
_kdfOptions;
|
|
3150
3245
|
_decryptSaltCache = /* @__PURE__ */ new Map();
|
|
3151
3246
|
constructor(key, options) {
|
|
3152
3247
|
super(key);
|
|
3153
3248
|
if (options) {
|
|
3249
|
+
if (options.kid || options.keyId) {
|
|
3250
|
+
this._configuredKid = options.kid || options.keyId;
|
|
3251
|
+
}
|
|
3154
3252
|
this._defaultKdf = options.kdf || "pbkdf2";
|
|
3155
3253
|
if (options.kdf && options.kdf !== "none") {
|
|
3156
3254
|
this._kdfOptions = {
|
|
@@ -3341,6 +3439,11 @@ class CWebCryptoAESCBCProvider extends AEncryptionProvider {
|
|
|
3341
3439
|
}
|
|
3342
3440
|
const passphraseBytes = textEncoder.encode(rawKey);
|
|
3343
3441
|
const kdf = (kdfOverride || options?.kdf || this._defaultKdf || "none").toLowerCase();
|
|
3442
|
+
if (kdf === "hkdf" && typeof rawKey === "string") {
|
|
3443
|
+
console.warn(
|
|
3444
|
+
'[CWebCryptoAESCBCProvider] ADVISORY: HKDF is designed for high-entropy input key material (IKM), not low-entropy human passphrases. Use "pbkdf2" for password-derived encryption.'
|
|
3445
|
+
);
|
|
3446
|
+
}
|
|
3344
3447
|
let raw512;
|
|
3345
3448
|
let saltStr;
|
|
3346
3449
|
let kdfType;
|
|
@@ -3352,7 +3455,7 @@ class CWebCryptoAESCBCProvider extends AEncryptionProvider {
|
|
|
3352
3455
|
saltStr = CKeyManager.toBase64(saltBytes);
|
|
3353
3456
|
kdfType = "PBKDF2";
|
|
3354
3457
|
const rawIter = iterationsOverride || options?.kdfIterations || this._kdfOptions?.iterations || 31e4;
|
|
3355
|
-
const iterations = Math.min(Math.max(rawIter, 1e3),
|
|
3458
|
+
const iterations = Math.min(Math.max(rawIter, 1e3), 6e5);
|
|
3356
3459
|
iterNum = iterations;
|
|
3357
3460
|
const baseKey = await subtle.importKey(
|
|
3358
3461
|
"raw",
|
|
@@ -3473,6 +3576,7 @@ class CWebCryptoAESCBCProvider extends AEncryptionProvider {
|
|
|
3473
3576
|
macPayload.set(iv, 0);
|
|
3474
3577
|
macPayload.set(ciphertextBytes, iv.length);
|
|
3475
3578
|
const tagBuffer = await subtle.sign("HMAC", macKey, macPayload);
|
|
3579
|
+
const kid = options?.kid || options?.keyId || this._configuredKid;
|
|
3476
3580
|
return {
|
|
3477
3581
|
__encrypted: true,
|
|
3478
3582
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
@@ -3481,7 +3585,8 @@ class CWebCryptoAESCBCProvider extends AEncryptionProvider {
|
|
|
3481
3585
|
alg: "AES-CBC-256+HMAC-SHA-256",
|
|
3482
3586
|
...salt ? { salt } : {},
|
|
3483
3587
|
...kdf && kdf !== "none" && kdf !== "raw" && kdf !== "hkdf-direct" ? { kdf } : {},
|
|
3484
|
-
...iter ? { iter } : {}
|
|
3588
|
+
...iter ? { iter } : {},
|
|
3589
|
+
...kid ? { kid } : {}
|
|
3485
3590
|
};
|
|
3486
3591
|
}
|
|
3487
3592
|
/**
|
|
@@ -3671,12 +3776,14 @@ class CRSAEncryptionProvider extends AEncryptionProvider {
|
|
|
3671
3776
|
new Uint8Array(rawKeyBuffer).fill(0);
|
|
3672
3777
|
}
|
|
3673
3778
|
const modulusLength = pubKey.algorithm?.modulusLength || 4096;
|
|
3779
|
+
const kid = options?.kid || options?.keyId;
|
|
3674
3780
|
return {
|
|
3675
3781
|
__encrypted: true,
|
|
3676
3782
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
3677
3783
|
iv: CKeyManager.toBase64(iv),
|
|
3678
3784
|
wrappedKey: CKeyManager.toBase64(wrappedKeyBuffer),
|
|
3679
|
-
alg: `RSA-OAEP-${modulusLength}+AES-GCM-256
|
|
3785
|
+
alg: `RSA-OAEP-${modulusLength}+AES-GCM-256`,
|
|
3786
|
+
...kid ? { kid } : {}
|
|
3680
3787
|
};
|
|
3681
3788
|
}
|
|
3682
3789
|
/**
|
|
@@ -3785,13 +3892,15 @@ class CRSAEncryptionProvider extends AEncryptionProvider {
|
|
|
3785
3892
|
dataKey,
|
|
3786
3893
|
textEncoder.encode(jsonString)
|
|
3787
3894
|
);
|
|
3895
|
+
const kid = options?.kid || options?.keyId;
|
|
3788
3896
|
const fieldPayload = {
|
|
3789
3897
|
__encrypted: true,
|
|
3790
3898
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
3791
3899
|
iv: CKeyManager.toBase64(iv),
|
|
3792
3900
|
wrappedKey: wrappedKeyBase64,
|
|
3793
3901
|
sharedKey: true,
|
|
3794
|
-
alg
|
|
3902
|
+
alg,
|
|
3903
|
+
...kid ? { kid } : {}
|
|
3795
3904
|
};
|
|
3796
3905
|
safeSetProperty(result, field, fieldPayload);
|
|
3797
3906
|
}
|
|
@@ -4067,13 +4176,15 @@ class CECDHEncryptionProvider extends AEncryptionProvider {
|
|
|
4067
4176
|
textEncoder.encode(jsonString)
|
|
4068
4177
|
);
|
|
4069
4178
|
const epkJwk = await subtle.exportKey("jwk", ephemeralPair.publicKey);
|
|
4179
|
+
const kid = options?.kid || options?.keyId;
|
|
4070
4180
|
return {
|
|
4071
4181
|
__encrypted: true,
|
|
4072
4182
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
4073
4183
|
iv: CKeyManager.toBase64(iv),
|
|
4074
4184
|
epk: epkJwk,
|
|
4075
4185
|
salt: CKeyManager.toBase64(saltBytes),
|
|
4076
|
-
alg: `ECDH-${curve}+AES-GCM-256
|
|
4186
|
+
alg: `ECDH-${curve}+AES-GCM-256`,
|
|
4187
|
+
...kid ? { kid } : {}
|
|
4077
4188
|
};
|
|
4078
4189
|
}
|
|
4079
4190
|
/**
|
|
@@ -4140,13 +4251,15 @@ class CECDHEncryptionProvider extends AEncryptionProvider {
|
|
|
4140
4251
|
dataKey,
|
|
4141
4252
|
textEncoder.encode(jsonString)
|
|
4142
4253
|
);
|
|
4254
|
+
const kid = options?.kid || options?.keyId;
|
|
4143
4255
|
safeSetProperty(result, field, {
|
|
4144
4256
|
__encrypted: true,
|
|
4145
4257
|
ciphertext: CKeyManager.toBase64(ciphertextBuffer),
|
|
4146
4258
|
iv: CKeyManager.toBase64(iv),
|
|
4147
4259
|
epk: epkJwk,
|
|
4148
4260
|
salt: saltBase64,
|
|
4149
|
-
alg
|
|
4261
|
+
alg,
|
|
4262
|
+
...kid ? { kid } : {}
|
|
4150
4263
|
});
|
|
4151
4264
|
}
|
|
4152
4265
|
return result;
|
|
@@ -4324,6 +4437,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4324
4437
|
_cachedKdf;
|
|
4325
4438
|
_cachedIter;
|
|
4326
4439
|
_cachedHash;
|
|
4440
|
+
_configuredKid;
|
|
4327
4441
|
setDefaultKey(key) {
|
|
4328
4442
|
super.setDefaultKey(key);
|
|
4329
4443
|
if (this._cachedKey) {
|
|
@@ -4379,6 +4493,9 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4379
4493
|
constructor(key, options) {
|
|
4380
4494
|
super(key);
|
|
4381
4495
|
if (options) {
|
|
4496
|
+
if (options.kid || options.keyId) {
|
|
4497
|
+
this._configuredKid = options.kid || options.keyId;
|
|
4498
|
+
}
|
|
4382
4499
|
this._defaultKdf = options.kdf || "pbkdf2";
|
|
4383
4500
|
if (options.kdf && options.kdf !== "none") {
|
|
4384
4501
|
this._kdfOptions = {
|
|
@@ -4481,7 +4598,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4481
4598
|
const saltBytes = CKeyManager.resolveSalt(s);
|
|
4482
4599
|
const saltBuf = Buffer.from(saltBytes.buffer, saltBytes.byteOffset, saltBytes.byteLength);
|
|
4483
4600
|
const rawIter = iterationsOverride || options?.kdfIterations || this._kdfOptions?.iterations || 31e4;
|
|
4484
|
-
const iterations = Math.min(Math.max(rawIter, 1e3),
|
|
4601
|
+
const iterations = Math.min(Math.max(rawIter, 1e3), 6e5);
|
|
4485
4602
|
const hash = (options?.kdfHash || this._kdfOptions?.hash || "SHA-256").toLowerCase().replace("-", "");
|
|
4486
4603
|
const key2 = crypto__namespace.pbkdf2Sync(passphrase, saltBuf, iterations, 32, hash);
|
|
4487
4604
|
if (!keyProvider && !saltOverride && !options?.kdfSalt) {
|
|
@@ -4499,6 +4616,11 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4499
4616
|
};
|
|
4500
4617
|
}
|
|
4501
4618
|
if (kdf === "hkdf") {
|
|
4619
|
+
if (typeof raw === "string") {
|
|
4620
|
+
console.warn(
|
|
4621
|
+
'[CNodeCryptoEncryptionProvider] ADVISORY: HKDF is designed for high-entropy input key material (IKM), not low-entropy human passphrases. Use "pbkdf2" for password-derived encryption.'
|
|
4622
|
+
);
|
|
4623
|
+
}
|
|
4502
4624
|
const s = saltOverride || options?.kdfSalt || this._kdfOptions?.salt;
|
|
4503
4625
|
const saltBytes = CKeyManager.resolveSalt(s);
|
|
4504
4626
|
const saltBuf = Buffer.from(saltBytes.buffer, saltBytes.byteOffset, saltBytes.byteLength);
|
|
@@ -4565,7 +4687,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4565
4687
|
const saltBytes = CKeyManager.resolveSalt(s);
|
|
4566
4688
|
const saltBuf = Buffer.from(saltBytes.buffer, saltBytes.byteOffset, saltBytes.byteLength);
|
|
4567
4689
|
const rawIter = iterationsOverride || options?.kdfIterations || this._kdfOptions?.iterations || 31e4;
|
|
4568
|
-
const iterations = Math.min(Math.max(rawIter, 1e3),
|
|
4690
|
+
const iterations = Math.min(Math.max(rawIter, 1e3), 6e5);
|
|
4569
4691
|
const hash = (options?.kdfHash || this._kdfOptions?.hash || "SHA-256").toLowerCase().replace("-", "");
|
|
4570
4692
|
const key2 = await new Promise((resolve, reject) => {
|
|
4571
4693
|
crypto__namespace.pbkdf2(passphrase, saltBuf, iterations, 32, hash, (err, derived) => {
|
|
@@ -4588,6 +4710,11 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4588
4710
|
};
|
|
4589
4711
|
}
|
|
4590
4712
|
if (kdf === "hkdf") {
|
|
4713
|
+
if (typeof raw === "string") {
|
|
4714
|
+
console.warn(
|
|
4715
|
+
'[CNodeCryptoEncryptionProvider] ADVISORY: HKDF is designed for high-entropy input key material (IKM), not low-entropy human passphrases. Use "pbkdf2" for password-derived encryption.'
|
|
4716
|
+
);
|
|
4717
|
+
}
|
|
4591
4718
|
const s = saltOverride || options?.kdfSalt || this._kdfOptions?.salt;
|
|
4592
4719
|
const saltBytes = CKeyManager.resolveSalt(s);
|
|
4593
4720
|
const saltBuf = Buffer.from(saltBytes.buffer, saltBytes.byteOffset, saltBytes.byteLength);
|
|
@@ -4649,12 +4776,22 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4649
4776
|
const jsonString = JSON.stringify(data);
|
|
4650
4777
|
const iv = crypto__namespace.randomBytes(12);
|
|
4651
4778
|
const cipher = crypto__namespace.createCipheriv("aes-256-gcm", key, iv);
|
|
4779
|
+
const aad = options?.aad;
|
|
4780
|
+
let hasAad = false;
|
|
4781
|
+
if (aad) {
|
|
4782
|
+
const aadBuffer = Buffer.isBuffer(aad) ? aad : Buffer.from(typeof aad === "string" ? aad : new Uint8Array(aad));
|
|
4783
|
+
if (aadBuffer.length > 0) {
|
|
4784
|
+
cipher.setAAD(aadBuffer);
|
|
4785
|
+
hasAad = true;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4652
4788
|
const encryptedBuffer = Buffer.concat([
|
|
4653
4789
|
cipher.update(jsonString, "utf8"),
|
|
4654
4790
|
cipher.final()
|
|
4655
4791
|
]);
|
|
4656
4792
|
const authTag = cipher.getAuthTag();
|
|
4657
4793
|
const combinedCiphertext = Buffer.concat([encryptedBuffer, authTag]);
|
|
4794
|
+
const kid = options?.kid || options?.keyId || this._configuredKid;
|
|
4658
4795
|
return {
|
|
4659
4796
|
__encrypted: true,
|
|
4660
4797
|
ciphertext: combinedCiphertext.toString("base64"),
|
|
@@ -4662,7 +4799,9 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4662
4799
|
alg: "AES-GCM",
|
|
4663
4800
|
...salt ? { salt } : {},
|
|
4664
4801
|
...kdf && kdf !== "none" && kdf !== "raw" ? { kdf } : {},
|
|
4665
|
-
...iter ? { iter } : {}
|
|
4802
|
+
...iter ? { iter } : {},
|
|
4803
|
+
...kid ? { kid } : {},
|
|
4804
|
+
...hasAad ? { aad: true } : {}
|
|
4666
4805
|
};
|
|
4667
4806
|
} finally {
|
|
4668
4807
|
if (key !== this._cachedKey) {
|
|
@@ -4670,7 +4809,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4670
4809
|
}
|
|
4671
4810
|
}
|
|
4672
4811
|
}
|
|
4673
|
-
decryptCiphertextWithKey(payload, key) {
|
|
4812
|
+
decryptCiphertextWithKey(payload, key, options) {
|
|
4674
4813
|
const iv = Buffer.from(payload.iv, "base64");
|
|
4675
4814
|
const fullCiphertext = Buffer.from(payload.ciphertext, "base64");
|
|
4676
4815
|
let ciphertext;
|
|
@@ -4678,6 +4817,9 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4678
4817
|
if (payload.tag) {
|
|
4679
4818
|
ciphertext = fullCiphertext;
|
|
4680
4819
|
authTag = Buffer.from(payload.tag, "base64");
|
|
4820
|
+
if (authTag.length !== 16) {
|
|
4821
|
+
throw new Error("[CNodeCryptoEncryptionProvider] Authentication tag must be exactly 16 bytes for AES-256-GCM");
|
|
4822
|
+
}
|
|
4681
4823
|
} else {
|
|
4682
4824
|
if (fullCiphertext.length < 16) {
|
|
4683
4825
|
throw new Error("Ciphertext too short to contain authentication tag");
|
|
@@ -4685,8 +4827,19 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4685
4827
|
ciphertext = fullCiphertext.subarray(0, fullCiphertext.length - 16);
|
|
4686
4828
|
authTag = fullCiphertext.subarray(fullCiphertext.length - 16);
|
|
4687
4829
|
}
|
|
4688
|
-
const decipher = crypto__namespace.createDecipheriv("aes-256-gcm", key, iv);
|
|
4830
|
+
const decipher = crypto__namespace.createDecipheriv("aes-256-gcm", key, iv, { authTagLength: 16 });
|
|
4689
4831
|
decipher.setAuthTag(authTag);
|
|
4832
|
+
const aad = options?.aad;
|
|
4833
|
+
if (payload.aad || aad) {
|
|
4834
|
+
if (aad) {
|
|
4835
|
+
const aadBuffer = Buffer.isBuffer(aad) ? aad : Buffer.from(typeof aad === "string" ? aad : new Uint8Array(aad));
|
|
4836
|
+
if (aadBuffer.length > 0) {
|
|
4837
|
+
decipher.setAAD(aadBuffer);
|
|
4838
|
+
}
|
|
4839
|
+
} else if (payload.aad) {
|
|
4840
|
+
throw new Error("[CNodeCryptoEncryptionProvider] Payload requires Authenticated Additional Data (AAD) for decryption, but none was provided.");
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4690
4843
|
const decrypted = Buffer.concat([
|
|
4691
4844
|
decipher.update(ciphertext),
|
|
4692
4845
|
decipher.final()
|
|
@@ -4715,7 +4868,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4715
4868
|
payload.iter
|
|
4716
4869
|
);
|
|
4717
4870
|
try {
|
|
4718
|
-
return this.decryptCiphertextWithKey(payload, key);
|
|
4871
|
+
return this.decryptCiphertextWithKey(payload, key, options);
|
|
4719
4872
|
} catch (err) {
|
|
4720
4873
|
if (err instanceof SyntaxError) throw err;
|
|
4721
4874
|
throw new Error(`[CNodeCryptoEncryptionProvider] Decryption failed: ${err?.message || "Authentication tag mismatch or corrupted ciphertext"}`);
|
|
@@ -4790,7 +4943,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4790
4943
|
derivedKey = derived.key;
|
|
4791
4944
|
keyCache.set(salt, derivedKey);
|
|
4792
4945
|
}
|
|
4793
|
-
safeSetProperty(result, key, this.decryptCiphertextWithKey(fieldPayload, derivedKey));
|
|
4946
|
+
safeSetProperty(result, key, this.decryptCiphertextWithKey(fieldPayload, derivedKey, options));
|
|
4794
4947
|
mutated = true;
|
|
4795
4948
|
}
|
|
4796
4949
|
}
|
|
@@ -4830,12 +4983,22 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4830
4983
|
const jsonString = JSON.stringify(data);
|
|
4831
4984
|
const iv = crypto__namespace.randomBytes(12);
|
|
4832
4985
|
const cipher = crypto__namespace.createCipheriv("aes-256-gcm", key, iv);
|
|
4986
|
+
const aad = options?.aad;
|
|
4987
|
+
let hasAad = false;
|
|
4988
|
+
if (aad) {
|
|
4989
|
+
const aadBuffer = Buffer.isBuffer(aad) ? aad : Buffer.from(typeof aad === "string" ? aad : new Uint8Array(aad));
|
|
4990
|
+
if (aadBuffer.length > 0) {
|
|
4991
|
+
cipher.setAAD(aadBuffer);
|
|
4992
|
+
hasAad = true;
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4833
4995
|
const ciphertext = Buffer.concat([
|
|
4834
4996
|
cipher.update(jsonString, "utf8"),
|
|
4835
4997
|
cipher.final()
|
|
4836
4998
|
]);
|
|
4837
4999
|
const authTag = cipher.getAuthTag();
|
|
4838
5000
|
const combined = Buffer.concat([ciphertext, authTag]);
|
|
5001
|
+
const kid = options?.kid || options?.keyId || this._configuredKid;
|
|
4839
5002
|
return {
|
|
4840
5003
|
__encrypted: true,
|
|
4841
5004
|
ciphertext: combined.toString("base64"),
|
|
@@ -4843,7 +5006,9 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4843
5006
|
alg: "AES-GCM",
|
|
4844
5007
|
...salt ? { salt } : {},
|
|
4845
5008
|
...kdf && kdf !== "none" && kdf !== "raw" ? { kdf } : {},
|
|
4846
|
-
...iter ? { iter } : {}
|
|
5009
|
+
...iter ? { iter } : {},
|
|
5010
|
+
...kid ? { kid } : {},
|
|
5011
|
+
...hasAad ? { aad: true } : {}
|
|
4847
5012
|
};
|
|
4848
5013
|
} finally {
|
|
4849
5014
|
if (key !== this._cachedKey) {
|
|
@@ -4865,7 +5030,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4865
5030
|
payload.iter
|
|
4866
5031
|
);
|
|
4867
5032
|
try {
|
|
4868
|
-
return this.decryptCiphertextWithKey(payload, key);
|
|
5033
|
+
return this.decryptCiphertextWithKey(payload, key, options);
|
|
4869
5034
|
} catch (err) {
|
|
4870
5035
|
if (err instanceof SyntaxError) throw err;
|
|
4871
5036
|
throw new Error(`[CNodeCryptoEncryptionProvider] Decryption failed: ${err?.message || "Authentication tag mismatch or corrupted ciphertext"}`);
|
|
@@ -4906,7 +5071,7 @@ class CNodeCryptoEncryptionProvider extends AEncryptionProvider {
|
|
|
4906
5071
|
derivedKey = derived.key;
|
|
4907
5072
|
keyCache.set(salt, derivedKey);
|
|
4908
5073
|
}
|
|
4909
|
-
safeSetProperty(result, key, this.decryptCiphertextWithKey(fieldPayload, derivedKey));
|
|
5074
|
+
safeSetProperty(result, key, this.decryptCiphertextWithKey(fieldPayload, derivedKey, options));
|
|
4910
5075
|
mutated = true;
|
|
4911
5076
|
}
|
|
4912
5077
|
}
|
|
@@ -5067,40 +5232,66 @@ class RequestProvider {
|
|
|
5067
5232
|
setDeduplicate(deduplicate) {
|
|
5068
5233
|
this.deduplicate = deduplicate;
|
|
5069
5234
|
}
|
|
5235
|
+
setQueue(queue) {
|
|
5236
|
+
this.queue = queue;
|
|
5237
|
+
}
|
|
5070
5238
|
encryption;
|
|
5071
5239
|
_cachedCipherProvider;
|
|
5072
5240
|
_lastEncryptionConfig;
|
|
5241
|
+
_scopedCipherProviders = /* @__PURE__ */ new WeakMap();
|
|
5242
|
+
/**
|
|
5243
|
+
* Configures E2EE payload encryption for outbound mutations and inbound responses.
|
|
5244
|
+
*
|
|
5245
|
+
* Threat Model: Protects sensitive SaaS tenant data against backend/database breaches.
|
|
5246
|
+
* Multi-user sharing is supported by role-based session keys passed dynamically.
|
|
5247
|
+
* Local client endpoint compromise (malware, trojans, keyloggers) is out of scope.
|
|
5248
|
+
*/
|
|
5249
|
+
disposeCipherInstance(provider) {
|
|
5250
|
+
if (!provider) return;
|
|
5251
|
+
if (typeof provider.dispose === "function") {
|
|
5252
|
+
try {
|
|
5253
|
+
provider.dispose();
|
|
5254
|
+
} catch {
|
|
5255
|
+
}
|
|
5256
|
+
} else if (typeof provider.clearKeys === "function") {
|
|
5257
|
+
try {
|
|
5258
|
+
provider.clearKeys();
|
|
5259
|
+
} catch {
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
}
|
|
5073
5263
|
setEncryption(encryption) {
|
|
5074
|
-
if (this.
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
} catch {
|
|
5079
|
-
}
|
|
5080
|
-
} else if (typeof this._cachedCipherProvider.clearKeys === "function") {
|
|
5081
|
-
try {
|
|
5082
|
-
this._cachedCipherProvider.clearKeys();
|
|
5083
|
-
} catch {
|
|
5084
|
-
}
|
|
5264
|
+
if (this._lastEncryptionConfig && this._lastEncryptionConfig !== encryption) {
|
|
5265
|
+
const scopedOld = this._scopedCipherProviders.get(this._lastEncryptionConfig);
|
|
5266
|
+
if (scopedOld && scopedOld !== this._cachedCipherProvider) {
|
|
5267
|
+
this.disposeCipherInstance(scopedOld);
|
|
5085
5268
|
}
|
|
5269
|
+
this._scopedCipherProviders.delete(this._lastEncryptionConfig);
|
|
5270
|
+
}
|
|
5271
|
+
if (this._cachedCipherProvider && this._lastEncryptionConfig !== encryption) {
|
|
5272
|
+
this.disposeCipherInstance(this._cachedCipherProvider);
|
|
5086
5273
|
}
|
|
5087
5274
|
this.encryption = encryption;
|
|
5088
5275
|
this._cachedCipherProvider = void 0;
|
|
5089
5276
|
this._lastEncryptionConfig = void 0;
|
|
5090
5277
|
}
|
|
5091
5278
|
clearEncryption() {
|
|
5092
|
-
if (this.
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5279
|
+
if (this.encryption) {
|
|
5280
|
+
const scoped = this._scopedCipherProviders.get(this.encryption);
|
|
5281
|
+
if (scoped && scoped !== this._cachedCipherProvider) {
|
|
5282
|
+
this.disposeCipherInstance(scoped);
|
|
5283
|
+
}
|
|
5284
|
+
this._scopedCipherProviders.delete(this.encryption);
|
|
5285
|
+
}
|
|
5286
|
+
if (this._lastEncryptionConfig) {
|
|
5287
|
+
const scopedLast = this._scopedCipherProviders.get(this._lastEncryptionConfig);
|
|
5288
|
+
if (scopedLast && scopedLast !== this._cachedCipherProvider) {
|
|
5289
|
+
this.disposeCipherInstance(scopedLast);
|
|
5103
5290
|
}
|
|
5291
|
+
this._scopedCipherProviders.delete(this._lastEncryptionConfig);
|
|
5292
|
+
}
|
|
5293
|
+
if (this._cachedCipherProvider) {
|
|
5294
|
+
this.disposeCipherInstance(this._cachedCipherProvider);
|
|
5104
5295
|
}
|
|
5105
5296
|
this.encryption = void 0;
|
|
5106
5297
|
this._cachedCipherProvider = void 0;
|
|
@@ -5166,6 +5357,7 @@ class RequestProvider {
|
|
|
5166
5357
|
}
|
|
5167
5358
|
return event.context.__katluxRequestsInFlight;
|
|
5168
5359
|
}
|
|
5360
|
+
return /* @__PURE__ */ new Map();
|
|
5169
5361
|
}
|
|
5170
5362
|
return RequestProvider.requestsInFlight;
|
|
5171
5363
|
}
|
|
@@ -5190,11 +5382,6 @@ class RequestProvider {
|
|
|
5190
5382
|
}
|
|
5191
5383
|
serverAuthIdentity = authHeader || authCookies || "";
|
|
5192
5384
|
}
|
|
5193
|
-
if (options?.key) {
|
|
5194
|
-
const authSuffix = serverAuthIdentity ? `|${hashIdentity(serverAuthIdentity)}` : "";
|
|
5195
|
-
const fullKey = `${options.key}${authSuffix}`;
|
|
5196
|
-
return namespace ? `${namespace}:${fullKey}` : fullKey;
|
|
5197
|
-
}
|
|
5198
5385
|
let headersForCache = headers || {};
|
|
5199
5386
|
if (headers) {
|
|
5200
5387
|
headersForCache = {};
|
|
@@ -5205,21 +5392,26 @@ class RequestProvider {
|
|
|
5205
5392
|
}
|
|
5206
5393
|
}
|
|
5207
5394
|
}
|
|
5395
|
+
const encOptions = options?.encryption || this.encryption;
|
|
5396
|
+
const encSuffix = encOptions?.enabled ? `|enc_${encOptions.keyId || encOptions.kid || (typeof encOptions.key === "string" ? fastKeyHash(encOptions.key) : "1")}` : "";
|
|
5208
5397
|
if (options?.key) {
|
|
5209
5398
|
const authSuffix = serverAuthIdentity ? `|${hashIdentity(serverAuthIdentity)}` : "";
|
|
5210
|
-
const fullKey = `${options.key}${authSuffix}`;
|
|
5399
|
+
const fullKey = `${options.key}${encSuffix}${authSuffix}`;
|
|
5211
5400
|
return namespace ? `${namespace}:${fullKey}` : fullKey;
|
|
5212
5401
|
}
|
|
5213
5402
|
const parts = [
|
|
5214
5403
|
url,
|
|
5215
5404
|
stableStringify(query || {}),
|
|
5216
5405
|
stableStringify(body || null),
|
|
5217
|
-
stableStringify(headersForCache)
|
|
5406
|
+
stableStringify(headersForCache),
|
|
5407
|
+
method || "GET"
|
|
5218
5408
|
];
|
|
5219
5409
|
if (serverAuthIdentity) {
|
|
5220
5410
|
parts.push(hashIdentity(serverAuthIdentity));
|
|
5221
5411
|
}
|
|
5222
|
-
|
|
5412
|
+
if (encSuffix) {
|
|
5413
|
+
parts.push(encSuffix.slice(1));
|
|
5414
|
+
}
|
|
5223
5415
|
const baseKey = parts.join("|");
|
|
5224
5416
|
return namespace ? `${namespace}:${baseKey}` : baseKey;
|
|
5225
5417
|
}
|
|
@@ -5233,13 +5425,31 @@ class RequestProvider {
|
|
|
5233
5425
|
const tags = effectiveOptions.tags || this.tags;
|
|
5234
5426
|
const label = effectiveOptions.label || effectiveOptions.queueLabel;
|
|
5235
5427
|
if (shouldQueue && method !== "GET") {
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5428
|
+
const enqueuePromise = (async () => {
|
|
5429
|
+
const encOptions = effectiveOptions.encryption;
|
|
5430
|
+
let effectiveBody = effectiveOptions.body;
|
|
5431
|
+
const isBinaryOrFormBody = effectiveBody !== void 0 && effectiveBody !== null && (typeof FormData !== "undefined" && effectiveBody instanceof FormData || typeof Blob !== "undefined" && effectiveBody instanceof Blob || typeof URLSearchParams !== "undefined" && effectiveBody instanceof URLSearchParams || typeof ArrayBuffer !== "undefined" && (effectiveBody instanceof ArrayBuffer || ArrayBuffer.isView(effectiveBody)));
|
|
5432
|
+
if (encOptions?.enabled && effectiveBody !== void 0 && effectiveBody !== null && !isBinaryOrFormBody) {
|
|
5433
|
+
const cipherProvider = this.getCipherProvider(encOptions);
|
|
5434
|
+
const isServer = typeof window === "undefined";
|
|
5435
|
+
effectiveBody = await cipherProvider.encrypt(
|
|
5436
|
+
effectiveBody,
|
|
5437
|
+
this.buildEncryptionContext(encOptions, url, method, isServer)
|
|
5438
|
+
);
|
|
5439
|
+
}
|
|
5440
|
+
const queuedOptions = {
|
|
5441
|
+
...effectiveOptions,
|
|
5442
|
+
body: effectiveBody
|
|
5443
|
+
};
|
|
5444
|
+
return RequestQueue.enqueue({
|
|
5445
|
+
url,
|
|
5446
|
+
method,
|
|
5447
|
+
options: queuedOptions,
|
|
5448
|
+
tags,
|
|
5449
|
+
label
|
|
5450
|
+
});
|
|
5451
|
+
})();
|
|
5452
|
+
return enqueuePromise;
|
|
5243
5453
|
}
|
|
5244
5454
|
const inFlightMap = this.getInFlightMap(options);
|
|
5245
5455
|
const uniqueKey = this.getUniqueKey(url, options);
|
|
@@ -5320,26 +5530,40 @@ class RequestProvider {
|
|
|
5320
5530
|
if (encOptions === this.encryption && this._cachedCipherProvider) {
|
|
5321
5531
|
return this._cachedCipherProvider;
|
|
5322
5532
|
}
|
|
5323
|
-
|
|
5533
|
+
let provider = this._scopedCipherProviders.get(encOptions);
|
|
5534
|
+
if (!provider) {
|
|
5535
|
+
provider = createEncryptionProvider(encOptions);
|
|
5536
|
+
this._scopedCipherProviders.set(encOptions, provider);
|
|
5537
|
+
}
|
|
5324
5538
|
if (encOptions === this.encryption) {
|
|
5325
5539
|
this._cachedCipherProvider = provider;
|
|
5326
5540
|
this._lastEncryptionConfig = encOptions;
|
|
5327
5541
|
}
|
|
5328
5542
|
return provider;
|
|
5329
5543
|
}
|
|
5330
|
-
isDataEncrypted(provider, data
|
|
5544
|
+
isDataEncrypted(provider, data) {
|
|
5331
5545
|
if (!data || typeof data !== "object") return false;
|
|
5332
|
-
if (
|
|
5333
|
-
visited.add(data);
|
|
5546
|
+
if (data.__encrypted === true) return true;
|
|
5334
5547
|
if (typeof provider.isEncrypted === "function" && provider.isEncrypted(data)) {
|
|
5335
5548
|
return true;
|
|
5336
5549
|
}
|
|
5337
5550
|
if (Array.isArray(data)) {
|
|
5338
|
-
|
|
5551
|
+
if (data.length === 0) return false;
|
|
5552
|
+
const first = data[0];
|
|
5553
|
+
return first !== null && typeof first === "object" && (first.__encrypted === true || typeof provider.isEncrypted === "function" && provider.isEncrypted(first) || this.isDataEncrypted(provider, first));
|
|
5554
|
+
}
|
|
5555
|
+
if (data.data && typeof data.data === "object") {
|
|
5556
|
+
return this.isDataEncrypted(provider, data.data);
|
|
5557
|
+
}
|
|
5558
|
+
if (data.items && typeof data.items === "object") {
|
|
5559
|
+
return this.isDataEncrypted(provider, data.items);
|
|
5560
|
+
}
|
|
5561
|
+
if (data.rows && typeof data.rows === "object") {
|
|
5562
|
+
return this.isDataEncrypted(provider, data.rows);
|
|
5339
5563
|
}
|
|
5340
5564
|
for (const key of Object.keys(data)) {
|
|
5341
5565
|
const val = data[key];
|
|
5342
|
-
if (val && typeof val === "object" &&
|
|
5566
|
+
if (val && typeof val === "object" && val.__encrypted === true) {
|
|
5343
5567
|
return true;
|
|
5344
5568
|
}
|
|
5345
5569
|
}
|
|
@@ -5374,13 +5598,20 @@ class RequestProvider {
|
|
|
5374
5598
|
return data;
|
|
5375
5599
|
}
|
|
5376
5600
|
const cipherProvider = this.getCipherProvider(encOptions);
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5601
|
+
let result = data;
|
|
5602
|
+
if (this.isDataEncrypted(cipherProvider, result) || encOptions.fields && encOptions.fields.length > 0) {
|
|
5603
|
+
result = await cipherProvider.decrypt(
|
|
5604
|
+
result,
|
|
5380
5605
|
this.buildEncryptionContext(encOptions, url, requestMethod, isServer)
|
|
5381
5606
|
);
|
|
5607
|
+
if (result && typeof result === "object" && encOptions.fields && encOptions.fields.length > 0 && this.isDataEncrypted(cipherProvider, result)) {
|
|
5608
|
+
result = await cipherProvider.decrypt(
|
|
5609
|
+
result,
|
|
5610
|
+
this.buildEncryptionContext(encOptions, url, requestMethod, isServer)
|
|
5611
|
+
);
|
|
5612
|
+
}
|
|
5382
5613
|
}
|
|
5383
|
-
return
|
|
5614
|
+
return result;
|
|
5384
5615
|
}
|
|
5385
5616
|
async request(url, options) {
|
|
5386
5617
|
const { cacheStrategy, lifetime, query, body, headers, method } = options || {};
|
|
@@ -5450,11 +5681,14 @@ class RequestProvider {
|
|
|
5450
5681
|
let dataToCache = responseData;
|
|
5451
5682
|
if (encOptions?.enabled) {
|
|
5452
5683
|
const cipherProvider = this.getCipherProvider(encOptions);
|
|
5453
|
-
|
|
5454
|
-
|
|
5455
|
-
|
|
5456
|
-
this.buildEncryptionContext(encOptions, url, requestMethod, isServer)
|
|
5457
|
-
|
|
5684
|
+
const isFullEnvelope = dataToCache && typeof dataToCache === "object" && dataToCache.__encrypted === true;
|
|
5685
|
+
if (!isFullEnvelope) {
|
|
5686
|
+
const cacheContext = {
|
|
5687
|
+
...this.buildEncryptionContext(encOptions, url, requestMethod, isServer),
|
|
5688
|
+
fields: void 0,
|
|
5689
|
+
valueEncryption: false
|
|
5690
|
+
};
|
|
5691
|
+
dataToCache = await cipherProvider.encrypt(dataToCache, cacheContext);
|
|
5458
5692
|
}
|
|
5459
5693
|
}
|
|
5460
5694
|
await provider.set(uniqueKey, dataToCache, cacheLifetime, context);
|
|
@@ -5505,21 +5739,31 @@ function clearCachedCipherProvider(encryption) {
|
|
|
5505
5739
|
providerCache.delete(encryption);
|
|
5506
5740
|
}
|
|
5507
5741
|
}
|
|
5508
|
-
function isDataEncrypted(provider, data
|
|
5742
|
+
function isDataEncrypted(provider, data) {
|
|
5509
5743
|
if (!data || typeof data !== "object") return false;
|
|
5510
|
-
if (
|
|
5511
|
-
visited.add(data);
|
|
5744
|
+
if (data.__encrypted === true) return true;
|
|
5512
5745
|
if (provider && typeof provider.isEncrypted === "function") {
|
|
5513
5746
|
if (provider.isEncrypted(data)) return true;
|
|
5514
5747
|
} else if (CWebCryptoEncryptionProvider.isEncrypted(data)) {
|
|
5515
5748
|
return true;
|
|
5516
5749
|
}
|
|
5517
5750
|
if (Array.isArray(data)) {
|
|
5518
|
-
|
|
5751
|
+
if (data.length === 0) return false;
|
|
5752
|
+
const first = data[0];
|
|
5753
|
+
return first !== null && typeof first === "object" && (first.__encrypted === true || (provider?.isEncrypted ? provider.isEncrypted(first) : CWebCryptoEncryptionProvider.isEncrypted(first)));
|
|
5754
|
+
}
|
|
5755
|
+
if (data.data && typeof data.data === "object") {
|
|
5756
|
+
return isDataEncrypted(provider, data.data);
|
|
5757
|
+
}
|
|
5758
|
+
if (data.items && typeof data.items === "object") {
|
|
5759
|
+
return isDataEncrypted(provider, data.items);
|
|
5760
|
+
}
|
|
5761
|
+
if (data.rows && typeof data.rows === "object") {
|
|
5762
|
+
return isDataEncrypted(provider, data.rows);
|
|
5519
5763
|
}
|
|
5520
5764
|
for (const key of Object.keys(data)) {
|
|
5521
5765
|
const val = data[key];
|
|
5522
|
-
if (val && typeof val === "object" &&
|
|
5766
|
+
if (val && typeof val === "object" && val.__encrypted === true) {
|
|
5523
5767
|
return true;
|
|
5524
5768
|
}
|
|
5525
5769
|
}
|
|
@@ -5551,7 +5795,15 @@ async function decryptPageRows(rows, encryption, apiUrl, idKey) {
|
|
|
5551
5795
|
if (!cipherProvider) {
|
|
5552
5796
|
return { rows, decrypted: false };
|
|
5553
5797
|
}
|
|
5554
|
-
|
|
5798
|
+
const hasEncryptedRows = rows.some((row) => {
|
|
5799
|
+
if (!row || typeof row !== "object") return false;
|
|
5800
|
+
if (row.__encrypted === true) return true;
|
|
5801
|
+
if (encryption?.fields && encryption.fields.length > 0) {
|
|
5802
|
+
return encryption.fields.some((f) => row[f]?.__encrypted === true);
|
|
5803
|
+
}
|
|
5804
|
+
return isDataEncrypted(cipherProvider, row);
|
|
5805
|
+
});
|
|
5806
|
+
if (!hasEncryptedRows) {
|
|
5555
5807
|
return { rows, decrypted: false };
|
|
5556
5808
|
}
|
|
5557
5809
|
const ctx = buildEncryptionContext(encryption, apiUrl);
|
|
@@ -5612,8 +5864,12 @@ class CAPIFlatClientDataProvider extends CFlatClientDataProvider {
|
|
|
5612
5864
|
cacheLifetime = 0;
|
|
5613
5865
|
refreshOnMutation = void 0;
|
|
5614
5866
|
encryption;
|
|
5867
|
+
_isAccumulating = false;
|
|
5868
|
+
_inFlightLoadMore = false;
|
|
5615
5869
|
constructor(options) {
|
|
5616
5870
|
super(options);
|
|
5871
|
+
if (options?.apiUrl) this.apiUrl = options.apiUrl;
|
|
5872
|
+
if (options?.url) this.apiUrl = options.url;
|
|
5617
5873
|
if (options?.cacheStrategy) {
|
|
5618
5874
|
this.cacheStrategy = options.cacheStrategy;
|
|
5619
5875
|
this.requestProvider.setCacheProvider(options.cacheStrategy);
|
|
@@ -5631,10 +5887,43 @@ class CAPIFlatClientDataProvider extends CFlatClientDataProvider {
|
|
|
5631
5887
|
this.requestProvider.onDataReceived((data) => {
|
|
5632
5888
|
if (data) {
|
|
5633
5889
|
const normalized = normalizeDataResult(data);
|
|
5634
|
-
|
|
5890
|
+
const rows = normalized ? normalized.rows : data.rows || data;
|
|
5891
|
+
if (this._isAccumulating) {
|
|
5892
|
+
this.allData = [...this.allData, ...rows];
|
|
5893
|
+
this.loadPageData();
|
|
5894
|
+
} else {
|
|
5895
|
+
this.setData(rows);
|
|
5896
|
+
}
|
|
5897
|
+
if (normalized?.rowCount !== void 0) {
|
|
5898
|
+
this.rowCount = normalized.rowCount;
|
|
5899
|
+
}
|
|
5635
5900
|
}
|
|
5636
5901
|
});
|
|
5637
5902
|
}
|
|
5903
|
+
async loadMore() {
|
|
5904
|
+
if (!this.hasMore || this.loading || this._inFlightLoadMore) return;
|
|
5905
|
+
this._inFlightLoadMore = true;
|
|
5906
|
+
this._isAccumulating = true;
|
|
5907
|
+
try {
|
|
5908
|
+
if (this.apiUrl) {
|
|
5909
|
+
const nextPage = this.currentPage + 1;
|
|
5910
|
+
await this.requestProvider.registerRequest(this.apiUrl, {
|
|
5911
|
+
query: {
|
|
5912
|
+
pageNumber: nextPage,
|
|
5913
|
+
pageSize: this.pageSize
|
|
5914
|
+
},
|
|
5915
|
+
deduplicate: this.deduplicate,
|
|
5916
|
+
context: this.context
|
|
5917
|
+
});
|
|
5918
|
+
this.setCurrentPage(nextPage);
|
|
5919
|
+
} else {
|
|
5920
|
+
await this.setCurrentPage(this.currentPage + 1);
|
|
5921
|
+
}
|
|
5922
|
+
} finally {
|
|
5923
|
+
this._isAccumulating = false;
|
|
5924
|
+
this._inFlightLoadMore = false;
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5638
5927
|
setEncryption(encryption) {
|
|
5639
5928
|
if (this.encryption && this.encryption !== encryption) {
|
|
5640
5929
|
clearCachedCipherProvider(this.encryption);
|
|
@@ -5707,6 +5996,9 @@ class CAPIFlatClientDataProvider extends CFlatClientDataProvider {
|
|
|
5707
5996
|
}
|
|
5708
5997
|
try {
|
|
5709
5998
|
const result = await fetchWithSSR(key, fetcher, this.context);
|
|
5999
|
+
if (result && typeof result === "object" && (result.__encrypted === true || result.ciphertext)) {
|
|
6000
|
+
return;
|
|
6001
|
+
}
|
|
5710
6002
|
const normalized = normalizeDataResult(result);
|
|
5711
6003
|
if (normalized) {
|
|
5712
6004
|
this.setData(normalized.rows);
|
|
@@ -6133,18 +6425,22 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6133
6425
|
_nodeMapCache = null;
|
|
6134
6426
|
_sortedNodeIdsCache = null;
|
|
6135
6427
|
_filteredNodesCache = null;
|
|
6428
|
+
_allVisibleRowsCache = null;
|
|
6136
6429
|
invalidateStaticCache() {
|
|
6137
6430
|
this._staticNodesCache = null;
|
|
6138
6431
|
this._nodeMapCache = null;
|
|
6139
6432
|
this._sortedNodeIdsCache = null;
|
|
6140
6433
|
this._filteredNodesCache = null;
|
|
6434
|
+
this._allVisibleRowsCache = null;
|
|
6141
6435
|
}
|
|
6142
6436
|
setFilter(filter, immediate = false) {
|
|
6143
6437
|
this._filteredNodesCache = null;
|
|
6438
|
+
this._allVisibleRowsCache = null;
|
|
6144
6439
|
super.setFilter(filter, immediate);
|
|
6145
6440
|
}
|
|
6146
6441
|
onFilterUpdated() {
|
|
6147
6442
|
this._filteredNodesCache = null;
|
|
6443
|
+
this._allVisibleRowsCache = null;
|
|
6148
6444
|
}
|
|
6149
6445
|
get _staticNodes() {
|
|
6150
6446
|
if (!this._staticNodesCache) {
|
|
@@ -6250,9 +6546,11 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6250
6546
|
}
|
|
6251
6547
|
onSortUpdated() {
|
|
6252
6548
|
this._sortedNodeIdsCache = null;
|
|
6549
|
+
this._allVisibleRowsCache = null;
|
|
6253
6550
|
}
|
|
6254
6551
|
setSortList(sortList, immediate = false) {
|
|
6255
6552
|
this._sortedNodeIdsCache = null;
|
|
6553
|
+
this._allVisibleRowsCache = null;
|
|
6256
6554
|
super.setSortList(sortList, immediate);
|
|
6257
6555
|
}
|
|
6258
6556
|
computeSortedIds() {
|
|
@@ -6262,16 +6560,29 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6262
6560
|
const nodeMap = this._nodeMap;
|
|
6263
6561
|
const sortNodes = (nodesToSort) => {
|
|
6264
6562
|
if (!this.sortList || this.sortList.length === 0) return nodesToSort;
|
|
6563
|
+
const nodeById = /* @__PURE__ */ new Map();
|
|
6564
|
+
const nodeByData = /* @__PURE__ */ new Map();
|
|
6565
|
+
for (const n of nodesToSort) {
|
|
6566
|
+
nodeById.set(n.id, n);
|
|
6567
|
+
if (n.data) nodeByData.set(n.data, n);
|
|
6568
|
+
}
|
|
6265
6569
|
const dataRows = nodesToSort.map((n) => n.data);
|
|
6266
6570
|
const sortedData = sortData(this.sortList, dataRows);
|
|
6267
6571
|
const sortedNodes = [];
|
|
6572
|
+
const visited = /* @__PURE__ */ new Set();
|
|
6268
6573
|
for (const row of sortedData) {
|
|
6269
6574
|
const id = row?.[this.idKey] ?? row?.id;
|
|
6270
|
-
const found =
|
|
6271
|
-
if (found && !
|
|
6575
|
+
const found = (id !== void 0 && id !== null ? nodeById.get(id) : void 0) ?? nodeByData.get(row);
|
|
6576
|
+
if (found && !visited.has(found)) {
|
|
6577
|
+
sortedNodes.push(found);
|
|
6578
|
+
visited.add(found);
|
|
6579
|
+
}
|
|
6272
6580
|
}
|
|
6273
6581
|
for (const n of nodesToSort) {
|
|
6274
|
-
if (!
|
|
6582
|
+
if (!visited.has(n)) {
|
|
6583
|
+
sortedNodes.push(n);
|
|
6584
|
+
visited.add(n);
|
|
6585
|
+
}
|
|
6275
6586
|
}
|
|
6276
6587
|
return sortedNodes;
|
|
6277
6588
|
};
|
|
@@ -6483,12 +6794,18 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6483
6794
|
}
|
|
6484
6795
|
return visibleNodes;
|
|
6485
6796
|
}
|
|
6797
|
+
get rowMap() {
|
|
6798
|
+
return this.allVisibleRows;
|
|
6799
|
+
}
|
|
6486
6800
|
get allVisibleRows() {
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6801
|
+
if (!this._allVisibleRowsCache) {
|
|
6802
|
+
this._allVisibleRowsCache = this.allVisibleNodes.map((node) => ({
|
|
6803
|
+
...node.data,
|
|
6804
|
+
...node,
|
|
6805
|
+
__treeNode: node
|
|
6806
|
+
}));
|
|
6807
|
+
}
|
|
6808
|
+
return this._allVisibleRowsCache;
|
|
6492
6809
|
}
|
|
6493
6810
|
get visibleRows() {
|
|
6494
6811
|
return this.paginateNodes(this.allVisibleNodes);
|
|
@@ -6503,6 +6820,7 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6503
6820
|
if (this.filter && this.filter.active) {
|
|
6504
6821
|
this._filteredNodesCache = null;
|
|
6505
6822
|
}
|
|
6823
|
+
this._allVisibleRowsCache = null;
|
|
6506
6824
|
if (this.expandedNodes.has(nodeId)) {
|
|
6507
6825
|
this.expandedNodes.delete(nodeId);
|
|
6508
6826
|
} else {
|
|
@@ -6515,6 +6833,7 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6515
6833
|
if (this.filter && this.filter.active) {
|
|
6516
6834
|
this._filteredNodesCache = null;
|
|
6517
6835
|
}
|
|
6836
|
+
this._allVisibleRowsCache = null;
|
|
6518
6837
|
this.expandedNodes.add(nodeId);
|
|
6519
6838
|
this.updatePageData();
|
|
6520
6839
|
this.notify();
|
|
@@ -6523,6 +6842,7 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6523
6842
|
if (this.filter && this.filter.active) {
|
|
6524
6843
|
this._filteredNodesCache = null;
|
|
6525
6844
|
}
|
|
6845
|
+
this._allVisibleRowsCache = null;
|
|
6526
6846
|
this.expandedNodes.delete(nodeId);
|
|
6527
6847
|
this.updatePageData();
|
|
6528
6848
|
this.notify();
|
|
@@ -6537,6 +6857,7 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6537
6857
|
if (this.filter && this.filter.active) {
|
|
6538
6858
|
this._filteredNodesCache = null;
|
|
6539
6859
|
}
|
|
6860
|
+
this._allVisibleRowsCache = null;
|
|
6540
6861
|
const allIds = this._staticNodes.filter((n) => n.hasChildren).map((n) => n.id);
|
|
6541
6862
|
this.expandedNodes = new Set(allIds);
|
|
6542
6863
|
this.updatePageData();
|
|
@@ -6546,6 +6867,7 @@ class CTreeClientDataProvider extends CFlatClientDataProvider {
|
|
|
6546
6867
|
if (this.filter && this.filter.active) {
|
|
6547
6868
|
this._filteredNodesCache = null;
|
|
6548
6869
|
}
|
|
6870
|
+
this._allVisibleRowsCache = null;
|
|
6549
6871
|
this.expandedNodes = /* @__PURE__ */ new Set();
|
|
6550
6872
|
this.updatePageData();
|
|
6551
6873
|
this.notify();
|
|
@@ -6578,8 +6900,14 @@ class CAPITreeClientDataProvider extends CTreeClientDataProvider {
|
|
|
6578
6900
|
encryption;
|
|
6579
6901
|
constructor(options) {
|
|
6580
6902
|
super(options);
|
|
6581
|
-
if (options?.cacheStrategy)
|
|
6582
|
-
|
|
6903
|
+
if (options?.cacheStrategy) {
|
|
6904
|
+
this.cacheStrategy = options.cacheStrategy;
|
|
6905
|
+
this.requestProvider.setCacheProvider(options.cacheStrategy);
|
|
6906
|
+
}
|
|
6907
|
+
if (options?.cacheLifetime !== void 0) {
|
|
6908
|
+
this.cacheLifetime = options.cacheLifetime;
|
|
6909
|
+
this.requestProvider.setCacheLifetime(options.cacheLifetime);
|
|
6910
|
+
}
|
|
6583
6911
|
if (options?.refreshOnMutation !== void 0) this.refreshOnMutation = options.refreshOnMutation;
|
|
6584
6912
|
if (options?.contextKey) this.contextKey = options.contextKey;
|
|
6585
6913
|
if (options?.encryption) {
|
|
@@ -7617,6 +7945,20 @@ class CServerSessionCache extends ACacheProvider {
|
|
|
7617
7945
|
async removeByPrefix(prefix, context) {
|
|
7618
7946
|
const fullPrefix = "cache:" + prefix;
|
|
7619
7947
|
try {
|
|
7948
|
+
if (!context || context === true || context?.allSessions === true) {
|
|
7949
|
+
for (const sessionData2 of CServerSessionCache.storage.values()) {
|
|
7950
|
+
const keysToDelete = [];
|
|
7951
|
+
for (const key of sessionData2.keys()) {
|
|
7952
|
+
if (key.startsWith(fullPrefix)) {
|
|
7953
|
+
keysToDelete.push(key);
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
for (const key of keysToDelete) {
|
|
7957
|
+
sessionData2.delete(key);
|
|
7958
|
+
}
|
|
7959
|
+
}
|
|
7960
|
+
return;
|
|
7961
|
+
}
|
|
7620
7962
|
const sessionId = await this.getSessionId(context);
|
|
7621
7963
|
const sessionData = CServerSessionCache.storage.get(sessionId);
|
|
7622
7964
|
if (sessionData) {
|
|
@@ -7815,6 +8157,7 @@ const CBrowserSessionCache$1 = {
|
|
|
7815
8157
|
|
|
7816
8158
|
class CLocalStorageCache extends ACacheProvider {
|
|
7817
8159
|
static instance = null;
|
|
8160
|
+
static _writeCount = 0;
|
|
7818
8161
|
static getInstance() {
|
|
7819
8162
|
if (!this.instance) {
|
|
7820
8163
|
this.instance = new CLocalStorageCache();
|
|
@@ -8019,12 +8362,17 @@ class CLocalStorageCache extends ACacheProvider {
|
|
|
8019
8362
|
accessCount: 1
|
|
8020
8363
|
};
|
|
8021
8364
|
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8365
|
+
const nearEntriesLimit = Boolean(
|
|
8366
|
+
this.quotaOptions.maxEntries && localStorage.length >= this.quotaOptions.maxEntries * this.quotaOptions.quotaThresholdRatio
|
|
8367
|
+
);
|
|
8368
|
+
if (nearEntriesLimit || ++CLocalStorageCache._writeCount % 50 === 0) {
|
|
8369
|
+
try {
|
|
8370
|
+
const usage = this.estimateStorageUsage();
|
|
8371
|
+
if (usage.isNearQuota) {
|
|
8372
|
+
this.evictLRU(0.25);
|
|
8373
|
+
}
|
|
8374
|
+
} catch (e) {
|
|
8026
8375
|
}
|
|
8027
|
-
} catch (e) {
|
|
8028
8376
|
}
|
|
8029
8377
|
const serialized = JSON.stringify(entry);
|
|
8030
8378
|
try {
|
|
@@ -8242,7 +8590,7 @@ class CIndexedDBCache extends ACacheProvider {
|
|
|
8242
8590
|
quota = estimate.quota || 0;
|
|
8243
8591
|
usage = estimate.usage || 0;
|
|
8244
8592
|
ratio = quota > 0 ? usage / quota : 0;
|
|
8245
|
-
if (ratio >= this.quotaOptions.quotaThresholdRatio) {
|
|
8593
|
+
if (ratio >= this.quotaOptions.quotaThresholdRatio || this.quotaOptions.maxSizeBytes > 0 && usage >= this.quotaOptions.maxSizeBytes * this.quotaOptions.quotaThresholdRatio) {
|
|
8246
8594
|
isNearQuota = true;
|
|
8247
8595
|
}
|
|
8248
8596
|
} catch {
|
|
@@ -8588,6 +8936,7 @@ exports.createEncryptionProvider = createEncryptionProvider;
|
|
|
8588
8936
|
exports.debounce = debounce;
|
|
8589
8937
|
exports.decryptPageRows = decryptPageRows;
|
|
8590
8938
|
exports.evaluateFilter = evaluateFilter;
|
|
8939
|
+
exports.fastKeyHash = fastKeyHash;
|
|
8591
8940
|
exports.fetchWithSSR = fetchWithSSR;
|
|
8592
8941
|
exports.filterData = filterData;
|
|
8593
8942
|
exports.filterTreeData = filterTreeData;
|
|
@@ -8595,14 +8944,23 @@ exports.getAppRoute = getAppRoute;
|
|
|
8595
8944
|
exports.getAppRouter = getAppRouter;
|
|
8596
8945
|
exports.getCipherProvider = getCipherProvider;
|
|
8597
8946
|
exports.getHydrationAdapter = getHydrationAdapter;
|
|
8947
|
+
exports.getKeyIdentifier = getKeyIdentifier;
|
|
8598
8948
|
exports.getPlatformApp = getPlatformApp;
|
|
8949
|
+
exports.getRandomValues = getRandomValues;
|
|
8599
8950
|
exports.getSSRData = getSSRData;
|
|
8600
8951
|
exports.getSSRPayload = getSSRPayload;
|
|
8952
|
+
exports.getSafeKeyIdentifier = getSafeKeyIdentifier;
|
|
8953
|
+
exports.getSubtleCrypto = getSubtleCrypto;
|
|
8601
8954
|
exports.isDataEncrypted = isDataEncrypted;
|
|
8602
8955
|
exports.isEncrypted = isEncrypted;
|
|
8603
8956
|
exports.onPlatformReady = onPlatformReady;
|
|
8957
|
+
exports.resolveInfoBytes = resolveInfoBytes;
|
|
8958
|
+
exports.safeSetProperty = safeSetProperty;
|
|
8604
8959
|
exports.setHydrationAdapter = setHydrationAdapter;
|
|
8605
8960
|
exports.sortData = sortData;
|
|
8961
|
+
exports.textDecoder = textDecoder;
|
|
8962
|
+
exports.textEncoder = textEncoder;
|
|
8963
|
+
exports.toBase64 = toBase64;
|
|
8606
8964
|
exports.useDebounce = useDebounce;
|
|
8607
8965
|
exports.useFilterLogic = useFilterLogic;
|
|
8608
8966
|
exports.useSortLogic = useSortLogic;
|