@querypanel/node-sdk 1.3.3 → 1.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,28 @@
1
1
  # QueryPanel Node SDK
2
2
 
3
+ `@querypanel/node-sdk` is the headless, server-side SDK for [QueryPanel](https://querypanel.io) embedded analytics. Use it in your Node.js (18+), Bun, or Deno backend to mint RS256 tenant JWTs, sync your Postgres, Amazon Redshift, ClickHouse, or BigQuery schema, and turn natural-language questions into SQL (natural-language-to-SQL / text-to-SQL) for multi-tenant SaaS products. The generated SQL runs against your database through a client function you provide, so database credentials and query results stay on your servers. For chart generation the SDK sends column names and value types, not row values (see `anonymizeResults`).
4
+
5
+ - Docs: [querypanel.io/docs/node-sdk](https://querypanel.io/docs/node-sdk)
6
+ - Tenant isolation: [querypanel.io/docs/tenant-isolation](https://querypanel.io/docs/tenant-isolation)
7
+ - JWT setup: [querypanel.io/docs/jwt](https://querypanel.io/docs/jwt)
8
+
9
+ ## When to use the Node SDK vs the React SDK
10
+
11
+ - **[React SDK](https://www.npmjs.com/package/@querypanel/react-sdk) (headful, start here for React apps):** `@querypanel/react-sdk` renders customer-facing dashboards with an AI assistant and per-tenant customization directly in your React tree, not an iframe ([why that matters](https://querypanel.io/blog/iframe-vs-native-react-embedded-analytics-2026)). It still needs this package on your server to mint the tenant JWT (`createJwt`).
12
+ - **Node SDK (this package, headless):** use it alone when you build your own UI and want `ask()` to return SQL, rows, and a chart spec from your API routes.
13
+
14
+ How it compares to other embedded analytics tools: [querypanel.io/compare](https://querypanel.io/compare).
15
+
16
+ ## Overview
17
+
3
18
  A TypeScript-first client for the QueryPanel Bun/Hono API. Its primary function is to **generate SQL from natural language**, but it also signs JWTs with your service private key, syncs database schemas, enforces tenant isolation, and wraps every public route under `src/routes/` (query, ingest, charts, active charts, and knowledge base).
4
19
 
5
20
  ## Installation
6
21
 
7
22
  ```bash
8
- bun add @querypanel/sdk
23
+ bun add @querypanel/node-sdk
9
24
  # or
10
- npm install @querypanel/sdk
25
+ npm install @querypanel/node-sdk
11
26
  ```
12
27
 
13
28
  > **Runtime:** Node.js 18+, Deno, or Bun. The SDK uses Web Crypto API for JWT signing and the native `fetch` API, making it compatible with modern JavaScript runtimes.
@@ -15,8 +30,9 @@ npm install @querypanel/sdk
15
30
  ## Quickstart
16
31
 
17
32
  ```ts
18
- import { QueryPanelSdkAPI } from "@querypanel/sdk";
33
+ import { QueryPanelSdkAPI } from "@querypanel/node-sdk";
19
34
  import { Pool } from "pg";
35
+ import { createClient } from "@clickhouse/client";
20
36
 
21
37
  const qp = new QueryPanelSdkAPI(
22
38
  process.env.QUERYPANEL_URL!,
@@ -42,21 +58,31 @@ const createPostgresClient = () => async (sql: string, params?: unknown[]) => {
42
58
  }
43
59
  };
44
60
 
45
- // Attach PostgreSQL database using the SDK's PostgresAdapter
46
- // The SDK will automatically handle tenant isolation when tenantFieldName is provided
47
- qp.attachPostgres(
48
- "pg_demo", // a uniq identifier for QueryPanel
49
- createPostgresClientFn(),
61
+ // Attach PostgreSQL database using the SDK's PostgresAdapter
62
+ // The SDK will automatically handle tenant isolation when tenantFieldName is provided
63
+ qp.attachPostgres(
64
+ "pg_demo", // a unique identifier for QueryPanel
65
+ createPostgresClient(),
50
66
  {
51
- database: "pg_demo", // database name
52
- description: "PostgreSQL demo database", // some description that QueryPanel can use
53
- tenantFieldName: "tenant_id", // SDK will automatically filter by tenant_id
54
- enforceTenantIsolation: true, // Ensures all queries include tenant_id filter
55
- allowedTables: ["orders"], // Only sync 'orders' table - 'users' will be excluded
56
- });
67
+ database: "pg_demo", // database name
68
+ description: "PostgreSQL demo database", // some description that QueryPanel can use
69
+ tenantFieldName: "tenant_id", // SDK will automatically filter by tenant_id
70
+ enforceTenantIsolation: true, // Ensures all queries include tenant_id filter
71
+ allowedTables: ["orders"], // Only sync 'orders' table - 'users' will be excluded
72
+ },
73
+ );
74
+
75
+ // Amazon Redshift speaks the Postgres wire protocol, so a pg-based client works.
76
+ // attachRedshift introspects via Redshift's svv_* views and generates Redshift SQL.
77
+ qp.attachRedshift("warehouse", createPostgresClient(), {
78
+ database: "dev",
79
+ tenantFieldName: "tenant_id",
80
+ });
81
+
82
+ const clickhouse = createClient({ url: process.env.CLICKHOUSE_URL });
57
83
 
58
84
  qp.attachClickhouse(
59
- "analytics", // uniq identifier for QueryPanel
85
+ "analytics", // unique identifier for QueryPanel
60
86
  (params) => clickhouse.query(params),
61
87
  {
62
88
  database: "analytics", // database name
@@ -100,6 +126,30 @@ await qp.syncSchema("analytics", {
100
126
 
101
127
  Optionally limit the payload with `tables: ["orders"]`.
102
128
 
129
+ #### Large databases
130
+
131
+ `allowedTables` (and `tables`) accept `schema.*` to include every table in a schema on Postgres/Redshift, e.g. `["crm.*", "public.orders"]`. On ClickHouse and BigQuery the adapter is bound to one database/dataset, so `*` or `<database>.*` means "all tables".
132
+
133
+ Browse the catalog cheaply (no columns; not restricted by `allowedTables`) to build a table picker:
134
+
135
+ ```ts
136
+ await qp.listSchemas("warehouse"); // [{ schema: "crm", tableCount: 12 }, ...]
137
+ await qp.listTables("warehouse", { schema: "crm", search: "user", limit: 100 });
138
+ // [{ schema: "crm", name: "users", type: "table" }, ...] (default limit 500, max 5000)
139
+ ```
140
+
141
+ For schemas too large for a single request, `syncSchemaInBatches` uploads tables in batches (≤ `maxBatchDocs` docs, default 1000, and ≤ `maxBatchBytes`, default 2 MB) and embeds them batch by batch:
142
+
143
+ ```ts
144
+ await qp.syncSchemaInBatches("warehouse", {
145
+ tenantId: "tenant_123",
146
+ maxColumns: 50_000, // throw SchemaTooLargeError before uploading if exceeded
147
+ onProgress: (e) => console.log(e.phase, e),
148
+ });
149
+ ```
150
+
151
+ To spread the work across requests (e.g. serverless time limits), call `stageSchemaIngest` (introspect + upload + commit), then `embedSchemaIngestBatch(sessionId, i, ...)` for each batch, then `finalizeSchemaIngest(sessionId, ...)`.
152
+
103
153
  ### Custom system prompt (`systemPrompt`)
104
154
 
105
155
  Pass `systemPrompt` on `ask()` to inject extra instructions for SQL generation. Use it when a **client** needs policies QueryPanel does not know about — retention windows, a max date range, excluded event types, and similar product rules. Look up that client’s config in your backend and pass it on every question.
@@ -143,7 +193,7 @@ const response = await qp.ask("Show order volume by week", {
143
193
  If your UI only supports a subset of chart kinds (for example no area or scatter), set **`supportedChartTypes`** on the SDK constructor or on each `ask` / `modifyChart` call (`line`, `bar`, `column`, `area`, `scatter`, `pie`).
144
194
 
145
195
  ```ts
146
- import { QueryPanelSdkAPI, ALL_VIZ_CHART_TYPES, type ChartType } from "@querypanel/sdk";
196
+ import { QueryPanelSdkAPI, ALL_VIZ_CHART_TYPES, type ChartType } from "@querypanel/node-sdk";
147
197
 
148
198
  const allowed: ChartType[] = ["line", "bar", "column", "pie"];
149
199
 
@@ -512,7 +562,7 @@ The API accepts up to **100** UUIDs per request. Examples: `?ids=a&ids=b` or `?i
512
562
  The SDK is fully compatible with Deno (including Supabase Edge Functions) thanks to its use of Web Crypto API for JWT signing. No additional configuration needed:
513
563
 
514
564
  ```ts
515
- import { QueryPanelSdkAPI } from "https://esm.sh/@querypanel/sdk";
565
+ import { QueryPanelSdkAPI } from "https://esm.sh/@querypanel/node-sdk";
516
566
 
517
567
  const qp = new QueryPanelSdkAPI(
518
568
  Deno.env.get("QUERYPANEL_URL")!,
@@ -526,10 +576,12 @@ const response = await qp.ask("Show top products", {
526
576
  });
527
577
  ```
528
578
 
579
+ BigQuery is attached the same way with `attachBigQuery(name, clientFn, options)`. Any other engine can be plugged in with `attachDatabase(name, adapter)` and your own `DatabaseAdapter` implementation.
580
+
529
581
  ## Building locally
530
582
 
531
583
  ```bash
532
- cd node-sdk
584
+ cd admin/packages/node-sdk
533
585
  bun install
534
586
  bun run build
535
587
  ```
@@ -571,4 +623,4 @@ Without `maxRetry`, execution errors throw immediately (default behavior).
571
623
 
572
624
  ## Need more?
573
625
 
574
- Open an issue or extend `node-sdk/src/index.ts`—every route lives in one file. Pull requests are welcome for additional adapters, richer param coercion, or convenience helpers around charts/annotations.
626
+ Open an issue or extend the SDK: the public class is in `src/index.ts` and each API route has a module under `src/routes/`. Pull requests are welcome for additional adapters, richer param coercion, or convenience helpers around charts/annotations.