@quantiya/codevibe-core 2.0.74 → 2.0.76

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.
@@ -8605,15 +8605,9 @@ function parseCompanionSyncState(value, environment, now = Date.now()) {
8605
8605
  let date = new Date(value.observedAtEpochMs), resetAt = Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1);
8606
8606
  (value.periodId !== date.toISOString().slice(0, 7) || value.resetAtEpochMs !== resetAt || value.validUntilEpochMs > resetAt) && invalid2(), count(value.usage.usageRevision);
8607
8607
  let gap2 = count(value.usage.gapStartedAtEpochMs), periodStart = Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
8608
- gap2 !== 0n && (gap2 < BigInt(periodStart) || gap2 > BigInt(value.observedAtEpochMs)) && invalid2();
8609
- let state = "ACTIVE";
8610
- for (let meter of METERS) {
8611
- let committed = count(value.usage[`${meter}Committed`]);
8612
- count(value.usage[`${meter}Reserved`]);
8613
- let limit = count(value.usage[`${meter}Limit`]), pausedAtLimit = count(value.usage[`${meter}PauseLimit`]);
8614
- pausedAtLimit > 0n && gap2 === 0n && invalid2(), value.usage[`${meter}Limit`] !== value.limits[meter] && invalid2(), meter === "syncUnits" && (committed >= limit || pausedAtLimit >= limit) ? state = "PAUSED" : committed * 5n >= limit * 4n && state !== "PAUSED" && (state = "WARNING");
8615
- }
8616
- value.usage.syncState !== state && invalid2();
8608
+ gap2 !== 0n && (gap2 < BigInt(periodStart) || gap2 > BigInt(value.observedAtEpochMs)) && invalid2(), ["ACTIVE", "WARNING", "PAUSED"].includes(value.usage.syncState) || invalid2();
8609
+ for (let meter of METERS)
8610
+ count(value.usage[`${meter}Committed`]), count(value.usage[`${meter}Reserved`]), count(value.usage[`${meter}Limit`]), count(value.usage[`${meter}PauseLimit`]) > 0n && gap2 === 0n && invalid2(), value.usage[`${meter}Limit`] !== value.limits[meter] && invalid2();
8617
8611
  } else (value.protocol === "SYNC_V2" && value.mode !== "SHADOW" || value.mode === "ROLLBACK_FREEZE" && value.protocol !== "FROZEN" || value.usage !== null || value.periodId !== null || value.resetAtEpochMs !== null) && invalid2();
8618
8612
  if (value.accountingGeneration === null && (value.mode !== "LEGACY" || value.controlGeneration !== 0) && invalid2(), value.accountingGeneration !== null && value.controlGeneration < 1 && invalid2(), value.usage?.syncState === "PAUSED") {
8619
8613
  let notice2 = value.quotaNotice;
@@ -10300,7 +10294,7 @@ var SyncJournalError = class extends Error {
10300
10294
  this.code = code;
10301
10295
  this.name = "SyncJournalError";
10302
10296
  }
10303
- }, UUID8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, MAX_RECORD_BYTES = 1024 * 1024, MAX_ENVELOPE_BYTES = 2 * MAX_RECORD_BYTES, MAX_FILES = 256, MAX_STORE_BYTES = 32 * 1024 * 1024, MAX_RETIREMENT_INTENTS = 16, MAX_RETIREMENT_BYTES = 32 * 1024, invalid7 = () => {
10297
+ }, UUID8 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, MAX_RECORD_BYTES = 1024 * 1024, MAX_ENVELOPE_BYTES = 2 * MAX_RECORD_BYTES, MAX_FILES = 256, MAX_STORE_BYTES = 32 * 1024 * 1024, MAX_RETIREMENT_INTENTS = 16, MAX_RETIREMENT_BYTES = 32 * 1024, MAX_INVENTORY_FILES = MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8, MAX_DIRECTORY_ENTRIES = MAX_INVENTORY_FILES * 4 + MAX_FILES + MAX_RETIREMENT_INTENTS * 2 + 8, invalid7 = () => {
10304
10298
  throw new SyncJournalError("SYNC_JOURNAL_INVALID");
10305
10299
  }, errorCode = (error) => error?.code;
10306
10300
  function operationId(value) {
@@ -10493,7 +10487,7 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10493
10487
  }) : (this.options.assertAccount(), []);
10494
10488
  }
10495
10489
  /** One encrypted intent/credential record per original desktop incarnation.
10496
- * This uses the account journal's existing 256-file / 32-MiB total bound. */
10490
+ * Bookkeeping shares the 32-MiB bound, but not outbound-operation slots. */
10497
10491
  desktopRegistration(register, now = Date.now) {
10498
10492
  let scope = this.sessionScope;
10499
10493
  if (!scope || typeof register != "function") return invalid7();
@@ -11129,6 +11123,14 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11129
11123
  let plan = await this.withStore((key) => this.retiredSourcePlan(key, input.expectedSessionKeyGen));
11130
11124
  if (!plan.sources.length) return { sourcesRemoved: 0, operationsRemoved: 0 };
11131
11125
  parseSyncSessionRetirementReceipt(await confirm(input), input), this.options.assertAccount();
11126
+ let total = { sourcesRemoved: 0, operationsRemoved: 0 };
11127
+ for (let page = 0; page < MAX_INVENTORY_FILES; page++) {
11128
+ let removed = await this.removeRetiredSourceBatch(plan, input.expectedSessionKeyGen);
11129
+ if (total.sourcesRemoved += removed.sourcesRemoved, total.operationsRemoved += removed.operationsRemoved, plan = await this.withStore((key) => this.retiredSourcePlan(key, input.expectedSessionKeyGen)), !plan.sources.length) return total;
11130
+ }
11131
+ throw new SyncJournalError("SYNC_OPERATION_PENDING");
11132
+ }
11133
+ async removeRetiredSourceBatch(plan, expectedSessionKeyGen) {
11132
11134
  let owners = [], fence = async () => {
11133
11135
  this.options.assertAccount();
11134
11136
  for (let owner of owners) if (!await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
@@ -11143,7 +11145,7 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11143
11145
  if (owners.push(owner), this.options.assertAccount(), !await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
11144
11146
  }
11145
11147
  return await this.withStore(async (key, storeFence) => {
11146
- let current = await this.retiredSourcePlan(key, input.expectedSessionKeyGen);
11148
+ let current = await this.retiredSourcePlan(key, expectedSessionKeyGen);
11147
11149
  if (current.digest !== plan.digest) throw new SyncJournalError("SYNC_OPERATION_PENDING");
11148
11150
  await fence();
11149
11151
  for (let name of current.operations)
@@ -11202,15 +11204,20 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11202
11204
  }
11203
11205
  async retiredSourcePlan(key, expectedSessionKeyGen) {
11204
11206
  if (!this.sessionScope) return invalid7();
11205
- let sources = [], operations = [], images = [], linked = /* @__PURE__ */ new Set(), outer = /* @__PURE__ */ new Set(), inner = /* @__PURE__ */ new Set(), expectedInputs = /* @__PURE__ */ new Map(), bind = (value) => {
11207
+ let sources = [], operations = [], images = [], linked = /* @__PURE__ */ new Set(), outer = /* @__PURE__ */ new Set(), inner = /* @__PURE__ */ new Set(), selectedLinks = /* @__PURE__ */ new Set(), sourceCount = 0, linkedOperationCount = 0, expectedInputs = /* @__PURE__ */ new Map(), bind = (value) => {
11206
11208
  let input = request2("CREATE_EVENT", value), digest2 = fingerprint("CREATE_EVENT", input), prior = expectedInputs.get(input.clientOperationId);
11207
11209
  if (prior !== void 0 && prior !== digest2) return invalid7();
11208
11210
  expectedInputs.set(input.clientOperationId, digest2);
11209
11211
  }, add = (name, row3, links, locks, innerLocks = []) => {
11210
- if (this.matchesScope(row3)) {
11211
- sources.push(name), images.push([name, row3]);
11212
- for (let id5 of links) linked.add(id5);
11213
- if (sources.length > MAX_FILES || linked.size > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11212
+ if (!this.matchesScope(row3)) return;
11213
+ sourceCount++, images.push([name, row3]);
11214
+ for (let id5 of links) linked.add(id5);
11215
+ if (sourceCount > MAX_INVENTORY_FILES || linked.size > MAX_INVENTORY_FILES * MAX_FILES)
11216
+ throw new SyncJournalError("SYNC_JOURNAL_FULL");
11217
+ let additionalLinks = links.filter((id5) => !selectedLinks.has(id5));
11218
+ if (!(sources.length >= MAX_FILES || selectedLinks.size + additionalLinks.length > MAX_FILES)) {
11219
+ sources.push(name);
11220
+ for (let id5 of links) selectedLinks.add(id5);
11214
11221
  for (let lock of locks) outer.add(lock);
11215
11222
  for (let lock of innerLocks) inner.add(lock);
11216
11223
  }
@@ -11261,16 +11268,16 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11261
11268
  let row3 = await this.read(id5, key);
11262
11269
  if (row3) {
11263
11270
  if (this.requireScope(row3), row3.action !== "CREATE_EVENT" || row3.state === "PENDING" && row3.input.expectedSessionKeyGen !== expectedSessionKeyGen || expectedInputs.has(id5) && expectedInputs.get(id5) !== row3.fingerprint) return invalid7();
11264
- operations.push(id5 + ".json"), images.push([id5 + ".json", row3]);
11271
+ linkedOperationCount++, images.push([id5 + ".json", row3]), selectedLinks.has(id5) && operations.push(id5 + ".json");
11265
11272
  }
11266
11273
  }
11267
- if (sources.length + operations.length > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11274
+ if (linkedOperationCount > MAX_FILES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11268
11275
  return {
11269
11276
  sources: sources.sort(),
11270
11277
  operations,
11271
11278
  // Even a missing operation may retain its dead sender/GC lock after an
11272
11279
  // interrupted unlink. The source's complete link set owns reclamation.
11273
- locks: [...[...outer].sort(), ...[...inner].sort(), ...[...linked].sort().map((id5) => `send-${id5}.lockdir`)],
11280
+ locks: [...[...outer].sort(), ...[...inner].sort(), ...[...selectedLinks].sort().map((id5) => `send-${id5}.lockdir`)],
11274
11281
  digest: (0, import_node_crypto14.createHash)("sha256").update((0, import_json_freeze12.canonicalize)(images)).digest("hex")
11275
11282
  };
11276
11283
  }
@@ -11529,21 +11536,21 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
11529
11536
  async recordNames(suffix = ".json") {
11530
11537
  let names = [], entries = 0, directory = await import_node_fs5.promises.opendir(this.directory);
11531
11538
  for await (let entry5 of directory) {
11532
- if (++entries > MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11533
- if (entry5.name.endsWith(suffix) && ((!entry5.isFile() || !UUID8.test(entry5.name.slice(0, -suffix.length))) && invalid7(), names.push(entry5.name), names.length > MAX_FILES))
11539
+ if (++entries > MAX_DIRECTORY_ENTRIES) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11540
+ if (entry5.name.endsWith(suffix) && ((!entry5.isFile() || !UUID8.test(entry5.name.slice(0, -suffix.length))) && invalid7(), names.push(entry5.name), names.length > (suffix === ".json" ? MAX_FILES : MAX_INVENTORY_FILES)))
11534
11541
  throw new SyncJournalError("SYNC_JOURNAL_FULL");
11535
11542
  }
11536
11543
  return names;
11537
11544
  }
11538
11545
  async checkCapacity(additionalBytes, replacedName, retirement = !1) {
11539
- let count4 = 0, bytes = additionalBytes, entries = 0, retirements = 0, directory = await import_node_fs5.promises.opendir(this.directory);
11546
+ let operations = 0, bookkeeping = 0, bytes = additionalBytes, entries = 0, retirements = 0, allocatesOperation = replacedName === void 0 || replacedName.endsWith(".json"), directory = await import_node_fs5.promises.opendir(this.directory);
11540
11547
  for await (let entry5 of directory)
11541
- if ((++entries > MAX_FILES * 4 + MAX_RETIREMENT_INTENTS * 2 + 8 || entry5.isSymbolicLink()) && invalid7(), entry5.isFile()) {
11548
+ if ((++entries > MAX_DIRECTORY_ENTRIES || entry5.isSymbolicLink()) && invalid7(), entry5.isFile()) {
11542
11549
  let stat13 = await import_node_fs5.promises.lstat(path18.join(this.directory, entry5.name));
11543
11550
  if ((!stat13.isFile() || stat13.nlink !== 1) && invalid7(), entry5.name === replacedName) continue;
11544
- entry5.name.endsWith(".retirement") && retirements++, bytes += stat13.size, count4++;
11551
+ bytes += stat13.size, entry5.name.endsWith(".json") ? operations++ : entry5.name.endsWith(".retirement") ? retirements++ : bookkeeping++;
11545
11552
  }
11546
- if (count4 >= MAX_FILES + (retirement ? MAX_RETIREMENT_INTENTS : 0) || bytes > MAX_STORE_BYTES + (retirement ? MAX_RETIREMENT_INTENTS * MAX_RETIREMENT_BYTES : 0) || retirement && retirements >= MAX_RETIREMENT_INTENTS) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11553
+ if (allocatesOperation && operations >= MAX_FILES || !allocatesOperation && !retirement && bookkeeping >= MAX_INVENTORY_FILES || bytes > MAX_STORE_BYTES + (retirement ? MAX_RETIREMENT_INTENTS * MAX_RETIREMENT_BYTES : 0) || retirement && retirements >= MAX_RETIREMENT_INTENTS) throw new SyncJournalError("SYNC_JOURNAL_FULL");
11547
11554
  }
11548
11555
  async ensureDirectory() {
11549
11556
  let current = path18.parse(this.directory).root;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.74",
3
+ "version": "2.0.76",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",