@mongrov/analytics 0.1.0-alpha.0 → 0.1.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) 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 +27 -16
  172. package/LICENSE +0 -21
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Thin wrapper around a native DuckDB instance.
3
+ *
4
+ * Owns lifecycle (`open`/`close`), maps native errors into the analytics
5
+ * error taxonomy, and normalises `execute`/`stream`/`createAppender` so the
6
+ * rest of the package doesn't touch `react-native-duckdb` directly.
7
+ *
8
+ * We depend on `react-native-duckdb` only structurally (via the
9
+ * `DuckDBInstance` interface below) so the package builds and tests without
10
+ * the native module installed. The public factory (T-10) supplies a real
11
+ * instance via a `DuckDBFactory`; test suites supply fakes.
12
+ */
13
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
14
+ if (kind === "m") throw new TypeError("Private method is not writable");
15
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
16
+ 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");
17
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
18
+ };
19
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
20
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
21
+ 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");
22
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
23
+ };
24
+ var _HybridDuckDB_instances, _HybridDuckDB_factory, _HybridDuckDB_instance, _HybridDuckDB_closed, _HybridDuckDB_ready;
25
+ import { AnalyticsError } from './errors';
26
+ /**
27
+ * Owns the DuckDB connection lifecycle.
28
+ *
29
+ * - `open()` is idempotent: repeated calls after a successful open are no-ops.
30
+ * - `close()` is idempotent and terminal — subsequent `execute`/`stream`/
31
+ * `createAppender` throw `not_ready`.
32
+ * - `execute()` returns a full row set; `stream()` yields pages of rows
33
+ * (recommended page size `HybridDuckDB.PAGE_SIZE`, applied by the native
34
+ * driver; the wrapper just forwards).
35
+ * - Any native throw is wrapped in `AnalyticsError`.
36
+ */
37
+ export class HybridDuckDB {
38
+ constructor(factory) {
39
+ _HybridDuckDB_instances.add(this);
40
+ _HybridDuckDB_factory.set(this, void 0);
41
+ _HybridDuckDB_instance.set(this, void 0);
42
+ _HybridDuckDB_closed.set(this, false);
43
+ __classPrivateFieldSet(this, _HybridDuckDB_factory, factory, "f");
44
+ }
45
+ /** Whether `open()` has completed successfully and `close()` has not been called. */
46
+ get isOpen() {
47
+ return __classPrivateFieldGet(this, _HybridDuckDB_instance, "f") !== undefined && !__classPrivateFieldGet(this, _HybridDuckDB_closed, "f");
48
+ }
49
+ async open() {
50
+ if (__classPrivateFieldGet(this, _HybridDuckDB_closed, "f")) {
51
+ throw new AnalyticsError('not_ready', 'HybridDuckDB has been closed');
52
+ }
53
+ if (__classPrivateFieldGet(this, _HybridDuckDB_instance, "f")) {
54
+ return;
55
+ }
56
+ try {
57
+ __classPrivateFieldSet(this, _HybridDuckDB_instance, await __classPrivateFieldGet(this, _HybridDuckDB_factory, "f").call(this), "f");
58
+ }
59
+ catch (cause) {
60
+ throw new AnalyticsError('engine_open_failed', 'Failed to open DuckDB instance', cause);
61
+ }
62
+ }
63
+ async execute(sql, params) {
64
+ const inst = __classPrivateFieldGet(this, _HybridDuckDB_instances, "m", _HybridDuckDB_ready).call(this);
65
+ try {
66
+ const rows = await inst.execute(sql, params);
67
+ return rows;
68
+ }
69
+ catch (cause) {
70
+ throw new AnalyticsError('query_failed', `execute failed: ${previewSql(sql)}`, cause);
71
+ }
72
+ }
73
+ async *stream(sql, params) {
74
+ const inst = __classPrivateFieldGet(this, _HybridDuckDB_instances, "m", _HybridDuckDB_ready).call(this);
75
+ try {
76
+ for await (const page of inst.stream(sql, params)) {
77
+ yield page;
78
+ }
79
+ }
80
+ catch (cause) {
81
+ throw new AnalyticsError('query_failed', `stream failed: ${previewSql(sql)}`, cause);
82
+ }
83
+ }
84
+ createAppender(table) {
85
+ const inst = __classPrivateFieldGet(this, _HybridDuckDB_instances, "m", _HybridDuckDB_ready).call(this);
86
+ try {
87
+ return inst.createAppender(table);
88
+ }
89
+ catch (cause) {
90
+ throw new AnalyticsError('query_failed', `createAppender failed for table ${table}`, cause);
91
+ }
92
+ }
93
+ async close() {
94
+ if (__classPrivateFieldGet(this, _HybridDuckDB_closed, "f")) {
95
+ return;
96
+ }
97
+ __classPrivateFieldSet(this, _HybridDuckDB_closed, true, "f");
98
+ const inst = __classPrivateFieldGet(this, _HybridDuckDB_instance, "f");
99
+ __classPrivateFieldSet(this, _HybridDuckDB_instance, undefined, "f");
100
+ if (inst) {
101
+ await inst.close();
102
+ }
103
+ }
104
+ }
105
+ _HybridDuckDB_factory = new WeakMap(), _HybridDuckDB_instance = new WeakMap(), _HybridDuckDB_closed = new WeakMap(), _HybridDuckDB_instances = new WeakSet(), _HybridDuckDB_ready = function _HybridDuckDB_ready() {
106
+ if (__classPrivateFieldGet(this, _HybridDuckDB_closed, "f")) {
107
+ throw new AnalyticsError('not_ready', 'HybridDuckDB is closed');
108
+ }
109
+ if (!__classPrivateFieldGet(this, _HybridDuckDB_instance, "f")) {
110
+ throw new AnalyticsError('not_ready', 'HybridDuckDB.open() has not been called');
111
+ }
112
+ return __classPrivateFieldGet(this, _HybridDuckDB_instance, "f");
113
+ };
114
+ /** Recommended page size for streamed queries (spec §Engine). */
115
+ HybridDuckDB.PAGE_SIZE = 500;
116
+ function previewSql(sql) {
117
+ return sql.length > 120 ? `${sql.slice(0, 120)}…` : sql;
118
+ }
119
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/core/engine.ts"],"names":[],"mappings":"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"}
@@ -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' | 'token_vendor_failed' | 'migration_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' | '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,qBAAqB,GACrB,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,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 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,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,yDAAyD,CAAC,CAAA;QAC5F,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,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,yDAAyD,CAAC,CAAA;QAC5F,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAA;IACnC,CAAC;CACF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * DuckDB extension bootstrap.
3
+ *
4
+ * Analytics needs `httpfs` + `iceberg` + `parquet` loaded before any
5
+ * `ATTACH 'iceberg://…'` can succeed. This module is the single place we
6
+ * issue `INSTALL/LOAD`, so failures map cleanly to
7
+ * `AnalyticsError('extension_load_failed', <name>)`.
8
+ *
9
+ * Bootstrapping is idempotent — a `#booted: Set<string>` guards repeated
10
+ * calls, and DuckDB itself no-ops re-loads, so calling twice is safe.
11
+ */
12
+ import type { HybridDuckDB } from './engine';
13
+ /** Extensions required for R2 Iceberg attach, in load order. */
14
+ export declare const REQUIRED_EXTENSIONS: readonly ["httpfs", "iceberg", "parquet"];
15
+ export type RequiredExtension = (typeof REQUIRED_EXTENSIONS)[number];
16
+ /**
17
+ * Issue `INSTALL <ext>; LOAD <ext>;` for each required extension in order.
18
+ *
19
+ * Idempotent per-engine: extensions already loaded on the same
20
+ * `HybridDuckDB` instance are skipped.
21
+ *
22
+ * @throws `AnalyticsError('extension_load_failed', <ext>)` if any extension
23
+ * fails; the extension name appears in the message + cause is preserved.
24
+ */
25
+ export declare function bootstrapExtensions(db: HybridDuckDB): Promise<void>;
26
+ /**
27
+ * Test-only: introspect which extensions have been booted for a given engine.
28
+ *
29
+ * Exposed for coverage of the idempotency path in
30
+ * `__tests__/extensions.test.ts`; not re-exported from `core/index.ts`.
31
+ */
32
+ export declare function getBootedExtensions(db: HybridDuckDB): ReadonlySet<string>;
33
+ //# sourceMappingURL=extensions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.d.ts","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,gEAAgE;AAChE,eAAO,MAAM,mBAAmB,2CAA4C,CAAA;AAE5E,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAA;AAQpE;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBzE;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAEzE"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * DuckDB extension bootstrap.
3
+ *
4
+ * Analytics needs `httpfs` + `iceberg` + `parquet` loaded before any
5
+ * `ATTACH 'iceberg://…'` can succeed. This module is the single place we
6
+ * issue `INSTALL/LOAD`, so failures map cleanly to
7
+ * `AnalyticsError('extension_load_failed', <name>)`.
8
+ *
9
+ * Bootstrapping is idempotent — a `#booted: Set<string>` guards repeated
10
+ * calls, and DuckDB itself no-ops re-loads, so calling twice is safe.
11
+ */
12
+ import { AnalyticsError } from './errors';
13
+ /** Extensions required for R2 Iceberg attach, in load order. */
14
+ export const REQUIRED_EXTENSIONS = ['httpfs', 'iceberg', 'parquet'];
15
+ /**
16
+ * Tracks which extensions this process has already booted. Keyed by
17
+ * `HybridDuckDB` instance to keep isolation across engines in tests.
18
+ */
19
+ const bootedByDb = new WeakMap();
20
+ /**
21
+ * Issue `INSTALL <ext>; LOAD <ext>;` for each required extension in order.
22
+ *
23
+ * Idempotent per-engine: extensions already loaded on the same
24
+ * `HybridDuckDB` instance are skipped.
25
+ *
26
+ * @throws `AnalyticsError('extension_load_failed', <ext>)` if any extension
27
+ * fails; the extension name appears in the message + cause is preserved.
28
+ */
29
+ export async function bootstrapExtensions(db) {
30
+ let booted = bootedByDb.get(db);
31
+ if (!booted) {
32
+ booted = new Set();
33
+ bootedByDb.set(db, booted);
34
+ }
35
+ for (const ext of REQUIRED_EXTENSIONS) {
36
+ if (booted.has(ext)) {
37
+ continue;
38
+ }
39
+ try {
40
+ await db.execute(`INSTALL ${ext};`);
41
+ await db.execute(`LOAD ${ext};`);
42
+ }
43
+ catch (cause) {
44
+ throw new AnalyticsError('extension_load_failed', `Failed to load DuckDB extension: ${ext}`, cause);
45
+ }
46
+ booted.add(ext);
47
+ }
48
+ }
49
+ /**
50
+ * Test-only: introspect which extensions have been booted for a given engine.
51
+ *
52
+ * Exposed for coverage of the idempotency path in
53
+ * `__tests__/extensions.test.ts`; not re-exported from `core/index.ts`.
54
+ */
55
+ export function getBootedExtensions(db) {
56
+ return bootedByDb.get(db) ?? new Set();
57
+ }
58
+ //# sourceMappingURL=extensions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/core/extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAGzC,gEAAgE;AAChE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAU,CAAA;AAI5E;;;GAGG;AACH,MAAM,UAAU,GAAG,IAAI,OAAO,EAA6B,CAAA;AAE3D;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,EAAgB;IACxD,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,KAAK,MAAM,GAAG,IAAI,mBAAmB,EAAE,CAAC;QACtC,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,9 +1,26 @@
1
- import type { AnalyticsConfig, AnalyticsEngine } from './types';
2
1
  /**
3
- * Wires config into engine + warehouse + machine.
2
+ * Wires config + engine + machine into an `AnalyticsEngine`.
3
+ *
4
+ * Public entry: `createAnalytics(config)` — used by apps. Uses the injected
5
+ * duckdb factory from `config.duckdb?.factory` (see below) or a lazy
6
+ * `react-native-duckdb` resolver.
4
7
  *
5
- * Stub in T-02. Full wiring lands in T-10 (Phase 4 factory) once the
6
- * engine (T-03/04), warehouse (T-05/06/07/08), and machine (T-09) exist.
8
+ * The 2nd (optional) `internal` argument is an escape hatch for tests +
9
+ * embed contexts that need to substitute a `DuckDBFactory` without shipping
10
+ * `react-native-duckdb`. Not part of the spec surface; consumers should
11
+ * stick to the 1-arg form.
12
+ */
13
+ import type { DuckDBFactory } from './engine';
14
+ import type { AnalyticsConfig, AnalyticsEngine } from './types';
15
+ /**
16
+ * Internal-only extra input for `createAnalytics`. Not exported from the
17
+ * package barrel; ships in the `factory.ts` module surface so the test suite
18
+ * and embedders can substitute a `DuckDBFactory` without shipping
19
+ * `react-native-duckdb`.
7
20
  */
8
- export declare function createAnalytics(_config: AnalyticsConfig): AnalyticsEngine;
21
+ export interface CreateAnalyticsInternal {
22
+ /** Substitute the DuckDB factory (fakes in tests; native adapter in app). */
23
+ duckdbFactory?: DuckDBFactory;
24
+ }
25
+ export declare function createAnalytics(config: AnalyticsConfig, internal?: CreateAnalyticsInternal): AnalyticsEngine;
9
26
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAE/D;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe,CAEzE"}
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;AAe7D,OAAO,KAAK,EAEV,eAAe,EACf,eAAe,EAIhB,MAAM,SAAS,CAAA;AA6BhB;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,aAAa,CAAA;CAC9B;AAoCD,wBAAgB,eAAe,CAC7B,MAAM,EAAE,eAAe,EACvB,QAAQ,GAAE,uBAA4B,GACrC,eAAe,CA2LjB"}
@@ -1,11 +1,236 @@
1
- import { NotImplementedError } from './errors';
2
1
  /**
3
- * Wires config into engine + warehouse + machine.
2
+ * Wires config + engine + machine into an `AnalyticsEngine`.
4
3
  *
5
- * Stub in T-02. Full wiring lands in T-10 (Phase 4 — factory) once the
6
- * engine (T-03/04), warehouse (T-05/06/07/08), and machine (T-09) exist.
4
+ * Public entry: `createAnalytics(config)` used by apps. Uses the injected
5
+ * duckdb factory from `config.duckdb?.factory` (see below) or a lazy
6
+ * `react-native-duckdb` resolver.
7
+ *
8
+ * The 2nd (optional) `internal` argument is an escape hatch for tests +
9
+ * embed contexts that need to substitute a `DuckDBFactory` without shipping
10
+ * `react-native-duckdb`. Not part of the spec surface; consumers should
11
+ * stick to the 1-arg form.
12
+ */
13
+ import { createActor } from 'xstate';
14
+ import { AnalyticsError, NotImplementedError } from './errors';
15
+ import { HybridDuckDB } from './engine';
16
+ import { bootstrapExtensions } from './extensions';
17
+ import { resolveLogger } from './logger';
18
+ import { analyticsMachine } from './machine';
19
+ import { ensureMigrations } from './migrations';
20
+ import { clearLastAttach, loadLastAttach, loadRetentionOverride, saveLastAttach, saveRetentionOverride, } from './persistence';
21
+ import { resolveEffectiveRetention, runRetentionSweep } from './retention';
22
+ import { attachWarehouse, detachWarehouse, warehouseSecretName, } from './warehouse';
23
+ // -------------------- default DuckDB factory --------------------
24
+ /**
25
+ * Lazy resolver for `react-native-duckdb`. Only fires on `open()` — importing
26
+ * `createAnalytics` on a Node/CI host without the native module must not
27
+ * throw. Failure is deferred to the machine's `openEngine` actor, which
28
+ * surfaces as `AnalyticsError('engine_open_failed')` per spec.
29
+ */
30
+ function defaultDuckdbFactory() {
31
+ return async () => {
32
+ throw new NotImplementedError('defaultDuckdbFactory — supply internal.duckdbFactory or wait for react-native-duckdb adapter');
33
+ // T-10 acceptance: apps must supply a factory via the internal arg while
34
+ // the react-native-duckdb adapter lands (tracked separately). Returning
35
+ // an unreachable satisfies the `DuckDBInstance` return contract.
36
+ return undefined;
37
+ };
38
+ }
39
+ // -------------------- state promise helper --------------------
40
+ /**
41
+ * Resolve when the actor next enters one of `targets` (excluding its
42
+ * *current* state at the time of subscription).
7
43
  */
8
- export function createAnalytics(_config) {
9
- throw new NotImplementedError('createAnalytics');
44
+ function waitForNextState(actor, targets) {
45
+ return new Promise((resolve) => {
46
+ let seenFirst = false;
47
+ const targetSet = new Set(targets);
48
+ const sub = actor.subscribe((snapshot) => {
49
+ if (!seenFirst) {
50
+ seenFirst = true;
51
+ return;
52
+ }
53
+ const value = typeof snapshot.value === 'string' ? snapshot.value : '';
54
+ if (targetSet.has(value)) {
55
+ sub.unsubscribe();
56
+ resolve(value);
57
+ }
58
+ });
59
+ });
60
+ }
61
+ function currentState(actor) {
62
+ const raw = actor.getSnapshot().value;
63
+ return typeof raw === 'string' ? raw : 'idle';
64
+ }
65
+ // -------------------- factory --------------------
66
+ export function createAnalytics(config, internal = {}) {
67
+ const log = resolveLogger(config.logger);
68
+ const duckdbFactory = internal.duckdbFactory ?? defaultDuckdbFactory();
69
+ const db = new HybridDuckDB(duckdbFactory);
70
+ const machineActors = {
71
+ async openEngine() {
72
+ await db.open();
73
+ await bootstrapExtensions(db);
74
+ },
75
+ async attachEngine({ ctx }) {
76
+ const attach = await attachWarehouse(db, ctx, {
77
+ warehouseUriBuilder: config.warehouseUriBuilder,
78
+ tokenVendor: config.tokenVendor,
79
+ familyMembersProvider: config.familyMembersProvider,
80
+ catalogEndpoint: config.catalogEndpoint,
81
+ });
82
+ await ensureMigrations(db, config.storage, { brand: ctx.brand, tenantId: ctx.tenantId }, attach.warehouseSecret);
83
+ return {
84
+ warehouseSecret: attach.warehouseSecret,
85
+ tokenExpiresAt: attach.tokenExpiresAt.getTime(),
86
+ };
87
+ },
88
+ async detachEngine({ ctx }) {
89
+ await detachWarehouse(db, ctx.tenantId);
90
+ },
91
+ async refreshToken({ ctx }) {
92
+ const token = await config.tokenVendor.fetch({
93
+ brand: ctx.brand,
94
+ tenantScope: ctx.tenantScope,
95
+ tenantId: ctx.tenantId,
96
+ });
97
+ const secretName = warehouseSecretName(ctx.tenantId);
98
+ try {
99
+ await db.execute(`CREATE OR REPLACE SECRET ${secretName} (TYPE ICEBERG, TOKEN $token, ENDPOINT $endpoint);`, { token: token.token, endpoint: config.catalogEndpoint });
100
+ }
101
+ catch (cause) {
102
+ throw new AnalyticsError('token_vendor_failed', `refreshToken: CREATE OR REPLACE SECRET failed for ${secretName}`, cause);
103
+ }
104
+ return { tokenExpiresAt: token.expiresAt.getTime() };
105
+ },
106
+ };
107
+ const actor = createActor(analyticsMachine, { input: { deps: machineActors } });
108
+ const publicSubscribers = new Set();
109
+ let lastLoggedState;
110
+ const internalSub = actor.subscribe(() => {
111
+ const s = currentState(actor);
112
+ if (s !== lastLoggedState) {
113
+ lastLoggedState = s;
114
+ log.debug('analytics.state', { value: s });
115
+ }
116
+ for (const fn of publicSubscribers)
117
+ fn(s);
118
+ });
119
+ actor.start();
120
+ actor.send({ type: 'OPEN' });
121
+ /**
122
+ * Ctx of the last successful attach; cleared on detach. Used by
123
+ * `setRetention` (needs `brand/tenantId/userId` for the override key) and
124
+ * by the attach-time persistence + sweep hook.
125
+ */
126
+ let currentCtx;
127
+ /**
128
+ * Load user override (if any), resolve effective retention against the
129
+ * brand default from `AnalyticsConfig.retention`, run one sweep. Errors
130
+ * are re-thrown; callers may choose to swallow (attach-time sweep does).
131
+ */
132
+ async function sweep(ctx, catalog) {
133
+ const brandCfg = config.retention[ctx.brand];
134
+ const brandDefault = brandCfg?.days ?? 0;
135
+ const userOverride = (await loadRetentionOverride(config.storage, ctx)) ?? undefined;
136
+ const effectiveDays = resolveEffectiveRetention({ brandDefault, userOverride });
137
+ if (effectiveDays <= 0)
138
+ return;
139
+ await runRetentionSweep(db, catalog, { effectiveDays });
140
+ }
141
+ const engine = {
142
+ async attach(ctx) {
143
+ const pending = waitForNextState(actor, ['attached', 'error']);
144
+ actor.send({ type: 'ATTACH', ctx });
145
+ const final = await pending;
146
+ if (final === 'error') {
147
+ throw actor.getSnapshot().context.lastError ?? new AnalyticsError('attach_failed', 'attach failed');
148
+ }
149
+ currentCtx = ctx;
150
+ log.info('analytics.attached', {
151
+ brand: ctx.brand,
152
+ tenantId: ctx.tenantId,
153
+ tenantScope: ctx.tenantScope,
154
+ });
155
+ // Persistence + retention sweep are best-effort so a KV / DELETE
156
+ // failure never rejects a successful attach.
157
+ try {
158
+ await saveLastAttach(config.storage, ctx);
159
+ }
160
+ catch (cause) {
161
+ log.warn('analytics.persist.last_attach_failed', { cause });
162
+ }
163
+ const catalog = actor.getSnapshot().context.warehouseSecret;
164
+ if (catalog) {
165
+ try {
166
+ await sweep(ctx, catalog);
167
+ }
168
+ catch (cause) {
169
+ log.warn('analytics.retention.sweep_failed', { cause });
170
+ }
171
+ }
172
+ },
173
+ async detach() {
174
+ const ctxAtDetach = currentCtx;
175
+ const pending = waitForNextState(actor, ['ready', 'error']);
176
+ actor.send({ type: 'DETACH' });
177
+ const final = await pending;
178
+ if (final === 'error') {
179
+ throw actor.getSnapshot().context.lastError ?? new AnalyticsError('detach_failed', 'detach failed');
180
+ }
181
+ currentCtx = undefined;
182
+ if (ctxAtDetach) {
183
+ log.info('analytics.detached', {
184
+ brand: ctxAtDetach.brand,
185
+ tenantId: ctxAtDetach.tenantId,
186
+ });
187
+ try {
188
+ await clearLastAttach(config.storage, ctxAtDetach.brand);
189
+ }
190
+ catch (cause) {
191
+ log.warn('analytics.persist.clear_last_attach_failed', { cause });
192
+ }
193
+ }
194
+ },
195
+ execute: (sql, params) => db.execute(sql, params),
196
+ stream: (sql, params) => db.stream(sql, params),
197
+ createAppender: (table) => db.createAppender(table),
198
+ get state() {
199
+ return currentState(actor);
200
+ },
201
+ get lastError() {
202
+ return actor.getSnapshot().context.lastError ?? null;
203
+ },
204
+ get catalog() {
205
+ return actor.getSnapshot().context.warehouseSecret;
206
+ },
207
+ subscribe(listener) {
208
+ publicSubscribers.add(listener);
209
+ return () => publicSubscribers.delete(listener);
210
+ },
211
+ async setRetention(days) {
212
+ if (!currentCtx) {
213
+ throw new AnalyticsError('not_attached', 'setRetention requires an attached engine');
214
+ }
215
+ const catalog = actor.getSnapshot().context.warehouseSecret;
216
+ if (!catalog) {
217
+ throw new AnalyticsError('not_attached', 'setRetention: no warehouse catalog');
218
+ }
219
+ await saveRetentionOverride(config.storage, currentCtx, days);
220
+ await sweep(currentCtx, catalog);
221
+ },
222
+ async getLastAttach(brand) {
223
+ return loadLastAttach(config.storage, brand);
224
+ },
225
+ async close() {
226
+ log.info('analytics.closed');
227
+ actor.send({ type: 'CLOSE' });
228
+ internalSub.unsubscribe();
229
+ publicSubscribers.clear();
230
+ await db.close();
231
+ actor.stop();
232
+ },
233
+ };
234
+ return engine;
10
235
  }
11
236
  //# sourceMappingURL=factory.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAA;AAG9C;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,MAAM,IAAI,mBAAmB,CAAC,iBAAiB,CAAC,CAAA;AAClD,CAAC"}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/core/factory.ts"],"names":[],"mappings":"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"}
@@ -1,27 +1,46 @@
1
- import type { AnalyticsState, Insight } from './types';
2
1
  /**
3
- * React hooks over the analytics engine. Stubs in T-02; real wiring via
4
- * `useSyncExternalStore` on `engine.subscribe()` lands in Phase 5 (T-11/12/13).
2
+ * React hooks over the analytics engine.
5
3
  *
6
- * React is an optional peer, so these stubs deliberately do not import
7
- * React they simply throw NotImplementedError. This keeps @mongrov/analytics
8
- * consumable from non-React runtimes (Node CLI, background workers) until
9
- * the hooks are actually implemented.
4
+ * All three hooks resolve the engine via `useAnalyticsEngine()` (context) and
5
+ * subscribe to state transitions with `useSyncExternalStore`. Query hooks
6
+ * (`useTimeseries`, `useInsight`) block until the engine is attached; a
7
+ * detach + re-attach (family switch) refires them via the state subscription.
10
8
  */
11
- export declare function useAnalytics(): {
9
+ import type { AnalyticsState, Insight } from './types';
10
+ export interface UseAnalyticsResult {
12
11
  state: AnalyticsState;
13
12
  isReady: boolean;
14
13
  isAttached: boolean;
15
14
  error: Error | null;
16
- };
17
- export declare function useTimeseries<T = unknown>(_key: string | undefined, _sql: string, _params?: Record<string, unknown>): {
15
+ }
16
+ /**
17
+ * Subscribe to the engine's state machine. Re-renders on every transition.
18
+ * `isReady` is true from `ready` onward (engine opened); `isAttached` is true
19
+ * only in the `attached` state.
20
+ */
21
+ export declare function useAnalytics(): UseAnalyticsResult;
22
+ export interface UseTimeseriesResult<T> {
18
23
  data: T[] | undefined;
19
24
  loading: boolean;
20
25
  error: Error | null;
21
26
  refetch: () => Promise<void>;
22
- };
23
- export declare function useInsight(_id: string): {
27
+ }
28
+ /**
29
+ * Runs `sql` (with `params`) against the engine whenever `key`, `sql`,
30
+ * `params`, or the engine's attached state changes. `key === undefined`
31
+ * disables the query (data stays `undefined`).
32
+ *
33
+ * `refetch()` re-runs the current query; stale results from prior effects are
34
+ * discarded via a per-effect abort flag so out-of-order responses never win.
35
+ */
36
+ export declare function useTimeseries<T = unknown>(key: string | undefined, sql: string, params?: Record<string, unknown>): UseTimeseriesResult<T>;
37
+ export interface UseInsightResult {
24
38
  insight: Insight | undefined;
25
39
  loading: boolean;
26
- };
40
+ }
41
+ /**
42
+ * Reads a single insight row by id. Returns `undefined` if the engine is not
43
+ * attached or the row does not exist.
44
+ */
45
+ export declare function useInsight(id: string): UseInsightResult;
27
46
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/core/hooks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtD;;;;;;;;GAQG;AAGH,wBAAgB,YAAY,IAAI;IAC9B,KAAK,EAAE,cAAc,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB,CAEA;AAGD,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EACvC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC;IACD,IAAI,EAAE,CAAC,EAAE,GAAG,SAAS,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B,CAEA;AAGD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG;IACvC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;CACjB,CAEA"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/core/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAmB,cAAc,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAIvE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,OAAO,CAAA;IACnB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,kBAAkB,CASjD;AAID,MAAM,WAAW,mBAAmB,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,EAAE,GAAG,SAAS,CAAA;IACrB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AA8BD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EACvC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,mBAAmB,CAAC,CAAC,CAAC,CA8ExB;AAID,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAA;IAC5B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,CAgBvD"}