Skip to content

Commit 8cdc129

Browse files
committed
chore: remove retryable
1 parent 2f6c67c commit 8cdc129

File tree

8 files changed

+4
-139
lines changed

8 files changed

+4
-139
lines changed

ARCHITECTURE.md

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -168,22 +168,6 @@ Implement `StateHandler` for any shape. The contract:
168168
- **Fail:** stashes the transition (reverts to the trailing fallback)
169169
- **Use case:** user deletes an entity, server rejects — undo the deletion, restore the entity
170170

171-
### Retry
172-
173-
Retry is always a consumer concern — timing, backoff, and reconnect logic belong in your app. The library provides:
174-
175-
```typescript
176-
import { retryTransition, selectFailedTransition, selectRetryCount } from '@lostsolution/optimistron';
177-
178-
const failed = selectFailedTransition(id)(state.todos);
179-
if (failed) {
180-
const retries = selectRetryCount(id)(state.todos);
181-
if (retries < 3) dispatch(retryTransition(failed)); // strips failure flags, re-stages
182-
}
183-
```
184-
185-
When `processTransition` overwrites a failed transition (re-stage or amend after fail), it increments `retryCount` and sets `lastRetry` (timestamp).
186-
187171
---
188172

189173
## Async Patterns
@@ -356,10 +340,6 @@ const crud = crudPrepare<ProjectTodo>()(['projectId', 'id']);
356340
// transitionId: "projectId-value/id-value"
357341
```
358342

359-
### `retryTransition(action)`
360-
361-
Strips `failed` and `conflict` flags from a `StagedAction`, returning a clean action for re-dispatch.
362-
363343
### Selectors
364344

365345
All transition selectors are curried: `selector(id)(transitionState)`.
@@ -371,7 +351,6 @@ All transition selectors are curried: `selector(id)(transitionState)`.
371351
| `selectIsConflicting(id)` | `boolean` — transition conflicts with committed state |
372352
| `selectFailedTransition(id)` | `StagedAction \| undefined` |
373353
| `selectConflictingTransition(id)` | `StagedAction \| undefined` |
374-
| `selectRetryCount(id)` | `number` — times re-staged after failure |
375354
| `selectFailedTransitions` | `(state) => StagedAction[]` — all failed in one slice |
376355
| `selectAllFailedTransitions` | `(...states) => StagedAction[]` — across slices |
377356

README.md

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -242,17 +242,6 @@ selectIsFailed(id)(state.todos); // failed?
242242
selectIsConflicting(id)(state.todos); // stale conflict?
243243
```
244244

245-
### Retry
246-
247-
```typescript
248-
import { retryTransition, selectFailedTransition, selectRetryCount } from '@lostsolution/optimistron';
249-
250-
const failed = selectFailedTransition(id)(state.todos);
251-
if (failed && selectRetryCount(id)(state.todos) < 3) {
252-
dispatch(retryTransition(failed));
253-
}
254-
```
255-
256245
### Aggregate failures
257246

258247
```typescript

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@ export {
88
selectIsConflicting,
99
selectIsFailed,
1010
selectIsOptimistic,
11-
selectRetryCount,
1211
} from './selectors/selectors';
1312
export { listState } from './state/list';
1413
export { nestedRecordState, recordState } from './state/record';
1514
export { singularState } from './state/singular';
16-
export { isTransition, Operation, OptimisticMergeResult, retryTransition, TransitionMode } from './transitions';
15+
export { isTransition, Operation, OptimisticMergeResult, TransitionMode } from './transitions';
1716

1817
export type { HandlerReducer, ReducerConfig } from './reducer';
1918
export type { ActionMatcher, BoundStateHandler, CrudActionMap, StateHandler, TransitionState, VersioningOptions, WiredStateHandler } from './state/types';

src/selectors/selectors.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,3 @@ export const selectIsConflicting =
5252

5353
/** Returns all failed transitions across multiple transition states */
5454
export const selectAllFailedTransitions = (...states: TransitionState<any>[]): StagedAction[] => states.flatMap(selectFailedTransitions);
55-
56-
/** Returns the retry count for a transition, or 0 if not found */
57-
export const selectRetryCount =
58-
(transitionId: string) =>
59-
<State>({ transitions }: TransitionState<State>): number => {
60-
const action = transitions.find((a) => getTransitionMeta(a).id === transitionId);
61-
return action ? (getTransitionMeta(action).retryCount ?? 0) : 0;
62-
};

src/transitions.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ export type Transition<T = Operation> = {
4242
conflict?: boolean;
4343
failed?: boolean;
4444
trailing?: StagedAction;
45-
retryCount?: number;
46-
lastRetry?: number;
4745
};
4846

4947
/** Extracts the transition meta definitions on an action */
@@ -84,9 +82,6 @@ export const toStaged = <P>(action: TransitionAction<Operation, P>, update: Part
8482
export const toCommit = <P>(action: TransitionAction<Operation, P>, update: Partial<Transition> = {}): CommittedAction<P> =>
8583
updateTransition({ ...action, type: toType(action.type, Operation.COMMIT) }, { ...update, operation: Operation.COMMIT });
8684

87-
/** Strips failure/conflict flags from a staged action, making it ready for re-dispatch */
88-
export const retryTransition = <P>(action: StagedAction<P>): StagedAction<P> => updateTransition(action, { failed: undefined, conflict: undefined });
89-
9085
export const processTransition = (transition: TransitionAction, transitions: StagedAction[]): StagedAction[] => {
9186
const { operation, id, mode } = getTransitionMeta(transition);
9287
const matchIdx = transitions.findIndex((entry) => id === getTransitionID(entry));
@@ -110,14 +105,11 @@ export const processTransition = (transition: TransitionAction, transitions: Sta
110105
const existingMeta = getTransitionMeta(existing);
111106
const trailing = existing.type === transition.type ? existingMeta.trailing : existing;
112107

113-
/** When overwriting a failed transition, track retry metadata */
114-
const retryMeta: Partial<Transition> = existingMeta.failed ? { retryCount: (existingMeta.retryCount ?? 0) + 1, lastRetry: Date.now() } : {};
115-
116108
/* REVERTIBLE mode stores the previous transition as a trailing transition.
117109
* This enables reversion to the previous state when stashing. */
118110
if (mode === TransitionMode.REVERTIBLE) {
119-
nextTransitions[matchIdx] = updateTransition(stage, { ...retryMeta, trailing });
120-
} else nextTransitions[matchIdx] = updateTransition(stage, retryMeta);
111+
nextTransitions[matchIdx] = updateTransition(stage, { trailing });
112+
} else nextTransitions[matchIdx] = stage;
121113

122114
return nextTransitions;
123115
}

test/integration/record.spec.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ describe('optimistron', () => {
9797

9898
expect(nextAfterRestage.state).toStrictEqual(initial.state);
9999
expect(nextAfterRestage.transitions.length).toBe(1);
100-
expect(getTransitionMeta(nextAfterRestage.transitions[0]).retryCount).toBe(1);
101-
expect(getTransitionMeta(nextAfterRestage.transitions[0]).lastRetry).toBeNumber();
102100
expect(selectOptimistic(selectState)(nextAfterRestage)).toStrictEqual({ [item.id]: item });
103101
expect(selectIsOptimistic(item.id)(nextAfterRestage)).toBe(true);
104102
expect(selectIsFailed(item.id)(nextAfterRestage)).toBe(false);
@@ -111,8 +109,6 @@ describe('optimistron', () => {
111109
expect(nextAfterAmend.state).toStrictEqual(initial.state);
112110
expect(nextAfterAmend.transitions.length).toBe(1);
113111
expect(getTransitionMeta(nextAfterAmend.transitions[0]).failed).toBe(true);
114-
expect(getTransitionMeta(nextAfterAmend.transitions[0]).retryCount).toBe(1);
115-
expect(getTransitionMeta(nextAfterAmend.transitions[0]).lastRetry).toBeNumber();
116112
expect(selectOptimistic(selectState)(nextAfterAmend)).toStrictEqual({ [item.id]: amendedItem });
117113
expect(selectIsOptimistic(item.id)(nextAfterAmend)).toBe(true);
118114
expect(selectIsFailed(item.id)(nextAfterAmend)).toBe(true);

test/unit/selectors.spec.ts

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
selectIsConflicting,
99
selectIsFailed,
1010
selectIsOptimistic,
11-
selectRetryCount,
1211
} from '~selectors/selectors';
1312
import { create, createIndexedState, createItem, indexedState, reducer, selectState } from '~test/utils';
1413
import { updateTransition } from '~transitions';
@@ -131,21 +130,4 @@ describe('selectors', () => {
131130
expect(selectAllFailedTransitions()).toEqual([]);
132131
});
133132
});
134-
135-
describe('selectRetryCount', () => {
136-
test('should return 0 for non-existent transition', () => {
137-
expect(selectRetryCount('unknown')(createIndexedState())).toBe(0);
138-
});
139-
140-
test('should return 0 for transition without retryCount', () => {
141-
const state = createIndexedState([stage]);
142-
expect(selectRetryCount(item.id)(state)).toBe(0);
143-
});
144-
145-
test('should return retryCount from transition meta', () => {
146-
const retried = updateTransition(stage, { retryCount: 3 });
147-
const state = createIndexedState([retried]);
148-
expect(selectRetryCount(item.id)(state)).toBe(3);
149-
});
150-
});
151133
});

test/unit/transitions.spec.ts

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,7 @@ import { bindReducer } from '~reducer';
44
import { bindStateFactory } from '~state/factory';
55
import { create, createIndexedState, createItem, edit, indexedState, reducer } from '~test/utils';
66
import type { StagedAction, TransitionAction } from '~transitions';
7-
import {
8-
TransitionMode,
9-
OptimisticMergeResult,
10-
getTransitionMeta,
11-
processTransition,
12-
retryTransition,
13-
sanitizeTransitions,
14-
toCommit,
15-
updateTransition,
16-
} from '~transitions';
7+
import { TransitionMode, OptimisticMergeResult, getTransitionMeta, processTransition, sanitizeTransitions, toCommit, updateTransition } from '~transitions';
178

189
const TestTransitionID = `${Math.random()}`;
1910

@@ -168,61 +159,6 @@ describe('processTransition', () => {
168159
});
169160
});
170161

171-
describe('retryTransition', () => {
172-
test('should strip failed and conflict flags', () => {
173-
const stage = transition.stage(TestTransitionID, 1);
174-
const failed = updateTransition(stage, { failed: true, conflict: true });
175-
const retried = retryTransition(failed);
176-
177-
expect(getTransitionMeta(retried).failed).toBeUndefined();
178-
expect(getTransitionMeta(retried).conflict).toBeUndefined();
179-
expect(getTransitionMeta(retried).id).toBe(TestTransitionID);
180-
expect(retried.payload).toEqual(stage.payload);
181-
});
182-
183-
test('should preserve other meta fields', () => {
184-
const stage = transition.stage(TestTransitionID, 1);
185-
const withRetry = updateTransition(stage, { failed: true, retryCount: 3, lastRetry: 12345 });
186-
const retried = retryTransition(withRetry);
187-
188-
expect(getTransitionMeta(retried).retryCount).toBe(3);
189-
expect(getTransitionMeta(retried).lastRetry).toBe(12345);
190-
});
191-
});
192-
193-
describe('processTransition retry metadata', () => {
194-
test('should increment retryCount when overwriting a failed transition', () => {
195-
const stage = transition.stage(TestTransitionID, 1);
196-
const fail = transition.fail(TestTransitionID, new Error());
197-
const restage = transition.stage(TestTransitionID, 2);
198-
199-
const afterFail = applyTransitions(stage, fail);
200-
const afterRestage = processTransition(restage, afterFail);
201-
202-
expect(getTransitionMeta(afterRestage[0]).retryCount).toBe(1);
203-
expect(getTransitionMeta(afterRestage[0]).lastRetry).toBeNumber();
204-
});
205-
206-
test('should accumulate retryCount across multiple retries', () => {
207-
const stage = transition.stage(TestTransitionID, 1);
208-
const fail1 = transition.fail(TestTransitionID, new Error());
209-
const restage1 = transition.stage(TestTransitionID, 2);
210-
const fail2 = transition.fail(TestTransitionID, new Error());
211-
const restage2 = transition.stage(TestTransitionID, 3);
212-
213-
const result = applyTransitions(stage, fail1, restage1, fail2, restage2);
214-
expect(getTransitionMeta(result[0]).retryCount).toBe(2);
215-
});
216-
217-
test('should not add retryCount when overwriting a non-failed transition', () => {
218-
const stage1 = transition.stage(TestTransitionID, 1);
219-
const stage2 = transition.stage(TestTransitionID, 2);
220-
221-
const result = applyTransitions(stage1, stage2);
222-
expect(getTransitionMeta(result[0]).retryCount).toBeUndefined();
223-
});
224-
});
225-
226162
describe('sanitizeTransition', () => {
227163
const item = createItem();
228164

0 commit comments

Comments
 (0)