@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.
- package/CHANGELOG.md +81 -4
- package/README.md +97 -133
- package/bin/anza/anza +0 -0
- package/bin/anza/anza.exe +0 -0
- package/bin/anza/find.js +35 -0
- package/bin/anza/index.js +34 -0
- package/bin/anza/launch.js +19 -0
- package/bin/common/index.js +7 -0
- package/bin/common/logs.js +62 -0
- package/bin/create/copy.js +18 -0
- package/bin/create/index.js +45 -0
- package/bin/create/run.js +210 -0
- package/bin/create/write.js +19 -0
- package/importmap.json +4 -0
- package/package.json +16 -10
- package/src/core/offline/{usage.md → notes/usage.md} +11 -1
- package/src/core/router/boot.js +82 -0
- package/src/core/router/cascade.js +76 -0
- package/src/core/router/container.js +63 -72
- package/src/core/router/graph.js +144 -0
- package/src/core/router/index.js +12 -2
- package/src/core/router/intercept.js +26 -7
- package/src/core/router/lca.js +58 -0
- package/src/core/router/match.js +49 -36
- package/src/core/router/notes/audit-old.md +887 -0
- package/src/core/router/notes/audti.md +773 -0
- package/src/core/router/notes/tasks.md +473 -0
- package/src/core/router/{usage.md → notes/usage.md} +57 -35
- package/src/core/router/sync/tab.js +6 -4
- package/src/core/router/transitions.js +35 -8
- package/src/core/router/trie.js +130 -0
- package/src/core/security/{usage.md → notes/usage.md} +1 -2
- package/src/core/storage/{usage.md → notes/usage.md} +6 -6
- package/src/core/theme/index.js +78 -0
- package/src/core/ui/define/index.js +2 -1
- package/src/core/ui/define/orchestrator.js +10 -4
- package/src/core/ui/defs/dock.js +134 -0
- package/src/core/ui/defs/index.js +20 -0
- package/src/core/ui/defs/page.js +89 -0
- package/src/core/ui/defs/part.js +28 -0
- package/src/core/ui/defs/spec.js +96 -0
- package/src/core/ui/defs/view.js +23 -0
- package/src/core/ui/index.js +16 -3
- package/src/core/ui/notes/definations.md +979 -0
- package/src/tokens/index.css +1 -0
- package/src/tokens/semantic/contrast.css +18 -0
- package/src/tokens/semantic/transitions.css +32 -0
- package/types/core/platform/index.d.ts +39 -10
- package/types/core/router/index.d.ts +9 -0
- package/types/core/theme/index.d.ts +18 -0
- package/types/core/ui/index.d.ts +11 -0
- package/types/index.d.ts +1 -0
- package/bin/anza.js +0 -63
- package/bin/create.js +0 -150
- package/src/core/api/plan.md +0 -209
- package/src/core/events/missing.md +0 -103
- package/src/core/events/plan.md +0 -177
- package/src/core/offline/missing.md +0 -89
- package/src/core/offline/plan.md +0 -143
- package/src/core/platform/missing.md +0 -119
- package/src/core/platform/platform.d.ts +0 -88
- package/src/core/router/missing.md +0 -716
- package/src/core/router/outlet.js +0 -139
- package/src/core/router/plan.md +0 -370
- package/src/core/security/missing.md +0 -97
- package/src/core/state/missing.md +0 -165
- package/src/core/storage/missing.md +0 -165
- package/src/core/storage/plan.md +0 -69
- package/src/core/ui/implementation.md +0 -170
- package/src/core/ui/plan.md +0 -510
- package/src/core/ui/ui.types.md +0 -890
- /package/src/core/animations/{usage.md → notes/usage.md} +0 -0
- /package/src/core/api/{usage.md → notes/usage.md} +0 -0
- /package/src/core/events/{usage.md → notes/usage.md} +0 -0
- /package/src/core/platform/{usage.md → notes/usage.md} +0 -0
- /package/src/core/state/{usage.md → notes/usage.md} +0 -0
- /package/src/core/ui/{usage.md → notes/usage.md} +0 -0
- /package/src/core/ui/{watch.md → notes/watch.md} +0 -0
- /package/src/core/workers/{plan.md → notes/plan.md} +0 -0
- /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.
|
package/src/core/events/plan.md
DELETED
|
@@ -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.
|
package/src/core/offline/plan.md
DELETED
|
@@ -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.
|