@adukiorg/anza 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/CHANGELOG.md +81 -4
  2. package/README.md +97 -133
  3. package/bin/anza/anza +0 -0
  4. package/bin/anza/anza.exe +0 -0
  5. package/bin/anza/find.js +35 -0
  6. package/bin/anza/index.js +34 -0
  7. package/bin/anza/launch.js +19 -0
  8. package/bin/common/index.js +7 -0
  9. package/bin/common/logs.js +62 -0
  10. package/bin/create/copy.js +18 -0
  11. package/bin/create/index.js +45 -0
  12. package/bin/create/run.js +210 -0
  13. package/bin/create/write.js +19 -0
  14. package/importmap.json +4 -0
  15. package/package.json +16 -10
  16. package/src/core/offline/{usage.md → notes/usage.md} +11 -1
  17. package/src/core/router/boot.js +82 -0
  18. package/src/core/router/cascade.js +76 -0
  19. package/src/core/router/container.js +63 -72
  20. package/src/core/router/graph.js +144 -0
  21. package/src/core/router/index.js +12 -2
  22. package/src/core/router/intercept.js +26 -7
  23. package/src/core/router/lca.js +58 -0
  24. package/src/core/router/match.js +49 -36
  25. package/src/core/router/notes/audit-old.md +887 -0
  26. package/src/core/router/notes/audti.md +773 -0
  27. package/src/core/router/notes/tasks.md +473 -0
  28. package/src/core/router/{usage.md → notes/usage.md} +57 -35
  29. package/src/core/router/sync/tab.js +6 -4
  30. package/src/core/router/transitions.js +35 -8
  31. package/src/core/router/trie.js +130 -0
  32. package/src/core/security/{usage.md → notes/usage.md} +1 -2
  33. package/src/core/storage/{usage.md → notes/usage.md} +6 -6
  34. package/src/core/theme/index.js +78 -0
  35. package/src/core/ui/define/index.js +2 -1
  36. package/src/core/ui/define/orchestrator.js +10 -4
  37. package/src/core/ui/defs/dock.js +134 -0
  38. package/src/core/ui/defs/index.js +20 -0
  39. package/src/core/ui/defs/page.js +89 -0
  40. package/src/core/ui/defs/part.js +28 -0
  41. package/src/core/ui/defs/spec.js +96 -0
  42. package/src/core/ui/defs/view.js +23 -0
  43. package/src/core/ui/index.js +16 -3
  44. package/src/core/ui/notes/definations.md +979 -0
  45. package/src/tokens/index.css +1 -0
  46. package/src/tokens/semantic/contrast.css +18 -0
  47. package/src/tokens/semantic/transitions.css +32 -0
  48. package/types/core/platform/index.d.ts +39 -10
  49. package/types/core/router/index.d.ts +9 -0
  50. package/types/core/theme/index.d.ts +18 -0
  51. package/types/core/ui/index.d.ts +11 -0
  52. package/types/index.d.ts +1 -0
  53. package/bin/anza.js +0 -63
  54. package/bin/create.js +0 -150
  55. package/src/core/api/plan.md +0 -209
  56. package/src/core/events/missing.md +0 -103
  57. package/src/core/events/plan.md +0 -177
  58. package/src/core/offline/missing.md +0 -89
  59. package/src/core/offline/plan.md +0 -143
  60. package/src/core/platform/missing.md +0 -119
  61. package/src/core/platform/platform.d.ts +0 -88
  62. package/src/core/router/missing.md +0 -716
  63. package/src/core/router/outlet.js +0 -139
  64. package/src/core/router/plan.md +0 -370
  65. package/src/core/security/missing.md +0 -97
  66. package/src/core/state/missing.md +0 -165
  67. package/src/core/storage/missing.md +0 -165
  68. package/src/core/storage/plan.md +0 -69
  69. package/src/core/ui/implementation.md +0 -170
  70. package/src/core/ui/plan.md +0 -510
  71. package/src/core/ui/ui.types.md +0 -890
  72. /package/src/core/animations/{usage.md → notes/usage.md} +0 -0
  73. /package/src/core/api/{usage.md → notes/usage.md} +0 -0
  74. /package/src/core/events/{usage.md → notes/usage.md} +0 -0
  75. /package/src/core/platform/{usage.md → notes/usage.md} +0 -0
  76. /package/src/core/state/{usage.md → notes/usage.md} +0 -0
  77. /package/src/core/ui/{usage.md → notes/usage.md} +0 -0
  78. /package/src/core/ui/{watch.md → notes/watch.md} +0 -0
  79. /package/src/core/workers/{plan.md → notes/plan.md} +0 -0
  80. /package/src/core/workers/{usage.md → notes/usage.md} +0 -0
@@ -1,103 +0,0 @@
1
- # Event Missing Support
2
-
3
- This document tracks remaining support, runtime gaps, type mismatches, and state/storage synchronization improvements for `src/core/events`. Implemented behavior belongs in `usage.md`; unsupported, under-tested, or performance-gated behavior belongs here until it is built and verified.
4
-
5
- ---
6
-
7
- ## 0. Toolchain and Naming Rules
8
-
9
- Heavy compilation, static analysis, and code generation belong in `tools/`, not in browser runtime modules.
10
-
11
- Current toolchain event requirements:
12
- - Statically verify event name strings inside `dispatchEvent` to ensure they are registered in the names registry.
13
- - Detect event listeners registered on `window` or `document` that do not supply an `AbortSignal`.
14
-
15
- Naming rules for event support:
16
- - Prefer one-word files: `bus.js`, `delegate.js`, `once.js`, `listen.js`, `index.js`.
17
- - Plural folders: `tests/`, `types/`.
18
- - Single-word methods: `on`, `emit`, `delegate`, `once`, `listen`.
19
-
20
- ---
21
-
22
- ## 1. Critical Runtime and Type Gaps
23
-
24
- ### 1.1. Native EventTarget Base Composition for EventBus
25
- - **Status**: Runtime gap & design code smell.
26
- - **Files**:
27
- - `src/core/events/bus.js`
28
- - **Problem**:
29
- The `EventBus` class is implemented as a custom subscriber registry utilizing a private Map. The architectural specifications state that the event bus must compose the browser's native `EventTarget` interface. By making `EventBus` extend `EventTarget`, we inherit native performance optimizations and DOM-standard listener registration, while maintaining backward-compatible helper wrappers.
30
- - **Expected Support**:
31
- - Refactor `EventBus` in `bus.js` to extend `EventTarget`.
32
- - Compose standard `EventTarget` capabilities, implementing `on()` and `emit()` as simple, clean wrappers on top of `addEventListener()` and `dispatchEvent()`.
33
-
34
- ### 1.2. Missing TypeScript Declarations
35
- - **Status**: Type mismatch.
36
- - **Files**:
37
- - `types/core/events/index.d.ts`
38
- - **Problem**:
39
- The TypeScript definitions for events do not export the `listen` function or the `names` namespace registry, even though both are public exports in `src/core/events/index.js`. Additionally, the declaration of the `EventBus` class does not denote its native `EventTarget` inheritance.
40
- - **Expected Support**:
41
- - Declare and export `listen` and `names` inside `types/core/events/index.d.ts`.
42
- - Update `EventBus` type definition to extend `EventTarget`.
43
-
44
- ---
45
-
46
- ## 2. State & Storage Synchronization Gaps
47
-
48
- ### 2.1. Missing Connectivity Broadcasts on the Event Bus
49
- - **Status**: Synchronization gap.
50
- - **Files**:
51
- - `src/core/offline/connectivity.js`
52
- - **Problem**:
53
- When network connectivity transitions between online and offline states, the connectivity monitor correctly updates the reactive state store but does not broadcast matching events to the global Event Bus. Consumers listening on the bus for `connectivity:online` and `connectivity:offline` are never notified.
54
- - **Expected Support**:
55
- - Synchronize connectivity updates by importing the global `bus` and dispatching `connectivity:online` or `connectivity:offline` events using standard naming constants.
56
-
57
- ### 2.2. Offline Sync Queue Broadcasts
58
- - **Status**: Synchronization gap.
59
- - **Files**:
60
- - `src/core/offline/sync.js`
61
- - **Problem**:
62
- Sync queue completion, replays, or failures are handled silently. Parent application views cannot react to queue status changes.
63
- - **Expected Support**:
64
- - Emit synchronization telemetry events on the Event Bus when tasks are successfully replayed or if they fail permanently.
65
-
66
- ---
67
-
68
- ## 3. Test Coverage Gaps
69
-
70
- ### 3.1. Single Event Awaiter Verification
71
- - **Status**: Test gap.
72
- - **Files**:
73
- - `tests/core/events/once.test.js` [NEW]
74
- - **Needed Coverage**:
75
- - Test that `once()` resolves immediately upon event firing.
76
- - Test that `once()` cleans up the registered listener after firing.
77
- - Test that `once()` rejects with an AbortError when its signal is aborted.
78
-
79
- ### 3.2. Listener Aggregation Edge Cases
80
- - **Status**: Test gap.
81
- - **Files**:
82
- - `tests/core/events/listen.test.js`
83
- - **Needed Coverage**:
84
- - Verify that options like `once: true` or `capture: true` are correctly passed through to the native target.
85
-
86
- ---
87
-
88
- ## 4. Suggested Implementation Order
89
-
90
- 1. Refactor `EventBus` to extend `EventTarget` inside `src/core/events/bus.js`.
91
- 2. Add connectivity event emission inside `src/core/offline/connectivity.js`.
92
- 3. Create the type declarations for `listen` and `names` in `types/core/events/index.d.ts`.
93
- 4. Add the unit test suite `tests/core/events/once.test.js`.
94
-
95
- ---
96
-
97
- ## 5. Done Criteria
98
-
99
- This missing-support list is complete when:
100
- - `EventBus` extends `EventTarget` and passes all existing/new test cases.
101
- - Connectivity status transitions emit corresponding events on the `bus`.
102
- - All public exports of the events module are fully typed.
103
- - `once()` and `listen()` are thoroughly covered by tests.
@@ -1,177 +0,0 @@
1
- # Native-First Event Architecture Spec & Plan
2
-
3
- This document establishes the comprehensive architectural plan, technical specifications, and system guidelines for the Native-First Event Architecture inside `src/core/events/`.
4
-
5
- ---
6
-
7
- ## 1. Architectural Philosophy & Principles
8
-
9
- The event system in this platform relies on the browser's high-performance native event-dispatch loop rather than recreating arbitrary JavaScript Pub/Sub emitters. We treat standard `EventTarget`, `Event`, and `CustomEvent` APIs as primary scheduling primitives:
10
-
11
- 1. **Zero Library Bloat:** We leverage native rendering engine loops. Subscribing to, firing, and propagating events has zero impact on bundle size.
12
- 2. **Memory Safety by Design:** No event handler should persist past its lifecycle. Every component uses a dedicated, centralized `AbortController` bound to the connection state (`disconnectedCallback`).
13
- 3. **Encapsulated & Composed Boundaries:** Communication boundaries respect the Shadow DOM layout, utilizing retargeting, flat tree propagation, and `composedPath` traversal for seamless cross-shadow event routing.
14
- 4. **Unidirectional Event Flow:**
15
- * **Upward Flow:** Custom events bubbled from child to ancestor (`{ bubbles: true, composed: true }`).
16
- * **Downward Flow:** Direct property/method invocations from parent to child.
17
- * **Decoupled System Flow:** Global Event Bus singleton (`bus.js`) reserved exclusively for out-of-band cross-cutting system telemetry (e.g., Auth, Connectivity, SW).
18
-
19
- ---
20
-
21
- ## 2. Review of Current Architecture
22
-
23
- The `src/core/events/` module is divided into four highly focused primitives:
24
-
25
- ```mermaid
26
- graph TD
27
- A[index.js] --> B[bus.js]
28
- A --> C[delegate.js]
29
- A --> D[once.js]
30
-
31
- subgraph Core Modules
32
- B
33
- C
34
- D
35
- end
36
- ```
37
-
38
- ### A. The Global Event Bus (`bus.js`)
39
-
40
- * **Purpose:** A decoupled central hub for system-wide notifications that do not map naturally to a DOM lineage.
41
- * **Mechanism:** Leverages an optimized internal `Map<string, Set<{ fn }>>`.
42
- * **Key Feature:** Highly performant execution with snapshotting (`[...set]`) to avoid runtime list mutations during event dispatch.
43
- * **Cleanup:** Integrates `AbortSignal` listeners to automatically execute the `dispose()` callback when component lifecycles cancel.
44
-
45
- ### B. Event Delegation (`delegate.js`)
46
-
47
- * **Purpose:** Attaches a single root listener to dynamically handle events from dynamic descendants, minimizing handler creation and memory consumption.
48
- * **Boundary Traversal:** Traverses through Web Component boundaries by evaluating `event.composedPath()`, checking if descendants match specified queries via `.matches(selector)`.
49
- * **Cleanup:** Disposes of listeners seamlessly on signal abort.
50
-
51
- ### C. Single Event Awaiter (`once.js`)
52
-
53
- * **Purpose:** Wraps standard event listener triggers in a Promise, allowing asynchronous waiting for one-off user or network events.
54
- * **Mechanism:** Passes `{ once: true }` down to the browser's `addEventListener` and handles clean early rejection if the abort signal triggers first.
55
-
56
- ---
57
-
58
- ## 3. Composed Event Routing (Shadow DOM Integration)
59
-
60
- To traverse the Shadow DOM encapsulation without breaking modular boundaries, our event system implements specific propagation combinations:
61
-
62
- | Propagation Mode | Configuration | Boundaries Crossed | Target Behavior | Recommended Use Case |
63
- |---|---|---|---|---|
64
- | **Fully Encapsulated** | `bubbles: false`, `composed: false` | None | Stays on target element | Internal component state ticks |
65
- | **Shadow-Local** | `bubbles: true`, `composed: false` | None (Stops at Shadow Root) | Normal bubbling | Internal compound component parts |
66
- | **Composed Bubbling** | `bubbles: true`, `composed: true` | All boundaries | Retargeted to Shadow Host | Standard child-to-parent callbacks |
67
-
68
- ```
69
- [Document Root]
70
-
71
- │ (Bubbles & Composed)
72
- [Shadow Host (Component)] ◄─── (Retargeted target appears here to Light DOM)
73
- ┌───┴───┐
74
- │ Shadow│ (Bubbles inside local tree)
75
- │ Root │
76
- └───┬───┘
77
-
78
- │ (Originates)
79
- [Shadow Target Element]
80
- ```
81
-
82
- ### Safe composedPath Traversal
83
-
84
- Standard event delegation utilizing `event.target` fails across Shadow DOM limits because of browser-enforced retargeting. `delegate.js` safely bypasses this restriction by reading `event.composedPath()`.
85
-
86
- * **Rule:** Always inspect `composedPath()[0]` when you need to resolve the exact physical leaf node that triggered the interaction.
87
-
88
- ---
89
-
90
- ## 4. Unidirectional Data Flow & Communication Contract
91
-
92
- We enforce highly strict API paths to guarantee components maintain unidirectional, predictable updates:
93
-
94
- ```mermaid
95
- sequenceDiagram
96
- participant Parent as Parent Component
97
- participant Child as Child Component (Shadow DOM)
98
-
99
- rect rgb(20, 20, 30)
100
- Note over Parent, Child: 1. Downward Communication
101
- Parent->>Child: Direct Property Assignment (child.items = data)
102
- Parent->>Child: Imperative Method Call (child.focus())
103
- end
104
-
105
- rect rgb(30, 20, 20)
106
- Note over Parent, Child: 2. Upward Communication
107
- Child-->>Parent: CustomEvent("domain:action", { bubbles, composed })
108
- end
109
- ```
110
-
111
- * **No Event Sinks Downward:** Never dispatch an event downward on a child element if setting a direct property or method accomplishes the same task.
112
- * **No Diagonal Bus Calls:** Avoid using the global Event Bus (`bus.js`) to coordinate between nearby siblings. Let their common ancestor mediate their states.
113
-
114
- ---
115
-
116
- ## 5. Memory Safety & Garbage Collection (GC) Boundary
117
-
118
- Event listeners keep their host components alive in memory because closures bind `this` strongly. The following strategies must be strictly applied:
119
-
120
- ```
121
- ┌─────────────────────────────────┐
122
- │ Garbage Collector │
123
- └────────────────┬────────────────┘
124
- │ (Checks for reference paths)
125
-
126
- ┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐
127
- │ Component Target │ ◄──── │ AbortSignal │ ◄──── │ Event Listener │
128
- └──────────────────┘ └──────────────┘ └──────────────────┘
129
- (Eligible for GC) (Aborted = Detached) (Strong Ref broken)
130
- ```
131
-
132
- 1. **Deterministic Teardown:** Ensure *every* single event listener attached outside the element's local DOM (e.g. on `window`, `document`, or `bus`) is attached with `signal: this.#controller.signal`.
133
- 2. **WeakMap for Auxiliary Metadata:** When maintaining auxiliary state outside the element class scope, store references in a `WeakMap`. This allows components to be GC'd cleanly when removed from the DOM:
134
-
135
- ```javascript
136
- const elementStates = new WeakMap();
137
- ```
138
-
139
- 3. **Avoid Dynamic Lambda Closures:** Prefer class methods or statically bound private arrow fields. Generating anonymous arrow functions inside rendering paths causes unnecessary garbage allocations:
140
-
141
- ```javascript
142
- // AVOID:
143
- this.addEventListener('click', (e) => this.handle(e));
144
-
145
- // PREFER:
146
- this.addEventListener('click', this.handle, { signal });
147
- ```
148
-
149
- ---
150
-
151
- ## 6. Actionable Implementation & Optimization Enhancements
152
-
153
- To make our current system even more robust, we will implement three core enhancements:
154
-
155
- ### 1. Optimize `delegate.js` (Fast Path Selector Matching)
156
-
157
- * **Status:** Current implementation iterates through the entire composed path.
158
- * **Enhancement:** Cache selector match results or stop iteration immediately when traversing past the designated boundaries.
159
-
160
- ### 2. Standardized Namespace Registry for System Events
161
-
162
- * **Status:** Events can be dispatched on the bus using freeform strings.
163
- * **Enhancement:** Maintain a central, typed list of valid events in `plan.md` and export standard constants to prevent typos (e.g., `events.NAMES.AUTH_SIGNED_IN`).
164
-
165
- ### 3. Progressive Passive Hooks
166
-
167
- * **Status:** Native scroll listeners default to passive, but custom handlers do not.
168
- * **Enhancement:** Automatically default touch and wheel event listeners inside components to `{ passive: true }` to enforce Interaction to Next Paint (INP) excellence.
169
-
170
- ---
171
-
172
- ## 7. Verification & Telemetry Performance Testing
173
-
174
- We verify the event architecture through several layers:
175
-
176
- * **Automated Unit Tests:** Assert composition properties, event delegation boundary crossing, and AbortSignal detaching.
177
- * **INP Measurement:** Utilize the `PerformanceObserver` with `type: 'event'` to guarantee that no event handler blocks the main thread for > 50ms.
@@ -1,89 +0,0 @@
1
- # Offline Missing Support
2
-
3
- This document tracks remaining support, runtime gaps, concurrency constraints, serialization enhancements, and state/storage synchronization work for `src/core/offline`. Implemented behavior belongs in `usage.md` (or core documentation); unsupported, under-tested, or performance-gated behavior belongs here until it is built and verified.
4
-
5
- ---
6
-
7
- ## 0. Toolchain and Naming Rules
8
-
9
- Heavy compilation, static analysis, and code generation belong in `tools/`, not in browser runtime modules.
10
-
11
- Current toolchain offline support requirements:
12
-
13
- - Statically parse and validate serialized HTTP request bodies.
14
- - Enforce idempotency key annotations on form submissions at build time.
15
-
16
- Naming rules for offline support:
17
-
18
- - Prefer one-word files: `connectivity.js`, `queue.js`, `sync.js`, `bridge.js`, `clock.js`, `state.js`, `index.js`.
19
- - Plural folders: `tests/`, `migrations/`.
20
- - Single-word methods: `check`, `subscribe`, `push`, `list`, `update`, `delete`, `clear`, `register`, `send`, `tick`.
21
- - Single-word properties in state: `online`, `status`, `pending`, `actor`, `clock`.
22
- - Avoid compound names where single words carry full meaning in context.
23
-
24
- ---
25
-
26
- ## 1. State and Storage Synchronization Gaps
27
-
28
- ### 1.1. Reactive State Integration
29
-
30
- - **Status**: Runtime gap.
31
- - **Files**:
32
- - `src/core/offline/connectivity.js`
33
- - `src/core/offline/queue.js`
34
- - `src/core/offline/state.js` [NEW]
35
- - `src/core/offline/index.js`
36
- - **Problem**:
37
- The connectivity monitor evaluates the network state via HEAD probes but does not expose it reactively using the `core.state` system. The offline queue manages deferred tasks inside IndexedDB but does not publish queue metrics (such as the number of pending tasks). Callers cannot bind UI elements (like sync indicators or queue counters) directly to the reactive state layer.
38
- - **Expected Support**:
39
- - Introduce `src/core/offline/state.js` exposing a reactive `state` store containing:
40
- - `online`: boolean indicating connectivity.
41
- - `status`: `'online' | 'offline' | 'unknown'` representing current reachability.
42
- - `pending`: number of elements currently in the sync queue.
43
- - Automatically update `online` and `status` in the state store whenever connectivity changes.
44
- - Automatically update `pending` in the state store whenever items are pushed, updated, deleted, or cleared in the queue.
45
-
46
- ### 1.2. Write-Ahead Journaling and Storage Durability
47
-
48
- - **Status**: Durability gap.
49
- - **Files**:
50
- - `src/core/offline/queue.js`
51
- - **Problem**:
52
- The offline queue writes directly to a raw IndexedDB connection (`new Database(...)` from `../storage/idb.js`). It bypasses the crash-durable journaling and quota warnings implemented in the unified `storage` gateway. Under sudden tab closure or power failure, queued tasks may fail to commit or corrupt database state.
53
- - **Expected Support**:
54
- - Integrate `OfflineQueue` with `localStorage`-based write-ahead journaling for queue writes.
55
- - Automatically recover/replay uncommitted journal records during offline engine initialization.
56
- - Listen to `onQuotaWarning` subscriptions to prevent queue pushes and trigger warning events when client storage usage exceeds 80%.
57
-
58
- ---
59
-
60
- ## 2. Concurrency and Fallback Coordination Gaps
61
-
62
- ### 2.1. Web Locks for Cross-Tab Fallback Coordination
63
-
64
- - **Status**: Concurrency gap.
65
- - **Files**:
66
- - `src/core/offline/sync.js`
67
- - **Problem**:
68
- On browsers without native Background Sync support (Firefox, Safari), the manual fallback listens for `online` transitions and triggers queue replay via custom event dispatch. In a multi-tab session, all open tabs will simultaneously receive the event and execute `replayQueue()`. This causes redundant HTTP requests, database write conflicts, and out-of-order network replay.
69
- - **Expected Support**:
70
- - Coordinate manual sync replay across tabs using an exclusive Web Lock (`navigator.locks.request`) named `"offline:sync"`.
71
- - Only the tab that successfully acquires the lock executes the replay loop, preventing concurrent replay attempts.
72
-
73
- ---
74
-
75
- ## 3. Logical Clocks and Conflict Resolution Gaps
76
-
77
- ### 3.1. Lamport Logical Clocks Engine
78
-
79
- - **Status**: Architectural gap.
80
- - **Files**:
81
- - `src/core/offline/clock.js` [NEW]
82
- - `src/core/offline/index.js`
83
- - **Problem**:
84
- To support reliable offline write replication, every queued operation must be stamped with a tuple of `(actor_id, lamport_timestamp, sequence_number)`. This ensures Last-Write-Wins (LWW) and CRDT merges resolve deterministically regardless of wall-clock drift. Currently, there is no implementation of actor registration or Lamport clock management.
85
- - **Expected Support**:
86
- - Implement a logical Lamport clock engine in `clock.js` exporting:
87
- - `actor`: a persistent UUID identifying the current client, stored in unified storage.
88
- - `tick()`: increments and returns the local logical clock count.
89
- - `sync(remoteTime)`: advances the local logical clock count to be greater than any incoming server/peer clock.
@@ -1,143 +0,0 @@
1
- # Offline & Background Capabilities Architecture Plan
2
-
3
- This document outlines the design, implementation, and optimization specifications for the resilient Offline and Background Capabilities engine under `core.offline` and the Service Worker runtime in the `@adukiorg/anza` library.
4
-
5
- ---
6
-
7
- ## 1. Architectural Strategy & Core Requirements
8
-
9
- Our offline-first architecture rests on the principle that **network absence is a normal mode of operation, not an error state**. The architecture decouples the initiation of an operation from its network execution, guaranteeing consistency, durability, and a highly responsive user experience under any connectivity condition.
10
-
11
- ### Key Pillars
12
-
13
- 1. **HEAD-Probe Connectivity Monitor (`connectivity.js`):** Resilient monitoring extending browser `navigator.onLine` with debounced, throttled (10s) HEAD probes using cache-busting headers. Support for memory-safe `subscribe` patterns utilizing the dual-cleanup pattern for `AbortSignal` listeners.
14
- 2. **IndexedDB Tasks Journal (`queue.js`):** Chronicled persistent queue leveraging IndexedDB to buffer and serialize background tasks when offline. We will enhance the deserialization module to gracefully stringify plain object payloads when `Content-Type: application/json` is specified, resolving a critical integration mismatch.
15
- 3. **Background Sync & Fallback (`sync.js`):** Native `SyncManager` registrations for Chromium-based browsers, paired with immediate event-driven fallbacks on `online` and custom triggers for Firefox and Safari. Memory-safe `onSyncFallback` listener registrations.
16
- 4. **Service Worker Message Bridge (`bridge.js`):** High-concurrency message corridors utilizing native `MessageChannel` for direct request/response dispatching to the active Service Worker controller.
17
- 5. **FIFO Replay Loop & Dead-Letter Management (`src/sw/sync.js`):** Chronological, sequential task processing with transaction safety, automatic retry limits (max 5), Dead-Letter Queue (DLQ) transitions, and tab-wide success/failure broadcasts.
18
- 6. **Conflict Resolution Architecture:** Standardized conflict resolution guidelines using logical Lamport timestamps `(actor_id, lamport_timestamp, sequence_number)` instead of physical wall clocks, supporting Last-Write-Wins (LWW) registers and Grow-Only (G-Set) or Observed-Remove (OR-Set) CRDT configurations.
19
-
20
- ---
21
-
22
- ## 2. Component Blueprint & Files Layout
23
-
24
- All files inside the offline module strictly adhere to the `RULE[user_global]` lowercase, single-word naming structure:
25
-
26
- ```
27
- src/core/offline/
28
- ├── index.js # Public offline entry point & unified facade
29
- ├── connectivity.js # Resilient connectivity check and listener subscriptions
30
- ├── queue.js # Persistent IndexedDB offline task journal
31
- ├── sync.js # Chromium Background Sync manager & Safari/Firefox online listeners
32
- ├── bridge.js # Bidirectional MessageChannel Service Worker corridor
33
- └── plan.md # This planning document
34
- ```
35
-
36
- ---
37
-
38
- ## 3. Detailed Component Designs
39
-
40
- ### 3.1. Resilient Connectivity Prober (`connectivity.js`)
41
-
42
- * **HEAD Probe with Cache-Busting:** Performs a rate-limited `fetch` request using the `HEAD` method to the local favicon or a health-check path (`/favicon.ico?_probe=Date.now()`) with `mode: 'no-cors'` and `cache: 'no-store'`.
43
- * **Shared In-Flight Promise:** Share single active in-flight check promise to prevent redundant parallel network requests.
44
- * **Leak-Free Dual Abort Cleanup:**
45
-
46
- ```javascript
47
- export function subscribe(fn, signal) {
48
- if (signal?.aborted) return () => {};
49
- listeners.add(fn);
50
- fn(isOnline);
51
-
52
- const dispose = () => {
53
- listeners.delete(fn);
54
- if (signal) {
55
- signal.removeEventListener('abort', dispose);
56
- }
57
- };
58
-
59
- if (signal) {
60
- signal.addEventListener('abort', dispose, { once: true });
61
- }
62
-
63
- return dispose;
64
- }
65
- ```
66
-
67
- ### 3.2. Idempotent Offline Queue (`queue.js`)
68
-
69
- * **IndexedDB-Backed Buffer:** Uses the `Database` client from `../storage/idb.js` under the store `tasks` inside `platform-offline-queue`.
70
- * **JSON Body Deserialization Fix:** In `src/sw/queue.js` (used during SW replay), if the serialized request `body` is not a string, Blob, or ArrayBuffer (e.g. is a plain object written by `ui-form`), it must be stringified if the header is `application/json`.
71
-
72
- ```javascript
73
- export function deserializeRequest(serialized) {
74
- const options = {
75
- method: serialized.method,
76
- headers: new Headers(serialized.headers)
77
- };
78
-
79
- if (serialized.body) {
80
- const isJson = options.headers.get('content-type')?.includes('application/json');
81
- if (isJson && typeof serialized.body === 'object' && !(serialized.body instanceof ArrayBuffer) && !(serialized.body instanceof Blob)) {
82
- options.body = JSON.stringify(serialized.body);
83
- } else {
84
- options.body = serialized.body;
85
- }
86
- }
87
-
88
- return new Request(serialized.url, options);
89
- }
90
- ```
91
-
92
- ### 3.3. Background Sync & Fallback Coordinator (`sync.js`)
93
-
94
- * **Sync API Registration:** Enqueues a sync tag (e.g., `'pending'`) with the browser's Background Sync API if supported.
95
- * **Browser-Safe Event Fallbacks:** Hooks into the window's `online` state on Safari/Firefox and dispatches a custom event (`core:sync-fallback`) detailed with the pending tag.
96
- * **Leak-Free `onSyncFallback`:** Applies the dual-cleanup unsubscription pattern for the `core:sync-fallback` abort listener to prevent memory accumulation in long-lived client tabs.
97
-
98
- ### 3.4. Service Worker Messaging Corridor (`bridge.js`)
99
-
100
- * **Response Channel Routing:** Utilizes transferable `MessageChannel` ports to match worker-side responses back to origin promises, avoiding race conditions in concurrent request dispatching.
101
- * **State Check:** Gracefully rejects with informative errors if the browser does not support Service Workers or if `navigator.serviceWorker.controller` is absent.
102
-
103
- ---
104
-
105
- ## 4. Conflict Resolution & Idempotency Guidelines
106
-
107
- To resolve concurrent offline edits reliably:
108
-
109
- 1. **Logical Clocks (Lamport):** Every offline operation writes a tuple `(actor_id, lamport_timestamp, sequence_number)`.
110
- * `actor_id`: Persisted UUID of the current device.
111
- * `lamport_timestamp`: Monotonically increasing logical count that advances locally and synchronizes on remote data delivery.
112
- 2. **Merge Semantics:**
113
- * **LWW-Register:** Scalar fields use Last-Write-Wins based on Lamport comparisons (lexicographical actor ID as a final tiebreaker).
114
- * **G-Set & OR-Set:** Collections (e.g. logs, attachment list mutations) use CRDT merge rules to ensure complete commutative, associative, and idempotent finality.
115
- 3. **Idempotency Keys:** Every queued task has an `idempotencyKey` UUID. The replay engine re-submits this key to the server which returns cached responses for duplicates, securing absolute safety across multiple retries.
116
-
117
- ---
118
-
119
- ## 5. Verification & Testing Strategy
120
-
121
- ### 5.1. Automated Unit Testing (`tests/core/offline/`)
122
-
123
- We will create a comprehensive suite of unit tests validating the offline capabilities:
124
-
125
- 1. **`connectivity.test.js`**:
126
- * Verify rate-limiting and cached status returns within the 10-second window.
127
- * Assert `subscribe` triggers immediate callback feed.
128
- * Assert that manual disposal and signal abort both clean up correctly without memory leaks.
129
- 2. **`queue.test.js`**:
130
- * Assert FIFO ordering on `list()`.
131
- * Assert push and delete operations execute successfully on IndexedDB.
132
- * Verify that `deserializeRequest` successfully stringifies plain object JSON payloads.
133
- 3. **`sync.test.js`**:
134
- * Verify Background Sync registers successfully if supported.
135
- * Assert that Safari/Firefox manual online trigger successfully dispatches the `core:sync-fallback` custom event.
136
- * Assert `onSyncFallback` correctly registers listeners and cleans up its abort hooks seamlessly.
137
- 4. **`bridge.test.js`**:
138
- * Assert that bridge messages throw when controller is absent.
139
-
140
- ### 5.2. Manual & Network Validation
141
-
142
- * Simulating offline states via DevTools and verifying that submissions to `<ui-form>` with the `offline` attribute are correctly buffered inside the IndexedDB queue.
143
- * Verifying that as soon as the network state recovers, the replayer is triggered and sequentially processes tasks, broadcasting `sync-success` events back to the UI element.
@@ -1,119 +0,0 @@
1
- # Platform Missing Support
2
-
3
- This document tracks remaining support, runtime gaps, type mismatches, and storage synchronization improvements for `src/core/platform`. Implemented behavior belongs in `usage.md` (or core documentation); unsupported, under-tested, or performance-gated behavior belongs here until it is built and verified.
4
-
5
- ---
6
-
7
- ## 0. Toolchain and Naming Rules
8
-
9
- Heavy compilation, static analysis, and code generation belong in `tools/`, not in browser runtime modules.
10
-
11
- Current toolchain platform support requirements:
12
-
13
- - Statically verify polyfill execution branches and eliminate unused polyfills in production builds.
14
- - Validate lazy-load wrapper targets at build time to prevent dynamic resolution failures.
15
- - Detect unsupported browser APIs used in application code without corresponding `supports` check.
16
-
17
- Naming rules for platform support:
18
-
19
- - Prefer one-word files: `supports.js`, `guard.js`, `index.js`.
20
- - Plural folders: `tests/`, `types/`, `polyfills/`.
21
- - Single-word methods: `yield` (as `yieldTask`), `urlPattern`, `navigation`, `popover`, `shadow`, `anchor`, `sanitizer`, `scheduler`.
22
- - Avoid compound names where single words carry full meaning in context.
23
-
24
- ---
25
-
26
- ## 1. Critical Runtime and Type Gaps
27
-
28
- ### 1.1. Missing Type Declarations for Guards and Cache Reset
29
-
30
- - **Status**: Type mismatch.
31
- - **Files**:
32
- - `types/core/platform/supports.d.ts`
33
- - **Problem**:
34
- The TypeScript definitions are severely limited. They only declare the `supports` object with a small fraction (8 out of 30+) of the actual lazy feature-detection flags. Furthermore, `guard` and `reset` are not typed or exported in the declaration file, despite being public exports in `src/core/platform/index.js`.
35
- - **Expected Support**:
36
- - Complete declarations for all 30+ feature detection keys on `supports`.
37
- - Type definitions for `reset(key: string): void`.
38
- - Type definitions for the `guard` object, including all feature-gate methods:
39
- - `urlPattern(): Promise<typeof URLPattern>`
40
- - `navigation(): Promise<Navigation>`
41
- - `popover(): Promise<void>`
42
- - `shadow(root?: ParentNode): Promise<void>`
43
- - `anchor(floating: HTMLElement, anchorEl: HTMLElement, options?: object): Promise<void>`
44
- - `sanitizer(): Promise<{ sanitizeToString(input: string): string }>`
45
- - `scheduler(): Promise<Scheduler>`
46
- - `yield(): Promise<void>`
47
-
48
- ### 1.2. Missing Critical Storage Feature Flags
49
-
50
- - **Status**: Runtime gap.
51
- - **Files**:
52
- - `src/core/platform/supports.js`
53
- - **Problem**:
54
- The `supports` detection registry is missing explicit flags for features utilized by the `storage` gateway, specifically:
55
- - `compression`: Checks for `CompressionStream` and `DecompressionStream` (required for transparent record compression in `core/storage`).
56
- - `storagePersistence`: Checks for `navigator.storage.persist` and `navigator.storage.persisted` (required for durable storage requests).
57
- - **Expected Support**:
58
- - Implement lazy `compression` detection checking `CompressionStream` and `DecompressionStream` in `globalThis`.
59
- - Implement lazy `storagePersistence` detection checking `navigator.storage` properties.
60
-
61
- ---
62
-
63
- ## 2. Storage Integration & Synchronization Gaps
64
-
65
- ### 2.1. Direct Browser API Access in Storage Gateway
66
-
67
- - **Status**: Code smell & consistency gap.
68
- - **Files**:
69
- - `src/core/storage/index.js`
70
- - `src/core/storage/quota.js`
71
- - `src/core/storage/opfs.js`
72
- - **Problem**:
73
- The `storage` gateway accesses raw APIs like `CompressionStream`, `localStorage`, and `navigator.storage` directly without consulting the centralized `platform/supports` registry. This creates duplication and makes it impossible to mock feature support in unit tests via `reset()`.
74
- - **Expected Support**:
75
- - Refactor `src/core/storage/index.js` to import `supports` and use `supports.compression` and `supports.storagePersistence`.
76
- - Refactor `src/core/storage/quota.js` to rely on `supports.storageManager` and `supports.storagePersistence` instead of doing in-line existence checks.
77
- - Refactor `src/core/storage/opfs.js` to verify `supports.opfs` on the main thread prior to worker instantiation, preventing redundant worker start failure.
78
-
79
- ---
80
-
81
- ## 3. Test Coverage Gaps
82
-
83
- ### 3.1. Unified Support Matrix & Reset Verification
84
-
85
- - **Status**: Test gap.
86
- - **Files**:
87
- - `tests/core/platform/supports.test.js`
88
- - **Needed Coverage**:
89
- - Add assertions for new lazy flags: `compression` and `storagePersistence`.
90
- - Verify that mock overrides via `reset()` correctly clear the lazy evaluation cache, permitting feature-detection simulation.
91
-
92
- ### 3.2. Polyfill Dynamic Loading Fallback Verification
93
-
94
- - **Status**: Test gap.
95
- - **Files**:
96
- - `tests/core/platform/guard.test.js`
97
- - **Needed Coverage**:
98
- - Mock supports to `false` for URLPattern, Navigation, and Scheduler.
99
- - Call the guards and verify they successfully load the polyfills dynamically and expose functional fallback behaviors.
100
-
101
- ---
102
-
103
- ## 4. Suggested Implementation Order
104
-
105
- 1. Implement `compression` and `storagePersistence` lazy detectors in `src/core/platform/supports.js`.
106
- 2. Clean up direct global checks in `src/core/storage/index.js`, `src/core/storage/quota.js`, and `src/core/storage/opfs.js` to use `supports`.
107
- 3. Update `types/core/platform/supports.d.ts` to fully type all `supports`, `guard`, and `reset` methods.
108
- 4. Add verification tests in `tests/core/platform/supports.test.js` and `tests/core/platform/guard.test.js`.
109
-
110
- ---
111
-
112
- ## 5. Done Criteria
113
-
114
- This missing-support list is complete when:
115
-
116
- - `supports` exposes `compression` and `storagePersistence` capability flags.
117
- - `core/storage` uses `supports` instead of direct global feature verification.
118
- - `types/core/platform/supports.d.ts` is fully populated.
119
- - Dynamic polyfill fallbacks are tested and pass successfully.