@mongrov/analytics 0.1.0-alpha.1 → 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.
Files changed (171) hide show
  1. package/README.md +456 -0
  2. package/dist/core/context.d.ts +24 -0
  3. package/dist/core/context.d.ts.map +1 -0
  4. package/dist/core/context.js +30 -0
  5. package/dist/core/context.js.map +1 -0
  6. package/dist/core/engine.d.ts +56 -0
  7. package/dist/core/engine.d.ts.map +1 -0
  8. package/dist/core/engine.js +119 -0
  9. package/dist/core/engine.js.map +1 -0
  10. package/dist/core/errors.d.ts +1 -1
  11. package/dist/core/errors.d.ts.map +1 -1
  12. package/dist/core/errors.js.map +1 -1
  13. package/dist/core/extensions.d.ts +33 -0
  14. package/dist/core/extensions.d.ts.map +1 -0
  15. package/dist/core/extensions.js +58 -0
  16. package/dist/core/extensions.js.map +1 -0
  17. package/dist/core/factory.d.ts +22 -5
  18. package/dist/core/factory.d.ts.map +1 -1
  19. package/dist/core/factory.js +231 -6
  20. package/dist/core/factory.js.map +1 -1
  21. package/dist/core/hooks.d.ts +32 -13
  22. package/dist/core/hooks.d.ts.map +1 -1
  23. package/dist/core/hooks.js +137 -15
  24. package/dist/core/hooks.js.map +1 -1
  25. package/dist/core/index.d.ts +3 -0
  26. package/dist/core/index.d.ts.map +1 -1
  27. package/dist/core/index.js +3 -1
  28. package/dist/core/index.js.map +1 -1
  29. package/dist/core/logger.d.ts +25 -0
  30. package/dist/core/logger.d.ts.map +1 -0
  31. package/dist/core/logger.js +33 -0
  32. package/dist/core/logger.js.map +1 -0
  33. package/dist/core/machine.d.ts +174 -0
  34. package/dist/core/machine.d.ts.map +1 -0
  35. package/dist/core/machine.js +228 -0
  36. package/dist/core/machine.js.map +1 -0
  37. package/dist/core/metric_metadata.d.ts +128 -0
  38. package/dist/core/metric_metadata.d.ts.map +1 -0
  39. package/dist/core/metric_metadata.js +47 -0
  40. package/dist/core/metric_metadata.js.map +1 -0
  41. package/dist/core/migrations.d.ts +52 -0
  42. package/dist/core/migrations.d.ts.map +1 -0
  43. package/dist/core/migrations.js +66 -0
  44. package/dist/core/migrations.js.map +1 -0
  45. package/dist/core/persistence.d.ts +50 -0
  46. package/dist/core/persistence.d.ts.map +1 -0
  47. package/dist/core/persistence.js +80 -0
  48. package/dist/core/persistence.js.map +1 -0
  49. package/dist/core/retention.d.ts +90 -0
  50. package/dist/core/retention.d.ts.map +1 -0
  51. package/dist/core/retention.js +119 -0
  52. package/dist/core/retention.js.map +1 -0
  53. package/dist/core/schemas.d.ts +35 -0
  54. package/dist/core/schemas.d.ts.map +1 -0
  55. package/dist/core/schemas.js +209 -0
  56. package/dist/core/schemas.js.map +1 -0
  57. package/dist/core/types.d.ts +10 -0
  58. package/dist/core/types.d.ts.map +1 -1
  59. package/dist/core/warehouse.d.ts +58 -0
  60. package/dist/core/warehouse.d.ts.map +1 -0
  61. package/dist/core/warehouse.js +116 -0
  62. package/dist/core/warehouse.js.map +1 -0
  63. package/dist/sync/buffer.d.ts +51 -0
  64. package/dist/sync/buffer.d.ts.map +1 -0
  65. package/dist/sync/buffer.js +188 -0
  66. package/dist/sync/buffer.js.map +1 -0
  67. package/dist/sync/context.d.ts +17 -0
  68. package/dist/sync/context.d.ts.map +1 -0
  69. package/dist/sync/context.js +23 -0
  70. package/dist/sync/context.js.map +1 -0
  71. package/dist/sync/errors.d.ts +19 -0
  72. package/dist/sync/errors.d.ts.map +1 -0
  73. package/dist/sync/errors.js +21 -0
  74. package/dist/sync/errors.js.map +1 -0
  75. package/dist/sync/events.d.ts +49 -0
  76. package/dist/sync/events.d.ts.map +1 -0
  77. package/dist/sync/events.js +46 -0
  78. package/dist/sync/events.js.map +1 -0
  79. package/dist/sync/factory.d.ts +57 -0
  80. package/dist/sync/factory.d.ts.map +1 -0
  81. package/dist/sync/factory.js +249 -0
  82. package/dist/sync/factory.js.map +1 -0
  83. package/dist/sync/fetcher.d.ts +74 -0
  84. package/dist/sync/fetcher.d.ts.map +1 -0
  85. package/dist/sync/fetcher.js +166 -0
  86. package/dist/sync/fetcher.js.map +1 -0
  87. package/dist/sync/flusher.d.ts +93 -0
  88. package/dist/sync/flusher.d.ts.map +1 -0
  89. package/dist/sync/flusher.js +234 -0
  90. package/dist/sync/flusher.js.map +1 -0
  91. package/dist/sync/hooks.d.ts +17 -0
  92. package/dist/sync/hooks.d.ts.map +1 -0
  93. package/dist/sync/hooks.js +48 -0
  94. package/dist/sync/hooks.js.map +1 -0
  95. package/dist/sync/index.d.ts +32 -1
  96. package/dist/sync/index.d.ts.map +1 -1
  97. package/dist/sync/index.js +36 -1
  98. package/dist/sync/index.js.map +1 -1
  99. package/dist/sync/manager.d.ts +48 -0
  100. package/dist/sync/manager.d.ts.map +1 -0
  101. package/dist/sync/manager.js +9 -0
  102. package/dist/sync/manager.js.map +1 -0
  103. package/dist/sync/mapper/activity.d.ts +31 -0
  104. package/dist/sync/mapper/activity.d.ts.map +1 -0
  105. package/dist/sync/mapper/activity.js +56 -0
  106. package/dist/sync/mapper/activity.js.map +1 -0
  107. package/dist/sync/mapper/battery.d.ts +12 -0
  108. package/dist/sync/mapper/battery.d.ts.map +1 -0
  109. package/dist/sync/mapper/battery.js +22 -0
  110. package/dist/sync/mapper/battery.js.map +1 -0
  111. package/dist/sync/mapper/firmware.d.ts +28 -0
  112. package/dist/sync/mapper/firmware.d.ts.map +1 -0
  113. package/dist/sync/mapper/firmware.js +43 -0
  114. package/dist/sync/mapper/firmware.js.map +1 -0
  115. package/dist/sync/mapper/heart-rate.d.ts +10 -0
  116. package/dist/sync/mapper/heart-rate.d.ts.map +1 -0
  117. package/dist/sync/mapper/heart-rate.js +19 -0
  118. package/dist/sync/mapper/heart-rate.js.map +1 -0
  119. package/dist/sync/mapper/hrv.d.ts +22 -0
  120. package/dist/sync/mapper/hrv.d.ts.map +1 -0
  121. package/dist/sync/mapper/hrv.js +56 -0
  122. package/dist/sync/mapper/hrv.js.map +1 -0
  123. package/dist/sync/mapper/ring-config.d.ts +33 -0
  124. package/dist/sync/mapper/ring-config.d.ts.map +1 -0
  125. package/dist/sync/mapper/ring-config.js +48 -0
  126. package/dist/sync/mapper/ring-config.js.map +1 -0
  127. package/dist/sync/mapper/sleep.d.ts +32 -0
  128. package/dist/sync/mapper/sleep.d.ts.map +1 -0
  129. package/dist/sync/mapper/sleep.js +103 -0
  130. package/dist/sync/mapper/sleep.js.map +1 -0
  131. package/dist/sync/mapper/spo2.d.ts +9 -0
  132. package/dist/sync/mapper/spo2.d.ts.map +1 -0
  133. package/dist/sync/mapper/spo2.js +18 -0
  134. package/dist/sync/mapper/spo2.js.map +1 -0
  135. package/dist/sync/mapper/temperature.d.ts +10 -0
  136. package/dist/sync/mapper/temperature.d.ts.map +1 -0
  137. package/dist/sync/mapper/temperature.js +19 -0
  138. package/dist/sync/mapper/temperature.js.map +1 -0
  139. package/dist/sync/mapper/time.d.ts +49 -0
  140. package/dist/sync/mapper/time.d.ts.map +1 -0
  141. package/dist/sync/mapper/time.js +107 -0
  142. package/dist/sync/mapper/time.js.map +1 -0
  143. package/dist/sync/mapper/types.d.ts +152 -0
  144. package/dist/sync/mapper/types.d.ts.map +1 -0
  145. package/dist/sync/mapper/types.js +15 -0
  146. package/dist/sync/mapper/types.js.map +1 -0
  147. package/dist/sync/overflow.d.ts +30 -0
  148. package/dist/sync/overflow.d.ts.map +1 -0
  149. package/dist/sync/overflow.js +114 -0
  150. package/dist/sync/overflow.js.map +1 -0
  151. package/dist/sync/pusher.d.ts +59 -0
  152. package/dist/sync/pusher.d.ts.map +1 -0
  153. package/dist/sync/pusher.js +115 -0
  154. package/dist/sync/pusher.js.map +1 -0
  155. package/dist/sync/scheduler.d.ts +84 -0
  156. package/dist/sync/scheduler.d.ts.map +1 -0
  157. package/dist/sync/scheduler.js +132 -0
  158. package/dist/sync/scheduler.js.map +1 -0
  159. package/dist/sync/triggers.d.ts +64 -0
  160. package/dist/sync/triggers.d.ts.map +1 -0
  161. package/dist/sync/triggers.js +113 -0
  162. package/dist/sync/triggers.js.map +1 -0
  163. package/dist/sync/types.d.ts +50 -0
  164. package/dist/sync/types.d.ts.map +1 -0
  165. package/dist/sync/types.js +8 -0
  166. package/dist/sync/types.js.map +1 -0
  167. package/dist/sync/watermark.d.ts +32 -0
  168. package/dist/sync/watermark.d.ts.map +1 -0
  169. package/dist/sync/watermark.js +61 -0
  170. package/dist/sync/watermark.js.map +1 -0
  171. package/package.json +12 -2
@@ -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"}
@@ -1,2 +1,33 @@
1
- export {};
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,37 @@
1
- export {};
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
@@ -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"}