@tinycloud/node-sdk 3.3.0-beta.28 → 3.3.0-beta.30

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 CHANGED
@@ -28902,6 +28902,34 @@ assertSyncEffective_fn = async function() {
28902
28902
  throw new ReplicaStorageError("GRANT_EXPIRED", "The replica grant's effective lifetime has expired.");
28903
28903
  }
28904
28904
  };
28905
+ async function listDir(dir) {
28906
+ try {
28907
+ return await (0, import_promises.readdir)(dir);
28908
+ } catch (error) {
28909
+ if (error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
28910
+ return [];
28911
+ }
28912
+ throw error;
28913
+ }
28914
+ }
28915
+ async function collectProfileOrphans(root, collectOrphans) {
28916
+ for (const partition of await listDir(root)) {
28917
+ const replicasDir = (0, import_node_path.join)(root, partition, "replicas");
28918
+ for (const replicaName of await listDir(replicasDir)) {
28919
+ await collectOrphans((0, import_node_path.join)(replicasDir, replicaName));
28920
+ }
28921
+ }
28922
+ }
28923
+ async function profileContentBytes(root, contentBytes) {
28924
+ let total = 0;
28925
+ for (const partition of await listDir(root)) {
28926
+ const replicasDir = (0, import_node_path.join)(root, partition, "replicas");
28927
+ for (const replicaName of await listDir(replicasDir)) {
28928
+ total += await contentBytes((0, import_node_path.join)(replicasDir, replicaName));
28929
+ }
28930
+ }
28931
+ return total;
28932
+ }
28905
28933
  function createSqliteReplicaStorage(options) {
28906
28934
  const root = options.dir;
28907
28935
  const profileDir = (0, import_node_path.dirname)(options.gateFile ?? (0, import_node_path.join)((0, import_node_path.dirname)(root), import_contractConstants.REPLICA_GATE_FILE));
@@ -29896,10 +29924,29 @@ function createSqliteReplicaStorage(options) {
29896
29924
  const replicaHash = replicaHashOf(spec.prefix, device.did);
29897
29925
  partitionId = `${identityKeyHash}:${replicaHash}`;
29898
29926
  const replicaDir = (0, import_node_path.join)(idDir, "replicas", replicaHash);
29899
- const store = await sqlite.SqliteReplicaStore.open(replicaDir, {
29900
- create: true,
29901
- guard: storeGuard
29902
- });
29927
+ const quota = spec.quota?.maxBytes ?? options.maxBytes;
29928
+ if (quota !== void 0 && (!Number.isSafeInteger(quota) || quota < 0)) {
29929
+ throw new TypeError(`maxBytes must be a non-negative safe integer, got ${quota}.`);
29930
+ }
29931
+ if (quota !== void 0) await collectProfileOrphans(root, sqlite.SqliteReplicaStore.collectOrphans);
29932
+ const store = await sqlite.SqliteReplicaStore.open(
29933
+ replicaDir,
29934
+ quota === void 0 ? { create: true, guard: storeGuard } : {
29935
+ create: true,
29936
+ guard: storeGuard,
29937
+ partitionId: (0, import_node_path.basename)(idDir),
29938
+ admit: async (page) => {
29939
+ await collectProfileOrphans(root, sqlite.SqliteReplicaStore.collectOrphans);
29940
+ const used = await profileContentBytes(root, sqlite.SqliteReplicaStore.contentBytes);
29941
+ if (page.blobBytes > 0 && used + page.blobBytes > quota) {
29942
+ throw new replica.ReplicaError(
29943
+ replica.ReplicaErrorCode.STORAGE_BUDGET,
29944
+ `Profile storage holds ${used} bytes; this page adds ${page.blobBytes} against a ${quota}-byte quota. Nothing was committed.`
29945
+ );
29946
+ }
29947
+ }
29948
+ }
29949
+ );
29903
29950
  let generation;
29904
29951
  try {
29905
29952
  try {