@mongrov/analytics 0.1.0-alpha.0 → 0.1.0-alpha.7
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/README.md +456 -0
- package/dist/core/context.d.ts +24 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +30 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/engine.d.ts +56 -0
- package/dist/core/engine.d.ts.map +1 -0
- package/dist/core/engine.js +119 -0
- package/dist/core/engine.js.map +1 -0
- package/dist/core/errors.d.ts +1 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/extensions.d.ts +33 -0
- package/dist/core/extensions.d.ts.map +1 -0
- package/dist/core/extensions.js +58 -0
- package/dist/core/extensions.js.map +1 -0
- package/dist/core/factory.d.ts +22 -5
- package/dist/core/factory.d.ts.map +1 -1
- package/dist/core/factory.js +231 -6
- package/dist/core/factory.js.map +1 -1
- package/dist/core/hooks.d.ts +32 -13
- package/dist/core/hooks.d.ts.map +1 -1
- package/dist/core/hooks.js +137 -15
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +25 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +33 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/machine.d.ts +174 -0
- package/dist/core/machine.d.ts.map +1 -0
- package/dist/core/machine.js +228 -0
- package/dist/core/machine.js.map +1 -0
- package/dist/core/metric_metadata.d.ts +128 -0
- package/dist/core/metric_metadata.d.ts.map +1 -0
- package/dist/core/metric_metadata.js +47 -0
- package/dist/core/metric_metadata.js.map +1 -0
- package/dist/core/migrations.d.ts +52 -0
- package/dist/core/migrations.d.ts.map +1 -0
- package/dist/core/migrations.js +66 -0
- package/dist/core/migrations.js.map +1 -0
- package/dist/core/persistence.d.ts +50 -0
- package/dist/core/persistence.d.ts.map +1 -0
- package/dist/core/persistence.js +80 -0
- package/dist/core/persistence.js.map +1 -0
- package/dist/core/retention.d.ts +90 -0
- package/dist/core/retention.d.ts.map +1 -0
- package/dist/core/retention.js +119 -0
- package/dist/core/retention.js.map +1 -0
- package/dist/core/schemas.d.ts +35 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +209 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/types.d.ts +10 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/warehouse.d.ts +58 -0
- package/dist/core/warehouse.d.ts.map +1 -0
- package/dist/core/warehouse.js +116 -0
- package/dist/core/warehouse.js.map +1 -0
- package/dist/sync/buffer.d.ts +51 -0
- package/dist/sync/buffer.d.ts.map +1 -0
- package/dist/sync/buffer.js +188 -0
- package/dist/sync/buffer.js.map +1 -0
- package/dist/sync/context.d.ts +17 -0
- package/dist/sync/context.d.ts.map +1 -0
- package/dist/sync/context.js +23 -0
- package/dist/sync/context.js.map +1 -0
- package/dist/sync/errors.d.ts +19 -0
- package/dist/sync/errors.d.ts.map +1 -0
- package/dist/sync/errors.js +21 -0
- package/dist/sync/errors.js.map +1 -0
- package/dist/sync/events.d.ts +49 -0
- package/dist/sync/events.d.ts.map +1 -0
- package/dist/sync/events.js +46 -0
- package/dist/sync/events.js.map +1 -0
- package/dist/sync/factory.d.ts +57 -0
- package/dist/sync/factory.d.ts.map +1 -0
- package/dist/sync/factory.js +249 -0
- package/dist/sync/factory.js.map +1 -0
- package/dist/sync/fetcher.d.ts +74 -0
- package/dist/sync/fetcher.d.ts.map +1 -0
- package/dist/sync/fetcher.js +166 -0
- package/dist/sync/fetcher.js.map +1 -0
- package/dist/sync/flusher.d.ts +93 -0
- package/dist/sync/flusher.d.ts.map +1 -0
- package/dist/sync/flusher.js +234 -0
- package/dist/sync/flusher.js.map +1 -0
- package/dist/sync/hooks.d.ts +17 -0
- package/dist/sync/hooks.d.ts.map +1 -0
- package/dist/sync/hooks.js +48 -0
- package/dist/sync/hooks.js.map +1 -0
- package/dist/sync/index.d.ts +32 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +36 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/manager.d.ts +48 -0
- package/dist/sync/manager.d.ts.map +1 -0
- package/dist/sync/manager.js +9 -0
- package/dist/sync/manager.js.map +1 -0
- package/dist/sync/mapper/activity.d.ts +31 -0
- package/dist/sync/mapper/activity.d.ts.map +1 -0
- package/dist/sync/mapper/activity.js +56 -0
- package/dist/sync/mapper/activity.js.map +1 -0
- package/dist/sync/mapper/battery.d.ts +12 -0
- package/dist/sync/mapper/battery.d.ts.map +1 -0
- package/dist/sync/mapper/battery.js +22 -0
- package/dist/sync/mapper/battery.js.map +1 -0
- package/dist/sync/mapper/firmware.d.ts +28 -0
- package/dist/sync/mapper/firmware.d.ts.map +1 -0
- package/dist/sync/mapper/firmware.js +43 -0
- package/dist/sync/mapper/firmware.js.map +1 -0
- package/dist/sync/mapper/heart-rate.d.ts +10 -0
- package/dist/sync/mapper/heart-rate.d.ts.map +1 -0
- package/dist/sync/mapper/heart-rate.js +19 -0
- package/dist/sync/mapper/heart-rate.js.map +1 -0
- package/dist/sync/mapper/hrv.d.ts +22 -0
- package/dist/sync/mapper/hrv.d.ts.map +1 -0
- package/dist/sync/mapper/hrv.js +56 -0
- package/dist/sync/mapper/hrv.js.map +1 -0
- package/dist/sync/mapper/ring-config.d.ts +33 -0
- package/dist/sync/mapper/ring-config.d.ts.map +1 -0
- package/dist/sync/mapper/ring-config.js +48 -0
- package/dist/sync/mapper/ring-config.js.map +1 -0
- package/dist/sync/mapper/sleep.d.ts +32 -0
- package/dist/sync/mapper/sleep.d.ts.map +1 -0
- package/dist/sync/mapper/sleep.js +103 -0
- package/dist/sync/mapper/sleep.js.map +1 -0
- package/dist/sync/mapper/spo2.d.ts +9 -0
- package/dist/sync/mapper/spo2.d.ts.map +1 -0
- package/dist/sync/mapper/spo2.js +18 -0
- package/dist/sync/mapper/spo2.js.map +1 -0
- package/dist/sync/mapper/temperature.d.ts +10 -0
- package/dist/sync/mapper/temperature.d.ts.map +1 -0
- package/dist/sync/mapper/temperature.js +19 -0
- package/dist/sync/mapper/temperature.js.map +1 -0
- package/dist/sync/mapper/time.d.ts +49 -0
- package/dist/sync/mapper/time.d.ts.map +1 -0
- package/dist/sync/mapper/time.js +107 -0
- package/dist/sync/mapper/time.js.map +1 -0
- package/dist/sync/mapper/types.d.ts +152 -0
- package/dist/sync/mapper/types.d.ts.map +1 -0
- package/dist/sync/mapper/types.js +15 -0
- package/dist/sync/mapper/types.js.map +1 -0
- package/dist/sync/overflow.d.ts +30 -0
- package/dist/sync/overflow.d.ts.map +1 -0
- package/dist/sync/overflow.js +114 -0
- package/dist/sync/overflow.js.map +1 -0
- package/dist/sync/pusher.d.ts +59 -0
- package/dist/sync/pusher.d.ts.map +1 -0
- package/dist/sync/pusher.js +115 -0
- package/dist/sync/pusher.js.map +1 -0
- package/dist/sync/scheduler.d.ts +84 -0
- package/dist/sync/scheduler.d.ts.map +1 -0
- package/dist/sync/scheduler.js +132 -0
- package/dist/sync/scheduler.js.map +1 -0
- package/dist/sync/triggers.d.ts +64 -0
- package/dist/sync/triggers.d.ts.map +1 -0
- package/dist/sync/triggers.js +113 -0
- package/dist/sync/triggers.js.map +1 -0
- package/dist/sync/types.d.ts +50 -0
- package/dist/sync/types.d.ts.map +1 -0
- package/dist/sync/types.js +8 -0
- package/dist/sync/types.js.map +1 -0
- package/dist/sync/watermark.d.ts +32 -0
- package/dist/sync/watermark.d.ts.map +1 -0
- package/dist/sync/watermark.js +61 -0
- package/dist/sync/watermark.js.map +1 -0
- package/package.json +27 -16
- package/LICENSE +0 -21
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch flusher (T-13 + T-15).
|
|
3
|
+
*
|
|
4
|
+
* Drains a `SensorBuffer` into a DuckDB Appender. Successful flushes are
|
|
5
|
+
* durably observable (buffer.drain() removes both in-memory and overflow
|
|
6
|
+
* copies), and a `SyncEmitter` fan-out surfaces `flushed` events for hooks +
|
|
7
|
+
* downstream invalidation.
|
|
8
|
+
*
|
|
9
|
+
* Retry / concurrency (T-15):
|
|
10
|
+
* - Wrapped in a `p-queue` (concurrency=2 by default) so multi-table flushes
|
|
11
|
+
* run in parallel without hammering the CPU.
|
|
12
|
+
* - Priorities: `foreground` (0) > `manual` (1) > `scheduled` (5) >
|
|
13
|
+
* `background` (10). Lower numeric priority = runs sooner.
|
|
14
|
+
* - Backoff schedule: 1s, 2s, 4s, 8s, 16s, 32s, 60s (capped). 5 consecutive
|
|
15
|
+
* failures per table → the flusher stops re-enqueuing and surfaces
|
|
16
|
+
* `error` state until the next explicit `flush()`.
|
|
17
|
+
* - Per-attempt timeout: 30s. Timeout aborts the attempt and counts as a
|
|
18
|
+
* failure toward the 5-failure limit.
|
|
19
|
+
*
|
|
20
|
+
* Data safety: attempts do *not* remove rows from the buffer until the
|
|
21
|
+
* appender reports success. On failure the drained entries are re-pushed onto
|
|
22
|
+
* the in-memory ring (front of queue) so subsequent retries see the same
|
|
23
|
+
* batch.
|
|
24
|
+
*/
|
|
25
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
26
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
27
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
28
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
29
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
30
|
+
};
|
|
31
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
32
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
33
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
34
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
35
|
+
};
|
|
36
|
+
var _BatchFlusher_instances, _BatchFlusher_engine, _BatchFlusher_buffer, _BatchFlusher_columnOrder, _BatchFlusher_queue, _BatchFlusher_sleep, _BatchFlusher_now, _BatchFlusher_emit, _BatchFlusher_tables, _BatchFlusher_runWithRetry, _BatchFlusher_flushWithTimeout, _BatchFlusher_writeToAppender, _BatchFlusher_restore, _BatchFlusher_ensureState;
|
|
37
|
+
import PQueue from 'p-queue';
|
|
38
|
+
import { SyncError } from './errors';
|
|
39
|
+
// p-queue: HIGHER priority values run first. Foreground / manual sit at the
|
|
40
|
+
// top; background sits at the floor.
|
|
41
|
+
const PRIORITY_BY_REASON = {
|
|
42
|
+
foreground: 100,
|
|
43
|
+
manual: 90,
|
|
44
|
+
'row-count': 50,
|
|
45
|
+
age: 40,
|
|
46
|
+
scheduled: 10,
|
|
47
|
+
background: 0,
|
|
48
|
+
};
|
|
49
|
+
/** Exponential backoff in ms, per attempt index (0-based). Capped at 60s. */
|
|
50
|
+
export const BACKOFF_SEQUENCE_MS = [
|
|
51
|
+
1000,
|
|
52
|
+
2000,
|
|
53
|
+
4000,
|
|
54
|
+
8000,
|
|
55
|
+
16000,
|
|
56
|
+
32000,
|
|
57
|
+
60000,
|
|
58
|
+
];
|
|
59
|
+
export const MAX_CONSECUTIVE_FAILURES = 5;
|
|
60
|
+
export const FLUSH_TIMEOUT_MS = 30000;
|
|
61
|
+
export class BatchFlusher {
|
|
62
|
+
constructor(config) {
|
|
63
|
+
_BatchFlusher_instances.add(this);
|
|
64
|
+
_BatchFlusher_engine.set(this, void 0);
|
|
65
|
+
_BatchFlusher_buffer.set(this, void 0);
|
|
66
|
+
_BatchFlusher_columnOrder.set(this, void 0);
|
|
67
|
+
_BatchFlusher_queue.set(this, void 0);
|
|
68
|
+
_BatchFlusher_sleep.set(this, void 0);
|
|
69
|
+
_BatchFlusher_now.set(this, void 0);
|
|
70
|
+
_BatchFlusher_emit.set(this, void 0);
|
|
71
|
+
_BatchFlusher_tables.set(this, new Map());
|
|
72
|
+
__classPrivateFieldSet(this, _BatchFlusher_engine, config.engine, "f");
|
|
73
|
+
__classPrivateFieldSet(this, _BatchFlusher_buffer, config.buffer, "f");
|
|
74
|
+
__classPrivateFieldSet(this, _BatchFlusher_columnOrder, config.columnOrder, "f");
|
|
75
|
+
__classPrivateFieldSet(this, _BatchFlusher_sleep, config.sleep ?? defaultSleep, "f");
|
|
76
|
+
__classPrivateFieldSet(this, _BatchFlusher_now, config.now ?? (() => Date.now()), "f");
|
|
77
|
+
__classPrivateFieldSet(this, _BatchFlusher_emit, config.emit, "f");
|
|
78
|
+
__classPrivateFieldSet(this, _BatchFlusher_queue, new PQueue({ concurrency: config.concurrency ?? 2 }), "f");
|
|
79
|
+
}
|
|
80
|
+
/** Runtime state for a table. `idle` if we've never touched it. */
|
|
81
|
+
stateOf(table) {
|
|
82
|
+
return __classPrivateFieldGet(this, _BatchFlusher_tables, "f").get(table)?.state ?? 'idle';
|
|
83
|
+
}
|
|
84
|
+
lastErrorOf(table) {
|
|
85
|
+
return __classPrivateFieldGet(this, _BatchFlusher_tables, "f").get(table)?.lastError;
|
|
86
|
+
}
|
|
87
|
+
/** Consecutive failures (reset on any success). */
|
|
88
|
+
failureCountOf(table) {
|
|
89
|
+
return __classPrivateFieldGet(this, _BatchFlusher_tables, "f").get(table)?.failureCount ?? 0;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Single flush attempt (no retry). Used directly by explicit user code and
|
|
93
|
+
* indirectly by `scheduleFlush` for the retry loop.
|
|
94
|
+
*/
|
|
95
|
+
async flush(table, reason = 'manual') {
|
|
96
|
+
const state = __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_ensureState).call(this, table);
|
|
97
|
+
state.state = 'flushing';
|
|
98
|
+
const drained = await __classPrivateFieldGet(this, _BatchFlusher_buffer, "f").drain(table);
|
|
99
|
+
if (drained.length === 0) {
|
|
100
|
+
state.state = state.failureCount > 0 ? 'error' : 'idle';
|
|
101
|
+
return { table, rowsFlushed: 0, ok: true };
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
const rowsFlushed = __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_writeToAppender).call(this, table, drained);
|
|
105
|
+
state.failureCount = 0;
|
|
106
|
+
state.lastError = undefined;
|
|
107
|
+
state.state = 'idle';
|
|
108
|
+
__classPrivateFieldGet(this, _BatchFlusher_emit, "f")?.call(this, { type: 'flushed', payload: { table, rowsFlushed, reason } });
|
|
109
|
+
return { table, rowsFlushed, ok: true };
|
|
110
|
+
}
|
|
111
|
+
catch (cause) {
|
|
112
|
+
// Return drained rows to the front of the ring so retries see them.
|
|
113
|
+
await __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_restore).call(this, table, drained);
|
|
114
|
+
const err = cause instanceof SyncError
|
|
115
|
+
? cause
|
|
116
|
+
: new SyncError('flush_failed', `flush failed for ${table}`, cause);
|
|
117
|
+
state.failureCount += 1;
|
|
118
|
+
state.lastError = err;
|
|
119
|
+
state.state = 'error';
|
|
120
|
+
__classPrivateFieldGet(this, _BatchFlusher_emit, "f")?.call(this, { type: 'flush-failed', payload: { table, error: err } });
|
|
121
|
+
return { table, rowsFlushed: 0, ok: false, error: err };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Enqueue a flush with retry orchestration. Non-blocking — returns the
|
|
126
|
+
* promise for callers that want to await final resolution.
|
|
127
|
+
*/
|
|
128
|
+
scheduleFlush(table, reason) {
|
|
129
|
+
const priority = PRIORITY_BY_REASON[reason];
|
|
130
|
+
return __classPrivateFieldGet(this, _BatchFlusher_queue, "f").add(() => __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_runWithRetry).call(this, table, reason), { priority })
|
|
131
|
+
// p-queue's typings make add() return `Promise<T | void>`; we always
|
|
132
|
+
// resolve with a FlushResult so this cast is safe.
|
|
133
|
+
.then(r => r);
|
|
134
|
+
}
|
|
135
|
+
/** Wait until every in-flight + queued flush settles. */
|
|
136
|
+
async drainQueue() {
|
|
137
|
+
await __classPrivateFieldGet(this, _BatchFlusher_queue, "f").onIdle();
|
|
138
|
+
}
|
|
139
|
+
/** Pause the queue — new `scheduleFlush()` calls enqueue but don't run. */
|
|
140
|
+
pauseQueue() {
|
|
141
|
+
__classPrivateFieldGet(this, _BatchFlusher_queue, "f").pause();
|
|
142
|
+
}
|
|
143
|
+
/** Resume a paused queue. */
|
|
144
|
+
resumeQueue() {
|
|
145
|
+
__classPrivateFieldGet(this, _BatchFlusher_queue, "f").start();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
_BatchFlusher_engine = new WeakMap(), _BatchFlusher_buffer = new WeakMap(), _BatchFlusher_columnOrder = new WeakMap(), _BatchFlusher_queue = new WeakMap(), _BatchFlusher_sleep = new WeakMap(), _BatchFlusher_now = new WeakMap(), _BatchFlusher_emit = new WeakMap(), _BatchFlusher_tables = new WeakMap(), _BatchFlusher_instances = new WeakSet(), _BatchFlusher_runWithRetry = async function _BatchFlusher_runWithRetry(table, reason) {
|
|
149
|
+
let lastResult = { table, rowsFlushed: 0, ok: false };
|
|
150
|
+
for (let attempt = 0; attempt < BACKOFF_SEQUENCE_MS.length; attempt++) {
|
|
151
|
+
const result = await __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_flushWithTimeout).call(this, table, reason);
|
|
152
|
+
lastResult = result;
|
|
153
|
+
if (result.ok)
|
|
154
|
+
return result;
|
|
155
|
+
const failures = this.failureCountOf(table);
|
|
156
|
+
if (failures >= MAX_CONSECUTIVE_FAILURES) {
|
|
157
|
+
// Terminal for this scheduled run. The `error` state persists on the
|
|
158
|
+
// table until an explicit `flush()` succeeds.
|
|
159
|
+
return result;
|
|
160
|
+
}
|
|
161
|
+
await __classPrivateFieldGet(this, _BatchFlusher_sleep, "f").call(this, BACKOFF_SEQUENCE_MS[attempt]);
|
|
162
|
+
}
|
|
163
|
+
return lastResult;
|
|
164
|
+
}, _BatchFlusher_flushWithTimeout = async function _BatchFlusher_flushWithTimeout(table, reason) {
|
|
165
|
+
const attempt = this.flush(table, reason);
|
|
166
|
+
let timeoutId;
|
|
167
|
+
const timeout = new Promise((resolve) => {
|
|
168
|
+
timeoutId = setTimeout(() => {
|
|
169
|
+
const err = new SyncError('flush_failed', `flush timed out after ${FLUSH_TIMEOUT_MS}ms for ${table}`);
|
|
170
|
+
const state = __classPrivateFieldGet(this, _BatchFlusher_instances, "m", _BatchFlusher_ensureState).call(this, table);
|
|
171
|
+
state.failureCount += 1;
|
|
172
|
+
state.lastError = err;
|
|
173
|
+
state.state = 'error';
|
|
174
|
+
__classPrivateFieldGet(this, _BatchFlusher_emit, "f")?.call(this, { type: 'flush-failed', payload: { table, error: err } });
|
|
175
|
+
resolve({ table, rowsFlushed: 0, ok: false, error: err });
|
|
176
|
+
}, FLUSH_TIMEOUT_MS);
|
|
177
|
+
});
|
|
178
|
+
try {
|
|
179
|
+
return await Promise.race([attempt, timeout]);
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
if (timeoutId !== undefined)
|
|
183
|
+
clearTimeout(timeoutId);
|
|
184
|
+
}
|
|
185
|
+
}, _BatchFlusher_writeToAppender = function _BatchFlusher_writeToAppender(table, entries) {
|
|
186
|
+
const cols = __classPrivateFieldGet(this, _BatchFlusher_columnOrder, "f")[table];
|
|
187
|
+
if (!cols) {
|
|
188
|
+
throw new SyncError('flush_failed', `no columnOrder registered for table "${table}"`);
|
|
189
|
+
}
|
|
190
|
+
const appender = __classPrivateFieldGet(this, _BatchFlusher_engine, "f").createAppender(table);
|
|
191
|
+
let rowsWritten = 0;
|
|
192
|
+
try {
|
|
193
|
+
for (const entry of entries) {
|
|
194
|
+
for (const row of entry.rows) {
|
|
195
|
+
appender.appendRow(cols.map(c => row[c] ?? null));
|
|
196
|
+
rowsWritten += 1;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
appender.flush();
|
|
200
|
+
return rowsWritten;
|
|
201
|
+
}
|
|
202
|
+
finally {
|
|
203
|
+
try {
|
|
204
|
+
appender.close();
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
// Swallow close errors — the surfaced error should be the write.
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}, _BatchFlusher_restore = async function _BatchFlusher_restore(table, entries) {
|
|
211
|
+
// Cheapest recovery: re-push each entry as a fresh batch. Preserves rows
|
|
212
|
+
// but reorders enqueuedAt — acceptable, since data survives.
|
|
213
|
+
for (const entry of entries) {
|
|
214
|
+
await __classPrivateFieldGet(this, _BatchFlusher_buffer, "f").push({
|
|
215
|
+
table,
|
|
216
|
+
brand: entry.brand,
|
|
217
|
+
familyId: entry.familyId,
|
|
218
|
+
userId: entry.userId,
|
|
219
|
+
deviceId: entry.deviceId,
|
|
220
|
+
rows: entry.rows,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
}, _BatchFlusher_ensureState = function _BatchFlusher_ensureState(table) {
|
|
224
|
+
let state = __classPrivateFieldGet(this, _BatchFlusher_tables, "f").get(table);
|
|
225
|
+
if (!state) {
|
|
226
|
+
state = { failureCount: 0, state: 'idle' };
|
|
227
|
+
__classPrivateFieldGet(this, _BatchFlusher_tables, "f").set(table, state);
|
|
228
|
+
}
|
|
229
|
+
return state;
|
|
230
|
+
};
|
|
231
|
+
function defaultSleep(ms) {
|
|
232
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=flusher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flusher.js","sourceRoot":"","sources":["../../src/sync/flusher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T-27 — React hooks over the SyncManager.
|
|
3
|
+
*
|
|
4
|
+
* `useSensorSink` returns the manager's memoised sink handle.
|
|
5
|
+
* `useSyncState` / `useSyncProgress` bind `useSyncExternalStore` to the manager
|
|
6
|
+
* subscribe fan-out. Each hook keeps a cached snapshot updated only inside the
|
|
7
|
+
* subscribe callback so `getSnapshot` returns a stable reference between
|
|
8
|
+
* transitions (React's snapshot-equality check requires this).
|
|
9
|
+
*/
|
|
10
|
+
import type { SensorSink, SyncManagerState, SyncProgress } from './manager';
|
|
11
|
+
/** Subscribe to the manager's aggregate scheduler state. */
|
|
12
|
+
export declare function useSyncState(): SyncManagerState;
|
|
13
|
+
/** Returns the SensorSink handle — memoised for the lifetime of the manager. */
|
|
14
|
+
export declare function useSensorSink(): SensorSink;
|
|
15
|
+
/** Progress snapshot: pending row counts + last flush / sync-complete stamps. */
|
|
16
|
+
export declare function useSyncProgress(): SyncProgress;
|
|
17
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/sync/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAe,gBAAgB,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExF,4DAA4D;AAC5D,wBAAgB,YAAY,IAAI,gBAAgB,CAI/C;AAED,gFAAgF;AAChF,wBAAgB,aAAa,IAAI,UAAU,CAE1C;AAED,iFAAiF;AACjF,wBAAgB,eAAe,IAAI,YAAY,CAI9C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T-27 — React hooks over the SyncManager.
|
|
3
|
+
*
|
|
4
|
+
* `useSensorSink` returns the manager's memoised sink handle.
|
|
5
|
+
* `useSyncState` / `useSyncProgress` bind `useSyncExternalStore` to the manager
|
|
6
|
+
* subscribe fan-out. Each hook keeps a cached snapshot updated only inside the
|
|
7
|
+
* subscribe callback so `getSnapshot` returns a stable reference between
|
|
8
|
+
* transitions (React's snapshot-equality check requires this).
|
|
9
|
+
*/
|
|
10
|
+
import { useMemo, useSyncExternalStore } from 'react';
|
|
11
|
+
import { useSyncManager } from './context';
|
|
12
|
+
/** Subscribe to the manager's aggregate scheduler state. */
|
|
13
|
+
export function useSyncState() {
|
|
14
|
+
const manager = useSyncManager();
|
|
15
|
+
const cache = useMemo(() => makeStateCache(manager), [manager]);
|
|
16
|
+
return useSyncExternalStore(cache.subscribe, cache.get, cache.get);
|
|
17
|
+
}
|
|
18
|
+
/** Returns the SensorSink handle — memoised for the lifetime of the manager. */
|
|
19
|
+
export function useSensorSink() {
|
|
20
|
+
return useSyncManager().sink;
|
|
21
|
+
}
|
|
22
|
+
/** Progress snapshot: pending row counts + last flush / sync-complete stamps. */
|
|
23
|
+
export function useSyncProgress() {
|
|
24
|
+
const manager = useSyncManager();
|
|
25
|
+
const cache = useMemo(() => makeProgressCache(manager), [manager]);
|
|
26
|
+
return useSyncExternalStore(cache.subscribe, cache.get, cache.get);
|
|
27
|
+
}
|
|
28
|
+
function makeStateCache(manager) {
|
|
29
|
+
let snapshot = manager.state();
|
|
30
|
+
return {
|
|
31
|
+
subscribe: (onStoreChange) => manager.subscribe((next) => {
|
|
32
|
+
snapshot = next;
|
|
33
|
+
onStoreChange();
|
|
34
|
+
}),
|
|
35
|
+
get: () => snapshot,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function makeProgressCache(manager) {
|
|
39
|
+
let snapshot = manager.progress();
|
|
40
|
+
return {
|
|
41
|
+
subscribe: (onStoreChange) => manager.subscribe(() => {
|
|
42
|
+
snapshot = manager.progress();
|
|
43
|
+
onStoreChange();
|
|
44
|
+
}),
|
|
45
|
+
get: () => snapshot,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/sync/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAG1C,4DAA4D;AAC5D,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,cAAc,EAAE,CAAA;IAChC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAC/D,OAAO,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;AACpE,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,aAAa;IAC3B,OAAO,cAAc,EAAE,CAAC,IAAI,CAAA;AAC9B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,eAAe;IAC7B,MAAM,OAAO,GAAG,cAAc,EAAE,CAAA;IAChC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,OAAO,oBAAoB,CAAC,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;AACpE,CAAC;AAOD,SAAS,cAAc,CAAC,OAAoB;IAC1C,IAAI,QAAQ,GAAG,OAAO,CAAC,KAAK,EAAE,CAAA;IAC9B,OAAO;QACL,SAAS,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YACvD,QAAQ,GAAG,IAAI,CAAA;YACf,aAAa,EAAE,CAAA;QACjB,CAAC,CAAC;QACF,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ;KACpB,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAoB;IAC7C,IAAI,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;IACjC,OAAO;QACL,SAAS,EAAE,CAAC,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE;YACnD,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAA;YAC7B,aAAa,EAAE,CAAA;QACjB,CAAC,CAAC;QACF,GAAG,EAAE,GAAG,EAAE,CAAC,QAAQ;KACpB,CAAA;AACH,CAAC"}
|
package/dist/sync/index.d.ts
CHANGED
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @mongrov/analytics/sync — public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Phases A–C: mapper + buffer + flusher surfaces. Pusher/fetcher/scheduler
|
|
5
|
+
* ship in subsequent phases (see `.specifica/features/analytics-sync/tasks.md`).
|
|
6
|
+
*/
|
|
7
|
+
export { SensorBuffer, type SensorBufferConfig } from './buffer';
|
|
8
|
+
export { OverflowStore } from './overflow';
|
|
9
|
+
export type { BufferEntry, BufferSize, FlushResult, OverflowPolicy, SensorBatch, } from './types';
|
|
10
|
+
export { type WatermarkKind, WatermarkStore, type WatermarkStoreConfig, } from './watermark';
|
|
11
|
+
export { type PushResult, R2Pusher, type R2PusherConfig, } from './pusher';
|
|
12
|
+
export { type FetchParams, type FetchResult, type PrefetchPolicy, R2Fetcher, type R2FetcherConfig, } from './fetcher';
|
|
13
|
+
export { BACKOFF_SEQUENCE_MS, BatchFlusher, type BatchFlusherConfig, FLUSH_TIMEOUT_MS, type FlushReason, type FlushedEvent, MAX_CONSECUTIVE_FAILURES, type FlusherState, type SyncEmitter, } from './flusher';
|
|
14
|
+
export { SyncError, type SyncErrorCode } from './errors';
|
|
15
|
+
export { DEFAULT_MAX_AGE_MS, DEFAULT_MAX_ROWS, FlushTriggers, type FlushTriggersConfig, } from './triggers';
|
|
16
|
+
export { createSyncManager, type CreateSyncManagerConfig } from './factory';
|
|
17
|
+
export type { SensorSink, SyncManager, SyncManagerState, SyncProgress, } from './manager';
|
|
18
|
+
export { SyncProvider, type SyncProviderProps, useSyncManager } from './context';
|
|
19
|
+
export { useSensorSink, useSyncProgress, useSyncState } from './hooks';
|
|
20
|
+
export { bindFlushEvents, bindPushEvents, type EventBus, type FlushInsertPayload, type PushEmitter, type SyncCompletePayload, } from './events';
|
|
21
|
+
export { type BackgroundTaskPort, type ConstraintPort, type CycleResult, type SchedulerConstraints, type SchedulerLogger, type SchedulerState, type SyncCoordinator, SyncScheduler, type SyncSchedulerConfig, } from './scheduler';
|
|
22
|
+
export { mapActivity, type MapActivityResult } from './mapper/activity';
|
|
23
|
+
export { BATTERY_EVENT, mapBattery } from './mapper/battery';
|
|
24
|
+
export { type FirmwareMappedBatch, mapFirmwareExport, type MapFirmwareOptions, } from './mapper/firmware';
|
|
25
|
+
export { mapHeartRate } from './mapper/heart-rate';
|
|
26
|
+
export { mapHrv } from './mapper/hrv';
|
|
27
|
+
export { type MapRingConfigResult, mapRingConfig, type RingConfigClose, } from './mapper/ring-config';
|
|
28
|
+
export { type ReconstructSleepResult, reconstructSleepSessions, } from './mapper/sleep';
|
|
29
|
+
export { mapSpo2 } from './mapper/spo2';
|
|
30
|
+
export { mapTemperature } from './mapper/temperature';
|
|
31
|
+
export { computeNightOf, parseTimestamp } from './mapper/time';
|
|
32
|
+
export type { ActivityBucketRow, ActivityRow, DeviceConfigRow, DeviceEventRow, FirmwareActivityRow, FirmwareBatteryRow, FirmwareExport, FirmwareHRRow, FirmwareHRVRow, FirmwareMonitoringWindow, FirmwareRingConfig, FirmwareSleepRow, FirmwareSpO2Row, FirmwareTempRow, HeartRateRow, HrvRow, MappedBatch, MapperContext, SleepRawRow, SleepSessionRow, SleepStageRow, Spo2Row, TemperatureRow, } from './mapper/types';
|
|
2
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/sync/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"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"}
|
package/dist/sync/index.js
CHANGED
|
@@ -1,2 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @mongrov/analytics/sync — public barrel.
|
|
3
|
+
*
|
|
4
|
+
* Phases A–C: mapper + buffer + flusher surfaces. Pusher/fetcher/scheduler
|
|
5
|
+
* ship in subsequent phases (see `.specifica/features/analytics-sync/tasks.md`).
|
|
6
|
+
*/
|
|
7
|
+
// Buffer + overflow (Phase B).
|
|
8
|
+
export { SensorBuffer } from './buffer';
|
|
9
|
+
export { OverflowStore } from './overflow';
|
|
10
|
+
// Watermark + pusher + fetcher (Phase D+E+F).
|
|
11
|
+
export { WatermarkStore, } from './watermark';
|
|
12
|
+
export { R2Pusher, } from './pusher';
|
|
13
|
+
export { R2Fetcher, } from './fetcher';
|
|
14
|
+
// Flusher + triggers (Phase C).
|
|
15
|
+
export { BACKOFF_SEQUENCE_MS, BatchFlusher, FLUSH_TIMEOUT_MS, MAX_CONSECUTIVE_FAILURES, } from './flusher';
|
|
16
|
+
export { SyncError } from './errors';
|
|
17
|
+
export { DEFAULT_MAX_AGE_MS, DEFAULT_MAX_ROWS, FlushTriggers, } from './triggers';
|
|
18
|
+
// Factory + hooks + provider (Phase I).
|
|
19
|
+
export { createSyncManager } from './factory';
|
|
20
|
+
export { SyncProvider, useSyncManager } from './context';
|
|
21
|
+
export { useSensorSink, useSyncProgress, useSyncState } from './hooks';
|
|
22
|
+
// Event bus integration (Phase H).
|
|
23
|
+
export { bindFlushEvents, bindPushEvents, } from './events';
|
|
24
|
+
// Scheduler (Phase G).
|
|
25
|
+
export { SyncScheduler, } from './scheduler';
|
|
26
|
+
// Mappers (Phase A).
|
|
27
|
+
export { mapActivity } from './mapper/activity';
|
|
28
|
+
export { BATTERY_EVENT, mapBattery } from './mapper/battery';
|
|
29
|
+
export { mapFirmwareExport, } from './mapper/firmware';
|
|
30
|
+
export { mapHeartRate } from './mapper/heart-rate';
|
|
31
|
+
export { mapHrv } from './mapper/hrv';
|
|
32
|
+
export { mapRingConfig, } from './mapper/ring-config';
|
|
33
|
+
export { reconstructSleepSessions, } from './mapper/sleep';
|
|
34
|
+
export { mapSpo2 } from './mapper/spo2';
|
|
35
|
+
export { mapTemperature } from './mapper/temperature';
|
|
36
|
+
export { computeNightOf, parseTimestamp } from './mapper/time';
|
|
2
37
|
//# sourceMappingURL=index.js.map
|
package/dist/sync/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,+BAA+B;AAC/B,OAAO,EAAE,YAAY,EAA2B,MAAM,UAAU,CAAA;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAS1C,8CAA8C;AAC9C,OAAO,EAEL,cAAc,GAEf,MAAM,aAAa,CAAA;AACpB,OAAO,EAEL,QAAQ,GAET,MAAM,UAAU,CAAA;AACjB,OAAO,EAIL,SAAS,GAEV,MAAM,WAAW,CAAA;AAElB,gCAAgC;AAChC,OAAO,EACL,mBAAmB,EACnB,YAAY,EAEZ,gBAAgB,EAGhB,wBAAwB,GAGzB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,SAAS,EAAsB,MAAM,UAAU,CAAA;AACxD,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,GAEd,MAAM,YAAY,CAAA;AAEnB,wCAAwC;AACxC,OAAO,EAAE,iBAAiB,EAAgC,MAAM,WAAW,CAAA;AAO3E,OAAO,EAAE,YAAY,EAA0B,cAAc,EAAE,MAAM,WAAW,CAAA;AAChF,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtE,mCAAmC;AACnC,OAAO,EACL,eAAe,EACf,cAAc,GAKf,MAAM,UAAU,CAAA;AAEjB,uBAAuB;AACvB,OAAO,EAQL,aAAa,GAEd,MAAM,aAAa,CAAA;AAEpB,qBAAqB;AACrB,OAAO,EAAE,WAAW,EAA0B,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC5D,OAAO,EAEL,iBAAiB,GAElB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAEL,aAAa,GAEd,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAEL,wBAAwB,GACzB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AACrD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T-26 — `createSyncManager` return type + shared interfaces.
|
|
3
|
+
*
|
|
4
|
+
* The `SyncManager` is the composition root the app holds. It owns the
|
|
5
|
+
* buffer, flusher, triggers, pusher, fetcher, scheduler, and event bus
|
|
6
|
+
* plumbing. `SensorSink` is the ergonomic write-side surface consumers see.
|
|
7
|
+
*/
|
|
8
|
+
import type { AnalyticsEngine, AttachContext } from '../core/types';
|
|
9
|
+
import type { BatchFlusher } from './flusher';
|
|
10
|
+
import type { FetchResult, R2Fetcher } from './fetcher';
|
|
11
|
+
import type { FirmwareExport, MapperContext } from './mapper/types';
|
|
12
|
+
import type { R2Pusher } from './pusher';
|
|
13
|
+
import type { CycleResult, SchedulerState, SyncScheduler } from './scheduler';
|
|
14
|
+
import type { FlushResult, SensorBatch } from './types';
|
|
15
|
+
/**
|
|
16
|
+
* Ergonomic write-side API the app calls from adapters. Matches spec §SensorSink.
|
|
17
|
+
*/
|
|
18
|
+
export interface SensorSink {
|
|
19
|
+
push: (batch: SensorBatch) => Promise<void>;
|
|
20
|
+
pushFirmware: (fw: FirmwareExport, ctx: MapperContext) => Promise<void>;
|
|
21
|
+
flush: () => Promise<FlushResult[]>;
|
|
22
|
+
pendingRowCount: (table?: string) => Promise<number>;
|
|
23
|
+
clear: () => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
export interface SyncManagerState {
|
|
26
|
+
scheduler: SchedulerState;
|
|
27
|
+
}
|
|
28
|
+
export interface SyncProgress {
|
|
29
|
+
pendingByTable: Record<string, number>;
|
|
30
|
+
lastFlushAt?: number;
|
|
31
|
+
lastSyncCompleteAt?: number;
|
|
32
|
+
}
|
|
33
|
+
export interface SyncManager {
|
|
34
|
+
readonly analytics: AnalyticsEngine;
|
|
35
|
+
readonly sink: SensorSink;
|
|
36
|
+
readonly flusher: BatchFlusher;
|
|
37
|
+
readonly pusher: R2Pusher;
|
|
38
|
+
readonly fetcher: R2Fetcher;
|
|
39
|
+
readonly scheduler: SyncScheduler;
|
|
40
|
+
state: () => SyncManagerState;
|
|
41
|
+
progress: () => SyncProgress;
|
|
42
|
+
subscribe: (fn: (state: SyncManagerState) => void) => () => void;
|
|
43
|
+
start: () => Promise<void>;
|
|
44
|
+
stop: () => Promise<void>;
|
|
45
|
+
triggerNow: () => Promise<CycleResult>;
|
|
46
|
+
prefetch: (ctx: AttachContext) => Promise<FetchResult[]>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/sync/manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,KAAK,EACV,WAAW,EACX,cAAc,EACd,aAAa,EACd,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAEvD;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3C,YAAY,EAAE,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvE,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;IACnC,eAAe,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IACpD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,cAAc,CAAA;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAA;IACnC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAA;IAC3B,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;IACjC,KAAK,EAAE,MAAM,gBAAgB,CAAA;IAC7B,QAAQ,EAAE,MAAM,YAAY,CAAA;IAC5B,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;IAChE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,UAAU,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAA;IACtC,QAAQ,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC,CAAA;CACzD"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T-26 — `createSyncManager` return type + shared interfaces.
|
|
3
|
+
*
|
|
4
|
+
* The `SyncManager` is the composition root the app holds. It owns the
|
|
5
|
+
* buffer, flusher, triggers, pusher, fetcher, scheduler, and event bus
|
|
6
|
+
* plumbing. `SensorSink` is the ergonomic write-side surface consumers see.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/sync/manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity mapper (T-05).
|
|
3
|
+
*
|
|
4
|
+
* Firmware `activitydetails` rows aggregate 10 minutes of steps in
|
|
5
|
+
* `arraySteps[10]` alongside a 10-minute bucket `step` (total), `calories`,
|
|
6
|
+
* and `distance` (km). We want both granularities in the warehouse:
|
|
7
|
+
*
|
|
8
|
+
* - `activity` — 1-min rows via `arraySteps` unnest
|
|
9
|
+
* - `activity_bucket` — 10-min rows preserving calories + distance
|
|
10
|
+
*
|
|
11
|
+
* Timestamp policy: the firmware `timestamp` marks the start of the 10-min
|
|
12
|
+
* block. Each unnested activity row is stamped at `base + i minutes` where
|
|
13
|
+
* `i` is the index into `arraySteps`.
|
|
14
|
+
*
|
|
15
|
+
* Known 1.3% mismatch: sum(arraySteps) can drift from `step` (firmware
|
|
16
|
+
* quirk). Spec calls for "flag in log" — deferred until the SyncLogger wire
|
|
17
|
+
* lands in Phase C. For now the mapper produces both outputs and the ground
|
|
18
|
+
* truth in the warehouse is the sum of `activity.steps` per user per
|
|
19
|
+
* 10-minute window.
|
|
20
|
+
*
|
|
21
|
+
* Distance unit: firmware `distance` is passed through as-is into
|
|
22
|
+
* `distance_km`. If field measurement shows the firmware reports metres, this
|
|
23
|
+
* mapper is the single place to divide.
|
|
24
|
+
*/
|
|
25
|
+
import type { ActivityBucketRow, ActivityRow, FirmwareActivityRow, MapperContext } from './types';
|
|
26
|
+
export interface MapActivityResult {
|
|
27
|
+
activity: ActivityRow[];
|
|
28
|
+
activity_bucket: ActivityBucketRow[];
|
|
29
|
+
}
|
|
30
|
+
export declare function mapActivity(rows: readonly FirmwareActivityRow[], ctx: MapperContext): MapActivityResult;
|
|
31
|
+
//# sourceMappingURL=activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../../src/sync/mapper/activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACX,mBAAmB,EACnB,aAAa,EACd,MAAM,SAAS,CAAA;AAEhB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAA;IACvB,eAAe,EAAE,iBAAiB,EAAE,CAAA;CACrC;AAID,wBAAgB,WAAW,CACzB,IAAI,EAAE,SAAS,mBAAmB,EAAE,EACpC,GAAG,EAAE,aAAa,GACjB,iBAAiB,CA8BnB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity mapper (T-05).
|
|
3
|
+
*
|
|
4
|
+
* Firmware `activitydetails` rows aggregate 10 minutes of steps in
|
|
5
|
+
* `arraySteps[10]` alongside a 10-minute bucket `step` (total), `calories`,
|
|
6
|
+
* and `distance` (km). We want both granularities in the warehouse:
|
|
7
|
+
*
|
|
8
|
+
* - `activity` — 1-min rows via `arraySteps` unnest
|
|
9
|
+
* - `activity_bucket` — 10-min rows preserving calories + distance
|
|
10
|
+
*
|
|
11
|
+
* Timestamp policy: the firmware `timestamp` marks the start of the 10-min
|
|
12
|
+
* block. Each unnested activity row is stamped at `base + i minutes` where
|
|
13
|
+
* `i` is the index into `arraySteps`.
|
|
14
|
+
*
|
|
15
|
+
* Known 1.3% mismatch: sum(arraySteps) can drift from `step` (firmware
|
|
16
|
+
* quirk). Spec calls for "flag in log" — deferred until the SyncLogger wire
|
|
17
|
+
* lands in Phase C. For now the mapper produces both outputs and the ground
|
|
18
|
+
* truth in the warehouse is the sum of `activity.steps` per user per
|
|
19
|
+
* 10-minute window.
|
|
20
|
+
*
|
|
21
|
+
* Distance unit: firmware `distance` is passed through as-is into
|
|
22
|
+
* `distance_km`. If field measurement shows the firmware reports metres, this
|
|
23
|
+
* mapper is the single place to divide.
|
|
24
|
+
*/
|
|
25
|
+
import { parseTimestamp } from './time';
|
|
26
|
+
const MINUTE_MS = 60000;
|
|
27
|
+
export function mapActivity(rows, ctx) {
|
|
28
|
+
const activity = [];
|
|
29
|
+
const activity_bucket = [];
|
|
30
|
+
for (const row of rows) {
|
|
31
|
+
const baseTs = parseTimestamp(row.timestamp);
|
|
32
|
+
const steps = row.arraySteps ?? [];
|
|
33
|
+
for (let i = 0; i < steps.length; i++) {
|
|
34
|
+
activity.push({
|
|
35
|
+
ts: new Date(baseTs.getTime() + i * MINUTE_MS),
|
|
36
|
+
brand: ctx.brand,
|
|
37
|
+
family_id: ctx.familyId,
|
|
38
|
+
user_id: ctx.userId,
|
|
39
|
+
device_id: ctx.deviceId,
|
|
40
|
+
steps: steps[i],
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
activity_bucket.push({
|
|
44
|
+
ts: baseTs,
|
|
45
|
+
brand: ctx.brand,
|
|
46
|
+
family_id: ctx.familyId,
|
|
47
|
+
user_id: ctx.userId,
|
|
48
|
+
device_id: ctx.deviceId,
|
|
49
|
+
steps: row.step,
|
|
50
|
+
calories: row.calories,
|
|
51
|
+
distance_km: row.distance,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
return { activity, activity_bucket };
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../../../src/sync/mapper/activity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAavC,MAAM,SAAS,GAAG,KAAM,CAAA;AAExB,MAAM,UAAU,WAAW,CACzB,IAAoC,EACpC,GAAkB;IAElB,MAAM,QAAQ,GAAkB,EAAE,CAAA;IAClC,MAAM,eAAe,GAAwB,EAAE,CAAA;IAE/C,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAA;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,QAAQ,CAAC,IAAI,CAAC;gBACZ,EAAE,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC;gBAC9C,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,SAAS,EAAE,GAAG,CAAC,QAAQ;gBACvB,OAAO,EAAE,GAAG,CAAC,MAAM;gBACnB,SAAS,EAAE,GAAG,CAAC,QAAQ;gBACvB,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;aAChB,CAAC,CAAA;QACJ,CAAC;QACD,eAAe,CAAC,IAAI,CAAC;YACnB,EAAE,EAAE,MAAM;YACV,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,SAAS,EAAE,GAAG,CAAC,QAAQ;YACvB,OAAO,EAAE,GAAG,CAAC,MAAM;YACnB,SAAS,EAAE,GAAG,CAAC,QAAQ;YACvB,KAAK,EAAE,GAAG,CAAC,IAAI;YACf,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,WAAW,EAAE,GAAG,CAAC,QAAQ;SAC1B,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAA;AACtC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Battery mapper (T-07).
|
|
3
|
+
*
|
|
4
|
+
* Firmware `battery_table` rows lift into the generic `device_event` stream
|
|
5
|
+
* with `event_type='battery_sample'`. The battery level lives in the JSON
|
|
6
|
+
* payload column so the `device_event` table doesn't grow bespoke columns
|
|
7
|
+
* for every metric variant.
|
|
8
|
+
*/
|
|
9
|
+
import type { DeviceEventRow, FirmwareBatteryRow, MapperContext } from './types';
|
|
10
|
+
export declare const BATTERY_EVENT = "battery_sample";
|
|
11
|
+
export declare function mapBattery(rows: readonly FirmwareBatteryRow[], ctx: MapperContext): DeviceEventRow[];
|
|
12
|
+
//# sourceMappingURL=battery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"battery.d.ts","sourceRoot":"","sources":["../../../src/sync/mapper/battery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EACV,cAAc,EACd,kBAAkB,EAClB,aAAa,EACd,MAAM,SAAS,CAAA;AAEhB,eAAO,MAAM,aAAa,mBAAmB,CAAA;AAE7C,wBAAgB,UAAU,CACxB,IAAI,EAAE,SAAS,kBAAkB,EAAE,EACnC,GAAG,EAAE,aAAa,GACjB,cAAc,EAAE,CAUlB"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Battery mapper (T-07).
|
|
3
|
+
*
|
|
4
|
+
* Firmware `battery_table` rows lift into the generic `device_event` stream
|
|
5
|
+
* with `event_type='battery_sample'`. The battery level lives in the JSON
|
|
6
|
+
* payload column so the `device_event` table doesn't grow bespoke columns
|
|
7
|
+
* for every metric variant.
|
|
8
|
+
*/
|
|
9
|
+
import { parseTimestamp } from './time';
|
|
10
|
+
export const BATTERY_EVENT = 'battery_sample';
|
|
11
|
+
export function mapBattery(rows, ctx) {
|
|
12
|
+
return rows.map(row => ({
|
|
13
|
+
ts: parseTimestamp(row.timestamp),
|
|
14
|
+
brand: ctx.brand,
|
|
15
|
+
family_id: ctx.familyId,
|
|
16
|
+
user_id: ctx.userId,
|
|
17
|
+
device_id: ctx.deviceId,
|
|
18
|
+
event_type: BATTERY_EVENT,
|
|
19
|
+
payload: { battery: row.battery },
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=battery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"battery.js","sourceRoot":"","sources":["../../../src/sync/mapper/battery.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAA;AAOvC,MAAM,CAAC,MAAM,aAAa,GAAG,gBAAgB,CAAA;AAE7C,MAAM,UAAU,UAAU,CACxB,IAAmC,EACnC,GAAkB;IAElB,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtB,EAAE,EAAE,cAAc,CAAC,GAAG,CAAC,SAAS,CAAC;QACjC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,SAAS,EAAE,GAAG,CAAC,QAAQ;QACvB,OAAO,EAAE,GAAG,CAAC,MAAM;QACnB,SAAS,EAAE,GAAG,CAAC,QAAQ;QACvB,UAAU,EAAE,aAAa;QACzB,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE;KAClC,CAAC,CAAC,CAAA;AACL,CAAC"}
|