@mongrov/analytics 0.4.0 → 0.6.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.
Files changed (63) hide show
  1. package/dist/core/extensions.d.ts +20 -6
  2. package/dist/core/extensions.d.ts.map +1 -1
  3. package/dist/core/extensions.js +21 -7
  4. package/dist/core/extensions.js.map +1 -1
  5. package/dist/core/factory.d.ts.map +1 -1
  6. package/dist/core/factory.js +58 -14
  7. package/dist/core/factory.js.map +1 -1
  8. package/dist/core/machine.d.ts.map +1 -1
  9. package/dist/core/machine.js +9 -1
  10. package/dist/core/machine.js.map +1 -1
  11. package/dist/core/metric_metadata.d.ts +2 -2
  12. package/dist/core/metric_metadata.js +1 -1
  13. package/dist/core/metric_metadata.js.map +1 -1
  14. package/dist/core/migrations.d.ts +28 -4
  15. package/dist/core/migrations.d.ts.map +1 -1
  16. package/dist/core/migrations.js +51 -6
  17. package/dist/core/migrations.js.map +1 -1
  18. package/dist/core/retention.d.ts.map +1 -1
  19. package/dist/core/retention.js +1 -0
  20. package/dist/core/retention.js.map +1 -1
  21. package/dist/core/schemas.d.ts +38 -7
  22. package/dist/core/schemas.d.ts.map +1 -1
  23. package/dist/core/schemas.js +52 -7
  24. package/dist/core/schemas.js.map +1 -1
  25. package/dist/core/table_metadata.d.ts.map +1 -1
  26. package/dist/core/table_metadata.js +1 -0
  27. package/dist/core/table_metadata.js.map +1 -1
  28. package/dist/core/types.d.ts +43 -5
  29. package/dist/core/types.d.ts.map +1 -1
  30. package/dist/core/warehouse.d.ts +55 -5
  31. package/dist/core/warehouse.d.ts.map +1 -1
  32. package/dist/core/warehouse.js +93 -18
  33. package/dist/core/warehouse.js.map +1 -1
  34. package/dist/rules/__fakes__/fakeEngine.d.ts.map +1 -1
  35. package/dist/rules/__fakes__/fakeEngine.js +1 -0
  36. package/dist/rules/__fakes__/fakeEngine.js.map +1 -1
  37. package/dist/rules/schema.d.ts +3 -3
  38. package/dist/sync/factory.d.ts.map +1 -1
  39. package/dist/sync/factory.js +21 -7
  40. package/dist/sync/factory.js.map +1 -1
  41. package/dist/sync/fetcher.d.ts.map +1 -1
  42. package/dist/sync/fetcher.js +18 -5
  43. package/dist/sync/fetcher.js.map +1 -1
  44. package/dist/sync/index.d.ts +1 -1
  45. package/dist/sync/index.d.ts.map +1 -1
  46. package/dist/sync/index.js.map +1 -1
  47. package/dist/sync/mapper/battery.d.ts +14 -7
  48. package/dist/sync/mapper/battery.d.ts.map +1 -1
  49. package/dist/sync/mapper/battery.js +13 -7
  50. package/dist/sync/mapper/battery.js.map +1 -1
  51. package/dist/sync/mapper/firmware.d.ts.map +1 -1
  52. package/dist/sync/mapper/firmware.js +4 -1
  53. package/dist/sync/mapper/firmware.js.map +1 -1
  54. package/dist/sync/mapper/types.d.ts +9 -0
  55. package/dist/sync/mapper/types.d.ts.map +1 -1
  56. package/dist/sync/pusher.d.ts +10 -3
  57. package/dist/sync/pusher.d.ts.map +1 -1
  58. package/dist/sync/pusher.js +1 -1
  59. package/dist/sync/pusher.js.map +1 -1
  60. package/dist/tools/__fakes__/engine.d.ts.map +1 -1
  61. package/dist/tools/__fakes__/engine.js +1 -0
  62. package/dist/tools/__fakes__/engine.js.map +1 -1
  63. package/package.json +3 -3
@@ -1,18 +1,29 @@
1
1
  /**
2
2
  * Table DDL for the analytics warehouse (spec §Table schema).
3
3
  *
4
- * Fourteen tables, verbatim from `.specifica/features/analytics-core/spec.md`.
4
+ * Fifteen tables, verbatim from `.specifica/features/analytics-core/spec.md`.
5
5
  * DDL strings are frozen — apps must not mutate them; migrations (T-08) own
6
6
  * schema evolution.
7
7
  *
8
- * `ensureSchemas(db, catalog)` idempotently creates every table inside the
9
- * attached catalog (i.e. `zone_<tenantId>`), rewriting `CREATE TABLE <name>`
10
- * to `CREATE TABLE IF NOT EXISTS <catalog>.<name>` at issue time so the base
11
- * DDL stays faithful to the spec text.
8
+ * Two DDL variants exist:
9
+ * - `SCHEMAS` for Iceberg-attached remote catalogs. Includes
10
+ * `PARTITIONED BY (day(ts), user_id)` clauses that Iceberg requires
11
+ * for partition pruning at scan time.
12
+ * - `LOCAL_SCHEMAS` — for the app's local DuckDB catalog. Identical to
13
+ * `SCHEMAS` minus the `PARTITIONED BY` clauses, which plain DuckDB
14
+ * (non-Iceberg) rejects with a parser error. Derived from `SCHEMAS`
15
+ * via `toLocalDdl` at module load time so both variants stay in sync
16
+ * through schema changes.
17
+ *
18
+ * `ensureSchemas(db, catalog, schemas)` idempotently creates every table
19
+ * inside the given catalog, rewriting `CREATE TABLE <name>` to
20
+ * `CREATE TABLE IF NOT EXISTS <catalog>.<name>` at issue time. Callers
21
+ * pick the variant: remote attach uses `SCHEMAS`, local mode uses
22
+ * `LOCAL_SCHEMAS`.
12
23
  */
13
24
  import type { HybridDuckDB } from './engine';
14
25
  /** Ordered list of every warehouse table. Order = creation order. */
15
- export declare const TABLE_NAMES: readonly ["hrv", "heart_rate", "spo2", "temperature", "activity", "activity_bucket", "sleep_session", "sleep_stage", "sleep_raw", "device_event", "device_config", "insight", "sync_watermark", "tool_call_audit"];
26
+ export declare const TABLE_NAMES: readonly ["hrv", "heart_rate", "spo2", "temperature", "activity", "activity_bucket", "sleep_session", "sleep_stage", "sleep_raw", "device_event", "device_battery", "device_config", "insight", "sync_watermark", "tool_call_audit"];
16
27
  export type TableName = (typeof TABLE_NAMES)[number];
17
28
  /**
18
29
  * Frozen DDL for every warehouse table. Copied verbatim from spec §Table
@@ -25,11 +36,31 @@ export declare const SCHEMAS: Readonly<Record<TableName, string>>;
25
36
  * Exported for tests; call sites should prefer `ensureSchemas`.
26
37
  */
27
38
  export declare function qualifyDdl(baseDdl: string, table: TableName, catalog: string): string;
39
+ /**
40
+ * Strip the Iceberg-only `PARTITIONED BY (...)` clause from a DDL string.
41
+ * Plain DuckDB (non-Iceberg) rejects the clause with a parser error; local
42
+ * mode uses the returned form. Preserves the trailing `);` terminator.
43
+ *
44
+ * Exported for tests; call sites should prefer `LOCAL_SCHEMAS`.
45
+ */
46
+ export declare function toLocalDdl(baseDdl: string): string;
47
+ /**
48
+ * Local-catalog DDL variants of `SCHEMAS` — same tables, same columns,
49
+ * same primary keys; only difference is the `PARTITIONED BY` clauses are
50
+ * stripped. Derived programmatically so schema changes in `SCHEMAS`
51
+ * propagate automatically.
52
+ */
53
+ export declare const LOCAL_SCHEMAS: Readonly<Record<TableName, string>>;
28
54
  /**
29
55
  * Create every warehouse table under `<catalog>.<table>`, in `TABLE_NAMES` order.
30
56
  *
31
57
  * Idempotent — every issued statement uses `IF NOT EXISTS`. Failure at any
32
58
  * table surfaces as `AnalyticsError('migration_failed', <table>, cause)`.
59
+ *
60
+ * `schemas` selects the DDL variant: pass `SCHEMAS` for remote iceberg
61
+ * catalogs (with `PARTITIONED BY`), `LOCAL_SCHEMAS` for the local DuckDB
62
+ * catalog (without). Default is `SCHEMAS` for back-compat with 0.4.x
63
+ * callers that only wrote to the attached remote.
33
64
  */
34
- export declare function ensureSchemas(db: HybridDuckDB, catalog: string): Promise<void>;
65
+ export declare function ensureSchemas(db: HybridDuckDB, catalog: string, schemas?: Readonly<Record<TableName, string>>): Promise<void>;
35
66
  //# sourceMappingURL=schemas.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,qEAAqE;AACrE,eAAO,MAAM,WAAW,oNAed,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAiKtD,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrF;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAcpF"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,qEAAqE;AACrE,eAAO,MAAM,WAAW,sOAgBd,CAAA;AAEV,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAA;AAEpD;;;GAGG;AACH,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CA0KtD,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKrF;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAI7D,CAAA;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,YAAY,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAW,GACrD,OAAO,CAAC,IAAI,CAAC,CAcf"}
@@ -1,14 +1,25 @@
1
1
  /**
2
2
  * Table DDL for the analytics warehouse (spec §Table schema).
3
3
  *
4
- * Fourteen tables, verbatim from `.specifica/features/analytics-core/spec.md`.
4
+ * Fifteen tables, verbatim from `.specifica/features/analytics-core/spec.md`.
5
5
  * DDL strings are frozen — apps must not mutate them; migrations (T-08) own
6
6
  * schema evolution.
7
7
  *
8
- * `ensureSchemas(db, catalog)` idempotently creates every table inside the
9
- * attached catalog (i.e. `zone_<tenantId>`), rewriting `CREATE TABLE <name>`
10
- * to `CREATE TABLE IF NOT EXISTS <catalog>.<name>` at issue time so the base
11
- * DDL stays faithful to the spec text.
8
+ * Two DDL variants exist:
9
+ * - `SCHEMAS` for Iceberg-attached remote catalogs. Includes
10
+ * `PARTITIONED BY (day(ts), user_id)` clauses that Iceberg requires
11
+ * for partition pruning at scan time.
12
+ * - `LOCAL_SCHEMAS` — for the app's local DuckDB catalog. Identical to
13
+ * `SCHEMAS` minus the `PARTITIONED BY` clauses, which plain DuckDB
14
+ * (non-Iceberg) rejects with a parser error. Derived from `SCHEMAS`
15
+ * via `toLocalDdl` at module load time so both variants stay in sync
16
+ * through schema changes.
17
+ *
18
+ * `ensureSchemas(db, catalog, schemas)` idempotently creates every table
19
+ * inside the given catalog, rewriting `CREATE TABLE <name>` to
20
+ * `CREATE TABLE IF NOT EXISTS <catalog>.<name>` at issue time. Callers
21
+ * pick the variant: remote attach uses `SCHEMAS`, local mode uses
22
+ * `LOCAL_SCHEMAS`.
12
23
  */
13
24
  import { AnalyticsError } from './errors';
14
25
  /** Ordered list of every warehouse table. Order = creation order. */
@@ -23,6 +34,7 @@ export const TABLE_NAMES = [
23
34
  'sleep_stage',
24
35
  'sleep_raw',
25
36
  'device_event',
37
+ 'device_battery',
26
38
  'device_config',
27
39
  'insight',
28
40
  'sync_watermark',
@@ -131,6 +143,14 @@ export const SCHEMAS = Object.freeze({
131
143
  event_type VARCHAR NOT NULL,
132
144
  payload VARCHAR
133
145
  ) PARTITIONED BY (day(ts));`,
146
+ device_battery: `CREATE TABLE device_battery (
147
+ ts TIMESTAMP NOT NULL,
148
+ brand VARCHAR NOT NULL,
149
+ family_id VARCHAR NOT NULL,
150
+ user_id VARCHAR NOT NULL,
151
+ device_id VARCHAR NOT NULL,
152
+ battery_pct DOUBLE NOT NULL
153
+ ) PARTITIONED BY (day(ts), device_id);`,
134
154
  device_config: `CREATE TABLE device_config (
135
155
  device_id VARCHAR NOT NULL,
136
156
  brand VARCHAR NOT NULL,
@@ -189,15 +209,40 @@ export const SCHEMAS = Object.freeze({
189
209
  export function qualifyDdl(baseDdl, table, catalog) {
190
210
  return baseDdl.replace(`CREATE TABLE ${table}`, `CREATE TABLE IF NOT EXISTS ${catalog}.${table}`);
191
211
  }
212
+ /**
213
+ * Strip the Iceberg-only `PARTITIONED BY (...)` clause from a DDL string.
214
+ * Plain DuckDB (non-Iceberg) rejects the clause with a parser error; local
215
+ * mode uses the returned form. Preserves the trailing `);` terminator.
216
+ *
217
+ * Exported for tests; call sites should prefer `LOCAL_SCHEMAS`.
218
+ */
219
+ export function toLocalDdl(baseDdl) {
220
+ // The clause always terminates the DDL, and its column list contains
221
+ // nested parens (`day(ts)`), so strip from the closing table paren to
222
+ // end-of-string rather than trying to match the paren group.
223
+ return baseDdl.replace(/\)\s*PARTITIONED BY[\s\S]*$/, ');');
224
+ }
225
+ /**
226
+ * Local-catalog DDL variants of `SCHEMAS` — same tables, same columns,
227
+ * same primary keys; only difference is the `PARTITIONED BY` clauses are
228
+ * stripped. Derived programmatically so schema changes in `SCHEMAS`
229
+ * propagate automatically.
230
+ */
231
+ export const LOCAL_SCHEMAS = Object.freeze(Object.fromEntries(TABLE_NAMES.map(table => [table, toLocalDdl(SCHEMAS[table])])));
192
232
  /**
193
233
  * Create every warehouse table under `<catalog>.<table>`, in `TABLE_NAMES` order.
194
234
  *
195
235
  * Idempotent — every issued statement uses `IF NOT EXISTS`. Failure at any
196
236
  * table surfaces as `AnalyticsError('migration_failed', <table>, cause)`.
237
+ *
238
+ * `schemas` selects the DDL variant: pass `SCHEMAS` for remote iceberg
239
+ * catalogs (with `PARTITIONED BY`), `LOCAL_SCHEMAS` for the local DuckDB
240
+ * catalog (without). Default is `SCHEMAS` for back-compat with 0.4.x
241
+ * callers that only wrote to the attached remote.
197
242
  */
198
- export async function ensureSchemas(db, catalog) {
243
+ export async function ensureSchemas(db, catalog, schemas = SCHEMAS) {
199
244
  for (const table of TABLE_NAMES) {
200
- const sql = qualifyDdl(SCHEMAS[table], table, catalog);
245
+ const sql = qualifyDdl(schemas[table], table, catalog);
201
246
  try {
202
247
  await db.execute(sql);
203
248
  }
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAGzC,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK;IACL,YAAY;IACZ,MAAM;IACN,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,WAAW;IACX,cAAc;IACd,eAAe;IACf,SAAS;IACT,gBAAgB;IAChB,iBAAiB;CACT,CAAA;AAIV;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAwC,MAAM,CAAC,MAAM,CAAC;IACxE,GAAG,EAAE;;;;;;;;;;;qCAW8B;IAEnC,UAAU,EAAE;;;;;;;qCAOuB;IAEnC,IAAI,EAAE;;;;;;;qCAO6B;IAEnC,WAAW,EAAE;;;;;;;qCAOsB;IAEnC,QAAQ,EAAE;;;;;;;qCAOyB;IAEnC,eAAe,EAAE;;;;;;;;qCAQkB;IAEnC,aAAa,EAAE;;;;;;;;;;;;;;;2CAe0B;IAEzC,WAAW,EAAE;;;;;;;;;qCASsB;IAEnC,SAAS,EAAE;;;;;;;;;mDASsC;IAEjD,YAAY,EAAE;;;;;;;;4BAQY;IAE1B,aAAa,EAAE;;;;;;;;;;;;;GAad;IAED,OAAO,EAAE;;;;;;;;;;;;4BAYiB;IAE1B,cAAc,EAAE;;;;;;;;GAQf;IAED,eAAe,EAAE;;;;;;;;;;;;4BAYS;CAC3B,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,KAAgB,EAAE,OAAe;IAC3E,OAAO,OAAO,CAAC,OAAO,CACpB,gBAAgB,KAAK,EAAE,EACvB,8BAA8B,OAAO,IAAI,KAAK,EAAE,CACjD,CAAA;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAAgB,EAAE,OAAe;IACnE,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QACtD,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,cAAc,CACtB,kBAAkB,EAClB,iCAAiC,KAAK,EAAE,EACxC,KAAK,CACN,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAGzC,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK;IACL,YAAY;IACZ,MAAM;IACN,aAAa;IACb,UAAU;IACV,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,WAAW;IACX,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,SAAS;IACT,gBAAgB;IAChB,iBAAiB;CACT,CAAA;AAIV;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAwC,MAAM,CAAC,MAAM,CAAC;IACxE,GAAG,EAAE;;;;;;;;;;;qCAW8B;IAEnC,UAAU,EAAE;;;;;;;qCAOuB;IAEnC,IAAI,EAAE;;;;;;;qCAO6B;IAEnC,WAAW,EAAE;;;;;;;qCAOsB;IAEnC,QAAQ,EAAE;;;;;;;qCAOyB;IAEnC,eAAe,EAAE;;;;;;;;qCAQkB;IAEnC,aAAa,EAAE;;;;;;;;;;;;;;;2CAe0B;IAEzC,WAAW,EAAE;;;;;;;;;qCASsB;IAEnC,SAAS,EAAE;;;;;;;;;mDASsC;IAEjD,YAAY,EAAE;;;;;;;;4BAQY;IAE1B,cAAc,EAAE;;;;;;;uCAOqB;IAErC,aAAa,EAAE;;;;;;;;;;;;;GAad;IAED,OAAO,EAAE;;;;;;;;;;;;4BAYiB;IAE1B,cAAc,EAAE;;;;;;;;GAQf;IAED,eAAe,EAAE;;;;;;;;;;;;4BAYS;CAC3B,CAAC,CAAA;AAEF;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,KAAgB,EAAE,OAAe;IAC3E,OAAO,OAAO,CAAC,OAAO,CACpB,gBAAgB,KAAK,EAAE,EACvB,8BAA8B,OAAO,IAAI,KAAK,EAAE,CACjD,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,qEAAqE;IACrE,sEAAsE;IACtE,6DAA6D;IAC7D,OAAO,OAAO,CAAC,OAAO,CAAC,6BAA6B,EAAE,IAAI,CAAC,CAAA;AAC7D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAwC,MAAM,CAAC,MAAM,CAC7E,MAAM,CAAC,WAAW,CAChB,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACjC,CAC/B,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAgB,EAChB,OAAe,EACf,UAA+C,OAAO;IAEtD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;QAChC,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAA;QACtD,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QACD,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,cAAc,CACtB,kBAAkB,EAClB,iCAAiC,KAAK,EAAE,EACxC,KAAK,CACN,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"table_metadata.d.ts","sourceRoot":"","sources":["../../src/core/table_metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAexE,CAAA;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAE7D"}
1
+ {"version":3,"file":"table_metadata.d.ts","sourceRoot":"","sources":["../../src/core/table_metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAE1C,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,eAAO,MAAM,cAAc,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAgBxE,CAAA;AAEF;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,MAAM,CAE/D;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAE7D"}
@@ -26,6 +26,7 @@ export const TABLE_METADATA = Object.freeze({
26
26
  sleep_stage: { timeColumn: 'ts', syncable: true },
27
27
  sleep_raw: { timeColumn: 'ts', syncable: true },
28
28
  device_event: { timeColumn: 'ts', syncable: true },
29
+ device_battery: { timeColumn: 'ts', syncable: true },
29
30
  device_config: { timeColumn: 'valid_from', syncable: true },
30
31
  insight: { timeColumn: 'ts', syncable: true },
31
32
  sync_watermark: { timeColumn: 'updated_at', syncable: false },
@@ -1 +1 @@
1
- {"version":3,"file":"table_metadata.js","sourceRoot":"","sources":["../../src/core/table_metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,CAAC,MAAM,cAAc,GAAmD,MAAM,CAAC,MAAM,CAAC;IAC1F,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzC,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAChD,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,WAAW,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjD,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC9C,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACrD,aAAa,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzD,WAAW,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjD,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC/C,YAAY,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,aAAa,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3D,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC7C,cAAc,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC7D,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;CACvD,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,OAAQ,cAAoD,CAAC,KAAK,CAAC,EAAE,UAAU,IAAI,IAAI,CAAA;AACzF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,OAAQ,cAAoD,CAAC,KAAK,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAA;AACxF,CAAC"}
1
+ {"version":3,"file":"table_metadata.js","sourceRoot":"","sources":["../../src/core/table_metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,CAAC,MAAM,cAAc,GAAmD,MAAM,CAAC,MAAM,CAAC;IAC1F,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzC,UAAU,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAChD,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC1C,WAAW,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjD,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC9C,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACrD,aAAa,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE;IACzD,WAAW,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACjD,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC/C,YAAY,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAClD,cAAc,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IACpD,aAAa,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC3D,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC7C,cAAc,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE;IAC7D,eAAe,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE;CACvD,CAAC,CAAA;AAEF;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,OAAQ,cAAoD,CAAC,KAAK,CAAC,EAAE,UAAU,IAAI,IAAI,CAAA;AACzF,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAyB;IAClD,OAAQ,cAAoD,CAAC,KAAK,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAA;AACxF,CAAC"}
@@ -67,13 +67,24 @@ export interface EventBus {
67
67
  subscribe<T>(name: string, handler: (payload: T) => void): Unsubscribe;
68
68
  subscribePattern<T>(pattern: string, handler: (name: string, payload: T) => void): Unsubscribe;
69
69
  }
70
- export interface AnalyticsConfig {
70
+ /**
71
+ * Attach mode — whether to wire a remote R2 Iceberg catalog (`'r2'`) or
72
+ * operate against local DuckDB only (`'local'`). Default `'r2'` for
73
+ * back-compat with 0.4.x consumers.
74
+ *
75
+ * In `'local'` mode:
76
+ * - `iceberg` + `httpfs` extensions are NOT loaded (removes the AWSSDK
77
+ * / vcpkg build burden on iOS + Android; apps that don't need remote
78
+ * sync can skip building those extensions entirely).
79
+ * - `attach()` transitions straight to `attached` after ensuring the
80
+ * local tables exist; no R2 auth handshake, no remote catalog.
81
+ * - `pusher` / `fetcher` in `@mongrov/analytics/sync` are no-ops.
82
+ * - Rules engine still runs on batch (local-only violation detection).
83
+ */
84
+ export type AnalyticsMode = 'local' | 'r2';
85
+ interface CommonAnalyticsConfig {
71
86
  storage: KVStore;
72
87
  logger?: AnalyticsLogger;
73
- warehouseUriBuilder: (brand: string, tenantScope: TenantScope, tenantId: string) => string;
74
- catalogEndpoint: string;
75
- tokenVendor: TokenVendor;
76
- familyMembersProvider: FamilyMembersProvider;
77
88
  retention: Record<string, {
78
89
  days: number;
79
90
  }>;
@@ -85,6 +96,25 @@ export interface AnalyticsConfig {
85
96
  };
86
97
  eventBus?: EventBus;
87
98
  }
99
+ /**
100
+ * Local-only config. Omits the R2 fields; `mode` is required as the
101
+ * discriminant so consumers explicitly opt in.
102
+ */
103
+ export interface LocalAnalyticsConfig extends CommonAnalyticsConfig {
104
+ mode: 'local';
105
+ }
106
+ /**
107
+ * Remote R2 Iceberg config. `mode` is optional and defaults to `'r2'` for
108
+ * back-compat with 0.4.x call sites that don't set it.
109
+ */
110
+ export interface R2AnalyticsConfig extends CommonAnalyticsConfig {
111
+ mode?: 'r2';
112
+ warehouseUriBuilder: (brand: string, tenantScope: TenantScope, tenantId: string) => string;
113
+ catalogEndpoint: string;
114
+ tokenVendor: TokenVendor;
115
+ familyMembersProvider: FamilyMembersProvider;
116
+ }
117
+ export type AnalyticsConfig = LocalAnalyticsConfig | R2AnalyticsConfig;
88
118
  export interface AnalyticsAppender {
89
119
  appendRow(values: unknown[]): void;
90
120
  flush(): void;
@@ -101,6 +131,13 @@ export interface AnalyticsEngine {
101
131
  readonly lastError: Error | null;
102
132
  /** Catalog / warehouse secret name for the current attach; undefined when not attached. */
103
133
  readonly catalog: string | undefined;
134
+ /**
135
+ * Resolved mode — `'local'` if `AnalyticsConfig.mode === 'local'`,
136
+ * `'r2'` otherwise (including undefined for back-compat). Consumers can
137
+ * use this to gate mode-specific work — e.g. `createSyncManager` skips
138
+ * wiring the R2 pusher/fetcher in local mode.
139
+ */
140
+ readonly mode: AnalyticsMode;
104
141
  subscribe(listener: (s: AnalyticsState) => void): Unsubscribe;
105
142
  setRetention(days: number): Promise<void>;
106
143
  /**
@@ -128,4 +165,5 @@ export interface Insight {
128
165
  thresholdValue?: number;
129
166
  payload?: Record<string, unknown>;
130
167
  }
168
+ export {};
131
169
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Warehouse attach / detach for a single tenant zone.
2
+ * Warehouse attach / detach.
3
3
  *
4
- * Attaches R2 Iceberg data as a named DuckDB catalog, so downstream code can
5
- * `SELECT ... FROM zone_<tenantId>.<table>`. The full sequence lives here so
6
- * the state machine (T-09) can invoke it as a single actor step.
4
+ * Two modes:
5
+ * - `attachWarehouse` (R2 mode): attaches R2 Iceberg data as a named
6
+ * DuckDB catalog, so downstream code can address remote tables via
7
+ * `<zone_<tenantId>>.default.<table>` (3-part names).
8
+ * - `attachLocal` (local mode): no ATTACH; local tables live in the
9
+ * current file-backed catalog. Returns a synthetic `AttachResult`
10
+ * whose `warehouseSecret` is the local catalog name (probed via
11
+ * `current_database()`), so downstream state-machine code keeps the
12
+ * same shape.
7
13
  *
8
- * Sequence per spec §Attach Protocol:
14
+ * Sequence for `attachWarehouse` per spec §Attach Protocol:
9
15
  * 1. Build warehouse URI via `warehouseUriBuilder(brand, scope, tenantId)`.
10
16
  * 2. Fetch bearer token via `tokenVendor.fetch({ brand, scope, tenantId })`.
11
17
  * 3. `CREATE OR REPLACE SECRET` bound to the catalog endpoint + bearer token.
@@ -13,6 +19,16 @@
13
19
  * 5. If `tenantScope === 'family'`, prime member ids via
14
20
  * `familyMembersProvider({ brand, familyId })` (for retention math).
15
21
  *
22
+ * NOTE: 0.5.0 dropped the previous `USE ${secretName}.default` step
23
+ * inside attach + the matching `USE memory.main` before detach. Rationale:
24
+ * `USE memory.main` fails on file-backed DuckDB (real devices open a
25
+ * `.duckdb` file → catalog name is the file stem, not `memory`), and the
26
+ * `USE remote` step made unqualified queries resolve to the remote
27
+ * catalog — silently breaking the pusher's `main.<table>` SQL by pointing
28
+ * `main` at the remote instead of local. Callers should address remote
29
+ * tables via 3-part names (`<secret>.default.<table>`); local tables stay
30
+ * addressable via unqualified names.
31
+ *
16
32
  * All failures map to `AnalyticsError('attach_failed' | 'token_vendor_failed',
17
33
  * <phase>, cause)`.
18
34
  */
@@ -53,6 +69,40 @@ export declare function attachWarehouse(db: HybridDuckDB, ctx: AttachContext, de
53
69
  * Reverse of `attachWarehouse`: `DETACH` the catalog then drop its secret.
54
70
  * Idempotent from the caller's perspective — a `DETACH` of an unknown alias
55
71
  * throws in DuckDB, but the machine only calls this from `attached`.
72
+ *
73
+ * Since 0.5.0's attach no longer switches the current catalog with
74
+ * `USE ${secretName}.default`, this detach no longer needs to reset via
75
+ * `USE memory.main` (which failed on file-backed DuckDB anyway — the
76
+ * catalog on a real device is `<filestem>`, not `memory`).
56
77
  */
57
78
  export declare function detachWarehouse(db: HybridDuckDB, tenantId: string): Promise<void>;
79
+ /**
80
+ * Local-mode "attach" — no ATTACH statement, no auth, no remote catalog.
81
+ * The consumer's DuckDB (in-memory or file-backed) is already the current
82
+ * catalog after `db.open()`; we just probe its name and return a synthetic
83
+ * `AttachResult`. Table creation is deferred to `ensureMigrations` (called
84
+ * next by the factory) so schema evolution stays in one place.
85
+ *
86
+ * `warehouseSecret` in the returned result is set to the local catalog
87
+ * name (from `current_database()`) so downstream state-machine code + the
88
+ * public `engine.catalog` getter surface a meaningful identifier. Fields
89
+ * that only make sense for R2 (`warehouseUri`, `tokenExpiresAt`) get
90
+ * sentinel values: URI is `local:`, expiry is far-future so token-refresh
91
+ * timers never fire.
92
+ */
93
+ export declare function attachLocal(db: HybridDuckDB, _ctx: AttachContext): Promise<AttachResult>;
94
+ /**
95
+ * Probe the current DuckDB catalog name (via `SELECT current_database()`).
96
+ * Used by R2 mode too — the pusher needs to know the local catalog name so
97
+ * its `INSERT INTO r2.default.<table> SELECT * FROM <local>.main.<table>`
98
+ * addresses the correct source (post-0.5.0 attach no longer switches the
99
+ * current catalog, so `main.<table>` still means local).
100
+ */
101
+ export declare function probeLocalCatalog(db: HybridDuckDB): Promise<string>;
102
+ /**
103
+ * Reverse of `attachLocal` — no-op. Local mode never issued any ATTACH /
104
+ * SECRET, so there's nothing to unwind. Kept as an explicit function so
105
+ * the state machine's `detachEngine` actor can dispatch symmetrically.
106
+ */
107
+ export declare function detachLocal(_db: HybridDuckDB, _tenantId: string): Promise<void>;
58
108
  //# sourceMappingURL=warehouse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"warehouse.d.ts","sourceRoot":"","sources":["../../src/core/warehouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,WAAW,EAEX,WAAW,EACZ,MAAM,SAAS,CAAA;AAchB,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,mBAAmB,EAAE,CACnB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAA;IACX,WAAW,EAAE,WAAW,CAAA;IACxB,qBAAqB,EAAE,qBAAqB,CAAA;IAC5C,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAA;IACvB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,cAAc,EAAE,IAAI,CAAA;IACpB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CA8FvB;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAiBf"}
1
+ {"version":3,"file":"warehouse.d.ts","sourceRoot":"","sources":["../../src/core/warehouse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,KAAK,EACV,aAAa,EACb,qBAAqB,EACrB,WAAW,EAEX,WAAW,EACZ,MAAM,SAAS,CAAA;AAchB,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,mBAAmB,EAAE,CACnB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,KACb,MAAM,CAAA;IACX,WAAW,EAAE,WAAW,CAAA;IACxB,qBAAqB,EAAE,qBAAqB,CAAA;IAC5C,eAAe,EAAE,MAAM,CAAA;CACxB;AAED,8EAA8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,yDAAyD;IACzD,eAAe,EAAE,MAAM,CAAA;IACvB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,cAAc,EAAE,IAAI,CAAA;IACpB,sDAAsD;IACtD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,CAAC,CA0FvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,YAAY,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAaf;AAID;;;;;;;;;;;;;GAaG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,YAAY,EAChB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CA8BvB;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAczE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,YAAY,EACjB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -1,11 +1,17 @@
1
1
  /**
2
- * Warehouse attach / detach for a single tenant zone.
2
+ * Warehouse attach / detach.
3
3
  *
4
- * Attaches R2 Iceberg data as a named DuckDB catalog, so downstream code can
5
- * `SELECT ... FROM zone_<tenantId>.<table>`. The full sequence lives here so
6
- * the state machine (T-09) can invoke it as a single actor step.
4
+ * Two modes:
5
+ * - `attachWarehouse` (R2 mode): attaches R2 Iceberg data as a named
6
+ * DuckDB catalog, so downstream code can address remote tables via
7
+ * `<zone_<tenantId>>.default.<table>` (3-part names).
8
+ * - `attachLocal` (local mode): no ATTACH; local tables live in the
9
+ * current file-backed catalog. Returns a synthetic `AttachResult`
10
+ * whose `warehouseSecret` is the local catalog name (probed via
11
+ * `current_database()`), so downstream state-machine code keeps the
12
+ * same shape.
7
13
  *
8
- * Sequence per spec §Attach Protocol:
14
+ * Sequence for `attachWarehouse` per spec §Attach Protocol:
9
15
  * 1. Build warehouse URI via `warehouseUriBuilder(brand, scope, tenantId)`.
10
16
  * 2. Fetch bearer token via `tokenVendor.fetch({ brand, scope, tenantId })`.
11
17
  * 3. `CREATE OR REPLACE SECRET` bound to the catalog endpoint + bearer token.
@@ -13,6 +19,16 @@
13
19
  * 5. If `tenantScope === 'family'`, prime member ids via
14
20
  * `familyMembersProvider({ brand, familyId })` (for retention math).
15
21
  *
22
+ * NOTE: 0.5.0 dropped the previous `USE ${secretName}.default` step
23
+ * inside attach + the matching `USE memory.main` before detach. Rationale:
24
+ * `USE memory.main` fails on file-backed DuckDB (real devices open a
25
+ * `.duckdb` file → catalog name is the file stem, not `memory`), and the
26
+ * `USE remote` step made unqualified queries resolve to the remote
27
+ * catalog — silently breaking the pusher's `main.<table>` SQL by pointing
28
+ * `main` at the remote instead of local. Callers should address remote
29
+ * tables via 3-part names (`<secret>.default.<table>`); local tables stay
30
+ * addressable via unqualified names.
31
+ *
16
32
  * All failures map to `AnalyticsError('attach_failed' | 'token_vendor_failed',
17
33
  * <phase>, cause)`.
18
34
  */
@@ -71,17 +87,13 @@ export async function attachWarehouse(db, ctx, deps) {
71
87
  catch (cause) {
72
88
  throw new AnalyticsError('attach_failed', `CREATE SECRET failed for ${secretName}`, rootCause(cause));
73
89
  }
74
- // Step 4: ATTACH + pin the current schema to the `default` namespace.
75
- //
76
- // DuckDB's Iceberg attach does not select a namespace, so unqualified
77
- // `<catalog>.<table>` DDL (see `schemas.ts` / `qualifyDdl`) would resolve
78
- // against schema `""` and fail with `Schema with name "" not found`.
79
- // Iceberg mandates 3-part names; picking `default` here lets the rest of
80
- // the codebase keep the 2-part `<catalog>.<table>` shape it was written
81
- // against. Callers that need a different namespace should attach directly.
90
+ // Step 4: ATTACH. See top-of-file NOTE for why the prior
91
+ // `USE ${secretName}.default` step was dropped in 0.5.0. Consumers write
92
+ // to the remote via 3-part names (`${secretName}.default.<table>`), keeping
93
+ // local `main.<table>` addressable for the pusher's SELECT source and the
94
+ // rules engine's INSERT sink.
82
95
  try {
83
96
  await db.execute(`ATTACH '${uri}' AS ${secretName} (TYPE ICEBERG);`);
84
- await db.execute(`USE ${secretName}.default;`);
85
97
  }
86
98
  catch (cause) {
87
99
  throw new AnalyticsError('attach_failed', `ATTACH failed for ${secretName}`, rootCause(cause));
@@ -110,14 +122,15 @@ export async function attachWarehouse(db, ctx, deps) {
110
122
  * Reverse of `attachWarehouse`: `DETACH` the catalog then drop its secret.
111
123
  * Idempotent from the caller's perspective — a `DETACH` of an unknown alias
112
124
  * throws in DuckDB, but the machine only calls this from `attached`.
125
+ *
126
+ * Since 0.5.0's attach no longer switches the current catalog with
127
+ * `USE ${secretName}.default`, this detach no longer needs to reset via
128
+ * `USE memory.main` (which failed on file-backed DuckDB anyway — the
129
+ * catalog on a real device is `<filestem>`, not `memory`).
113
130
  */
114
131
  export async function detachWarehouse(db, tenantId) {
115
132
  const secretName = warehouseSecretName(tenantId);
116
133
  try {
117
- // DuckDB refuses to detach the current default database, and `attach`
118
- // above pinned it to `${secretName}.default`. Reset to the in-memory
119
- // catalog before detaching so DETACH succeeds.
120
- await db.execute(`USE memory.main;`);
121
134
  await db.execute(`DETACH ${secretName};`);
122
135
  await db.execute(`DROP SECRET ${secretName};`);
123
136
  }
@@ -125,4 +138,66 @@ export async function detachWarehouse(db, tenantId) {
125
138
  throw new AnalyticsError('detach_failed', `detach failed for ${secretName}`, rootCause(cause));
126
139
  }
127
140
  }
141
+ // -------------------- local mode --------------------
142
+ /**
143
+ * Local-mode "attach" — no ATTACH statement, no auth, no remote catalog.
144
+ * The consumer's DuckDB (in-memory or file-backed) is already the current
145
+ * catalog after `db.open()`; we just probe its name and return a synthetic
146
+ * `AttachResult`. Table creation is deferred to `ensureMigrations` (called
147
+ * next by the factory) so schema evolution stays in one place.
148
+ *
149
+ * `warehouseSecret` in the returned result is set to the local catalog
150
+ * name (from `current_database()`) so downstream state-machine code + the
151
+ * public `engine.catalog` getter surface a meaningful identifier. Fields
152
+ * that only make sense for R2 (`warehouseUri`, `tokenExpiresAt`) get
153
+ * sentinel values: URI is `local:`, expiry is far-future so token-refresh
154
+ * timers never fire.
155
+ */
156
+ export async function attachLocal(db, _ctx) {
157
+ // Probe the current catalog name so downstream code addresses local
158
+ // tables via `${catalog}.main.<table>` when it needs to be explicit.
159
+ let catalog;
160
+ try {
161
+ const rows = await db.execute(`SELECT current_database() AS current_database;`);
162
+ catalog = rows[0]?.current_database ?? 'memory';
163
+ }
164
+ catch (cause) {
165
+ throw new AnalyticsError('attach_failed', `attachLocal: current_database() probe failed`, rootCause(cause));
166
+ }
167
+ // Sentinel expiry — 100 years from now. Token-refresh scheduling in the
168
+ // state machine keys off this; setting it far-future prevents the
169
+ // refresh actor from ever firing in local mode.
170
+ const farFuture = new Date(Date.now() + 100 * 365 * 24 * 60 * 60 * 1000);
171
+ return {
172
+ warehouseSecret: catalog,
173
+ warehouseUri: 'local:',
174
+ tokenExpiresAt: farFuture,
175
+ // No family fanout in local mode; retention math falls back to ctx.userId.
176
+ familyMemberIds: undefined,
177
+ };
178
+ }
179
+ /**
180
+ * Probe the current DuckDB catalog name (via `SELECT current_database()`).
181
+ * Used by R2 mode too — the pusher needs to know the local catalog name so
182
+ * its `INSERT INTO r2.default.<table> SELECT * FROM <local>.main.<table>`
183
+ * addresses the correct source (post-0.5.0 attach no longer switches the
184
+ * current catalog, so `main.<table>` still means local).
185
+ */
186
+ export async function probeLocalCatalog(db) {
187
+ try {
188
+ const rows = await db.execute(`SELECT current_database() AS current_database;`);
189
+ return rows[0]?.current_database ?? 'memory';
190
+ }
191
+ catch (cause) {
192
+ throw new AnalyticsError('query_failed', `probeLocalCatalog: current_database() failed`, rootCause(cause));
193
+ }
194
+ }
195
+ /**
196
+ * Reverse of `attachLocal` — no-op. Local mode never issued any ATTACH /
197
+ * SECRET, so there's nothing to unwind. Kept as an explicit function so
198
+ * the state machine's `detachEngine` actor can dispatch symmetrically.
199
+ */
200
+ export async function detachLocal(_db, _tenantId) {
201
+ // intentional no-op
202
+ }
128
203
  //# sourceMappingURL=warehouse.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"warehouse.js","sourceRoot":"","sources":["../../src/core/warehouse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"warehouse.js","sourceRoot":"","sources":["../../src/core/warehouse.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"fakeEngine.d.ts","sourceRoot":"","sources":["../../../src/rules/__fakes__/fakeEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEvE,wDAAwD;AACxD,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAA;IAC3D,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAClC,UAAU,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAAA;IACnC,oFAAoF;IACpF,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CACxC;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAiC7C"}
1
+ {"version":3,"file":"fakeEngine.d.ts","sourceRoot":"","sources":["../../../src/rules/__fakes__/fakeEngine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEvE,wDAAwD;AACxD,MAAM,WAAW,UAAW,SAAQ,eAAe;IACjD,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAA;IAC3D,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAA;IAClC,UAAU,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,GAAG,IAAI,CAAA;IACnC,oFAAoF;IACpF,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAA;CACxC;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAkC7C"}
@@ -21,6 +21,7 @@ export function createFakeEngine() {
21
21
  get state() { return state; },
22
22
  lastError: null,
23
23
  catalog: 'fake',
24
+ mode: 'r2',
24
25
  subscribe: () => () => { },
25
26
  async setRetention() { },
26
27
  async getLastAttach() { return null; },
@@ -1 +1 @@
1
- {"version":3,"file":"fakeEngine.js","sourceRoot":"","sources":["../../../src/rules/__fakes__/fakeEngine.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,gBAAgB;IAC9B,IAAI,MAAM,GAAc,EAAE,CAAA;IAC1B,IAAI,SAAS,GAAiB,IAAI,CAAA;IAClC,IAAI,KAAK,GAAmB,UAAU,CAAA;IACtC,MAAM,KAAK,GAAuD,EAAE,CAAA;IAEpE,MAAM,MAAM,GAAe;QACzB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,OAAO,CAAI,GAAW,EAAE,MAAgC;YAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;YACzC,IAAI,SAAS;gBAAE,MAAM,SAAS,CAAA;YAC9B,OAAO,MAAa,CAAA;QACtB,CAAC;QACD,MAAM;YACJ,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QACD,cAAc;YACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,KAAK,KAAK,OAAO,KAAK,CAAA,CAAC,CAAC;QAC5B,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,MAAM;QACf,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;QACzB,KAAK,CAAC,YAAY,KAAI,CAAC;QACvB,KAAK,CAAC,aAAa,KAAK,OAAO,IAAI,CAAA,CAAC,CAAC;QACrC,KAAK,CAAC,KAAK,KAAI,CAAC;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,CAAC,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAA,CAAC,CAAC;QACrD,UAAU,CAAC,GAAG,IAAI,SAAS,GAAG,GAAG,CAAA,CAAC,CAAC;QACnC,UAAU,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAA,CAAC,CAAC;KAC5B,CAAA;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
1
+ {"version":3,"file":"fakeEngine.js","sourceRoot":"","sources":["../../../src/rules/__fakes__/fakeEngine.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,gBAAgB;IAC9B,IAAI,MAAM,GAAc,EAAE,CAAA;IAC1B,IAAI,SAAS,GAAiB,IAAI,CAAA;IAClC,IAAI,KAAK,GAAmB,UAAU,CAAA;IACtC,MAAM,KAAK,GAAuD,EAAE,CAAA;IAEpE,MAAM,MAAM,GAAe;QACzB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,MAAM,KAAI,CAAC;QACjB,KAAK,CAAC,OAAO,CAAI,GAAW,EAAE,MAAgC;YAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;YACzC,IAAI,SAAS;gBAAE,MAAM,SAAS,CAAA;YAC9B,OAAO,MAAa,CAAA;QACtB,CAAC;QACD,MAAM;YACJ,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAA;QACnD,CAAC;QACD,cAAc;YACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;QAC3D,CAAC;QACD,IAAI,KAAK,KAAK,OAAO,KAAK,CAAA,CAAC,CAAC;QAC5B,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,IAAI;QACV,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC;QACzB,KAAK,CAAC,YAAY,KAAI,CAAC;QACvB,KAAK,CAAC,aAAa,KAAK,OAAO,IAAI,CAAA,CAAC,CAAC;QACrC,KAAK,CAAC,KAAK,KAAI,CAAC;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,CAAC,IAAI,IAAI,MAAM,GAAG,IAAI,CAAC,CAAC,SAAS,GAAG,IAAI,CAAA,CAAC,CAAC;QACrD,UAAU,CAAC,GAAG,IAAI,SAAS,GAAG,GAAG,CAAA,CAAC,CAAC;QACnC,UAAU,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAA,CAAC,CAAC;KAC5B,CAAA;IACD,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -82,7 +82,7 @@ export declare const RuleSchema: z.ZodObject<{
82
82
  brand: z.ZodOptional<z.ZodString>;
83
83
  name: z.ZodString;
84
84
  description: z.ZodOptional<z.ZodString>;
85
- metric: z.ZodEnum<["spo2" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score" | "device_battery", ...("spo2" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score" | "device_battery")[]]>;
85
+ metric: z.ZodEnum<["spo2" | "device_battery" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score", ...("spo2" | "device_battery" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score")[]]>;
86
86
  window: z.ZodEnum<["1h", "6h", "24h", "3d", "7d", "30d"]>;
87
87
  aggregation: z.ZodDefault<z.ZodEnum<["avg", "min", "max", "sum", "last", "count"]>>;
88
88
  compare: z.ZodEnum<["less_than", "greater_than", "equals", "not_equals", "between"]>;
@@ -169,7 +169,7 @@ export declare const RuleSchema: z.ZodObject<{
169
169
  max: number;
170
170
  };
171
171
  name: string;
172
- metric: "spo2" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score" | "device_battery";
172
+ metric: "spo2" | "device_battery" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score";
173
173
  window: "1h" | "6h" | "24h" | "3d" | "7d" | "30d";
174
174
  aggregation: "avg" | "min" | "max" | "sum" | "last" | "count";
175
175
  compare: "less_than" | "greater_than" | "equals" | "not_equals" | "between";
@@ -202,7 +202,7 @@ export declare const RuleSchema: z.ZodObject<{
202
202
  max: number;
203
203
  };
204
204
  name: string;
205
- metric: "spo2" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score" | "device_battery";
205
+ metric: "spo2" | "device_battery" | "hrv_ms" | "stress" | "systolic_bp" | "diastolic_bp" | "vascular_aging" | "hr_bpm" | "temp_c" | "activity_steps" | "calories" | "distance_km" | "sleep_total_minutes" | "sleep_score";
206
206
  window: "1h" | "6h" | "24h" | "3d" | "7d" | "30d";
207
207
  compare: "less_than" | "greater_than" | "equals" | "not_equals" | "between";
208
208
  severity: "info" | "warn" | "critical";