@mongrov/analytics 0.6.0 → 0.7.0
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 +23 -10
- package/UPGRADING.md +370 -0
- package/dist/core/device-events.d.ts +14 -0
- package/dist/core/device-events.d.ts.map +1 -0
- package/dist/core/device-events.js +13 -0
- package/dist/core/device-events.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 +21 -4
- package/dist/core/extensions.d.ts.map +1 -1
- package/dist/core/extensions.js +21 -4
- package/dist/core/extensions.js.map +1 -1
- package/dist/core/factory.d.ts.map +1 -1
- package/dist/core/factory.js +125 -23
- package/dist/core/factory.js.map +1 -1
- package/dist/core/hooks.js +1 -1
- package/dist/core/hooks.js.map +1 -1
- package/dist/core/index.d.ts +11 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +14 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/insight.d.ts +44 -0
- package/dist/core/insight.d.ts.map +1 -0
- package/dist/core/insight.js +62 -0
- package/dist/core/insight.js.map +1 -0
- package/dist/core/metric_metadata.d.ts +55 -0
- package/dist/core/metric_metadata.d.ts.map +1 -1
- package/dist/core/metric_metadata.js +35 -7
- package/dist/core/metric_metadata.js.map +1 -1
- package/dist/core/migrations.d.ts.map +1 -1
- package/dist/core/migrations.js +64 -2
- package/dist/core/migrations.js.map +1 -1
- package/dist/core/retention.d.ts +44 -13
- package/dist/core/retention.d.ts.map +1 -1
- package/dist/core/retention.js +49 -22
- package/dist/core/retention.js.map +1 -1
- package/dist/core/schemas.d.ts +73 -2
- package/dist/core/schemas.d.ts.map +1 -1
- package/dist/core/schemas.js +154 -3
- package/dist/core/schemas.js.map +1 -1
- package/dist/core/table_metadata.d.ts.map +1 -1
- package/dist/core/table_metadata.js +3 -0
- package/dist/core/table_metadata.js.map +1 -1
- package/dist/core/types.d.ts +45 -10
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/warehouse.d.ts +28 -0
- package/dist/core/warehouse.d.ts.map +1 -1
- package/dist/core/warehouse.js +44 -0
- package/dist/core/warehouse.js.map +1 -1
- package/dist/core/watermark-cache.d.ts +75 -0
- package/dist/core/watermark-cache.d.ts.map +1 -0
- package/dist/core/watermark-cache.js +0 -0
- package/dist/core/watermark-cache.js.map +1 -0
- package/dist/rules/__fakes__/fakeEngine.d.ts +2 -0
- package/dist/rules/__fakes__/fakeEngine.d.ts.map +1 -1
- package/dist/rules/__fakes__/fakeEngine.js +4 -0
- package/dist/rules/__fakes__/fakeEngine.js.map +1 -1
- package/dist/rules/baseline-reader.d.ts +55 -0
- package/dist/rules/baseline-reader.d.ts.map +1 -0
- package/dist/rules/baseline-reader.js +111 -0
- package/dist/rules/baseline-reader.js.map +1 -0
- package/dist/rules/compiler.d.ts +36 -1
- package/dist/rules/compiler.d.ts.map +1 -1
- package/dist/rules/compiler.js +185 -39
- package/dist/rules/compiler.js.map +1 -1
- package/dist/rules/defaults/luminx.d.ts.map +1 -1
- package/dist/rules/defaults/luminx.js +8 -0
- package/dist/rules/defaults/luminx.js.map +1 -1
- package/dist/rules/defaults/viva.d.ts.map +1 -1
- package/dist/rules/defaults/viva.js +7 -0
- package/dist/rules/defaults/viva.js.map +1 -1
- package/dist/rules/defaults/yogaring.d.ts.map +1 -1
- package/dist/rules/defaults/yogaring.js +7 -0
- package/dist/rules/defaults/yogaring.js.map +1 -1
- package/dist/rules/defaults/ziva.d.ts.map +1 -1
- package/dist/rules/defaults/ziva.js +100 -24
- package/dist/rules/defaults/ziva.js.map +1 -1
- package/dist/rules/evaluator.d.ts +14 -3
- package/dist/rules/evaluator.d.ts.map +1 -1
- package/dist/rules/evaluator.js +157 -5
- package/dist/rules/evaluator.js.map +1 -1
- package/dist/rules/factory.d.ts.map +1 -1
- package/dist/rules/factory.js +5 -1
- package/dist/rules/factory.js.map +1 -1
- package/dist/rules/index.d.ts +2 -1
- package/dist/rules/index.d.ts.map +1 -1
- package/dist/rules/index.js +2 -1
- package/dist/rules/index.js.map +1 -1
- package/dist/rules/schema.d.ts +75 -4
- package/dist/rules/schema.d.ts.map +1 -1
- package/dist/rules/schema.js +44 -0
- package/dist/rules/schema.js.map +1 -1
- package/dist/rules/types.d.ts +16 -1
- package/dist/rules/types.d.ts.map +1 -1
- package/dist/rules/validator.d.ts.map +1 -1
- package/dist/rules/validator.js +56 -0
- package/dist/rules/validator.js.map +1 -1
- package/dist/sync/baseline-compute.d.ts +63 -0
- package/dist/sync/baseline-compute.d.ts.map +1 -0
- package/dist/sync/baseline-compute.js +211 -0
- package/dist/sync/baseline-compute.js.map +1 -0
- package/dist/sync/events.d.ts +19 -5
- package/dist/sync/events.d.ts.map +1 -1
- package/dist/sync/events.js +17 -0
- package/dist/sync/events.js.map +1 -1
- package/dist/sync/factory.d.ts +25 -4
- package/dist/sync/factory.d.ts.map +1 -1
- package/dist/sync/factory.js +108 -15
- package/dist/sync/factory.js.map +1 -1
- package/dist/sync/fetcher.d.ts +15 -2
- package/dist/sync/fetcher.d.ts.map +1 -1
- package/dist/sync/fetcher.js +43 -7
- package/dist/sync/fetcher.js.map +1 -1
- package/dist/sync/flusher.d.ts +52 -2
- package/dist/sync/flusher.d.ts.map +1 -1
- package/dist/sync/flusher.js +78 -9
- package/dist/sync/flusher.js.map +1 -1
- package/dist/sync/index.d.ts +3 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/mapper/activity.d.ts.map +1 -1
- package/dist/sync/mapper/activity.js +2 -1
- package/dist/sync/mapper/activity.js.map +1 -1
- package/dist/sync/mapper/ring-config.js +1 -1
- package/dist/sync/mapper/ring-config.js.map +1 -1
- package/dist/sync/mapper/schema.d.ts +411 -0
- package/dist/sync/mapper/schema.d.ts.map +1 -0
- package/dist/sync/mapper/schema.js +128 -0
- package/dist/sync/mapper/schema.js.map +1 -0
- package/dist/sync/mapper/sleep.d.ts +58 -13
- package/dist/sync/mapper/sleep.d.ts.map +1 -1
- package/dist/sync/mapper/sleep.js +141 -44
- package/dist/sync/mapper/sleep.js.map +1 -1
- package/dist/sync/mapper/types.d.ts +66 -10
- package/dist/sync/mapper/types.d.ts.map +1 -1
- package/dist/sync/scheduler.d.ts +7 -0
- package/dist/sync/scheduler.d.ts.map +1 -1
- package/dist/sync/scheduler.js +14 -0
- package/dist/sync/scheduler.js.map +1 -1
- package/dist/tools/__fakes__/engine.d.ts +2 -0
- package/dist/tools/__fakes__/engine.d.ts.map +1 -1
- package/dist/tools/__fakes__/engine.js +10 -0
- package/dist/tools/__fakes__/engine.js.map +1 -1
- package/dist/tools/authorize.d.ts +19 -12
- package/dist/tools/authorize.d.ts.map +1 -1
- package/dist/tools/authorize.js +31 -40
- package/dist/tools/authorize.js.map +1 -1
- package/dist/tools/factory.d.ts +2 -0
- package/dist/tools/factory.d.ts.map +1 -1
- package/dist/tools/factory.js +12 -1
- package/dist/tools/factory.js.map +1 -1
- package/dist/tools/formatters/copy-guidelines.d.ts +57 -0
- package/dist/tools/formatters/copy-guidelines.d.ts.map +1 -0
- package/dist/tools/formatters/copy-guidelines.js +110 -0
- package/dist/tools/formatters/copy-guidelines.js.map +1 -0
- package/dist/tools/formatters/index.d.ts +14 -0
- package/dist/tools/formatters/index.d.ts.map +1 -0
- package/dist/tools/formatters/index.js +14 -0
- package/dist/tools/formatters/index.js.map +1 -0
- package/dist/tools/formatters/spo2.d.ts +21 -0
- package/dist/tools/formatters/spo2.d.ts.map +1 -0
- package/dist/tools/formatters/spo2.js +79 -0
- package/dist/tools/formatters/spo2.js.map +1 -0
- package/dist/tools/{formatters.d.ts → formatters/text.d.ts} +1 -1
- package/dist/tools/formatters/text.d.ts.map +1 -0
- package/dist/tools/{formatters.js → formatters/text.js} +1 -1
- package/dist/tools/formatters/text.js.map +1 -0
- package/dist/tools/impls/activity.d.ts +2 -2
- package/dist/tools/impls/activity.js +7 -3
- package/dist/tools/impls/activity.js.map +1 -1
- package/dist/tools/impls/anomaly.d.ts +2 -2
- package/dist/tools/impls/anomaly.js +8 -4
- package/dist/tools/impls/anomaly.js.map +1 -1
- package/dist/tools/impls/compare.d.ts +2 -2
- package/dist/tools/impls/compare.js +8 -4
- package/dist/tools/impls/compare.js.map +1 -1
- package/dist/tools/impls/hrv.d.ts +2 -2
- package/dist/tools/impls/hrv.js +6 -2
- package/dist/tools/impls/hrv.js.map +1 -1
- package/dist/tools/impls/insights.d.ts +4 -4
- package/dist/tools/impls/insights.d.ts.map +1 -1
- package/dist/tools/impls/insights.js +10 -3
- package/dist/tools/impls/insights.js.map +1 -1
- package/dist/tools/impls/sleep.d.ts +2 -2
- package/dist/tools/impls/sleep.js +6 -2
- package/dist/tools/impls/sleep.js.map +1 -1
- package/dist/tools/impls/spo2.d.ts +52 -0
- package/dist/tools/impls/spo2.d.ts.map +1 -0
- package/dist/tools/impls/spo2.js +65 -0
- package/dist/tools/impls/spo2.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +4 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/mcp/guard.d.ts +28 -11
- package/dist/tools/mcp/guard.d.ts.map +1 -1
- package/dist/tools/mcp/guard.js +45 -15
- package/dist/tools/mcp/guard.js.map +1 -1
- package/dist/tools/mcp/index.d.ts +1 -1
- package/dist/tools/mcp/index.d.ts.map +1 -1
- package/dist/tools/mcp/index.js +1 -1
- package/dist/tools/mcp/index.js.map +1 -1
- package/dist/tools/mcp/server.d.ts.map +1 -1
- package/dist/tools/mcp/server.js +4 -0
- package/dist/tools/mcp/server.js.map +1 -1
- package/dist/tools/mcp/transports/http.d.ts.map +1 -1
- package/dist/tools/mcp/transports/http.js +4 -0
- package/dist/tools/mcp/transports/http.js.map +1 -1
- package/package.json +8 -5
- package/dist/tools/formatters.d.ts.map +0 -1
- package/dist/tools/formatters.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,16 +6,29 @@ Per-family (or per-tenant) warehouses attached as DuckDB catalogs. Zero-copy
|
|
|
6
6
|
reads against R2 Iceberg tables. Headless core with optional React hooks and
|
|
7
7
|
UI subpaths.
|
|
8
8
|
|
|
9
|
-
Status: **0.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
Status: **0.7.0** — Sprint 5 hardening. Core engine, `/sync`, `/rules`,
|
|
10
|
+
`/tools` and `/tools/mcp` subpaths all landed; 727 tests green, plus the
|
|
11
|
+
T-18 / T-28 integration suites against the MinIO + Iceberg REST docker
|
|
12
|
+
stack.
|
|
13
|
+
|
|
14
|
+
0.7.0 lands: `icu` extension, `v_{table}` union views (local-unpushed +
|
|
15
|
+
remote), `user_baseline` with day-first quantiles, `batch:complete` batch
|
|
16
|
+
lifecycle, rules `context` / `consecutive` / `user_setting` targets, the
|
|
17
|
+
`getSpO2` tool, and copy guardrails on every formatter.
|
|
18
|
+
|
|
19
|
+
**Breaking** — see [UPGRADING.md](./UPGRADING.md) for rewrites. Headlines:
|
|
20
|
+
mapped sleep row shapes now match the DDL (they did not before, and sleep
|
|
21
|
+
flushes were writing NULLs into NOT NULL columns); `AnalyticsEngine` gained
|
|
22
|
+
`getFamilyMembers()` and `dismissInsight()`; rule and tool SQL now reads
|
|
23
|
+
`v_{table}` views, so an attach is required; rules evaluate once per batch
|
|
24
|
+
rather than per table.
|
|
25
|
+
|
|
26
|
+
> Historical note (0.3.0): SCD-2 `device_config` support inverted the
|
|
27
|
+
> ring-config mapping direction — `DeviceConfigRow` moved from `metric` to
|
|
28
|
+
> `data_type`, with a consumer-supplied `RingConfigTranslator` producing the
|
|
29
|
+
> firmware enum from our metric names. Sprint 5 §2 intended to reverse this
|
|
30
|
+
> (`metric VARCHAR`), but the change is **blocked**: the spec's firmware
|
|
31
|
+
> codes do not match the real JStyle codes. See UPGRADING §12.
|
|
19
32
|
|
|
20
33
|
## Features
|
|
21
34
|
|
package/UPGRADING.md
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
# Upgrading
|
|
2
|
+
|
|
3
|
+
## 0.6.0 → 0.7.0 (Sprint 5 coordinated release)
|
|
4
|
+
|
|
5
|
+
This is a **coordinated release**. Upgrade all four together — the packages
|
|
6
|
+
share contracts that changed in lockstep:
|
|
7
|
+
|
|
8
|
+
| Package | From | To |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `@mongrov/analytics` | 0.6.0 | **0.7.0** |
|
|
11
|
+
| `@mongrov/data-access` | 0.1.0 | **0.2.0** |
|
|
12
|
+
| `@mongrov/types` | 0.4.0 | **0.5.0** |
|
|
13
|
+
| `@mongrov/device` | 0.1.1 | **0.2.0** |
|
|
14
|
+
|
|
15
|
+
> The Sprint 5 spec named these 0.2.0 / 0.2.0 / 0.4.0 / 0.2.0. Those targets
|
|
16
|
+
> were unreachable: analytics had already shipped 0.2.0→0.6.0 across five
|
|
17
|
+
> post-Sprint-4 releases, and types had reached 0.4.0 without ever landing
|
|
18
|
+
> the Sprint 3 §18 content. Versions are next-minor-from-actual.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 1. Breaking: mapped sleep row shapes
|
|
23
|
+
|
|
24
|
+
**Who is affected:** anyone who consumes `MappedBatch` directly, supplies
|
|
25
|
+
`columnOrder` for sleep tables, or has snapshot tests over mapper output.
|
|
26
|
+
|
|
27
|
+
The sleep mapper had drifted from the DDL it writes to and was emitting rows
|
|
28
|
+
the `sleep_session` table could not accept. If you were flushing sleep data,
|
|
29
|
+
it was failing (or writing NULLs into NOT NULL columns) — this release fixes
|
|
30
|
+
that, and the row types changed as a result.
|
|
31
|
+
|
|
32
|
+
```diff
|
|
33
|
+
interface SleepSessionRow {
|
|
34
|
+
session_id: string
|
|
35
|
+
- ts: Date // no such column; DDL partitions on day(ts_start)
|
|
36
|
+
- start_ts: Date
|
|
37
|
+
- end_ts: Date
|
|
38
|
+
+ ts_start: Date
|
|
39
|
+
+ ts_end: Date
|
|
40
|
+
+ total_minutes: number // NOT NULL — was never produced
|
|
41
|
+
+ deep_minutes: number | null
|
|
42
|
+
+ rem_minutes: number | null
|
|
43
|
+
+ light_minutes: number | null
|
|
44
|
+
+ awake_minutes: number | null
|
|
45
|
+
+ avg_confidence: number | null
|
|
46
|
+
night_of: Date
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface SleepStageRow {
|
|
50
|
+
- stage: string // firmware block_type leaked into an INTEGER column
|
|
51
|
+
+ stage: number // 1=awake, 2=light, 3=deep, 5=rem
|
|
52
|
+
- confidence: number
|
|
53
|
+
+ confidence: number | null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface SleepRawRow {
|
|
57
|
+
- payload: FirmwareSleepRow // no such column
|
|
58
|
+
+ ts_session_start: Date
|
|
59
|
+
+ quality: number // NOT NULL; derived from confidence when
|
|
60
|
+
+ unit_length: number | null // firmware omits it
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Two smaller removals in the same pass — both were keys with no column:
|
|
65
|
+
|
|
66
|
+
```diff
|
|
67
|
+
-interface ActivityBucketRow { steps: number; … } // steps live on `activity`
|
|
68
|
+
-interface DeviceConfigRow { ts: Date; … } // axis is valid_from/valid_to
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Migrating `columnOrder`:** if you hand-wrote sleep entries, regenerate them
|
|
72
|
+
from the DDL. Column names now match exactly, so
|
|
73
|
+
`columnOrder[table].map(c => row[c])` works without translation.
|
|
74
|
+
|
|
75
|
+
**Behaviour changes worth knowing:**
|
|
76
|
+
|
|
77
|
+
- Session boundaries come from the firmware's own `start`/`end` fields, not
|
|
78
|
+
min/max of block instants. Deriving from blocks under-reported any session
|
|
79
|
+
whose first or last minutes went unclassified.
|
|
80
|
+
- `primary` blocks produce **no** `sleep_stage` row. The DDL enum has no code
|
|
81
|
+
for them and they read as the session envelope rather than a stage. All
|
|
82
|
+
blocks are still preserved in `sleep_raw`. *Open question with the firmware
|
|
83
|
+
team — see `analytics-sync/tasks.md` T-06.*
|
|
84
|
+
|
|
85
|
+
A new contract test (`mapper/__tests__/ddl-contract.test.ts`) parses
|
|
86
|
+
`core/schemas.ts` and asserts every mapped row's keys are real columns and
|
|
87
|
+
every NOT NULL column is populated. If you extend the mapper, it will tell
|
|
88
|
+
you when you drift.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 2. Breaking: `AnalyticsEngine` gained two methods
|
|
93
|
+
|
|
94
|
+
**Who is affected:** anyone implementing `AnalyticsEngine` — test fakes,
|
|
95
|
+
custom adapters.
|
|
96
|
+
|
|
97
|
+
```diff
|
|
98
|
+
interface AnalyticsEngine {
|
|
99
|
+
…
|
|
100
|
+
+ getFamilyMembers(): Promise<string[]>
|
|
101
|
+
+ dismissInsight(args: { insightId: string; userId: string }): Promise<void>
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`getFamilyMembers()` closes a principle-39 gap: the rules evaluator and the
|
|
106
|
+
AI-tools authorize hook each held their own wire to family membership. Now
|
|
107
|
+
both go through the engine, which delegates to the `familyMembersProvider`
|
|
108
|
+
you configured at `createAnalytics` and caches for 60s.
|
|
109
|
+
|
|
110
|
+
Minimal fake:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
const engine: AnalyticsEngine = {
|
|
114
|
+
…,
|
|
115
|
+
async getFamilyMembers() { return ['alice', 'bob'] },
|
|
116
|
+
async dismissInsight() {},
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## 3. Breaking: authorize hooks no longer fall back to SQL
|
|
123
|
+
|
|
124
|
+
`familyScopeAuthorize` / `orgScopeAuthorize` previously fell back to
|
|
125
|
+
`SELECT 1 FROM family_member …` when no provider was passed. **No DDL in this
|
|
126
|
+
package ever created that table**, so the fallback could only throw and fail
|
|
127
|
+
closed — silently denying every cross-member query on any install that did
|
|
128
|
+
not pass a provider explicitly.
|
|
129
|
+
|
|
130
|
+
```diff
|
|
131
|
+
-familyScopeAuthorize(analytics) // used a phantom table
|
|
132
|
+
+familyScopeAuthorize(analytics) // uses engine roster
|
|
133
|
+
familyScopeAuthorize(analytics, { familyMembersProvider }) // still wins
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
If you relied on the SQL path, wire `familyMembersProvider` at
|
|
137
|
+
`createAnalytics` instead. Membership lives in the RxDB Family doc, not
|
|
138
|
+
DuckDB.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 4. Breaking: generated SQL reads `v_{table}` views
|
|
143
|
+
|
|
144
|
+
Rule SQL and tool SQL now target the union views instead of raw catalogs.
|
|
145
|
+
This is what lets a rule fire on data flushed locally but not yet pushed to
|
|
146
|
+
R2 — i.e. this morning's sync.
|
|
147
|
+
|
|
148
|
+
**Consequence:** the views must exist. They are created on `attach()` and
|
|
149
|
+
dropped on `detach()`, so anything executing rule or tool SQL against a
|
|
150
|
+
non-attached engine now fails where it previously read stale remote rows.
|
|
151
|
+
|
|
152
|
+
View bodies inline `brand` and `family_id`, because DuckDB views cannot bind
|
|
153
|
+
parameters. That makes per-attach recreation a **correctness** requirement,
|
|
154
|
+
not housekeeping — a brand switch reusing old views would serve the previous
|
|
155
|
+
tenant's rows. Handled automatically; do not cache view DDL yourself.
|
|
156
|
+
|
|
157
|
+
`insight` is deliberately *not* viewed — it is local-authoritative.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 5. Behaviour change: rules evaluate on `batch:complete`
|
|
162
|
+
|
|
163
|
+
Rules previously evaluated once per table, on each `{table}:insert`. They now
|
|
164
|
+
evaluate once per batch. **Default is the new behaviour.**
|
|
165
|
+
|
|
166
|
+
This fixes a real race: a `context: 'asleep'` rule JOINs `v_sleep_session`,
|
|
167
|
+
and firing it the moment `spo2` flushed let it evaluate against a night whose
|
|
168
|
+
sleep rows were still buffered.
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
createSyncManager({
|
|
172
|
+
…,
|
|
173
|
+
strictBatchOrdering: false, // opt out — restores per-table triggering
|
|
174
|
+
})
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Only opt out if you need lower evaluation latency **and** ship no
|
|
178
|
+
context-JOIN or `consecutive` rules.
|
|
179
|
+
|
|
180
|
+
Per-table `{table}:insert` events still fire — they drive cache
|
|
181
|
+
invalidation, which wants to refresh as early as possible. `batch:complete`
|
|
182
|
+
is additional, not a replacement.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## 6. New config: `userTimezoneProvider`
|
|
187
|
+
|
|
188
|
+
Day-first baselines bucket by **local** day, so they need each user's IANA
|
|
189
|
+
zone. `User.timezone` lives in auth/RxDB where this package cannot reach it.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
createSyncManager({
|
|
193
|
+
…,
|
|
194
|
+
userTimezoneProvider: async (userId) => (await getUser(userId))?.timezone,
|
|
195
|
+
})
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Unwired, it falls back to the device zone — wrong for a travelling user or
|
|
199
|
+
one whose profile zone differs from their device. Baselines still compute;
|
|
200
|
+
they just bucket by the wrong midnight.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 7. Rules schema additions
|
|
205
|
+
|
|
206
|
+
Additive — existing rules keep parsing. New fields:
|
|
207
|
+
|
|
208
|
+
```toml
|
|
209
|
+
context = "asleep" # 'any' (default) | 'asleep' | 'resting'
|
|
210
|
+
consecutive = 3 # require N adjacent breaching samples
|
|
211
|
+
|
|
212
|
+
[rule.target]
|
|
213
|
+
type = "user_setting" # threshold read from KVStore at eval time
|
|
214
|
+
key = "user:spo2SafeLevel"
|
|
215
|
+
defaultValue = 90
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`user_setting` is what makes a user-configurable threshold work without
|
|
219
|
+
per-user rule rows: the compiled SQL is threshold-agnostic, and the evaluator
|
|
220
|
+
binds `analytics:{userId}:{key}` at eval time, falling back to `defaultValue`.
|
|
221
|
+
|
|
222
|
+
Two constraints the validator now enforces:
|
|
223
|
+
|
|
224
|
+
- `consecutive` is **rejected with baseline targets**. Baselines resolve
|
|
225
|
+
per-window, not per-sample; there is no correct query shape, so it throws
|
|
226
|
+
rather than emitting something subtly wrong.
|
|
227
|
+
- `consecutive × sampling_minutes` must fit the window, or the rule could
|
|
228
|
+
never fire.
|
|
229
|
+
|
|
230
|
+
**Ziva catalog rule ids changed.** Throttle state is keyed by rule id, so
|
|
231
|
+
existing throttle counters for the renamed rules are orphaned (they expire
|
|
232
|
+
naturally):
|
|
233
|
+
|
|
234
|
+
| Was | Now |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `ziva.sleep-deprivation-3d` | `ziva.sleep-deprivation-3` |
|
|
237
|
+
| `ziva.stress-elevated` | `ziva.stress-elevated-day` |
|
|
238
|
+
| `ziva.activity-low-24h` | `ziva.low-activity-week` |
|
|
239
|
+
|
|
240
|
+
`ziva.hrv-drop-30` and `ziva.stress-elevated-day` also switched from
|
|
241
|
+
`absolute` to `baseline_percent` / `baseline_stddev` targets — a fixed HRV
|
|
242
|
+
threshold is meaningless across users.
|
|
243
|
+
|
|
244
|
+
Also note `registry.register()` is **async**. An un-awaited call silently
|
|
245
|
+
no-ops:
|
|
246
|
+
|
|
247
|
+
```diff
|
|
248
|
+
-rules.register(zivaDefaults)
|
|
249
|
+
+await rules.register(zivaDefaults)
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## 8. Copy guardrails — contract for tool authors
|
|
255
|
+
|
|
256
|
+
Every tool formatter must call `assertNoBanTerms(text, formatterName)` on its
|
|
257
|
+
return path. Tool output lands in an LLM's context, and the model repeats
|
|
258
|
+
whatever register it finds there.
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { assertNoBanTerms } from '@mongrov/analytics/tools'
|
|
262
|
+
|
|
263
|
+
function finalize(text: string, rowCount: number): ToolResult {
|
|
264
|
+
assertNoBanTerms(text, 'myTool')
|
|
265
|
+
return { text, rowCount, bytes: formatBytes(text) }
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
It throws `FormatterCopyError` on any banned medical term. Matching is
|
|
270
|
+
leading-boundary, so `desaturation` also catches `desaturations` — over-
|
|
271
|
+
blocking is the right bias here. `applyPreferredLanguage(text)` rewrites the
|
|
272
|
+
common phrasings, but it is a convenience, not a substitute: the guard still
|
|
273
|
+
runs afterwards.
|
|
274
|
+
|
|
275
|
+
This applies to text you did not author. An insight row titled *"Nocturnal
|
|
276
|
+
desaturation detected"* interpolated into `getInsights` output fails the tool
|
|
277
|
+
call — which is the point.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## 9. `@mongrov/data-access` 0.2.0
|
|
282
|
+
|
|
283
|
+
`RequestContext` shape:
|
|
284
|
+
|
|
285
|
+
```diff
|
|
286
|
+
interface RequestContext {
|
|
287
|
+
- requesterUserId: string
|
|
288
|
+
+ userId: string // canonical — queries bind it as $userId
|
|
289
|
+
brand: string
|
|
290
|
+
familyId: string
|
|
291
|
+
+ timezone: string // bound as $tz by every day-grouped query
|
|
292
|
+
now: () => Date
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Both are required. Update your `DataAccessProvider` context factory.
|
|
297
|
+
|
|
298
|
+
The remaining 0.2.0 items (`asyncFetch`, `fetching` hook state,
|
|
299
|
+
JOIN-invalidation validator, `transform` field, `MutationContext.analytics`)
|
|
300
|
+
were already implemented before this release; 0.2.0 records the version.
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## 10. `@mongrov/types` 0.5.0
|
|
305
|
+
|
|
306
|
+
Additive. Lands the Sprint 3 §18 layer every Sprint 4 feature was written
|
|
307
|
+
against but which never shipped: `Brand`, `Family`, `User`,
|
|
308
|
+
`AnalyticsDevice`, `SensorSink`, `FirmwareExport`, `MapperContext`,
|
|
309
|
+
`EventBus`, and the seven missing `AnalyticsQuerySchemas`.
|
|
310
|
+
|
|
311
|
+
**`AnalyticsDevice`, not `Device`.** `types/device.ts` already exports a
|
|
312
|
+
`Device` describing the BLE transport's view (adapterId, connection state,
|
|
313
|
+
RSSI). Both are legitimate and neither is a superset — one is the durable
|
|
314
|
+
tenancy record sensor rows key against, the other is the live connection
|
|
315
|
+
handle. The existing `Device` is unchanged.
|
|
316
|
+
|
|
317
|
+
`DEVICE_EVENT_TYPES` and its payload schemas now live here canonically
|
|
318
|
+
(`@mongrov/types/device-events`); `@mongrov/analytics` re-exports them. This
|
|
319
|
+
is what lets `@mongrov/device` emit events the analytics engine will store
|
|
320
|
+
without depending on the engine.
|
|
321
|
+
|
|
322
|
+
**Packaging change: dual CJS/ESM emit.** `dist/` is now `dist/esm` +
|
|
323
|
+
`dist/cjs`, each with its own `type` marker, and every export declares
|
|
324
|
+
`import` / `require` / `types` conditions. Previously the package emitted
|
|
325
|
+
ESM only and declared no `require` condition — which nothing noticed,
|
|
326
|
+
because every cross-package import was type-only and therefore erased at
|
|
327
|
+
compile. The first *value* import from a subpath (`device-events`,
|
|
328
|
+
`analytics-queries`) failed to resolve under CommonJS.
|
|
329
|
+
|
|
330
|
+
If you deep-imported `@mongrov/types/dist/...` — don't; use the subpath
|
|
331
|
+
exports. `main` / `module` / `types` now point into the split trees.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## 11. Migrations
|
|
336
|
+
|
|
337
|
+
One new migration runs automatically on attach:
|
|
338
|
+
|
|
339
|
+
| Version | What |
|
|
340
|
+
|---|---|
|
|
341
|
+
| v4 | `user_baseline` table (local catalog only) |
|
|
342
|
+
|
|
343
|
+
**Numbering note.** The Sprint 5 spec called this "migration v3" and
|
|
344
|
+
specified a "v4" adding `insight.dismissed_at`. Versions 2 and 3 were already
|
|
345
|
+
spent (`device_battery`, `insight` v2 rebuild), and `dismissed_at` already
|
|
346
|
+
ships in the baseline DDL with migration v3 backfilling it — so the ALTER
|
|
347
|
+
would have been a no-op against an existing column.
|
|
348
|
+
|
|
349
|
+
`user_baseline` and `sync_watermark` are **local-only** — never created in
|
|
350
|
+
the attached R2 zone. Baselines are derived data, cheap to recompute, and
|
|
351
|
+
pushing them would invite two devices in one family to race on the same
|
|
352
|
+
composite PK.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## 12. Known gaps in this release
|
|
357
|
+
|
|
358
|
+
Documented so you do not go looking:
|
|
359
|
+
|
|
360
|
+
- **`device_config` still uses `data_type SMALLINT`.** Sprint 5 §2's change
|
|
361
|
+
to `metric VARCHAR` is blocked: the spec's firmware codes (1/2/4) do not
|
|
362
|
+
match the real JStyle codes (`HR:0, SLEEP:1, SPO2:3, HRV:8, ACTIVITY:9,
|
|
363
|
+
TEMPERATURE:14`), and SpO₂/temperature are separate schedules — so the
|
|
364
|
+
"fan-out `data_type=2` into two rows" the task describes may not correspond
|
|
365
|
+
to real hardware behaviour. Unresolved with the firmware team.
|
|
366
|
+
- **`@mongrov/device` sync events are emitter-only.** `createSyncEventEmitter`
|
|
367
|
+
and the `DeviceEventSink` port ship and are usable stand-alone, but the sync
|
|
368
|
+
machine that would call them is D5 work and does not exist yet.
|
|
369
|
+
- **`transform` is declared but not resolved** by the data-access dispatcher.
|
|
370
|
+
Queries declaring it will not produce derived output fields yet.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `device_event.event_type` enum + per-type payload schemas (Sprint 5 §6).
|
|
3
|
+
*
|
|
4
|
+
* **Re-export only.** The canonical definition lives in
|
|
5
|
+
* `@mongrov/types/device-events` so that `@mongrov/device` — which must
|
|
6
|
+
* never depend on the analytics engine — can emit events this engine will
|
|
7
|
+
* store, against the same contract.
|
|
8
|
+
*
|
|
9
|
+
* Kept as a module here so analytics consumers get one import surface, and
|
|
10
|
+
* so the `core/index.ts` export list stays stable.
|
|
11
|
+
*/
|
|
12
|
+
export { decodeDeviceEventPayload, DEVICE_EVENT_PAYLOAD_SCHEMAS, DEVICE_EVENT_TYPES, encodeDeviceEventPayload, isDeviceEventType, SyncTrigger, } from '@mongrov/types/device-events';
|
|
13
|
+
export type { DeviceEventPayload, DeviceEventType, SyncTriggerValue, } from '@mongrov/types/device-events';
|
|
14
|
+
//# sourceMappingURL=device-events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-events.d.ts","sourceRoot":"","sources":["../../src/core/device-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,EACxB,iBAAiB,EACjB,WAAW,GACZ,MAAM,8BAA8B,CAAA;AAErC,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,GACjB,MAAM,8BAA8B,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `device_event.event_type` enum + per-type payload schemas (Sprint 5 §6).
|
|
3
|
+
*
|
|
4
|
+
* **Re-export only.** The canonical definition lives in
|
|
5
|
+
* `@mongrov/types/device-events` so that `@mongrov/device` — which must
|
|
6
|
+
* never depend on the analytics engine — can emit events this engine will
|
|
7
|
+
* store, against the same contract.
|
|
8
|
+
*
|
|
9
|
+
* Kept as a module here so analytics consumers get one import surface, and
|
|
10
|
+
* so the `core/index.ts` export list stays stable.
|
|
11
|
+
*/
|
|
12
|
+
export { decodeDeviceEventPayload, DEVICE_EVENT_PAYLOAD_SCHEMAS, DEVICE_EVENT_TYPES, encodeDeviceEventPayload, isDeviceEventType, SyncTrigger, } from '@mongrov/types/device-events';
|
|
13
|
+
//# sourceMappingURL=device-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"device-events.js","sourceRoot":"","sources":["../../src/core/device-events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,EACxB,iBAAiB,EACjB,WAAW,GACZ,MAAM,8BAA8B,CAAA"}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* ships the class and code union so stubs can throw typed errors from
|
|
6
6
|
* day one; downstream phases add more codes without breaking imports.
|
|
7
7
|
*/
|
|
8
|
-
export type AnalyticsErrorCode = 'engine_open_failed' | 'extension_load_failed' | 'attach_failed' | 'detach_failed' | 'token_vendor_failed' | 'migration_failed' | 'retention_failed' | 'query_failed' | 'not_attached' | 'not_ready' | 'not_implemented';
|
|
8
|
+
export type AnalyticsErrorCode = 'engine_open_failed' | 'extension_load_failed' | 'attach_failed' | 'detach_failed' | 'token_vendor_failed' | 'migration_failed' | 'retention_failed' | 'family_members_failed' | 'query_failed' | 'not_attached' | 'not_ready' | 'not_implemented';
|
|
9
9
|
export declare class AnalyticsError extends Error {
|
|
10
10
|
readonly code: AnalyticsErrorCode;
|
|
11
11
|
readonly cause?: unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,uBAAuB,GACvB,eAAe,GACf,eAAe,GACf,qBAAqB,GACrB,kBAAkB,GAClB,kBAAkB,GAClB,cAAc,GACd,cAAc,GACd,WAAW,GACX,iBAAiB,CAAA;AAErB,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,IAAI,EAAE,kBAAkB,CAAA;IACxC,SAAgB,KAAK,CAAC,EAAE,OAAO,CAAA;gBAEnB,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAMvE;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;gBACzC,MAAM,EAAE,MAAM;CAI3B"}
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,kBAAkB,GAC1B,oBAAoB,GACpB,uBAAuB,GACvB,eAAe,GACf,eAAe,GACf,qBAAqB,GACrB,kBAAkB,GAClB,kBAAkB,GAClB,uBAAuB,GACvB,cAAc,GACd,cAAc,GACd,WAAW,GACX,iBAAiB,CAAA;AAErB,qBAAa,cAAe,SAAQ,KAAK;IACvC,SAAgB,IAAI,EAAE,kBAAkB,CAAA;IACxC,SAAgB,KAAK,CAAC,EAAE,OAAO,CAAA;gBAEnB,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAMvE;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,cAAc;gBACzC,MAAM,EAAE,MAAM;CAI3B"}
|
package/dist/core/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,OAAO,cAAe,SAAQ,KAAK;IAIvC,YAAY,IAAwB,EAAE,OAAe,EAAE,KAAe;QACpE,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAA;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAoB,SAAQ,cAAc;IACrD,YAAY,MAAc;QACxB,KAAK,CAAC,iBAAiB,EAAE,GAAG,MAAM,qBAAqB,CAAC,CAAA;QACxD,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
|
|
@@ -18,10 +18,27 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import type { HybridDuckDB } from './engine';
|
|
20
20
|
import type { AnalyticsMode } from './types';
|
|
21
|
-
/**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Extensions required for R2 Iceberg attach, in load order.
|
|
23
|
+
*
|
|
24
|
+
* `icu` sits between `httpfs` and `iceberg` per Sprint 5 T-01. It is not
|
|
25
|
+
* optional: every registry query and every baseline computation groups by
|
|
26
|
+
* local day via `timezone($tz, ts)` / `date_trunc('day', timezone(...))`,
|
|
27
|
+
* and DuckDB's `timezone()` with a named IANA zone resolves only when
|
|
28
|
+
* `icu` is loaded. Without it those queries fail at parse time rather than
|
|
29
|
+
* silently returning UTC-grouped rows.
|
|
30
|
+
*/
|
|
31
|
+
export declare const REQUIRED_EXTENSIONS: readonly ["httpfs", "icu", "iceberg", "parquet"];
|
|
32
|
+
/**
|
|
33
|
+
* Extensions required for local-only mode (no remote sync, no iceberg).
|
|
34
|
+
*
|
|
35
|
+
* `icu` is here too, and deliberately so: local mode skips `httpfs` +
|
|
36
|
+
* `iceberg` to avoid the AWSSDK/vcpkg build burden, but it does NOT skip
|
|
37
|
+
* timezone-aware queries — a local-only install still renders day charts
|
|
38
|
+
* and computes day-first baselines. Omitting `icu` here would make those
|
|
39
|
+
* paths work on R2 installs and fail on local ones.
|
|
40
|
+
*/
|
|
41
|
+
export declare const LOCAL_EXTENSIONS: readonly ["icu", "parquet"];
|
|
25
42
|
export type RequiredExtension = (typeof REQUIRED_EXTENSIONS)[number];
|
|
26
43
|
/**
|
|
27
44
|
* Issue `INSTALL <ext>; LOAD <ext>;` for each mode-appropriate extension
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C
|
|
1
|
+
{"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,kDAAmD,CAAA;AAEnF;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,6BAA8B,CAAA;AAE3D,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAQpE;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,EAAE,EAAE,YAAY,EAChB,IAAI,GAAE,aAAoB,GACzB,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAEzE"}
|
package/dist/core/extensions.js
CHANGED
|
@@ -17,10 +17,27 @@
|
|
|
17
17
|
* calls, and DuckDB itself no-ops re-loads, so calling twice is safe.
|
|
18
18
|
*/
|
|
19
19
|
import { AnalyticsError } from './errors';
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Extensions required for R2 Iceberg attach, in load order.
|
|
22
|
+
*
|
|
23
|
+
* `icu` sits between `httpfs` and `iceberg` per Sprint 5 T-01. It is not
|
|
24
|
+
* optional: every registry query and every baseline computation groups by
|
|
25
|
+
* local day via `timezone($tz, ts)` / `date_trunc('day', timezone(...))`,
|
|
26
|
+
* and DuckDB's `timezone()` with a named IANA zone resolves only when
|
|
27
|
+
* `icu` is loaded. Without it those queries fail at parse time rather than
|
|
28
|
+
* silently returning UTC-grouped rows.
|
|
29
|
+
*/
|
|
30
|
+
export const REQUIRED_EXTENSIONS = ['httpfs', 'icu', 'iceberg', 'parquet'];
|
|
31
|
+
/**
|
|
32
|
+
* Extensions required for local-only mode (no remote sync, no iceberg).
|
|
33
|
+
*
|
|
34
|
+
* `icu` is here too, and deliberately so: local mode skips `httpfs` +
|
|
35
|
+
* `iceberg` to avoid the AWSSDK/vcpkg build burden, but it does NOT skip
|
|
36
|
+
* timezone-aware queries — a local-only install still renders day charts
|
|
37
|
+
* and computes day-first baselines. Omitting `icu` here would make those
|
|
38
|
+
* paths work on R2 installs and fail on local ones.
|
|
39
|
+
*/
|
|
40
|
+
export const LOCAL_EXTENSIONS = ['icu', 'parquet'];
|
|
24
41
|
/**
|
|
25
42
|
* Tracks which extensions this process has already booted. Keyed by
|
|
26
43
|
* `HybridDuckDB` instance to keep isolation across engines in tests.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAIzC
|
|
1
|
+
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAIzC;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAEnF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,CAAU,CAAA;AAI3D;;;GAGG;AACH,MAAM,UAAU,GAAG,IAAI,OAAO,EAA6B,CAAA;AAE3D;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAgB,EAChB,OAAsB,IAAI;IAE1B,IAAI,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,IAAI,GAAG,EAAE,CAAA;QAClB,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IAC5B,CAAC;IAED,MAAM,UAAU,GACZ,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,mBAAmB,CAAA;IAE7D,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,SAAQ;QACV,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC,WAAW,GAAG,GAAG,CAAC,CAAA;YACnC,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,cAAc,CACtB,uBAAuB,EACvB,oCAAoC,GAAG,EAAE,EACzC,KAAK,CACN,CAAA;QACH,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAgB;IAClD,OAAO,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,GAAG,EAAE,CAAA;AACxC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAkB,MAAM,UAAU,CAAA;AAgB7D,OAAO,KAAK,EAEV,eAAe,EACf,eAAe,EAKhB,MAAM,SAAS,CAAA;AAkChB;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,aAAa,CAAA;CAC9B;AAwED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,GAAE,uBAA4B,GACrC,eAAe,CAoYjB"}
|