@oxy-hq/sdk 1.0.0 → 2.0.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.
package/dist/index.d.mts CHANGED
@@ -1,967 +1,534 @@
1
1
 
2
- import * as duckdb from "@duckdb/duckdb-wasm";
3
- import React, { ReactNode } from "react";
2
+ import * as React from "react";
4
3
 
5
- //#region src/config.d.ts
6
- /**
7
- * Configuration for the Oxy SDK
8
- */
9
- interface OxyConfig {
4
+ //#region src/customer-app/manifest.d.ts
5
+ /** Wire shape of `oxy-app.json` (v2 only). */
6
+ interface OxyAppManifest {
7
+ /** Must be 2. v1 manifests are no longer supported. */
8
+ schemaVersion: 2;
10
9
  /**
11
- * Base URL of the Oxy API (e.g., 'https://api.oxy.tech' or 'http://localhost:3000')
10
+ * Optional display name. The admin "Link existing" dialog prefills
11
+ * its Name field from this. Omit to let oxy fall back to the
12
+ * folder basename.
12
13
  */
13
- baseUrl: string;
14
+ name?: string;
14
15
  /**
15
- * API key for authentication (optional for local development)
16
+ * URL slug. **Required.** The canonical source of truth — the
17
+ * dialog locks the slug field to this value, and
18
+ * `OXY_APP_BASE_PATH=/customer-apps/<org>/<slug>/` baked into the
19
+ * build must match.
16
20
  */
17
- apiKey?: string;
21
+ slug: string;
18
22
  /**
19
- * Project ID (UUID)
23
+ * Optional org slug. Prefills the dialog's org picker; operator
24
+ * can still override. Carries no security weight — the actual
25
+ * access check is on the linked row.
20
26
  */
21
- projectId: string;
27
+ orgSlug?: string;
22
28
  /**
23
- * Optional branch name (defaults to current branch if not specified)
29
+ * Optional project (workspace) uuid the bundle expects to read
30
+ * from. Used by `useQuery` to construct the
31
+ * `/api/projects/:id/query` URL.
24
32
  */
25
- branch?: string;
33
+ projectId?: string;
34
+ }
35
+ /**
36
+ * Manifest + runtime-injected identity needed to call oxy. Callers
37
+ * should treat this as the only source of truth for "which org/app
38
+ * does this bundle belong to."
39
+ */
40
+ interface ResolvedCustomerAppManifest {
41
+ manifest: OxyAppManifest;
26
42
  /**
27
- * Request timeout in milliseconds (default: 30000)
43
+ * Always an empty array for v2 manifests. Kept for API compatibility;
44
+ * callers that previously iterated product names should switch to
45
+ * explicit `useQuery` calls.
46
+ * @deprecated Will be removed in a future version.
28
47
  */
29
- timeout?: number;
48
+ productNames: string[];
49
+ /** Org slug injected by oxy. */
50
+ orgSlug: string;
51
+ /** App slug injected by oxy. */
52
+ appSlug: string;
30
53
  /**
31
- * Parent window origin for postMessage authentication (iframe scenarios)
32
- * Required when using postMessage auth for security.
33
- * Example: 'https://app.example.com'
34
- * Use '*' only in development!
54
+ * The oxy server's API base URL. Empty string when oxy serves the
55
+ * bundle itself (same-origin, the common case); a full URL only
56
+ * when the bundle is running under a dev server proxy.
35
57
  */
36
- parentOrigin?: string;
58
+ apiBaseUrl: string;
59
+ /** App UUID; informational. */
60
+ appId?: string;
37
61
  /**
38
- * Disable automatic postMessage authentication even if in iframe
39
- * Set to true if you want to provide API key manually in iframe context
62
+ * Project (workspace) UUID. Injection (`window.__OXY_APP__.projectId`)
63
+ * wins over the manifest's `projectId` field the admin row is
64
+ * authoritative. Manifest `projectId` is a dev-time hint used only
65
+ * when running without a server. Used by `useQuery` to construct the
66
+ * `/api/projects/:id/query` URL.
40
67
  */
41
- disableAutoAuth?: boolean;
42
- }
43
- /**
44
- * Creates an Oxy configuration from environment variables
45
- *
46
- * Environment variables:
47
- * - OXY_URL: Base URL of the Oxy API
48
- * - OXY_API_KEY: API key for authentication
49
- * - OXY_PROJECT_ID: Project ID (UUID)
50
- * - OXY_BRANCH: (Optional) Branch name
51
- *
52
- * @param overrides - Optional configuration overrides
53
- * @returns OxyConfig object
54
- * @throws Error if required environment variables are missing
55
- */
56
- declare function createConfig(overrides?: Partial<OxyConfig>): OxyConfig;
57
- /**
58
- * Creates an Oxy configuration asynchronously with support for postMessage authentication
59
- *
60
- * This is the recommended method for iframe scenarios where authentication
61
- * needs to be obtained from the parent window via postMessage.
62
- *
63
- * When running in an iframe without an API key, this function will:
64
- * 1. Detect the iframe context
65
- * 2. Send an authentication request to the parent window
66
- * 3. Wait for the parent to respond with credentials
67
- * 4. Return the configured client
68
- *
69
- * Environment variables (fallback):
70
- * - OXY_URL: Base URL of the Oxy API
71
- * - OXY_API_KEY: API key for authentication
72
- * - OXY_PROJECT_ID: Project ID (UUID)
73
- * - OXY_BRANCH: (Optional) Branch name
74
- *
75
- * @param overrides - Optional configuration overrides
76
- * @returns Promise resolving to OxyConfig object
77
- * @throws Error if required configuration is missing
78
- * @throws PostMessageAuthTimeoutError if parent doesn't respond
79
- *
80
- * @example
81
- * ```typescript
82
- * // Automatic iframe detection and authentication
83
- * const config = await createConfigAsync({
84
- * parentOrigin: 'https://app.example.com',
85
- * projectId: 'my-project-id',
86
- * baseUrl: 'https://api.oxy.tech'
87
- * });
88
- * ```
89
- */
90
- declare function createConfigAsync(overrides?: Partial<OxyConfig>): Promise<OxyConfig>;
91
- //#endregion
92
- //#region src/types.d.ts
93
- /**
94
- * Represents an app item in the project
95
- */
96
- interface AppItem {
97
- name: string;
98
- path: string;
99
- }
100
- /**
101
- * Reference to a data file (usually parquet)
102
- */
103
- interface FileReference {
104
- file_path: string;
105
- }
106
- /**
107
- * Table data structure for in-memory tables
108
- * (used when data is fetched and parsed)
109
- */
110
- interface TableData {
111
- columns: string[];
112
- rows: unknown[][];
113
- total_rows?: number;
114
- }
115
- type DataContainer = Record<string, FileReference>;
116
- /**
117
- * Response from app data endpoints
118
- */
119
- interface AppDataResponse {
120
- data: DataContainer | null;
121
- error: string | null;
122
- }
123
- /**
124
- * Display with potential error
125
- */
126
- interface DisplayWithError {
127
- display?: DisplayData;
128
- error?: string;
129
- }
130
- /**
131
- * Display data structure
132
- */
133
- interface DisplayData {
134
- type: string;
135
- content: unknown;
136
- }
137
- /**
138
- * Response from get displays endpoint
139
- */
140
- interface GetDisplaysResponse {
141
- displays: DisplayWithError[];
142
- }
143
- /**
144
- * PostMessage authentication protocol types
145
- */
146
- /**
147
- * Request message sent from iframe to parent window
148
- */
149
- interface OxyAuthRequestMessage {
150
- type: "OXY_AUTH_REQUEST";
151
- version: "1.0";
152
- timestamp: number;
153
- requestId: string;
154
- }
155
- /**
156
- * Response message sent from parent window to iframe
157
- */
158
- interface OxyAuthResponseMessage {
159
- type: "OXY_AUTH_RESPONSE";
160
- version: "1.0";
161
- requestId: string;
162
- apiKey?: string;
163
68
  projectId?: string;
164
- baseUrl?: string;
165
69
  }
166
- /**
167
- * Options for postMessage authentication
168
- */
169
- interface PostMessageAuthOptions {
170
- /** Required parent window origin for security (e.g., 'https://app.example.com'). Use '*' only in development! */
171
- parentOrigin?: string;
172
- /** Timeout in milliseconds (default: 5000) */
173
- timeout?: number;
174
- /** Number of retry attempts (default: 0) */
175
- retries?: number;
70
+ interface LoadManifestOptions {
71
+ /**
72
+ * Override the URL the manifest is fetched from. Default:
73
+ * `<injected_base>/oxy-app.json` or `/oxy-app.json`.
74
+ * Useful for non-Next bundlers set explicitly to wherever your
75
+ * bundler emits static assets.
76
+ */
77
+ manifestUrl?: string;
176
78
  }
177
79
  /**
178
- * Result from successful postMessage authentication
80
+ * Load + validate the manifest. Cached after the first call so callers
81
+ * can invoke this from every component without coordinating.
179
82
  */
180
- interface PostMessageAuthResult {
181
- apiKey?: string;
182
- projectId?: string;
183
- baseUrl?: string;
184
- source: "postmessage";
83
+ declare function loadCustomerAppManifest(options?: LoadManifestOptions): Promise<ResolvedCustomerAppManifest>;
84
+ /** For tests: reset the cache between runs. */
85
+ declare function _resetCustomerAppManifestCacheForTest(): void;
86
+ //#endregion
87
+ //#region src/customer-app/debug.d.ts
88
+ /** Untyped at the boundary — keep it loose so server-side schema
89
+ * additions don't break older bundles. Stable enough for inspection
90
+ * but not a contract clients should depend on field-by-field. */
91
+ interface CustomerAppDebugSnapshot {
92
+ org_slug: string;
93
+ app_slug: string;
94
+ app: {
95
+ id: string;
96
+ slug: string;
97
+ name: string;
98
+ status: string;
99
+ source_type: string;
100
+ project_id: string;
101
+ branch: string;
102
+ };
103
+ bundle_dir: string | null;
104
+ bundle_dir_exists: boolean;
105
+ /** Raw parsed manifest from the server — kept loose so schema additions don't break older bundles. */
106
+ manifest: Record<string, unknown> | null;
107
+ manifest_error: string | null;
108
+ products: Array<{
109
+ name: string;
110
+ producer: string;
111
+ }>;
185
112
  }
186
113
  /**
187
- * Custom error classes for postMessage authentication
188
- */
189
- /**
190
- * Error thrown when postMessage authentication times out
114
+ * Fetch the server-side diagnostic snapshot for this bundle. Pair with
115
+ * `loadCustomerAppManifest()` — pass its result here. Logs the
116
+ * snapshot through the SDK logger so it appears in the bundle's
117
+ * console at info level.
191
118
  */
192
- declare class PostMessageAuthTimeoutError extends Error {
193
- constructor(timeout: number);
119
+ declare function getCustomerAppDebug(resolved: ResolvedCustomerAppManifest): Promise<CustomerAppDebugSnapshot>;
120
+ //#endregion
121
+ //#region src/customer-app/errors.d.ts
122
+ interface CustomerAppErrorReport {
123
+ title: string;
124
+ message: string;
125
+ hint: string;
126
+ docs?: string;
194
127
  }
128
+ /** Interpret a thrown error as a structured report for UI display. */
129
+ declare function interpretCustomerAppError(err: unknown): CustomerAppErrorReport;
130
+ //#endregion
131
+ //#region src/customer-app/inject.d.ts
195
132
  /**
196
- * Error thrown when authentication response comes from unauthorized origin
133
+ * Shape of `window.__OXY_APP__` written by oxy at serve time.
134
+ * Consumed by `loadCustomerAppManifest` as the authoritative identity
135
+ * source (overrides any hints in `oxy-app.json`).
197
136
  */
198
- declare class PostMessageAuthInvalidOriginError extends Error {
199
- constructor(expected: string, actual: string);
137
+ interface OxyInjectedAppConfig {
138
+ appId: string;
139
+ slug: string;
140
+ orgId: string;
141
+ orgSlug: string;
142
+ projectId: string;
143
+ branch: string;
144
+ /** Empty string means same-origin (the default for v2). */
145
+ apiBaseUrl: string;
200
146
  }
201
- /**
202
- * Error thrown when postMessage authentication is attempted outside iframe context
203
- */
204
- declare class PostMessageAuthNotInIframeError extends Error {
205
- constructor();
147
+ declare global {
148
+ interface Window {
149
+ __OXY_APP__?: OxyInjectedAppConfig;
150
+ }
206
151
  }
207
152
  /**
208
- * Error thrown when authentication response is malformed or invalid
153
+ * Read the runtime app-config oxy injected at serve time. Returns
154
+ * `undefined` outside the browser or when the global isn't set
155
+ * (`pnpm dev` against a non-oxy server, etc. — manifest hints are
156
+ * the fallback).
209
157
  */
210
- declare class PostMessageAuthInvalidResponseError extends Error {
211
- constructor(reason: string);
158
+ declare function readInjectedAppConfig(): OxyInjectedAppConfig | undefined;
159
+ //#endregion
160
+ //#region src/customer-app/logger.d.ts
161
+ type OxyAppLogLevel = "debug" | "info" | "warn" | "error";
162
+ interface OxyAppLogger {
163
+ log(level: OxyAppLogLevel, msg: string, ctx?: Record<string, unknown>): void;
212
164
  }
165
+ /** Replace the global logger. Pass `null` to silence everything. */
166
+ declare function setOxyAppLogger(logger: OxyAppLogger | null): void;
167
+ /** Used by the SDK internals; not part of the public surface. */
168
+ declare function getOxyAppLogger(): OxyAppLogger;
213
169
  //#endregion
214
- //#region src/client.d.ts
170
+ //#region src/customer-app/react.d.ts
215
171
  /**
216
- * Oxy API Client for interacting with Oxy data
172
+ * Credentialed fetch wrapper stored in context so `useQuery` can share
173
+ * the same request mechanism without coupling it to the global `fetch`.
174
+ *
175
+ * Sends `credentials: "include"` so the session cookie rides along when
176
+ * the app is served by oxy (in-workspace / admin preview) — that cookie
177
+ * authorizes data calls. For local dev (cross-origin), the
178
+ * `@oxy-hq/vite-plugin` proxy attaches the developer's token. Bundles may
179
+ * override the fetcher for test/proxy environments.
217
180
  */
218
- declare class OxyClient {
219
- private config;
220
- constructor(config: OxyConfig);
181
+ type AppFetcher = typeof fetch;
182
+ interface OxyAppProviderProps {
183
+ /** Optional manifest load options. Same shape as `loadCustomerAppManifest`. */
184
+ manifestOptions?: LoadManifestOptions;
221
185
  /**
222
- * Creates an OxyClient instance asynchronously with support for postMessage authentication
223
- *
224
- * This is the recommended method when using the SDK in an iframe that needs to
225
- * obtain authentication from the parent window via postMessage.
226
- *
227
- * @param config - Optional configuration overrides
228
- * @returns Promise resolving to OxyClient instance
229
- * @throws Error if required configuration is missing
230
- * @throws PostMessageAuthTimeoutError if parent doesn't respond
231
- *
232
- * @example
233
- * ```typescript
234
- * // In an iframe - automatic postMessage auth
235
- * const client = await OxyClient.create({
236
- * parentOrigin: 'https://app.example.com',
237
- * projectId: 'my-project-id',
238
- * baseUrl: 'https://api.oxy.tech'
239
- * });
240
- *
241
- * // Use the client normally
242
- * const apps = await client.listApps();
243
- * ```
244
- */
245
- static create(config?: Partial<OxyConfig>): Promise<OxyClient>;
246
- /**
247
- * Encodes a file path to base64 for use in API URLs.
248
- * Handles Unicode characters (e.g., emojis) properly in both Node.js and browser.
249
- */
250
- private encodePathBase64;
251
- /**
252
- * Makes an authenticated HTTP request to the Oxy API
253
- */
254
- private request;
255
- /**
256
- * Builds query parameters including optional branch
257
- */
258
- private buildQueryParams;
259
- /**
260
- * Lists all apps in the project
261
- *
262
- * @returns Array of app items
263
- *
264
- * @example
265
- * ```typescript
266
- * const apps = await client.listApps();
267
- * console.log('Available apps:', apps);
268
- * ```
269
- */
270
- listApps(): Promise<AppItem[]>;
271
- /**
272
- * Gets data for a specific app
273
- *
274
- * @param appPath - Relative path to the app file (e.g., 'my-app.app.yml')
275
- * @returns App data response
276
- *
277
- * @example
278
- * ```typescript
279
- * const data = await client.getAppData('dashboard.app.yml');
280
- * if (data.error) {
281
- * console.error('Error:', data.error);
282
- * } else {
283
- * console.log('App data:', data.data);
284
- * }
285
- * ```
286
- */
287
- getAppData(appPath: string): Promise<AppDataResponse>;
288
- /**
289
- * Runs an app and returns fresh data (bypasses cache)
290
- *
291
- * @param appPath - Relative path to the app file
292
- * @returns App data response
293
- *
294
- * @example
295
- * ```typescript
296
- * const data = await client.runApp('dashboard.app.yml');
297
- * console.log('Fresh app data:', data.data);
298
- * ```
186
+ * Rendered while the manifest is loading. Defaults to nothing; pass a
187
+ * spinner if you want one.
299
188
  */
300
- runApp(appPath: string): Promise<AppDataResponse>;
189
+ fallback?: React.ReactNode;
301
190
  /**
302
- * Gets display configurations for an app
303
- *
304
- * @param appPath - Relative path to the app file
305
- * @returns Display configurations with potential errors
306
- *
307
- * @example
308
- * ```typescript
309
- * const displays = await client.getDisplays('dashboard.app.yml');
310
- * displays.displays.forEach(d => {
311
- * if (d.error) {
312
- * console.error('Display error:', d.error);
313
- * } else {
314
- * console.log('Display:', d.display);
315
- * }
316
- * });
317
- * ```
318
- */
319
- getDisplays(appPath: string): Promise<GetDisplaysResponse>;
320
- /**
321
- * Gets a file from the app state directory (e.g., generated charts, images)
322
- *
323
- * This is useful for retrieving generated assets like charts, images, or other
324
- * files produced by app workflows and stored in the state directory.
325
- *
326
- * @param filePath - Relative path to the file in state directory
327
- * @returns Blob containing the file data
328
- *
329
- * @example
330
- * ```typescript
331
- * // Get a generated chart image
332
- * const blob = await client.getFile('charts/sales-chart.png');
333
- * const imageUrl = URL.createObjectURL(blob);
334
- *
335
- * // Use in an img tag
336
- * document.querySelector('img').src = imageUrl;
337
- * ```
338
- *
339
- * @example
340
- * ```typescript
341
- * // Download a file
342
- * const blob = await client.getFile('exports/data.csv');
343
- * const a = document.createElement('a');
344
- * a.href = URL.createObjectURL(blob);
345
- * a.download = 'data.csv';
346
- * a.click();
347
- * ```
348
- */
349
- getFile(filePath: string): Promise<Blob>;
350
- /**
351
- * Gets a file URL for direct browser access
352
- *
353
- * This returns a URL that can be used directly in img tags, fetch calls, etc.
354
- * The URL includes authentication via query parameters.
355
- *
356
- * @param filePath - Relative path to the file in state directory
357
- * @returns Full URL to the file
358
- *
359
- * @example
360
- * ```typescript
361
- * const imageUrl = client.getFileUrl('charts/sales-chart.png');
362
- *
363
- * // Use directly in img tag (in environments where query-based auth is supported)
364
- * document.querySelector('img').src = imageUrl;
365
- * ```
191
+ * Rendered on manifest load failure. Receives the structured error
192
+ * report so the bundle can show its own branded error card. Defaults
193
+ * to a minimal text-only fallback (better than a blank page).
366
194
  */
367
- getFileUrl(filePath: string): string;
195
+ errorFallback?: (err: CustomerAppErrorReport) => React.ReactNode;
368
196
  /**
369
- * Fetches a parquet file and parses it into table data
370
- *
371
- * @param filePath - Relative path to the parquet file
372
- * @param limit - Maximum number of rows to return (default: 100)
373
- * @returns TableData with columns and rows
374
- *
375
- * @example
376
- * ```typescript
377
- * const tableData = await client.getTableData('data/sales.parquet', 50);
378
- * console.log(tableData.columns);
379
- * console.log(tableData.rows);
380
- * console.log(`Total rows: ${tableData.total_rows}`);
381
- * ```
197
+ * Override the fetch implementation used by all hooks (`useQuery`).
198
+ * Useful for test environments or proxy setups. Defaults to a wrapper
199
+ * that sets `credentials: "include"` on every request.
382
200
  */
383
- getTableData(filePath: string, limit?: number): Promise<TableData>;
201
+ fetcher?: AppFetcher;
202
+ children: React.ReactNode;
384
203
  }
385
- //#endregion
386
- //#region src/parquet.d.ts
387
204
  /**
388
- * Initialize DuckDB-WASM instance
389
- */
390
- declare function initializeDuckDB(): Promise<duckdb.AsyncDuckDB>;
205
+ * Top-level provider. Loads the manifest once on mount; children only
206
+ * render after the manifest is ready (or the error fallback fires).
207
+ */
208
+ declare function OxyAppProvider(props: OxyAppProviderProps): React.JSX.Element;
209
+ /**
210
+ * Error thrown by all customer-app hooks when an API call returns a
211
+ * non-2xx response. Carries the structured `code` + `hint` the server
212
+ * emits so bundle UIs can render an actionable message instead of
213
+ * "404: { ...json... }".
214
+ *
215
+ * The server contract is documented in
216
+ * `crates/app/src/server/api/projects/agent_ask.rs` and
217
+ * `procedure_run.rs` — both emit `{ message, code?, hint? }` as JSON.
218
+ * Hooks that previously wrapped the raw text in `new Error()` now
219
+ * throw this type instead.
220
+ */
221
+ declare class OxyApiError extends Error {
222
+ readonly status: number;
223
+ readonly code: string | null;
224
+ readonly hint: string | null;
225
+ constructor(opts: {
226
+ status: number;
227
+ message: string;
228
+ code?: string | null;
229
+ hint?: string | null;
230
+ });
231
+ }
391
232
  /**
392
- * Query result interface
233
+ * Read the resolved manifest from context. Throws if called outside
234
+ * `<OxyAppProvider>` — that's a programmer error worth surfacing
235
+ * loudly, not silently swallowing.
393
236
  */
394
- interface QueryResult {
237
+ declare function useResolvedManifest(): ResolvedCustomerAppManifest;
238
+ interface UseQueryInput {
239
+ sql: string;
240
+ database?: string;
241
+ }
242
+ interface UseQueryOpts {
243
+ params?: Record<string, string | number | boolean | null | undefined>;
244
+ /** Set false to skip the request (e.g., waiting on user input). */
245
+ enabled?: boolean;
246
+ }
247
+ interface UseQueryResult<Row = Record<string, unknown>> {
248
+ rows: Row[];
395
249
  columns: string[];
396
- rows: unknown[][];
397
- rowCount: number;
250
+ loading: boolean;
251
+ error: Error | null;
252
+ refetch: () => void;
398
253
  }
399
254
  /**
400
- * ParquetReader provides methods to read and query Parquet files.
401
- * Supports registering multiple Parquet files with different table names.
402
- */
403
- declare class ParquetReader {
404
- private tableMap;
405
- constructor();
406
- /**
407
- * Generate a unique internal table name to prevent conflicts
408
- */
409
- private generateInternalTableName;
410
- /**
411
- * Register a Parquet file from a Blob with a specific table name
412
- *
413
- * @param blob - Parquet file as Blob
414
- * @param tableName - Name to use for the table in queries (required)
415
- *
416
- * @example
417
- * ```typescript
418
- * const blob = await client.getFile('data/sales.parquet');
419
- * const reader = new ParquetReader();
420
- * await reader.registerParquet(blob, 'sales');
421
- * ```
422
- *
423
- * @example
424
- * ```typescript
425
- * // Register multiple files
426
- * const reader = new ParquetReader();
427
- * await reader.registerParquet(salesBlob, 'sales');
428
- * await reader.registerParquet(customersBlob, 'customers');
429
- * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');
430
- * ```
431
- */
432
- registerParquet(blob: Blob, tableName: string): Promise<void>;
433
- /**
434
- * Register multiple Parquet files at once
435
- *
436
- * @param files - Array of objects containing blob and tableName
437
- *
438
- * @example
439
- * ```typescript
440
- * const reader = new ParquetReader();
441
- * await reader.registerMultipleParquet([
442
- * { blob: salesBlob, tableName: 'sales' },
443
- * { blob: customersBlob, tableName: 'customers' },
444
- * { blob: productsBlob, tableName: 'products' }
445
- * ]);
446
- * const result = await reader.query('SELECT * FROM sales JOIN customers ON sales.customer_id = customers.id');
447
- * ```
448
- */
449
- registerMultipleParquet(files: Array<{
450
- blob: Blob;
451
- tableName: string;
452
- }>): Promise<void>;
453
- /**
454
- * Execute a SQL query against the registered Parquet data
455
- *
456
- * @param sql - SQL query string
457
- * @returns Query result with columns and rows
458
- *
459
- * @example
460
- * ```typescript
461
- * const result = await reader.query('SELECT * FROM sales LIMIT 10');
462
- * console.log(result.columns);
463
- * console.log(result.rows);
464
- * ```
465
- *
466
- * @example
467
- * ```typescript
468
- * // Query multiple tables
469
- * await reader.registerParquet(salesBlob, 'sales');
470
- * await reader.registerParquet(customersBlob, 'customers');
471
- * const result = await reader.query(`
472
- * SELECT s.*, c.name
473
- * FROM sales s
474
- * JOIN customers c ON s.customer_id = c.id
475
- * `);
476
- * ```
477
- */
478
- query(sql: string): Promise<QueryResult>;
479
- /**
480
- * Get all data from a registered table
481
- *
482
- * @param tableName - Name of the table to query
483
- * @param limit - Maximum number of rows to return (default: all)
484
- * @returns Query result
485
- *
486
- * @example
487
- * ```typescript
488
- * const allData = await reader.getAll('sales');
489
- * const first100 = await reader.getAll('sales', 100);
490
- * ```
491
- */
492
- getAll(tableName: string, limit?: number): Promise<QueryResult>;
493
- /**
494
- * Get table schema information
495
- *
496
- * @param tableName - Name of the table to describe
497
- * @returns Schema information
498
- *
499
- * @example
500
- * ```typescript
501
- * const schema = await reader.getSchema('sales');
502
- * console.log(schema.columns); // ['id', 'name', 'sales']
503
- * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]
504
- * ```
505
- */
506
- getSchema(tableName: string): Promise<QueryResult>;
507
- /**
508
- * Get row count for a table
509
- *
510
- * @param tableName - Name of the table to count
511
- * @returns Number of rows in the table
512
- *
513
- * @example
514
- * ```typescript
515
- * const count = await reader.count('sales');
516
- * console.log(`Total rows: ${count}`);
517
- * ```
518
- */
519
- count(tableName: string): Promise<number>;
255
+ * Execute an ad-hoc SQL query against the project linked to this
256
+ * customer app. The query is specified inline by the caller; no
257
+ * manifest declaration is involved.
258
+ *
259
+ * Re-runs whenever `input` or enabled `params` change. Use the
260
+ * `enabled` option to defer the first fetch until required data is
261
+ * available (e.g. a user-supplied filter value).
262
+ */
263
+ declare function useQuery<Row = Record<string, unknown>>(input: UseQueryInput, opts?: UseQueryOpts): UseQueryResult<Row>;
264
+ /** Scalar filter operators (compared against a single value). */
265
+ type SemanticScalarOp = "eq" | "neq" | "lt" | "lte" | "gt" | "gte";
266
+ /** Array filter operators (compared against a list). */
267
+ type SemanticArrayOp = "in" | "not_in";
268
+ /** Date-range filter operators. `from` / `to` accept ISO date strings. */
269
+ type SemanticDateRangeOp = "in_date_range" | "not_in_date_range";
270
+ /**
271
+ * One filter clause. The `field` references a dimension name within
272
+ * the topic; the `op` discriminator picks which other fields are
273
+ * meaningful. Wire shape matches `agentic_semantic::SemanticFilter`
274
+ * verbatim the bundle's request body is forwarded to airlayer's
275
+ * compiler with no translation.
276
+ */
277
+ type SemanticFilter = {
278
+ field: string;
279
+ op: SemanticScalarOp;
280
+ value: string | number | boolean | null;
281
+ } | {
282
+ field: string;
283
+ op: SemanticArrayOp;
284
+ values: Array<string | number | boolean | null>;
285
+ } | {
286
+ field: string;
287
+ op: SemanticDateRangeOp;
288
+ from: string;
289
+ to: string;
290
+ };
291
+ /** Time dimensions with optional granularity (e.g. "day", "month"). */
292
+ interface SemanticTimeDimension {
293
+ dimension: string;
294
+ granularity?: "day" | "week" | "month" | "quarter" | "year";
295
+ }
296
+ interface UseSemanticQueryInput {
297
+ topic: string;
298
+ dimensions?: string[];
299
+ measures?: string[];
300
+ time_dimensions?: SemanticTimeDimension[];
301
+ filters?: SemanticFilter[];
302
+ limit?: number;
303
+ }
304
+ interface UseSemanticQueryOpts {
305
+ /** Set false to skip the request (e.g., waiting on user input). */
306
+ enabled?: boolean;
520
307
  /**
521
- * Close and cleanup all registered resources
308
+ * When true, the response includes the compiled SQL string at
309
+ * `sql`. Off by default — production callers shouldn't bake the
310
+ * warehouse SQL into their UI. Bundle authors flip this on while
311
+ * debugging.
522
312
  */
523
- close(): Promise<void>;
313
+ debug?: boolean;
314
+ }
315
+ interface UseSemanticQueryResult<Row = Record<string, unknown>> {
316
+ rows: Row[];
317
+ columns: string[];
318
+ /** True when the result was capped at the server's row limit. */
319
+ truncated: boolean;
320
+ /** Compiled SQL — populated only when `opts.debug` is true. */
321
+ sql: string | null;
322
+ loading: boolean;
323
+ error: Error | null;
324
+ refetch: () => void;
524
325
  }
525
326
  /**
526
- * Helper function to quickly read a Parquet blob and execute a query
527
- *
528
- * @param blob - Parquet file as Blob
529
- * @param tableName - Name to use for the table in queries (default: 'data')
530
- * @param sql - SQL query to execute (optional, defaults to SELECT * FROM tableName)
531
- * @returns Query result
532
- *
533
- * @example
534
- * ```typescript
535
- * const blob = await client.getFile('data/sales.parquet');
536
- * const result = await queryParquet(blob, 'sales', 'SELECT product, SUM(amount) as total FROM sales GROUP BY product');
537
- * console.log(result);
538
- * ```
539
- */
540
- declare function queryParquet(blob: Blob, tableName?: string, sql?: string): Promise<QueryResult>;
541
- /**
542
- * Helper function to read Parquet file and get all data
543
- *
544
- * @param blob - Parquet file as Blob
545
- * @param tableName - Name to use for the table (default: 'data')
546
- * @param limit - Maximum number of rows (optional)
547
- * @returns Query result
548
- *
549
- * @example
550
- * ```typescript
551
- * const blob = await client.getFile('data/sales.parquet');
552
- * const data = await readParquet(blob, 'sales', 1000);
553
- * console.log(`Loaded ${data.rowCount} rows`);
554
- * ```
555
- */
556
- declare function readParquet(blob: Blob, tableName?: string, limit?: number): Promise<QueryResult>;
557
- //#endregion
558
- //#region src/sdk.d.ts
559
- /**
560
- * OxySDK provides a unified interface for fetching data from Oxy and querying it with SQL.
561
- * It combines OxyClient (for API calls) and ParquetReader (for SQL queries) into a single,
562
- * easy-to-use interface.
563
- *
564
- * @example
565
- * ```typescript
566
- * // Create SDK instance
567
- * const sdk = new OxySDK({ apiKey: 'your-key', projectId: 'your-project' });
568
- *
569
- * // Load a parquet file and query it
570
- * await sdk.loadFile('data/sales.parquet', 'sales');
571
- * const result = await sdk.query('SELECT * FROM sales WHERE amount > 1000');
572
- * console.log(result.rows);
327
+ * Run a semantic-layer query against the project's `.view.yml` /
328
+ * `.topic.yml` definitions. The server compiles to SQL and executes
329
+ * through the same connector path as `useQuery`, so result shape
330
+ * matches.
573
331
  *
574
- * // Clean up when done
575
- * await sdk.close();
576
- * ```
332
+ * Re-runs whenever the input shape changes (deep-compared via JSON).
333
+ * Use `opts.enabled = false` to defer the first fetch until required
334
+ * inputs (e.g. a user-picked filter value) are available.
577
335
  */
578
- declare class OxySDK {
579
- private client;
580
- private reader;
581
- constructor(config: OxyConfig);
582
- /**
583
- * Creates an OxySDK instance asynchronously with support for postMessage authentication
584
- *
585
- * @param config - Optional configuration overrides
586
- * @returns Promise resolving to OxySDK instance
587
- *
588
- * @example
589
- * ```typescript
590
- * // In an iframe - automatic postMessage auth
591
- * const sdk = await OxySDK.create({
592
- * parentOrigin: 'https://app.example.com',
593
- * projectId: 'my-project-id'
594
- * });
595
- * ```
596
- */
597
- static create(config?: Partial<OxyConfig>): Promise<OxySDK>;
598
- /**
599
- * Load a Parquet file from Oxy and register it for SQL queries
600
- *
601
- * @param filePath - Path to the parquet file in the app state directory
602
- * @param tableName - Name to use for the table in SQL queries
603
- *
604
- * @example
605
- * ```typescript
606
- * await sdk.loadFile('data/sales.parquet', 'sales');
607
- * await sdk.loadFile('data/customers.parquet', 'customers');
608
- *
609
- * const result = await sdk.query(`
610
- * SELECT s.*, c.name
611
- * FROM sales s
612
- * JOIN customers c ON s.customer_id = c.id
613
- * `);
614
- * ```
615
- */
616
- loadFile(filePath: string, tableName: string): Promise<void>;
617
- /**
618
- * Load multiple Parquet files at once
619
- *
620
- * @param files - Array of file paths and table names
621
- *
622
- * @example
623
- * ```typescript
624
- * await sdk.loadFiles([
625
- * { filePath: 'data/sales.parquet', tableName: 'sales' },
626
- * { filePath: 'data/customers.parquet', tableName: 'customers' },
627
- * { filePath: 'data/products.parquet', tableName: 'products' }
628
- * ]);
629
- *
630
- * const result = await sdk.query('SELECT * FROM sales');
631
- * ```
632
- */
633
- loadFiles(files: Array<{
634
- filePath: string;
635
- tableName: string;
636
- }>): Promise<void>;
637
- /**
638
- * Load all data from an app's data container
639
- *
640
- * This fetches the app's data and registers all parquet files using their container keys as table names.
641
- *
642
- * @param appPath - Path to the app file
643
- * @returns DataContainer with file references
644
- *
645
- * @example
646
- * ```typescript
647
- * // If app has data: { sales: { file_path: 'data/sales.parquet' } }
648
- * const data = await sdk.loadAppData('dashboard.app.yml');
649
- * // Now you can query the 'sales' table
650
- * const result = await sdk.query('SELECT * FROM sales LIMIT 10');
651
- * ```
652
- */
653
- loadAppData(appPath: string): Promise<DataContainer | null>;
654
- /**
655
- * Execute a SQL query against loaded data
656
- *
657
- * @param sql - SQL query to execute
658
- * @returns Query result with columns and rows
659
- *
660
- * @example
661
- * ```typescript
662
- * await sdk.loadFile('data/sales.parquet', 'sales');
663
- *
664
- * const result = await sdk.query('SELECT product, SUM(amount) as total FROM sales GROUP BY product');
665
- * console.log(result.columns); // ['product', 'total']
666
- * console.log(result.rows); // [['Product A', 1000], ['Product B', 2000]]
667
- * console.log(result.rowCount); // 2
668
- * ```
669
- */
670
- query(sql: string): Promise<QueryResult>;
671
- /**
672
- * Get all data from a loaded table
673
- *
674
- * @param tableName - Name of the table
675
- * @param limit - Maximum number of rows (optional)
676
- * @returns Query result
677
- *
678
- * @example
679
- * ```typescript
680
- * await sdk.loadFile('data/sales.parquet', 'sales');
681
- * const allData = await sdk.getAll('sales');
682
- * const first100 = await sdk.getAll('sales', 100);
683
- * ```
684
- */
685
- getAll(tableName: string, limit?: number): Promise<QueryResult>;
686
- /**
687
- * Get schema information for a loaded table
688
- *
689
- * @param tableName - Name of the table
690
- * @returns Schema information
691
- *
692
- * @example
693
- * ```typescript
694
- * await sdk.loadFile('data/sales.parquet', 'sales');
695
- * const schema = await sdk.getSchema('sales');
696
- * console.log(schema.columns); // ['column_name', 'column_type', ...]
697
- * console.log(schema.rows); // [['id', 'INTEGER'], ['name', 'VARCHAR'], ...]
698
- * ```
699
- */
700
- getSchema(tableName: string): Promise<QueryResult>;
701
- /**
702
- * Get row count for a loaded table
703
- *
704
- * @param tableName - Name of the table
705
- * @returns Number of rows
706
- *
707
- * @example
708
- * ```typescript
709
- * await sdk.loadFile('data/sales.parquet', 'sales');
710
- * const count = await sdk.count('sales');
711
- * console.log(`Total rows: ${count}`);
712
- * ```
713
- */
714
- count(tableName: string): Promise<number>;
715
- /**
716
- * Get direct access to the underlying OxyClient
717
- *
718
- * Useful for advanced operations like listing apps, getting displays, etc.
719
- *
720
- * @returns The OxyClient instance
721
- *
722
- * @example
723
- * ```typescript
724
- * const apps = await sdk.getClient().listApps();
725
- * const displays = await sdk.getClient().getDisplays('my-app.app.yml');
726
- * ```
727
- */
728
- getClient(): OxyClient;
729
- /**
730
- * Get direct access to the underlying ParquetReader
731
- *
732
- * Useful for advanced operations like registering blobs directly.
733
- *
734
- * @returns The ParquetReader instance
735
- *
736
- * @example
737
- * ```typescript
738
- * const myBlob = new Blob([parquetData]);
739
- * await sdk.getReader().registerParquet(myBlob, 'mydata');
740
- * ```
741
- */
742
- getReader(): ParquetReader;
743
- /**
744
- * Close and cleanup all resources
745
- *
746
- * This clears all loaded data and releases resources. Call this when you're done with the SDK.
747
- *
748
- * @example
749
- * ```typescript
750
- * const sdk = new OxySDK({ apiKey: 'key', projectId: 'project' });
751
- * await sdk.loadFile('data/sales.parquet', 'sales');
752
- * const result = await sdk.query('SELECT * FROM sales');
753
- * await sdk.close(); // Clean up
754
- * ```
755
- */
756
- close(): Promise<void>;
336
+ declare function useSemanticQuery<Row = Record<string, unknown>>(input: UseSemanticQueryInput, opts?: UseSemanticQueryOpts): UseSemanticQueryResult<Row>;
337
+ type ProcedureRunState = "idle" | "running" | "done" | "failed";
338
+ interface UseProcedureRunInput {
339
+ procedureId: string;
757
340
  }
758
- //#endregion
759
- //#region src/react.d.ts
760
- /**
761
- * Context value provided to child components
762
- */
763
- interface OxyContextValue {
764
- sdk: OxySDK | null;
765
- isLoading: boolean;
341
+ interface UseProcedureRunOpts {
342
+ /** Polling cadence in ms while running. Default: 2000 (procedures
343
+ * are typically minutes-long; tighter cadence wastes resources). */
344
+ pollIntervalMs?: number;
345
+ pollIntervalBackoffMs?: number;
346
+ /** Max client-side wait in ms. Default: 1 hour. */
347
+ maxWaitMs?: number;
348
+ }
349
+ interface ProcedureProgress {
350
+ step: string;
351
+ percent: number;
352
+ }
353
+ interface ProcedureResult {
354
+ summary: string;
355
+ outputs: Record<string, unknown>;
356
+ }
357
+ interface UseProcedureRunResult {
358
+ state: ProcedureRunState;
359
+ run: (params?: Record<string, unknown>) => void;
360
+ /** Cancel the in-flight run. Idempotent. */
361
+ cancel: () => void;
362
+ progress: ProcedureProgress | null;
363
+ result: ProcedureResult | null;
766
364
  error: Error | null;
767
365
  }
768
366
  /**
769
- * Props for OxyProvider component
770
- */
771
- interface OxyProviderProps {
772
- children: ReactNode;
773
- config?: Partial<OxyConfig>;
774
- /**
775
- * If true, uses async initialization (supports postMessage auth in iframes)
776
- * If false, uses synchronous initialization with provided config
777
- */
778
- useAsync?: boolean;
779
- /**
780
- * Optional app path to load initial app data from upon initialization
781
- */
782
- appPath?: string;
783
- /**
784
- * Optional initial files to preload into the SDK as a mapping of filename to content
785
- */
786
- files?: Record<string, string>;
787
- /**
788
- * Called when SDK is successfully initialized
789
- */
790
- onReady?: (sdk: OxySDK) => void;
791
- /**
792
- * Called when initialization fails
793
- */
794
- onError?: (error: Error) => void;
795
- /**
796
- * Rendered while the SDK is initializing. Defaults to rendering children (no loading UI).
797
- */
798
- loadingFallback?: ReactNode;
799
- /**
800
- * Rendered when SDK initialization fails. Receives the error.
801
- * Defaults to rendering children (no error UI).
802
- */
803
- errorFallback?: ReactNode | ((error: Error) => ReactNode);
367
+ * @beta Long-running procedure runner. The wire shape works end-to-end
368
+ * (start → poll → cancel; runs survive server restarts via the
369
+ * `customer_app_procedure_runs` table) but a few rough edges remain
370
+ * before this is GA-ready:
371
+ *
372
+ * - Hint surfaces for `procedure_not_found` are correct but the
373
+ * procedure-discovery rules (which directories the server scans,
374
+ * case-sensitivity, branch awareness) aren't documented yet.
375
+ * - Cancellation across multi-instance deployments leans on a
376
+ * periodic sweep — fine for now, but expect occasional latency
377
+ * between `cancel()` and the run actually stopping.
378
+ * - Progress reporting requires the procedure to emit named
379
+ * steps; bundles get `progress: null` until that lands.
380
+ *
381
+ * The API surface is stable; expect breaking changes only if the
382
+ * server-side `customer_app_procedure_runs` schema changes.
383
+ */
384
+ declare function useProcedureRun(input: UseProcedureRunInput, opts?: UseProcedureRunOpts): UseProcedureRunResult;
385
+ type AgentRunState = "idle" | "running" | "needs_clarification" | "done" | "failed";
386
+ interface AgentRunEvent {
387
+ type: string;
388
+ data: unknown;
389
+ }
390
+ /** SQL produced and (optionally) executed by the agent. Extracted
391
+ * from `query_generated` / `query_executed` / `verified_sql` /
392
+ * `semantic_query` / `omni_query` SSE events so callers don't have
393
+ * to scan the raw event stream themselves. */
394
+ interface AgentSqlArtifact {
395
+ type: "sql";
396
+ /** Stable id derived from the SSE event id so React keys stay
397
+ * stable across re-renders / reconnects. */
398
+ id: string;
399
+ /** Originating UI event type preserves the verified/semantic/etc.
400
+ * flavor in case the renderer wants a badge. */
401
+ source: string;
402
+ sql: string;
403
+ /** Present when the SQL was executed and rows came back. */
404
+ results?: {
405
+ columns: string[];
406
+ rows: unknown[][];
407
+ rowCount: number;
408
+ };
409
+ /** Present when execution failed — surface it so the bundle UI can
410
+ * show the failure inline next to the SQL instead of swallowing
411
+ * it inside the agent's final answer. */
412
+ error?: string;
413
+ }
414
+ type AgentArtifact = AgentSqlArtifact;
415
+ interface UseAgentRunInput {
416
+ agentId: string;
417
+ }
418
+ interface UseAgentRunResult {
419
+ state: AgentRunState;
420
+ /** Submit a question and open the SSE stream. */
421
+ ask: (question: string, opts?: {
422
+ threadId?: string;
423
+ }) => void;
424
+ /** Cancel the in-flight stream + the server-side run. Idempotent. */
425
+ cancel: () => void;
426
+ /** Accumulated raw events for advanced consumers. */
427
+ events: AgentRunEvent[];
428
+ /** SQL artifacts extracted from the event stream — convenience
429
+ * view over `events` so renderers don't have to know which event
430
+ * types carry SQL. */
431
+ artifacts: AgentArtifact[];
432
+ /** Final answer once a `done` event arrives. Markdown. */
433
+ answer: string | null;
434
+ /** Clarification text once a suspension event arrives. */
435
+ clarification: string | null;
436
+ /** Thread id used by the active run (stable across follow-ups). */
437
+ threadId: string | null;
438
+ /**
439
+ * @beta Relative path to the full thread view in oxy (e.g.
440
+ * `/threads/<id>` for local mode, or
441
+ * `/<org_slug>/workspaces/<ws_id>/threads/<id>` in cloud). Set
442
+ * once the run starts so a bundle can render a "Continue in Oxy"
443
+ * link without constructing the URL itself.
444
+ *
445
+ * Caveats while in beta:
446
+ * - The bundle's origin and the oxy app shell's origin can
447
+ * differ in cloud deployments. If they do, this relative URL
448
+ * resolves against the bundle's origin and 404s. A future
449
+ * release will expose the oxy app origin via the manifest;
450
+ * for now, prefix at the call site if you know your
451
+ * deployment topology, or hide the link entirely.
452
+ * - The thread row may not be queryable until the run produces
453
+ * its first event — clicking the link immediately after
454
+ * `ask()` can land on a "thread not found" page.
455
+ */
456
+ threadUrl: string | null;
457
+ error: Error | null;
458
+ }
459
+ declare function useAgentRun(input: UseAgentRunInput): UseAgentRunResult;
460
+ interface OxyAnswerProps {
461
+ /** Markdown answer text from `useAgentRun().answer`. */
462
+ answer: string | null;
463
+ /** SQL artifacts from `useAgentRun().artifacts`. */
464
+ artifacts?: AgentArtifact[];
465
+ /** Lifecycle state — drives the placeholder, spinner, error UI. */
466
+ state: AgentRunState;
467
+ /** Clarification text when `state === "needs_clarification"`. */
468
+ clarification?: string | null;
469
+ /** Failure reason when `state === "failed"`. */
470
+ error?: Error | null;
471
+ /**
472
+ * @beta Relative URL to the thread view in oxy — renders a
473
+ * "Continue in Oxy (beta)" link when set. Pass `null` to suppress
474
+ * the link entirely; the link is marked beta because the resolved
475
+ * URL may not reach a live thread in every deployment topology
476
+ * (see `UseAgentRunResult.threadUrl`).
477
+ */
478
+ threadUrl?: string | null;
479
+ /** Override the link label. Default: "Continue this thread in Oxy". */
480
+ threadLinkLabel?: string;
481
+ /** Maximum number of SQL result rows to render per artifact. Older
482
+ * rows truncated with a "+N more" note. Default: 10. */
483
+ maxArtifactRows?: number;
484
+ /** Class on the outer container — for callers using utility CSS. */
485
+ className?: string;
804
486
  }
805
487
  /**
806
- * Provider component that initializes and provides OxySDK to child components
807
- *
808
- * @example
809
- * ```tsx
810
- * // Synchronous initialization with config
811
- * function App() {
812
- * return (
813
- * <OxyProvider config={{
814
- * apiKey: 'your-key',
815
- * projectId: 'your-project',
816
- * baseUrl: 'https://api.oxy.tech'
817
- * }}>
818
- * <Dashboard />
819
- * </OxyProvider>
820
- * );
821
- * }
822
- * ```
823
- *
824
- * @example
825
- * ```tsx
826
- * // Async initialization (for iframe/postMessage auth)
827
- * function App() {
828
- * return (
829
- * <OxyProvider
830
- * useAsync
831
- * config={{ parentOrigin: 'https://app.example.com' }}
832
- * >
833
- * <Dashboard />
834
- * </OxyProvider>
835
- * );
836
- * }
837
- * ```
838
- *
839
- * @example
840
- * ```tsx
841
- * // With environment variables
842
- * import { createConfig } from '@oxy/sdk';
843
- *
844
- * function App() {
845
- * return (
846
- * <OxyProvider config={createConfig()}>
847
- * <Dashboard />
848
- * </OxyProvider>
849
- * );
850
- * }
851
- * ```
852
- *
853
- * @example
854
- * ```tsx
855
- * // With loading and error slots
856
- * function App() {
857
- * return (
858
- * <OxyProvider
859
- * config={createConfig()}
860
- * loadingFallback={<div>Loading SDK...</div>}
861
- * errorFallback={(error) => <div>Error: {error.message}</div>}
862
- * >
863
- * <Dashboard />
864
- * </OxyProvider>
865
- * );
866
- * }
867
- * ```
868
- */
869
- declare function OxyProvider({
870
- children,
871
- config,
872
- useAsync,
873
- appPath,
874
- files,
875
- onReady,
876
- onError,
877
- loadingFallback,
878
- errorFallback
879
- }: OxyProviderProps): React.JSX.Element;
880
- /**
881
- * Hook to access OxySDK from child components
882
- *
883
- * @throws {Error} If used outside of OxyProvider
884
- * @returns {OxyContextValue} The SDK instance, loading state, and error
885
- *
886
- * @example
887
- * ```tsx
888
- * function Dashboard() {
889
- * const { sdk, isLoading, error } = useOxy();
890
- *
891
- * useEffect(() => {
892
- * if (sdk) {
893
- * sdk.loadAppData('dashboard.app.yml')
894
- * .then(() => sdk.query('SELECT * FROM my_table'))
895
- * .then(result => console.log(result));
896
- * }
897
- * }, [sdk]);
898
- *
899
- * if (isLoading) return <div>Loading SDK...</div>;
900
- * if (error) return <div>Error: {error.message}</div>;
901
- * if (!sdk) return null;
902
- *
903
- * return <div>Dashboard</div>;
904
- * }
905
- * ```
906
- */
907
- declare function useOxy(): OxyContextValue;
908
- /**
909
- * Hook to access OxySDK that throws if not ready
910
- *
911
- * This is a convenience hook that returns the SDK directly or throws an error if not initialized.
912
- * Use this when you know the SDK should be ready.
488
+ * Renders an agent run's answer + artifacts + thread link as a
489
+ * single block. The default styling is intentionally neutral
490
+ * (system fonts, gray surfaces) so it blends into any bundle.
913
491
  *
914
- * @throws {Error} If used outside of OxyProvider or if SDK is not initialized
915
- * @returns {OxySDK} The SDK instance
492
+ * Designed to be paired with `useAgentRun`:
916
493
  *
917
- * @example
918
494
  * ```tsx
919
- * function DataTable() {
920
- * const sdk = useOxySDK();
921
- * const [data, setData] = useState(null);
922
- *
923
- * useEffect(() => {
924
- * sdk.loadFile('data.parquet', 'data')
925
- * .then(() => sdk.query('SELECT * FROM data LIMIT 100'))
926
- * .then(setData);
927
- * }, [sdk]);
928
- *
929
- * return <table>...</table>;
930
- * }
495
+ * const run = useAgentRun({ agentId: "analyst" });
496
+ * return (
497
+ * <>
498
+ * <button onClick={() => run.ask("how many users last week?")}>Ask</button>
499
+ * <OxyAnswer {...run} />
500
+ * </>
501
+ * );
931
502
  * ```
932
503
  */
933
- declare function useOxySDK(): OxySDK;
934
- //#endregion
935
- //#region src/auth/postMessage.d.ts
936
- /**
937
- * Check if the current context is running inside an iframe
938
- *
939
- * @returns true if running in an iframe, false otherwise (including Node.js)
940
- */
941
- declare function isInIframe(): boolean;
504
+ declare function OxyAnswer(props: OxyAnswerProps): React.JSX.Element;
505
+ interface OxyChatProps {
506
+ /** Agent id (matches `<id>.agentic.yml` in the project). */
507
+ agentId: string;
508
+ /** Placeholder for the question input. */
509
+ placeholder?: string;
510
+ /** Button label. Default: "Ask". */
511
+ submitLabel?: string;
512
+ /** Rendered when the user hasn't asked anything yet. */
513
+ emptyState?: React.ReactNode;
514
+ /** Forwarded to the inner `<OxyAnswer>`. */
515
+ maxArtifactRows?: number;
516
+ /** Class on the outer container. */
517
+ className?: string;
518
+ }
942
519
  /**
943
- * Request authentication from parent window via postMessage
944
- *
945
- * This is the main entry point for iframe-based authentication.
946
- * It sends a request to the parent window and waits for a response.
520
+ * Complete drop-in chat surface. One agent, one input, one answer
521
+ * view. The chat is single-turn by default — each new question
522
+ * cancels the previous run and clears the answer. Bundles that
523
+ * want a multi-turn conversation history compose their own UI
524
+ * using `useAgentRun` directly.
947
525
  *
948
- * @param options - Configuration options for the auth request
949
- * @returns Promise that resolves with authentication credentials
950
- * @throws {PostMessageAuthNotInIframeError} If not in an iframe
951
- * @throws {PostMessageAuthTimeoutError} If parent doesn't respond in time
952
- * @throws {PostMessageAuthInvalidOriginError} If response from wrong origin
953
- * @throws {PostMessageAuthInvalidResponseError} If response is malformed
954
- *
955
- * @example
956
- * ```typescript
957
- * const auth = await requestAuthFromParent({
958
- * parentOrigin: 'https://app.example.com',
959
- * timeout: 5000
960
- * });
961
- * console.log('Received API key:', auth.apiKey);
962
- * ```
526
+ * Single-turn keeps the surface dead simple: bundles use this for
527
+ * the "ask anything about your data" widget that sits next to
528
+ * structured panels. Multi-turn is rare in those contexts and
529
+ * better expressed by the bundle.
963
530
  */
964
- declare function requestAuthFromParent(options?: PostMessageAuthOptions): Promise<PostMessageAuthResult>;
531
+ declare function OxyChat(props: OxyChatProps): React.JSX.Element;
965
532
  //#endregion
966
- export { type AppDataResponse, type AppItem, type DataContainer, type DisplayData, type DisplayWithError, type FileReference, type OxyAuthRequestMessage, type OxyAuthResponseMessage, OxyClient, type OxyConfig, type OxyContextValue, OxyProvider, type OxyProviderProps, OxySDK, ParquetReader, PostMessageAuthInvalidOriginError, PostMessageAuthInvalidResponseError, PostMessageAuthNotInIframeError, type PostMessageAuthOptions, type PostMessageAuthResult, PostMessageAuthTimeoutError, type QueryResult, type TableData, createConfig, createConfigAsync, initializeDuckDB, isInIframe, queryParquet, readParquet, requestAuthFromParent, useOxy, useOxySDK };
533
+ export { type AgentArtifact, type AgentRunEvent, type AgentRunState, type AgentSqlArtifact, type AppFetcher, type CustomerAppDebugSnapshot, type CustomerAppErrorReport, type LoadManifestOptions, OxyAnswer, type OxyAnswerProps, OxyApiError, type OxyAppLogLevel, type OxyAppLogger, type OxyAppManifest, OxyAppProvider, type OxyAppProviderProps, OxyChat, type OxyChatProps, type OxyInjectedAppConfig, type ProcedureProgress, type ProcedureResult, type ProcedureRunState, type ResolvedCustomerAppManifest, type SemanticArrayOp, type SemanticDateRangeOp, type SemanticFilter, type SemanticScalarOp, type SemanticTimeDimension, type UseAgentRunInput, type UseAgentRunResult, type UseProcedureRunInput, type UseProcedureRunOpts, type UseProcedureRunResult, type UseQueryInput, type UseQueryOpts, type UseQueryResult, type UseSemanticQueryInput, type UseSemanticQueryOpts, type UseSemanticQueryResult, _resetCustomerAppManifestCacheForTest, getCustomerAppDebug, getOxyAppLogger, interpretCustomerAppError, loadCustomerAppManifest, readInjectedAppConfig, setOxyAppLogger, useAgentRun, useProcedureRun, useQuery, useResolvedManifest, useSemanticQuery };
967
534
  //# sourceMappingURL=index.d.mts.map