@quantiya/codevibe-codex-plugin 2.0.71 → 2.0.72

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.
@@ -10969,7 +10969,7 @@ function coerceAwsJsonObject(raw, op) {
10969
10969
  }
10970
10970
  var AppSyncGraphQLError = class extends Error {
10971
10971
  constructor(opts) {
10972
- super(`GraphQL error: ${opts.message}`), this.name = "AppSyncGraphQLError", this.responseMessage = opts.message, this.errorType = opts.errorType, this.extensions = opts.extensions, this.path = opts.path;
10972
+ super(`GraphQL error: ${opts.message}`), this.name = "AppSyncGraphQLError", this.responseMessage = opts.message, this.errorType = opts.errorType, this.data = opts.data, this.extensions = opts.extensions, this.path = opts.path;
10973
10973
  }
10974
10974
  }, AppSyncAuthenticationError = class extends Error {
10975
10975
  constructor(kind) {
@@ -11032,6 +11032,10 @@ var AppSyncClient = class _AppSyncClient {
11032
11032
  this.syncDisplayAppliedSequence = 0;
11033
11033
  this.syncDisplay = null;
11034
11034
  this.syncDisplayListeners = /* @__PURE__ */ new Set();
11035
+ /** Passive server-denial deadlines shared by existing source retry owners.
11036
+ * Exactly two producer families; no timer, durable state or admission grant. */
11037
+ this.syncProducerEpoch = 0;
11038
+ this.syncProducerRetry = /* @__PURE__ */ new Map();
11035
11039
  this.activeSubscriptions = /* @__PURE__ */ new Map();
11036
11040
  /**
11037
11041
  * Set by `authenticateWithStoredTokens()` on every false-return path
@@ -11187,7 +11191,7 @@ var AppSyncClient = class _AppSyncClient {
11187
11191
  * Authenticate using stored OAuth tokens from keychain
11188
11192
  */
11189
11193
  async authenticateWithStoredTokens() {
11190
- this.lastAuthFailureKind = null, this.lastAuthFailureDetail = null, this.resetCompanionSyncDisplay();
11194
+ this.lastAuthFailureKind = null, this.lastAuthFailureDetail = null, this.resetSyncProducerAuthority(), this.resetCompanionSyncDisplay();
11191
11195
  try {
11192
11196
  let tokens;
11193
11197
  try {
@@ -11507,12 +11511,12 @@ var AppSyncClient = class _AppSyncClient {
11507
11511
  * Sign out
11508
11512
  */
11509
11513
  signOut() {
11510
- this.authenticated = !1, this.replaceTokens(null), this.currentUserId = null, this.currentEmail = null, this.resetCompanionSyncDisplay(), this.cleanupSubscriptions(), logger.info("[AppSyncClient] Signed out");
11514
+ this.resetSyncProducerAuthority(), this.authenticated = !1, this.replaceTokens(null), this.currentUserId = null, this.currentEmail = null, this.resetCompanionSyncDisplay(), this.cleanupSubscriptions(), logger.info("[AppSyncClient] Signed out");
11511
11515
  }
11512
11516
  /**
11513
11517
  * Make a GraphQL request
11514
11518
  */
11515
- async graphqlRequest(query, variables, isRetry = !1, signal, expectedUserId, maxResponseBytes) {
11519
+ async graphqlRequest(query, variables, isRetry = !1, signal, expectedUserId, maxResponseBytes, beforeSend) {
11516
11520
  _AppSyncClient.throwIfAborted(signal), expectedUserId !== void 0 && this.assertSyncAccount(expectedUserId);
11517
11521
  let config = getConfig();
11518
11522
  if (!this.tokens?.idToken)
@@ -11520,7 +11524,9 @@ var AppSyncClient = class _AppSyncClient {
11520
11524
  let headers = {
11521
11525
  "Content-Type": "application/json",
11522
11526
  Authorization: this.tokens.idToken
11523
- }, response = await fetchWithDiagnostics(
11527
+ };
11528
+ beforeSend?.();
11529
+ let response = await fetchWithDiagnostics(
11524
11530
  config.aws.appsyncUrl,
11525
11531
  {
11526
11532
  method: "POST",
@@ -11536,7 +11542,7 @@ var AppSyncClient = class _AppSyncClient {
11536
11542
  logger.info("[AppSyncClient] 401 Unauthorized, refreshing token..."), _AppSyncClient.throwIfAborted(signal);
11537
11543
  let refreshed = await this.refreshTokens(this.tokens, signal);
11538
11544
  if (_AppSyncClient.throwIfAborted(signal), refreshed)
11539
- return this.graphqlRequest(query, variables, !0, signal, expectedUserId, maxResponseBytes);
11545
+ return this.graphqlRequest(query, variables, !0, signal, expectedUserId, maxResponseBytes, beforeSend);
11540
11546
  throw new AppSyncAuthenticationError(
11541
11547
  this.lastRefreshNetworkError ? "refresh_network" : "refresh_auth_rejected"
11542
11548
  );
@@ -11549,6 +11555,7 @@ var AppSyncClient = class _AppSyncClient {
11549
11555
  throw new AppSyncGraphQLError({
11550
11556
  message: first.message,
11551
11557
  errorType: first.errorType,
11558
+ data: first.data,
11552
11559
  extensions: first.extensions,
11553
11560
  path: first.path
11554
11561
  });
@@ -11634,6 +11641,9 @@ var AppSyncClient = class _AppSyncClient {
11634
11641
  logger.warn("[AppSyncClient] Companion status display listener failed");
11635
11642
  }
11636
11643
  }
11644
+ resetSyncProducerAuthority() {
11645
+ this.syncProducerEpoch++, this.syncProducerRetry.clear();
11646
+ }
11637
11647
  resetCompanionSyncDisplay() {
11638
11648
  this.syncDisplayEpoch += 1, this.syncDisplay = null, this.syncDisplayAppliedSequence = this.syncDisplaySequence;
11639
11649
  for (let entry5 of this.syncDisplayListeners) this.notifyCompanionSyncDisplay(entry5);
@@ -12440,10 +12450,18 @@ var AppSyncClient = class _AppSyncClient {
12440
12450
  }
12441
12451
  async mutateDesktopSyncEvent(action, input, signal) {
12442
12452
  _AppSyncClient.throwIfAborted(signal);
12443
- let data = snapshotDesktopSyncInput(action, input), userId = this.getCurrentUserId();
12444
- this.assertSyncAccount(userId);
12453
+ let data = snapshotDesktopSyncInput(action, input), userId = this.getCurrentUserId(), epoch = this.syncProducerEpoch, deniedLocally = !1, check = () => {
12454
+ if (this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), epoch !== this.syncProducerEpoch) throw new SyncEventClientError("SYNC_ACCOUNT_CHANGED");
12455
+ for (let family of ["PRODUCER", "ENRICHMENT"]) {
12456
+ if (family === "ENRICHMENT" && action !== "UPDATE_EVENT") continue;
12457
+ let cooldown = this.syncProducerRetry.get(family);
12458
+ if (cooldown?.userId === userId && cooldown.epoch === epoch && cooldown.retryAtMs > Date.now())
12459
+ throw deniedLocally = !0, cooldown.error;
12460
+ }
12461
+ };
12462
+ check();
12445
12463
  let identity = await keychainManager.getDeviceIdentity();
12446
- if (this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), !identity) throw new SyncEventClientError("SYNC_IDENTITY_UNAVAILABLE");
12464
+ if (check(), !identity) throw new SyncEventClientError("SYNC_IDENTITY_UNAVAILABLE");
12447
12465
  let prepared = signDesktopSyncInput(
12448
12466
  action,
12449
12467
  data,
@@ -12452,9 +12470,16 @@ var AppSyncClient = class _AppSyncClient {
12452
12470
  Date.now()
12453
12471
  ), field2 = action === "CREATE_EVENT" ? "createEventV2" : "updateEventV2", response;
12454
12472
  try {
12455
- response = await this.graphqlRequest(mutations[field2], { input: prepared }, !1, signal, userId);
12473
+ response = await this.graphqlRequest(mutations[field2], { input: prepared }, !1, signal, userId, void 0, check);
12456
12474
  } catch (error) {
12457
- if (this.assertSyncAccount(userId), error instanceof AppSyncGraphQLError && error.errorType === "SYNC_QUOTA_EXHAUSTED") {
12475
+ if (this.assertSyncAccount(userId), !deniedLocally && epoch === this.syncProducerEpoch && error instanceof AppSyncGraphQLError) {
12476
+ let serverDelay = error.data && typeof error.data == "object" && !Array.isArray(error.data) ? error.data.retryAfterMs : void 0, retryFamily = error.errorType === "PRODUCER_RETRY_AFTER" ? "PRODUCER" : action === "UPDATE_EVENT" && error.errorType === "UPDATE_ENRICHMENT_RETRY_AFTER" ? "ENRICHMENT" : null, family = retryFamily ?? "PRODUCER", delay = retryFamily !== null && typeof serverDelay == "number" && Number.isSafeInteger(serverDelay) && serverDelay >= 0 ? Math.max(1, serverDelay) : error.errorType === "CONTROL_BREAKER_CONTENTION" ? 1e4 : null;
12477
+ if (delay !== null) {
12478
+ let retryAtMs = Date.now() + delay, prior = this.syncProducerRetry.get(family);
12479
+ Number.isSafeInteger(retryAtMs) && (!prior || prior.userId !== userId || prior.epoch !== epoch || prior.retryAtMs < retryAtMs) && this.syncProducerRetry.set(family, { userId, epoch, retryAtMs, error });
12480
+ }
12481
+ }
12482
+ if (error instanceof AppSyncGraphQLError && error.errorType === "SYNC_QUOTA_EXHAUSTED") {
12458
12483
  let displayed = this.syncDisplay?.userId === userId ? this.syncDisplay.state : null;
12459
12484
  if (displayed?.usage?.syncState !== "PAUSED" || displayed.validUntilEpochMs <= Date.now()) {
12460
12485
  try {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.62",
3
+ "version": "2.0.63",
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-codex-plugin",
3
- "version": "2.0.71",
3
+ "version": "2.0.72",
4
4
  "description": "Control OpenAI Codex CLI from your iPhone and Android — real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
5
5
  "main": "dist/server.js",
6
6
  "codevibe": {
@@ -47,7 +47,7 @@
47
47
  "node": ">=22.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@quantiya/codevibe-core": "^2.0.62",
50
+ "@quantiya/codevibe-core": "^2.0.63",
51
51
  "@quantiya/quorum-core": "^1.0.1",
52
52
  "chokidar": "^4.0.0",
53
53
  "dotenv": "^16.6.1",