@uptimizr/db 2.0.1 → 2.1.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 (171) hide show
  1. package/AGENTS.md +228 -3
  2. package/README.md +13 -0
  3. package/dist/duckdb/migrations.d.ts.map +1 -1
  4. package/dist/duckdb/migrations.js +169 -0
  5. package/dist/duckdb/migrations.js.map +1 -1
  6. package/dist/duckdb/panelSpecs.d.ts +29 -0
  7. package/dist/duckdb/panelSpecs.d.ts.map +1 -0
  8. package/dist/duckdb/panelSpecs.js +104 -0
  9. package/dist/duckdb/panelSpecs.js.map +1 -0
  10. package/dist/duckdb/projectMetadata.d.ts +43 -0
  11. package/dist/duckdb/projectMetadata.d.ts.map +1 -0
  12. package/dist/duckdb/projectMetadata.js +222 -0
  13. package/dist/duckdb/projectMetadata.js.map +1 -0
  14. package/dist/duckdb/subscriptions.d.ts +45 -0
  15. package/dist/duckdb/subscriptions.d.ts.map +1 -0
  16. package/dist/duckdb/subscriptions.js +202 -0
  17. package/dist/duckdb/subscriptions.js.map +1 -0
  18. package/dist/index.d.ts +18 -4
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +48 -3
  21. package/dist/index.js.map +1 -1
  22. package/dist/insights/anomalies.d.ts +213 -0
  23. package/dist/insights/anomalies.d.ts.map +1 -0
  24. package/dist/insights/anomalies.js +340 -0
  25. package/dist/insights/anomalies.js.map +1 -0
  26. package/dist/insights/baseline.d.ts +51 -0
  27. package/dist/insights/baseline.d.ts.map +1 -0
  28. package/dist/insights/baseline.js +48 -0
  29. package/dist/insights/baseline.js.map +1 -0
  30. package/dist/insights/buckets.d.ts +114 -0
  31. package/dist/insights/buckets.d.ts.map +1 -0
  32. package/dist/insights/buckets.js +220 -0
  33. package/dist/insights/buckets.js.map +1 -0
  34. package/dist/insights/changepoint.d.ts +130 -0
  35. package/dist/insights/changepoint.d.ts.map +1 -0
  36. package/dist/insights/changepoint.js +209 -0
  37. package/dist/insights/changepoint.js.map +1 -0
  38. package/dist/insights/evaluate.d.ts +63 -0
  39. package/dist/insights/evaluate.d.ts.map +1 -0
  40. package/dist/insights/evaluate.js +158 -0
  41. package/dist/insights/evaluate.js.map +1 -0
  42. package/dist/insights/health.d.ts +219 -0
  43. package/dist/insights/health.d.ts.map +1 -0
  44. package/dist/insights/health.js +349 -0
  45. package/dist/insights/health.js.map +1 -0
  46. package/dist/insights/index.d.ts +45 -0
  47. package/dist/insights/index.d.ts.map +1 -0
  48. package/dist/insights/index.js +40 -0
  49. package/dist/insights/index.js.map +1 -0
  50. package/dist/insights/measures.d.ts +222 -0
  51. package/dist/insights/measures.d.ts.map +1 -0
  52. package/dist/insights/measures.js +431 -0
  53. package/dist/insights/measures.js.map +1 -0
  54. package/dist/insights/movers.d.ts +123 -0
  55. package/dist/insights/movers.d.ts.map +1 -0
  56. package/dist/insights/movers.js +166 -0
  57. package/dist/insights/movers.js.map +1 -0
  58. package/dist/insights/significance.d.ts +221 -0
  59. package/dist/insights/significance.d.ts.map +1 -0
  60. package/dist/insights/significance.js +531 -0
  61. package/dist/insights/significance.js.map +1 -0
  62. package/dist/insights/stats.d.ts +104 -0
  63. package/dist/insights/stats.d.ts.map +1 -0
  64. package/dist/insights/stats.js +181 -0
  65. package/dist/insights/stats.js.map +1 -0
  66. package/dist/insights/windows.d.ts +95 -0
  67. package/dist/insights/windows.d.ts.map +1 -0
  68. package/dist/insights/windows.js +97 -0
  69. package/dist/insights/windows.js.map +1 -0
  70. package/dist/metadata.d.ts +178 -1
  71. package/dist/metadata.d.ts.map +1 -1
  72. package/dist/metadata.js +80 -0
  73. package/dist/metadata.js.map +1 -1
  74. package/dist/narrative/build.d.ts +78 -0
  75. package/dist/narrative/build.d.ts.map +1 -0
  76. package/dist/narrative/build.js +437 -0
  77. package/dist/narrative/build.js.map +1 -0
  78. package/dist/narrative/index.d.ts +14 -0
  79. package/dist/narrative/index.d.ts.map +1 -0
  80. package/dist/narrative/index.js +13 -0
  81. package/dist/narrative/index.js.map +1 -0
  82. package/dist/narrative/text.d.ts +25 -0
  83. package/dist/narrative/text.d.ts.map +1 -0
  84. package/dist/narrative/text.js +41 -0
  85. package/dist/narrative/text.js.map +1 -0
  86. package/dist/parity/cases.d.ts +3 -0
  87. package/dist/parity/cases.d.ts.map +1 -1
  88. package/dist/parity/cases.js +387 -7
  89. package/dist/parity/cases.js.map +1 -1
  90. package/dist/parity/compare.d.ts +19 -0
  91. package/dist/parity/compare.d.ts.map +1 -1
  92. package/dist/parity/compare.js +19 -0
  93. package/dist/parity/compare.js.map +1 -1
  94. package/dist/parity/fixtures.d.ts.map +1 -1
  95. package/dist/parity/fixtures.js +25 -0
  96. package/dist/parity/fixtures.js.map +1 -1
  97. package/dist/query/aggregations.d.ts +46 -1
  98. package/dist/query/aggregations.d.ts.map +1 -1
  99. package/dist/query/aggregations.js +86 -0
  100. package/dist/query/aggregations.js.map +1 -1
  101. package/dist/query/clickhouseDialect.d.ts.map +1 -1
  102. package/dist/query/clickhouseDialect.js +5 -1
  103. package/dist/query/clickhouseDialect.js.map +1 -1
  104. package/dist/query/customEventVocabulary.d.ts +46 -0
  105. package/dist/query/customEventVocabulary.d.ts.map +1 -0
  106. package/dist/query/customEventVocabulary.js +127 -0
  107. package/dist/query/customEventVocabulary.js.map +1 -0
  108. package/dist/query/dsl/builders.d.ts +38 -0
  109. package/dist/query/dsl/builders.d.ts.map +1 -0
  110. package/dist/query/dsl/builders.js +35 -0
  111. package/dist/query/dsl/builders.js.map +1 -0
  112. package/dist/query/dsl/compare.d.ts +167 -0
  113. package/dist/query/dsl/compare.d.ts.map +1 -0
  114. package/dist/query/dsl/compare.js +358 -0
  115. package/dist/query/dsl/compare.js.map +1 -0
  116. package/dist/query/dsl/compile.d.ts +89 -0
  117. package/dist/query/dsl/compile.d.ts.map +1 -0
  118. package/dist/query/dsl/compile.js +174 -0
  119. package/dist/query/dsl/compile.js.map +1 -0
  120. package/dist/query/dsl/explain.d.ts +115 -0
  121. package/dist/query/dsl/explain.d.ts.map +1 -0
  122. package/dist/query/dsl/explain.js +143 -0
  123. package/dist/query/dsl/explain.js.map +1 -0
  124. package/dist/query/dsl/generic.d.ts +127 -0
  125. package/dist/query/dsl/generic.d.ts.map +1 -0
  126. package/dist/query/dsl/generic.js +323 -0
  127. package/dist/query/dsl/generic.js.map +1 -0
  128. package/dist/query/dsl/index.d.ts +30 -0
  129. package/dist/query/dsl/index.d.ts.map +1 -0
  130. package/dist/query/dsl/index.js +23 -0
  131. package/dist/query/dsl/index.js.map +1 -0
  132. package/dist/query/dsl/order.d.ts +41 -0
  133. package/dist/query/dsl/order.d.ts.map +1 -0
  134. package/dist/query/dsl/order.js +55 -0
  135. package/dist/query/dsl/order.js.map +1 -0
  136. package/dist/query/dsl/significance.d.ts +130 -0
  137. package/dist/query/dsl/significance.d.ts.map +1 -0
  138. package/dist/query/dsl/significance.js +224 -0
  139. package/dist/query/dsl/significance.js.map +1 -0
  140. package/dist/query/index.d.ts +2 -0
  141. package/dist/query/index.d.ts.map +1 -1
  142. package/dist/query/index.js +8 -0
  143. package/dist/query/index.js.map +1 -1
  144. package/dist/query/summary/index.d.ts +4 -2
  145. package/dist/query/summary/index.d.ts.map +1 -1
  146. package/dist/query/summary/index.js +2 -1
  147. package/dist/query/summary/index.js.map +1 -1
  148. package/dist/query/summary/labels.d.ts +101 -0
  149. package/dist/query/summary/labels.d.ts.map +1 -0
  150. package/dist/query/summary/labels.js +261 -0
  151. package/dist/query/summary/labels.js.map +1 -0
  152. package/dist/query/summary/reading.d.ts.map +1 -1
  153. package/dist/query/summary/reading.js +21 -2
  154. package/dist/query/summary/reading.js.map +1 -1
  155. package/dist/query/summary/schema.d.ts +250 -20
  156. package/dist/query/summary/schema.d.ts.map +1 -1
  157. package/dist/query/summary/schema.js +135 -123
  158. package/dist/query/summary/schema.js.map +1 -1
  159. package/dist/query/summary/summarize.d.ts.map +1 -1
  160. package/dist/query/summary/summarize.js +91 -5
  161. package/dist/query/summary/summarize.js.map +1 -1
  162. package/dist/query/summary/types.d.ts +77 -2
  163. package/dist/query/summary/types.d.ts.map +1 -1
  164. package/dist/query/types.d.ts +47 -1
  165. package/dist/query/types.d.ts.map +1 -1
  166. package/dist/subscriptions.d.ts +208 -0
  167. package/dist/subscriptions.d.ts.map +1 -0
  168. package/dist/subscriptions.js +153 -0
  169. package/dist/subscriptions.js.map +1 -0
  170. package/llms.txt +9 -0
  171. package/package.json +8 -8
@@ -0,0 +1 @@
1
+ {"version":3,"file":"panelSpecs.js","sourceRoot":"","sources":["../../src/duckdb/panelSpecs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type AnnotationRecord, type CreateAnnotationInput, type CreateSavedAnalysisInput, type GlossaryEntryRecord, type ListAnnotationsOptions, type MetadataListOptions, type PutGlossaryEntryInput, type SavedAnalysisRecord } from "../metadata.js";
2
+ import type { DuckdbClient } from "./client.js";
3
+ /**
4
+ * Create one annotation and return the stored row.
5
+ *
6
+ * Refuses with {@link MetadataLimitError} once the project holds
7
+ * {@link METADATA_LIMITS.annotations} rows: metadata is curated notes, not an
8
+ * unbounded write surface, and refusing is more honest than evicting somebody
9
+ * else's note.
10
+ */
11
+ export declare function createAnnotation(client: DuckdbClient, projectId: string, input: CreateAnnotationInput): Promise<AnnotationRecord>;
12
+ /**
13
+ * A project's annotations, newest first.
14
+ *
15
+ * The optional `since`/`until` bounds are an **overlap** filter, not a
16
+ * containment one: an annotation matches when its period intersects the
17
+ * requested window, and a standing note (no period at all) always matches
18
+ * because it is about the project rather than about a moment.
19
+ */
20
+ export declare function listAnnotations(client: DuckdbClient, projectId: string, opts?: ListAnnotationsOptions): Promise<AnnotationRecord[]>;
21
+ /**
22
+ * Delete one annotation of this project. Returns whether a row was removed, so
23
+ * the route can answer 404 for an id that is not there (or belongs to another
24
+ * project — the two are indistinguishable to the caller, deliberately).
25
+ */
26
+ export declare function deleteAnnotation(client: DuckdbClient, projectId: string, id: string): Promise<boolean>;
27
+ /**
28
+ * Upsert one glossary entry and return the stored row. Idempotent: the term is
29
+ * the identity, so re-defining it replaces the meaning instead of accumulating
30
+ * duplicates. The per-project cap applies only when a *new* term is added.
31
+ */
32
+ export declare function putGlossaryEntry(client: DuckdbClient, projectId: string, input: PutGlossaryEntryInput): Promise<GlossaryEntryRecord>;
33
+ /** A project's whole glossary, ordered by term (stable for diffs and prompts). */
34
+ export declare function listGlossary(client: DuckdbClient, projectId: string, opts?: MetadataListOptions): Promise<GlossaryEntryRecord[]>;
35
+ /** Delete one term. Returns whether it existed. */
36
+ export declare function deleteGlossaryEntry(client: DuckdbClient, projectId: string, term: string): Promise<boolean>;
37
+ /** Create one saved analysis and return the stored row. */
38
+ export declare function createSavedAnalysis(client: DuckdbClient, projectId: string, input: CreateSavedAnalysisInput): Promise<SavedAnalysisRecord>;
39
+ /** A project's saved analyses, newest first. */
40
+ export declare function listSavedAnalyses(client: DuckdbClient, projectId: string, opts?: MetadataListOptions): Promise<SavedAnalysisRecord[]>;
41
+ /** Delete one saved analysis. Returns whether it existed. */
42
+ export declare function deleteSavedAnalysis(client: DuckdbClient, projectId: string, id: string): Promise<boolean>;
43
+ //# sourceMappingURL=projectMetadata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectMetadata.d.ts","sourceRoot":"","sources":["../../src/duckdb/projectMetadata.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,gBAAgB,EAErB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAE3B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACzB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiEhD;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAqC3B;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CA6B7B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC,CAYlB;AAkBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,qBAAqB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA8B9B;AAED,kFAAkF;AAClF,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAUhC;AAED,mDAAmD;AACnD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,OAAO,CAAC,CAYlB;AA6BD,2DAA2D;AAC3D,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAAC,mBAAmB,CAAC,CA8B9B;AAED,gDAAgD;AAChD,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,mBAAwB,GAC7B,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAUhC;AAED,6DAA6D;AAC7D,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC,CAYlB"}
@@ -0,0 +1,222 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { METADATA_LIMITS, MetadataLimitError, clampMetadataLimit, parseSavedAnalysisQuery, } from "../metadata.js";
3
+ const ANNOTATION_COLS = `id, project_id, target_kind, target_id,
4
+ epoch_ms(since) AS since_ms, epoch_ms(until) AS until_ms, text,
5
+ author_kind, author_key_id,
6
+ epoch_ms(created_at) AS created_at_ms, epoch_ms(updated_at) AS updated_at_ms`;
7
+ function toDate(ms) {
8
+ return ms == null ? null : new Date(Number(ms));
9
+ }
10
+ function rowToAnnotation(row) {
11
+ return {
12
+ id: row.id,
13
+ projectId: row.project_id,
14
+ targetKind: row.target_kind,
15
+ targetId: row.target_id,
16
+ since: toDate(row.since_ms),
17
+ until: toDate(row.until_ms),
18
+ text: row.text,
19
+ authorKind: row.author_kind,
20
+ authorKeyId: row.author_key_id,
21
+ createdAt: new Date(Number(row.created_at_ms)),
22
+ updatedAt: new Date(Number(row.updated_at_ms)),
23
+ };
24
+ }
25
+ /** `SELECT count(*)` as a plain number, whatever width the driver returns. */
26
+ async function countRows(client, sql, params) {
27
+ const rows = await client.all(sql, params);
28
+ return Number(rows[0]?.n ?? 0);
29
+ }
30
+ /**
31
+ * Create one annotation and return the stored row.
32
+ *
33
+ * Refuses with {@link MetadataLimitError} once the project holds
34
+ * {@link METADATA_LIMITS.annotations} rows: metadata is curated notes, not an
35
+ * unbounded write surface, and refusing is more honest than evicting somebody
36
+ * else's note.
37
+ */
38
+ export async function createAnnotation(client, projectId, input) {
39
+ const count = await countRows(client, `SELECT count(*) AS n FROM annotations WHERE project_id = $projectId`, { projectId });
40
+ if (count >= METADATA_LIMITS.annotations) {
41
+ throw new MetadataLimitError("annotations", METADATA_LIMITS.annotations);
42
+ }
43
+ const { annotation } = input;
44
+ const id = randomUUID();
45
+ await client.run(`INSERT INTO annotations
46
+ (id, project_id, target_kind, target_id, since, until, text,
47
+ author_kind, author_key_id, created_at, updated_at)
48
+ VALUES ($id, $projectId, $targetKind, $targetId,
49
+ CASE WHEN $sinceUs IS NULL THEN NULL ELSE make_timestamp($sinceUs) END,
50
+ CASE WHEN $untilUs IS NULL THEN NULL ELSE make_timestamp($untilUs) END,
51
+ $text, $authorKind, $authorKeyId, now(), now())`, {
52
+ id,
53
+ projectId,
54
+ targetKind: annotation.targetKind,
55
+ targetId: annotation.targetId ?? null,
56
+ sinceUs: annotation.since == null ? null : annotation.since * 1000,
57
+ untilUs: annotation.until == null ? null : annotation.until * 1000,
58
+ text: annotation.text,
59
+ authorKind: input.authorKind,
60
+ authorKeyId: input.authorKeyId,
61
+ });
62
+ const rows = await client.all(`SELECT ${ANNOTATION_COLS} FROM annotations WHERE id = $id`, { id });
63
+ // The row was just inserted on the same connection, so it is always there.
64
+ return rowToAnnotation(rows[0]);
65
+ }
66
+ /**
67
+ * A project's annotations, newest first.
68
+ *
69
+ * The optional `since`/`until` bounds are an **overlap** filter, not a
70
+ * containment one: an annotation matches when its period intersects the
71
+ * requested window, and a standing note (no period at all) always matches
72
+ * because it is about the project rather than about a moment.
73
+ */
74
+ export async function listAnnotations(client, projectId, opts = {}) {
75
+ const limit = clampMetadataLimit(opts.limit);
76
+ const params = { projectId };
77
+ const where = ["project_id = $projectId"];
78
+ if (opts.targetKind != null) {
79
+ where.push("target_kind = $targetKind");
80
+ params.targetKind = opts.targetKind;
81
+ }
82
+ if (opts.targetId != null) {
83
+ where.push("target_id = $targetId");
84
+ params.targetId = opts.targetId;
85
+ }
86
+ if (opts.since != null) {
87
+ where.push("(until IS NULL OR until >= make_timestamp($since))");
88
+ params.since = Math.trunc(opts.since) * 1000;
89
+ }
90
+ if (opts.until != null) {
91
+ where.push("(since IS NULL OR since < make_timestamp($until))");
92
+ params.until = Math.trunc(opts.until) * 1000;
93
+ }
94
+ const rows = await client.all(`SELECT ${ANNOTATION_COLS}
95
+ FROM annotations
96
+ WHERE ${where.join(" AND ")}
97
+ ORDER BY created_at DESC, id DESC
98
+ LIMIT ${limit}`, params);
99
+ return rows.map(rowToAnnotation);
100
+ }
101
+ /**
102
+ * Delete one annotation of this project. Returns whether a row was removed, so
103
+ * the route can answer 404 for an id that is not there (or belongs to another
104
+ * project — the two are indistinguishable to the caller, deliberately).
105
+ */
106
+ export async function deleteAnnotation(client, projectId, id) {
107
+ const before = await countRows(client, `SELECT count(*) AS n FROM annotations WHERE project_id = $projectId AND id = $id`, { projectId, id });
108
+ if (before === 0)
109
+ return false;
110
+ await client.run(`DELETE FROM annotations WHERE project_id = $projectId AND id = $id`, {
111
+ projectId,
112
+ id,
113
+ });
114
+ return true;
115
+ }
116
+ function rowToGlossaryEntry(row) {
117
+ return {
118
+ projectId: row.project_id,
119
+ term: row.term,
120
+ meaning: row.meaning,
121
+ updatedAt: new Date(Number(row.updated_at_ms)),
122
+ };
123
+ }
124
+ /**
125
+ * Upsert one glossary entry and return the stored row. Idempotent: the term is
126
+ * the identity, so re-defining it replaces the meaning instead of accumulating
127
+ * duplicates. The per-project cap applies only when a *new* term is added.
128
+ */
129
+ export async function putGlossaryEntry(client, projectId, input) {
130
+ const { term, meaning } = input.entry;
131
+ const existing = await countRows(client, `SELECT count(*) AS n FROM glossary WHERE project_id = $projectId AND term = $term`, { projectId, term });
132
+ if (existing === 0) {
133
+ const count = await countRows(client, `SELECT count(*) AS n FROM glossary WHERE project_id = $projectId`, { projectId });
134
+ if (count >= METADATA_LIMITS.glossary) {
135
+ throw new MetadataLimitError("glossary", METADATA_LIMITS.glossary);
136
+ }
137
+ }
138
+ await client.run(`INSERT INTO glossary (project_id, term, meaning, updated_at)
139
+ VALUES ($projectId, $term, $meaning, now())
140
+ ON CONFLICT (project_id, term)
141
+ DO UPDATE SET meaning = EXCLUDED.meaning, updated_at = now()`, { projectId, term, meaning });
142
+ const rows = await client.all(`SELECT project_id, term, meaning, epoch_ms(updated_at) AS updated_at_ms
143
+ FROM glossary WHERE project_id = $projectId AND term = $term`, { projectId, term });
144
+ return rowToGlossaryEntry(rows[0]);
145
+ }
146
+ /** A project's whole glossary, ordered by term (stable for diffs and prompts). */
147
+ export async function listGlossary(client, projectId, opts = {}) {
148
+ const limit = clampMetadataLimit(opts.limit, METADATA_LIMITS.glossary, METADATA_LIMITS.glossary);
149
+ const rows = await client.all(`SELECT project_id, term, meaning, epoch_ms(updated_at) AS updated_at_ms
150
+ FROM glossary WHERE project_id = $projectId
151
+ ORDER BY term
152
+ LIMIT ${limit}`, { projectId });
153
+ return rows.map(rowToGlossaryEntry);
154
+ }
155
+ /** Delete one term. Returns whether it existed. */
156
+ export async function deleteGlossaryEntry(client, projectId, term) {
157
+ const before = await countRows(client, `SELECT count(*) AS n FROM glossary WHERE project_id = $projectId AND term = $term`, { projectId, term });
158
+ if (before === 0)
159
+ return false;
160
+ await client.run(`DELETE FROM glossary WHERE project_id = $projectId AND term = $term`, {
161
+ projectId,
162
+ term,
163
+ });
164
+ return true;
165
+ }
166
+ const ANALYSIS_COLS = `id, project_id, title, query, conclusion, author_kind, author_key_id,
167
+ epoch_ms(created_at) AS created_at_ms`;
168
+ function rowToSavedAnalysis(row) {
169
+ return {
170
+ id: row.id,
171
+ projectId: row.project_id,
172
+ title: row.title,
173
+ query: parseSavedAnalysisQuery(row.query),
174
+ conclusion: row.conclusion,
175
+ authorKind: row.author_kind,
176
+ authorKeyId: row.author_key_id,
177
+ createdAt: new Date(Number(row.created_at_ms)),
178
+ };
179
+ }
180
+ /** Create one saved analysis and return the stored row. */
181
+ export async function createSavedAnalysis(client, projectId, input) {
182
+ const count = await countRows(client, `SELECT count(*) AS n FROM saved_analyses WHERE project_id = $projectId`, { projectId });
183
+ if (count >= METADATA_LIMITS.savedAnalyses) {
184
+ throw new MetadataLimitError("savedAnalyses", METADATA_LIMITS.savedAnalyses);
185
+ }
186
+ const { analysis } = input;
187
+ const id = randomUUID();
188
+ await client.run(`INSERT INTO saved_analyses
189
+ (id, project_id, title, query, conclusion, author_kind, author_key_id, created_at)
190
+ VALUES ($id, $projectId, $title, $query, $conclusion, $authorKind, $authorKeyId, now())`, {
191
+ id,
192
+ projectId,
193
+ title: analysis.title,
194
+ query: JSON.stringify(analysis.query),
195
+ conclusion: analysis.conclusion ?? null,
196
+ authorKind: input.authorKind,
197
+ authorKeyId: input.authorKeyId,
198
+ });
199
+ const rows = await client.all(`SELECT ${ANALYSIS_COLS} FROM saved_analyses WHERE id = $id`, { id });
200
+ return rowToSavedAnalysis(rows[0]);
201
+ }
202
+ /** A project's saved analyses, newest first. */
203
+ export async function listSavedAnalyses(client, projectId, opts = {}) {
204
+ const limit = clampMetadataLimit(opts.limit);
205
+ const rows = await client.all(`SELECT ${ANALYSIS_COLS}
206
+ FROM saved_analyses WHERE project_id = $projectId
207
+ ORDER BY created_at DESC, id DESC
208
+ LIMIT ${limit}`, { projectId });
209
+ return rows.map(rowToSavedAnalysis);
210
+ }
211
+ /** Delete one saved analysis. Returns whether it existed. */
212
+ export async function deleteSavedAnalysis(client, projectId, id) {
213
+ const before = await countRows(client, `SELECT count(*) AS n FROM saved_analyses WHERE project_id = $projectId AND id = $id`, { projectId, id });
214
+ if (before === 0)
215
+ return false;
216
+ await client.run(`DELETE FROM saved_analyses WHERE project_id = $projectId AND id = $id`, {
217
+ projectId,
218
+ id,
219
+ });
220
+ return true;
221
+ }
222
+ //# sourceMappingURL=projectMetadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectMetadata.js","sourceRoot":"","sources":["../../src/duckdb/projectMetadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import type { Subscription } from "@uptimizr/schema";
2
+ import { type SubscriptionDeliveryOutcome, type SubscriptionEventInput, type SubscriptionEventQueryOptions, type SubscriptionEventRecord, type SubscriptionRecord } from "../subscriptions.js";
3
+ import type { DuckdbClient } from "./client.js";
4
+ /** A project's subscriptions, oldest first. */
5
+ export declare function listSubscriptions(client: DuckdbClient, projectId: string): Promise<SubscriptionRecord[]>;
6
+ /** Every enabled subscription across every project — the scheduler's resume read. */
7
+ export declare function listEnabledSubscriptions(client: DuckdbClient, limit?: number): Promise<SubscriptionRecord[]>;
8
+ /** One subscription, or `null` when it does not exist in this project. */
9
+ export declare function getSubscription(client: DuckdbClient, projectId: string, id: string): Promise<SubscriptionRecord | null>;
10
+ /**
11
+ * Store a new subscription.
12
+ *
13
+ * The per-project cap is checked and the row inserted inside one transaction on
14
+ * the exclusive connection, so two concurrent creates cannot both read
15
+ * `count = 99` and both insert.
16
+ */
17
+ export declare function createSubscription(client: DuckdbClient, projectId: string, sub: Subscription): Promise<SubscriptionRecord>;
18
+ /** Enable or disable one subscription. `null` when it does not exist. */
19
+ export declare function setSubscriptionEnabled(client: DuckdbClient, projectId: string, id: string, enabled: boolean): Promise<SubscriptionRecord | null>;
20
+ /** Delete a subscription and its firings. `false` when it did not exist. */
21
+ export declare function deleteSubscription(client: DuckdbClient, projectId: string, id: string): Promise<boolean>;
22
+ /**
23
+ * Write back what a delivery attempt learned. Each field is optional, so a
24
+ * successful delivery (`firedAt`, `failures: 0`, `lastError: null`) and a failed
25
+ * one (`lastError`, `failures: n`) use the same call.
26
+ */
27
+ export declare function recordSubscriptionOutcome(client: DuckdbClient, projectId: string, id: string, outcome: SubscriptionDeliveryOutcome): Promise<void>;
28
+ /**
29
+ * The webhook signing secret for one subscription, or `null`.
30
+ *
31
+ * The only path that reads the column. Everything else — the list, the get, the
32
+ * API responses — selects {@link SELECT_COLS}, which deliberately omits it.
33
+ */
34
+ export declare function getWebhookSecret(client: DuckdbClient, projectId: string, id: string): Promise<string | null>;
35
+ /**
36
+ * Append one firing and drop everything past the retained window.
37
+ *
38
+ * The trim is a `DELETE … WHERE "at" < (the Nth newest)` rather than a row-number
39
+ * window, because DuckDB will not delete from a CTE over the same table. Both
40
+ * statements run in one transaction, so the bound is never observed broken.
41
+ */
42
+ export declare function recordSubscriptionEvent(client: DuckdbClient, entry: SubscriptionEventInput): Promise<void>;
43
+ /** A subscription's recent firings, newest first. */
44
+ export declare function listSubscriptionEvents(client: DuckdbClient, projectId: string, id: string, opts?: SubscriptionEventQueryOptions): Promise<SubscriptionEventRecord[]>;
45
+ //# sourceMappingURL=subscriptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../../src/duckdb/subscriptions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAUL,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EAClC,KAAK,uBAAuB,EAE5B,KAAK,kBAAkB,EAExB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA6BhD,+CAA+C;AAC/C,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAQ/B;AAED,qFAAqF;AACrF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,YAAY,EACpB,KAAK,GAAE,MAAkC,GACxC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAS/B;AAED,0EAA0E;AAC1E,wBAAsB,eAAe,CACnC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAQpC;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,kBAAkB,CAAC,CAyC7B;AAED,yEAAyE;AACzE,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAOpC;AAED,4EAA4E;AAC5E,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAED;;;;GAIG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,IAAI,CAAC,CAoBf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxB;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAiCf;AAED,qDAAqD;AACrD,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,6BAAkC,GACvC,OAAO,CAAC,uBAAuB,EAAE,CAAC,CAUpC"}
@@ -0,0 +1,202 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { MAX_ENABLED_SUBSCRIPTIONS, MAX_SUBSCRIPTIONS_PER_PROJECT, MAX_SUBSCRIPTION_EVENTS, SubscriptionLimitError, clampEventLimit, clampSubscriptionError, rowToSubscription, rowToSubscriptionEvent, toSubscriptionColumns, } from "../subscriptions.js";
3
+ /**
4
+ * **Conditional subscriptions** for the DuckDB single-file store (ADR 0051 §6 /
5
+ * sketch §F.1–F.2).
6
+ *
7
+ * Two tables, both plain metadata — no event type is added and
8
+ * `@uptimizr/schema`'s event union is untouched:
9
+ *
10
+ * - `subscriptions` — one row per standing question, keyed by `id` and scoped to
11
+ * a project. The declaration itself lives in a JSON `config` column; the
12
+ * scalars beside it are exactly what the store must filter, order or update.
13
+ * - `subscription_events` — the bounded firing log, last
14
+ * {@link MAX_SUBSCRIPTION_EVENTS} per subscription. The trim runs inside the
15
+ * same transaction as the insert, so the bound holds even if the collector
16
+ * dies between the two.
17
+ *
18
+ * `at` is a DuckDB keyword, so it is double-quoted here and in the migration —
19
+ * the column name matches the other three engines, where it needs no quoting.
20
+ */
21
+ const SELECT_COLS = `id, project_id, name, metric, config, enabled,
22
+ epoch_ms(created_at) AS created_at_ms,
23
+ epoch_ms(updated_at) AS updated_at_ms,
24
+ epoch_ms(last_fired_at) AS last_fired_at_ms,
25
+ last_error, failures`;
26
+ const EVENT_COLS = `id, subscription_id, project_id, epoch_ms("at") AS at_ms, payload`;
27
+ /** A project's subscriptions, oldest first. */
28
+ export async function listSubscriptions(client, projectId) {
29
+ const rows = await client.all(`SELECT ${SELECT_COLS} FROM subscriptions
30
+ WHERE project_id = $projectId
31
+ ORDER BY created_at, id`, { projectId });
32
+ return rows.map(rowToSubscription);
33
+ }
34
+ /** Every enabled subscription across every project — the scheduler's resume read. */
35
+ export async function listEnabledSubscriptions(client, limit = MAX_ENABLED_SUBSCRIPTIONS) {
36
+ const capped = Math.min(Math.max(Math.trunc(limit), 1), MAX_ENABLED_SUBSCRIPTIONS);
37
+ const rows = await client.all(`SELECT ${SELECT_COLS} FROM subscriptions
38
+ WHERE enabled
39
+ ORDER BY created_at, id
40
+ LIMIT ${capped}`);
41
+ return rows.map(rowToSubscription);
42
+ }
43
+ /** One subscription, or `null` when it does not exist in this project. */
44
+ export async function getSubscription(client, projectId, id) {
45
+ const rows = await client.all(`SELECT ${SELECT_COLS} FROM subscriptions
46
+ WHERE project_id = $projectId AND id = $id`, { projectId, id });
47
+ const row = rows[0];
48
+ return row == null ? null : rowToSubscription(row);
49
+ }
50
+ /**
51
+ * Store a new subscription.
52
+ *
53
+ * The per-project cap is checked and the row inserted inside one transaction on
54
+ * the exclusive connection, so two concurrent creates cannot both read
55
+ * `count = 99` and both insert.
56
+ */
57
+ export async function createSubscription(client, projectId, sub) {
58
+ const id = `sub_${randomUUID().replace(/-/g, "").slice(0, 24)}`;
59
+ const cols = toSubscriptionColumns(sub);
60
+ await client.exclusive(async (con) => {
61
+ await con.run("BEGIN TRANSACTION");
62
+ try {
63
+ const reader = await con.runAndReadAll(`SELECT count(*) AS n FROM subscriptions WHERE project_id = $projectId`, { projectId });
64
+ const counted = reader.getRowObjects()[0]?.n;
65
+ if (Number(counted ?? 0) >= MAX_SUBSCRIPTIONS_PER_PROJECT) {
66
+ throw new SubscriptionLimitError();
67
+ }
68
+ await con.run(`INSERT INTO subscriptions
69
+ (id, project_id, name, metric, config, webhook_secret, enabled,
70
+ created_at, updated_at, last_fired_at, last_error, failures)
71
+ VALUES ($id, $projectId, $name, $metric, $config, $webhookSecret, $enabled,
72
+ now(), now(), NULL, NULL, 0)`, {
73
+ id,
74
+ projectId,
75
+ name: cols.name,
76
+ metric: cols.metric,
77
+ config: cols.config,
78
+ webhookSecret: cols.webhookSecret,
79
+ enabled: cols.enabled,
80
+ });
81
+ await con.run("COMMIT");
82
+ }
83
+ catch (err) {
84
+ await con.run("ROLLBACK");
85
+ throw err;
86
+ }
87
+ });
88
+ const stored = await getSubscription(client, projectId, id);
89
+ // The row was just inserted in a committed transaction; a null here would mean
90
+ // the store lost it, which is a fault, not an empty result.
91
+ if (stored == null)
92
+ throw new Error(`subscription ${id} vanished after insert`);
93
+ return stored;
94
+ }
95
+ /** Enable or disable one subscription. `null` when it does not exist. */
96
+ export async function setSubscriptionEnabled(client, projectId, id, enabled) {
97
+ await client.run(`UPDATE subscriptions SET enabled = $enabled, updated_at = now()
98
+ WHERE project_id = $projectId AND id = $id`, { projectId, id, enabled });
99
+ return getSubscription(client, projectId, id);
100
+ }
101
+ /** Delete a subscription and its firings. `false` when it did not exist. */
102
+ export async function deleteSubscription(client, projectId, id) {
103
+ const existing = await getSubscription(client, projectId, id);
104
+ if (existing == null)
105
+ return false;
106
+ await client.exclusive(async (con) => {
107
+ await con.run("BEGIN TRANSACTION");
108
+ try {
109
+ await con.run(`DELETE FROM subscription_events WHERE project_id = $projectId AND subscription_id = $id`, { projectId, id });
110
+ await con.run(`DELETE FROM subscriptions WHERE project_id = $projectId AND id = $id`, {
111
+ projectId,
112
+ id,
113
+ });
114
+ await con.run("COMMIT");
115
+ }
116
+ catch (err) {
117
+ await con.run("ROLLBACK");
118
+ throw err;
119
+ }
120
+ });
121
+ return true;
122
+ }
123
+ /**
124
+ * Write back what a delivery attempt learned. Each field is optional, so a
125
+ * successful delivery (`firedAt`, `failures: 0`, `lastError: null`) and a failed
126
+ * one (`lastError`, `failures: n`) use the same call.
127
+ */
128
+ export async function recordSubscriptionOutcome(client, projectId, id, outcome) {
129
+ const sets = ["updated_at = now()"];
130
+ const params = { projectId, id };
131
+ if (outcome.firedAt != null) {
132
+ sets.push("last_fired_at = make_timestamp($firedAtUs)");
133
+ params.firedAtUs = outcome.firedAt.getTime() * 1000;
134
+ }
135
+ if (outcome.lastError !== undefined) {
136
+ sets.push("last_error = $lastError");
137
+ params.lastError = outcome.lastError == null ? null : clampSubscriptionError(outcome.lastError);
138
+ }
139
+ if (outcome.failures !== undefined) {
140
+ sets.push("failures = CAST($failures AS BIGINT)");
141
+ params.failures = Math.max(0, Math.trunc(outcome.failures));
142
+ }
143
+ await client.run(`UPDATE subscriptions SET ${sets.join(", ")}
144
+ WHERE project_id = $projectId AND id = $id`, params);
145
+ }
146
+ /**
147
+ * The webhook signing secret for one subscription, or `null`.
148
+ *
149
+ * The only path that reads the column. Everything else — the list, the get, the
150
+ * API responses — selects {@link SELECT_COLS}, which deliberately omits it.
151
+ */
152
+ export async function getWebhookSecret(client, projectId, id) {
153
+ const rows = await client.all(`SELECT webhook_secret FROM subscriptions WHERE project_id = $projectId AND id = $id`, { projectId, id });
154
+ const secret = rows[0]?.webhook_secret;
155
+ return secret == null || secret === "" ? null : secret;
156
+ }
157
+ /**
158
+ * Append one firing and drop everything past the retained window.
159
+ *
160
+ * The trim is a `DELETE … WHERE "at" < (the Nth newest)` rather than a row-number
161
+ * window, because DuckDB will not delete from a CTE over the same table. Both
162
+ * statements run in one transaction, so the bound is never observed broken.
163
+ */
164
+ export async function recordSubscriptionEvent(client, entry) {
165
+ const at = entry.at ?? new Date();
166
+ await client.exclusive(async (con) => {
167
+ await con.run("BEGIN TRANSACTION");
168
+ try {
169
+ await con.run(`INSERT INTO subscription_events (id, subscription_id, project_id, "at", payload)
170
+ VALUES ($id, $subscriptionId, $projectId, make_timestamp($atUs), $payload)`, {
171
+ id: randomUUID(),
172
+ subscriptionId: entry.subscriptionId,
173
+ projectId: entry.projectId,
174
+ atUs: at.getTime() * 1000,
175
+ payload: JSON.stringify(entry.payload),
176
+ });
177
+ await con.run(`DELETE FROM subscription_events
178
+ WHERE subscription_id = $subscriptionId
179
+ AND id NOT IN (
180
+ SELECT id FROM subscription_events
181
+ WHERE subscription_id = $subscriptionId
182
+ ORDER BY "at" DESC, id DESC
183
+ LIMIT ${MAX_SUBSCRIPTION_EVENTS}
184
+ )`, { subscriptionId: entry.subscriptionId });
185
+ await con.run("COMMIT");
186
+ }
187
+ catch (err) {
188
+ await con.run("ROLLBACK");
189
+ throw err;
190
+ }
191
+ });
192
+ }
193
+ /** A subscription's recent firings, newest first. */
194
+ export async function listSubscriptionEvents(client, projectId, id, opts = {}) {
195
+ const limit = clampEventLimit(opts.limit);
196
+ const rows = await client.all(`SELECT ${EVENT_COLS} FROM subscription_events
197
+ WHERE project_id = $projectId AND subscription_id = $id
198
+ ORDER BY "at" DESC, id DESC
199
+ LIMIT ${limit}`, { projectId, id });
200
+ return rows.map(rowToSubscriptionEvent);
201
+ }
202
+ //# sourceMappingURL=subscriptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriptions.js","sourceRoot":"","sources":["../../src/duckdb/subscriptions.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -17,6 +17,8 @@ export { toNodeSampleRow, nodeSampleRowToEvent } from "./events.js";
17
17
  export type { NodeSampleRow } from "./events.js";
18
18
  export { hashApiKey, apiKeyPrefix, generateApiKey } from "./metadata.js";
19
19
  export { API_KEY_CAPABILITIES, AUDIT_PARAMS_MAX_LENGTH, AUDIT_TOOL_MAX_LENGTH, DEFAULT_API_KEY_CAPABILITIES, clampAuditTool, hasCapability, isApiKeyCapability, parseApiKeyCapabilities, parseCapabilityList, serializeApiKeyCapabilities, serializeAuditParams, toApiKeyColumns, toApiKeyRateLimit, } from "./metadata.js";
20
+ export { METADATA_LIMITS, MetadataLimitError, clampMetadataLimit, parsePanelSpec, parseSavedAnalysisQuery, } from "./metadata.js";
21
+ export type { AnnotationRecord, AnnotationTargetKind, CreateAnnotationInput, CreatePanelSpecInput, CreateSavedAnalysisInput, GlossaryEntryRecord, ListAnnotationsOptions, MetadataAuthor, MetadataAuthorKind, MetadataListOptions, MetadataTable, PanelSpecRecord, PutGlossaryEntryInput, SavedAnalysisRecord, UpdatePanelSpecInput, } from "./metadata.js";
20
22
  export type { Project, AgentAuditEntry, AgentAuditInput, ApiKeyRecord, ApiKeyCapability, ApiKeyRateLimit, AuditQueryOptions, AuditSurface, CreateApiKeyOptions, ResolvedApiKey, SceneRepresentation, SceneRepresentationKind, SceneRepresentationSummary, SceneRegionRecord, SceneRegionSummary, } from "./metadata.js";
21
23
  export type { Dialect, ParamType, AsofJoinSpec } from "./query/dialect.js";
22
24
  export { duckdbDialect, toDuckdbTimestamp } from "./query/duckdbDialect.js";
@@ -25,11 +27,18 @@ export { postgresDialect, toPostgresTimestamp, POSTGRES_NEAREST_ROW_JOIN, } from
25
27
  export { mssqlDialect, toMssqlTimestamp, toTsql, mssqlVectorElement, MSSQL_NEAREST_ROW_JOIN, MSSQL_BIN_COLLATION, MSSQL_QUANTILE_FUNCTION, } from "./query/mssqlDialect.js";
26
28
  export { renderNativeAsofJoin, renderNearestRowJoin, toPositionalParams, } from "./query/relational.js";
27
29
  export type { NearestRowJoinTokens, PositionalQuery } from "./query/relational.js";
28
- export { buildListSessions, buildPointerHeatmap, buildMeshUvHeatmap, buildWorldHeatmap, buildWorldHeatmapStats, buildGazeHeatmap, buildGazeHeatmapStats, buildCameraDirectionHeatmap, buildViewCoverageHistogram, buildCameraPositionHeatmap, defaultCellSizeForBounds, buildSessionTrajectory, buildAggregateTrajectories, buildClickGazeRay, buildFlowHeatmap, buildTopMeshes, buildTopMeshesBySource, buildTopMeshesTrend, buildMeshDwell, buildMeshBlindSpots, buildMeshInteractionKinds, buildReachability, buildTopInputActions, buildDeadClicks, buildRageClicks, buildHoverDwell, buildCompileStalls, buildResourceSummary, buildCapabilityChanges, buildCameraGestures, buildPerfSummary, buildRenderScaleTruth, buildPerfDistribution, buildFpsHistogram, buildFrameTimePercentiles, buildJankRate, buildPerfChurn, buildPerfByDevice, buildPerfByScene, buildResourcePercentiles, buildStabilityCounts, buildGraphicsDiagnosticCounts, buildErrorHeatmap, buildBoundaryHeatmap, buildBoundaryHeatmapStats, buildBoundaryContacts, buildRenderingTechnology, buildPerfDaily, buildEventsDaily, buildDistinctScenes, buildTimeseries, buildEventTypeCounts, buildSceneCoverage, buildPerfHeatmap, buildCameraDistance, buildNavigationStats, buildBacktrackRatio, buildXrRotationRate, buildXrSourceUsage, buildXrAbandonment, buildXrLocomotionComfort, buildTrackingQuality, buildInteractionsBySource, buildArPlacementTimeToPlace, buildArPlacementAttempts, buildArPlacementSurfaces, buildFunnel, buildSceneRetention, buildLoadBounceFunnel, buildVariantLeaderboard, } from "./query/aggregations.js";
30
+ export { buildListSessions, buildPointerHeatmap, buildMeshUvHeatmap, buildWorldHeatmap, buildWorldHeatmapStats, buildGazeHeatmap, buildGazeHeatmapStats, buildCameraDirectionHeatmap, buildViewCoverageHistogram, buildCameraPositionHeatmap, defaultCellSizeForBounds, buildSessionTrajectory, buildAggregateTrajectories, buildClickGazeRay, buildFlowHeatmap, buildTopMeshes, buildTopMeshesBySource, buildTopMeshesTrend, buildMeshDwell, buildMeshBlindSpots, buildMeshInteractionKinds, buildReachability, buildTopInputActions, buildCustomEventVocabulary, CUSTOM_EVENT_VOCABULARY_LIMIT, CUSTOM_EVENT_VOCABULARY_MAX_LIMIT, CUSTOM_EVENT_VOCABULARY_SAMPLE_ROWS, CUSTOM_EVENT_VOCABULARY_MAX_SAMPLE_ROWS, buildDeadClicks, buildRageClicks, buildHoverDwell, buildCompileStalls, buildResourceSummary, buildCapabilityChanges, buildCameraGestures, buildPerfSummary, buildRenderScaleTruth, buildPerfDistribution, buildFpsHistogram, buildFrameTimePercentiles, buildJankRate, buildPerfChurn, buildPerfByDevice, buildPerfByScene, buildResourcePercentiles, buildStabilityCounts, buildGraphicsDiagnosticCounts, buildErrorHeatmap, buildBoundaryHeatmap, buildBoundaryHeatmapStats, buildBoundaryContacts, buildRenderingTechnology, buildPerfDaily, buildEventsDaily, buildDistinctScenes, buildTimeseries, buildEventTypeCounts, buildSceneCoverage, buildPerfHeatmap, buildCameraDistance, buildNavigationStats, buildBacktrackRatio, buildXrRotationRate, buildXrSourceUsage, buildXrAbandonment, buildXrLocomotionComfort, buildTrackingQuality, buildInteractionsBySource, buildArPlacementTimeToPlace, buildArPlacementAttempts, buildArPlacementSurfaces, buildFunnel, buildSceneRetention, buildLoadBounceFunnel, buildVariantLeaderboard, } from "./query/aggregations.js";
31
+ export { foldCustomEventVocabulary, CUSTOM_EVENT_VOCABULARY_MAX_PROPS, } from "./query/customEventVocabulary.js";
32
+ export type { FoldCustomEventVocabularyOptions } from "./query/customEventVocabulary.js";
29
33
  export { coerceRows, numericColumns, numericColumnsOfMetric } from "./query/coerce.js";
30
34
  export type { CoerceRowsOptions } from "./query/coerce.js";
35
+ export { DEFAULT_ALPHA, ORDER_AFTER_CAP_CAVEAT, applyOrder, compileGenericGroupBy, builderFor, cameraTypeForMode, channelRows, compareRows, comparisonKeys, compileMetric, compileQuery, explainQuery, explainSpec, genericResultColumns, planWarnings, reordersCappedResult, sampleOf, silentChannels, studentTTwoSided, summarizeComparison, toBuilderOptions, twoProportionZ, welchT, wilsonScoreInterval, } from "./query/dsl/index.js";
36
+ export type { AggregationBuilder, ComparisonBasis, ComparisonContext, ComparisonMeta, ComparisonResult, ComparisonRow, ComparisonSide, ExplainParam, ExplainParamType, GenericDeviceFilter, GenericEventPredicate, GenericQueryOptions, MeanSignificance, MetricQueryOptions, MoversSummary, PlanContext, Proportion, ProportionSignificance, QueryPlan, QueryResolution, ResultOrder, Sample, ScoreInterval, Significance, } from "./query/dsl/index.js";
31
37
  export * from "./query/summary/index.js";
32
- export type { QuerySpec, RangeOptions, SceneOptions, SourceOptions, SessionOptions, MeshOptions, RegionOptions, ErrorHeatmapOptions, WorldAabb, CameraModeOptions, TimeseriesOptions, SessionSummaryRow, HeatmapBinRow, WorldHeatmapBinRow, SpatialStatsRow, PositionBinRow, TrajectoryPointRow, AggregateTrajectoryPointRow, DirectionBinRow, ViewCoverageHistogramRow, ClickGazeRayRow, FlowLinkRow, MeshCountRow, MeshDwellRow, MeshBlindSpotRow, MeshInteractionKindRow, ReachabilityBinRow, MeshSourceCountRow, MeshTrendPointRow, InputActionCountRow, DeadClickRow, RageClickRow, HoverDwellRow, CompileStallRow, ArPlacementTimeToPlaceRow, ArPlacementAttemptsRow, ArPlacementSurfaceRow, ResourceSummaryRow, CapabilityChangeRow, CameraGestureRow, PerfSummaryRow, RenderScaleTruthRow, PerfDistributionRow, FpsHistogramRow, FrameTimePercentileRow, JankRateRow, PerfChurnOptions, PerfChurnRow, PerfByDeviceRow, PerfBySceneRow, ResourcePercentileRow, StabilityCountRow, GraphicsDiagnosticCountRow, RenderingTechnologyRow, PerfDailyRow, EventsDailyRow, SceneRow, TimeseriesBucketRow, EventTypeCountRow, CoverageVoxelRow, PerfHeatmapVoxelRow, CameraDistanceBucketRow, NavigationStatsRow, BacktrackRatioRow, XrRotationRateRow, XrSourceUsageRow, XrAbandonmentRow, XrLocomotionRow, BoundaryContactsRow, TrackingQualityRow, InteractionSourceRow, FunnelStepInput, FunnelOptions, FunnelStepResultRow, SceneRetentionOptions, SceneRetentionRow, LoadBounceFunnelOptions, LoadBounceBandRow, VariantLeaderboardOptions, VariantLeaderboardRow, } from "./query/types.js";
38
+ export * from "./insights/index.js";
39
+ export type { QuerySpec, RangeOptions, SceneOptions, SourceOptions, SessionOptions, MeshOptions, RegionOptions, ErrorHeatmapOptions, WorldAabb, CameraModeOptions, TimeseriesOptions, SessionSummaryRow, HeatmapBinRow, WorldHeatmapBinRow, SpatialStatsRow, PositionBinRow, TrajectoryPointRow, AggregateTrajectoryPointRow, DirectionBinRow, ViewCoverageHistogramRow, ClickGazeRayRow, FlowLinkRow, MeshCountRow, MeshDwellRow, MeshBlindSpotRow, MeshInteractionKindRow, ReachabilityBinRow, MeshSourceCountRow, MeshTrendPointRow, InputActionCountRow, CustomEventVocabularyOptions, CustomEventVocabularyRow, CustomEventVocabularySampleRow, CustomPropType, DeadClickRow, RageClickRow, HoverDwellRow, CompileStallRow, ArPlacementTimeToPlaceRow, ArPlacementAttemptsRow, ArPlacementSurfaceRow, ResourceSummaryRow, CapabilityChangeRow, CameraGestureRow, PerfSummaryRow, RenderScaleTruthRow, PerfDistributionRow, FpsHistogramRow, FrameTimePercentileRow, JankRateRow, PerfChurnOptions, PerfChurnRow, PerfByDeviceRow, PerfBySceneRow, ResourcePercentileRow, StabilityCountRow, GraphicsDiagnosticCountRow, RenderingTechnologyRow, PerfDailyRow, EventsDailyRow, SceneRow, TimeseriesBucketRow, EventTypeCountRow, CoverageVoxelRow, PerfHeatmapVoxelRow, CameraDistanceBucketRow, NavigationStatsRow, BacktrackRatioRow, XrRotationRateRow, XrSourceUsageRow, XrAbandonmentRow, XrLocomotionRow, BoundaryContactsRow, TrackingQualityRow, InteractionSourceRow, FunnelStepInput, FunnelOptions, FunnelStepResultRow, SceneRetentionOptions, SceneRetentionRow, LoadBounceFunnelOptions, LoadBounceBandRow, VariantLeaderboardOptions, VariantLeaderboardRow, } from "./query/types.js";
40
+ export { DEFAULT_COOLDOWN, MASKED_SECRET, MAX_ENABLED_SUBSCRIPTIONS, MAX_SUBSCRIPTIONS_PER_PROJECT, MAX_SUBSCRIPTION_EVENTS, SUBSCRIPTION_ERROR_MAX_LENGTH, SubscriptionLimitError, clampEventLimit, clampSubscriptionError, rowToSubscription, rowToSubscriptionEvent, toSubscriptionColumns, } from "./subscriptions.js";
41
+ export type { SubscriptionDeliveryOutcome, SubscriptionEventInput, SubscriptionEventQueryOptions, SubscriptionEventRecord, SubscriptionEventRowLike, SubscriptionRecord, SubscriptionRowLike, SubscriptionStore, } from "./subscriptions.js";
33
42
  export { createDuckdbClient, convertValue } from "./duckdb/client.js";
34
43
  export type { DuckdbClient, DuckdbRow } from "./duckdb/client.js";
35
44
  export { DUCKDB_MIGRATIONS, migrateDuckdb } from "./duckdb/migrations.js";
@@ -39,9 +48,14 @@ export { createProject as duckdbCreateProject, getProject as duckdbGetProject, c
39
48
  export { recordAudit as duckdbRecordAudit, listAudit as duckdbListAudit, pruneAudit as duckdbPruneAudit, } from "./duckdb/audit.js";
40
49
  export { upsertSceneProxy as duckdbUpsertSceneProxy, getSceneRepresentation as duckdbGetSceneRepresentation, listSceneRepresentations as duckdbListSceneRepresentations, } from "./duckdb/sceneRegistry.js";
41
50
  export { putSceneRegions as duckdbPutSceneRegions, getSceneRegions as duckdbGetSceneRegions, listSceneRegions as duckdbListSceneRegions, } from "./duckdb/sceneRegions.js";
51
+ export { createAnnotation as duckdbCreateAnnotation, listAnnotations as duckdbListAnnotations, deleteAnnotation as duckdbDeleteAnnotation, putGlossaryEntry as duckdbPutGlossaryEntry, listGlossary as duckdbListGlossary, deleteGlossaryEntry as duckdbDeleteGlossaryEntry, createSavedAnalysis as duckdbCreateSavedAnalysis, listSavedAnalyses as duckdbListSavedAnalyses, deleteSavedAnalysis as duckdbDeleteSavedAnalysis, } from "./duckdb/projectMetadata.js";
52
+ export { createPanelSpec as duckdbCreatePanelSpec, listPanelSpecs as duckdbListPanelSpecs, updatePanelSpec as duckdbUpdatePanelSpec, deletePanelSpec as duckdbDeletePanelSpec, } from "./duckdb/panelSpecs.js";
53
+ export { listSubscriptions as duckdbListSubscriptions, listEnabledSubscriptions as duckdbListEnabledSubscriptions, getSubscription as duckdbGetSubscription, createSubscription as duckdbCreateSubscription, setSubscriptionEnabled as duckdbSetSubscriptionEnabled, deleteSubscription as duckdbDeleteSubscription, recordSubscriptionOutcome as duckdbRecordSubscriptionOutcome, getWebhookSecret as duckdbGetWebhookSecret, recordSubscriptionEvent as duckdbRecordSubscriptionEvent, listSubscriptionEvents as duckdbListSubscriptionEvents, } from "./duckdb/subscriptions.js";
42
54
  export { PARITY_PROJECT_ID, PARITY_T0, PARITY_RANGE, PARITY_DAY_RANGE, PARITY_DAY, PARITY_EVENTS, } from "./parity/fixtures.js";
43
- export { PARITY_ABS_TOLERANCE, PARITY_REL_TOLERANCE, diffParity, numericColumnsForSpec, } from "./parity/compare.js";
55
+ export { ENGINE_FORMATTED_COLUMNS, PARITY_ABS_TOLERANCE, PARITY_REL_TOLERANCE, diffParity, numericColumnsForSpec, } from "./parity/compare.js";
44
56
  export type { ParityRow, ParityCompareOptions } from "./parity/compare.js";
45
- export { PARITY_CASES } from "./parity/cases.js";
57
+ export { GENERIC_PARITY_CASE_NAMES, PARITY_CASES } from "./parity/cases.js";
46
58
  export type { ParityCase } from "./parity/cases.js";
59
+ export { buildSessionNarrative, renderSessionNarrativeText } from "./narrative/index.js";
60
+ export type { SessionNarrative, SessionNarrativeOptions } from "./narrative/index.js";
47
61
  //# sourceMappingURL=index.d.ts.map