@useatlas/types
Advanced tools
+16
-4
@@ -33,4 +33,7 @@ /** | ||
| * that adding a new role forces a conscious bucket choice (org-assignable | ||
| * vs platform-only). The user.role column may legitimately hold any of | ||
| * these values. | ||
| * vs platform-only). This union spans both role surfaces: as of #2890 the | ||
| * admin-plugin `user.role` column only ever holds `platform_admin` (or a | ||
| * non-admin default), while `owner`/`admin`/`member` live on the org | ||
| * plugin's `member.role`. An effective role (the merge of the two) may be | ||
| * any value in this tuple. | ||
| */ | ||
@@ -41,4 +44,13 @@ export declare const ATLAS_ROLES: readonly ["member", "admin", "owner", "platform_admin"]; | ||
| export type AtlasMode = (typeof ATLAS_MODES)[number]; | ||
| /** Roles that qualify for admin-level features (developer mode, admin console, etc.). */ | ||
| export declare const ADMIN_ROLES: readonly ["admin", "owner", "platform_admin"]; | ||
| /** | ||
| * Roles that qualify for admin-level features (developer mode, admin console, etc.). | ||
| * | ||
| * Single-sourced as of #2890: `owner` and `admin` are the org-plugin | ||
| * `member.role` values (per-workspace), and `platform_admin` is the only | ||
| * remaining admin-plugin `user.role` value (cross-tenant). The redundant | ||
| * system-wide `user.role = "admin"` middle state was dropped — every tenant | ||
| * admin now flows exclusively through `member.role`, so the `admin` here | ||
| * comes from exactly one surface. | ||
| */ | ||
| export declare const ADMIN_ROLES: readonly ["owner", "admin", "platform_admin"]; | ||
| export type AdminRole = (typeof ADMIN_ROLES)[number]; | ||
@@ -45,0 +57,0 @@ /** |
+1
-1
@@ -7,3 +7,3 @@ // src/auth.ts | ||
| var ATLAS_MODES = ["developer", "published"]; | ||
| var ADMIN_ROLES = ["admin", "owner", "platform_admin"]; | ||
| var ADMIN_ROLES = ["owner", "admin", "platform_admin"]; | ||
| export { | ||
@@ -10,0 +10,0 @@ PLATFORM_ROLES, |
@@ -20,2 +20,8 @@ /** Known database types for UI dropdowns and wire format validation. Plugins may register additional dbType values not listed here. */ | ||
| readonly label: "Salesforce"; | ||
| }, { | ||
| readonly value: "elasticsearch"; | ||
| readonly label: "Elasticsearch"; | ||
| }, { | ||
| readonly value: "opensearch"; | ||
| readonly label: "OpenSearch"; | ||
| }]; | ||
@@ -22,0 +28,0 @@ /** Database type — closed union derived from DB_TYPES. The backend's internal DBType in @atlas/api/lib/db/connection.ts is wider to accommodate plugin-registered databases. */ |
@@ -8,3 +8,5 @@ // src/connection.ts | ||
| { value: "duckdb", label: "DuckDB" }, | ||
| { value: "salesforce", label: "Salesforce" } | ||
| { value: "salesforce", label: "Salesforce" }, | ||
| { value: "elasticsearch", label: "Elasticsearch" }, | ||
| { value: "opensearch", label: "OpenSearch" } | ||
| ]; | ||
@@ -11,0 +13,0 @@ var CONNECTION_STATUSES = ["published", "draft", "archived"]; |
+182
-3
| import type { ShareMode } from "./share"; | ||
| export declare const CHART_TYPES: readonly ["bar", "line", "pie", "area", "scatter", "table"]; | ||
| export declare const CHART_TYPES: readonly ["bar", "line", "pie", "area", "scatter", "table", "kpi"]; | ||
| export type ChartType = (typeof CHART_TYPES)[number]; | ||
| /** | ||
| * Formatting applied to a KPI card's big number (#3137). Drives the | ||
| * client-side `formatKpiValue` formatter — `currency`/`percent` add the | ||
| * symbol, `number` adds thousands grouping, `duration` renders seconds as a | ||
| * compact `1h 2m`. Wire-type mirror of `dashboardKpiValueFormatSchema` in | ||
| * `@useatlas/schemas`. | ||
| */ | ||
| export type DashboardKpiValueFormat = "currency" | "number" | "percent" | "duration"; | ||
| /** | ||
| * KPI / scorecard configuration (#3137), present only on a `kpi` chart card. | ||
| * The card's primary `sql` returns the headline metric: `categoryColumn` names | ||
| * the label column and `valueColumns[0]` the number. A single row is the common | ||
| * case (a plain scorecard); a multi-row trend is also valid — the last row is | ||
| * the headline and the value column drives an optional sparkline. `comparisonSql` | ||
| * is an OPTIONAL second single-number query run through the SAME SQL guard | ||
| * (validation + auto-LIMIT + statement timeout) at view time; the UI computes | ||
| * the delta chip from the two values. Both queries bind the dashboard's | ||
| * `:<param>` placeholders identically. | ||
| */ | ||
| export interface DashboardKpiConfig { | ||
| /** How to format the headline number. Defaults to `number` when omitted. */ | ||
| valueFormat?: DashboardKpiValueFormat; | ||
| /** | ||
| * Second single-number query for the delta chip. Runs through the same SQL | ||
| * guard as the primary query — never string-interpolated. Omit for a KPI | ||
| * card with no comparison (big number only). Mutually exclusive with | ||
| * {@link autoComparison}. | ||
| */ | ||
| comparisonSql?: string; | ||
| /** | ||
| * Request an AUTOMATIC period-over-period comparison (#3207) without a | ||
| * hand-written {@link comparisonSql}. When true, the render endpoint re-runs | ||
| * the card's OWN `sql` with the bound date window shifted back exactly one | ||
| * period — a `[date_from, date_to)` window of length N days is compared | ||
| * against the immediately-preceding N-day window — through the same SQL guard | ||
| * (parameterized, auto-LIMIT, timeout). Requires the card to bind the | ||
| * dashboard's `:date_from` / `:date_to` params (or the pair named in | ||
| * {@link comparisonDateParams}). Mutually exclusive with `comparisonSql`. | ||
| */ | ||
| autoComparison?: boolean; | ||
| /** | ||
| * Override the two date parameters the automatic comparison shifts. Defaults | ||
| * to `{ from: "date_from", to: "date_to" }`. Only meaningful with | ||
| * {@link autoComparison}. | ||
| */ | ||
| comparisonDateParams?: { | ||
| from: string; | ||
| to: string; | ||
| }; | ||
| /** Caption under the delta chip, e.g. "vs. last month". */ | ||
| comparisonLabel?: string; | ||
| /** | ||
| * Lower-is-better metric (#3207). Inverts the delta chip's colour so a | ||
| * DECREASE renders green and an INCREASE red — for churn, latency, error | ||
| * rate, cost. The direction arrow still follows the actual change; only the | ||
| * colour flips. Defaults to false (higher-is-better). | ||
| */ | ||
| inverse?: boolean; | ||
| } | ||
| /** | ||
| * Click-to-drilldown target (#3212 — drilldown foundation). When set, clicking | ||
| * a data point (bar / line / area / pie slice, or a table row) on this card | ||
| * sets the named dashboard parameter to the clicked CATEGORY value and refetches | ||
| * every card through the render path (server-side parameterized binding — never | ||
| * string-interpolated). The clicked value is the chart's category-axis value | ||
| * for chart views, or the row's `categoryColumn` cell for the table view. | ||
| * | ||
| * Optional + back-compatible: a card with no `drilldown` is inert on click (no | ||
| * regression to existing view/interaction). The cross-filter UX (filter chips, | ||
| * card-A-filters-B..N) is the follow-up (#3213) — this is the plumbing layer. | ||
| * | ||
| * Wire-type mirror of `dashboardDrilldownConfigSchema` in `@useatlas/schemas`. | ||
| */ | ||
| export interface DashboardDrilldownConfig { | ||
| /** | ||
| * Key of the dashboard parameter a click populates. References a declared | ||
| * {@link DashboardParameter.key} (same lower-snake identifier constraint). | ||
| * A target that names no declared parameter is ignored at click time — the | ||
| * render endpoint binds declared parameters only. | ||
| */ | ||
| targetParam: string; | ||
| } | ||
| /** | ||
| * A goal line / threshold on a chart card (#3208). Rendered as a horizontal | ||
| * Recharts `<ReferenceLine>` on bar / line / area / stacked-bar cards, and as an | ||
| * above/below target callout on a KPI card (the first threshold only — a | ||
| * scorecard shows one target). `value` is a data-space number on the chart's value axis; | ||
| * `color` overrides the default goal-line stroke (a CSS colour — hex, `rgb()`, | ||
| * or a named colour); `label` is an optional caption drawn at the line. | ||
| * | ||
| * Wire-type mirror of `dashboardThresholdSchema` in `@useatlas/schemas`. The | ||
| * count is bounded there (`DASHBOARD_THRESHOLDS_MAX`) so a card can't stack so | ||
| * many goal lines that the chart stops being readable. | ||
| */ | ||
| export interface DashboardThreshold { | ||
| /** Position of the line on the value (Y) axis, in the chart's data space. */ | ||
| value: number; | ||
| /** Stroke colour for the line / callout. Defaults to a theme goal-line | ||
| * colour when omitted. */ | ||
| color?: string; | ||
| /** Optional caption rendered at the line (e.g. "Target", "$1M goal"). */ | ||
| label?: string; | ||
| } | ||
| /** | ||
| * A dated event marker on a time-series card (#3209). Rendered as a VERTICAL | ||
| * Recharts `<ReferenceLine>` on line / area cards — marking when a product | ||
| * launch, campaign start, or other event happened on the time axis. The | ||
| * vertical sibling of {@link DashboardThreshold} (horizontal goal lines, #3208): | ||
| * thresholds position on the value (Y) axis, annotations on the category (X) | ||
| * axis. | ||
| * | ||
| * Unlike thresholds (which live inside {@link DashboardChartConfig}), annotations | ||
| * live in their OWN card-level column (`dashboard_cards.annotations`, migration | ||
| * 0121) and surface as {@link DashboardCard.annotations} — so they survive a | ||
| * chart-type re-detection and belong to the card's time context rather than a | ||
| * specific viz. Bar / pie / KPI / table cards ignore them gracefully. | ||
| * | ||
| * Wire-type mirror of `dashboardCardAnnotationSchema` in `@useatlas/schemas`. | ||
| * The count is bounded there (`DASHBOARD_ANNOTATIONS_MAX`) so a card can't stack | ||
| * so many markers that the chart stops being readable. | ||
| */ | ||
| export interface DashboardCardAnnotation { | ||
| /** | ||
| * Position of the line on the category (X) axis. Matched against the chart's | ||
| * rendered category-axis value (e.g. an ISO date `"2026-01-15"` or a month | ||
| * label `"Jan"`) — the marker draws where that value sits on the axis. A | ||
| * value that matches no data point renders no line (Recharts no-op). | ||
| */ | ||
| x: string; | ||
| /** Caption rendered at the line (e.g. "Product launch", "Campaign start"). */ | ||
| label: string; | ||
| /** Stroke colour for the line. A CSS colour (hex, `rgb()`, or a named colour); | ||
| * defaults to a theme annotation colour when omitted. */ | ||
| color?: string; | ||
| } | ||
| export interface DashboardChartConfig { | ||
@@ -8,2 +143,17 @@ type: ChartType; | ||
| valueColumns: string[]; | ||
| /** Present only when `type === "kpi"` (#3137). */ | ||
| kpi?: DashboardKpiConfig; | ||
| /** | ||
| * Click-to-drilldown target (#3212). Absent → the card is inert on click. | ||
| * See {@link DashboardDrilldownConfig}. | ||
| */ | ||
| drilldown?: DashboardDrilldownConfig; | ||
| /** | ||
| * Goal lines / thresholds (#3208). Each renders as a horizontal reference | ||
| * line on bar / line / area / stacked-bar cards; on a KPI card the first | ||
| * threshold drives an above/below-target callout + colours the headline | ||
| * number. Absent → the card renders exactly as before (back-compat). See | ||
| * {@link DashboardThreshold}. | ||
| */ | ||
| thresholds?: DashboardThreshold[]; | ||
| } | ||
@@ -96,2 +246,9 @@ /** | ||
| content: string | null; | ||
| /** | ||
| * Event annotations (#3209) — dated markers rendered as vertical reference | ||
| * lines on a line / area card. Always present on the wire (empty array when | ||
| * the card has none); a card-level field rather than part of `chartConfig` | ||
| * so it survives a chart-type re-detection. See {@link DashboardCardAnnotation}. | ||
| */ | ||
| annotations: DashboardCardAnnotation[]; | ||
| cachedColumns: string[] | null; | ||
@@ -123,2 +280,5 @@ cachedRows: Record<string, unknown>[] | null; | ||
| chartConfig: DashboardChartConfig; | ||
| /** Event annotations (#3209) carried through the propose/save flow. Omitted → | ||
| * the saved card has no markers. See {@link DashboardCardAnnotation}. */ | ||
| annotations?: DashboardCardAnnotation[]; | ||
| layout?: DashboardCardLayout; | ||
@@ -168,5 +328,24 @@ connectionId?: string; | ||
| } | ||
| /** Wire shape returned by the card render endpoint (mirrors {@link PreviewCardResponse}). */ | ||
| export type RenderCardResponse = PreviewCardResponse; | ||
| /** | ||
| * Result of a KPI card's comparison query (#3137) — the second single-number | ||
| * query run alongside the primary at render time. Carries the raw | ||
| * `{ columns, rows }` (same shape as the primary result) so the client extracts | ||
| * the comparison number with the exact same logic it uses for the headline | ||
| * value. `null` when the card has no `comparisonSql` or the comparison query | ||
| * failed (the delta chip is then simply omitted — a broken comparison never | ||
| * breaks the primary KPI render). | ||
| */ | ||
| export interface KpiComparisonResult { | ||
| columns: string[]; | ||
| rows: Record<string, unknown>[]; | ||
| } | ||
| /** Wire shape returned by the card render endpoint (extends {@link PreviewCardResponse}). */ | ||
| export interface RenderCardResponse extends PreviewCardResponse { | ||
| /** | ||
| * KPI comparison query result (#3137). Present (possibly `null`) only for a | ||
| * `kpi` card; omitted entirely for every other card type. | ||
| */ | ||
| comparison?: KpiComparisonResult | null; | ||
| } | ||
| /** | ||
| * Per-user destructive-op staging (#2365, PRD #2362). | ||
@@ -173,0 +352,0 @@ * |
| // src/dashboard.ts | ||
| var CHART_TYPES = ["bar", "line", "pie", "area", "scatter", "table"]; | ||
| var CHART_TYPES = ["bar", "line", "pie", "area", "scatter", "table", "kpi"]; | ||
| export { | ||
| CHART_TYPES | ||
| }; |
+20
-3
@@ -124,5 +124,7 @@ import type { AuthMode } from "./auth"; | ||
| * | ||
| * `code` is a suggested `ChatErrorCode`. Callers may override it based | ||
| * on context (e.g. ECONNREFUSED in the chat route is `provider_unreachable`, | ||
| * but in startup it's `internal_error`). | ||
| * `code` is the resolved `ChatErrorCode`. A bare connection failure | ||
| * (ECONNREFUSED/ENOTFOUND) is ambiguous — the unreachable host could be the | ||
| * analytics datasource or the LLM provider — so callers pass `subsystem` to | ||
| * `matchError()` and the returned `code`/`message` are already correct for | ||
| * that context (no post-hoc re-labeling needed). | ||
| */ | ||
@@ -134,2 +136,11 @@ export interface MatchedError { | ||
| /** | ||
| * Which dependency a caller was talking to when the error was raised. | ||
| * | ||
| * Disambiguates connection failures whose error text is identical regardless | ||
| * of the unreachable host: `"provider"` → the LLM/AI provider, `"datasource"` | ||
| * → the analytics database. Defaults to `"datasource"` to preserve the | ||
| * historical framing every DB-connectivity caller relies on. | ||
| */ | ||
| export type ErrorSubsystem = "provider" | "datasource"; | ||
| /** | ||
| * Pattern-match common runtime errors into user-safe messages. | ||
@@ -143,5 +154,11 @@ * | ||
| * timeout messages so users know the limit. Defaults to 30. | ||
| * @param opts.subsystem - Which dependency the caller was talking to, used to | ||
| * label connection failures (ECONNREFUSED/ENOTFOUND) correctly. Defaults to | ||
| * `"datasource"`. Provider-facing callers (the chat/demo agent routes) pass | ||
| * `"provider"` so an unreachable LLM host maps to `provider_unreachable` | ||
| * instead of the datasource-framed `internal_error`. | ||
| */ | ||
| export declare function matchError(error: unknown, opts?: { | ||
| timeoutSeconds?: number; | ||
| subsystem?: ErrorSubsystem; | ||
| }): MatchedError | null; | ||
@@ -148,0 +165,0 @@ /** |
+11
-7
@@ -114,2 +114,3 @@ // src/errors.ts | ||
| const msg = error instanceof Error ? error.message : String(error); | ||
| const subsystem = opts?.subsystem ?? "datasource"; | ||
| if (/too many (clients already|connections)|connection pool exhausted|remaining connection slots are reserved/i.test(msg)) { | ||
@@ -121,12 +122,15 @@ return { | ||
| } | ||
| if (/ECONNREFUSED/i.test(msg)) { | ||
| const isConnRefused = /ECONNREFUSED/i.test(msg); | ||
| if (isConnRefused || /ENOTFOUND/i.test(msg)) { | ||
| if (subsystem === "provider") { | ||
| return { | ||
| code: "provider_unreachable", | ||
| message: "Could not reach the LLM provider. Check your network connection and provider status." | ||
| }; | ||
| } | ||
| const host = extractHostFromError(msg); | ||
| return { | ||
| return isConnRefused ? { | ||
| code: "internal_error", | ||
| message: `Database unreachable at ${host} — check that the database is running and accessible` | ||
| }; | ||
| } | ||
| if (/ENOTFOUND/i.test(msg)) { | ||
| const host = extractHostFromError(msg); | ||
| return { | ||
| } : { | ||
| code: "internal_error", | ||
@@ -133,0 +137,0 @@ message: `Could not resolve hostname "${host}" — check your connection URL` |
+16
-10
@@ -7,3 +7,3 @@ // src/auth.ts | ||
| var ATLAS_MODES = ["developer", "published"]; | ||
| var ADMIN_ROLES = ["admin", "owner", "platform_admin"]; | ||
| var ADMIN_ROLES = ["owner", "admin", "platform_admin"]; | ||
@@ -45,3 +45,5 @@ // src/conversation.ts | ||
| { value: "duckdb", label: "DuckDB" }, | ||
| { value: "salesforce", label: "Salesforce" } | ||
| { value: "salesforce", label: "Salesforce" }, | ||
| { value: "elasticsearch", label: "Elasticsearch" }, | ||
| { value: "opensearch", label: "OpenSearch" } | ||
| ]; | ||
@@ -236,2 +238,3 @@ var CONNECTION_STATUSES = ["published", "draft", "archived"]; | ||
| const msg = error instanceof Error ? error.message : String(error); | ||
| const subsystem = opts?.subsystem ?? "datasource"; | ||
| if (/too many (clients already|connections)|connection pool exhausted|remaining connection slots are reserved/i.test(msg)) { | ||
@@ -243,12 +246,15 @@ return { | ||
| } | ||
| if (/ECONNREFUSED/i.test(msg)) { | ||
| const isConnRefused = /ECONNREFUSED/i.test(msg); | ||
| if (isConnRefused || /ENOTFOUND/i.test(msg)) { | ||
| if (subsystem === "provider") { | ||
| return { | ||
| code: "provider_unreachable", | ||
| message: "Could not reach the LLM provider. Check your network connection and provider status." | ||
| }; | ||
| } | ||
| const host = extractHostFromError(msg); | ||
| return { | ||
| return isConnRefused ? { | ||
| code: "internal_error", | ||
| message: `Database unreachable at ${host} — check that the database is running and accessible` | ||
| }; | ||
| } | ||
| if (/ENOTFOUND/i.test(msg)) { | ||
| const host = extractHostFromError(msg); | ||
| return { | ||
| } : { | ||
| code: "internal_error", | ||
@@ -470,3 +476,3 @@ message: `Could not resolve hostname "${host}" — check your connection URL` | ||
| // src/dashboard.ts | ||
| var CHART_TYPES = ["bar", "line", "pie", "area", "scatter", "table"]; | ||
| var CHART_TYPES = ["bar", "line", "pie", "area", "scatter", "table", "kpi"]; | ||
| // src/integrations.ts | ||
@@ -473,0 +479,0 @@ var INTEGRATION_PLATFORMS = [ |
+15
-0
@@ -143,1 +143,16 @@ /** | ||
| } | ||
| /** | ||
| * Result of a single table's Phase-2 enrichment | ||
| * (POST /api/v1/wizard/enrich — issue #3236, semantic-onboarding § D). | ||
| * | ||
| * The enrich endpoint is per-table so the two-phase generate UI can stream | ||
| * results in and upgrade each row in place. `yaml` is the LLM-enriched entity | ||
| * YAML when `enriched` is true, or the unchanged mechanical baseline when the | ||
| * model returned an unusable response (`enriched: false`) — either way it's a | ||
| * valid YAML string safe to save. | ||
| */ | ||
| export interface WizardEnrichResult { | ||
| tableName: string; | ||
| yaml: string; | ||
| enriched: boolean; | ||
| } |
@@ -7,3 +7,17 @@ import type { ActionApprovalMode } from "./action"; | ||
| export declare const DELIVERY_STATUSES: readonly ["pending", "sent", "failed"]; | ||
| export type DeliveryStatus = (typeof DELIVERY_STATUSES)[number]; | ||
| /** | ||
| * `"failed_permanent"` (#3379) marks a run whose delivery failures were ALL | ||
| * permanent (misconfiguration — no email sender, no Slack token, blocked | ||
| * webhook URL) as opposed to transient (network, 5xx). It is appended to the | ||
| * union TYPE-ONLY rather than to the `DELIVERY_STATUSES` value above: this | ||
| * package is consumed from the npm registry by scaffold builds, and a value | ||
| * change would drift between the workspace and the pinned published version | ||
| * (publish-before-ref-bump rule — see CLAUDE.md "Publishing @useatlas/*"). | ||
| * The runtime accept-list that includes it lives in | ||
| * `@atlas/api/lib/scheduled-task-types` (`KNOWN_DELIVERY_STATUSES`), which is | ||
| * scaffold-bound *source* and therefore always in sync. When this package is | ||
| * next published and refs bumped, fold `"failed_permanent"` into | ||
| * `DELIVERY_STATUSES` and collapse this union back to the derived form. | ||
| */ | ||
| export type DeliveryStatus = (typeof DELIVERY_STATUSES)[number] | "failed_permanent"; | ||
| export interface EmailRecipient { | ||
@@ -10,0 +24,0 @@ type: "email"; |
+6
-3
| { | ||
| "name": "@useatlas/types", | ||
| "version": "0.1.13", | ||
| "version": "0.1.17", | ||
| "description": "Shared types for the Atlas text-to-SQL agent", | ||
| "type": "module", | ||
| "scripts": { | ||
| "build": "rm -rf dist && bun build src/index.ts src/auth.ts src/conversation.ts src/connection.ts src/action.ts src/scheduled-task.ts src/errors.ts src/semantic.ts src/share.ts src/billing.ts src/dashboard.ts src/mode.ts src/starter-prompt.ts src/integrations.ts src/email-provider.ts src/mcp.ts src/preferences.ts src/execute-sql.ts src/proactive.ts src/catalog.ts --outdir dist --root src --target node --packages external && bun x tsc -p tsconfig.build.json", | ||
| "build": "rm -rf dist && bun build src/index.ts src/auth.ts src/conversation.ts src/connection.ts src/action.ts src/scheduled-task.ts src/errors.ts src/semantic.ts src/share.ts src/billing.ts src/dashboard.ts src/mode.ts src/starter-prompt.ts src/integrations.ts src/email-provider.ts src/mcp.ts src/preferences.ts src/execute-sql.ts src/proactive.ts src/catalog.ts --outdir dist --root src --target node --packages external && ./node_modules/.bin/tsc -p tsconfig.build.json", | ||
| "prepare": "bun run build" | ||
@@ -132,3 +132,6 @@ }, | ||
| }, | ||
| "license": "MIT" | ||
| "license": "MIT", | ||
| "devDependencies": { | ||
| "typescript": "^6.0.3" | ||
| } | ||
| } |
240046
5.77%5908
4.51%1
Infinity%