{"version":3,"file":"TransactionExecutor.cjs","sources":["../../../src/executor/TransactionExecutor.ts"],"sourcesContent":["import { createTransaction } from '@tanstack/db'\nimport { OutboxTransactionNotFoundError } from '../outbox/OutboxManager'\nimport { DefaultRetryPolicy } from '../retry/RetryPolicy'\nimport { NonRetriableError } from '../types'\nimport { withNestedSpan } from '../telemetry/tracer'\nimport type { KeyScheduler } from './KeyScheduler'\nimport type { OutboxManager } from '../outbox/OutboxManager'\nimport type {\n  OfflineConfig,\n  OfflineTransaction,\n  TransactionSignaler,\n} from '../types'\n\nconst HANDLED_EXECUTION_ERROR = Symbol(`HandledExecutionError`)\n\nexport class TransactionExecutor {\n  private scheduler: KeyScheduler\n  private outbox: OutboxManager\n  private config: OfflineConfig\n  private retryPolicy: DefaultRetryPolicy\n  private isExecuting = false\n  private executionPromise: Promise<void> | null = null\n  private offlineExecutor: TransactionSignaler\n  private retryTimer: ReturnType<typeof setTimeout> | null = null\n  private fatalError: Error | null = null\n\n  constructor(\n    scheduler: KeyScheduler,\n    outbox: OutboxManager,\n    config: OfflineConfig,\n    offlineExecutor: TransactionSignaler,\n  ) {\n    this.scheduler = scheduler\n    this.outbox = outbox\n    this.config = config\n    this.retryPolicy = new DefaultRetryPolicy(\n      Number.POSITIVE_INFINITY,\n      config.jitter ?? true,\n    )\n    this.offlineExecutor = offlineExecutor\n  }\n\n  async execute(transaction: OfflineTransaction): Promise<void> {\n    this.assertHealthy()\n    this.scheduler.schedule(transaction)\n    await this.executeAll()\n  }\n\n  async executeAll(): Promise<void> {\n    this.assertHealthy()\n    if (this.isExecuting) {\n      return this.executionPromise!\n    }\n\n    this.isExecuting = true\n    this.executionPromise = this.runExecution()\n\n    try {\n      await this.executionPromise\n    } finally {\n      this.isExecuting = false\n      this.executionPromise = null\n      this.scheduleNextRetry()\n    }\n  }\n\n  private async runExecution(): Promise<void> {\n    while (this.scheduler.getPendingCount() > 0) {\n      if (!this.canExecute()) {\n        break\n      }\n\n      const transaction = this.scheduler.getNext()\n\n      if (!transaction) {\n        break\n      }\n\n      await this.executeTransaction(transaction)\n    }\n  }\n\n  private async executeTransaction(\n    transaction: OfflineTransaction,\n  ): Promise<void> {\n    try {\n      await withNestedSpan(\n        `transaction.execute`,\n        {\n          'transaction.id': transaction.id,\n          'transaction.mutationFnName': transaction.mutationFnName,\n          'transaction.retryCount': transaction.retryCount,\n          'transaction.keyCount': transaction.keys.length,\n        },\n        async (span) => {\n          const terminalError =\n            transaction.outboxPhase === `rejection-pending`\n              ? this.getTerminalError(transaction)\n              : undefined\n          this.scheduler.markStarted(transaction)\n\n          if (transaction.retryCount > 0) {\n            span.setAttribute(`retry.attempt`, transaction.retryCount)\n          }\n\n          if (!transaction.outboxPhase) {\n            try {\n              await this.runMutationFn(transaction)\n            } catch (error) {\n              const err =\n                error instanceof Error ? error : new Error(String(error))\n\n              span.setAttribute(`result`, `error`)\n\n              await this.handleError(transaction, err)\n              ;(err as any)[HANDLED_EXECUTION_ERROR] = true\n              throw err\n            }\n          }\n\n          // A successful provider call can outlive this executor. Persist that\n          // fact before removal so a restarted executor only retries deletion.\n          const deletionPending: OfflineTransaction = transaction.outboxPhase\n            ? transaction\n            : { ...transaction, outboxPhase: `deletion-pending` }\n          try {\n            await this.removeSettledTransaction(\n              deletionPending,\n              !transaction.outboxPhase,\n            )\n          } catch (error) {\n            const storageError = error as Error\n            span.recordException(storageError)\n            span.setAttribute(`result`, `outbox_failure`)\n            this.offlineExecutor.rejectTransaction(\n              transaction.id,\n              terminalError ?? storageError,\n            )\n            throw storageError\n          }\n\n          if (terminalError) {\n            span.setAttribute(`result`, `permanent_failure`)\n            this.offlineExecutor.rejectTransaction(\n              transaction.id,\n              terminalError,\n            )\n          } else {\n            span.setAttribute(`result`, `success`)\n            this.offlineExecutor.resolveTransaction(transaction.id, undefined)\n          }\n        },\n      )\n    } catch (error) {\n      if (\n        error instanceof Error &&\n        (error as any)[HANDLED_EXECUTION_ERROR] === true\n      ) {\n        return\n      }\n\n      throw error\n    }\n  }\n\n  private async runMutationFn(transaction: OfflineTransaction): Promise<void> {\n    const mutationFn = this.config.mutationFns[transaction.mutationFnName]\n\n    if (!mutationFn) {\n      const errorMessage = `Unknown mutation function: ${transaction.mutationFnName}`\n\n      if (this.config.onUnknownMutationFn) {\n        this.config.onUnknownMutationFn(transaction.mutationFnName, transaction)\n      }\n\n      throw new NonRetriableError(errorMessage)\n    }\n\n    // Mutations are already PendingMutation objects with collections attached\n    // from the deserializer, so we can use them directly\n    const transactionWithMutations = {\n      id: transaction.id,\n      mutations: transaction.mutations,\n      metadata: transaction.metadata ?? {},\n    }\n\n    await mutationFn({\n      transaction: transactionWithMutations as any,\n      idempotencyKey: transaction.idempotencyKey,\n    })\n  }\n\n  private async handleError(\n    transaction: OfflineTransaction,\n    error: Error,\n  ): Promise<void> {\n    return withNestedSpan(\n      `transaction.handleError`,\n      {\n        'transaction.id': transaction.id,\n        'error.name': error.name,\n        'error.message': error.message,\n      },\n      async (span) => {\n        const shouldRetry = this.retryPolicy.shouldRetry(\n          error,\n          transaction.retryCount,\n        )\n\n        span.setAttribute(`shouldRetry`, shouldRetry)\n\n        if (!shouldRetry) {\n          const rejectionPending: OfflineTransaction = {\n            ...transaction,\n            outboxPhase: `rejection-pending`,\n            lastError: {\n              name: error.name,\n              message: error.message,\n              stack: error.stack,\n            },\n          }\n          console.warn(\n            `Transaction ${transaction.id} failed permanently:`,\n            error,\n          )\n          try {\n            await this.removeSettledTransaction(rejectionPending, true)\n          } catch (storageError) {\n            span.recordException(storageError as Error)\n            span.setAttribute(`result`, `outbox_failure`)\n            this.offlineExecutor.rejectTransaction(transaction.id, error)\n            throw storageError\n          }\n\n          span.setAttribute(`result`, `permanent_failure`)\n          this.offlineExecutor.rejectTransaction(transaction.id, error)\n          return\n        }\n\n        const delay = Math.max(\n          0,\n          this.retryPolicy.calculateDelay(transaction.retryCount),\n        )\n        const updatedTransaction: OfflineTransaction = {\n          ...transaction,\n          retryCount: transaction.retryCount + 1,\n          nextAttemptAt: Date.now() + delay,\n          lastError: {\n            name: error.name,\n            message: error.message,\n            stack: error.stack,\n          },\n        }\n\n        span.setAttribute(`retryDelay`, delay)\n        span.setAttribute(`nextRetryCount`, updatedTransaction.retryCount)\n\n        this.scheduler.updateTransaction(updatedTransaction)\n\n        try {\n          await this.outbox.update(transaction.id, updatedTransaction)\n          span.setAttribute(`result`, `scheduled_retry`)\n        } catch (persistError) {\n          span.recordException(persistError as Error)\n          span.setAttribute(`result`, `persist_failed`)\n          throw persistError\n        } finally {\n          this.scheduler.markFailed(transaction)\n        }\n      },\n    )\n  }\n\n  private async removeSettledTransaction(\n    transaction: OfflineTransaction,\n    persistMarker: boolean,\n  ): Promise<void> {\n    try {\n      if (persistMarker) {\n        try {\n          await this.outbox.update(transaction.id, transaction)\n        } catch (error) {\n          // A public removal can finish while the provider is still running.\n          if (!(error instanceof OutboxTransactionNotFoundError)) throw error\n        }\n      }\n      await this.outbox.remove(transaction.id)\n      this.scheduler.markCompleted(transaction)\n    } catch (error) {\n      const storageError =\n        error instanceof Error ? error : new Error(String(error))\n      this.fatalError = storageError\n      this.scheduler.markFailed(transaction)\n      this.clearRetryTimer()\n      throw storageError\n    }\n  }\n\n  assertHealthy(): void {\n    if (this.fatalError) throw this.fatalError\n  }\n\n  private getTerminalError(transaction: OfflineTransaction): Error {\n    if (!transaction.lastError)\n      throw new Error(`Terminal transaction ${transaction.id} has no error`)\n    const { name, message, stack } = transaction.lastError\n    const error =\n      name === `NonRetriableError`\n        ? new NonRetriableError(message)\n        : new Error(message)\n    error.name = name\n    error.stack = stack\n    return error\n  }\n\n  async loadPendingTransactions(): Promise<void> {\n    let removedIds: Array<string> = []\n    await this.outbox.withAll((transactions) => {\n      const { isOfflineEnabled } = this.offlineExecutor\n      if (!isOfflineEnabled) return\n      const providerPending = transactions.filter(\n        (transaction) => !transaction.outboxPhase,\n      )\n      const selectedProvider = this.config.beforeRetry\n        ? this.config.beforeRetry(providerPending)\n        : providerPending\n      const selectedById = new Map(selectedProvider.map((tx) => [tx.id, tx]))\n      const filteredTransactions = transactions.flatMap((transaction) => {\n        if (transaction.outboxPhase) return [transaction]\n        const selected = selectedById.get(transaction.id)\n        return selected ? [selected] : []\n      })\n\n      // The retry hook is user code and may synchronously revoke replay rights.\n      if (!this.offlineExecutor.isOfflineEnabled) return\n\n      const newlyLoaded = filteredTransactions.filter((transaction) =>\n        this.scheduler.schedule(transaction),\n      )\n\n      removedIds = providerPending\n        .filter(({ id }) => !selectedById.has(id))\n        .map(({ id }) => id)\n      removedIds = this.scheduler.removePendingTransactions(removedIds)\n\n      // Restore optimistic state for loaded transactions\n      // This ensures the UI shows the optimistic data while transactions are pending\n      this.restoreOptimisticState(\n        newlyLoaded.filter(\n          (transaction) => transaction.outboxPhase !== `rejection-pending`,\n        ),\n      )\n\n      // Reset retry delays for all loaded transactions so they can run immediately\n      this.resetRetryDelays()\n\n      // Schedule retry timer for loaded transactions\n      this.scheduleNextRetry()\n    })\n\n    if (removedIds.length > 0) {\n      const error = new NonRetriableError(`Transaction excluded by beforeRetry`)\n      await Promise.all(\n        removedIds.map(async (id) => {\n          try {\n            await this.outbox.remove(id)\n            this.offlineExecutor.rejectTransaction(id, error)\n          } catch (cleanupError) {\n            console.warn(\n              `Failed to remove transaction excluded by beforeRetry:`,\n              id,\n              cleanupError,\n            )\n          }\n        }),\n      )\n    }\n  }\n\n  /**\n   * Restore optimistic state from loaded transactions.\n   * Creates internal transactions to hold the mutations so the collection's\n   * state manager can show optimistic data while waiting for sync.\n   */\n  private restoreOptimisticState(\n    transactions: Array<OfflineTransaction>,\n  ): void {\n    for (const offlineTx of transactions) {\n      if (offlineTx.mutations.length === 0) {\n        continue\n      }\n\n      try {\n        // Create a restoration transaction that holds mutations for optimistic state display.\n        // It will never commit - the real mutation is handled by the offline executor.\n        const restorationTx = createTransaction({\n          id: offlineTx.id,\n          autoCommit: false,\n          mutationFn: async () => {},\n        })\n\n        // Prevent unhandled promise rejection when cleanup calls rollback()\n        // We don't care about this promise - it's just for holding mutations\n        restorationTx.isPersisted.promise.catch(() => {\n          // Intentionally ignored - restoration transactions are cleaned up\n          // via cleanupRestorationTransaction, not through normal commit flow\n        })\n\n        restorationTx.applyMutations(offlineTx.mutations)\n\n        // Register with each affected collection's state manager\n        const touchedCollections = new Set<string>()\n        for (const mutation of offlineTx.mutations) {\n          // Defensive check for corrupted deserialized data\n          // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n          if (!mutation.collection) {\n            continue\n          }\n          const collectionId = mutation.collection.id\n          if (touchedCollections.has(collectionId)) {\n            continue\n          }\n          touchedCollections.add(collectionId)\n\n          mutation.collection._state.transactions.set(\n            restorationTx.id,\n            restorationTx,\n          )\n          mutation.collection._state.recomputeOptimisticState(true)\n        }\n\n        this.offlineExecutor.registerRestorationTransaction(\n          offlineTx.id,\n          restorationTx,\n        )\n      } catch (error) {\n        console.warn(\n          `Failed to restore optimistic state for transaction ${offlineTx.id}:`,\n          error,\n        )\n      }\n    }\n  }\n\n  clear(): void {\n    this.scheduler.clear()\n    this.clearRetryTimer()\n  }\n\n  pause(): void {\n    // Retain queued work and let the issued call finish its acknowledgment.\n    this.clearRetryTimer()\n  }\n\n  getPendingCount(): number {\n    return this.scheduler.getPendingCount()\n  }\n\n  private scheduleNextRetry(): void {\n    // Clear existing timer\n    this.clearRetryTimer()\n\n    if (this.fatalError || !this.canExecute()) {\n      return\n    }\n\n    const nextRetryTime = this.getNextRetryTime()\n\n    if (nextRetryTime === null) {\n      return // No transactions pending retry\n    }\n\n    const delay = Math.max(0, nextRetryTime - Date.now())\n\n    this.retryTimer = setTimeout(() => {\n      this.executeAll().catch((error) => {\n        console.warn(`Failed to execute retry batch:`, error)\n      })\n    }, delay)\n  }\n\n  private getNextRetryTime(): number | null {\n    const allTransactions = this.scheduler.getAllPendingTransactions()\n\n    if (allTransactions.length === 0) {\n      return null\n    }\n\n    // Later transactions cannot overtake the FIFO head, even if they are ready.\n    return allTransactions[0]!.nextAttemptAt\n  }\n\n  private clearRetryTimer(): void {\n    if (this.retryTimer) {\n      clearTimeout(this.retryTimer)\n      this.retryTimer = null\n    }\n  }\n\n  private canExecute(): boolean {\n    return (\n      this.offlineExecutor.isOfflineEnabled && this.offlineExecutor.isOnline()\n    )\n  }\n\n  getRunningCount(): number {\n    return this.scheduler.getRunningCount()\n  }\n\n  resetRetryDelays(): void {\n    const allTransactions = this.scheduler.getAllPendingTransactions()\n    const updatedTransactions = allTransactions.map((transaction) => ({\n      ...transaction,\n      nextAttemptAt: Date.now(),\n    }))\n\n    this.scheduler.updateTransactions(updatedTransactions)\n  }\n}\n"],"names":["DefaultRetryPolicy","withNestedSpan","NonRetriableError","OutboxTransactionNotFoundError","createTransaction"],"mappings":"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"}