refactor: reorganize operation-log files into src/app/op-log/

Move operation-log from src/app/core/persistence/operation-log/ to
src/app/op-log/ with improved subdirectory organization:

- core/: Types, constants, errors, entity registry
- capture/: Write path (Actions → Operations)
  - operation-capture.meta-reducer.ts
  - operation-capture.service.ts
  - operation-log.effects.ts
- apply/: Read path (Operations → State)
  - bulk-hydration.action.ts/.meta-reducer.ts
  - operation-applier.service.ts
  - operation-converter.util.ts
  - hydration-state.service.ts
  - archive-operation-handler.service.ts/.effects.ts
- store/: IndexedDB persistence
  - operation-log-store.service.ts
  - operation-log-hydrator.service.ts
  - operation-log-compaction.service.ts
  - schema-migration.service.ts
- sync/: Server sync (SuperSync)
  - operation-log-sync.service.ts
  - operation-log-upload.service.ts
  - operation-log-download.service.ts
  - conflict-resolution.service.ts
  - sync-import-filter.service.ts
  - vector-clock.service.ts
  - operation-encryption.service.ts
- validation/: State validation
  - validate-state.service.ts
  - validate-operation-payload.ts
- util/: Shared utilities
  - entity-key.util.ts
  - client-id.provider.ts
- testing/: Integration tests and benchmarks

This reorganization:
- Places op-log at the same level as pfapi for better visibility
- Groups files by responsibility (write path vs read path)
- Makes the sync architecture more discoverable
- Improves navigation for developers new to the codebase
This commit is contained in:
Johannes Millan 2025-12-27 17:52:11 +01:00
parent 693e71deeb
commit d6dcc86ca0
157 changed files with 693 additions and 643 deletions

View file

@ -4,11 +4,11 @@ This checklist ensures new entity types integrate properly with the operation lo
## When adding a new entity type:
### 1. Type Definition (`src/app/core/persistence/operation-log/operation.types.ts`)
### 1. Type Definition (`src/app/op-log/core/operation.types.ts`)
- [ ] Add to `EntityType` union (line ~15)
### 2. Entity Registry (`src/app/core/persistence/operation-log/entity-registry.ts`)
### 2. Entity Registry (`src/app/op-log/core/entity-registry.ts`)
- [ ] Add entry to `ENTITY_CONFIGS` with:
- `storagePattern`: 'adapter' | 'singleton' | 'map' | 'array' | 'virtual'
@ -21,7 +21,7 @@ This checklist ensures new entity types integrate properly with the operation lo
- **array**: `selectState`, `arrayKey`
- **virtual**: just `payloadKey`
### 3. Test Arrays (`src/app/core/persistence/operation-log/entity-registry.spec.ts`)
### 3. Test Arrays (`src/app/op-log/core/entity-registry.spec.ts`)
- [ ] Add to `REGULAR_ENTITY_TYPES` array (line ~17) OR `SPECIAL_OPERATION_TYPES` if special
- [ ] Add to appropriate category array:
@ -64,11 +64,11 @@ updateTasks: (taskProps: { tasks: Update<Task>[] }) => ({
```bash
# Check the modified files
npm run checkFile src/app/core/persistence/operation-log/entity-registry.ts
npm run checkFile src/app/core/persistence/operation-log/operation.types.ts
npm run checkFile src/app/op-log/core/entity-registry.ts
npm run checkFile src/app/op-log/core/operation.types.ts
# Run the entity registry tests
npm run test:file src/app/core/persistence/operation-log/entity-registry.spec.ts
npm run test:file src/app/op-log/core/entity-registry.spec.ts
```
## Why this matters

View file

@ -5,7 +5,7 @@
> This plan has been fully implemented. For the current implementation details, see:
>
> - [supersync-encryption-architecture.md](../supersync-encryption-architecture.md) - Implementation documentation with diagrams
> - `src/app/core/persistence/operation-log/sync/operation-encryption.service.ts` - Core encryption service
> - `src/app/op-log/sync/operation-encryption.service.ts` - Core encryption service
## Summary
@ -86,7 +86,7 @@ export interface SuperSyncPrivateCfg extends SyncProviderPrivateCfgBase {
### Phase 2: Client-Side Encryption Service
**New file:** `src/app/core/persistence/operation-log/sync/operation-encryption.service.ts`
**New file:** `src/app/op-log/sync/operation-encryption.service.ts`
```typescript
import { inject, Injectable } from '@angular/core';
@ -154,7 +154,7 @@ export class OperationEncryptionService {
### Phase 3: Upload Integration
**File:** `src/app/core/persistence/operation-log/sync/operation-log-upload.service.ts`
**File:** `src/app/op-log/sync/operation-log-upload.service.ts`
Modify `_uploadPendingOpsViaApi()`:
@ -188,7 +188,7 @@ if (response.newOps && response.newOps.length > 0) {
### Phase 4: Download Integration
**File:** `src/app/core/persistence/operation-log/sync/operation-log-download.service.ts`
**File:** `src/app/op-log/sync/operation-log-download.service.ts`
Modify `_downloadRemoteOpsViaApi()`:
@ -304,22 +304,22 @@ Simple dialog to prompt for encryption password when needed:
### New Files
| File | Purpose |
| ----------------------------------------------------------------------------- | -------------------------- |
| `src/app/core/persistence/operation-log/sync/operation-encryption.service.ts` | Encrypt/decrypt operations |
| `src/app/imex/sync/dialog-encryption-password/` | Password prompt dialog |
| File | Purpose |
| ----------------------------------------------------- | -------------------------- |
| `src/app/op-log/sync/operation-encryption.service.ts` | Encrypt/decrypt operations |
| `src/app/imex/sync/dialog-encryption-password/` | Password prompt dialog |
### Modified Files
| File | Changes |
| ------------------------------------------------------------------------------- | ----------------------------------------- |
| `src/app/pfapi/api/sync/sync-provider.interface.ts` | Add `isPayloadEncrypted` to SyncOperation |
| `src/app/pfapi/api/sync/providers/super-sync/super-sync.model.ts` | Add `isEncryptionEnabled` flag |
| `src/app/core/persistence/operation-log/sync/operation-log-upload.service.ts` | Encrypt before upload |
| `src/app/core/persistence/operation-log/sync/operation-log-download.service.ts` | Decrypt after download |
| `src/app/features/config/form-cfgs/sync-form.const.ts` | Add encryption toggle + password field |
| `src/app/t.const.ts` | Add translation keys |
| `src/assets/i18n/en.json` | Add translation strings |
| File | Changes |
| ----------------------------------------------------------------- | ----------------------------------------- |
| `src/app/pfapi/api/sync/sync-provider.interface.ts` | Add `isPayloadEncrypted` to SyncOperation |
| `src/app/pfapi/api/sync/providers/super-sync/super-sync.model.ts` | Add `isEncryptionEnabled` flag |
| `src/app/op-log/sync/operation-log-upload.service.ts` | Encrypt before upload |
| `src/app/op-log/sync/operation-log-download.service.ts` | Decrypt after download |
| `src/app/features/config/form-cfgs/sync-form.const.ts` | Add encryption toggle + password field |
| `src/app/t.const.ts` | Add translation keys |
| `src/assets/i18n/en.json` | Add translation strings |
### No Server Changes Required

View file

@ -615,7 +615,7 @@ The following questions were resolved during implementation:
### Code Files
```
src/app/core/persistence/operation-log/
src/app/op-log/
├── operation.types.ts # HybridManifest, SnapshotReference types
├── store/
│ └── operation-log-manifest.service.ts # Manifest management

View file

@ -38,7 +38,7 @@ Simplify the codebase by removing PFAPI's model-by-model sync and using operatio
**New file:**
- `src/app/core/persistence/operation-log/migration/pfapi-migration.service.ts`
- `src/app/op-log/migration/pfapi-migration.service.ts`
**Migration flow:**
@ -93,10 +93,10 @@ src/app/pfapi/api/sync/providers/local-file-sync/local-file-sync-base.ts
### Operation Log Sync
```
src/app/core/persistence/operation-log/sync/operation-log-upload.service.ts
src/app/core/persistence/operation-log/sync/operation-log-download.service.ts
src/app/core/persistence/operation-log/sync/operation-log-manifest.service.ts
src/app/core/persistence/operation-log/sync/operation-log-sync.service.ts
src/app/op-log/sync/operation-log-upload.service.ts
src/app/op-log/sync/operation-log-download.service.ts
src/app/op-log/sync/operation-log-manifest.service.ts
src/app/op-log/sync/operation-log-sync.service.ts
```
### PFAPI (to simplify/remove)

View file

@ -556,7 +556,7 @@ When Super Productivity's data model changes (new fields, renamed properties, re
### Configuration
`CURRENT_SCHEMA_VERSION` is defined in `src/app/core/persistence/operation-log/schema-migration.service.ts`:
`CURRENT_SCHEMA_VERSION` is defined in `src/app/op-log/store/schema-migration.service.ts`:
```typescript
export const CURRENT_SCHEMA_VERSION = 1;
@ -730,7 +730,7 @@ async handleFullStateImport(payload: { appDataComplete: AppDataComplete }): Prom
### A.7.5 Migration Implementation
Migrations are defined in `src/app/core/persistence/operation-log/schema-migration.service.ts`.
Migrations are defined in `src/app/op-log/store/schema-migration.service.ts`.
**How to Create a New Migration:**
@ -1986,7 +1986,7 @@ When adding new entities or relationships:
# File Reference
```
src/app/core/persistence/operation-log/
src/app/op-log/
├── operation.types.ts # Type definitions (Operation, OpType, EntityType)
├── operation-log.const.ts # Constants (thresholds, timeouts, limits)
├── operation-log.effects.ts # Action capture + META_MODEL bridge

View file

@ -719,24 +719,43 @@ Remote Storage (WebDAV/Dropbox folder):
## File Reference
```
src/app/core/persistence/operation-log/
├── operation.types.ts # Type definitions
├── operation-log.const.ts # Constants
├── operation-log.effects.ts # Write path effect
├── store/
src/app/op-log/
├── core/ # Types, constants, errors
│ ├── operation.types.ts # Type definitions
│ ├── operation-log.const.ts # Constants
│ ├── persistent-action.interface.ts # Action interface
│ └── entity-registry.ts # Entity type registry
├── capture/ # Write path: Actions → Operations
│ ├── operation-capture.meta-reducer.ts # Captures persistent actions
│ ├── operation-capture.service.ts # FIFO queue
│ └── operation-log.effects.ts # Writes to IndexedDB
├── apply/ # Read path: Operations → State
│ ├── bulk-hydration.action.ts # Bulk apply action
│ ├── bulk-hydration.meta-reducer.ts # Applies ops in single pass
│ ├── operation-applier.service.ts # Apply ops to NgRx
│ ├── operation-converter.util.ts # Op → Action conversion
│ ├── hydration-state.service.ts # Tracks hydration state
│ └── archive-operation-handler.service.ts # Archive side effects
├── store/ # IndexedDB persistence
│ ├── operation-log-store.service.ts # IndexedDB wrapper
│ ├── operation-log-hydrator.service.ts # Hydration
│ ├── operation-log-hydrator.service.ts # Startup hydration
│ ├── operation-log-compaction.service.ts # Snapshot + GC
│ └── schema-migration.service.ts # Schema migrations
├── sync/
├── sync/ # Server sync (SuperSync)
│ ├── operation-log-sync.service.ts # Sync orchestration
│ ├── operation-log-upload.service.ts # Upload logic
│ ├── operation-log-download.service.ts # Download logic
│ ├── conflict-resolution.service.ts # LWW resolution
│ ├── sync-import-filter.service.ts # SYNC_IMPORT filtering
│ └── vector-clock.service.ts # Clock management
└── processing/
├── operation-applier.service.ts # Apply ops to NgRx
├── operation-capture.meta-reducer.ts # Capture actions
├── operation-capture.service.ts # FIFO queue
└── archive-operation-handler.service.ts # Archive side effects
│ ├── vector-clock.service.ts # Clock management
│ └── operation-encryption.service.ts # E2E encryption
├── validation/ # State validation
│ ├── validate-state.service.ts # State consistency checks
│ └── validate-operation-payload.ts # Operation validation
├── util/ # Shared utilities
│ ├── entity-key.util.ts # Entity key helpers
│ └── client-id.provider.ts # Client ID management
└── testing/ # Test infrastructure
├── integration/ # Integration tests
└── benchmarks/ # Performance tests
```

View file

@ -159,7 +159,7 @@ SuperSync uses **AES-256-GCM** encryption with **Argon2id** key derivation for e
### 1. OperationEncryptionService
**Location**: `src/app/core/persistence/operation-log/sync/operation-encryption.service.ts`
**Location**: `src/app/op-log/sync/operation-encryption.service.ts`
```typescript
// Encrypt before upload
@ -189,7 +189,7 @@ async decryptOperation(op: SyncOperation, encryptKey: string): Promise<SyncOpera
### 3. Upload Integration
**Location**: `src/app/core/persistence/operation-log/sync/operation-log-upload.service.ts`
**Location**: `src/app/op-log/sync/operation-log-upload.service.ts`
```typescript
// Check if encryption is enabled
@ -204,7 +204,7 @@ if (isEncryptionEnabled && encryptKey) {
### 4. Download Integration
**Location**: `src/app/core/persistence/operation-log/sync/operation-log-download.service.ts`
**Location**: `src/app/op-log/sync/operation-log-download.service.ts`
```typescript
// Decrypt if encrypted

View file

@ -6,7 +6,7 @@ import { allDataWasLoaded } from '../../root-store/meta/all-data-was-loaded.acti
import { PfapiService } from '../../pfapi/pfapi.service';
import { DataInitStateService } from './data-init-state.service';
import { UserProfileService } from '../../features/user-profile/user-profile.service';
import { OperationLogHydratorService } from '../persistence/operation-log/store/operation-log-hydrator.service';
import { OperationLogHydratorService } from '../../op-log/store/operation-log-hydrator.service';
@Injectable({ providedIn: 'root' })
export class DataInitService {

View file

@ -17,7 +17,7 @@ import { selectCurrentTask, selectCurrentTaskId } from '../../tasks/store/task.s
import { combineLatest } from 'rxjs';
import { FocusModeMode, TimerState } from '../../focus-mode/focus-mode.model';
import { DroidLog } from '../../../core/log';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
@Injectable()
export class AndroidFocusModeEffects {

View file

@ -19,7 +19,7 @@ import { DateService } from '../../../core/date/date.service';
import { Task } from '../../tasks/task.model';
import { selectTimer } from '../../focus-mode/store/focus-mode.selectors';
import { combineLatest } from 'rxjs';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
@Injectable()
export class AndroidForegroundTrackingEffects {

View file

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { createAction } from '@ngrx/store';
import { BoardCfg, BoardPanelCfg } from '../boards.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const addBoard = createAction(
'[Boards] Add Board',

View file

@ -1,7 +1,7 @@
import { createAction } from '@ngrx/store';
import { GlobalConfigSectionKey, GlobalSectionConfig } from '../global-config.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const updateGlobalConfigSection = createAction(
'[Global Config] Update Global Config Section',

View file

@ -1,8 +1,8 @@
import { createActionGroup, emptyProps, props } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { IssueProvider } from '../issue.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
/* eslint-disable @typescript-eslint/naming-convention */

View file

@ -6,7 +6,7 @@
* @see ArchiveOperationHandler._handleDeleteIssueProvider
* @see ArchiveOperationHandler._handleDeleteIssueProviders
* @see ArchiveOperationHandlerEffects at:
* src/app/core/persistence/operation-log/processing/archive-operation-handler.effects.ts
* src/app/op-log/apply/archive-operation-handler.effects.ts
*
* All archive-affecting operations are now routed through ArchiveOperationHandler,
* which is the SINGLE SOURCE OF TRUTH for archive storage operations.

View file

@ -1,7 +1,7 @@
import { createAction } from '@ngrx/store';
import { MenuTreeKind, MenuTreeTreeNode } from './menu-tree.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
type MenuTreeItemKind = MenuTreeKind.PROJECT | MenuTreeKind.TAG;

View file

@ -1,8 +1,8 @@
import { createAction } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { Metric } from '../metric.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
enum MetricActionTypes {
'AddMetric' = '[Metric] Add Metric',

View file

@ -2,8 +2,8 @@ import { createAction } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { Note } from '../note.model';
import { WorkContextType } from '../../work-context/work-context.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const updateNoteOrder = createAction(
'[Note] Update Note Order',

View file

@ -1,8 +1,8 @@
import { createActionGroup } from '@ngrx/store';
import { ADD_TASK_PANEL_ID } from '../planner.model';
import { TaskCopy } from '../../tasks/task.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
/* eslint-disable @typescript-eslint/naming-convention */

View file

@ -3,8 +3,8 @@ import { Update } from '@ngrx/entity';
import { Project } from '../project.model';
import { WorkContextAdvancedCfgKey } from '../../work-context/work-context.model';
import { DropListModelSource } from '../../tasks/task.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const setCurrentProject = createAction(
'[Project] SetCurrentProject',

View file

@ -1,8 +1,8 @@
import { createAction, props } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { SimpleCounter } from '../simple-counter.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const addSimpleCounter = createAction(
'[SimpleCounter] Add SimpleCounter',

View file

@ -12,7 +12,7 @@ import {
} from '../simple-counter.model';
import { EMPTY_SIMPLE_COUNTER, DEFAULT_SIMPLE_COUNTERS } from '../simple-counter.const';
import { AppDataCompleteLegacy } from '../../../imex/sync/sync.model';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { OpType } from '../../../op-log/core/operation.types';
const createCounter = (
id: string,

View file

@ -34,7 +34,7 @@ import {
updateSimpleCounter,
upsertSimpleCounter,
} from './simple-counter.actions';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
export const SIMPLE_COUNTER_FEATURE_NAME = 'simpleCounter';

View file

@ -2,8 +2,8 @@ import { createAction } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { Tag } from '../tag.model';
import { WorkContextAdvancedCfgKey } from '../../work-context/work-context.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const addTag = createAction('[Tag] Add Tag', (tagProps: { tag: Tag }) => ({
...tagProps,

View file

@ -6,7 +6,7 @@ import { TagEffects } from './tag.effects';
import { updateTag } from './tag.actions';
import { TODAY_TAG } from '../tag.const';
import { selectTodayTagRepair } from '../../work-context/store/work-context.selectors';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
import { SnackService } from '../../../core/snack/snack.service';
import { TagService } from '../tag.service';
import { WorkContextService } from '../../work-context/work-context.service';

View file

@ -1,8 +1,8 @@
import { createAction, props } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { TaskRepeatCfg } from '../task-repeat-cfg.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const addTaskRepeatCfgToTask = createAction(
'[TaskRepeatCfg][Task] Add TaskRepeatCfg to Task',

View file

@ -21,7 +21,7 @@ import { getDbDateStr } from '../../../util/get-db-date-str';
import { TaskLog } from '../../../core/log';
import { SyncTriggerService } from '../../../imex/sync/sync-trigger.service';
import { environment } from '../../../../environments/environment';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
@Injectable()
export class TaskDueEffects {

View file

@ -7,7 +7,7 @@ import { Action } from '@ngrx/store';
import { TaskRelatedModelEffects } from './task-related-model.effects';
import { TaskService } from '../task.service';
import { GlobalConfigService } from '../../config/global-config.service';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
import { LOCAL_ACTIONS } from '../../../util/local-actions.token';
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { DEFAULT_TASK, Task } from '../task.model';

View file

@ -12,7 +12,7 @@ import { TimeTrackingActions } from '../../time-tracking/store/time-tracking.act
import { Store } from '@ngrx/store';
import { selectTodayTaskIds } from '../../work-context/store/work-context.selectors';
import { LOCAL_ACTIONS } from '../../../util/local-actions.token';
import { HydrationStateService } from '../../../core/persistence/operation-log/processing/hydration-state.service';
import { HydrationStateService } from '../../../op-log/apply/hydration-state.service';
import { getDbDateStr } from '../../../util/get-db-date-str';
@Injectable()

View file

@ -2,8 +2,8 @@ import { createAction, props } from '@ngrx/store';
import { Update } from '@ngrx/entity';
import { Task, TaskDetailTargetPanel } from '../task.model';
import { RoundTimeOption } from '../../project/project.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const setCurrentTask = createAction(
'[Task] SetCurrentTask',

View file

@ -1,4 +1,4 @@
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import {
__updateMultipleTaskSimple,
addSubTask,

View file

@ -1,8 +1,8 @@
import { Update } from '@ngrx/entity';
import { TaskAttachment } from './task-attachment.model';
import { createAction } from '@ngrx/store';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
// NOTE: all is handled in task reducer too
export const addTaskAttachment = createAction(

View file

@ -1,6 +1,6 @@
import { createAction } from '@ngrx/store';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
/**
* Non-persistent action dispatched after remote archive-affecting operations

View file

@ -3,8 +3,8 @@ import { createAction, createActionGroup, props } from '@ngrx/store';
import { WorkContextType } from '../../work-context/work-context.model';
import { TimeTrackingState, TTWorkContextData } from '../time-tracking.model';
import { Task } from '../../tasks/task.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
// Standalone persistent action for updating work context data (manual worklog edits)
export const updateWorkContextData = createAction(

View file

@ -2,8 +2,8 @@
import { createAction } from '@ngrx/store';
import { DropListModelSource } from '../../tasks/task.model';
import { WorkContextType } from '../work-context.model';
import { PersistentActionMeta } from '../../../core/persistence/operation-log/persistent-action.interface';
import { OpType } from '../../../core/persistence/operation-log/operation.types';
import { PersistentActionMeta } from '../../../op-log/core/persistent-action.interface';
import { OpType } from '../../../op-log/core/operation.types';
export const moveTaskInTodayList = createAction(
'[WorkContextMeta] Move Task in Today',

View file

@ -2,9 +2,9 @@ import { TestBed } from '@angular/core/testing';
import { EncryptionPasswordChangeService } from './encryption-password-change.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { OperationEncryptionService } from '../../core/persistence/operation-log/sync/operation-encryption.service';
import { VectorClockService } from '../../core/persistence/operation-log/sync/vector-clock.service';
import { CLIENT_ID_PROVIDER } from '../../core/persistence/operation-log/client-id.provider';
import { OperationEncryptionService } from '../../op-log/sync/operation-encryption.service';
import { VectorClockService } from '../../op-log/sync/vector-clock.service';
import { CLIENT_ID_PROVIDER } from '../../op-log/util/client-id.provider';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
describe('EncryptionPasswordChangeService', () => {

View file

@ -1,16 +1,16 @@
import { inject, Injectable } from '@angular/core';
import { PfapiService } from '../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { OperationEncryptionService } from '../../core/persistence/operation-log/sync/operation-encryption.service';
import { VectorClockService } from '../../core/persistence/operation-log/sync/vector-clock.service';
import { OperationEncryptionService } from '../../op-log/sync/operation-encryption.service';
import { VectorClockService } from '../../op-log/sync/vector-clock.service';
import {
CLIENT_ID_PROVIDER,
ClientIdProvider,
} from '../../core/persistence/operation-log/client-id.provider';
import { isOperationSyncCapable } from '../../core/persistence/operation-log/sync/operation-sync.util';
} from '../../op-log/util/client-id.provider';
import { isOperationSyncCapable } from '../../op-log/sync/operation-sync.util';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { SuperSyncPrivateCfg } from '../../pfapi/api/sync/providers/super-sync/super-sync.model';
import { CURRENT_SCHEMA_VERSION } from '../../core/persistence/operation-log/store/schema-migration.service';
import { CURRENT_SCHEMA_VERSION } from '../../op-log/store/schema-migration.service';
import { SyncLog } from '../../core/log';
/**

View file

@ -49,9 +49,9 @@ import { devError } from '../../util/dev-error';
import { UserInputWaitStateService } from './user-input-wait-state.service';
import { LegacySyncProvider } from './legacy-sync-provider.model';
import { SYNC_WAIT_TIMEOUT_MS, SYNC_REINIT_DELAY_MS } from './sync.const';
import { SuperSyncStatusService } from '../../core/persistence/operation-log/sync/super-sync-status.service';
import { SuperSyncStatusService } from '../../op-log/sync/super-sync-status.service';
import { IS_ELECTRON } from '../../app.constants';
import { OperationLogStoreService } from '../../core/persistence/operation-log/store/operation-log-store.service';
import { OperationLogStoreService } from '../../op-log/store/operation-log-store.service';
/**
* Converts LegacySyncProvider to SyncProviderId.

View file

@ -6,15 +6,15 @@ import {
ArchiveOperationHandler,
isArchiveAffectingAction,
} from './archive-operation-handler.service';
import { LOCAL_ACTIONS } from '../../../../util/local-actions.token';
import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actions';
import { flushYoungToOld } from '../../../../features/time-tracking/store/archive.actions';
import { deleteTag } from '../../../../features/tag/store/tag.actions';
import { LOCAL_ACTIONS } from '../../util/local-actions.token';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { flushYoungToOld } from '../../features/time-tracking/store/archive.actions';
import { deleteTag } from '../../features/tag/store/tag.actions';
import { Action } from '@ngrx/store';
import { Task, TaskWithSubTasks } from '../../../../features/tasks/task.model';
import { WorkContextType } from '../../../../features/work-context/work-context.model';
import { SnackService } from '../../../snack/snack.service';
import { WorklogService } from '../../../../features/worklog/worklog.service';
import { Task, TaskWithSubTasks } from '../../features/tasks/task.model';
import { WorkContextType } from '../../features/work-context/work-context.model';
import { SnackService } from '../../core/snack/snack.service';
import { WorklogService } from '../../features/worklog/worklog.service';
describe('ArchiveOperationHandlerEffects', () => {
let effects: ArchiveOperationHandlerEffects;

View file

@ -1,16 +1,16 @@
import { inject, Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { LOCAL_ACTIONS } from '../../../../util/local-actions.token';
import { LOCAL_ACTIONS } from '../../util/local-actions.token';
import { concatMap, filter, tap } from 'rxjs/operators';
import {
ArchiveOperationHandler,
isArchiveAffectingAction,
} from './archive-operation-handler.service';
import { devError } from '../../../../util/dev-error';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { remoteArchiveDataApplied } from '../../../../features/time-tracking/store/archive.actions';
import { WorklogService } from '../../../../features/worklog/worklog.service';
import { devError } from '../../util/dev-error';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { remoteArchiveDataApplied } from '../../features/time-tracking/store/archive.actions';
import { WorklogService } from '../../features/worklog/worklog.service';
/**
* Unified effect for all archive-affecting operations.

View file

@ -3,17 +3,17 @@ import {
ArchiveOperationHandler,
isArchiveAffectingAction,
} from './archive-operation-handler.service';
import { PersistentAction } from '../persistent-action.interface';
import { ArchiveService } from '../../../../features/time-tracking/archive.service';
import { TaskArchiveService } from '../../../../features/time-tracking/task-archive.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { Task, TaskWithSubTasks } from '../../../../features/tasks/task.model';
import { ArchiveModel } from '../../../../features/time-tracking/time-tracking.model';
import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actions';
import { flushYoungToOld } from '../../../../features/time-tracking/store/archive.actions';
import { deleteTag, deleteTags } from '../../../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../../../features/time-tracking/time-tracking.service';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
import { PersistentAction } from '../core/persistent-action.interface';
import { ArchiveService } from '../../features/time-tracking/archive.service';
import { TaskArchiveService } from '../../features/time-tracking/task-archive.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { Task, TaskWithSubTasks } from '../../features/tasks/task.model';
import { ArchiveModel } from '../../features/time-tracking/time-tracking.model';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { flushYoungToOld } from '../../features/time-tracking/store/archive.actions';
import { deleteTag, deleteTags } from '../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../features/time-tracking/time-tracking.service';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
describe('isArchiveAffectingAction', () => {
it('should return true for moveToArchive action', () => {

View file

@ -1,25 +1,25 @@
import { inject, Injectable, Injector } from '@angular/core';
import { Update } from '@ngrx/entity';
import { Action } from '@ngrx/store';
import { PersistentAction } from '../persistent-action.interface';
import { Task } from '../../../../features/tasks/task.model';
import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actions';
import { PersistentAction } from '../core/persistent-action.interface';
import { Task } from '../../features/tasks/task.model';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import {
compressArchive,
flushYoungToOld,
} from '../../../../features/time-tracking/store/archive.actions';
import { ArchiveService } from '../../../../features/time-tracking/archive.service';
import { TaskArchiveService } from '../../../../features/time-tracking/task-archive.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { sortTimeTrackingAndTasksFromArchiveYoungToOld } from '../../../../features/time-tracking/sort-data-to-flush';
import { ARCHIVE_TASK_YOUNG_TO_OLD_THRESHOLD } from '../../../../features/time-tracking/archive.service';
import { OpLog } from '../../../log';
import { lazyInject } from '../../../../util/lazy-inject';
import { deleteTag, deleteTags } from '../../../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../../../features/time-tracking/time-tracking.service';
import { ArchiveCompressionService } from '../../../../features/time-tracking/archive-compression.service';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
import { ArchiveModel } from '../../../../features/time-tracking/time-tracking.model';
} from '../../features/time-tracking/store/archive.actions';
import { ArchiveService } from '../../features/time-tracking/archive.service';
import { TaskArchiveService } from '../../features/time-tracking/task-archive.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { sortTimeTrackingAndTasksFromArchiveYoungToOld } from '../../features/time-tracking/sort-data-to-flush';
import { ARCHIVE_TASK_YOUNG_TO_OLD_THRESHOLD } from '../../features/time-tracking/archive.service';
import { OpLog } from '../../core/log';
import { lazyInject } from '../../util/lazy-inject';
import { deleteTag, deleteTags } from '../../features/tag/store/tag.actions';
import { TimeTrackingService } from '../../features/time-tracking/time-tracking.service';
import { ArchiveCompressionService } from '../../features/time-tracking/archive-compression.service';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
import { ArchiveModel } from '../../features/time-tracking/time-tracking.model';
/**
* Action types that affect archive storage and require special handling.

View file

@ -1,5 +1,5 @@
import { createAction, props } from '@ngrx/store';
import { Operation } from './operation.types';
import { Operation } from '../core/operation.types';
/**
* Action to bulk-apply operations in a single NgRx dispatch.

View file

@ -1,14 +1,14 @@
import { Action } from '@ngrx/store';
import { bulkHydrationMetaReducer } from './bulk-hydration.meta-reducer';
import { bulkApplyHydrationOperations } from './bulk-hydration.action';
import { Operation, OpType } from './operation.types';
import { RootState } from '../../../root-store/root-state';
import { TASK_FEATURE_NAME } from '../../../features/tasks/store/task.reducer';
import { PROJECT_FEATURE_NAME } from '../../../features/project/store/project.reducer';
import { TAG_FEATURE_NAME } from '../../../features/tag/store/tag.reducer';
import { Task } from '../../../features/tasks/task.model';
import { Project } from '../../../features/project/project.model';
import { Tag } from '../../../features/tag/tag.model';
import { Operation, OpType } from '../core/operation.types';
import { RootState } from '../../root-store/root-state';
import { TASK_FEATURE_NAME } from '../../features/tasks/store/task.reducer';
import { PROJECT_FEATURE_NAME } from '../../features/project/store/project.reducer';
import { TAG_FEATURE_NAME } from '../../features/tag/store/tag.reducer';
import { Task } from '../../features/tasks/task.model';
import { Project } from '../../features/project/project.model';
import { Tag } from '../../features/tag/tag.model';
describe('bulkHydrationMetaReducer', () => {
// Track all reducer calls for verification

View file

@ -1,6 +1,6 @@
import { TestBed } from '@angular/core/testing';
import { HydrationStateService } from './hydration-state.service';
import { getIsApplyingRemoteOps } from './operation-capture.meta-reducer';
import { getIsApplyingRemoteOps } from '../capture/operation-capture.meta-reducer';
describe('HydrationStateService', () => {
let service: HydrationStateService;

View file

@ -1,6 +1,6 @@
import { Injectable, signal } from '@angular/core';
import { setIsApplyingRemoteOps } from './operation-capture.meta-reducer';
import { POST_SYNC_COOLDOWN_MS } from '../operation-log.const';
import { setIsApplyingRemoteOps } from '../capture/operation-capture.meta-reducer';
import { POST_SYNC_COOLDOWN_MS } from '../core/operation-log.const';
/**
* Tracks whether the application is currently applying remote operations

View file

@ -1,13 +1,13 @@
import { TestBed } from '@angular/core/testing';
import { Store } from '@ngrx/store';
import { OperationApplierService } from './operation-applier.service';
import { Operation, OpType, EntityType } from '../operation.types';
import { Operation, OpType, EntityType } from '../core/operation.types';
import { ArchiveOperationHandler } from './archive-operation-handler.service';
import { HydrationStateService } from './hydration-state.service';
import { TaskSharedActions } from '../../../../root-store/meta/task-shared.actions';
import { remoteArchiveDataApplied } from '../../../../features/time-tracking/store/archive.actions';
import { bulkApplyOperations } from '../bulk-hydration.action';
import { OperationLogEffects } from '../operation-log.effects';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { remoteArchiveDataApplied } from '../../features/time-tracking/store/archive.actions';
import { bulkApplyOperations } from './bulk-hydration.action';
import { OperationLogEffects } from '../capture/operation-log.effects';
describe('OperationApplierService', () => {
let service: OperationApplierService;

View file

@ -1,16 +1,16 @@
import { inject, Injectable, Injector } from '@angular/core';
import { Store } from '@ngrx/store';
import { Operation } from '../operation.types';
import { convertOpToAction } from '../operation-converter.util';
import { OpLog } from '../../../log';
import { Operation } from '../core/operation.types';
import { convertOpToAction } from './operation-converter.util';
import { OpLog } from '../../core/log';
import {
ArchiveOperationHandler,
isArchiveAffectingAction,
} from './archive-operation-handler.service';
import { HydrationStateService } from './hydration-state.service';
import { remoteArchiveDataApplied } from '../../../../features/time-tracking/store/archive.actions';
import { bulkApplyOperations } from '../bulk-hydration.action';
import { OperationLogEffects } from '../operation-log.effects';
import { remoteArchiveDataApplied } from '../../features/time-tracking/store/archive.actions';
import { bulkApplyOperations } from './bulk-hydration.action';
import { OperationLogEffects } from '../capture/operation-log.effects';
/**
* Result of applying operations to the NgRx store.

View file

@ -1,5 +1,5 @@
import { convertOpToAction, ACTION_TYPE_ALIASES } from './operation-converter.util';
import { Operation, OpType } from './operation.types';
import { Operation, OpType } from '../core/operation.types';
describe('operation-converter utility', () => {
const createMockOperation = (overrides: Partial<Operation> = {}): Operation => ({

View file

@ -1,5 +1,5 @@
import { extractActionPayload, Operation, OpType } from './operation.types';
import { PersistentAction } from './persistent-action.interface';
import { extractActionPayload, Operation, OpType } from '../core/operation.types';
import { PersistentAction } from '../core/persistent-action.interface';
/**
* Maps old/renamed action types to their current names.

View file

@ -10,9 +10,9 @@ import {
} from './operation-capture.meta-reducer';
import { OperationCaptureService } from './operation-capture.service';
import { Action } from '@ngrx/store';
import { PersistentAction } from '../persistent-action.interface';
import { EntityType, OpType } from '../operation.types';
import { RootState } from '../../../../root-store/root-state';
import { PersistentAction } from '../core/persistent-action.interface';
import { EntityType, OpType } from '../core/operation.types';
import { RootState } from '../../root-store/root-state';
describe('operationCaptureMetaReducer', () => {
let mockCaptureService: jasmine.SpyObj<OperationCaptureService>;

View file

@ -1,7 +1,10 @@
import { Action, ActionReducer } from '@ngrx/store';
import { isPersistentAction, PersistentAction } from '../persistent-action.interface';
import {
isPersistentAction,
PersistentAction,
} from '../core/persistent-action.interface';
import { OperationCaptureService } from './operation-capture.service';
import { OpLog } from '../../../log';
import { OpLog } from '../../core/log';
// ═══════════════════════════════════════════════════════════════════════════
// ARCHITECTURAL DEBT: Module-Level State for Meta-Reducer Service Injection

View file

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { OperationCaptureService } from './operation-capture.service';
import { OpType, EntityType } from '../operation.types';
import { PersistentAction } from '../persistent-action.interface';
import { OpType, EntityType } from '../core/operation.types';
import { PersistentAction } from '../core/persistent-action.interface';
describe('OperationCaptureService', () => {
let service: OperationCaptureService;

View file

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { EntityChange, OpType } from '../operation.types';
import { PersistentAction } from '../persistent-action.interface';
import { OpLog } from '../../../log';
import { EntityChange, OpType } from '../core/operation.types';
import { PersistentAction } from '../core/persistent-action.interface';
import { OpLog } from '../../core/log';
/**
* Captures action payloads and queues them for persistence using a simple FIFO queue.

View file

@ -3,21 +3,21 @@ import { provideMockActions } from '@ngrx/effects/testing';
import { Action, Store } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import { OperationLogEffects } from './operation-log.effects';
import { OperationLogStoreService } from './store/operation-log-store.service';
import { LockService } from './sync/lock.service';
import { VectorClockService } from './sync/vector-clock.service';
import { OperationLogCompactionService } from './store/operation-log-compaction.service';
import { SnackService } from '../../snack/snack.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { LockService } from '../sync/lock.service';
import { VectorClockService } from '../sync/vector-clock.service';
import { OperationLogCompactionService } from '../store/operation-log-compaction.service';
import { SnackService } from '../../core/snack/snack.service';
import { Injector } from '@angular/core';
import { ImmediateUploadService } from './sync/immediate-upload.service';
import { HydrationStateService } from './processing/hydration-state.service';
import { OpType } from './operation.types';
import { PersistentAction } from './persistent-action.interface';
import { COMPACTION_THRESHOLD } from './operation-log.const';
import { ImmediateUploadService } from '../sync/immediate-upload.service';
import { HydrationStateService } from '../apply/hydration-state.service';
import { OpType } from '../core/operation.types';
import { PersistentAction } from '../core/persistent-action.interface';
import { COMPACTION_THRESHOLD } from '../core/operation-log.const';
import {
bufferDeferredAction,
clearDeferredActions,
} from './processing/operation-capture.meta-reducer';
} from './operation-capture.meta-reducer';
describe('OperationLogEffects', () => {
let effects: OperationLogEffects;

View file

@ -1,31 +1,34 @@
import { inject, Injectable, Injector } from '@angular/core';
import { createEffect } from '@ngrx/effects';
import { ALL_ACTIONS } from '../../../util/local-actions.token';
import { ALL_ACTIONS } from '../../util/local-actions.token';
import { concatMap, filter } from 'rxjs/operators';
import { LockService } from './sync/lock.service';
import { OperationLogStoreService } from './store/operation-log-store.service';
import { isPersistentAction, PersistentAction } from './persistent-action.interface';
import { uuidv7 } from '../../../util/uuid-v7';
import { devError } from '../../../util/dev-error';
import { incrementVectorClock } from '../../../pfapi/api/util/vector-clock';
import { MultiEntityPayload, Operation } from './operation.types';
import { PfapiService } from '../../../pfapi/pfapi.service';
import { OperationLogCompactionService } from './store/operation-log-compaction.service';
import { OpLog } from '../../log';
import { SnackService } from '../../snack/snack.service';
import { T } from '../../../t.const';
import { validateOperationPayload } from './processing/validate-operation-payload';
import { VectorClockService } from './sync/vector-clock.service';
import { LockService } from '../sync/lock.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import {
isPersistentAction,
PersistentAction,
} from '../core/persistent-action.interface';
import { uuidv7 } from '../../util/uuid-v7';
import { devError } from '../../util/dev-error';
import { incrementVectorClock } from '../../pfapi/api/util/vector-clock';
import { MultiEntityPayload, Operation } from '../core/operation.types';
import { PfapiService } from '../../pfapi/pfapi.service';
import { OperationLogCompactionService } from '../store/operation-log-compaction.service';
import { OpLog } from '../../core/log';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { validateOperationPayload } from '../validation/validate-operation-payload';
import { VectorClockService } from '../sync/vector-clock.service';
import {
COMPACTION_THRESHOLD,
LOCK_NAMES,
MAX_COMPACTION_FAILURES,
} from './operation-log.const';
import { CURRENT_SCHEMA_VERSION } from './store/schema-migration.service';
import { OperationCaptureService } from './processing/operation-capture.service';
import { ImmediateUploadService } from './sync/immediate-upload.service';
import { HydrationStateService } from './processing/hydration-state.service';
import { getDeferredActions } from './processing/operation-capture.meta-reducer';
} from '../core/operation-log.const';
import { CURRENT_SCHEMA_VERSION } from '../store/schema-migration.service';
import { OperationCaptureService } from './operation-capture.service';
import { ImmediateUploadService } from '../sync/immediate-upload.service';
import { HydrationStateService } from '../apply/hydration-state.service';
import { getDeferredActions } from './operation-capture.meta-reducer';
/**
* NgRx Effects for persisting application state changes as operations to the

View file

@ -6,7 +6,7 @@
* ## Adding a New Entity Type:
* 1. Add the type to EntityType union in operation.types.ts
* 2. Add config here
* 3. Run `npm run checkFile src/app/core/persistence/operation-log/entity-registry.ts`
* 3. Run `npm run checkFile src/app/op-log/core/entity-registry.ts`
*/
import { EntityAdapter } from '@ngrx/entity';
@ -17,41 +17,38 @@ import { EntityType } from './operation.types';
// ─────────────────────────────────────────────────────────────────────────────
// IMPORTS - Adapters & Feature Names
// ─────────────────────────────────────────────────────────────────────────────
import {
TASK_FEATURE_NAME,
taskAdapter,
} from '../../../features/tasks/store/task.reducer';
import { TASK_FEATURE_NAME, taskAdapter } from '../../features/tasks/store/task.reducer';
import {
PROJECT_FEATURE_NAME,
projectAdapter,
} from '../../../features/project/store/project.reducer';
import { TAG_FEATURE_NAME, tagAdapter } from '../../../features/tag/store/tag.reducer';
} from '../../features/project/store/project.reducer';
import { TAG_FEATURE_NAME, tagAdapter } from '../../features/tag/store/tag.reducer';
import {
adapter as noteAdapter,
NOTE_FEATURE_NAME,
} from '../../../features/note/store/note.reducer';
} from '../../features/note/store/note.reducer';
import {
adapter as simpleCounterAdapter,
SIMPLE_COUNTER_FEATURE_NAME,
} from '../../../features/simple-counter/store/simple-counter.reducer';
} from '../../features/simple-counter/store/simple-counter.reducer';
import {
adapter as taskRepeatCfgAdapter,
TASK_REPEAT_CFG_FEATURE_NAME,
} from '../../../features/task-repeat-cfg/store/task-repeat-cfg.selectors';
} from '../../features/task-repeat-cfg/store/task-repeat-cfg.selectors';
import {
metricAdapter,
METRIC_FEATURE_NAME,
} from '../../../features/metric/store/metric.reducer';
} from '../../features/metric/store/metric.reducer';
import {
adapter as issueProviderAdapter,
ISSUE_PROVIDER_FEATURE_KEY,
} from '../../../features/issue/store/issue-provider.reducer';
import { CONFIG_FEATURE_NAME } from '../../../features/config/store/global-config.reducer';
import { TIME_TRACKING_FEATURE_KEY } from '../../../features/time-tracking/store/time-tracking.reducer';
import { plannerFeatureKey } from '../../../features/planner/store/planner.reducer';
import { BOARDS_FEATURE_NAME } from '../../../features/boards/store/boards.reducer';
import { menuTreeFeatureKey } from '../../../features/menu-tree/store/menu-tree.reducer';
import { REMINDER_FEATURE_NAME } from '../../../features/reminder/store/reminder.reducer';
} from '../../features/issue/store/issue-provider.reducer';
import { CONFIG_FEATURE_NAME } from '../../features/config/store/global-config.reducer';
import { TIME_TRACKING_FEATURE_KEY } from '../../features/time-tracking/store/time-tracking.reducer';
import { plannerFeatureKey } from '../../features/planner/store/planner.reducer';
import { BOARDS_FEATURE_NAME } from '../../features/boards/store/boards.reducer';
import { menuTreeFeatureKey } from '../../features/menu-tree/store/menu-tree.reducer';
import { REMINDER_FEATURE_NAME } from '../../features/reminder/store/reminder.reducer';
// ─────────────────────────────────────────────────────────────────────────────
// IMPORTS - Selectors
@ -59,51 +56,51 @@ import { REMINDER_FEATURE_NAME } from '../../../features/reminder/store/reminder
import {
selectTaskEntities,
selectTaskById,
} from '../../../features/tasks/store/task.selectors';
} from '../../features/tasks/store/task.selectors';
import {
selectProjectFeatureState,
selectEntities as selectProjectEntitiesFromAdapter,
} from '../../../features/project/store/project.reducer';
import { selectProjectById } from '../../../features/project/store/project.selectors';
} from '../../features/project/store/project.reducer';
import { selectProjectById } from '../../features/project/store/project.selectors';
import {
selectTagFeatureState,
selectEntities as selectTagEntitiesFromAdapter,
selectTagById,
} from '../../../features/tag/store/tag.reducer';
} from '../../features/tag/store/tag.reducer';
import {
selectNoteFeatureState,
selectEntities as selectNoteEntitiesFromAdapter,
selectNoteById,
} from '../../../features/note/store/note.reducer';
} from '../../features/note/store/note.reducer';
import {
selectSimpleCounterFeatureState,
selectEntities as selectSimpleCounterEntitiesFromAdapter,
selectSimpleCounterById,
} from '../../../features/simple-counter/store/simple-counter.reducer';
} from '../../features/simple-counter/store/simple-counter.reducer';
import {
selectTaskRepeatCfgFeatureState,
selectTaskRepeatCfgById,
} from '../../../features/task-repeat-cfg/store/task-repeat-cfg.selectors';
} from '../../features/task-repeat-cfg/store/task-repeat-cfg.selectors';
import {
selectMetricFeatureState,
selectEntities as selectMetricEntitiesFromAdapter,
selectMetricById,
} from '../../../features/metric/store/metric.selectors';
} from '../../features/metric/store/metric.selectors';
import {
selectIssueProviderState,
selectEntities as selectIssueProviderEntitiesFromAdapter,
selectIssueProviderById,
} from '../../../features/issue/store/issue-provider.selectors';
import { selectConfigFeatureState } from '../../../features/config/store/global-config.reducer';
import { selectTimeTrackingState } from '../../../features/time-tracking/store/time-tracking.selectors';
import { selectPlannerState } from '../../../features/planner/store/planner.selectors';
import { selectBoardsState } from '../../../features/boards/store/boards.selectors';
import { selectMenuTreeState } from '../../../features/menu-tree/store/menu-tree.selectors';
import { selectReminderFeatureState } from '../../../features/reminder/store/reminder.reducer';
} from '../../features/issue/store/issue-provider.selectors';
import { selectConfigFeatureState } from '../../features/config/store/global-config.reducer';
import { selectTimeTrackingState } from '../../features/time-tracking/store/time-tracking.selectors';
import { selectPlannerState } from '../../features/planner/store/planner.selectors';
import { selectBoardsState } from '../../features/boards/store/boards.selectors';
import { selectMenuTreeState } from '../../features/menu-tree/store/menu-tree.selectors';
import { selectReminderFeatureState } from '../../features/reminder/store/reminder.reducer';
import {
selectContextFeatureState,
WORK_CONTEXT_FEATURE_NAME,
} from '../../../features/work-context/store/work-context.selectors';
} from '../../features/work-context/store/work-context.selectors';
// ─────────────────────────────────────────────────────────────────────────────
// TYPES

View file

@ -1,4 +1,4 @@
import { VectorClock } from '../../../pfapi/api/util/vector-clock';
import { VectorClock } from '../../pfapi/api/util/vector-clock';
export { VectorClock };
export enum OpType {

View file

@ -9,21 +9,17 @@
* The alias registry ensures old operations can still be replayed after renames.
*/
import { TaskSharedActions } from '../../../root-store/meta/task-shared.actions';
import { syncTimeSpent } from '../../../features/time-tracking/store/time-tracking.actions';
import { flushYoungToOld } from '../../../features/time-tracking/store/archive.actions';
import { TaskSharedActions } from '../../root-store/meta/task-shared.actions';
import { syncTimeSpent } from '../../features/time-tracking/store/time-tracking.actions';
import { flushYoungToOld } from '../../features/time-tracking/store/archive.actions';
import {
addProject,
updateProject,
archiveProject,
} from '../../../features/project/store/project.actions';
import { addTag, updateTag, deleteTag } from '../../../features/tag/store/tag.actions';
import {
addNote,
updateNote,
deleteNote,
} from '../../../features/note/store/note.actions';
import { updateGlobalConfigSection } from '../../../features/config/store/global-config.actions';
} from '../../features/project/store/project.actions';
import { addTag, updateTag, deleteTag } from '../../features/tag/store/tag.actions';
import { addNote, updateNote, deleteNote } from '../../features/note/store/note.actions';
import { updateGlobalConfigSection } from '../../features/config/store/global-config.actions';
describe('Persistent Action Types Stability', () => {
/**

View file

@ -2,16 +2,16 @@ import { TestBed } from '@angular/core/testing';
import { OperationLogCompactionService } from './operation-log-compaction.service';
import { OperationLogStoreService } from './operation-log-store.service';
import { LockService } from '../sync/lock.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { VectorClockService } from '../sync/vector-clock.service';
import {
COMPACTION_RETENTION_MS,
SLOW_COMPACTION_THRESHOLD_MS,
} from '../operation-log.const';
} from '../core/operation-log.const';
import { CURRENT_SCHEMA_VERSION } from './schema-migration.service';
import { OperationLogEntry } from '../operation.types';
import { OpLog } from '../../../log';
import { PFAPI_MODEL_CFGS } from '../../../../pfapi/pfapi-config';
import { OperationLogEntry } from '../core/operation.types';
import { OpLog } from '../../core/log';
import { PFAPI_MODEL_CFGS } from '../../pfapi/pfapi-config';
const MS_PER_DAY = 24 * 60 * 60 * 1000;

View file

@ -6,14 +6,14 @@ import {
EMERGENCY_COMPACTION_RETENTION_MS,
LOCK_NAMES,
SLOW_COMPACTION_THRESHOLD_MS,
} from '../operation-log.const';
} from '../core/operation-log.const';
import { OperationLogStoreService } from './operation-log-store.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { CURRENT_SCHEMA_VERSION } from './schema-migration.service';
import { VectorClockService } from '../sync/vector-clock.service';
import { OpLog } from '../../../log';
import { PfapiAllModelCfg } from '../../../../pfapi/pfapi-config';
import { AllSyncModels } from '../../../../pfapi/api/pfapi.model';
import { OpLog } from '../../core/log';
import { PfapiAllModelCfg } from '../../pfapi/pfapi-config';
import { AllSyncModels } from '../../pfapi/api/pfapi.model';
/**
* Manages the compaction (garbage collection) of the operation log.

View file

@ -8,17 +8,17 @@ import {
SchemaMigrationService,
CURRENT_SCHEMA_VERSION,
} from './schema-migration.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { SnackService } from '../../../snack/snack.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { RepairOperationService } from '../processing/repair-operation.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { SnackService } from '../../core/snack/snack.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { RepairOperationService } from '../validation/repair-operation.service';
import { VectorClockService } from '../sync/vector-clock.service';
import { OperationApplierService } from '../processing/operation-applier.service';
import { HydrationStateService } from '../processing/hydration-state.service';
import { Operation, OperationLogEntry, OpType } from '../operation.types';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
import { bulkApplyHydrationOperations } from '../bulk-hydration.action';
import { OperationApplierService } from '../apply/operation-applier.service';
import { HydrationStateService } from '../apply/hydration-state.service';
import { Operation, OperationLogEntry, OpType } from '../core/operation.types';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
import { bulkApplyHydrationOperations } from '../apply/bulk-hydration.action';
describe('OperationLogHydratorService', () => {
let service: OperationLogHydratorService;

View file

@ -1,36 +1,36 @@
import { inject, Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { OperationLogStoreService } from './operation-log-store.service';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
import { OperationLogMigrationService } from './operation-log-migration.service';
import {
CURRENT_SCHEMA_VERSION,
MigratableStateCache,
SchemaMigrationService,
} from './schema-migration.service';
import { OpLog } from '../../../log';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { Operation, OpType, RepairPayload } from '../operation.types';
import { uuidv7 } from '../../../../util/uuid-v7';
import { OpLog } from '../../core/log';
import { PfapiService } from '../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { Operation, OpType, RepairPayload } from '../core/operation.types';
import { uuidv7 } from '../../util/uuid-v7';
import {
incrementVectorClock,
mergeVectorClocks,
} from '../../../../pfapi/api/util/vector-clock';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { ValidateStateService } from '../processing/validate-state.service';
} from '../../pfapi/api/util/vector-clock';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { ValidateStateService } from '../validation/validate-state.service';
// DISABLED: Repair system is non-functional
// import { RepairOperationService } from '../processing/repair-operation.service';
import { OperationApplierService } from '../processing/operation-applier.service';
import { HydrationStateService } from '../processing/hydration-state.service';
import { bulkApplyOperations } from '../bulk-hydration.action';
import { AppDataCompleteNew } from '../../../../pfapi/pfapi-config';
// import { RepairOperationService } from '../validation/repair-operation.service';
import { OperationApplierService } from '../apply/operation-applier.service';
import { HydrationStateService } from '../apply/hydration-state.service';
import { bulkApplyOperations } from '../apply/bulk-hydration.action';
import { AppDataCompleteNew } from '../../pfapi/pfapi-config';
import { VectorClockService } from '../sync/vector-clock.service';
import {
MAX_CONFLICT_RETRY_ATTEMPTS,
PENDING_OPERATION_EXPIRY_MS,
} from '../operation-log.const';
} from '../core/operation-log.const';
type StateCache = MigratableStateCache;

View file

@ -3,9 +3,9 @@ import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { of } from 'rxjs';
import { OperationLogMigrationService } from './operation-log-migration.service';
import { OperationLogStoreService } from './operation-log-store.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { OpLog } from '../../../log';
import { OpType } from '../operation.types';
import { PfapiService } from '../../pfapi/pfapi.service';
import { OpLog } from '../../core/log';
import { OpType } from '../core/operation.types';
describe('OperationLogMigrationService', () => {
let service: OperationLogMigrationService;

View file

@ -2,14 +2,14 @@ import { inject, Injectable } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { firstValueFrom } from 'rxjs';
import { OperationLogStoreService } from './operation-log-store.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { Operation, OpType } from '../operation.types';
import { uuidv7 } from '../../../../util/uuid-v7';
import { OpLog } from '../../../log';
import { PfapiService } from '../../pfapi/pfapi.service';
import { Operation, OpType } from '../core/operation.types';
import { uuidv7 } from '../../util/uuid-v7';
import { OpLog } from '../../core/log';
import { CURRENT_SCHEMA_VERSION } from './schema-migration.service';
import { DialogConfirmComponent } from '../../../../ui/dialog-confirm/dialog-confirm.component';
import { download } from '../../../../util/download';
import { T } from '../../../../t.const';
import { DialogConfirmComponent } from '../../ui/dialog-confirm/dialog-confirm.component';
import { download } from '../../util/download';
import { T } from '../../t.const';
@Injectable({ providedIn: 'root' })
export class OperationLogMigrationService {

View file

@ -1,8 +1,8 @@
import { TestBed } from '@angular/core/testing';
import { OperationLogStoreService } from './operation-log-store.service';
import { VectorClockService } from '../sync/vector-clock.service';
import { Operation, OpType, EntityType, VectorClock } from '../operation.types';
import { uuidv7 } from '../../../../util/uuid-v7';
import { Operation, OpType, EntityType, VectorClock } from '../core/operation.types';
import { uuidv7 } from '../../util/uuid-v7';
describe('OperationLogStoreService', () => {
let service: OperationLogStoreService;

View file

@ -1,7 +1,12 @@
import { Injectable } from '@angular/core';
import { DBSchema, IDBPDatabase, openDB } from 'idb';
import { Operation, OperationLogEntry, OpType, VectorClock } from '../operation.types';
import { toEntityKey } from '../entity-key.util';
import {
Operation,
OperationLogEntry,
OpType,
VectorClock,
} from '../core/operation.types';
import { toEntityKey } from '../util/entity-key.util';
const DB_NAME = 'SUP_OPS';
const DB_VERSION = 3;

View file

@ -4,7 +4,7 @@ import {
MigratableStateCache,
CURRENT_SCHEMA_VERSION,
} from './schema-migration.service';
import { Operation, OpType } from '../operation.types';
import { Operation, OpType } from '../core/operation.types';
describe('SchemaMigrationService', () => {
let service: SchemaMigrationService;

View file

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core';
import { Operation, VectorClock } from '../operation.types';
import { OpLog } from '../../../log';
import { Operation, VectorClock } from '../core/operation.types';
import { OpLog } from '../../core/log';
import {
CURRENT_SCHEMA_VERSION as SHARED_CURRENT_SCHEMA_VERSION,
MAX_VERSION_SKIP as SHARED_MAX_VERSION_SKIP,

View file

@ -1,14 +1,14 @@
import { TestBed } from '@angular/core/testing';
import { ConflictResolutionService } from './conflict-resolution.service';
import { Store } from '@ngrx/store';
import { OperationApplierService } from '../processing/operation-applier.service';
import { OperationApplierService } from '../apply/operation-applier.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { SnackService } from '../../../snack/snack.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { SnackService } from '../../core/snack/snack.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { of } from 'rxjs';
import { EntityConflict, OpType, Operation } from '../operation.types';
import { SyncSafetyBackupService } from '../../../../imex/sync/sync-safety-backup.service';
import { BACKUP_TIMEOUT_MS } from '../operation-log.const';
import { EntityConflict, OpType, Operation } from '../core/operation.types';
import { SyncSafetyBackupService } from '../../imex/sync/sync-safety-backup.service';
import { BACKUP_TIMEOUT_MS } from '../core/operation-log.const';
describe('ConflictResolutionService', () => {
let service: ConflictResolutionService;

View file

@ -6,35 +6,38 @@ import {
Operation,
OpType,
VectorClock,
} from '../operation.types';
import { OperationApplierService } from '../processing/operation-applier.service';
} from '../core/operation.types';
import { OperationApplierService } from '../apply/operation-applier.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { OpLog } from '../../../log';
import { toEntityKey } from '../entity-key.util';
import { OpLog } from '../../core/log';
import { toEntityKey } from '../util/entity-key.util';
import { firstValueFrom } from 'rxjs';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { ValidateStateService } from '../processing/validate-state.service';
import { BACKUP_TIMEOUT_MS, MAX_CONFLICT_RETRY_ATTEMPTS } from '../operation-log.const';
import { SyncSafetyBackupService } from '../../../../imex/sync/sync-safety-backup.service';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { ValidateStateService } from '../validation/validate-state.service';
import {
BACKUP_TIMEOUT_MS,
MAX_CONFLICT_RETRY_ATTEMPTS,
} from '../core/operation-log.const';
import { SyncSafetyBackupService } from '../../imex/sync/sync-safety-backup.service';
import {
compareVectorClocks,
incrementVectorClock,
mergeVectorClocks,
VectorClockComparison,
} from '../../../../pfapi/api/util/vector-clock';
import { devError } from '../../../../util/dev-error';
import { uuidv7 } from '../../../../util/uuid-v7';
} from '../../pfapi/api/util/vector-clock';
import { devError } from '../../util/dev-error';
import { uuidv7 } from '../../util/uuid-v7';
import { CURRENT_SCHEMA_VERSION } from '../store/schema-migration.service';
import { CLIENT_ID_PROVIDER } from '../client-id.provider';
import { CLIENT_ID_PROVIDER } from '../util/client-id.provider';
import {
getEntityConfig,
isAdapterEntity,
isSingletonEntity,
isMapEntity,
isArrayEntity,
} from '../entity-registry';
import { selectIssueProviderById } from '../../../../features/issue/store/issue-provider.selectors';
} from '../core/entity-registry';
import { selectIssueProviderById } from '../../features/issue/store/issue-provider.selectors';
/**
* Represents the result of LWW (Last-Write-Wins) conflict resolution.

View file

@ -1,8 +1,8 @@
import { TestBed, fakeAsync, tick } from '@angular/core/testing';
import { ImmediateUploadService } from './immediate-upload.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { OperationLogSyncService } from './operation-log-sync.service';
import { Operation, OpType } from '../operation.types';
import { Operation, OpType } from '../core/operation.types';
describe('ImmediateUploadService', () => {
let service: ImmediateUploadService;

View file

@ -1,11 +1,11 @@
import { inject, Injectable, OnDestroy } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { debounceTime, exhaustMap, filter } from 'rxjs/operators';
import { isOnline } from '../../../../util/is-online';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { isOnline } from '../../util/is-online';
import { PfapiService } from '../../pfapi/pfapi.service';
import { OperationLogSyncService } from './operation-log-sync.service';
import { isOperationSyncCapable } from './operation-sync.util';
import { OpLog } from '../../../log';
import { OpLog } from '../../core/log';
const IMMEDIATE_UPLOAD_DEBOUNCE_MS = 2000;

View file

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { OpLog } from '../../../log';
import { IS_ELECTRON } from '../../../../app.constants';
import { IS_ANDROID_WEB_VIEW } from '../../../../util/is-android-web-view';
import { OpLog } from '../../core/log';
import { IS_ELECTRON } from '../../app.constants';
import { IS_ANDROID_WEB_VIEW } from '../../util/is-android-web-view';
/**
* Provides a cross-tab locking mechanism for critical operations using the Web Locks API.

View file

@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { OperationEncryptionService } from './operation-encryption.service';
import { SyncOperation } from '../../../../pfapi/api/sync/sync-provider.interface';
import { DecryptError } from '../../../../pfapi/api/errors/errors';
import { SyncOperation } from '../../pfapi/api/sync/sync-provider.interface';
import { DecryptError } from '../../pfapi/api/errors/errors';
describe('OperationEncryptionService', () => {
let service: OperationEncryptionService;

View file

@ -1,7 +1,7 @@
import { Injectable } from '@angular/core';
import { encrypt, decrypt } from '../../../../pfapi/api/encryption/encryption';
import { SyncOperation } from '../../../../pfapi/api/sync/sync-provider.interface';
import { DecryptError } from '../../../../pfapi/api/errors/errors';
import { encrypt, decrypt } from '../../pfapi/api/encryption/encryption';
import { SyncOperation } from '../../pfapi/api/sync/sync-provider.interface';
import { DecryptError } from '../../pfapi/api/errors/errors';
/**
* Handles E2E encryption/decryption of operation payloads for SuperSync.

View file

@ -2,16 +2,16 @@ import { fakeAsync, TestBed, tick } from '@angular/core/testing';
import { OperationLogDownloadService } from './operation-log-download.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { LockService } from './lock.service';
import { SnackService } from '../../../snack/snack.service';
import { SnackService } from '../../core/snack/snack.service';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
import { OpType } from '../operation.types';
import { CLOCK_DRIFT_THRESHOLD_MS } from '../operation-log.const';
import { OpLog } from '../../../log';
import { T } from '../../../../t.const';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { OpType } from '../core/operation.types';
import { CLOCK_DRIFT_THRESHOLD_MS } from '../core/operation-log.const';
import { OpLog } from '../../core/log';
import { T } from '../../t.const';
describe('OperationLogDownloadService', () => {
let service: OperationLogDownloadService;

View file

@ -1,26 +1,26 @@
import { inject, Injectable } from '@angular/core';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { LockService } from './lock.service';
import { Operation } from '../operation.types';
import { OpLog } from '../../../log';
import { Operation } from '../core/operation.types';
import { OpLog } from '../../core/log';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
SyncOperation,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { isOperationSyncCapable, syncOpToOperation } from './operation-sync.util';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import {
LOCK_NAMES,
MAX_DOWNLOAD_OPS_IN_MEMORY,
MAX_DOWNLOAD_ITERATIONS,
CLOCK_DRIFT_THRESHOLD_MS,
} from '../operation-log.const';
} from '../core/operation-log.const';
import { OperationEncryptionService } from './operation-encryption.service';
import { SuperSyncPrivateCfg } from '../../../../pfapi/api/sync/providers/super-sync/super-sync.model';
import { DecryptError } from '../../../../pfapi/api/errors/errors';
import { SuperSyncPrivateCfg } from '../../pfapi/api/sync/providers/super-sync/super-sync.model';
import { DecryptError } from '../../pfapi/api/errors/errors';
import { SuperSyncStatusService } from './super-sync-status.service';
/**
@ -50,13 +50,13 @@ export interface DownloadResult {
* This is populated when forceFromSeq0 is true, allowing callers to rebuild their
* vector clock state from all known ops on the server.
*/
allOpClocks?: import('../operation.types').VectorClock[];
allOpClocks?: import('../core/operation.types').VectorClock[];
/**
* Aggregated vector clock from all ops before and including the snapshot.
* Only set when snapshot optimization is used (sinceSeq < latestSnapshotSeq).
* Clients need this to create merged updates that dominate all known clocks.
*/
snapshotVectorClock?: import('../operation.types').VectorClock;
snapshotVectorClock?: import('../core/operation.types').VectorClock;
}
/**
@ -116,11 +116,11 @@ export class OperationLogDownloadService {
);
const allNewOps: Operation[] = [];
const allOpClocks: import('../operation.types').VectorClock[] = [];
const allOpClocks: import('../core/operation.types').VectorClock[] = [];
let downloadFailed = false;
let needsFullStateUpload = false;
let finalLatestSeq = 0;
let snapshotVectorClock: import('../operation.types').VectorClock | undefined;
let snapshotVectorClock: import('../core/operation.types').VectorClock | undefined;
// Get encryption key upfront
const privateCfg =

View file

@ -4,15 +4,15 @@ import {
SchemaMigrationService,
MAX_VERSION_SKIP,
} from '../store/schema-migration.service';
import { SnackService } from '../../../snack/snack.service';
import { SnackService } from '../../core/snack/snack.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { VectorClockService } from './vector-clock.service';
import { OperationApplierService } from '../processing/operation-applier.service';
import { OperationApplierService } from '../apply/operation-applier.service';
import { ConflictResolutionService } from './conflict-resolution.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { RepairOperationService } from '../processing/repair-operation.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { RepairOperationService } from '../validation/repair-operation.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import { OperationLogUploadService } from './operation-log-upload.service';
import { OperationLogDownloadService } from './operation-log-download.service';
import { LockService } from './lock.service';
@ -21,14 +21,14 @@ import { SyncImportFilterService } from './sync-import-filter.service';
import { ServerMigrationService } from './server-migration.service';
import { StaleOperationResolverService } from './stale-operation-resolver.service';
import { provideMockStore } from '@ngrx/store/testing';
import { EntityConflict, Operation, OpType, VectorClock } from '../operation.types';
import { EntityConflict, Operation, OpType, VectorClock } from '../core/operation.types';
import {
compareVectorClocks,
mergeVectorClocks,
VectorClockComparison,
} from '../../../../pfapi/api/util/vector-clock';
import { toEntityKey } from '../entity-key.util';
import { T } from '../../../../t.const';
} from '../../pfapi/api/util/vector-clock';
import { toEntityKey } from '../util/entity-key.util';
import { T } from '../../t.const';
import { TranslateService } from '@ngx-translate/core';
// Helper to mock OpLogEntry

View file

@ -8,14 +8,14 @@ import {
Operation,
OpType,
VectorClock,
} from '../operation.types';
import { OpLog } from '../../../log';
import { SyncProviderServiceInterface } from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
} from '../core/operation.types';
import { OpLog } from '../../core/log';
import { SyncProviderServiceInterface } from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { isOperationSyncCapable } from './operation-sync.util';
import { OperationApplierService } from '../processing/operation-applier.service';
import { OperationApplierService } from '../apply/operation-applier.service';
import { ConflictResolutionService } from './conflict-resolution.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { OperationLogUploadService, UploadResult } from './operation-log-upload.service';
import { OperationLogDownloadService } from './operation-log-download.service';
import { VectorClockService } from './vector-clock.service';
@ -23,13 +23,13 @@ import {
MAX_VERSION_SKIP,
SchemaMigrationService,
} from '../store/schema-migration.service';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { lazyInject } from '../../../../util/lazy-inject';
import { LOCK_NAMES, MAX_REJECTED_OPS_BEFORE_WARNING } from '../operation-log.const';
import { CLIENT_ID_PROVIDER } from '../client-id.provider';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { PfapiService } from '../../pfapi/pfapi.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { lazyInject } from '../../util/lazy-inject';
import { LOCK_NAMES, MAX_REJECTED_OPS_BEFORE_WARNING } from '../core/operation-log.const';
import { CLIENT_ID_PROVIDER } from '../util/client-id.provider';
import { LockService } from './lock.service';
import { OperationLogCompactionService } from '../store/operation-log-compaction.service';
import { SuperSyncStatusService } from './super-sync-status.service';

View file

@ -5,10 +5,10 @@ import { LockService } from './lock.service';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
import { OpType, OperationLogEntry } from '../operation.types';
import { SnackService } from '../../../snack/snack.service';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { OpType, OperationLogEntry } from '../core/operation.types';
import { SnackService } from '../../core/snack/snack.service';
import { provideMockStore } from '@ngrx/store/testing';
describe('OperationLogUploadService', () => {

View file

@ -1,19 +1,19 @@
import { inject, Injectable } from '@angular/core';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { LockService } from './lock.service';
import { Operation, OperationLogEntry, OpType } from '../operation.types';
import { OpLog } from '../../../log';
import { LOCK_NAMES } from '../operation-log.const';
import { chunkArray } from '../../../../util/chunk-array';
import { Operation, OperationLogEntry, OpType } from '../core/operation.types';
import { OpLog } from '../../core/log';
import { LOCK_NAMES } from '../core/operation-log.const';
import { chunkArray } from '../../util/chunk-array';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
SyncOperation,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { isOperationSyncCapable, syncOpToOperation } from './operation-sync.util';
import { OperationEncryptionService } from './operation-encryption.service';
import { SuperSyncPrivateCfg } from '../../../../pfapi/api/sync/providers/super-sync/super-sync.model';
import { SuperSyncPrivateCfg } from '../../pfapi/api/sync/providers/super-sync/super-sync.model';
/**
* Operation types that contain full application state and should use

View file

@ -3,9 +3,9 @@ import {
SyncProviderServiceInterface,
OperationSyncCapable,
SyncOperation,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
import { OpType } from '../operation.types';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { OpType } from '../core/operation.types';
describe('operation-sync utility', () => {
describe('isOperationSyncCapable', () => {

View file

@ -1,10 +1,10 @@
import { Operation } from '../operation.types';
import { Operation } from '../core/operation.types';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
SyncOperation,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
/**
* Type guard to check if a provider supports operation-based sync (API sync).

View file

@ -1,8 +1,8 @@
import { inject, Injectable } from '@angular/core';
import { LockService } from './lock.service';
import { OperationCaptureService } from '../processing/operation-capture.service';
import { OpLog } from '../../../log';
import { LOCK_NAMES } from '../operation-log.const';
import { OperationCaptureService } from '../capture/operation-capture.service';
import { OpLog } from '../../core/log';
import { LOCK_NAMES } from '../core/operation-log.const';
/**
* Service to ensure all pending operation writes have completed.

View file

@ -4,18 +4,18 @@ import { provideMockStore, MockStore } from '@ngrx/store/testing';
import { ServerMigrationService } from './server-migration.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { VectorClockService } from './vector-clock.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { SnackService } from '../../../snack/snack.service';
import { PfapiService } from '../../../../pfapi/pfapi.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { SnackService } from '../../core/snack/snack.service';
import { PfapiService } from '../../pfapi/pfapi.service';
import {
SyncProviderServiceInterface,
OperationSyncCapable,
} from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
import { OpType } from '../operation.types';
import { SYSTEM_TAG_IDS } from '../../../../features/tag/tag.const';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
} from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { OpType } from '../core/operation.types';
import { SYSTEM_TAG_IDS } from '../../features/tag/tag.const';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
describe('ServerMigrationService', () => {
let service: ServerMigrationService;

View file

@ -1,23 +1,23 @@
import { inject, Injectable } from '@angular/core';
import { Store } from '@ngrx/store';
import { SyncProviderServiceInterface } from '../../../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../../../pfapi/api/pfapi.const';
import { SyncProviderServiceInterface } from '../../pfapi/api/sync/sync-provider.interface';
import { SyncProviderId } from '../../pfapi/api/pfapi.const';
import { isOperationSyncCapable } from './operation-sync.util';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { VectorClockService } from './vector-clock.service';
import { incrementVectorClock } from '../../../../pfapi/api/util/vector-clock';
import { PfapiStoreDelegateService } from '../../../../pfapi/pfapi-store-delegate.service';
import { ValidateStateService } from '../processing/validate-state.service';
import { AppDataCompleteNew } from '../../../../pfapi/pfapi-config';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { loadAllData } from '../../../../root-store/meta/load-all-data.action';
import { incrementVectorClock } from '../../pfapi/api/util/vector-clock';
import { PfapiStoreDelegateService } from '../../pfapi/pfapi-store-delegate.service';
import { ValidateStateService } from '../validation/validate-state.service';
import { AppDataCompleteNew } from '../../pfapi/pfapi-config';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { loadAllData } from '../../root-store/meta/load-all-data.action';
import { CURRENT_SCHEMA_VERSION } from '../store/schema-migration.service';
import { Operation, OpType } from '../operation.types';
import { uuidv7 } from '../../../../util/uuid-v7';
import { OpLog } from '../../../log';
import { SYSTEM_TAG_IDS } from '../../../../features/tag/tag.const';
import { CLIENT_ID_PROVIDER } from '../client-id.provider';
import { Operation, OpType } from '../core/operation.types';
import { uuidv7 } from '../../util/uuid-v7';
import { OpLog } from '../../core/log';
import { SYSTEM_TAG_IDS } from '../../features/tag/tag.const';
import { CLIENT_ID_PROVIDER } from '../util/client-id.provider';
/**
* Service responsible for handling server migration scenarios.

View file

@ -1,19 +1,19 @@
import { inject, Injectable } from '@angular/core';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { Operation, OpType, VectorClock } from '../operation.types';
import { Operation, OpType, VectorClock } from '../core/operation.types';
import {
incrementVectorClock,
mergeVectorClocks,
} from '../../../../pfapi/api/util/vector-clock';
import { OpLog } from '../../../log';
} from '../../pfapi/api/util/vector-clock';
import { OpLog } from '../../core/log';
import { ConflictResolutionService } from './conflict-resolution.service';
import { VectorClockService } from './vector-clock.service';
import { toEntityKey } from '../entity-key.util';
import { toEntityKey } from '../util/entity-key.util';
import { CURRENT_SCHEMA_VERSION } from '../store/schema-migration.service';
import { SnackService } from '../../../snack/snack.service';
import { T } from '../../../../t.const';
import { uuidv7 } from '../../../../util/uuid-v7';
import { CLIENT_ID_PROVIDER } from '../client-id.provider';
import { SnackService } from '../../core/snack/snack.service';
import { T } from '../../t.const';
import { uuidv7 } from '../../util/uuid-v7';
import { CLIENT_ID_PROVIDER } from '../util/client-id.provider';
/**
* Resolves stale local operations that were rejected due to concurrent modification.

View file

@ -1,7 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { SyncImportFilterService } from './sync-import-filter.service';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { Operation, OpType } from '../operation.types';
import { Operation, OpType } from '../core/operation.types';
describe('SyncImportFilterService', () => {
let service: SyncImportFilterService;

View file

@ -1,11 +1,11 @@
import { inject, Injectable } from '@angular/core';
import { OperationLogStoreService } from '../store/operation-log-store.service';
import { Operation, OpType } from '../operation.types';
import { Operation, OpType } from '../core/operation.types';
import {
compareVectorClocks,
VectorClockComparison,
} from '../../../../pfapi/api/util/vector-clock';
import { OpLog } from '../../../log';
} from '../../pfapi/api/util/vector-clock';
import { OpLog } from '../../core/log';
/**
* Service responsible for filtering operations invalidated by SYNC_IMPORT, BACKUP_IMPORT, or REPAIR operations.

Some files were not shown because too many files have changed in this diff Show more