@frostpillar/frostpillar-storage-engine 0.0.1 → 0.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/README-JA.md CHANGED
@@ -207,16 +207,29 @@ const db = new Datastore({
207
207
 
208
208
  #### ペイロードバリデーション
209
209
 
210
- ペイロードは `put()`、`putMany()`、`updateById()` の呼び出しごとにバリデーションされます。以下の制限が適用されます:
210
+ ペイロードは `put()`、`putMany()`、`updateById()`、`replaceById()` の呼び出しごとにバリデーションされます。以下のデフォルト制限が適用されます:
211
211
 
212
- | 制約 | 上限 |
213
- |------|------|
214
- | ペイロード合計バイト数 | 1,048,576(1 MB) |
215
- | 最大ネスト深度 | 64 オブジェクトレベル |
216
- | キー合計数 | 4,096 |
217
- | オブジェクトあたりの最大キー数 | 256 |
218
- | キーの最大サイズ | 1,024 バイト(UTF-8) |
219
- | 文字列値の最大サイズ | 65,535 バイト(UTF-8) |
212
+ | 制約 | デフォルト | 設定キー |
213
+ |------|-----------|----------|
214
+ | ペイロード合計バイト数 | 1,048,576(1 MB) | `maxTotalBytes` |
215
+ | 最大ネスト深度 | 64 オブジェクトレベル | `maxDepth` |
216
+ | キー合計数 | 4,096 | `maxTotalKeys` |
217
+ | オブジェクトあたりの最大キー数 | 256 | `maxKeysPerObject` |
218
+ | キーの最大サイズ | 1,024 バイト(UTF-8) | `maxKeyBytes` |
219
+ | 文字列値の最大サイズ | 65,535 バイト(UTF-8) | `maxStringBytes` |
220
+
221
+ これらの制限は `payloadLimits` でデータストアごとにカスタマイズできます:
222
+
223
+ ```ts
224
+ const db = new Datastore({
225
+ payloadLimits: {
226
+ maxDepth: 8,
227
+ maxTotalBytes: 4096,
228
+ },
229
+ });
230
+ ```
231
+
232
+ 各フィールドは独立してオプションです。省略されたフィールドはデフォルト値を使用します。各値は正の安全な整数である必要があり、そうでない場合は `ConfigurationError` で構築が失敗します。
220
233
 
221
234
  追加ルール:
222
235
  - ペイロードはプレーンオブジェクトである必要があります(トップレベルで配列、関数、`BigInt` は不可)。
@@ -231,7 +244,7 @@ const db = new Datastore({
231
244
  const db = new Datastore({ skipPayloadValidation: true });
232
245
  ```
233
246
 
234
- > **警告:** バリデーションのスキップは、すべてのペイロード安全チェックを無効化します。入力が正しい形式であることが確実な場合のみ使用してください。
247
+ > **警告:** バリデーションのスキップは、すべてのペイロード安全チェックを無効化し、`payloadLimits` も無視されます。入力が正しい形式であることが確実な場合のみ使用してください。
235
248
 
236
249
  ---
237
250
 
@@ -316,6 +329,12 @@ const exists = await db.has('k1');
316
329
  const updated = await db.updateById(id, { name: 'Alice V2' });
317
330
  ```
318
331
 
332
+ **`replaceById(id, payload)`** — `_id` で指定したレコードの payload を完全に置換します。`updateById` とは異なり、新しい payload に存在しない既存フィールドは削除されます。見つかった場合は `true`、見つからなかった場合は `false` を返します。`key` や `_id` は変更されません。
333
+
334
+ ```ts
335
+ const replaced = await db.replaceById(id, { name: 'Alice V3', score: 100 });
336
+ ```
337
+
319
338
  #### 削除
320
339
 
321
340
  **`delete(key)`** — 指定キーのすべてのレコードを削除します。削除件数を返します。
@@ -336,6 +355,12 @@ const removed = await db.deleteById(id);
336
355
  const count = await db.deleteMany(['k1', 'k2']);
337
356
  ```
338
357
 
358
+ **`deleteByIds(ids)`** — `_id` の配列でレコードを削除します。実際に削除された件数を返します(存在しない id はスキップされます)。
359
+
360
+ ```ts
361
+ const count = await db.deleteByIds([id1, id2, id3]);
362
+ ```
363
+
339
364
  **`clear()`** — 全レコードを削除します。
340
365
 
341
366
  ```ts
@@ -1090,11 +1115,12 @@ try {
1090
1115
 
1091
1116
  ### ID ベース操作
1092
1117
 
1093
- | メソッド | パラメータ | 戻り値 | 説明 |
1094
- | ----------------------- | ------------------------- | ------------------------------ | -------------------- |
1095
- | `getById(id)` | `EntryId` | `Promise<KeyedRecord \| null>` | レコード ID で取得 |
1096
- | `updateById(id, patch)` | `EntryId`、payload パッチ | `Promise<boolean>` | shallow merge で更新 |
1097
- | `deleteById(id)` | `EntryId` | `Promise<boolean>` | レコード ID で削除 |
1118
+ | メソッド | パラメータ | 戻り値 | 説明 |
1119
+ | ------------------------------ | ------------------------- | ------------------------------ | ---------------------- |
1120
+ | `getById(id)` | `EntryId` | `Promise<KeyedRecord \| null>` | レコード ID で取得 |
1121
+ | `updateById(id, patch)` | `EntryId`、payload パッチ | `Promise<boolean>` | shallow merge で更新 |
1122
+ | `replaceById(id, payload)` | `EntryId`、完全な payload | `Promise<boolean>` | payload を完全置換 |
1123
+ | `deleteById(id)` | `EntryId` | `Promise<boolean>` | レコード ID で削除 |
1098
1124
 
1099
1125
  ### バルク操作
1100
1126
 
@@ -1105,6 +1131,7 @@ try {
1105
1131
  | `getMany(keys)` | キー配列 | `Promise<KeyedRecord[]>` | 複数キーのレコード |
1106
1132
  | `putMany(records)` | レコード配列 | `Promise<void>` | 複数レコードを挿入 |
1107
1133
  | `deleteMany(keys)` | キー配列 | `Promise<number>` | 複数キーのレコードを削除 |
1134
+ | `deleteByIds(ids)` | `EntryId` 配列 | `Promise<number>` | レコード ID 群で削除 |
1108
1135
  | `clear()` | — | `Promise<void>` | 全レコードを削除 |
1109
1136
 
1110
1137
  ### メタデータ
package/README.md CHANGED
@@ -207,16 +207,29 @@ const db = new Datastore({
207
207
 
208
208
  #### Payload Validation
209
209
 
210
- Payloads are validated on every `put()`, `putMany()`, and `updateById()` call. The following limits apply:
210
+ Payloads are validated on every `put()`, `putMany()`, `updateById()`, and `replaceById()` call. The following default limits apply:
211
211
 
212
- | Constraint | Limit |
213
- |------------|-------|
214
- | Total payload bytes | 1,048,576 (1 MB) |
215
- | Max nesting depth | 64 object levels |
216
- | Max total keys | 4,096 |
217
- | Max keys per object | 256 |
218
- | Max key size | 1,024 bytes (UTF-8) |
219
- | Max string value | 65,535 bytes (UTF-8) |
212
+ | Constraint | Default | Config key |
213
+ |------------|---------|------------|
214
+ | Total payload bytes | 1,048,576 (1 MB) | `maxTotalBytes` |
215
+ | Max nesting depth | 64 object levels | `maxDepth` |
216
+ | Max total keys | 4,096 | `maxTotalKeys` |
217
+ | Max keys per object | 256 | `maxKeysPerObject` |
218
+ | Max key size | 1,024 bytes (UTF-8) | `maxKeyBytes` |
219
+ | Max string value | 65,535 bytes (UTF-8) | `maxStringBytes` |
220
+
221
+ These limits can be customized per-datastore via `payloadLimits`:
222
+
223
+ ```ts
224
+ const db = new Datastore({
225
+ payloadLimits: {
226
+ maxDepth: 8,
227
+ maxTotalBytes: 4096,
228
+ },
229
+ });
230
+ ```
231
+
232
+ Each field is independently optional; omitted fields use the default value. Each value must be a positive safe integer, otherwise construction fails with `ConfigurationError`.
220
233
 
221
234
  Additional rules:
222
235
  - Payload must be a plain object (no arrays, functions, or `BigInt` at top level).
@@ -231,7 +244,7 @@ For trusted input where you control the shape, you can skip validation:
231
244
  const db = new Datastore({ skipPayloadValidation: true });
232
245
  ```
233
246
 
234
- > **Warning:** Skipping validation disables all payload safety checks. Only use this when you are certain the input is well-formed.
247
+ > **Warning:** Skipping validation disables all payload safety checks and ignores `payloadLimits`. Only use this when you are certain the input is well-formed.
235
248
 
236
249
  ---
237
250
 
@@ -316,6 +329,12 @@ All record-returning APIs include the `_id` field in the result.
316
329
  const updated = await db.updateById(id, { name: 'Alice V2' });
317
330
  ```
318
331
 
332
+ **`replaceById(id, payload)`** — fully replace the payload of a record by `_id`. Unlike `updateById`, existing fields not present in the new payload are removed. Returns `true` if found, `false` otherwise. Does not change `key` or `_id`.
333
+
334
+ ```ts
335
+ const replaced = await db.replaceById(id, { name: 'Alice V3', score: 100 });
336
+ ```
337
+
319
338
  #### Delete
320
339
 
321
340
  **`delete(key)`** — remove all records with `key`. Returns the number of records removed.
@@ -336,6 +355,12 @@ const removed = await db.deleteById(id);
336
355
  const count = await db.deleteMany(['k1', 'k2']);
337
356
  ```
338
357
 
358
+ **`deleteByIds(ids)`** — remove records by their `_id` values. Returns total deleted (non-existent ids are skipped).
359
+
360
+ ```ts
361
+ const count = await db.deleteByIds([id1, id2, id3]);
362
+ ```
363
+
339
364
  **`clear()`** — remove all records.
340
365
 
341
366
  ```ts
@@ -1090,11 +1115,12 @@ If both a deferred backend initialization failure and a backend close failure oc
1090
1115
 
1091
1116
  ### ID-Based Operations
1092
1117
 
1093
- | Method | Parameters | Returns | Description |
1094
- | ----------------------- | ------------------------ | ------------------------------ | -------------------- |
1095
- | `getById(id)` | `EntryId` | `Promise<KeyedRecord \| null>` | Get by record ID |
1096
- | `updateById(id, patch)` | `EntryId`, payload patch | `Promise<boolean>` | Shallow-merge update |
1097
- | `deleteById(id)` | `EntryId` | `Promise<boolean>` | Delete by record ID |
1118
+ | Method | Parameters | Returns | Description |
1119
+ | -------------------------- | ------------------------ | ------------------------------ | ---------------------- |
1120
+ | `getById(id)` | `EntryId` | `Promise<KeyedRecord \| null>` | Get by record ID |
1121
+ | `updateById(id, patch)` | `EntryId`, payload patch | `Promise<boolean>` | Shallow-merge update |
1122
+ | `replaceById(id, payload)` | `EntryId`, full payload | `Promise<boolean>` | Full payload replace |
1123
+ | `deleteById(id)` | `EntryId` | `Promise<boolean>` | Delete by record ID |
1098
1124
 
1099
1125
  ### Bulk Operations
1100
1126
 
@@ -1105,6 +1131,7 @@ If both a deferred backend initialization failure and a backend close failure oc
1105
1131
  | `getMany(keys)` | key array | `Promise<KeyedRecord[]>` | Records for multiple keys |
1106
1132
  | `putMany(records)` | record array | `Promise<void>` | Insert multiple records |
1107
1133
  | `deleteMany(keys)` | key array | `Promise<number>` | Delete across multiple keys |
1134
+ | `deleteByIds(ids)` | `EntryId` array | `Promise<number>` | Delete by record IDs |
1108
1135
  | `clear()` | — | `Promise<void>` | Remove all records |
1109
1136
 
1110
1137
  ### Metadata
@@ -254,6 +254,34 @@ var createCloseAggregateError = (flushError, drainError) => {
254
254
  return fallbackError;
255
255
  };
256
256
 
257
+ // src/storage/backend/encoding.ts
258
+ var computeUtf8ByteLengthJs = (value) => {
259
+ let bytes = 0;
260
+ for (let i = 0; i < value.length; i++) {
261
+ const code = value.charCodeAt(i);
262
+ if (code <= 127) {
263
+ bytes += 1;
264
+ } else if (code <= 2047) {
265
+ bytes += 2;
266
+ } else if (code >= 55296 && code <= 56319) {
267
+ const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
268
+ if (next >= 56320 && next <= 57343) {
269
+ bytes += 4;
270
+ i++;
271
+ } else {
272
+ bytes += 3;
273
+ }
274
+ } else if (code >= 56320 && code <= 57343) {
275
+ bytes += 3;
276
+ } else {
277
+ bytes += 3;
278
+ }
279
+ }
280
+ return bytes;
281
+ };
282
+ var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
283
+ var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
284
+
257
285
  // src/storage/config/config.shared.ts
258
286
  var BYTE_SIZE_MULTIPLIER = {
259
287
  B: 1,
@@ -576,34 +604,6 @@ var releaseFileLock = (backend) => {
576
604
  var import_node_fs3 = require("node:fs");
577
605
  var import_node_path3 = require("node:path");
578
606
 
579
- // src/storage/backend/encoding.ts
580
- var computeUtf8ByteLengthJs = (value) => {
581
- let bytes = 0;
582
- for (let i = 0; i < value.length; i++) {
583
- const code = value.charCodeAt(i);
584
- if (code <= 127) {
585
- bytes += 1;
586
- } else if (code <= 2047) {
587
- bytes += 2;
588
- } else if (code >= 55296 && code <= 56319) {
589
- const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
590
- if (next >= 56320 && next <= 57343) {
591
- bytes += 4;
592
- i++;
593
- } else {
594
- bytes += 3;
595
- }
596
- } else if (code >= 56320 && code <= 57343) {
597
- bytes += 3;
598
- } else {
599
- bytes += 3;
600
- }
601
- }
602
- return bytes;
603
- };
604
- var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
605
- var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
606
-
607
607
  // src/storage/btree/recordKeyIndexBTree.ts
608
608
  var import_frostpillar_btree = require("@frostpillar/frostpillar-btree");
609
609
  var clampComparatorResult = (compared) => {
@@ -723,7 +723,7 @@ var createEmptyTreeJSON = () => {
723
723
  };
724
724
  var ensureNonNegativeSafeInteger = (value, field) => {
725
725
  if (!Number.isSafeInteger(value) || typeof value !== "number" || value < 0) {
726
- throw new PageCorruptionError(`${field} must be a non-negative safe integer.`);
726
+ throw new PageCorruptionError(`${field} must be a non-negative safe integer, got ${String(value)}.`);
727
727
  }
728
728
  return value;
729
729
  };
@@ -49,6 +49,34 @@ var toErrorInstance = (error, fallbackMessage) => {
49
49
  return new Error(fallbackMessage, { cause: error });
50
50
  };
51
51
 
52
+ // src/storage/backend/encoding.ts
53
+ var computeUtf8ByteLengthJs = (value) => {
54
+ let bytes = 0;
55
+ for (let i = 0; i < value.length; i++) {
56
+ const code = value.charCodeAt(i);
57
+ if (code <= 127) {
58
+ bytes += 1;
59
+ } else if (code <= 2047) {
60
+ bytes += 2;
61
+ } else if (code >= 55296 && code <= 56319) {
62
+ const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
63
+ if (next >= 56320 && next <= 57343) {
64
+ bytes += 4;
65
+ i++;
66
+ } else {
67
+ bytes += 3;
68
+ }
69
+ } else if (code >= 56320 && code <= 57343) {
70
+ bytes += 3;
71
+ } else {
72
+ bytes += 3;
73
+ }
74
+ }
75
+ return bytes;
76
+ };
77
+ var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
78
+ var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
79
+
52
80
  // src/storage/config/config.shared.ts
53
81
  var BYTE_SIZE_MULTIPLIER = {
54
82
  B: 1,
@@ -339,34 +367,6 @@ var parseNonNegativeSafeInteger = (value, fieldName, backendName) => {
339
367
  return value;
340
368
  };
341
369
 
342
- // src/storage/backend/encoding.ts
343
- var computeUtf8ByteLengthJs = (value) => {
344
- let bytes = 0;
345
- for (let i = 0; i < value.length; i++) {
346
- const code = value.charCodeAt(i);
347
- if (code <= 127) {
348
- bytes += 1;
349
- } else if (code <= 2047) {
350
- bytes += 2;
351
- } else if (code >= 55296 && code <= 56319) {
352
- const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
353
- if (next >= 56320 && next <= 57343) {
354
- bytes += 4;
355
- i++;
356
- } else {
357
- bytes += 3;
358
- }
359
- } else if (code >= 56320 && code <= 57343) {
360
- bytes += 3;
361
- } else {
362
- bytes += 3;
363
- }
364
- }
365
- return bytes;
366
- };
367
- var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
368
- var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
369
-
370
370
  // src/storage/drivers/IndexedDB/indexedDBBackend.ts
371
371
  var IDB_MAGIC = "FPIDB_META";
372
372
  var IDB_VERSION_VALUE = 2;
@@ -459,7 +459,16 @@ var loadIndexedDBSnapshot = async (db, _objectStoreName) => {
459
459
  if (typeof treeJSON !== "object" || treeJSON === null || Array.isArray(treeJSON)) {
460
460
  throw new PageCorruptionError("treeJSON must be a non-null plain object.");
461
461
  }
462
- const currentSizeBytes = computeUtf8ByteLength(JSON.stringify(treeJSON));
462
+ let serialized;
463
+ try {
464
+ serialized = JSON.stringify(treeJSON);
465
+ } catch (err) {
466
+ throw new PageCorruptionError(
467
+ "Failed to serialize BTree snapshot for size estimation.",
468
+ { cause: err }
469
+ );
470
+ }
471
+ const currentSizeBytes = computeUtf8ByteLength(serialized);
463
472
  return { treeJSON, currentSizeBytes, commitId };
464
473
  };
465
474
  var commitIndexedDBSnapshot = async (db, _objectStoreName, treeJSON, commitId) => {
@@ -240,6 +240,34 @@ var createCloseAggregateError = (flushError, drainError) => {
240
240
  return fallbackError;
241
241
  };
242
242
 
243
+ // src/storage/backend/encoding.ts
244
+ var computeUtf8ByteLengthJs = (value) => {
245
+ let bytes = 0;
246
+ for (let i = 0; i < value.length; i++) {
247
+ const code = value.charCodeAt(i);
248
+ if (code <= 127) {
249
+ bytes += 1;
250
+ } else if (code <= 2047) {
251
+ bytes += 2;
252
+ } else if (code >= 55296 && code <= 56319) {
253
+ const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
254
+ if (next >= 56320 && next <= 57343) {
255
+ bytes += 4;
256
+ i++;
257
+ } else {
258
+ bytes += 3;
259
+ }
260
+ } else if (code >= 56320 && code <= 57343) {
261
+ bytes += 3;
262
+ } else {
263
+ bytes += 3;
264
+ }
265
+ }
266
+ return bytes;
267
+ };
268
+ var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
269
+ var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
270
+
243
271
  // src/storage/config/config.shared.ts
244
272
  var BYTE_SIZE_MULTIPLIER = {
245
273
  B: 1,
@@ -320,6 +348,11 @@ var parseLocalStorageConfig = (config) => {
320
348
  "localStorage.maxChunks must be a positive safe integer."
321
349
  );
322
350
  }
351
+ if (maxChunkChars * maxChunks > Number.MAX_SAFE_INTEGER) {
352
+ throw new ConfigurationError(
353
+ "localStorage.maxChunkChars * localStorage.maxChunks product exceeds Number.MAX_SAFE_INTEGER."
354
+ );
355
+ }
323
356
  return { keyPrefix, databaseKey, maxChunkChars, maxChunks };
324
357
  };
325
358
 
@@ -342,9 +375,12 @@ var cleanupGenerationChunks = (state, generation, knownChunkCount) => {
342
375
  return;
343
376
  }
344
377
  for (let i = 0; i < knownChunkCount; i += 1) {
345
- state.adapter.removeItem(
346
- chunkKey(state.keyPrefix, state.databaseKey, generation, i)
347
- );
378
+ try {
379
+ state.adapter.removeItem(
380
+ chunkKey(state.keyPrefix, state.databaseKey, generation, i)
381
+ );
382
+ } catch {
383
+ }
348
384
  }
349
385
  return;
350
386
  }
@@ -354,7 +390,10 @@ var cleanupGenerationChunks = (state, generation, knownChunkCount) => {
354
390
  for (let i = 0; i < state.maxChunks; i += 1) {
355
391
  const key = chunkKey(state.keyPrefix, state.databaseKey, generation, i);
356
392
  if (state.adapter.getItem(key) !== null) {
357
- state.adapter.removeItem(key);
393
+ try {
394
+ state.adapter.removeItem(key);
395
+ } catch {
396
+ }
358
397
  }
359
398
  }
360
399
  };
@@ -365,34 +404,6 @@ var isQuotaBrowserError = (error) => {
365
404
  return error.name === "QuotaExceededError" || error.name === "NS_ERROR_DOM_QUOTA_REACHED";
366
405
  };
367
406
 
368
- // src/storage/backend/encoding.ts
369
- var computeUtf8ByteLengthJs = (value) => {
370
- let bytes = 0;
371
- for (let i = 0; i < value.length; i++) {
372
- const code = value.charCodeAt(i);
373
- if (code <= 127) {
374
- bytes += 1;
375
- } else if (code <= 2047) {
376
- bytes += 2;
377
- } else if (code >= 55296 && code <= 56319) {
378
- const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
379
- if (next >= 56320 && next <= 57343) {
380
- bytes += 4;
381
- i++;
382
- } else {
383
- bytes += 3;
384
- }
385
- } else if (code >= 56320 && code <= 57343) {
386
- bytes += 3;
387
- } else {
388
- bytes += 3;
389
- }
390
- }
391
- return bytes;
392
- };
393
- var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
394
- var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
395
-
396
407
  // src/storage/drivers/localStorage/localStorageBackend.ts
397
408
  var LS_MAGIC = "FPLS_META";
398
409
  var LS_VERSION = 2;
@@ -60,6 +60,34 @@ var toErrorInstance = (error, fallbackMessage) => {
60
60
  return new Error(fallbackMessage, { cause: error });
61
61
  };
62
62
 
63
+ // src/storage/backend/encoding.ts
64
+ var computeUtf8ByteLengthJs = (value) => {
65
+ let bytes = 0;
66
+ for (let i = 0; i < value.length; i++) {
67
+ const code = value.charCodeAt(i);
68
+ if (code <= 127) {
69
+ bytes += 1;
70
+ } else if (code <= 2047) {
71
+ bytes += 2;
72
+ } else if (code >= 55296 && code <= 56319) {
73
+ const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
74
+ if (next >= 56320 && next <= 57343) {
75
+ bytes += 4;
76
+ i++;
77
+ } else {
78
+ bytes += 3;
79
+ }
80
+ } else if (code >= 56320 && code <= 57343) {
81
+ bytes += 3;
82
+ } else {
83
+ bytes += 3;
84
+ }
85
+ }
86
+ return bytes;
87
+ };
88
+ var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
89
+ var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
90
+
63
91
  // src/storage/config/config.shared.ts
64
92
  var BYTE_SIZE_MULTIPLIER = {
65
93
  B: 1,
@@ -321,34 +349,6 @@ var parseNonNegativeSafeInteger = (value, fieldName, backendName) => {
321
349
  return value;
322
350
  };
323
351
 
324
- // src/storage/backend/encoding.ts
325
- var computeUtf8ByteLengthJs = (value) => {
326
- let bytes = 0;
327
- for (let i = 0; i < value.length; i++) {
328
- const code = value.charCodeAt(i);
329
- if (code <= 127) {
330
- bytes += 1;
331
- } else if (code <= 2047) {
332
- bytes += 2;
333
- } else if (code >= 55296 && code <= 56319) {
334
- const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
335
- if (next >= 56320 && next <= 57343) {
336
- bytes += 4;
337
- i++;
338
- } else {
339
- bytes += 3;
340
- }
341
- } else if (code >= 56320 && code <= 57343) {
342
- bytes += 3;
343
- } else {
344
- bytes += 3;
345
- }
346
- }
347
- return bytes;
348
- };
349
- var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
350
- var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
351
-
352
352
  // src/storage/drivers/opfs/opfsBackend.ts
353
353
  var OPFS_MAGIC = "FPOPFS_META";
354
354
  var OPFS_VERSION_VALUE = 2;
@@ -51,6 +51,34 @@ var toErrorInstance = (error, fallbackMessage) => {
51
51
  return new Error(fallbackMessage, { cause: error });
52
52
  };
53
53
 
54
+ // src/storage/backend/encoding.ts
55
+ var computeUtf8ByteLengthJs = (value) => {
56
+ let bytes = 0;
57
+ for (let i = 0; i < value.length; i++) {
58
+ const code = value.charCodeAt(i);
59
+ if (code <= 127) {
60
+ bytes += 1;
61
+ } else if (code <= 2047) {
62
+ bytes += 2;
63
+ } else if (code >= 55296 && code <= 56319) {
64
+ const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
65
+ if (next >= 56320 && next <= 57343) {
66
+ bytes += 4;
67
+ i++;
68
+ } else {
69
+ bytes += 3;
70
+ }
71
+ } else if (code >= 56320 && code <= 57343) {
72
+ bytes += 3;
73
+ } else {
74
+ bytes += 3;
75
+ }
76
+ }
77
+ return bytes;
78
+ };
79
+ var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
80
+ var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
81
+
54
82
  // src/storage/config/config.shared.ts
55
83
  var BYTE_SIZE_MULTIPLIER = {
56
84
  B: 1,
@@ -548,8 +576,8 @@ var isQuotaBrowserError = (error) => {
548
576
  if (!(error instanceof Error)) {
549
577
  return false;
550
578
  }
551
- const normalized = `${error.name}:${error.message}`;
552
- return /quota|max_items|quota_bytes|quota_bytes_per_item/i.test(normalized);
579
+ const normalized = `${error.name}:${error.message}`.toLowerCase();
580
+ return normalized.includes("quota") || normalized.includes("max_items");
553
581
  };
554
582
  var validateSyncStorageCommitQuota = (state, generation, chunks, manifest, resolveChunkKey, manifestStorageKey) => {
555
583
  const pendingItems = chunks.map(
@@ -589,34 +617,6 @@ var validateSyncStorageCommitQuota = (state, generation, chunks, manifest, resol
589
617
  }
590
618
  };
591
619
 
592
- // src/storage/backend/encoding.ts
593
- var computeUtf8ByteLengthJs = (value) => {
594
- let bytes = 0;
595
- for (let i = 0; i < value.length; i++) {
596
- const code = value.charCodeAt(i);
597
- if (code <= 127) {
598
- bytes += 1;
599
- } else if (code <= 2047) {
600
- bytes += 2;
601
- } else if (code >= 55296 && code <= 56319) {
602
- const next = i + 1 < value.length ? value.charCodeAt(i + 1) : 0;
603
- if (next >= 56320 && next <= 57343) {
604
- bytes += 4;
605
- i++;
606
- } else {
607
- bytes += 3;
608
- }
609
- } else if (code >= 56320 && code <= 57343) {
610
- bytes += 3;
611
- } else {
612
- bytes += 3;
613
- }
614
- }
615
- return bytes;
616
- };
617
- var hasBuffer = typeof Buffer !== "undefined" && typeof Buffer.byteLength === "function";
618
- var computeUtf8ByteLength = hasBuffer ? (value) => Buffer.byteLength(value, "utf8") : computeUtf8ByteLengthJs;
619
-
620
620
  // src/storage/drivers/syncStorage/syncStorageBackend.ts
621
621
  var SYNC_STORAGE_MAGIC = "FPSYNC_META";
622
622
  var SYNC_STORAGE_VERSION = 2;