- 1A: Create & configure a new TypeScript project
- Initialize
package.json - Add
tsconfig.jsonwith standard TS settings - Set up Jest or Vitest test runner
- Initialize
- 1B: Linting & Formatting - [ ] Install ESLint / Prettier (or similar) - [ ] Add minimal lint/format config - [ ] Create a "hello world" test in
tests/hello.test.tsto verify everything works
- 2A: Define core interfaces in
src/types.ts- [ ]TransactionState- [ ]Attempt- [ ]PendingMutation- [ ]Transaction - 2B: Define Sync-related types in
src/types.ts- [ ]SyncConfig- [ ]MutationFn- [ ]MutationStrategy - 2C: Create
NonRetriableErrorinsrc/errors.ts - 2D: Create a placeholder
getLockedObjectsinsrc/utils.ts(return emptySetfor now) - 2E: Unit tests in
tests/types.test.ts- [ ] Confirm each interface/type is defined correctly - [ ] Verify basic usage or shape checking
- 3A: Implement
TransactionStoreinsrc/TransactionStore.ts- [ ]getTransactions(): Promise<Transaction[]>- [ ]putTransaction(tx: Transaction): Promise<void>- [ ]deleteTransaction(id: string): Promise<void>- [ ] Internally use IndexedDB or an equivalent library - 3B: Write tests in
tests/TransactionStore.test.ts- [ ] Confirm create/update/delete flow - [ ] Verify correct reading of stored transactions
- 4A: Create
TransactionManagerinsrc/TransactionManager.ts- [ ] Constructor acceptsTransactionStore- [ ]createTransaction(mutations: PendingMutation[], strategy: MutationStrategy): Promise<Transaction> - 4B: Add lifecycle state management - [ ]
updateTransactionState(id: string, newState: TransactionState): Promise<void>- [ ] Transitions:pending,persisting,completed,failed, etc. - 4C: Implement exponential backoff in
scheduleRetry(id: string, attemptNumber: number) - 4D: Write tests in
tests/TransactionManager.test.ts- [ ] Creating a new transaction - [ ] Changing transaction states & verifying correctness - [ ] Checking scheduled retry times (no actual timer needed, just stored times)
- 5A: Extend
TransactionManagerto handle atypefield inMutationStrategy(either'ordered'or'parallel') - 5B: Ordered logic - [ ] Enqueue new transactions if an existing one is still
persistingorqueued - 5C: Parallel logic - [ ] Immediately mark transactions
pendingorpersisting- [ ] No explicit queue - 5D: Concurrency tests in
tests/TransactionManager.test.ts- [ ] Multiple transactions in ordered mode (should not persist in parallel) - [ ] Multiple transactions in parallel mode (should run immediately)
- 6A: Create
src/useCollection.ts- [ ] ExportuseCollection(config: { sync: SyncConfig; mutationFn?: MutationFn })- [ ] Return{ data, update, insert, delete: deleteFn, withMutation } - 6B: Connect to
TransactionManager- [ ] Onupdate/insert/delete, callcreateTransaction() - 6C: Basic test in
tests/useCollection.test.ts- [ ] Render a React component using the hook - [ ] Callupdate()orinsert()- [ ] Confirm that a transaction is created (verify some state in manager or a mock function) - [ ]datacan be empty or unchanged for now
- 7A: Implement local data state inside
useCollection - 7B: On transaction creation, immediately apply changes to
data - 7C: On transaction failure, revert changes
- 7D: Write new tests in
tests/useCollection.test.ts- [ ] Simulate success ->dataremains updated - [ ] Simulate failure ->datareverts
- 8A: Add a mock
persistmethod inmutationFn- [ ] Wait ~100–500ms - [ ] 50% chance success, 50% chance fail - 8B: On failure, trigger retries in
TransactionManager- [ ] Up to 4 retries - 8C: Unit tests for retry behavior - [ ] Verify final transaction state after repeated failures ->
failed- [ ] Verify success after a retry ->completed- [ ] Check local data for revert vs. final updates
- 9A: For ordered mode, block subsequent transactions while one is
persisting- [ ] Release lock afterpersistingtransaction completes - 9B: Provide a minimal or no-op merge function for parallel mode - [ ] Reapply optimistic updates on new sync data
- 9C: Allow a custom merge function to be passed in
- 9D: Add concurrency tests - [ ] Locking logic in ordered mode - [ ] Parallel concurrency with merges
- 10A: Implement a real or mock
setupinSyncConfig- [ ] Fetch initial data from an endpoint or test fixture - 10B: Evolve the mock
persistinto a more realistic approach - [ ] Possibly call a local in-memory server or a test-based REST endpoint - 10C: Write integration test in
tests/integration.test.ts- [ ] Confirm initial data is loaded - [ ] Perform a successful update -> data updates - [ ] Perform a failing update -> confirm revert or eventual success with retry - [ ] Ensure everything ties together end-to-end
- 11A: Utilize
NonRetriableError- [ ] E.g., if API returns 400, throwNonRetriableErrorand skip retries - 11B: Optional logging / event hooks in
TransactionManager- [ ] Provide ways to track or debug transaction states - 11C: Final code cleanup - [ ] Remove stubs/orphan code - [ ] Ensure everything is exported from
src/index.tsor a root file - 11D: Final coverage check / polish - [ ] Ensure tests cover all key flows - [ ] Document usage in a short README or doc